]> git.karo-electronics.de Git - mv-sheeva.git/commitdiff
Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/bwh/sfc...
authorDavid S. Miller <davem@davemloft.net>
Fri, 10 Dec 2010 18:20:43 +0000 (10:20 -0800)
committerDavid S. Miller <davem@davemloft.net>
Fri, 10 Dec 2010 18:20:43 +0000 (10:20 -0800)
245 files changed:
Documentation/DocBook/80211.tmpl
Documentation/networking/dccp.txt
Documentation/networking/ip-sysctl.txt
MAINTAINERS
drivers/atm/lanai.c
drivers/bluetooth/ath3k.c
drivers/bluetooth/btusb.c
drivers/isdn/hisax/config.c
drivers/isdn/icn/icn.c
drivers/net/Kconfig
drivers/net/arm/am79c961a.c
drivers/net/atl1c/atl1c_hw.c
drivers/net/au1000_eth.c
drivers/net/b44.c
drivers/net/benet/be.h
drivers/net/benet/be_cmds.c
drivers/net/benet/be_main.c
drivers/net/bnx2x/bnx2x.h
drivers/net/bnx2x/bnx2x_cmn.c
drivers/net/bnx2x/bnx2x_init_ops.h
drivers/net/bnx2x/bnx2x_main.c
drivers/net/bonding/bond_main.c
drivers/net/caif/caif_shm_u5500.c
drivers/net/caif/caif_shmcore.c
drivers/net/can/Kconfig
drivers/net/can/Makefile
drivers/net/can/slcan.c [new file with mode: 0644]
drivers/net/cris/eth_v10.c
drivers/net/cxgb4/t4_hw.c
drivers/net/cxgb4vf/cxgb4vf_main.c
drivers/net/cxgb4vf/t4vf_hw.c
drivers/net/e1000/e1000_main.c
drivers/net/ehea/ehea_ethtool.c
drivers/net/ehea/ehea_main.c
drivers/net/ifb.c
drivers/net/irda/sh_sir.c
drivers/net/ixgbe/ixgbe_82599.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixgbe/ixgbe_type.h
drivers/net/jme.c
drivers/net/pch_gbe/pch_gbe_ethtool.c
drivers/net/pch_gbe/pch_gbe_main.c
drivers/net/pch_gbe/pch_gbe_param.c
drivers/net/phy/marvell.c
drivers/net/ppp_generic.c
drivers/net/qlge/qlge_main.c
drivers/net/sc92031.c
drivers/net/sfc/efx.c
drivers/net/sfc/net_driver.h
drivers/net/sfc/nic.c
drivers/net/stmmac/stmmac_ethtool.c
drivers/net/stmmac/stmmac_main.c
drivers/net/tg3.c
drivers/net/tg3.h
drivers/net/tulip/dmfe.c
drivers/net/ucc_geth.h
drivers/net/usb/Kconfig
drivers/net/usb/Makefile
drivers/net/usb/cdc_ncm.c [new file with mode: 0644]
drivers/net/usb/hso.c
drivers/net/usb/usbnet.c
drivers/net/via-rhine.c
drivers/net/vxge/vxge-ethtool.c
drivers/net/vxge/vxge-main.c
drivers/net/wan/x25_asy.c
drivers/net/wireless/ath/ar9170/usb.c
drivers/net/wireless/ath/ath.h
drivers/net/wireless/ath/ath5k/Kconfig
drivers/net/wireless/ath/ath5k/Makefile
drivers/net/wireless/ath/ath5k/ahb.c [new file with mode: 0644]
drivers/net/wireless/ath/ath5k/ani.c
drivers/net/wireless/ath/ath5k/ath5k.h
drivers/net/wireless/ath/ath5k/attach.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/base.h
drivers/net/wireless/ath/ath5k/caps.c
drivers/net/wireless/ath/ath5k/debug.c
drivers/net/wireless/ath/ath5k/debug.h
drivers/net/wireless/ath/ath5k/desc.c
drivers/net/wireless/ath/ath5k/dma.c
drivers/net/wireless/ath/ath5k/eeprom.c
drivers/net/wireless/ath/ath5k/eeprom.h
drivers/net/wireless/ath/ath5k/initvals.c
drivers/net/wireless/ath/ath5k/led.c
drivers/net/wireless/ath/ath5k/pci.c [new file with mode: 0644]
drivers/net/wireless/ath/ath5k/pcu.c
drivers/net/wireless/ath/ath5k/phy.c
drivers/net/wireless/ath/ath5k/qcu.c
drivers/net/wireless/ath/ath5k/reg.h
drivers/net/wireless/ath/ath5k/reset.c
drivers/net/wireless/ath/ath5k/rfbuffer.h
drivers/net/wireless/ath/ath5k/sysfs.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.h
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/btcoex.c
drivers/net/wireless/ath/ath9k/btcoex.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/eeprom.c
drivers/net/wireless/ath/ath9k/eeprom.h
drivers/net/wireless/ath/ath9k/eeprom_def.c
drivers/net/wireless/ath/ath9k/hif_usb.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/htc_hst.h
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/reg.h
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/fw.c
drivers/net/wireless/ath/carl9170/main.c
drivers/net/wireless/ath/carl9170/tx.c
drivers/net/wireless/ath/carl9170/usb.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/b43/phy_n.h
drivers/net/wireless/b43/radio_2055.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-eeprom.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn-ucode.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-commands.h
drivers/net/wireless/iwlwifi/iwl-eeprom.h
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/libertas/if_spi.c
drivers/net/wireless/libertas/main.c
drivers/net/wireless/orinoco/main.c
drivers/net/wireless/orinoco/scan.c
drivers/net/wireless/orinoco/scan.h
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/ray_cs.c
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/zd1201.c
drivers/net/xilinx_emaclite.c
drivers/ssb/main.c
drivers/ssb/pci.c
drivers/vhost/net.c
include/linux/dccp.h
include/linux/filter.h
include/linux/inetdevice.h
include/linux/jhash.h
include/linux/marvell_phy.h
include/linux/mdio.h
include/linux/netdevice.h
include/linux/nl80211.h
include/linux/snmp.h
include/linux/ssb/ssb.h
include/linux/ssb/ssb_regs.h
include/linux/usb/usbnet.h
include/net/af_unix.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/bluetooth/rfcomm.h
include/net/bluetooth/sco.h
include/net/cfg80211.h
include/net/dst.h
include/net/inet_sock.h
include/net/inet_timewait_sock.h
include/net/mac80211.h
include/net/sock.h
net/9p/protocol.c
net/bluetooth/bnep/core.c
net/bluetooth/cmtp/core.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/hidp/core.c
net/bluetooth/l2cap.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/rfcomm/tty.c
net/bluetooth/sco.c
net/bridge/br_device.c
net/bridge/br_netfilter.c
net/ceph/Makefile
net/ceph/buffer.c
net/core/datagram.c
net/core/dev.c
net/core/ethtool.c
net/core/filter.c
net/core/request_sock.c
net/core/skbuff.c
net/core/sock.c
net/core/timestamping.c
net/dccp/Makefile
net/dccp/dccp.h
net/dccp/input.c
net/dccp/output.c
net/dccp/proto.c
net/dccp/qpolicy.c [new file with mode: 0644]
net/decnet/af_decnet.c
net/decnet/dn_route.c
net/econet/af_econet.c
net/ieee802154/af_ieee802154.c
net/ipv4/arp.c
net/ipv4/devinet.c
net/ipv4/fib_trie.c
net/ipv4/inet_connection_sock.c
net/ipv4/inet_hashtables.c
net/ipv4/ip_gre.c
net/ipv4/proc.c
net/ipv4/route.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_output.c
net/ipv6/ip6_tunnel.c
net/ipv6/ndisc.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/udp.c
net/l2tp/l2tp_ip.c
net/llc/af_llc.c
net/mac80211/agg-rx.c
net/mac80211/cfg.c
net/mac80211/debugfs_sta.c
net/mac80211/ieee80211_i.h
net/mac80211/rx.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/tx.c
net/mac80211/work.c
net/packet/af_packet.c
net/sctp/socket.c
net/unix/af_unix.c
net/unix/garbage.c
net/wireless/core.h
net/wireless/mlme.c
net/wireless/nl80211.c
net/x25/x25_link.c
net/xfrm/xfrm_hash.c
net/xfrm/xfrm_policy.c

index 19a1210c2530681762b6d77b46901fa3374b54ec..03641a08e2753416fb3d32362771c9fed7ca7ed4 100644 (file)
 !Finclude/net/cfg80211.h cfg80211_rx_mgmt
 !Finclude/net/cfg80211.h cfg80211_mgmt_tx_status
 !Finclude/net/cfg80211.h cfg80211_cqm_rssi_notify
+!Finclude/net/cfg80211.h cfg80211_cqm_pktloss_notify
 !Finclude/net/cfg80211.h cfg80211_michael_mic_failure
       </chapter>
       <chapter>
           <title>functions/definitions</title>
 !Finclude/net/mac80211.h ieee80211_rx_status
 !Finclude/net/mac80211.h mac80211_rx_flags
+!Finclude/net/mac80211.h mac80211_tx_control_flags
+!Finclude/net/mac80211.h mac80211_rate_control_flags
+!Finclude/net/mac80211.h ieee80211_tx_rate
 !Finclude/net/mac80211.h ieee80211_tx_info
+!Finclude/net/mac80211.h ieee80211_tx_info_clear_status
 !Finclude/net/mac80211.h ieee80211_rx
+!Finclude/net/mac80211.h ieee80211_rx_ni
 !Finclude/net/mac80211.h ieee80211_rx_irqsafe
 !Finclude/net/mac80211.h ieee80211_tx_status
+!Finclude/net/mac80211.h ieee80211_tx_status_ni
 !Finclude/net/mac80211.h ieee80211_tx_status_irqsafe
 !Finclude/net/mac80211.h ieee80211_rts_get
 !Finclude/net/mac80211.h ieee80211_rts_duration
 !Finclude/net/mac80211.h ieee80211_stop_queue
 !Finclude/net/mac80211.h ieee80211_wake_queues
 !Finclude/net/mac80211.h ieee80211_stop_queues
+!Finclude/net/mac80211.h ieee80211_queue_stopped
         </sect1>
       </chapter>
 
 !Pinclude/net/mac80211.h Frame filtering
 !Finclude/net/mac80211.h ieee80211_filter_flags
       </chapter>
+
+      <chapter id="workqueue">
+        <title>The mac80211 workqueue</title>
+!Pinclude/net/mac80211.h mac80211 workqueue
+!Finclude/net/mac80211.h ieee80211_queue_work
+!Finclude/net/mac80211.h ieee80211_queue_delayed_work
+      </chapter>
     </part>
 
     <part id="advanced">
 !Finclude/net/mac80211.h set_key_cmd
 !Finclude/net/mac80211.h ieee80211_key_conf
 !Finclude/net/mac80211.h ieee80211_key_flags
+!Finclude/net/mac80211.h ieee80211_tkip_key_type
+!Finclude/net/mac80211.h ieee80211_get_tkip_key
+!Finclude/net/mac80211.h ieee80211_key_removed
       </chapter>
 
       <chapter id="powersave">
           supported by mac80211, add notes about supporting hw crypto
           with it.
         </para>
+!Finclude/net/mac80211.h ieee80211_iterate_active_interfaces
+!Finclude/net/mac80211.h ieee80211_iterate_active_interfaces_atomic
+      </chapter>
+
+      <chapter id="station-handling">
+        <title>Station handling</title>
+        <para>TODO</para>
+!Finclude/net/mac80211.h ieee80211_sta
+!Finclude/net/mac80211.h sta_notify_cmd
+!Finclude/net/mac80211.h ieee80211_find_sta
+!Finclude/net/mac80211.h ieee80211_find_sta_by_ifaddr
+!Finclude/net/mac80211.h ieee80211_sta_block_awake
       </chapter>
 
       <chapter id="hardware-scan-offload">
         <para>TBD</para>
 !Finclude/net/mac80211.h ieee80211_scan_completed
       </chapter>
+
+      <chapter id="aggregation">
+        <title>Aggregation</title>
+        <sect1>
+          <title>TX A-MPDU aggregation</title>
+!Pnet/mac80211/agg-tx.c TX A-MPDU aggregation
+!Cnet/mac80211/agg-tx.c
+        </sect1>
+        <sect1>
+          <title>RX A-MPDU aggregation</title>
+!Pnet/mac80211/agg-rx.c RX A-MPDU aggregation
+!Cnet/mac80211/agg-rx.c
+        </sect1>
+!Finclude/net/mac80211.h ieee80211_ampdu_mlme_action
+      </chapter>
+
+      <chapter id="smps">
+        <title>Spatial Multiplexing Powersave (SMPS)</title>
+!Pinclude/net/mac80211.h Spatial multiplexing power save
+!Finclude/net/mac80211.h ieee80211_request_smps
+!Finclude/net/mac80211.h ieee80211_smps_mode
+      </chapter>
     </part>
 
     <part id="rate-control">
          interface and how it relates to mac80211 and drivers.
         </para>
       </partintro>
-      <chapter id="dummy">
-        <title>dummy chapter</title>
+      <chapter id="ratecontrol-api">
+        <title>Rate Control API</title>
         <para>TBD</para>
+!Finclude/net/mac80211.h ieee80211_start_tx_ba_session
+!Finclude/net/mac80211.h ieee80211_start_tx_ba_cb_irqsafe
+!Finclude/net/mac80211.h ieee80211_stop_tx_ba_session
+!Finclude/net/mac80211.h ieee80211_stop_tx_ba_cb_irqsafe
+!Finclude/net/mac80211.h rate_control_changed
+!Finclude/net/mac80211.h ieee80211_tx_rate_control
+!Finclude/net/mac80211.h rate_control_send_low
       </chapter>
     </part>
 
         </sect1>
       </chapter>
 
+      <chapter id="aggregation-internals">
+        <title>Aggregation</title>
+!Fnet/mac80211/sta_info.h sta_ampdu_mlme
+!Fnet/mac80211/sta_info.h tid_ampdu_tx
+!Fnet/mac80211/sta_info.h tid_ampdu_rx
+      </chapter>
+
       <chapter id="synchronisation">
         <title>Synchronisation</title>
         <para>TBD</para>
index 271d524a4c8d53dc4fab4aa91fee28ea89fe4f62..b395ca6a49f296e7b1ddda4e6a580f8691b22532 100644 (file)
@@ -47,6 +47,26 @@ http://linux-net.osdl.org/index.php/DCCP_Testing#Experimental_DCCP_source_tree
 
 Socket options
 ==============
+DCCP_SOCKOPT_QPOLICY_ID sets the dequeuing policy for outgoing packets. It takes
+a policy ID as argument and can only be set before the connection (i.e. changes
+during an established connection are not supported). Currently, two policies are
+defined: the "simple" policy (DCCPQ_POLICY_SIMPLE), which does nothing special,
+and a priority-based variant (DCCPQ_POLICY_PRIO). The latter allows to pass an
+u32 priority value as ancillary data to sendmsg(), where higher numbers indicate
+a higher packet priority (similar to SO_PRIORITY). This ancillary data needs to
+be formatted using a cmsg(3) message header filled in as follows:
+       cmsg->cmsg_level = SOL_DCCP;
+       cmsg->cmsg_type  = DCCP_SCM_PRIORITY;
+       cmsg->cmsg_len   = CMSG_LEN(sizeof(uint32_t));  /* or CMSG_LEN(4) */
+
+DCCP_SOCKOPT_QPOLICY_TXQLEN sets the maximum length of the output queue. A zero
+value is always interpreted as unbounded queue length. If different from zero,
+the interpretation of this parameter depends on the current dequeuing policy
+(see above): the "simple" policy will enforce a fixed queue size by returning
+EAGAIN, whereas the "prio" policy enforces a fixed queue length by dropping the
+lowest-priority packet first. The default value for this parameter is
+initialised from /proc/sys/net/dccp/default/tx_qlen.
+
 DCCP_SOCKOPT_SERVICE sets the service. The specification mandates use of
 service codes (RFC 4340, sec. 8.1.2); if this socket option is not set,
 the socket will fall back to 0 (which means that no meaningful service code
index ae5522703d16e8b579e3ed3c0b2e03f1d707bea5..2193a5d124c5982a85398bc42094a91225236df0 100644 (file)
@@ -144,6 +144,7 @@ tcp_adv_win_scale - INTEGER
        Count buffering overhead as bytes/2^tcp_adv_win_scale
        (if tcp_adv_win_scale > 0) or bytes-bytes/2^(-tcp_adv_win_scale),
        if it is <= 0.
+       Possible values are [-31, 31], inclusive.
        Default: 2
 
 tcp_allowed_congestion_control - STRING
index 8b6ca96435eeec015930a4f130c76da0210dd753..9206cb4629135aeb7e8b1f5cfedb4aeb256a3391 100644 (file)
@@ -1359,7 +1359,7 @@ F:        include/net/bluetooth/
 
 BONDING DRIVER
 M:     Jay Vosburgh <fubar@us.ibm.com>
-L:     bonding-devel@lists.sourceforge.net
+L:     netdev@vger.kernel.org
 W:     http://sourceforge.net/projects/bonding/
 S:     Supported
 F:     drivers/net/bonding/
index cbe15a86c6698b2044b45469fa57f8d199aca15e..930051d941a7817a65b75ca7cc7fe72f9e045d00 100644 (file)
@@ -2241,11 +2241,8 @@ static int __devinit lanai_dev_open(struct atm_dev *atmdev)
        memcpy(atmdev->esi, eeprom_mac(lanai), ESI_LEN);
        lanai_timed_poll_start(lanai);
        printk(KERN_NOTICE DEV_LABEL "(itf %d): rev.%d, base=0x%lx, irq=%u "
-           "(%02X-%02X-%02X-%02X-%02X-%02X)\n", lanai->number,
-           (int) lanai->pci->revision, (unsigned long) lanai->base,
-           lanai->pci->irq,
-           atmdev->esi[0], atmdev->esi[1], atmdev->esi[2],
-           atmdev->esi[3], atmdev->esi[4], atmdev->esi[5]);
+               "(%pMF)\n", lanai->number, (int) lanai->pci->revision,
+               (unsigned long) lanai->base, lanai->pci->irq, atmdev->esi);
        printk(KERN_NOTICE DEV_LABEL "(itf %d): LANAI%s, serialno=%u(0x%X), "
            "board_rev=%d\n", lanai->number,
            lanai->type==lanai2 ? "2" : "HB", (unsigned int) lanai->serialno,
index 128cae4e8629465429cf271209f587b8e192b3ad..949ed09c6361130c30c3ebda1bc4db02b00fa4c2 100644 (file)
 static struct usb_device_id ath3k_table[] = {
        /* Atheros AR3011 */
        { USB_DEVICE(0x0CF3, 0x3000) },
+
+       /* Atheros AR3011 with sflash firmware*/
+       { USB_DEVICE(0x0CF3, 0x3002) },
+
        { }     /* Terminating entry */
 };
 
index ab3894f742c3002a90a98b89f116ab30c75cdb28..1da773f899a2708f1c151b892098ed3ddbaf79cf 100644 (file)
@@ -99,6 +99,9 @@ static struct usb_device_id blacklist_table[] = {
        /* Broadcom BCM2033 without firmware */
        { USB_DEVICE(0x0a5c, 0x2033), .driver_info = BTUSB_IGNORE },
 
+       /* Atheros 3011 with sflash firmware */
+       { USB_DEVICE(0x0cf3, 0x3002), .driver_info = BTUSB_IGNORE },
+
        /* Broadcom BCM2035 */
        { USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
        { USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
@@ -239,7 +242,8 @@ static void btusb_intr_complete(struct urb *urb)
 
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err < 0) {
-               BT_ERR("%s urb %p failed to resubmit (%d)",
+               if (err != -EPERM)
+                       BT_ERR("%s urb %p failed to resubmit (%d)",
                                                hdev->name, urb, -err);
                usb_unanchor_urb(urb);
        }
@@ -323,7 +327,8 @@ static void btusb_bulk_complete(struct urb *urb)
 
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err < 0) {
-               BT_ERR("%s urb %p failed to resubmit (%d)",
+               if (err != -EPERM)
+                       BT_ERR("%s urb %p failed to resubmit (%d)",
                                                hdev->name, urb, -err);
                usb_unanchor_urb(urb);
        }
@@ -412,7 +417,8 @@ static void btusb_isoc_complete(struct urb *urb)
 
        err = usb_submit_urb(urb, GFP_ATOMIC);
        if (err < 0) {
-               BT_ERR("%s urb %p failed to resubmit (%d)",
+               if (err != -EPERM)
+                       BT_ERR("%s urb %p failed to resubmit (%d)",
                                                hdev->name, urb, -err);
                usb_unanchor_urb(urb);
        }
index b133378d4dc9b1707c749102c345c3c2f7b2d7d4..c110f8679babd4407c44172456272722a879cf8b 100644 (file)
@@ -1917,7 +1917,7 @@ static void EChannel_proc_rcv(struct hisax_d_if *d_if)
 #ifdef CONFIG_PCI
 #include <linux/pci.h>
 
-static struct pci_device_id hisax_pci_tbl[] __devinitdata = {
+static struct pci_device_id hisax_pci_tbl[] __devinitdata __used = {
 #ifdef CONFIG_HISAX_FRITZPCI
        {PCI_VDEVICE(AVM,      PCI_DEVICE_ID_AVM_A1)                    },
 #endif
index 2e847a90bad0d601f8bcc5f9a7bd4d7440f929c0..f2b5bab5e6a191761d2f56331c792ca8f7f78182 100644 (file)
@@ -1627,7 +1627,7 @@ __setup("icn=", icn_setup);
 static int __init icn_init(void)
 {
        char *p;
-       char rev[10];
+       char rev[20];
 
        memset(&dev, 0, sizeof(icn_dev));
        dev.memaddr = (membase & 0x0ffc000);
@@ -1637,9 +1637,10 @@ static int __init icn_init(void)
        spin_lock_init(&dev.devlock);
 
        if ((p = strchr(revision, ':'))) {
-               strcpy(rev, p + 1);
+               strncpy(rev, p + 1, 20);
                p = strchr(rev, '$');
-               *p = 0;
+               if (p)
+                       *p = 0;
        } else
                strcpy(rev, " ??? ");
        printk(KERN_NOTICE "ICN-ISDN-driver Rev%smem=0x%08lx\n", rev,
index a11dc735752c2278478d2a040fe651223d3c70e6..a20693fcb3210518e9437448cf79ea8d116483f3 100644 (file)
@@ -2543,10 +2543,10 @@ config PCH_GBE
        depends on PCI
        select MII
        ---help---
-         This is a gigabit ethernet driver for Topcliff PCH.
-         Topcliff PCH is the platform controller hub that is used in Intel's
+         This is a gigabit ethernet driver for EG20T PCH.
+         EG20T PCH is the platform controller hub that is used in Intel's
          general embedded platform.
-         Topcliff PCH has Gigabit Ethernet interface.
+         EG20T PCH has Gigabit Ethernet interface.
          Using this interface, it is able to access system devices connected
          to Gigabit Ethernet.
          This driver enables Gigabit Ethernet function.
index 62f21106efec224d3447f408439a55bb7d4743e3..0c9217f48b72060d77c6ac20eaa592011cb4a009 100644 (file)
@@ -340,14 +340,6 @@ am79c961_close(struct net_device *dev)
        return 0;
 }
 
-/*
- * Get the current statistics.
- */
-static struct net_device_stats *am79c961_getstats (struct net_device *dev)
-{
-       return &dev->stats;
-}
-
 static void am79c961_mc_hash(char *addr, unsigned short *hash)
 {
        if (addr[0] & 0x01) {
@@ -665,7 +657,6 @@ static const struct net_device_ops am79c961_netdev_ops = {
        .ndo_open               = am79c961_open,
        .ndo_stop               = am79c961_close,
        .ndo_start_xmit         = am79c961_sendpacket,
-       .ndo_get_stats          = am79c961_getstats,
        .ndo_set_multicast_list = am79c961_setmulticastlist,
        .ndo_tx_timeout         = am79c961_timeout,
        .ndo_validate_addr      = eth_validate_addr,
index 919080b2c3a50eb48bea7311ac0db4e8d3e8103e..1bf67200994827fd76250e718b3bdf4a67a609e8 100644 (file)
@@ -82,7 +82,7 @@ static int atl1c_get_permanent_address(struct atl1c_hw *hw)
        addr[0] = addr[1] = 0;
        AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
        if (atl1c_check_eeprom_exist(hw)) {
-               if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c_b) {
+               if (hw->nic_type == athr_l1c || hw->nic_type == athr_l2c) {
                        /* Enable OTP CLK */
                        if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) {
                                otp_ctrl_data |= OTP_CTRL_CLK_EN;
index 43489f89c142f7d10e25f0454287ef28939fd228..53eff9ba6e9500a3ea2327a55a42fcb9d9aeefea 100644 (file)
@@ -155,10 +155,10 @@ static void au1000_enable_mac(struct net_device *dev, int force_reset)
        spin_lock_irqsave(&aup->lock, flags);
 
        if (force_reset || (!aup->mac_enabled)) {
-               writel(MAC_EN_CLOCK_ENABLE, &aup->enable);
+               writel(MAC_EN_CLOCK_ENABLE, aup->enable);
                au_sync_delay(2);
                writel((MAC_EN_RESET0 | MAC_EN_RESET1 | MAC_EN_RESET2
-                               | MAC_EN_CLOCK_ENABLE), &aup->enable);
+                               | MAC_EN_CLOCK_ENABLE), aup->enable);
                au_sync_delay(2);
 
                aup->mac_enabled = 1;
@@ -503,9 +503,9 @@ static void au1000_reset_mac_unlocked(struct net_device *dev)
 
        au1000_hard_stop(dev);
 
-       writel(MAC_EN_CLOCK_ENABLE, &aup->enable);
+       writel(MAC_EN_CLOCK_ENABLE, aup->enable);
        au_sync_delay(2);
-       writel(0, &aup->enable);
+       writel(0, aup->enable);
        au_sync_delay(2);
 
        aup->tx_full = 0;
@@ -1119,7 +1119,7 @@ static int __devinit au1000_probe(struct platform_device *pdev)
        /* set a random MAC now in case platform_data doesn't provide one */
        random_ether_addr(dev->dev_addr);
 
-       writel(0, &aup->enable);
+       writel(0, aup->enable);
        aup->mac_enabled = 0;
 
        pd = pdev->dev.platform_data;
index c6e86315b3f8df37aa2ac1a767ac46fc1b5eba60..2e2b76258ab42cbc6b0dc73f70bd9547a5846857 100644 (file)
@@ -381,11 +381,11 @@ static void b44_set_flow_ctrl(struct b44 *bp, u32 local, u32 remote)
        __b44_set_flow_ctrl(bp, pause_enab);
 }
 
-#ifdef SSB_DRIVER_MIPS
-extern char *nvram_get(char *name);
+#ifdef CONFIG_BCM47XX
+#include <asm/mach-bcm47xx/nvram.h>
 static void b44_wap54g10_workaround(struct b44 *bp)
 {
-       const char *str;
+       char buf[20];
        u32 val;
        int err;
 
@@ -394,10 +394,9 @@ static void b44_wap54g10_workaround(struct b44 *bp)
         * see https://dev.openwrt.org/ticket/146
         * check and reset bit "isolate"
         */
-       str = nvram_get("boardnum");
-       if (!str)
+       if (nvram_getenv("boardnum", buf, sizeof(buf)) < 0)
                return;
-       if (simple_strtoul(str, NULL, 0) == 2) {
+       if (simple_strtoul(buf, NULL, 0) == 2) {
                err = __b44_readphy(bp, 0, MII_BMCR, &val);
                if (err)
                        goto error;
index b61a1dfebcafb0e83b903a87b00c90b7dfcb09e7..9cab32328bbacc8103c3a52a5b2668e605481fda 100644 (file)
@@ -220,7 +220,9 @@ struct be_rx_obj {
        struct be_rx_stats stats;
        u8 rss_id;
        bool rx_post_starved;   /* Zero rx frags have been posted to BE */
-       u32 cache_line_barrier[16];
+       u16 last_frag_index;
+       u16 rsvd;
+       u32 cache_line_barrier[15];
 };
 
 struct be_vf_cfg {
index 3865b2bc65e6abab69ab071d13dae8930c2372e2..171a08caf2be0c156205ce09417d269423c9c365 100644 (file)
@@ -470,25 +470,14 @@ int be_cmd_fw_init(struct be_adapter *adapter)
        spin_lock(&adapter->mbox_lock);
 
        wrb = (u8 *)wrb_from_mbox(adapter);
-       if (lancer_chip(adapter)) {
-               *wrb++ = 0xFF;
-               *wrb++ = 0x34;
-               *wrb++ = 0x12;
-               *wrb++ = 0xFF;
-               *wrb++ = 0xFF;
-               *wrb++ = 0x78;
-               *wrb++ = 0x56;
-               *wrb = 0xFF;
-       } else {
-               *wrb++ = 0xFF;
-               *wrb++ = 0x12;
-               *wrb++ = 0x34;
-               *wrb++ = 0xFF;
-               *wrb++ = 0xFF;
-               *wrb++ = 0x56;
-               *wrb++ = 0x78;
-               *wrb = 0xFF;
-       }
+       *wrb++ = 0xFF;
+       *wrb++ = 0x12;
+       *wrb++ = 0x34;
+       *wrb++ = 0xFF;
+       *wrb++ = 0xFF;
+       *wrb++ = 0x56;
+       *wrb++ = 0x78;
+       *wrb = 0xFF;
 
        status = be_mbox_notify_wait(adapter);
 
@@ -1285,7 +1274,7 @@ int be_cmd_multicast_set(struct be_adapter *adapter, u32 if_id,
 
                i = 0;
                netdev_for_each_mc_addr(ha, netdev)
-                       memcpy(req->mac[i].byte, ha->addr, ETH_ALEN);
+                       memcpy(req->mac[i++].byte, ha->addr, ETH_ALEN);
        } else {
                req->promiscuous = 1;
        }
index 102567ee68c2e22d8efb3cb0c4deff7891056515..0b35e4a8bf193fd90fd586278340bcc85281dbf7 100644 (file)
@@ -911,11 +911,17 @@ static void be_rx_compl_discard(struct be_adapter *adapter,
        rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
        num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
 
-       for (i = 0; i < num_rcvd; i++) {
-               page_info = get_rx_page_info(adapter, rxo, rxq_idx);
-               put_page(page_info->page);
-               memset(page_info, 0, sizeof(*page_info));
-               index_inc(&rxq_idx, rxq->len);
+        /* Skip out-of-buffer compl(lancer) or flush compl(BE) */
+       if (likely(rxq_idx != rxo->last_frag_index && num_rcvd != 0)) {
+
+               rxo->last_frag_index = rxq_idx;
+
+               for (i = 0; i < num_rcvd; i++) {
+                       page_info = get_rx_page_info(adapter, rxo, rxq_idx);
+                       put_page(page_info->page);
+                       memset(page_info, 0, sizeof(*page_info));
+                       index_inc(&rxq_idx, rxq->len);
+               }
        }
 }
 
@@ -1016,9 +1022,6 @@ static void be_rx_compl_process(struct be_adapter *adapter,
        u8 vtm;
 
        num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
-       /* Is it a flush compl that has no data */
-       if (unlikely(num_rcvd == 0))
-               return;
 
        skb = netdev_alloc_skb_ip_align(adapter->netdev, BE_HDR_LEN);
        if (unlikely(!skb)) {
@@ -1075,10 +1078,6 @@ static void be_rx_compl_process_gro(struct be_adapter *adapter,
        u8 pkt_type;
 
        num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
-       /* Is it a flush compl that has no data */
-       if (unlikely(num_rcvd == 0))
-               return;
-
        pkt_size = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp);
        vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
        rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
@@ -1349,7 +1348,7 @@ static void be_rx_q_clean(struct be_adapter *adapter, struct be_rx_obj *rxo)
        while ((rxcp = be_rx_compl_get(rxo)) != NULL) {
                be_rx_compl_discard(adapter, rxo, rxcp);
                be_rx_compl_reset(rxcp);
-               be_cq_notify(adapter, rx_cq->id, true, 1);
+               be_cq_notify(adapter, rx_cq->id, false, 1);
        }
 
        /* Then free posted rx buffer that were not used */
@@ -1576,6 +1575,9 @@ static int be_rx_queues_create(struct be_adapter *adapter)
        adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;
        for_all_rx_queues(adapter, rxo, i) {
                rxo->adapter = adapter;
+               /* Init last_frag_index so that the frag index in the first
+                * completion will never match */
+               rxo->last_frag_index = 0xffff;
                rxo->rx_eq.max_eqd = BE_MAX_EQD;
                rxo->rx_eq.enable_aic = true;
 
@@ -1697,10 +1699,9 @@ static irqreturn_t be_msix_tx_mcc(int irq, void *dev)
        return IRQ_HANDLED;
 }
 
-static inline bool do_gro(struct be_adapter *adapter, struct be_rx_obj *rxo,
-                       struct be_eth_rx_compl *rxcp)
+static inline bool do_gro(struct be_rx_obj *rxo,
+                       struct be_eth_rx_compl *rxcp, u8 err)
 {
-       int err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp);
        int tcp_frame = AMAP_GET_BITS(struct amap_eth_rx_compl, tcpf, rxcp);
 
        if (err)
@@ -1717,6 +1718,8 @@ static int be_poll_rx(struct napi_struct *napi, int budget)
        struct be_queue_info *rx_cq = &rxo->cq;
        struct be_eth_rx_compl *rxcp;
        u32 work_done;
+       u16 frag_index, num_rcvd;
+       u8 err;
 
        rxo->stats.rx_polls++;
        for (work_done = 0; work_done < budget; work_done++) {
@@ -1724,10 +1727,22 @@ static int be_poll_rx(struct napi_struct *napi, int budget)
                if (!rxcp)
                        break;
 
-               if (do_gro(adapter, rxo, rxcp))
-                       be_rx_compl_process_gro(adapter, rxo, rxcp);
-               else
-                       be_rx_compl_process(adapter, rxo, rxcp);
+               err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp);
+               frag_index = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx,
+                                                               rxcp);
+               num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags,
+                                                               rxcp);
+
+               /* Skip out-of-buffer compl(lancer) or flush compl(BE) */
+               if (likely(frag_index != rxo->last_frag_index &&
+                               num_rcvd != 0)) {
+                       rxo->last_frag_index = frag_index;
+
+                       if (do_gro(rxo, rxcp, err))
+                               be_rx_compl_process_gro(adapter, rxo, rxcp);
+                       else
+                               be_rx_compl_process(adapter, rxo, rxcp);
+               }
 
                be_rx_compl_reset(rxcp);
        }
@@ -2583,10 +2598,12 @@ static void be_netdev_init(struct net_device *netdev)
        int i;
 
        netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO |
-               NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_HW_CSUM |
+               NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER |
+               NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
                NETIF_F_GRO | NETIF_F_TSO6;
 
-       netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO | NETIF_F_HW_CSUM;
+       netdev->vlan_features |= NETIF_F_SG | NETIF_F_TSO |
+               NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
 
        if (lancer_chip(adapter))
                netdev->vlan_features |= NETIF_F_TSO6;
@@ -2899,7 +2916,7 @@ static int __devinit be_probe(struct pci_dev *pdev,
        pci_set_drvdata(pdev, adapter);
 
        status = be_dev_family_check(adapter);
-       if (!status)
+       if (status)
                goto free_netdev;
 
        adapter->netdev = netdev;
index cfc25cf064d3ad84ec28e3bfd8d0cf15d7669e84..7e4d682f0df11e9ad33c61b016b1205b33bc30e6 100644 (file)
@@ -20,8 +20,8 @@
  * (you will need to reboot afterwards) */
 /* #define BNX2X_STOP_ON_ERROR */
 
-#define DRV_MODULE_VERSION      "1.60.00-6"
-#define DRV_MODULE_RELDATE      "2010/11/29"
+#define DRV_MODULE_VERSION      "1.60.00-7"
+#define DRV_MODULE_RELDATE      "2010/12/08"
 #define BNX2X_BC_VER            0x040200
 
 #define BNX2X_MULTI_QUEUE
@@ -1336,7 +1336,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 
 #define BNX2X_ILT_ZALLOC(x, y, size) \
        do { \
-               x = pci_alloc_consistent(bp->pdev, size, y); \
+               x = dma_alloc_coherent(&bp->pdev->dev, size, y, GFP_KERNEL); \
                if (x) \
                        memset(x, 0, size); \
        } while (0)
@@ -1344,7 +1344,7 @@ static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
 #define BNX2X_ILT_FREE(x, y, size) \
        do { \
                if (x) { \
-                       pci_free_consistent(bp->pdev, size, x, y); \
+                       dma_free_coherent(&bp->pdev->dev, size, x, y); \
                        x = NULL; \
                        y = 0; \
                } \
index a4555edbe9ce3ec03cd5e2eb68704dc5abcbd43d..236c00c3f568a599e56fd8c00ce2f377cbefdc59 100644 (file)
@@ -1795,15 +1795,15 @@ exit_lbl:
 }
 #endif
 
-static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb,
-                                    struct eth_tx_parse_bd_e2 *pbd,
-                                    u32 xmit_type)
+static inline void bnx2x_set_pbd_gso_e2(struct sk_buff *skb, u32 *parsing_data,
+                                       u32 xmit_type)
 {
-       pbd->parsing_data |= cpu_to_le16(skb_shinfo(skb)->gso_size) <<
-               ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT;
+       *parsing_data |= (skb_shinfo(skb)->gso_size <<
+                             ETH_TX_PARSE_BD_E2_LSO_MSS_SHIFT) &
+                             ETH_TX_PARSE_BD_E2_LSO_MSS;
        if ((xmit_type & XMIT_GSO_V6) &&
            (ipv6_hdr(skb)->nexthdr == NEXTHDR_IPV6))
-               pbd->parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
+               *parsing_data |= ETH_TX_PARSE_BD_E2_IPV6_WITH_EXT_HDR;
 }
 
 /**
@@ -1848,15 +1848,15 @@ static inline void bnx2x_set_pbd_gso(struct sk_buff *skb,
  * @return header len
  */
 static inline  u8 bnx2x_set_pbd_csum_e2(struct bnx2x *bp, struct sk_buff *skb,
-       struct eth_tx_parse_bd_e2 *pbd,
-       u32 xmit_type)
+       u32 *parsing_data, u32 xmit_type)
 {
-       pbd->parsing_data |= cpu_to_le16(tcp_hdrlen(skb)/4) <<
-               ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT;
+       *parsing_data |= ((tcp_hdrlen(skb)/4) <<
+               ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW_SHIFT) &
+               ETH_TX_PARSE_BD_E2_TCP_HDR_LENGTH_DW;
 
-       pbd->parsing_data |= cpu_to_le16(((unsigned char *)tcp_hdr(skb) -
-                                         skb->data) / 2) <<
-               ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT;
+       *parsing_data |= ((((u8 *)tcp_hdr(skb) - skb->data) / 2) <<
+               ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W_SHIFT) &
+               ETH_TX_PARSE_BD_E2_TCP_HDR_START_OFFSET_W;
 
        return skb_transport_header(skb) + tcp_hdrlen(skb) - skb->data;
 }
@@ -1925,6 +1925,7 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct eth_tx_bd *tx_data_bd, *total_pkt_bd = NULL;
        struct eth_tx_parse_bd_e1x *pbd_e1x = NULL;
        struct eth_tx_parse_bd_e2 *pbd_e2 = NULL;
+       u32 pbd_e2_parsing_data = 0;
        u16 pkt_prod, bd_prod;
        int nbd, fp_index;
        dma_addr_t mapping;
@@ -2046,8 +2047,9 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                memset(pbd_e2, 0, sizeof(struct eth_tx_parse_bd_e2));
                /* Set PBD in checksum offload case */
                if (xmit_type & XMIT_CSUM)
-                       hlen = bnx2x_set_pbd_csum_e2(bp,
-                                                    skb, pbd_e2, xmit_type);
+                       hlen = bnx2x_set_pbd_csum_e2(bp, skb,
+                                                    &pbd_e2_parsing_data,
+                                                    xmit_type);
        } else {
                pbd_e1x = &fp->tx_desc_ring[bd_prod].parse_bd_e1x;
                memset(pbd_e1x, 0, sizeof(struct eth_tx_parse_bd_e1x));
@@ -2089,10 +2091,18 @@ netdev_tx_t bnx2x_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        bd_prod = bnx2x_tx_split(bp, fp, tx_buf, &tx_start_bd,
                                                 hlen, bd_prod, ++nbd);
                if (CHIP_IS_E2(bp))
-                       bnx2x_set_pbd_gso_e2(skb, pbd_e2, xmit_type);
+                       bnx2x_set_pbd_gso_e2(skb, &pbd_e2_parsing_data,
+                                            xmit_type);
                else
                        bnx2x_set_pbd_gso(skb, pbd_e1x, xmit_type);
        }
+
+       /* Set the PBD's parsing_data field if not zero
+        * (for the chips newer than 57711).
+        */
+       if (pbd_e2_parsing_data)
+               pbd_e2->parsing_data = cpu_to_le32(pbd_e2_parsing_data);
+
        tx_data_bd = (struct eth_tx_bd *)tx_start_bd;
 
        /* Handle fragmented skb */
index a306b0e46b613417c630e79398c5f8250204195d..66df29fcf7516e45b7794fee314d0122fca6d42b 100644 (file)
@@ -838,7 +838,7 @@ static void bnx2x_qm_init_ptr_table(struct bnx2x *bp, int qm_cid_count,
 /****************************************************************************
 * SRC initializations
 ****************************************************************************/
-
+#ifdef BCM_CNIC
 /* called during init func stage */
 static void bnx2x_src_init_t2(struct bnx2x *bp, struct src_ent *t2,
                              dma_addr_t t2_mapping, int src_cid_count)
@@ -862,5 +862,5 @@ static void bnx2x_src_init_t2(struct bnx2x *bp, struct src_ent *t2,
                    U64_HI((u64)t2_mapping +
                           (src_cid_count-1) * sizeof(struct src_ent)));
 }
-
+#endif
 #endif /* BNX2X_INIT_OPS_H */
index 1552fc3c1351d68741f40263990700b60eea9f06..0068a1dbc064e52537cc894d588b3a161d654e92 100644 (file)
@@ -8957,7 +8957,7 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
        dev->netdev_ops = &bnx2x_netdev_ops;
        bnx2x_set_ethtool_ops(dev);
        dev->features |= NETIF_F_SG;
-       dev->features |= NETIF_F_HW_CSUM;
+       dev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
        if (bp->flags & USING_DAC_FLAG)
                dev->features |= NETIF_F_HIGHDMA;
        dev->features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
@@ -8965,7 +8965,7 @@ static int __devinit bnx2x_init_dev(struct pci_dev *pdev,
        dev->features |= (NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX);
 
        dev->vlan_features |= NETIF_F_SG;
-       dev->vlan_features |= NETIF_F_HW_CSUM;
+       dev->vlan_features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
        if (bp->flags & USING_DAC_FLAG)
                dev->vlan_features |= NETIF_F_HIGHDMA;
        dev->vlan_features |= (NETIF_F_TSO | NETIF_F_TSO_ECN);
index 0273ad0b57bb00167591414ca2937ce84e6794b1..bb33b3b347fabf10263748ca02c626751aee3eca 100644 (file)
@@ -1570,7 +1570,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev)
 
        /* If this is the first slave, then we need to set the master's hardware
         * address to be the same as the slave's. */
-       if (bond->slave_cnt == 0)
+       if (is_zero_ether_addr(bond->dev->dev_addr))
                memcpy(bond->dev->dev_addr, slave_dev->dev_addr,
                       slave_dev->addr_len);
 
index 1cd90da86f130ea588070634db35959a47ca7b87..32b1c6fb2de1a74e5b97254cdf075ca933464734 100644 (file)
@@ -5,7 +5,7 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ":" __func__ "():" fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt
 
 #include <linux/version.h>
 #include <linux/init.h>
index 19f9c065666745633752c3e59b312d2a4e9812c0..80511167f35bd4bcfb53cf424eb58ff4174a558b 100644 (file)
@@ -6,7 +6,7 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ":" __func__ "():" fmt
+#define pr_fmt(fmt) KBUILD_MODNAME ":" fmt
 
 #include <linux/spinlock.h>
 #include <linux/sched.h>
index 080574b0fff0c222510df389641c669d5fad1429..d5a9db60ade9cf783273f57a7abac5679aea0003 100644 (file)
@@ -12,6 +12,27 @@ config CAN_VCAN
          This driver can also be built as a module.  If so, the module
          will be called vcan.
 
+config CAN_SLCAN
+       tristate "Serial / USB serial CAN Adaptors (slcan)"
+       depends on CAN
+       default N
+       ---help---
+         CAN driver for several 'low cost' CAN interfaces that are attached
+         via serial lines or via USB-to-serial adapters using the LAWICEL
+         ASCII protocol. The driver implements the tty linediscipline N_SLCAN.
+
+         As only the sending and receiving of CAN frames is implemented, this
+         driver should work with the (serial/USB) CAN hardware from:
+         www.canusb.com / www.can232.com / www.mictronic.com / www.canhack.de
+
+         Userspace tools to attach the SLCAN line discipline (slcan_attach,
+         slcand) can be found in the can-utils at the SocketCAN SVN, see
+         http://developer.berlios.de/projects/socketcan for details.
+
+         The slcan driver supports up to 10 CAN netdevices by default which
+         can be changed by the 'maxdev=xx' module option. This driver can
+         also be built as a module. If so, the module will be called slcan.
+
 config CAN_DEV
        tristate "Platform CAN drivers with Netlink support"
        depends on CAN
index 90af15a4f106a7031a8eafce16b6f2b9d3cc0eaf..07ca159ba3f91ab643a167cda786d46a488c2e05 100644 (file)
@@ -3,6 +3,7 @@
 #
 
 obj-$(CONFIG_CAN_VCAN)         += vcan.o
+obj-$(CONFIG_CAN_SLCAN)                += slcan.o
 
 obj-$(CONFIG_CAN_DEV)          += can-dev.o
 can-dev-y                      := dev.o
diff --git a/drivers/net/can/slcan.c b/drivers/net/can/slcan.c
new file mode 100644 (file)
index 0000000..b423965
--- /dev/null
@@ -0,0 +1,756 @@
+/*
+ * slcan.c - serial line CAN interface driver (using tty line discipline)
+ *
+ * This file is derived from linux/drivers/net/slip.c
+ *
+ * slip.c Authors  : Laurence Culhane <loz@holmes.demon.co.uk>
+ *                   Fred N. van Kempen <waltje@uwalt.nl.mugnet.org>
+ * slcan.c Author  : Oliver Hartkopp <socketcan@hartkopp.net>
+ *
+ * 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. You can also get it
+ * at http://www.gnu.org/licenses/gpl.html
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
+ * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
+ * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
+ * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
+ * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
+ * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
+ * DAMAGE.
+ *
+ * Send feedback to <socketcan-users@lists.berlios.de>
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+
+#include <asm/system.h>
+#include <linux/uaccess.h>
+#include <linux/bitops.h>
+#include <linux/string.h>
+#include <linux/tty.h>
+#include <linux/errno.h>
+#include <linux/netdevice.h>
+#include <linux/skbuff.h>
+#include <linux/rtnetlink.h>
+#include <linux/if_arp.h>
+#include <linux/if_ether.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/can.h>
+
+static __initdata const char banner[] =
+       KERN_INFO "slcan: serial line CAN interface driver\n";
+
+MODULE_ALIAS_LDISC(N_SLCAN);
+MODULE_DESCRIPTION("serial line CAN interface");
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Oliver Hartkopp <socketcan@hartkopp.net>");
+
+#define SLCAN_MAGIC 0x53CA
+
+static int maxdev = 10;                /* MAX number of SLCAN channels;
+                                  This can be overridden with
+                                  insmod slcan.ko maxdev=nnn   */
+module_param(maxdev, int, 0);
+MODULE_PARM_DESC(maxdev, "Maximum number of slcan interfaces");
+
+/* maximum rx buffer len: extended CAN frame with timestamp */
+#define SLC_MTU (sizeof("T1111222281122334455667788EA5F\r")+1)
+
+struct slcan {
+       int                     magic;
+
+       /* Various fields. */
+       struct tty_struct       *tty;           /* ptr to TTY structure      */
+       struct net_device       *dev;           /* easy for intr handling    */
+       spinlock_t              lock;
+
+       /* These are pointers to the malloc()ed frame buffers. */
+       unsigned char           rbuff[SLC_MTU]; /* receiver buffer           */
+       int                     rcount;         /* received chars counter    */
+       unsigned char           xbuff[SLC_MTU]; /* transmitter buffer        */
+       unsigned char           *xhead;         /* pointer to next XMIT byte */
+       int                     xleft;          /* bytes left in XMIT queue  */
+
+       unsigned long           flags;          /* Flag values/ mode etc     */
+#define SLF_INUSE              0               /* Channel in use            */
+#define SLF_ERROR              1               /* Parity, etc. error        */
+
+       unsigned char           leased;
+       dev_t                   line;
+       pid_t                   pid;
+};
+
+static struct net_device **slcan_devs;
+
+ /************************************************************************
+  *                    SLCAN ENCAPSULATION FORMAT                       *
+  ************************************************************************/
+
+/*
+ * A CAN frame has a can_id (11 bit standard frame format OR 29 bit extended
+ * frame format) a data length code (can_dlc) which can be from 0 to 8
+ * and up to <can_dlc> data bytes as payload.
+ * Additionally a CAN frame may become a remote transmission frame if the
+ * RTR-bit is set. This causes another ECU to send a CAN frame with the
+ * given can_id.
+ *
+ * The SLCAN ASCII representation of these different frame types is:
+ * <type> <id> <dlc> <data>*
+ *
+ * Extended frames (29 bit) are defined by capital characters in the type.
+ * RTR frames are defined as 'r' types - normal frames have 't' type:
+ * t => 11 bit data frame
+ * r => 11 bit RTR frame
+ * T => 29 bit data frame
+ * R => 29 bit RTR frame
+ *
+ * The <id> is 3 (standard) or 8 (extended) bytes in ASCII Hex (base64).
+ * The <dlc> is a one byte ASCII number ('0' - '8')
+ * The <data> section has at much ASCII Hex bytes as defined by the <dlc>
+ *
+ * Examples:
+ *
+ * t1230 : can_id 0x123, can_dlc 0, no data
+ * t4563112233 : can_id 0x456, can_dlc 3, data 0x11 0x22 0x33
+ * T12ABCDEF2AA55 : extended can_id 0x12ABCDEF, can_dlc 2, data 0xAA 0x55
+ * r1230 : can_id 0x123, can_dlc 0, no data, remote transmission request
+ *
+ */
+
+ /************************************************************************
+  *                    STANDARD SLCAN DECAPSULATION                     *
+  ************************************************************************/
+
+static int asc2nibble(char c)
+{
+
+       if ((c >= '0') && (c <= '9'))
+               return c - '0';
+
+       if ((c >= 'A') && (c <= 'F'))
+               return c - 'A' + 10;
+
+       if ((c >= 'a') && (c <= 'f'))
+               return c - 'a' + 10;
+
+       return 16; /* error */
+}
+
+/* Send one completely decapsulated can_frame to the network layer */
+static void slc_bump(struct slcan *sl)
+{
+       struct sk_buff *skb;
+       struct can_frame cf;
+       int i, dlc_pos, tmp;
+       unsigned long ultmp;
+       char cmd = sl->rbuff[0];
+
+       if ((cmd != 't') && (cmd != 'T') && (cmd != 'r') && (cmd != 'R'))
+               return;
+
+       if (cmd & 0x20) /* tiny chars 'r' 't' => standard frame format */
+               dlc_pos = 4; /* dlc position tiiid */
+       else
+               dlc_pos = 9; /* dlc position Tiiiiiiiid */
+
+       if (!((sl->rbuff[dlc_pos] >= '0') && (sl->rbuff[dlc_pos] < '9')))
+               return;
+
+       cf.can_dlc = sl->rbuff[dlc_pos] - '0'; /* get can_dlc from ASCII val */
+
+       sl->rbuff[dlc_pos] = 0; /* terminate can_id string */
+
+       if (strict_strtoul(sl->rbuff+1, 16, &ultmp))
+               return;
+
+       cf.can_id = ultmp;
+
+       if (!(cmd & 0x20)) /* NO tiny chars => extended frame format */
+               cf.can_id |= CAN_EFF_FLAG;
+
+       if ((cmd | 0x20) == 'r') /* RTR frame */
+               cf.can_id |= CAN_RTR_FLAG;
+
+       *(u64 *) (&cf.data) = 0; /* clear payload */
+
+       for (i = 0, dlc_pos++; i < cf.can_dlc; i++) {
+
+               tmp = asc2nibble(sl->rbuff[dlc_pos++]);
+               if (tmp > 0x0F)
+                       return;
+               cf.data[i] = (tmp << 4);
+               tmp = asc2nibble(sl->rbuff[dlc_pos++]);
+               if (tmp > 0x0F)
+                       return;
+               cf.data[i] |= tmp;
+       }
+
+
+       skb = dev_alloc_skb(sizeof(struct can_frame));
+       if (!skb)
+               return;
+
+       skb->dev = sl->dev;
+       skb->protocol = htons(ETH_P_CAN);
+       skb->pkt_type = PACKET_BROADCAST;
+       skb->ip_summed = CHECKSUM_UNNECESSARY;
+       memcpy(skb_put(skb, sizeof(struct can_frame)),
+              &cf, sizeof(struct can_frame));
+       netif_rx(skb);
+
+       sl->dev->stats.rx_packets++;
+       sl->dev->stats.rx_bytes += cf.can_dlc;
+}
+
+/* parse tty input stream */
+static void slcan_unesc(struct slcan *sl, unsigned char s)
+{
+
+       if ((s == '\r') || (s == '\a')) { /* CR or BEL ends the pdu */
+               if (!test_and_clear_bit(SLF_ERROR, &sl->flags) &&
+                   (sl->rcount > 4))  {
+                       slc_bump(sl);
+               }
+               sl->rcount = 0;
+       } else {
+               if (!test_bit(SLF_ERROR, &sl->flags))  {
+                       if (sl->rcount < SLC_MTU)  {
+                               sl->rbuff[sl->rcount++] = s;
+                               return;
+                       } else {
+                               sl->dev->stats.rx_over_errors++;
+                               set_bit(SLF_ERROR, &sl->flags);
+                       }
+               }
+       }
+}
+
+ /************************************************************************
+  *                    STANDARD SLCAN ENCAPSULATION                     *
+  ************************************************************************/
+
+/* Encapsulate one can_frame and stuff into a TTY queue. */
+static void slc_encaps(struct slcan *sl, struct can_frame *cf)
+{
+       int actual, idx, i;
+       char cmd;
+
+       if (cf->can_id & CAN_RTR_FLAG)
+               cmd = 'R'; /* becomes 'r' in standard frame format */
+       else
+               cmd = 'T'; /* becomes 't' in standard frame format */
+
+       if (cf->can_id & CAN_EFF_FLAG)
+               sprintf(sl->xbuff, "%c%08X%d", cmd,
+                       cf->can_id & CAN_EFF_MASK, cf->can_dlc);
+       else
+               sprintf(sl->xbuff, "%c%03X%d", cmd | 0x20,
+                       cf->can_id & CAN_SFF_MASK, cf->can_dlc);
+
+       idx = strlen(sl->xbuff);
+
+       for (i = 0; i < cf->can_dlc; i++)
+               sprintf(&sl->xbuff[idx + 2*i], "%02X", cf->data[i]);
+
+       strcat(sl->xbuff, "\r"); /* add terminating character */
+
+       /* Order of next two lines is *very* important.
+        * When we are sending a little amount of data,
+        * the transfer may be completed inside the ops->write()
+        * routine, because it's running with interrupts enabled.
+        * In this case we *never* got WRITE_WAKEUP event,
+        * if we did not request it before write operation.
+        *       14 Oct 1994  Dmitry Gorodchanin.
+        */
+       set_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
+       actual = sl->tty->ops->write(sl->tty, sl->xbuff, strlen(sl->xbuff));
+       sl->xleft = strlen(sl->xbuff) - actual;
+       sl->xhead = sl->xbuff + actual;
+       sl->dev->stats.tx_bytes += cf->can_dlc;
+}
+
+/*
+ * Called by the driver when there's room for more data.  If we have
+ * more packets to send, we send them here.
+ */
+static void slcan_write_wakeup(struct tty_struct *tty)
+{
+       int actual;
+       struct slcan *sl = (struct slcan *) tty->disc_data;
+
+       /* First make sure we're connected. */
+       if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev))
+               return;
+
+       if (sl->xleft <= 0)  {
+               /* Now serial buffer is almost free & we can start
+                * transmission of another packet */
+               sl->dev->stats.tx_packets++;
+               clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
+               netif_wake_queue(sl->dev);
+               return;
+       }
+
+       actual = tty->ops->write(tty, sl->xhead, sl->xleft);
+       sl->xleft -= actual;
+       sl->xhead += actual;
+}
+
+/* Send a can_frame to a TTY queue. */
+static netdev_tx_t slc_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct slcan *sl = netdev_priv(dev);
+
+       if (skb->len != sizeof(struct can_frame))
+               goto out;
+
+       spin_lock(&sl->lock);
+       if (!netif_running(dev))  {
+               spin_unlock(&sl->lock);
+               printk(KERN_WARNING "%s: xmit: iface is down\n", dev->name);
+               goto out;
+       }
+       if (sl->tty == NULL) {
+               spin_unlock(&sl->lock);
+               goto out;
+       }
+
+       netif_stop_queue(sl->dev);
+       slc_encaps(sl, (struct can_frame *) skb->data); /* encaps & send */
+       spin_unlock(&sl->lock);
+
+out:
+       kfree_skb(skb);
+       return NETDEV_TX_OK;
+}
+
+
+/******************************************
+ *   Routines looking at netdevice side.
+ ******************************************/
+
+/* Netdevice UP -> DOWN routine */
+static int slc_close(struct net_device *dev)
+{
+       struct slcan *sl = netdev_priv(dev);
+
+       spin_lock_bh(&sl->lock);
+       if (sl->tty) {
+               /* TTY discipline is running. */
+               clear_bit(TTY_DO_WRITE_WAKEUP, &sl->tty->flags);
+       }
+       netif_stop_queue(dev);
+       sl->rcount   = 0;
+       sl->xleft    = 0;
+       spin_unlock_bh(&sl->lock);
+
+       return 0;
+}
+
+/* Netdevice DOWN -> UP routine */
+static int slc_open(struct net_device *dev)
+{
+       struct slcan *sl = netdev_priv(dev);
+
+       if (sl->tty == NULL)
+               return -ENODEV;
+
+       sl->flags &= (1 << SLF_INUSE);
+       netif_start_queue(dev);
+       return 0;
+}
+
+/* Hook the destructor so we can free slcan devs at the right point in time */
+static void slc_free_netdev(struct net_device *dev)
+{
+       int i = dev->base_addr;
+       free_netdev(dev);
+       slcan_devs[i] = NULL;
+}
+
+static const struct net_device_ops slc_netdev_ops = {
+       .ndo_open               = slc_open,
+       .ndo_stop               = slc_close,
+       .ndo_start_xmit         = slc_xmit,
+};
+
+static void slc_setup(struct net_device *dev)
+{
+       dev->netdev_ops         = &slc_netdev_ops;
+       dev->destructor         = slc_free_netdev;
+
+       dev->hard_header_len    = 0;
+       dev->addr_len           = 0;
+       dev->tx_queue_len       = 10;
+
+       dev->mtu                = sizeof(struct can_frame);
+       dev->type               = ARPHRD_CAN;
+
+       /* New-style flags. */
+       dev->flags              = IFF_NOARP;
+       dev->features           = NETIF_F_NO_CSUM;
+}
+
+/******************************************
+  Routines looking at TTY side.
+ ******************************************/
+
+/*
+ * Handle the 'receiver data ready' interrupt.
+ * This function is called by the 'tty_io' module in the kernel when
+ * a block of SLCAN data has been received, which can now be decapsulated
+ * and sent on to some IP layer for further processing. This will not
+ * be re-entered while running but other ldisc functions may be called
+ * in parallel
+ */
+
+static void slcan_receive_buf(struct tty_struct *tty,
+                             const unsigned char *cp, char *fp, int count)
+{
+       struct slcan *sl = (struct slcan *) tty->disc_data;
+
+       if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev))
+               return;
+
+       /* Read the characters out of the buffer */
+       while (count--) {
+               if (fp && *fp++) {
+                       if (!test_and_set_bit(SLF_ERROR, &sl->flags))
+                               sl->dev->stats.rx_errors++;
+                       cp++;
+                       continue;
+               }
+               slcan_unesc(sl, *cp++);
+       }
+}
+
+/************************************
+ *  slcan_open helper routines.
+ ************************************/
+
+/* Collect hanged up channels */
+static void slc_sync(void)
+{
+       int i;
+       struct net_device *dev;
+       struct slcan      *sl;
+
+       for (i = 0; i < maxdev; i++) {
+               dev = slcan_devs[i];
+               if (dev == NULL)
+                       break;
+
+               sl = netdev_priv(dev);
+               if (sl->tty || sl->leased)
+                       continue;
+               if (dev->flags & IFF_UP)
+                       dev_close(dev);
+       }
+}
+
+/* Find a free SLCAN channel, and link in this `tty' line. */
+static struct slcan *slc_alloc(dev_t line)
+{
+       int i;
+       struct net_device *dev = NULL;
+       struct slcan       *sl;
+
+       if (slcan_devs == NULL)
+               return NULL;    /* Master array missing ! */
+
+       for (i = 0; i < maxdev; i++) {
+               dev = slcan_devs[i];
+               if (dev == NULL)
+                       break;
+
+       }
+
+       /* Sorry, too many, all slots in use */
+       if (i >= maxdev)
+               return NULL;
+
+       if (dev) {
+               sl = netdev_priv(dev);
+               if (test_bit(SLF_INUSE, &sl->flags)) {
+                       unregister_netdevice(dev);
+                       dev = NULL;
+                       slcan_devs[i] = NULL;
+               }
+       }
+
+       if (!dev) {
+               char name[IFNAMSIZ];
+               sprintf(name, "slcan%d", i);
+
+               dev = alloc_netdev(sizeof(*sl), name, slc_setup);
+               if (!dev)
+                       return NULL;
+               dev->base_addr  = i;
+       }
+
+       sl = netdev_priv(dev);
+
+       /* Initialize channel control data */
+       sl->magic = SLCAN_MAGIC;
+       sl->dev = dev;
+       spin_lock_init(&sl->lock);
+       slcan_devs[i] = dev;
+
+       return sl;
+}
+
+/*
+ * Open the high-level part of the SLCAN channel.
+ * This function is called by the TTY module when the
+ * SLCAN line discipline is called for.  Because we are
+ * sure the tty line exists, we only have to link it to
+ * a free SLCAN channel...
+ *
+ * Called in process context serialized from other ldisc calls.
+ */
+
+static int slcan_open(struct tty_struct *tty)
+{
+       struct slcan *sl;
+       int err;
+
+       if (!capable(CAP_NET_ADMIN))
+               return -EPERM;
+
+       if (tty->ops->write == NULL)
+               return -EOPNOTSUPP;
+
+       /* RTnetlink lock is misused here to serialize concurrent
+          opens of slcan channels. There are better ways, but it is
+          the simplest one.
+        */
+       rtnl_lock();
+
+       /* Collect hanged up channels. */
+       slc_sync();
+
+       sl = tty->disc_data;
+
+       err = -EEXIST;
+       /* First make sure we're not already connected. */
+       if (sl && sl->magic == SLCAN_MAGIC)
+               goto err_exit;
+
+       /* OK.  Find a free SLCAN channel to use. */
+       err = -ENFILE;
+       sl = slc_alloc(tty_devnum(tty));
+       if (sl == NULL)
+               goto err_exit;
+
+       sl->tty = tty;
+       tty->disc_data = sl;
+       sl->line = tty_devnum(tty);
+       sl->pid = current->pid;
+
+       if (!test_bit(SLF_INUSE, &sl->flags)) {
+               /* Perform the low-level SLCAN initialization. */
+               sl->rcount   = 0;
+               sl->xleft    = 0;
+
+               set_bit(SLF_INUSE, &sl->flags);
+
+               err = register_netdevice(sl->dev);
+               if (err)
+                       goto err_free_chan;
+       }
+
+       /* Done.  We have linked the TTY line to a channel. */
+       rtnl_unlock();
+       tty->receive_room = 65536;      /* We don't flow control */
+       return sl->dev->base_addr;
+
+err_free_chan:
+       sl->tty = NULL;
+       tty->disc_data = NULL;
+       clear_bit(SLF_INUSE, &sl->flags);
+
+err_exit:
+       rtnl_unlock();
+
+       /* Count references from TTY module */
+       return err;
+}
+
+/*
+ * Close down a SLCAN channel.
+ * This means flushing out any pending queues, and then returning. This
+ * call is serialized against other ldisc functions.
+ *
+ * We also use this method for a hangup event.
+ */
+
+static void slcan_close(struct tty_struct *tty)
+{
+       struct slcan *sl = (struct slcan *) tty->disc_data;
+
+       /* First make sure we're connected. */
+       if (!sl || sl->magic != SLCAN_MAGIC || sl->tty != tty)
+               return;
+
+       tty->disc_data = NULL;
+       sl->tty = NULL;
+       if (!sl->leased)
+               sl->line = 0;
+
+       /* Flush network side */
+       unregister_netdev(sl->dev);
+       /* This will complete via sl_free_netdev */
+}
+
+static int slcan_hangup(struct tty_struct *tty)
+{
+       slcan_close(tty);
+       return 0;
+}
+
+/* Perform I/O control on an active SLCAN channel. */
+static int slcan_ioctl(struct tty_struct *tty, struct file *file,
+                      unsigned int cmd, unsigned long arg)
+{
+       struct slcan *sl = (struct slcan *) tty->disc_data;
+       unsigned int tmp;
+
+       /* First make sure we're connected. */
+       if (!sl || sl->magic != SLCAN_MAGIC)
+               return -EINVAL;
+
+       switch (cmd) {
+       case SIOCGIFNAME:
+               tmp = strlen(sl->dev->name) + 1;
+               if (copy_to_user((void __user *)arg, sl->dev->name, tmp))
+                       return -EFAULT;
+               return 0;
+
+       case SIOCSIFHWADDR:
+               return -EINVAL;
+
+       default:
+               return tty_mode_ioctl(tty, file, cmd, arg);
+       }
+}
+
+static struct tty_ldisc_ops slc_ldisc = {
+       .owner          = THIS_MODULE,
+       .magic          = TTY_LDISC_MAGIC,
+       .name           = "slcan",
+       .open           = slcan_open,
+       .close          = slcan_close,
+       .hangup         = slcan_hangup,
+       .ioctl          = slcan_ioctl,
+       .receive_buf    = slcan_receive_buf,
+       .write_wakeup   = slcan_write_wakeup,
+};
+
+static int __init slcan_init(void)
+{
+       int status;
+
+       if (maxdev < 4)
+               maxdev = 4; /* Sanity */
+
+       printk(banner);
+       printk(KERN_INFO "slcan: %d dynamic interface channels.\n", maxdev);
+
+       slcan_devs = kzalloc(sizeof(struct net_device *)*maxdev, GFP_KERNEL);
+       if (!slcan_devs) {
+               printk(KERN_ERR "slcan: can't allocate slcan device array!\n");
+               return -ENOMEM;
+       }
+
+       /* Fill in our line protocol discipline, and register it */
+       status = tty_register_ldisc(N_SLCAN, &slc_ldisc);
+       if (status)  {
+               printk(KERN_ERR "slcan: can't register line discipline\n");
+               kfree(slcan_devs);
+       }
+       return status;
+}
+
+static void __exit slcan_exit(void)
+{
+       int i;
+       struct net_device *dev;
+       struct slcan *sl;
+       unsigned long timeout = jiffies + HZ;
+       int busy = 0;
+
+       if (slcan_devs == NULL)
+               return;
+
+       /* First of all: check for active disciplines and hangup them.
+        */
+       do {
+               if (busy)
+                       msleep_interruptible(100);
+
+               busy = 0;
+               for (i = 0; i < maxdev; i++) {
+                       dev = slcan_devs[i];
+                       if (!dev)
+                               continue;
+                       sl = netdev_priv(dev);
+                       spin_lock_bh(&sl->lock);
+                       if (sl->tty) {
+                               busy++;
+                               tty_hangup(sl->tty);
+                       }
+                       spin_unlock_bh(&sl->lock);
+               }
+       } while (busy && time_before(jiffies, timeout));
+
+       /* FIXME: hangup is async so we should wait when doing this second
+          phase */
+
+       for (i = 0; i < maxdev; i++) {
+               dev = slcan_devs[i];
+               if (!dev)
+                       continue;
+               slcan_devs[i] = NULL;
+
+               sl = netdev_priv(dev);
+               if (sl->tty) {
+                       printk(KERN_ERR "%s: tty discipline still running\n",
+                              dev->name);
+                       /* Intentionally leak the control block. */
+                       dev->destructor = NULL;
+               }
+
+               unregister_netdev(dev);
+       }
+
+       kfree(slcan_devs);
+       slcan_devs = NULL;
+
+       i = tty_unregister_ldisc(N_SLCAN);
+       if (i)
+               printk(KERN_ERR "slcan: can't unregister ldisc (err %d)\n", i);
+}
+
+module_init(slcan_init);
+module_exit(slcan_exit);
index 81475cc80e1cfd77f364afecde37bf21d9261052..80c2feeefec5542266a4444c341a864c8a905cf9 100644 (file)
@@ -59,7 +59,6 @@ static struct sockaddr default_mac = {
 
 /* Information that need to be kept for each board. */
 struct net_local {
-       struct net_device_stats stats;
        struct mii_if_info mii_if;
 
        /* Tx control lock.  This protects the transmit buffer ring
@@ -1059,7 +1058,7 @@ e100_tx_timeout(struct net_device *dev)
 
        /* remember we got an error */
 
-       np->stats.tx_errors++;
+       dev->stats.tx_errors++;
 
        /* reset the TX DMA in case it has hung on something */
 
@@ -1157,7 +1156,7 @@ e100rxtx_interrupt(int irq, void *dev_id)
                         * allocate a new buffer to put a packet in.
                         */
                        e100_rx(dev);
-                       np->stats.rx_packets++;
+                       dev->stats.rx_packets++;
                        /* restart/continue on the channel, for safety */
                        *R_DMA_CH1_CMD = IO_STATE(R_DMA_CH1_CMD, cmd, restart);
                        /* clear dma channel 1 eop/descr irq bits */
@@ -1173,8 +1172,8 @@ e100rxtx_interrupt(int irq, void *dev_id)
        /* Report any packets that have been sent */
        while (virt_to_phys(myFirstTxDesc) != *R_DMA_CH0_FIRST &&
               (netif_queue_stopped(dev) || myFirstTxDesc != myNextTxDesc)) {
-               np->stats.tx_bytes += myFirstTxDesc->skb->len;
-               np->stats.tx_packets++;
+               dev->stats.tx_bytes += myFirstTxDesc->skb->len;
+               dev->stats.tx_packets++;
 
                /* dma is ready with the transmission of the data in tx_skb, so now
                   we can release the skb memory */
@@ -1197,7 +1196,6 @@ static irqreturn_t
 e100nw_interrupt(int irq, void *dev_id)
 {
        struct net_device *dev = (struct net_device *)dev_id;
-       struct net_local *np = netdev_priv(dev);
        unsigned long irqbits = *R_IRQ_MASK0_RD;
 
        /* check for underrun irq */
@@ -1205,13 +1203,13 @@ e100nw_interrupt(int irq, void *dev_id)
                SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);
                *R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
                SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop);
-               np->stats.tx_errors++;
+               dev->stats.tx_errors++;
                D(printk("ethernet receiver underrun!\n"));
        }
 
        /* check for overrun irq */
        if (irqbits & IO_STATE(R_IRQ_MASK0_RD, overrun, active)) {
-               update_rx_stats(&np->stats); /* this will ack the irq */
+               update_rx_stats(&dev->stats); /* this will ack the irq */
                D(printk("ethernet receiver overrun!\n"));
        }
        /* check for excessive collision irq */
@@ -1219,7 +1217,7 @@ e100nw_interrupt(int irq, void *dev_id)
                SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, clr);
                *R_NETWORK_TR_CTRL = network_tr_ctrl_shadow;
                SETS(network_tr_ctrl_shadow, R_NETWORK_TR_CTRL, clr_error, nop);
-               np->stats.tx_errors++;
+               dev->stats.tx_errors++;
                D(printk("ethernet excessive collisions!\n"));
        }
        return IRQ_HANDLED;
@@ -1250,7 +1248,7 @@ e100_rx(struct net_device *dev)
        spin_unlock(&np->led_lock);
 
        length = myNextRxDesc->descr.hw_len - 4;
-       np->stats.rx_bytes += length;
+       dev->stats.rx_bytes += length;
 
 #ifdef ETHDEBUG
        printk("Got a packet of length %d:\n", length);
@@ -1268,7 +1266,7 @@ e100_rx(struct net_device *dev)
                /* Small packet, copy data */
                skb = dev_alloc_skb(length - ETHER_HEAD_LEN);
                if (!skb) {
-                       np->stats.rx_errors++;
+                       dev->stats.rx_errors++;
                        printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
                        goto update_nextrxdesc;
                }
@@ -1294,7 +1292,7 @@ e100_rx(struct net_device *dev)
                int align;
                struct sk_buff *new_skb = dev_alloc_skb(MAX_MEDIA_DATA_SIZE + 2 * L1_CACHE_BYTES);
                if (!new_skb) {
-                       np->stats.rx_errors++;
+                       dev->stats.rx_errors++;
                        printk(KERN_NOTICE "%s: Memory squeeze, dropping packet.\n", dev->name);
                        goto update_nextrxdesc;
                }
@@ -1333,8 +1331,6 @@ e100_rx(struct net_device *dev)
 static int
 e100_close(struct net_device *dev)
 {
-       struct net_local *np = netdev_priv(dev);
-
        printk(KERN_INFO "Closing %s.\n", dev->name);
 
        netif_stop_queue(dev);
@@ -1366,8 +1362,8 @@ e100_close(struct net_device *dev)
 
        /* Update the statistics here. */
 
-       update_rx_stats(&np->stats);
-       update_tx_stats(&np->stats);
+       update_rx_stats(&dev->stats);
+       update_tx_stats(&dev->stats);
 
        /* Stop speed/duplex timers */
        del_timer(&speed_timer);
@@ -1545,11 +1541,11 @@ e100_get_stats(struct net_device *dev)
 
        spin_lock_irqsave(&lp->lock, flags);
 
-       update_rx_stats(&lp->stats);
-       update_tx_stats(&lp->stats);
+       update_rx_stats(&dev->stats);
+       update_tx_stats(&dev->stats);
 
        spin_unlock_irqrestore(&lp->lock, flags);
-       return &lp->stats;
+       return &dev->stats;
 }
 
 /*
index bb813d94aea8ef5ae11db63ce6ac795fd0a62c39..e97521c801ea6e4a90714bd2038d4c0610b8806a 100644 (file)
@@ -2408,7 +2408,7 @@ int t4_alloc_mac_filt(struct adapter *adap, unsigned int mbox,
                if (index < NEXACT_MAC)
                        ret++;
                else if (hash)
-                       *hash |= (1 << hash_mac_addr(addr[i]));
+                       *hash |= (1ULL << hash_mac_addr(addr[i]));
        }
        return ret;
 }
index 9246d2fa6cf9bfa835c34ded95b6c8febddebe77..f54af48edb939641eb1b4654328fdc46bb7b4769 100644 (file)
@@ -814,40 +814,48 @@ static struct net_device_stats *cxgb4vf_get_stats(struct net_device *dev)
 }
 
 /*
- * Collect up to maxaddrs worth of a netdevice's unicast addresses into an
- * array of addrss pointers and return the number collected.
+ * Collect up to maxaddrs worth of a netdevice's unicast addresses, starting
+ * at a specified offset within the list, into an array of addrss pointers and
+ * return the number collected.
  */
-static inline int collect_netdev_uc_list_addrs(const struct net_device *dev,
-                                              const u8 **addr,
-                                              unsigned int maxaddrs)
+static inline unsigned int collect_netdev_uc_list_addrs(const struct net_device *dev,
+                                                       const u8 **addr,
+                                                       unsigned int offset,
+                                                       unsigned int maxaddrs)
 {
+       unsigned int index = 0;
        unsigned int naddr = 0;
        const struct netdev_hw_addr *ha;
 
-       for_each_dev_addr(dev, ha) {
-               addr[naddr++] = ha->addr;
-               if (naddr >= maxaddrs)
-                       break;
-       }
+       for_each_dev_addr(dev, ha)
+               if (index++ >= offset) {
+                       addr[naddr++] = ha->addr;
+                       if (naddr >= maxaddrs)
+                               break;
+               }
        return naddr;
 }
 
 /*
- * Collect up to maxaddrs worth of a netdevice's multicast addresses into an
- * array of addrss pointers and return the number collected.
+ * Collect up to maxaddrs worth of a netdevice's multicast addresses, starting
+ * at a specified offset within the list, into an array of addrss pointers and
+ * return the number collected.
  */
-static inline int collect_netdev_mc_list_addrs(const struct net_device *dev,
-                                              const u8 **addr,
-                                              unsigned int maxaddrs)
+static inline unsigned int collect_netdev_mc_list_addrs(const struct net_device *dev,
+                                                       const u8 **addr,
+                                                       unsigned int offset,
+                                                       unsigned int maxaddrs)
 {
+       unsigned int index = 0;
        unsigned int naddr = 0;
        const struct netdev_hw_addr *ha;
 
-       netdev_for_each_mc_addr(ha, dev) {
-               addr[naddr++] = ha->addr;
-               if (naddr >= maxaddrs)
-                       break;
-       }
+       netdev_for_each_mc_addr(ha, dev)
+               if (index++ >= offset) {
+                       addr[naddr++] = ha->addr;
+                       if (naddr >= maxaddrs)
+                               break;
+               }
        return naddr;
 }
 
@@ -860,16 +868,20 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
        u64 mhash = 0;
        u64 uhash = 0;
        bool free = true;
-       u16 filt_idx[7];
+       unsigned int offset, naddr;
        const u8 *addr[7];
-       int ret, naddr = 0;
+       int ret;
        const struct port_info *pi = netdev_priv(dev);
 
        /* first do the secondary unicast addresses */
-       naddr = collect_netdev_uc_list_addrs(dev, addr, ARRAY_SIZE(addr));
-       if (naddr > 0) {
+       for (offset = 0; ; offset += naddr) {
+               naddr = collect_netdev_uc_list_addrs(dev, addr, offset,
+                                                    ARRAY_SIZE(addr));
+               if (naddr == 0)
+                       break;
+
                ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free,
-                                         naddr, addr, filt_idx, &uhash, sleep);
+                                         naddr, addr, NULL, &uhash, sleep);
                if (ret < 0)
                        return ret;
 
@@ -877,12 +889,17 @@ static int set_addr_filters(const struct net_device *dev, bool sleep)
        }
 
        /* next set up the multicast addresses */
-       naddr = collect_netdev_mc_list_addrs(dev, addr, ARRAY_SIZE(addr));
-       if (naddr > 0) {
+       for (offset = 0; ; offset += naddr) {
+               naddr = collect_netdev_mc_list_addrs(dev, addr, offset,
+                                                    ARRAY_SIZE(addr));
+               if (naddr == 0)
+                       break;
+
                ret = t4vf_alloc_mac_filt(pi->adapter, pi->viid, free,
-                                         naddr, addr, filt_idx, &mhash, sleep);
+                                         naddr, addr, NULL, &mhash, sleep);
                if (ret < 0)
                        return ret;
+               free = false;
        }
 
        return t4vf_set_addr_hash(pi->adapter, pi->viid, uhash != 0,
index f7d7f976064b6cf6c888a524e34726147fb03728..35fc803a6a04074518add1b74a49a22df3442f8f 100644 (file)
@@ -1014,48 +1014,72 @@ int t4vf_alloc_mac_filt(struct adapter *adapter, unsigned int viid, bool free,
                        unsigned int naddr, const u8 **addr, u16 *idx,
                        u64 *hash, bool sleep_ok)
 {
-       int i, ret;
+       int offset, ret = 0;
+       unsigned nfilters = 0;
+       unsigned int rem = naddr;
        struct fw_vi_mac_cmd cmd, rpl;
-       struct fw_vi_mac_exact *p;
-       size_t len16;
 
-       if (naddr > ARRAY_SIZE(cmd.u.exact))
+       if (naddr > FW_CLS_TCAM_NUM_ENTRIES)
                return -EINVAL;
-       len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
-                                     u.exact[naddr]), 16);
 
-       memset(&cmd, 0, sizeof(cmd));
-       cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
-                                    FW_CMD_REQUEST |
-                                    FW_CMD_WRITE |
-                                    (free ? FW_CMD_EXEC : 0) |
-                                    FW_VI_MAC_CMD_VIID(viid));
-       cmd.freemacs_to_len16 = cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) |
-                                           FW_CMD_LEN16(len16));
+       for (offset = 0; offset < naddr; /**/) {
+               unsigned int fw_naddr = (rem < ARRAY_SIZE(cmd.u.exact)
+                                        ? rem
+                                        : ARRAY_SIZE(cmd.u.exact));
+               size_t len16 = DIV_ROUND_UP(offsetof(struct fw_vi_mac_cmd,
+                                                    u.exact[fw_naddr]), 16);
+               struct fw_vi_mac_exact *p;
+               int i;
 
-       for (i = 0, p = cmd.u.exact; i < naddr; i++, p++) {
-               p->valid_to_idx =
-                       cpu_to_be16(FW_VI_MAC_CMD_VALID |
-                                   FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC));
-               memcpy(p->macaddr, addr[i], sizeof(p->macaddr));
-       }
+               memset(&cmd, 0, sizeof(cmd));
+               cmd.op_to_viid = cpu_to_be32(FW_CMD_OP(FW_VI_MAC_CMD) |
+                                            FW_CMD_REQUEST |
+                                            FW_CMD_WRITE |
+                                            (free ? FW_CMD_EXEC : 0) |
+                                            FW_VI_MAC_CMD_VIID(viid));
+               cmd.freemacs_to_len16 =
+                       cpu_to_be32(FW_VI_MAC_CMD_FREEMACS(free) |
+                                   FW_CMD_LEN16(len16));
+
+               for (i = 0, p = cmd.u.exact; i < fw_naddr; i++, p++) {
+                       p->valid_to_idx = cpu_to_be16(
+                               FW_VI_MAC_CMD_VALID |
+                               FW_VI_MAC_CMD_IDX(FW_VI_MAC_ADD_MAC));
+                       memcpy(p->macaddr, addr[offset+i], sizeof(p->macaddr));
+               }
+
+
+               ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl,
+                                       sleep_ok);
+               if (ret && ret != -ENOMEM)
+                       break;
 
-       ret = t4vf_wr_mbox_core(adapter, &cmd, sizeof(cmd), &rpl, sleep_ok);
-       if (ret)
-               return ret;
-
-       for (i = 0, p = rpl.u.exact; i < naddr; i++, p++) {
-               u16 index = FW_VI_MAC_CMD_IDX_GET(be16_to_cpu(p->valid_to_idx));
-
-               if (idx)
-                       idx[i] = (index >= FW_CLS_TCAM_NUM_ENTRIES
-                                 ? 0xffff
-                                 : index);
-               if (index < FW_CLS_TCAM_NUM_ENTRIES)
-                       ret++;
-               else if (hash)
-                       *hash |= (1 << hash_mac_addr(addr[i]));
+               for (i = 0, p = rpl.u.exact; i < fw_naddr; i++, p++) {
+                       u16 index = FW_VI_MAC_CMD_IDX_GET(
+                               be16_to_cpu(p->valid_to_idx));
+
+                       if (idx)
+                               idx[offset+i] =
+                                       (index >= FW_CLS_TCAM_NUM_ENTRIES
+                                        ? 0xffff
+                                        : index);
+                       if (index < FW_CLS_TCAM_NUM_ENTRIES)
+                               nfilters++;
+                       else if (hash)
+                               *hash |= (1ULL << hash_mac_addr(addr[offset+i]));
+               }
+
+               free = false;
+               offset += fw_naddr;
+               rem -= fw_naddr;
        }
+
+       /*
+        * If there were no errors or we merely ran out of room in our MAC
+        * address arena, return the number of filters actually written.
+        */
+       if (ret == 0 || ret == -ENOMEM)
+               ret = nfilters;
        return ret;
 }
 
index dcb7f82c27017af001c0a567de84d732efbb717b..06c7d1c675175f561e0a596f7f72ceabced2b40a 100644 (file)
@@ -31,7 +31,7 @@
 
 char e1000_driver_name[] = "e1000";
 static char e1000_driver_string[] = "Intel(R) PRO/1000 Network Driver";
-#define DRV_VERSION "7.3.21-k6-NAPI"
+#define DRV_VERSION "7.3.21-k8-NAPI"
 const char e1000_driver_version[] = DRV_VERSION;
 static const char e1000_copyright[] = "Copyright (c) 1999-2006 Intel Corporation.";
 
@@ -485,9 +485,6 @@ void e1000_down(struct e1000_adapter *adapter)
        struct net_device *netdev = adapter->netdev;
        u32 rctl, tctl;
 
-       /* signal that we're down so the interrupt handler does not
-        * reschedule our watchdog timer */
-       set_bit(__E1000_DOWN, &adapter->flags);
 
        /* disable receives in the hardware */
        rctl = er32(RCTL);
@@ -508,6 +505,13 @@ void e1000_down(struct e1000_adapter *adapter)
 
        e1000_irq_disable(adapter);
 
+       /*
+        * Setting DOWN must be after irq_disable to prevent
+        * a screaming interrupt.  Setting DOWN also prevents
+        * timers and tasks from rescheduling.
+        */
+       set_bit(__E1000_DOWN, &adapter->flags);
+
        del_timer_sync(&adapter->tx_fifo_stall_timer);
        del_timer_sync(&adapter->watchdog_timer);
        del_timer_sync(&adapter->phy_info_timer);
index 75b099ce49c9b47e361adc66da99d148b58640f3..1f37ee6b2a2626282fd5a772cc21f821321b9379 100644 (file)
@@ -261,6 +261,13 @@ static void ehea_get_ethtool_stats(struct net_device *dev,
 
 }
 
+static int ehea_set_flags(struct net_device *dev, u32 data)
+{
+       return ethtool_op_set_flags(dev, data, ETH_FLAG_LRO
+                                       | ETH_FLAG_TXVLAN
+                                       | ETH_FLAG_RXVLAN);
+}
+
 const struct ethtool_ops ehea_ethtool_ops = {
        .get_settings = ehea_get_settings,
        .get_drvinfo = ehea_get_drvinfo,
@@ -273,6 +280,8 @@ const struct ethtool_ops ehea_ethtool_ops = {
        .get_ethtool_stats = ehea_get_ethtool_stats,
        .get_rx_csum = ehea_get_rx_csum,
        .set_settings = ehea_set_settings,
+       .get_flags = ethtool_op_get_flags,
+       .set_flags = ehea_set_flags,
        .nway_reset = ehea_nway_reset,          /* Restart autonegotiation */
 };
 
index a84c389d3db71a78d47d2a3b0c54a0f15736c53c..69f61523fcc8483eed3d1d5b27de515316b824ef 100644 (file)
@@ -400,6 +400,7 @@ static void ehea_refill_rq1(struct ehea_port_res *pr, int index, int nr_of_wqes)
                        skb_arr_rq1[index] = netdev_alloc_skb(dev,
                                                              EHEA_L_PKT_SIZE);
                        if (!skb_arr_rq1[index]) {
+                               ehea_info("Unable to allocate enough skb in the array\n");
                                pr->rq1_skba.os_skbs = fill_wqes - i;
                                break;
                        }
@@ -422,13 +423,20 @@ static void ehea_init_fill_rq1(struct ehea_port_res *pr, int nr_rq1a)
        struct net_device *dev = pr->port->netdev;
        int i;
 
-       for (i = 0; i < pr->rq1_skba.len; i++) {
+       if (nr_rq1a > pr->rq1_skba.len) {
+               ehea_error("NR_RQ1A bigger than skb array len\n");
+               return;
+       }
+
+       for (i = 0; i < nr_rq1a; i++) {
                skb_arr_rq1[i] = netdev_alloc_skb(dev, EHEA_L_PKT_SIZE);
-               if (!skb_arr_rq1[i])
+               if (!skb_arr_rq1[i]) {
+                       ehea_info("No enough memory to allocate skb array\n");
                        break;
+               }
        }
        /* Ring doorbell */
-       ehea_update_rq1a(pr->qp, nr_rq1a);
+       ehea_update_rq1a(pr->qp, i);
 }
 
 static int ehea_refill_rq_def(struct ehea_port_res *pr,
@@ -675,7 +683,7 @@ static void ehea_proc_skb(struct ehea_port_res *pr, struct ehea_cqe *cqe,
        int vlan_extracted = ((cqe->status & EHEA_CQE_VLAN_TAG_XTRACT) &&
                              pr->port->vgrp);
 
-       if (use_lro) {
+       if (skb->dev->features & NETIF_F_LRO) {
                if (vlan_extracted)
                        lro_vlan_hwaccel_receive_skb(&pr->lro_mgr, skb,
                                                     pr->port->vgrp,
@@ -735,8 +743,10 @@ static int ehea_proc_rwqes(struct net_device *dev,
 
                                        skb = netdev_alloc_skb(dev,
                                                               EHEA_L_PKT_SIZE);
-                                       if (!skb)
+                                       if (!skb) {
+                                               ehea_info("Not enough memory to allocate skb\n");
                                                break;
+                                       }
                                }
                                skb_copy_to_linear_data(skb, ((char *)cqe) + 64,
                                                 cqe->num_bytes_transfered - 4);
@@ -777,7 +787,7 @@ static int ehea_proc_rwqes(struct net_device *dev,
                }
                cqe = ehea_poll_rq1(qp, &wqe_index);
        }
-       if (use_lro)
+       if (dev->features & NETIF_F_LRO)
                lro_flush_all(&pr->lro_mgr);
 
        pr->rx_packets += processed;
@@ -3266,6 +3276,9 @@ struct ehea_port *ehea_setup_single_port(struct ehea_adapter *adapter,
                      | NETIF_F_LLTX;
        dev->watchdog_timeo = EHEA_WATCH_DOG_TIMEOUT;
 
+       if (use_lro)
+               dev->features |= NETIF_F_LRO;
+
        INIT_WORK(&port->reset_task, ehea_reset_port);
 
        ret = register_netdev(dev);
index ab9f675c5b8b8b86473d07b60b3ad933523b3ab5..fe337bd121aa74d3eb60cf866e31b8f76fa84573 100644 (file)
@@ -104,6 +104,8 @@ static void ri_tasklet(unsigned long dev)
                        rcu_read_unlock();
                        dev_kfree_skb(skb);
                        stats->tx_dropped++;
+                       if (skb_queue_len(&dp->tq) != 0)
+                               goto resched;
                        break;
                }
                rcu_read_unlock();
index 00b38bccd6d0fd51f19cfe383f71a1f5952d6a43..52a7c86af66347c388d24d29b043fe52e6a2ca5f 100644 (file)
@@ -258,7 +258,7 @@ static int sh_sir_set_baudrate(struct sh_sir_self *self, u32 baudrate)
 
        /* Baud Rate Error Correction x 10000 */
        u32 rate_err_array[] = {
-               0000, 0625, 1250, 1875,
+                  0,  625, 1250, 1875,
                2500, 3125, 3750, 4375,
                5000, 5625, 6250, 6875,
                7500, 8125, 8750, 9375,
index 385ccebb826cbe65e5216a5ecc83674844140369..6827dddc383e0f99334f9e76b131695ba6a58773 100644 (file)
@@ -96,6 +96,8 @@ static void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)
 static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
 {
        s32 ret_val = 0;
+       u32 reg_anlp1 = 0;
+       u32 i = 0;
        u16 list_offset, data_offset, data_value;
 
        if (hw->phy.sfp_type != ixgbe_sfp_type_unknown) {
@@ -122,14 +124,34 @@ static s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
                        IXGBE_WRITE_FLUSH(hw);
                        hw->eeprom.ops.read(hw, ++data_offset, &data_value);
                }
-               /* Now restart DSP by setting Restart_AN */
-               IXGBE_WRITE_REG(hw, IXGBE_AUTOC,
-                   (IXGBE_READ_REG(hw, IXGBE_AUTOC) | IXGBE_AUTOC_AN_RESTART));
 
                /* Release the semaphore */
                ixgbe_release_swfw_sync(hw, IXGBE_GSSR_MAC_CSR_SM);
                /* Delay obtaining semaphore again to allow FW access */
                msleep(hw->eeprom.semaphore_delay);
+
+               /* Now restart DSP by setting Restart_AN and clearing LMS */
+               IXGBE_WRITE_REG(hw, IXGBE_AUTOC, ((IXGBE_READ_REG(hw,
+                               IXGBE_AUTOC) & ~IXGBE_AUTOC_LMS_MASK) |
+                               IXGBE_AUTOC_AN_RESTART));
+
+               /* Wait for AN to leave state 0 */
+               for (i = 0; i < 10; i++) {
+                       msleep(4);
+                       reg_anlp1 = IXGBE_READ_REG(hw, IXGBE_ANLP1);
+                       if (reg_anlp1 & IXGBE_ANLP1_AN_STATE_MASK)
+                               break;
+               }
+               if (!(reg_anlp1 & IXGBE_ANLP1_AN_STATE_MASK)) {
+                       hw_dbg(hw, "sfp module setup not complete\n");
+                       ret_val = IXGBE_ERR_SFP_SETUP_NOT_COMPLETE;
+                       goto setup_sfp_out;
+               }
+
+               /* Restart DSP by setting Restart_AN and return to SFI mode */
+               IXGBE_WRITE_REG(hw, IXGBE_AUTOC, (IXGBE_READ_REG(hw,
+                               IXGBE_AUTOC) | IXGBE_AUTOC_LMS_10G_SERIAL |
+                               IXGBE_AUTOC_AN_RESTART));
        }
 
 setup_sfp_out:
index f97353cdb60727eae424b0382e77afa5171eaf40..fdb35d040d23249c077449c5ad603ef6ea63bbc1 100644 (file)
@@ -3800,7 +3800,7 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
        /* enable the optics for both mult-speed fiber and 82599 SFP+ fiber */
        if (hw->mac.ops.enable_tx_laser &&
            ((hw->phy.multispeed_fiber) ||
-            ((hw->phy.type == ixgbe_media_type_fiber) &&
+            ((hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) &&
              (hw->mac.type == ixgbe_mac_82599EB))))
                hw->mac.ops.enable_tx_laser(hw);
 
@@ -4122,7 +4122,7 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
        /* power down the optics for multispeed fiber and 82599 SFP+ fiber */
        if (hw->mac.ops.disable_tx_laser &&
            ((hw->phy.multispeed_fiber) ||
-            ((hw->phy.type == ixgbe_media_type_fiber) &&
+            ((hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) &&
              (hw->mac.type == ixgbe_mac_82599EB))))
                hw->mac.ops.disable_tx_laser(hw);
 
@@ -4987,6 +4987,9 @@ void ixgbe_clear_interrupt_scheme(struct ixgbe_adapter *adapter)
                adapter->rx_ring[i] = NULL;
        }
 
+       adapter->num_tx_queues = 0;
+       adapter->num_rx_queues = 0;
+
        ixgbe_free_q_vectors(adapter);
        ixgbe_reset_interrupt_capability(adapter);
 }
@@ -7212,7 +7215,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        /* power down the optics for multispeed fiber and 82599 SFP+ fiber */
        if (hw->mac.ops.disable_tx_laser &&
            ((hw->phy.multispeed_fiber) ||
-            ((hw->phy.type == ixgbe_media_type_fiber) &&
+            ((hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) &&
              (hw->mac.type == ixgbe_mac_82599EB))))
                hw->mac.ops.disable_tx_laser(hw);
 
index ef816dd5a8f01ac9356d1f10d4aa3ddbc57cae28..0f80893edabf67326b3b574a2e3f517744d8bae7 100644 (file)
 #define IXGBE_ANLP1_PAUSE               0x0C00
 #define IXGBE_ANLP1_SYM_PAUSE           0x0400
 #define IXGBE_ANLP1_ASM_PAUSE           0x0800
+#define IXGBE_ANLP1_AN_STATE_MASK       0x000f0000
+
 
 /* SW Semaphore Register bitmasks */
 #define IXGBE_SWSM_SMBI 0x00000001 /* Driver Semaphore bit */
@@ -2641,6 +2643,7 @@ struct ixgbe_info {
 #define IXGBE_ERR_NO_SPACE                      -25
 #define IXGBE_ERR_OVERTEMP                      -26
 #define IXGBE_ERR_RAR_INDEX                     -27
+#define IXGBE_ERR_SFP_SETUP_NOT_COMPLETE        -30
 #define IXGBE_ERR_PBA_SECTION                   -31
 #define IXGBE_ERR_INVALID_ARGUMENT              -32
 #define IXGBE_NOT_IMPLEMENTED                   0x7FFFFFFF
index c57d9a43cecacbf8a668a0c4b1cca5e7b93c3521..2411e72ba572d00f6a76646e0f7a34da500f7e53 100644 (file)
@@ -2076,12 +2076,11 @@ jme_change_mtu(struct net_device *netdev, int new_mtu)
        }
 
        if (new_mtu > 1900) {
-               netdev->features &= ~(NETIF_F_HW_CSUM |
-                               NETIF_F_TSO |
-                               NETIF_F_TSO6);
+               netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM |
+                               NETIF_F_TSO | NETIF_F_TSO6);
        } else {
                if (test_bit(JME_FLAG_TXCSUM, &jme->flags))
-                       netdev->features |= NETIF_F_HW_CSUM;
+                       netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
                if (test_bit(JME_FLAG_TSO, &jme->flags))
                        netdev->features |= NETIF_F_TSO | NETIF_F_TSO6;
        }
@@ -2514,10 +2513,12 @@ jme_set_tx_csum(struct net_device *netdev, u32 on)
        if (on) {
                set_bit(JME_FLAG_TXCSUM, &jme->flags);
                if (netdev->mtu <= 1900)
-                       netdev->features |= NETIF_F_HW_CSUM;
+                       netdev->features |=
+                               NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
        } else {
                clear_bit(JME_FLAG_TXCSUM, &jme->flags);
-               netdev->features &= ~NETIF_F_HW_CSUM;
+               netdev->features &=
+                               ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
        }
 
        return 0;
@@ -2797,7 +2798,8 @@ jme_init_one(struct pci_dev *pdev,
        netdev->netdev_ops = &jme_netdev_ops;
        netdev->ethtool_ops             = &jme_ethtool_ops;
        netdev->watchdog_timeo          = TX_TIMEOUT;
-       netdev->features                =       NETIF_F_HW_CSUM |
+       netdev->features                =       NETIF_F_IP_CSUM |
+                                               NETIF_F_IPV6_CSUM |
                                                NETIF_F_SG |
                                                NETIF_F_TSO |
                                                NETIF_F_TSO6 |
index c8cc32c0edc9678d6174693412e977e43a4ebf29..c8c873b31a899a47ae002826efff438893646178 100644 (file)
@@ -468,18 +468,6 @@ static int pch_gbe_set_rx_csum(struct net_device *netdev, u32 data)
        return 0;
 }
 
-/**
- * pch_gbe_get_tx_csum - Report whether transmit checksums are turned on or off
- * @netdev:  Network interface device structure
- * Returns
- *     true(1):  Checksum On
- *     false(0): Checksum Off
- */
-static u32 pch_gbe_get_tx_csum(struct net_device *netdev)
-{
-       return (netdev->features & NETIF_F_HW_CSUM) != 0;
-}
-
 /**
  * pch_gbe_set_tx_csum - Turn transmit checksums on or off
  * @netdev: Network interface device structure
@@ -493,11 +481,7 @@ static int pch_gbe_set_tx_csum(struct net_device *netdev, u32 data)
        struct pch_gbe_adapter *adapter = netdev_priv(netdev);
 
        adapter->tx_csum = data;
-       if (data)
-               netdev->features |= NETIF_F_HW_CSUM;
-       else
-               netdev->features &= ~NETIF_F_HW_CSUM;
-       return 0;
+       return ethtool_op_set_tx_ipv6_csum(netdev, data);
 }
 
 /**
@@ -572,7 +556,6 @@ static const struct ethtool_ops pch_gbe_ethtool_ops = {
        .set_pauseparam = pch_gbe_set_pauseparam,
        .get_rx_csum = pch_gbe_get_rx_csum,
        .set_rx_csum = pch_gbe_set_rx_csum,
-       .get_tx_csum = pch_gbe_get_tx_csum,
        .set_tx_csum = pch_gbe_set_tx_csum,
        .get_strings = pch_gbe_get_strings,
        .get_ethtool_stats = pch_gbe_get_ethtool_stats,
index afb75066b14d1cce3505963d74d4f0b26d83f8fe..d7355306a738fbbe78b7848423ea203a6fd5c444 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * Copyright (C) 1999 - 2010 Intel Corporation.
- * Copyright (C) 2010 OKI SEMICONDUCTOR Co., LTD.
+ * Copyright (C) 2010 OKI SEMICONDUCTOR CO., LTD.
  *
  * This code was derived from the Intel e1000e Linux driver.
  *
@@ -2319,7 +2319,7 @@ static int pch_gbe_probe(struct pci_dev *pdev,
        netdev->watchdog_timeo = PCH_GBE_WATCHDOG_PERIOD;
        netif_napi_add(netdev, &adapter->napi,
                       pch_gbe_napi_poll, PCH_GBE_RX_WEIGHT);
-       netdev->features = NETIF_F_HW_CSUM | NETIF_F_GRO;
+       netdev->features = NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM | NETIF_F_GRO;
        pch_gbe_set_ethtool_ops(netdev);
 
        pch_gbe_mac_reset_hw(&adapter->hw);
@@ -2358,9 +2358,9 @@ static int pch_gbe_probe(struct pci_dev *pdev,
        pch_gbe_check_options(adapter);
 
        if (adapter->tx_csum)
-               netdev->features |= NETIF_F_HW_CSUM;
+               netdev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
        else
-               netdev->features &= ~NETIF_F_HW_CSUM;
+               netdev->features &= ~(NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM);
 
        /* initialize the wol settings based on the eeprom settings */
        adapter->wake_up_evt = PCH_GBE_WL_INIT_SETTING;
@@ -2462,8 +2462,8 @@ static void __exit pch_gbe_exit_module(void)
 module_init(pch_gbe_init_module);
 module_exit(pch_gbe_exit_module);
 
-MODULE_DESCRIPTION("OKI semiconductor PCH Gigabit ethernet Driver");
-MODULE_AUTHOR("OKI semiconductor, <masa-korg@dsn.okisemi.com>");
+MODULE_DESCRIPTION("EG20T PCH Gigabit ethernet Driver");
+MODULE_AUTHOR("OKI SEMICONDUCTOR, <toshiharu-linux@dsn.okisemi.com>");
 MODULE_LICENSE("GPL");
 MODULE_VERSION(DRV_VERSION);
 MODULE_DEVICE_TABLE(pci, pch_gbe_pcidev_id);
index 2510146fc5607db7a26d9b54ad634f8941d65ae2..ef0996a0eaaaa9e39e84d183cbc074be9bff5080 100644 (file)
@@ -434,8 +434,8 @@ void pch_gbe_check_options(struct pch_gbe_adapter *adapter)
                        .err  = "using default of "
                                __MODULE_STRING(PCH_GBE_DEFAULT_TXD),
                        .def  = PCH_GBE_DEFAULT_TXD,
-                       .arg  = { .r = { .min = PCH_GBE_MIN_TXD } },
-                       .arg  = { .r = { .max = PCH_GBE_MAX_TXD } }
+                       .arg  = { .r = { .min = PCH_GBE_MIN_TXD,
+                                        .max = PCH_GBE_MAX_TXD } }
                };
                struct pch_gbe_tx_ring *tx_ring = adapter->tx_ring;
                tx_ring->count = TxDescriptors;
@@ -450,8 +450,8 @@ void pch_gbe_check_options(struct pch_gbe_adapter *adapter)
                        .err  = "using default of "
                                __MODULE_STRING(PCH_GBE_DEFAULT_RXD),
                        .def  = PCH_GBE_DEFAULT_RXD,
-                       .arg  = { .r = { .min = PCH_GBE_MIN_RXD } },
-                       .arg  = { .r = { .max = PCH_GBE_MAX_RXD } }
+                       .arg  = { .r = { .min = PCH_GBE_MIN_RXD,
+                                        .max = PCH_GBE_MAX_RXD } }
                };
                struct pch_gbe_rx_ring *rx_ring = adapter->rx_ring;
                rx_ring->count = RxDescriptors;
index f0bd1a1aba3ab3413a16eab296b4881d99ea1145..e8b9c53c304b63d2ba2b4a530504e5fafb08f6dc 100644 (file)
 #include <linux/ethtool.h>
 #include <linux/phy.h>
 #include <linux/marvell_phy.h>
+#include <linux/of.h>
 
 #include <asm/io.h>
 #include <asm/irq.h>
 #include <asm/uaccess.h>
 
+#define MII_MARVELL_PHY_PAGE           22
+
 #define MII_M1011_IEVENT               0x13
 #define MII_M1011_IEVENT_CLEAR         0x0000
 
@@ -80,7 +83,6 @@
 #define MII_88E1121_PHY_LED_CTRL       16
 #define MII_88E1121_PHY_LED_PAGE       3
 #define MII_88E1121_PHY_LED_DEF                0x0030
-#define MII_88E1121_PHY_PAGE           22
 
 #define MII_M1011_PHY_STATUS           0x11
 #define MII_M1011_PHY_STATUS_1000      0x8000
@@ -186,13 +188,94 @@ static int marvell_config_aneg(struct phy_device *phydev)
        return 0;
 }
 
+#ifdef CONFIG_OF_MDIO
+/*
+ * Set and/or override some configuration registers based on the
+ * marvell,reg-init property stored in the of_node for the phydev.
+ *
+ * marvell,reg-init = <reg-page reg mask value>,...;
+ *
+ * There may be one or more sets of <reg-page reg mask value>:
+ *
+ * reg-page: which register bank to use.
+ * reg: the register.
+ * mask: if non-zero, ANDed with existing register value.
+ * value: ORed with the masked value and written to the regiser.
+ *
+ */
+static int marvell_of_reg_init(struct phy_device *phydev)
+{
+       const __be32 *paddr;
+       int len, i, saved_page, current_page, page_changed, ret;
+
+       if (!phydev->dev.of_node)
+               return 0;
+
+       paddr = of_get_property(phydev->dev.of_node, "marvell,reg-init", &len);
+       if (!paddr || len < (4 * sizeof(*paddr)))
+               return 0;
+
+       saved_page = phy_read(phydev, MII_MARVELL_PHY_PAGE);
+       if (saved_page < 0)
+               return saved_page;
+       page_changed = 0;
+       current_page = saved_page;
+
+       ret = 0;
+       len /= sizeof(*paddr);
+       for (i = 0; i < len - 3; i += 4) {
+               u16 reg_page = be32_to_cpup(paddr + i);
+               u16 reg = be32_to_cpup(paddr + i + 1);
+               u16 mask = be32_to_cpup(paddr + i + 2);
+               u16 val_bits = be32_to_cpup(paddr + i + 3);
+               int val;
+
+               if (reg_page != current_page) {
+                       current_page = reg_page;
+                       page_changed = 1;
+                       ret = phy_write(phydev, MII_MARVELL_PHY_PAGE, reg_page);
+                       if (ret < 0)
+                               goto err;
+               }
+
+               val = 0;
+               if (mask) {
+                       val = phy_read(phydev, reg);
+                       if (val < 0) {
+                               ret = val;
+                               goto err;
+                       }
+                       val &= mask;
+               }
+               val |= val_bits;
+
+               ret = phy_write(phydev, reg, val);
+               if (ret < 0)
+                       goto err;
+
+       }
+err:
+       if (page_changed) {
+               i = phy_write(phydev, MII_MARVELL_PHY_PAGE, saved_page);
+               if (ret == 0)
+                       ret = i;
+       }
+       return ret;
+}
+#else
+static int marvell_of_reg_init(struct phy_device *phydev)
+{
+       return 0;
+}
+#endif /* CONFIG_OF_MDIO */
+
 static int m88e1121_config_aneg(struct phy_device *phydev)
 {
        int err, oldpage, mscr;
 
-       oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
+       oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
 
-       err = phy_write(phydev, MII_88E1121_PHY_PAGE,
+       err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
                        MII_88E1121_PHY_MSCR_PAGE);
        if (err < 0)
                return err;
@@ -218,7 +301,7 @@ static int m88e1121_config_aneg(struct phy_device *phydev)
                        return err;
        }
 
-       phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
+       phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
 
        err = phy_write(phydev, MII_BMCR, BMCR_RESET);
        if (err < 0)
@@ -229,11 +312,11 @@ static int m88e1121_config_aneg(struct phy_device *phydev)
        if (err < 0)
                return err;
 
-       oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
+       oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
 
-       phy_write(phydev, MII_88E1121_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
+       phy_write(phydev, MII_MARVELL_PHY_PAGE, MII_88E1121_PHY_LED_PAGE);
        phy_write(phydev, MII_88E1121_PHY_LED_CTRL, MII_88E1121_PHY_LED_DEF);
-       phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
+       phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
 
        err = genphy_config_aneg(phydev);
 
@@ -244,9 +327,9 @@ static int m88e1318_config_aneg(struct phy_device *phydev)
 {
        int err, oldpage, mscr;
 
-       oldpage = phy_read(phydev, MII_88E1121_PHY_PAGE);
+       oldpage = phy_read(phydev, MII_MARVELL_PHY_PAGE);
 
-       err = phy_write(phydev, MII_88E1121_PHY_PAGE,
+       err = phy_write(phydev, MII_MARVELL_PHY_PAGE,
                        MII_88E1121_PHY_MSCR_PAGE);
        if (err < 0)
                return err;
@@ -258,7 +341,7 @@ static int m88e1318_config_aneg(struct phy_device *phydev)
        if (err < 0)
                return err;
 
-       err = phy_write(phydev, MII_88E1121_PHY_PAGE, oldpage);
+       err = phy_write(phydev, MII_MARVELL_PHY_PAGE, oldpage);
        if (err < 0)
                return err;
 
@@ -368,6 +451,9 @@ static int m88e1111_config_init(struct phy_device *phydev)
                        return err;
        }
 
+       err = marvell_of_reg_init(phydev);
+       if (err < 0)
+               return err;
 
        err = phy_write(phydev, MII_BMCR, BMCR_RESET);
        if (err < 0)
@@ -398,7 +484,7 @@ static int m88e1118_config_init(struct phy_device *phydev)
        int err;
 
        /* Change address */
-       err = phy_write(phydev, 0x16, 0x0002);
+       err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
        if (err < 0)
                return err;
 
@@ -408,7 +494,7 @@ static int m88e1118_config_init(struct phy_device *phydev)
                return err;
 
        /* Change address */
-       err = phy_write(phydev, 0x16, 0x0003);
+       err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0003);
        if (err < 0)
                return err;
 
@@ -420,8 +506,42 @@ static int m88e1118_config_init(struct phy_device *phydev)
        if (err < 0)
                return err;
 
+       err = marvell_of_reg_init(phydev);
+       if (err < 0)
+               return err;
+
        /* Reset address */
-       err = phy_write(phydev, 0x16, 0x0);
+       err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
+       if (err < 0)
+               return err;
+
+       err = phy_write(phydev, MII_BMCR, BMCR_RESET);
+       if (err < 0)
+               return err;
+
+       return 0;
+}
+
+static int m88e1149_config_init(struct phy_device *phydev)
+{
+       int err;
+
+       /* Change address */
+       err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0002);
+       if (err < 0)
+               return err;
+
+       /* Enable 1000 Mbit */
+       err = phy_write(phydev, 0x15, 0x1048);
+       if (err < 0)
+               return err;
+
+       err = marvell_of_reg_init(phydev);
+       if (err < 0)
+               return err;
+
+       /* Reset address */
+       err = phy_write(phydev, MII_MARVELL_PHY_PAGE, 0x0);
        if (err < 0)
                return err;
 
@@ -491,6 +611,10 @@ static int m88e1145_config_init(struct phy_device *phydev)
                }
        }
 
+       err = marvell_of_reg_init(phydev);
+       if (err < 0)
+               return err;
+
        return 0;
 }
 
@@ -684,6 +808,19 @@ static struct phy_driver marvell_drivers[] = {
                .config_intr = &marvell_config_intr,
                .driver = { .owner = THIS_MODULE },
        },
+       {
+               .phy_id = MARVELL_PHY_ID_88E1149R,
+               .phy_id_mask = MARVELL_PHY_ID_MASK,
+               .name = "Marvell 88E1149R",
+               .features = PHY_GBIT_FEATURES,
+               .flags = PHY_HAS_INTERRUPT,
+               .config_init = &m88e1149_config_init,
+               .config_aneg = &m88e1118_config_aneg,
+               .read_status = &genphy_read_status,
+               .ack_interrupt = &marvell_ack_interrupt,
+               .config_intr = &marvell_config_intr,
+               .driver = { .owner = THIS_MODULE },
+       },
        {
                .phy_id = MARVELL_PHY_ID_88E1240,
                .phy_id_mask = MARVELL_PHY_ID_MASK,
@@ -735,6 +872,7 @@ static struct mdio_device_id __maybe_unused marvell_tbl[] = {
        { 0x01410e10, 0xfffffff0 },
        { 0x01410cb0, 0xfffffff0 },
        { 0x01410cd0, 0xfffffff0 },
+       { 0x01410e50, 0xfffffff0 },
        { 0x01410e30, 0xfffffff0 },
        { 0x01410e90, 0xfffffff0 },
        { }
index 0c91598ae2806377aa901175afe75b2632ed9a3a..b708f68471a61b4b63bf06ed51886418c332ec23 100644 (file)
@@ -2580,16 +2580,16 @@ ppp_create_interface(struct net *net, int unit, int *retp)
         */
        dev_net_set(dev, net);
 
-       ret = -EEXIST;
        mutex_lock(&pn->all_ppp_mutex);
 
        if (unit < 0) {
                unit = unit_get(&pn->units_idr, ppp);
                if (unit < 0) {
-                       *retp = unit;
+                       ret = unit;
                        goto out2;
                }
        } else {
+               ret = -EEXIST;
                if (unit_find(&pn->units_idr, unit))
                        goto out2; /* unit already exists */
                /*
@@ -2664,10 +2664,10 @@ static void ppp_shutdown_interface(struct ppp *ppp)
                ppp->closing = 1;
                ppp_unlock(ppp);
                unregister_netdev(ppp->dev);
+               unit_put(&pn->units_idr, ppp->file.index);
        } else
                ppp_unlock(ppp);
 
-       unit_put(&pn->units_idr, ppp->file.index);
        ppp->file.dead = 1;
        ppp->owner = NULL;
        wake_up_interruptible(&ppp->file.rwait);
@@ -2855,8 +2855,7 @@ static void __exit ppp_cleanup(void)
  * by holding all_ppp_mutex
  */
 
-/* associate pointer with specified number */
-static int unit_set(struct idr *p, void *ptr, int n)
+static int __unit_alloc(struct idr *p, void *ptr, int n)
 {
        int unit, err;
 
@@ -2867,10 +2866,24 @@ again:
        }
 
        err = idr_get_new_above(p, ptr, n, &unit);
-       if (err == -EAGAIN)
-               goto again;
+       if (err < 0) {
+               if (err == -EAGAIN)
+                       goto again;
+               return err;
+       }
+
+       return unit;
+}
+
+/* associate pointer with specified number */
+static int unit_set(struct idr *p, void *ptr, int n)
+{
+       int unit;
 
-       if (unit != n) {
+       unit = __unit_alloc(p, ptr, n);
+       if (unit < 0)
+               return unit;
+       else if (unit != n) {
                idr_remove(p, unit);
                return -EINVAL;
        }
@@ -2881,19 +2894,7 @@ again:
 /* get new free unit number and associate pointer with it */
 static int unit_get(struct idr *p, void *ptr)
 {
-       int unit, err;
-
-again:
-       if (!idr_pre_get(p, GFP_KERNEL)) {
-               printk(KERN_ERR "PPP: No free memory for idr\n");
-               return -ENOMEM;
-       }
-
-       err = idr_get_new_above(p, ptr, 0, &unit);
-       if (err == -EAGAIN)
-               goto again;
-
-       return unit;
+       return __unit_alloc(p, ptr, 0);
 }
 
 /* put unit number back to a pool */
index d9a76260880b6d8e8c21ba815ba42f7ed04fdece..e4dbbbfec7232e9f75df168c50aaf106a3efe1e5 100644 (file)
@@ -62,15 +62,15 @@ static const u32 default_msg =
 /* NETIF_MSG_PKTDATA | */
     NETIF_MSG_HW | NETIF_MSG_WOL | 0;
 
-static int debug = 0x00007fff; /* defaults above */
-module_param(debug, int, 0);
+static int debug = -1; /* defaults above */
+module_param(debug, int, 0664);
 MODULE_PARM_DESC(debug, "Debug level (0=none,...,16=all)");
 
 #define MSIX_IRQ 0
 #define MSI_IRQ 1
 #define LEG_IRQ 2
 static int qlge_irq_type = MSIX_IRQ;
-module_param(qlge_irq_type, int, MSIX_IRQ);
+module_param(qlge_irq_type, int, 0664);
 MODULE_PARM_DESC(qlge_irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy.");
 
 static int qlge_mpi_coredump;
index 417adf372828bca69bcc3fd8c274e29fdfb6ac8b..76290a8c3c146f8eec24bd8e93cf201469c1082a 100644 (file)
@@ -1449,7 +1449,8 @@ static int __devinit sc92031_probe(struct pci_dev *pdev,
        dev->irq = pdev->irq;
 
        /* faked with skb_copy_and_csum_dev */
-       dev->features = NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA;
+       dev->features = NETIF_F_SG | NETIF_F_HIGHDMA |
+               NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
 
        dev->netdev_ops         = &sc92031_netdev_ops;
        dev->watchdog_timeo     = TX_TIMEOUT;
index f3e4043d70eee852a98d7fe7eddc8bef1e219a6f..2166c1d0a5332dfe47daa8c8af33520b9d4c7b88 100644 (file)
@@ -196,7 +196,9 @@ MODULE_PARM_DESC(debug, "Bitmapped debugging message enable value");
 
 static void efx_remove_channels(struct efx_nic *efx);
 static void efx_remove_port(struct efx_nic *efx);
+static void efx_init_napi(struct efx_nic *efx);
 static void efx_fini_napi(struct efx_nic *efx);
+static void efx_fini_napi_channel(struct efx_channel *channel);
 static void efx_fini_struct(struct efx_nic *efx);
 static void efx_start_all(struct efx_nic *efx);
 static void efx_stop_all(struct efx_nic *efx);
@@ -334,8 +336,10 @@ void efx_process_channel_now(struct efx_channel *channel)
 
        /* Disable interrupts and wait for ISRs to complete */
        efx_nic_disable_interrupts(efx);
-       if (efx->legacy_irq)
+       if (efx->legacy_irq) {
                synchronize_irq(efx->legacy_irq);
+               efx->legacy_irq_enabled = false;
+       }
        if (channel->irq)
                synchronize_irq(channel->irq);
 
@@ -350,6 +354,8 @@ void efx_process_channel_now(struct efx_channel *channel)
        efx_channel_processed(channel);
 
        napi_enable(&channel->napi_str);
+       if (efx->legacy_irq)
+               efx->legacy_irq_enabled = true;
        efx_nic_enable_interrupts(efx);
 }
 
@@ -425,6 +431,7 @@ efx_alloc_channel(struct efx_nic *efx, int i, struct efx_channel *old_channel)
 
                *channel = *old_channel;
 
+               channel->napi_dev = NULL;
                memset(&channel->eventq, 0, sizeof(channel->eventq));
 
                rx_queue = &channel->rx_queue;
@@ -735,9 +742,13 @@ efx_realloc_channels(struct efx_nic *efx, u32 rxq_entries, u32 txq_entries)
        if (rc)
                goto rollback;
 
+       efx_init_napi(efx);
+
        /* Destroy old channels */
-       for (i = 0; i < efx->n_channels; i++)
+       for (i = 0; i < efx->n_channels; i++) {
+               efx_fini_napi_channel(other_channel[i]);
                efx_remove_channel(other_channel[i]);
+       }
 out:
        /* Free unused channel structures */
        for (i = 0; i < efx->n_channels; i++)
@@ -1401,6 +1412,8 @@ static void efx_start_all(struct efx_nic *efx)
                efx_start_channel(channel);
        }
 
+       if (efx->legacy_irq)
+               efx->legacy_irq_enabled = true;
        efx_nic_enable_interrupts(efx);
 
        /* Switch to event based MCDI completions after enabling interrupts.
@@ -1461,8 +1474,10 @@ static void efx_stop_all(struct efx_nic *efx)
 
        /* Disable interrupts and wait for ISR to complete */
        efx_nic_disable_interrupts(efx);
-       if (efx->legacy_irq)
+       if (efx->legacy_irq) {
                synchronize_irq(efx->legacy_irq);
+               efx->legacy_irq_enabled = false;
+       }
        efx_for_each_channel(channel, efx) {
                if (channel->irq)
                        synchronize_irq(channel->irq);
@@ -1594,7 +1609,7 @@ static int efx_ioctl(struct net_device *net_dev, struct ifreq *ifr, int cmd)
  *
  **************************************************************************/
 
-static int efx_init_napi(struct efx_nic *efx)
+static void efx_init_napi(struct efx_nic *efx)
 {
        struct efx_channel *channel;
 
@@ -1603,18 +1618,21 @@ static int efx_init_napi(struct efx_nic *efx)
                netif_napi_add(channel->napi_dev, &channel->napi_str,
                               efx_poll, napi_weight);
        }
-       return 0;
+}
+
+static void efx_fini_napi_channel(struct efx_channel *channel)
+{
+       if (channel->napi_dev)
+               netif_napi_del(&channel->napi_str);
+       channel->napi_dev = NULL;
 }
 
 static void efx_fini_napi(struct efx_nic *efx)
 {
        struct efx_channel *channel;
 
-       efx_for_each_channel(channel, efx) {
-               if (channel->napi_dev)
-                       netif_napi_del(&channel->napi_str);
-               channel->napi_dev = NULL;
-       }
+       efx_for_each_channel(channel, efx)
+               efx_fini_napi_channel(channel);
 }
 
 /**************************************************************************
@@ -2331,9 +2349,7 @@ static int efx_pci_probe_main(struct efx_nic *efx)
        if (rc)
                goto fail1;
 
-       rc = efx_init_napi(efx);
-       if (rc)
-               goto fail2;
+       efx_init_napi(efx);
 
        rc = efx->type->init(efx);
        if (rc) {
@@ -2364,7 +2380,6 @@ static int efx_pci_probe_main(struct efx_nic *efx)
        efx->type->fini(efx);
  fail3:
        efx_fini_napi(efx);
- fail2:
        efx_remove_all(efx);
  fail1:
        return rc;
index 270e217a53f9b52f3401bc2fe151169620e76d00..76f2fb197f0ac91b49c71bd9e55ece94d21a477f 100644 (file)
@@ -637,6 +637,7 @@ struct efx_filter_state;
  * @pci_dev: The PCI device
  * @type: Controller type attributes
  * @legacy_irq: IRQ number
+ * @legacy_irq_enabled: Are IRQs enabled on NIC (INT_EN_KER register)?
  * @workqueue: Workqueue for port reconfigures and the HW monitor.
  *     Work items do not hold and must not acquire RTNL.
  * @workqueue_name: Name of workqueue
@@ -720,6 +721,7 @@ struct efx_nic {
        struct pci_dev *pci_dev;
        const struct efx_nic_type *type;
        int legacy_irq;
+       bool legacy_irq_enabled;
        struct workqueue_struct *workqueue;
        char workqueue_name[16];
        struct work_struct reset_work;
index bda6b1bd072c10872a46bb8cb0f9ce52cb320c46..da386599ab68d0a42686eaf4c7af2837fa4b04a9 100644 (file)
@@ -1418,6 +1418,12 @@ static irqreturn_t efx_legacy_interrupt(int irq, void *dev_id)
        u32 queues;
        int syserr;
 
+       /* Could this be ours?  If interrupts are disabled then the
+        * channel state may not be valid.
+        */
+       if (!efx->legacy_irq_enabled)
+               return result;
+
        /* Read the ISR which also ACKs the interrupts */
        efx_readd(efx, &reg, FR_BZ_INT_ISR0);
        queues = EFX_EXTRACT_DWORD(reg, 0, 31);
index f2695fd180ca08531cb857c51e91ff7ca0223237..fd719edc7f7c1842682c14e668d448af3c75361c 100644 (file)
@@ -197,16 +197,6 @@ static void stmmac_ethtool_gregs(struct net_device *dev,
        }
 }
 
-static int stmmac_ethtool_set_tx_csum(struct net_device *netdev, u32 data)
-{
-       if (data)
-               netdev->features |= NETIF_F_HW_CSUM;
-       else
-               netdev->features &= ~NETIF_F_HW_CSUM;
-
-       return 0;
-}
-
 static u32 stmmac_ethtool_get_rx_csum(struct net_device *dev)
 {
        struct stmmac_priv *priv = netdev_priv(dev);
@@ -370,7 +360,7 @@ static struct ethtool_ops stmmac_ethtool_ops = {
        .get_link = ethtool_op_get_link,
        .get_rx_csum = stmmac_ethtool_get_rx_csum,
        .get_tx_csum = ethtool_op_get_tx_csum,
-       .set_tx_csum = stmmac_ethtool_set_tx_csum,
+       .set_tx_csum = ethtool_op_set_tx_ipv6_csum,
        .get_sg = ethtool_op_get_sg,
        .set_sg = ethtool_op_set_sg,
        .get_pauseparam = stmmac_get_pauseparam,
index 730a6fd79ee005a0f7c452653af678ff23930ac0..c0dc78571c628f8b8ecb0afd8f175eeb679dddba 100644 (file)
@@ -1494,7 +1494,8 @@ static int stmmac_probe(struct net_device *dev)
        dev->netdev_ops = &stmmac_netdev_ops;
        stmmac_set_ethtool_ops(dev);
 
-       dev->features |= (NETIF_F_SG | NETIF_F_HW_CSUM | NETIF_F_HIGHDMA);
+       dev->features |= NETIF_F_SG | NETIF_F_HIGHDMA |
+               NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
        dev->watchdog_timeo = msecs_to_jiffies(watchdog);
 #ifdef STMMAC_VLAN_TAG_USED
        /* Both mac100 and gmac support receive VLAN tag detection */
@@ -1516,6 +1517,8 @@ static int stmmac_probe(struct net_device *dev)
                pr_warning("\tno valid MAC address;"
                        "please, use ifconfig or nwhwconfig!\n");
 
+       spin_lock_init(&priv->lock);
+
        ret = register_netdev(dev);
        if (ret) {
                pr_err("%s: ERROR %i registering the device\n",
@@ -1525,9 +1528,7 @@ static int stmmac_probe(struct net_device *dev)
 
        DBG(probe, DEBUG, "%s: Scatter/Gather: %s - HW checksums: %s\n",
            dev->name, (dev->features & NETIF_F_SG) ? "on" : "off",
-           (dev->features & NETIF_F_HW_CSUM) ? "on" : "off");
-
-       spin_lock_init(&priv->lock);
+           (dev->features & NETIF_F_IP_CSUM) ? "on" : "off");
 
        return ret;
 }
index afb79db5327eeab0b9d9e9e787d8c09d23d0a28a..5faa87d86c6667fed06e5b7aa9a7ce9610d23bab 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/ethtool.h>
+#include <linux/mdio.h>
 #include <linux/mii.h>
 #include <linux/phy.h>
 #include <linux/brcmphy.h>
 
 #define DRV_MODULE_NAME                "tg3"
 #define TG3_MAJ_NUM                    3
-#define TG3_MIN_NUM                    115
+#define TG3_MIN_NUM                    116
 #define DRV_MODULE_VERSION     \
        __stringify(TG3_MAJ_NUM) "." __stringify(TG3_MIN_NUM)
-#define DRV_MODULE_RELDATE     "October 14, 2010"
+#define DRV_MODULE_RELDATE     "December 3, 2010"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -1769,9 +1770,9 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
 
        if (tp->link_config.autoneg == AUTONEG_ENABLE &&
            current_link_up == 1 &&
-           (tp->link_config.active_speed == SPEED_1000 ||
-            (tp->link_config.active_speed == SPEED_100 &&
-             tp->link_config.active_duplex == DUPLEX_FULL))) {
+           tp->link_config.active_duplex == DUPLEX_FULL &&
+           (tp->link_config.active_speed == SPEED_100 ||
+            tp->link_config.active_speed == SPEED_1000)) {
                u32 eeectl;
 
                if (tp->link_config.active_speed == SPEED_1000)
@@ -1781,7 +1782,8 @@ static void tg3_phy_eee_adjust(struct tg3 *tp, u32 current_link_up)
 
                tw32(TG3_CPMU_EEE_CTRL, eeectl);
 
-               tg3_phy_cl45_read(tp, 0x7, TG3_CL45_D7_EEERES_STAT, &val);
+               tg3_phy_cl45_read(tp, MDIO_MMD_AN,
+                                 TG3_CL45_D7_EEERES_STAT, &val);
 
                if (val == TG3_CL45_D7_EEERES_STAT_LP_1000T ||
                    val == TG3_CL45_D7_EEERES_STAT_LP_100TX)
@@ -2967,7 +2969,7 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
        }
 
        if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) {
-               u32 val = 0;
+               u32 val;
 
                tw32(TG3_CPMU_EEE_MODE,
                     tr32(TG3_CPMU_EEE_MODE) & ~TG3_CPMU_EEEMD_LPI_ENABLE);
@@ -2984,19 +2986,18 @@ static void tg3_phy_copper_begin(struct tg3 *tp)
                        tg3_phydsp_write(tp, MII_TG3_DSP_CH34TP2,
                                         val | MII_TG3_DSP_CH34TP2_HIBW01);
 
+               val = 0;
                if (tp->link_config.autoneg == AUTONEG_ENABLE) {
                        /* Advertise 100-BaseTX EEE ability */
                        if (tp->link_config.advertising &
-                           (ADVERTISED_100baseT_Half |
-                            ADVERTISED_100baseT_Full))
-                               val |= TG3_CL45_D7_EEEADV_CAP_100TX;
+                           ADVERTISED_100baseT_Full)
+                               val |= MDIO_AN_EEE_ADV_100TX;
                        /* Advertise 1000-BaseT EEE ability */
                        if (tp->link_config.advertising &
-                           (ADVERTISED_1000baseT_Half |
-                            ADVERTISED_1000baseT_Full))
-                               val |= TG3_CL45_D7_EEEADV_CAP_1000T;
+                           ADVERTISED_1000baseT_Full)
+                               val |= MDIO_AN_EEE_ADV_1000T;
                }
-               tg3_phy_cl45_write(tp, 0x7, TG3_CL45_D7_EEEADV_CAP, val);
+               tg3_phy_cl45_write(tp, MDIO_MMD_AN, MDIO_AN_EEE_ADV, val);
 
                /* Turn off SM_DSP clock. */
                val = MII_TG3_AUXCTL_SHDWSEL_AUXCTL |
@@ -5761,7 +5762,7 @@ static netdev_tx_t tg3_start_xmit(struct sk_buff *skb,
        dma_unmap_addr_set(&tnapi->tx_buffers[entry], mapping, mapping);
 
        if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) &&
-           !mss && skb->len > ETH_DATA_LEN)
+           !mss && skb->len > VLAN_ETH_FRAME_LEN)
                base_flags |= TXD_FLAG_JMB_PKT;
 
        tg3_set_txd(tnapi, entry, mapping, len, base_flags,
@@ -5995,7 +5996,7 @@ static netdev_tx_t tg3_start_xmit_dma_bug(struct sk_buff *skb,
 #endif
 
        if ((tp->tg3_flags3 & TG3_FLG3_USE_JUMBO_BDFLAG) &&
-           !mss && skb->len > ETH_DATA_LEN)
+           !mss && skb->len > VLAN_ETH_FRAME_LEN)
                base_flags |= TXD_FLAG_JMB_PKT;
 
        len = skb_headlen(skb);
@@ -7809,6 +7810,37 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        if (tp->tg3_flags & TG3_FLAG_INIT_COMPLETE)
                tg3_abort_hw(tp, 1);
 
+       /* Enable MAC control of LPI */
+       if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) {
+               tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL,
+                      TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
+                      TG3_CPMU_EEE_LNKIDL_UART_IDL);
+
+               tw32_f(TG3_CPMU_EEE_CTRL,
+                      TG3_CPMU_EEE_CTRL_EXIT_20_1_US);
+
+               val = TG3_CPMU_EEEMD_ERLY_L1_XIT_DET |
+                     TG3_CPMU_EEEMD_LPI_IN_TX |
+                     TG3_CPMU_EEEMD_LPI_IN_RX |
+                     TG3_CPMU_EEEMD_EEE_ENABLE;
+
+               if (GET_ASIC_REV(tp->pci_chip_rev_id) != ASIC_REV_5717)
+                       val |= TG3_CPMU_EEEMD_SND_IDX_DET_EN;
+
+               if (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE)
+                       val |= TG3_CPMU_EEEMD_APE_TX_DET_EN;
+
+               tw32_f(TG3_CPMU_EEE_MODE, val);
+
+               tw32_f(TG3_CPMU_EEE_DBTMR1,
+                      TG3_CPMU_DBTMR1_PCIEXIT_2047US |
+                      TG3_CPMU_DBTMR1_LNKIDLE_2047US);
+
+               tw32_f(TG3_CPMU_EEE_DBTMR2,
+                      TG3_CPMU_DBTMR1_APE_TX_2047US |
+                      TG3_CPMU_DBTMR2_TXIDXEQ_2047US);
+       }
+
        if (reset_phy)
                tg3_phy_reset(tp);
 
@@ -7890,22 +7922,6 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
                tw32(TG3_CPMU_LSPD_10MB_CLK, val);
        }
 
-       /* Enable MAC control of LPI */
-       if (tp->phy_flags & TG3_PHYFLG_EEE_CAP) {
-               tw32_f(TG3_CPMU_EEE_LNKIDL_CTRL,
-                      TG3_CPMU_EEE_LNKIDL_PCIE_NL0 |
-                      TG3_CPMU_EEE_LNKIDL_UART_IDL);
-
-               tw32_f(TG3_CPMU_EEE_CTRL,
-                      TG3_CPMU_EEE_CTRL_EXIT_20_1_US);
-
-               tw32_f(TG3_CPMU_EEE_MODE,
-                      TG3_CPMU_EEEMD_ERLY_L1_XIT_DET |
-                      TG3_CPMU_EEEMD_LPI_IN_TX |
-                      TG3_CPMU_EEEMD_LPI_IN_RX |
-                      TG3_CPMU_EEEMD_EEE_ENABLE);
-       }
-
        /* This works around an issue with Athlon chipsets on
         * B3 tigon3 silicon.  This bit has no effect on any
         * other revision.  But do not set this on PCI Express
@@ -12569,9 +12585,11 @@ static int __devinit tg3_phy_probe(struct tg3 *tp)
                }
        }
 
-       if (tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 ||
-           (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
-            tp->pci_chip_rev_id != CHIPREV_ID_57765_A0))
+       if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
+           ((tp->pdev->device == TG3PCI_DEVICE_TIGON3_5718 &&
+             tp->pci_chip_rev_id != CHIPREV_ID_5717_A0) ||
+            (GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_57765 &&
+             tp->pci_chip_rev_id != CHIPREV_ID_57765_A0)))
                tp->phy_flags |= TG3_PHYFLG_EEE_CAP;
 
        if (!(tp->phy_flags & TG3_PHYFLG_ANY_SERDES) &&
index 59b0e096149ea49fff5aa1160fcb4c526fc86f41..d62c8d937c820cf3a124a2250a351156b49a84c6 100644 (file)
 /* 0x3664 --> 0x36b0 unused */
 
 #define TG3_CPMU_EEE_MODE              0x000036b0
-#define TG3_CPMU_EEEMD_ERLY_L1_XIT_DET  0x00000008
-#define TG3_CPMU_EEEMD_LPI_ENABLE       0x00000080
-#define TG3_CPMU_EEEMD_LPI_IN_TX        0x00000100
-#define TG3_CPMU_EEEMD_LPI_IN_RX        0x00000200
-#define TG3_CPMU_EEEMD_EEE_ENABLE       0x00100000
-/* 0x36b4 --> 0x36b8 unused */
-
+#define  TG3_CPMU_EEEMD_APE_TX_DET_EN   0x00000004
+#define  TG3_CPMU_EEEMD_ERLY_L1_XIT_DET         0x00000008
+#define  TG3_CPMU_EEEMD_SND_IDX_DET_EN  0x00000040
+#define  TG3_CPMU_EEEMD_LPI_ENABLE      0x00000080
+#define  TG3_CPMU_EEEMD_LPI_IN_TX       0x00000100
+#define  TG3_CPMU_EEEMD_LPI_IN_RX       0x00000200
+#define  TG3_CPMU_EEEMD_EEE_ENABLE      0x00100000
+#define TG3_CPMU_EEE_DBTMR1            0x000036b4
+#define  TG3_CPMU_DBTMR1_PCIEXIT_2047US         0x07ff0000
+#define  TG3_CPMU_DBTMR1_LNKIDLE_2047US         0x000070ff
+#define TG3_CPMU_EEE_DBTMR2            0x000036b8
+#define  TG3_CPMU_DBTMR1_APE_TX_2047US  0x07ff0000
+#define  TG3_CPMU_DBTMR2_TXIDXEQ_2047US         0x000070ff
 #define TG3_CPMU_EEE_LNKIDL_CTRL       0x000036bc
 #define  TG3_CPMU_EEE_LNKIDL_PCIE_NL0   0x01000000
 #define  TG3_CPMU_EEE_LNKIDL_UART_IDL   0x00000004
 #define MII_TG3_TEST1_CRC_EN           0x8000
 
 /* Clause 45 expansion registers */
-#define TG3_CL45_D7_EEEADV_CAP         0x003c
-#define TG3_CL45_D7_EEEADV_CAP_100TX   0x0002
-#define TG3_CL45_D7_EEEADV_CAP_1000T   0x0004
 #define TG3_CL45_D7_EEERES_STAT                0x803e
 #define TG3_CL45_D7_EEERES_STAT_LP_100TX       0x0002
 #define TG3_CL45_D7_EEERES_STAT_LP_1000T       0x0004
index a9f7d5d1a2695f95a968001a93c1449b9ac998be..7064e035757a16b927d35aa61991268089275744 100644 (file)
@@ -688,9 +688,6 @@ static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb,
 
        DMFE_DBUG(0, "dmfe_start_xmit", 0);
 
-       /* Resource flag check */
-       netif_stop_queue(dev);
-
        /* Too large packet check */
        if (skb->len > MAX_PACKET_SIZE) {
                pr_err("big packet = %d\n", (u16)skb->len);
@@ -698,6 +695,9 @@ static netdev_tx_t dmfe_start_xmit(struct sk_buff *skb,
                return NETDEV_TX_OK;
        }
 
+       /* Resource flag check */
+       netif_stop_queue(dev);
+
        spin_lock_irqsave(&db->lock, flags);
 
        /* No Tx resource check, it never happen nromally */
index 05a95586f3c52f76ead1b26bb6545b3a18b1a076..055b87ab4f075b66afb7cc4d33c58b440d4f83be 100644 (file)
@@ -899,7 +899,8 @@ struct ucc_geth_hardware_statistics {
 #define UCC_GETH_UTFS_INIT                      512    /* Tx virtual FIFO size
                                                         */
 #define UCC_GETH_UTFET_INIT                     256    /* 1/2 utfs */
-#define UCC_GETH_UTFTT_INIT                     512
+#define UCC_GETH_UTFTT_INIT                     256    /* 1/2 utfs
+                                                          due to errata */
 /* Gigabit Ethernet (1000 Mbps) */
 #define UCC_GETH_URFS_GIGA_INIT                 4096/*2048*/   /* Rx virtual
                                                                   FIFO size */
index 52ffabe6db0eac43cc39a14ece7326f1d686b5aa..6f600cced6e1f5e10d3002fba267f052e6b05544 100644 (file)
@@ -196,6 +196,25 @@ config USB_NET_CDC_EEM
          IEEE 802 "local assignment" bit is set in the address, a "usbX"
          name is used instead.
 
+config USB_NET_CDC_NCM
+       tristate "CDC NCM support"
+       depends on USB_USBNET
+       default y
+       help
+         This driver provides support for CDC NCM (Network Control Model
+         Device USB Class Specification). The CDC NCM specification is
+         available from <http://www.usb.org/>.
+
+         Say "y" to link the driver statically, or "m" to build a
+         dynamically linked module.
+
+         This driver should work with at least the following devices:
+           * ST-Ericsson M700 LTE FDD/TDD Mobile Broadband Modem (ref. design)
+           * ST-Ericsson M5730 HSPA+ Mobile Broadband Modem (reference design)
+           * ST-Ericsson M570 HSPA+ Mobile Broadband Modem (reference design)
+           * ST-Ericsson M343 HSPA Mobile Broadband Modem (reference design)
+           * Ericsson F5521gw Mobile Broadband Module
+
 config USB_NET_DM9601
        tristate "Davicom DM9601 based USB 1.1 10/100 ethernet devices"
        depends on USB_USBNET
index a19b0259ae16c118165be08720553f0bbfa4d289..cac1703011877e9648680362b1a28461ea72dcb6 100644 (file)
@@ -26,4 +26,5 @@ obj-$(CONFIG_USB_CDC_PHONET)  += cdc-phonet.o
 obj-$(CONFIG_USB_IPHETH)       += ipheth.o
 obj-$(CONFIG_USB_SIERRA_NET)   += sierra_net.o
 obj-$(CONFIG_USB_NET_CX82310_ETH)      += cx82310_eth.o
+obj-$(CONFIG_USB_NET_CDC_NCM)  += cdc_ncm.o
 
diff --git a/drivers/net/usb/cdc_ncm.c b/drivers/net/usb/cdc_ncm.c
new file mode 100644 (file)
index 0000000..593c104
--- /dev/null
@@ -0,0 +1,1213 @@
+/*
+ * cdc_ncm.c
+ *
+ * Copyright (C) ST-Ericsson 2010
+ * Contact: Alexey Orishko <alexey.orishko@stericsson.com>
+ * Original author: Hans Petter Selasky <hans.petter.selasky@stericsson.com>
+ *
+ * USB Host Driver for Network Control Model (NCM)
+ * http://www.usb.org/developers/devclass_docs/NCM10.zip
+ *
+ * The NCM encoding, decoding and initialization logic
+ * derives from FreeBSD 8.x. if_cdce.c and if_cdcereg.h
+ *
+ * This software is available to you under a choice of one of two
+ * licenses. You may choose this file to be licensed under the terms
+ * of the GNU General Public License (GPL) Version 2 or the 2-clause
+ * BSD license listed below:
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/ctype.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+#include <linux/usb.h>
+#include <linux/version.h>
+#include <linux/timer.h>
+#include <linux/spinlock.h>
+#include <linux/atomic.h>
+#include <linux/usb/usbnet.h>
+#include <linux/usb/cdc.h>
+
+#define        DRIVER_VERSION                          "30-Nov-2010"
+
+/* CDC NCM subclass 3.2.1 */
+#define USB_CDC_NCM_NDP16_LENGTH_MIN           0x10
+
+/* Maximum NTB length */
+#define        CDC_NCM_NTB_MAX_SIZE_TX                 16384   /* bytes */
+#define        CDC_NCM_NTB_MAX_SIZE_RX                 16384   /* bytes */
+
+/* Minimum value for MaxDatagramSize, ch. 6.2.9 */
+#define        CDC_NCM_MIN_DATAGRAM_SIZE               1514    /* bytes */
+
+#define        CDC_NCM_MIN_TX_PKT                      512     /* bytes */
+
+/* Default value for MaxDatagramSize */
+#define        CDC_NCM_MAX_DATAGRAM_SIZE               2048    /* bytes */
+
+/*
+ * Maximum amount of datagrams in NCM Datagram Pointer Table, not counting
+ * the last NULL entry. Any additional datagrams in NTB would be discarded.
+ */
+#define        CDC_NCM_DPT_DATAGRAMS_MAX               32
+
+/* Restart the timer, if amount of datagrams is less than given value */
+#define        CDC_NCM_RESTART_TIMER_DATAGRAM_CNT      3
+
+/* The following macro defines the minimum header space */
+#define        CDC_NCM_MIN_HDR_SIZE \
+       (sizeof(struct usb_cdc_ncm_nth16) + sizeof(struct usb_cdc_ncm_ndp16) + \
+       (CDC_NCM_DPT_DATAGRAMS_MAX + 1) * sizeof(struct usb_cdc_ncm_dpe16))
+
+struct connection_speed_change {
+       __le32  USBitRate; /* holds 3GPP downlink value, bits per second */
+       __le32  DSBitRate; /* holds 3GPP uplink value, bits per second */
+} __attribute__ ((packed));
+
+struct cdc_ncm_data {
+       struct usb_cdc_ncm_nth16 nth16;
+       struct usb_cdc_ncm_ndp16 ndp16;
+       struct usb_cdc_ncm_dpe16 dpe16[CDC_NCM_DPT_DATAGRAMS_MAX + 1];
+};
+
+struct cdc_ncm_ctx {
+       struct cdc_ncm_data rx_ncm;
+       struct cdc_ncm_data tx_ncm;
+       struct usb_cdc_ncm_ntb_parameters ncm_parm;
+       struct timer_list tx_timer;
+
+       const struct usb_cdc_ncm_desc *func_desc;
+       const struct usb_cdc_header_desc *header_desc;
+       const struct usb_cdc_union_desc *union_desc;
+       const struct usb_cdc_ether_desc *ether_desc;
+
+       struct net_device *netdev;
+       struct usb_device *udev;
+       struct usb_host_endpoint *in_ep;
+       struct usb_host_endpoint *out_ep;
+       struct usb_host_endpoint *status_ep;
+       struct usb_interface *intf;
+       struct usb_interface *control;
+       struct usb_interface *data;
+
+       struct sk_buff *tx_curr_skb;
+       struct sk_buff *tx_rem_skb;
+
+       spinlock_t mtx;
+
+       u32 tx_timer_pending;
+       u32 tx_curr_offset;
+       u32 tx_curr_last_offset;
+       u32 tx_curr_frame_num;
+       u32 rx_speed;
+       u32 tx_speed;
+       u32 rx_max;
+       u32 tx_max;
+       u32 max_datagram_size;
+       u16 tx_max_datagrams;
+       u16 tx_remainder;
+       u16 tx_modulus;
+       u16 tx_ndp_modulus;
+       u16 tx_seq;
+       u16 connected;
+       u8 data_claimed;
+       u8 control_claimed;
+};
+
+static void cdc_ncm_tx_timeout(unsigned long arg);
+static const struct driver_info cdc_ncm_info;
+static struct usb_driver cdc_ncm_driver;
+static struct ethtool_ops cdc_ncm_ethtool_ops;
+
+static const struct usb_device_id cdc_devs[] = {
+       { USB_INTERFACE_INFO(USB_CLASS_COMM,
+               USB_CDC_SUBCLASS_NCM, USB_CDC_PROTO_NONE),
+               .driver_info = (unsigned long)&cdc_ncm_info,
+       },
+       {
+       },
+};
+
+MODULE_DEVICE_TABLE(usb, cdc_devs);
+
+static void
+cdc_ncm_get_drvinfo(struct net_device *net, struct ethtool_drvinfo *info)
+{
+       struct usbnet *dev = netdev_priv(net);
+
+       strncpy(info->driver, dev->driver_name, sizeof(info->driver));
+       strncpy(info->version, DRIVER_VERSION, sizeof(info->version));
+       strncpy(info->fw_version, dev->driver_info->description,
+               sizeof(info->fw_version));
+       usb_make_path(dev->udev, info->bus_info, sizeof(info->bus_info));
+}
+
+static int
+cdc_ncm_do_request(struct cdc_ncm_ctx *ctx, struct usb_cdc_notification *req,
+                  void *data, u16 flags, u16 *actlen, u16 timeout)
+{
+       int err;
+
+       err = usb_control_msg(ctx->udev, (req->bmRequestType & USB_DIR_IN) ?
+                               usb_rcvctrlpipe(ctx->udev, 0) :
+                               usb_sndctrlpipe(ctx->udev, 0),
+                               req->bNotificationType, req->bmRequestType,
+                               req->wValue,
+                               req->wIndex, data,
+                               req->wLength, timeout);
+
+       if (err < 0) {
+               if (actlen)
+                       *actlen = 0;
+               return err;
+       }
+
+       if (actlen)
+               *actlen = err;
+
+       return 0;
+}
+
+static u8 cdc_ncm_setup(struct cdc_ncm_ctx *ctx)
+{
+       struct usb_cdc_notification req;
+       u32 val;
+       __le16 max_datagram_size;
+       u8 flags;
+       u8 iface_no;
+       int err;
+
+       iface_no = ctx->control->cur_altsetting->desc.bInterfaceNumber;
+
+       req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE;
+       req.bNotificationType = USB_CDC_GET_NTB_PARAMETERS;
+       req.wValue = 0;
+       req.wIndex = cpu_to_le16(iface_no);
+       req.wLength = cpu_to_le16(sizeof(ctx->ncm_parm));
+
+       err = cdc_ncm_do_request(ctx, &req, &ctx->ncm_parm, 0, NULL, 1000);
+       if (err) {
+               pr_debug("failed GET_NTB_PARAMETERS\n");
+               return 1;
+       }
+
+       /* read correct set of parameters according to device mode */
+       ctx->rx_max = le32_to_cpu(ctx->ncm_parm.dwNtbInMaxSize);
+       ctx->tx_max = le32_to_cpu(ctx->ncm_parm.dwNtbOutMaxSize);
+       ctx->tx_remainder = le16_to_cpu(ctx->ncm_parm.wNdpOutPayloadRemainder);
+       ctx->tx_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutDivisor);
+       ctx->tx_ndp_modulus = le16_to_cpu(ctx->ncm_parm.wNdpOutAlignment);
+
+       if (ctx->func_desc != NULL)
+               flags = ctx->func_desc->bmNetworkCapabilities;
+       else
+               flags = 0;
+
+       pr_debug("dwNtbInMaxSize=%u dwNtbOutMaxSize=%u "
+                "wNdpOutPayloadRemainder=%u wNdpOutDivisor=%u "
+                "wNdpOutAlignment=%u flags=0x%x\n",
+                ctx->rx_max, ctx->tx_max, ctx->tx_remainder, ctx->tx_modulus,
+                ctx->tx_ndp_modulus, flags);
+
+       /* max count of tx datagrams without terminating NULL entry */
+       ctx->tx_max_datagrams = CDC_NCM_DPT_DATAGRAMS_MAX;
+
+       /* verify maximum size of received NTB in bytes */
+       if ((ctx->rx_max <
+           (CDC_NCM_MIN_HDR_SIZE + CDC_NCM_MIN_DATAGRAM_SIZE)) ||
+           (ctx->rx_max > CDC_NCM_NTB_MAX_SIZE_RX)) {
+               pr_debug("Using default maximum receive length=%d\n",
+                                               CDC_NCM_NTB_MAX_SIZE_RX);
+               ctx->rx_max = CDC_NCM_NTB_MAX_SIZE_RX;
+       }
+
+       /* verify maximum size of transmitted NTB in bytes */
+       if ((ctx->tx_max <
+           (CDC_NCM_MIN_HDR_SIZE + CDC_NCM_MIN_DATAGRAM_SIZE)) ||
+           (ctx->tx_max > CDC_NCM_NTB_MAX_SIZE_TX)) {
+               pr_debug("Using default maximum transmit length=%d\n",
+                                               CDC_NCM_NTB_MAX_SIZE_TX);
+               ctx->tx_max = CDC_NCM_NTB_MAX_SIZE_TX;
+       }
+
+       /*
+        * verify that the structure alignment is:
+        * - power of two
+        * - not greater than the maximum transmit length
+        * - not less than four bytes
+        */
+       val = ctx->tx_ndp_modulus;
+
+       if ((val < USB_CDC_NCM_NDP_ALIGN_MIN_SIZE) ||
+           (val != ((-val) & val)) || (val >= ctx->tx_max)) {
+               pr_debug("Using default alignment: 4 bytes\n");
+               ctx->tx_ndp_modulus = USB_CDC_NCM_NDP_ALIGN_MIN_SIZE;
+       }
+
+       /*
+        * verify that the payload alignment is:
+        * - power of two
+        * - not greater than the maximum transmit length
+        * - not less than four bytes
+        */
+       val = ctx->tx_modulus;
+
+       if ((val < USB_CDC_NCM_NDP_ALIGN_MIN_SIZE) ||
+           (val != ((-val) & val)) || (val >= ctx->tx_max)) {
+               pr_debug("Using default transmit modulus: 4 bytes\n");
+               ctx->tx_modulus = USB_CDC_NCM_NDP_ALIGN_MIN_SIZE;
+       }
+
+       /* verify the payload remainder */
+       if (ctx->tx_remainder >= ctx->tx_modulus) {
+               pr_debug("Using default transmit remainder: 0 bytes\n");
+               ctx->tx_remainder = 0;
+       }
+
+       /* adjust TX-remainder according to NCM specification. */
+       ctx->tx_remainder = ((ctx->tx_remainder - ETH_HLEN) &
+                                               (ctx->tx_modulus - 1));
+
+       /* additional configuration */
+
+       /* set CRC Mode */
+       req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE;
+       req.bNotificationType = USB_CDC_SET_CRC_MODE;
+       req.wValue = cpu_to_le16(USB_CDC_NCM_CRC_NOT_APPENDED);
+       req.wIndex = cpu_to_le16(iface_no);
+       req.wLength = 0;
+
+       err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
+       if (err)
+               pr_debug("Setting CRC mode off failed\n");
+
+       /* set NTB format */
+       req.bmRequestType = USB_TYPE_CLASS | USB_DIR_OUT | USB_RECIP_INTERFACE;
+       req.bNotificationType = USB_CDC_SET_NTB_FORMAT;
+       req.wValue = cpu_to_le16(USB_CDC_NCM_NTB16_FORMAT);
+       req.wIndex = cpu_to_le16(iface_no);
+       req.wLength = 0;
+
+       err = cdc_ncm_do_request(ctx, &req, NULL, 0, NULL, 1000);
+       if (err)
+               pr_debug("Setting NTB format to 16-bit failed\n");
+
+       /* set Max Datagram Size (MTU) */
+       req.bmRequestType = USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE;
+       req.bNotificationType = USB_CDC_GET_MAX_DATAGRAM_SIZE;
+       req.wValue = 0;
+       req.wIndex = cpu_to_le16(iface_no);
+       req.wLength = cpu_to_le16(2);
+
+       err = cdc_ncm_do_request(ctx, &req, &max_datagram_size, 0, NULL, 1000);
+       if (err) {
+               pr_debug(" GET_MAX_DATAGRAM_SIZE failed, using size=%u\n",
+                        CDC_NCM_MIN_DATAGRAM_SIZE);
+               /* use default */
+               ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE;
+       } else {
+               ctx->max_datagram_size = le16_to_cpu(max_datagram_size);
+
+               if (ctx->max_datagram_size < CDC_NCM_MIN_DATAGRAM_SIZE)
+                       ctx->max_datagram_size = CDC_NCM_MIN_DATAGRAM_SIZE;
+               else if (ctx->max_datagram_size > CDC_NCM_MAX_DATAGRAM_SIZE)
+                       ctx->max_datagram_size = CDC_NCM_MAX_DATAGRAM_SIZE;
+       }
+
+       if (ctx->netdev->mtu != (ctx->max_datagram_size - ETH_HLEN))
+               ctx->netdev->mtu = ctx->max_datagram_size - ETH_HLEN;
+
+       return 0;
+}
+
+static void
+cdc_ncm_find_endpoints(struct cdc_ncm_ctx *ctx, struct usb_interface *intf)
+{
+       struct usb_host_endpoint *e;
+       u8 ep;
+
+       for (ep = 0; ep < intf->cur_altsetting->desc.bNumEndpoints; ep++) {
+
+               e = intf->cur_altsetting->endpoint + ep;
+               switch (e->desc.bmAttributes & USB_ENDPOINT_XFERTYPE_MASK) {
+               case USB_ENDPOINT_XFER_INT:
+                       if (usb_endpoint_dir_in(&e->desc)) {
+                               if (ctx->status_ep == NULL)
+                                       ctx->status_ep = e;
+                       }
+                       break;
+
+               case USB_ENDPOINT_XFER_BULK:
+                       if (usb_endpoint_dir_in(&e->desc)) {
+                               if (ctx->in_ep == NULL)
+                                       ctx->in_ep = e;
+                       } else {
+                               if (ctx->out_ep == NULL)
+                                       ctx->out_ep = e;
+                       }
+                       break;
+
+               default:
+                       break;
+               }
+       }
+}
+
+static void cdc_ncm_free(struct cdc_ncm_ctx *ctx)
+{
+       if (ctx == NULL)
+               return;
+
+       del_timer_sync(&ctx->tx_timer);
+
+       if (ctx->data_claimed) {
+               usb_set_intfdata(ctx->data, NULL);
+               usb_driver_release_interface(driver_of(ctx->intf), ctx->data);
+       }
+
+       if (ctx->control_claimed) {
+               usb_set_intfdata(ctx->control, NULL);
+               usb_driver_release_interface(driver_of(ctx->intf),
+                                                               ctx->control);
+       }
+
+       if (ctx->tx_rem_skb != NULL) {
+               dev_kfree_skb_any(ctx->tx_rem_skb);
+               ctx->tx_rem_skb = NULL;
+       }
+
+       if (ctx->tx_curr_skb != NULL) {
+               dev_kfree_skb_any(ctx->tx_curr_skb);
+               ctx->tx_curr_skb = NULL;
+       }
+
+       kfree(ctx);
+}
+
+static int cdc_ncm_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+       struct cdc_ncm_ctx *ctx;
+       struct usb_driver *driver;
+       u8 *buf;
+       int len;
+       int temp;
+       u8 iface_no;
+
+       ctx = kmalloc(sizeof(*ctx), GFP_KERNEL);
+       if (ctx == NULL)
+               goto error;
+
+       memset(ctx, 0, sizeof(*ctx));
+
+       init_timer(&ctx->tx_timer);
+       spin_lock_init(&ctx->mtx);
+       ctx->netdev = dev->net;
+
+       /* store ctx pointer in device data field */
+       dev->data[0] = (unsigned long)ctx;
+
+       /* get some pointers */
+       driver = driver_of(intf);
+       buf = intf->cur_altsetting->extra;
+       len = intf->cur_altsetting->extralen;
+
+       ctx->udev = dev->udev;
+       ctx->intf = intf;
+
+       /* parse through descriptors associated with control interface */
+       while ((len > 0) && (buf[0] > 2) && (buf[0] <= len)) {
+
+               if (buf[1] != USB_DT_CS_INTERFACE)
+                       goto advance;
+
+               switch (buf[2]) {
+               case USB_CDC_UNION_TYPE:
+                       if (buf[0] < sizeof(*(ctx->union_desc)))
+                               break;
+
+                       ctx->union_desc =
+                                       (const struct usb_cdc_union_desc *)buf;
+
+                       ctx->control = usb_ifnum_to_if(dev->udev,
+                                       ctx->union_desc->bMasterInterface0);
+                       ctx->data = usb_ifnum_to_if(dev->udev,
+                                       ctx->union_desc->bSlaveInterface0);
+                       break;
+
+               case USB_CDC_ETHERNET_TYPE:
+                       if (buf[0] < sizeof(*(ctx->ether_desc)))
+                               break;
+
+                       ctx->ether_desc =
+                                       (const struct usb_cdc_ether_desc *)buf;
+
+                       dev->hard_mtu =
+                               le16_to_cpu(ctx->ether_desc->wMaxSegmentSize);
+
+                       if (dev->hard_mtu <
+                           (CDC_NCM_MIN_DATAGRAM_SIZE - ETH_HLEN))
+                               dev->hard_mtu =
+                                       CDC_NCM_MIN_DATAGRAM_SIZE - ETH_HLEN;
+
+                       else if (dev->hard_mtu >
+                                (CDC_NCM_MAX_DATAGRAM_SIZE - ETH_HLEN))
+                               dev->hard_mtu =
+                                       CDC_NCM_MAX_DATAGRAM_SIZE - ETH_HLEN;
+                       break;
+
+               case USB_CDC_NCM_TYPE:
+                       if (buf[0] < sizeof(*(ctx->func_desc)))
+                               break;
+
+                       ctx->func_desc = (const struct usb_cdc_ncm_desc *)buf;
+                       break;
+
+               default:
+                       break;
+               }
+advance:
+               /* advance to next descriptor */
+               temp = buf[0];
+               buf += temp;
+               len -= temp;
+       }
+
+       /* check if we got everything */
+       if ((ctx->control == NULL) || (ctx->data == NULL) ||
+           (ctx->ether_desc == NULL))
+               goto error;
+
+       /* claim interfaces, if any */
+       if (ctx->data != intf) {
+               temp = usb_driver_claim_interface(driver, ctx->data, dev);
+               if (temp)
+                       goto error;
+               ctx->data_claimed = 1;
+       }
+
+       if (ctx->control != intf) {
+               temp = usb_driver_claim_interface(driver, ctx->control, dev);
+               if (temp)
+                       goto error;
+               ctx->control_claimed = 1;
+       }
+
+       iface_no = ctx->data->cur_altsetting->desc.bInterfaceNumber;
+
+       /* reset data interface */
+       temp = usb_set_interface(dev->udev, iface_no, 0);
+       if (temp)
+               goto error;
+
+       /* initialize data interface */
+       if (cdc_ncm_setup(ctx))
+               goto error;
+
+       /* configure data interface */
+       temp = usb_set_interface(dev->udev, iface_no, 1);
+       if (temp)
+               goto error;
+
+       cdc_ncm_find_endpoints(ctx, ctx->data);
+       cdc_ncm_find_endpoints(ctx, ctx->control);
+
+       if ((ctx->in_ep == NULL) || (ctx->out_ep == NULL) ||
+           (ctx->status_ep == NULL))
+               goto error;
+
+       dev->net->ethtool_ops = &cdc_ncm_ethtool_ops;
+
+       usb_set_intfdata(ctx->data, dev);
+       usb_set_intfdata(ctx->control, dev);
+       usb_set_intfdata(ctx->intf, dev);
+
+       temp = usbnet_get_ethernet_addr(dev, ctx->ether_desc->iMACAddress);
+       if (temp)
+               goto error;
+
+       dev_info(&dev->udev->dev, "MAC-Address: "
+                               "0x%02x:0x%02x:0x%02x:0x%02x:0x%02x:0x%02x\n",
+                               dev->net->dev_addr[0], dev->net->dev_addr[1],
+                               dev->net->dev_addr[2], dev->net->dev_addr[3],
+                               dev->net->dev_addr[4], dev->net->dev_addr[5]);
+
+       dev->in = usb_rcvbulkpipe(dev->udev,
+               ctx->in_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+       dev->out = usb_sndbulkpipe(dev->udev,
+               ctx->out_ep->desc.bEndpointAddress & USB_ENDPOINT_NUMBER_MASK);
+       dev->status = ctx->status_ep;
+       dev->rx_urb_size = ctx->rx_max;
+
+       /*
+        * We should get an event when network connection is "connected" or
+        * "disconnected". Set network connection in "disconnected" state
+        * (carrier is OFF) during attach, so the IP network stack does not
+        * start IPv6 negotiation and more.
+        */
+       netif_carrier_off(dev->net);
+       ctx->tx_speed = ctx->rx_speed = 0;
+       return 0;
+
+error:
+       cdc_ncm_free((struct cdc_ncm_ctx *)dev->data[0]);
+       dev->data[0] = 0;
+       dev_info(&dev->udev->dev, "Descriptor failure\n");
+       return -ENODEV;
+}
+
+static void cdc_ncm_unbind(struct usbnet *dev, struct usb_interface *intf)
+{
+       struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+       struct usb_driver *driver;
+
+       if (ctx == NULL)
+               return;         /* no setup */
+
+       driver = driver_of(intf);
+
+       usb_set_intfdata(ctx->data, NULL);
+       usb_set_intfdata(ctx->control, NULL);
+       usb_set_intfdata(ctx->intf, NULL);
+
+       /* release interfaces, if any */
+       if (ctx->data_claimed) {
+               usb_driver_release_interface(driver, ctx->data);
+               ctx->data_claimed = 0;
+       }
+
+       if (ctx->control_claimed) {
+               usb_driver_release_interface(driver, ctx->control);
+               ctx->control_claimed = 0;
+       }
+
+       cdc_ncm_free(ctx);
+}
+
+static void cdc_ncm_zero_fill(u8 *ptr, u32 first, u32 end, u32 max)
+{
+       if (first >= max)
+               return;
+       if (first >= end)
+               return;
+       if (end > max)
+               end = max;
+       memset(ptr + first, 0, end - first);
+}
+
+static struct sk_buff *
+cdc_ncm_fill_tx_frame(struct cdc_ncm_ctx *ctx, struct sk_buff *skb)
+{
+       struct sk_buff *skb_out;
+       u32 rem;
+       u32 offset;
+       u32 last_offset;
+       u16 n = 0;
+       u8 timeout = 0;
+
+       /* if there is a remaining skb, it gets priority */
+       if (skb != NULL)
+               swap(skb, ctx->tx_rem_skb);
+       else
+               timeout = 1;
+
+       /*
+        * +----------------+
+        * | skb_out        |
+        * +----------------+
+        *           ^ offset
+        *        ^ last_offset
+        */
+
+       /* check if we are resuming an OUT skb */
+       if (ctx->tx_curr_skb != NULL) {
+               /* pop variables */
+               skb_out = ctx->tx_curr_skb;
+               offset = ctx->tx_curr_offset;
+               last_offset = ctx->tx_curr_last_offset;
+               n = ctx->tx_curr_frame_num;
+
+       } else {
+               /* reset variables */
+               skb_out = alloc_skb(ctx->tx_max, GFP_ATOMIC);
+               if (skb_out == NULL) {
+                       if (skb != NULL) {
+                               dev_kfree_skb_any(skb);
+                               ctx->netdev->stats.tx_dropped++;
+                       }
+                       goto exit_no_skb;
+               }
+
+               /* make room for NTH and NDP */
+               offset = ALIGN(sizeof(struct usb_cdc_ncm_nth16),
+                                       ctx->tx_ndp_modulus) +
+                                       sizeof(struct usb_cdc_ncm_ndp16) +
+                                       (ctx->tx_max_datagrams + 1) *
+                                       sizeof(struct usb_cdc_ncm_dpe16);
+
+               /* store last valid offset before alignment */
+               last_offset = offset;
+               /* align first Datagram offset correctly */
+               offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder;
+               /* zero buffer till the first IP datagram */
+               cdc_ncm_zero_fill(skb_out->data, 0, offset, offset);
+               n = 0;
+               ctx->tx_curr_frame_num = 0;
+       }
+
+       for (; n < ctx->tx_max_datagrams; n++) {
+               /* check if end of transmit buffer is reached */
+               if (offset >= ctx->tx_max)
+                       break;
+
+               /* compute maximum buffer size */
+               rem = ctx->tx_max - offset;
+
+               if (skb == NULL) {
+                       skb = ctx->tx_rem_skb;
+                       ctx->tx_rem_skb = NULL;
+
+                       /* check for end of skb */
+                       if (skb == NULL)
+                               break;
+               }
+
+               if (skb->len > rem) {
+                       if (n == 0) {
+                               /* won't fit, MTU problem? */
+                               dev_kfree_skb_any(skb);
+                               skb = NULL;
+                               ctx->netdev->stats.tx_dropped++;
+                       } else {
+                               /* no room for skb - store for later */
+                               if (ctx->tx_rem_skb != NULL) {
+                                       dev_kfree_skb_any(ctx->tx_rem_skb);
+                                       ctx->netdev->stats.tx_dropped++;
+                               }
+                               ctx->tx_rem_skb = skb;
+                               skb = NULL;
+
+                               /* loop one more time */
+                               timeout = 1;
+                       }
+                       break;
+               }
+
+               memcpy(((u8 *)skb_out->data) + offset, skb->data, skb->len);
+
+               ctx->tx_ncm.dpe16[n].wDatagramLength = cpu_to_le16(skb->len);
+               ctx->tx_ncm.dpe16[n].wDatagramIndex = cpu_to_le16(offset);
+
+               /* update offset */
+               offset += skb->len;
+
+               /* store last valid offset before alignment */
+               last_offset = offset;
+
+               /* align offset correctly */
+               offset = ALIGN(offset, ctx->tx_modulus) + ctx->tx_remainder;
+
+               /* zero padding */
+               cdc_ncm_zero_fill(skb_out->data, last_offset, offset,
+                                                               ctx->tx_max);
+               dev_kfree_skb_any(skb);
+               skb = NULL;
+       }
+
+       /* free up any dangling skb */
+       if (skb != NULL) {
+               dev_kfree_skb_any(skb);
+               skb = NULL;
+               ctx->netdev->stats.tx_dropped++;
+       }
+
+       ctx->tx_curr_frame_num = n;
+
+       if (n == 0) {
+               /* wait for more frames */
+               /* push variables */
+               ctx->tx_curr_skb = skb_out;
+               ctx->tx_curr_offset = offset;
+               ctx->tx_curr_last_offset = last_offset;
+               goto exit_no_skb;
+
+       } else if ((n < ctx->tx_max_datagrams) && (timeout == 0)) {
+               /* wait for more frames */
+               /* push variables */
+               ctx->tx_curr_skb = skb_out;
+               ctx->tx_curr_offset = offset;
+               ctx->tx_curr_last_offset = last_offset;
+               /* set the pending count */
+               if (n < CDC_NCM_RESTART_TIMER_DATAGRAM_CNT)
+                       ctx->tx_timer_pending = 2;
+               goto exit_no_skb;
+
+       } else {
+               /* frame goes out */
+               /* variables will be reset at next call */
+       }
+
+       /* check for overflow */
+       if (last_offset > ctx->tx_max)
+               last_offset = ctx->tx_max;
+
+       /* revert offset */
+       offset = last_offset;
+
+       /*
+        * If collected data size is less or equal CDC_NCM_MIN_TX_PKT bytes,
+        * we send buffers as it is. If we get more data, it would be more
+        * efficient for USB HS mobile device with DMA engine to receive a full
+        * size NTB, than canceling DMA transfer and receiving a short packet.
+        */
+       if (offset > CDC_NCM_MIN_TX_PKT)
+               offset = ctx->tx_max;
+
+       /* final zero padding */
+       cdc_ncm_zero_fill(skb_out->data, last_offset, offset, ctx->tx_max);
+
+       /* store last offset */
+       last_offset = offset;
+
+       if ((last_offset < ctx->tx_max) && ((last_offset %
+                       le16_to_cpu(ctx->out_ep->desc.wMaxPacketSize)) == 0)) {
+               /* force short packet */
+               *(((u8 *)skb_out->data) + last_offset) = 0;
+               last_offset++;
+       }
+
+       /* zero the rest of the DPEs plus the last NULL entry */
+       for (; n <= CDC_NCM_DPT_DATAGRAMS_MAX; n++) {
+               ctx->tx_ncm.dpe16[n].wDatagramLength = 0;
+               ctx->tx_ncm.dpe16[n].wDatagramIndex = 0;
+       }
+
+       /* fill out 16-bit NTB header */
+       ctx->tx_ncm.nth16.dwSignature = cpu_to_le32(USB_CDC_NCM_NTH16_SIGN);
+       ctx->tx_ncm.nth16.wHeaderLength =
+                                       cpu_to_le16(sizeof(ctx->tx_ncm.nth16));
+       ctx->tx_ncm.nth16.wSequence = cpu_to_le16(ctx->tx_seq);
+       ctx->tx_ncm.nth16.wBlockLength = cpu_to_le16(last_offset);
+       ctx->tx_ncm.nth16.wFpIndex = ALIGN(sizeof(struct usb_cdc_ncm_nth16),
+                                                       ctx->tx_ndp_modulus);
+
+       memcpy(skb_out->data, &(ctx->tx_ncm.nth16), sizeof(ctx->tx_ncm.nth16));
+       ctx->tx_seq++;
+
+       /* fill out 16-bit NDP table */
+       ctx->tx_ncm.ndp16.dwSignature =
+                               cpu_to_le32(USB_CDC_NCM_NDP16_NOCRC_SIGN);
+       rem = sizeof(ctx->tx_ncm.ndp16) + ((ctx->tx_curr_frame_num + 1) *
+                                       sizeof(struct usb_cdc_ncm_dpe16));
+       ctx->tx_ncm.ndp16.wLength = cpu_to_le16(rem);
+       ctx->tx_ncm.ndp16.wNextFpIndex = 0; /* reserved */
+
+       memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wFpIndex,
+                                               &(ctx->tx_ncm.ndp16),
+                                               sizeof(ctx->tx_ncm.ndp16));
+
+       memcpy(((u8 *)skb_out->data) + ctx->tx_ncm.nth16.wFpIndex +
+                                       sizeof(ctx->tx_ncm.ndp16),
+                                       &(ctx->tx_ncm.dpe16),
+                                       (ctx->tx_curr_frame_num + 1) *
+                                       sizeof(struct usb_cdc_ncm_dpe16));
+
+       /* set frame length */
+       skb_put(skb_out, last_offset);
+
+       /* return skb */
+       ctx->tx_curr_skb = NULL;
+       return skb_out;
+
+exit_no_skb:
+       return NULL;
+}
+
+static void cdc_ncm_tx_timeout_start(struct cdc_ncm_ctx *ctx)
+{
+       /* start timer, if not already started */
+       if (timer_pending(&ctx->tx_timer) == 0) {
+               ctx->tx_timer.function = &cdc_ncm_tx_timeout;
+               ctx->tx_timer.data = (unsigned long)ctx;
+               ctx->tx_timer.expires = jiffies + ((HZ + 999) / 1000);
+               add_timer(&ctx->tx_timer);
+       }
+}
+
+static void cdc_ncm_tx_timeout(unsigned long arg)
+{
+       struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)arg;
+       u8 restart;
+
+       spin_lock(&ctx->mtx);
+       if (ctx->tx_timer_pending != 0) {
+               ctx->tx_timer_pending--;
+               restart = 1;
+       } else
+               restart = 0;
+
+       spin_unlock(&ctx->mtx);
+
+       if (restart)
+               cdc_ncm_tx_timeout_start(ctx);
+       else if (ctx->netdev != NULL)
+               usbnet_start_xmit(NULL, ctx->netdev);
+}
+
+static struct sk_buff *
+cdc_ncm_tx_fixup(struct usbnet *dev, struct sk_buff *skb, gfp_t flags)
+{
+       struct sk_buff *skb_out;
+       struct cdc_ncm_ctx *ctx = (struct cdc_ncm_ctx *)dev->data[0];
+       u8 need_timer = 0;
+
+       /*
+        * The Ethernet API we are using does not support transmitting
+        * multiple Ethernet frames in a single call. This driver will
+        * accumulate multiple Ethernet frames and send out a larger
+        * USB frame when the USB buffer is full or when a single jiffies
+        * timeout happens.
+        */
+       if (ctx == NULL)
+               goto error;
+
+       spin_lock(&ctx->mtx);
+       skb_out = cdc_ncm_fill_tx_frame(ctx, skb);
+       if (ctx->tx_curr_skb != NULL)
+               need_timer = 1;
+       spin_unlock(&ctx->mtx);
+
+       /* Start timer, if there is a remaining skb */
+       if (need_timer)
+               cdc_ncm_tx_timeout_start(ctx);
+
+       if (skb_out)
+               dev->net->stats.tx_packets += ctx->tx_curr_frame_num;
+       return skb_out;
+
+error:
+       if (skb != NULL)
+               dev_kfree_skb_any(skb);
+
+       return NULL;
+}
+
+static int cdc_ncm_rx_fixup(struct usbnet *dev, struct sk_buff *skb_in)
+{
+       struct sk_buff *skb;
+       struct cdc_ncm_ctx *ctx;
+       int sumlen;
+       int actlen;
+       int temp;
+       int nframes;
+       int x;
+       int offset;
+
+       ctx = (struct cdc_ncm_ctx *)dev->data[0];
+       if (ctx == NULL)
+               goto error;
+
+       actlen = skb_in->len;
+       sumlen = CDC_NCM_NTB_MAX_SIZE_RX;
+
+       if (actlen < (sizeof(ctx->rx_ncm.nth16) + sizeof(ctx->rx_ncm.ndp16))) {
+               pr_debug("frame too short\n");
+               goto error;
+       }
+
+       memcpy(&(ctx->rx_ncm.nth16), ((u8 *)skb_in->data),
+                                               sizeof(ctx->rx_ncm.nth16));
+
+       if (le32_to_cpu(ctx->rx_ncm.nth16.dwSignature) !=
+           USB_CDC_NCM_NTH16_SIGN) {
+               pr_debug("invalid NTH16 signature <%u>\n",
+                        le32_to_cpu(ctx->rx_ncm.nth16.dwSignature));
+               goto error;
+       }
+
+       temp = le16_to_cpu(ctx->rx_ncm.nth16.wBlockLength);
+       if (temp > sumlen) {
+               pr_debug("unsupported NTB block length %u/%u\n", temp, sumlen);
+               goto error;
+       }
+
+       temp = le16_to_cpu(ctx->rx_ncm.nth16.wFpIndex);
+       if ((temp + sizeof(ctx->rx_ncm.ndp16)) > actlen) {
+               pr_debug("invalid DPT16 index\n");
+               goto error;
+       }
+
+       memcpy(&(ctx->rx_ncm.ndp16), ((u8 *)skb_in->data) + temp,
+                                               sizeof(ctx->rx_ncm.ndp16));
+
+       if (le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature) !=
+           USB_CDC_NCM_NDP16_NOCRC_SIGN) {
+               pr_debug("invalid DPT16 signature <%u>\n",
+                        le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature));
+               goto error;
+       }
+
+       if (le16_to_cpu(ctx->rx_ncm.ndp16.wLength) <
+           USB_CDC_NCM_NDP16_LENGTH_MIN) {
+               pr_debug("invalid DPT16 length <%u>\n",
+                        le32_to_cpu(ctx->rx_ncm.ndp16.dwSignature));
+               goto error;
+       }
+
+       nframes = ((le16_to_cpu(ctx->rx_ncm.ndp16.wLength) -
+                                       sizeof(struct usb_cdc_ncm_ndp16)) /
+                                       sizeof(struct usb_cdc_ncm_dpe16));
+       nframes--; /* we process NDP entries except for the last one */
+
+       pr_debug("nframes = %u\n", nframes);
+
+       temp += sizeof(ctx->rx_ncm.ndp16);
+
+       if ((temp + nframes * (sizeof(struct usb_cdc_ncm_dpe16))) > actlen) {
+               pr_debug("Invalid nframes = %d\n", nframes);
+               goto error;
+       }
+
+       if (nframes > CDC_NCM_DPT_DATAGRAMS_MAX) {
+               pr_debug("Truncating number of frames from %u to %u\n",
+                                       nframes, CDC_NCM_DPT_DATAGRAMS_MAX);
+               nframes = CDC_NCM_DPT_DATAGRAMS_MAX;
+       }
+
+       memcpy(&(ctx->rx_ncm.dpe16), ((u8 *)skb_in->data) + temp,
+                               nframes * (sizeof(struct usb_cdc_ncm_dpe16)));
+
+       for (x = 0; x < nframes; x++) {
+               offset = le16_to_cpu(ctx->rx_ncm.dpe16[x].wDatagramIndex);
+               temp = le16_to_cpu(ctx->rx_ncm.dpe16[x].wDatagramLength);
+
+               /*
+                * CDC NCM ch. 3.7
+                * All entries after first NULL entry are to be ignored
+                */
+               if ((offset == 0) || (temp == 0)) {
+                       if (!x)
+                               goto error; /* empty NTB */
+                       break;
+               }
+
+               /* sanity checking */
+               if (((offset + temp) > actlen) ||
+                   (temp > CDC_NCM_MAX_DATAGRAM_SIZE) || (temp < ETH_HLEN)) {
+                       pr_debug("invalid frame detected (ignored)"
+                               "offset[%u]=%u, length=%u, skb=%p\n",
+                                                       x, offset, temp, skb);
+                       if (!x)
+                               goto error;
+                       break;
+
+               } else {
+                       skb = skb_clone(skb_in, GFP_ATOMIC);
+                       skb->len = temp;
+                       skb->data = ((u8 *)skb_in->data) + offset;
+                       skb_set_tail_pointer(skb, temp);
+                       usbnet_skb_return(dev, skb);
+               }
+       }
+       return 1;
+error:
+       return 0;
+}
+
+static void
+cdc_ncm_speed_change(struct cdc_ncm_ctx *ctx,
+                    struct connection_speed_change *data)
+{
+       uint32_t rx_speed = le32_to_cpu(data->USBitRate);
+       uint32_t tx_speed = le32_to_cpu(data->DSBitRate);
+
+       /*
+        * Currently the USB-NET API does not support reporting the actual
+        * device speed. Do print it instead.
+        */
+       if ((tx_speed != ctx->tx_speed) || (rx_speed != ctx->rx_speed)) {
+               ctx->tx_speed = tx_speed;
+               ctx->rx_speed = rx_speed;
+
+               if ((tx_speed > 1000000) && (rx_speed > 1000000)) {
+                       printk(KERN_INFO KBUILD_MODNAME
+                               ": %s: %u mbit/s downlink "
+                               "%u mbit/s uplink\n",
+                               ctx->netdev->name,
+                               (unsigned int)(rx_speed / 1000000U),
+                               (unsigned int)(tx_speed / 1000000U));
+               } else {
+                       printk(KERN_INFO KBUILD_MODNAME
+                               ": %s: %u kbit/s downlink "
+                               "%u kbit/s uplink\n",
+                               ctx->netdev->name,
+                               (unsigned int)(rx_speed / 1000U),
+                               (unsigned int)(tx_speed / 1000U));
+               }
+       }
+}
+
+static void cdc_ncm_status(struct usbnet *dev, struct urb *urb)
+{
+       struct cdc_ncm_ctx *ctx;
+       struct usb_cdc_notification *event;
+
+       ctx = (struct cdc_ncm_ctx *)dev->data[0];
+
+       if (urb->actual_length < sizeof(*event))
+               return;
+
+       /* test for split data in 8-byte chunks */
+       if (test_and_clear_bit(EVENT_STS_SPLIT, &dev->flags)) {
+               cdc_ncm_speed_change(ctx,
+                     (struct connection_speed_change *)urb->transfer_buffer);
+               return;
+       }
+
+       event = urb->transfer_buffer;
+
+       switch (event->bNotificationType) {
+       case USB_CDC_NOTIFY_NETWORK_CONNECTION:
+               /*
+                * According to the CDC NCM specification ch.7.1
+                * USB_CDC_NOTIFY_NETWORK_CONNECTION notification shall be
+                * sent by device after USB_CDC_NOTIFY_SPEED_CHANGE.
+                */
+               ctx->connected = event->wValue;
+
+               printk(KERN_INFO KBUILD_MODNAME ": %s: network connection:"
+                       " %sconnected\n",
+                       ctx->netdev->name, ctx->connected ? "" : "dis");
+
+               if (ctx->connected)
+                       netif_carrier_on(dev->net);
+               else {
+                       netif_carrier_off(dev->net);
+                       ctx->tx_speed = ctx->rx_speed = 0;
+               }
+               break;
+
+       case USB_CDC_NOTIFY_SPEED_CHANGE:
+               if (urb->actual_length <
+                   (sizeof(*event) + sizeof(struct connection_speed_change)))
+                       set_bit(EVENT_STS_SPLIT, &dev->flags);
+               else
+                       cdc_ncm_speed_change(ctx,
+                               (struct connection_speed_change *) &event[1]);
+               break;
+
+       default:
+               dev_err(&dev->udev->dev, "NCM: unexpected "
+                       "notification 0x%02x!\n", event->bNotificationType);
+               break;
+       }
+}
+
+static int cdc_ncm_check_connect(struct usbnet *dev)
+{
+       struct cdc_ncm_ctx *ctx;
+
+       ctx = (struct cdc_ncm_ctx *)dev->data[0];
+       if (ctx == NULL)
+               return 1;       /* disconnected */
+
+       return !ctx->connected;
+}
+
+static int
+cdc_ncm_probe(struct usb_interface *udev, const struct usb_device_id *prod)
+{
+       return usbnet_probe(udev, prod);
+}
+
+static void cdc_ncm_disconnect(struct usb_interface *intf)
+{
+       struct usbnet *dev = usb_get_intfdata(intf);
+
+       if (dev == NULL)
+               return;         /* already disconnected */
+
+       usbnet_disconnect(intf);
+}
+
+static int cdc_ncm_manage_power(struct usbnet *dev, int status)
+{
+       dev->intf->needs_remote_wakeup = status;
+       return 0;
+}
+
+static const struct driver_info cdc_ncm_info = {
+       .description = "CDC NCM",
+       .flags = FLAG_NO_SETINT | FLAG_MULTI_PACKET,
+       .bind = cdc_ncm_bind,
+       .unbind = cdc_ncm_unbind,
+       .check_connect = cdc_ncm_check_connect,
+       .manage_power = cdc_ncm_manage_power,
+       .status = cdc_ncm_status,
+       .rx_fixup = cdc_ncm_rx_fixup,
+       .tx_fixup = cdc_ncm_tx_fixup,
+};
+
+static struct usb_driver cdc_ncm_driver = {
+       .name = "cdc_ncm",
+       .id_table = cdc_devs,
+       .probe = cdc_ncm_probe,
+       .disconnect = cdc_ncm_disconnect,
+       .suspend = usbnet_suspend,
+       .resume = usbnet_resume,
+       .supports_autosuspend = 1,
+};
+
+static struct ethtool_ops cdc_ncm_ethtool_ops = {
+       .get_drvinfo = cdc_ncm_get_drvinfo,
+       .get_link = usbnet_get_link,
+       .get_msglevel = usbnet_get_msglevel,
+       .set_msglevel = usbnet_set_msglevel,
+       .get_settings = usbnet_get_settings,
+       .set_settings = usbnet_set_settings,
+       .nway_reset = usbnet_nway_reset,
+};
+
+static int __init cdc_ncm_init(void)
+{
+       printk(KERN_INFO KBUILD_MODNAME ": " DRIVER_VERSION "\n");
+       return usb_register(&cdc_ncm_driver);
+}
+
+module_init(cdc_ncm_init);
+
+static void __exit cdc_ncm_exit(void)
+{
+       usb_deregister(&cdc_ncm_driver);
+}
+
+module_exit(cdc_ncm_exit);
+
+MODULE_AUTHOR("Hans Petter Selasky");
+MODULE_DESCRIPTION("USB CDC NCM host driver");
+MODULE_LICENSE("Dual BSD/GPL");
index be8cc2a8e2137105ab85060472b748f4423f601d..93c6b5f62ac42bd8002e00d8e414befb0fb20f9b 100644 (file)
@@ -2993,12 +2993,14 @@ static int hso_probe(struct usb_interface *interface,
 
        case HSO_INTF_BULK:
                /* It's a regular bulk interface */
-               if (((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) &&
-                   !disable_net)
-                       hso_dev = hso_create_net_device(interface, port_spec);
-               else
+               if ((port_spec & HSO_PORT_MASK) == HSO_PORT_NETWORK) {
+                       if (!disable_net)
+                               hso_dev =
+                                   hso_create_net_device(interface, port_spec);
+               } else {
                        hso_dev =
                            hso_create_bulk_serial_device(interface, port_spec);
+               }
                if (!hso_dev)
                        goto exit;
                break;
index c04d49e31f814fe11d2f1b730dcba014afeb324c..cff74b81a7d2ccfdb566ea16901a2076d78964e5 100644 (file)
@@ -391,14 +391,19 @@ static inline void rx_process (struct usbnet *dev, struct sk_buff *skb)
                goto error;
        // else network stack removes extra byte if we forced a short packet
 
-       if (skb->len)
-               usbnet_skb_return (dev, skb);
-       else {
-               netif_dbg(dev, rx_err, dev->net, "drop\n");
-error:
-               dev->net->stats.rx_errors++;
-               skb_queue_tail (&dev->done, skb);
+       if (skb->len) {
+               /* all data was already cloned from skb inside the driver */
+               if (dev->driver_info->flags & FLAG_MULTI_PACKET)
+                       dev_kfree_skb_any(skb);
+               else
+                       usbnet_skb_return(dev, skb);
+               return;
        }
+
+       netif_dbg(dev, rx_err, dev->net, "drop\n");
+error:
+       dev->net->stats.rx_errors++;
+       skb_queue_tail(&dev->done, skb);
 }
 
 /*-------------------------------------------------------------------------*/
@@ -971,7 +976,8 @@ static void tx_complete (struct urb *urb)
        struct usbnet           *dev = entry->dev;
 
        if (urb->status == 0) {
-               dev->net->stats.tx_packets++;
+               if (!(dev->driver_info->flags & FLAG_MULTI_PACKET))
+                       dev->net->stats.tx_packets++;
                dev->net->stats.tx_bytes += entry->length;
        } else {
                dev->net->stats.tx_errors++;
@@ -1044,8 +1050,13 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
        if (info->tx_fixup) {
                skb = info->tx_fixup (dev, skb, GFP_ATOMIC);
                if (!skb) {
-                       netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n");
-                       goto drop;
+                       if (netif_msg_tx_err(dev)) {
+                               netif_dbg(dev, tx_err, dev->net, "can't tx_fixup skb\n");
+                               goto drop;
+                       } else {
+                               /* cdc_ncm collected packet; waits for more */
+                               goto not_drop;
+                       }
                }
        }
        length = skb->len;
@@ -1067,13 +1078,18 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
        /* don't assume the hardware handles USB_ZERO_PACKET
         * NOTE:  strictly conforming cdc-ether devices should expect
         * the ZLP here, but ignore the one-byte packet.
+        * NOTE2: CDC NCM specification is different from CDC ECM when
+        * handling ZLP/short packets, so cdc_ncm driver will make short
+        * packet itself if needed.
         */
        if (length % dev->maxpacket == 0) {
                if (!(info->flags & FLAG_SEND_ZLP)) {
-                       urb->transfer_buffer_length++;
-                       if (skb_tailroom(skb)) {
-                               skb->data[skb->len] = 0;
-                               __skb_put(skb, 1);
+                       if (!(info->flags & FLAG_MULTI_PACKET)) {
+                               urb->transfer_buffer_length++;
+                               if (skb_tailroom(skb)) {
+                                       skb->data[skb->len] = 0;
+                                       __skb_put(skb, 1);
+                               }
                        }
                } else
                        urb->transfer_flags |= URB_ZERO_PACKET;
@@ -1122,6 +1138,7 @@ netdev_tx_t usbnet_start_xmit (struct sk_buff *skb,
                netif_dbg(dev, tx_err, dev->net, "drop, code %d\n", retval);
 drop:
                dev->net->stats.tx_dropped++;
+not_drop:
                if (skb)
                        dev_kfree_skb_any (skb);
                usb_free_urb (urb);
index 4930f9dbc493d50d2b46f7829d62541bc8b1e646..5e7f069eab533e75cf950294648a7967da104bb0 100644 (file)
@@ -30,8 +30,8 @@
 */
 
 #define DRV_NAME       "via-rhine"
-#define DRV_VERSION    "1.4.3"
-#define DRV_RELDATE    "2007-03-06"
+#define DRV_VERSION    "1.5.0"
+#define DRV_RELDATE    "2010-10-09"
 
 
 /* A few user-configurable values.
@@ -100,6 +100,7 @@ static const int multicast_filter_limit = 32;
 #include <linux/mii.h>
 #include <linux/ethtool.h>
 #include <linux/crc32.h>
+#include <linux/if_vlan.h>
 #include <linux/bitops.h>
 #include <linux/workqueue.h>
 #include <asm/processor.h>     /* Processor type for cache alignment. */
@@ -133,6 +134,9 @@ MODULE_PARM_DESC(debug, "VIA Rhine debug level (0-7)");
 MODULE_PARM_DESC(rx_copybreak, "VIA Rhine copy breakpoint for copy-only-tiny-frames");
 MODULE_PARM_DESC(avoid_D3, "Avoid power state D3 (work-around for broken BIOSes)");
 
+#define MCAM_SIZE      32
+#define VCAM_SIZE      32
+
 /*
                Theory of Operation
 
@@ -279,15 +283,16 @@ MODULE_DEVICE_TABLE(pci, rhine_pci_tbl);
 /* Offsets to the device registers. */
 enum register_offsets {
        StationAddr=0x00, RxConfig=0x06, TxConfig=0x07, ChipCmd=0x08,
-       ChipCmd1=0x09,
+       ChipCmd1=0x09, TQWake=0x0A,
        IntrStatus=0x0C, IntrEnable=0x0E,
        MulticastFilter0=0x10, MulticastFilter1=0x14,
        RxRingPtr=0x18, TxRingPtr=0x1C, GFIFOTest=0x54,
-       MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E,
+       MIIPhyAddr=0x6C, MIIStatus=0x6D, PCIBusConfig=0x6E, PCIBusConfig1=0x6F,
        MIICmd=0x70, MIIRegAddr=0x71, MIIData=0x72, MACRegEEcsr=0x74,
        ConfigA=0x78, ConfigB=0x79, ConfigC=0x7A, ConfigD=0x7B,
        RxMissed=0x7C, RxCRCErrs=0x7E, MiscCmd=0x81,
        StickyHW=0x83, IntrStatus2=0x84,
+       CamMask=0x88, CamCon=0x92, CamAddr=0x93,
        WOLcrSet=0xA0, PwcfgSet=0xA1, WOLcgSet=0xA3, WOLcrClr=0xA4,
        WOLcrClr1=0xA6, WOLcgClr=0xA7,
        PwrcsrSet=0xA8, PwrcsrSet1=0xA9, PwrcsrClr=0xAC, PwrcsrClr1=0xAD,
@@ -299,6 +304,40 @@ enum backoff_bits {
        BackCaptureEffect=0x04, BackRandom=0x08
 };
 
+/* Bits in the TxConfig (TCR) register */
+enum tcr_bits {
+       TCR_PQEN=0x01,
+       TCR_LB0=0x02,           /* loopback[0] */
+       TCR_LB1=0x04,           /* loopback[1] */
+       TCR_OFSET=0x08,
+       TCR_RTGOPT=0x10,
+       TCR_RTFT0=0x20,
+       TCR_RTFT1=0x40,
+       TCR_RTSF=0x80,
+};
+
+/* Bits in the CamCon (CAMC) register */
+enum camcon_bits {
+       CAMC_CAMEN=0x01,
+       CAMC_VCAMSL=0x02,
+       CAMC_CAMWR=0x04,
+       CAMC_CAMRD=0x08,
+};
+
+/* Bits in the PCIBusConfig1 (BCR1) register */
+enum bcr1_bits {
+       BCR1_POT0=0x01,
+       BCR1_POT1=0x02,
+       BCR1_POT2=0x04,
+       BCR1_CTFT0=0x08,
+       BCR1_CTFT1=0x10,
+       BCR1_CTSF=0x20,
+       BCR1_TXQNOBK=0x40,      /* for VT6105 */
+       BCR1_VIDFR=0x80,        /* for VT6105 */
+       BCR1_MED0=0x40,         /* for VT6102 */
+       BCR1_MED1=0x80,         /* for VT6102 */
+};
+
 #ifdef USE_MMIO
 /* Registers we check that mmio and reg are the same. */
 static const int mmio_verify_registers[] = {
@@ -356,6 +395,11 @@ enum desc_status_bits {
        DescOwn=0x80000000
 };
 
+/* Bits in *_desc.*_length */
+enum desc_length_bits {
+       DescTag=0x00010000
+};
+
 /* Bits in ChipCmd. */
 enum chip_cmd_bits {
        CmdInit=0x01, CmdStart=0x02, CmdStop=0x04, CmdRxOn=0x08,
@@ -365,6 +409,9 @@ enum chip_cmd_bits {
 };
 
 struct rhine_private {
+       /* Bit mask for configured VLAN ids */
+       unsigned long active_vlans[BITS_TO_LONGS(VLAN_N_VID)];
+
        /* Descriptor rings */
        struct rx_desc *rx_ring;
        struct tx_desc *tx_ring;
@@ -405,6 +452,23 @@ struct rhine_private {
        void __iomem *base;
 };
 
+#define BYTE_REG_BITS_ON(x, p)      do { iowrite8((ioread8((p))|(x)), (p)); } while (0)
+#define WORD_REG_BITS_ON(x, p)      do { iowrite16((ioread16((p))|(x)), (p)); } while (0)
+#define DWORD_REG_BITS_ON(x, p)     do { iowrite32((ioread32((p))|(x)), (p)); } while (0)
+
+#define BYTE_REG_BITS_IS_ON(x, p)   (ioread8((p)) & (x))
+#define WORD_REG_BITS_IS_ON(x, p)   (ioread16((p)) & (x))
+#define DWORD_REG_BITS_IS_ON(x, p)  (ioread32((p)) & (x))
+
+#define BYTE_REG_BITS_OFF(x, p)     do { iowrite8(ioread8((p)) & (~(x)), (p)); } while (0)
+#define WORD_REG_BITS_OFF(x, p)     do { iowrite16(ioread16((p)) & (~(x)), (p)); } while (0)
+#define DWORD_REG_BITS_OFF(x, p)    do { iowrite32(ioread32((p)) & (~(x)), (p)); } while (0)
+
+#define BYTE_REG_BITS_SET(x, m, p)   do { iowrite8((ioread8((p)) & (~(m)))|(x), (p)); } while (0)
+#define WORD_REG_BITS_SET(x, m, p)   do { iowrite16((ioread16((p)) & (~(m)))|(x), (p)); } while (0)
+#define DWORD_REG_BITS_SET(x, m, p)  do { iowrite32((ioread32((p)) & (~(m)))|(x), (p)); } while (0)
+
+
 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  rhine_open(struct net_device *dev);
@@ -422,6 +486,14 @@ static int netdev_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 static const struct ethtool_ops netdev_ethtool_ops;
 static int  rhine_close(struct net_device *dev);
 static void rhine_shutdown (struct pci_dev *pdev);
+static void rhine_vlan_rx_add_vid(struct net_device *dev, unsigned short vid);
+static void rhine_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid);
+static void rhine_set_cam(void __iomem *ioaddr, int idx, u8 *addr);
+static void rhine_set_vlan_cam(void __iomem *ioaddr, int idx, u8 *addr);
+static void rhine_set_cam_mask(void __iomem *ioaddr, u32 mask);
+static void rhine_set_vlan_cam_mask(void __iomem *ioaddr, u32 mask);
+static void rhine_init_cam_filter(struct net_device *dev);
+static void rhine_update_vcam(struct net_device *dev);
 
 #define RHINE_WAIT_FOR(condition) do {                                 \
        int i=1024;                                                     \
@@ -629,6 +701,8 @@ static const struct net_device_ops rhine_netdev_ops = {
        .ndo_set_mac_address     = eth_mac_addr,
        .ndo_do_ioctl            = netdev_ioctl,
        .ndo_tx_timeout          = rhine_tx_timeout,
+       .ndo_vlan_rx_add_vid     = rhine_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid    = rhine_vlan_rx_kill_vid,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller     = rhine_poll,
 #endif
@@ -795,6 +869,10 @@ static int __devinit rhine_init_one(struct pci_dev *pdev,
        if (rp->quirks & rqRhineI)
                dev->features |= NETIF_F_SG|NETIF_F_HW_CSUM;
 
+       if (pdev->revision >= VT6105M)
+               dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX |
+               NETIF_F_HW_VLAN_FILTER;
+
        /* dev->name not defined before register_netdev()! */
        rc = register_netdev(dev);
        if (rc)
@@ -1040,6 +1118,167 @@ static void rhine_set_carrier(struct mii_if_info *mii)
                       netif_carrier_ok(mii->dev));
 }
 
+/**
+ * rhine_set_cam - set CAM multicast filters
+ * @ioaddr: register block of this Rhine
+ * @idx: multicast CAM index [0..MCAM_SIZE-1]
+ * @addr: multicast address (6 bytes)
+ *
+ * Load addresses into multicast filters.
+ */
+static void rhine_set_cam(void __iomem *ioaddr, int idx, u8 *addr)
+{
+       int i;
+
+       iowrite8(CAMC_CAMEN, ioaddr + CamCon);
+       wmb();
+
+       /* Paranoid -- idx out of range should never happen */
+       idx &= (MCAM_SIZE - 1);
+
+       iowrite8((u8) idx, ioaddr + CamAddr);
+
+       for (i = 0; i < 6; i++, addr++)
+               iowrite8(*addr, ioaddr + MulticastFilter0 + i);
+       udelay(10);
+       wmb();
+
+       iowrite8(CAMC_CAMWR | CAMC_CAMEN, ioaddr + CamCon);
+       udelay(10);
+
+       iowrite8(0, ioaddr + CamCon);
+}
+
+/**
+ * rhine_set_vlan_cam - set CAM VLAN filters
+ * @ioaddr: register block of this Rhine
+ * @idx: VLAN CAM index [0..VCAM_SIZE-1]
+ * @addr: VLAN ID (2 bytes)
+ *
+ * Load addresses into VLAN filters.
+ */
+static void rhine_set_vlan_cam(void __iomem *ioaddr, int idx, u8 *addr)
+{
+       iowrite8(CAMC_CAMEN | CAMC_VCAMSL, ioaddr + CamCon);
+       wmb();
+
+       /* Paranoid -- idx out of range should never happen */
+       idx &= (VCAM_SIZE - 1);
+
+       iowrite8((u8) idx, ioaddr + CamAddr);
+
+       iowrite16(*((u16 *) addr), ioaddr + MulticastFilter0 + 6);
+       udelay(10);
+       wmb();
+
+       iowrite8(CAMC_CAMWR | CAMC_CAMEN, ioaddr + CamCon);
+       udelay(10);
+
+       iowrite8(0, ioaddr + CamCon);
+}
+
+/**
+ * rhine_set_cam_mask - set multicast CAM mask
+ * @ioaddr: register block of this Rhine
+ * @mask: multicast CAM mask
+ *
+ * Mask sets multicast filters active/inactive.
+ */
+static void rhine_set_cam_mask(void __iomem *ioaddr, u32 mask)
+{
+       iowrite8(CAMC_CAMEN, ioaddr + CamCon);
+       wmb();
+
+       /* write mask */
+       iowrite32(mask, ioaddr + CamMask);
+
+       /* disable CAMEN */
+       iowrite8(0, ioaddr + CamCon);
+}
+
+/**
+ * rhine_set_vlan_cam_mask - set VLAN CAM mask
+ * @ioaddr: register block of this Rhine
+ * @mask: VLAN CAM mask
+ *
+ * Mask sets VLAN filters active/inactive.
+ */
+static void rhine_set_vlan_cam_mask(void __iomem *ioaddr, u32 mask)
+{
+       iowrite8(CAMC_CAMEN | CAMC_VCAMSL, ioaddr + CamCon);
+       wmb();
+
+       /* write mask */
+       iowrite32(mask, ioaddr + CamMask);
+
+       /* disable CAMEN */
+       iowrite8(0, ioaddr + CamCon);
+}
+
+/**
+ * rhine_init_cam_filter - initialize CAM filters
+ * @dev: network device
+ *
+ * Initialize (disable) hardware VLAN and multicast support on this
+ * Rhine.
+ */
+static void rhine_init_cam_filter(struct net_device *dev)
+{
+       struct rhine_private *rp = netdev_priv(dev);
+       void __iomem *ioaddr = rp->base;
+
+       /* Disable all CAMs */
+       rhine_set_vlan_cam_mask(ioaddr, 0);
+       rhine_set_cam_mask(ioaddr, 0);
+
+       /* disable hardware VLAN support */
+       BYTE_REG_BITS_ON(TCR_PQEN, ioaddr + TxConfig);
+       BYTE_REG_BITS_OFF(BCR1_VIDFR, ioaddr + PCIBusConfig1);
+}
+
+/**
+ * rhine_update_vcam - update VLAN CAM filters
+ * @rp: rhine_private data of this Rhine
+ *
+ * Update VLAN CAM filters to match configuration change.
+ */
+static void rhine_update_vcam(struct net_device *dev)
+{
+       struct rhine_private *rp = netdev_priv(dev);
+       void __iomem *ioaddr = rp->base;
+       u16 vid;
+       u32 vCAMmask = 0;       /* 32 vCAMs (6105M and better) */
+       unsigned int i = 0;
+
+       for_each_set_bit(vid, rp->active_vlans, VLAN_N_VID) {
+               rhine_set_vlan_cam(ioaddr, i, (u8 *)&vid);
+               vCAMmask |= 1 << i;
+               if (++i >= VCAM_SIZE)
+                       break;
+       }
+       rhine_set_vlan_cam_mask(ioaddr, vCAMmask);
+}
+
+static void rhine_vlan_rx_add_vid(struct net_device *dev, unsigned short vid)
+{
+       struct rhine_private *rp = netdev_priv(dev);
+
+       spin_lock_irq(&rp->lock);
+       set_bit(vid, rp->active_vlans);
+       rhine_update_vcam(dev);
+       spin_unlock_irq(&rp->lock);
+}
+
+static void rhine_vlan_rx_kill_vid(struct net_device *dev, unsigned short vid)
+{
+       struct rhine_private *rp = netdev_priv(dev);
+
+       spin_lock_irq(&rp->lock);
+       clear_bit(vid, rp->active_vlans);
+       rhine_update_vcam(dev);
+       spin_unlock_irq(&rp->lock);
+}
+
 static void init_registers(struct net_device *dev)
 {
        struct rhine_private *rp = netdev_priv(dev);
@@ -1061,6 +1300,9 @@ static void init_registers(struct net_device *dev)
 
        rhine_set_rx_mode(dev);
 
+       if (rp->pdev->revision >= VT6105M)
+               rhine_init_cam_filter(dev);
+
        napi_enable(&rp->napi);
 
        /* Enable interrupts by setting the interrupt mask. */
@@ -1276,16 +1518,28 @@ static netdev_tx_t rhine_start_tx(struct sk_buff *skb,
        rp->tx_ring[entry].desc_length =
                cpu_to_le32(TXDESC | (skb->len >= ETH_ZLEN ? skb->len : ETH_ZLEN));
 
+       if (unlikely(vlan_tx_tag_present(skb))) {
+               rp->tx_ring[entry].tx_status = cpu_to_le32((vlan_tx_tag_get(skb)) << 16);
+               /* request tagging */
+               rp->tx_ring[entry].desc_length |= cpu_to_le32(0x020000);
+       }
+       else
+               rp->tx_ring[entry].tx_status = 0;
+
        /* lock eth irq */
        spin_lock_irqsave(&rp->lock, flags);
        wmb();
-       rp->tx_ring[entry].tx_status = cpu_to_le32(DescOwn);
+       rp->tx_ring[entry].tx_status |= cpu_to_le32(DescOwn);
        wmb();
 
        rp->cur_tx++;
 
        /* Non-x86 Todo: explicitly flush cache lines here. */
 
+       if (vlan_tx_tag_present(skb))
+               /* Tx queues are bits 7-0 (first Tx queue: bit 7) */
+               BYTE_REG_BITS_ON(1 << 7, ioaddr + TQWake);
+
        /* Wake the potentially-idle transmit channel */
        iowrite8(ioread8(ioaddr + ChipCmd1) | Cmd1TxDemand,
               ioaddr + ChipCmd1);
@@ -1437,6 +1691,21 @@ static void rhine_tx(struct net_device *dev)
        spin_unlock(&rp->lock);
 }
 
+/**
+ * rhine_get_vlan_tci - extract TCI from Rx data buffer
+ * @skb: pointer to sk_buff
+ * @data_size: used data area of the buffer including CRC
+ *
+ * If hardware VLAN tag extraction is enabled and the chip indicates a 802.1Q
+ * packet, the extracted 802.1Q header (2 bytes TPID + 2 bytes TCI) is 4-byte
+ * aligned following the CRC.
+ */
+static inline u16 rhine_get_vlan_tci(struct sk_buff *skb, int data_size)
+{
+       u8 *trailer = (u8 *)skb->data + ((data_size + 3) & ~3) + 2;
+       return ntohs(*(u16 *)trailer);
+}
+
 /* Process up to limit frames from receive ring */
 static int rhine_rx(struct net_device *dev, int limit)
 {
@@ -1454,6 +1723,7 @@ static int rhine_rx(struct net_device *dev, int limit)
        for (count = 0; count < limit; ++count) {
                struct rx_desc *desc = rp->rx_head_desc;
                u32 desc_status = le32_to_cpu(desc->rx_status);
+               u32 desc_length = le32_to_cpu(desc->desc_length);
                int data_size = desc_status >> 16;
 
                if (desc_status & DescOwn)
@@ -1498,6 +1768,7 @@ static int rhine_rx(struct net_device *dev, int limit)
                        struct sk_buff *skb = NULL;
                        /* Length should omit the CRC */
                        int pkt_len = data_size - 4;
+                       u16 vlan_tci = 0;
 
                        /* Check if the packet is long enough to accept without
                           copying to a minimally-sized skbuff. */
@@ -1532,7 +1803,14 @@ static int rhine_rx(struct net_device *dev, int limit)
                                                 rp->rx_buf_sz,
                                                 PCI_DMA_FROMDEVICE);
                        }
+
+                       if (unlikely(desc_length & DescTag))
+                               vlan_tci = rhine_get_vlan_tci(skb, data_size);
+
                        skb->protocol = eth_type_trans(skb, dev);
+
+                       if (unlikely(desc_length & DescTag))
+                               __vlan_hwaccel_put_tag(skb, vlan_tci);
                        netif_receive_skb(skb);
                        dev->stats.rx_bytes += pkt_len;
                        dev->stats.rx_packets++;
@@ -1596,6 +1874,11 @@ static void rhine_restart_tx(struct net_device *dev) {
 
                iowrite8(ioread8(ioaddr + ChipCmd) | CmdTxOn,
                       ioaddr + ChipCmd);
+
+               if (rp->tx_ring[entry].desc_length & cpu_to_le32(0x020000))
+                       /* Tx queues are bits 7-0 (first Tx queue: bit 7) */
+                       BYTE_REG_BITS_ON(1 << 7, ioaddr + TQWake);
+
                iowrite8(ioread8(ioaddr + ChipCmd1) | Cmd1TxDemand,
                       ioaddr + ChipCmd1);
                IOSYNC;
@@ -1631,7 +1914,7 @@ static void rhine_error(struct net_device *dev, int intr_status)
        }
        if (intr_status & IntrTxUnderrun) {
                if (rp->tx_thresh < 0xE0)
-                       iowrite8(rp->tx_thresh += 0x20, ioaddr + TxConfig);
+                       BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig);
                if (debug > 1)
                        printk(KERN_INFO "%s: Transmitter underrun, Tx "
                               "threshold now %2.2x.\n",
@@ -1646,7 +1929,7 @@ static void rhine_error(struct net_device *dev, int intr_status)
            (intr_status & (IntrTxAborted |
             IntrTxUnderrun | IntrTxDescRace)) == 0) {
                if (rp->tx_thresh < 0xE0) {
-                       iowrite8(rp->tx_thresh += 0x20, ioaddr + TxConfig);
+                       BYTE_REG_BITS_SET((rp->tx_thresh += 0x20), 0x80, ioaddr + TxConfig);
                }
                if (debug > 1)
                        printk(KERN_INFO "%s: Unspecified error. Tx "
@@ -1688,7 +1971,8 @@ static void rhine_set_rx_mode(struct net_device *dev)
        struct rhine_private *rp = netdev_priv(dev);
        void __iomem *ioaddr = rp->base;
        u32 mc_filter[2];       /* Multicast hash filter */
-       u8 rx_mode;             /* Note: 0x02=accept runt, 0x01=accept errs */
+       u8 rx_mode = 0x0C;      /* Note: 0x02=accept runt, 0x01=accept errs */
+       struct netdev_hw_addr *ha;
 
        if (dev->flags & IFF_PROMISC) {         /* Set promiscuous. */
                rx_mode = 0x1C;
@@ -1699,10 +1983,18 @@ static void rhine_set_rx_mode(struct net_device *dev)
                /* Too many to match, or accept all multicasts. */
                iowrite32(0xffffffff, ioaddr + MulticastFilter0);
                iowrite32(0xffffffff, ioaddr + MulticastFilter1);
-               rx_mode = 0x0C;
+       } else if (rp->pdev->revision >= VT6105M) {
+               int i = 0;
+               u32 mCAMmask = 0;       /* 32 mCAMs (6105M and better) */
+               netdev_for_each_mc_addr(ha, dev) {
+                       if (i == MCAM_SIZE)
+                               break;
+                       rhine_set_cam(ioaddr, i, ha->addr);
+                       mCAMmask |= 1 << i;
+                       i++;
+               }
+               rhine_set_cam_mask(ioaddr, mCAMmask);
        } else {
-               struct netdev_hw_addr *ha;
-
                memset(mc_filter, 0, sizeof(mc_filter));
                netdev_for_each_mc_addr(ha, dev) {
                        int bit_nr = ether_crc(ETH_ALEN, ha->addr) >> 26;
@@ -1711,9 +2003,15 @@ static void rhine_set_rx_mode(struct net_device *dev)
                }
                iowrite32(mc_filter[0], ioaddr + MulticastFilter0);
                iowrite32(mc_filter[1], ioaddr + MulticastFilter1);
-               rx_mode = 0x0C;
        }
-       iowrite8(rp->rx_thresh | rx_mode, ioaddr + RxConfig);
+       /* enable/disable VLAN receive filtering */
+       if (rp->pdev->revision >= VT6105M) {
+               if (dev->flags & IFF_PROMISC)
+                       BYTE_REG_BITS_OFF(BCR1_VIDFR, ioaddr + PCIBusConfig1);
+               else
+                       BYTE_REG_BITS_ON(BCR1_VIDFR, ioaddr + PCIBusConfig1);
+       }
+       BYTE_REG_BITS_ON(rx_mode, ioaddr + RxConfig);
 }
 
 static void netdev_get_drvinfo(struct net_device *dev, struct ethtool_drvinfo *info)
@@ -1966,7 +2264,7 @@ static int rhine_resume(struct pci_dev *pdev)
        if (!netif_running(dev))
                return 0;
 
-        if (request_irq(dev->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev))
+       if (request_irq(dev->irq, rhine_interrupt, IRQF_SHARED, dev->name, dev))
                printk(KERN_ERR "via-rhine %s: request_irq failed\n", dev->name);
 
        ret = pci_set_power_state(pdev, PCI_D0);
index bc9bd10357060e429146f613554923e7e3bda01c..1dd3a21b3a4365110690f2ae3953185d361baba6 100644 (file)
@@ -1177,7 +1177,7 @@ static const struct ethtool_ops vxge_ethtool_ops = {
        .get_rx_csum            = vxge_get_rx_csum,
        .set_rx_csum            = vxge_set_rx_csum,
        .get_tx_csum            = ethtool_op_get_tx_csum,
-       .set_tx_csum            = ethtool_op_set_tx_hw_csum,
+       .set_tx_csum            = ethtool_op_set_tx_ipv6_csum,
        .get_sg                 = ethtool_op_get_sg,
        .set_sg                 = ethtool_op_set_sg,
        .get_tso                = ethtool_op_get_tso,
index 8a84152e320a19f8635a99767b2f95c8ddffbe02..4877b3b8a29e9f8ba92a374266bd9d8519449c0c 100644 (file)
@@ -3368,7 +3368,7 @@ static int __devinit vxge_device_register(struct __vxge_hw_device *hldev,
 
        ndev->features |= NETIF_F_SG;
 
-       ndev->features |= NETIF_F_HW_CSUM;
+       ndev->features |= NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM;
        vxge_debug_init(vxge_hw_device_trace_level_get(hldev),
                "%s : checksuming enabled", __func__);
 
index d81ad83978855ac4929a93f082139afd63f8cc41..cf05504d951130bf1f0f8460f9525ff8eaa0ab0c 100644 (file)
@@ -498,7 +498,6 @@ norbuff:
 static int x25_asy_close(struct net_device *dev)
 {
        struct x25_asy *sl = netdev_priv(dev);
-       int err;
 
        spin_lock(&sl->lock);
        if (sl->tty)
@@ -507,10 +506,6 @@ static int x25_asy_close(struct net_device *dev)
        netif_stop_queue(dev);
        sl->rcount = 0;
        sl->xleft  = 0;
-       err = lapb_unregister(dev);
-       if (err != LAPB_OK)
-               printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",
-                       err);
        spin_unlock(&sl->lock);
        return 0;
 }
@@ -595,6 +590,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 = tty->disc_data;
+       int err;
 
        /* First make sure we're connected. */
        if (!sl || sl->magic != X25_ASY_MAGIC)
@@ -605,6 +601,11 @@ static void x25_asy_close_tty(struct tty_struct *tty)
                dev_close(sl->dev);
        rtnl_unlock();
 
+       err = lapb_unregister(sl->dev);
+       if (err != LAPB_OK)
+               printk(KERN_ERR "x25_asy_close: lapb_unregister error -%d\n",
+                       err);
+
        tty->disc_data = NULL;
        sl->tty = NULL;
        x25_asy_free(sl);
index 5dbb5361fd516808fccc79bc9c2dbd2fc22c5963..d3be6f9816b5c0b6f7dded683eee5f04d26e0765 100644 (file)
@@ -161,8 +161,7 @@ static void ar9170_usb_submit_urb(struct ar9170_usb *aru)
 static void ar9170_usb_tx_urb_complete_frame(struct urb *urb)
 {
        struct sk_buff *skb = urb->context;
-       struct ar9170_usb *aru = (struct ar9170_usb *)
-             usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
+       struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
 
        if (unlikely(!aru)) {
                dev_kfree_skb_irq(skb);
@@ -219,8 +218,7 @@ free:
 static void ar9170_usb_rx_completed(struct urb *urb)
 {
        struct sk_buff *skb = urb->context;
-       struct ar9170_usb *aru = (struct ar9170_usb *)
-               usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
+       struct ar9170_usb *aru = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
        int err;
 
        if (!aru)
index 20ea68c59f7b9dbdb6ac1503660ee197d1a39497..26bdbeee424f6d905ec744ee38715d2b3551c1ac 100644 (file)
@@ -168,6 +168,8 @@ struct ath_common {
        struct ath_regulatory regulatory;
        const struct ath_ops *ops;
        const struct ath_bus_ops *bus_ops;
+
+       bool btcoex_enabled;
 };
 
 struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
index 47844575caa3e2426e0a64bc2583179477accea7..e0793319389d19a7aa27b52a3346f30bb68366cc 100644 (file)
@@ -1,10 +1,12 @@
 config ATH5K
        tristate "Atheros 5xxx wireless cards support"
-       depends on PCI && MAC80211
+       depends on (PCI || ATHEROS_AR231X) && MAC80211
        select MAC80211_LEDS
        select LEDS_CLASS
        select NEW_LEDS
        select AVERAGE
+       select ATH5K_AHB if (ATHEROS_AR231X && !PCI)
+       select ATH5K_PCI if (!ATHEROS_AR231X && PCI)
        ---help---
          This module adds support for wireless adapters based on
          Atheros 5xxx chipset.
@@ -38,3 +40,16 @@ config ATH5K_DEBUG
 
          modprobe ath5k debug=0x00000400
 
+config ATH5K_AHB
+       bool "Atheros 5xxx AHB bus support"
+       depends on (ATHEROS_AR231X && !PCI)
+       ---help---
+         This adds support for WiSoC type chipsets of the 5xxx Atheros
+         family.
+
+config ATH5K_PCI
+       bool "Atheros 5xxx PCI bus support"
+       depends on (!ATHEROS_AR231X && PCI)
+       ---help---
+         This adds support for PCI type chipsets of the 5xxx Atheros
+         family.
index 2242a140e4fe95c9dbcd17ca8d8ca728e5b3ff2e..67dd9fd0650e1b7ce21008034c91619b0410ee11 100644 (file)
@@ -15,4 +15,6 @@ ath5k-y                               += rfkill.o
 ath5k-y                                += ani.o
 ath5k-y                                += sysfs.o
 ath5k-$(CONFIG_ATH5K_DEBUG)    += debug.o
+ath5k-$(CONFIG_ATH5K_AHB)      += ahb.o
+ath5k-$(CONFIG_ATH5K_PCI)      += pci.o
 obj-$(CONFIG_ATH5K)            += ath5k.o
diff --git a/drivers/net/wireless/ath/ath5k/ahb.c b/drivers/net/wireless/ath/ath5k/ahb.c
new file mode 100644 (file)
index 0000000..707cde1
--- /dev/null
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ * Copyright (c) 2009 Gabor Juhos <juhosg@openwrt.org>
+ * Copyright (c) 2009 Imre Kaloz <kaloz@openwrt.org>
+ *
+ * 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 <linux/nl80211.h>
+#include <linux/platform_device.h>
+#include <ar231x_platform.h>
+#include "ath5k.h"
+#include "debug.h"
+#include "base.h"
+#include "reg.h"
+#include "debug.h"
+
+/* return bus cachesize in 4B word units */
+static void ath5k_ahb_read_cachesize(struct ath_common *common, int *csz)
+{
+       *csz = L1_CACHE_BYTES >> 2;
+}
+
+bool ath5k_ahb_eeprom_read(struct ath_common *common, u32 off, u16 *data)
+{
+       struct ath5k_softc *sc = common->priv;
+       struct platform_device *pdev = to_platform_device(sc->dev);
+       struct ar231x_board_config *bcfg = pdev->dev.platform_data;
+       u16 *eeprom, *eeprom_end;
+
+
+
+       bcfg = pdev->dev.platform_data;
+       eeprom = (u16 *) bcfg->radio;
+       eeprom_end = ((void *) bcfg->config) + BOARD_CONFIG_BUFSZ;
+
+       eeprom += off;
+       if (eeprom > eeprom_end)
+               return -EINVAL;
+
+       *data = *eeprom;
+       return 0;
+}
+
+int ath5k_hw_read_srev(struct ath5k_hw *ah)
+{
+       struct ath5k_softc *sc = ah->ah_sc;
+       struct platform_device *pdev = to_platform_device(sc->dev);
+       struct ar231x_board_config *bcfg = pdev->dev.platform_data;
+       ah->ah_mac_srev = bcfg->devid;
+       return 0;
+}
+
+static const struct ath_bus_ops ath_ahb_bus_ops = {
+       .ath_bus_type = ATH_AHB,
+       .read_cachesize = ath5k_ahb_read_cachesize,
+       .eeprom_read = ath5k_ahb_eeprom_read,
+};
+
+/*Initialization*/
+static int ath_ahb_probe(struct platform_device *pdev)
+{
+       struct ar231x_board_config *bcfg = pdev->dev.platform_data;
+       struct ath5k_softc *sc;
+       struct ieee80211_hw *hw;
+       struct resource *res;
+       void __iomem *mem;
+       int irq;
+       int ret = 0;
+       u32 reg;
+
+       if (!pdev->dev.platform_data) {
+               dev_err(&pdev->dev, "no platform data specified\n");
+               ret = -EINVAL;
+               goto err_out;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "no memory resource found\n");
+               ret = -ENXIO;
+               goto err_out;
+       }
+
+       mem = ioremap_nocache(res->start, res->end - res->start + 1);
+       if (mem == NULL) {
+               dev_err(&pdev->dev, "ioremap failed\n");
+               ret = -ENOMEM;
+               goto err_out;
+       }
+
+       res = platform_get_resource(pdev, IORESOURCE_IRQ, 0);
+       if (res == NULL) {
+               dev_err(&pdev->dev, "no IRQ resource found\n");
+               ret = -ENXIO;
+               goto err_out;
+       }
+
+       irq = res->start;
+
+       hw = ieee80211_alloc_hw(sizeof(struct ath5k_softc), &ath5k_hw_ops);
+       if (hw == NULL) {
+               dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
+               ret = -ENOMEM;
+               goto err_out;
+       }
+
+       sc = hw->priv;
+       sc->hw = hw;
+       sc->dev = &pdev->dev;
+       sc->iobase = mem;
+       sc->irq = irq;
+       sc->devid = bcfg->devid;
+
+       if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
+               /* Enable WMAC AHB arbitration */
+               reg = __raw_readl((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+               reg |= AR5K_AR2315_AHB_ARB_CTL_WLAN;
+               __raw_writel(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+
+               /* Enable global WMAC swapping */
+               reg = __raw_readl((void __iomem *) AR5K_AR2315_BYTESWAP);
+               reg |= AR5K_AR2315_BYTESWAP_WMAC;
+               __raw_writel(reg, (void __iomem *) AR5K_AR2315_BYTESWAP);
+       } else {
+               /* Enable WMAC DMA access (assuming 5312 or 231x*/
+               /* TODO: check other platforms */
+               reg = __raw_readl((void __iomem *) AR5K_AR5312_ENABLE);
+               if (to_platform_device(sc->dev)->id == 0)
+                       reg |= AR5K_AR5312_ENABLE_WLAN0;
+               else
+                       reg |= AR5K_AR5312_ENABLE_WLAN1;
+               __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
+       }
+
+       ret = ath5k_init_softc(sc, &ath_ahb_bus_ops);
+       if (ret != 0) {
+               dev_err(&pdev->dev, "failed to attach device, err=%d\n", ret);
+               ret = -ENODEV;
+               goto err_free_hw;
+       }
+
+       platform_set_drvdata(pdev, hw);
+
+       return 0;
+
+ err_free_hw:
+       ieee80211_free_hw(hw);
+       platform_set_drvdata(pdev, NULL);
+ err_out:
+       return ret;
+}
+
+static int ath_ahb_remove(struct platform_device *pdev)
+{
+       struct ar231x_board_config *bcfg = pdev->dev.platform_data;
+       struct ieee80211_hw *hw = platform_get_drvdata(pdev);
+       struct ath5k_softc *sc;
+       u32 reg;
+
+       if (!hw)
+               return 0;
+
+       sc = hw->priv;
+
+       if (bcfg->devid >= AR5K_SREV_AR2315_R6) {
+               /* Disable WMAC AHB arbitration */
+               reg = __raw_readl((void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+               reg &= ~AR5K_AR2315_AHB_ARB_CTL_WLAN;
+               __raw_writel(reg, (void __iomem *) AR5K_AR2315_AHB_ARB_CTL);
+       } else {
+               /*Stop DMA access */
+               reg = __raw_readl((void __iomem *) AR5K_AR5312_ENABLE);
+               if (to_platform_device(sc->dev)->id == 0)
+                       reg &= ~AR5K_AR5312_ENABLE_WLAN0;
+               else
+                       reg &= ~AR5K_AR5312_ENABLE_WLAN1;
+               __raw_writel(reg, (void __iomem *) AR5K_AR5312_ENABLE);
+       }
+
+       ath5k_deinit_softc(sc);
+       platform_set_drvdata(pdev, NULL);
+
+       return 0;
+}
+
+static struct platform_driver ath_ahb_driver = {
+       .probe      = ath_ahb_probe,
+       .remove     = ath_ahb_remove,
+       .driver         = {
+               .name   = "ar231x-wmac",
+               .owner  = THIS_MODULE,
+       },
+};
+
+static int __init
+ath5k_ahb_init(void)
+{
+       return platform_driver_register(&ath_ahb_driver);
+}
+
+static void __exit
+ath5k_ahb_exit(void)
+{
+       platform_driver_unregister(&ath_ahb_driver);
+}
+
+module_init(ath5k_ahb_init);
+module_exit(ath5k_ahb_exit);
index 6b75b22a929af2a41027bbf51bf15bf7fff456cb..f915f404302d68f2457797fb38255d6920381255 100644 (file)
@@ -58,19 +58,19 @@ ath5k_ani_set_noise_immunity_level(struct ath5k_hw *ah, int level)
 {
        /* TODO:
         * ANI documents suggest the following five levels to use, but the HAL
-        * and ath9k use only use the last two levels, making this
+        * and ath9k use only the last two levels, making this
         * essentially an on/off option. There *may* be a reason for this (???),
         * so i stick with the HAL version for now...
         */
 #if 0
-       static const s8 hi[] = { -18, -18, -16, -14, -12 };
        static const s8 lo[] = { -52, -56, -60, -64, -70 };
+       static const s8 hi[] = { -18, -18, -16, -14, -12 };
        static const s8 sz[] = { -34, -41, -48, -55, -62 };
        static const s8 fr[] = { -70, -72, -75, -78, -80 };
 #else
-       static const s8 sz[] = { -55, -62 };
        static const s8 lo[] = { -64, -70 };
        static const s8 hi[] = { -14, -12 };
+       static const s8 sz[] = { -55, -62 };
        static const s8 fr[] = { -78, -80 };
 #endif
        if (level < 0 || level >= ARRAY_SIZE(sz)) {
index 2718136e488610f00095d4a0e7c47f2de0d4d701..d6e744088bc6960cc67a4bec335b3246874f296e 100644 (file)
 #define AR5K_INI_RFGAIN_5GHZ           0
 #define AR5K_INI_RFGAIN_2GHZ           1
 
-/* TODO: Clean this up */
-#define AR5K_INI_VAL_11A               0
-#define AR5K_INI_VAL_11A_TURBO         1
-#define AR5K_INI_VAL_11B               2
-#define AR5K_INI_VAL_11G               3
-#define AR5K_INI_VAL_11G_TURBO         4
-#define AR5K_INI_VAL_XR                        0
-#define AR5K_INI_VAL_MAX               5
-
 /*
  * Some tuneable values (these should be changeable by the user)
  * TODO: Make use of them and add more options OR use debug/configfs
 
 /* Initial values */
 #define        AR5K_INIT_CYCRSSI_THR1                  2
-#define AR5K_INIT_TX_LATENCY                   502
-#define AR5K_INIT_USEC                         39
-#define AR5K_INIT_USEC_TURBO                   79
-#define AR5K_INIT_USEC_32                      31
-#define AR5K_INIT_SLOT_TIME                    396
-#define AR5K_INIT_SLOT_TIME_TURBO              480
-#define AR5K_INIT_ACK_CTS_TIMEOUT              1024
-#define AR5K_INIT_ACK_CTS_TIMEOUT_TURBO                0x08000800
-#define AR5K_INIT_PROG_IFS                     920
-#define AR5K_INIT_PROG_IFS_TURBO               960
-#define AR5K_INIT_EIFS                         3440
-#define AR5K_INIT_EIFS_TURBO                   6880
-#define AR5K_INIT_SIFS                         560
-#define AR5K_INIT_SIFS_TURBO                   480
+
+/* Tx retry limits */
 #define AR5K_INIT_SH_RETRY                     10
 #define AR5K_INIT_LG_RETRY                     AR5K_INIT_SH_RETRY
+/* For station mode */
 #define AR5K_INIT_SSH_RETRY                    32
 #define AR5K_INIT_SLG_RETRY                    AR5K_INIT_SSH_RETRY
 #define AR5K_INIT_TX_RETRY                     10
 
-#define AR5K_INIT_TRANSMIT_LATENCY             (                       \
-       (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |       \
-       (AR5K_INIT_USEC)                                                \
-)
-#define AR5K_INIT_TRANSMIT_LATENCY_TURBO       (                       \
-       (AR5K_INIT_TX_LATENCY << 14) | (AR5K_INIT_USEC_32 << 7) |       \
-       (AR5K_INIT_USEC_TURBO)                                          \
-)
-#define AR5K_INIT_PROTO_TIME_CNTRL             (                       \
-       (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS << 12) |      \
-       (AR5K_INIT_PROG_IFS)                                            \
-)
-#define AR5K_INIT_PROTO_TIME_CNTRL_TURBO       (                       \
-       (AR5K_INIT_CARR_SENSE_EN << 26) | (AR5K_INIT_EIFS_TURBO << 12) | \
-       (AR5K_INIT_PROG_IFS_TURBO)                                      \
-)
+
+/* Slot time */
+#define AR5K_INIT_SLOT_TIME_TURBO              6
+#define AR5K_INIT_SLOT_TIME_DEFAULT            9
+#define        AR5K_INIT_SLOT_TIME_HALF_RATE           13
+#define        AR5K_INIT_SLOT_TIME_QUARTER_RATE        21
+#define        AR5K_INIT_SLOT_TIME_B                   20
+#define AR5K_SLOT_TIME_MAX                     0xffff
+
+/* SIFS */
+#define        AR5K_INIT_SIFS_TURBO                    6
+/* XXX: 8 from initvals 10 from standard */
+#define        AR5K_INIT_SIFS_DEFAULT_BG               8
+#define        AR5K_INIT_SIFS_DEFAULT_A                16
+#define        AR5K_INIT_SIFS_HALF_RATE                32
+#define AR5K_INIT_SIFS_QUARTER_RATE            64
+
+/* Used to calculate tx time for non 5/10/40MHz
+ * operation */
+/* It's preamble time + signal time (16 + 4) */
+#define        AR5K_INIT_OFDM_PREAMPLE_TIME            20
+/* Preamble time for 40MHz (turbo) operation (min ?) */
+#define        AR5K_INIT_OFDM_PREAMBLE_TIME_MIN        14
+#define        AR5K_INIT_OFDM_SYMBOL_TIME              4
+#define        AR5K_INIT_OFDM_PLCP_BITS                22
+
+/* Rx latency for 5 and 10MHz operation (max ?) */
+#define AR5K_INIT_RX_LAT_MAX                   63
+/* Tx latencies from initvals (5212 only but no problem
+ * because we only tweak them on 5212) */
+#define        AR5K_INIT_TX_LAT_A                      54
+#define        AR5K_INIT_TX_LAT_BG                     384
+/* Tx latency for 40MHz (turbo) operation (min ?) */
+#define        AR5K_INIT_TX_LAT_MIN                    32
+/* Default Tx/Rx latencies (same for 5211)*/
+#define AR5K_INIT_TX_LATENCY_5210              54
+#define        AR5K_INIT_RX_LATENCY_5210               29
+
+/* Tx frame to Tx data start delay */
+#define AR5K_INIT_TXF2TXD_START_DEFAULT                14
+#define AR5K_INIT_TXF2TXD_START_DELAY_10MHZ    12
+#define AR5K_INIT_TXF2TXD_START_DELAY_5MHZ     13
+
+/* We need to increase PHY switch and agc settling time
+ * on turbo mode */
+#define        AR5K_SWITCH_SETTLING                    5760
+#define        AR5K_SWITCH_SETTLING_TURBO              7168
+
+#define        AR5K_AGC_SETTLING                       28
+/* 38 on 5210 but shouldn't matter */
+#define        AR5K_AGC_SETTLING_TURBO                 37
 
 
 /* GENERIC CHIPSET DEFINITIONS */
@@ -304,12 +319,19 @@ struct ath5k_srev_name {
 #define AR5K_SREV_AR5311B      0x30 /* Spirit */
 #define AR5K_SREV_AR5211       0x40 /* Oahu */
 #define AR5K_SREV_AR5212       0x50 /* Venice */
+#define AR5K_SREV_AR5312_R2    0x52 /* AP31 */
 #define AR5K_SREV_AR5212_V4    0x54 /* ??? */
 #define AR5K_SREV_AR5213       0x55 /* ??? */
+#define AR5K_SREV_AR5312_R7    0x57 /* AP30 */
+#define AR5K_SREV_AR2313_R8    0x58 /* AP43 */
 #define AR5K_SREV_AR5213A      0x59 /* Hainan */
 #define AR5K_SREV_AR2413       0x78 /* Griffin lite */
 #define AR5K_SREV_AR2414       0x70 /* Griffin */
+#define AR5K_SREV_AR2315_R6 0x86 /* AP51-Light */
+#define AR5K_SREV_AR2315_R7 0x87 /* AP51-Full */
 #define AR5K_SREV_AR5424       0x90 /* Condor */
+#define AR5K_SREV_AR2317_R1 0x90 /* AP61-Light */
+#define AR5K_SREV_AR2317_R2 0x91 /* AP61-Full */
 #define AR5K_SREV_AR5413       0xa4 /* Eagle lite */
 #define AR5K_SREV_AR5414       0xa0 /* Eagle */
 #define AR5K_SREV_AR2415       0xb0 /* Talon */
@@ -405,12 +427,10 @@ struct ath5k_srev_name {
 
 enum ath5k_driver_mode {
        AR5K_MODE_11A           =       0,
-       AR5K_MODE_11A_TURBO     =       1,
-       AR5K_MODE_11B           =       2,
-       AR5K_MODE_11G           =       3,
-       AR5K_MODE_11G_TURBO     =       4,
+       AR5K_MODE_11B           =       1,
+       AR5K_MODE_11G           =       2,
        AR5K_MODE_XR            =       0,
-       AR5K_MODE_MAX           =       5
+       AR5K_MODE_MAX           =       3
 };
 
 enum ath5k_ant_mode {
@@ -424,6 +444,12 @@ enum ath5k_ant_mode {
        AR5K_ANTMODE_MAX,
 };
 
+enum ath5k_bw_mode {
+       AR5K_BWMODE_DEFAULT     = 0,    /* 20MHz, default operation */
+       AR5K_BWMODE_5MHZ        = 1,    /* Quarter rate */
+       AR5K_BWMODE_10MHZ       = 2,    /* Half rate */
+       AR5K_BWMODE_40MHZ       = 3     /* Turbo */
+};
 
 /****************\
   TX DEFINITIONS
@@ -656,7 +682,6 @@ struct ath5k_gain {
 
 /* channel_flags */
 #define        CHANNEL_CW_INT  0x0008  /* Contention Window interference detected */
-#define        CHANNEL_TURBO   0x0010  /* Turbo Channel */
 #define        CHANNEL_CCK     0x0020  /* CCK channel */
 #define        CHANNEL_OFDM    0x0040  /* OFDM channel */
 #define        CHANNEL_2GHZ    0x0080  /* 2GHz channel. */
@@ -668,16 +693,10 @@ struct ath5k_gain {
 #define        CHANNEL_A       (CHANNEL_5GHZ|CHANNEL_OFDM)
 #define        CHANNEL_B       (CHANNEL_2GHZ|CHANNEL_CCK)
 #define        CHANNEL_G       (CHANNEL_2GHZ|CHANNEL_OFDM)
-#define        CHANNEL_T       (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
-#define        CHANNEL_TG      (CHANNEL_2GHZ|CHANNEL_OFDM|CHANNEL_TURBO)
-#define        CHANNEL_108A    CHANNEL_T
-#define        CHANNEL_108G    CHANNEL_TG
 #define        CHANNEL_X       (CHANNEL_5GHZ|CHANNEL_OFDM|CHANNEL_XR)
 
-#define        CHANNEL_ALL     (CHANNEL_OFDM|CHANNEL_CCK|CHANNEL_2GHZ|CHANNEL_5GHZ| \
-               CHANNEL_TURBO)
+#define        CHANNEL_ALL     (CHANNEL_OFDM|CHANNEL_CCK|CHANNEL_2GHZ|CHANNEL_5GHZ)
 
-#define        CHANNEL_ALL_NOTURBO     (CHANNEL_ALL & ~CHANNEL_TURBO)
 #define CHANNEL_MODES          CHANNEL_ALL
 
 /*
@@ -1026,7 +1045,6 @@ struct ath5k_hw {
        enum ath5k_int          ah_imr;
 
        struct ieee80211_channel *ah_current_channel;
-       bool                    ah_turbo;
        bool                    ah_calibration;
        bool                    ah_single_chip;
 
@@ -1035,6 +1053,7 @@ struct ath5k_hw {
        u32                     ah_phy;
        u32                     ah_mac_srev;
        u16                     ah_mac_version;
+       u16                     ah_mac_revision;
        u16                     ah_phy_revision;
        u16                     ah_radio_5ghz_revision;
        u16                     ah_radio_2ghz_revision;
@@ -1044,6 +1063,8 @@ struct ath5k_hw {
 
        u32                     ah_limit_tx_retries;
        u8                      ah_coverage_class;
+       bool                    ah_ack_bitrate_high;
+       u8                      ah_bwmode;
 
        /* Antenna Control */
        u32                     ah_ant_ctl[AR5K_EEPROM_N_MODES][AR5K_ANT_MAX];
@@ -1132,36 +1153,50 @@ struct ath5k_hw {
 /*
  * Prototypes
  */
+extern const struct ieee80211_ops ath5k_hw_ops;
 
-/* Attach/Detach Functions */
-int ath5k_hw_attach(struct ath5k_softc *sc);
-void ath5k_hw_detach(struct ath5k_hw *ah);
+/* Initialization and detach functions */
+int ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops);
+void ath5k_deinit_softc(struct ath5k_softc *sc);
+int ath5k_hw_init(struct ath5k_softc *sc);
+void ath5k_hw_deinit(struct ath5k_hw *ah);
 
 int ath5k_sysfs_register(struct ath5k_softc *sc);
 void ath5k_sysfs_unregister(struct ath5k_softc *sc);
 
+/*Chip id helper functions */
+const char *ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val);
+int ath5k_hw_read_srev(struct ath5k_hw *ah);
+
 /* LED functions */
 int ath5k_init_leds(struct ath5k_softc *sc);
 void ath5k_led_enable(struct ath5k_softc *sc);
 void ath5k_led_off(struct ath5k_softc *sc);
 void ath5k_unregister_leds(struct ath5k_softc *sc);
 
+
 /* Reset Functions */
 int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
 int ath5k_hw_on_hold(struct ath5k_hw *ah);
 int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
-                  struct ieee80211_channel *channel, bool change_channel);
+          struct ieee80211_channel *channel, bool fast, bool skip_pcu);
 int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
                              bool is_set);
 /* Power management functions */
 
+
+/* Clock rate related functions */
+unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec);
+unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock);
+void ath5k_hw_set_clockrate(struct ath5k_hw *ah);
+
+
 /* DMA Related Functions */
 void ath5k_hw_start_rx_dma(struct ath5k_hw *ah);
-int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah);
 u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah);
-void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr);
+int ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr);
 int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue);
-int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue);
+int ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue);
 u32 ath5k_hw_get_txdp(struct ath5k_hw *ah, unsigned int queue);
 int ath5k_hw_set_txdp(struct ath5k_hw *ah, unsigned int queue,
                                u32 phys_addr);
@@ -1171,38 +1206,43 @@ bool ath5k_hw_is_intr_pending(struct ath5k_hw *ah);
 int ath5k_hw_get_isr(struct ath5k_hw *ah, enum ath5k_int *interrupt_mask);
 enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask);
 void ath5k_hw_update_mib_counters(struct ath5k_hw *ah);
+/* Init/Stop functions */
+void ath5k_hw_dma_init(struct ath5k_hw *ah);
+int ath5k_hw_dma_stop(struct ath5k_hw *ah);
 
 /* EEPROM access functions */
 int ath5k_eeprom_init(struct ath5k_hw *ah);
 void ath5k_eeprom_detach(struct ath5k_hw *ah);
 int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac);
 
+
 /* Protocol Control Unit Functions */
+/* Helpers */
+int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
+               int len, struct ieee80211_rate *rate);
+unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah);
+unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah);
 extern int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype opmode);
 void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class);
-/* BSSID Functions */
+/* RX filter control*/
 int ath5k_hw_set_lladdr(struct ath5k_hw *ah, const u8 *mac);
 void ath5k_hw_set_bssid(struct ath5k_hw *ah);
 void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask);
-/* Receive start/stop functions */
-void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
-void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah);
-/* RX Filter functions */
 void ath5k_hw_set_mcast_filter(struct ath5k_hw *ah, u32 filter0, u32 filter1);
 u32 ath5k_hw_get_rx_filter(struct ath5k_hw *ah);
 void ath5k_hw_set_rx_filter(struct ath5k_hw *ah, u32 filter);
+/* Receive (DRU) start/stop functions */
+void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah);
+void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah);
 /* Beacon control functions */
 u64 ath5k_hw_get_tsf64(struct ath5k_hw *ah);
 void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64);
 void ath5k_hw_reset_tsf(struct ath5k_hw *ah);
 void ath5k_hw_init_beacon(struct ath5k_hw *ah, u32 next_beacon, u32 interval);
 bool ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval);
-/* ACK bit rate */
-void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high);
-/* Clock rate related functions */
-unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec);
-unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock);
-void ath5k_hw_set_clockrate(struct ath5k_hw *ah);
+/* Init function */
+void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
+                                                               u8 mode);
 
 /* Queue Control Unit, DFS Control Unit Functions */
 int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
@@ -1215,7 +1255,9 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah,
 u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue);
 void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue);
 int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue);
-int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time);
+int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time);
+/* Init function */
+int ath5k_hw_init_queues(struct ath5k_hw *ah);
 
 /* Hardware Descriptor Functions */
 int ath5k_hw_init_desc_functions(struct ath5k_hw *ah);
@@ -1225,6 +1267,7 @@ int ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
        unsigned int tx_rate1, u_int tx_tries1, u_int tx_rate2,
        u_int tx_tries2, unsigned int tx_rate3, u_int tx_tries3);
 
+
 /* GPIO Functions */
 void ath5k_hw_set_ledstate(struct ath5k_hw *ah, unsigned int state);
 int ath5k_hw_set_gpio_input(struct ath5k_hw *ah, u32 gpio);
@@ -1234,11 +1277,13 @@ int ath5k_hw_set_gpio(struct ath5k_hw *ah, u32 gpio, u32 val);
 void ath5k_hw_set_gpio_intr(struct ath5k_hw *ah, unsigned int gpio,
                            u32 interrupt_level);
 
-/* rfkill Functions */
+
+/* RFkill Functions */
 void ath5k_rfkill_hw_start(struct ath5k_hw *ah);
 void ath5k_rfkill_hw_stop(struct ath5k_hw *ah);
 
-/* Misc functions */
+
+/* Misc functions TODO: Cleanup */
 int ath5k_hw_set_capabilities(struct ath5k_hw *ah);
 int ath5k_hw_get_capability(struct ath5k_hw *ah,
                            enum ath5k_capability_type cap_type, u32 capability,
@@ -1246,19 +1291,20 @@ int ath5k_hw_get_capability(struct ath5k_hw *ah,
 int ath5k_hw_enable_pspoll(struct ath5k_hw *ah, u8 *bssid, u16 assoc_id);
 int ath5k_hw_disable_pspoll(struct ath5k_hw *ah);
 
+
 /* Initial register settings functions */
 int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel);
 
-/* Initialize RF */
-int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
-                        struct ieee80211_channel *channel,
-                        unsigned int mode);
-int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq);
+
+/* PHY functions */
+/* Misc PHY functions */
+u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
+int ath5k_hw_phy_disable(struct ath5k_hw *ah);
+/* Gain_F optimization */
 enum ath5k_rfgain ath5k_hw_gainf_calibrate(struct ath5k_hw *ah);
 int ath5k_hw_rfgain_opt_init(struct ath5k_hw *ah);
 /* PHY/RF channel functions */
 bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags);
-int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel);
 /* PHY calibration */
 void ath5k_hw_init_nfcal_hist(struct ath5k_hw *ah);
 int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
@@ -1267,18 +1313,14 @@ void ath5k_hw_update_noise_floor(struct ath5k_hw *ah);
 /* Spur mitigation */
 bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
                                  struct ieee80211_channel *channel);
-void ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
-                                        struct ieee80211_channel *channel);
-/* Misc PHY functions */
-u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan);
-int ath5k_hw_phy_disable(struct ath5k_hw *ah);
 /* Antenna control */
 void ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode);
 void ath5k_hw_set_antenna_switch(struct ath5k_hw *ah, u8 ee_mode);
 /* TX power setup */
-int ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
-                    u8 ee_mode, u8 txpower);
 int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower);
+/* Init function */
+int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
+                               u8 mode, u8 ee_mode, u8 freq, bool fast);
 
 /*
  * Functions used internaly
@@ -1294,6 +1336,32 @@ static inline struct ath_regulatory *ath5k_hw_regulatory(struct ath5k_hw *ah)
         return &(ath5k_hw_common(ah)->regulatory);
 }
 
+#ifdef CONFIG_ATHEROS_AR231X
+#define AR5K_AR2315_PCI_BASE   ((void __iomem *)0xb0100000)
+
+static inline void __iomem *ath5k_ahb_reg(struct ath5k_hw *ah, u16 reg)
+{
+       /* On AR2315 and AR2317 the PCI clock domain registers
+        * are outside of the WMAC register space */
+       if (unlikely((reg >= 0x4000) && (reg < 0x5000) &&
+               (ah->ah_mac_srev >= AR5K_SREV_AR2315_R6)))
+               return AR5K_AR2315_PCI_BASE + reg;
+
+       return ah->ah_iobase + reg;
+}
+
+static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
+{
+       return __raw_readl(ath5k_ahb_reg(ah, reg));
+}
+
+static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
+{
+       __raw_writel(val, ath5k_ahb_reg(ah, reg));
+}
+
+#else
+
 static inline u32 ath5k_hw_reg_read(struct ath5k_hw *ah, u16 reg)
 {
        return ioread32(ah->ah_iobase + reg);
@@ -1304,6 +1372,24 @@ static inline void ath5k_hw_reg_write(struct ath5k_hw *ah, u32 val, u16 reg)
        iowrite32(val, ah->ah_iobase + reg);
 }
 
+#endif
+
+static inline enum ath_bus_type ath5k_get_bus_type(struct ath5k_hw *ah)
+{
+       return ath5k_hw_common(ah)->bus_ops->ath_bus_type;
+}
+
+static inline void ath5k_read_cachesize(struct ath_common *common, int *csz)
+{
+       common->bus_ops->read_cachesize(common, csz);
+}
+
+static inline bool ath5k_hw_nvram_read(struct ath5k_hw *ah, u32 off, u16 *data)
+{
+       struct ath_common *common = ath5k_hw_common(ah);
+       return common->bus_ops->eeprom_read(common, off, data);
+}
+
 static inline u32 ath5k_hw_bitswap(u32 val, unsigned int bits)
 {
        u32 retval = 0, bit, i;
index fbe8aca975d85d940e4ee0f60b1283eb2357a339..9dbc1fa81795310f2322870d73ea26f102d7ddfd 100644 (file)
@@ -93,16 +93,16 @@ static int ath5k_hw_post(struct ath5k_hw *ah)
 }
 
 /**
- * ath5k_hw_attach - Check if hw is supported and init the needed structs
+ * ath5k_hw_init - Check if hw is supported and init the needed structs
  *
- * @sc: The &struct ath5k_softc we got from the driver's attach function
+ * @sc: The &struct ath5k_softc we got from the driver's init_softc function
  *
  * Check if the device is supported, perform a POST and initialize the needed
  * structs. Returns -ENOMEM if we don't have memory for the needed structs,
  * -ENODEV if the device is not supported or prints an error msg if something
  * else went wrong.
  */
-int ath5k_hw_attach(struct ath5k_softc *sc)
+int ath5k_hw_init(struct ath5k_softc *sc)
 {
        struct ath5k_hw *ah = sc->ah;
        struct ath_common *common = ath5k_hw_common(ah);
@@ -115,7 +115,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
         * HW information
         */
        ah->ah_radar.r_enabled = AR5K_TUNE_RADAR_ALERT;
-       ah->ah_turbo = false;
+       ah->ah_bwmode = AR5K_BWMODE_DEFAULT;
        ah->ah_txpower.txp_tpc = AR5K_TUNE_TPC_TXPOWER;
        ah->ah_imr = 0;
        ah->ah_limit_tx_retries = AR5K_INIT_TX_RETRY;
@@ -128,7 +128,8 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
        /*
         * Find the mac version
         */
-       srev = ath5k_hw_reg_read(ah, AR5K_SREV);
+       ath5k_hw_read_srev(ah);
+       srev = ah->ah_mac_srev;
        if (srev < AR5K_SREV_AR5311)
                ah->ah_version = AR5K_AR5210;
        else if (srev < AR5K_SREV_AR5212)
@@ -136,6 +137,10 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
        else
                ah->ah_version = AR5K_AR5212;
 
+       /* Get the MAC revision */
+       ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
+       ah->ah_mac_revision = AR5K_REG_MS(srev, AR5K_SREV_REV);
+
        /* Fill the ath5k_hw struct with the needed functions */
        ret = ath5k_hw_init_desc_functions(ah);
        if (ret)
@@ -146,9 +151,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
        if (ret)
                goto err;
 
-       /* Get MAC, PHY and RADIO revisions */
-       ah->ah_mac_srev = srev;
-       ah->ah_mac_version = AR5K_REG_MS(srev, AR5K_SREV_VER);
+       /* Get PHY and RADIO revisions */
        ah->ah_phy_revision = ath5k_hw_reg_read(ah, AR5K_PHY_CHIP_ID) &
                        0xffffffff;
        ah->ah_radio_5ghz_revision = ath5k_hw_radio_revision(ah,
@@ -273,7 +276,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
        /*
         * Write PCI-E power save settings
         */
-       if ((ah->ah_version == AR5K_AR5212) && (pdev->is_pcie)) {
+       if ((ah->ah_version == AR5K_AR5212) && pdev && (pdev->is_pcie)) {
                ath5k_hw_reg_write(ah, 0x9248fc00, AR5K_PCIE_SERDES);
                ath5k_hw_reg_write(ah, 0x24924924, AR5K_PCIE_SERDES);
 
@@ -305,8 +308,7 @@ int ath5k_hw_attach(struct ath5k_softc *sc)
        /* Get misc capabilities */
        ret = ath5k_hw_set_capabilities(ah);
        if (ret) {
-               ATH5K_ERR(sc, "unable to get device capabilities: 0x%04x\n",
-                       sc->pdev->device);
+               ATH5K_ERR(sc, "unable to get device capabilities\n");
                goto err;
        }
 
@@ -346,11 +348,11 @@ err:
 }
 
 /**
- * ath5k_hw_detach - Free the ath5k_hw struct
+ * ath5k_hw_deinit - Free the ath5k_hw struct
  *
  * @ah: The &struct ath5k_hw
  */
-void ath5k_hw_detach(struct ath5k_hw *ah)
+void ath5k_hw_deinit(struct ath5k_hw *ah)
 {
        __set_bit(ATH_STAT_INVALID, ah->ah_sc->status);
 
index 7f783d9462aa2049afb125832b34a269fc2897e1..0a7071a6dd7a941a692a225a9023a743e362dfdb 100644 (file)
@@ -47,8 +47,6 @@
 #include <linux/io.h>
 #include <linux/netdevice.h>
 #include <linux/cache.h>
-#include <linux/pci.h>
-#include <linux/pci-aspm.h>
 #include <linux/ethtool.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
@@ -80,37 +78,24 @@ MODULE_SUPPORTED_DEVICE("Atheros 5xxx WLAN cards");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_VERSION("0.6.0 (EXPERIMENTAL)");
 
-static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan);
+static int ath5k_init(struct ieee80211_hw *hw);
+static int ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
+                                                               bool skip_pcu);
 static int ath5k_beacon_update(struct ieee80211_hw *hw,
                struct ieee80211_vif *vif);
 static void ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
 
-/* Known PCI ids */
-static DEFINE_PCI_DEVICE_TABLE(ath5k_pci_id_table) = {
-       { PCI_VDEVICE(ATHEROS, 0x0207) }, /* 5210 early */
-       { PCI_VDEVICE(ATHEROS, 0x0007) }, /* 5210 */
-       { PCI_VDEVICE(ATHEROS, 0x0011) }, /* 5311 - this is on AHB bus !*/
-       { PCI_VDEVICE(ATHEROS, 0x0012) }, /* 5211 */
-       { PCI_VDEVICE(ATHEROS, 0x0013) }, /* 5212 */
-       { PCI_VDEVICE(3COM_2,  0x0013) }, /* 3com 5212 */
-       { PCI_VDEVICE(3COM,    0x0013) }, /* 3com 3CRDAG675 5212 */
-       { PCI_VDEVICE(ATHEROS, 0x1014) }, /* IBM minipci 5212 */
-       { PCI_VDEVICE(ATHEROS, 0x0014) }, /* 5212 combatible */
-       { PCI_VDEVICE(ATHEROS, 0x0015) }, /* 5212 combatible */
-       { PCI_VDEVICE(ATHEROS, 0x0016) }, /* 5212 combatible */
-       { PCI_VDEVICE(ATHEROS, 0x0017) }, /* 5212 combatible */
-       { PCI_VDEVICE(ATHEROS, 0x0018) }, /* 5212 combatible */
-       { PCI_VDEVICE(ATHEROS, 0x0019) }, /* 5212 combatible */
-       { PCI_VDEVICE(ATHEROS, 0x001a) }, /* 2413 Griffin-lite */
-       { PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */
-       { PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */
-       { PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */
-       { 0 }
-};
-MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table);
-
 /* Known SREVs */
 static const struct ath5k_srev_name srev_names[] = {
+#ifdef CONFIG_ATHEROS_AR231X
+       { "5312",       AR5K_VERSION_MAC,       AR5K_SREV_AR5312_R2 },
+       { "5312",       AR5K_VERSION_MAC,       AR5K_SREV_AR5312_R7 },
+       { "2313",       AR5K_VERSION_MAC,       AR5K_SREV_AR2313_R8 },
+       { "2315",       AR5K_VERSION_MAC,       AR5K_SREV_AR2315_R6 },
+       { "2315",       AR5K_VERSION_MAC,       AR5K_SREV_AR2315_R7 },
+       { "2317",       AR5K_VERSION_MAC,       AR5K_SREV_AR2317_R1 },
+       { "2317",       AR5K_VERSION_MAC,       AR5K_SREV_AR2317_R2 },
+#else
        { "5210",       AR5K_VERSION_MAC,       AR5K_SREV_AR5210 },
        { "5311",       AR5K_VERSION_MAC,       AR5K_SREV_AR5311 },
        { "5311A",      AR5K_VERSION_MAC,       AR5K_SREV_AR5311A },
@@ -129,6 +114,7 @@ static const struct ath5k_srev_name srev_names[] = {
        { "5418",       AR5K_VERSION_MAC,       AR5K_SREV_AR5418 },
        { "2425",       AR5K_VERSION_MAC,       AR5K_SREV_AR2425 },
        { "2417",       AR5K_VERSION_MAC,       AR5K_SREV_AR2417 },
+#endif
        { "xxxxx",      AR5K_VERSION_MAC,       AR5K_SREV_UNKNOWN },
        { "5110",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5110 },
        { "5111",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5111 },
@@ -142,10 +128,12 @@ static const struct ath5k_srev_name srev_names[] = {
        { "2112B",      AR5K_VERSION_RAD,       AR5K_SREV_RAD_2112B },
        { "2413",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_2413 },
        { "5413",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5413 },
-       { "2316",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_2316 },
-       { "2317",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_2317 },
        { "5424",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5424 },
        { "5133",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_5133 },
+#ifdef CONFIG_ATHEROS_AR231X
+       { "2316",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_2316 },
+       { "2317",       AR5K_VERSION_RAD,       AR5K_SREV_RAD_2317 },
+#endif
        { "xxxxx",      AR5K_VERSION_RAD,       AR5K_SREV_UNKNOWN },
 };
 
@@ -197,8 +185,8 @@ static inline void ath5k_txbuf_free_skb(struct ath5k_softc *sc,
        BUG_ON(!bf);
        if (!bf->skb)
                return;
-       pci_unmap_single(sc->pdev, bf->skbaddr, bf->skb->len,
-                       PCI_DMA_TODEVICE);
+       dma_unmap_single(sc->dev, bf->skbaddr, bf->skb->len,
+                       DMA_TO_DEVICE);
        dev_kfree_skb_any(bf->skb);
        bf->skb = NULL;
        bf->skbaddr = 0;
@@ -214,8 +202,8 @@ static inline void ath5k_rxbuf_free_skb(struct ath5k_softc *sc,
        BUG_ON(!bf);
        if (!bf->skb)
                return;
-       pci_unmap_single(sc->pdev, bf->skbaddr, common->rx_bufsize,
-                       PCI_DMA_FROMDEVICE);
+       dma_unmap_single(sc->dev, bf->skbaddr, common->rx_bufsize,
+                       DMA_FROM_DEVICE);
        dev_kfree_skb_any(bf->skb);
        bf->skb = NULL;
        bf->skbaddr = 0;
@@ -233,7 +221,7 @@ static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
        return (tsf & ~0x7fff) | rstamp;
 }
 
-static const char *
+const char *
 ath5k_chip_name(enum ath5k_srev_type type, u_int16_t val)
 {
        const char *name = "xxxxx";
@@ -327,14 +315,12 @@ ath5k_copy_channels(struct ath5k_hw *ah,
 
        switch (mode) {
        case AR5K_MODE_11A:
-       case AR5K_MODE_11A_TURBO:
                /* 1..220, but 2GHz frequencies are filtered by check_channel */
                size = 220 ;
                chfreq = CHANNEL_5GHZ;
                break;
        case AR5K_MODE_11B:
        case AR5K_MODE_11G:
-       case AR5K_MODE_11G_TURBO:
                size = 26;
                chfreq = CHANNEL_2GHZ;
                break;
@@ -363,11 +349,6 @@ ath5k_copy_channels(struct ath5k_hw *ah,
                case AR5K_MODE_11G:
                        channels[count].hw_value = chfreq | CHANNEL_OFDM;
                        break;
-               case AR5K_MODE_11A_TURBO:
-               case AR5K_MODE_11G_TURBO:
-                       channels[count].hw_value = chfreq |
-                               CHANNEL_OFDM | CHANNEL_TURBO;
-                       break;
                case AR5K_MODE_11B:
                        channels[count].hw_value = CHANNEL_B;
                }
@@ -496,7 +477,7 @@ ath5k_chan_set(struct ath5k_softc *sc, struct ieee80211_channel *chan)
         * hardware at the new frequency, and then re-enable
         * the relevant bits of the h/w.
         */
-       return ath5k_reset(sc, chan);
+       return ath5k_reset(sc, chan, true);
 }
 
 static void
@@ -653,10 +634,11 @@ struct sk_buff *ath5k_rx_skb_alloc(struct ath5k_softc *sc, dma_addr_t *skb_addr)
                return NULL;
        }
 
-       *skb_addr = pci_map_single(sc->pdev,
+       *skb_addr = dma_map_single(sc->dev,
                                   skb->data, common->rx_bufsize,
-                                  PCI_DMA_FROMDEVICE);
-       if (unlikely(pci_dma_mapping_error(sc->pdev, *skb_addr))) {
+                                  DMA_FROM_DEVICE);
+
+       if (unlikely(dma_mapping_error(sc->dev, *skb_addr))) {
                ATH5K_ERR(sc, "%s: DMA mapping failed\n", __func__);
                dev_kfree_skb(skb);
                return NULL;
@@ -752,8 +734,8 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
        flags = AR5K_TXDESC_INTREQ | AR5K_TXDESC_CLRDMASK;
 
        /* XXX endianness */
-       bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
-                       PCI_DMA_TODEVICE);
+       bf->skbaddr = dma_map_single(sc->dev, skb->data, skb->len,
+                       DMA_TO_DEVICE);
 
        rate = ieee80211_get_tx_rate(sc->hw, info);
        if (!rate) {
@@ -833,7 +815,7 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf,
 
        return 0;
 err_unmap:
-       pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE);
+       dma_unmap_single(sc->dev, bf->skbaddr, skb->len, DMA_TO_DEVICE);
        return ret;
 }
 
@@ -842,7 +824,7 @@ err_unmap:
 \*******************/
 
 static int
-ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev)
+ath5k_desc_alloc(struct ath5k_softc *sc)
 {
        struct ath5k_desc *ds;
        struct ath5k_buf *bf;
@@ -853,7 +835,9 @@ ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev)
        /* allocate descriptors */
        sc->desc_len = sizeof(struct ath5k_desc) *
                        (ATH_TXBUF + ATH_RXBUF + ATH_BCBUF + 1);
-       sc->desc = pci_alloc_consistent(pdev, sc->desc_len, &sc->desc_daddr);
+
+       sc->desc = dma_alloc_coherent(sc->dev, sc->desc_len,
+                               &sc->desc_daddr, GFP_KERNEL);
        if (sc->desc == NULL) {
                ATH5K_ERR(sc, "can't allocate descriptors\n");
                ret = -ENOMEM;
@@ -899,14 +883,14 @@ ath5k_desc_alloc(struct ath5k_softc *sc, struct pci_dev *pdev)
 
        return 0;
 err_free:
-       pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
+       dma_free_coherent(sc->dev, sc->desc_len, sc->desc, sc->desc_daddr);
 err:
        sc->desc = NULL;
        return ret;
 }
 
 static void
-ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)
+ath5k_desc_free(struct ath5k_softc *sc)
 {
        struct ath5k_buf *bf;
 
@@ -918,7 +902,7 @@ ath5k_desc_free(struct ath5k_softc *sc, struct pci_dev *pdev)
                ath5k_txbuf_free_skb(sc, bf);
 
        /* Free memory associated with all descriptors */
-       pci_free_consistent(pdev, sc->desc_len, sc->desc, sc->desc_daddr);
+       dma_free_coherent(sc->dev, sc->desc_len, sc->desc, sc->desc_daddr);
        sc->desc = NULL;
        sc->desc_daddr = 0;
 
@@ -1063,62 +1047,44 @@ err:
        return ret;
 }
 
+/**
+ * ath5k_drain_tx_buffs - Empty tx buffers
+ *
+ * @sc The &struct ath5k_softc
+ *
+ * Empty tx buffers from all queues in preparation
+ * of a reset or during shutdown.
+ *
+ * NB: this assumes output has been stopped and
+ *     we do not need to block ath5k_tx_tasklet
+ */
 static void
-ath5k_txq_drainq(struct ath5k_softc *sc, struct ath5k_txq *txq)
+ath5k_drain_tx_buffs(struct ath5k_softc *sc)
 {
+       struct ath5k_txq *txq;
        struct ath5k_buf *bf, *bf0;
+       int i;
 
-       /*
-        * NB: this assumes output has been stopped and
-        *     we do not need to block ath5k_tx_tasklet
-        */
-       spin_lock_bh(&txq->lock);
-       list_for_each_entry_safe(bf, bf0, &txq->q, list) {
-               ath5k_debug_printtxbuf(sc, bf);
-
-               ath5k_txbuf_free_skb(sc, bf);
-
-               spin_lock_bh(&sc->txbuflock);
-               list_move_tail(&bf->list, &sc->txbuf);
-               sc->txbuf_len++;
-               txq->txq_len--;
-               spin_unlock_bh(&sc->txbuflock);
-       }
-       txq->link = NULL;
-       txq->txq_poll_mark = false;
-       spin_unlock_bh(&txq->lock);
-}
+       for (i = 0; i < ARRAY_SIZE(sc->txqs); i++) {
+               if (sc->txqs[i].setup) {
+                       txq = &sc->txqs[i];
+                       spin_lock_bh(&txq->lock);
+                       list_for_each_entry_safe(bf, bf0, &txq->q, list) {
+                               ath5k_debug_printtxbuf(sc, bf);
 
-/*
- * Drain the transmit queues and reclaim resources.
- */
-static void
-ath5k_txq_cleanup(struct ath5k_softc *sc)
-{
-       struct ath5k_hw *ah = sc->ah;
-       unsigned int i;
+                               ath5k_txbuf_free_skb(sc, bf);
 
-       /* XXX return value */
-       if (likely(!test_bit(ATH_STAT_INVALID, sc->status))) {
-               /* don't touch the hardware if marked invalid */
-               ath5k_hw_stop_tx_dma(ah, sc->bhalq);
-               ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "beacon queue %x\n",
-                       ath5k_hw_get_txdp(ah, sc->bhalq));
-               for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
-                       if (sc->txqs[i].setup) {
-                               ath5k_hw_stop_tx_dma(ah, sc->txqs[i].qnum);
-                               ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "txq [%u] %x, "
-                                       "link %p\n",
-                                       sc->txqs[i].qnum,
-                                       ath5k_hw_get_txdp(ah,
-                                                       sc->txqs[i].qnum),
-                                       sc->txqs[i].link);
+                               spin_lock_bh(&sc->txbuflock);
+                               list_move_tail(&bf->list, &sc->txbuf);
+                               sc->txbuf_len++;
+                               txq->txq_len--;
+                               spin_unlock_bh(&sc->txbuflock);
                        }
+                       txq->link = NULL;
+                       txq->txq_poll_mark = false;
+                       spin_unlock_bh(&txq->lock);
+               }
        }
-
-       for (i = 0; i < ARRAY_SIZE(sc->txqs); i++)
-               if (sc->txqs[i].setup)
-                       ath5k_txq_drainq(sc, &sc->txqs[i]);
 }
 
 static void
@@ -1178,16 +1144,19 @@ err:
 }
 
 /*
- * Disable the receive h/w in preparation for a reset.
+ * Disable the receive logic on PCU (DRU)
+ * In preparation for a shutdown.
+ *
+ * Note: Doesn't stop rx DMA, ath5k_hw_dma_stop
+ * does.
  */
 static void
 ath5k_rx_stop(struct ath5k_softc *sc)
 {
        struct ath5k_hw *ah = sc->ah;
 
-       ath5k_hw_stop_rx_pcu(ah);       /* disable PCU */
        ath5k_hw_set_rx_filter(ah, 0);  /* clear recv filter */
-       ath5k_hw_stop_rx_dma(ah);       /* disable DMA engine */
+       ath5k_hw_stop_rx_pcu(ah);       /* disable PCU */
 
        ath5k_debug_printrxbuffs(sc, ah);
 }
@@ -1544,9 +1513,9 @@ ath5k_tasklet_rx(unsigned long data)
                        if (!next_skb)
                                goto next;
 
-                       pci_unmap_single(sc->pdev, bf->skbaddr,
+                       dma_unmap_single(sc->dev, bf->skbaddr,
                                         common->rx_bufsize,
-                                        PCI_DMA_FROMDEVICE);
+                                        DMA_FROM_DEVICE);
 
                        skb_put(skb, rs.rs_datalen);
 
@@ -1709,8 +1678,9 @@ ath5k_tx_processq(struct ath5k_softc *sc, struct ath5k_txq *txq)
 
                        skb = bf->skb;
                        bf->skb = NULL;
-                       pci_unmap_single(sc->pdev, bf->skbaddr, skb->len,
-                                       PCI_DMA_TODEVICE);
+
+                       dma_unmap_single(sc->dev, bf->skbaddr, skb->len,
+                                       DMA_TO_DEVICE);
                        ath5k_tx_frame_completed(sc, skb, &ts);
                }
 
@@ -1764,12 +1734,13 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
        u32 flags;
        const int padsize = 0;
 
-       bf->skbaddr = pci_map_single(sc->pdev, skb->data, skb->len,
-                       PCI_DMA_TODEVICE);
+       bf->skbaddr = dma_map_single(sc->dev, skb->data, skb->len,
+                       DMA_TO_DEVICE);
        ATH5K_DBG(sc, ATH5K_DEBUG_BEACON, "skb %p [data %p len %u] "
                        "skbaddr %llx\n", skb, skb->data, skb->len,
                        (unsigned long long)bf->skbaddr);
-       if (pci_dma_mapping_error(sc->pdev, bf->skbaddr)) {
+
+       if (dma_mapping_error(sc->dev, bf->skbaddr)) {
                ATH5K_ERR(sc, "beacon DMA mapping failed\n");
                return -EIO;
        }
@@ -1821,7 +1792,7 @@ ath5k_beacon_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
 
        return 0;
 err_unmap:
-       pci_unmap_single(sc->pdev, bf->skbaddr, skb->len, PCI_DMA_TODEVICE);
+       dma_unmap_single(sc->dev, bf->skbaddr, skb->len, DMA_TO_DEVICE);
        return ret;
 }
 
@@ -1937,7 +1908,7 @@ ath5k_beacon_send(struct ath5k_softc *sc)
         * This should never fail since we check above that no frames
         * are still pending on the queue.
         */
-       if (unlikely(ath5k_hw_stop_tx_dma(ah, sc->bhalq))) {
+       if (unlikely(ath5k_hw_stop_beacon_queue(ah, sc->bhalq))) {
                ATH5K_WARN(sc, "beacon queue %u didn't start/stop ?\n", sc->bhalq);
                /* NB: hw still stops DMA, so proceed */
        }
@@ -2106,7 +2077,7 @@ ath5k_beacon_config(struct ath5k_softc *sc)
                } else
                        ath5k_beacon_update_timers(sc, -1);
        } else {
-               ath5k_hw_stop_tx_dma(sc->ah, sc->bhalq);
+               ath5k_hw_stop_beacon_queue(sc->ah, sc->bhalq);
        }
 
        ath5k_hw_set_imr(ah, sc->imask);
@@ -2168,7 +2139,7 @@ ath5k_intr_calibration_poll(struct ath5k_hw *ah)
         * AR5K_REG_ENABLE_BITS(ah, AR5K_CR, AR5K_CR_SWI); */
 }
 
-static irqreturn_t
+irqreturn_t
 ath5k_intr(int irq, void *dev_id)
 {
        struct ath5k_softc *sc = dev_id;
@@ -2177,7 +2148,8 @@ ath5k_intr(int irq, void *dev_id)
        unsigned int counter = 1000;
 
        if (unlikely(test_bit(ATH_STAT_INVALID, sc->status) ||
-                               !ath5k_hw_is_intr_pending(ah)))
+               ((ath5k_get_bus_type(ah) != ATH_AHB) &&
+                               !ath5k_hw_is_intr_pending(ah))))
                return IRQ_NONE;
 
        do {
@@ -2243,6 +2215,10 @@ ath5k_intr(int irq, void *dev_id)
                                tasklet_schedule(&sc->rf_kill.toggleq);
 
                }
+
+               if (ath5k_get_bus_type(ah) == ATH_AHB)
+                       break;
+
        } while (ath5k_hw_is_intr_pending(ah) && --counter > 0);
 
        if (unlikely(!counter))
@@ -2342,7 +2318,7 @@ ath5k_tx_complete_poll_work(struct work_struct *work)
        if (needreset) {
                ATH5K_DBG(sc, ATH5K_DEBUG_RESET,
                          "TX queues stuck, resetting\n");
-               ath5k_reset(sc, sc->curchan);
+               ath5k_reset(sc, NULL, true);
        }
 
        ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work,
@@ -2354,6 +2330,158 @@ ath5k_tx_complete_poll_work(struct work_struct *work)
 * Initialization routines *
 \*************************/
 
+int
+ath5k_init_softc(struct ath5k_softc *sc, const struct ath_bus_ops *bus_ops)
+{
+       struct ieee80211_hw *hw = sc->hw;
+       struct ath_common *common;
+       int ret;
+       int csz;
+
+       /* Initialize driver private data */
+       SET_IEEE80211_DEV(hw, sc->dev);
+       hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+                   IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
+                   IEEE80211_HW_SIGNAL_DBM;
+
+       hw->wiphy->interface_modes =
+               BIT(NL80211_IFTYPE_AP) |
+               BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_ADHOC) |
+               BIT(NL80211_IFTYPE_MESH_POINT);
+
+       hw->extra_tx_headroom = 2;
+       hw->channel_change_time = 5000;
+
+       /*
+        * Mark the device as detached to avoid processing
+        * interrupts until setup is complete.
+        */
+       __set_bit(ATH_STAT_INVALID, sc->status);
+
+       sc->opmode = NL80211_IFTYPE_STATION;
+       sc->bintval = 1000;
+       mutex_init(&sc->lock);
+       spin_lock_init(&sc->rxbuflock);
+       spin_lock_init(&sc->txbuflock);
+       spin_lock_init(&sc->block);
+
+
+       /* Setup interrupt handler */
+       ret = request_irq(sc->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
+       if (ret) {
+               ATH5K_ERR(sc, "request_irq failed\n");
+               goto err;
+       }
+
+       /* If we passed the test, malloc an ath5k_hw struct */
+       sc->ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
+       if (!sc->ah) {
+               ret = -ENOMEM;
+               ATH5K_ERR(sc, "out of memory\n");
+               goto err_irq;
+       }
+
+       sc->ah->ah_sc = sc;
+       sc->ah->ah_iobase = sc->iobase;
+       common = ath5k_hw_common(sc->ah);
+       common->ops = &ath5k_common_ops;
+       common->bus_ops = bus_ops;
+       common->ah = sc->ah;
+       common->hw = hw;
+       common->priv = sc;
+
+       /*
+        * Cache line size is used to size and align various
+        * structures used to communicate with the hardware.
+        */
+       ath5k_read_cachesize(common, &csz);
+       common->cachelsz = csz << 2; /* convert to bytes */
+
+       spin_lock_init(&common->cc_lock);
+
+       /* Initialize device */
+       ret = ath5k_hw_init(sc);
+       if (ret)
+               goto err_free_ah;
+
+       /* set up multi-rate retry capabilities */
+       if (sc->ah->ah_version == AR5K_AR5212) {
+               hw->max_rates = 4;
+               hw->max_rate_tries = 11;
+       }
+
+       hw->vif_data_size = sizeof(struct ath5k_vif);
+
+       /* Finish private driver data initialization */
+       ret = ath5k_init(hw);
+       if (ret)
+               goto err_ah;
+
+       ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n",
+                       ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev),
+                                       sc->ah->ah_mac_srev,
+                                       sc->ah->ah_phy_revision);
+
+       if (!sc->ah->ah_single_chip) {
+               /* Single chip radio (!RF5111) */
+               if (sc->ah->ah_radio_5ghz_revision &&
+                       !sc->ah->ah_radio_2ghz_revision) {
+                       /* No 5GHz support -> report 2GHz radio */
+                       if (!test_bit(AR5K_MODE_11A,
+                               sc->ah->ah_capabilities.cap_mode)) {
+                               ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
+                                       ath5k_chip_name(AR5K_VERSION_RAD,
+                                               sc->ah->ah_radio_5ghz_revision),
+                                               sc->ah->ah_radio_5ghz_revision);
+                       /* No 2GHz support (5110 and some
+                        * 5Ghz only cards) -> report 5Ghz radio */
+                       } else if (!test_bit(AR5K_MODE_11B,
+                               sc->ah->ah_capabilities.cap_mode)) {
+                               ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
+                                       ath5k_chip_name(AR5K_VERSION_RAD,
+                                               sc->ah->ah_radio_5ghz_revision),
+                                               sc->ah->ah_radio_5ghz_revision);
+                       /* Multiband radio */
+                       } else {
+                               ATH5K_INFO(sc, "RF%s multiband radio found"
+                                       " (0x%x)\n",
+                                       ath5k_chip_name(AR5K_VERSION_RAD,
+                                               sc->ah->ah_radio_5ghz_revision),
+                                               sc->ah->ah_radio_5ghz_revision);
+                       }
+               }
+               /* Multi chip radio (RF5111 - RF2111) ->
+                * report both 2GHz/5GHz radios */
+               else if (sc->ah->ah_radio_5ghz_revision &&
+                               sc->ah->ah_radio_2ghz_revision){
+                       ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
+                               ath5k_chip_name(AR5K_VERSION_RAD,
+                                       sc->ah->ah_radio_5ghz_revision),
+                                       sc->ah->ah_radio_5ghz_revision);
+                       ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
+                               ath5k_chip_name(AR5K_VERSION_RAD,
+                                       sc->ah->ah_radio_2ghz_revision),
+                                       sc->ah->ah_radio_2ghz_revision);
+               }
+       }
+
+       ath5k_debug_init_device(sc);
+
+       /* ready to process interrupts */
+       __clear_bit(ATH_STAT_INVALID, sc->status);
+
+       return 0;
+err_ah:
+       ath5k_hw_deinit(sc->ah);
+err_free_ah:
+       kfree(sc->ah);
+err_irq:
+       free_irq(sc->irq, sc);
+err:
+       return ret;
+}
+
 static int
 ath5k_stop_locked(struct ath5k_softc *sc)
 {
@@ -2382,11 +2510,10 @@ ath5k_stop_locked(struct ath5k_softc *sc)
        if (!test_bit(ATH_STAT_INVALID, sc->status)) {
                ath5k_led_off(sc);
                ath5k_hw_set_imr(ah, 0);
-               synchronize_irq(sc->pdev->irq);
-       }
-       ath5k_txq_cleanup(sc);
-       if (!test_bit(ATH_STAT_INVALID, sc->status)) {
+               synchronize_irq(sc->irq);
                ath5k_rx_stop(sc);
+               ath5k_hw_dma_stop(ah);
+               ath5k_drain_tx_buffs(sc);
                ath5k_hw_phy_disable(ah);
        }
 
@@ -2394,7 +2521,7 @@ ath5k_stop_locked(struct ath5k_softc *sc)
 }
 
 static int
-ath5k_init(struct ath5k_softc *sc)
+ath5k_init_hw(struct ath5k_softc *sc)
 {
        struct ath5k_hw *ah = sc->ah;
        struct ath_common *common = ath5k_hw_common(ah);
@@ -2423,7 +2550,7 @@ ath5k_init(struct ath5k_softc *sc)
                AR5K_INT_RXORN | AR5K_INT_TXDESC | AR5K_INT_TXEOL |
                AR5K_INT_FATAL | AR5K_INT_GLOBAL | AR5K_INT_MIB;
 
-       ret = ath5k_reset(sc, NULL);
+       ret = ath5k_reset(sc, NULL, false);
        if (ret)
                goto done;
 
@@ -2436,7 +2563,9 @@ ath5k_init(struct ath5k_softc *sc)
        for (i = 0; i < common->keymax; i++)
                ath_hw_keyreset(common, (u16) i);
 
-       ath5k_hw_set_ack_bitrate_high(ah, true);
+       /* Use higher rates for acks instead of base
+        * rate */
+       ah->ah_ack_bitrate_high = true;
 
        for (i = 0; i < ARRAY_SIZE(sc->bslot); i++)
                sc->bslot[i] = NULL;
@@ -2520,7 +2649,8 @@ ath5k_stop_hw(struct ath5k_softc *sc)
  * This should be called with sc->lock.
  */
 static int
-ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
+ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
+                                                       bool skip_pcu)
 {
        struct ath5k_hw *ah = sc->ah;
        int ret;
@@ -2528,17 +2658,17 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan)
        ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n");
 
        ath5k_hw_set_imr(ah, 0);
-       synchronize_irq(sc->pdev->irq);
+       synchronize_irq(sc->irq);
        stop_tasklets(sc);
 
        if (chan) {
-               ath5k_txq_cleanup(sc);
-               ath5k_rx_stop(sc);
+               ath5k_drain_tx_buffs(sc);
 
                sc->curchan = chan;
                sc->curband = &sc->sbands[chan->band];
        }
-       ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL);
+       ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL,
+                                                               skip_pcu);
        if (ret) {
                ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
                goto err;
@@ -2584,13 +2714,14 @@ static void ath5k_reset_work(struct work_struct *work)
                reset_work);
 
        mutex_lock(&sc->lock);
-       ath5k_reset(sc, sc->curchan);
+       ath5k_reset(sc, NULL, true);
        mutex_unlock(&sc->lock);
 }
 
 static int
-ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
+ath5k_init(struct ieee80211_hw *hw)
 {
+
        struct ath5k_softc *sc = hw->priv;
        struct ath5k_hw *ah = sc->ah;
        struct ath_regulatory *regulatory = ath5k_hw_regulatory(ah);
@@ -2598,7 +2729,6 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
        u8 mac[ETH_ALEN] = {};
        int ret;
 
-       ATH5K_DBG(sc, ATH5K_DEBUG_ANY, "devid 0x%x\n", pdev->device);
 
        /*
         * Check if the MAC has multi-rate retry support.
@@ -2635,7 +2765,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
        /*
         * Allocate tx+rx descriptors and populate the lists.
         */
-       ret = ath5k_desc_alloc(sc, pdev);
+       ret = ath5k_desc_alloc(sc);
        if (ret) {
                ATH5K_ERR(sc, "can't allocate descriptors\n");
                goto err;
@@ -2699,8 +2829,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
 
        ret = ath5k_eeprom_read_mac(ah, mac);
        if (ret) {
-               ATH5K_ERR(sc, "unable to read address from EEPROM: 0x%04x\n",
-                       sc->pdev->device);
+               ATH5K_ERR(sc, "unable to read address from EEPROM\n");
                goto err_queues;
        }
 
@@ -2735,15 +2864,15 @@ err_queues:
 err_bhal:
        ath5k_hw_release_tx_queue(ah, sc->bhalq);
 err_desc:
-       ath5k_desc_free(sc, pdev);
+       ath5k_desc_free(sc);
 err:
        return ret;
 }
 
-static void
-ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
+void
+ath5k_deinit_softc(struct ath5k_softc *sc)
 {
-       struct ath5k_softc *sc = hw->priv;
+       struct ieee80211_hw *hw = sc->hw;
 
        /*
         * NB: the order of these is important:
@@ -2758,8 +2887,9 @@ ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
         * XXX: ??? detach ath5k_hw ???
         * Other than that, it's straightforward...
         */
+       ath5k_debug_finish_device(sc);
        ieee80211_unregister_hw(hw);
-       ath5k_desc_free(sc, pdev);
+       ath5k_desc_free(sc);
        ath5k_txq_release(sc);
        ath5k_hw_release_tx_queue(sc->ah, sc->bhalq);
        ath5k_unregister_leds(sc);
@@ -2770,6 +2900,8 @@ ath5k_detach(struct pci_dev *pdev, struct ieee80211_hw *hw)
         * returns because we'll get called back to reclaim node
         * state and potentially want to use them.
         */
+       ath5k_hw_deinit(sc->ah);
+       free_irq(sc->irq, sc);
 }
 
 /********************\
@@ -2792,7 +2924,7 @@ ath5k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 
 static int ath5k_start(struct ieee80211_hw *hw)
 {
-       return ath5k_init(hw->priv);
+       return ath5k_init_hw(hw->priv);
 }
 
 static void ath5k_stop(struct ieee80211_hw *hw)
@@ -3437,7 +3569,7 @@ static int ath5k_get_antenna(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant)
        return 0;
 }
 
-static const struct ieee80211_ops ath5k_hw_ops = {
+const struct ieee80211_ops ath5k_hw_ops = {
        .tx             = ath5k_tx,
        .start          = ath5k_start,
        .stop           = ath5k_stop,
@@ -3460,340 +3592,3 @@ static const struct ieee80211_ops ath5k_hw_ops = {
        .set_antenna    = ath5k_set_antenna,
        .get_antenna    = ath5k_get_antenna,
 };
-
-/********************\
-* PCI Initialization *
-\********************/
-
-static int __devinit
-ath5k_pci_probe(struct pci_dev *pdev,
-               const struct pci_device_id *id)
-{
-       void __iomem *mem;
-       struct ath5k_softc *sc;
-       struct ath_common *common;
-       struct ieee80211_hw *hw;
-       int ret;
-       u8 csz;
-
-       /*
-        * L0s needs to be disabled on all ath5k cards.
-        *
-        * For distributions shipping with CONFIG_PCIEASPM (this will be enabled
-        * by default in the future in 2.6.36) this will also mean both L1 and
-        * L0s will be disabled when a pre 1.1 PCIe device is detected. We do
-        * know L1 works correctly even for all ath5k pre 1.1 PCIe devices
-        * though but cannot currently undue the effect of a blacklist, for
-        * details you can read pcie_aspm_sanity_check() and see how it adjusts
-        * the device link capability.
-        *
-        * It may be possible in the future to implement some PCI API to allow
-        * drivers to override blacklists for pre 1.1 PCIe but for now it is
-        * best to accept that both L0s and L1 will be disabled completely for
-        * distributions shipping with CONFIG_PCIEASPM rather than having this
-        * issue present. Motivation for adding this new API will be to help
-        * with power consumption for some of these devices.
-        */
-       pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S);
-
-       ret = pci_enable_device(pdev);
-       if (ret) {
-               dev_err(&pdev->dev, "can't enable device\n");
-               goto err;
-       }
-
-       /* XXX 32-bit addressing only */
-       ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
-       if (ret) {
-               dev_err(&pdev->dev, "32-bit DMA not available\n");
-               goto err_dis;
-       }
-
-       /*
-        * Cache line size is used to size and align various
-        * structures used to communicate with the hardware.
-        */
-       pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
-       if (csz == 0) {
-               /*
-                * Linux 2.4.18 (at least) writes the cache line size
-                * register as a 16-bit wide register which is wrong.
-                * We must have this setup properly for rx buffer
-                * DMA to work so force a reasonable value here if it
-                * comes up zero.
-                */
-               csz = L1_CACHE_BYTES >> 2;
-               pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
-       }
-       /*
-        * The default setting of latency timer yields poor results,
-        * set it to the value used by other systems.  It may be worth
-        * tweaking this setting more.
-        */
-       pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
-
-       /* Enable bus mastering */
-       pci_set_master(pdev);
-
-       /*
-        * Disable the RETRY_TIMEOUT register (0x41) to keep
-        * PCI Tx retries from interfering with C3 CPU state.
-        */
-       pci_write_config_byte(pdev, 0x41, 0);
-
-       ret = pci_request_region(pdev, 0, "ath5k");
-       if (ret) {
-               dev_err(&pdev->dev, "cannot reserve PCI memory region\n");
-               goto err_dis;
-       }
-
-       mem = pci_iomap(pdev, 0, 0);
-       if (!mem) {
-               dev_err(&pdev->dev, "cannot remap PCI memory region\n") ;
-               ret = -EIO;
-               goto err_reg;
-       }
-
-       /*
-        * Allocate hw (mac80211 main struct)
-        * and hw->priv (driver private data)
-        */
-       hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops);
-       if (hw == NULL) {
-               dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n");
-               ret = -ENOMEM;
-               goto err_map;
-       }
-
-       dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy));
-
-       /* Initialize driver private data */
-       SET_IEEE80211_DEV(hw, &pdev->dev);
-       hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
-                   IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
-                   IEEE80211_HW_SIGNAL_DBM;
-
-       hw->wiphy->interface_modes =
-               BIT(NL80211_IFTYPE_AP) |
-               BIT(NL80211_IFTYPE_STATION) |
-               BIT(NL80211_IFTYPE_ADHOC) |
-               BIT(NL80211_IFTYPE_MESH_POINT);
-
-       hw->extra_tx_headroom = 2;
-       hw->channel_change_time = 5000;
-       sc = hw->priv;
-       sc->hw = hw;
-       sc->pdev = pdev;
-
-       /*
-        * Mark the device as detached to avoid processing
-        * interrupts until setup is complete.
-        */
-       __set_bit(ATH_STAT_INVALID, sc->status);
-
-       sc->iobase = mem; /* So we can unmap it on detach */
-       sc->opmode = NL80211_IFTYPE_STATION;
-       sc->bintval = 1000;
-       mutex_init(&sc->lock);
-       spin_lock_init(&sc->rxbuflock);
-       spin_lock_init(&sc->txbuflock);
-       spin_lock_init(&sc->block);
-
-       /* Set private data */
-       pci_set_drvdata(pdev, sc);
-
-       /* Setup interrupt handler */
-       ret = request_irq(pdev->irq, ath5k_intr, IRQF_SHARED, "ath", sc);
-       if (ret) {
-               ATH5K_ERR(sc, "request_irq failed\n");
-               goto err_free;
-       }
-
-       /* If we passed the test, malloc an ath5k_hw struct */
-       sc->ah = kzalloc(sizeof(struct ath5k_hw), GFP_KERNEL);
-       if (!sc->ah) {
-               ret = -ENOMEM;
-               ATH5K_ERR(sc, "out of memory\n");
-               goto err_irq;
-       }
-
-       sc->ah->ah_sc = sc;
-       sc->ah->ah_iobase = sc->iobase;
-       common = ath5k_hw_common(sc->ah);
-       common->ops = &ath5k_common_ops;
-       common->ah = sc->ah;
-       common->hw = hw;
-       common->cachelsz = csz << 2; /* convert to bytes */
-       spin_lock_init(&common->cc_lock);
-
-       /* Initialize device */
-       ret = ath5k_hw_attach(sc);
-       if (ret) {
-               goto err_free_ah;
-       }
-
-       /* set up multi-rate retry capabilities */
-       if (sc->ah->ah_version == AR5K_AR5212) {
-               hw->max_rates = 4;
-               hw->max_rate_tries = 11;
-       }
-
-       hw->vif_data_size = sizeof(struct ath5k_vif);
-
-       /* Finish private driver data initialization */
-       ret = ath5k_attach(pdev, hw);
-       if (ret)
-               goto err_ah;
-
-       ATH5K_INFO(sc, "Atheros AR%s chip found (MAC: 0x%x, PHY: 0x%x)\n",
-                       ath5k_chip_name(AR5K_VERSION_MAC, sc->ah->ah_mac_srev),
-                                       sc->ah->ah_mac_srev,
-                                       sc->ah->ah_phy_revision);
-
-       if (!sc->ah->ah_single_chip) {
-               /* Single chip radio (!RF5111) */
-               if (sc->ah->ah_radio_5ghz_revision &&
-                       !sc->ah->ah_radio_2ghz_revision) {
-                       /* No 5GHz support -> report 2GHz radio */
-                       if (!test_bit(AR5K_MODE_11A,
-                               sc->ah->ah_capabilities.cap_mode)) {
-                               ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
-                                       ath5k_chip_name(AR5K_VERSION_RAD,
-                                               sc->ah->ah_radio_5ghz_revision),
-                                               sc->ah->ah_radio_5ghz_revision);
-                       /* No 2GHz support (5110 and some
-                        * 5Ghz only cards) -> report 5Ghz radio */
-                       } else if (!test_bit(AR5K_MODE_11B,
-                               sc->ah->ah_capabilities.cap_mode)) {
-                               ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
-                                       ath5k_chip_name(AR5K_VERSION_RAD,
-                                               sc->ah->ah_radio_5ghz_revision),
-                                               sc->ah->ah_radio_5ghz_revision);
-                       /* Multiband radio */
-                       } else {
-                               ATH5K_INFO(sc, "RF%s multiband radio found"
-                                       " (0x%x)\n",
-                                       ath5k_chip_name(AR5K_VERSION_RAD,
-                                               sc->ah->ah_radio_5ghz_revision),
-                                               sc->ah->ah_radio_5ghz_revision);
-                       }
-               }
-               /* Multi chip radio (RF5111 - RF2111) ->
-                * report both 2GHz/5GHz radios */
-               else if (sc->ah->ah_radio_5ghz_revision &&
-                               sc->ah->ah_radio_2ghz_revision){
-                       ATH5K_INFO(sc, "RF%s 5GHz radio found (0x%x)\n",
-                               ath5k_chip_name(AR5K_VERSION_RAD,
-                                       sc->ah->ah_radio_5ghz_revision),
-                                       sc->ah->ah_radio_5ghz_revision);
-                       ATH5K_INFO(sc, "RF%s 2GHz radio found (0x%x)\n",
-                               ath5k_chip_name(AR5K_VERSION_RAD,
-                                       sc->ah->ah_radio_2ghz_revision),
-                                       sc->ah->ah_radio_2ghz_revision);
-               }
-       }
-
-       ath5k_debug_init_device(sc);
-
-       /* ready to process interrupts */
-       __clear_bit(ATH_STAT_INVALID, sc->status);
-
-       return 0;
-err_ah:
-       ath5k_hw_detach(sc->ah);
-err_free_ah:
-       kfree(sc->ah);
-err_irq:
-       free_irq(pdev->irq, sc);
-err_free:
-       ieee80211_free_hw(hw);
-err_map:
-       pci_iounmap(pdev, mem);
-err_reg:
-       pci_release_region(pdev, 0);
-err_dis:
-       pci_disable_device(pdev);
-err:
-       return ret;
-}
-
-static void __devexit
-ath5k_pci_remove(struct pci_dev *pdev)
-{
-       struct ath5k_softc *sc = pci_get_drvdata(pdev);
-
-       ath5k_debug_finish_device(sc);
-       ath5k_detach(pdev, sc->hw);
-       ath5k_hw_detach(sc->ah);
-       kfree(sc->ah);
-       free_irq(pdev->irq, sc);
-       pci_iounmap(pdev, sc->iobase);
-       pci_release_region(pdev, 0);
-       pci_disable_device(pdev);
-       ieee80211_free_hw(sc->hw);
-}
-
-#ifdef CONFIG_PM_SLEEP
-static int ath5k_pci_suspend(struct device *dev)
-{
-       struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev));
-
-       ath5k_led_off(sc);
-       return 0;
-}
-
-static int ath5k_pci_resume(struct device *dev)
-{
-       struct pci_dev *pdev = to_pci_dev(dev);
-       struct ath5k_softc *sc = pci_get_drvdata(pdev);
-
-       /*
-        * Suspend/Resume resets the PCI configuration space, so we have to
-        * re-disable the RETRY_TIMEOUT register (0x41) to keep
-        * PCI Tx retries from interfering with C3 CPU state
-        */
-       pci_write_config_byte(pdev, 0x41, 0);
-
-       ath5k_led_enable(sc);
-       return 0;
-}
-
-static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume);
-#define ATH5K_PM_OPS   (&ath5k_pm_ops)
-#else
-#define ATH5K_PM_OPS   NULL
-#endif /* CONFIG_PM_SLEEP */
-
-static struct pci_driver ath5k_pci_driver = {
-       .name           = KBUILD_MODNAME,
-       .id_table       = ath5k_pci_id_table,
-       .probe          = ath5k_pci_probe,
-       .remove         = __devexit_p(ath5k_pci_remove),
-       .driver.pm      = ATH5K_PM_OPS,
-};
-
-/*
- * Module init/exit functions
- */
-static int __init
-init_ath5k_pci(void)
-{
-       int ret;
-
-       ret = pci_register_driver(&ath5k_pci_driver);
-       if (ret) {
-               printk(KERN_ERR "ath5k_pci: can't register pci driver\n");
-               return ret;
-       }
-
-       return 0;
-}
-
-static void __exit
-exit_ath5k_pci(void)
-{
-       pci_unregister_driver(&ath5k_pci_driver);
-}
-
-module_init(init_ath5k_pci);
-module_exit(exit_ath5k_pci);
index 9a79773cdc2a43f59ccbddf2a53f51172e06d8a6..aa6c32aafb5927102160c0aba6f6dd77074800b5 100644 (file)
@@ -169,7 +169,10 @@ struct ath5k_vif {
 /* Software Carrier, keeps track of the driver state
  * associated with an instance of a device */
 struct ath5k_softc {
-       struct pci_dev          *pdev;          /* for dma mapping */
+       struct pci_dev          *pdev;
+       struct device           *dev;           /* for dma mapping */
+       int irq;
+       u16 devid;
        void __iomem            *iobase;        /* address of the device */
        struct mutex            lock;           /* dev-level lock */
        struct ieee80211_hw     *hw;            /* IEEE 802.11 common */
index beae519aa735a63e91e7dc8ff2cab52b2493f695..31cad80e9b01f84c17e536371ce25f6887ca74e4 100644 (file)
@@ -49,7 +49,6 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
 
                /* Set supported modes */
                __set_bit(AR5K_MODE_11A, ah->ah_capabilities.cap_mode);
-               __set_bit(AR5K_MODE_11A_TURBO, ah->ah_capabilities.cap_mode);
        } else {
                /*
                 * XXX The tranceiver supports frequencies from 4920 to 6100GHz
@@ -74,11 +73,6 @@ int ath5k_hw_set_capabilities(struct ath5k_hw *ah)
                        /* Set supported modes */
                        __set_bit(AR5K_MODE_11A,
                                        ah->ah_capabilities.cap_mode);
-                       __set_bit(AR5K_MODE_11A_TURBO,
-                                       ah->ah_capabilities.cap_mode);
-                       if (ah->ah_version == AR5K_AR5212)
-                               __set_bit(AR5K_MODE_11G_TURBO,
-                                               ah->ah_capabilities.cap_mode);
                }
 
                /* Enable  802.11b if a 2GHz capable radio (2111/5112) is
index 7d785cb60ce0a02a426f065a97f42c2fbdf2f101..5341dd2860d32cfbb38554004d488408ab3d4bb7 100644 (file)
@@ -312,6 +312,7 @@ static const struct {
        { ATH5K_DEBUG_DUMP_RX,  "dumprx",       "print received skb content" },
        { ATH5K_DEBUG_DUMP_TX,  "dumptx",       "print transmit skb content" },
        { ATH5K_DEBUG_DUMPBANDS, "dumpbands",   "dump bands" },
+       { ATH5K_DEBUG_DMA,      "dma",          "dma start/stop" },
        { ATH5K_DEBUG_ANI,      "ani",          "adaptive noise immunity" },
        { ATH5K_DEBUG_DESC,     "desc",         "descriptor chains" },
        { ATH5K_DEBUG_ANY,      "all",          "show all debug levels" },
index 236edbd2507ddaa4a7a26eecadc79aadfe4f9219..3e34428d5126146b1cab147ef5a82f0858069e04 100644 (file)
@@ -95,6 +95,7 @@ struct ath5k_dbg_info {
  * @ATH5K_DEBUG_DUMP_RX: print received skb content
  * @ATH5K_DEBUG_DUMP_TX: print transmit skb content
  * @ATH5K_DEBUG_DUMPBANDS: dump bands
+ * @ATH5K_DEBUG_DMA: debug dma start/stop
  * @ATH5K_DEBUG_TRACE: trace function calls
  * @ATH5K_DEBUG_DESC: descriptor setup
  * @ATH5K_DEBUG_ANY: show at any debug level
@@ -118,6 +119,7 @@ enum ath5k_debug_level {
        ATH5K_DEBUG_DUMP_RX     = 0x00000100,
        ATH5K_DEBUG_DUMP_TX     = 0x00000200,
        ATH5K_DEBUG_DUMPBANDS   = 0x00000400,
+       ATH5K_DEBUG_DMA         = 0x00000800,
        ATH5K_DEBUG_ANI         = 0x00002000,
        ATH5K_DEBUG_DESC        = 0x00004000,
        ATH5K_DEBUG_ANY         = 0xffffffff
index 43244382f213f67b4733c2cd9b50c0c7ce90db18..16b44ff7dd3e925f069cdfff8977c84866334a7c 100644 (file)
 #include "debug.h"
 #include "base.h"
 
-/*
- * TX Descriptors
- */
+
+/************************\
+* TX Control descriptors *
+\************************/
 
 /*
  * Initialize the 2-word tx control descriptor on 5210/5211
@@ -335,6 +336,11 @@ ath5k_hw_setup_mrr_tx_desc(struct ath5k_hw *ah, struct ath5k_desc *desc,
        return 0;
 }
 
+
+/***********************\
+* TX Status descriptors *
+\***********************/
+
 /*
  * Proccess the tx status descriptor on 5210/5211
  */
@@ -476,9 +482,10 @@ static int ath5k_hw_proc_4word_tx_status(struct ath5k_hw *ah,
        return 0;
 }
 
-/*
- * RX Descriptors
- */
+
+/****************\
+* RX Descriptors *
+\****************/
 
 /*
  * Initialize an rx control descriptor
@@ -666,6 +673,11 @@ static int ath5k_hw_proc_5212_rx_status(struct ath5k_hw *ah,
        return 0;
 }
 
+
+/********\
+* Attach *
+\********/
+
 /*
  * Init function pointers inside ath5k_hw struct
  */
index 923c9ca5c4f0fe424186ff978839eca80c9c2617..82541fec9f0e08731c2341aa693bd6da981583a5 100644 (file)
@@ -37,6 +37,7 @@
 #include "debug.h"
 #include "base.h"
 
+
 /*********\
 * Receive *
 \*********/
@@ -57,7 +58,7 @@ void ath5k_hw_start_rx_dma(struct ath5k_hw *ah)
  *
  * @ah:        The &struct ath5k_hw
  */
-int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
+static int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
 {
        unsigned int i;
 
@@ -69,7 +70,11 @@ int ath5k_hw_stop_rx_dma(struct ath5k_hw *ah)
        for (i = 1000; i > 0 &&
                        (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) != 0;
                        i--)
-               udelay(10);
+               udelay(100);
+
+       if (i)
+               ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA,
+                               "failed to stop RX DMA !\n");
 
        return i ? 0 : -EBUSY;
 }
@@ -90,11 +95,18 @@ u32 ath5k_hw_get_rxdp(struct ath5k_hw *ah)
  * @ah: The &struct ath5k_hw
  * @phys_addr: RX descriptor address
  *
- * XXX: Should we check if rx is enabled before setting rxdp ?
+ * Returns -EIO if rx is active
  */
-void ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
+int ath5k_hw_set_rxdp(struct ath5k_hw *ah, u32 phys_addr)
 {
+       if (ath5k_hw_reg_read(ah, AR5K_CR) & AR5K_CR_RXE) {
+               ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA,
+                               "tried to set RXDP while rx was active !\n");
+               return -EIO;
+       }
+
        ath5k_hw_reg_write(ah, phys_addr, AR5K_RXDP);
+       return 0;
 }
 
 
@@ -125,7 +137,7 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
 
        /* Return if queue is declared inactive */
        if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
-               return -EIO;
+               return -EINVAL;
 
        if (ah->ah_version == AR5K_AR5210) {
                tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
@@ -173,10 +185,10 @@ int ath5k_hw_start_tx_dma(struct ath5k_hw *ah, unsigned int queue)
  *
  * Stop DMA transmit on a specific hw queue and drain queue so we don't
  * have any pending frames. Returns -EBUSY if we still have pending frames,
- * -EINVAL if queue number is out of range.
+ * -EINVAL if queue number is out of range or inactive.
  *
  */
-int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
+static int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
 {
        unsigned int i = 40;
        u32 tx_queue, pending;
@@ -185,7 +197,7 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
 
        /* Return if queue is declared inactive */
        if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
-               return -EIO;
+               return -EINVAL;
 
        if (ah->ah_version == AR5K_AR5210) {
                tx_queue = ath5k_hw_reg_read(ah, AR5K_CR);
@@ -211,12 +223,31 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
                ath5k_hw_reg_write(ah, tx_queue, AR5K_CR);
                ath5k_hw_reg_read(ah, AR5K_CR);
        } else {
+
+               /*
+                * Enable DCU early termination to quickly
+                * flush any pending frames from QCU
+                */
+               AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+                                       AR5K_QCU_MISC_DCU_EARLY);
+
                /*
                 * Schedule TX disable and wait until queue is empty
                 */
                AR5K_REG_WRITE_Q(ah, AR5K_QCU_TXD, queue);
 
-               /*Check for pending frames*/
+               /* Wait for queue to stop */
+               for (i = 1000; i > 0 &&
+               (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue) != 0);
+               i--)
+                       udelay(100);
+
+               if (AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
+                       ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA,
+                               "queue %i didn't stop !\n", queue);
+
+               /* Check for pending frames */
+               i = 1000;
                do {
                        pending = ath5k_hw_reg_read(ah,
                                AR5K_QUEUE_STATUS(queue)) &
@@ -247,12 +278,12 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
                                        AR5K_DIAG_SW_CHANNEL_IDLE_HIGH);
 
                        /* Wait a while and disable mechanism */
-                       udelay(200);
+                       udelay(400);
                        AR5K_REG_DISABLE_BITS(ah, AR5K_QUIET_CTL1,
                                                AR5K_QUIET_CTL1_QT_EN);
 
                        /* Re-check for pending frames */
-                       i = 40;
+                       i = 100;
                        do {
                                pending = ath5k_hw_reg_read(ah,
                                        AR5K_QUEUE_STATUS(queue)) &
@@ -262,18 +293,53 @@ int ath5k_hw_stop_tx_dma(struct ath5k_hw *ah, unsigned int queue)
 
                        AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW_5211,
                                        AR5K_DIAG_SW_CHANNEL_IDLE_HIGH);
+
+                       if (pending)
+                               ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA,
+                                       "quiet mechanism didn't work q:%i !\n",
+                                       queue);
                }
 
+               /*
+                * Disable DCU early termination
+                */
+               AR5K_REG_DISABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+                                       AR5K_QCU_MISC_DCU_EARLY);
+
                /* Clear register */
                ath5k_hw_reg_write(ah, 0, AR5K_QCU_TXD);
-               if (pending)
+               if (pending) {
+                       ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA,
+                                       "tx dma didn't stop (q:%i, frm:%i) !\n",
+                                       queue, pending);
                        return -EBUSY;
+               }
        }
 
        /* TODO: Check for success on 5210 else return error */
        return 0;
 }
 
+/**
+ * ath5k_hw_stop_beacon_queue - Stop beacon queue
+ *
+ * @ah The &struct ath5k_hw
+ * @queue The queue number
+ *
+ * Returns -EIO if queue didn't stop
+ */
+int ath5k_hw_stop_beacon_queue(struct ath5k_hw *ah, unsigned int queue)
+{
+       int ret;
+       ret = ath5k_hw_stop_tx_dma(ah, queue);
+       if (ret) {
+               ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_DMA,
+                               "beacon queue didn't stop !\n");
+               return -EIO;
+       }
+       return 0;
+}
+
 /**
  * ath5k_hw_get_txdp - Get TX Descriptor's address for a specific queue
  *
@@ -427,6 +493,7 @@ done:
        return ret;
 }
 
+
 /*******************\
 * Interrupt masking *
 \*******************/
@@ -688,3 +755,92 @@ enum ath5k_int ath5k_hw_set_imr(struct ath5k_hw *ah, enum ath5k_int new_mask)
        return old_mask;
 }
 
+
+/********************\
+ Init/Stop functions
+\********************/
+
+/**
+ * ath5k_hw_dma_init - Initialize DMA unit
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Set DMA size and pre-enable interrupts
+ * (driver handles tx/rx buffer setup and
+ * dma start/stop)
+ *
+ * XXX: Save/restore RXDP/TXDP registers ?
+ */
+void ath5k_hw_dma_init(struct ath5k_hw *ah)
+{
+       /*
+        * Set Rx/Tx DMA Configuration
+        *
+        * Set standard DMA size (128). Note that
+        * a DMA size of 512 causes rx overruns and tx errors
+        * on pci-e cards (tested on 5424 but since rx overruns
+        * also occur on 5416/5418 with madwifi we set 128
+        * for all PCI-E cards to be safe).
+        *
+        * XXX: need to check 5210 for this
+        * TODO: Check out tx triger level, it's always 64 on dumps but I
+        * guess we can tweak it and see how it goes ;-)
+        */
+       if (ah->ah_version != AR5K_AR5210) {
+               AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
+                       AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
+               AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
+                       AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B);
+       }
+
+       /* Pre-enable interrupts on 5211/5212*/
+       if (ah->ah_version != AR5K_AR5210)
+               ath5k_hw_set_imr(ah, ah->ah_imr);
+
+}
+
+/**
+ * ath5k_hw_dma_stop - stop DMA unit
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Stop tx/rx DMA and interrupts. Returns
+ * -EBUSY if tx or rx dma failed to stop.
+ *
+ * XXX: Sometimes DMA unit hangs and we have
+ * stuck frames on tx queues, only a reset
+ * can fix that.
+ */
+int ath5k_hw_dma_stop(struct ath5k_hw *ah)
+{
+       int i, qmax, err;
+       err = 0;
+
+       /* Disable interrupts */
+       ath5k_hw_set_imr(ah, 0);
+
+       /* Stop rx dma */
+       err = ath5k_hw_stop_rx_dma(ah);
+       if (err)
+               return err;
+
+       /* Clear any pending interrupts
+        * and disable tx dma */
+       if (ah->ah_version != AR5K_AR5210) {
+               ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR);
+               qmax = AR5K_NUM_TX_QUEUES;
+       } else {
+               /* PISR/SISR Not available on 5210 */
+               ath5k_hw_reg_read(ah, AR5K_ISR);
+               qmax = AR5K_NUM_TX_QUEUES_NOQCU;
+       }
+
+       for (i = 0; i < qmax; i++) {
+               err = ath5k_hw_stop_tx_dma(ah, i);
+               /* -EINVAL -> queue inactive */
+               if (err != -EINVAL)
+                       return err;
+       }
+
+       return err;
+}
index 39722dd73e433ae606f2ef6804b18c1ff23b70fa..97eaa9a4415ed9f36b18111878689ae135793c7b 100644 (file)
 #include "debug.h"
 #include "base.h"
 
-/*
- * Read from eeprom
- */
-static int ath5k_hw_eeprom_read(struct ath5k_hw *ah, u32 offset, u16 *data)
-{
-       u32 status, timeout;
-
-       /*
-        * Initialize EEPROM access
-        */
-       if (ah->ah_version == AR5K_AR5210) {
-               AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
-               (void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset));
-       } else {
-               ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
-               AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
-                               AR5K_EEPROM_CMD_READ);
-       }
 
-       for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
-               status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
-               if (status & AR5K_EEPROM_STAT_RDDONE) {
-                       if (status & AR5K_EEPROM_STAT_RDERR)
-                               return -EIO;
-                       *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) &
-                                       0xffff);
-                       return 0;
-               }
-               udelay(15);
-       }
-
-       return -ETIMEDOUT;
-}
+/******************\
+* Helper functions *
+\******************/
 
 /*
  * Translate binary channel representation in EEPROM to frequency
  */
 static u16 ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, u16 bin,
-                                 unsigned int mode)
+                                                       unsigned int mode)
 {
        u16 val;
 
@@ -89,6 +60,11 @@ static u16 ath5k_eeprom_bin2freq(struct ath5k_eeprom_info *ee, u16 bin,
        return val;
 }
 
+
+/*********\
+* Parsers *
+\*********/
+
 /*
  * Initialize eeprom & capabilities structs
  */
@@ -198,7 +174,7 @@ ath5k_eeprom_init_header(struct ath5k_hw *ah)
         *
         * XXX: Serdes values seem to be fixed so
         * no need to read them here, we write them
-        * during ath5k_hw_attach */
+        * during ath5k_hw_init */
        AR5K_EEPROM_READ(AR5K_EEPROM_PCIE_OFFSET, val);
        ee->ee_serdes = (val == AR5K_EEPROM_PCIE_SERDES_SECTION) ?
                                                        true : false;
@@ -647,6 +623,7 @@ ath5k_eeprom_init_11bg_2413(struct ath5k_hw *ah, unsigned int mode, int offset)
        return 0;
 }
 
+
 /*
  * Read power calibration for RF5111 chips
  *
@@ -1514,6 +1491,7 @@ ath5k_eeprom_read_target_rate_pwr_info(struct ath5k_hw *ah, unsigned int mode)
        return 0;
 }
 
+
 /*
  * Read per channel calibration info from EEPROM
  *
@@ -1607,15 +1585,6 @@ ath5k_eeprom_free_pcal_info(struct ath5k_hw *ah, int mode)
        return 0;
 }
 
-void
-ath5k_eeprom_detach(struct ath5k_hw *ah)
-{
-       u8 mode;
-
-       for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++)
-               ath5k_eeprom_free_pcal_info(ah, mode);
-}
-
 /* Read conformance test limits used for regulatory control */
 static int
 ath5k_eeprom_read_ctl_info(struct ath5k_hw *ah)
@@ -1756,6 +1725,44 @@ ath5k_eeprom_read_spur_chans(struct ath5k_hw *ah)
        return ret;
 }
 
+/*
+ * Read the MAC address from eeprom
+ */
+int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
+{
+       u8 mac_d[ETH_ALEN] = {};
+       u32 total, offset;
+       u16 data;
+       int octet, ret;
+
+       ret = ath5k_hw_nvram_read(ah, 0x20, &data);
+       if (ret)
+               return ret;
+
+       for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
+               ret = ath5k_hw_nvram_read(ah, offset, &data);
+               if (ret)
+                       return ret;
+
+               total += data;
+               mac_d[octet + 1] = data & 0xff;
+               mac_d[octet] = data >> 8;
+               octet += 2;
+       }
+
+       if (!total || total == 3 * 0xffff)
+               return -EINVAL;
+
+       memcpy(mac, mac_d, ETH_ALEN);
+
+       return 0;
+}
+
+
+/***********************\
+* Init/Detach functions *
+\***********************/
+
 /*
  * Initialize eeprom data structure
  */
@@ -1787,35 +1794,11 @@ ath5k_eeprom_init(struct ath5k_hw *ah)
        return 0;
 }
 
-/*
- * Read the MAC address from eeprom
- */
-int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
+void
+ath5k_eeprom_detach(struct ath5k_hw *ah)
 {
-       u8 mac_d[ETH_ALEN] = {};
-       u32 total, offset;
-       u16 data;
-       int octet, ret;
-
-       ret = ath5k_hw_eeprom_read(ah, 0x20, &data);
-       if (ret)
-               return ret;
-
-       for (offset = 0x1f, octet = 0, total = 0; offset >= 0x1d; offset--) {
-               ret = ath5k_hw_eeprom_read(ah, offset, &data);
-               if (ret)
-                       return ret;
-
-               total += data;
-               mac_d[octet + 1] = data & 0xff;
-               mac_d[octet] = data >> 8;
-               octet += 2;
-       }
-
-       if (!total || total == 3 * 0xffff)
-               return -EINVAL;
-
-       memcpy(mac, mac_d, ETH_ALEN);
+       u8 mode;
 
-       return 0;
+       for (mode = AR5K_EEPROM_MODE_11A; mode <= AR5K_EEPROM_MODE_11G; mode++)
+               ath5k_eeprom_free_pcal_info(ah, mode);
 }
index c4a6d5f26af4f08ac9b379a22045aaed1a6c5c84..0017006be8414d5f07a83a7f08746efe969ef508 100644 (file)
@@ -241,7 +241,7 @@ enum ath5k_eeprom_freq_bands{
 #define        AR5K_SPUR_SYMBOL_WIDTH_TURBO_100Hz      6250
 
 #define AR5K_EEPROM_READ(_o, _v) do {                  \
-       ret = ath5k_hw_eeprom_read(ah, (_o), &(_v));    \
+       ret = ath5k_hw_nvram_read(ah, (_o), &(_v));     \
        if (ret)                                        \
                return ret;                             \
 } while (0)
index 8fa4393088285c4e2f59ad78b65893a89a995aef..e49340d18df48694b8e6be1bf483929cfdf13757 100644 (file)
@@ -44,7 +44,7 @@ struct ath5k_ini {
 
 struct ath5k_ini_mode {
        u16     mode_register;
-       u32     mode_value[5];
+       u32     mode_value[3];
 };
 
 /* Initial register settings for AR5210 */
@@ -391,76 +391,74 @@ static const struct ath5k_ini ar5211_ini[] = {
  */
 static const struct ath5k_ini_mode ar5211_ini_mode[] = {
        { AR5K_TXCFG,
-       /*        a         aTurbo        b       g (OFDM)    */
-          { 0x00000015, 0x00000015, 0x0000001d, 0x00000015 } },
+       /*      A/XR          B           G       */
+          { 0x00000015, 0x0000001d, 0x00000015 } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(0),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(1),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(2),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(3),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(4),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(5),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(6),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(7),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(8),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(9),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_DCU_GBL_IFS_SLOT,
-          { 0x00000168, 0x000001e0, 0x000001b8, 0x00000168 } },
+          { 0x00000168, 0x000001b8, 0x00000168 } },
        { AR5K_DCU_GBL_IFS_SIFS,
-          { 0x00000230, 0x000001e0, 0x000000b0, 0x00000230 } },
+          { 0x00000230, 0x000000b0, 0x00000230 } },
        { AR5K_DCU_GBL_IFS_EIFS,
-          { 0x00000d98, 0x00001180, 0x00001f48, 0x00000d98 } },
+          { 0x00000d98, 0x00001f48, 0x00000d98 } },
        { AR5K_DCU_GBL_IFS_MISC,
-          { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000a0e0 } },
+          { 0x0000a0e0, 0x00005880, 0x0000a0e0 } },
        { AR5K_TIME_OUT,
-          { 0x04000400, 0x08000800, 0x20003000, 0x04000400 } },
+          { 0x04000400, 0x20003000, 0x04000400 } },
        { AR5K_USEC_5211,
-          { 0x0e8d8fa7, 0x0e8d8fcf, 0x01608f95, 0x0e8d8fa7 } },
-       { AR5K_PHY_TURBO,
-          { 0x00000000, 0x00000003, 0x00000000, 0x00000000 } },
+          { 0x0e8d8fa7, 0x01608f95, 0x0e8d8fa7 } },
        { AR5K_PHY(8),
-          { 0x02020200, 0x02020200, 0x02010200, 0x02020200 } },
-       { AR5K_PHY(9),
-          { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e } },
-       { AR5K_PHY(10),
-          { 0x0a020001, 0x0a020001, 0x05010000, 0x0a020001 } },
-       { AR5K_PHY(13),
-          { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
-       { AR5K_PHY(14),
-          { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b } },
-       { AR5K_PHY(17),
-          { 0x1372169c, 0x137216a5, 0x137216a8, 0x1372169c } },
-       { AR5K_PHY(18),
-          { 0x0018ba67, 0x0018ba67, 0x0018ba69, 0x0018ba69 } },
-       { AR5K_PHY(20),
-          { 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 } },
+          { 0x02020200, 0x02010200, 0x02020200 } },
+       { AR5K_PHY_RF_CTL2,
+          { 0x00000e0e, 0x00000707, 0x00000e0e } },
+       { AR5K_PHY_RF_CTL3,
+          { 0x0a020001, 0x05010000, 0x0a020001 } },
+       { AR5K_PHY_RF_CTL4,
+          { 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+       { AR5K_PHY_PA_CTL,
+          { 0x00000007, 0x0000000b, 0x0000000b } },
+       { AR5K_PHY_SETTLING,
+          { 0x1372169c, 0x137216a8, 0x1372169c } },
+       { AR5K_PHY_GAIN,
+          { 0x0018ba67, 0x0018ba69, 0x0018ba69 } },
+       { AR5K_PHY_DESIRED_SIZE,
+          { 0x0c28b4e0, 0x0c28b4e0, 0x0c28b4e0 } },
        { AR5K_PHY_SIG,
-          { 0x7e800d2e, 0x7e800d2e, 0x7ec00d2e, 0x7e800d2e } },
+          { 0x7e800d2e, 0x7ec00d2e, 0x7e800d2e } },
        { AR5K_PHY_AGCCOARSE,
-          { 0x31375d5e, 0x31375d5e, 0x313a5d5e, 0x31375d5e } },
+          { 0x31375d5e, 0x313a5d5e, 0x31375d5e } },
        { AR5K_PHY_AGCCTL,
-          { 0x0000bd10, 0x0000bd10, 0x0000bd38, 0x0000bd10 } },
+          { 0x0000bd10, 0x0000bd38, 0x0000bd10 } },
        { AR5K_PHY_NF,
-          { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
+          { 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
        { AR5K_PHY_RX_DELAY,
-          { 0x00002710, 0x00002710, 0x0000157c, 0x00002710 } },
+          { 0x00002710, 0x0000157c, 0x00002710 } },
        { AR5K_PHY(70),
-          { 0x00000190, 0x00000190, 0x00000084, 0x00000190 } },
+          { 0x00000190, 0x00000084, 0x00000190 } },
        { AR5K_PHY_FRAME_CTL_5211,
-          { 0x6fe01020, 0x6fe01020, 0x6fe00920, 0x6fe01020 } },
+          { 0x6fe01020, 0x6fe00920, 0x6fe01020 } },
        { AR5K_PHY_PCDAC_TXPOWER_BASE,
-          { 0x05ff14ff, 0x05ff14ff, 0x05ff14ff, 0x05ff19ff } },
+          { 0x05ff14ff, 0x05ff14ff, 0x05ff19ff } },
        { AR5K_RF_BUFFER_CONTROL_4,
-          { 0x00000010, 0x00000014, 0x00000010, 0x00000010 } },
+          { 0x00000010, 0x00000010, 0x00000010 } },
 };
 
 /* Initial register settings for AR5212 */
@@ -677,89 +675,87 @@ static const struct ath5k_ini ar5212_ini_common_start[] = {
 /* Initial mode-specific settings for AR5212 (Written before ar5212_ini) */
 static const struct ath5k_ini_mode ar5212_ini_mode_start[] = {
        { AR5K_QUEUE_DFS_LOCAL_IFS(0),
-       /*      a/XR       aTurbo         b        g (DYN)     gTurbo     */
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+       /*      A/XR          B           G       */
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(1),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(2),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(3),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(4),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(5),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(6),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(7),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(8),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_QUEUE_DFS_LOCAL_IFS(9),
-          { 0x002ffc0f, 0x002ffc0f, 0x002ffc1f, 0x002ffc0f, 0x002ffc0f } },
+          { 0x002ffc0f, 0x002ffc1f, 0x002ffc0f } },
        { AR5K_DCU_GBL_IFS_SIFS,
-          { 0x00000230, 0x000001e0, 0x000000b0, 0x00000160, 0x000001e0 } },
+          { 0x00000230, 0x000000b0, 0x00000160 } },
        { AR5K_DCU_GBL_IFS_SLOT,
-          { 0x00000168, 0x000001e0, 0x000001b8, 0x0000018c, 0x000001e0 } },
+          { 0x00000168, 0x000001b8, 0x0000018c } },
        { AR5K_DCU_GBL_IFS_EIFS,
-          { 0x00000e60, 0x00001180, 0x00001f1c, 0x00003e38, 0x00001180 } },
+          { 0x00000e60, 0x00001f1c, 0x00003e38 } },
        { AR5K_DCU_GBL_IFS_MISC,
-          { 0x0000a0e0, 0x00014068, 0x00005880, 0x0000b0e0, 0x00014068 } },
+          { 0x0000a0e0, 0x00005880, 0x0000b0e0 } },
        { AR5K_TIME_OUT,
-          { 0x03e803e8, 0x06e006e0, 0x04200420, 0x08400840, 0x06e006e0 } },
-       { AR5K_PHY_TURBO,
-          { 0x00000000, 0x00000003, 0x00000000, 0x00000000, 0x00000003 } },
+          { 0x03e803e8, 0x04200420, 0x08400840 } },
        { AR5K_PHY(8),
-          { 0x02020200, 0x02020200, 0x02010200, 0x02020200, 0x02020200 } },
+          { 0x02020200, 0x02010200, 0x02020200 } },
        { AR5K_PHY_RF_CTL2,
-          { 0x00000e0e, 0x00000e0e, 0x00000707, 0x00000e0e, 0x00000e0e } },
+          { 0x00000e0e, 0x00000707, 0x00000e0e } },
        { AR5K_PHY_SETTLING,
-          { 0x1372161c, 0x13721c25, 0x13721722, 0x137216a2, 0x13721c25 } },
+          { 0x1372161c, 0x13721722, 0x137216a2 } },
        { AR5K_PHY_AGCCTL,
-          { 0x00009d10, 0x00009d10, 0x00009d18, 0x00009d18, 0x00009d10 } },
+          { 0x00009d10, 0x00009d18, 0x00009d18 } },
        { AR5K_PHY_NF,
-          { 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
+          { 0x0001ce00, 0x0001ce00, 0x0001ce00 } },
        { AR5K_PHY_WEAK_OFDM_HIGH_THR,
-          { 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190, 0x409a4190 } },
+          { 0x409a4190, 0x409a4190, 0x409a4190 } },
        { AR5K_PHY(70),
-          { 0x000001b8, 0x000001b8, 0x00000084, 0x00000108, 0x000001b8 } },
+          { 0x000001b8, 0x00000084, 0x00000108 } },
        { AR5K_PHY_OFDM_SELFCORR,
-          { 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05, 0x10058a05 } },
+          { 0x10058a05, 0x10058a05, 0x10058a05 } },
        { 0xa230,
-          { 0x00000000, 0x00000000, 0x00000000, 0x00000108, 0x00000000 } },
+          { 0x00000000, 0x00000000, 0x00000108 } },
 };
 
 /* Initial mode-specific settings for AR5212 + RF5111 (Written after ar5212_ini) */
 static const struct ath5k_ini_mode rf5111_ini_mode_end[] = {
        { AR5K_TXCFG,
-       /*      a/XR       aTurbo         b        g (DYN)     gTurbo     */
-          { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
+       /*      A/XR          B           G       */
+          { 0x00008015, 0x00008015, 0x00008015 } },
        { AR5K_USEC_5211,
-          { 0x128d8fa7, 0x09880fcf, 0x04e00f95, 0x12e00fab, 0x09880fcf } },
+          { 0x128d8fa7, 0x04e00f95, 0x12e00fab } },
        { AR5K_PHY_RF_CTL3,
-          { 0x0a020001, 0x0a020001, 0x05010100, 0x0a020001, 0x0a020001 } },
+          { 0x0a020001, 0x05010100, 0x0a020001 } },
        { AR5K_PHY_RF_CTL4,
-          { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+          { 0x00000e0e, 0x00000e0e, 0x00000e0e } },
        { AR5K_PHY_PA_CTL,
-          { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+          { 0x00000007, 0x0000000b, 0x0000000b } },
        { AR5K_PHY_GAIN,
-          { 0x0018da5a, 0x0018da5a, 0x0018ca69, 0x0018ca69, 0x0018ca69 } },
+          { 0x0018da5a, 0x0018ca69, 0x0018ca69 } },
        { AR5K_PHY_DESIRED_SIZE,
-          { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
+          { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
        { AR5K_PHY_SIG,
-          { 0x7e800d2e, 0x7e800d2e, 0x7ee84d2e, 0x7ee84d2e, 0x7e800d2e } },
+          { 0x7e800d2e, 0x7ee84d2e, 0x7ee84d2e } },
        { AR5K_PHY_AGCCOARSE,
-          { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137615e } },
+          { 0x3137665e, 0x3137665e, 0x3137665e } },
        { AR5K_PHY_WEAK_OFDM_LOW_THR,
-          { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb080, 0x050cb080 } },
+          { 0x050cb081, 0x050cb081, 0x050cb080 } },
        { AR5K_PHY_RX_DELAY,
-          { 0x00002710, 0x00002710, 0x0000157c, 0x00002af8, 0x00002710 } },
+          { 0x00002710, 0x0000157c, 0x00002af8 } },
        { AR5K_PHY_FRAME_CTL_5211,
-          { 0xf7b81020, 0xf7b81020, 0xf7b80d20, 0xf7b81020, 0xf7b81020 } },
+          { 0xf7b81020, 0xf7b80d20, 0xf7b81020 } },
        { AR5K_PHY_GAIN_2GHZ,
-          { 0x642c416a, 0x642c416a, 0x6440416a, 0x6440416a, 0x6440416a } },
+          { 0x642c416a, 0x6440416a, 0x6440416a } },
        { AR5K_PHY_CCK_RX_CTL_4,
-          { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
+          { 0x1883800a, 0x1873800a, 0x1883800a } },
 };
 
 static const struct ath5k_ini rf5111_ini_common_end[] = {
@@ -782,38 +778,38 @@ static const struct ath5k_ini rf5111_ini_common_end[] = {
 /* Initial mode-specific settings for AR5212 + RF5112 (Written after ar5212_ini) */
 static const struct ath5k_ini_mode rf5112_ini_mode_end[] = {
        { AR5K_TXCFG,
-       /*      a/XR       aTurbo         b        g (DYN)     gTurbo     */
-          { 0x00008015, 0x00008015, 0x00008015, 0x00008015, 0x00008015 } },
+       /*      A/XR          B           G       */
+          { 0x00008015, 0x00008015, 0x00008015 } },
        { AR5K_USEC_5211,
-          { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+          { 0x128d93a7, 0x04e01395, 0x12e013ab } },
        { AR5K_PHY_RF_CTL3,
-          { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+          { 0x0a020001, 0x05020100, 0x0a020001 } },
        { AR5K_PHY_RF_CTL4,
-          { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+          { 0x00000e0e, 0x00000e0e, 0x00000e0e } },
        { AR5K_PHY_PA_CTL,
-          { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+          { 0x00000007, 0x0000000b, 0x0000000b } },
        { AR5K_PHY_GAIN,
-          { 0x0018da6d, 0x0018da6d, 0x0018ca75, 0x0018ca75, 0x0018ca75 } },
+          { 0x0018da6d, 0x0018ca75, 0x0018ca75 } },
        { AR5K_PHY_DESIRED_SIZE,
-          { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
+          { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b4e0 } },
        { AR5K_PHY_SIG,
-          { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e, 0x7e800d2e } },
+          { 0x7e800d2e, 0x7ee80d2e, 0x7ee80d2e } },
        { AR5K_PHY_AGCCOARSE,
-          { 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e, 0x3137665e } },
+          { 0x3137665e, 0x3137665e, 0x3137665e } },
        { AR5K_PHY_WEAK_OFDM_LOW_THR,
-          { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+          { 0x050cb081, 0x050cb081, 0x050cb081 } },
        { AR5K_PHY_RX_DELAY,
-          { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+          { 0x000007d0, 0x0000044c, 0x00000898 } },
        { AR5K_PHY_FRAME_CTL_5211,
-          { 0xf7b81020, 0xf7b81020, 0xf7b80d10, 0xf7b81010, 0xf7b81010 } },
+          { 0xf7b81020, 0xf7b80d10, 0xf7b81010 } },
        { AR5K_PHY_CCKTXCTL,
-          { 0x00000000, 0x00000000, 0x00000008, 0x00000008, 0x00000008 } },
+          { 0x00000000, 0x00000008, 0x00000008 } },
        { AR5K_PHY_CCK_CROSSCORR,
-          { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+          { 0xd6be6788, 0xd03e6788, 0xd03e6788 } },
        { AR5K_PHY_GAIN_2GHZ,
-          { 0x642c0140, 0x642c0140, 0x6442c160, 0x6442c160, 0x6442c160 } },
+          { 0x642c0140, 0x6442c160, 0x6442c160 } },
        { AR5K_PHY_CCK_RX_CTL_4,
-          { 0x1883800a, 0x1883800a, 0x1873800a, 0x1883800a, 0x1883800a } },
+          { 0x1883800a, 0x1873800a, 0x1883800a } },
 };
 
 static const struct ath5k_ini rf5112_ini_common_end[] = {
@@ -833,66 +829,66 @@ static const struct ath5k_ini rf5112_ini_common_end[] = {
 /* Initial mode-specific settings for RF5413/5414 (Written after ar5212_ini) */
 static const struct ath5k_ini_mode rf5413_ini_mode_end[] = {
        { AR5K_TXCFG,
-       /*      a/XR       aTurbo         b        g (DYN)     gTurbo     */
-          { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
+       /*      A/XR          B           G       */
+          { 0x00000015, 0x00000015, 0x00000015 } },
        { AR5K_USEC_5211,
-          { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+          { 0x128d93a7, 0x04e01395, 0x12e013ab } },
        { AR5K_PHY_RF_CTL3,
-          { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+          { 0x0a020001, 0x05020100, 0x0a020001 } },
        { AR5K_PHY_RF_CTL4,
-          { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+          { 0x00000e0e, 0x00000e0e, 0x00000e0e } },
        { AR5K_PHY_PA_CTL,
-          { 0x00000007, 0x00000007, 0x0000000b, 0x0000000b, 0x0000000b } },
+          { 0x00000007, 0x0000000b, 0x0000000b } },
        { AR5K_PHY_GAIN,
-          { 0x0018fa61, 0x0018fa61, 0x001a1a63, 0x001a1a63, 0x001a1a63 } },
+          { 0x0018fa61, 0x001a1a63, 0x001a1a63 } },
        { AR5K_PHY_DESIRED_SIZE,
-          { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } },
+          { 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da } },
        { AR5K_PHY_SIG,
-          { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
+          { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
        { AR5K_PHY_AGCCOARSE,
-          { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } },
+          { 0x3139605e, 0x3139605e, 0x3139605e } },
        { AR5K_PHY_WEAK_OFDM_LOW_THR,
-          { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+          { 0x050cb081, 0x050cb081, 0x050cb081 } },
        { AR5K_PHY_RX_DELAY,
-          { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+          { 0x000007d0, 0x0000044c, 0x00000898 } },
        { AR5K_PHY_FRAME_CTL_5211,
-          { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
+          { 0xf7b81000, 0xf7b80d00, 0xf7b81000 } },
        { AR5K_PHY_CCKTXCTL,
-          { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+          { 0x00000000, 0x00000000, 0x00000000 } },
        { AR5K_PHY_CCK_CROSSCORR,
-          { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+          { 0xd6be6788, 0xd03e6788, 0xd03e6788 } },
        { AR5K_PHY_GAIN_2GHZ,
-          { 0x002ec1e0, 0x002ec1e0, 0x002ac120, 0x002ac120, 0x002ac120 } },
+          { 0x002ec1e0, 0x002ac120, 0x002ac120 } },
        { AR5K_PHY_CCK_RX_CTL_4,
-          { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
+          { 0x1883800a, 0x1863800a, 0x1883800a } },
        { 0xa300,
-          { 0x18010000, 0x18010000, 0x18010000, 0x18010000, 0x18010000 } },
+          { 0x18010000, 0x18010000, 0x18010000 } },
        { 0xa304,
-          { 0x30032602, 0x30032602, 0x30032602, 0x30032602, 0x30032602 } },
+          { 0x30032602, 0x30032602, 0x30032602 } },
        { 0xa308,
-          { 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06, 0x48073e06 } },
+          { 0x48073e06, 0x48073e06, 0x48073e06 } },
        { 0xa30c,
-          { 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } },
+          { 0x560b4c0a, 0x560b4c0a, 0x560b4c0a } },
        { 0xa310,
-          { 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f, 0x641a600f } },
+          { 0x641a600f, 0x641a600f, 0x641a600f } },
        { 0xa314,
-          { 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } },
+          { 0x784f6e1b, 0x784f6e1b, 0x784f6e1b } },
        { 0xa318,
-          { 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } },
+          { 0x868f7c5a, 0x868f7c5a, 0x868f7c5a } },
        { 0xa31c,
-          { 0x90cf865b, 0x90cf865b, 0x8ecf865b, 0x8ecf865b, 0x8ecf865b } },
+          { 0x90cf865b, 0x8ecf865b, 0x8ecf865b } },
        { 0xa320,
-          { 0x9d4f970f, 0x9d4f970f, 0x9b4f970f, 0x9b4f970f, 0x9b4f970f } },
+          { 0x9d4f970f, 0x9b4f970f, 0x9b4f970f } },
        { 0xa324,
-          { 0xa7cfa38f, 0xa7cfa38f, 0xa3cf9f8f, 0xa3cf9f8f, 0xa3cf9f8f } },
+          { 0xa7cfa38f, 0xa3cf9f8f, 0xa3cf9f8f } },
        { 0xa328,
-          { 0xb55faf1f, 0xb55faf1f, 0xb35faf1f, 0xb35faf1f, 0xb35faf1f } },
+          { 0xb55faf1f, 0xb35faf1f, 0xb35faf1f } },
        { 0xa32c,
-          { 0xbddfb99f, 0xbddfb99f, 0xbbdfb99f, 0xbbdfb99f, 0xbbdfb99f } },
+          { 0xbddfb99f, 0xbbdfb99f, 0xbbdfb99f } },
        { 0xa330,
-          { 0xcb7fc53f, 0xcb7fc53f, 0xcb7fc73f, 0xcb7fc73f, 0xcb7fc73f } },
+          { 0xcb7fc53f, 0xcb7fc73f, 0xcb7fc73f } },
        { 0xa334,
-          { 0xd5ffd1bf, 0xd5ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf } },
+          { 0xd5ffd1bf, 0xd3ffd1bf, 0xd3ffd1bf } },
 };
 
 static const struct ath5k_ini rf5413_ini_common_end[] = {
@@ -972,38 +968,38 @@ static const struct ath5k_ini rf5413_ini_common_end[] = {
 /* XXX: a mode ? */
 static const struct ath5k_ini_mode rf2413_ini_mode_end[] = {
        { AR5K_TXCFG,
-       /*      a/XR       aTurbo         b        g (DYN)     gTurbo     */
-          { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
+       /*      A/XR          B           G       */
+          { 0x00000015, 0x00000015, 0x00000015 } },
        { AR5K_USEC_5211,
-          { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
+          { 0x128d93a7, 0x04e01395, 0x12e013ab } },
        { AR5K_PHY_RF_CTL3,
-          { 0x0a020001, 0x0a020001, 0x05020000, 0x0a020001, 0x0a020001 } },
+          { 0x0a020001, 0x05020000, 0x0a020001 } },
        { AR5K_PHY_RF_CTL4,
-          { 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00, 0x00000e00 } },
+          { 0x00000e00, 0x00000e00, 0x00000e00 } },
        { AR5K_PHY_PA_CTL,
-          { 0x00000002, 0x00000002, 0x0000000a, 0x0000000a, 0x0000000a } },
+          { 0x00000002, 0x0000000a, 0x0000000a } },
        { AR5K_PHY_GAIN,
-          { 0x0018da6d, 0x0018da6d, 0x001a6a64, 0x001a6a64, 0x001a6a64 } },
+          { 0x0018da6d, 0x001a6a64, 0x001a6a64 } },
        { AR5K_PHY_DESIRED_SIZE,
-          { 0x0de8b4e0, 0x0de8b4e0, 0x0de8b0da, 0x0c98b0da, 0x0de8b0da } },
+          { 0x0de8b4e0, 0x0de8b0da, 0x0c98b0da } },
        { AR5K_PHY_SIG,
-          { 0x7e800d2e, 0x7e800d2e, 0x7ee80d2e, 0x7ec80d2e, 0x7e800d2e } },
+          { 0x7e800d2e, 0x7ee80d2e, 0x7ec80d2e } },
        { AR5K_PHY_AGCCOARSE,
-          { 0x3137665e, 0x3137665e, 0x3137665e, 0x3139605e, 0x3137665e } },
+          { 0x3137665e, 0x3137665e, 0x3139605e } },
        { AR5K_PHY_WEAK_OFDM_LOW_THR,
-          { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+          { 0x050cb081, 0x050cb081, 0x050cb081 } },
        { AR5K_PHY_RX_DELAY,
-          { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+          { 0x000007d0, 0x0000044c, 0x00000898 } },
        { AR5K_PHY_FRAME_CTL_5211,
-          { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
+          { 0xf7b81000, 0xf7b80d00, 0xf7b81000 } },
        { AR5K_PHY_CCKTXCTL,
-          { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+          { 0x00000000, 0x00000000, 0x00000000 } },
        { AR5K_PHY_CCK_CROSSCORR,
-          { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+          { 0xd6be6788, 0xd03e6788, 0xd03e6788 } },
        { AR5K_PHY_GAIN_2GHZ,
-          { 0x002c0140, 0x002c0140, 0x0042c140, 0x0042c140, 0x0042c140 } },
+          { 0x002c0140, 0x0042c140, 0x0042c140 } },
        { AR5K_PHY_CCK_RX_CTL_4,
-          { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
+          { 0x1883800a, 0x1863800a, 0x1883800a } },
 };
 
 static const struct ath5k_ini rf2413_ini_common_end[] = {
@@ -1094,52 +1090,50 @@ static const struct ath5k_ini rf2413_ini_common_end[] = {
 /* XXX: a mode ? */
 static const struct ath5k_ini_mode rf2425_ini_mode_end[] = {
        { AR5K_TXCFG,
-       /*      a/XR       aTurbo         b        g (DYN)     gTurbo     */
-          { 0x00000015, 0x00000015, 0x00000015, 0x00000015, 0x00000015 } },
+       /*      A/XR          B           G       */
+          { 0x00000015, 0x00000015, 0x00000015 } },
        { AR5K_USEC_5211,
-          { 0x128d93a7, 0x098813cf, 0x04e01395, 0x12e013ab, 0x098813cf } },
-       { AR5K_PHY_TURBO,
-          { 0x00000000, 0x00000001, 0x00000000, 0x00000000, 0x00000001 } },
+          { 0x128d93a7, 0x04e01395, 0x12e013ab } },
        { AR5K_PHY_RF_CTL3,
-          { 0x0a020001, 0x0a020001, 0x05020100, 0x0a020001, 0x0a020001 } },
+          { 0x0a020001, 0x05020100, 0x0a020001 } },
        { AR5K_PHY_RF_CTL4,
-          { 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e, 0x00000e0e } },
+          { 0x00000e0e, 0x00000e0e, 0x00000e0e } },
        { AR5K_PHY_PA_CTL,
-          { 0x00000003, 0x00000003, 0x0000000b, 0x0000000b, 0x0000000b } },
+          { 0x00000003, 0x0000000b, 0x0000000b } },
        { AR5K_PHY_SETTLING,
-          { 0x1372161c, 0x13721c25, 0x13721722, 0x13721422, 0x13721c25 } },
+          { 0x1372161c, 0x13721722, 0x13721422 } },
        { AR5K_PHY_GAIN,
-          { 0x0018fa61, 0x0018fa61, 0x00199a65, 0x00199a65, 0x00199a65 } },
+          { 0x0018fa61, 0x00199a65, 0x00199a65 } },
        { AR5K_PHY_DESIRED_SIZE,
-          { 0x0c98b4e0, 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da, 0x0c98b0da } },
+          { 0x0c98b4e0, 0x0c98b0da, 0x0c98b0da } },
        { AR5K_PHY_SIG,
-          { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
+          { 0x7ec80d2e, 0x7ec80d2e, 0x7ec80d2e } },
        { AR5K_PHY_AGCCOARSE,
-          { 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e, 0x3139605e } },
+          { 0x3139605e, 0x3139605e, 0x3139605e } },
        { AR5K_PHY_WEAK_OFDM_LOW_THR,
-          { 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081, 0x050cb081 } },
+          { 0x050cb081, 0x050cb081, 0x050cb081 } },
        { AR5K_PHY_RX_DELAY,
-          { 0x000007d0, 0x000007d0, 0x0000044c, 0x00000898, 0x000007d0 } },
+          { 0x000007d0, 0x0000044c, 0x00000898 } },
        { AR5K_PHY_FRAME_CTL_5211,
-          { 0xf7b81000, 0xf7b81000, 0xf7b80d00, 0xf7b81000, 0xf7b81000 } },
+          { 0xf7b81000, 0xf7b80d00, 0xf7b81000 } },
        { AR5K_PHY_CCKTXCTL,
-          { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
+          { 0x00000000, 0x00000000, 0x00000000 } },
        { AR5K_PHY_CCK_CROSSCORR,
-          { 0xd6be6788, 0xd6be6788, 0xd03e6788, 0xd03e6788, 0xd03e6788 } },
+          { 0xd6be6788, 0xd03e6788, 0xd03e6788 } },
        { AR5K_PHY_GAIN_2GHZ,
-          { 0x00000140, 0x00000140, 0x0052c140, 0x0052c140, 0x0052c140 } },
+          { 0x00000140, 0x0052c140, 0x0052c140 } },
        { AR5K_PHY_CCK_RX_CTL_4,
-          { 0x1883800a, 0x1883800a, 0x1863800a, 0x1883800a, 0x1883800a } },
+          { 0x1883800a, 0x1863800a, 0x1883800a } },
        { 0xa324,
-          { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+          { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
        { 0xa328,
-          { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+          { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
        { 0xa32c,
-          { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+          { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
        { 0xa330,
-          { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+          { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
        { 0xa334,
-          { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
+          { 0xa7cfa7cf, 0xa7cfa7cf, 0xa7cfa7cf } },
 };
 
 static const struct ath5k_ini rf2425_ini_common_end[] = {
@@ -1368,15 +1362,15 @@ static const struct ath5k_ini rf5112_ini_bbgain[] = {
  * Write initial register dump
  */
 static void ath5k_hw_ini_registers(struct ath5k_hw *ah, unsigned int size,
-               const struct ath5k_ini *ini_regs, bool change_channel)
+               const struct ath5k_ini *ini_regs, bool skip_pcu)
 {
        unsigned int i;
 
        /* Write initial registers */
        for (i = 0; i < size; i++) {
-               /* On channel change there is
-                * no need to mess with PCU */
-               if (change_channel &&
+               /* Skip PCU registers if
+                * requested */
+               if (skip_pcu &&
                                ini_regs[i].ini_register >= AR5K_PCU_MIN &&
                                ini_regs[i].ini_register <= AR5K_PCU_MAX)
                        continue;
@@ -1409,7 +1403,7 @@ static void ath5k_hw_ini_mode_registers(struct ath5k_hw *ah,
 
 }
 
-int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
+int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool skip_pcu)
 {
        /*
         * Write initial register settings
@@ -1427,7 +1421,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
                 * Write initial settings common for all modes
                 */
                ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5212_ini_common_start),
-                               ar5212_ini_common_start, change_channel);
+                               ar5212_ini_common_start, skip_pcu);
 
                /* Second set of mode-specific settings */
                switch (ah->ah_radio) {
@@ -1439,12 +1433,12 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
 
                        ath5k_hw_ini_registers(ah,
                                        ARRAY_SIZE(rf5111_ini_common_end),
-                                       rf5111_ini_common_end, change_channel);
+                                       rf5111_ini_common_end, skip_pcu);
 
                        /* Baseband gain table */
                        ath5k_hw_ini_registers(ah,
                                        ARRAY_SIZE(rf5111_ini_bbgain),
-                                       rf5111_ini_bbgain, change_channel);
+                                       rf5111_ini_bbgain, skip_pcu);
 
                        break;
                case AR5K_RF5112:
@@ -1455,11 +1449,11 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
 
                        ath5k_hw_ini_registers(ah,
                                        ARRAY_SIZE(rf5112_ini_common_end),
-                                       rf5112_ini_common_end, change_channel);
+                                       rf5112_ini_common_end, skip_pcu);
 
                        ath5k_hw_ini_registers(ah,
                                        ARRAY_SIZE(rf5112_ini_bbgain),
-                                       rf5112_ini_bbgain, change_channel);
+                                       rf5112_ini_bbgain, skip_pcu);
 
                        break;
                case AR5K_RF5413:
@@ -1470,11 +1464,11 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
 
                        ath5k_hw_ini_registers(ah,
                                        ARRAY_SIZE(rf5413_ini_common_end),
-                                       rf5413_ini_common_end, change_channel);
+                                       rf5413_ini_common_end, skip_pcu);
 
                        ath5k_hw_ini_registers(ah,
                                        ARRAY_SIZE(rf5112_ini_bbgain),
-                                       rf5112_ini_bbgain, change_channel);
+                                       rf5112_ini_bbgain, skip_pcu);
 
                        break;
                case AR5K_RF2316:
@@ -1486,7 +1480,7 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
 
                        ath5k_hw_ini_registers(ah,
                                        ARRAY_SIZE(rf2413_ini_common_end),
-                                       rf2413_ini_common_end, change_channel);
+                                       rf2413_ini_common_end, skip_pcu);
 
                        /* Override settings from rf2413_ini_common_end */
                        if (ah->ah_radio == AR5K_RF2316) {
@@ -1498,9 +1492,32 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
 
                        ath5k_hw_ini_registers(ah,
                                        ARRAY_SIZE(rf5112_ini_bbgain),
-                                       rf5112_ini_bbgain, change_channel);
+                                       rf5112_ini_bbgain, skip_pcu);
                        break;
                case AR5K_RF2317:
+
+                       ath5k_hw_ini_mode_registers(ah,
+                                       ARRAY_SIZE(rf2413_ini_mode_end),
+                                       rf2413_ini_mode_end, mode);
+
+                       ath5k_hw_ini_registers(ah,
+                                       ARRAY_SIZE(rf2425_ini_common_end),
+                                       rf2425_ini_common_end, skip_pcu);
+
+                       /* Override settings from rf2413_ini_mode_end */
+                       ath5k_hw_reg_write(ah, 0x00180a65, AR5K_PHY_GAIN);
+
+                       /* Override settings from rf2413_ini_common_end */
+                       ath5k_hw_reg_write(ah, 0x00004000, AR5K_PHY_AGC);
+                       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TPC_RG5,
+                               AR5K_PHY_TPC_RG5_PD_GAIN_OVERLAP, 0xa);
+                       ath5k_hw_reg_write(ah, 0x800000a8, 0x8140);
+                       ath5k_hw_reg_write(ah, 0x000000ff, 0x9958);
+
+                       ath5k_hw_ini_registers(ah,
+                                       ARRAY_SIZE(rf5112_ini_bbgain),
+                                       rf5112_ini_bbgain, skip_pcu);
+                       break;
                case AR5K_RF2425:
 
                        ath5k_hw_ini_mode_registers(ah,
@@ -1509,11 +1526,11 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
 
                        ath5k_hw_ini_registers(ah,
                                        ARRAY_SIZE(rf2425_ini_common_end),
-                                       rf2425_ini_common_end, change_channel);
+                                       rf2425_ini_common_end, skip_pcu);
 
                        ath5k_hw_ini_registers(ah,
                                        ARRAY_SIZE(rf5112_ini_bbgain),
-                                       rf5112_ini_bbgain, change_channel);
+                                       rf5112_ini_bbgain, skip_pcu);
                        break;
                default:
                        return -EINVAL;
@@ -1538,17 +1555,17 @@ int ath5k_hw_write_initvals(struct ath5k_hw *ah, u8 mode, bool change_channel)
                 * Write initial settings common for all modes
                 */
                ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5211_ini),
-                               ar5211_ini, change_channel);
+                               ar5211_ini, skip_pcu);
 
                /* AR5211 only comes with 5111 */
 
                /* Baseband gain table */
                ath5k_hw_ini_registers(ah, ARRAY_SIZE(rf5111_ini_bbgain),
-                               rf5111_ini_bbgain, change_channel);
+                               rf5111_ini_bbgain, skip_pcu);
        /* For AR5210 (for mode settings check out ath5k_hw_reset_tx_queue) */
        } else if (ah->ah_version == AR5K_AR5210) {
                ath5k_hw_ini_registers(ah, ARRAY_SIZE(ar5210_ini),
-                               ar5210_ini, change_channel);
+                               ar5210_ini, skip_pcu);
        }
 
        return 0;
index 67aa52e9bf9404a581c7084d12f058f21df13bbc..576edf2965dc0acd46c035aa0180eb9fb42fe670 100644 (file)
@@ -133,7 +133,7 @@ ath5k_register_led(struct ath5k_softc *sc, struct ath5k_led *led,
        led->led_dev.default_trigger = trigger;
        led->led_dev.brightness_set = ath5k_led_brightness_set;
 
-       err = led_classdev_register(&sc->pdev->dev, &led->led_dev);
+       err = led_classdev_register(sc->dev, &led->led_dev);
        if (err) {
                ATH5K_WARN(sc, "could not register LED %s\n", name);
                led->sc = NULL;
@@ -161,11 +161,20 @@ int ath5k_init_leds(struct ath5k_softc *sc)
 {
        int ret = 0;
        struct ieee80211_hw *hw = sc->hw;
+#ifndef CONFIG_ATHEROS_AR231X
        struct pci_dev *pdev = sc->pdev;
+#endif
        char name[ATH5K_LED_MAX_NAME_LEN + 1];
        const struct pci_device_id *match;
 
+       if (!sc->pdev)
+               return 0;
+
+#ifdef CONFIG_ATHEROS_AR231X
+       match = NULL;
+#else
        match = pci_match_id(&ath5k_led_devices[0], pdev);
+#endif
        if (match) {
                __set_bit(ATH_STAT_LEDSOFT, sc->status);
                sc->led_pin = ATH_PIN(match->driver_data);
diff --git a/drivers/net/wireless/ath/ath5k/pci.c b/drivers/net/wireless/ath/ath5k/pci.c
new file mode 100644 (file)
index 0000000..39f0331
--- /dev/null
@@ -0,0 +1,326 @@
+/*
+ * Copyright (c) 2008-2009 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 <linux/nl80211.h>
+#include <linux/pci.h>
+#include <linux/pci-aspm.h>
+#include "../ath.h"
+#include "ath5k.h"
+#include "debug.h"
+#include "base.h"
+#include "reg.h"
+
+/* Known PCI ids */
+static DEFINE_PCI_DEVICE_TABLE(ath5k_pci_id_table) = {
+       { PCI_VDEVICE(ATHEROS, 0x0207) }, /* 5210 early */
+       { PCI_VDEVICE(ATHEROS, 0x0007) }, /* 5210 */
+       { PCI_VDEVICE(ATHEROS, 0x0011) }, /* 5311 - this is on AHB bus !*/
+       { PCI_VDEVICE(ATHEROS, 0x0012) }, /* 5211 */
+       { PCI_VDEVICE(ATHEROS, 0x0013) }, /* 5212 */
+       { PCI_VDEVICE(3COM_2,  0x0013) }, /* 3com 5212 */
+       { PCI_VDEVICE(3COM,    0x0013) }, /* 3com 3CRDAG675 5212 */
+       { PCI_VDEVICE(ATHEROS, 0x1014) }, /* IBM minipci 5212 */
+       { PCI_VDEVICE(ATHEROS, 0x0014) }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x0015) }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x0016) }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x0017) }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x0018) }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x0019) }, /* 5212 combatible */
+       { PCI_VDEVICE(ATHEROS, 0x001a) }, /* 2413 Griffin-lite */
+       { PCI_VDEVICE(ATHEROS, 0x001b) }, /* 5413 Eagle */
+       { PCI_VDEVICE(ATHEROS, 0x001c) }, /* PCI-E cards */
+       { PCI_VDEVICE(ATHEROS, 0x001d) }, /* 2417 Nala */
+       { 0 }
+};
+
+/* return bus cachesize in 4B word units */
+static void ath5k_pci_read_cachesize(struct ath_common *common, int *csz)
+{
+       struct ath5k_softc *sc = (struct ath5k_softc *) common->priv;
+       u8 u8tmp;
+
+       pci_read_config_byte(sc->pdev, PCI_CACHE_LINE_SIZE, &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 = L1_CACHE_BYTES >> 2;   /* Use the default size */
+}
+
+/*
+ * Read from eeprom
+ */
+bool ath5k_pci_eeprom_read(struct ath_common *common, u32 offset, u16 *data)
+{
+       struct ath5k_hw *ah = (struct ath5k_hw *) common->ah;
+       u32 status, timeout;
+
+       /*
+        * Initialize EEPROM access
+        */
+       if (ah->ah_version == AR5K_AR5210) {
+               AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG, AR5K_PCICFG_EEAE);
+               (void)ath5k_hw_reg_read(ah, AR5K_EEPROM_BASE + (4 * offset));
+       } else {
+               ath5k_hw_reg_write(ah, offset, AR5K_EEPROM_BASE);
+               AR5K_REG_ENABLE_BITS(ah, AR5K_EEPROM_CMD,
+                               AR5K_EEPROM_CMD_READ);
+       }
+
+       for (timeout = AR5K_TUNE_REGISTER_TIMEOUT; timeout > 0; timeout--) {
+               status = ath5k_hw_reg_read(ah, AR5K_EEPROM_STATUS);
+               if (status & AR5K_EEPROM_STAT_RDDONE) {
+                       if (status & AR5K_EEPROM_STAT_RDERR)
+                               return -EIO;
+                       *data = (u16)(ath5k_hw_reg_read(ah, AR5K_EEPROM_DATA) &
+                                       0xffff);
+                       return 0;
+               }
+               udelay(15);
+       }
+
+       return -ETIMEDOUT;
+}
+
+int ath5k_hw_read_srev(struct ath5k_hw *ah)
+{
+       ah->ah_mac_srev = ath5k_hw_reg_read(ah, AR5K_SREV);
+       return 0;
+}
+
+/* Common ath_bus_opts structure */
+static const struct ath_bus_ops ath_pci_bus_ops = {
+       .ath_bus_type = ATH_PCI,
+       .read_cachesize = ath5k_pci_read_cachesize,
+       .eeprom_read = ath5k_pci_eeprom_read,
+};
+
+/********************\
+* PCI Initialization *
+\********************/
+
+static int __devinit
+ath5k_pci_probe(struct pci_dev *pdev,
+               const struct pci_device_id *id)
+{
+       void __iomem *mem;
+       struct ath5k_softc *sc;
+       struct ieee80211_hw *hw;
+       int ret;
+       u8 csz;
+
+       /*
+        * L0s needs to be disabled on all ath5k cards.
+        *
+        * For distributions shipping with CONFIG_PCIEASPM (this will be enabled
+        * by default in the future in 2.6.36) this will also mean both L1 and
+        * L0s will be disabled when a pre 1.1 PCIe device is detected. We do
+        * know L1 works correctly even for all ath5k pre 1.1 PCIe devices
+        * though but cannot currently undue the effect of a blacklist, for
+        * details you can read pcie_aspm_sanity_check() and see how it adjusts
+        * the device link capability.
+        *
+        * It may be possible in the future to implement some PCI API to allow
+        * drivers to override blacklists for pre 1.1 PCIe but for now it is
+        * best to accept that both L0s and L1 will be disabled completely for
+        * distributions shipping with CONFIG_PCIEASPM rather than having this
+        * issue present. Motivation for adding this new API will be to help
+        * with power consumption for some of these devices.
+        */
+       pci_disable_link_state(pdev, PCIE_LINK_STATE_L0S);
+
+       ret = pci_enable_device(pdev);
+       if (ret) {
+               dev_err(&pdev->dev, "can't enable device\n");
+               goto err;
+       }
+
+       /* XXX 32-bit addressing only */
+       ret = pci_set_dma_mask(pdev, DMA_BIT_MASK(32));
+       if (ret) {
+               dev_err(&pdev->dev, "32-bit DMA not available\n");
+               goto err_dis;
+       }
+
+       /*
+        * Cache line size is used to size and align various
+        * structures used to communicate with the hardware.
+        */
+       pci_read_config_byte(pdev, PCI_CACHE_LINE_SIZE, &csz);
+       if (csz == 0) {
+               /*
+                * Linux 2.4.18 (at least) writes the cache line size
+                * register as a 16-bit wide register which is wrong.
+                * We must have this setup properly for rx buffer
+                * DMA to work so force a reasonable value here if it
+                * comes up zero.
+                */
+               csz = L1_CACHE_BYTES >> 2;
+               pci_write_config_byte(pdev, PCI_CACHE_LINE_SIZE, csz);
+       }
+       /*
+        * The default setting of latency timer yields poor results,
+        * set it to the value used by other systems.  It may be worth
+        * tweaking this setting more.
+        */
+       pci_write_config_byte(pdev, PCI_LATENCY_TIMER, 0xa8);
+
+       /* Enable bus mastering */
+       pci_set_master(pdev);
+
+       /*
+        * Disable the RETRY_TIMEOUT register (0x41) to keep
+        * PCI Tx retries from interfering with C3 CPU state.
+        */
+       pci_write_config_byte(pdev, 0x41, 0);
+
+       ret = pci_request_region(pdev, 0, "ath5k");
+       if (ret) {
+               dev_err(&pdev->dev, "cannot reserve PCI memory region\n");
+               goto err_dis;
+       }
+
+       mem = pci_iomap(pdev, 0, 0);
+       if (!mem) {
+               dev_err(&pdev->dev, "cannot remap PCI memory region\n") ;
+               ret = -EIO;
+               goto err_reg;
+       }
+
+       /*
+        * Allocate hw (mac80211 main struct)
+        * and hw->priv (driver private data)
+        */
+       hw = ieee80211_alloc_hw(sizeof(*sc), &ath5k_hw_ops);
+       if (hw == NULL) {
+               dev_err(&pdev->dev, "cannot allocate ieee80211_hw\n");
+               ret = -ENOMEM;
+               goto err_map;
+       }
+
+       dev_info(&pdev->dev, "registered as '%s'\n", wiphy_name(hw->wiphy));
+
+       sc = hw->priv;
+       sc->hw = hw;
+       sc->pdev = pdev;
+       sc->dev = &pdev->dev;
+       sc->irq = pdev->irq;
+       sc->devid = id->device;
+       sc->iobase = mem; /* So we can unmap it on detach */
+
+       /* Initialize */
+       ret = ath5k_init_softc(sc, &ath_pci_bus_ops);
+       if (ret)
+               goto err_free;
+
+       /* Set private data */
+       pci_set_drvdata(pdev, hw);
+
+       return 0;
+err_free:
+       ieee80211_free_hw(hw);
+err_map:
+       pci_iounmap(pdev, mem);
+err_reg:
+       pci_release_region(pdev, 0);
+err_dis:
+       pci_disable_device(pdev);
+err:
+       return ret;
+}
+
+static void __devexit
+ath5k_pci_remove(struct pci_dev *pdev)
+{
+       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+       struct ath5k_softc *sc = hw->priv;
+
+       ath5k_deinit_softc(sc);
+       pci_iounmap(pdev, sc->iobase);
+       pci_release_region(pdev, 0);
+       pci_disable_device(pdev);
+       ieee80211_free_hw(hw);
+}
+
+#ifdef CONFIG_PM_SLEEP
+static int ath5k_pci_suspend(struct device *dev)
+{
+       struct ath5k_softc *sc = pci_get_drvdata(to_pci_dev(dev));
+
+       ath5k_led_off(sc);
+       return 0;
+}
+
+static int ath5k_pci_resume(struct device *dev)
+{
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct ath5k_softc *sc = pci_get_drvdata(pdev);
+
+       /*
+        * Suspend/Resume resets the PCI configuration space, so we have to
+        * re-disable the RETRY_TIMEOUT register (0x41) to keep
+        * PCI Tx retries from interfering with C3 CPU state
+        */
+       pci_write_config_byte(pdev, 0x41, 0);
+
+       ath5k_led_enable(sc);
+       return 0;
+}
+
+static SIMPLE_DEV_PM_OPS(ath5k_pm_ops, ath5k_pci_suspend, ath5k_pci_resume);
+#define ATH5K_PM_OPS   (&ath5k_pm_ops)
+#else
+#define ATH5K_PM_OPS   NULL
+#endif /* CONFIG_PM_SLEEP */
+
+static struct pci_driver ath5k_pci_driver = {
+       .name           = KBUILD_MODNAME,
+       .id_table       = ath5k_pci_id_table,
+       .probe          = ath5k_pci_probe,
+       .remove         = __devexit_p(ath5k_pci_remove),
+       .driver.pm      = ATH5K_PM_OPS,
+};
+
+/*
+ * Module init/exit functions
+ */
+static int __init
+init_ath5k_pci(void)
+{
+       int ret;
+
+       ret = pci_register_driver(&ath5k_pci_driver);
+       if (ret) {
+               printk(KERN_ERR "ath5k_pci: can't register pci driver\n");
+               return ret;
+       }
+
+       return 0;
+}
+
+static void __exit
+exit_ath5k_pci(void)
+{
+       pci_unregister_driver(&ath5k_pci_driver);
+}
+
+module_init(init_ath5k_pci);
+module_exit(exit_ath5k_pci);
index 074b4c644399c8f5f3790a1d6ff0f8be9f8b2ccc..e5f2b96a4c63621cfd1ab41156f6f93d1a352a25 100644 (file)
 #include "debug.h"
 #include "base.h"
 
+/*
+ * AR5212+ can use higher rates for ack transmition
+ * based on current tx rate instead of the base rate.
+ * It does this to better utilize channel usage.
+ * This is a mapping between G rates (that cover both
+ * CCK and OFDM) and ack rates that we use when setting
+ * rate -> duration table. This mapping is hw-based so
+ * don't change anything.
+ *
+ * To enable this functionality we must set
+ * ah->ah_ack_bitrate_high to true else base rate is
+ * used (1Mb for CCK, 6Mb for OFDM).
+ */
+static const unsigned int ack_rates_high[] =
+/* Tx  -> ACK  */
+/* 1Mb -> 1Mb  */      { 0,
+/* 2MB -> 2Mb  */      1,
+/* 5.5Mb -> 2Mb        */      1,
+/* 11Mb        -> 2Mb  */      1,
+/* 6Mb -> 6Mb  */      4,
+/* 9Mb -> 6Mb  */      4,
+/* 12Mb        -> 12Mb */      6,
+/* 18Mb        -> 12Mb */      6,
+/* 24Mb        -> 24Mb */      8,
+/* 36Mb        -> 24Mb */      8,
+/* 48Mb        -> 24Mb */      8,
+/* 54Mb        -> 24Mb */      8 };
+
 /*******************\
-* Generic functions *
+* Helper functions *
 \*******************/
 
 /**
- * ath5k_hw_set_opmode - Set PCU operating mode
+ * ath5k_hw_get_frame_duration - Get tx time of a frame
  *
  * @ah: The &struct ath5k_hw
- * @op_mode: &enum nl80211_iftype operating mode
+ * @len: Frame's length in bytes
+ * @rate: The @struct ieee80211_rate
  *
- * Initialize PCU for the various operating modes (AP/STA etc)
+ * Calculate tx duration of a frame given it's rate and length
+ * It extends ieee80211_generic_frame_duration for non standard
+ * bwmodes.
  */
-int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
+int ath5k_hw_get_frame_duration(struct ath5k_hw *ah,
+               int len, struct ieee80211_rate *rate)
 {
-       struct ath_common *common = ath5k_hw_common(ah);
-       u32 pcu_reg, beacon_reg, low_id, high_id;
+       struct ath5k_softc *sc = ah->ah_sc;
+       int sifs, preamble, plcp_bits, sym_time;
+       int bitrate, bits, symbols, symbol_bits;
+       int dur;
+
+       /* Fallback */
+       if (!ah->ah_bwmode) {
+               dur = ieee80211_generic_frame_duration(sc->hw,
+                                               NULL, len, rate);
+               return dur;
+       }
 
-       ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_MODE, "mode %d\n", op_mode);
+       bitrate = rate->bitrate;
+       preamble = AR5K_INIT_OFDM_PREAMPLE_TIME;
+       plcp_bits = AR5K_INIT_OFDM_PLCP_BITS;
+       sym_time = AR5K_INIT_OFDM_SYMBOL_TIME;
 
-       /* 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));
+       switch (ah->ah_bwmode) {
+       case AR5K_BWMODE_40MHZ:
+               sifs = AR5K_INIT_SIFS_TURBO;
+               preamble = AR5K_INIT_OFDM_PREAMBLE_TIME_MIN;
+               break;
+       case AR5K_BWMODE_10MHZ:
+               sifs = AR5K_INIT_SIFS_HALF_RATE;
+               preamble *= 2;
+               sym_time *= 2;
+               break;
+       case AR5K_BWMODE_5MHZ:
+               sifs = AR5K_INIT_SIFS_QUARTER_RATE;
+               preamble *= 4;
+               sym_time *= 4;
+               break;
+       default:
+               sifs = AR5K_INIT_SIFS_DEFAULT_BG;
+               break;
+       }
 
-       beacon_reg = 0;
+       bits = plcp_bits + (len << 3);
+       /* Bit rate is in 100Kbits */
+       symbol_bits = bitrate * sym_time;
+       symbols = DIV_ROUND_UP(bits * 10, symbol_bits);
 
-       switch (op_mode) {
-       case NL80211_IFTYPE_ADHOC:
-               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_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
-               break;
+       dur = sifs + preamble + (sym_time * symbols);
 
-       case NL80211_IFTYPE_AP:
-       case NL80211_IFTYPE_MESH_POINT:
-               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_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
-               break;
+       return dur;
+}
 
-       case NL80211_IFTYPE_STATION:
-               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_KEYSRCH_MODE
-                       | (ah->ah_version == AR5K_AR5210 ?
-                               AR5K_STA_ID1_NO_PSPOLL : 0);
-               break;
+/**
+ * ath5k_hw_get_default_slottime - Get the default slot time for current mode
+ *
+ * @ah: The &struct ath5k_hw
+ */
+unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
+{
+       struct ieee80211_channel *channel = ah->ah_current_channel;
+       unsigned int slot_time;
 
+       switch (ah->ah_bwmode) {
+       case AR5K_BWMODE_40MHZ:
+               slot_time = AR5K_INIT_SLOT_TIME_TURBO;
+               break;
+       case AR5K_BWMODE_10MHZ:
+               slot_time = AR5K_INIT_SLOT_TIME_HALF_RATE;
+               break;
+       case AR5K_BWMODE_5MHZ:
+               slot_time = AR5K_INIT_SLOT_TIME_QUARTER_RATE;
+               break;
+       case AR5K_BWMODE_DEFAULT:
+               slot_time = AR5K_INIT_SLOT_TIME_DEFAULT;
        default:
-               return -EINVAL;
+               if (channel->hw_value & CHANNEL_CCK)
+                       slot_time = AR5K_INIT_SLOT_TIME_B;
+               break;
        }
 
-       /*
-        * Set PCU registers
-        */
-       low_id = get_unaligned_le32(common->macaddr);
-       high_id = get_unaligned_le16(common->macaddr + 4);
-       ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
-       ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
+       return slot_time;
+}
 
-       /*
-        * Set Beacon Control Register on 5210
-        */
-       if (ah->ah_version == AR5K_AR5210)
-               ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
+/**
+ * ath5k_hw_get_default_sifs - Get the default SIFS for current mode
+ *
+ * @ah: The &struct ath5k_hw
+ */
+unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
+{
+       struct ieee80211_channel *channel = ah->ah_current_channel;
+       unsigned int sifs;
 
-       return 0;
+       switch (ah->ah_bwmode) {
+       case AR5K_BWMODE_40MHZ:
+               sifs = AR5K_INIT_SIFS_TURBO;
+               break;
+       case AR5K_BWMODE_10MHZ:
+               sifs = AR5K_INIT_SIFS_HALF_RATE;
+               break;
+       case AR5K_BWMODE_5MHZ:
+               sifs = AR5K_INIT_SIFS_QUARTER_RATE;
+               break;
+       case AR5K_BWMODE_DEFAULT:
+               sifs = AR5K_INIT_SIFS_DEFAULT_BG;
+       default:
+               if (channel->hw_value & CHANNEL_5GHZ)
+                       sifs = AR5K_INIT_SIFS_DEFAULT_A;
+               break;
+       }
+
+       return sifs;
 }
 
 /**
- * ath5k_hw_update - Update MIB counters (mac layer statistics)
+ * ath5k_hw_update_mib_counters - Update MIB counters (mac layer statistics)
  *
  * @ah: The &struct ath5k_hw
  *
@@ -133,36 +209,88 @@ void ath5k_hw_update_mib_counters(struct ath5k_hw *ah)
        stats->beacons += ath5k_hw_reg_read(ah, AR5K_BEACON_CNT);
 }
 
+
+/******************\
+* ACK/CTS Timeouts *
+\******************/
+
 /**
- * ath5k_hw_set_ack_bitrate - set bitrate for ACKs
+ * ath5k_hw_write_rate_duration - fill rate code to duration table
  *
- * @ah: The &struct ath5k_hw
- * @high: Flag to determine if we want to use high transmission rate
- * for ACKs or not
+ * @ah: the &struct ath5k_hw
+ * @mode: one of enum ath5k_driver_mode
+ *
+ * Write the rate code to duration table upon hw reset. This is a helper for
+ * ath5k_hw_pcu_init(). It seems all this is doing is setting an ACK timeout on
+ * the hardware, based on current mode, for each rate. The rates which are
+ * capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have
+ * different rate code so we write their value twice (one for long preamble
+ * and one for short).
+ *
+ * Note: Band doesn't matter here, if we set the values for OFDM it works
+ * on both a and g modes. So all we have to do is set values for all g rates
+ * that include all OFDM and CCK rates.
  *
- * If high flag is set, we tell hw to use a set of control rates based on
- * the current transmission rate (check out control_rates array inside reset.c).
- * If not hw just uses the lowest rate available for the current modulation
- * scheme being used (1Mbit for CCK and 6Mbits for OFDM).
  */
-void ath5k_hw_set_ack_bitrate_high(struct ath5k_hw *ah, bool high)
+static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah)
 {
-       if (ah->ah_version != AR5K_AR5212)
-               return;
-       else {
-               u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
-               if (high)
-                       AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
+       struct ath5k_softc *sc = ah->ah_sc;
+       struct ieee80211_rate *rate;
+       unsigned int i;
+       /* 802.11g covers both OFDM and CCK */
+       u8 band = IEEE80211_BAND_2GHZ;
+
+       /* Write rate duration table */
+       for (i = 0; i < sc->sbands[band].n_bitrates; i++) {
+               u32 reg;
+               u16 tx_time;
+
+               if (ah->ah_ack_bitrate_high)
+                       rate = &sc->sbands[band].bitrates[ack_rates_high[i]];
+               /* CCK -> 1Mb */
+               else if (i < 4)
+                       rate = &sc->sbands[band].bitrates[0];
+               /* OFDM -> 6Mb */
                else
-                       AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
+                       rate = &sc->sbands[band].bitrates[4];
+
+               /* Set ACK timeout */
+               reg = AR5K_RATE_DUR(rate->hw_value);
+
+               /* An ACK frame consists of 10 bytes. If you add the FCS,
+                * which ieee80211_generic_frame_duration() adds,
+                * its 14 bytes. Note we use the control rate and not the
+                * actual rate for this rate. See mac80211 tx.c
+                * ieee80211_duration() for a brief description of
+                * what rate we should choose to TX ACKs. */
+               tx_time = ath5k_hw_get_frame_duration(ah, 10, rate);
+
+               tx_time = le16_to_cpu(tx_time);
+
+               ath5k_hw_reg_write(ah, tx_time, reg);
+
+               if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
+                       continue;
+
+               /*
+                * We're not distinguishing short preamble here,
+                * This is true, all we'll get is a longer value here
+                * which is not necessarilly bad. We could use
+                * export ieee80211_frame_duration() but that needs to be
+                * fixed first to be properly used by mac802111 drivers:
+                *
+                *  - remove erp stuff and let the routine figure ofdm
+                *    erp rates
+                *  - remove passing argument ieee80211_local as
+                *    drivers don't have access to it
+                *  - move drivers using ieee80211_generic_frame_duration()
+                *    to this
+                */
+               ath5k_hw_reg_write(ah, tx_time,
+                       reg + (AR5K_SET_SHORT_PREAMBLE << 2));
        }
 }
 
-
-/******************\
-* ACK/CTS Timeouts *
-\******************/
-
 /**
  * ath5k_hw_set_ack_timeout - Set ACK timeout on PCU
  *
@@ -199,88 +327,10 @@ static int ath5k_hw_set_cts_timeout(struct ath5k_hw *ah, unsigned int timeout)
        return 0;
 }
 
-/**
- * ath5k_hw_htoclock - Translate usec to hw clock units
- *
- * @ah: The &struct ath5k_hw
- * @usec: value in microseconds
- */
-unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec)
-{
-       struct ath_common *common = ath5k_hw_common(ah);
-       return usec * common->clockrate;
-}
-
-/**
- * ath5k_hw_clocktoh - Translate hw clock units to usec
- * @clock: value in hw clock units
- */
-unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock)
-{
-       struct ath_common *common = ath5k_hw_common(ah);
-       return clock / common->clockrate;
-}
-
-/**
- * ath5k_hw_set_clockrate - Set common->clockrate for the current channel
- *
- * @ah: The &struct ath5k_hw
- */
-void ath5k_hw_set_clockrate(struct ath5k_hw *ah)
-{
-       struct ieee80211_channel *channel = ah->ah_current_channel;
-       struct ath_common *common = ath5k_hw_common(ah);
-       int clock;
-
-       if (channel->hw_value & CHANNEL_5GHZ)
-               clock = 40; /* 802.11a */
-       else if (channel->hw_value & CHANNEL_CCK)
-               clock = 22; /* 802.11b */
-       else
-               clock = 44; /* 802.11g */
-
-       /* Clock rate in turbo modes is twice the normal rate */
-       if (channel->hw_value & CHANNEL_TURBO)
-               clock *= 2;
-
-       common->clockrate = clock;
-}
-
-/**
- * ath5k_hw_get_default_slottime - Get the default slot time for current mode
- *
- * @ah: The &struct ath5k_hw
- */
-static unsigned int ath5k_hw_get_default_slottime(struct ath5k_hw *ah)
-{
-       struct ieee80211_channel *channel = ah->ah_current_channel;
-
-       if (channel->hw_value & CHANNEL_TURBO)
-               return 6; /* both turbo modes */
-
-       if (channel->hw_value & CHANNEL_CCK)
-               return 20; /* 802.11b */
-
-       return 9; /* 802.11 a/g */
-}
-
-/**
- * ath5k_hw_get_default_sifs - Get the default SIFS for current mode
- *
- * @ah: The &struct ath5k_hw
- */
-static unsigned int ath5k_hw_get_default_sifs(struct ath5k_hw *ah)
-{
-       struct ieee80211_channel *channel = ah->ah_current_channel;
-
-       if (channel->hw_value & CHANNEL_TURBO)
-               return 8; /* both turbo modes */
 
-       if (channel->hw_value & CHANNEL_5GHZ)
-               return 16; /* 802.11a */
-
-       return 10; /* 802.11 b/g */
-}
+/*******************\
+* RX filter Control *
+\*******************/
 
 /**
  * ath5k_hw_set_lladdr - Set station id
@@ -362,39 +412,6 @@ void ath5k_hw_set_bssid_mask(struct ath5k_hw *ah, const u8 *mask)
                ath_hw_setbssidmask(common);
 }
 
-/************\
-* RX Control *
-\************/
-
-/**
- * ath5k_hw_start_rx_pcu - Start RX engine
- *
- * @ah: The &struct ath5k_hw
- *
- * Starts RX engine on PCU so that hw can process RXed frames
- * (ACK etc).
- *
- * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma
- */
-void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
-{
-       AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
-}
-
-/**
- * at5k_hw_stop_rx_pcu - Stop RX engine
- *
- * @ah: The &struct ath5k_hw
- *
- * Stops RX engine on PCU
- *
- * TODO: Detach ANI here
- */
-void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
-{
-       AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
-}
-
 /*
  * Set multicast filter
  */
@@ -746,7 +763,7 @@ ath5k_hw_check_beacon_timers(struct ath5k_hw *ah, int intval)
  * @ah: The &struct ath5k_hw
  * @coverage_class: IEEE 802.11 coverage class number
  *
- * Sets slot time, ACK timeout and CTS timeout for given coverage class.
+ * Sets IFS intervals and ACK/CTS timeouts for given coverage class.
  */
 void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
 {
@@ -755,9 +772,175 @@ void ath5k_hw_set_coverage_class(struct ath5k_hw *ah, u8 coverage_class)
        int ack_timeout = ath5k_hw_get_default_sifs(ah) + slot_time;
        int cts_timeout = ack_timeout;
 
-       ath5k_hw_set_slot_time(ah, slot_time);
+       ath5k_hw_set_ifs_intervals(ah, slot_time);
        ath5k_hw_set_ack_timeout(ah, ack_timeout);
        ath5k_hw_set_cts_timeout(ah, cts_timeout);
 
        ah->ah_coverage_class = coverage_class;
 }
+
+/***************************\
+* Init/Start/Stop functions *
+\***************************/
+
+/**
+ * ath5k_hw_start_rx_pcu - Start RX engine
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Starts RX engine on PCU so that hw can process RXed frames
+ * (ACK etc).
+ *
+ * NOTE: RX DMA should be already enabled using ath5k_hw_start_rx_dma
+ */
+void ath5k_hw_start_rx_pcu(struct ath5k_hw *ah)
+{
+       AR5K_REG_DISABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
+}
+
+/**
+ * at5k_hw_stop_rx_pcu - Stop RX engine
+ *
+ * @ah: The &struct ath5k_hw
+ *
+ * Stops RX engine on PCU
+ */
+void ath5k_hw_stop_rx_pcu(struct ath5k_hw *ah)
+{
+       AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW, AR5K_DIAG_SW_DIS_RX);
+}
+
+/**
+ * ath5k_hw_set_opmode - Set PCU operating mode
+ *
+ * @ah: The &struct ath5k_hw
+ * @op_mode: &enum nl80211_iftype operating mode
+ *
+ * Configure PCU for the various operating modes (AP/STA etc)
+ */
+int ath5k_hw_set_opmode(struct ath5k_hw *ah, enum nl80211_iftype op_mode)
+{
+       struct ath_common *common = ath5k_hw_common(ah);
+       u32 pcu_reg, beacon_reg, low_id, high_id;
+
+       ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_MODE, "mode %d\n", op_mode);
+
+       /* 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;
+
+       switch (op_mode) {
+       case NL80211_IFTYPE_ADHOC:
+               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_ENABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
+               break;
+
+       case NL80211_IFTYPE_AP:
+       case NL80211_IFTYPE_MESH_POINT:
+               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_DISABLE_BITS(ah, AR5K_CFG, AR5K_CFG_IBSS);
+               break;
+
+       case NL80211_IFTYPE_STATION:
+               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_KEYSRCH_MODE
+                       | (ah->ah_version == AR5K_AR5210 ?
+                               AR5K_STA_ID1_NO_PSPOLL : 0);
+               break;
+
+       default:
+               return -EINVAL;
+       }
+
+       /*
+        * Set PCU registers
+        */
+       low_id = get_unaligned_le32(common->macaddr);
+       high_id = get_unaligned_le16(common->macaddr + 4);
+       ath5k_hw_reg_write(ah, low_id, AR5K_STA_ID0);
+       ath5k_hw_reg_write(ah, pcu_reg | high_id, AR5K_STA_ID1);
+
+       /*
+        * Set Beacon Control Register on 5210
+        */
+       if (ah->ah_version == AR5K_AR5210)
+               ath5k_hw_reg_write(ah, beacon_reg, AR5K_BCR);
+
+       return 0;
+}
+
+void ath5k_hw_pcu_init(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
+                                                               u8 mode)
+{
+       /* Set bssid and bssid mask */
+       ath5k_hw_set_bssid(ah);
+
+       /* Set PCU config */
+       ath5k_hw_set_opmode(ah, op_mode);
+
+       /* Write rate duration table only on AR5212 and if
+        * virtual interface has already been brought up
+        * XXX: rethink this after new mode changes to
+        * mac80211 are integrated */
+       if (ah->ah_version == AR5K_AR5212 &&
+               ah->ah_sc->nvifs)
+               ath5k_hw_write_rate_duration(ah);
+
+       /* Set RSSI/BRSSI thresholds
+        *
+        * Note: If we decide to set this value
+        * dynamicaly, have in mind that when AR5K_RSSI_THR
+        * register is read it might return 0x40 if we haven't
+        * wrote anything to it plus BMISS RSSI threshold is zeroed.
+        * So doing a save/restore procedure here isn't the right
+        * choice. Instead store it on ath5k_hw */
+       ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES |
+                               AR5K_TUNE_BMISS_THRES <<
+                               AR5K_RSSI_THR_BMISS_S),
+                               AR5K_RSSI_THR);
+
+       /* MIC QoS support */
+       if (ah->ah_mac_srev >= AR5K_SREV_AR2413) {
+               ath5k_hw_reg_write(ah, 0x000100aa, AR5K_MIC_QOS_CTL);
+               ath5k_hw_reg_write(ah, 0x00003210, AR5K_MIC_QOS_SEL);
+       }
+
+       /* QoS NOACK Policy */
+       if (ah->ah_version == AR5K_AR5212) {
+               ath5k_hw_reg_write(ah,
+                       AR5K_REG_SM(2, AR5K_QOS_NOACK_2BIT_VALUES) |
+                       AR5K_REG_SM(5, AR5K_QOS_NOACK_BIT_OFFSET)  |
+                       AR5K_REG_SM(0, AR5K_QOS_NOACK_BYTE_OFFSET),
+                       AR5K_QOS_NOACK);
+       }
+
+       /* Restore slot time and ACK timeouts */
+       if (ah->ah_coverage_class > 0)
+               ath5k_hw_set_coverage_class(ah, ah->ah_coverage_class);
+
+       /* Set ACK bitrate mode (see ack_rates_high) */
+       if (ah->ah_version == AR5K_AR5212) {
+               u32 val = AR5K_STA_ID1_BASE_RATE_11B | AR5K_STA_ID1_ACKCTS_6MB;
+               if (ah->ah_ack_bitrate_high)
+                       AR5K_REG_DISABLE_BITS(ah, AR5K_STA_ID1, val);
+               else
+                       AR5K_REG_ENABLE_BITS(ah, AR5K_STA_ID1, val);
+       }
+       return;
+}
index 6b43f535ff5374d018438a809804b68ee9820eb3..df5cd0fd69d650bda0849c8650e86e5ae417d2fc 100644 (file)
 #include "rfbuffer.h"
 #include "rfgain.h"
 
+
+/******************\
+* Helper functions *
+\******************/
+
+/*
+ * Get the PHY Chip revision
+ */
+u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
+{
+       unsigned int i;
+       u32 srev;
+       u16 ret;
+
+       /*
+        * Set the radio chip access register
+        */
+       switch (chan) {
+       case CHANNEL_2GHZ:
+               ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0));
+               break;
+       case CHANNEL_5GHZ:
+               ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+               break;
+       default:
+               return 0;
+       }
+
+       mdelay(2);
+
+       /* ...wait until PHY is ready and read the selected radio revision */
+       ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34));
+
+       for (i = 0; i < 8; i++)
+               ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));
+
+       if (ah->ah_version == AR5K_AR5210) {
+               srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf;
+               ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;
+       } else {
+               srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff;
+               ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) |
+                               ((srev & 0x0f) << 4), 8);
+       }
+
+       /* Reset to the 5GHz mode */
+       ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
+
+       return ret;
+}
+
+/*
+ * Check if a channel is supported
+ */
+bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags)
+{
+       /* Check if the channel is in our supported range */
+       if (flags & CHANNEL_2GHZ) {
+               if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) &&
+                   (freq <= ah->ah_capabilities.cap_range.range_2ghz_max))
+                       return true;
+       } else if (flags & CHANNEL_5GHZ)
+               if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) &&
+                   (freq <= ah->ah_capabilities.cap_range.range_5ghz_max))
+                       return true;
+
+       return false;
+}
+
+bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
+                               struct ieee80211_channel *channel)
+{
+       u8 refclk_freq;
+
+       if ((ah->ah_radio == AR5K_RF5112) ||
+       (ah->ah_radio == AR5K_RF5413) ||
+       (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
+               refclk_freq = 40;
+       else
+               refclk_freq = 32;
+
+       if ((channel->center_freq % refclk_freq != 0) &&
+       ((channel->center_freq % refclk_freq < 10) ||
+       (channel->center_freq % refclk_freq > 22)))
+               return true;
+       else
+               return false;
+}
+
 /*
  * Used to modify RF Banks before writing them to AR5K_RF_BUFFER
  */
@@ -110,6 +199,90 @@ static unsigned int ath5k_hw_rfb_op(struct ath5k_hw *ah,
        return data;
 }
 
+/**
+ * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212
+ *
+ * @ah: the &struct ath5k_hw
+ * @channel: the currently set channel upon reset
+ *
+ * Write the delta slope coefficient (used on pilot tracking ?) for OFDM
+ * operation on the AR5212 upon reset. This is a helper for ath5k_hw_phy_init.
+ *
+ * Since delta slope is floating point we split it on its exponent and
+ * mantissa and provide these values on hw.
+ *
+ * For more infos i think this patent is related
+ * http://www.freepatentsonline.com/7184495.html
+ */
+static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
+       struct ieee80211_channel *channel)
+{
+       /* Get exponent and mantissa and set it */
+       u32 coef_scaled, coef_exp, coef_man,
+               ds_coef_exp, ds_coef_man, clock;
+
+       BUG_ON(!(ah->ah_version == AR5K_AR5212) ||
+               !(channel->hw_value & CHANNEL_OFDM));
+
+       /* Get coefficient
+        * ALGO: coef = (5 * clock / carrier_freq) / 2
+        * we scale coef by shifting clock value by 24 for
+        * better precision since we use integers */
+       switch (ah->ah_bwmode) {
+       case AR5K_BWMODE_40MHZ:
+               clock = 40 * 2;
+               break;
+       case AR5K_BWMODE_10MHZ:
+               clock = 40 / 2;
+               break;
+       case AR5K_BWMODE_5MHZ:
+               clock = 40 / 4;
+               break;
+       default:
+               clock = 40;
+               break;
+       }
+       coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq;
+
+       /* Get exponent
+        * ALGO: coef_exp = 14 - highest set bit position */
+       coef_exp = ilog2(coef_scaled);
+
+       /* Doesn't make sense if it's zero*/
+       if (!coef_scaled || !coef_exp)
+               return -EINVAL;
+
+       /* Note: we've shifted coef_scaled by 24 */
+       coef_exp = 14 - (coef_exp - 24);
+
+
+       /* Get mantissa (significant digits)
+        * ALGO: coef_mant = floor(coef_scaled* 2^coef_exp+0.5) */
+       coef_man = coef_scaled +
+               (1 << (24 - coef_exp - 1));
+
+       /* Calculate delta slope coefficient exponent
+        * and mantissa (remove scaling) and set them on hw */
+       ds_coef_man = coef_man >> (24 - coef_exp);
+       ds_coef_exp = coef_exp - 16;
+
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
+               AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man);
+       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
+               AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp);
+
+       return 0;
+}
+
+int ath5k_hw_phy_disable(struct ath5k_hw *ah)
+{
+       /*Just a try M.F.*/
+       ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
+
+       return 0;
+}
+
+
 /**********************\
 * RF Gain optimization *
 \**********************/
@@ -436,7 +609,7 @@ done:
 /* Write initial RF gain table to set the RF sensitivity
  * this one works on all RF chips and has nothing to do
  * with gain_F calibration */
-int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
+static int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
 {
        const struct ath5k_ini_rfgain *ath5k_rfg;
        unsigned int i, size;
@@ -494,12 +667,11 @@ int ath5k_hw_rfgain_init(struct ath5k_hw *ah, unsigned int freq)
 * RF Registers setup *
 \********************/
 
-
 /*
  * Setup RF registers by writing RF buffer on hw
  */
-int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
-               unsigned int mode)
+static int ath5k_hw_rfregs_init(struct ath5k_hw *ah,
+       struct ieee80211_channel *channel, unsigned int mode)
 {
        const struct ath5k_rf_reg *rf_regs;
        const struct ath5k_ini_rfbuffer *ini_rfb;
@@ -652,6 +824,11 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
 
        g_step = &go->go_step[ah->ah_gain.g_step_idx];
 
+       /* Set turbo mode (N/A on RF5413) */
+       if ((ah->ah_bwmode == AR5K_BWMODE_40MHZ) &&
+       (ah->ah_radio != AR5K_RF5413))
+               ath5k_hw_rfb_op(ah, rf_regs, 1, AR5K_RF_TURBO, false);
+
        /* Bank Modifications (chip-specific) */
        if (ah->ah_radio == AR5K_RF5111) {
 
@@ -691,7 +868,23 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
                ath5k_hw_rfb_op(ah, rf_regs, ee->ee_xpd[ee_mode],
                                                AR5K_RF_PLO_SEL, true);
 
-               /* TODO: Half/quarter channel support */
+               /* Tweak power detectors for half/quarter rate support */
+               if (ah->ah_bwmode == AR5K_BWMODE_5MHZ ||
+               ah->ah_bwmode == AR5K_BWMODE_10MHZ) {
+                       u8 wait_i;
+
+                       ath5k_hw_rfb_op(ah, rf_regs, 0x1f,
+                                               AR5K_RF_WAIT_S, true);
+
+                       wait_i = (ah->ah_bwmode == AR5K_BWMODE_5MHZ) ?
+                                                       0x1f : 0x10;
+
+                       ath5k_hw_rfb_op(ah, rf_regs, wait_i,
+                                               AR5K_RF_WAIT_I, true);
+                       ath5k_hw_rfb_op(ah, rf_regs, 3,
+                                               AR5K_RF_MAX_TIME, true);
+
+               }
        }
 
        if (ah->ah_radio == AR5K_RF5112) {
@@ -789,8 +982,20 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
                ath5k_hw_rfb_op(ah, rf_regs, ee->ee_i_gain[ee_mode],
                                                AR5K_RF_GAIN_I, true);
 
-               /* TODO: Half/quarter channel support */
+               /* Tweak power detector for half/quarter rates */
+               if (ah->ah_bwmode == AR5K_BWMODE_5MHZ ||
+               ah->ah_bwmode == AR5K_BWMODE_10MHZ) {
+                       u8 pd_delay;
 
+                       pd_delay = (ah->ah_bwmode == AR5K_BWMODE_5MHZ) ?
+                                                       0xf : 0x8;
+
+                       ath5k_hw_rfb_op(ah, rf_regs, pd_delay,
+                                               AR5K_RF_PD_PERIOD_A, true);
+                       ath5k_hw_rfb_op(ah, rf_regs, 0xf,
+                                               AR5K_RF_PD_DELAY_A, true);
+
+               }
        }
 
        if (ah->ah_radio == AR5K_RF5413 &&
@@ -821,24 +1026,6 @@ int ath5k_hw_rfregs_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
   PHY/RF channel functions
 \**************************/
 
-/*
- * Check if a channel is supported
- */
-bool ath5k_channel_ok(struct ath5k_hw *ah, u16 freq, unsigned int flags)
-{
-       /* Check if the channel is in our supported range */
-       if (flags & CHANNEL_2GHZ) {
-               if ((freq >= ah->ah_capabilities.cap_range.range_2ghz_min) &&
-                   (freq <= ah->ah_capabilities.cap_range.range_2ghz_max))
-                       return true;
-       } else if (flags & CHANNEL_5GHZ)
-               if ((freq >= ah->ah_capabilities.cap_range.range_5ghz_min) &&
-                   (freq <= ah->ah_capabilities.cap_range.range_5ghz_max))
-                       return true;
-
-       return false;
-}
-
 /*
  * Convertion needed for RF5110
  */
@@ -1045,7 +1232,8 @@ static int ath5k_hw_rf2425_channel(struct ath5k_hw *ah,
 /*
  * Set a channel on the radio chip
  */
-int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
+static int ath5k_hw_channel(struct ath5k_hw *ah,
+               struct ieee80211_channel *channel)
 {
        int ret;
        /*
@@ -1092,8 +1280,6 @@ int ath5k_hw_channel(struct ath5k_hw *ah, struct ieee80211_channel *channel)
        }
 
        ah->ah_current_channel = channel;
-       ah->ah_turbo = channel->hw_value == CHANNEL_T ? true : false;
-       ath5k_hw_set_clockrate(ah);
 
        return 0;
 }
@@ -1177,12 +1363,10 @@ void ath5k_hw_update_noise_floor(struct ath5k_hw *ah)
 
        switch (ah->ah_current_channel->hw_value & CHANNEL_MODES) {
        case CHANNEL_A:
-       case CHANNEL_T:
        case CHANNEL_XR:
                ee_mode = AR5K_EEPROM_MODE_11A;
                break;
        case CHANNEL_G:
-       case CHANNEL_TG:
                ee_mode = AR5K_EEPROM_MODE_11G;
                break;
        default:
@@ -1419,31 +1603,12 @@ int ath5k_hw_phy_calibrate(struct ath5k_hw *ah,
        return ret;
 }
 
+
 /***************************\
 * Spur mitigation functions *
 \***************************/
 
-bool ath5k_hw_chan_has_spur_noise(struct ath5k_hw *ah,
-                               struct ieee80211_channel *channel)
-{
-       u8 refclk_freq;
-
-       if ((ah->ah_radio == AR5K_RF5112) ||
-       (ah->ah_radio == AR5K_RF5413) ||
-       (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
-               refclk_freq = 40;
-       else
-               refclk_freq = 32;
-
-       if ((channel->center_freq % refclk_freq != 0) &&
-       ((channel->center_freq % refclk_freq < 10) ||
-       (channel->center_freq % refclk_freq > 22)))
-               return true;
-       else
-               return false;
-}
-
-void
+static void
 ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
                                struct ieee80211_channel *channel)
 {
@@ -1472,7 +1637,7 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
        spur_chan_fbin = AR5K_EEPROM_NO_SPUR;
        spur_detection_window = AR5K_SPUR_CHAN_WIDTH;
        /* XXX: Half/Quarter channels ?*/
-       if (channel->hw_value & CHANNEL_TURBO)
+       if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
                spur_detection_window *= 2;
 
        for (i = 0; i < AR5K_EEPROM_N_SPUR_CHANS; i++) {
@@ -1501,32 +1666,43 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
                 * Calculate deltas:
                 * spur_freq_sigma_delta -> spur_offset / sample_freq << 21
                 * spur_delta_phase -> spur_offset / chip_freq << 11
-                * Note: Both values have 100KHz resolution
+                * Note: Both values have 100Hz resolution
                 */
-               /* XXX: Half/Quarter rate channels ? */
-               switch (channel->hw_value) {
-               case CHANNEL_A:
-                       /* Both sample_freq and chip_freq are 40MHz */
-                       spur_delta_phase = (spur_offset << 17) / 25;
-                       spur_freq_sigma_delta = (spur_delta_phase >> 10);
-                       symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz;
-                       break;
-               case CHANNEL_G:
-                       /* sample_freq -> 40MHz chip_freq -> 44MHz
-                        * (for b compatibility) */
-                       spur_freq_sigma_delta = (spur_offset << 8) / 55;
-                       spur_delta_phase = (spur_offset << 17) / 25;
-                       symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz;
-                       break;
-               case CHANNEL_T:
-               case CHANNEL_TG:
+               switch (ah->ah_bwmode) {
+               case AR5K_BWMODE_40MHZ:
                        /* Both sample_freq and chip_freq are 80MHz */
                        spur_delta_phase = (spur_offset << 16) / 25;
                        spur_freq_sigma_delta = (spur_delta_phase >> 10);
-                       symbol_width = AR5K_SPUR_SYMBOL_WIDTH_TURBO_100Hz;
+                       symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz * 2;
                        break;
+               case AR5K_BWMODE_10MHZ:
+                       /* Both sample_freq and chip_freq are 20MHz (?) */
+                       spur_delta_phase = (spur_offset << 18) / 25;
+                       spur_freq_sigma_delta = (spur_delta_phase >> 10);
+                       symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 2;
+               case AR5K_BWMODE_5MHZ:
+                       /* Both sample_freq and chip_freq are 10MHz (?) */
+                       spur_delta_phase = (spur_offset << 19) / 25;
+                       spur_freq_sigma_delta = (spur_delta_phase >> 10);
+                       symbol_width = AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz / 4;
                default:
-                       return;
+                       if (channel->hw_value == CHANNEL_A) {
+                               /* Both sample_freq and chip_freq are 40MHz */
+                               spur_delta_phase = (spur_offset << 17) / 25;
+                               spur_freq_sigma_delta =
+                                               (spur_delta_phase >> 10);
+                               symbol_width =
+                                       AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz;
+                       } else {
+                               /* sample_freq -> 40MHz chip_freq -> 44MHz
+                                * (for b compatibility) */
+                               spur_delta_phase = (spur_offset << 17) / 25;
+                               spur_freq_sigma_delta =
+                                               (spur_offset << 8) / 55;
+                               symbol_width =
+                                       AR5K_SPUR_SYMBOL_WIDTH_BASE_100Hz;
+                       }
+                       break;
                }
 
                /* Calculate pilot and magnitude masks */
@@ -1666,63 +1842,6 @@ ath5k_hw_set_spur_mitigation_filter(struct ath5k_hw *ah,
        }
 }
 
-/********************\
-  Misc PHY functions
-\********************/
-
-int ath5k_hw_phy_disable(struct ath5k_hw *ah)
-{
-       /*Just a try M.F.*/
-       ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
-
-       return 0;
-}
-
-/*
- * Get the PHY Chip revision
- */
-u16 ath5k_hw_radio_revision(struct ath5k_hw *ah, unsigned int chan)
-{
-       unsigned int i;
-       u32 srev;
-       u16 ret;
-
-       /*
-        * Set the radio chip access register
-        */
-       switch (chan) {
-       case CHANNEL_2GHZ:
-               ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_2GHZ, AR5K_PHY(0));
-               break;
-       case CHANNEL_5GHZ:
-               ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
-               break;
-       default:
-               return 0;
-       }
-
-       mdelay(2);
-
-       /* ...wait until PHY is ready and read the selected radio revision */
-       ath5k_hw_reg_write(ah, 0x00001c16, AR5K_PHY(0x34));
-
-       for (i = 0; i < 8; i++)
-               ath5k_hw_reg_write(ah, 0x00010000, AR5K_PHY(0x20));
-
-       if (ah->ah_version == AR5K_AR5210) {
-               srev = ath5k_hw_reg_read(ah, AR5K_PHY(256) >> 28) & 0xf;
-               ret = (u16)ath5k_hw_bitswap(srev, 4) + 1;
-       } else {
-               srev = (ath5k_hw_reg_read(ah, AR5K_PHY(0x100)) >> 24) & 0xff;
-               ret = (u16)ath5k_hw_bitswap(((srev & 0xf0) >> 4) |
-                               ((srev & 0x0f) << 4), 8);
-       }
-
-       /* Reset to the 5GHz mode */
-       ath5k_hw_reg_write(ah, AR5K_PHY_SHIFT_5GHZ, AR5K_PHY(0));
-
-       return ret;
-}
 
 /*****************\
 * Antenna control *
@@ -1830,12 +1949,10 @@ ath5k_hw_set_antenna_mode(struct ath5k_hw *ah, u8 ant_mode)
 
        switch (channel->hw_value & CHANNEL_MODES) {
        case CHANNEL_A:
-       case CHANNEL_T:
        case CHANNEL_XR:
                ee_mode = AR5K_EEPROM_MODE_11A;
                break;
        case CHANNEL_G:
-       case CHANNEL_TG:
                ee_mode = AR5K_EEPROM_MODE_11G;
                break;
        case CHANNEL_B:
@@ -2269,20 +2386,20 @@ ath5k_get_max_ctl_power(struct ath5k_hw *ah,
 
        switch (channel->hw_value & CHANNEL_MODES) {
        case CHANNEL_A:
-               ctl_mode |= AR5K_CTL_11A;
+               if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
+                       ctl_mode |= AR5K_CTL_TURBO;
+               else
+                       ctl_mode |= AR5K_CTL_11A;
                break;
        case CHANNEL_G:
-               ctl_mode |= AR5K_CTL_11G;
+               if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
+                       ctl_mode |= AR5K_CTL_TURBOG;
+               else
+                       ctl_mode |= AR5K_CTL_11G;
                break;
        case CHANNEL_B:
                ctl_mode |= AR5K_CTL_11B;
                break;
-       case CHANNEL_T:
-               ctl_mode |= AR5K_CTL_TURBO;
-               break;
-       case CHANNEL_TG:
-               ctl_mode |= AR5K_CTL_TURBOG;
-               break;
        case CHANNEL_XR:
                /* Fall through */
        default:
@@ -2984,9 +3101,9 @@ ath5k_setup_rate_powertable(struct ath5k_hw *ah, u16 max_pwr,
 /*
  * Set transmission power
  */
-int
+static int
 ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
-               u8 ee_mode, u8 txpower)
+               u8 ee_mode, u8 txpower, bool fast)
 {
        struct ath5k_rate_pcal_info rate_info;
        u8 type;
@@ -3005,6 +3122,9 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
 
        /* Initialize TX power table */
        switch (ah->ah_radio) {
+       case AR5K_RF5110:
+               /* TODO */
+               return 0;
        case AR5K_RF5111:
                type = AR5K_PWRTABLE_PWR_TO_PCDAC;
                break;
@@ -3022,10 +3142,15 @@ ath5k_hw_txpower(struct ath5k_hw *ah, struct ieee80211_channel *channel,
                return -EINVAL;
        }
 
-       /* FIXME: Only on channel/mode change */
-       ret = ath5k_setup_channel_powertable(ah, channel, ee_mode, type);
-       if (ret)
-               return ret;
+       /* If fast is set it means we are on the same channel/mode
+        * so there is no need to recalculate the powertable, we 'll
+        * just use the cached one */
+       if (!fast) {
+               ret = ath5k_setup_channel_powertable(ah, channel,
+                                                       ee_mode, type);
+                       if (ret)
+                               return ret;
+       }
 
        /* Limit max power if we have a CTL available */
        ath5k_get_max_ctl_power(ah, channel);
@@ -3086,12 +3211,10 @@ int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
 
        switch (channel->hw_value & CHANNEL_MODES) {
        case CHANNEL_A:
-       case CHANNEL_T:
        case CHANNEL_XR:
                ee_mode = AR5K_EEPROM_MODE_11A;
                break;
        case CHANNEL_G:
-       case CHANNEL_TG:
                ee_mode = AR5K_EEPROM_MODE_11G;
                break;
        case CHANNEL_B:
@@ -3106,5 +3229,229 @@ int ath5k_hw_set_txpower_limit(struct ath5k_hw *ah, u8 txpower)
        ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_TXPOWER,
                "changing txpower to %d\n", txpower);
 
-       return ath5k_hw_txpower(ah, channel, ee_mode, txpower);
+       return ath5k_hw_txpower(ah, channel, ee_mode, txpower, true);
+}
+
+/*************\
+ Init function
+\*************/
+
+int ath5k_hw_phy_init(struct ath5k_hw *ah, struct ieee80211_channel *channel,
+                               u8 mode, u8 ee_mode, u8 freq, bool fast)
+{
+       struct ieee80211_channel *curr_channel;
+       int ret, i;
+       u32 phy_tst1;
+       bool fast_txp;
+       ret = 0;
+
+       /*
+        * Sanity check for fast flag
+        * Don't try fast channel change when changing modulation
+        * mode/band. We check for chip compatibility on
+        * ath5k_hw_reset.
+        */
+       curr_channel = ah->ah_current_channel;
+       if (fast && (channel->hw_value != curr_channel->hw_value))
+               return -EINVAL;
+
+       /*
+        * On fast channel change we only set the synth parameters
+        * while PHY is running, enable calibration and skip the rest.
+        */
+       if (fast) {
+               AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_RFBUS_REQ,
+                                   AR5K_PHY_RFBUS_REQ_REQUEST);
+               for (i = 0; i < 100; i++) {
+                       if (ath5k_hw_reg_read(ah, AR5K_PHY_RFBUS_GRANT))
+                               break;
+                       udelay(5);
+               }
+               /* Failed */
+               if (i >= 100)
+                       return -EIO;
+       }
+
+       /*
+        * If we don't change channel/mode skip
+        * tx powertable calculation and use the
+        * cached one.
+        */
+       if ((channel->hw_value == curr_channel->hw_value) &&
+       (channel->center_freq == curr_channel->center_freq))
+               fast_txp = true;
+       else
+               fast_txp = false;
+
+       /*
+        * Set TX power
+        *
+        * Note: We need to do that before we set
+        * RF buffer settings on 5211/5212+ so that we
+        * properly set curve indices.
+        */
+       ret = ath5k_hw_txpower(ah, channel, ee_mode,
+                               ah->ah_txpower.txp_max_pwr / 2,
+                               fast_txp);
+       if (ret)
+               return ret;
+
+       /*
+        * For 5210 we do all initialization using
+        * initvals, so we don't have to modify
+        * any settings (5210 also only supports
+        * a/aturbo modes)
+        */
+       if ((ah->ah_version != AR5K_AR5210) && !fast) {
+
+               /*
+                * Write initial RF gain settings
+                * This should work for both 5111/5112
+                */
+               ret = ath5k_hw_rfgain_init(ah, freq);
+               if (ret)
+                       return ret;
+
+               mdelay(1);
+
+               /*
+                * Write RF buffer
+                */
+               ret = ath5k_hw_rfregs_init(ah, channel, mode);
+               if (ret)
+                       return ret;
+
+               /* Write OFDM timings on 5212*/
+               if (ah->ah_version == AR5K_AR5212 &&
+                       channel->hw_value & CHANNEL_OFDM) {
+
+                       ret = ath5k_hw_write_ofdm_timings(ah, channel);
+                       if (ret)
+                               return ret;
+
+                       /* Spur info is available only from EEPROM versions
+                        * greater than 5.3, but the EEPROM routines will use
+                        * static values for older versions */
+                       if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
+                               ath5k_hw_set_spur_mitigation_filter(ah,
+                                                                   channel);
+               }
+
+               /*Enable/disable 802.11b mode on 5111
+               (enable 2111 frequency converter + CCK)*/
+               if (ah->ah_radio == AR5K_RF5111) {
+                       if (mode == AR5K_MODE_11B)
+                               AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG,
+                                   AR5K_TXCFG_B_MODE);
+                       else
+                               AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
+                                   AR5K_TXCFG_B_MODE);
+               }
+
+       } else if (ah->ah_version == AR5K_AR5210) {
+               mdelay(1);
+               /* Disable phy and wait */
+               ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
+               mdelay(1);
+       }
+
+       /* Set channel on PHY */
+       ret = ath5k_hw_channel(ah, channel);
+       if (ret)
+               return ret;
+
+       /*
+        * Enable the PHY and wait until completion
+        * This includes BaseBand and Synthesizer
+        * activation.
+        */
+       ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
+
+       /*
+        * On 5211+ read activation -> rx delay
+        * and use it.
+        */
+       if (ah->ah_version != AR5K_AR5210) {
+               u32 delay;
+               delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
+                       AR5K_PHY_RX_DELAY_M;
+               delay = (channel->hw_value & CHANNEL_CCK) ?
+                       ((delay << 2) / 22) : (delay / 10);
+               if (ah->ah_bwmode == AR5K_BWMODE_10MHZ)
+                       delay = delay << 1;
+               if (ah->ah_bwmode == AR5K_BWMODE_5MHZ)
+                       delay = delay << 2;
+               /* XXX: /2 on turbo ? Let's be safe
+                * for now */
+               udelay(100 + delay);
+       } else {
+               mdelay(1);
+       }
+
+       if (fast)
+               /*
+                * Release RF Bus grant
+                */
+               AR5K_REG_DISABLE_BITS(ah, AR5K_PHY_RFBUS_REQ,
+                                   AR5K_PHY_RFBUS_REQ_REQUEST);
+       else {
+               /*
+                * Perform ADC test to see if baseband is ready
+                * Set tx hold and check adc test register
+                */
+               phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
+               ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
+               for (i = 0; i <= 20; i++) {
+                       if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
+                               break;
+                       udelay(200);
+               }
+               ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
+       }
+
+       /*
+        * Start automatic gain control calibration
+        *
+        * During AGC calibration RX path is re-routed to
+        * a power detector so we don't receive anything.
+        *
+        * This method is used to calibrate some static offsets
+        * used together with on-the fly I/Q calibration (the
+        * one performed via ath5k_hw_phy_calibrate), which doesn't
+        * interrupt rx path.
+        *
+        * While rx path is re-routed to the power detector we also
+        * start a noise floor calibration to measure the
+        * card's noise floor (the noise we measure when we are not
+        * transmitting or receiving anything).
+        *
+        * If we are in a noisy environment, AGC calibration may time
+        * out and/or noise floor calibration might timeout.
+        */
+       AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
+                               AR5K_PHY_AGCCTL_CAL | AR5K_PHY_AGCCTL_NF);
+
+       /* At the same time start I/Q calibration for QAM constellation
+        * -no need for CCK- */
+       ah->ah_calibration = false;
+       if (!(mode == AR5K_MODE_11B)) {
+               ah->ah_calibration = true;
+               AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
+                               AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
+               AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
+                               AR5K_PHY_IQ_RUN);
+       }
+
+       /* Wait for gain calibration to finish (we check for I/Q calibration
+        * during ath5k_phy_calibrate) */
+       if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
+                       AR5K_PHY_AGCCTL_CAL, 0, false)) {
+               ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n",
+                       channel->center_freq);
+       }
+
+       /* Restore antenna mode */
+       ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
+
+       return ret;
 }
index 84c717ded1c5de8aad2a952f4d6afb507da8d261..1849eee8235c6aab94c945a4d7b3077aeb70ae5a 100644 (file)
@@ -25,14 +25,52 @@ Queue Control Unit, DFS Control Unit Functions
 #include "debug.h"
 #include "base.h"
 
+
+/******************\
+* Helper functions *
+\******************/
+
 /*
- * Get properties for a transmit queue
+ * Get number of pending frames
+ * for a specific queue [5211+]
  */
-int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
-               struct ath5k_txq_info *queue_info)
+u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
 {
-       memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
-       return 0;
+       u32 pending;
+       AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
+
+       /* Return if queue is declared inactive */
+       if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
+               return false;
+
+       /* XXX: How about AR5K_CFG_TXCNT ? */
+       if (ah->ah_version == AR5K_AR5210)
+               return false;
+
+       pending = ath5k_hw_reg_read(ah, AR5K_QUEUE_STATUS(queue));
+       pending &= AR5K_QCU_STS_FRMPENDCNT;
+
+       /* It's possible to have no frames pending even if TXE
+        * is set. To indicate that q has not stopped return
+        * true */
+       if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
+               return true;
+
+       return pending;
+}
+
+/*
+ * Set a transmit queue inactive
+ */
+void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
+{
+       if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
+               return;
+
+       /* This queue will be skipped in further operations */
+       ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
+       /*For SIMR setup*/
+       AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
 }
 
 /*
@@ -49,6 +87,16 @@ static u16 ath5k_cw_validate(u16 cw_req)
        return cw;
 }
 
+/*
+ * Get properties for a transmit queue
+ */
+int ath5k_hw_get_tx_queueprops(struct ath5k_hw *ah, int queue,
+               struct ath5k_txq_info *queue_info)
+{
+       memcpy(queue_info, &ah->ah_txq[queue], sizeof(struct ath5k_txq_info));
+       return 0;
+}
+
 /*
  * Set properties for a transmit queue
  */
@@ -172,113 +220,18 @@ int ath5k_hw_setup_tx_queue(struct ath5k_hw *ah, enum ath5k_tx_queue queue_type,
        return queue;
 }
 
-/*
- * Get number of pending frames
- * for a specific queue [5211+]
- */
-u32 ath5k_hw_num_tx_pending(struct ath5k_hw *ah, unsigned int queue)
-{
-       u32 pending;
-       AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
-
-       /* Return if queue is declared inactive */
-       if (ah->ah_txq[queue].tqi_type == AR5K_TX_QUEUE_INACTIVE)
-               return false;
-
-       /* XXX: How about AR5K_CFG_TXCNT ? */
-       if (ah->ah_version == AR5K_AR5210)
-               return false;
-
-       pending = ath5k_hw_reg_read(ah, AR5K_QUEUE_STATUS(queue));
-       pending &= AR5K_QCU_STS_FRMPENDCNT;
-
-       /* It's possible to have no frames pending even if TXE
-        * is set. To indicate that q has not stopped return
-        * true */
-       if (!pending && AR5K_REG_READ_Q(ah, AR5K_QCU_TXE, queue))
-               return true;
-
-       return pending;
-}
-
-/*
- * Set a transmit queue inactive
- */
-void ath5k_hw_release_tx_queue(struct ath5k_hw *ah, unsigned int queue)
-{
-       if (WARN_ON(queue >= ah->ah_capabilities.cap_queues.q_tx_num))
-               return;
 
-       /* This queue will be skipped in further operations */
-       ah->ah_txq[queue].tqi_type = AR5K_TX_QUEUE_INACTIVE;
-       /*For SIMR setup*/
-       AR5K_Q_DISABLE_BITS(ah->ah_txq_status, queue);
-}
+/*******************************\
+* Single QCU/DCU initialization *
+\*******************************/
 
 /*
- * Set DFS properties for a transmit queue on DCU
+ * Set tx retry limits on DCU
  */
-int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
+static void ath5k_hw_set_tx_retry_limits(struct ath5k_hw *ah,
+                                       unsigned int queue)
 {
        u32 retry_lg, retry_sh;
-       struct ath5k_txq_info *tq = &ah->ah_txq[queue];
-
-       AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
-
-       tq = &ah->ah_txq[queue];
-
-       if (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE)
-               return 0;
-
-       if (ah->ah_version == AR5K_AR5210) {
-               /* Only handle data queues, others will be ignored */
-               if (tq->tqi_type != AR5K_TX_QUEUE_DATA)
-                       return 0;
-
-               /* Set Slot time */
-               ath5k_hw_reg_write(ah, ah->ah_turbo ?
-                       AR5K_INIT_SLOT_TIME_TURBO : AR5K_INIT_SLOT_TIME,
-                       AR5K_SLOT_TIME);
-               /* Set ACK_CTS timeout */
-               ath5k_hw_reg_write(ah, ah->ah_turbo ?
-                       AR5K_INIT_ACK_CTS_TIMEOUT_TURBO :
-                       AR5K_INIT_ACK_CTS_TIMEOUT, AR5K_SLOT_TIME);
-               /* Set Transmit Latency */
-               ath5k_hw_reg_write(ah, ah->ah_turbo ?
-                       AR5K_INIT_TRANSMIT_LATENCY_TURBO :
-                       AR5K_INIT_TRANSMIT_LATENCY, AR5K_USEC_5210);
-
-               /* Set IFS0 */
-               if (ah->ah_turbo) {
-                        ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS_TURBO +
-                               tq->tqi_aifs * AR5K_INIT_SLOT_TIME_TURBO) <<
-                               AR5K_IFS0_DIFS_S) | AR5K_INIT_SIFS_TURBO,
-                               AR5K_IFS0);
-               } else {
-                       ath5k_hw_reg_write(ah, ((AR5K_INIT_SIFS +
-                               tq->tqi_aifs * AR5K_INIT_SLOT_TIME) <<
-                               AR5K_IFS0_DIFS_S) |
-                               AR5K_INIT_SIFS, AR5K_IFS0);
-               }
-
-               /* Set IFS1 */
-               ath5k_hw_reg_write(ah, ah->ah_turbo ?
-                       AR5K_INIT_PROTO_TIME_CNTRL_TURBO :
-                       AR5K_INIT_PROTO_TIME_CNTRL, AR5K_IFS1);
-               /* Set AR5K_PHY_SETTLING */
-               ath5k_hw_reg_write(ah, ah->ah_turbo ?
-                       (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
-                       | 0x38 :
-                       (ath5k_hw_reg_read(ah, AR5K_PHY_SETTLING) & ~0x7F)
-                       | 0x1C,
-                       AR5K_PHY_SETTLING);
-               /* Set Frame Control Register */
-               ath5k_hw_reg_write(ah, ah->ah_turbo ?
-                       (AR5K_PHY_FRAME_CTL_INI | AR5K_PHY_TURBO_MODE |
-                       AR5K_PHY_TURBO_SHORT | 0x2020) :
-                       (AR5K_PHY_FRAME_CTL_INI | 0x1020),
-                       AR5K_PHY_FRAME_CTL_5210);
-       }
 
        /*
         * Calculate and set retry limits
@@ -293,8 +246,13 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
                retry_sh = AR5K_INIT_SH_RETRY;
        }
 
-       /*No QCU/DCU [5210]*/
+       /* Single data queue on AR5210 */
        if (ah->ah_version == AR5K_AR5210) {
+               struct ath5k_txq_info *tq = &ah->ah_txq[queue];
+
+               if (queue > 0)
+                       return;
+
                ath5k_hw_reg_write(ah,
                        (tq->tqi_cw_min << AR5K_NODCU_RETRY_LMT_CW_MIN_S)
                        | AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
@@ -304,8 +262,8 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
                        | AR5K_REG_SM(retry_lg, AR5K_NODCU_RETRY_LMT_LG_RETRY)
                        | AR5K_REG_SM(retry_sh, AR5K_NODCU_RETRY_LMT_SH_RETRY),
                        AR5K_NODCU_RETRY_LMT);
+       /* DCU on AR5211+ */
        } else {
-               /*QCU/DCU [5211+]*/
                ath5k_hw_reg_write(ah,
                        AR5K_REG_SM(AR5K_INIT_SLG_RETRY,
                                AR5K_DCU_RETRY_LMT_SLG_RETRY) |
@@ -314,219 +272,393 @@ int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
                        AR5K_REG_SM(retry_lg, AR5K_DCU_RETRY_LMT_LG_RETRY) |
                        AR5K_REG_SM(retry_sh, AR5K_DCU_RETRY_LMT_SH_RETRY),
                        AR5K_QUEUE_DFS_RETRY_LIMIT(queue));
+       }
+       return;
+}
+
+/**
+ * ath5k_hw_reset_tx_queue - Initialize a single hw queue
+ *
+ * @ah The &struct ath5k_hw
+ * @queue The hw queue number
+ *
+ * Set DFS properties for the given transmit queue on DCU
+ * and configures all queue-specific parameters.
+ */
+int ath5k_hw_reset_tx_queue(struct ath5k_hw *ah, unsigned int queue)
+{
+       struct ath5k_txq_info *tq = &ah->ah_txq[queue];
 
-       /*===Rest is also for QCU/DCU only [5211+]===*/
+       AR5K_ASSERT_ENTRY(queue, ah->ah_capabilities.cap_queues.q_tx_num);
 
-               /*
-                * Set contention window (cw_min/cw_max)
-                * and arbitrated interframe space (aifs)...
-                */
-               ath5k_hw_reg_write(ah,
-                       AR5K_REG_SM(tq->tqi_cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
-                       AR5K_REG_SM(tq->tqi_cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
-                       AR5K_REG_SM(tq->tqi_aifs, AR5K_DCU_LCL_IFS_AIFS),
-                       AR5K_QUEUE_DFS_LOCAL_IFS(queue));
-
-               /*
-                * Set misc registers
-                */
-               /* Enable DCU early termination for this queue */
-               AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
-                                       AR5K_QCU_MISC_DCU_EARLY);
+       tq = &ah->ah_txq[queue];
+
+       /* Skip if queue inactive or if we are on AR5210
+        * that doesn't have QCU/DCU */
+       if ((ah->ah_version == AR5K_AR5210) ||
+       (tq->tqi_type == AR5K_TX_QUEUE_INACTIVE))
+               return 0;
+
+       /*
+        * Set contention window (cw_min/cw_max)
+        * and arbitrated interframe space (aifs)...
+        */
+       ath5k_hw_reg_write(ah,
+               AR5K_REG_SM(tq->tqi_cw_min, AR5K_DCU_LCL_IFS_CW_MIN) |
+               AR5K_REG_SM(tq->tqi_cw_max, AR5K_DCU_LCL_IFS_CW_MAX) |
+               AR5K_REG_SM(tq->tqi_aifs, AR5K_DCU_LCL_IFS_AIFS),
+               AR5K_QUEUE_DFS_LOCAL_IFS(queue));
+
+       /*
+        * Set tx retry limits for this queue
+        */
+       ath5k_hw_set_tx_retry_limits(ah, queue);
+
+
+       /*
+        * Set misc registers
+        */
+
+       /* Enable DCU to wait for next fragment from QCU */
+       AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+                               AR5K_DCU_MISC_FRAG_WAIT);
 
-               /* Enable DCU to wait for next fragment from QCU */
+       /* On Maui and Spirit use the global seqnum on DCU */
+       if (ah->ah_mac_version < AR5K_SREV_AR5211)
                AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
-                                       AR5K_DCU_MISC_FRAG_WAIT);
-
-               /* On Maui and Spirit use the global seqnum on DCU */
-               if (ah->ah_mac_version < AR5K_SREV_AR5211)
-                       AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
-                                               AR5K_DCU_MISC_SEQNUM_CTL);
-
-               if (tq->tqi_cbr_period) {
-                       ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
-                               AR5K_QCU_CBRCFG_INTVAL) |
-                               AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
-                               AR5K_QCU_CBRCFG_ORN_THRES),
-                               AR5K_QUEUE_CBRCFG(queue));
+                                       AR5K_DCU_MISC_SEQNUM_CTL);
+
+       /* Constant bit rate period */
+       if (tq->tqi_cbr_period) {
+               ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_cbr_period,
+                                       AR5K_QCU_CBRCFG_INTVAL) |
+                                       AR5K_REG_SM(tq->tqi_cbr_overflow_limit,
+                                       AR5K_QCU_CBRCFG_ORN_THRES),
+                                       AR5K_QUEUE_CBRCFG(queue));
+
+               AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+                                       AR5K_QCU_MISC_FRSHED_CBR);
+
+               if (tq->tqi_cbr_overflow_limit)
                        AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
-                               AR5K_QCU_MISC_FRSHED_CBR);
-                       if (tq->tqi_cbr_overflow_limit)
-                               AR5K_REG_ENABLE_BITS(ah,
-                                       AR5K_QUEUE_MISC(queue),
                                        AR5K_QCU_MISC_CBR_THRES_ENABLE);
-               }
+       }
 
-               if (tq->tqi_ready_time &&
-               (tq->tqi_type != AR5K_TX_QUEUE_CAB))
-                       ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
-                               AR5K_QCU_RDYTIMECFG_INTVAL) |
-                               AR5K_QCU_RDYTIMECFG_ENABLE,
-                               AR5K_QUEUE_RDYTIMECFG(queue));
-
-               if (tq->tqi_burst_time) {
-                       ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
-                               AR5K_DCU_CHAN_TIME_DUR) |
-                               AR5K_DCU_CHAN_TIME_ENABLE,
-                               AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
-
-                       if (tq->tqi_flags
-                       & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
-                               AR5K_REG_ENABLE_BITS(ah,
-                                       AR5K_QUEUE_MISC(queue),
+       /* Ready time interval */
+       if (tq->tqi_ready_time && (tq->tqi_type != AR5K_TX_QUEUE_CAB))
+               ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_ready_time,
+                                       AR5K_QCU_RDYTIMECFG_INTVAL) |
+                                       AR5K_QCU_RDYTIMECFG_ENABLE,
+                                       AR5K_QUEUE_RDYTIMECFG(queue));
+
+       if (tq->tqi_burst_time) {
+               ath5k_hw_reg_write(ah, AR5K_REG_SM(tq->tqi_burst_time,
+                                       AR5K_DCU_CHAN_TIME_DUR) |
+                                       AR5K_DCU_CHAN_TIME_ENABLE,
+                                       AR5K_QUEUE_DFS_CHANNEL_TIME(queue));
+
+               if (tq->tqi_flags & AR5K_TXQ_FLAG_RDYTIME_EXP_POLICY_ENABLE)
+                       AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
                                        AR5K_QCU_MISC_RDY_VEOL_POLICY);
-               }
+       }
 
-               if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
-                       ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
-                               AR5K_QUEUE_DFS_MISC(queue));
+       /* Enable/disable Post frame backoff */
+       if (tq->tqi_flags & AR5K_TXQ_FLAG_BACKOFF_DISABLE)
+               ath5k_hw_reg_write(ah, AR5K_DCU_MISC_POST_FR_BKOFF_DIS,
+                                       AR5K_QUEUE_DFS_MISC(queue));
 
-               if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
-                       ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
-                               AR5K_QUEUE_DFS_MISC(queue));
+       /* Enable/disable fragmentation burst backoff */
+       if (tq->tqi_flags & AR5K_TXQ_FLAG_FRAG_BURST_BACKOFF_ENABLE)
+               ath5k_hw_reg_write(ah, AR5K_DCU_MISC_BACKOFF_FRAG,
+                                       AR5K_QUEUE_DFS_MISC(queue));
 
-               /*
-                * Set registers by queue type
-                */
-               switch (tq->tqi_type) {
-               case AR5K_TX_QUEUE_BEACON:
-                       AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+       /*
+        * Set registers by queue type
+        */
+       switch (tq->tqi_type) {
+       case AR5K_TX_QUEUE_BEACON:
+               AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
                                AR5K_QCU_MISC_FRSHED_DBA_GT |
                                AR5K_QCU_MISC_CBREXP_BCN_DIS |
                                AR5K_QCU_MISC_BCN_ENABLE);
 
-                       AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+               AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
                                (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
                                AR5K_DCU_MISC_ARBLOCK_CTL_S) |
                                AR5K_DCU_MISC_ARBLOCK_IGNORE |
                                AR5K_DCU_MISC_POST_FR_BKOFF_DIS |
                                AR5K_DCU_MISC_BCN_ENABLE);
-                       break;
+               break;
 
-               case AR5K_TX_QUEUE_CAB:
-                       /* XXX: use BCN_SENT_GT, if we can figure out how */
-                       AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
-                               AR5K_QCU_MISC_FRSHED_DBA_GT |
-                               AR5K_QCU_MISC_CBREXP_DIS |
-                               AR5K_QCU_MISC_CBREXP_BCN_DIS);
+       case AR5K_TX_QUEUE_CAB:
+               /* XXX: use BCN_SENT_GT, if we can figure out how */
+               AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+                                       AR5K_QCU_MISC_FRSHED_DBA_GT |
+                                       AR5K_QCU_MISC_CBREXP_DIS |
+                                       AR5K_QCU_MISC_CBREXP_BCN_DIS);
 
-                       ath5k_hw_reg_write(ah, ((tq->tqi_ready_time -
-                               (AR5K_TUNE_SW_BEACON_RESP -
-                               AR5K_TUNE_DMA_BEACON_RESP) -
+               ath5k_hw_reg_write(ah, ((tq->tqi_ready_time -
+                                       (AR5K_TUNE_SW_BEACON_RESP -
+                                       AR5K_TUNE_DMA_BEACON_RESP) -
                                AR5K_TUNE_ADDITIONAL_SWBA_BACKOFF) * 1024) |
-                               AR5K_QCU_RDYTIMECFG_ENABLE,
-                               AR5K_QUEUE_RDYTIMECFG(queue));
+                                       AR5K_QCU_RDYTIMECFG_ENABLE,
+                                       AR5K_QUEUE_RDYTIMECFG(queue));
 
-                       AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
-                               (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
-                               AR5K_DCU_MISC_ARBLOCK_CTL_S));
-                       break;
+               AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_DFS_MISC(queue),
+                                       (AR5K_DCU_MISC_ARBLOCK_CTL_GLOBAL <<
+                                       AR5K_DCU_MISC_ARBLOCK_CTL_S));
+               break;
 
-               case AR5K_TX_QUEUE_UAPSD:
-                       AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
-                               AR5K_QCU_MISC_CBREXP_DIS);
-                       break;
+       case AR5K_TX_QUEUE_UAPSD:
+               AR5K_REG_ENABLE_BITS(ah, AR5K_QUEUE_MISC(queue),
+                                       AR5K_QCU_MISC_CBREXP_DIS);
+               break;
 
-               case AR5K_TX_QUEUE_DATA:
-               default:
+       case AR5K_TX_QUEUE_DATA:
+       default:
                        break;
-               }
-
-               /* TODO: Handle frame compression */
-
-               /*
-                * Enable interrupts for this tx queue
-                * in the secondary interrupt mask registers
-                */
-               if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
-                       AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
-
-               if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
-                       AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
-
-               if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
-                       AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
-
-               if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
-                       AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, 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) |
-                       AR5K_REG_SM(ah->ah_txq_imr_txdesc,
-                       AR5K_SIMR0_QCU_TXDESC), AR5K_SIMR0);
-               ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
-                       AR5K_SIMR1_QCU_TXERR) |
-                       AR5K_REG_SM(ah->ah_txq_imr_txeol,
-                       AR5K_SIMR1_QCU_TXEOL), AR5K_SIMR1);
-               /* 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);
-
-               /* Set QCU mask for this DCU to save power */
-               AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue);
        }
 
+       /* TODO: Handle frame compression */
+
+       /*
+        * Enable interrupts for this tx queue
+        * in the secondary interrupt mask registers
+        */
+       if (tq->tqi_flags & AR5K_TXQ_FLAG_TXOKINT_ENABLE)
+               AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txok, queue);
+
+       if (tq->tqi_flags & AR5K_TXQ_FLAG_TXERRINT_ENABLE)
+               AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txerr, queue);
+
+       if (tq->tqi_flags & AR5K_TXQ_FLAG_TXURNINT_ENABLE)
+               AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txurn, queue);
+
+       if (tq->tqi_flags & AR5K_TXQ_FLAG_TXDESCINT_ENABLE)
+               AR5K_Q_ENABLE_BITS(ah->ah_txq_imr_txdesc, 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) |
+                                       AR5K_REG_SM(ah->ah_txq_imr_txdesc,
+                                       AR5K_SIMR0_QCU_TXDESC),
+                                       AR5K_SIMR0);
+
+       ath5k_hw_reg_write(ah, AR5K_REG_SM(ah->ah_txq_imr_txerr,
+                                       AR5K_SIMR1_QCU_TXERR) |
+                                       AR5K_REG_SM(ah->ah_txq_imr_txeol,
+                                       AR5K_SIMR1_QCU_TXEOL),
+                                       AR5K_SIMR1);
+
+       /* 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);
+
+       /* Set QCU mask for this DCU to save power */
+       AR5K_REG_WRITE_Q(ah, AR5K_QUEUE_QCUMASK(queue), queue);
+
        return 0;
 }
 
-/*
- * Set slot time on DCU
+
+/**************************\
+* Global QCU/DCU functions *
+\**************************/
+
+/**
+ * ath5k_hw_set_ifs_intervals  - Set global inter-frame spaces on DCU
+ *
+ * @ah The &struct ath5k_hw
+ * @slot_time Slot time in us
+ *
+ * Sets the global IFS intervals on DCU (also works on AR5210) for
+ * the given slot time and the current bwmode.
  */
-int ath5k_hw_set_slot_time(struct ath5k_hw *ah, unsigned int slot_time)
+int ath5k_hw_set_ifs_intervals(struct ath5k_hw *ah, unsigned int slot_time)
 {
+       struct ieee80211_channel *channel = ah->ah_current_channel;
+       struct ath5k_softc *sc = ah->ah_sc;
+       struct ieee80211_rate *rate;
+       u32 ack_tx_time, eifs, eifs_clock, sifs, sifs_clock;
        u32 slot_time_clock = ath5k_hw_htoclock(ah, slot_time);
 
        if (slot_time < 6 || slot_time_clock > AR5K_SLOT_TIME_MAX)
                return -EINVAL;
 
-       if (ah->ah_version == AR5K_AR5210)
-               ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME);
+       sifs = ath5k_hw_get_default_sifs(ah);
+       sifs_clock = ath5k_hw_htoclock(ah, sifs);
+
+       /* EIFS
+        * Txtime of ack at lowest rate + SIFS + DIFS
+        * (DIFS = SIFS + 2 * Slot time)
+        *
+        * Note: HAL has some predefined values for EIFS
+        * Turbo:   (37 + 2 * 6)
+        * Default: (74 + 2 * 9)
+        * Half:    (149 + 2 * 13)
+        * Quarter: (298 + 2 * 21)
+        *
+        * (74 + 2 * 6) for AR5210 default and turbo !
+        *
+        * According to the formula we have
+        * ack_tx_time = 25 for turbo and
+        * ack_tx_time = 42.5 * clock multiplier
+        * for default/half/quarter.
+        *
+        * This can't be right, 42 is what we would get
+        * from ath5k_hw_get_frame_dur_for_bwmode or
+        * ieee80211_generic_frame_duration for zero frame
+        * length and without SIFS !
+        *
+        * Also we have different lowest rate for 802.11a
+        */
+       if (channel->hw_value & CHANNEL_5GHZ)
+               rate = &sc->sbands[IEEE80211_BAND_5GHZ].bitrates[0];
        else
-               ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT);
+               rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[0];
+
+       ack_tx_time = ath5k_hw_get_frame_duration(ah, 10, rate);
+
+       /* ack_tx_time includes an SIFS already */
+       eifs = ack_tx_time + sifs + 2 * slot_time;
+       eifs_clock = ath5k_hw_htoclock(ah, eifs);
+
+       /* Set IFS settings on AR5210 */
+       if (ah->ah_version == AR5K_AR5210) {
+               u32 pifs, pifs_clock, difs, difs_clock;
+
+               /* Set slot time */
+               ath5k_hw_reg_write(ah, slot_time_clock, AR5K_SLOT_TIME);
+
+               /* Set EIFS */
+               eifs_clock = AR5K_REG_SM(eifs_clock, AR5K_IFS1_EIFS);
+
+               /* PIFS = Slot time + SIFS */
+               pifs = slot_time + sifs;
+               pifs_clock = ath5k_hw_htoclock(ah, pifs);
+               pifs_clock = AR5K_REG_SM(pifs_clock, AR5K_IFS1_PIFS);
+
+               /* DIFS = SIFS + 2 * Slot time */
+               difs = sifs + 2 * slot_time;
+               difs_clock = ath5k_hw_htoclock(ah, difs);
+
+               /* Set SIFS/DIFS */
+               ath5k_hw_reg_write(ah, (difs_clock <<
+                               AR5K_IFS0_DIFS_S) | sifs_clock,
+                               AR5K_IFS0);
+
+               /* Set PIFS/EIFS and preserve AR5K_INIT_CARR_SENSE_EN */
+               ath5k_hw_reg_write(ah, pifs_clock | eifs_clock |
+                               (AR5K_INIT_CARR_SENSE_EN << AR5K_IFS1_CS_EN_S),
+                               AR5K_IFS1);
+
+               return 0;
+       }
+
+       /* Set IFS slot time */
+       ath5k_hw_reg_write(ah, slot_time_clock, AR5K_DCU_GBL_IFS_SLOT);
+
+       /* Set EIFS interval */
+       ath5k_hw_reg_write(ah, eifs_clock, AR5K_DCU_GBL_IFS_EIFS);
+
+       /* Set SIFS interval in usecs */
+       AR5K_REG_WRITE_BITS(ah, AR5K_DCU_GBL_IFS_MISC,
+                               AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC,
+                               sifs);
+
+       /* Set SIFS interval in clock cycles */
+       ath5k_hw_reg_write(ah, sifs_clock, AR5K_DCU_GBL_IFS_SIFS);
 
        return 0;
 }
 
+
+int ath5k_hw_init_queues(struct ath5k_hw *ah)
+{
+       int i, ret;
+
+       /* TODO: HW Compression support for data queues */
+       /* TODO: Burst prefetch for data queues */
+
+       /*
+        * Reset queues and start beacon timers at the end of the reset routine
+        * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping
+        * Note: If we want we can assign multiple qcus on one dcu.
+        */
+       if (ah->ah_version != AR5K_AR5210)
+               for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) {
+                       ret = ath5k_hw_reset_tx_queue(ah, i);
+                       if (ret) {
+                               ATH5K_ERR(ah->ah_sc,
+                                       "failed to reset TX queue #%d\n", i);
+                               return ret;
+                       }
+               }
+       else
+               /* No QCU/DCU on AR5210, just set tx
+                * retry limits. We set IFS parameters
+                * on ath5k_hw_set_ifs_intervals */
+               ath5k_hw_set_tx_retry_limits(ah, 0);
+
+       /* Set the turbo flag when operating on 40MHz */
+       if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
+               AR5K_REG_ENABLE_BITS(ah, AR5K_DCU_GBL_IFS_MISC,
+                               AR5K_DCU_GBL_IFS_MISC_TURBO_MODE);
+
+       /* If we didn't set IFS timings through
+        * ath5k_hw_set_coverage_class make sure
+        * we set them here */
+       if (!ah->ah_coverage_class) {
+               unsigned int slot_time = ath5k_hw_get_default_slottime(ah);
+               ath5k_hw_set_ifs_intervals(ah, slot_time);
+       }
+
+       return 0;
+}
index ca79ecd832fd939d645ca55e03a03eab07b58eeb..7ad05d401ab5229cd020492e6bab49c4ed98a769 100644 (file)
 #define        AR5K_DCU_GBL_IFS_MISC_LFSR_SLICE        0x00000007      /* LFSR Slice Select */
 #define        AR5K_DCU_GBL_IFS_MISC_TURBO_MODE        0x00000008      /* Turbo mode */
 #define        AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC     0x000003f0      /* SIFS Duration mask */
+#define        AR5K_DCU_GBL_IFS_MISC_SIFS_DUR_USEC_S   4
 #define        AR5K_DCU_GBL_IFS_MISC_USEC_DUR          0x000ffc00      /* USEC Duration mask */
 #define        AR5K_DCU_GBL_IFS_MISC_USEC_DUR_S        10
 #define        AR5K_DCU_GBL_IFS_MISC_DCU_ARB_DELAY     0x00300000      /* DCU Arbiter delay mask */
 #define AR5K_IFS1_EIFS         0x03fff000
 #define AR5K_IFS1_EIFS_S       12
 #define AR5K_IFS1_CS_EN                0x04000000
-
+#define AR5K_IFS1_CS_EN_S      26
 
 /*
  * CFP duration register
 
 #define AR5K_PHY_SCAL                  0x9878
 #define AR5K_PHY_SCAL_32MHZ            0x0000000e
+#define        AR5K_PHY_SCAL_32MHZ_5311        0x00000008
 #define        AR5K_PHY_SCAL_32MHZ_2417        0x0000000a
 #define        AR5K_PHY_SCAL_32MHZ_HB63        0x00000032
 
 #define        AR5K_PHY_FRAME_CTL              (ah->ah_version == AR5K_AR5210 ? \
                                        AR5K_PHY_FRAME_CTL_5210 : AR5K_PHY_FRAME_CTL_5211)
 /*---[5111+]---*/
+#define        AR5K_PHY_FRAME_CTL_WIN_LEN      0x00000003      /* Force window length (?) */
+#define        AR5K_PHY_FRAME_CTL_WIN_LEN_S    0
 #define        AR5K_PHY_FRAME_CTL_TX_CLIP      0x00000038      /* Mask for tx clip (?) */
 #define        AR5K_PHY_FRAME_CTL_TX_CLIP_S    3
 #define        AR5K_PHY_FRAME_CTL_PREP_CHINFO  0x00010000      /* Prepend chan info */
  */
 #define AR5K_PHY_PDADC_TXPOWER_BASE    0xa280
 #define        AR5K_PHY_PDADC_TXPOWER(_n)      (AR5K_PHY_PDADC_TXPOWER_BASE + ((_n) << 2))
+
+/*
+ * Platform registers for WiSoC
+ */
+#define AR5K_AR5312_RESET              0xbc003020
+#define AR5K_AR5312_RESET_BB0_COLD     0x00000004
+#define AR5K_AR5312_RESET_BB1_COLD     0x00000200
+#define AR5K_AR5312_RESET_WMAC0                0x00002000
+#define AR5K_AR5312_RESET_BB0_WARM     0x00004000
+#define AR5K_AR5312_RESET_WMAC1                0x00020000
+#define AR5K_AR5312_RESET_BB1_WARM     0x00040000
+
+#define AR5K_AR5312_ENABLE             0xbc003080
+#define AR5K_AR5312_ENABLE_WLAN0    0x00000001
+#define AR5K_AR5312_ENABLE_WLAN1    0x00000008
+
+#define AR5K_AR2315_RESET              0xb1000004
+#define AR5K_AR2315_RESET_WMAC         0x00000001
+#define AR5K_AR2315_RESET_BB_WARM      0x00000002
+
+#define AR5K_AR2315_AHB_ARB_CTL                0xb1000008
+#define AR5K_AR2315_AHB_ARB_CTL_WLAN   0x00000002
+
+#define AR5K_AR2315_BYTESWAP   0xb100000c
+#define AR5K_AR2315_BYTESWAP_WMAC      0x00000002
index 5b179d01f97db16c64bddc97fc0ade0005bf57ee..bc84aaa314461772278137c69676d362840ea672 100644 (file)
 
 #include <linux/pci.h>                 /* To determine if a card is pci-e */
 #include <linux/log2.h>
+#include <linux/platform_device.h>
 #include "ath5k.h"
 #include "reg.h"
 #include "base.h"
 #include "debug.h"
 
+
+/******************\
+* Helper functions *
+\******************/
+
 /*
  * Check if a register write has been completed
  */
@@ -53,146 +59,267 @@ int ath5k_hw_register_timeout(struct ath5k_hw *ah, u32 reg, u32 flag, u32 val,
        return (i <= 0) ? -EAGAIN : 0;
 }
 
+
+/*************************\
+* Clock related functions *
+\*************************/
+
 /**
- * ath5k_hw_write_ofdm_timings - set OFDM timings on AR5212
+ * ath5k_hw_htoclock - Translate usec to hw clock units
  *
- * @ah: the &struct ath5k_hw
- * @channel: the currently set channel upon reset
- *
- * Write the delta slope coefficient (used on pilot tracking ?) for OFDM
- * operation on the AR5212 upon reset. This is a helper for ath5k_hw_reset().
+ * @ah: The &struct ath5k_hw
+ * @usec: value in microseconds
+ */
+unsigned int ath5k_hw_htoclock(struct ath5k_hw *ah, unsigned int usec)
+{
+       struct ath_common *common = ath5k_hw_common(ah);
+       return usec * common->clockrate;
+}
+
+/**
+ * ath5k_hw_clocktoh - Translate hw clock units to usec
+ * @clock: value in hw clock units
+ */
+unsigned int ath5k_hw_clocktoh(struct ath5k_hw *ah, unsigned int clock)
+{
+       struct ath_common *common = ath5k_hw_common(ah);
+       return clock / common->clockrate;
+}
+
+/**
+ * ath5k_hw_init_core_clock - Initialize core clock
  *
- * Since delta slope is floating point we split it on its exponent and
- * mantissa and provide these values on hw.
+ * @ah The &struct ath5k_hw
  *
- * For more infos i think this patent is related
- * http://www.freepatentsonline.com/7184495.html
+ * Initialize core clock parameters (usec, usec32, latencies etc).
  */
-static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
-       struct ieee80211_channel *channel)
+static void ath5k_hw_init_core_clock(struct ath5k_hw *ah)
 {
-       /* Get exponent and mantissa and set it */
-       u32 coef_scaled, coef_exp, coef_man,
-               ds_coef_exp, ds_coef_man, clock;
-
-       BUG_ON(!(ah->ah_version == AR5K_AR5212) ||
-               !(channel->hw_value & CHANNEL_OFDM));
-
-       /* Get coefficient
-        * ALGO: coef = (5 * clock / carrier_freq) / 2
-        * we scale coef by shifting clock value by 24 for
-        * better precision since we use integers */
-       /* TODO: Half/quarter rate */
-       clock =  (channel->hw_value & CHANNEL_TURBO) ? 80 : 40;
-       coef_scaled = ((5 * (clock << 24)) / 2) / channel->center_freq;
-
-       /* Get exponent
-        * ALGO: coef_exp = 14 - highest set bit position */
-       coef_exp = ilog2(coef_scaled);
-
-       /* Doesn't make sense if it's zero*/
-       if (!coef_scaled || !coef_exp)
-               return -EINVAL;
+       struct ieee80211_channel *channel = ah->ah_current_channel;
+       struct ath_common *common = ath5k_hw_common(ah);
+       u32 usec_reg, txlat, rxlat, usec, clock, sclock, txf2txs;
+
+       /*
+        * Set core clock frequency
+        */
+       if (channel->hw_value & CHANNEL_5GHZ)
+               clock = 40; /* 802.11a */
+       else if (channel->hw_value & CHANNEL_CCK)
+               clock = 22; /* 802.11b */
+       else
+               clock = 44; /* 802.11g */
+
+       /* Use clock multiplier for non-default
+        * bwmode */
+       switch (ah->ah_bwmode) {
+       case AR5K_BWMODE_40MHZ:
+               clock *= 2;
+               break;
+       case AR5K_BWMODE_10MHZ:
+               clock /= 2;
+               break;
+       case AR5K_BWMODE_5MHZ:
+               clock /= 4;
+               break;
+       default:
+               break;
+       }
 
-       /* Note: we've shifted coef_scaled by 24 */
-       coef_exp = 14 - (coef_exp - 24);
+       common->clockrate = clock;
 
+       /*
+        * Set USEC parameters
+        */
+       /* Set USEC counter on PCU*/
+       usec = clock - 1;
+       usec = AR5K_REG_SM(usec, AR5K_USEC_1);
 
-       /* Get mantissa (significant digits)
-        * ALGO: coef_mant = floor(coef_scaled* 2^coef_exp+0.5) */
-       coef_man = coef_scaled +
-               (1 << (24 - coef_exp - 1));
+       /* Set usec duration on DCU */
+       if (ah->ah_version != AR5K_AR5210)
+               AR5K_REG_WRITE_BITS(ah, AR5K_DCU_GBL_IFS_MISC,
+                                       AR5K_DCU_GBL_IFS_MISC_USEC_DUR,
+                                       clock);
 
-       /* Calculate delta slope coefficient exponent
-        * and mantissa (remove scaling) and set them on hw */
-       ds_coef_man = coef_man >> (24 - coef_exp);
-       ds_coef_exp = coef_exp - 16;
+       /* Set 32MHz USEC counter */
+       if ((ah->ah_radio == AR5K_RF5112) ||
+               (ah->ah_radio == AR5K_RF5413) ||
+               (ah->ah_radio == AR5K_RF2316) ||
+               (ah->ah_radio == AR5K_RF2317))
+       /* Remain on 40MHz clock ? */
+               sclock = 40 - 1;
+       else
+               sclock = 32 - 1;
+       sclock = AR5K_REG_SM(sclock, AR5K_USEC_32);
 
-       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
-               AR5K_PHY_TIMING_3_DSC_MAN, ds_coef_man);
-       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_TIMING_3,
-               AR5K_PHY_TIMING_3_DSC_EXP, ds_coef_exp);
+       /*
+        * Set tx/rx latencies
+        */
+       usec_reg = ath5k_hw_reg_read(ah, AR5K_USEC_5211);
+       txlat = AR5K_REG_MS(usec_reg, AR5K_USEC_TX_LATENCY_5211);
+       rxlat = AR5K_REG_MS(usec_reg, AR5K_USEC_RX_LATENCY_5211);
 
-       return 0;
-}
+       /*
+        * 5210 initvals don't include usec settings
+        * so we need to use magic values here for
+        * tx/rx latencies
+        */
+       if (ah->ah_version == AR5K_AR5210) {
+               /* same for turbo */
+               txlat = AR5K_INIT_TX_LATENCY_5210;
+               rxlat = AR5K_INIT_RX_LATENCY_5210;
+       }
 
+       if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
+               /* 5311 has different tx/rx latency masks
+                * from 5211, since we deal 5311 the same
+                * as 5211 when setting initvals, shift
+                * values here to their proper locations
+                *
+                * Note: Initvals indicate tx/rx/ latencies
+                * are the same for turbo mode */
+               txlat = AR5K_REG_SM(txlat, AR5K_USEC_TX_LATENCY_5210);
+               rxlat = AR5K_REG_SM(rxlat, AR5K_USEC_RX_LATENCY_5210);
+       } else
+       switch (ah->ah_bwmode) {
+       case AR5K_BWMODE_10MHZ:
+               txlat = AR5K_REG_SM(txlat * 2,
+                               AR5K_USEC_TX_LATENCY_5211);
+               rxlat = AR5K_REG_SM(AR5K_INIT_RX_LAT_MAX,
+                               AR5K_USEC_RX_LATENCY_5211);
+               txf2txs = AR5K_INIT_TXF2TXD_START_DELAY_10MHZ;
+               break;
+       case AR5K_BWMODE_5MHZ:
+               txlat = AR5K_REG_SM(txlat * 4,
+                               AR5K_USEC_TX_LATENCY_5211);
+               rxlat = AR5K_REG_SM(AR5K_INIT_RX_LAT_MAX,
+                               AR5K_USEC_RX_LATENCY_5211);
+               txf2txs = AR5K_INIT_TXF2TXD_START_DELAY_5MHZ;
+               break;
+       case AR5K_BWMODE_40MHZ:
+               txlat = AR5K_INIT_TX_LAT_MIN;
+               rxlat = AR5K_REG_SM(rxlat / 2,
+                               AR5K_USEC_RX_LATENCY_5211);
+               txf2txs = AR5K_INIT_TXF2TXD_START_DEFAULT;
+               break;
+       default:
+               break;
+       }
 
-/*
- * index into rates for control rates, we can set it up like this because
- * this is only used for AR5212 and we know it supports G mode
- */
-static const unsigned int control_rates[] =
-       { 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 };
+       usec_reg = (usec | sclock | txlat | rxlat);
+       ath5k_hw_reg_write(ah, usec_reg, AR5K_USEC);
 
-/**
- * ath5k_hw_write_rate_duration - fill rate code to duration table
- *
- * @ah: the &struct ath5k_hw
- * @mode: one of enum ath5k_driver_mode
- *
- * Write the rate code to duration table upon hw reset. This is a helper for
- * ath5k_hw_reset(). It seems all this is doing is setting an ACK timeout on
- * the hardware, based on current mode, for each rate. The rates which are
- * capable of short preamble (802.11b rates 2Mbps, 5.5Mbps, and 11Mbps) have
- * different rate code so we write their value twice (one for long preample
- * and one for short).
+       /* On 5112 set tx frane to tx data start delay */
+       if (ah->ah_radio == AR5K_RF5112) {
+               AR5K_REG_WRITE_BITS(ah, AR5K_PHY_RF_CTL2,
+                                       AR5K_PHY_RF_CTL2_TXF2TXD_START,
+                                       txf2txs);
+       }
+}
+
+/*
+ * If there is an external 32KHz crystal available, use it
+ * as ref. clock instead of 32/40MHz clock and baseband clocks
+ * to save power during sleep or restore normal 32/40MHz
+ * operation.
  *
- * Note: Band doesn't matter here, if we set the values for OFDM it works
- * on both a and g modes. So all we have to do is set values for all g rates
- * that include all OFDM and CCK rates. If we operate in turbo or xr/half/
- * quarter rate mode, we need to use another set of bitrates (that's why we
- * need the mode parameter) but we don't handle these proprietary modes yet.
+ * XXX: When operating on 32KHz certain PHY registers (27 - 31,
+ *     123 - 127) require delay on access.
  */
-static inline void ath5k_hw_write_rate_duration(struct ath5k_hw *ah,
-       unsigned int mode)
+static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
 {
-       struct ath5k_softc *sc = ah->ah_sc;
-       struct ieee80211_rate *rate;
-       unsigned int i;
+       struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
+       u32 scal, spending;
 
-       /* Write rate duration table */
-       for (i = 0; i < sc->sbands[IEEE80211_BAND_2GHZ].n_bitrates; i++) {
-               u32 reg;
-               u16 tx_time;
+       /* Only set 32KHz settings if we have an external
+        * 32KHz crystal present */
+       if ((AR5K_EEPROM_HAS32KHZCRYSTAL(ee->ee_misc1) ||
+       AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(ee->ee_misc1)) &&
+       enable) {
 
-               rate = &sc->sbands[IEEE80211_BAND_2GHZ].bitrates[control_rates[i]];
+               /* 1 usec/cycle */
+               AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, 1);
+               /* Set up tsf increment on each cycle */
+               AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 61);
 
-               /* Set ACK timeout */
-               reg = AR5K_RATE_DUR(rate->hw_value);
+               /* Set baseband sleep control registers
+                * and sleep control rate */
+               ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR);
 
-               /* An ACK frame consists of 10 bytes. If you add the FCS,
-                * which ieee80211_generic_frame_duration() adds,
-                * its 14 bytes. Note we use the control rate and not the
-                * actual rate for this rate. See mac80211 tx.c
-                * ieee80211_duration() for a brief description of
-                * what rate we should choose to TX ACKs. */
-               tx_time = le16_to_cpu(ieee80211_generic_frame_duration(sc->hw,
-                                                       NULL, 10, rate));
+               if ((ah->ah_radio == AR5K_RF5112) ||
+               (ah->ah_radio == AR5K_RF5413) ||
+               (ah->ah_radio == AR5K_RF2316) ||
+               (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
+                       spending = 0x14;
+               else
+                       spending = 0x18;
+               ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING);
 
-               ath5k_hw_reg_write(ah, tx_time, reg);
+               if ((ah->ah_radio == AR5K_RF5112) ||
+               (ah->ah_radio == AR5K_RF5413) ||
+               (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
+                       ath5k_hw_reg_write(ah, 0x26, AR5K_PHY_SLMT);
+                       ath5k_hw_reg_write(ah, 0x0d, AR5K_PHY_SCAL);
+                       ath5k_hw_reg_write(ah, 0x07, AR5K_PHY_SCLOCK);
+                       ath5k_hw_reg_write(ah, 0x3f, AR5K_PHY_SDELAY);
+                       AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
+                               AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x02);
+               } else {
+                       ath5k_hw_reg_write(ah, 0x0a, AR5K_PHY_SLMT);
+                       ath5k_hw_reg_write(ah, 0x0c, AR5K_PHY_SCAL);
+                       ath5k_hw_reg_write(ah, 0x03, AR5K_PHY_SCLOCK);
+                       ath5k_hw_reg_write(ah, 0x20, AR5K_PHY_SDELAY);
+                       AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
+                               AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x03);
+               }
 
-               if (!(rate->flags & IEEE80211_RATE_SHORT_PREAMBLE))
-                       continue;
+               /* Enable sleep clock operation */
+               AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG,
+                               AR5K_PCICFG_SLEEP_CLOCK_EN);
 
-               /*
-                * We're not distinguishing short preamble here,
-                * This is true, all we'll get is a longer value here
-                * which is not necessarilly bad. We could use
-                * export ieee80211_frame_duration() but that needs to be
-                * fixed first to be properly used by mac802111 drivers:
-                *
-                *  - remove erp stuff and let the routine figure ofdm
-                *    erp rates
-                *  - remove passing argument ieee80211_local as
-                *    drivers don't have access to it
-                *  - move drivers using ieee80211_generic_frame_duration()
-                *    to this
-                */
-               ath5k_hw_reg_write(ah, tx_time,
-                       reg + (AR5K_SET_SHORT_PREAMBLE << 2));
+       } else {
+
+               /* Disable sleep clock operation and
+                * restore default parameters */
+               AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG,
+                               AR5K_PCICFG_SLEEP_CLOCK_EN);
+
+               AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
+                               AR5K_PCICFG_SLEEP_CLOCK_RATE, 0);
+
+               /* Set DAC/ADC delays */
+               ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR);
+               ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT);
+
+               if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))
+                       scal = AR5K_PHY_SCAL_32MHZ_2417;
+               else if (ee->ee_is_hb63)
+                       scal = AR5K_PHY_SCAL_32MHZ_HB63;
+               else
+                       scal = AR5K_PHY_SCAL_32MHZ;
+               ath5k_hw_reg_write(ah, scal, AR5K_PHY_SCAL);
+
+               ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
+               ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
+
+               if ((ah->ah_radio == AR5K_RF5112) ||
+               (ah->ah_radio == AR5K_RF5413) ||
+               (ah->ah_radio == AR5K_RF2316) ||
+               (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
+                       spending = 0x14;
+               else
+                       spending = 0x18;
+               ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING);
+
+               /* Set up tsf increment on each cycle */
+               AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 1);
        }
 }
 
+
+/*********************\
+* Reset/Sleep control *
+\*********************/
+
 /*
  * Reset chipset
  */
@@ -235,6 +362,64 @@ static int ath5k_hw_nic_reset(struct ath5k_hw *ah, u32 val)
        return ret;
 }
 
+/*
+ * Reset AHB chipset
+ * AR5K_RESET_CTL_PCU flag resets WMAC
+ * AR5K_RESET_CTL_BASEBAND flag resets WBB
+ */
+static int ath5k_hw_wisoc_reset(struct ath5k_hw *ah, u32 flags)
+{
+       u32 mask = flags ? flags : ~0U;
+       volatile u32 *reg;
+       u32 regval;
+       u32 val = 0;
+
+       /* ah->ah_mac_srev is not available at this point yet */
+       if (ah->ah_sc->devid >= AR5K_SREV_AR2315_R6) {
+               reg = (u32 *) AR5K_AR2315_RESET;
+               if (mask & AR5K_RESET_CTL_PCU)
+                       val |= AR5K_AR2315_RESET_WMAC;
+               if (mask & AR5K_RESET_CTL_BASEBAND)
+                       val |= AR5K_AR2315_RESET_BB_WARM;
+       } else {
+               reg = (u32 *) AR5K_AR5312_RESET;
+               if (to_platform_device(ah->ah_sc->dev)->id == 0) {
+                       if (mask & AR5K_RESET_CTL_PCU)
+                               val |= AR5K_AR5312_RESET_WMAC0;
+                       if (mask & AR5K_RESET_CTL_BASEBAND)
+                               val |= AR5K_AR5312_RESET_BB0_COLD |
+                                      AR5K_AR5312_RESET_BB0_WARM;
+               } else {
+                       if (mask & AR5K_RESET_CTL_PCU)
+                               val |= AR5K_AR5312_RESET_WMAC1;
+                       if (mask & AR5K_RESET_CTL_BASEBAND)
+                               val |= AR5K_AR5312_RESET_BB1_COLD |
+                                      AR5K_AR5312_RESET_BB1_WARM;
+               }
+       }
+
+       /* Put BB/MAC into reset */
+       regval = __raw_readl(reg);
+       __raw_writel(regval | val, reg);
+       regval = __raw_readl(reg);
+       udelay(100);
+
+       /* Bring BB/MAC out of reset */
+       __raw_writel(regval & ~val, reg);
+       regval = __raw_readl(reg);
+
+       /*
+        * Reset configuration register (for hw byte-swap). Note that this
+        * is only set for big endian. We do the necessary magic in
+        * AR5K_INIT_CFG.
+        */
+       if ((flags & AR5K_RESET_CTL_PCU) == 0)
+               ath5k_hw_reg_write(ah, AR5K_INIT_CFG, AR5K_CFG);
+
+       return 0;
+}
+
+
 /*
  * Sleep control
  */
@@ -334,6 +519,9 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
        u32 bus_flags;
        int ret;
 
+       if (ath5k_get_bus_type(ah) == ATH_AHB)
+               return 0;
+
        /* Make sure device is awake */
        ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
        if (ret) {
@@ -349,7 +537,7 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
         * we ingore that flag for PCI-E cards. On PCI cards
         * this flag gets cleared after 64 PCI clocks.
         */
-       bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
+       bus_flags = (pdev && pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
 
        if (ah->ah_version == AR5K_AR5210) {
                ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
@@ -378,7 +566,6 @@ int ath5k_hw_on_hold(struct ath5k_hw *ah)
 
 /*
  * Bring up MAC + PHY Chips and program PLL
- * TODO: Half/Quarter rate support
  */
 int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
 {
@@ -390,11 +577,13 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
        mode = 0;
        clock = 0;
 
-       /* Wakeup the device */
-       ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
-       if (ret) {
-               ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");
-               return ret;
+       if ((ath5k_get_bus_type(ah) != ATH_AHB) || !initial) {
+               /* Wakeup the device */
+               ret = ath5k_hw_set_power(ah, AR5K_PM_AWAKE, true, 0);
+               if (ret) {
+                       ATH5K_ERR(ah->ah_sc, "failed to wakeup the MAC Chip\n");
+                       return ret;
+               }
        }
 
        /*
@@ -405,7 +594,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
         * we ingore that flag for PCI-E cards. On PCI cards
         * this flag gets cleared after 64 PCI clocks.
         */
-       bus_flags = (pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
+       bus_flags = (pdev && pdev->is_pcie) ? 0 : AR5K_RESET_CTL_PCI;
 
        if (ah->ah_version == AR5K_AR5210) {
                ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
@@ -413,8 +602,12 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
                        AR5K_RESET_CTL_PHY | AR5K_RESET_CTL_PCI);
                        mdelay(2);
        } else {
-               ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
-                       AR5K_RESET_CTL_BASEBAND | bus_flags);
+               if (ath5k_get_bus_type(ah) == ATH_AHB)
+                       ret = ath5k_hw_wisoc_reset(ah, AR5K_RESET_CTL_PCU |
+                               AR5K_RESET_CTL_BASEBAND);
+               else
+                       ret = ath5k_hw_nic_reset(ah, AR5K_RESET_CTL_PCU |
+                               AR5K_RESET_CTL_BASEBAND | bus_flags);
        }
 
        if (ret) {
@@ -429,9 +622,15 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
                return ret;
        }
 
-       /* ...clear reset control register and pull device out of
-        * warm reset */
-       if (ath5k_hw_nic_reset(ah, 0)) {
+       /* ...reset configuration regiter on Wisoc ...
+        * ...clear reset control register and pull device out of
+        * warm reset on others */
+       if (ath5k_get_bus_type(ah) == ATH_AHB)
+               ret = ath5k_hw_wisoc_reset(ah, 0);
+       else
+               ret = ath5k_hw_nic_reset(ah, 0);
+
+       if (ret) {
                ATH5K_ERR(ah->ah_sc, "failed to warm reset the MAC Chip\n");
                return -EIO;
        }
@@ -466,7 +665,8 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
                                 * CCK headers) operation. We need to test
                                 * this, 5211 might support ofdm-only g after
                                 * all, there are also initial register values
-                                * in the code for g mode (see initvals.c). */
+                                * in the code for g mode (see initvals.c).
+                                */
                                if (ah->ah_version == AR5K_AR5211)
                                        mode |= AR5K_PHY_MODE_MOD_OFDM;
                                else
@@ -479,6 +679,7 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
                } else if (flags & CHANNEL_5GHZ) {
                        mode |= AR5K_PHY_MODE_FREQ_5GHZ;
 
+                       /* Different PLL setting for 5413 */
                        if (ah->ah_radio == AR5K_RF5413)
                                clock = AR5K_PHY_PLL_40MHZ_5413;
                        else
@@ -496,12 +697,29 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
                        return -EINVAL;
                }
 
-               if (flags & CHANNEL_TURBO)
-                       turbo = AR5K_PHY_TURBO_MODE | AR5K_PHY_TURBO_SHORT;
+               /*XXX: Can bwmode be used with dynamic mode ?
+                * (I don't think it supports 44MHz) */
+               /* On 2425 initvals TURBO_SHORT is not pressent */
+               if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) {
+                       turbo = AR5K_PHY_TURBO_MODE |
+                               (ah->ah_radio == AR5K_RF2425) ? 0 :
+                               AR5K_PHY_TURBO_SHORT;
+               } else if (ah->ah_bwmode != AR5K_BWMODE_DEFAULT) {
+                       if (ah->ah_radio == AR5K_RF5413) {
+                               mode |= (ah->ah_bwmode == AR5K_BWMODE_10MHZ) ?
+                                       AR5K_PHY_MODE_HALF_RATE :
+                                       AR5K_PHY_MODE_QUARTER_RATE;
+                       } else if (ah->ah_version == AR5K_AR5212) {
+                               clock |= (ah->ah_bwmode == AR5K_BWMODE_10MHZ) ?
+                                       AR5K_PHY_PLL_HALF_RATE :
+                                       AR5K_PHY_PLL_QUARTER_RATE;
+                       }
+               }
+
        } else { /* Reset the device */
 
                /* ...enable Atheros turbo mode if requested */
-               if (flags & CHANNEL_TURBO)
+               if (ah->ah_bwmode == AR5K_BWMODE_40MHZ)
                        ath5k_hw_reg_write(ah, AR5K_PHY_TURBO_MODE,
                                        AR5K_PHY_TURBO);
        }
@@ -522,107 +740,10 @@ int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial)
        return 0;
 }
 
-/*
- * If there is an external 32KHz crystal available, use it
- * as ref. clock instead of 32/40MHz clock and baseband clocks
- * to save power during sleep or restore normal 32/40MHz
- * operation.
- *
- * XXX: When operating on 32KHz certain PHY registers (27 - 31,
- *     123 - 127) require delay on access.
- */
-static void ath5k_hw_set_sleep_clock(struct ath5k_hw *ah, bool enable)
-{
-       struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-       u32 scal, spending, usec32;
-
-       /* Only set 32KHz settings if we have an external
-        * 32KHz crystal present */
-       if ((AR5K_EEPROM_HAS32KHZCRYSTAL(ee->ee_misc1) ||
-       AR5K_EEPROM_HAS32KHZCRYSTAL_OLD(ee->ee_misc1)) &&
-       enable) {
-
-               /* 1 usec/cycle */
-               AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, 1);
-               /* Set up tsf increment on each cycle */
-               AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 61);
-
-               /* Set baseband sleep control registers
-                * and sleep control rate */
-               ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR);
-
-               if ((ah->ah_radio == AR5K_RF5112) ||
-               (ah->ah_radio == AR5K_RF5413) ||
-               (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
-                       spending = 0x14;
-               else
-                       spending = 0x18;
-               ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING);
-
-               if ((ah->ah_radio == AR5K_RF5112) ||
-               (ah->ah_radio == AR5K_RF5413) ||
-               (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
-                       ath5k_hw_reg_write(ah, 0x26, AR5K_PHY_SLMT);
-                       ath5k_hw_reg_write(ah, 0x0d, AR5K_PHY_SCAL);
-                       ath5k_hw_reg_write(ah, 0x07, AR5K_PHY_SCLOCK);
-                       ath5k_hw_reg_write(ah, 0x3f, AR5K_PHY_SDELAY);
-                       AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
-                               AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x02);
-               } else {
-                       ath5k_hw_reg_write(ah, 0x0a, AR5K_PHY_SLMT);
-                       ath5k_hw_reg_write(ah, 0x0c, AR5K_PHY_SCAL);
-                       ath5k_hw_reg_write(ah, 0x03, AR5K_PHY_SCLOCK);
-                       ath5k_hw_reg_write(ah, 0x20, AR5K_PHY_SDELAY);
-                       AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
-                               AR5K_PCICFG_SLEEP_CLOCK_RATE, 0x03);
-               }
-
-               /* Enable sleep clock operation */
-               AR5K_REG_ENABLE_BITS(ah, AR5K_PCICFG,
-                               AR5K_PCICFG_SLEEP_CLOCK_EN);
-
-       } else {
-
-               /* Disable sleep clock operation and
-                * restore default parameters */
-               AR5K_REG_DISABLE_BITS(ah, AR5K_PCICFG,
-                               AR5K_PCICFG_SLEEP_CLOCK_EN);
-
-               AR5K_REG_WRITE_BITS(ah, AR5K_PCICFG,
-                               AR5K_PCICFG_SLEEP_CLOCK_RATE, 0);
-
-               ath5k_hw_reg_write(ah, 0x1f, AR5K_PHY_SCR);
-               ath5k_hw_reg_write(ah, AR5K_PHY_SLMT_32MHZ, AR5K_PHY_SLMT);
-
-               if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))
-                       scal = AR5K_PHY_SCAL_32MHZ_2417;
-               else if (ee->ee_is_hb63)
-                       scal = AR5K_PHY_SCAL_32MHZ_HB63;
-               else
-                       scal = AR5K_PHY_SCAL_32MHZ;
-               ath5k_hw_reg_write(ah, scal, AR5K_PHY_SCAL);
-
-               ath5k_hw_reg_write(ah, AR5K_PHY_SCLOCK_32MHZ, AR5K_PHY_SCLOCK);
-               ath5k_hw_reg_write(ah, AR5K_PHY_SDELAY_32MHZ, AR5K_PHY_SDELAY);
 
-               if ((ah->ah_radio == AR5K_RF5112) ||
-               (ah->ah_radio == AR5K_RF5413) ||
-               (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4)))
-                       spending = 0x14;
-               else
-                       spending = 0x18;
-               ath5k_hw_reg_write(ah, spending, AR5K_PHY_SPENDING);
-
-               if ((ah->ah_radio == AR5K_RF5112) ||
-               (ah->ah_radio == AR5K_RF5413))
-                       usec32 = 39;
-               else
-                       usec32 = 31;
-               AR5K_REG_WRITE_BITS(ah, AR5K_USEC_5211, AR5K_USEC_32, usec32);
-
-               AR5K_REG_WRITE_BITS(ah, AR5K_TSF_PARM, AR5K_TSF_PARM_INC, 1);
-       }
-}
+/**************************************\
+* Post-initvals register modifications *
+\**************************************/
 
 /* TODO: Half/Quarter rate */
 static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
@@ -663,22 +784,10 @@ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
                AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
                                AR5K_TXCFG_DCU_DBL_BUF_DIS);
 
-       /* Set DAC/ADC delays */
-       if (ah->ah_version == AR5K_AR5212) {
-               u32 scal;
-               struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
-               if (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))
-                       scal = AR5K_PHY_SCAL_32MHZ_2417;
-               else if (ee->ee_is_hb63)
-                       scal = AR5K_PHY_SCAL_32MHZ_HB63;
-               else
-                       scal = AR5K_PHY_SCAL_32MHZ;
-               ath5k_hw_reg_write(ah, scal, AR5K_PHY_SCAL);
-       }
-
        /* Set fast ADC */
        if ((ah->ah_radio == AR5K_RF5413) ||
-       (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
+               (ah->ah_radio == AR5K_RF2317) ||
+               (ah->ah_mac_version == (AR5K_SREV_AR2417 >> 4))) {
                u32 fast_adc = true;
 
                if (channel->center_freq == 2462 ||
@@ -706,26 +815,54 @@ static void ath5k_hw_tweak_initval_settings(struct ath5k_hw *ah,
        }
 
        if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
-               u32 usec_reg;
-               /* 5311 has different tx/rx latency masks
-                * from 5211, since we deal 5311 the same
-                * as 5211 when setting initvals, shift
-                * values here to their proper locations */
-               usec_reg = ath5k_hw_reg_read(ah, AR5K_USEC_5211);
-               ath5k_hw_reg_write(ah, usec_reg & (AR5K_USEC_1 |
-                               AR5K_USEC_32 |
-                               AR5K_USEC_TX_LATENCY_5211 |
-                               AR5K_REG_SM(29,
-                               AR5K_USEC_RX_LATENCY_5210)),
-                               AR5K_USEC_5211);
                /* Clear QCU/DCU clock gating register */
                ath5k_hw_reg_write(ah, 0, AR5K_QCUDCU_CLKGT);
                /* Set DAC/ADC delays */
-               ath5k_hw_reg_write(ah, 0x08, AR5K_PHY_SCAL);
+               ath5k_hw_reg_write(ah, AR5K_PHY_SCAL_32MHZ_5311,
+                                               AR5K_PHY_SCAL);
                /* Enable PCU FIFO corruption ECO */
                AR5K_REG_ENABLE_BITS(ah, AR5K_DIAG_SW_5211,
                                        AR5K_DIAG_SW_ECO_ENABLE);
        }
+
+       if (ah->ah_bwmode) {
+               /* Increase PHY switch and AGC settling time
+                * on turbo mode (ath5k_hw_commit_eeprom_settings
+                * will override settling time if available) */
+               if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) {
+
+                       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
+                                               AR5K_PHY_SETTLING_AGC,
+                                               AR5K_AGC_SETTLING_TURBO);
+
+                       /* XXX: Initvals indicate we only increase
+                        * switch time on AR5212, 5211 and 5210
+                        * only change agc time (bug?) */
+                       if (ah->ah_version == AR5K_AR5212)
+                               AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
+                                               AR5K_PHY_SETTLING_SWITCH,
+                                               AR5K_SWITCH_SETTLING_TURBO);
+
+                       if (ah->ah_version == AR5K_AR5210) {
+                               /* Set Frame Control Register */
+                               ath5k_hw_reg_write(ah,
+                                       (AR5K_PHY_FRAME_CTL_INI |
+                                       AR5K_PHY_TURBO_MODE |
+                                       AR5K_PHY_TURBO_SHORT | 0x2020),
+                                       AR5K_PHY_FRAME_CTL_5210);
+                       }
+               /* On 5413 PHY force window length for half/quarter rate*/
+               } else if ((ah->ah_mac_srev >= AR5K_SREV_AR5424) &&
+               (ah->ah_mac_srev <= AR5K_SREV_AR5414)) {
+                       AR5K_REG_WRITE_BITS(ah, AR5K_PHY_FRAME_CTL_5211,
+                                               AR5K_PHY_FRAME_CTL_WIN_LEN,
+                                               3);
+               }
+       } else if (ah->ah_version == AR5K_AR5210) {
+               /* Set Frame Control Register for normal operation */
+               ath5k_hw_reg_write(ah, (AR5K_PHY_FRAME_CTL_INI | 0x1020),
+                                               AR5K_PHY_FRAME_CTL_5210);
+       }
 }
 
 static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
@@ -734,6 +871,10 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
        struct ath5k_eeprom_info *ee = &ah->ah_capabilities.cap_eeprom;
        s16 cck_ofdm_pwr_delta;
 
+       /* TODO: Add support for AR5210 EEPROM */
+       if (ah->ah_version == AR5K_AR5210)
+               return;
+
        /* Adjust power delta for channel 14 */
        if (channel->center_freq == 2484)
                cck_ofdm_pwr_delta =
@@ -772,7 +913,7 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
                AR5K_PHY_NF_SVAL(ee->ee_noise_floor_thr[ee_mode]),
                AR5K_PHY_NFTHRES);
 
-       if ((channel->hw_value & CHANNEL_TURBO) &&
+       if ((ah->ah_bwmode == AR5K_BWMODE_40MHZ) &&
        (ah->ah_ee_version >= AR5K_EEPROM_VERSION_5_0)) {
                /* Switch settling time (Turbo) */
                AR5K_REG_WRITE_BITS(ah, AR5K_PHY_SETTLING,
@@ -870,143 +1011,183 @@ static void ath5k_hw_commit_eeprom_settings(struct ath5k_hw *ah,
                ath5k_hw_reg_write(ah, 0, AR5K_PHY_HEAVY_CLIP_ENABLE);
 }
 
-/*
- * Main reset function
- */
+
+/*********************\
+* Main reset function *
+\*********************/
+
 int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
-       struct ieee80211_channel *channel, bool change_channel)
+               struct ieee80211_channel *channel, bool fast, bool skip_pcu)
 {
-       struct ath_common *common = ath5k_hw_common(ah);
-       u32 s_seq[10], s_led[3], staid1_flags, tsf_up, tsf_lo;
-       u32 phy_tst1;
+       u32 s_seq[10], s_led[3], tsf_up, tsf_lo;
        u8 mode, freq, ee_mode;
        int i, ret;
 
        ee_mode = 0;
-       staid1_flags = 0;
        tsf_up = 0;
        tsf_lo = 0;
        freq = 0;
        mode = 0;
 
        /*
-        * Save some registers before a reset
+        * Sanity check for fast flag
+        * Fast channel change only available
+        * on AR2413/AR5413.
         */
-       /*DCU/Antenna selection not available on 5210*/
-       if (ah->ah_version != AR5K_AR5210) {
+       if (fast && (ah->ah_radio != AR5K_RF2413) &&
+       (ah->ah_radio != AR5K_RF5413))
+               fast = 0;
 
-               switch (channel->hw_value & CHANNEL_MODES) {
-               case CHANNEL_A:
-                       mode = AR5K_MODE_11A;
-                       freq = AR5K_INI_RFGAIN_5GHZ;
-                       ee_mode = AR5K_EEPROM_MODE_11A;
-                       break;
-               case CHANNEL_G:
-                       mode = AR5K_MODE_11G;
-                       freq = AR5K_INI_RFGAIN_2GHZ;
-                       ee_mode = AR5K_EEPROM_MODE_11G;
-                       break;
-               case CHANNEL_B:
-                       mode = AR5K_MODE_11B;
-                       freq = AR5K_INI_RFGAIN_2GHZ;
-                       ee_mode = AR5K_EEPROM_MODE_11B;
-                       break;
-               case CHANNEL_T:
-                       mode = AR5K_MODE_11A_TURBO;
-                       freq = AR5K_INI_RFGAIN_5GHZ;
-                       ee_mode = AR5K_EEPROM_MODE_11A;
-                       break;
-               case CHANNEL_TG:
-                       if (ah->ah_version == AR5K_AR5211) {
-                               ATH5K_ERR(ah->ah_sc,
-                                       "TurboG mode not available on 5211");
-                               return -EINVAL;
-                       }
-                       mode = AR5K_MODE_11G_TURBO;
-                       freq = AR5K_INI_RFGAIN_2GHZ;
-                       ee_mode = AR5K_EEPROM_MODE_11G;
-                       break;
-               case CHANNEL_XR:
-                       if (ah->ah_version == AR5K_AR5211) {
-                               ATH5K_ERR(ah->ah_sc,
-                                       "XR mode not available on 5211");
-                               return -EINVAL;
-                       }
-                       mode = AR5K_MODE_XR;
-                       freq = AR5K_INI_RFGAIN_5GHZ;
-                       ee_mode = AR5K_EEPROM_MODE_11A;
-                       break;
-               default:
+       /* Disable sleep clock operation
+        * to avoid register access delay on certain
+        * PHY registers */
+       if (ah->ah_version == AR5K_AR5212)
+               ath5k_hw_set_sleep_clock(ah, false);
+
+       /*
+        * Stop PCU
+        */
+       ath5k_hw_stop_rx_pcu(ah);
+
+       /*
+        * Stop DMA
+        *
+        * Note: If DMA didn't stop continue
+        * since only a reset will fix it.
+        */
+       ret = ath5k_hw_dma_stop(ah);
+
+       /* RF Bus grant won't work if we have pending
+        * frames */
+       if (ret && fast) {
+               ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_RESET,
+                       "DMA didn't stop, falling back to normal reset\n");
+               fast = 0;
+               /* Non fatal, just continue with
+                * normal reset */
+               ret = 0;
+       }
+
+       switch (channel->hw_value & CHANNEL_MODES) {
+       case CHANNEL_A:
+               mode = AR5K_MODE_11A;
+               freq = AR5K_INI_RFGAIN_5GHZ;
+               ee_mode = AR5K_EEPROM_MODE_11A;
+               break;
+       case CHANNEL_G:
+
+               if (ah->ah_version <= AR5K_AR5211) {
                        ATH5K_ERR(ah->ah_sc,
-                               "invalid channel: %d\n", channel->center_freq);
+                               "G mode not available on 5210/5211");
                        return -EINVAL;
                }
 
-               if (change_channel) {
-                       /*
-                        * Save frame sequence count
-                        * For revs. after Oahu, only save
-                        * seq num for DCU 0 (Global seq num)
-                        */
-                       if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
-
-                               for (i = 0; i < 10; i++)
-                                       s_seq[i] = ath5k_hw_reg_read(ah,
-                                               AR5K_QUEUE_DCU_SEQNUM(i));
+               mode = AR5K_MODE_11G;
+               freq = AR5K_INI_RFGAIN_2GHZ;
+               ee_mode = AR5K_EEPROM_MODE_11G;
+               break;
+       case CHANNEL_B:
 
-                       } else {
-                               s_seq[0] = ath5k_hw_reg_read(ah,
-                                               AR5K_QUEUE_DCU_SEQNUM(0));
-                       }
+               if (ah->ah_version < AR5K_AR5211) {
+                       ATH5K_ERR(ah->ah_sc,
+                               "B mode not available on 5210");
+                       return -EINVAL;
+               }
 
-                       /* TSF accelerates on AR5211 during reset
-                        * As a workaround save it here and restore
-                        * it later so that it's back in time after
-                        * reset. This way it'll get re-synced on the
-                        * next beacon without breaking ad-hoc.
-                        *
-                        * On AR5212 TSF is almost preserved across a
-                        * reset so it stays back in time anyway and
-                        * we don't have to save/restore it.
-                        *
-                        * XXX: Since this breaks power saving we have
-                        * to disable power saving until we receive the
-                        * next beacon, so we can resync beacon timers */
-                       if (ah->ah_version == AR5K_AR5211) {
-                               tsf_up = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
-                               tsf_lo = ath5k_hw_reg_read(ah, AR5K_TSF_L32);
-                       }
+               mode = AR5K_MODE_11B;
+               freq = AR5K_INI_RFGAIN_2GHZ;
+               ee_mode = AR5K_EEPROM_MODE_11B;
+               break;
+       case CHANNEL_XR:
+               if (ah->ah_version == AR5K_AR5211) {
+                       ATH5K_ERR(ah->ah_sc,
+                               "XR mode not available on 5211");
+                       return -EINVAL;
                }
+               mode = AR5K_MODE_XR;
+               freq = AR5K_INI_RFGAIN_5GHZ;
+               ee_mode = AR5K_EEPROM_MODE_11A;
+               break;
+       default:
+               ATH5K_ERR(ah->ah_sc,
+                       "invalid channel: %d\n", channel->center_freq);
+               return -EINVAL;
+       }
 
-               if (ah->ah_version == AR5K_AR5212) {
-                       /* Restore normal 32/40MHz clock operation
-                        * to avoid register access delay on certain
-                        * PHY registers */
-                       ath5k_hw_set_sleep_clock(ah, false);
+       /*
+        * If driver requested fast channel change and DMA has stopped
+        * go on. If it fails continue with a normal reset.
+        */
+       if (fast) {
+               ret = ath5k_hw_phy_init(ah, channel, mode,
+                                       ee_mode, freq, true);
+               if (ret) {
+                       ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_RESET,
+                               "fast chan change failed, falling back to normal reset\n");
+                       /* Non fatal, can happen eg.
+                        * on mode change */
+                       ret = 0;
+               } else
+                       return 0;
+       }
 
-                       /* Since we are going to write rf buffer
-                        * check if we have any pending gain_F
-                        * optimization settings */
-                       if (change_channel && ah->ah_rf_banks != NULL)
-                               ath5k_hw_gainf_calibrate(ah);
+       /*
+        * Save some registers before a reset
+        */
+       if (ah->ah_version != AR5K_AR5210) {
+               /*
+                * Save frame sequence count
+                * For revs. after Oahu, only save
+                * seq num for DCU 0 (Global seq num)
+                */
+               if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
+
+                       for (i = 0; i < 10; i++)
+                               s_seq[i] = ath5k_hw_reg_read(ah,
+                                       AR5K_QUEUE_DCU_SEQNUM(i));
+
+               } else {
+                       s_seq[0] = ath5k_hw_reg_read(ah,
+                                       AR5K_QUEUE_DCU_SEQNUM(0));
+               }
+
+               /* TSF accelerates on AR5211 during reset
+                * As a workaround save it here and restore
+                * it later so that it's back in time after
+                * reset. This way it'll get re-synced on the
+                * next beacon without breaking ad-hoc.
+                *
+                * On AR5212 TSF is almost preserved across a
+                * reset so it stays back in time anyway and
+                * we don't have to save/restore it.
+                *
+                * XXX: Since this breaks power saving we have
+                * to disable power saving until we receive the
+                * next beacon, so we can resync beacon timers */
+               if (ah->ah_version == AR5K_AR5211) {
+                       tsf_up = ath5k_hw_reg_read(ah, AR5K_TSF_U32);
+                       tsf_lo = ath5k_hw_reg_read(ah, AR5K_TSF_L32);
                }
        }
 
+
        /*GPIOs*/
        s_led[0] = ath5k_hw_reg_read(ah, AR5K_PCICFG) &
                                        AR5K_PCICFG_LEDSTATE;
        s_led[1] = ath5k_hw_reg_read(ah, AR5K_GPIOCR);
        s_led[2] = ath5k_hw_reg_read(ah, AR5K_GPIODO);
 
-       /* AR5K_STA_ID1 flags, only preserve antenna
-        * settings and ack/cts rate mode */
-       staid1_flags = ath5k_hw_reg_read(ah, AR5K_STA_ID1) &
-                       (AR5K_STA_ID1_DEFAULT_ANTENNA |
-                       AR5K_STA_ID1_DESC_ANTENNA |
-                       AR5K_STA_ID1_RTS_DEF_ANTENNA |
-                       AR5K_STA_ID1_ACKCTS_6MB |
-                       AR5K_STA_ID1_BASE_RATE_11B |
-                       AR5K_STA_ID1_SELFGEN_DEF_ANT);
+
+       /*
+        * Since we are going to write rf buffer
+        * check if we have any pending gain_F
+        * optimization settings
+        */
+       if (ah->ah_version == AR5K_AR5212 &&
+       (ah->ah_radio <= AR5K_RF5112)) {
+               if (!fast && ah->ah_rf_banks != NULL)
+                               ath5k_hw_gainf_calibrate(ah);
+       }
 
        /* Wakeup the device */
        ret = ath5k_hw_nic_wakeup(ah, channel->hw_value, false);
@@ -1021,121 +1202,42 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
                                                        AR5K_PHY(0));
 
        /* Write initial settings */
-       ret = ath5k_hw_write_initvals(ah, mode, change_channel);
+       ret = ath5k_hw_write_initvals(ah, mode, skip_pcu);
        if (ret)
                return ret;
 
+       /* Initialize core clock settings */
+       ath5k_hw_init_core_clock(ah);
+
        /*
-        * 5211/5212 Specific
+        * Tweak initval settings for revised
+        * chipsets and add some more config
+        * bits
         */
-       if (ah->ah_version != AR5K_AR5210) {
-
-               /*
-                * Write initial RF gain settings
-                * This should work for both 5111/5112
-                */
-               ret = ath5k_hw_rfgain_init(ah, freq);
-               if (ret)
-                       return ret;
-
-               mdelay(1);
-
-               /*
-                * Tweak initval settings for revised
-                * chipsets and add some more config
-                * bits
-                */
-               ath5k_hw_tweak_initval_settings(ah, channel);
-
-               /*
-                * Set TX power
-                */
-               ret = ath5k_hw_txpower(ah, channel, ee_mode,
-                                       ah->ah_txpower.txp_max_pwr / 2);
-               if (ret)
-                       return ret;
+       ath5k_hw_tweak_initval_settings(ah, channel);
 
-               /* Write rate duration table only on AR5212 and if
-                * virtual interface has already been brought up
-                * XXX: rethink this after new mode changes to
-                * mac80211 are integrated */
-               if (ah->ah_version == AR5K_AR5212 &&
-                       ah->ah_sc->nvifs)
-                       ath5k_hw_write_rate_duration(ah, mode);
+       /* Commit values from EEPROM */
+       ath5k_hw_commit_eeprom_settings(ah, channel, ee_mode);
 
-               /*
-                * Write RF buffer
-                */
-               ret = ath5k_hw_rfregs_init(ah, channel, mode);
-               if (ret)
-                       return ret;
-
-
-               /* Write OFDM timings on 5212*/
-               if (ah->ah_version == AR5K_AR5212 &&
-                       channel->hw_value & CHANNEL_OFDM) {
-
-                       ret = ath5k_hw_write_ofdm_timings(ah, channel);
-                       if (ret)
-                               return ret;
-
-                       /* Spur info is available only from EEPROM versions
-                        * greater than 5.3, but the EEPROM routines will use
-                        * static values for older versions */
-                       if (ah->ah_mac_srev >= AR5K_SREV_AR5424)
-                               ath5k_hw_set_spur_mitigation_filter(ah,
-                                                                   channel);
-               }
-
-               /*Enable/disable 802.11b mode on 5111
-               (enable 2111 frequency converter + CCK)*/
-               if (ah->ah_radio == AR5K_RF5111) {
-                       if (mode == AR5K_MODE_11B)
-                               AR5K_REG_ENABLE_BITS(ah, AR5K_TXCFG,
-                                   AR5K_TXCFG_B_MODE);
-                       else
-                               AR5K_REG_DISABLE_BITS(ah, AR5K_TXCFG,
-                                   AR5K_TXCFG_B_MODE);
-               }
-
-               /* Commit values from EEPROM */
-               ath5k_hw_commit_eeprom_settings(ah, channel, ee_mode);
-
-       } else {
-               /*
-                * For 5210 we do all initialization using
-                * initvals, so we don't have to modify
-                * any settings (5210 also only supports
-                * a/aturbo modes)
-                */
-               mdelay(1);
-               /* Disable phy and wait */
-               ath5k_hw_reg_write(ah, AR5K_PHY_ACT_DISABLE, AR5K_PHY_ACT);
-               mdelay(1);
-       }
 
        /*
         * Restore saved values
         */
 
-       /*DCU/Antenna selection not available on 5210*/
+       /* Seqnum, TSF */
        if (ah->ah_version != AR5K_AR5210) {
+               if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
+                       for (i = 0; i < 10; i++)
+                               ath5k_hw_reg_write(ah, s_seq[i],
+                                       AR5K_QUEUE_DCU_SEQNUM(i));
+               } else {
+                       ath5k_hw_reg_write(ah, s_seq[0],
+                               AR5K_QUEUE_DCU_SEQNUM(0));
+               }
 
-               if (change_channel) {
-                       if (ah->ah_mac_srev < AR5K_SREV_AR5211) {
-                               for (i = 0; i < 10; i++)
-                                       ath5k_hw_reg_write(ah, s_seq[i],
-                                               AR5K_QUEUE_DCU_SEQNUM(i));
-                       } else {
-                               ath5k_hw_reg_write(ah, s_seq[0],
-                                       AR5K_QUEUE_DCU_SEQNUM(0));
-                       }
-
-
-                       if (ah->ah_version == AR5K_AR5211) {
-                               ath5k_hw_reg_write(ah, tsf_up, AR5K_TSF_U32);
-                               ath5k_hw_reg_write(ah, tsf_lo, AR5K_TSF_L32);
-                       }
+               if (ah->ah_version == AR5K_AR5211) {
+                       ath5k_hw_reg_write(ah, tsf_up, AR5K_TSF_U32);
+                       ath5k_hw_reg_write(ah, tsf_lo, AR5K_TSF_L32);
                }
        }
 
@@ -1146,203 +1248,34 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
        ath5k_hw_reg_write(ah, s_led[1], AR5K_GPIOCR);
        ath5k_hw_reg_write(ah, s_led[2], AR5K_GPIODO);
 
-       /* Restore sta_id flags and preserve our mac address*/
-       ath5k_hw_reg_write(ah,
-                          get_unaligned_le32(common->macaddr),
-                          AR5K_STA_ID0);
-       ath5k_hw_reg_write(ah,
-                          staid1_flags | get_unaligned_le16(common->macaddr + 4),
-                          AR5K_STA_ID1);
-
-
        /*
-        * Configure PCU
+        * Initialize PCU
         */
-
-       /* Restore bssid and bssid mask */
-       ath5k_hw_set_bssid(ah);
-
-       /* Set PCU config */
-       ath5k_hw_set_opmode(ah, op_mode);
-
-       /* Clear any pending interrupts
-        * PISR/SISR Not available on 5210 */
-       if (ah->ah_version != AR5K_AR5210)
-               ath5k_hw_reg_write(ah, 0xffffffff, AR5K_PISR);
-
-       /* Set RSSI/BRSSI thresholds
-        *
-        * Note: If we decide to set this value
-        * dynamically, keep in mind that when AR5K_RSSI_THR
-        * register is read, it might return 0x40 if we haven't
-        * written anything to it.  Also, BMISS RSSI threshold is zeroed.
-        * So doing a save/restore procedure here isn't the right
-        * choice. Instead, store it in ath5k_hw */
-       ath5k_hw_reg_write(ah, (AR5K_TUNE_RSSI_THRES |
-                               AR5K_TUNE_BMISS_THRES <<
-                               AR5K_RSSI_THR_BMISS_S),
-                               AR5K_RSSI_THR);
-
-       /* MIC QoS support */
-       if (ah->ah_mac_srev >= AR5K_SREV_AR2413) {
-               ath5k_hw_reg_write(ah, 0x000100aa, AR5K_MIC_QOS_CTL);
-               ath5k_hw_reg_write(ah, 0x00003210, AR5K_MIC_QOS_SEL);
-       }
-
-       /* QoS NOACK Policy */
-       if (ah->ah_version == AR5K_AR5212) {
-               ath5k_hw_reg_write(ah,
-                       AR5K_REG_SM(2, AR5K_QOS_NOACK_2BIT_VALUES) |
-                       AR5K_REG_SM(5, AR5K_QOS_NOACK_BIT_OFFSET)  |
-                       AR5K_REG_SM(0, AR5K_QOS_NOACK_BYTE_OFFSET),
-                       AR5K_QOS_NOACK);
-       }
-
+       ath5k_hw_pcu_init(ah, op_mode, mode);
 
        /*
-        * Configure PHY
+        * Initialize PHY
         */
-
-       /* Set channel on PHY */
-       ret = ath5k_hw_channel(ah, channel);
-       if (ret)
+       ret = ath5k_hw_phy_init(ah, channel, mode, ee_mode, freq, false);
+       if (ret) {
+               ATH5K_ERR(ah->ah_sc,
+                       "failed to initialize PHY (%i) !\n", ret);
                return ret;
-
-       /*
-        * Enable the PHY and wait until completion
-        * This includes BaseBand and Synthesizer
-        * activation.
-        */
-       ath5k_hw_reg_write(ah, AR5K_PHY_ACT_ENABLE, AR5K_PHY_ACT);
-
-       /*
-        * On 5211+ read activation -> rx delay
-        * and use it.
-        *
-        * TODO: Half/quarter rate support
-        */
-       if (ah->ah_version != AR5K_AR5210) {
-               u32 delay;
-               delay = ath5k_hw_reg_read(ah, AR5K_PHY_RX_DELAY) &
-                       AR5K_PHY_RX_DELAY_M;
-               delay = (channel->hw_value & CHANNEL_CCK) ?
-                       ((delay << 2) / 22) : (delay / 10);
-
-               udelay(100 + (2 * delay));
-       } else {
-               mdelay(1);
        }
 
-       /*
-        * Perform ADC test to see if baseband is ready
-        * Set TX hold and check ADC test register
-        */
-       phy_tst1 = ath5k_hw_reg_read(ah, AR5K_PHY_TST1);
-       ath5k_hw_reg_write(ah, AR5K_PHY_TST1_TXHOLD, AR5K_PHY_TST1);
-       for (i = 0; i <= 20; i++) {
-               if (!(ath5k_hw_reg_read(ah, AR5K_PHY_ADC_TEST) & 0x10))
-                       break;
-               udelay(200);
-       }
-       ath5k_hw_reg_write(ah, phy_tst1, AR5K_PHY_TST1);
-
-       /*
-        * Start automatic gain control calibration
-        *
-        * During AGC calibration RX path is re-routed to
-        * a power detector so we don't receive anything.
-        *
-        * This method is used to calibrate some static offsets
-        * used together with on-the fly I/Q calibration (the
-        * one performed via ath5k_hw_phy_calibrate), which doesn't
-        * interrupt rx path.
-        *
-        * While rx path is re-routed to the power detector we also
-        * start a noise floor calibration to measure the
-        * card's noise floor (the noise we measure when we are not
-        * transmitting or receiving anything).
-        *
-        * If we are in a noisy environment, AGC calibration may time
-        * out and/or noise floor calibration might timeout.
-        */
-       AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_AGCCTL,
-                               AR5K_PHY_AGCCTL_CAL | AR5K_PHY_AGCCTL_NF);
-
-       /* At the same time start I/Q calibration for QAM constellation
-        * -no need for CCK- */
-       ah->ah_calibration = false;
-       if (!(mode == AR5K_MODE_11B)) {
-               ah->ah_calibration = true;
-               AR5K_REG_WRITE_BITS(ah, AR5K_PHY_IQ,
-                               AR5K_PHY_IQ_CAL_NUM_LOG_MAX, 15);
-               AR5K_REG_ENABLE_BITS(ah, AR5K_PHY_IQ,
-                               AR5K_PHY_IQ_RUN);
-       }
-
-       /* Wait for gain calibration to finish (we check for I/Q calibration
-        * during ath5k_phy_calibrate) */
-       if (ath5k_hw_register_timeout(ah, AR5K_PHY_AGCCTL,
-                       AR5K_PHY_AGCCTL_CAL, 0, false)) {
-               ATH5K_ERR(ah->ah_sc, "gain calibration timeout (%uMHz)\n",
-                       channel->center_freq);
-       }
-
-       /* Restore antenna mode */
-       ath5k_hw_set_antenna_mode(ah, ah->ah_ant_mode);
-
-       /* Restore slot time and ACK timeouts */
-       if (ah->ah_coverage_class > 0)
-               ath5k_hw_set_coverage_class(ah, ah->ah_coverage_class);
-
        /*
         * Configure QCUs/DCUs
         */
+       ret = ath5k_hw_init_queues(ah);
+       if (ret)
+               return ret;
 
-       /* TODO: HW Compression support for data queues */
-       /* TODO: Burst prefetch for data queues */
-
-       /*
-        * Reset queues and start beacon timers at the end of the reset routine
-        * This also sets QCU mask on each DCU for 1:1 qcu to dcu mapping
-        * Note: If we want we can assign multiple qcus on one dcu.
-        */
-       for (i = 0; i < ah->ah_capabilities.cap_queues.q_tx_num; i++) {
-               ret = ath5k_hw_reset_tx_queue(ah, i);
-               if (ret) {
-                       ATH5K_ERR(ah->ah_sc,
-                               "failed to reset TX queue #%d\n", i);
-                       return ret;
-               }
-       }
-
-
-       /*
-        * Configure DMA/Interrupts
-        */
 
        /*
-        * Set Rx/Tx DMA Configuration
-        *
-        * Set standard DMA size (128). Note that
-        * a DMA size of 512 causes rx overruns and tx errors
-        * on pci-e cards (tested on 5424 but since rx overruns
-        * also occur on 5416/5418 with madwifi we set 128
-        * for all PCI-E cards to be safe).
-        *
-        * XXX: need to check 5210 for this
-        * TODO: Check out tx triger level, it's always 64 on dumps but I
-        * guess we can tweak it and see how it goes ;-)
+        * Initialize DMA/Interrupts
         */
-       if (ah->ah_version != AR5K_AR5210) {
-               AR5K_REG_WRITE_BITS(ah, AR5K_TXCFG,
-                       AR5K_TXCFG_SDMAMR, AR5K_DMASIZE_128B);
-               AR5K_REG_WRITE_BITS(ah, AR5K_RXCFG,
-                       AR5K_RXCFG_SDMAMW, AR5K_DMASIZE_128B);
-       }
+       ath5k_hw_dma_init(ah);
 
-       /* Pre-enable interrupts on 5211/5212*/
-       if (ah->ah_version != AR5K_AR5210)
-               ath5k_hw_set_imr(ah, ah->ah_imr);
 
        /* Enable 32KHz clock function for AR5212+ chips
         * Set clocks to 32KHz operation and use an
index 3ac4cff4239de9d8457246e8089caf8a9b5906c2..16b67e84906d10cf59e89160acbad401f8a986ca 100644 (file)
@@ -51,7 +51,7 @@
 struct ath5k_ini_rfbuffer {
        u8      rfb_bank;               /* RF Bank number */
        u16     rfb_ctrl_register;      /* RF Buffer control register */
-       u32     rfb_mode_data[5];       /* RF Buffer data for each mode */
+       u32     rfb_mode_data[3];       /* RF Buffer data for each mode */
 };
 
 /*
@@ -79,8 +79,10 @@ struct ath5k_rf_reg {
  * life easier by using an index for each register
  * instead of a full rfb_field */
 enum ath5k_rf_regs_idx {
+       /* BANK 2 */
+       AR5K_RF_TURBO = 0,
        /* BANK 6 */
-       AR5K_RF_OB_2GHZ = 0,
+       AR5K_RF_OB_2GHZ,
        AR5K_RF_OB_5GHZ,
        AR5K_RF_DB_2GHZ,
        AR5K_RF_DB_5GHZ,
@@ -134,6 +136,9 @@ enum ath5k_rf_regs_idx {
 * RF5111 (Sombrero) *
 \*******************/
 
+/* BANK 2                              len  pos col */
+#define        AR5K_RF5111_RF_TURBO            { 1, 3,   0 }
+
 /* BANK 6                              len  pos col */
 #define        AR5K_RF5111_OB_2GHZ             { 3, 119, 0 }
 #define        AR5K_RF5111_DB_2GHZ             { 3, 122, 0 }
@@ -158,6 +163,7 @@ enum ath5k_rf_regs_idx {
 #define        AR5K_RF5111_MAX_TIME            { 2, 49,  0 }
 
 static const struct ath5k_rf_reg rf_regs_5111[] = {
+       {2, AR5K_RF_TURBO,              AR5K_RF5111_RF_TURBO},
        {6, AR5K_RF_OB_2GHZ,            AR5K_RF5111_OB_2GHZ},
        {6, AR5K_RF_DB_2GHZ,            AR5K_RF5111_DB_2GHZ},
        {6, AR5K_RF_OB_5GHZ,            AR5K_RF5111_OB_5GHZ},
@@ -177,97 +183,52 @@ static const struct ath5k_rf_reg rf_regs_5111[] = {
 
 /* Default mode specific settings */
 static const struct ath5k_ini_rfbuffer rfb_5111[] = {
-       { 0, 0x989c,
-       /*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 0, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 0, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 0, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 0, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 0, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 0, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 0, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 0, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 0, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 0, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 0, 0x989c,
-           { 0x00380000, 0x00380000, 0x00380000, 0x00380000, 0x00380000 } },
-       { 0, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 0, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 0, 0x989c,
-           { 0x00000000, 0x00000000, 0x000000c0, 0x00000080, 0x00000080 } },
-       { 0, 0x989c,
-           { 0x000400f9, 0x000400f9, 0x000400ff, 0x000400fd, 0x000400fd } },
-       { 0, 0x98d4,
-           { 0x00000000, 0x00000000, 0x00000004, 0x00000004, 0x00000004 } },
-       { 1, 0x98d4,
-           { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-       { 2, 0x98d4,
-           { 0x00000010, 0x00000014, 0x00000010, 0x00000010, 0x00000014 } },
-       { 3, 0x98d8,
-           { 0x00601068, 0x00601068, 0x00601068, 0x00601068, 0x00601068 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
-       { 6, 0x989c,
-           { 0x04000000, 0x04000000, 0x04000000, 0x04000000, 0x04000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x0a000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x003800c0, 0x00380080, 0x023800c0, 0x003800c0, 0x003800c0 } },
-       { 6, 0x989c,
-           { 0x00020006, 0x00020006, 0x00000006, 0x00020006, 0x00020006 } },
-       { 6, 0x989c,
-           { 0x00000089, 0x00000089, 0x00000089, 0x00000089, 0x00000089 } },
-       { 6, 0x989c,
-           { 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0, 0x000000a0 } },
-       { 6, 0x989c,
-           { 0x00040007, 0x00040007, 0x00040007, 0x00040007, 0x00040007 } },
-       { 6, 0x98d4,
-           { 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a, 0x0000001a } },
-       { 7, 0x989c,
-           { 0x00000040, 0x00000048, 0x00000040, 0x00000040, 0x00000040 } },
-       { 7, 0x989c,
-           { 0x00000010, 0x00000010, 0x00000010, 0x00000010, 0x00000010 } },
-       { 7, 0x989c,
-           { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } },
-       { 7, 0x989c,
-           { 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f, 0x0000004f } },
-       { 7, 0x989c,
-           { 0x000000f1, 0x000000f1, 0x00000061, 0x000000f1, 0x000000f1 } },
-       { 7, 0x989c,
-           { 0x0000904f, 0x0000904f, 0x0000904c, 0x0000904f, 0x0000904f } },
-       { 7, 0x989c,
-           { 0x0000125a, 0x0000125a, 0x0000129a, 0x0000125a, 0x0000125a } },
-       { 7, 0x98cc,
-           { 0x0000000e, 0x0000000e, 0x0000000f, 0x0000000e, 0x0000000e } },
+       /* BANK / C.R.     A/XR         B           G      */
+       { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c, { 0x00380000, 0x00380000, 0x00380000 } },
+       { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 0, 0x989c, { 0x00000000, 0x000000c0, 0x00000080 } },
+       { 0, 0x989c, { 0x000400f9, 0x000400ff, 0x000400fd } },
+       { 0, 0x98d4, { 0x00000000, 0x00000004, 0x00000004 } },
+       { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+       { 2, 0x98d4, { 0x00000010, 0x00000010, 0x00000010 } },
+       { 3, 0x98d8, { 0x00601068, 0x00601068, 0x00601068 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x10000000, 0x10000000, 0x10000000 } },
+       { 6, 0x989c, { 0x04000000, 0x04000000, 0x04000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x0a000000, 0x00000000 } },
+       { 6, 0x989c, { 0x003800c0, 0x023800c0, 0x003800c0 } },
+       { 6, 0x989c, { 0x00020006, 0x00000006, 0x00020006 } },
+       { 6, 0x989c, { 0x00000089, 0x00000089, 0x00000089 } },
+       { 6, 0x989c, { 0x000000a0, 0x000000a0, 0x000000a0 } },
+       { 6, 0x989c, { 0x00040007, 0x00040007, 0x00040007 } },
+       { 6, 0x98d4, { 0x0000001a, 0x0000001a, 0x0000001a } },
+       { 7, 0x989c, { 0x00000040, 0x00000040, 0x00000040 } },
+       { 7, 0x989c, { 0x00000010, 0x00000010, 0x00000010 } },
+       { 7, 0x989c, { 0x00000008, 0x00000008, 0x00000008 } },
+       { 7, 0x989c, { 0x0000004f, 0x0000004f, 0x0000004f } },
+       { 7, 0x989c, { 0x000000f1, 0x00000061, 0x000000f1 } },
+       { 7, 0x989c, { 0x0000904f, 0x0000904c, 0x0000904f } },
+       { 7, 0x989c, { 0x0000125a, 0x0000129a, 0x0000125a } },
+       { 7, 0x98cc, { 0x0000000e, 0x0000000f, 0x0000000e } },
 };
 
 
@@ -276,6 +237,9 @@ static const struct ath5k_ini_rfbuffer rfb_5111[] = {
 * RF5112/RF2112 (Derby) *
 \***********************/
 
+/* BANK 2 (Common)                     len  pos col */
+#define        AR5K_RF5112X_RF_TURBO           { 1, 1,   2 }
+
 /* BANK 7 (Common)                     len  pos col */
 #define        AR5K_RF5112X_GAIN_I             { 6, 14,  0 }
 #define        AR5K_RF5112X_MIXVGA_OVR         { 1, 36,  0 }
@@ -307,6 +271,7 @@ static const struct ath5k_ini_rfbuffer rfb_5111[] = {
 #define AR5K_RF5112_PWD(_n)            { 1, (302 - _n), 3 }
 
 static const struct ath5k_rf_reg rf_regs_5112[] = {
+       {2, AR5K_RF_TURBO,              AR5K_RF5112X_RF_TURBO},
        {6, AR5K_RF_OB_2GHZ,            AR5K_RF5112_OB_2GHZ},
        {6, AR5K_RF_DB_2GHZ,            AR5K_RF5112_DB_2GHZ},
        {6, AR5K_RF_OB_5GHZ,            AR5K_RF5112_OB_5GHZ},
@@ -335,115 +300,61 @@ static const struct ath5k_rf_reg rf_regs_5112[] = {
 
 /* Default mode specific settings */
 static const struct ath5k_ini_rfbuffer rfb_5112[] = {
-       { 1, 0x98d4,
-       /*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-           { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-       { 2, 0x98d0,
-           { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } },
-       { 3, 0x98dc,
-           { 0x00a0c0c0, 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0, 0x00e0c0c0 } },
-       { 6, 0x989c,
-           { 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000, 0x00a00000 } },
-       { 6, 0x989c,
-           { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00660000, 0x00660000, 0x00660000, 0x00660000, 0x00660000 } },
-       { 6, 0x989c,
-           { 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000, 0x00db0000 } },
-       { 6, 0x989c,
-           { 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000, 0x00f10000 } },
-       { 6, 0x989c,
-           { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
-       { 6, 0x989c,
-           { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
-       { 6, 0x989c,
-           { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
-       { 6, 0x989c,
-           { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
-       { 6, 0x989c,
-           { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
-       { 6, 0x989c,
-           { 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000, 0x008b0000 } },
-       { 6, 0x989c,
-           { 0x00600000, 0x00600000, 0x00600000, 0x00600000, 0x00600000 } },
-       { 6, 0x989c,
-           { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
-       { 6, 0x989c,
-           { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } },
-       { 6, 0x989c,
-           { 0x00640000, 0x00640000, 0x00640000, 0x00640000, 0x00640000 } },
-       { 6, 0x989c,
-           { 0x00200000, 0x00200000, 0x00200000, 0x00200000, 0x00200000 } },
-       { 6, 0x989c,
-           { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } },
-       { 6, 0x989c,
-           { 0x00250000, 0x00250000, 0x00250000, 0x00250000, 0x00250000 } },
-       { 6, 0x989c,
-           { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
-       { 6, 0x989c,
-           { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
-       { 6, 0x989c,
-           { 0x00510000, 0x00510000, 0x00510000, 0x00510000, 0x00510000 } },
-       { 6, 0x989c,
-           { 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000, 0x1c040000 } },
-       { 6, 0x989c,
-           { 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000, 0x000a0000 } },
-       { 6, 0x989c,
-           { 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000, 0x00a10000 } },
-       { 6, 0x989c,
-           { 0x00400000, 0x00400000, 0x00400000, 0x00400000, 0x00400000 } },
-       { 6, 0x989c,
-           { 0x03090000, 0x03090000, 0x03090000, 0x03090000, 0x03090000 } },
-       { 6, 0x989c,
-           { 0x06000000, 0x06000000, 0x06000000, 0x06000000, 0x06000000 } },
-       { 6, 0x989c,
-           { 0x000000b0, 0x000000b0, 0x000000a8, 0x000000a8, 0x000000a8 } },
-       { 6, 0x989c,
-           { 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e, 0x0000002e } },
-       { 6, 0x989c,
-           { 0x006c4a41, 0x006c4a41, 0x006c4af1, 0x006c4a61, 0x006c4a61 } },
-       { 6, 0x989c,
-           { 0x0050892a, 0x0050892a, 0x0050892b, 0x0050892b, 0x0050892b } },
-       { 6, 0x989c,
-           { 0x00842400, 0x00842400, 0x00842400, 0x00842400, 0x00842400 } },
-       { 6, 0x989c,
-           { 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200, 0x00c69200 } },
-       { 6, 0x98d0,
-           { 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c, 0x0002000c } },
-       { 7, 0x989c,
-           { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } },
-       { 7, 0x989c,
-           { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } },
-       { 7, 0x989c,
-           { 0x0000000a, 0x0000000a, 0x00000012, 0x00000012, 0x00000012 } },
-       { 7, 0x989c,
-           { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
-       { 7, 0x989c,
-           { 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1, 0x000000c1 } },
-       { 7, 0x989c,
-           { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
-       { 7, 0x989c,
-           { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } },
-       { 7, 0x989c,
-           { 0x00000022, 0x00000022, 0x00000022, 0x00000022, 0x00000022 } },
-       { 7, 0x989c,
-           { 0x00000092, 0x00000092, 0x00000092, 0x00000092, 0x00000092 } },
-       { 7, 0x989c,
-           { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } },
-       { 7, 0x989c,
-           { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } },
-       { 7, 0x989c,
-           { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } },
-       { 7, 0x98c4,
-           { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
+       /* BANK / C.R.     A/XR         B           G      */
+       { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+       { 2, 0x98d0, { 0x03060408, 0x03060408, 0x03060408 } },
+       { 3, 0x98dc, { 0x00a0c0c0, 0x00e0c0c0, 0x00e0c0c0 } },
+       { 6, 0x989c, { 0x00a00000, 0x00a00000, 0x00a00000 } },
+       { 6, 0x989c, { 0x000a0000, 0x000a0000, 0x000a0000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00660000, 0x00660000, 0x00660000 } },
+       { 6, 0x989c, { 0x00db0000, 0x00db0000, 0x00db0000 } },
+       { 6, 0x989c, { 0x00f10000, 0x00f10000, 0x00f10000 } },
+       { 6, 0x989c, { 0x00120000, 0x00120000, 0x00120000 } },
+       { 6, 0x989c, { 0x00120000, 0x00120000, 0x00120000 } },
+       { 6, 0x989c, { 0x00730000, 0x00730000, 0x00730000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x000c0000, 0x000c0000, 0x000c0000 } },
+       { 6, 0x989c, { 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+       { 6, 0x989c, { 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+       { 6, 0x989c, { 0x008b0000, 0x008b0000, 0x008b0000 } },
+       { 6, 0x989c, { 0x00600000, 0x00600000, 0x00600000 } },
+       { 6, 0x989c, { 0x000c0000, 0x000c0000, 0x000c0000 } },
+       { 6, 0x989c, { 0x00840000, 0x00840000, 0x00840000 } },
+       { 6, 0x989c, { 0x00640000, 0x00640000, 0x00640000 } },
+       { 6, 0x989c, { 0x00200000, 0x00200000, 0x00200000 } },
+       { 6, 0x989c, { 0x00240000, 0x00240000, 0x00240000 } },
+       { 6, 0x989c, { 0x00250000, 0x00250000, 0x00250000 } },
+       { 6, 0x989c, { 0x00110000, 0x00110000, 0x00110000 } },
+       { 6, 0x989c, { 0x00110000, 0x00110000, 0x00110000 } },
+       { 6, 0x989c, { 0x00510000, 0x00510000, 0x00510000 } },
+       { 6, 0x989c, { 0x1c040000, 0x1c040000, 0x1c040000 } },
+       { 6, 0x989c, { 0x000a0000, 0x000a0000, 0x000a0000 } },
+       { 6, 0x989c, { 0x00a10000, 0x00a10000, 0x00a10000 } },
+       { 6, 0x989c, { 0x00400000, 0x00400000, 0x00400000 } },
+       { 6, 0x989c, { 0x03090000, 0x03090000, 0x03090000 } },
+       { 6, 0x989c, { 0x06000000, 0x06000000, 0x06000000 } },
+       { 6, 0x989c, { 0x000000b0, 0x000000a8, 0x000000a8 } },
+       { 6, 0x989c, { 0x0000002e, 0x0000002e, 0x0000002e } },
+       { 6, 0x989c, { 0x006c4a41, 0x006c4af1, 0x006c4a61 } },
+       { 6, 0x989c, { 0x0050892a, 0x0050892b, 0x0050892b } },
+       { 6, 0x989c, { 0x00842400, 0x00842400, 0x00842400 } },
+       { 6, 0x989c, { 0x00c69200, 0x00c69200, 0x00c69200 } },
+       { 6, 0x98d0, { 0x0002000c, 0x0002000c, 0x0002000c } },
+       { 7, 0x989c, { 0x00000094, 0x00000094, 0x00000094 } },
+       { 7, 0x989c, { 0x00000091, 0x00000091, 0x00000091 } },
+       { 7, 0x989c, { 0x0000000a, 0x00000012, 0x00000012 } },
+       { 7, 0x989c, { 0x00000080, 0x00000080, 0x00000080 } },
+       { 7, 0x989c, { 0x000000c1, 0x000000c1, 0x000000c1 } },
+       { 7, 0x989c, { 0x00000060, 0x00000060, 0x00000060 } },
+       { 7, 0x989c, { 0x000000f0, 0x000000f0, 0x000000f0 } },
+       { 7, 0x989c, { 0x00000022, 0x00000022, 0x00000022 } },
+       { 7, 0x989c, { 0x00000092, 0x00000092, 0x00000092 } },
+       { 7, 0x989c, { 0x000000d4, 0x000000d4, 0x000000d4 } },
+       { 7, 0x989c, { 0x000014cc, 0x000014cc, 0x000014cc } },
+       { 7, 0x989c, { 0x0000048c, 0x0000048c, 0x0000048c } },
+       { 7, 0x98c4, { 0x00000003, 0x00000003, 0x00000003 } },
 };
 
 /* RFX112A (Derby 2) */
@@ -477,6 +388,7 @@ static const struct ath5k_ini_rfbuffer rfb_5112[] = {
 #define        AR5K_RF5112A_XB5_LVL            { 2, 3,   3 }
 
 static const struct ath5k_rf_reg rf_regs_5112a[] = {
+       {2, AR5K_RF_TURBO,              AR5K_RF5112X_RF_TURBO},
        {6, AR5K_RF_OB_2GHZ,            AR5K_RF5112A_OB_2GHZ},
        {6, AR5K_RF_DB_2GHZ,            AR5K_RF5112A_DB_2GHZ},
        {6, AR5K_RF_OB_5GHZ,            AR5K_RF5112A_OB_5GHZ},
@@ -515,119 +427,63 @@ static const struct ath5k_rf_reg rf_regs_5112a[] = {
 
 /* Default mode specific settings */
 static const struct ath5k_ini_rfbuffer rfb_5112a[] = {
-       { 1, 0x98d4,
-       /*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-           { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-       { 2, 0x98d0,
-           { 0x03060408, 0x03070408, 0x03060408, 0x03060408, 0x03070408 } },
-       { 3, 0x98dc,
-           { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
-       { 6, 0x989c,
-           { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00800000, 0x00800000, 0x00800000, 0x00800000, 0x00800000 } },
-       { 6, 0x989c,
-           { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
-       { 6, 0x989c,
-           { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00180000, 0x00180000, 0x00180000, 0x00180000, 0x00180000 } },
-       { 6, 0x989c,
-           { 0x00600000, 0x00600000, 0x006e0000, 0x006e0000, 0x006e0000 } },
-       { 6, 0x989c,
-           { 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000, 0x00c70000 } },
-       { 6, 0x989c,
-           { 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000, 0x004b0000 } },
-       { 6, 0x989c,
-           { 0x04480000, 0x04480000, 0x04480000, 0x04480000, 0x04480000 } },
-       { 6, 0x989c,
-           { 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000, 0x004c0000 } },
-       { 6, 0x989c,
-           { 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000, 0x00e40000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000, 0x00fc0000 } },
-       { 6, 0x989c,
-           { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
-       { 6, 0x989c,
-           { 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000, 0x043f0000 } },
-       { 6, 0x989c,
-           { 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000, 0x000c0000 } },
-       { 6, 0x989c,
-           { 0x02190000, 0x02190000, 0x02190000, 0x02190000, 0x02190000 } },
-       { 6, 0x989c,
-           { 0x00240000, 0x00240000, 0x00240000, 0x00240000, 0x00240000 } },
-       { 6, 0x989c,
-           { 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000, 0x00b40000 } },
-       { 6, 0x989c,
-           { 0x00990000, 0x00990000, 0x00990000, 0x00990000, 0x00990000 } },
-       { 6, 0x989c,
-           { 0x00500000, 0x00500000, 0x00500000, 0x00500000, 0x00500000 } },
-       { 6, 0x989c,
-           { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
-       { 6, 0x989c,
-           { 0x00120000, 0x00120000, 0x00120000, 0x00120000, 0x00120000 } },
-       { 6, 0x989c,
-           { 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000, 0xc0320000 } },
-       { 6, 0x989c,
-           { 0x01740000, 0x01740000, 0x01740000, 0x01740000, 0x01740000 } },
-       { 6, 0x989c,
-           { 0x00110000, 0x00110000, 0x00110000, 0x00110000, 0x00110000 } },
-       { 6, 0x989c,
-           { 0x86280000, 0x86280000, 0x86280000, 0x86280000, 0x86280000 } },
-       { 6, 0x989c,
-           { 0x31840000, 0x31840000, 0x31840000, 0x31840000, 0x31840000 } },
-       { 6, 0x989c,
-           { 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080, 0x00f20080 } },
-       { 6, 0x989c,
-           { 0x00270019, 0x00270019, 0x00270019, 0x00270019, 0x00270019 } },
-       { 6, 0x989c,
-           { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2, 0x000000b2 } },
-       { 6, 0x989c,
-           { 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084, 0x00b02084 } },
-       { 6, 0x989c,
-           { 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4, 0x004125a4 } },
-       { 6, 0x989c,
-           { 0x00119220, 0x00119220, 0x00119220, 0x00119220, 0x00119220 } },
-       { 6, 0x989c,
-           { 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800, 0x001a4800 } },
-       { 6, 0x98d8,
-           { 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230, 0x000b0230 } },
-       { 7, 0x989c,
-           { 0x00000094, 0x00000094, 0x00000094, 0x00000094, 0x00000094 } },
-       { 7, 0x989c,
-           { 0x00000091, 0x00000091, 0x00000091, 0x00000091, 0x00000091 } },
-       { 7, 0x989c,
-           { 0x00000012, 0x00000012, 0x00000012, 0x00000012, 0x00000012 } },
-       { 7, 0x989c,
-           { 0x00000080, 0x00000080, 0x00000080, 0x00000080, 0x00000080 } },
-       { 7, 0x989c,
-           { 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9, 0x000000d9 } },
-       { 7, 0x989c,
-           { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
-       { 7, 0x989c,
-           { 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0, 0x000000f0 } },
-       { 7, 0x989c,
-           { 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2, 0x000000a2 } },
-       { 7, 0x989c,
-           { 0x00000052, 0x00000052, 0x00000052, 0x00000052, 0x00000052 } },
-       { 7, 0x989c,
-           { 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4, 0x000000d4 } },
-       { 7, 0x989c,
-           { 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc, 0x000014cc } },
-       { 7, 0x989c,
-           { 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c, 0x0000048c } },
-       { 7, 0x98c4,
-           { 0x00000003, 0x00000003, 0x00000003, 0x00000003, 0x00000003 } },
+       /* BANK / C.R.     A/XR         B           G      */
+       { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+       { 2, 0x98d0, { 0x03060408, 0x03060408, 0x03060408 } },
+       { 3, 0x98dc, { 0x00a020c0, 0x00e020c0, 0x00e020c0 } },
+       { 6, 0x989c, { 0x0f000000, 0x0f000000, 0x0f000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00800000, 0x00800000, 0x00800000 } },
+       { 6, 0x989c, { 0x002a0000, 0x002a0000, 0x002a0000 } },
+       { 6, 0x989c, { 0x00010000, 0x00010000, 0x00010000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00180000, 0x00180000, 0x00180000 } },
+       { 6, 0x989c, { 0x00600000, 0x006e0000, 0x006e0000 } },
+       { 6, 0x989c, { 0x00c70000, 0x00c70000, 0x00c70000 } },
+       { 6, 0x989c, { 0x004b0000, 0x004b0000, 0x004b0000 } },
+       { 6, 0x989c, { 0x04480000, 0x04480000, 0x04480000 } },
+       { 6, 0x989c, { 0x004c0000, 0x004c0000, 0x004c0000 } },
+       { 6, 0x989c, { 0x00e40000, 0x00e40000, 0x00e40000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00fc0000, 0x00fc0000, 0x00fc0000 } },
+       { 6, 0x989c, { 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+       { 6, 0x989c, { 0x043f0000, 0x043f0000, 0x043f0000 } },
+       { 6, 0x989c, { 0x000c0000, 0x000c0000, 0x000c0000 } },
+       { 6, 0x989c, { 0x02190000, 0x02190000, 0x02190000 } },
+       { 6, 0x989c, { 0x00240000, 0x00240000, 0x00240000 } },
+       { 6, 0x989c, { 0x00b40000, 0x00b40000, 0x00b40000 } },
+       { 6, 0x989c, { 0x00990000, 0x00990000, 0x00990000 } },
+       { 6, 0x989c, { 0x00500000, 0x00500000, 0x00500000 } },
+       { 6, 0x989c, { 0x002a0000, 0x002a0000, 0x002a0000 } },
+       { 6, 0x989c, { 0x00120000, 0x00120000, 0x00120000 } },
+       { 6, 0x989c, { 0xc0320000, 0xc0320000, 0xc0320000 } },
+       { 6, 0x989c, { 0x01740000, 0x01740000, 0x01740000 } },
+       { 6, 0x989c, { 0x00110000, 0x00110000, 0x00110000 } },
+       { 6, 0x989c, { 0x86280000, 0x86280000, 0x86280000 } },
+       { 6, 0x989c, { 0x31840000, 0x31840000, 0x31840000 } },
+       { 6, 0x989c, { 0x00f20080, 0x00f20080, 0x00f20080 } },
+       { 6, 0x989c, { 0x00270019, 0x00270019, 0x00270019 } },
+       { 6, 0x989c, { 0x00000003, 0x00000003, 0x00000003 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x000000b2, 0x000000b2, 0x000000b2 } },
+       { 6, 0x989c, { 0x00b02084, 0x00b02084, 0x00b02084 } },
+       { 6, 0x989c, { 0x004125a4, 0x004125a4, 0x004125a4 } },
+       { 6, 0x989c, { 0x00119220, 0x00119220, 0x00119220 } },
+       { 6, 0x989c, { 0x001a4800, 0x001a4800, 0x001a4800 } },
+       { 6, 0x98d8, { 0x000b0230, 0x000b0230, 0x000b0230 } },
+       { 7, 0x989c, { 0x00000094, 0x00000094, 0x00000094 } },
+       { 7, 0x989c, { 0x00000091, 0x00000091, 0x00000091 } },
+       { 7, 0x989c, { 0x00000012, 0x00000012, 0x00000012 } },
+       { 7, 0x989c, { 0x00000080, 0x00000080, 0x00000080 } },
+       { 7, 0x989c, { 0x000000d9, 0x000000d9, 0x000000d9 } },
+       { 7, 0x989c, { 0x00000060, 0x00000060, 0x00000060 } },
+       { 7, 0x989c, { 0x000000f0, 0x000000f0, 0x000000f0 } },
+       { 7, 0x989c, { 0x000000a2, 0x000000a2, 0x000000a2 } },
+       { 7, 0x989c, { 0x00000052, 0x00000052, 0x00000052 } },
+       { 7, 0x989c, { 0x000000d4, 0x000000d4, 0x000000d4 } },
+       { 7, 0x989c, { 0x000014cc, 0x000014cc, 0x000014cc } },
+       { 7, 0x989c, { 0x0000048c, 0x0000048c, 0x0000048c } },
+       { 7, 0x98c4, { 0x00000003, 0x00000003, 0x00000003 } },
 };
 
 
@@ -636,11 +492,15 @@ static const struct ath5k_ini_rfbuffer rfb_5112a[] = {
 * RF2413 (Griffin) *
 \******************/
 
+/* BANK 2                              len  pos col */
+#define AR5K_RF2413_RF_TURBO           { 1, 1,   2 }
+
 /* BANK 6                              len  pos col */
 #define        AR5K_RF2413_OB_2GHZ             { 3, 168, 0 }
 #define        AR5K_RF2413_DB_2GHZ             { 3, 165, 0 }
 
 static const struct ath5k_rf_reg rf_regs_2413[] = {
+       {2, AR5K_RF_TURBO,              AR5K_RF2413_RF_TURBO},
        {6, AR5K_RF_OB_2GHZ,            AR5K_RF2413_OB_2GHZ},
        {6, AR5K_RF_DB_2GHZ,            AR5K_RF2413_DB_2GHZ},
 };
@@ -649,73 +509,40 @@ static const struct ath5k_rf_reg rf_regs_2413[] = {
  * XXX: a/aTurbo ???
  */
 static const struct ath5k_ini_rfbuffer rfb_2413[] = {
-       { 1, 0x98d4,
-       /*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-           { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-       { 2, 0x98d0,
-           { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
-       { 3, 0x98dc,
-           { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
-       { 6, 0x989c,
-           { 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000, 0xf0000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x03000000, 0x03000000, 0x03000000, 0x03000000, 0x03000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x40400000, 0x40400000, 0x40400000, 0x40400000, 0x40400000 } },
-       { 6, 0x989c,
-           { 0x65050000, 0x65050000, 0x65050000, 0x65050000, 0x65050000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00420000, 0x00420000, 0x00420000, 0x00420000, 0x00420000 } },
-       { 6, 0x989c,
-           { 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000, 0x00b50000 } },
-       { 6, 0x989c,
-           { 0x00030000, 0x00030000, 0x00030000, 0x00030000, 0x00030000 } },
-       { 6, 0x989c,
-           { 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000, 0x00f70000 } },
-       { 6, 0x989c,
-           { 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000, 0x009d0000 } },
-       { 6, 0x989c,
-           { 0x00220000, 0x00220000, 0x00220000, 0x00220000, 0x00220000 } },
-       { 6, 0x989c,
-           { 0x04220000, 0x04220000, 0x04220000, 0x04220000, 0x04220000 } },
-       { 6, 0x989c,
-           { 0x00230018, 0x00230018, 0x00230018, 0x00230018, 0x00230018 } },
-       { 6, 0x989c,
-           { 0x00280000, 0x00280000, 0x00280060, 0x00280060, 0x00280060 } },
-       { 6, 0x989c,
-           { 0x005000c0, 0x005000c0, 0x005000c3, 0x005000c3, 0x005000c3 } },
-       { 6, 0x989c,
-           { 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f, 0x0004007f } },
-       { 6, 0x989c,
-           { 0x00000458, 0x00000458, 0x00000458, 0x00000458, 0x00000458 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000, 0x0000c000 } },
-       { 6, 0x98d8,
-           { 0x00400230, 0x00400230, 0x00400230, 0x00400230, 0x00400230 } },
-       { 7, 0x989c,
-           { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
-       { 7, 0x989c,
-           { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
-       { 7, 0x98cc,
-           { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+       /* BANK / C.R.     A/XR         B           G      */
+       { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+       { 2, 0x98d0, { 0x02001408, 0x02001408, 0x02001408 } },
+       { 3, 0x98dc, { 0x00a020c0, 0x00e020c0, 0x00e020c0 } },
+       { 6, 0x989c, { 0xf0000000, 0xf0000000, 0xf0000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x03000000, 0x03000000, 0x03000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x40400000, 0x40400000, 0x40400000 } },
+       { 6, 0x989c, { 0x65050000, 0x65050000, 0x65050000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00420000, 0x00420000, 0x00420000 } },
+       { 6, 0x989c, { 0x00b50000, 0x00b50000, 0x00b50000 } },
+       { 6, 0x989c, { 0x00030000, 0x00030000, 0x00030000 } },
+       { 6, 0x989c, { 0x00f70000, 0x00f70000, 0x00f70000 } },
+       { 6, 0x989c, { 0x009d0000, 0x009d0000, 0x009d0000 } },
+       { 6, 0x989c, { 0x00220000, 0x00220000, 0x00220000 } },
+       { 6, 0x989c, { 0x04220000, 0x04220000, 0x04220000 } },
+       { 6, 0x989c, { 0x00230018, 0x00230018, 0x00230018 } },
+       { 6, 0x989c, { 0x00280000, 0x00280060, 0x00280060 } },
+       { 6, 0x989c, { 0x005000c0, 0x005000c3, 0x005000c3 } },
+       { 6, 0x989c, { 0x0004007f, 0x0004007f, 0x0004007f } },
+       { 6, 0x989c, { 0x00000458, 0x00000458, 0x00000458 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x0000c000, 0x0000c000, 0x0000c000 } },
+       { 6, 0x98d8, { 0x00400230, 0x00400230, 0x00400230 } },
+       { 7, 0x989c, { 0x00006400, 0x00006400, 0x00006400 } },
+       { 7, 0x989c, { 0x00000800, 0x00000800, 0x00000800 } },
+       { 7, 0x98cc, { 0x0000000e, 0x0000000e, 0x0000000e } },
 };
 
 
@@ -724,88 +551,57 @@ static const struct ath5k_ini_rfbuffer rfb_2413[] = {
 * RF2315/RF2316 (Cobra SoC) *
 \***************************/
 
+/* BANK 2                              len  pos col */
+#define        AR5K_RF2316_RF_TURBO            { 1, 1,   2 }
+
 /* BANK 6                              len  pos col */
 #define        AR5K_RF2316_OB_2GHZ             { 3, 178, 0 }
 #define        AR5K_RF2316_DB_2GHZ             { 3, 175, 0 }
 
 static const struct ath5k_rf_reg rf_regs_2316[] = {
+       {2, AR5K_RF_TURBO,              AR5K_RF2316_RF_TURBO},
        {6, AR5K_RF_OB_2GHZ,            AR5K_RF2316_OB_2GHZ},
        {6, AR5K_RF_DB_2GHZ,            AR5K_RF2316_DB_2GHZ},
 };
 
 /* Default mode specific settings */
 static const struct ath5k_ini_rfbuffer rfb_2316[] = {
-       { 1, 0x98d4,
-       /*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-           { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-       { 2, 0x98d0,
-           { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
-       { 3, 0x98dc,
-           { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000, 0xc0000000 } },
-       { 6, 0x989c,
-           { 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000, 0x0f000000 } },
-       { 6, 0x989c,
-           { 0x02000000, 0x02000000, 0x02000000, 0x02000000, 0x02000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000, 0xf8000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x95150000, 0x95150000, 0x95150000, 0x95150000, 0x95150000 } },
-       { 6, 0x989c,
-           { 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000, 0xc1000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00080000, 0x00080000, 0x00080000, 0x00080000, 0x00080000 } },
-       { 6, 0x989c,
-           { 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000, 0x00d50000 } },
-       { 6, 0x989c,
-           { 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000, 0x000e0000 } },
-       { 6, 0x989c,
-           { 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000, 0x00dc0000 } },
-       { 6, 0x989c,
-           { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } },
-       { 6, 0x989c,
-           { 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000, 0x008a0000 } },
-       { 6, 0x989c,
-           { 0x10880000, 0x10880000, 0x10880000, 0x10880000, 0x10880000 } },
-       { 6, 0x989c,
-           { 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060, 0x008c0060 } },
-       { 6, 0x989c,
-           { 0x00a00000, 0x00a00000, 0x00a00080, 0x00a00080, 0x00a00080 } },
-       { 6, 0x989c,
-           { 0x00400000, 0x00400000, 0x0040000d, 0x0040000d, 0x0040000d } },
-       { 6, 0x989c,
-           { 0x00110400, 0x00110400, 0x00110400, 0x00110400, 0x00110400 } },
-       { 6, 0x989c,
-           { 0x00000060, 0x00000060, 0x00000060, 0x00000060, 0x00000060 } },
-       { 6, 0x989c,
-           { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
-       { 6, 0x989c,
-           { 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00, 0x00000b00 } },
-       { 6, 0x989c,
-           { 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8, 0x00000be8 } },
-       { 6, 0x98c0,
-           { 0x00010000, 0x00010000, 0x00010000, 0x00010000, 0x00010000 } },
-       { 7, 0x989c,
-           { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
-       { 7, 0x989c,
-           { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
-       { 7, 0x98cc,
-           { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+       /* BANK / C.R.     A/XR         B           G      */
+       { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+       { 2, 0x98d0, { 0x02001408, 0x02001408, 0x02001408 } },
+       { 3, 0x98dc, { 0x00a020c0, 0x00e020c0, 0x00e020c0 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0xc0000000, 0xc0000000, 0xc0000000 } },
+       { 6, 0x989c, { 0x0f000000, 0x0f000000, 0x0f000000 } },
+       { 6, 0x989c, { 0x02000000, 0x02000000, 0x02000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0xf8000000, 0xf8000000, 0xf8000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x95150000, 0x95150000, 0x95150000 } },
+       { 6, 0x989c, { 0xc1000000, 0xc1000000, 0xc1000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00080000, 0x00080000, 0x00080000 } },
+       { 6, 0x989c, { 0x00d50000, 0x00d50000, 0x00d50000 } },
+       { 6, 0x989c, { 0x000e0000, 0x000e0000, 0x000e0000 } },
+       { 6, 0x989c, { 0x00dc0000, 0x00dc0000, 0x00dc0000 } },
+       { 6, 0x989c, { 0x00770000, 0x00770000, 0x00770000 } },
+       { 6, 0x989c, { 0x008a0000, 0x008a0000, 0x008a0000 } },
+       { 6, 0x989c, { 0x10880000, 0x10880000, 0x10880000 } },
+       { 6, 0x989c, { 0x008c0060, 0x008c0060, 0x008c0060 } },
+       { 6, 0x989c, { 0x00a00000, 0x00a00080, 0x00a00080 } },
+       { 6, 0x989c, { 0x00400000, 0x0040000d, 0x0040000d } },
+       { 6, 0x989c, { 0x00110400, 0x00110400, 0x00110400 } },
+       { 6, 0x989c, { 0x00000060, 0x00000060, 0x00000060 } },
+       { 6, 0x989c, { 0x00000001, 0x00000001, 0x00000001 } },
+       { 6, 0x989c, { 0x00000b00, 0x00000b00, 0x00000b00 } },
+       { 6, 0x989c, { 0x00000be8, 0x00000be8, 0x00000be8 } },
+       { 6, 0x98c0, { 0x00010000, 0x00010000, 0x00010000 } },
+       { 7, 0x989c, { 0x00006400, 0x00006400, 0x00006400 } },
+       { 7, 0x989c, { 0x00000800, 0x00000800, 0x00000800 } },
+       { 7, 0x98cc, { 0x0000000e, 0x0000000e, 0x0000000e } },
 };
 
 
@@ -835,93 +631,50 @@ static const struct ath5k_rf_reg rf_regs_5413[] = {
 
 /* Default mode specific settings */
 static const struct ath5k_ini_rfbuffer rfb_5413[] = {
-       { 1, 0x98d4,
-       /*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-           { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-       { 2, 0x98d0,
-           { 0x00000008, 0x00000008, 0x00000008, 0x00000008, 0x00000008 } },
-       { 3, 0x98dc,
-           { 0x00a000c0, 0x00a000c0, 0x00e000c0, 0x00e000c0, 0x00e000c0 } },
-       { 6, 0x989c,
-           { 0x33000000, 0x33000000, 0x33000000, 0x33000000, 0x33000000 } },
-       { 6, 0x989c,
-           { 0x01000000, 0x01000000, 0x01000000, 0x01000000, 0x01000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000, 0x1f000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000, 0x00b80000 } },
-       { 6, 0x989c,
-           { 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000, 0x00b70000 } },
-       { 6, 0x989c,
-           { 0x00840000, 0x00840000, 0x00840000, 0x00840000, 0x00840000 } },
-       { 6, 0x989c,
-           { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } },
-       { 6, 0x989c,
-           { 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000, 0x00c00000 } },
-       { 6, 0x989c,
-           { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
-       { 6, 0x989c,
-           { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
-       { 6, 0x989c,
-           { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
-       { 6, 0x989c,
-           { 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
-       { 6, 0x989c,
-           { 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000, 0x00d70000 } },
-       { 6, 0x989c,
-           { 0x00610000, 0x00610000, 0x00610000, 0x00610000, 0x00610000 } },
-       { 6, 0x989c,
-           { 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000, 0x00fe0000 } },
-       { 6, 0x989c,
-           { 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000, 0x00de0000 } },
-       { 6, 0x989c,
-           { 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000, 0x007f0000 } },
-       { 6, 0x989c,
-           { 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000, 0x043d0000 } },
-       { 6, 0x989c,
-           { 0x00770000, 0x00770000, 0x00770000, 0x00770000, 0x00770000 } },
-       { 6, 0x989c,
-           { 0x00440000, 0x00440000, 0x00440000, 0x00440000, 0x00440000 } },
-       { 6, 0x989c,
-           { 0x00980000, 0x00980000, 0x00980000, 0x00980000, 0x00980000 } },
-       { 6, 0x989c,
-           { 0x00100080, 0x00100080, 0x00100080, 0x00100080, 0x00100080 } },
-       { 6, 0x989c,
-           { 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034, 0x0005c034 } },
-       { 6, 0x989c,
-           { 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0, 0x003100f0 } },
-       { 6, 0x989c,
-           { 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f, 0x000c011f } },
-       { 6, 0x989c,
-           { 0x00510040, 0x00510040, 0x00510040, 0x00510040, 0x00510040 } },
-       { 6, 0x989c,
-           { 0x005000da, 0x005000da, 0x005000da, 0x005000da, 0x005000da } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00004044, 0x00004044, 0x00004044, 0x00004044, 0x00004044 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0, 0x000060c0 } },
-       { 6, 0x989c,
-           { 0x00002c00, 0x00002c00, 0x00003600, 0x00003600, 0x00002c00 } },
-       { 6, 0x98c8,
-           { 0x00000403, 0x00000403, 0x00040403, 0x00040403, 0x00040403 } },
-       { 7, 0x989c,
-           { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
-       { 7, 0x989c,
-           { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
-       { 7, 0x98cc,
-           { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+       /* BANK / C.R.     A/XR         B           G      */
+       { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+       { 2, 0x98d0, { 0x00000008, 0x00000008, 0x00000008 } },
+       { 3, 0x98dc, { 0x00a000c0, 0x00e000c0, 0x00e000c0 } },
+       { 6, 0x989c, { 0x33000000, 0x33000000, 0x33000000 } },
+       { 6, 0x989c, { 0x01000000, 0x01000000, 0x01000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x1f000000, 0x1f000000, 0x1f000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00b80000, 0x00b80000, 0x00b80000 } },
+       { 6, 0x989c, { 0x00b70000, 0x00b70000, 0x00b70000 } },
+       { 6, 0x989c, { 0x00840000, 0x00840000, 0x00840000 } },
+       { 6, 0x989c, { 0x00980000, 0x00980000, 0x00980000 } },
+       { 6, 0x989c, { 0x00c00000, 0x00c00000, 0x00c00000 } },
+       { 6, 0x989c, { 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+       { 6, 0x989c, { 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+       { 6, 0x989c, { 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+       { 6, 0x989c, { 0x00ff0000, 0x00ff0000, 0x00ff0000 } },
+       { 6, 0x989c, { 0x00d70000, 0x00d70000, 0x00d70000 } },
+       { 6, 0x989c, { 0x00610000, 0x00610000, 0x00610000 } },
+       { 6, 0x989c, { 0x00fe0000, 0x00fe0000, 0x00fe0000 } },
+       { 6, 0x989c, { 0x00de0000, 0x00de0000, 0x00de0000 } },
+       { 6, 0x989c, { 0x007f0000, 0x007f0000, 0x007f0000 } },
+       { 6, 0x989c, { 0x043d0000, 0x043d0000, 0x043d0000 } },
+       { 6, 0x989c, { 0x00770000, 0x00770000, 0x00770000 } },
+       { 6, 0x989c, { 0x00440000, 0x00440000, 0x00440000 } },
+       { 6, 0x989c, { 0x00980000, 0x00980000, 0x00980000 } },
+       { 6, 0x989c, { 0x00100080, 0x00100080, 0x00100080 } },
+       { 6, 0x989c, { 0x0005c034, 0x0005c034, 0x0005c034 } },
+       { 6, 0x989c, { 0x003100f0, 0x003100f0, 0x003100f0 } },
+       { 6, 0x989c, { 0x000c011f, 0x000c011f, 0x000c011f } },
+       { 6, 0x989c, { 0x00510040, 0x00510040, 0x00510040 } },
+       { 6, 0x989c, { 0x005000da, 0x005000da, 0x005000da } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00004044, 0x00004044, 0x00004044 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x000060c0, 0x000060c0, 0x000060c0 } },
+       { 6, 0x989c, { 0x00002c00, 0x00003600, 0x00003600 } },
+       { 6, 0x98c8, { 0x00000403, 0x00040403, 0x00040403 } },
+       { 7, 0x989c, { 0x00006400, 0x00006400, 0x00006400 } },
+       { 7, 0x989c, { 0x00000800, 0x00000800, 0x00000800 } },
+       { 7, 0x98cc, { 0x0000000e, 0x0000000e, 0x0000000e } },
 };
 
 
@@ -931,92 +684,59 @@ static const struct ath5k_ini_rfbuffer rfb_5413[] = {
 * AR2317 (Spider SoC)       *
 \***************************/
 
+/* BANK 2                              len  pos col */
+#define AR5K_RF2425_RF_TURBO           { 1, 1,   2 }
+
 /* BANK 6                              len  pos col */
 #define        AR5K_RF2425_OB_2GHZ             { 3, 193, 0 }
 #define        AR5K_RF2425_DB_2GHZ             { 3, 190, 0 }
 
 static const struct ath5k_rf_reg rf_regs_2425[] = {
+       {2, AR5K_RF_TURBO,              AR5K_RF2425_RF_TURBO},
        {6, AR5K_RF_OB_2GHZ,            AR5K_RF2425_OB_2GHZ},
        {6, AR5K_RF_DB_2GHZ,            AR5K_RF2425_DB_2GHZ},
 };
 
 /* Default mode specific settings
- * XXX: a/aTurbo ?
  */
 static const struct ath5k_ini_rfbuffer rfb_2425[] = {
-       { 1, 0x98d4,
-       /*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-           { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-       { 2, 0x98d0,
-           { 0x02001408, 0x02001408, 0x02001408, 0x02001408, 0x02001408 } },
-       { 3, 0x98dc,
-           { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
-       { 6, 0x989c,
-           { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
-       { 6, 0x989c,
-           { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
-       { 6, 0x989c,
-           { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
-       { 6, 0x989c,
-           { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
-       { 6, 0x989c,
-           { 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 } },
-       { 6, 0x989c,
-           { 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 } },
-       { 6, 0x989c,
-           { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
-       { 6, 0x989c,
-           { 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a } },
-       { 6, 0x989c,
-           { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
-       { 6, 0x989c,
-           { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
-       { 6, 0x989c,
-           { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
-       { 6, 0x989c,
-           { 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 } },
-       { 6, 0x98c4,
-           { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
-       { 7, 0x989c,
-           { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
-       { 7, 0x989c,
-           { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
-       { 7, 0x98cc,
-           { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+       /* BANK / C.R.     A/XR         B           G      */
+       { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+       { 2, 0x98d0, { 0x02001408, 0x02001408, 0x02001408 } },
+       { 3, 0x98dc, { 0x00a020c0, 0x00e020c0, 0x00e020c0 } },
+       { 6, 0x989c, { 0x10000000, 0x10000000, 0x10000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x002a0000, 0x002a0000, 0x002a0000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00100000, 0x00100000, 0x00100000 } },
+       { 6, 0x989c, { 0x00020000, 0x00020000, 0x00020000 } },
+       { 6, 0x989c, { 0x00730000, 0x00730000, 0x00730000 } },
+       { 6, 0x989c, { 0x00f80000, 0x00f80000, 0x00f80000 } },
+       { 6, 0x989c, { 0x00e70000, 0x00e70000, 0x00e70000 } },
+       { 6, 0x989c, { 0x00140000, 0x00140000, 0x00140000 } },
+       { 6, 0x989c, { 0x00910040, 0x00910040, 0x00910040 } },
+       { 6, 0x989c, { 0x0007001a, 0x0007001a, 0x0007001a } },
+       { 6, 0x989c, { 0x00410000, 0x00410000, 0x00410000 } },
+       { 6, 0x989c, { 0x00810000, 0x00810060, 0x00810060 } },
+       { 6, 0x989c, { 0x00020800, 0x00020803, 0x00020803 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00001660, 0x00001660, 0x00001660 } },
+       { 6, 0x989c, { 0x00001688, 0x00001688, 0x00001688 } },
+       { 6, 0x98c4, { 0x00000001, 0x00000001, 0x00000001 } },
+       { 7, 0x989c, { 0x00006400, 0x00006400, 0x00006400 } },
+       { 7, 0x989c, { 0x00000800, 0x00000800, 0x00000800 } },
+       { 7, 0x98cc, { 0x0000000e, 0x0000000e, 0x0000000e } },
 };
 
 /*
@@ -1024,158 +744,85 @@ static const struct ath5k_ini_rfbuffer rfb_2425[] = {
  * bank modification and get rid of this
  */
 static const struct ath5k_ini_rfbuffer rfb_2317[] = {
-       { 1, 0x98d4,
-       /*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-           { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-       { 2, 0x98d0,
-           { 0x02001408, 0x02011408, 0x02001408, 0x02001408, 0x02011408 } },
-       { 3, 0x98dc,
-           { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
-       { 6, 0x989c,
-           { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
-       { 6, 0x989c,
-           { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
-       { 6, 0x989c,
-           { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
-       { 6, 0x989c,
-           { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
-       { 6, 0x989c,
-           { 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000, 0x00e70000 } },
-       { 6, 0x989c,
-           { 0x00140100, 0x00140100, 0x00140100, 0x00140100, 0x00140100 } },
-       { 6, 0x989c,
-           { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
-       { 6, 0x989c,
-           { 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a, 0x0007001a } },
-       { 6, 0x989c,
-           { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
-       { 6, 0x989c,
-           { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
-       { 6, 0x989c,
-           { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
-       { 6, 0x989c,
-           { 0x00009688, 0x00009688, 0x00009688, 0x00009688, 0x00009688 } },
-       { 6, 0x98c4,
-           { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
-       { 7, 0x989c,
-           { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
-       { 7, 0x989c,
-           { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
-       { 7, 0x98cc,
-           { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+       /* BANK / C.R.     A/XR         B           G      */
+       { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+       { 2, 0x98d0, { 0x02001408, 0x02001408, 0x02001408 } },
+       { 3, 0x98dc, { 0x00a020c0, 0x00e020c0, 0x00e020c0 } },
+       { 6, 0x989c, { 0x10000000, 0x10000000, 0x10000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x002a0000, 0x002a0000, 0x002a0000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00100000, 0x00100000, 0x00100000 } },
+       { 6, 0x989c, { 0x00020000, 0x00020000, 0x00020000 } },
+       { 6, 0x989c, { 0x00730000, 0x00730000, 0x00730000 } },
+       { 6, 0x989c, { 0x00f80000, 0x00f80000, 0x00f80000 } },
+       { 6, 0x989c, { 0x00e70000, 0x00e70000, 0x00e70000 } },
+       { 6, 0x989c, { 0x00140100, 0x00140100, 0x00140100 } },
+       { 6, 0x989c, { 0x00910040, 0x00910040, 0x00910040 } },
+       { 6, 0x989c, { 0x0007001a, 0x0007001a, 0x0007001a } },
+       { 6, 0x989c, { 0x00410000, 0x00410000, 0x00410000 } },
+       { 6, 0x989c, { 0x00810000, 0x00810060, 0x00810060 } },
+       { 6, 0x989c, { 0x00020800, 0x00020803, 0x00020803 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00001660, 0x00001660, 0x00001660 } },
+       { 6, 0x989c, { 0x00009688, 0x00009688, 0x00009688 } },
+       { 6, 0x98c4, { 0x00000001, 0x00000001, 0x00000001 } },
+       { 7, 0x989c, { 0x00006400, 0x00006400, 0x00006400 } },
+       { 7, 0x989c, { 0x00000800, 0x00000800, 0x00000800 } },
+       { 7, 0x98cc, { 0x0000000e, 0x0000000e, 0x0000000e } },
 };
 
 /*
  * TODO: Handle the few differences with swan during
  * bank modification and get rid of this
- * XXX: a/aTurbo ?
  */
 static const struct ath5k_ini_rfbuffer rfb_2417[] = {
-       { 1, 0x98d4,
-       /*     mode a/XR  mode aTurbo    mode b     mode g    mode gTurbo */
-           { 0x00000020, 0x00000020, 0x00000020, 0x00000020, 0x00000020 } },
-       { 2, 0x98d0,
-           { 0x02001408, 0x02001408, 0x02001408, 0x02001408, 0x02001408 } },
-       { 3, 0x98dc,
-           { 0x00a020c0, 0x00a020c0, 0x00e020c0, 0x00e020c0, 0x00e020c0 } },
-       { 6, 0x989c,
-           { 0x10000000, 0x10000000, 0x10000000, 0x10000000, 0x10000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000, 0x002a0000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00100000, 0x00100000, 0x00100000, 0x00100000, 0x00100000 } },
-       { 6, 0x989c,
-           { 0x00020000, 0x00020000, 0x00020000, 0x00020000, 0x00020000 } },
-       { 6, 0x989c,
-           { 0x00730000, 0x00730000, 0x00730000, 0x00730000, 0x00730000 } },
-       { 6, 0x989c,
-           { 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000, 0x00f80000 } },
-       { 6, 0x989c,
-           { 0x00e70000, 0x00e70000, 0x80e70000, 0x80e70000, 0x00e70000 } },
-       { 6, 0x989c,
-           { 0x00140000, 0x00140000, 0x00140000, 0x00140000, 0x00140000 } },
-       { 6, 0x989c,
-           { 0x00910040, 0x00910040, 0x00910040, 0x00910040, 0x00910040 } },
-       { 6, 0x989c,
-           { 0x0007001a, 0x0007001a, 0x0207001a, 0x0207001a, 0x0007001a } },
-       { 6, 0x989c,
-           { 0x00410000, 0x00410000, 0x00410000, 0x00410000, 0x00410000 } },
-       { 6, 0x989c,
-           { 0x00810000, 0x00810000, 0x00810060, 0x00810060, 0x00810060 } },
-       { 6, 0x989c,
-           { 0x00020800, 0x00020800, 0x00020803, 0x00020803, 0x00020803 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 } },
-       { 6, 0x989c,
-           { 0x00001660, 0x00001660, 0x00001660, 0x00001660, 0x00001660 } },
-       { 6, 0x989c,
-           { 0x00001688, 0x00001688, 0x00001688, 0x00001688, 0x00001688 } },
-       { 6, 0x98c4,
-           { 0x00000001, 0x00000001, 0x00000001, 0x00000001, 0x00000001 } },
-       { 7, 0x989c,
-           { 0x00006400, 0x00006400, 0x00006400, 0x00006400, 0x00006400 } },
-       { 7, 0x989c,
-           { 0x00000800, 0x00000800, 0x00000800, 0x00000800, 0x00000800 } },
-       { 7, 0x98cc,
-           { 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e, 0x0000000e } },
+       /* BANK / C.R.     A/XR         B           G      */
+       { 1, 0x98d4, { 0x00000020, 0x00000020, 0x00000020 } },
+       { 2, 0x98d0, { 0x02001408, 0x02001408, 0x02001408 } },
+       { 3, 0x98dc, { 0x00a020c0, 0x00e020c0, 0x00e020c0 } },
+       { 6, 0x989c, { 0x10000000, 0x10000000, 0x10000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x002a0000, 0x002a0000, 0x002a0000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00100000, 0x00100000, 0x00100000 } },
+       { 6, 0x989c, { 0x00020000, 0x00020000, 0x00020000 } },
+       { 6, 0x989c, { 0x00730000, 0x00730000, 0x00730000 } },
+       { 6, 0x989c, { 0x00f80000, 0x00f80000, 0x00f80000 } },
+       { 6, 0x989c, { 0x00e70000, 0x80e70000, 0x80e70000 } },
+       { 6, 0x989c, { 0x00140000, 0x00140000, 0x00140000 } },
+       { 6, 0x989c, { 0x00910040, 0x00910040, 0x00910040 } },
+       { 6, 0x989c, { 0x0007001a, 0x0207001a, 0x0207001a } },
+       { 6, 0x989c, { 0x00410000, 0x00410000, 0x00410000 } },
+       { 6, 0x989c, { 0x00810000, 0x00810060, 0x00810060 } },
+       { 6, 0x989c, { 0x00020800, 0x00020803, 0x00020803 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00000000, 0x00000000, 0x00000000 } },
+       { 6, 0x989c, { 0x00001660, 0x00001660, 0x00001660 } },
+       { 6, 0x989c, { 0x00001688, 0x00001688, 0x00001688 } },
+       { 6, 0x98c4, { 0x00000001, 0x00000001, 0x00000001 } },
+       { 7, 0x989c, { 0x00006400, 0x00006400, 0x00006400 } },
+       { 7, 0x989c, { 0x00000800, 0x00000800, 0x00000800 } },
+       { 7, 0x98cc, { 0x0000000e, 0x0000000e, 0x0000000e } },
 };
index 90757de7bf599e70291af0e226ae29d377b7c67e..929c68cdf8ab498dc1f35e7cb5b20b08be861e47 100644 (file)
@@ -95,7 +95,7 @@ static struct attribute_group ath5k_attribute_group_ani = {
 int
 ath5k_sysfs_register(struct ath5k_softc *sc)
 {
-       struct device *dev = &sc->pdev->dev;
+       struct device *dev = sc->dev;
        int err;
 
        err = sysfs_create_group(&dev->kobj, &ath5k_attribute_group_ani);
@@ -110,7 +110,7 @@ ath5k_sysfs_register(struct ath5k_softc *sc)
 void
 ath5k_sysfs_unregister(struct ath5k_softc *sc)
 {
-       struct device *dev = &sc->pdev->dev;
+       struct device *dev = sc->dev;
 
        sysfs_remove_group(&dev->kobj, &ath5k_attribute_group_ani);
 }
index 3161a5901a7a8d257412864fda3e35d11b454db4..73a8014cacb2e1d51c5dc63b99ed14be6901ca03 100644 (file)
 #define SUB_NUM_CTL_MODES_AT_5G_40 2    /* excluding HT40, EXT-OFDM */
 #define SUB_NUM_CTL_MODES_AT_2G_40 3    /* excluding HT40, EXT-OFDM, EXT-CCK */
 
+#define CTL(_tpower, _flag) ((_tpower) | ((_flag) << 6))
+
 static int ar9003_hw_power_interpolate(int32_t x,
                                       int32_t *px, int32_t *py, u_int16_t np);
+
+
 static const struct ar9300_eeprom ar9300_default = {
        .eepromVersion = 2,
        .templateVersion = 2,
@@ -296,21 +300,21 @@ static const struct ar9300_eeprom ar9300_default = {
                }
         },
        .ctlPowerData_2G = {
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-                { { {60, 1}, {60, 0}, {60, 0}, {60, 1} } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+                { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
 
-                { { {60, 1}, {60, 0}, {0, 0}, {0, 0} } },
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+                { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
 
-                { { {60, 0}, {60, 1}, {60, 1}, {60, 0} } },
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
 
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-                { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } },
-                { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
         },
        .modalHeader5G = {
                /* 4 idle,t1,t2,b (4 bits per setting) */
@@ -582,56 +586,56 @@ static const struct ar9300_eeprom ar9300_default = {
        .ctlPowerData_5G = {
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 0}, {60, 1}, {60, 0}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
+                               CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
                        }
                },
                {
                        {
-                               {60, 0}, {60, 1}, {60, 1}, {60, 0},
-                               {60, 1}, {60, 0}, {60, 0}, {60, 0},
+                               CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+                               CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
-                               {60, 0}, {60, 0}, {60, 0}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+                               CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 0}, {60, 0}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 0}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 0}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 0}, {60, 1},
+                               CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
                        }
                },
         }
@@ -873,21 +877,21 @@ static const struct ar9300_eeprom ar9300_x113 = {
                }
         },
        .ctlPowerData_2G = {
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-                { { {60, 1}, {60, 0}, {60, 0}, {60, 1} } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+                { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
 
-                { { {60, 1}, {60, 0}, {0, 0}, {0, 0} } },
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+                { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
 
-                { { {60, 0}, {60, 1}, {60, 1}, {60, 0} } },
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
 
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-                { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } },
-                { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
         },
        .modalHeader5G = {
                /* 4 idle,t1,t2,b (4 bits per setting) */
@@ -1159,56 +1163,56 @@ static const struct ar9300_eeprom ar9300_x113 = {
        .ctlPowerData_5G = {
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 0}, {60, 1}, {60, 0}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
+                               CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
                        }
                },
                {
                        {
-                               {60, 0}, {60, 1}, {60, 1}, {60, 0},
-                               {60, 1}, {60, 0}, {60, 0}, {60, 0},
+                               CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+                               CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
-                               {60, 0}, {60, 0}, {60, 0}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+                               CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 0}, {60, 0}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 0}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 0}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 0}, {60, 1},
+                               CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
                        }
                },
         }
@@ -1451,21 +1455,21 @@ static const struct ar9300_eeprom ar9300_h112 = {
                }
        },
        .ctlPowerData_2G = {
-               { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-               { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-               { { {60, 1}, {60, 0}, {60, 0}, {60, 1} } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+               { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
 
-               { { {60, 1}, {60, 0}, {0, 0}, {0, 0} } },
-               { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-               { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+               { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
 
-               { { {60, 0}, {60, 1}, {60, 1}, {60, 0} } },
-               { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-               { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
 
-               { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-               { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } },
-               { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
        },
        .modalHeader5G = {
                /* 4 idle,t1,t2,b (4 bits per setting) */
@@ -1737,56 +1741,56 @@ static const struct ar9300_eeprom ar9300_h112 = {
        .ctlPowerData_5G = {
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 0}, {60, 1}, {60, 0}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
+                               CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
                        }
                },
                {
                        {
-                               {60, 0}, {60, 1}, {60, 1}, {60, 0},
-                               {60, 1}, {60, 0}, {60, 0}, {60, 0},
+                               CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+                               CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
-                               {60, 0}, {60, 0}, {60, 0}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+                               CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 0}, {60, 0}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 0}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 0}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 0}, {60, 1},
+                               CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
                        }
                },
        }
@@ -2029,21 +2033,21 @@ static const struct ar9300_eeprom ar9300_x112 = {
                }
        },
        .ctlPowerData_2G = {
-               { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-               { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-               { { {60, 1}, {60, 0}, {60, 0}, {60, 1} } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+               { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
 
-               { { {60, 1}, {60, 0}, {0, 0}, {0, 0} } },
-               { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-               { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+               { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
 
-               { { {60, 0}, {60, 1}, {60, 1}, {60, 0} } },
-               { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-               { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
 
-               { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-               { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } },
-               { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+               { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
        },
        .modalHeader5G = {
                /* 4 idle,t1,t2,b (4 bits per setting) */
@@ -2315,56 +2319,56 @@ static const struct ar9300_eeprom ar9300_x112 = {
        .ctlPowerData_5G = {
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 0}, {60, 1}, {60, 0}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
+                               CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
                        }
                },
                {
                        {
-                               {60, 0}, {60, 1}, {60, 1}, {60, 0},
-                               {60, 1}, {60, 0}, {60, 0}, {60, 0},
+                               CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+                               CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
-                               {60, 0}, {60, 0}, {60, 0}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+                               CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 0}, {60, 0}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 0}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 0}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 0}, {60, 1},
+                               CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
                        }
                },
        }
@@ -2606,21 +2610,21 @@ static const struct ar9300_eeprom ar9300_h116 = {
                }
         },
        .ctlPowerData_2G = {
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-                { { {60, 1}, {60, 0}, {60, 0}, {60, 1} } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+                { { CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 1) } },
 
-                { { {60, 1}, {60, 0}, {0, 0}, {0, 0} } },
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+                { { CTL(60, 1), CTL(60, 0), CTL(0, 0), CTL(0, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
 
-                { { {60, 0}, {60, 1}, {60, 1}, {60, 0} } },
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
 
-                { { {60, 0}, {60, 1}, {60, 0}, {60, 0} } },
-                { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } },
-                { { {60, 0}, {60, 1}, {60, 1}, {60, 1} } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 0) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
+                { { CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 1) } },
         },
        .modalHeader5G = {
                /* 4 idle,t1,t2,b (4 bits per setting) */
@@ -2892,56 +2896,56 @@ static const struct ar9300_eeprom ar9300_h116 = {
        .ctlPowerData_5G = {
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 0}, {60, 1}, {60, 0}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
+                               CTL(60, 0), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
                        }
                },
                {
                        {
-                               {60, 0}, {60, 1}, {60, 1}, {60, 0},
-                               {60, 1}, {60, 0}, {60, 0}, {60, 0},
+                               CTL(60, 0), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+                               CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
-                               {60, 0}, {60, 0}, {60, 0}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
+                               CTL(60, 0), CTL(60, 0), CTL(60, 0), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 0}, {60, 0}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 0), CTL(60, 0), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 1},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 1),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 1}, {60, 0}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 1}, {60, 0},
+                               CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 1), CTL(60, 0),
                        }
                },
                {
                        {
-                               {60, 1}, {60, 0}, {60, 1}, {60, 1},
-                               {60, 1}, {60, 1}, {60, 0}, {60, 1},
+                               CTL(60, 1), CTL(60, 0), CTL(60, 1), CTL(60, 1),
+                               CTL(60, 1), CTL(60, 1), CTL(60, 0), CTL(60, 1),
                        }
                },
         }
@@ -3029,6 +3033,8 @@ static u32 ath9k_hw_ar9300_get_eeprom(struct ath_hw *ah,
                return le32_to_cpu(pBase->swreg);
        case EEP_PAPRD:
                return !!(pBase->featureEnable & BIT(5));
+       case EEP_CHAIN_MASK_REDUCE:
+               return (pBase->miscConfiguration >> 0x3) & 0x1;
        default:
                return 0;
        }
@@ -4363,9 +4369,9 @@ static u16 ar9003_hw_get_direct_edge_power(struct ar9300_eeprom *eep,
        struct cal_ctl_data_5g *ctl_5g = eep->ctlPowerData_5G;
 
        if (is2GHz)
-               return ctl_2g[idx].ctlEdges[edge].tPower;
+               return CTL_EDGE_TPOWER(ctl_2g[idx].ctlEdges[edge]);
        else
-               return ctl_5g[idx].ctlEdges[edge].tPower;
+               return CTL_EDGE_TPOWER(ctl_5g[idx].ctlEdges[edge]);
 }
 
 static u16 ar9003_hw_get_indirect_edge_power(struct ar9300_eeprom *eep,
@@ -4383,12 +4389,12 @@ static u16 ar9003_hw_get_indirect_edge_power(struct ar9300_eeprom *eep,
 
        if (is2GHz) {
                if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 1) < freq &&
-                   ctl_2g[idx].ctlEdges[edge - 1].flag)
-                       return ctl_2g[idx].ctlEdges[edge - 1].tPower;
+                   CTL_EDGE_FLAGS(ctl_2g[idx].ctlEdges[edge - 1]))
+                       return CTL_EDGE_TPOWER(ctl_2g[idx].ctlEdges[edge - 1]);
        } else {
                if (ath9k_hw_fbin2freq(ctl_freqbin[edge - 1], 0) < freq &&
-                   ctl_5g[idx].ctlEdges[edge - 1].flag)
-                       return ctl_5g[idx].ctlEdges[edge - 1].tPower;
+                   CTL_EDGE_FLAGS(ctl_5g[idx].ctlEdges[edge - 1]))
+                       return CTL_EDGE_TPOWER(ctl_5g[idx].ctlEdges[edge - 1]);
        }
 
        return AR9300_MAX_RATE_POWER;
index 57f64dbbcd8993eafc16e7dc732da9899cb5f1a1..9c1463307f0c94a4dffbd99f418eadcf859d71f1 100644 (file)
@@ -270,17 +270,12 @@ struct cal_tgt_pow_ht {
        u8 tPow2x[14];
 } __packed;
 
-struct cal_ctl_edge_pwr {
-       u8 tPower:6,
-          flag:2;
-} __packed;
-
 struct cal_ctl_data_2g {
-       struct cal_ctl_edge_pwr ctlEdges[AR9300_NUM_BAND_EDGES_2G];
+       u8 ctlEdges[AR9300_NUM_BAND_EDGES_2G];
 } __packed;
 
 struct cal_ctl_data_5g {
-       struct cal_ctl_edge_pwr ctlEdges[AR9300_NUM_BAND_EDGES_5G];
+       u8 ctlEdges[AR9300_NUM_BAND_EDGES_5G];
 } __packed;
 
 struct ar9300_BaseExtension_1 {
index 656d8ce251a7f243df8667f23775276648adfd83..b34a9e91edd80ff4616cb3f844f5c5341e09b1ef 100644 (file)
@@ -487,7 +487,11 @@ void ar9003_hw_set_chain_masks(struct ath_hw *ah, u8 rx, u8 tx)
                break;
        }
 
-       REG_WRITE(ah, AR_SELFGEN_MASK, tx);
+       if ((ah->caps.hw_caps & ATH9K_HW_CAP_APM) && (tx == 0x7))
+               REG_WRITE(ah, AR_SELFGEN_MASK, 0x3);
+       else
+               REG_WRITE(ah, AR_SELFGEN_MASK, tx);
+
        if (tx == 0x5) {
                REG_SET_BIT(ah, AR_PHY_ANALOG_SWAP,
                            AR_PHY_SWAP_ALT_CHAIN);
index 6f90acc5cca76296d7bcc7b7cb31797c7ffcfb59..4210a9306955f500674985357655c52ee7674637 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/device.h>
 #include <linux/leds.h>
 #include <linux/completion.h>
+#include <linux/pm_qos_params.h>
 
 #include "debug.h"
 #include "common.h"
@@ -544,6 +545,7 @@ struct ath_ant_comb {
 #define SC_OP_BT_PRIORITY_DETECTED   BIT(12)
 #define SC_OP_BT_SCAN               BIT(13)
 #define SC_OP_ANI_RUN               BIT(14)
+#define SC_OP_ENABLE_APM            BIT(15)
 
 /* Powersave flags */
 #define PS_WAIT_FOR_BEACON        BIT(0)
@@ -628,6 +630,8 @@ struct ath_softc {
        struct ath_descdma txsdma;
 
        struct ath_ant_comb ant_comb;
+
+       struct pm_qos_request_list pm_qos_req;
 };
 
 struct ath_wiphy {
@@ -657,7 +661,6 @@ static inline void ath_read_cachesize(struct ath_common *common, int *csz)
 }
 
 extern struct ieee80211_ops ath9k_ops;
-extern struct pm_qos_request_list ath9k_pm_qos_req;
 extern int modparam_nohwcrypt;
 extern int led_blink;
 
@@ -695,6 +698,8 @@ static inline void ath_ahb_exit(void) {};
 void ath9k_ps_wakeup(struct ath_softc *sc);
 void ath9k_ps_restore(struct ath_softc *sc);
 
+u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate);
+
 void ath9k_set_bssid_mask(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
 int ath9k_wiphy_add(struct ath_softc *sc);
 int ath9k_wiphy_del(struct ath_wiphy *aphy);
index 30724a4e8bb2ed34b8a96db84c02493a0d911e1d..47bedd82e9a90b7c050fbcfe9d6347f83f7c2726 100644 (file)
@@ -103,7 +103,8 @@ static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
        memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
        series[0].Tries = 1;
        series[0].Rate = rate;
-       series[0].ChSel = common->tx_chainmask;
+       series[0].ChSel = ath_txchainmask_reduction(sc,
+                       common->tx_chainmask, series[0].Rate);
        series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0;
        ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration,
                                     series, 4, 0);
index 6a92e57fddf0dc2c8127ef544dcdfd36d4d41d38..d33bf204c995e743f1650e053a7030fbcc110721 100644 (file)
@@ -35,29 +35,6 @@ struct ath_btcoex_config {
        bool bt_hold_rx_clear;
 };
 
-static const u16 ath_subsysid_tbl[] = {
-       AR9280_COEX2WIRE_SUBSYSID,
-       AT9285_COEX3WIRE_SA_SUBSYSID,
-       AT9285_COEX3WIRE_DA_SUBSYSID
-};
-
-/*
- * Checks the subsystem id of the device to see if it
- * supports btcoex
- */
-bool ath9k_hw_btcoex_supported(struct ath_hw *ah)
-{
-       int i;
-
-       if (!ah->hw_version.subsysid)
-               return false;
-
-       for (i = 0; i < ARRAY_SIZE(ath_subsysid_tbl); i++)
-               if (ah->hw_version.subsysid == ath_subsysid_tbl[i])
-                       return true;
-
-       return false;
-}
 
 void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
 {
index 1ee5a15ccbb1a8c714692e52ddd81542e0b84411..588dfd464dd19938a59a3517729c1ed4330a6506 100644 (file)
@@ -49,7 +49,6 @@ struct ath_btcoex_hw {
        u32 bt_coex_mode2;      /* Register setting for AR_BT_COEX_MODE2 */
 };
 
-bool ath9k_hw_btcoex_supported(struct ath_hw *ah);
 void ath9k_hw_btcoex_init_2wire(struct ath_hw *ah);
 void ath9k_hw_btcoex_init_3wire(struct ath_hw *ah);
 void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum);
index 0c3c74c157fb036123322ae7176f51543ae3f999..3586c43077a72801a342480c8a93447d5f92f268 100644 (file)
@@ -24,8 +24,6 @@
 #define REG_READ_D(_ah, _reg) \
        ath9k_hw_common(_ah)->ops->read((_ah), (_reg))
 
-static struct dentry *ath9k_debugfs_root;
-
 static int ath9k_debugfs_open(struct inode *inode, struct file *file)
 {
        file->private_data = inode->i_private;
@@ -878,11 +876,8 @@ int ath9k_init_debug(struct ath_hw *ah)
        struct ath_common *common = ath9k_hw_common(ah);
        struct ath_softc *sc = (struct ath_softc *) common->priv;
 
-       if (!ath9k_debugfs_root)
-               return -ENOENT;
-
-       sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
-                                                     ath9k_debugfs_root);
+       sc->debug.debugfs_phy = debugfs_create_dir("ath9k",
+                                                  sc->hw->wiphy->debugfsdir);
        if (!sc->debug.debugfs_phy)
                return -ENOMEM;
 
@@ -935,29 +930,7 @@ int ath9k_init_debug(struct ath_hw *ah)
        sc->debug.regidx = 0;
        return 0;
 err:
-       ath9k_exit_debug(ah);
-       return -ENOMEM;
-}
-
-void ath9k_exit_debug(struct ath_hw *ah)
-{
-       struct ath_common *common = ath9k_hw_common(ah);
-       struct ath_softc *sc = (struct ath_softc *) common->priv;
-
        debugfs_remove_recursive(sc->debug.debugfs_phy);
-}
-
-int ath9k_debug_create_root(void)
-{
-       ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
-       if (!ath9k_debugfs_root)
-               return -ENOENT;
-
-       return 0;
-}
-
-void ath9k_debug_remove_root(void)
-{
-       debugfs_remove(ath9k_debugfs_root);
-       ath9k_debugfs_root = NULL;
+       sc->debug.debugfs_phy = NULL;
+       return -ENOMEM;
 }
index 646ff7e04c88d983ec3504a2befdc8d343f249f1..1e5078bd03444481b1e64794d9d7944398b91d80 100644 (file)
@@ -164,10 +164,7 @@ struct ath9k_debug {
 };
 
 int ath9k_init_debug(struct ath_hw *ah);
-void ath9k_exit_debug(struct ath_hw *ah);
 
-int ath9k_debug_create_root(void);
-void ath9k_debug_remove_root(void);
 void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
 void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
                       struct ath_tx_status *ts);
@@ -180,19 +177,6 @@ static inline int ath9k_init_debug(struct ath_hw *ah)
        return 0;
 }
 
-static inline void ath9k_exit_debug(struct ath_hw *ah)
-{
-}
-
-static inline int ath9k_debug_create_root(void)
-{
-       return 0;
-}
-
-static inline void ath9k_debug_remove_root(void)
-{
-}
-
 static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
                                            enum ath9k_int status)
 {
index 1266333f586d8f574cf8fcda7086f036f3d56403..2bbf94d0191edb0ddc84084a37b07172203f2485 100644 (file)
@@ -240,16 +240,16 @@ u16 ath9k_hw_get_max_edge_power(u16 freq, struct cal_ctl_edges *pRdEdgesPower,
        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;
+                       twiceMaxEdgePower = CTL_EDGE_TPOWER(pRdEdgesPower[i].ctl);
                        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) {
+                           CTL_EDGE_FLAGS(pRdEdgesPower[i - 1].ctl)) {
                                twiceMaxEdgePower =
-                                       pRdEdgesPower[i - 1].tPower;
+                                       CTL_EDGE_TPOWER(pRdEdgesPower[i - 1].ctl);
                        }
                        break;
                }
index 3c99830dab0c2b385725075e5d36afa05d7d44b6..8b9885b5243f059a6f7e4a6e6ab2ebfdcf534412 100644 (file)
 
 #define AR9287_CHECKSUM_LOCATION (AR9287_EEP_START_LOC + 1)
 
+#define CTL_EDGE_TPOWER(_ctl) ((_ctl) & 0x3f)
+#define CTL_EDGE_FLAGS(_ctl) (((_ctl) >> 6) & 0x03)
+
+#define LNA_CTL_BUF_MODE       BIT(0)
+#define LNA_CTL_ISEL_LO                BIT(1)
+#define LNA_CTL_ISEL_HI                BIT(2)
+#define LNA_CTL_BUF_IN         BIT(3)
+#define LNA_CTL_FEM_BAND       BIT(4)
+#define LNA_CTL_LOCAL_BIAS     BIT(5)
+#define LNA_CTL_FORCE_XPA      BIT(6)
+#define LNA_CTL_USE_ANT1       BIT(7)
+
 enum eeprom_param {
        EEP_NFTHRESH_5,
        EEP_NFTHRESH_2,
@@ -268,6 +280,7 @@ enum eeprom_param {
        EEP_PAPRD,
        EEP_MODAL_VER,
        EEP_ANT_DIV_CTL1,
+       EEP_CHAIN_MASK_REDUCE
 };
 
 enum ar5416_rates {
@@ -378,10 +391,7 @@ struct modal_eep_header {
        u8 xatten2Margin[AR5416_MAX_CHAINS];
        u8 ob_ch1;
        u8 db_ch1;
-       u8 useAnt1:1,
-           force_xpaon:1,
-           local_bias:1,
-           femBandSelectUsed:1, xlnabufin:1, xlnaisel:2, xlnabufmode:1;
+       u8 lna_ctl;
        u8 miscBits;
        u16 xpaBiasLvlFreq[3];
        u8 futureModal[6];
@@ -535,18 +545,10 @@ struct cal_target_power_ht {
        u8 tPow2x[8];
 } __packed;
 
-
-#ifdef __BIG_ENDIAN_BITFIELD
-struct cal_ctl_edges {
-       u8 bChannel;
-       u8 flag:2, tPower:6;
-} __packed;
-#else
 struct cal_ctl_edges {
        u8 bChannel;
-       u8 tPower:6, flag:2;
+       u8 ctl;
 } __packed;
-#endif
 
 struct cal_data_op_loop_ar9287 {
        u8 pwrPdg[2][5];
index e94216e1e107684b3cee23320b401dedff60c732..45f70b2404a19c48af7604bc02f1d61a8b27c5d3 100644 (file)
@@ -451,9 +451,10 @@ static void ath9k_hw_def_set_board_values(struct ath_hw *ah,
                ath9k_hw_analog_shift_rmw(ah, AR_AN_TOP2,
                                          AR_AN_TOP2_LOCALBIAS,
                                          AR_AN_TOP2_LOCALBIAS_S,
-                                         pModal->local_bias);
+                                         !!(pModal->lna_ctl &
+                                            LNA_CTL_LOCAL_BIAS));
                REG_RMW_FIELD(ah, AR_PHY_XPA_CFG, AR_PHY_FORCE_XPA_CFG,
-                             pModal->force_xpaon);
+                             !!(pModal->lna_ctl & LNA_CTL_FORCE_XPA));
        }
 
        REG_RMW_FIELD(ah, AR_PHY_SETTLING, AR_PHY_SETTLING_SWITCH,
@@ -1435,9 +1436,9 @@ static u8 ath9k_hw_def_get_num_ant_config(struct ath_hw *ah,
 
        num_ant_config = 1;
 
-       if (pBase->version >= 0x0E0D)
-               if (pModal->useAnt1)
-                       num_ant_config += 1;
+       if (pBase->version >= 0x0E0D &&
+           (pModal->lna_ctl & LNA_CTL_USE_ANT1))
+               num_ant_config += 1;
 
        return num_ant_config;
 }
index ae842dbf9b5087a5ea456a2f241eb9ff806fe061..8946e8ad1b85e9a238c562e5aae6b0803573cf77 100644 (file)
@@ -363,9 +363,9 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
                                    struct sk_buff *skb)
 {
        struct sk_buff *nskb, *skb_pool[MAX_PKT_NUM_IN_TRANSFER];
-       int index = 0, i = 0, chk_idx, len = skb->len;
-       int rx_remain_len = 0, rx_pkt_len = 0;
-       u16 pkt_len, pkt_tag, pool_index = 0;
+       int index = 0, i = 0, len = skb->len;
+       int rx_remain_len, rx_pkt_len;
+       u16 pool_index = 0;
        u8 *ptr;
 
        spin_lock(&hif_dev->rx_lock);
@@ -399,64 +399,64 @@ static void ath9k_hif_usb_rx_stream(struct hif_device_usb *hif_dev,
        spin_unlock(&hif_dev->rx_lock);
 
        while (index < len) {
+               u16 pkt_len;
+               u16 pkt_tag;
+               u16 pad_len;
+               int chk_idx;
+
                ptr = (u8 *) skb->data;
 
                pkt_len = ptr[index] + (ptr[index+1] << 8);
                pkt_tag = ptr[index+2] + (ptr[index+3] << 8);
 
-               if (pkt_tag == ATH_USB_RX_STREAM_MODE_TAG) {
-                       u16 pad_len;
-
-                       pad_len = 4 - (pkt_len & 0x3);
-                       if (pad_len == 4)
-                               pad_len = 0;
-
-                       chk_idx = index;
-                       index = index + 4 + pkt_len + pad_len;
-
-                       if (index > MAX_RX_BUF_SIZE) {
-                               spin_lock(&hif_dev->rx_lock);
-                               hif_dev->rx_remain_len = index - MAX_RX_BUF_SIZE;
-                               hif_dev->rx_transfer_len =
-                                       MAX_RX_BUF_SIZE - chk_idx - 4;
-                               hif_dev->rx_pad_len = pad_len;
-
-                               nskb = __dev_alloc_skb(pkt_len + 32,
-                                                      GFP_ATOMIC);
-                               if (!nskb) {
-                                       dev_err(&hif_dev->udev->dev,
-                                       "ath9k_htc: RX memory allocation"
-                                       " error\n");
-                                       spin_unlock(&hif_dev->rx_lock);
-                                       goto err;
-                               }
-                               skb_reserve(nskb, 32);
-                               RX_STAT_INC(skb_allocated);
-
-                               memcpy(nskb->data, &(skb->data[chk_idx+4]),
-                                      hif_dev->rx_transfer_len);
-
-                               /* Record the buffer pointer */
-                               hif_dev->remain_skb = nskb;
+               if (pkt_tag != ATH_USB_RX_STREAM_MODE_TAG) {
+                       RX_STAT_INC(skb_dropped);
+                       return;
+               }
+
+               pad_len = 4 - (pkt_len & 0x3);
+               if (pad_len == 4)
+                       pad_len = 0;
+
+               chk_idx = index;
+               index = index + 4 + pkt_len + pad_len;
+
+               if (index > MAX_RX_BUF_SIZE) {
+                       spin_lock(&hif_dev->rx_lock);
+                       hif_dev->rx_remain_len = index - MAX_RX_BUF_SIZE;
+                       hif_dev->rx_transfer_len =
+                               MAX_RX_BUF_SIZE - chk_idx - 4;
+                       hif_dev->rx_pad_len = pad_len;
+
+                       nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC);
+                       if (!nskb) {
+                               dev_err(&hif_dev->udev->dev,
+                                       "ath9k_htc: RX memory allocation error\n");
                                spin_unlock(&hif_dev->rx_lock);
-                       } else {
-                               nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC);
-                               if (!nskb) {
-                                       dev_err(&hif_dev->udev->dev,
-                                       "ath9k_htc: RX memory allocation"
-                                       " error\n");
-                                       goto err;
-                               }
-                               skb_reserve(nskb, 32);
-                               RX_STAT_INC(skb_allocated);
-
-                               memcpy(nskb->data, &(skb->data[chk_idx+4]), pkt_len);
-                               skb_put(nskb, pkt_len);
-                               skb_pool[pool_index++] = nskb;
+                               goto err;
                        }
+                       skb_reserve(nskb, 32);
+                       RX_STAT_INC(skb_allocated);
+
+                       memcpy(nskb->data, &(skb->data[chk_idx+4]),
+                              hif_dev->rx_transfer_len);
+
+                       /* Record the buffer pointer */
+                       hif_dev->remain_skb = nskb;
+                       spin_unlock(&hif_dev->rx_lock);
                } else {
-                       RX_STAT_INC(skb_dropped);
-                       return;
+                       nskb = __dev_alloc_skb(pkt_len + 32, GFP_ATOMIC);
+                       if (!nskb) {
+                               dev_err(&hif_dev->udev->dev,
+                                       "ath9k_htc: RX memory allocation error\n");
+                               goto err;
+                       }
+                       skb_reserve(nskb, 32);
+                       RX_STAT_INC(skb_allocated);
+
+                       memcpy(nskb->data, &(skb->data[chk_idx+4]), pkt_len);
+                       skb_put(nskb, pkt_len);
+                       skb_pool[pool_index++] = nskb;
                }
        }
 
@@ -471,7 +471,7 @@ err:
 static void ath9k_hif_usb_rx_cb(struct urb *urb)
 {
        struct sk_buff *skb = (struct sk_buff *) urb->context;
-       struct hif_device_usb *hif_dev = (struct hif_device_usb *)
+       struct hif_device_usb *hif_dev =
                usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
        int ret;
 
@@ -518,7 +518,7 @@ static void ath9k_hif_usb_reg_in_cb(struct urb *urb)
 {
        struct sk_buff *skb = (struct sk_buff *) urb->context;
        struct sk_buff *nskb;
-       struct hif_device_usb *hif_dev = (struct hif_device_usb *)
+       struct hif_device_usb *hif_dev =
                usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
        int ret;
 
@@ -993,8 +993,7 @@ static void ath9k_hif_usb_reboot(struct usb_device *udev)
 static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
 {
        struct usb_device *udev = interface_to_usbdev(interface);
-       struct hif_device_usb *hif_dev =
-               (struct hif_device_usb *) usb_get_intfdata(interface);
+       struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
 
        if (hif_dev) {
                ath9k_htc_hw_deinit(hif_dev->htc_handle,
@@ -1016,8 +1015,7 @@ static void ath9k_hif_usb_disconnect(struct usb_interface *interface)
 static int ath9k_hif_usb_suspend(struct usb_interface *interface,
                                 pm_message_t message)
 {
-       struct hif_device_usb *hif_dev =
-               (struct hif_device_usb *) usb_get_intfdata(interface);
+       struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
 
        ath9k_hif_usb_dealloc_urbs(hif_dev);
 
@@ -1026,8 +1024,7 @@ static int ath9k_hif_usb_suspend(struct usb_interface *interface,
 
 static int ath9k_hif_usb_resume(struct usb_interface *interface)
 {
-       struct hif_device_usb *hif_dev =
-               (struct hif_device_usb *) usb_get_intfdata(interface);
+       struct hif_device_usb *hif_dev = usb_get_intfdata(interface);
        struct htc_target *htc_handle = hif_dev->htc_handle;
        int ret;
 
index e9761c2c870073a4fa08e6a7b276bc8f95136c40..8266ce1f02e324a7f1d511b51d6a916d9977d538 100644 (file)
@@ -184,6 +184,47 @@ err:
        return ret;
 }
 
+static int ath9k_htc_add_monitor_interface(struct ath9k_htc_priv *priv)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ath9k_htc_target_vif hvif;
+       int ret = 0;
+       u8 cmd_rsp;
+
+       if (priv->nvifs > 0)
+               return -ENOBUFS;
+
+       memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
+       memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
+
+       hvif.opmode = cpu_to_be32(HTC_M_MONITOR);
+       priv->ah->opmode = NL80211_IFTYPE_MONITOR;
+       hvif.index = priv->nvifs;
+
+       WMI_CMD_BUF(WMI_VAP_CREATE_CMDID, &hvif);
+       if (ret)
+               return ret;
+
+       priv->nvifs++;
+       return 0;
+}
+
+static int ath9k_htc_remove_monitor_interface(struct ath9k_htc_priv *priv)
+{
+       struct ath_common *common = ath9k_hw_common(priv->ah);
+       struct ath9k_htc_target_vif hvif;
+       int ret = 0;
+       u8 cmd_rsp;
+
+       memset(&hvif, 0, sizeof(struct ath9k_htc_target_vif));
+       memcpy(&hvif.myaddr, common->macaddr, ETH_ALEN);
+       hvif.index = 0; /* Should do for now */
+       WMI_CMD_BUF(WMI_VAP_REMOVE_CMDID, &hvif);
+       priv->nvifs--;
+
+       return ret;
+}
+
 static int ath9k_htc_add_station(struct ath9k_htc_priv *priv,
                                 struct ieee80211_vif *vif,
                                 struct ieee80211_sta *sta)
@@ -1199,6 +1240,16 @@ static void ath9k_htc_stop(struct ieee80211_hw *hw)
        WMI_CMD(WMI_STOP_RECV_CMDID);
        skb_queue_purge(&priv->tx_queue);
 
+       /* Remove monitor interface here */
+       if (ah->opmode == NL80211_IFTYPE_MONITOR) {
+               if (ath9k_htc_remove_monitor_interface(priv))
+                       ath_print(common, ATH_DBG_FATAL,
+                                 "Unable to remove monitor interface\n");
+               else
+                       ath_print(common, ATH_DBG_CONFIG,
+                                 "Monitor interface removed\n");
+       }
+
        if (ah->btcoex_hw.enabled) {
                ath9k_hw_btcoex_disable(ah);
                if (ah->btcoex_hw.scheme == ATH_BTCOEX_CFG_3WIRE)
@@ -1372,13 +1423,16 @@ static int ath9k_htc_config(struct ieee80211_hw *hw, u32 changed)
                }
        }
 
-       if (changed & IEEE80211_CONF_CHANGE_MONITOR)
+       if (changed & IEEE80211_CONF_CHANGE_MONITOR) {
                if (conf->flags & IEEE80211_CONF_MONITOR) {
-                       ath_print(common, ATH_DBG_CONFIG,
-                                 "HW opmode set to Monitor mode\n");
-                       priv->ah->opmode = NL80211_IFTYPE_MONITOR;
+                       if (ath9k_htc_add_monitor_interface(priv))
+                               ath_print(common, ATH_DBG_FATAL,
+                                         "Failed to set monitor mode\n");
+                       else
+                               ath_print(common, ATH_DBG_CONFIG,
+                                         "HW opmode set to Monitor mode\n");
                }
-
+       }
 
        if (changed & IEEE80211_CONF_CHANGE_IDLE) {
                mutex_lock(&priv->htc_pm_lock);
index 6fc1b21faa5db1f3c02fc5a71a6eeec99ce13d4e..ecd018798c4721d6d62c8802b53c87d28673a66d 100644 (file)
@@ -77,20 +77,6 @@ struct htc_config_pipe_msg {
        u8 credits;
 } __packed;
 
-struct htc_packet {
-       void *pktcontext;
-       u8 *buf;
-       u8 *buf_payload;
-       u32 buflen;
-       u32 payload_len;
-
-       int endpoint;
-       int status;
-
-       void *context;
-       u32 reserved;
-};
-
 struct htc_ep_callbacks {
        void *priv;
        void (*tx) (void *, struct sk_buff *, enum htc_endpoint_id, bool txok);
@@ -123,11 +109,6 @@ struct htc_endpoint {
 #define HTC_CONTROL_BUFFER_SIZE        \
        (HTC_MAX_CONTROL_MESSAGE_LENGTH + sizeof(struct htc_frame_hdr))
 
-struct htc_control_buf {
-       struct htc_packet htc_pkt;
-       u8 buf[HTC_CONTROL_BUFFER_SIZE];
-};
-
 #define HTC_OP_START_WAIT           BIT(0)
 #define HTC_OP_CONFIG_PIPE_CREDITS  BIT(1)
 
index ce9e59f4cd3dbf9cae16e2086bc419a1a150da47..9b1ee7fc05c1ae88037366d1ede69e0bec5793b4 100644 (file)
@@ -1925,8 +1925,7 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
        pCap->num_antcfg_2ghz =
                ah->eep_ops->get_num_ant_config(ah, ATH9K_HAL_FREQ_BAND_2GHZ);
 
-       if (AR_SREV_9280_20_OR_LATER(ah) &&
-           ath9k_hw_btcoex_supported(ah)) {
+       if (AR_SREV_9280_20_OR_LATER(ah) && common->btcoex_enabled) {
                btcoex_hw->btactive_gpio = ATH_BTACTIVE_GPIO;
                btcoex_hw->wlanactive_gpio = ATH_WLANACTIVE_GPIO;
 
@@ -1975,6 +1974,12 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                        if ((ant_div_ctl1 & 0x1) && ((ant_div_ctl1 >> 3) & 0x1))
                                pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
                }
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
+               if (ah->eep_ops->get_eeprom(ah, EEP_CHAIN_MASK_REDUCE))
+                       pCap->hw_caps |= ATH9K_HW_CAP_APM;
+       }
+
+
 
        return 0;
 }
@@ -2046,7 +2051,8 @@ u32 ath9k_hw_gpio_get(struct ath_hw *ah, u32 gpio)
                val = REG_READ(ah, AR7010_GPIO_IN);
                return (MS(val, AR7010_GPIO_IN_VAL) & AR_GPIO_BIT(gpio)) == 0;
        } else if (AR_SREV_9300_20_OR_LATER(ah))
-               return MS_REG_READ(AR9300, gpio) != 0;
+               return (MS(REG_READ(ah, AR_GPIO_IN), AR9300_GPIO_IN_VAL) &
+                       AR_GPIO_BIT(gpio)) != 0;
        else if (AR_SREV_9271(ah))
                return MS_REG_READ(AR9271, gpio) != 0;
        else if (AR_SREV_9287_11_OR_LATER(ah))
index cc8f3b9af71f7152b31634b942ef5d6c50f68187..5fcfa48a45df9132c4f0df65ab11441a1cd23432 100644 (file)
@@ -187,6 +187,7 @@ enum ath9k_hw_caps {
        ATH9K_HW_CAP_ANT_DIV_COMB               = BIT(12),
        ATH9K_HW_CAP_2GHZ                       = BIT(13),
        ATH9K_HW_CAP_5GHZ                       = BIT(14),
+       ATH9K_HW_CAP_APM                        = BIT(15),
 };
 
 struct ath9k_hw_capabilities {
index 7eef1faee668787fed775db0a1f751c24c44597f..918308a2841055010f0263a53513cfb8a95db2b4 100644 (file)
@@ -15,7 +15,6 @@
  */
 
 #include <linux/slab.h>
-#include <linux/pm_qos_params.h>
 
 #include "ath9k.h"
 
@@ -38,6 +37,10 @@ int led_blink;
 module_param_named(blink, led_blink, int, 0444);
 MODULE_PARM_DESC(blink, "Enable LED blink on activity");
 
+static int ath9k_btcoex_enable;
+module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444);
+MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence");
+
 /* We use the hw_value as an index into our private channel structure */
 
 #define CHAN2G(_freq, _idx)  { \
@@ -180,8 +183,6 @@ static const struct ath_ops ath9k_common_ops = {
        .write = ath9k_iowrite32,
 };
 
-struct pm_qos_request_list ath9k_pm_qos_req;
-
 /**************************/
 /*     Initialization     */
 /**************************/
@@ -543,6 +544,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
        common->hw = sc->hw;
        common->priv = sc;
        common->debug_mask = ath9k_debug;
+       common->btcoex_enabled = ath9k_btcoex_enable == 1;
        spin_lock_init(&common->cc_lock);
 
        spin_lock_init(&sc->wiphy_lock);
@@ -565,13 +567,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
        if (ret)
                goto err_hw;
 
-       ret = ath9k_init_debug(ah);
-       if (ret) {
-               ath_print(common, ATH_DBG_FATAL,
-                         "Unable to create debugfs files\n");
-               goto err_debug;
-       }
-
        ret = ath9k_init_queues(sc);
        if (ret)
                goto err_queues;
@@ -594,8 +589,6 @@ err_btcoex:
                if (ATH_TXQ_SETUP(sc, i))
                        ath_tx_cleanupq(sc, &sc->tx.txq[i]);
 err_queues:
-       ath9k_exit_debug(ah);
-err_debug:
        ath9k_hw_deinit(ah);
 err_hw:
        tasklet_kill(&sc->intr_tq);
@@ -657,6 +650,8 @@ void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
                hw->flags |= IEEE80211_HW_MFP_CAPABLE;
 
        hw->wiphy->interface_modes =
+               BIT(NL80211_IFTYPE_P2P_GO) |
+               BIT(NL80211_IFTYPE_P2P_CLIENT) |
                BIT(NL80211_IFTYPE_AP) |
                BIT(NL80211_IFTYPE_WDS) |
                BIT(NL80211_IFTYPE_STATION) |
@@ -739,6 +734,13 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
        if (error)
                goto error_register;
 
+       error = ath9k_init_debug(ah);
+       if (error) {
+               ath_print(common, ATH_DBG_FATAL,
+                         "Unable to create debugfs files\n");
+               goto error_world;
+       }
+
        /* Handle world regulatory */
        if (!ath_is_world_regd(reg)) {
                error = regulatory_hint(hw->wiphy, reg->alpha2);
@@ -756,7 +758,7 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
        ath_init_leds(sc);
        ath_start_rfkill_poll(sc);
 
-       pm_qos_add_request(&ath9k_pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
+       pm_qos_add_request(&sc->pm_qos_req, PM_QOS_CPU_DMA_LATENCY,
                           PM_QOS_DEFAULT_VALUE);
 
        return 0;
@@ -797,7 +799,6 @@ static void ath9k_deinit_softc(struct ath_softc *sc)
                if (ATH_TXQ_SETUP(sc, i))
                        ath_tx_cleanupq(sc, &sc->tx.txq[i]);
 
-       ath9k_exit_debug(sc->sc_ah);
        ath9k_hw_deinit(sc->sc_ah);
 
        tasklet_kill(&sc->intr_tq);
@@ -827,7 +828,7 @@ void ath9k_deinit_device(struct ath_softc *sc)
        }
 
        ieee80211_unregister_hw(hw);
-       pm_qos_remove_request(&ath9k_pm_qos_req);
+       pm_qos_remove_request(&sc->pm_qos_req);
        ath_rx_cleanup(sc);
        ath_tx_cleanup(sc);
        ath9k_deinit_softc(sc);
@@ -864,20 +865,12 @@ static int __init ath9k_init(void)
                goto err_out;
        }
 
-       error = ath9k_debug_create_root();
-       if (error) {
-               printk(KERN_ERR
-                       "ath9k: Unable to create debugfs root: %d\n",
-                       error);
-               goto err_rate_unregister;
-       }
-
        error = ath_pci_init();
        if (error < 0) {
                printk(KERN_ERR
                        "ath9k: No PCI devices found, driver not installed.\n");
                error = -ENODEV;
-               goto err_remove_root;
+               goto err_rate_unregister;
        }
 
        error = ath_ahb_init();
@@ -891,8 +884,6 @@ static int __init ath9k_init(void)
  err_pci_exit:
        ath_pci_exit();
 
- err_remove_root:
-       ath9k_debug_remove_root();
  err_rate_unregister:
        ath_rate_control_unregister();
  err_out:
@@ -904,7 +895,6 @@ static void __exit ath9k_exit(void)
 {
        ath_ahb_exit();
        ath_pci_exit();
-       ath9k_debug_remove_root();
        ath_rate_control_unregister();
        printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
 }
index 50bdb5db23b4e1292fe20d55072353105a72fcda..f026a031713b8e03b979bf95b724b965f3b97e8f 100644 (file)
@@ -15,7 +15,6 @@
  */
 
 #include <linux/nl80211.h>
-#include <linux/pm_qos_params.h>
 #include "ath9k.h"
 #include "btcoex.h"
 
@@ -554,9 +553,12 @@ void ath_update_chainmask(struct ath_softc *sc, int is_ht)
 static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta)
 {
        struct ath_node *an;
-
+       struct ath_hw *ah = sc->sc_ah;
        an = (struct ath_node *)sta->drv_priv;
 
+       if ((ah->caps.hw_caps) & ATH9K_HW_CAP_APM)
+               sc->sc_flags |= SC_OP_ENABLE_APM;
+
        if (sc->sc_flags & SC_OP_TXAGGR) {
                ath_tx_node_init(sc, an);
                an->maxampdu = 1 << (IEEE80211_HT_MAX_AMPDU_FACTOR +
@@ -1184,7 +1186,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
                        ath9k_btcoex_timer_resume(sc);
        }
 
-       pm_qos_update_request(&ath9k_pm_qos_req, 55);
+       pm_qos_update_request(&sc->pm_qos_req, 55);
 
 mutex_unlock:
        mutex_unlock(&sc->mutex);
@@ -1339,7 +1341,7 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
        sc->sc_flags |= SC_OP_INVALID;
 
-       pm_qos_update_request(&ath9k_pm_qos_req, PM_QOS_DEFAULT_VALUE);
+       pm_qos_update_request(&sc->pm_qos_req, PM_QOS_DEFAULT_VALUE);
 
        mutex_unlock(&sc->mutex);
 
@@ -1436,6 +1438,7 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
        struct ath_softc *sc = aphy->sc;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_vif *avp = (void *)vif->drv_priv;
+       bool bs_valid = false;
        int i;
 
        ath_print(common, ATH_DBG_CONFIG, "Detach Interface\n");
@@ -1464,7 +1467,15 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
                               "slot\n", __func__);
                        sc->beacon.bslot[i] = NULL;
                        sc->beacon.bslot_aphy[i] = NULL;
-               }
+               } else if (sc->beacon.bslot[i])
+                       bs_valid = true;
+       }
+       if (!bs_valid && (sc->sc_ah->imask & ATH9K_INT_SWBA)) {
+               /* Disable SWBA interrupt */
+               sc->sc_ah->imask &= ~ATH9K_INT_SWBA;
+               ath9k_ps_wakeup(sc);
+               ath9k_hw_set_interrupts(sc->sc_ah, sc->sc_ah->imask);
+               ath9k_ps_restore(sc);
        }
 
        sc->nvifs--;
index a597cc8d864472139403516e93f21ed18c7ee442..c2472edab5e0b448930c1c5a56d213598d8a9dd0 100644 (file)
@@ -976,11 +976,13 @@ enum {
 #define AR9287_GPIO_IN_VAL_S                     11
 #define AR9271_GPIO_IN_VAL                       0xFFFF0000
 #define AR9271_GPIO_IN_VAL_S                     16
-#define AR9300_GPIO_IN_VAL                       0x0001FFFF
-#define AR9300_GPIO_IN_VAL_S                     0
 #define AR7010_GPIO_IN_VAL                       0x0000FFFF
 #define AR7010_GPIO_IN_VAL_S                     0
 
+#define AR_GPIO_IN                              0x404c
+#define AR9300_GPIO_IN_VAL                       0x0001FFFF
+#define AR9300_GPIO_IN_VAL_S                     0
+
 #define AR_GPIO_OE_OUT                           (AR_SREV_9300_20_OR_LATER(ah) ? 0x4050 : 0x404c)
 #define AR_GPIO_OE_OUT_DRV                       0x3
 #define AR_GPIO_OE_OUT_DRV_NO                    0x0
index 495432ec85a99d65cfc710737bbbf6fdb7878281..821d3679c6ffe6d6d1a7133b67b57c530c80a095 100644 (file)
@@ -250,11 +250,11 @@ static void ath_tid_drain(struct ath_softc *sc, struct ath_txq *txq,
 static void ath_tx_set_retry(struct ath_softc *sc, struct ath_txq *txq,
                             struct sk_buff *skb)
 {
-       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ath_frame_info *fi = get_frame_info(skb);
        struct ieee80211_hdr *hdr;
 
        TX_STAT_INC(txq->axq_qnum, a_retries);
-       if (tx_info->control.rates[4].count++ > 0)
+       if (fi->retries++ > 0)
                return;
 
        hdr = (struct ieee80211_hdr *)skb->data;
@@ -1506,6 +1506,18 @@ static u32 ath_pkt_duration(struct ath_softc *sc, u8 rix, int pktlen,
        return duration;
 }
 
+u8 ath_txchainmask_reduction(struct ath_softc *sc, u8 chainmask, u32 rate)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath9k_channel *curchan = ah->curchan;
+       if ((sc->sc_flags & SC_OP_ENABLE_APM) &&
+                       (curchan->channelFlags & CHANNEL_5GHZ) &&
+                       (chainmask == 0x7) && (rate < 0x90))
+               return 0x3;
+       else
+               return chainmask;
+}
+
 static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
@@ -1546,7 +1558,6 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
 
                rix = rates[i].idx;
                series[i].Tries = rates[i].count;
-               series[i].ChSel = common->tx_chainmask;
 
                if ((sc->config.ath_aggr_prot && bf_isaggr(bf)) ||
                    (rates[i].flags & IEEE80211_TX_RC_USE_RTS_CTS)) {
@@ -1569,6 +1580,8 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
                if (rates[i].flags & IEEE80211_TX_RC_MCS) {
                        /* MCS rates */
                        series[i].Rate = rix | 0x80;
+                       series[i].ChSel = ath_txchainmask_reduction(sc,
+                                       common->tx_chainmask, series[i].Rate);
                        series[i].PktDuration = ath_pkt_duration(sc, rix, len,
                                 is_40, is_sgi, is_sp);
                        if (rix < 8 && (tx_info->flags & IEEE80211_TX_CTL_STBC))
@@ -1576,7 +1589,7 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
                        continue;
                }
 
-               /* legcay rates */
+               /* legacy rates */
                if ((tx_info->band == IEEE80211_BAND_2GHZ) &&
                    !(rate->flags & IEEE80211_RATE_ERP_G))
                        phy = WLAN_RC_PHY_CCK;
@@ -1592,6 +1605,12 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len)
                        is_sp = false;
                }
 
+               if (bf->bf_state.bfs_paprd)
+                       series[i].ChSel = common->tx_chainmask;
+               else
+                       series[i].ChSel = ath_txchainmask_reduction(sc,
+                                       common->tx_chainmask, series[i].Rate);
+
                series[i].PktDuration = ath9k_hw_computetxtime(sc->sc_ah,
                        phy, rate->bitrate * 100, len, rix, is_sp);
        }
index ae6c006bbc56c03bd76f0e1cc56c46a927db1db9..546b4e4ec5ea090aaf6ed0ce7b77ed024e3c8fd6 100644 (file)
@@ -291,7 +291,8 @@ static int carl9170_fw(struct ar9170 *ar, const __u8 *data, size_t len)
 
                if (SUPP(CARL9170FW_WLANTX_CAB)) {
                        ar->hw->wiphy->interface_modes |=
-                               BIT(NL80211_IFTYPE_AP);
+                               BIT(NL80211_IFTYPE_AP) |
+                               BIT(NL80211_IFTYPE_P2P_GO);
                }
        }
 
index 511dbe3caf58bdc517cdff1d8399f07bb0881997..870df8c42622bab94db2aab3da880ad61381bb16 100644 (file)
@@ -1648,7 +1648,8 @@ void *carl9170_alloc(size_t priv_size)
         * supports these modes. The code which will add the
         * additional interface_modes is in fw.c.
         */
-       hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+       hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
+                                    BIT(NL80211_IFTYPE_P2P_CLIENT);
 
        hw->flags |= IEEE80211_HW_RX_INCLUDES_FCS |
                     IEEE80211_HW_REPORTS_TX_ACK_STATUS |
index aee5c9d89a144c9da093c52ad577097d6f064b42..6cc58e052d101727c00e084667ba4527d7d74ef1 100644 (file)
@@ -867,7 +867,7 @@ static int carl9170_tx_prepare(struct ar9170 *ar, struct sk_buff *skb)
 
        mac_tmp = cpu_to_le16(AR9170_TX_MAC_HW_DURATION |
                              AR9170_TX_MAC_BACKOFF);
-       mac_tmp |= cpu_to_le16((hw_queue << AR9170_TX_MAC_QOS_S) &&
+       mac_tmp |= cpu_to_le16((hw_queue << AR9170_TX_MAC_QOS_S) &
                               AR9170_TX_MAC_QOS);
 
        no_ack = !!(info->flags & IEEE80211_TX_CTL_NO_ACK);
index a268053e18e5e1e2f430deb19d2edc1ab158fd1d..2d947a30d29e5fcc495e3a2a8fe930108c330231 100644 (file)
@@ -160,8 +160,7 @@ err_acc:
 
 static void carl9170_usb_tx_data_complete(struct urb *urb)
 {
-       struct ar9170 *ar = (struct ar9170 *)
-             usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
+       struct ar9170 *ar = usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
 
        if (WARN_ON_ONCE(!ar)) {
                dev_kfree_skb_irq(urb->context);
index 9769483156e7990567df34e037415bc889fddb71..905f1d7bac2004ab86ce7b0be4163226df0e1d09 100644 (file)
@@ -67,6 +67,18 @@ enum b43_nphy_rf_sequence {
        B43_RFSEQ_UPDATE_GAINU,
 };
 
+enum b43_nphy_rssi_type {
+       B43_NPHY_RSSI_X = 0,
+       B43_NPHY_RSSI_Y,
+       B43_NPHY_RSSI_Z,
+       B43_NPHY_RSSI_PWRDET,
+       B43_NPHY_RSSI_TSSI_I,
+       B43_NPHY_RSSI_TSSI_Q,
+       B43_NPHY_RSSI_TBD,
+};
+
+static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev,
+                                               bool enable);
 static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd,
                                        u8 *events, u8 *delays, u8 length);
 static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
@@ -145,9 +157,153 @@ static void b43_chantab_phy_upload(struct b43_wldev *dev,
        b43_phy_write(dev, B43_NPHY_BW6, e->phy_bw6);
 }
 
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlEnable */
+static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
+{
+       struct b43_phy_n *nphy = dev->phy.n;
+       u8 i;
+       u16 tmp;
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 1);
+
+       nphy->txpwrctrl = enable;
+       if (!enable) {
+               if (dev->phy.rev >= 3)
+                       ; /* TODO */
+
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x6840);
+               for (i = 0; i < 84; i++)
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0);
+
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x6C40);
+               for (i = 0; i < 84; i++)
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0);
+
+               tmp = B43_NPHY_TXPCTL_CMD_COEFF | B43_NPHY_TXPCTL_CMD_HWPCTLEN;
+               if (dev->phy.rev >= 3)
+                       tmp |= B43_NPHY_TXPCTL_CMD_PCTLEN;
+               b43_phy_mask(dev, B43_NPHY_TXPCTL_CMD, ~tmp);
+
+               if (dev->phy.rev >= 3) {
+                       b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x0100);
+                       b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0100);
+               } else {
+                       b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x4000);
+               }
+
+               if (dev->phy.rev == 2)
+                       b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
+                               ~B43_NPHY_BPHY_CTL3_SCALE, 0x53);
+               else if (dev->phy.rev < 2)
+                       b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
+                               ~B43_NPHY_BPHY_CTL3_SCALE, 0x5A);
+
+               if (dev->phy.rev < 2 && 0)
+                       ; /* TODO */
+       } else {
+               b43err(dev->wl, "enabling tx pwr ctrl not implemented yet\n");
+       }
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 0);
+}
+
+/* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrFix */
 static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
 {
-       //TODO
+       struct b43_phy_n *nphy = dev->phy.n;
+       struct ssb_sprom *sprom = &(dev->dev->bus->sprom);
+
+       u8 txpi[2], bbmult, i;
+       u16 tmp, radio_gain, dac_gain;
+       u16 freq = dev->phy.channel_freq;
+       u32 txgain;
+       /* u32 gaintbl; rev3+ */
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 1);
+
+       if (dev->phy.rev >= 3) {
+               txpi[0] = 40;
+               txpi[1] = 40;
+       } else if (sprom->revision < 4) {
+               txpi[0] = 72;
+               txpi[1] = 72;
+       } else {
+               if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+                       txpi[0] = sprom->txpid2g[0];
+                       txpi[1] = sprom->txpid2g[1];
+               } else if (freq >= 4900 && freq < 5100) {
+                       txpi[0] = sprom->txpid5gl[0];
+                       txpi[1] = sprom->txpid5gl[1];
+               } else if (freq >= 5100 && freq < 5500) {
+                       txpi[0] = sprom->txpid5g[0];
+                       txpi[1] = sprom->txpid5g[1];
+               } else if (freq >= 5500) {
+                       txpi[0] = sprom->txpid5gh[0];
+                       txpi[1] = sprom->txpid5gh[1];
+               } else {
+                       txpi[0] = 91;
+                       txpi[1] = 91;
+               }
+       }
+
+       /*
+       for (i = 0; i < 2; i++) {
+               nphy->txpwrindex[i].index_internal = txpi[i];
+               nphy->txpwrindex[i].index_internal_save = txpi[i];
+       }
+       */
+
+       for (i = 0; i < 2; i++) {
+               if (dev->phy.rev >= 3) {
+                       /* TODO */
+                       radio_gain = (txgain >> 16) & 0x1FFFF;
+               } else {
+                       txgain = b43_ntab_tx_gain_rev0_1_2[txpi[i]];
+                       radio_gain = (txgain >> 16) & 0x1FFF;
+               }
+
+               dac_gain = (txgain >> 8) & 0x3F;
+               bbmult = txgain & 0xFF;
+
+               if (dev->phy.rev >= 3) {
+                       if (i == 0)
+                               b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x0100);
+                       else
+                               b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0100);
+               } else {
+                       b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x4000);
+               }
+
+               if (i == 0)
+                       b43_phy_write(dev, B43_NPHY_AFECTL_DACGAIN1, dac_gain);
+               else
+                       b43_phy_write(dev, B43_NPHY_AFECTL_DACGAIN2, dac_gain);
+
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D10 + i);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, radio_gain);
+
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x3C57);
+               tmp = b43_phy_read(dev, B43_NPHY_TABLE_DATALO);
+
+               if (i == 0)
+                       tmp = (tmp & 0x00FF) | (bbmult << 8);
+               else
+                       tmp = (tmp & 0xFF00) | bbmult;
+
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x3C57);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, tmp);
+
+               if (0)
+                       ; /* TODO */
+       }
+
+       b43_phy_mask(dev, B43_NPHY_BPHY_CTL2, ~B43_NPHY_BPHY_CTL2_LUT);
+
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 0);
 }
 
 
@@ -1593,7 +1749,8 @@ static void b43_nphy_bphy_init(struct b43_wldev *dev)
 
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ScaleOffsetRssi */
 static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale,
-                                      s8 offset, u8 core, u8 rail, u8 type)
+                                       s8 offset, u8 core, u8 rail,
+                                       enum b43_nphy_rssi_type type)
 {
        u16 tmp;
        bool core1or5 = (core == 1) || (core == 5);
@@ -1602,53 +1759,59 @@ static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale,
        offset = clamp_val(offset, -32, 31);
        tmp = ((scale & 0x3F) << 8) | (offset & 0x3F);
 
-       if (core1or5 && (rail == 0) && (type == 2))
+       if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_Z))
                b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, tmp);
-       if (core1or5 && (rail == 1) && (type == 2))
+       if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_Z))
                b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, tmp);
-       if (core2or5 && (rail == 0) && (type == 2))
+       if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_Z))
                b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Z, tmp);
-       if (core2or5 && (rail == 1) && (type == 2))
+       if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_Z))
                b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Z, tmp);
-       if (core1or5 && (rail == 0) && (type == 0))
+
+       if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_X))
                b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_X, tmp);
-       if (core1or5 && (rail == 1) && (type == 0))
+       if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_X))
                b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_X, tmp);
-       if (core2or5 && (rail == 0) && (type == 0))
+       if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_X))
                b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_X, tmp);
-       if (core2or5 && (rail == 1) && (type == 0))
+       if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_X))
                b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_X, tmp);
-       if (core1or5 && (rail == 0) && (type == 1))
+
+       if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_Y))
                b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Y, tmp);
-       if (core1or5 && (rail == 1) && (type == 1))
+       if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_Y))
                b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Y, tmp);
-       if (core2or5 && (rail == 0) && (type == 1))
+       if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_Y))
                b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Y, tmp);
-       if (core2or5 && (rail == 1) && (type == 1))
+       if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_Y))
                b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, tmp);
-       if (core1or5 && (rail == 0) && (type == 6))
+
+       if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_TBD))
                b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TBD, tmp);
-       if (core1or5 && (rail == 1) && (type == 6))
+       if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_TBD))
                b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TBD, tmp);
-       if (core2or5 && (rail == 0) && (type == 6))
+       if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_TBD))
                b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TBD, tmp);
-       if (core2or5 && (rail == 1) && (type == 6))
+       if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_TBD))
                b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TBD, tmp);
-       if (core1or5 && (rail == 0) && (type == 3))
+
+       if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_PWRDET))
                b43_phy_write(dev, B43_NPHY_RSSIMC_0I_PWRDET, tmp);
-       if (core1or5 && (rail == 1) && (type == 3))
+       if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_PWRDET))
                b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_PWRDET, tmp);
-       if (core2or5 && (rail == 0) && (type == 3))
+       if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_PWRDET))
                b43_phy_write(dev, B43_NPHY_RSSIMC_1I_PWRDET, tmp);
-       if (core2or5 && (rail == 1) && (type == 3))
+       if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_PWRDET))
                b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_PWRDET, tmp);
-       if (core1or5 && (type == 4))
+
+       if (core1or5 && (type == B43_NPHY_RSSI_TSSI_I))
                b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TSSI, tmp);
-       if (core2or5 && (type == 4))
+       if (core2or5 && (type == B43_NPHY_RSSI_TSSI_I))
                b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TSSI, tmp);
-       if (core1or5 && (type == 5))
+
+       if (core1or5 && (type == B43_NPHY_RSSI_TSSI_Q))
                b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TSSI, tmp);
-       if (core2or5 && (type == 5))
+       if (core2or5 && (type == B43_NPHY_RSSI_TSSI_Q))
                b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TSSI, tmp);
 }
 
@@ -1676,27 +1839,39 @@ static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
                                (type + 1) << 4);
        }
 
-       /* TODO use some definitions */
        if (code == 0) {
-               b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF, 0);
+               b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x3000);
                if (type < 3) {
-                       b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFEC7, 0);
-                       b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xEFDC, 0);
-                       b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFFFE, 0);
+                       b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+                               ~(B43_NPHY_RFCTL_CMD_RXEN |
+                                 B43_NPHY_RFCTL_CMD_CORESEL));
+                       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER,
+                               ~(0x1 << 12 |
+                                 0x1 << 5 |
+                                 0x1 << 1 |
+                                 0x1));
+                       b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+                               ~B43_NPHY_RFCTL_CMD_START);
                        udelay(20);
-                       b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xFFFE, 0);
+                       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~0x1);
                }
        } else {
-               b43_phy_maskset(dev, B43_NPHY_AFECTL_OVER, 0xCFFF,
-                               0x3000);
+               b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x3000);
                if (type < 3) {
                        b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
-                                       0xFEC7, 0x0180);
-                       b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
-                                       0xEFDC, (code << 1 | 0x1021));
-                       b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD, 0xFFFE, 0x1);
+                               ~(B43_NPHY_RFCTL_CMD_RXEN |
+                                 B43_NPHY_RFCTL_CMD_CORESEL),
+                               (B43_NPHY_RFCTL_CMD_RXEN |
+                                code << B43_NPHY_RFCTL_CMD_CORESEL_SHIFT));
+                       b43_phy_set(dev, B43_NPHY_RFCTL_OVER,
+                               (0x1 << 12 |
+                                 0x1 << 5 |
+                                 0x1 << 1 |
+                                 0x1));
+                       b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+                               B43_NPHY_RFCTL_CMD_START);
                        udelay(20);
-                       b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER, 0xFFFE, 0);
+                       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~0x1);
                }
        }
 }
@@ -1918,7 +2093,10 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
        u16 class, override;
        u8 regs_save_radio[2];
        u16 regs_save_phy[2];
+
        s8 offset[4];
+       u8 core;
+       u8 rail;
 
        u16 clip_state[2];
        u16 clip_off[2] = { 0xFFFF, 0xFFFF };
@@ -2019,12 +2197,11 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
                if (results_min[i] == 248)
                        offset[i] = code - 32;
 
-               if (i % 2 == 0)
-                       b43_nphy_scale_offset_rssi(dev, 0, offset[i], 1, 0,
-                                                       type);
-               else
-                       b43_nphy_scale_offset_rssi(dev, 0, offset[i], 2, 1,
-                                                       type);
+               core = (i / 2) ? 2 : 1;
+               rail = (i % 2) ? 1 : 0;
+
+               b43_nphy_scale_offset_rssi(dev, 0, offset[i], core, rail,
+                                               type);
        }
 
        b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[0]);
@@ -2066,6 +2243,9 @@ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
 
        b43_nphy_classifier(dev, 7, class);
        b43_nphy_write_clip_detection(dev, clip_state);
+       /* Specs don't say about reset here, but it makes wl and b43 dumps
+          identical, it really seems wl performs this */
+       b43_nphy_reset_cca(dev);
 }
 
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */
@@ -2083,9 +2263,9 @@ static void b43_nphy_rssi_cal(struct b43_wldev *dev)
        if (dev->phy.rev >= 3) {
                b43_nphy_rev3_rssi_cal(dev);
        } else {
-               b43_nphy_rev2_rssi_cal(dev, 2);
-               b43_nphy_rev2_rssi_cal(dev, 0);
-               b43_nphy_rev2_rssi_cal(dev, 1);
+               b43_nphy_rev2_rssi_cal(dev, B43_NPHY_RSSI_Z);
+               b43_nphy_rev2_rssi_cal(dev, B43_NPHY_RSSI_X);
+               b43_nphy_rev2_rssi_cal(dev, B43_NPHY_RSSI_Y);
        }
 }
 
@@ -2351,7 +2531,7 @@ static struct nphy_txgains b43_nphy_get_tx_gains(struct b43_wldev *dev)
        struct nphy_txgains target;
        const u32 *table = NULL;
 
-       if (nphy->txpwrctrl == 0) {
+       if (!nphy->txpwrctrl) {
                int i;
 
                if (nphy->hang_avoid)
@@ -3260,9 +3440,8 @@ int b43_phy_initn(struct b43_wldev *dev)
                b43_nphy_bphy_init(dev);
 
        tx_pwr_state = nphy->txpwrctrl;
-       /* TODO N PHY TX power control with argument 0
-               (turning off power control) */
-       /* TODO Fix the TX Power Settings */
+       b43_nphy_tx_power_ctrl(dev, false);
+       b43_nphy_tx_power_fix(dev);
        /* TODO N PHY TX Power Control Idle TSSI */
        /* TODO N PHY TX Power Control Setup */
 
@@ -3319,21 +3498,18 @@ int b43_phy_initn(struct b43_wldev *dev)
                                        /* TODO N PHY Pre Calibrate TX Gain */
                                        target = b43_nphy_get_tx_gains(dev);
                                }
-                       }
+                               if (!b43_nphy_cal_tx_iq_lo(dev, target, true, false))
+                                       if (b43_nphy_cal_rx_iq(dev, target, 2, 0) == 0)
+                                               b43_nphy_save_cal(dev);
+                       } else if (nphy->mphase_cal_phase_id == 0)
+                               ;/* N PHY Periodic Calibration with arg 3 */
+               } else {
+                       b43_nphy_restore_cal(dev);
                }
        }
 
-       if (!b43_nphy_cal_tx_iq_lo(dev, target, true, false)) {
-               if (b43_nphy_cal_rx_iq(dev, target, 2, 0) == 0)
-                       b43_nphy_save_cal(dev);
-               else if (nphy->mphase_cal_phase_id == 0)
-                       ;/* N PHY Periodic Calibration with argument 3 */
-       } else {
-               b43_nphy_restore_cal(dev);
-       }
-
        b43_nphy_tx_pwr_ctrl_coef_setup(dev);
-       /* TODO N PHY TX Power Control Enable with argument tx_pwr_state */
+       b43_nphy_tx_power_ctrl(dev, tx_pwr_state);
        b43_phy_write(dev, B43_NPHY_TXMACIF_HOLDOFF, 0x0015);
        b43_phy_write(dev, B43_NPHY_TXMACDELAY, 0x0320);
        if (phy->rev >= 3 && phy->rev <= 6)
@@ -3384,7 +3560,7 @@ static void b43_nphy_channel_setup(struct b43_wldev *dev,
                        b43_phy_mask(dev, B43_PHY_B_TEST, ~0x840);
        }
 
-       if (nphy->txpwrctrl)
+       if (!nphy->txpwrctrl)
                b43_nphy_tx_power_fix(dev);
 
        if (dev->phy.rev < 3)
@@ -3480,6 +3656,7 @@ static void b43_nphy_op_prepare_structs(struct b43_wldev *dev)
        nphy->gain_boost = true; /* this way we follow wl, assume it is true */
        nphy->txrx_chain = 2; /* sth different than 0 and 1 for now */
        nphy->phyrxchain = 3; /* to avoid b43_nphy_set_rx_core_state like wl */
+       nphy->perical = 2; /* avoid additional rssi cal on init (like wl) */
 }
 
 static void b43_nphy_op_free(struct b43_wldev *dev)
index c144e59a708bc5b4257181fd8044a4f757a11996..001e841f118c97ebfae1815035d539a33e199af0 100644 (file)
@@ -782,7 +782,7 @@ struct b43_phy_n {
        u16 mphase_txcal_numcmds;
        u16 mphase_txcal_bestcoeffs[11];
 
-       u8 txpwrctrl;
+       bool txpwrctrl;
        u16 txcal_bbmult;
        u16 txiqlocal_bestc[11];
        bool txiqlocal_coeffsvalid;
index 10910dc4184b958c1e7c3392d4f7438a8db306fa..44c6dea668820da78fb70851bf22eb6d26045d0c 100644 (file)
@@ -304,7 +304,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 184,
        .freq                   = 4920, /* MHz */
        .unk2                   = 3280,
-       RADIOREGS(0x71, 0x01, 0xEC, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xEC, 0x01, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
                  0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F,
                  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
        PHYREGS(0x07B4, 0x07B0, 0x07AC, 0x0214, 0x0215, 0x0216),
@@ -312,7 +312,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 186,
        .freq                   = 4930, /* MHz */
        .unk2                   = 3287,
-       RADIOREGS(0x71, 0x01, 0xED, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xED, 0x01, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
                  0x00, 0x8F, 0xFF, 0xFF, 0xFF, 0x00, 0x0F, 0x0F,
                  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
        PHYREGS(0x07B8, 0x07B4, 0x07B0, 0x0213, 0x0214, 0x0215),
@@ -320,7 +320,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 188,
        .freq                   = 4940, /* MHz */
        .unk2                   = 3293,
-       RADIOREGS(0x71, 0x01, 0xEE, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xEE, 0x01, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
                  0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
                  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
        PHYREGS(0x07BC, 0x07B8, 0x07B4, 0x0212, 0x0213, 0x0214),
@@ -328,7 +328,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 190,
        .freq                   = 4950, /* MHz */
        .unk2                   = 3300,
-       RADIOREGS(0x71, 0x01, 0xEF, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xEF, 0x01, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
                  0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
                  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
        PHYREGS(0x07C0, 0x07BC, 0x07B8, 0x0211, 0x0212, 0x0213),
@@ -336,7 +336,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 192,
        .freq                   = 4960, /* MHz */
        .unk2                   = 3307,
-       RADIOREGS(0x71, 0x01, 0xF0, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xF0, 0x01, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
                  0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
                  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
        PHYREGS(0x07C4, 0x07C0, 0x07BC, 0x020F, 0x0211, 0x0212),
@@ -344,7 +344,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 194,
        .freq                   = 4970, /* MHz */
        .unk2                   = 3313,
-       RADIOREGS(0x71, 0x01, 0xF1, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xF1, 0x01, 0x0F, 0xFF, 0x01, 0x04, 0x0A,
                  0x00, 0x8F, 0xEE, 0xEE, 0xFF, 0x00, 0x0F, 0x0F,
                  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
        PHYREGS(0x07C8, 0x07C4, 0x07C0, 0x020E, 0x020F, 0x0211),
@@ -352,7 +352,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 196,
        .freq                   = 4980, /* MHz */
        .unk2                   = 3320,
-       RADIOREGS(0x71, 0x01, 0xF2, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xF2, 0x01, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
                  0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
                  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
        PHYREGS(0x07CC, 0x07C8, 0x07C4, 0x020D, 0x020E, 0x020F),
@@ -360,7 +360,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 198,
        .freq                   = 4990, /* MHz */
        .unk2                   = 3327,
-       RADIOREGS(0x71, 0x01, 0xF3, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xF3, 0x01, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
                  0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
                  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
        PHYREGS(0x07D0, 0x07CC, 0x07C8, 0x020C, 0x020D, 0x020E),
@@ -368,7 +368,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 200,
        .freq                   = 5000, /* MHz */
        .unk2                   = 3333,
-       RADIOREGS(0x71, 0x01, 0xF4, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xF4, 0x01, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
                  0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
                  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
        PHYREGS(0x07D4, 0x07D0, 0x07CC, 0x020B, 0x020C, 0x020D),
@@ -376,7 +376,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 202,
        .freq                   = 5010, /* MHz */
        .unk2                   = 3340,
-       RADIOREGS(0x71, 0x01, 0xF5, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xF5, 0x01, 0x0E, 0xFF, 0x01, 0x04, 0x0A,
                  0x00, 0x8F, 0xDD, 0xDD, 0xFF, 0x00, 0x0F, 0x0F,
                  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
        PHYREGS(0x07D8, 0x07D4, 0x07D0, 0x020A, 0x020B, 0x020C),
@@ -384,7 +384,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 204,
        .freq                   = 5020, /* MHz */
        .unk2                   = 3347,
-       RADIOREGS(0x71, 0x01, 0xF6, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xF6, 0x01, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
                  0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
                  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
        PHYREGS(0x07DC, 0x07D8, 0x07D4, 0x0209, 0x020A, 0x020B),
@@ -392,7 +392,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 206,
        .freq                   = 5030, /* MHz */
        .unk2                   = 3353,
-       RADIOREGS(0x71, 0x01, 0xF7, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xF7, 0x01, 0x0E, 0xF7, 0x01, 0x04, 0x0A,
                  0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
                  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
        PHYREGS(0x07E0, 0x07DC, 0x07D8, 0x0208, 0x0209, 0x020A),
@@ -400,7 +400,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 208,
        .freq                   = 5040, /* MHz */
        .unk2                   = 3360,
-       RADIOREGS(0x71, 0x01, 0xF8, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xF8, 0x01, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
                  0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
                  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
        PHYREGS(0x07E4, 0x07E0, 0x07DC, 0x0207, 0x0208, 0x0209),
@@ -408,7 +408,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 210,
        .freq                   = 5050, /* MHz */
        .unk2                   = 3367,
-       RADIOREGS(0x71, 0x01, 0xF9, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xF9, 0x01, 0x0D, 0xEF, 0x01, 0x04, 0x0A,
                  0x00, 0x8F, 0xCC, 0xCC, 0xFF, 0x00, 0x0F, 0x0F,
                  0x8F, 0xFF, 0x00, 0x0F, 0x0F, 0x8F),
        PHYREGS(0x07E8, 0x07E4, 0x07E0, 0x0206, 0x0207, 0x0208),
@@ -416,7 +416,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 212,
        .freq                   = 5060, /* MHz */
        .unk2                   = 3373,
-       RADIOREGS(0x71, 0x01, 0xFA, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xFA, 0x01, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
                  0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F,
                  0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E),
        PHYREGS(0x07EC, 0x07E8, 0x07E4, 0x0205, 0x0206, 0x0207),
@@ -424,7 +424,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 214,
        .freq                   = 5070, /* MHz */
        .unk2                   = 3380,
-       RADIOREGS(0x71, 0x01, 0xFB, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xFB, 0x01, 0x0D, 0xE6, 0x01, 0x04, 0x0A,
                  0x00, 0x8F, 0xBB, 0xBB, 0xFF, 0x00, 0x0E, 0x0F,
                  0x8E, 0xFF, 0x00, 0x0E, 0x0F, 0x8E),
        PHYREGS(0x07F0, 0x07EC, 0x07E8, 0x0204, 0x0205, 0x0206),
@@ -432,7 +432,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 216,
        .freq                   = 5080, /* MHz */
        .unk2                   = 3387,
-       RADIOREGS(0x71, 0x01, 0xFC, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xFC, 0x01, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
                  0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F,
                  0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D),
        PHYREGS(0x07F4, 0x07F0, 0x07EC, 0x0203, 0x0204, 0x0205),
@@ -440,7 +440,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 218,
        .freq                   = 5090, /* MHz */
        .unk2                   = 3393,
-       RADIOREGS(0x71, 0x01, 0xFD, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xFD, 0x01, 0x0D, 0xDE, 0x01, 0x04, 0x0A,
                  0x00, 0x8E, 0xBB, 0xBB, 0xEE, 0x00, 0x0E, 0x0F,
                  0x8D, 0xEE, 0x00, 0x0E, 0x0F, 0x8D),
        PHYREGS(0x07F8, 0x07F4, 0x07F0, 0x0202, 0x0203, 0x0204),
@@ -448,7 +448,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 220,
        .freq                   = 5100, /* MHz */
        .unk2                   = 3400,
-       RADIOREGS(0x71, 0x01, 0xFE, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xFE, 0x01, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
                  0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F,
                  0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D),
        PHYREGS(0x07FC, 0x07F8, 0x07F4, 0x0201, 0x0202, 0x0203),
@@ -456,7 +456,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 222,
        .freq                   = 5110, /* MHz */
        .unk2                   = 3407,
-       RADIOREGS(0x71, 0x01, 0xFF, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0xFF, 0x01, 0x0C, 0xD6, 0x01, 0x04, 0x0A,
                  0x00, 0x8E, 0xAA, 0xAA, 0xEE, 0x00, 0x0D, 0x0F,
                  0x8D, 0xEE, 0x00, 0x0D, 0x0F, 0x8D),
        PHYREGS(0x0800, 0x07FC, 0x07F8, 0x0200, 0x0201, 0x0202),
@@ -464,7 +464,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 224,
        .freq                   = 5120, /* MHz */
        .unk2                   = 3413,
-       RADIOREGS(0x71, 0x02, 0x00, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x00, 0x02, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
                  0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F,
                  0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C),
        PHYREGS(0x0804, 0x0800, 0x07FC, 0x01FF, 0x0200, 0x0201),
@@ -472,7 +472,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 226,
        .freq                   = 5130, /* MHz */
        .unk2                   = 3420,
-       RADIOREGS(0x71, 0x02, 0x01, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x01, 0x02, 0x0C, 0xCE, 0x01, 0x04, 0x0A,
                  0x00, 0x8D, 0xAA, 0xAA, 0xDD, 0x00, 0x0D, 0x0F,
                  0x8C, 0xDD, 0x00, 0x0D, 0x0F, 0x8C),
        PHYREGS(0x0808, 0x0804, 0x0800, 0x01FE, 0x01FF, 0x0200),
@@ -488,7 +488,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 32,
        .freq                   = 5160, /* MHz */
        .unk2                   = 3440,
-       RADIOREGS(0x71, 0x02, 0x04, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x04, 0x02, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
                  0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D,
                  0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A),
        PHYREGS(0x0814, 0x0810, 0x080C, 0x01FB, 0x01FC, 0x01FD),
@@ -496,7 +496,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 34,
        .freq                   = 5170, /* MHz */
        .unk2                   = 3447,
-       RADIOREGS(0x71, 0x02, 0x05, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x05, 0x02, 0x0B, 0xBE, 0x01, 0x04, 0x0A,
                  0x00, 0x8C, 0x99, 0x99, 0xCC, 0x00, 0x0B, 0x0D,
                  0x8A, 0xCC, 0x00, 0x0B, 0x0D, 0x8A),
        PHYREGS(0x0818, 0x0814, 0x0810, 0x01FA, 0x01FB, 0x01FC),
@@ -504,7 +504,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 36,
        .freq                   = 5180, /* MHz */
        .unk2                   = 3453,
-       RADIOREGS(0x71, 0x02, 0x06, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x06, 0x02, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
                  0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C,
                  0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89),
        PHYREGS(0x081C, 0x0818, 0x0814, 0x01F9, 0x01FA, 0x01FB),
@@ -512,7 +512,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 38,
        .freq                   = 5190, /* MHz */
        .unk2                   = 3460,
-       RADIOREGS(0x71, 0x02, 0x07, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x07, 0x02, 0x0B, 0xB6, 0x01, 0x04, 0x0A,
                  0x00, 0x8C, 0x88, 0x88, 0xCC, 0x00, 0x0B, 0x0C,
                  0x89, 0xCC, 0x00, 0x0B, 0x0C, 0x89),
        PHYREGS(0x0820, 0x081C, 0x0818, 0x01F8, 0x01F9, 0x01FA),
@@ -520,7 +520,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 40,
        .freq                   = 5200, /* MHz */
        .unk2                   = 3467,
-       RADIOREGS(0x71, 0x02, 0x08, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x08, 0x02, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
                  0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B,
                  0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89),
        PHYREGS(0x0824, 0x0820, 0x081C, 0x01F7, 0x01F8, 0x01F9),
@@ -528,7 +528,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 42,
        .freq                   = 5210, /* MHz */
        .unk2                   = 3473,
-       RADIOREGS(0x71, 0x02, 0x09, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x09, 0x02, 0x0B, 0xAF, 0x01, 0x04, 0x0A,
                  0x00, 0x8B, 0x88, 0x88, 0xBB, 0x00, 0x0A, 0x0B,
                  0x89, 0xBB, 0x00, 0x0A, 0x0B, 0x89),
        PHYREGS(0x0828, 0x0824, 0x0820, 0x01F6, 0x01F7, 0x01F8),
@@ -536,7 +536,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 44,
        .freq                   = 5220, /* MHz */
        .unk2                   = 3480,
-       RADIOREGS(0x71, 0x02, 0x0A, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x0A, 0x02, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
                  0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A,
                  0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88),
        PHYREGS(0x082C, 0x0828, 0x0824, 0x01F5, 0x01F6, 0x01F7),
@@ -544,7 +544,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 46,
        .freq                   = 5230, /* MHz */
        .unk2                   = 3487,
-       RADIOREGS(0x71, 0x02, 0x0B, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x0B, 0x02, 0x0A, 0xA7, 0x01, 0x04, 0x0A,
                  0x00, 0x8B, 0x77, 0x77, 0xBB, 0x00, 0x09, 0x0A,
                  0x88, 0xBB, 0x00, 0x09, 0x0A, 0x88),
        PHYREGS(0x0830, 0x082C, 0x0828, 0x01F4, 0x01F5, 0x01F6),
@@ -552,7 +552,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 48,
        .freq                   = 5240, /* MHz */
        .unk2                   = 3493,
-       RADIOREGS(0x71, 0x02, 0x0C, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x0C, 0x02, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
                  0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A,
                  0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87),
        PHYREGS(0x0834, 0x0830, 0x082C, 0x01F3, 0x01F4, 0x01F5),
@@ -560,7 +560,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 50,
        .freq                   = 5250, /* MHz */
        .unk2                   = 3500,
-       RADIOREGS(0x71, 0x02, 0x0D, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x0D, 0x02, 0x0A, 0xA0, 0x01, 0x04, 0x0A,
                  0x00, 0x8A, 0x77, 0x77, 0xAA, 0x00, 0x09, 0x0A,
                  0x87, 0xAA, 0x00, 0x09, 0x0A, 0x87),
        PHYREGS(0x0838, 0x0834, 0x0830, 0x01F2, 0x01F3, 0x01F4),
@@ -568,7 +568,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 52,
        .freq                   = 5260, /* MHz */
        .unk2                   = 3507,
-       RADIOREGS(0x71, 0x02, 0x0E, 0x0A, 0x98, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x0E, 0x02, 0x0A, 0x98, 0x01, 0x04, 0x0A,
                  0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09,
                  0x87, 0xAA, 0x00, 0x08, 0x09, 0x87),
        PHYREGS(0x083C, 0x0838, 0x0834, 0x01F1, 0x01F2, 0x01F3),
@@ -576,7 +576,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 54,
        .freq                   = 5270, /* MHz */
        .unk2                   = 3513,
-       RADIOREGS(0x71, 0x02, 0x0F, 0x0A, 0x98, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x0F, 0x02, 0x0A, 0x98, 0x01, 0x04, 0x0A,
                  0x00, 0x8A, 0x66, 0x66, 0xAA, 0x00, 0x08, 0x09,
                  0x87, 0xAA, 0x00, 0x08, 0x09, 0x87),
        PHYREGS(0x0840, 0x083C, 0x0838, 0x01F0, 0x01F1, 0x01F2),
@@ -584,7 +584,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 56,
        .freq                   = 5280, /* MHz */
        .unk2                   = 3520,
-       RADIOREGS(0x71, 0x02, 0x10, 0x09, 0x91, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x10, 0x02, 0x09, 0x91, 0x01, 0x04, 0x0A,
                  0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08,
                  0x86, 0x99, 0x00, 0x08, 0x08, 0x86),
        PHYREGS(0x0844, 0x0840, 0x083C, 0x01F0, 0x01F0, 0x01F1),
@@ -592,7 +592,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 58,
        .freq                   = 5290, /* MHz */
        .unk2                   = 3527,
-       RADIOREGS(0x71, 0x02, 0x11, 0x09, 0x91, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x11, 0x02, 0x09, 0x91, 0x01, 0x04, 0x0A,
                  0x00, 0x89, 0x66, 0x66, 0x99, 0x00, 0x08, 0x08,
                  0x86, 0x99, 0x00, 0x08, 0x08, 0x86),
        PHYREGS(0x0848, 0x0844, 0x0840, 0x01EF, 0x01F0, 0x01F0),
@@ -600,7 +600,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 60,
        .freq                   = 5300, /* MHz */
        .unk2                   = 3533,
-       RADIOREGS(0x71, 0x02, 0x12, 0x09, 0x8A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x12, 0x02, 0x09, 0x8A, 0x01, 0x04, 0x0A,
                  0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07,
                  0x85, 0x99, 0x00, 0x08, 0x07, 0x85),
        PHYREGS(0x084C, 0x0848, 0x0844, 0x01EE, 0x01EF, 0x01F0),
@@ -608,7 +608,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 62,
        .freq                   = 5310, /* MHz */
        .unk2                   = 3540,
-       RADIOREGS(0x71, 0x02, 0x13, 0x09, 0x8A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x13, 0x02, 0x09, 0x8A, 0x01, 0x04, 0x0A,
                  0x00, 0x89, 0x55, 0x55, 0x99, 0x00, 0x08, 0x07,
                  0x85, 0x99, 0x00, 0x08, 0x07, 0x85),
        PHYREGS(0x0850, 0x084C, 0x0848, 0x01ED, 0x01EE, 0x01EF),
@@ -616,7 +616,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 64,
        .freq                   = 5320, /* MHz */
        .unk2                   = 3547,
-       RADIOREGS(0x71, 0x02, 0x14, 0x09, 0x83, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x14, 0x02, 0x09, 0x83, 0x01, 0x04, 0x0A,
                  0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07,
                  0x84, 0x88, 0x00, 0x07, 0x07, 0x84),
        PHYREGS(0x0854, 0x0850, 0x084C, 0x01EC, 0x01ED, 0x01EE),
@@ -624,7 +624,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 66,
        .freq                   = 5330, /* MHz */
        .unk2                   = 3553,
-       RADIOREGS(0x71, 0x02, 0x15, 0x09, 0x83, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x15, 0x02, 0x09, 0x83, 0x01, 0x04, 0x0A,
                  0x00, 0x88, 0x55, 0x55, 0x88, 0x00, 0x07, 0x07,
                  0x84, 0x88, 0x00, 0x07, 0x07, 0x84),
        PHYREGS(0x0858, 0x0854, 0x0850, 0x01EB, 0x01EC, 0x01ED),
@@ -632,7 +632,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 68,
        .freq                   = 5340, /* MHz */
        .unk2                   = 3560,
-       RADIOREGS(0x71, 0x02, 0x16, 0x08, 0x7C, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x16, 0x02, 0x08, 0x7C, 0x01, 0x04, 0x0A,
                  0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06,
                  0x84, 0x88, 0x00, 0x07, 0x06, 0x84),
        PHYREGS(0x085C, 0x0858, 0x0854, 0x01EA, 0x01EB, 0x01EC),
@@ -640,7 +640,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 70,
        .freq                   = 5350, /* MHz */
        .unk2                   = 3567,
-       RADIOREGS(0x71, 0x02, 0x17, 0x08, 0x7C, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x17, 0x02, 0x08, 0x7C, 0x01, 0x04, 0x0A,
                  0x00, 0x88, 0x44, 0x44, 0x88, 0x00, 0x07, 0x06,
                  0x84, 0x88, 0x00, 0x07, 0x06, 0x84),
        PHYREGS(0x0860, 0x085C, 0x0858, 0x01E9, 0x01EA, 0x01EB),
@@ -648,7 +648,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 72,
        .freq                   = 5360, /* MHz */
        .unk2                   = 3573,
-       RADIOREGS(0x71, 0x02, 0x18, 0x08, 0x75, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x18, 0x02, 0x08, 0x75, 0x01, 0x04, 0x0A,
                  0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05,
                  0x83, 0x77, 0x00, 0x06, 0x05, 0x83),
        PHYREGS(0x0864, 0x0860, 0x085C, 0x01E8, 0x01E9, 0x01EA),
@@ -656,7 +656,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 74,
        .freq                   = 5370, /* MHz */
        .unk2                   = 3580,
-       RADIOREGS(0x71, 0x02, 0x19, 0x08, 0x75, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x19, 0x02, 0x08, 0x75, 0x01, 0x04, 0x0A,
                  0x00, 0x87, 0x44, 0x44, 0x77, 0x00, 0x06, 0x05,
                  0x83, 0x77, 0x00, 0x06, 0x05, 0x83),
        PHYREGS(0x0868, 0x0864, 0x0860, 0x01E7, 0x01E8, 0x01E9),
@@ -664,7 +664,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 76,
        .freq                   = 5380, /* MHz */
        .unk2                   = 3587,
-       RADIOREGS(0x71, 0x02, 0x1A, 0x08, 0x6E, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x1A, 0x02, 0x08, 0x6E, 0x01, 0x04, 0x0A,
                  0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04,
                  0x82, 0x77, 0x00, 0x06, 0x04, 0x82),
        PHYREGS(0x086C, 0x0868, 0x0864, 0x01E6, 0x01E7, 0x01E8),
@@ -672,7 +672,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 78,
        .freq                   = 5390, /* MHz */
        .unk2                   = 3593,
-       RADIOREGS(0x71, 0x02, 0x1B, 0x08, 0x6E, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x1B, 0x02, 0x08, 0x6E, 0x01, 0x04, 0x0A,
                  0x00, 0x87, 0x33, 0x33, 0x77, 0x00, 0x06, 0x04,
                  0x82, 0x77, 0x00, 0x06, 0x04, 0x82),
        PHYREGS(0x0870, 0x086C, 0x0868, 0x01E5, 0x01E6, 0x01E7),
@@ -680,7 +680,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 80,
        .freq                   = 5400, /* MHz */
        .unk2                   = 3600,
-       RADIOREGS(0x71, 0x02, 0x1C, 0x07, 0x67, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x1C, 0x02, 0x07, 0x67, 0x01, 0x04, 0x0A,
                  0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04,
                  0x81, 0x66, 0x00, 0x05, 0x04, 0x81),
        PHYREGS(0x0874, 0x0870, 0x086C, 0x01E5, 0x01E5, 0x01E6),
@@ -688,7 +688,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 82,
        .freq                   = 5410, /* MHz */
        .unk2                   = 3607,
-       RADIOREGS(0x71, 0x02, 0x1D, 0x07, 0x67, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x1D, 0x02, 0x07, 0x67, 0x01, 0x04, 0x0A,
                  0x00, 0x86, 0x33, 0x33, 0x66, 0x00, 0x05, 0x04,
                  0x81, 0x66, 0x00, 0x05, 0x04, 0x81),
        PHYREGS(0x0878, 0x0874, 0x0870, 0x01E4, 0x01E5, 0x01E5),
@@ -696,7 +696,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 84,
        .freq                   = 5420, /* MHz */
        .unk2                   = 3613,
-       RADIOREGS(0x71, 0x02, 0x1E, 0x07, 0x61, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x1E, 0x02, 0x07, 0x61, 0x01, 0x04, 0x0A,
                  0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03,
                  0x80, 0x66, 0x00, 0x05, 0x03, 0x80),
        PHYREGS(0x087C, 0x0878, 0x0874, 0x01E3, 0x01E4, 0x01E5),
@@ -704,7 +704,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 86,
        .freq                   = 5430, /* MHz */
        .unk2                   = 3620,
-       RADIOREGS(0x71, 0x02, 0x1F, 0x07, 0x61, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x1F, 0x02, 0x07, 0x61, 0x01, 0x04, 0x0A,
                  0x00, 0x86, 0x22, 0x22, 0x66, 0x00, 0x05, 0x03,
                  0x80, 0x66, 0x00, 0x05, 0x03, 0x80),
        PHYREGS(0x0880, 0x087C, 0x0878, 0x01E2, 0x01E3, 0x01E4),
@@ -712,7 +712,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 88,
        .freq                   = 5440, /* MHz */
        .unk2                   = 3627,
-       RADIOREGS(0x71, 0x02, 0x20, 0x07, 0x5A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x20, 0x02, 0x07, 0x5A, 0x01, 0x04, 0x0A,
                  0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02,
                  0x80, 0x55, 0x00, 0x04, 0x02, 0x80),
        PHYREGS(0x0884, 0x0880, 0x087C, 0x01E1, 0x01E2, 0x01E3),
@@ -720,7 +720,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 90,
        .freq                   = 5450, /* MHz */
        .unk2                   = 3633,
-       RADIOREGS(0x71, 0x02, 0x21, 0x07, 0x5A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x21, 0x02, 0x07, 0x5A, 0x01, 0x04, 0x0A,
                  0x00, 0x85, 0x22, 0x22, 0x55, 0x00, 0x04, 0x02,
                  0x80, 0x55, 0x00, 0x04, 0x02, 0x80),
        PHYREGS(0x0888, 0x0884, 0x0880, 0x01E0, 0x01E1, 0x01E2),
@@ -728,7 +728,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 92,
        .freq                   = 5460, /* MHz */
        .unk2                   = 3640,
-       RADIOREGS(0x71, 0x02, 0x22, 0x06, 0x53, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x22, 0x02, 0x06, 0x53, 0x01, 0x04, 0x0A,
                  0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01,
                  0x80, 0x55, 0x00, 0x04, 0x01, 0x80),
        PHYREGS(0x088C, 0x0888, 0x0884, 0x01DF, 0x01E0, 0x01E1),
@@ -736,7 +736,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 94,
        .freq                   = 5470, /* MHz */
        .unk2                   = 3647,
-       RADIOREGS(0x71, 0x02, 0x23, 0x06, 0x53, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x23, 0x02, 0x06, 0x53, 0x01, 0x04, 0x0A,
                  0x00, 0x85, 0x11, 0x11, 0x55, 0x00, 0x04, 0x01,
                  0x80, 0x55, 0x00, 0x04, 0x01, 0x80),
        PHYREGS(0x0890, 0x088C, 0x0888, 0x01DE, 0x01DF, 0x01E0),
@@ -744,7 +744,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 96,
        .freq                   = 5480, /* MHz */
        .unk2                   = 3653,
-       RADIOREGS(0x71, 0x02, 0x24, 0x06, 0x4D, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x24, 0x02, 0x06, 0x4D, 0x01, 0x04, 0x0A,
                  0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00,
                  0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
        PHYREGS(0x0894, 0x0890, 0x088C, 0x01DD, 0x01DE, 0x01DF),
@@ -752,7 +752,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 98,
        .freq                   = 5490, /* MHz */
        .unk2                   = 3660,
-       RADIOREGS(0x71, 0x02, 0x25, 0x06, 0x4D, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x25, 0x02, 0x06, 0x4D, 0x01, 0x04, 0x0A,
                  0x00, 0x84, 0x11, 0x11, 0x44, 0x00, 0x03, 0x00,
                  0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
        PHYREGS(0x0898, 0x0894, 0x0890, 0x01DD, 0x01DD, 0x01DE),
@@ -760,7 +760,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 100,
        .freq                   = 5500, /* MHz */
        .unk2                   = 3667,
-       RADIOREGS(0x71, 0x02, 0x26, 0x06, 0x47, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x26, 0x02, 0x06, 0x47, 0x01, 0x04, 0x0A,
                  0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00,
                  0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
        PHYREGS(0x089C, 0x0898, 0x0894, 0x01DC, 0x01DD, 0x01DD),
@@ -768,7 +768,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 102,
        .freq                   = 5510, /* MHz */
        .unk2                   = 3673,
-       RADIOREGS(0x71, 0x02, 0x27, 0x06, 0x47, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x27, 0x02, 0x06, 0x47, 0x01, 0x04, 0x0A,
                  0x00, 0x84, 0x00, 0x00, 0x44, 0x00, 0x03, 0x00,
                  0x80, 0x44, 0x00, 0x03, 0x00, 0x80),
        PHYREGS(0x08A0, 0x089C, 0x0898, 0x01DB, 0x01DC, 0x01DD),
@@ -776,7 +776,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 104,
        .freq                   = 5520, /* MHz */
        .unk2                   = 3680,
-       RADIOREGS(0x71, 0x02, 0x28, 0x05, 0x40, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x28, 0x02, 0x05, 0x40, 0x01, 0x04, 0x0A,
                  0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
                  0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
        PHYREGS(0x08A4, 0x08A0, 0x089C, 0x01DA, 0x01DB, 0x01DC),
@@ -784,7 +784,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 106,
        .freq                   = 5530, /* MHz */
        .unk2                   = 3687,
-       RADIOREGS(0x71, 0x02, 0x29, 0x05, 0x40, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x29, 0x02, 0x05, 0x40, 0x01, 0x04, 0x0A,
                  0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
                  0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
        PHYREGS(0x08A8, 0x08A4, 0x08A0, 0x01D9, 0x01DA, 0x01DB),
@@ -792,7 +792,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 108,
        .freq                   = 5540, /* MHz */
        .unk2                   = 3693,
-       RADIOREGS(0x71, 0x02, 0x2A, 0x05, 0x3A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x2A, 0x02, 0x05, 0x3A, 0x01, 0x04, 0x0A,
                  0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
                  0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
        PHYREGS(0x08AC, 0x08A8, 0x08A4, 0x01D8, 0x01D9, 0x01DA),
@@ -800,7 +800,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 110,
        .freq                   = 5550, /* MHz */
        .unk2                   = 3700,
-       RADIOREGS(0x71, 0x02, 0x2B, 0x05, 0x3A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x2B, 0x02, 0x05, 0x3A, 0x01, 0x04, 0x0A,
                  0x00, 0x83, 0x00, 0x00, 0x33, 0x00, 0x02, 0x00,
                  0x80, 0x33, 0x00, 0x02, 0x00, 0x80),
        PHYREGS(0x08B0, 0x08AC, 0x08A8, 0x01D7, 0x01D8, 0x01D9),
@@ -808,7 +808,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 112,
        .freq                   = 5560, /* MHz */
        .unk2                   = 3707,
-       RADIOREGS(0x71, 0x02, 0x2C, 0x05, 0x34, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x2C, 0x02, 0x05, 0x34, 0x01, 0x04, 0x0A,
                  0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
                  0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
        PHYREGS(0x08B4, 0x08B0, 0x08AC, 0x01D7, 0x01D7, 0x01D8),
@@ -816,7 +816,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 114,
        .freq                   = 5570, /* MHz */
        .unk2                   = 3713,
-       RADIOREGS(0x71, 0x02, 0x2D, 0x05, 0x34, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x2D, 0x02, 0x05, 0x34, 0x01, 0x04, 0x0A,
                  0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
                  0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
        PHYREGS(0x08B8, 0x08B4, 0x08B0, 0x01D6, 0x01D7, 0x01D7),
@@ -824,7 +824,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 116,
        .freq                   = 5580, /* MHz */
        .unk2                   = 3720,
-       RADIOREGS(0x71, 0x02, 0x2E, 0x04, 0x2E, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x2E, 0x02, 0x04, 0x2E, 0x01, 0x04, 0x0A,
                  0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
                  0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
        PHYREGS(0x08BC, 0x08B8, 0x08B4, 0x01D5, 0x01D6, 0x01D7),
@@ -832,7 +832,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 118,
        .freq                   = 5590, /* MHz */
        .unk2                   = 3727,
-       RADIOREGS(0x71, 0x02, 0x2F, 0x04, 0x2E, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x2F, 0x02, 0x04, 0x2E, 0x01, 0x04, 0x0A,
                  0x00, 0x82, 0x00, 0x00, 0x22, 0x00, 0x01, 0x00,
                  0x80, 0x22, 0x00, 0x01, 0x00, 0x80),
        PHYREGS(0x08C0, 0x08BC, 0x08B8, 0x01D4, 0x01D5, 0x01D6),
@@ -840,7 +840,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 120,
        .freq                   = 5600, /* MHz */
        .unk2                   = 3733,
-       RADIOREGS(0x71, 0x02, 0x30, 0x04, 0x28, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x30, 0x02, 0x04, 0x28, 0x01, 0x04, 0x0A,
                  0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00,
                  0x80, 0x11, 0x00, 0x01, 0x00, 0x80),
        PHYREGS(0x08C4, 0x08C0, 0x08BC, 0x01D3, 0x01D4, 0x01D5),
@@ -848,7 +848,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 122,
        .freq                   = 5610, /* MHz */
        .unk2                   = 3740,
-       RADIOREGS(0x71, 0x02, 0x31, 0x04, 0x28, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x31, 0x02, 0x04, 0x28, 0x01, 0x04, 0x0A,
                  0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x01, 0x00,
                  0x80, 0x11, 0x00, 0x01, 0x00, 0x80),
        PHYREGS(0x08C8, 0x08C4, 0x08C0, 0x01D2, 0x01D3, 0x01D4),
@@ -856,7 +856,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 124,
        .freq                   = 5620, /* MHz */
        .unk2                   = 3747,
-       RADIOREGS(0x71, 0x02, 0x32, 0x04, 0x21, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x32, 0x02, 0x04, 0x21, 0x01, 0x04, 0x0A,
                  0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
                  0x80, 0x11, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x08CC, 0x08C8, 0x08C4, 0x01D2, 0x01D2, 0x01D3),
@@ -864,7 +864,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 126,
        .freq                   = 5630, /* MHz */
        .unk2                   = 3753,
-       RADIOREGS(0x71, 0x02, 0x33, 0x04, 0x21, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x33, 0x02, 0x04, 0x21, 0x01, 0x04, 0x0A,
                  0x00, 0x81, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00,
                  0x80, 0x11, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x08D0, 0x08CC, 0x08C8, 0x01D1, 0x01D2, 0x01D2),
@@ -872,7 +872,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 128,
        .freq                   = 5640, /* MHz */
        .unk2                   = 3760,
-       RADIOREGS(0x71, 0x02, 0x34, 0x03, 0x1C, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x34, 0x02, 0x03, 0x1C, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x08D4, 0x08D0, 0x08CC, 0x01D0, 0x01D1, 0x01D2),
@@ -880,7 +880,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 130,
        .freq                   = 5650, /* MHz */
        .unk2                   = 3767,
-       RADIOREGS(0x71, 0x02, 0x35, 0x03, 0x1C, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x35, 0x02, 0x03, 0x1C, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x08D8, 0x08D4, 0x08D0, 0x01CF, 0x01D0, 0x01D1),
@@ -888,7 +888,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 132,
        .freq                   = 5660, /* MHz */
        .unk2                   = 3773,
-       RADIOREGS(0x71, 0x02, 0x36, 0x03, 0x16, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x36, 0x02, 0x03, 0x16, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x08DC, 0x08D8, 0x08D4, 0x01CE, 0x01CF, 0x01D0),
@@ -896,7 +896,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 134,
        .freq                   = 5670, /* MHz */
        .unk2                   = 3780,
-       RADIOREGS(0x71, 0x02, 0x37, 0x03, 0x16, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x37, 0x02, 0x03, 0x16, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x08E0, 0x08DC, 0x08D8, 0x01CE, 0x01CE, 0x01CF),
@@ -904,7 +904,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 136,
        .freq                   = 5680, /* MHz */
        .unk2                   = 3787,
-       RADIOREGS(0x71, 0x02, 0x38, 0x03, 0x10, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x38, 0x02, 0x03, 0x10, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x08E4, 0x08E0, 0x08DC, 0x01CD, 0x01CE, 0x01CE),
@@ -912,7 +912,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 138,
        .freq                   = 5690, /* MHz */
        .unk2                   = 3793,
-       RADIOREGS(0x71, 0x02, 0x39, 0x03, 0x10, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x39, 0x02, 0x03, 0x10, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x08E8, 0x08E4, 0x08E0, 0x01CC, 0x01CD, 0x01CE),
@@ -920,7 +920,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 140,
        .freq                   = 5700, /* MHz */
        .unk2                   = 3800,
-       RADIOREGS(0x71, 0x02, 0x3A, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x3A, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x08EC, 0x08E8, 0x08E4, 0x01CB, 0x01CC, 0x01CD),
@@ -928,7 +928,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 142,
        .freq                   = 5710, /* MHz */
        .unk2                   = 3807,
-       RADIOREGS(0x71, 0x02, 0x3B, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x3B, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x08F0, 0x08EC, 0x08E8, 0x01CA, 0x01CB, 0x01CC),
@@ -936,7 +936,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 144,
        .freq                   = 5720, /* MHz */
        .unk2                   = 3813,
-       RADIOREGS(0x71, 0x02, 0x3C, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x3C, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x08F4, 0x08F0, 0x08EC, 0x01C9, 0x01CA, 0x01CB),
@@ -944,7 +944,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 145,
        .freq                   = 5725, /* MHz */
        .unk2                   = 3817,
-       RADIOREGS(0x72, 0x04, 0x79, 0x02, 0x03, 0x01, 0x03, 0x14,
+       RADIOREGS(0x72, 0x79, 0x04, 0x02, 0x03, 0x01, 0x03, 0x14,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x08F6, 0x08F2, 0x08EE, 0x01C9, 0x01CA, 0x01CB),
@@ -952,7 +952,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 146,
        .freq                   = 5730, /* MHz */
        .unk2                   = 3820,
-       RADIOREGS(0x71, 0x02, 0x3D, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x3D, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x08F8, 0x08F4, 0x08F0, 0x01C9, 0x01C9, 0x01CA),
@@ -960,7 +960,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 147,
        .freq                   = 5735, /* MHz */
        .unk2                   = 3823,
-       RADIOREGS(0x72, 0x04, 0x7B, 0x02, 0x03, 0x01, 0x03, 0x14,
+       RADIOREGS(0x72, 0x7B, 0x04, 0x02, 0x03, 0x01, 0x03, 0x14,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x08FA, 0x08F6, 0x08F2, 0x01C8, 0x01C9, 0x01CA),
@@ -968,7 +968,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 148,
        .freq                   = 5740, /* MHz */
        .unk2                   = 3827,
-       RADIOREGS(0x71, 0x02, 0x3E, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x3E, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x08FC, 0x08F8, 0x08F4, 0x01C8, 0x01C9, 0x01C9),
@@ -976,7 +976,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 149,
        .freq                   = 5745, /* MHz */
        .unk2                   = 3830,
-       RADIOREGS(0x72, 0x04, 0x7D, 0x02, 0xFE, 0x00, 0x03, 0x14,
+       RADIOREGS(0x72, 0x7D, 0x04, 0x02, 0xFE, 0x00, 0x03, 0x14,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x08FE, 0x08FA, 0x08F6, 0x01C8, 0x01C8, 0x01C9),
@@ -984,7 +984,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 150,
        .freq                   = 5750, /* MHz */
        .unk2                   = 3833,
-       RADIOREGS(0x71, 0x02, 0x3F, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x3F, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x0900, 0x08FC, 0x08F8, 0x01C7, 0x01C8, 0x01C9),
@@ -992,7 +992,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 151,
        .freq                   = 5755, /* MHz */
        .unk2                   = 3837,
-       RADIOREGS(0x72, 0x04, 0x7F, 0x02, 0xFE, 0x00, 0x03, 0x14,
+       RADIOREGS(0x72, 0x7F, 0x04, 0x02, 0xFE, 0x00, 0x03, 0x14,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x0902, 0x08FE, 0x08FA, 0x01C7, 0x01C8, 0x01C8),
@@ -1000,7 +1000,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 152,
        .freq                   = 5760, /* MHz */
        .unk2                   = 3840,
-       RADIOREGS(0x71, 0x02, 0x40, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x40, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x0904, 0x0900, 0x08FC, 0x01C6, 0x01C7, 0x01C8),
@@ -1008,7 +1008,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 153,
        .freq                   = 5765, /* MHz */
        .unk2                   = 3843,
-       RADIOREGS(0x72, 0x04, 0x81, 0x02, 0xF8, 0x00, 0x03, 0x14,
+       RADIOREGS(0x72, 0x81, 0x04, 0x02, 0xF8, 0x00, 0x03, 0x14,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x0906, 0x0902, 0x08FE, 0x01C6, 0x01C7, 0x01C8),
@@ -1016,7 +1016,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 154,
        .freq                   = 5770, /* MHz */
        .unk2                   = 3847,
-       RADIOREGS(0x71, 0x02, 0x41, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x41, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x0908, 0x0904, 0x0900, 0x01C6, 0x01C6, 0x01C7),
@@ -1024,7 +1024,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 155,
        .freq                   = 5775, /* MHz */
        .unk2                   = 3850,
-       RADIOREGS(0x72, 0x04, 0x83, 0x02, 0xF8, 0x00, 0x03, 0x14,
+       RADIOREGS(0x72, 0x83, 0x04, 0x02, 0xF8, 0x00, 0x03, 0x14,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x090A, 0x0906, 0x0902, 0x01C5, 0x01C6, 0x01C7),
@@ -1032,7 +1032,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 156,
        .freq                   = 5780, /* MHz */
        .unk2                   = 3853,
-       RADIOREGS(0x71, 0x02, 0x42, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x42, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x090C, 0x0908, 0x0904, 0x01C5, 0x01C6, 0x01C6),
@@ -1040,7 +1040,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 157,
        .freq                   = 5785, /* MHz */
        .unk2                   = 3857,
-       RADIOREGS(0x72, 0x04, 0x85, 0x02, 0xF2, 0x00, 0x03, 0x14,
+       RADIOREGS(0x72, 0x85, 0x04, 0x02, 0xF2, 0x00, 0x03, 0x14,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x090E, 0x090A, 0x0906, 0x01C4, 0x01C5, 0x01C6),
@@ -1048,7 +1048,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 158,
        .freq                   = 5790, /* MHz */
        .unk2                   = 3860,
-       RADIOREGS(0x71, 0x02, 0x43, 0x02, 0x0A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x43, 0x02, 0x02, 0x0A, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x0910, 0x090C, 0x0908, 0x01C4, 0x01C5, 0x01C6),
@@ -1056,7 +1056,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 159,
        .freq                   = 5795, /* MHz */
        .unk2                   = 3863,
-       RADIOREGS(0x72, 0x04, 0x87, 0x02, 0xF2, 0x00, 0x03, 0x14,
+       RADIOREGS(0x72, 0x87, 0x04, 0x02, 0xF2, 0x00, 0x03, 0x14,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x0912, 0x090E, 0x090A, 0x01C4, 0x01C4, 0x01C5),
@@ -1064,7 +1064,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 160,
        .freq                   = 5800, /* MHz */
        .unk2                   = 3867,
-       RADIOREGS(0x71, 0x02, 0x44, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x44, 0x02, 0x01, 0x0A, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x0914, 0x0910, 0x090C, 0x01C3, 0x01C4, 0x01C5),
@@ -1072,7 +1072,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 161,
        .freq                   = 5805, /* MHz */
        .unk2                   = 3870,
-       RADIOREGS(0x72, 0x04, 0x89, 0x01, 0xED, 0x00, 0x03, 0x14,
+       RADIOREGS(0x72, 0x89, 0x04, 0x01, 0xED, 0x00, 0x03, 0x14,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x0916, 0x0912, 0x090E, 0x01C3, 0x01C4, 0x01C4),
@@ -1080,7 +1080,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 162,
        .freq                   = 5810, /* MHz */
        .unk2                   = 3873,
-       RADIOREGS(0x71, 0x02, 0x45, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x45, 0x02, 0x01, 0x0A, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x0918, 0x0914, 0x0910, 0x01C2, 0x01C3, 0x01C4),
@@ -1088,7 +1088,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 163,
        .freq                   = 5815, /* MHz */
        .unk2                   = 3877,
-       RADIOREGS(0x72, 0x04, 0x8B, 0x01, 0xED, 0x00, 0x03, 0x14,
+       RADIOREGS(0x72, 0x8B, 0x04, 0x01, 0xED, 0x00, 0x03, 0x14,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x091A, 0x0916, 0x0912, 0x01C2, 0x01C3, 0x01C4),
@@ -1096,7 +1096,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 164,
        .freq                   = 5820, /* MHz */
        .unk2                   = 3880,
-       RADIOREGS(0x71, 0x02, 0x46, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x46, 0x02, 0x01, 0x0A, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x091C, 0x0918, 0x0914, 0x01C2, 0x01C2, 0x01C3),
@@ -1104,7 +1104,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 165,
        .freq                   = 5825, /* MHz */
        .unk2                   = 3883,
-       RADIOREGS(0x72, 0x04, 0x8D, 0x01, 0xED, 0x00, 0x03, 0x14,
+       RADIOREGS(0x72, 0x8D, 0x04, 0x01, 0xED, 0x00, 0x03, 0x14,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x091E, 0x091A, 0x0916, 0x01C1, 0x01C2, 0x01C3),
@@ -1112,7 +1112,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 166,
        .freq                   = 5830, /* MHz */
        .unk2                   = 3887,
-       RADIOREGS(0x71, 0x02, 0x47, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x47, 0x02, 0x01, 0x0A, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x0920, 0x091C, 0x0918, 0x01C1, 0x01C2, 0x01C2),
@@ -1120,7 +1120,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 168,
        .freq                   = 5840, /* MHz */
        .unk2                   = 3893,
-       RADIOREGS(0x71, 0x02, 0x48, 0x01, 0x0A, 0x01, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x48, 0x02, 0x01, 0x0A, 0x01, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x0924, 0x0920, 0x091C, 0x01C0, 0x01C1, 0x01C2),
@@ -1128,7 +1128,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 170,
        .freq                   = 5850, /* MHz */
        .unk2                   = 3900,
-       RADIOREGS(0x71, 0x02, 0x49, 0x01, 0xE0, 0x00, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x49, 0x02, 0x01, 0xE0, 0x00, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x0928, 0x0924, 0x0920, 0x01BF, 0x01C0, 0x01C1),
@@ -1136,7 +1136,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 172,
        .freq                   = 5860, /* MHz */
        .unk2                   = 3907,
-       RADIOREGS(0x71, 0x02, 0x4A, 0x01, 0xDE, 0x00, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x4A, 0x02, 0x01, 0xDE, 0x00, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x092C, 0x0928, 0x0924, 0x01BF, 0x01BF, 0x01C0),
@@ -1144,7 +1144,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 174,
        .freq                   = 5870, /* MHz */
        .unk2                   = 3913,
-       RADIOREGS(0x71, 0x02, 0x4B, 0x00, 0xDB, 0x00, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x4B, 0x02, 0x00, 0xDB, 0x00, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x0930, 0x092C, 0x0928, 0x01BE, 0x01BF, 0x01BF),
@@ -1152,7 +1152,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 176,
        .freq                   = 5880, /* MHz */
        .unk2                   = 3920,
-       RADIOREGS(0x71, 0x02, 0x4C, 0x00, 0xD8, 0x00, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x4C, 0x02, 0x00, 0xD8, 0x00, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x0934, 0x0930, 0x092C, 0x01BD, 0x01BE, 0x01BF),
@@ -1160,7 +1160,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 178,
        .freq                   = 5890, /* MHz */
        .unk2                   = 3927,
-       RADIOREGS(0x71, 0x02, 0x4D, 0x00, 0xD6, 0x00, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x4D, 0x02, 0x00, 0xD6, 0x00, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x0938, 0x0934, 0x0930, 0x01BC, 0x01BD, 0x01BE),
@@ -1168,7 +1168,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 180,
        .freq                   = 5900, /* MHz */
        .unk2                   = 3933,
-       RADIOREGS(0x71, 0x02, 0x4E, 0x00, 0xD3, 0x00, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x4E, 0x02, 0x00, 0xD3, 0x00, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x093C, 0x0938, 0x0934, 0x01BC, 0x01BC, 0x01BD),
@@ -1176,7 +1176,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 182,
        .freq                   = 5910, /* MHz */
        .unk2                   = 3940,
-       RADIOREGS(0x71, 0x02, 0x4F, 0x00, 0xD6, 0x00, 0x04, 0x0A,
+       RADIOREGS(0x71, 0x4F, 0x02, 0x00, 0xD6, 0x00, 0x04, 0x0A,
                  0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
                  0x80, 0x00, 0x00, 0x00, 0x00, 0x80),
        PHYREGS(0x0940, 0x093C, 0x0938, 0x01BB, 0x01BC, 0x01BC),
@@ -1184,7 +1184,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 1,
        .freq                   = 2412, /* MHz */
        .unk2                   = 3216,
-       RADIOREGS(0x73, 0x09, 0x6C, 0x0F, 0x00, 0x01, 0x07, 0x15,
+       RADIOREGS(0x73, 0x6C, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
                  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0D, 0x0C,
                  0x80, 0xFF, 0x88, 0x0D, 0x0C, 0x80),
        PHYREGS(0x03C9, 0x03C5, 0x03C1, 0x043A, 0x043F, 0x0443),
@@ -1192,7 +1192,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 2,
        .freq                   = 2417, /* MHz */
        .unk2                   = 3223,
-       RADIOREGS(0x73, 0x09, 0x71, 0x0F, 0x00, 0x01, 0x07, 0x15,
+       RADIOREGS(0x73, 0x71, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
                  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0B,
                  0x80, 0xFF, 0x88, 0x0C, 0x0B, 0x80),
        PHYREGS(0x03CB, 0x03C7, 0x03C3, 0x0438, 0x043D, 0x0441),
@@ -1200,7 +1200,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 3,
        .freq                   = 2422, /* MHz */
        .unk2                   = 3229,
-       RADIOREGS(0x73, 0x09, 0x76, 0x0F, 0x00, 0x01, 0x07, 0x15,
+       RADIOREGS(0x73, 0x76, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
                  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A,
                  0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80),
        PHYREGS(0x03CD, 0x03C9, 0x03C5, 0x0436, 0x043A, 0x043F),
@@ -1208,7 +1208,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 4,
        .freq                   = 2427, /* MHz */
        .unk2                   = 3236,
-       RADIOREGS(0x73, 0x09, 0x7B, 0x0F, 0x00, 0x01, 0x07, 0x15,
+       RADIOREGS(0x73, 0x7B, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
                  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x0A,
                  0x80, 0xFF, 0x88, 0x0C, 0x0A, 0x80),
        PHYREGS(0x03CF, 0x03CB, 0x03C7, 0x0434, 0x0438, 0x043D),
@@ -1216,7 +1216,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 5,
        .freq                   = 2432, /* MHz */
        .unk2                   = 3243,
-       RADIOREGS(0x73, 0x09, 0x80, 0x0F, 0x00, 0x01, 0x07, 0x15,
+       RADIOREGS(0x73, 0x80, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
                  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0C, 0x09,
                  0x80, 0xFF, 0x88, 0x0C, 0x09, 0x80),
        PHYREGS(0x03D1, 0x03CD, 0x03C9, 0x0431, 0x0436, 0x043A),
@@ -1224,7 +1224,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 6,
        .freq                   = 2437, /* MHz */
        .unk2                   = 3249,
-       RADIOREGS(0x73, 0x09, 0x85, 0x0F, 0x00, 0x01, 0x07, 0x15,
+       RADIOREGS(0x73, 0x85, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
                  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0B, 0x08,
                  0x80, 0xFF, 0x88, 0x0B, 0x08, 0x80),
        PHYREGS(0x03D3, 0x03CF, 0x03CB, 0x042F, 0x0434, 0x0438),
@@ -1232,7 +1232,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 7,
        .freq                   = 2442, /* MHz */
        .unk2                   = 3256,
-       RADIOREGS(0x73, 0x09, 0x8A, 0x0F, 0x00, 0x01, 0x07, 0x15,
+       RADIOREGS(0x73, 0x8A, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
                  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x07,
                  0x80, 0xFF, 0x88, 0x0A, 0x07, 0x80),
        PHYREGS(0x03D5, 0x03D1, 0x03CD, 0x042D, 0x0431, 0x0436),
@@ -1240,7 +1240,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 8,
        .freq                   = 2447, /* MHz */
        .unk2                   = 3263,
-       RADIOREGS(0x73, 0x09, 0x8F, 0x0F, 0x00, 0x01, 0x07, 0x15,
+       RADIOREGS(0x73, 0x8F, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
                  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x0A, 0x06,
                  0x80, 0xFF, 0x88, 0x0A, 0x06, 0x80),
        PHYREGS(0x03D7, 0x03D3, 0x03CF, 0x042B, 0x042F, 0x0434),
@@ -1248,7 +1248,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 9,
        .freq                   = 2452, /* MHz */
        .unk2                   = 3269,
-       RADIOREGS(0x73, 0x09, 0x94, 0x0F, 0x00, 0x01, 0x07, 0x15,
+       RADIOREGS(0x73, 0x94, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
                  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x09, 0x06,
                  0x80, 0xFF, 0x88, 0x09, 0x06, 0x80),
        PHYREGS(0x03D9, 0x03D5, 0x03D1, 0x0429, 0x042D, 0x0431),
@@ -1256,7 +1256,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 10,
        .freq                   = 2457, /* MHz */
        .unk2                   = 3276,
-       RADIOREGS(0x73, 0x09, 0x99, 0x0F, 0x00, 0x01, 0x07, 0x15,
+       RADIOREGS(0x73, 0x99, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
                  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x05,
                  0x80, 0xFF, 0x88, 0x08, 0x05, 0x80),
        PHYREGS(0x03DB, 0x03D7, 0x03D3, 0x0427, 0x042B, 0x042F),
@@ -1264,7 +1264,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 11,
        .freq                   = 2462, /* MHz */
        .unk2                   = 3283,
-       RADIOREGS(0x73, 0x09, 0x9E, 0x0F, 0x00, 0x01, 0x07, 0x15,
+       RADIOREGS(0x73, 0x9E, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
                  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x04,
                  0x80, 0xFF, 0x88, 0x08, 0x04, 0x80),
        PHYREGS(0x03DD, 0x03D9, 0x03D5, 0x0424, 0x0429, 0x042D),
@@ -1272,7 +1272,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 12,
        .freq                   = 2467, /* MHz */
        .unk2                   = 3289,
-       RADIOREGS(0x73, 0x09, 0xA3, 0x0F, 0x00, 0x01, 0x07, 0x15,
+       RADIOREGS(0x73, 0xA3, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
                  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x08, 0x03,
                  0x80, 0xFF, 0x88, 0x08, 0x03, 0x80),
        PHYREGS(0x03DF, 0x03DB, 0x03D7, 0x0422, 0x0427, 0x042B),
@@ -1280,7 +1280,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 13,
        .freq                   = 2472, /* MHz */
        .unk2                   = 3296,
-       RADIOREGS(0x73, 0x09, 0xA8, 0x0F, 0x00, 0x01, 0x07, 0x15,
+       RADIOREGS(0x73, 0xA8, 0x09, 0x0F, 0x00, 0x01, 0x07, 0x15,
                  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x03,
                  0x80, 0xFF, 0x88, 0x07, 0x03, 0x80),
        PHYREGS(0x03E1, 0x03DD, 0x03D9, 0x0420, 0x0424, 0x0429),
@@ -1288,7 +1288,7 @@ static const struct b43_nphy_channeltab_entry_rev2 b43_nphy_channeltab_rev2[] =
   {    .channel                = 14,
        .freq                   = 2484, /* MHz */
        .unk2                   = 3312,
-       RADIOREGS(0x73, 0x09, 0xB4, 0x0F, 0xFF, 0x01, 0x07, 0x15,
+       RADIOREGS(0x73, 0xB4, 0x09, 0x0F, 0xFF, 0x01, 0x07, 0x15,
                  0x01, 0x8F, 0xFF, 0xFF, 0xFF, 0x88, 0x07, 0x01,
                  0x80, 0xFF, 0x88, 0x07, 0x01, 0x80),
        PHYREGS(0x03E6, 0x03E2, 0x03DE, 0x041B, 0x041F, 0x0424),
index 3100a72b9b44885379e24de680c0e619f9496c8b..fb3e3713bae4a015e69e9e56359794891078c01e 100644 (file)
@@ -278,8 +278,6 @@ struct iwl_cfg iwl1000_bgn_cfg = {
        .fw_name_pre = IWL1000_FW_PRE,
        .ucode_api_max = IWL1000_UCODE_API_MAX,
        .ucode_api_min = IWL1000_UCODE_API_MIN,
-       .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
        .ops = &iwl1000_ops,
@@ -294,8 +292,6 @@ struct iwl_cfg iwl1000_bg_cfg = {
        .fw_name_pre = IWL1000_FW_PRE,
        .ucode_api_max = IWL1000_UCODE_API_MAX,
        .ucode_api_min = IWL1000_UCODE_API_MIN,
-       .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
        .ops = &iwl1000_ops,
@@ -305,12 +301,10 @@ struct iwl_cfg iwl1000_bg_cfg = {
 };
 
 struct iwl_cfg iwl100_bgn_cfg = {
-       .name = "Intel(R) 100 Series 1x1 BGN",
+       .name = "Intel(R) Centrino(R) Wireless-N 100 BGN",
        .fw_name_pre = IWL100_FW_PRE,
        .ucode_api_max = IWL100_UCODE_API_MAX,
        .ucode_api_min = IWL100_UCODE_API_MIN,
-       .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_A,
        .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
        .ops = &iwl1000_ops,
@@ -321,12 +315,10 @@ struct iwl_cfg iwl100_bgn_cfg = {
 };
 
 struct iwl_cfg iwl100_bg_cfg = {
-       .name = "Intel(R) 100 Series 1x1 BG",
+       .name = "Intel(R) Centrino(R) Wireless-N 100 BG",
        .fw_name_pre = IWL100_FW_PRE,
        .ucode_api_max = IWL100_UCODE_API_MAX,
        .ucode_api_min = IWL100_UCODE_API_MIN,
-       .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_A,
        .eeprom_ver = EEPROM_1000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_1000_TX_POWER_VERSION,
        .ops = &iwl1000_ops,
index 3ee0f7c035cf2ffff22dd443ede736b96e16f260..cf74edb82a7031a17ae7b7380f98aef391439673 100644 (file)
@@ -527,8 +527,6 @@ struct iwl_cfg iwl5300_agn_cfg = {
        .fw_name_pre = IWL5000_FW_PRE,
        .ucode_api_max = IWL5000_UCODE_API_MAX,
        .ucode_api_min = IWL5000_UCODE_API_MIN,
-       .valid_tx_ant = ANT_ABC,
-       .valid_rx_ant = ANT_ABC,
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
        .ops = &iwl5000_ops,
@@ -543,8 +541,8 @@ struct iwl_cfg iwl5100_bgn_cfg = {
        .fw_name_pre = IWL5000_FW_PRE,
        .ucode_api_max = IWL5000_UCODE_API_MAX,
        .ucode_api_min = IWL5000_UCODE_API_MIN,
-       .valid_tx_ant = ANT_B,
-       .valid_rx_ant = ANT_AB,
+       .valid_tx_ant = ANT_B,          /* .cfg overwrite */
+       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
        .ops = &iwl5000_ops,
@@ -559,8 +557,8 @@ struct iwl_cfg iwl5100_abg_cfg = {
        .fw_name_pre = IWL5000_FW_PRE,
        .ucode_api_max = IWL5000_UCODE_API_MAX,
        .ucode_api_min = IWL5000_UCODE_API_MIN,
-       .valid_tx_ant = ANT_B,
-       .valid_rx_ant = ANT_AB,
+       .valid_tx_ant = ANT_B,          /* .cfg overwrite */
+       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
        .ops = &iwl5000_ops,
@@ -574,8 +572,8 @@ struct iwl_cfg iwl5100_agn_cfg = {
        .fw_name_pre = IWL5000_FW_PRE,
        .ucode_api_max = IWL5000_UCODE_API_MAX,
        .ucode_api_min = IWL5000_UCODE_API_MIN,
-       .valid_tx_ant = ANT_B,
-       .valid_rx_ant = ANT_AB,
+       .valid_tx_ant = ANT_B,          /* .cfg overwrite */
+       .valid_rx_ant = ANT_AB,         /* .cfg overwrite */
        .eeprom_ver = EEPROM_5000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5000_TX_POWER_VERSION,
        .ops = &iwl5000_ops,
@@ -590,8 +588,6 @@ struct iwl_cfg iwl5350_agn_cfg = {
        .fw_name_pre = IWL5000_FW_PRE,
        .ucode_api_max = IWL5000_UCODE_API_MAX,
        .ucode_api_min = IWL5000_UCODE_API_MIN,
-       .valid_tx_ant = ANT_ABC,
-       .valid_rx_ant = ANT_ABC,
        .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
        .ops = &iwl5000_ops,
@@ -606,8 +602,6 @@ struct iwl_cfg iwl5150_agn_cfg = {
        .fw_name_pre = IWL5150_FW_PRE,
        .ucode_api_max = IWL5150_UCODE_API_MAX,
        .ucode_api_min = IWL5150_UCODE_API_MIN,
-       .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
        .ops = &iwl5150_ops,
@@ -623,8 +617,6 @@ struct iwl_cfg iwl5150_abg_cfg = {
        .fw_name_pre = IWL5150_FW_PRE,
        .ucode_api_max = IWL5150_UCODE_API_MAX,
        .ucode_api_min = IWL5150_UCODE_API_MIN,
-       .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_5050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_5050_TX_POWER_VERSION,
        .ops = &iwl5150_ops,
index 93e3fe92f389175063ae072067119e3a06711b98..ec41f2725292443ac95c7534925cd4e3a6a13b82 100644 (file)
@@ -553,12 +553,10 @@ static struct iwl_bt_params iwl6000_bt_params = {
 };
 
 struct iwl_cfg iwl6000g2a_2agn_cfg = {
-       .name = "6000 Series 2x2 AGN Gen2a",
+       .name = "Intel(R) Centrino(R) Advanced-N 6205 AGN",
        .fw_name_pre = IWL6000G2A_FW_PRE,
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
        .ops = &iwl6000_ops,
@@ -571,12 +569,10 @@ struct iwl_cfg iwl6000g2a_2agn_cfg = {
 };
 
 struct iwl_cfg iwl6000g2a_2abg_cfg = {
-       .name = "6000 Series 2x2 ABG Gen2a",
+       .name = "Intel(R) Centrino(R) Advanced-N 6205 ABG",
        .fw_name_pre = IWL6000G2A_FW_PRE,
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
        .ops = &iwl6000_ops,
@@ -588,12 +584,10 @@ struct iwl_cfg iwl6000g2a_2abg_cfg = {
 };
 
 struct iwl_cfg iwl6000g2a_2bg_cfg = {
-       .name = "6000 Series 2x2 BG Gen2a",
+       .name = "Intel(R) Centrino(R) Advanced-N 6205 BG",
        .fw_name_pre = IWL6000G2A_FW_PRE,
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
        .ops = &iwl6000_ops,
@@ -605,12 +599,10 @@ struct iwl_cfg iwl6000g2a_2bg_cfg = {
 };
 
 struct iwl_cfg iwl6000g2b_2agn_cfg = {
-       .name = "6000 Series 2x2 AGN Gen2b",
+       .name = "Intel(R) Centrino(R) Advanced-N 6230 AGN",
        .fw_name_pre = IWL6000G2B_FW_PRE,
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
        .ops = &iwl6000g2b_ops,
@@ -627,12 +619,10 @@ struct iwl_cfg iwl6000g2b_2agn_cfg = {
 };
 
 struct iwl_cfg iwl6000g2b_2abg_cfg = {
-       .name = "6000 Series 2x2 ABG Gen2b",
+       .name = "Intel(R) Centrino(R) Advanced-N 6230 ABG",
        .fw_name_pre = IWL6000G2B_FW_PRE,
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
        .ops = &iwl6000g2b_ops,
@@ -648,12 +638,10 @@ struct iwl_cfg iwl6000g2b_2abg_cfg = {
 };
 
 struct iwl_cfg iwl6000g2b_2bgn_cfg = {
-       .name = "6000 Series 2x2 BGN Gen2b",
+       .name = "Intel(R) Centrino(R) Advanced-N 6230 BGN",
        .fw_name_pre = IWL6000G2B_FW_PRE,
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
        .ops = &iwl6000g2b_ops,
@@ -670,12 +658,10 @@ struct iwl_cfg iwl6000g2b_2bgn_cfg = {
 };
 
 struct iwl_cfg iwl6000g2b_2bg_cfg = {
-       .name = "6000 Series 2x2 BG Gen2b",
+       .name = "Intel(R) Centrino(R) Advanced-N 6230 BG",
        .fw_name_pre = IWL6000G2B_FW_PRE,
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
        .ops = &iwl6000g2b_ops,
@@ -691,12 +677,10 @@ struct iwl_cfg iwl6000g2b_2bg_cfg = {
 };
 
 struct iwl_cfg iwl6000g2b_bgn_cfg = {
-       .name = "6000 Series 1x2 BGN Gen2b",
+       .name = "Intel(R) Centrino(R) Wireless-N 1030 BGN",
        .fw_name_pre = IWL6000G2B_FW_PRE,
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
-       .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
        .ops = &iwl6000g2b_ops,
@@ -713,12 +697,10 @@ struct iwl_cfg iwl6000g2b_bgn_cfg = {
 };
 
 struct iwl_cfg iwl6000g2b_bg_cfg = {
-       .name = "6000 Series 1x2 BG Gen2b",
+       .name = "Intel(R) Centrino(R) Wireless-N 1030 BG",
        .fw_name_pre = IWL6000G2B_FW_PRE,
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
-       .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
        .ops = &iwl6000g2b_ops,
@@ -741,8 +723,8 @@ struct iwl_cfg iwl6000i_2agn_cfg = {
        .fw_name_pre = IWL6000_FW_PRE,
        .ucode_api_max = IWL6000_UCODE_API_MAX,
        .ucode_api_min = IWL6000_UCODE_API_MIN,
-       .valid_tx_ant = ANT_BC,
-       .valid_rx_ant = ANT_BC,
+       .valid_tx_ant = ANT_BC,         /* .cfg overwrite */
+       .valid_rx_ant = ANT_BC,         /* .cfg overwrite */
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
        .ops = &iwl6000_ops,
@@ -758,8 +740,8 @@ struct iwl_cfg iwl6000i_2abg_cfg = {
        .fw_name_pre = IWL6000_FW_PRE,
        .ucode_api_max = IWL6000_UCODE_API_MAX,
        .ucode_api_min = IWL6000_UCODE_API_MIN,
-       .valid_tx_ant = ANT_BC,
-       .valid_rx_ant = ANT_BC,
+       .valid_tx_ant = ANT_BC,         /* .cfg overwrite */
+       .valid_rx_ant = ANT_BC,         /* .cfg overwrite */
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
        .ops = &iwl6000_ops,
@@ -774,8 +756,8 @@ struct iwl_cfg iwl6000i_2bg_cfg = {
        .fw_name_pre = IWL6000_FW_PRE,
        .ucode_api_max = IWL6000_UCODE_API_MAX,
        .ucode_api_min = IWL6000_UCODE_API_MIN,
-       .valid_tx_ant = ANT_BC,
-       .valid_rx_ant = ANT_BC,
+       .valid_tx_ant = ANT_BC,         /* .cfg overwrite */
+       .valid_rx_ant = ANT_BC,         /* .cfg overwrite */
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
        .ops = &iwl6000_ops,
@@ -790,8 +772,6 @@ struct iwl_cfg iwl6050_2agn_cfg = {
        .fw_name_pre = IWL6050_FW_PRE,
        .ucode_api_max = IWL6050_UCODE_API_MAX,
        .ucode_api_min = IWL6050_UCODE_API_MIN,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
        .ops = &iwl6050_ops,
        .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
@@ -803,12 +783,10 @@ struct iwl_cfg iwl6050_2agn_cfg = {
 };
 
 struct iwl_cfg iwl6050g2_bgn_cfg = {
-       .name = "6050 Series 1x2 BGN Gen2",
+       .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BGN",
        .fw_name_pre = IWL6050_FW_PRE,
        .ucode_api_max = IWL6050_UCODE_API_MAX,
        .ucode_api_min = IWL6050_UCODE_API_MIN,
-       .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6050G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6050G2_TX_POWER_VERSION,
        .ops = &iwl6050g2_ops,
@@ -824,8 +802,6 @@ struct iwl_cfg iwl6050_2abg_cfg = {
        .fw_name_pre = IWL6050_FW_PRE,
        .ucode_api_max = IWL6050_UCODE_API_MAX,
        .ucode_api_min = IWL6050_UCODE_API_MIN,
-       .valid_tx_ant = ANT_AB,
-       .valid_rx_ant = ANT_AB,
        .eeprom_ver = EEPROM_6050_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6050_TX_POWER_VERSION,
        .ops = &iwl6050_ops,
@@ -840,8 +816,6 @@ struct iwl_cfg iwl6000_3agn_cfg = {
        .fw_name_pre = IWL6000_FW_PRE,
        .ucode_api_max = IWL6000_UCODE_API_MAX,
        .ucode_api_min = IWL6000_UCODE_API_MIN,
-       .valid_tx_ant = ANT_ABC,
-       .valid_rx_ant = ANT_ABC,
        .eeprom_ver = EEPROM_6000_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000_TX_POWER_VERSION,
        .ops = &iwl6000_ops,
@@ -853,12 +827,10 @@ struct iwl_cfg iwl6000_3agn_cfg = {
 };
 
 struct iwl_cfg iwl130_bgn_cfg = {
-       .name = "Intel(R) 130 Series 1x1 BGN",
+       .name = "Intel(R) Centrino(R) Wireless-N 130 BGN",
        .fw_name_pre = IWL6000G2B_FW_PRE,
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
-       .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_A,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
        .ops = &iwl6000g2b_ops,
@@ -874,12 +846,10 @@ struct iwl_cfg iwl130_bgn_cfg = {
 };
 
 struct iwl_cfg iwl130_bg_cfg = {
-       .name = "Intel(R) 130 Series 1x2 BG",
+       .name = "Intel(R) Centrino(R) Wireless-N 130 BG",
        .fw_name_pre = IWL6000G2B_FW_PRE,
        .ucode_api_max = IWL6000G2_UCODE_API_MAX,
        .ucode_api_min = IWL6000G2_UCODE_API_MIN,
-       .valid_tx_ant = ANT_A,
-       .valid_rx_ant = ANT_A,
        .eeprom_ver = EEPROM_6000G2_EEPROM_VERSION,
        .eeprom_calib_ver = EEPROM_6000G2_TX_POWER_VERSION,
        .ops = &iwl6000g2b_ops,
index 8a4d3acb9b79114088885123de8dec407156ed69..dbada761624dae241fd493f944508b851d734474 100644 (file)
@@ -251,6 +251,7 @@ err:
 int iwl_eeprom_check_sku(struct iwl_priv *priv)
 {
        u16 eeprom_sku;
+       u16 radio_cfg;
 
        eeprom_sku = iwl_eeprom_query16(priv, EEPROM_SKU_CAP);
 
@@ -266,6 +267,25 @@ int iwl_eeprom_check_sku(struct iwl_priv *priv)
 
        IWL_INFO(priv, "Device SKU: 0X%x\n", priv->cfg->sku);
 
+       if (!priv->cfg->valid_tx_ant && !priv->cfg->valid_rx_ant) {
+               /* not using .cfg overwrite */
+               radio_cfg = iwl_eeprom_query16(priv, EEPROM_RADIO_CONFIG);
+               priv->cfg->valid_tx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg);
+               priv->cfg->valid_rx_ant = EEPROM_RF_CFG_TX_ANT_MSK(radio_cfg);
+               if (!priv->cfg->valid_tx_ant || !priv->cfg->valid_rx_ant) {
+                       IWL_ERR(priv, "Invalid chain (0X%x, 0X%x)\n",
+                               priv->cfg->valid_tx_ant,
+                               priv->cfg->valid_rx_ant);
+                       return -EINVAL;
+               }
+               IWL_INFO(priv, "Valid Tx ant: 0X%x, Valid Rx ant: 0X%x\n",
+                        priv->cfg->valid_tx_ant, priv->cfg->valid_rx_ant);
+       }
+       /*
+        * for some special cases,
+        * EEPROM did not reflect the correct antenna setting
+        * so overwrite the valid tx/rx antenna from .cfg
+        */
        return 0;
 }
 
index f8fe5f44e19fbca2d912d3b4abe791278c5f017c..407f0bb8422a926dda78a0a381700246c2958257 100644 (file)
@@ -1778,7 +1778,7 @@ static const __le32 iwlagn_def_3w_lookup[12] = {
        cpu_to_le32(0xc0004000),
        cpu_to_le32(0x00004000),
        cpu_to_le32(0xf0005000),
-       cpu_to_le32(0xf0004000),
+       cpu_to_le32(0xf0005000),
 };
 
 static const __le32 iwlagn_concurrent_lookup[12] = {
@@ -1814,6 +1814,7 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
                bt_cmd.prio_boost = 0;
        bt_cmd.kill_ack_mask = priv->kill_ack_mask;
        bt_cmd.kill_cts_mask = priv->kill_cts_mask;
+
        bt_cmd.valid = priv->bt_valid;
        bt_cmd.tx_prio_boost = 0;
        bt_cmd.rx_prio_boost = 0;
@@ -1996,24 +1997,29 @@ static void iwlagn_print_uartmsg(struct iwl_priv *priv,
                        BT_UART_MSG_FRAME7CONNECTABLE_POS);
 }
 
-static void iwlagn_set_kill_ack_msk(struct iwl_priv *priv,
-                                    struct iwl_bt_uart_msg *uart_msg)
+static void iwlagn_set_kill_msk(struct iwl_priv *priv,
+                               struct iwl_bt_uart_msg *uart_msg)
 {
-       u8 kill_ack_msk;
+       u8 kill_msk;
        static const __le32 bt_kill_ack_msg[2] = {
-                       cpu_to_le32(0xFFFFFFF), cpu_to_le32(0xFFFFFC00) };
-
-       kill_ack_msk = (((BT_UART_MSG_FRAME3A2DP_MSK |
-                       BT_UART_MSG_FRAME3SNIFF_MSK |
-                       BT_UART_MSG_FRAME3SCOESCO_MSK) &
-                       uart_msg->frame3) == 0) ? 1 : 0;
-       if (priv->kill_ack_mask != bt_kill_ack_msg[kill_ack_msk]) {
+               IWLAGN_BT_KILL_ACK_MASK_DEFAULT,
+               IWLAGN_BT_KILL_ACK_CTS_MASK_SCO };
+       static const __le32 bt_kill_cts_msg[2] = {
+               IWLAGN_BT_KILL_CTS_MASK_DEFAULT,
+               IWLAGN_BT_KILL_ACK_CTS_MASK_SCO };
+
+       kill_msk = (BT_UART_MSG_FRAME3SCOESCO_MSK & uart_msg->frame3)
+               ? 1 : 0;
+       if (priv->kill_ack_mask != bt_kill_ack_msg[kill_msk] ||
+           priv->kill_cts_mask != bt_kill_cts_msg[kill_msk]) {
                priv->bt_valid |= IWLAGN_BT_VALID_KILL_ACK_MASK;
-               priv->kill_ack_mask = bt_kill_ack_msg[kill_ack_msk];
+               priv->kill_ack_mask = bt_kill_ack_msg[kill_msk];
+               priv->bt_valid |= IWLAGN_BT_VALID_KILL_CTS_MASK;
+               priv->kill_cts_mask = bt_kill_cts_msg[kill_msk];
+
                /* schedule to send runtime bt_config */
                queue_work(priv->workqueue, &priv->bt_runtime_config);
        }
-
 }
 
 void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
@@ -2064,7 +2070,7 @@ void iwlagn_bt_coex_profile_notif(struct iwl_priv *priv,
                }
        }
 
-       iwlagn_set_kill_ack_msk(priv, uart_msg);
+       iwlagn_set_kill_msk(priv, uart_msg);
 
        /* FIXME: based on notification, adjust the prio_boost */
 
index 07bbc915529a34ac0945565b30d4126ef2ab559e..72b1f262796ca73ecd7cc3e8f0d4d46e2e7ec51b 100644 (file)
  */
 
 static const u8 tid_to_ac[] = {
-       /* this matches the mac80211 numbers */
-       2, 3, 3, 2, 1, 1, 0, 0
+       IEEE80211_AC_BE,
+       IEEE80211_AC_BK,
+       IEEE80211_AC_BK,
+       IEEE80211_AC_BE,
+       IEEE80211_AC_VI,
+       IEEE80211_AC_VI,
+       IEEE80211_AC_VO,
+       IEEE80211_AC_VO
 };
 
 static inline int get_ac_from_tid(u16 tid)
@@ -531,6 +537,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        u8 tid = 0;
        u8 *qc = NULL;
        unsigned long flags;
+       bool is_agg = false;
 
        if (info->control.vif)
                ctx = iwl_rxon_ctx_from_vif(info->control.vif);
@@ -567,8 +574,8 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
        if (sta)
                sta_priv = (void *)sta->drv_priv;
 
-       if (sta_priv && sta_priv->asleep) {
-               WARN_ON(!(info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE));
+       if (sta_priv && sta_priv->asleep &&
+           (info->flags & IEEE80211_TX_CTL_PSPOLL_RESPONSE)) {
                /*
                 * This sends an asynchronous command to the device,
                 * but we can rely on it being processed before the
@@ -616,6 +623,7 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                if (info->flags & IEEE80211_TX_CTL_AMPDU &&
                    priv->stations[sta_id].tid[tid].agg.state == IWL_AGG_ON) {
                        txq_id = priv->stations[sta_id].tid[tid].agg.txq_id;
+                       is_agg = true;
                }
        }
 
@@ -763,8 +771,14 @@ int iwlagn_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
         * whether or not we should update the write pointer.
         */
 
-       /* avoid atomic ops if it isn't an associated client */
-       if (sta_priv && sta_priv->client)
+       /*
+        * Avoid atomic ops if it isn't an associated client.
+        * Also, if this is a packet for aggregation, don't
+        * increase the counter because the ucode will stop
+        * aggregation queues when their respective station
+        * goes to sleep.
+        */
+       if (sta_priv && sta_priv->client && !is_agg)
                atomic_inc(&sta_priv->pending_frames);
 
        if ((iwl_queue_space(q) < q->high_mark) && priv->mac80211_registered) {
@@ -1143,14 +1157,15 @@ int iwlagn_txq_check_empty(struct iwl_priv *priv,
        return 0;
 }
 
-static void iwlagn_tx_status(struct iwl_priv *priv, struct iwl_tx_info *tx_info)
+static void iwlagn_non_agg_tx_status(struct iwl_priv *priv,
+                                    struct iwl_rxon_context *ctx,
+                                    const u8 *addr1)
 {
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx_info->skb->data;
        struct ieee80211_sta *sta;
        struct iwl_station_priv *sta_priv;
 
        rcu_read_lock();
-       sta = ieee80211_find_sta(tx_info->ctx->vif, hdr->addr1);
+       sta = ieee80211_find_sta(ctx->vif, addr1);
        if (sta) {
                sta_priv = (void *)sta->drv_priv;
                /* avoid atomic ops if this isn't a client */
@@ -1159,6 +1174,15 @@ static void iwlagn_tx_status(struct iwl_priv *priv, struct iwl_tx_info *tx_info)
                        ieee80211_sta_block_awake(priv->hw, sta, false);
        }
        rcu_read_unlock();
+}
+
+static void iwlagn_tx_status(struct iwl_priv *priv, struct iwl_tx_info *tx_info,
+                            bool is_agg)
+{
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) tx_info->skb->data;
+
+       if (!is_agg)
+               iwlagn_non_agg_tx_status(priv, tx_info->ctx, hdr->addr1);
 
        ieee80211_tx_status_irqsafe(priv->hw, tx_info->skb);
 }
@@ -1183,7 +1207,8 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
             q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
 
                tx_info = &txq->txb[txq->q.read_ptr];
-               iwlagn_tx_status(priv, tx_info);
+               iwlagn_tx_status(priv, tx_info,
+                                txq_id >= IWLAGN_FIRST_AMPDU_QUEUE);
 
                hdr = (struct ieee80211_hdr *)tx_info->skb->data;
                if (hdr && ieee80211_is_data_qos(hdr->frame_control))
index 411a7a20450a975768c8b0f8f41dd0af67c79dc5..0bdd2bb0bbd315337ed887b8b7078c48e26bab30 100644 (file)
@@ -47,10 +47,10 @@ struct queue_to_fifo_ac {
 };
 
 static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = {
-       { IWL_TX_FIFO_VO, 0, },
-       { IWL_TX_FIFO_VI, 1, },
-       { IWL_TX_FIFO_BE, 2, },
-       { IWL_TX_FIFO_BK, 3, },
+       { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
+       { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
+       { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
+       { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
        { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
        { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
        { IWL_TX_FIFO_UNUSED, IWL_AC_UNSET, },
@@ -60,14 +60,14 @@ static const struct queue_to_fifo_ac iwlagn_default_queue_to_tx_fifo[] = {
 };
 
 static const struct queue_to_fifo_ac iwlagn_ipan_queue_to_tx_fifo[] = {
-       { IWL_TX_FIFO_VO, 0, },
-       { IWL_TX_FIFO_VI, 1, },
-       { IWL_TX_FIFO_BE, 2, },
-       { IWL_TX_FIFO_BK, 3, },
-       { IWL_TX_FIFO_BK_IPAN, 3, },
-       { IWL_TX_FIFO_BE_IPAN, 2, },
-       { IWL_TX_FIFO_VI_IPAN, 1, },
-       { IWL_TX_FIFO_VO_IPAN, 0, },
+       { IWL_TX_FIFO_VO, IEEE80211_AC_VO, },
+       { IWL_TX_FIFO_VI, IEEE80211_AC_VI, },
+       { IWL_TX_FIFO_BE, IEEE80211_AC_BE, },
+       { IWL_TX_FIFO_BK, IEEE80211_AC_BK, },
+       { IWL_TX_FIFO_BK_IPAN, IEEE80211_AC_BK, },
+       { IWL_TX_FIFO_BE_IPAN, IEEE80211_AC_BE, },
+       { IWL_TX_FIFO_VI_IPAN, IEEE80211_AC_VI, },
+       { IWL_TX_FIFO_VO_IPAN, IEEE80211_AC_VO, },
        { IWL_TX_FIFO_BE_IPAN, 2, },
        { IWLAGN_CMD_FIFO_NUM, IWL_AC_UNSET, },
 };
index 5b96b0d80091c648fd1b6cd5af557493393d1d81..50cee2b5a6b7b61251c2a49d93825561709d6e07 100644 (file)
@@ -3175,7 +3175,8 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
        hw->flags = IEEE80211_HW_SIGNAL_DBM |
                    IEEE80211_HW_AMPDU_AGGREGATION |
                    IEEE80211_HW_NEED_DTIM_PERIOD |
-                   IEEE80211_HW_SPECTRUM_MGMT;
+                   IEEE80211_HW_SPECTRUM_MGMT |
+                   IEEE80211_HW_REPORTS_TX_ACK_STATUS;
 
        if (!priv->cfg->base_params->broken_powersave)
                hw->flags |= IEEE80211_HW_SUPPORTS_PS |
index c9448cba1e20aebbd349524effe75e6337ffda7a..f893d4a6aa876a69b2869c3fbb0edaa642b7dfed 100644 (file)
@@ -2453,6 +2453,7 @@ struct iwl_bt_cmd {
 
 #define IWLAGN_BT_KILL_ACK_MASK_DEFAULT        cpu_to_le32(0xffff0000)
 #define IWLAGN_BT_KILL_CTS_MASK_DEFAULT        cpu_to_le32(0xffff0000)
+#define IWLAGN_BT_KILL_ACK_CTS_MASK_SCO        cpu_to_le32(0xffffffff)
 
 #define IWLAGN_BT3_PRIO_SAMPLE_DEFAULT 2
 
index e87be1e551aa0127f22cb2badd2e3257ac6f75b0..583916db46e49a0f74b7ea31a3056676d421e5e4 100644 (file)
@@ -410,7 +410,6 @@ struct iwl_eeprom_calib_info {
 #define EEPROM_OEM_MODE                     (2*0x46)   /* 2  bytes */
 #define EEPROM_WOWLAN_MODE                  (2*0x47)   /* 2  bytes */
 #define EEPROM_RADIO_CONFIG                 (2*0x48)   /* 2  bytes */
-#define EEPROM_3945_M_VERSION               (2*0x4A)   /* 1  bytes */
 #define EEPROM_NUM_MAC_ADDRESS              (2*0x4C)   /* 2  bytes */
 
 /* The following masks are to be applied on EEPROM_RADIO_CONFIG */
index e5685dc317a80423a7acb6a68694bba4043d3897..b4de0ca10feb8f9ef18b826e00f82a240fb40e91 100644 (file)
@@ -1170,7 +1170,6 @@ static void if_sdio_remove(struct sdio_func *func)
        lbs_deb_sdio("call remove card\n");
        lbs_stop_card(card->priv);
        lbs_remove_card(card->priv);
-       card->priv->surpriseremoved = 1;
 
        flush_workqueue(card->workqueue);
        destroy_workqueue(card->workqueue);
index 79bcb4e5d2ca03c7ccb82621576296a6ea68b5d0..ecd4d04b2c3cea67aebd6d62c9446a3318a2840c 100644 (file)
@@ -1055,7 +1055,6 @@ static int __devexit libertas_spi_remove(struct spi_device *spi)
        lbs_stop_card(priv);
        lbs_remove_card(priv); /* will call free_netdev */
 
-       priv->surpriseremoved = 1;
        free_irq(spi->irq, card);
        if_spi_terminate_spi_thread(card);
        if (card->pdata->teardown)
index 143473c5939323c75a2a15a915bfd1df5d9f315d..6836a6dd985331d7462034b808ffcf422c6e587d 100644 (file)
@@ -916,8 +916,6 @@ void lbs_remove_card(struct lbs_private *priv)
 
        lbs_free_adapter(priv);
        lbs_cfg_free(priv);
-
-       priv->dev = NULL;
        free_netdev(dev);
 
        lbs_deb_leave(LBS_DEB_MAIN);
index e8e2d0f4763db4f33e899ad712595d9af5173333..fa0cf744958fc2f21d1d61f842bd9e2214ba0b7f 100644 (file)
@@ -1392,10 +1392,9 @@ static void orinoco_process_scan_results(struct work_struct *work)
                                orinoco_add_hostscan_results(priv, buf, len);
 
                        kfree(buf);
-               } else if (priv->scan_request) {
+               } else {
                        /* Either abort or complete the scan */
-                       cfg80211_scan_done(priv->scan_request, (len < 0));
-                       priv->scan_request = NULL;
+                       orinoco_scan_done(priv, (len < 0));
                }
 
                spin_lock_irqsave(&priv->scan_lock, flags);
@@ -1684,6 +1683,8 @@ static int __orinoco_down(struct orinoco_private *priv)
                hermes_write_regn(hw, EVACK, 0xffff);
        }
 
+       orinoco_scan_done(priv, true);
+
        /* firmware will have to reassociate */
        netif_carrier_off(dev);
        priv->last_linkstatus = 0xffff;
@@ -1762,10 +1763,7 @@ void orinoco_reset(struct work_struct *work)
        orinoco_unlock(priv, &flags);
 
        /* Scanning support: Notify scan cancellation */
-       if (priv->scan_request) {
-               cfg80211_scan_done(priv->scan_request, 1);
-               priv->scan_request = NULL;
-       }
+       orinoco_scan_done(priv, true);
 
        if (priv->hard_reset) {
                err = (*priv->hard_reset)(priv);
index 4300d9db7d8caab2d70442b7cbd37a9da69adef9..86cb54c842e745ffd7863457f23f45185440f556 100644 (file)
@@ -229,3 +229,11 @@ void orinoco_add_hostscan_results(struct orinoco_private *priv,
                priv->scan_request = NULL;
        }
 }
+
+void orinoco_scan_done(struct orinoco_private *priv, bool abort)
+{
+       if (priv->scan_request) {
+               cfg80211_scan_done(priv->scan_request, abort);
+               priv->scan_request = NULL;
+       }
+}
index 2dc4e046dbdb61c5c19f33e14f6ae4fae381a8c9..27281fb0a6dc02f529b4ea1edf2fb29e2a6903be 100644 (file)
@@ -16,5 +16,6 @@ void orinoco_add_extscan_result(struct orinoco_private *priv,
 void orinoco_add_hostscan_results(struct orinoco_private *dev,
                                  unsigned char *buf,
                                  size_t len);
+void orinoco_scan_done(struct orinoco_private *priv, bool abort);
 
 #endif /* _ORINOCO_SCAN_H_ */
index d5bc21e5a02c7520d6599ad5822eafe85b267823..dd4d8fc9ad7ad9cb8f467a4e9dc011048e5c8c0b 100644 (file)
@@ -183,7 +183,7 @@ static void p54u_rx_cb(struct urb *urb)
 static void p54u_tx_cb(struct urb *urb)
 {
        struct sk_buff *skb = urb->context;
-       struct ieee80211_hw *dev = (struct ieee80211_hw *)
+       struct ieee80211_hw *dev =
                usb_get_intfdata(usb_ifnum_to_if(urb->dev, 0));
 
        p54_free_skb(dev, skb);
index 2b1cbba90a84056e098b0b20af32389840d0e58a..0764d1a30d13f2637ae624d43446e26a07f6ffd9 100644 (file)
@@ -1776,11 +1776,8 @@ static void ray_update_multi_list(struct net_device *dev, int all)
                /* Copy the kernel's list of MC addresses to card */
                netdev_for_each_mc_addr(ha, dev) {
                        memcpy_toio(p, ha->addr, ETH_ALEN);
-                       dev_dbg(&link->dev,
-                             "ray_update_multi add addr %02x%02x%02x%02x%02x%02x\n",
-                             ha->addr[0], ha->addr[1],
-                             ha->addr[2], ha->addr[3],
-                             ha->addr[4], ha->addr[5]);
+                       dev_dbg(&link->dev, "ray_update_multi add addr %pm\n",
+                               ha->addr);
                        p += ETH_ALEN;
                        i++;
                }
@@ -2015,11 +2012,8 @@ static irqreturn_t ray_interrupt(int irq, void *dev_id)
                                memcpy_fromio(&local->bss_id,
                                              prcs->var.rejoin_net_complete.
                                              bssid, ADDRLEN);
-                               dev_dbg(&link->dev,
-                                     "ray_cs new BSSID = %02x%02x%02x%02x%02x%02x\n",
-                                     local->bss_id[0], local->bss_id[1],
-                                     local->bss_id[2], local->bss_id[3],
-                                     local->bss_id[4], local->bss_id[5]);
+                               dev_dbg(&link->dev, "ray_cs new BSSID = %pm\n",
+                                       local->bss_id);
                                if (!sniffer)
                                        authenticate(local);
                        }
index 433c7f3ef837c901ec149905e3443fffd8a16b1f..b989b0d3ed499e9f7667f40094134d47ee87e6aa 100644 (file)
@@ -911,6 +911,7 @@ static int rt2800pci_probe_hw(struct rt2x00_dev *rt2x00dev)
        __set_bit(DRIVER_REQUIRE_DMA, &rt2x00dev->flags);
        __set_bit(DRIVER_REQUIRE_L2PAD, &rt2x00dev->flags);
        __set_bit(DRIVER_REQUIRE_TXSTATUS_FIFO, &rt2x00dev->flags);
+       __set_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags);
        if (!modparam_nohwcrypt)
                __set_bit(CONFIG_SUPPORT_HW_CRYPTO, &rt2x00dev->flags);
        __set_bit(DRIVER_SUPPORT_LINK_TUNING, &rt2x00dev->flags);
index 0a55eeff871e80126c07616eac938087393f184e..e72117f3fdf59d2d6c9f134bc182854c9d2456db 100644 (file)
@@ -664,6 +664,7 @@ enum rt2x00_flags {
        DRIVER_REQUIRE_COPY_IV,
        DRIVER_REQUIRE_L2PAD,
        DRIVER_REQUIRE_TXSTATUS_FIFO,
+       DRIVER_REQUIRE_TASKLET_CONTEXT,
 
        /*
         * Driver features
index c879f9a7037c39a76a2d709e6de3f3aa901417f3..bd3afc92f4343af8b006bf5597136ceafb6312fb 100644 (file)
@@ -379,9 +379,12 @@ void rt2x00lib_txdone(struct queue_entry *entry,
         * through a mac80211 library call (RTS/CTS) then we should not
         * send the status report back.
         */
-       if (!(skbdesc_flags & SKBDESC_NOT_MAC80211))
-               ieee80211_tx_status(rt2x00dev->hw, entry->skb);
-       else
+       if (!(skbdesc_flags & SKBDESC_NOT_MAC80211)) {
+               if (test_bit(DRIVER_REQUIRE_TASKLET_CONTEXT, &rt2x00dev->flags))
+                       ieee80211_tx_status(rt2x00dev->hw, entry->skb);
+               else
+                       ieee80211_tx_status_ni(rt2x00dev->hw, entry->skb);
+       } else
                dev_kfree_skb_any(entry->skb);
 
        /*
index b97aa9c78a96d925e4de5f25504c008f60f3dfad..415eec401e2e5aa55be1f4f688f90ef7f50785a2 100644 (file)
@@ -1830,7 +1830,7 @@ err_zd:
 
 static void zd1201_disconnect(struct usb_interface *interface)
 {
-       struct zd1201 *zd=(struct zd1201 *)usb_get_intfdata(interface);
+       struct zd1201 *zd = usb_get_intfdata(interface);
        struct hlist_node *node, *node2;
        struct zd1201_frag *frag;
 
index 2de52d18152f1fb6b71ff631b576e5252059c4ed..de6c3086d232b64eab460764b3407edba021a328 100644 (file)
@@ -1000,21 +1000,6 @@ static int xemaclite_close(struct net_device *dev)
        return 0;
 }
 
-/**
- * xemaclite_get_stats - Get the stats for the net_device
- * @dev:       Pointer to the network device
- *
- * This function returns the address of the 'net_device_stats' structure for the
- * given network device. This structure holds usage statistics for the network
- * device.
- *
- * Return:     Pointer to the net_device_stats structure.
- */
-static struct net_device_stats *xemaclite_get_stats(struct net_device *dev)
-{
-       return &dev->stats;
-}
-
 /**
  * xemaclite_send - Transmit a frame
  * @orig_skb:  Pointer to the socket buffer to be transmitted
@@ -1285,7 +1270,6 @@ static struct net_device_ops xemaclite_netdev_ops = {
        .ndo_start_xmit         = xemaclite_send,
        .ndo_set_mac_address    = xemaclite_set_mac_address,
        .ndo_tx_timeout         = xemaclite_tx_timeout,
-       .ndo_get_stats          = xemaclite_get_stats,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller = xemaclite_poll_controller,
 #endif
index c68b3dc19e11d3368cbd2c1dac1dc0a2d451ef48..3918d2cc5856b333600c6fc313a611eb66ff97fd 100644 (file)
@@ -383,6 +383,35 @@ static int ssb_device_uevent(struct device *dev, struct kobj_uevent_env *env)
                             ssb_dev->id.revision);
 }
 
+#define ssb_config_attr(attrib, field, format_string) \
+static ssize_t \
+attrib##_show(struct device *dev, struct device_attribute *attr, char *buf) \
+{ \
+       return sprintf(buf, format_string, dev_to_ssb_dev(dev)->field); \
+}
+
+ssb_config_attr(core_num, core_index, "%u\n")
+ssb_config_attr(coreid, id.coreid, "0x%04x\n")
+ssb_config_attr(vendor, id.vendor, "0x%04x\n")
+ssb_config_attr(revision, id.revision, "%u\n")
+ssb_config_attr(irq, irq, "%u\n")
+static ssize_t
+name_show(struct device *dev, struct device_attribute *attr, char *buf)
+{
+       return sprintf(buf, "%s\n",
+                      ssb_core_name(dev_to_ssb_dev(dev)->id.coreid));
+}
+
+static struct device_attribute ssb_device_attrs[] = {
+       __ATTR_RO(name),
+       __ATTR_RO(core_num),
+       __ATTR_RO(coreid),
+       __ATTR_RO(vendor),
+       __ATTR_RO(revision),
+       __ATTR_RO(irq),
+       __ATTR_NULL,
+};
+
 static struct bus_type ssb_bustype = {
        .name           = "ssb",
        .match          = ssb_bus_match,
@@ -392,6 +421,7 @@ static struct bus_type ssb_bustype = {
        .suspend        = ssb_device_suspend,
        .resume         = ssb_device_resume,
        .uevent         = ssb_device_uevent,
+       .dev_attrs      = ssb_device_attrs,
 };
 
 static void ssb_buses_lock(void)
index f52966305e05f9135714e72f757d2a3fa2637a3a..158449e55044f91b93970a995c612ef9f1c28e76 100644 (file)
@@ -406,6 +406,46 @@ static void sprom_extract_r123(struct ssb_sprom *out, const u16 *in)
        out->antenna_gain.ghz5.a3 = gain;
 }
 
+/* Revs 4 5 and 8 have partially shared layout */
+static void sprom_extract_r458(struct ssb_sprom *out, const u16 *in)
+{
+       SPEX(txpid2g[0], SSB_SPROM4_TXPID2G01,
+            SSB_SPROM4_TXPID2G0, SSB_SPROM4_TXPID2G0_SHIFT);
+       SPEX(txpid2g[1], SSB_SPROM4_TXPID2G01,
+            SSB_SPROM4_TXPID2G1, SSB_SPROM4_TXPID2G1_SHIFT);
+       SPEX(txpid2g[2], SSB_SPROM4_TXPID2G23,
+            SSB_SPROM4_TXPID2G2, SSB_SPROM4_TXPID2G2_SHIFT);
+       SPEX(txpid2g[3], SSB_SPROM4_TXPID2G23,
+            SSB_SPROM4_TXPID2G3, SSB_SPROM4_TXPID2G3_SHIFT);
+
+       SPEX(txpid5gl[0], SSB_SPROM4_TXPID5GL01,
+            SSB_SPROM4_TXPID5GL0, SSB_SPROM4_TXPID5GL0_SHIFT);
+       SPEX(txpid5gl[1], SSB_SPROM4_TXPID5GL01,
+            SSB_SPROM4_TXPID5GL1, SSB_SPROM4_TXPID5GL1_SHIFT);
+       SPEX(txpid5gl[2], SSB_SPROM4_TXPID5GL23,
+            SSB_SPROM4_TXPID5GL2, SSB_SPROM4_TXPID5GL2_SHIFT);
+       SPEX(txpid5gl[3], SSB_SPROM4_TXPID5GL23,
+            SSB_SPROM4_TXPID5GL3, SSB_SPROM4_TXPID5GL3_SHIFT);
+
+       SPEX(txpid5g[0], SSB_SPROM4_TXPID5G01,
+            SSB_SPROM4_TXPID5G0, SSB_SPROM4_TXPID5G0_SHIFT);
+       SPEX(txpid5g[1], SSB_SPROM4_TXPID5G01,
+            SSB_SPROM4_TXPID5G1, SSB_SPROM4_TXPID5G1_SHIFT);
+       SPEX(txpid5g[2], SSB_SPROM4_TXPID5G23,
+            SSB_SPROM4_TXPID5G2, SSB_SPROM4_TXPID5G2_SHIFT);
+       SPEX(txpid5g[3], SSB_SPROM4_TXPID5G23,
+            SSB_SPROM4_TXPID5G3, SSB_SPROM4_TXPID5G3_SHIFT);
+
+       SPEX(txpid5gh[0], SSB_SPROM4_TXPID5GH01,
+            SSB_SPROM4_TXPID5GH0, SSB_SPROM4_TXPID5GH0_SHIFT);
+       SPEX(txpid5gh[1], SSB_SPROM4_TXPID5GH01,
+            SSB_SPROM4_TXPID5GH1, SSB_SPROM4_TXPID5GH1_SHIFT);
+       SPEX(txpid5gh[2], SSB_SPROM4_TXPID5GH23,
+            SSB_SPROM4_TXPID5GH2, SSB_SPROM4_TXPID5GH2_SHIFT);
+       SPEX(txpid5gh[3], SSB_SPROM4_TXPID5GH23,
+            SSB_SPROM4_TXPID5GH3, SSB_SPROM4_TXPID5GH3_SHIFT);
+}
+
 static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
 {
        int i;
@@ -471,6 +511,8 @@ static void sprom_extract_r45(struct ssb_sprom *out, const u16 *in)
        memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
               sizeof(out->antenna_gain.ghz5));
 
+       sprom_extract_r458(out, in);
+
        /* TODO - get remaining rev 4 stuff needed */
 }
 
@@ -561,6 +603,8 @@ static void sprom_extract_r8(struct ssb_sprom *out, const u16 *in)
        memcpy(&out->antenna_gain.ghz5, &out->antenna_gain.ghz24,
               sizeof(out->antenna_gain.ghz5));
 
+       sprom_extract_r458(out, in);
+
        /* TODO - get remaining rev 8 stuff needed */
 }
 
index 4b4da5b86ff99337fc0d81afeb48363918df65c3..f442668a1e52e137b347419f9938d386f638b16b 100644 (file)
@@ -129,8 +129,9 @@ static void handle_tx(struct vhost_net *net)
        size_t hdr_size;
        struct socket *sock;
 
-       sock = rcu_dereference_check(vq->private_data,
-                                    lockdep_is_held(&vq->mutex));
+       /* TODO: check that we are running from vhost_worker?
+        * Not sure it's worth it, it's straight-forward enough. */
+       sock = rcu_dereference_check(vq->private_data, 1);
        if (!sock)
                return;
 
index eed52bcd35d0d7e2e6e0e36e12ac773ada2dbb6d..010e2d87ed7568ea1019f57447f671666e56fbb3 100644 (file)
@@ -197,6 +197,21 @@ enum dccp_feature_numbers {
        DCCPF_MAX_CCID_SPECIFIC = 255,
 };
 
+/* DCCP socket control message types for cmsg */
+enum dccp_cmsg_type {
+       DCCP_SCM_PRIORITY = 1,
+       DCCP_SCM_QPOLICY_MAX = 0xFFFF,
+       /* ^-- Up to here reserved exclusively for qpolicy parameters */
+       DCCP_SCM_MAX
+};
+
+/* DCCP priorities for outgoing/queued packets */
+enum dccp_packet_dequeueing_policy {
+       DCCPQ_POLICY_SIMPLE,
+       DCCPQ_POLICY_PRIO,
+       DCCPQ_POLICY_MAX
+};
+
 /* DCCP socket options */
 #define DCCP_SOCKOPT_PACKET_SIZE       1 /* XXX deprecated, without effect */
 #define DCCP_SOCKOPT_SERVICE           2
@@ -210,6 +225,8 @@ enum dccp_feature_numbers {
 #define DCCP_SOCKOPT_CCID              13
 #define DCCP_SOCKOPT_TX_CCID           14
 #define DCCP_SOCKOPT_RX_CCID           15
+#define DCCP_SOCKOPT_QPOLICY_ID                16
+#define DCCP_SOCKOPT_QPOLICY_TXQLEN    17
 #define DCCP_SOCKOPT_CCID_RX_INFO      128
 #define DCCP_SOCKOPT_CCID_TX_INFO      192
 
@@ -458,6 +475,8 @@ struct dccp_ackvec;
  * @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)
  * @dccps_options_received - parsed set of retrieved options
+ * @dccps_qpolicy - TX dequeueing policy, one of %dccp_packet_dequeueing_policy
+ * @dccps_tx_qlen - maximum length of the TX queue
  * @dccps_role - role of this sock, one of %dccp_role
  * @dccps_hc_rx_insert_options - receiver wants to add options when acking
  * @dccps_hc_tx_insert_options - sender wants to add options when sending
@@ -500,6 +519,8 @@ struct dccp_sock {
        struct ccid                     *dccps_hc_rx_ccid;
        struct ccid                     *dccps_hc_tx_ccid;
        struct dccp_options_received    dccps_options_received;
+       __u8                            dccps_qpolicy;
+       __u32                           dccps_tx_qlen;
        enum dccp_role                  dccps_role:2;
        __u8                            dccps_hc_rx_insert_options:1;
        __u8                            dccps_hc_tx_insert_options:1;
index 447a775878fb94db30df9ac047327fcc8746079b..45266b75409a4718f5d294c6ddbc8e30e6984f66 100644 (file)
@@ -124,7 +124,9 @@ struct sock_fprog { /* Required for SO_ATTACH_FILTER. */
 #define SKF_AD_MARK    20
 #define SKF_AD_QUEUE   24
 #define SKF_AD_HATYPE  28
-#define SKF_AD_MAX     32
+#define SKF_AD_RXHASH  32
+#define SKF_AD_CPU     36
+#define SKF_AD_MAX     40
 #define SKF_NET_OFF   (-0x100000)
 #define SKF_LL_OFF    (-0x200000)
 
@@ -146,7 +148,7 @@ struct sk_buff;
 struct sock;
 
 extern int sk_filter(struct sock *sk, struct sk_buff *skb);
-extern unsigned int sk_run_filter(struct sk_buff *skb,
+extern unsigned int sk_run_filter(const struct sk_buff *skb,
                                  const struct sock_filter *filter);
 extern int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk);
 extern int sk_detach_filter(struct sock *sk);
index 2b86eaf11773fd80cb58d4b4e19b2640ae833dae..ae8fdc54e0c06941356de75606fc186f7cc63507 100644 (file)
@@ -222,7 +222,7 @@ static inline struct in_device *in_dev_get(const struct net_device *dev)
 
 static inline struct in_device *__in_dev_get_rtnl(const struct net_device *dev)
 {
-       return rcu_dereference_check(dev->ip_ptr, lockdep_rtnl_is_held());
+       return rtnl_dereference(dev->ip_ptr);
 }
 
 extern void in_dev_finish_destroy(struct in_device *idev);
index ced1159fa4f247e10becefdf6bd3ec3d6cbf873b..47cb09edec1a613821b734a7b4a0aa1def2ab0ae 100644 (file)
 
 /* jhash.h: Jenkins hash support.
  *
- * Copyright (C) 1996 Bob Jenkins (bob_jenkins@burtleburtle.net)
+ * Copyright (C) 2006. Bob Jenkins (bob_jenkins@burtleburtle.net)
  *
  * http://burtleburtle.net/bob/hash/
  *
  * These are the credits from Bob's sources:
  *
- * lookup2.c, by Bob Jenkins, December 1996, Public Domain.
- * hash(), hash2(), hash3, and mix() are externally useful functions.
- * Routines to test the hash are included if SELF_TEST is defined.
- * You can use this free for any purpose.  It has no warranty.
+ * lookup3.c, by Bob Jenkins, May 2006, Public Domain.
  *
- * Copyright (C) 2003 David S. Miller (davem@redhat.com)
+ * These are functions for producing 32-bit hashes for hash table lookup.
+ * hashword(), hashlittle(), hashlittle2(), hashbig(), mix(), and final()
+ * are externally useful functions.  Routines to test the hash are included
+ * if SELF_TEST is defined.  You can use this free for any purpose.  It's in
+ * the public domain.  It has no warranty.
+ *
+ * Copyright (C) 2009-2010 Jozsef Kadlecsik (kadlec@blackhole.kfki.hu)
  *
  * I've modified Bob's hash to be useful in the Linux kernel, and
- * any bugs present are surely my fault.  -DaveM
+ * any bugs present are my fault.
+ * Jozsef
  */
+#include <linux/bitops.h>
+#include <linux/unaligned/packed_struct.h>
+
+/* Best hash sizes are of power of two */
+#define jhash_size(n)   ((u32)1<<(n))
+/* Mask the hash value, i.e (value & jhash_mask(n)) instead of (value % n) */
+#define jhash_mask(n)   (jhash_size(n)-1)
+
+/* __jhash_mix -- mix 3 32-bit values reversibly. */
+#define __jhash_mix(a, b, c)                   \
+{                                              \
+       a -= c;  a ^= rol32(c, 4);  c += b;     \
+       b -= a;  b ^= rol32(a, 6);  a += c;     \
+       c -= b;  c ^= rol32(b, 8);  b += a;     \
+       a -= c;  a ^= rol32(c, 16); c += b;     \
+       b -= a;  b ^= rol32(a, 19); a += c;     \
+       c -= b;  c ^= rol32(b, 4);  b += a;     \
+}
 
-/* NOTE: Arguments are modified. */
-#define __jhash_mix(a, b, c) \
-{ \
-  a -= b; a -= c; a ^= (c>>13); \
-  b -= c; b -= a; b ^= (a<<8); \
-  c -= a; c -= b; c ^= (b>>13); \
-  a -= b; a -= c; a ^= (c>>12);  \
-  b -= c; b -= a; b ^= (a<<16); \
-  c -= a; c -= b; c ^= (b>>5); \
-  a -= b; a -= c; a ^= (c>>3);  \
-  b -= c; b -= a; b ^= (a<<10); \
-  c -= a; c -= b; c ^= (b>>15); \
+/* __jhash_final - final mixing of 3 32-bit values (a,b,c) into c */
+#define __jhash_final(a, b, c)                 \
+{                                              \
+       c ^= b; c -= rol32(b, 14);              \
+       a ^= c; a -= rol32(c, 11);              \
+       b ^= a; b -= rol32(a, 25);              \
+       c ^= b; c -= rol32(b, 16);              \
+       a ^= c; a -= rol32(c, 4);               \
+       b ^= a; b -= rol32(a, 14);              \
+       c ^= b; c -= rol32(b, 24);              \
 }
 
-/* The golden ration: an arbitrary value */
-#define JHASH_GOLDEN_RATIO     0x9e3779b9
+/* An arbitrary initial parameter */
+#define JHASH_INITVAL          0xdeadbeef
 
-/* The most generic version, hashes an arbitrary sequence
- * of bytes.  No alignment or length assumptions are made about
- * the input key.
+/* jhash - hash an arbitrary key
+ * @k: sequence of bytes as key
+ * @length: the length of the key
+ * @initval: the previous hash, or an arbitray value
+ *
+ * The generic version, hashes an arbitrary sequence of bytes.
+ * No alignment or length assumptions are made about the input key.
+ *
+ * Returns the hash value of the key. The result depends on endianness.
  */
 static inline u32 jhash(const void *key, u32 length, u32 initval)
 {
-       u32 a, b, c, len;
+       u32 a, b, c;
        const u8 *k = key;
 
-       len = length;
-       a = b = JHASH_GOLDEN_RATIO;
-       c = initval;
-
-       while (len >= 12) {
-               a += (k[0] +((u32)k[1]<<8) +((u32)k[2]<<16) +((u32)k[3]<<24));
-               b += (k[4] +((u32)k[5]<<8) +((u32)k[6]<<16) +((u32)k[7]<<24));
-               c += (k[8] +((u32)k[9]<<8) +((u32)k[10]<<16)+((u32)k[11]<<24));
-
-               __jhash_mix(a,b,c);
+       /* Set up the internal state */
+       a = b = c = JHASH_INITVAL + length + initval;
 
+       /* All but the last block: affect some 32 bits of (a,b,c) */
+       while (length > 12) {
+               a += __get_unaligned_cpu32(k);
+               b += __get_unaligned_cpu32(k + 4);
+               c += __get_unaligned_cpu32(k + 8);
+               __jhash_mix(a, b, c);
+               length -= 12;
                k += 12;
-               len -= 12;
        }
-
-       c += length;
-       switch (len) {
-       case 11: c += ((u32)k[10]<<24);
-       case 10: c += ((u32)k[9]<<16);
-       case 9 : c += ((u32)k[8]<<8);
-       case 8 : b += ((u32)k[7]<<24);
-       case 7 : b += ((u32)k[6]<<16);
-       case 6 : b += ((u32)k[5]<<8);
-       case 5 : b += k[4];
-       case 4 : a += ((u32)k[3]<<24);
-       case 3 : a += ((u32)k[2]<<16);
-       case 2 : a += ((u32)k[1]<<8);
-       case 1 : a += k[0];
-       };
-
-       __jhash_mix(a,b,c);
+       /* Last block: affect all 32 bits of (c) */
+       /* All the case statements fall through */
+       switch (length) {
+       case 12: c += (u32)k[11]<<24;
+       case 11: c += (u32)k[10]<<16;
+       case 10: c += (u32)k[9]<<8;
+       case 9:  c += k[8];
+       case 8:  b += (u32)k[7]<<24;
+       case 7:  b += (u32)k[6]<<16;
+       case 6:  b += (u32)k[5]<<8;
+       case 5:  b += k[4];
+       case 4:  a += (u32)k[3]<<24;
+       case 3:  a += (u32)k[2]<<16;
+       case 2:  a += (u32)k[1]<<8;
+       case 1:  a += k[0];
+                __jhash_final(a, b, c);
+       case 0: /* Nothing left to add */
+               break;
+       }
 
        return c;
 }
 
-/* A special optimized version that handles 1 or more of u32s.
- * The length parameter here is the number of u32s in the key.
+/* jhash2 - hash an array of u32's
+ * @k: the key which must be an array of u32's
+ * @length: the number of u32's in the key
+ * @initval: the previous hash, or an arbitray value
+ *
+ * Returns the hash value of the key.
  */
 static inline u32 jhash2(const u32 *k, u32 length, u32 initval)
 {
-       u32 a, b, c, len;
+       u32 a, b, c;
 
-       a = b = JHASH_GOLDEN_RATIO;
-       c = initval;
-       len = length;
+       /* Set up the internal state */
+       a = b = c = JHASH_INITVAL + (length<<2) + initval;
 
-       while (len >= 3) {
+       /* Handle most of the key */
+       while (length > 3) {
                a += k[0];
                b += k[1];
                c += k[2];
                __jhash_mix(a, b, c);
-               k += 3; len -= 3;
+               length -= 3;
+               k += 3;
        }
 
-       c += length * 4;
-
-       switch (len) {
-       case 2 : b += k[1];
-       case 1 : a += k[0];
-       };
-
-       __jhash_mix(a,b,c);
+       /* Handle the last 3 u32's: all the case statements fall through */
+       switch (length) {
+       case 3: c += k[2];
+       case 2: b += k[1];
+       case 1: a += k[0];
+               __jhash_final(a, b, c);
+       case 0: /* Nothing left to add */
+               break;
+       }
 
        return c;
 }
 
 
-/* A special ultra-optimized versions that knows they are hashing exactly
- * 3, 2 or 1 word(s).
- *
- * NOTE: In particular the "c += length; __jhash_mix(a,b,c);" normally
- *       done at the end is not done here.
- */
+/* jhash_3words - hash exactly 3, 2 or 1 word(s) */
 static inline u32 jhash_3words(u32 a, u32 b, u32 c, u32 initval)
 {
-       a += JHASH_GOLDEN_RATIO;
-       b += JHASH_GOLDEN_RATIO;
+       a += JHASH_INITVAL;
+       b += JHASH_INITVAL;
        c += initval;
 
-       __jhash_mix(a, b, c);
+       __jhash_final(a, b, c);
 
        return c;
 }
index 1ff81b51b656a13f32c4d8b5253f803593cd033b..dd3c34ebca9a67e05c2e59649da81486210e802c 100644 (file)
@@ -11,6 +11,7 @@
 #define MARVELL_PHY_ID_88E1118         0x01410e10
 #define MARVELL_PHY_ID_88E1121R                0x01410cb0
 #define MARVELL_PHY_ID_88E1145         0x01410cd0
+#define MARVELL_PHY_ID_88E1149R                0x01410e50
 #define MARVELL_PHY_ID_88E1240         0x01410e30
 #define MARVELL_PHY_ID_88E1318S                0x01410e90
 
index c779b49a1fda3158c4278f05379b5f41fb95cabf..b1494aced217d0bcdab6967a896025043cecd263 100644 (file)
@@ -55,6 +55,7 @@
 #define MDIO_PCS_10GBRT_STAT2  33      /* 10GBASE-R/-T PCS status 2 */
 #define MDIO_AN_10GBT_CTRL     32      /* 10GBASE-T auto-negotiation control */
 #define MDIO_AN_10GBT_STAT     33      /* 10GBASE-T auto-negotiation status */
+#define MDIO_AN_EEE_ADV                60      /* EEE advertisement */
 
 /* LASI (Link Alarm Status Interrupt) registers, defined by XENPAK MSA. */
 #define MDIO_PMA_LASI_RXCTRL   0x9000  /* RX_ALARM control */
 #define MDIO_AN_10GBT_STAT_MS          0x4000  /* Master/slave config */
 #define MDIO_AN_10GBT_STAT_MSFLT       0x8000  /* Master/slave config fault */
 
+/* AN EEE Advertisement register. */
+#define MDIO_AN_EEE_ADV_100TX          0x0002  /* Advertise 100TX EEE cap */
+#define MDIO_AN_EEE_ADV_1000T          0x0004  /* Advertise 1000T EEE cap */
+
 /* LASI RX_ALARM control/status registers. */
 #define MDIO_PMA_LASI_RX_PHYXSLFLT     0x0001  /* PHY XS RX local fault */
 #define MDIO_PMA_LASI_RX_PCSLFLT       0x0008  /* PCS RX local fault */
index a9ac5dc26e3c88700462babf34a9106c52c6b799..d31bc3c9471712a1b17172194c3f132a86a12f72 100644 (file)
@@ -1360,7 +1360,8 @@ static inline struct net_device *first_net_device(struct net *net)
 
 extern int                     netdev_boot_setup_check(struct net_device *dev);
 extern unsigned long           netdev_boot_base(const char *prefix, int unit);
-extern struct net_device    *dev_getbyhwaddr(struct net *net, unsigned short type, char *hwaddr);
+extern struct net_device *dev_getbyhwaddr_rcu(struct net *net, unsigned short type,
+                                             const char *hwaddr);
 extern struct net_device *dev_getfirstbyhwtype(struct net *net, unsigned short type);
 extern struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type);
 extern void            dev_add_pack(struct packet_type *pt);
index d706bf3badc850c0889e107b49fc25c7b701e43d..5cfa579df47611dec87561006b6a03db2063ec63 100644 (file)
  *     user space application). %NL80211_ATTR_FRAME is used to specify the
  *     frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and
  *     optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on
- *     which channel the frame is to be transmitted or was received. This
- *     channel has to be the current channel (remain-on-channel or the
- *     operational channel). When called, this operation returns a cookie
- *     (%NL80211_ATTR_COOKIE) that will be included with the TX status event
- *     pertaining to the TX request.
+ *     which channel the frame is to be transmitted or was received. If this
+ *     channel is not the current channel (remain-on-channel or the
+ *     operational channel) the device will switch to the given channel and
+ *     transmit the frame, optionally waiting for a response for the time
+ *     specified using %NL80211_ATTR_DURATION. When called, this operation
+ *     returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the
+ *     TX status event pertaining to the TX request.
+ * @NL80211_CMD_FRAME_WAIT_CANCEL: When an off-channel TX was requested, this
+ *     command may be used with the corresponding cookie to cancel the wait
+ *     time if it is known that it is no longer necessary.
  * @NL80211_CMD_ACTION: Alias for @NL80211_CMD_FRAME for backward compatibility.
  * @NL80211_CMD_FRAME_TX_STATUS: Report TX status of a management frame
  *     transmitted with %NL80211_CMD_FRAME. %NL80211_ATTR_COOKIE identifies
@@ -493,6 +498,8 @@ enum nl80211_commands {
        NL80211_CMD_SET_CHANNEL,
        NL80211_CMD_SET_WDS_PEER,
 
+       NL80211_CMD_FRAME_WAIT_CANCEL,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -828,6 +835,12 @@ enum nl80211_commands {
  *
  * @NL80211_ATTR_MCAST_RATE: Multicast tx rate (in 100 kbps) for IBSS
  *
+ * @NL80211_ATTR_OFFCHANNEL_TX_OK: For management frame TX, the frame may be
+ *     transmitted on another channel when the channel given doesn't match
+ *     the current channel. If the current channel doesn't match and this
+ *     flag isn't set, the frame will be rejected. This is also used as an
+ *     nl80211 capability flag.
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -1002,6 +1015,8 @@ enum nl80211_attrs {
 
        NL80211_ATTR_MCAST_RATE,
 
+       NL80211_ATTR_OFFCHANNEL_TX_OK,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
index ebb0c80ffd6ebb53b02fb2263e0a6ff6a634eb6a..12b2b18e50c1c321f208a83d4bbda61ce985450c 100644 (file)
@@ -230,6 +230,7 @@ enum
        LINUX_MIB_TCPMINTTLDROP, /* RFC 5082 */
        LINUX_MIB_TCPDEFERACCEPTDROP,
        LINUX_MIB_IPRPFILTER, /* IP Reverse Path Filter (rp_filter) */
+       LINUX_MIB_TCPTIMEWAITOVERFLOW,          /* TCPTimeWaitOverflow */
        __LINUX_MIB_MAX
 };
 
index 623b704fdc42a371bfdf0c20d5a381d8598e1a21..9659eff52ca2d146fa18cf85e97eb3bc4e9b150e 100644 (file)
@@ -55,6 +55,10 @@ struct ssb_sprom {
        u8 tri5gl;              /* 5.2GHz TX isolation */
        u8 tri5g;               /* 5.3GHz TX isolation */
        u8 tri5gh;              /* 5.8GHz TX isolation */
+       u8 txpid2g[4];          /* 2GHz TX power index */
+       u8 txpid5gl[4];         /* 4.9 - 5.1GHz TX power index */
+       u8 txpid5g[4];          /* 5.1 - 5.5GHz TX power index */
+       u8 txpid5gh[4];         /* 5.5 - ...GHz TX power index */
        u8 rxpo2g;              /* 2GHz RX power offset */
        u8 rxpo5g;              /* 5GHz RX power offset */
        u8 rssisav2g;           /* 2GHz RSSI params */
index 11daf9c140e78f7e82a62aafff0419992abdd09a..489f7b6d61c5eea7f92d53780609898f334eb22e 100644 (file)
 #define  SSB_SPROM4_AGAIN2_SHIFT       0
 #define  SSB_SPROM4_AGAIN3             0xFF00  /* Antenna 3 */
 #define  SSB_SPROM4_AGAIN3_SHIFT       8
+#define SSB_SPROM4_TXPID2G01           0x0062  /* TX Power Index 2GHz */
+#define  SSB_SPROM4_TXPID2G0           0x00FF
+#define  SSB_SPROM4_TXPID2G0_SHIFT     0
+#define  SSB_SPROM4_TXPID2G1           0xFF00
+#define  SSB_SPROM4_TXPID2G1_SHIFT     8
+#define SSB_SPROM4_TXPID2G23           0x0064  /* TX Power Index 2GHz */
+#define  SSB_SPROM4_TXPID2G2           0x00FF
+#define  SSB_SPROM4_TXPID2G2_SHIFT     0
+#define  SSB_SPROM4_TXPID2G3           0xFF00
+#define  SSB_SPROM4_TXPID2G3_SHIFT     8
+#define SSB_SPROM4_TXPID5G01           0x0066  /* TX Power Index 5GHz middle subband */
+#define  SSB_SPROM4_TXPID5G0           0x00FF
+#define  SSB_SPROM4_TXPID5G0_SHIFT     0
+#define  SSB_SPROM4_TXPID5G1           0xFF00
+#define  SSB_SPROM4_TXPID5G1_SHIFT     8
+#define SSB_SPROM4_TXPID5G23           0x0068  /* TX Power Index 5GHz middle subband */
+#define  SSB_SPROM4_TXPID5G2           0x00FF
+#define  SSB_SPROM4_TXPID5G2_SHIFT     0
+#define  SSB_SPROM4_TXPID5G3           0xFF00
+#define  SSB_SPROM4_TXPID5G3_SHIFT     8
+#define SSB_SPROM4_TXPID5GL01          0x006A  /* TX Power Index 5GHz low subband */
+#define  SSB_SPROM4_TXPID5GL0          0x00FF
+#define  SSB_SPROM4_TXPID5GL0_SHIFT    0
+#define  SSB_SPROM4_TXPID5GL1          0xFF00
+#define  SSB_SPROM4_TXPID5GL1_SHIFT    8
+#define SSB_SPROM4_TXPID5GL23          0x006C  /* TX Power Index 5GHz low subband */
+#define  SSB_SPROM4_TXPID5GL2          0x00FF
+#define  SSB_SPROM4_TXPID5GL2_SHIFT    0
+#define  SSB_SPROM4_TXPID5GL3          0xFF00
+#define  SSB_SPROM4_TXPID5GL3_SHIFT    8
+#define SSB_SPROM4_TXPID5GH01          0x006E  /* TX Power Index 5GHz high subband */
+#define  SSB_SPROM4_TXPID5GH0          0x00FF
+#define  SSB_SPROM4_TXPID5GH0_SHIFT    0
+#define  SSB_SPROM4_TXPID5GH1          0xFF00
+#define  SSB_SPROM4_TXPID5GH1_SHIFT    8
+#define SSB_SPROM4_TXPID5GH23          0x0070  /* TX Power Index 5GHz high subband */
+#define  SSB_SPROM4_TXPID5GH2          0x00FF
+#define  SSB_SPROM4_TXPID5GH2_SHIFT    0
+#define  SSB_SPROM4_TXPID5GH3          0xFF00
+#define  SSB_SPROM4_TXPID5GH3_SHIFT    8
 #define SSB_SPROM4_MAXP_BG             0x0080  /* Max Power BG in path 1 */
 #define  SSB_SPROM4_MAXP_BG_MASK       0x00FF  /* Mask for Max Power BG */
 #define  SSB_SPROM4_ITSSI_BG           0xFF00  /* Mask for path 1 itssi_bg */
index 7ae27a473818ced2a93d84b997a47783504c3e1d..44842c8d38c04f949b9edfb2eb9bb04dc6bdb6d3 100644 (file)
@@ -97,6 +97,12 @@ struct driver_info {
 
 #define FLAG_LINK_INTR 0x0800          /* updates link (carrier) status */
 
+/*
+ * Indicates to usbnet, that USB driver accumulates multiple IP packets.
+ * Affects statistic (counters) and short packet handling.
+ */
+#define FLAG_MULTI_PACKET      0x1000
+
        /* init device ... can sleep, or cause probe() failure */
        int     (*bind)(struct usbnet *, struct usb_interface *);
 
index 90c9e2872f27214b4727ecf4f440e4975be1f1df..18e5c3f675804eb6fbc84bb4aa0781944807c260 100644 (file)
@@ -10,6 +10,7 @@ extern void unix_inflight(struct file *fp);
 extern void unix_notinflight(struct file *fp);
 extern void unix_gc(void);
 extern void wait_for_unix_gc(void);
+extern struct sock *unix_get_socket(struct file *filp);
 
 #define UNIX_HASH_SIZE 256
 
@@ -56,6 +57,7 @@ struct unix_sock {
        spinlock_t              lock;
        unsigned int            gc_candidate : 1;
        unsigned int            gc_maybe_cycle : 1;
+       unsigned char           recursion_level;
        struct socket_wq        peer_wq;
 };
 #define unix_sk(__sk) ((struct unix_sock *)__sk)
index e30e00834340a1330e373d7397fadbbccb1f035f..f3c5ed6d7bda92ac7ec96142ba18458fbd23b578 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    BlueZ - Bluetooth protocol stack for Linux
    Copyright (C) 2000-2001 Qualcomm Incorporated
 
    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 
+   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 
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
    SOFTWARE IS DISCLAIMED.
 */
 
@@ -489,7 +489,7 @@ struct hci_rp_read_local_name {
 
 #define HCI_OP_WRITE_PG_TIMEOUT                0x0c18
 
-#define HCI_OP_WRITE_SCAN_ENABLE       0x0c1a
+#define HCI_OP_WRITE_SCAN_ENABLE       0x0c1a
        #define SCAN_DISABLED           0x00
        #define SCAN_INQUIRY            0x01
        #define SCAN_PAGE               0x02
@@ -874,7 +874,7 @@ struct hci_ev_si_security {
 
 struct hci_command_hdr {
        __le16  opcode;         /* OCF & OGF */
-       __u8    plen;
+       __u8    plen;
 } __packed;
 
 struct hci_event_hdr {
index ebec8c9a929dce74d022f16dcf02aa56a17ac640..9c08625617a142085b2709bbf38f20535db41996 100644 (file)
@@ -44,15 +44,15 @@ struct inquiry_data {
 };
 
 struct inquiry_entry {
-       struct inquiry_entry    *next;
+       struct inquiry_entry    *next;
        __u32                   timestamp;
        struct inquiry_data     data;
 };
 
 struct inquiry_cache {
-       spinlock_t              lock;
+       spinlock_t              lock;
        __u32                   timestamp;
-       struct inquiry_entry    *list;
+       struct inquiry_entry    *list;
 };
 
 struct hci_conn_hash {
@@ -141,7 +141,7 @@ struct hci_dev {
        void                    *driver_data;
        void                    *core_data;
 
-       atomic_t                promisc;
+       atomic_t                promisc;
 
        struct dentry           *debugfs;
 
@@ -150,7 +150,7 @@ struct hci_dev {
 
        struct rfkill           *rfkill;
 
-       struct module           *owner;
+       struct module           *owner;
 
        int (*open)(struct hci_dev *hdev);
        int (*close)(struct hci_dev *hdev);
@@ -215,8 +215,8 @@ extern rwlock_t hci_dev_list_lock;
 extern rwlock_t hci_cb_list_lock;
 
 /* ----- Inquiry cache ----- */
-#define INQUIRY_CACHE_AGE_MAX   (HZ*30)   // 30 seconds
-#define INQUIRY_ENTRY_AGE_MAX   (HZ*60)   // 60 seconds
+#define INQUIRY_CACHE_AGE_MAX   (HZ*30)   /* 30 seconds */
+#define INQUIRY_ENTRY_AGE_MAX   (HZ*60)   /* 60 seconds */
 
 #define inquiry_cache_lock(c)          spin_lock(&c->lock)
 #define inquiry_cache_unlock(c)                spin_unlock(&c->lock)
index c819c8bf9b68345b3f448fbaa2e6d19a189e5e86..7ad25ca60ec042aeac8b2336c003fbc9e6fe07e5 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    BlueZ - Bluetooth protocol stack for Linux
    Copyright (C) 2000-2001 Qualcomm Incorporated
    Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
    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 
+   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 
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
    SOFTWARE IS DISCLAIMED.
 */
 
@@ -417,11 +417,11 @@ static inline int l2cap_tx_window_full(struct sock *sk)
        return sub == pi->remote_tx_win;
 }
 
-#define __get_txseq(ctrl) ((ctrl) & L2CAP_CTRL_TXSEQ) >> 1
-#define __get_reqseq(ctrl) ((ctrl) & L2CAP_CTRL_REQSEQ) >> 8
-#define __is_iframe(ctrl) !((ctrl) & L2CAP_CTRL_FRAME_TYPE)
-#define __is_sframe(ctrl) (ctrl) & L2CAP_CTRL_FRAME_TYPE
-#define __is_sar_start(ctrl) ((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START
+#define __get_txseq(ctrl)      (((ctrl) & L2CAP_CTRL_TXSEQ) >> 1)
+#define __get_reqseq(ctrl)     (((ctrl) & L2CAP_CTRL_REQSEQ) >> 8)
+#define __is_iframe(ctrl)      (!((ctrl) & L2CAP_CTRL_FRAME_TYPE))
+#define __is_sframe(ctrl)      ((ctrl) & L2CAP_CTRL_FRAME_TYPE)
+#define __is_sar_start(ctrl)   (((ctrl) & L2CAP_CTRL_SAR) == L2CAP_SDU_START)
 
 void l2cap_load(void);
 
index 71047bc0af842a2b72f379096d8baaf84234f16e..6eac4a760c3be903d1f7feb7bad94b08d2a408e5 100644 (file)
@@ -1,5 +1,5 @@
-/* 
-   RFCOMM implementation for Linux Bluetooth stack (BlueZ).
+/*
+   RFCOMM implementation for Linux Bluetooth stack (BlueZ)
    Copyright (C) 2002 Maxim Krasnyansky <maxk@qualcomm.com>
    Copyright (C) 2002 Marcel Holtmann <marcel@holtmann.org>
 
    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 
+   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 
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
    SOFTWARE IS DISCLAIMED.
 */
 
 struct rfcomm_hdr {
        u8 addr;
        u8 ctrl;
-       u8 len;    // Actual size can be 2 bytes
+       u8 len;    /* Actual size can be 2 bytes */
 } __packed;
 
 struct rfcomm_cmd {
@@ -228,7 +228,7 @@ struct rfcomm_dlc {
 /* ---- RFCOMM SEND RPN ---- */
 int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
                        u8 bit_rate, u8 data_bits, u8 stop_bits,
-                       u8 parity, u8 flow_ctrl_settings, 
+                       u8 parity, u8 flow_ctrl_settings,
                        u8 xon_char, u8 xoff_char, u16 param_mask);
 
 /* ---- RFCOMM DLCs (channels) ---- */
index e28a2a7714713a4cbb05dbfd3cd0c514ede79d66..1e35c43657c85c71560f2010242c4105701b6287 100644 (file)
@@ -1,4 +1,4 @@
-/* 
+/*
    BlueZ - Bluetooth protocol stack for Linux
    Copyright (C) 2000-2001 Qualcomm Incorporated
 
    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 
+   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 
+   ALL LIABILITY, INCLUDING LIABILITY FOR INFRINGEMENT OF ANY PATENTS,
+   COPYRIGHTS, TRADEMARKS OR OTHER RIGHTS, RELATING TO USE OF THIS
    SOFTWARE IS DISCLAIMED.
 */
 
@@ -55,11 +55,11 @@ struct sco_conninfo {
 struct sco_conn {
        struct hci_conn *hcon;
 
-       bdaddr_t        *dst;
-       bdaddr_t        *src;
-       
+       bdaddr_t        *dst;
+       bdaddr_t        *src;
+
        spinlock_t      lock;
-       struct sock     *sk;
+       struct sock     *sk;
 
        unsigned int    mtu;
 };
index 0663945cfa48190f173da24812326261ff6c8d61..6b2af7aeddd342b84ca80d26e2c12730f6207acd 100644 (file)
@@ -1134,7 +1134,9 @@ struct cfg80211_pmksa {
  * @cancel_remain_on_channel: Cancel an on-going remain-on-channel operation.
  *     This allows the operation to be terminated prior to timeout based on
  *     the duration value.
- * @mgmt_tx: Transmit a management frame
+ * @mgmt_tx: Transmit a management frame.
+ * @mgmt_tx_cancel_wait: Cancel the wait time from transmitting a management
+ *     frame on another channel
  *
  * @testmode_cmd: run a test mode command
  *
@@ -1152,6 +1154,13 @@ struct cfg80211_pmksa {
  * @mgmt_frame_register: Notify driver that a management frame type was
  *     registered. Note that this callback may not sleep, and cannot run
  *     concurrently with itself.
+ *
+ * @set_antenna: Set antenna configuration (tx_ant, rx_ant) on the device.
+ *     Parameters are bitmaps of allowed antennas to use for TX/RX. Drivers may
+ *     reject TX/RX mask combinations they cannot support by returning -EINVAL
+ *     (also see nl80211.h @NL80211_ATTR_WIPHY_ANTENNA_TX).
+ *
+ * @get_antenna: Get current antenna configuration from device (tx_ant, rx_ant).
  */
 struct cfg80211_ops {
        int     (*suspend)(struct wiphy *wiphy);
@@ -1291,10 +1300,13 @@ struct cfg80211_ops {
                                            u64 cookie);
 
        int     (*mgmt_tx)(struct wiphy *wiphy, struct net_device *dev,
-                         struct ieee80211_channel *chan,
+                         struct ieee80211_channel *chan, bool offchan,
                          enum nl80211_channel_type channel_type,
-                         bool channel_type_valid,
+                         bool channel_type_valid, unsigned int wait,
                          const u8 *buf, size_t len, u64 *cookie);
+       int     (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
+                                      struct net_device *dev,
+                                      u64 cookie);
 
        int     (*set_power_mgmt)(struct wiphy *wiphy, struct net_device *dev,
                                  bool enabled, int timeout);
index a5bd72646d6510f18ff085674283f55386e118bc..85dee3a57b9b464afceb8c02baf1d9e55da918ad 100644 (file)
@@ -70,7 +70,7 @@ struct dst_entry {
 
        struct  dst_ops         *ops;
 
-       u32                     metrics[RTAX_MAX];
+       u32                     _metrics[RTAX_MAX];
 
 #ifdef CONFIG_NET_CLS_ROUTE
        __u32                   tclassid;
@@ -106,7 +106,27 @@ struct dst_entry {
 static inline u32
 dst_metric(const struct dst_entry *dst, int metric)
 {
-       return dst->metrics[metric-1];
+       return dst->_metrics[metric-1];
+}
+
+static inline void dst_metric_set(struct dst_entry *dst, int metric, u32 val)
+{
+       dst->_metrics[metric-1] = val;
+}
+
+static inline void dst_import_metrics(struct dst_entry *dst, const u32 *src_metrics)
+{
+       memcpy(dst->_metrics, src_metrics, RTAX_MAX * sizeof(u32));
+}
+
+static inline void dst_copy_metrics(struct dst_entry *dest, const struct dst_entry *src)
+{
+       dst_import_metrics(dest, src->_metrics);
+}
+
+static inline u32 *dst_metrics_ptr(struct dst_entry *dst)
+{
+       return dst->_metrics;
 }
 
 static inline u32
@@ -134,7 +154,7 @@ static inline unsigned long dst_metric_rtt(const struct dst_entry *dst, int metr
 static inline void set_dst_metric_rtt(struct dst_entry *dst, int metric,
                                      unsigned long rtt)
 {
-       dst->metrics[metric-1] = jiffies_to_msecs(rtt);
+       dst_metric_set(dst, metric, jiffies_to_msecs(rtt));
 }
 
 static inline u32
index 8945f9fb192ab536d0e27f0b9617046f5086b9bc..8181498fa96ca5334cbff5f10a36a41abd8882dd 100644 (file)
@@ -116,8 +116,9 @@ struct inet_sock {
        struct ipv6_pinfo       *pinet6;
 #endif
        /* Socket demultiplex comparisons on incoming packets. */
-       __be32                  inet_daddr;
-       __be32                  inet_rcv_saddr;
+#define inet_daddr             sk.__sk_common.skc_daddr
+#define inet_rcv_saddr         sk.__sk_common.skc_rcv_saddr
+
        __be16                  inet_dport;
        __u16                   inet_num;
        __be32                  inet_saddr;
index a066fdd50da6c5041a12bb4983eeb4b9c8b9eee1..17404b5388a75302c4951d5f469fd96814ad7709 100644 (file)
@@ -88,12 +88,6 @@ extern void inet_twdr_hangman(unsigned long data);
 extern void inet_twdr_twkill_work(struct work_struct *work);
 extern void inet_twdr_twcal_tick(unsigned long data);
 
-#if (BITS_PER_LONG == 64)
-#define INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES 8
-#else
-#define INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES 4
-#endif
-
 struct inet_bind_bucket;
 
 /*
@@ -117,15 +111,15 @@ struct inet_timewait_sock {
 #define tw_hash                        __tw_common.skc_hash
 #define tw_prot                        __tw_common.skc_prot
 #define tw_net                 __tw_common.skc_net
+#define tw_daddr               __tw_common.skc_daddr
+#define tw_rcv_saddr           __tw_common.skc_rcv_saddr
        int                     tw_timeout;
        volatile unsigned char  tw_substate;
-       /* 3 bits hole, try to pack */
        unsigned char           tw_rcv_wscale;
+
        /* Socket demultiplex comparisons on incoming packets. */
-       /* these five are in inet_sock */
+       /* these three are in inet_sock */
        __be16                  tw_sport;
-       __be32                  tw_daddr __attribute__((aligned(INET_TIMEWAIT_ADDRCMP_ALIGN_BYTES)));
-       __be32                  tw_rcv_saddr;
        __be16                  tw_dport;
        __u16                   tw_num;
        kmemcheck_bitfield_begin(flags);
@@ -191,10 +185,10 @@ static inline struct inet_timewait_sock *inet_twsk(const struct sock *sk)
        return (struct inet_timewait_sock *)sk;
 }
 
-static inline __be32 inet_rcv_saddr(const struct sock *sk)
+static inline __be32 sk_rcv_saddr(const struct sock *sk)
 {
-       return likely(sk->sk_state != TCP_TIME_WAIT) ?
-               inet_sk(sk)->inet_rcv_saddr : inet_twsk(sk)->tw_rcv_saddr;
+/* both inet_sk() and inet_twsk() store rcv_saddr in skc_rcv_saddr */
+       return sk->__sk_common.skc_rcv_saddr;
 }
 
 extern void inet_twsk_put(struct inet_timewait_sock *tw);
index eaa4affd40cd79bf62b69e88ee49690bdb51f07e..e411cf87fb4152af0fe79bc7616eee34ca29dc38 100644 (file)
@@ -2055,8 +2055,8 @@ static inline void ieee80211_rx_ni(struct ieee80211_hw *hw,
  *
  * This function may not be called in IRQ context. Calls to this function
  * for a single hardware must be synchronized against each other. Calls
- * to this function and ieee80211_tx_status_irqsafe() may not be mixed
- * for a single hardware.
+ * to this function, ieee80211_tx_status_ni() and ieee80211_tx_status_irqsafe()
+ * may not be mixed for a single hardware.
  *
  * @hw: the hardware the frame was transmitted by
  * @skb: the frame that was transmitted, owned by mac80211 after this call
@@ -2064,14 +2064,34 @@ static inline void ieee80211_rx_ni(struct ieee80211_hw *hw,
 void ieee80211_tx_status(struct ieee80211_hw *hw,
                         struct sk_buff *skb);
 
+/**
+ * ieee80211_tx_status_ni - transmit status callback (in process context)
+ *
+ * Like ieee80211_tx_status() but can be called in process context.
+ *
+ * Calls to this function, ieee80211_tx_status() and
+ * ieee80211_tx_status_irqsafe() may not be mixed
+ * for a single hardware.
+ *
+ * @hw: the hardware the frame was transmitted by
+ * @skb: the frame that was transmitted, owned by mac80211 after this call
+ */
+static inline void ieee80211_tx_status_ni(struct ieee80211_hw *hw,
+                                         struct sk_buff *skb)
+{
+       local_bh_disable();
+       ieee80211_tx_status(hw, skb);
+       local_bh_enable();
+}
+
 /**
  * ieee80211_tx_status_irqsafe - IRQ-safe transmit status callback
  *
  * Like ieee80211_tx_status() but can be called in IRQ context
  * (internally defers to a tasklet.)
  *
- * Calls to this function and ieee80211_tx_status() may not be mixed for a
- * single hardware.
+ * Calls to this function, ieee80211_tx_status() and
+ * ieee80211_tx_status_ni() may not be mixed for a single hardware.
  *
  * @hw: the hardware the frame was transmitted by
  * @skb: the frame that was transmitted, owned by mac80211 after this call
index 717cfbf649dfb5ef092867756a70ebf22d122484..82e86034702f020915af395e4f57ca8a6609e3e1 100644 (file)
@@ -105,10 +105,8 @@ struct net;
 
 /**
  *     struct sock_common - minimal network layer representation of sockets
- *     @skc_node: main hash linkage for various protocol lookup tables
- *     @skc_nulls_node: main hash linkage for TCP/UDP/UDP-Lite protocol
- *     @skc_refcnt: reference count
- *     @skc_tx_queue_mapping: tx queue number for this connection
+ *     @skc_daddr: Foreign IPv4 addr
+ *     @skc_rcv_saddr: Bound local IPv4 addr
  *     @skc_hash: hash value used with various protocol lookup tables
  *     @skc_u16hashes: two u16 hash values used by UDP lookup tables
  *     @skc_family: network address family
@@ -119,20 +117,20 @@ struct net;
  *     @skc_portaddr_node: second hash linkage for UDP/UDP-Lite protocol
  *     @skc_prot: protocol handlers inside a network family
  *     @skc_net: reference to the network namespace of this socket
+ *     @skc_node: main hash linkage for various protocol lookup tables
+ *     @skc_nulls_node: main hash linkage for TCP/UDP/UDP-Lite protocol
+ *     @skc_tx_queue_mapping: tx queue number for this connection
+ *     @skc_refcnt: reference count
  *
  *     This is the minimal network layer representation of sockets, the header
  *     for struct sock and struct inet_timewait_sock.
  */
 struct sock_common {
-       /*
-        * first fields are not copied in sock_copy()
+       /* skc_daddr and skc_rcv_saddr must be grouped :
+        * cf INET_MATCH() and INET_TW_MATCH()
         */
-       union {
-               struct hlist_node       skc_node;
-               struct hlist_nulls_node skc_nulls_node;
-       };
-       atomic_t                skc_refcnt;
-       int                     skc_tx_queue_mapping;
+       __be32                  skc_daddr;
+       __be32                  skc_rcv_saddr;
 
        union  {
                unsigned int    skc_hash;
@@ -150,6 +148,18 @@ struct sock_common {
 #ifdef CONFIG_NET_NS
        struct net              *skc_net;
 #endif
+       /*
+        * fields between dontcopy_begin/dontcopy_end
+        * are not copied in sock_copy()
+        */
+       int                     skc_dontcopy_begin[0];
+       union {
+               struct hlist_node       skc_node;
+               struct hlist_nulls_node skc_nulls_node;
+       };
+       int                     skc_tx_queue_mapping;
+       atomic_t                skc_refcnt;
+       int                     skc_dontcopy_end[0];
 };
 
 /**
@@ -232,7 +242,8 @@ struct sock {
 #define sk_refcnt              __sk_common.skc_refcnt
 #define sk_tx_queue_mapping    __sk_common.skc_tx_queue_mapping
 
-#define sk_copy_start          __sk_common.skc_hash
+#define sk_dontcopy_begin      __sk_common.skc_dontcopy_begin
+#define sk_dontcopy_end                __sk_common.skc_dontcopy_end
 #define sk_hash                        __sk_common.skc_hash
 #define sk_family              __sk_common.skc_family
 #define sk_state               __sk_common.skc_state
@@ -1159,6 +1170,8 @@ extern void sk_common_release(struct sock *sk);
 /* Initialise core socket variables */
 extern void sock_init_data(struct socket *sock, struct sock *sk);
 
+extern void sk_filter_release_rcu(struct rcu_head *rcu);
+
 /**
  *     sk_filter_release - release a socket filter
  *     @fp: filter to remove
@@ -1169,7 +1182,7 @@ extern void sock_init_data(struct socket *sock, struct sock *sk);
 static inline void sk_filter_release(struct sk_filter *fp)
 {
        if (atomic_dec_and_test(&fp->refcnt))
-               kfree(fp);
+               call_rcu_bh(&fp->rcu, sk_filter_release_rcu);
 }
 
 static inline void sk_filter_uncharge(struct sock *sk, struct sk_filter *fp)
index 45c15f491401c017f8fa423b465f3c910de08685..798beac7f100271f0ca4607fe4b3b1fee3fc1d34 100644 (file)
 
 #include <linux/module.h>
 #include <linux/errno.h>
+#include <linux/kernel.h>
 #include <linux/uaccess.h>
 #include <linux/slab.h>
 #include <linux/sched.h>
+#include <linux/stddef.h>
 #include <linux/types.h>
 #include <net/9p/9p.h>
 #include <net/9p/client.h>
 #include "protocol.h"
 
-#ifndef MIN
-#define MIN(a, b) (((a) < (b)) ? (a) : (b))
-#endif
-
-#ifndef MAX
-#define MAX(a, b) (((a) > (b)) ? (a) : (b))
-#endif
-
-#ifndef offset_of
-#define offset_of(type, memb) \
-       ((unsigned long)(&((type *)0)->memb))
-#endif
-#ifndef container_of
-#define container_of(obj, type, memb) \
-       ((type *)(((char *)obj) - offset_of(type, memb)))
-#endif
-
 static int
 p9pdu_writef(struct p9_fcall *pdu, int proto_version, const char *fmt, ...);
 
@@ -104,7 +89,7 @@ EXPORT_SYMBOL(p9stat_free);
 
 static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
 {
-       size_t len = MIN(pdu->size - pdu->offset, size);
+       size_t len = min(pdu->size - pdu->offset, size);
        memcpy(data, &pdu->sdata[pdu->offset], len);
        pdu->offset += len;
        return size - len;
@@ -112,7 +97,7 @@ static size_t pdu_read(struct p9_fcall *pdu, void *data, size_t size)
 
 static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
 {
-       size_t len = MIN(pdu->capacity - pdu->size, size);
+       size_t len = min(pdu->capacity - pdu->size, size);
        memcpy(&pdu->sdata[pdu->size], data, len);
        pdu->size += len;
        return size - len;
@@ -121,7 +106,7 @@ static size_t pdu_write(struct p9_fcall *pdu, const void *data, size_t size)
 static size_t
 pdu_write_u(struct p9_fcall *pdu, const char __user *udata, size_t size)
 {
-       size_t len = MIN(pdu->capacity - pdu->size, size);
+       size_t len = min(pdu->capacity - pdu->size, size);
        if (copy_from_user(&pdu->sdata[pdu->size], udata, len))
                len = 0;
 
@@ -201,7 +186,7 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
                                if (errcode)
                                        break;
 
-                               size = MAX(len, 0);
+                               size = max_t(int16_t, len, 0);
 
                                *sptr = kmalloc(size + 1, GFP_KERNEL);
                                if (*sptr == NULL) {
@@ -256,8 +241,8 @@ p9pdu_vreadf(struct p9_fcall *pdu, int proto_version, const char *fmt,
                                    p9pdu_readf(pdu, proto_version, "d", count);
                                if (!errcode) {
                                        *count =
-                                           MIN(*count,
-                                               pdu->size - pdu->offset);
+                                           min_t(int32_t, *count,
+                                                 pdu->size - pdu->offset);
                                        *data = &pdu->sdata[pdu->offset];
                                }
                        }
@@ -421,7 +406,7 @@ p9pdu_vwritef(struct p9_fcall *pdu, int proto_version, const char *fmt,
                                const char *sptr = va_arg(ap, const char *);
                                int16_t len = 0;
                                if (sptr)
-                                       len = MIN(strlen(sptr), USHRT_MAX);
+                                       len = min_t(int16_t, strlen(sptr), USHRT_MAX);
 
                                errcode = p9pdu_writef(pdu, proto_version,
                                                                "w", len);
index f10b41fb05a0e1cd51ebae02320f755c249ef0a3..5868597534e529b4c33d1e603cbe38bed740a4ad 100644 (file)
@@ -648,6 +648,7 @@ int bnep_del_connection(struct bnep_conndel_req *req)
 
 static void __bnep_copy_ci(struct bnep_conninfo *ci, struct bnep_session *s)
 {
+       memset(ci, 0, sizeof(*ci));
        memcpy(ci->dst, s->eh.h_source, ETH_ALEN);
        strcpy(ci->device, s->dev->name);
        ci->flags = s->flags;
index ec0a1347f933cbdb9ca70be4f869d459f0ec9565..8e5f292529accd5784482c72a2090816a1ab7df6 100644 (file)
@@ -78,6 +78,7 @@ static void __cmtp_unlink_session(struct cmtp_session *session)
 
 static void __cmtp_copy_session(struct cmtp_session *session, struct cmtp_conninfo *ci)
 {
+       memset(ci, 0, sizeof(*ci));
        bacpy(&ci->bdaddr, &session->bdaddr);
 
        ci->flags = session->flags;
index 0b1e460fe440cfb07a86c0a15e87b7e98c03ba0f..6b90a41917347826f2a81fea590124a54af1f9bd 100644 (file)
@@ -39,7 +39,7 @@
 #include <net/sock.h>
 
 #include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -66,7 +66,8 @@ void hci_acl_connect(struct hci_conn *conn)
        bacpy(&cp.bdaddr, &conn->dst);
        cp.pscan_rep_mode = 0x02;
 
-       if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst))) {
+       ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
+       if (ie) {
                if (inquiry_entry_age(ie) <= INQUIRY_ENTRY_AGE_MAX) {
                        cp.pscan_rep_mode = ie->data.pscan_rep_mode;
                        cp.pscan_mode     = ie->data.pscan_mode;
@@ -368,8 +369,10 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
 
        BT_DBG("%s dst %s", hdev->name, batostr(dst));
 
-       if (!(acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst))) {
-               if (!(acl = hci_conn_add(hdev, ACL_LINK, dst)))
+       acl = hci_conn_hash_lookup_ba(hdev, ACL_LINK, dst);
+       if (!acl) {
+               acl = hci_conn_add(hdev, ACL_LINK, dst);
+               if (!acl)
                        return NULL;
        }
 
@@ -389,8 +392,10 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
        if (type == ACL_LINK)
                return acl;
 
-       if (!(sco = hci_conn_hash_lookup_ba(hdev, type, dst))) {
-               if (!(sco = hci_conn_add(hdev, type, dst))) {
+       sco = hci_conn_hash_lookup_ba(hdev, type, dst);
+       if (!sco) {
+               sco = hci_conn_add(hdev, type, dst);
+               if (!sco) {
                        hci_conn_put(acl);
                        return NULL;
                }
@@ -647,10 +652,12 @@ int hci_get_conn_list(void __user *arg)
 
        size = sizeof(req) + req.conn_num * sizeof(*ci);
 
-       if (!(cl = kmalloc(size, GFP_KERNEL)))
+       cl = kmalloc(size, GFP_KERNEL);
+       if (!cl)
                return -ENOMEM;
 
-       if (!(hdev = hci_dev_get(req.dev_id))) {
+       hdev = hci_dev_get(req.dev_id);
+       if (!hdev) {
                kfree(cl);
                return -ENODEV;
        }
index bc2a052e518b37518eaf9e128ce418d195bd91e1..51c61f75a7972170eceafb08b774adb2cd1d3da5 100644 (file)
@@ -44,7 +44,7 @@
 #include <net/sock.h>
 
 #include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -349,20 +349,23 @@ struct inquiry_entry *hci_inquiry_cache_lookup(struct hci_dev *hdev, bdaddr_t *b
 void hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data)
 {
        struct inquiry_cache *cache = &hdev->inq_cache;
-       struct inquiry_entry *e;
+       struct inquiry_entry *ie;
 
        BT_DBG("cache %p, %s", cache, batostr(&data->bdaddr));
 
-       if (!(e = hci_inquiry_cache_lookup(hdev, &data->bdaddr))) {
+       ie = hci_inquiry_cache_lookup(hdev, &data->bdaddr);
+       if (!ie) {
                /* Entry not in the cache. Add new one. */
-               if (!(e = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC)))
+               ie = kzalloc(sizeof(struct inquiry_entry), GFP_ATOMIC);
+               if (!ie)
                        return;
-               e->next     = cache->list;
-               cache->list = e;
+
+               ie->next = cache->list;
+               cache->list = ie;
        }
 
-       memcpy(&e->data, data, sizeof(*data));
-       e->timestamp = jiffies;
+       memcpy(&ie->data, data, sizeof(*data));
+       ie->timestamp = jiffies;
        cache->timestamp = jiffies;
 }
 
@@ -422,16 +425,20 @@ int hci_inquiry(void __user *arg)
 
        hci_dev_lock_bh(hdev);
        if (inquiry_cache_age(hdev) > INQUIRY_CACHE_AGE_MAX ||
-                                       inquiry_cache_empty(hdev) ||
-                                       ir.flags & IREQ_CACHE_FLUSH) {
+                               inquiry_cache_empty(hdev) ||
+                               ir.flags & IREQ_CACHE_FLUSH) {
                inquiry_cache_flush(hdev);
                do_inquiry = 1;
        }
        hci_dev_unlock_bh(hdev);
 
        timeo = ir.length * msecs_to_jiffies(2000);
-       if (do_inquiry && (err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo)) < 0)
-               goto done;
+
+       if (do_inquiry) {
+               err = hci_request(hdev, hci_inq_req, (unsigned long)&ir, timeo);
+               if (err < 0)
+                       goto done;
+       }
 
        /* for unlimited number of responses we will use buffer with 255 entries */
        max_rsp = (ir.num_rsp == 0) ? 255 : ir.num_rsp;
@@ -439,7 +446,8 @@ int hci_inquiry(void __user *arg)
        /* cache_dump can't sleep. Therefore we allocate temp buffer and then
         * copy it to the user space.
         */
-       if (!(buf = kmalloc(sizeof(struct inquiry_info) * max_rsp, GFP_KERNEL))) {
+       buf = kmalloc(sizeof(struct inquiry_info) *max_rsp, GFP_KERNEL);
+       if (!buf) {
                err = -ENOMEM;
                goto done;
        }
@@ -611,7 +619,8 @@ int hci_dev_close(__u16 dev)
        struct hci_dev *hdev;
        int err;
 
-       if (!(hdev = hci_dev_get(dev)))
+       hdev = hci_dev_get(dev);
+       if (!hdev)
                return -ENODEV;
        err = hci_dev_do_close(hdev);
        hci_dev_put(hdev);
@@ -623,7 +632,8 @@ int hci_dev_reset(__u16 dev)
        struct hci_dev *hdev;
        int ret = 0;
 
-       if (!(hdev = hci_dev_get(dev)))
+       hdev = hci_dev_get(dev);
+       if (!hdev)
                return -ENODEV;
 
        hci_req_lock(hdev);
@@ -663,7 +673,8 @@ int hci_dev_reset_stat(__u16 dev)
        struct hci_dev *hdev;
        int ret = 0;
 
-       if (!(hdev = hci_dev_get(dev)))
+       hdev = hci_dev_get(dev);
+       if (!hdev)
                return -ENODEV;
 
        memset(&hdev->stat, 0, sizeof(struct hci_dev_stats));
@@ -682,7 +693,8 @@ int hci_dev_cmd(unsigned int cmd, void __user *arg)
        if (copy_from_user(&dr, arg, sizeof(dr)))
                return -EFAULT;
 
-       if (!(hdev = hci_dev_get(dr.dev_id)))
+       hdev = hci_dev_get(dr.dev_id);
+       if (!hdev)
                return -ENODEV;
 
        switch (cmd) {
@@ -763,7 +775,8 @@ int hci_get_dev_list(void __user *arg)
 
        size = sizeof(*dl) + dev_num * sizeof(*dr);
 
-       if (!(dl = kzalloc(size, GFP_KERNEL)))
+       dl = kzalloc(size, GFP_KERNEL);
+       if (!dl)
                return -ENOMEM;
 
        dr = dl->dev_req;
@@ -797,7 +810,8 @@ int hci_get_dev_info(void __user *arg)
        if (copy_from_user(&di, arg, sizeof(di)))
                return -EFAULT;
 
-       if (!(hdev = hci_dev_get(di.dev_id)))
+       hdev = hci_dev_get(di.dev_id);
+       if (!hdev)
                return -ENODEV;
 
        strcpy(di.name, hdev->name);
@@ -905,7 +919,7 @@ int hci_register_dev(struct hci_dev *hdev)
        hdev->sniff_max_interval = 800;
        hdev->sniff_min_interval = 80;
 
-       tasklet_init(&hdev->cmd_task, hci_cmd_task,(unsigned long) hdev);
+       tasklet_init(&hdev->cmd_task, hci_cmd_task, (unsigned long) hdev);
        tasklet_init(&hdev->rx_task, hci_rx_task, (unsigned long) hdev);
        tasklet_init(&hdev->tx_task, hci_tx_task, (unsigned long) hdev);
 
@@ -1368,7 +1382,8 @@ void hci_send_acl(struct hci_conn *conn, struct sk_buff *skb, __u16 flags)
        bt_cb(skb)->pkt_type = HCI_ACLDATA_PKT;
        hci_add_acl_hdr(skb, conn->handle, flags | ACL_START);
 
-       if (!(list = skb_shinfo(skb)->frag_list)) {
+       list = skb_shinfo(skb)->frag_list;
+       if (!list) {
                /* Non fragmented */
                BT_DBG("%s nonfrag skb %p len %d", hdev->name, skb, skb->len);
 
@@ -1609,7 +1624,8 @@ static inline void hci_acldata_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_conn_enter_active_mode(conn);
 
                /* Send to upper protocol */
-               if ((hp = hci_proto[HCI_PROTO_L2CAP]) && hp->recv_acldata) {
+               hp = hci_proto[HCI_PROTO_L2CAP];
+               if (hp && hp->recv_acldata) {
                        hp->recv_acldata(conn, skb, flags);
                        return;
                }
@@ -1644,7 +1660,8 @@ static inline void hci_scodata_packet(struct hci_dev *hdev, struct sk_buff *skb)
                register struct hci_proto *hp;
 
                /* Send to upper protocol */
-               if ((hp = hci_proto[HCI_PROTO_SCO]) && hp->recv_scodata) {
+               hp = hci_proto[HCI_PROTO_SCO];
+               if (hp && hp->recv_scodata) {
                        hp->recv_scodata(conn, skb);
                        return;
                }
@@ -1727,7 +1744,8 @@ static void hci_cmd_task(unsigned long arg)
        if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) {
                kfree_skb(hdev->sent_cmd);
 
-               if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) {
+               hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC);
+               if (hdev->sent_cmd) {
                        atomic_dec(&hdev->cmd_cnt);
                        hci_send_frame(skb);
                        hdev->cmd_last_tx = jiffies;
index 84093b0000b9e0eb0107d22dd0503e699d36eff8..8923b36a67a28d69952807da655cdfb42717119a 100644 (file)
@@ -39,7 +39,7 @@
 #include <net/sock.h>
 
 #include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -677,9 +677,50 @@ static void hci_cs_set_conn_encrypt(struct hci_dev *hdev, __u8 status)
        hci_dev_unlock(hdev);
 }
 
+static int hci_outgoing_auth_needed(struct hci_dev *hdev,
+                                               struct hci_conn *conn)
+{
+       if (conn->state != BT_CONFIG || !conn->out)
+               return 0;
+
+       if (conn->sec_level == BT_SECURITY_SDP)
+               return 0;
+
+       /* Only request authentication for SSP connections or non-SSP
+        * devices with sec_level HIGH */
+       if (!(hdev->ssp_mode > 0 && conn->ssp_mode > 0) &&
+                                       conn->sec_level != BT_SECURITY_HIGH)
+               return 0;
+
+       return 1;
+}
+
 static void hci_cs_remote_name_req(struct hci_dev *hdev, __u8 status)
 {
+       struct hci_cp_remote_name_req *cp;
+       struct hci_conn *conn;
+
        BT_DBG("%s status 0x%x", hdev->name, status);
+
+       /* If successful wait for the name req complete event before
+        * checking for the need to do authentication */
+       if (!status)
+               return;
+
+       cp = hci_sent_cmd_data(hdev, HCI_OP_REMOTE_NAME_REQ);
+       if (!cp)
+               return;
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &cp->bdaddr);
+       if (conn && hci_outgoing_auth_needed(hdev, conn)) {
+               struct hci_cp_auth_requested cp;
+               cp.handle = __cpu_to_le16(conn->handle);
+               hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
+       }
+
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cs_read_remote_features(struct hci_dev *hdev, __u8 status)
@@ -955,12 +996,14 @@ static inline void hci_conn_request_evt(struct hci_dev *hdev, struct sk_buff *sk
 
                hci_dev_lock(hdev);
 
-               if ((ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr)))
+               ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
+               if (ie)
                        memcpy(ie->data.dev_class, ev->dev_class, 3);
 
                conn = hci_conn_hash_lookup_ba(hdev, ev->link_type, &ev->bdaddr);
                if (!conn) {
-                       if (!(conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr))) {
+                       conn = hci_conn_add(hdev, ev->link_type, &ev->bdaddr);
+                       if (!conn) {
                                BT_ERR("No memory for new connection");
                                hci_dev_unlock(hdev);
                                return;
@@ -1090,9 +1133,23 @@ static inline void hci_auth_complete_evt(struct hci_dev *hdev, struct sk_buff *s
 
 static inline void hci_remote_name_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
+       struct hci_ev_remote_name *ev = (void *) skb->data;
+       struct hci_conn *conn;
+
        BT_DBG("%s", hdev->name);
 
        hci_conn_check_pending(hdev);
+
+       hci_dev_lock(hdev);
+
+       conn = hci_conn_hash_lookup_ba(hdev, ACL_LINK, &ev->bdaddr);
+       if (conn && hci_outgoing_auth_needed(hdev, conn)) {
+               struct hci_cp_auth_requested cp;
+               cp.handle = __cpu_to_le16(conn->handle);
+               hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED, sizeof(cp), &cp);
+       }
+
+       hci_dev_unlock(hdev);
 }
 
 static inline void hci_encrypt_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
@@ -1162,33 +1219,39 @@ static inline void hci_remote_features_evt(struct hci_dev *hdev, struct sk_buff
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
-       if (conn) {
-               if (!ev->status)
-                       memcpy(conn->features, ev->features, 8);
+       if (!conn)
+               goto unlock;
 
-               if (conn->state == BT_CONFIG) {
-                       if (!ev->status && lmp_ssp_capable(hdev) &&
-                                               lmp_ssp_capable(conn)) {
-                               struct hci_cp_read_remote_ext_features cp;
-                               cp.handle = ev->handle;
-                               cp.page = 0x01;
-                               hci_send_cmd(hdev,
-                                       HCI_OP_READ_REMOTE_EXT_FEATURES,
-                                                       sizeof(cp), &cp);
-                       } else if (!ev->status && conn->out &&
-                                       conn->sec_level == BT_SECURITY_HIGH) {
-                               struct hci_cp_auth_requested cp;
-                               cp.handle = ev->handle;
-                               hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED,
+       if (!ev->status)
+               memcpy(conn->features, ev->features, 8);
+
+       if (conn->state != BT_CONFIG)
+               goto unlock;
+
+       if (!ev->status && lmp_ssp_capable(hdev) && lmp_ssp_capable(conn)) {
+               struct hci_cp_read_remote_ext_features cp;
+               cp.handle = ev->handle;
+               cp.page = 0x01;
+               hci_send_cmd(hdev, HCI_OP_READ_REMOTE_EXT_FEATURES,
                                                        sizeof(cp), &cp);
-                       } else {
-                               conn->state = BT_CONNECTED;
-                               hci_proto_connect_cfm(conn, ev->status);
-                               hci_conn_put(conn);
-                       }
-               }
+               goto unlock;
+       }
+
+       if (!ev->status) {
+               struct hci_cp_remote_name_req cp;
+               memset(&cp, 0, sizeof(cp));
+               bacpy(&cp.bdaddr, &conn->dst);
+               cp.pscan_rep_mode = 0x02;
+               hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
        }
 
+       if (!hci_outgoing_auth_needed(hdev, conn)) {
+               conn->state = BT_CONNECTED;
+               hci_proto_connect_cfm(conn, ev->status);
+               hci_conn_put(conn);
+       }
+
+unlock:
        hci_dev_unlock(hdev);
 }
 
@@ -1449,10 +1512,12 @@ static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *s
                        conn->sent -= count;
 
                        if (conn->type == ACL_LINK) {
-                               if ((hdev->acl_cnt += count) > hdev->acl_pkts)
+                               hdev->acl_cnt += count;
+                               if (hdev->acl_cnt > hdev->acl_pkts)
                                        hdev->acl_cnt = hdev->acl_pkts;
                        } else {
-                               if ((hdev->sco_cnt += count) > hdev->sco_pkts)
+                               hdev->sco_cnt += count;
+                               if (hdev->sco_cnt > hdev->sco_pkts)
                                        hdev->sco_cnt = hdev->sco_pkts;
                        }
                }
@@ -1547,7 +1612,8 @@ static inline void hci_clock_offset_evt(struct hci_dev *hdev, struct sk_buff *sk
        if (conn && !ev->status) {
                struct inquiry_entry *ie;
 
-               if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst))) {
+               ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
+               if (ie) {
                        ie->data.clock_offset = ev->clock_offset;
                        ie->timestamp = jiffies;
                }
@@ -1581,7 +1647,8 @@ static inline void hci_pscan_rep_mode_evt(struct hci_dev *hdev, struct sk_buff *
 
        hci_dev_lock(hdev);
 
-       if ((ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr))) {
+       ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
+       if (ie) {
                ie->data.pscan_rep_mode = ev->pscan_rep_mode;
                ie->timestamp = jiffies;
        }
@@ -1646,32 +1713,37 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b
        hci_dev_lock(hdev);
 
        conn = hci_conn_hash_lookup_handle(hdev, __le16_to_cpu(ev->handle));
-       if (conn) {
-               if (!ev->status && ev->page == 0x01) {
-                       struct inquiry_entry *ie;
+       if (!conn)
+               goto unlock;
 
-                       if ((ie = hci_inquiry_cache_lookup(hdev, &conn->dst)))
-                               ie->data.ssp_mode = (ev->features[0] & 0x01);
+       if (!ev->status && ev->page == 0x01) {
+               struct inquiry_entry *ie;
 
-                       conn->ssp_mode = (ev->features[0] & 0x01);
-               }
+               ie = hci_inquiry_cache_lookup(hdev, &conn->dst);
+               if (ie)
+                       ie->data.ssp_mode = (ev->features[0] & 0x01);
 
-               if (conn->state == BT_CONFIG) {
-                       if (!ev->status && hdev->ssp_mode > 0 &&
-                                       conn->ssp_mode > 0 && conn->out &&
-                                       conn->sec_level != BT_SECURITY_SDP) {
-                               struct hci_cp_auth_requested cp;
-                               cp.handle = ev->handle;
-                               hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED,
-                                                       sizeof(cp), &cp);
-                       } else {
-                               conn->state = BT_CONNECTED;
-                               hci_proto_connect_cfm(conn, ev->status);
-                               hci_conn_put(conn);
-                       }
-               }
+               conn->ssp_mode = (ev->features[0] & 0x01);
        }
 
+       if (conn->state != BT_CONFIG)
+               goto unlock;
+
+       if (!ev->status) {
+               struct hci_cp_remote_name_req cp;
+               memset(&cp, 0, sizeof(cp));
+               bacpy(&cp.bdaddr, &conn->dst);
+               cp.pscan_rep_mode = 0x02;
+               hci_send_cmd(hdev, HCI_OP_REMOTE_NAME_REQ, sizeof(cp), &cp);
+       }
+
+       if (!hci_outgoing_auth_needed(hdev, conn)) {
+               conn->state = BT_CONNECTED;
+               hci_proto_connect_cfm(conn, ev->status);
+               hci_conn_put(conn);
+       }
+
+unlock:
        hci_dev_unlock(hdev);
 }
 
@@ -1821,7 +1893,8 @@ static inline void hci_remote_host_features_evt(struct hci_dev *hdev, struct sk_
 
        hci_dev_lock(hdev);
 
-       if ((ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr)))
+       ie = hci_inquiry_cache_lookup(hdev, &ev->bdaddr);
+       if (ie)
                ie->data.ssp_mode = (ev->features[0] & 0x01);
 
        hci_dev_unlock(hdev);
index 83acd164d39e33d0401edd09273bdfe9223d6284..b3753bad2a554535a347599e97210e45395f6819 100644 (file)
@@ -43,7 +43,7 @@
 #include <net/sock.h>
 
 #include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -125,7 +125,8 @@ void hci_send_to_sock(struct hci_dev *hdev, struct sk_buff *skb)
                                continue;
                }
 
-               if (!(nskb = skb_clone(skb, GFP_ATOMIC)))
+               nskb = skb_clone(skb, GFP_ATOMIC);
+               if (!nskb)
                        continue;
 
                /* Put type byte before the data */
@@ -370,7 +371,8 @@ static int hci_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_le
        }
 
        if (haddr->hci_dev != HCI_DEV_NONE) {
-               if (!(hdev = hci_dev_get(haddr->hci_dev))) {
+               hdev = hci_dev_get(haddr->hci_dev);
+               if (!hdev) {
                        err = -ENODEV;
                        goto done;
                }
@@ -457,7 +459,8 @@ static int hci_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
        if (sk->sk_state == BT_CLOSED)
                return 0;
 
-       if (!(skb = skb_recv_datagram(sk, flags, noblock, &err)))
+       skb = skb_recv_datagram(sk, flags, noblock, &err);
+       if (!skb)
                return err;
 
        msg->msg_namelen = 0;
@@ -499,7 +502,8 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
 
        lock_sock(sk);
 
-       if (!(hdev = hci_pi(sk)->hdev)) {
+       hdev = hci_pi(sk)->hdev;
+       if (!hdev) {
                err = -EBADFD;
                goto done;
        }
@@ -509,7 +513,8 @@ static int hci_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
                goto done;
        }
 
-       if (!(skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err)))
+       skb = bt_skb_send_alloc(sk, len, msg->msg_flags & MSG_DONTWAIT, &err);
+       if (!skb)
                goto done;
 
        if (memcpy_fromiovec(skb_put(skb, len), msg->msg_iov, len)) {
index c0ee8b3928ed9b97eeaf7ef8d195a222bc2a3225..29544c21f4b52b33a34b87a8621d6150cd9b2455 100644 (file)
@@ -107,6 +107,7 @@ static void __hidp_unlink_session(struct hidp_session *session)
 
 static void __hidp_copy_session(struct hidp_session *session, struct hidp_conninfo *ci)
 {
+       memset(ci, 0, sizeof(*ci));
        bacpy(&ci->bdaddr, &session->bdaddr);
 
        ci->flags = session->flags;
@@ -115,7 +116,6 @@ static void __hidp_copy_session(struct hidp_session *session, struct hidp_connin
        ci->vendor  = 0x0000;
        ci->product = 0x0000;
        ci->version = 0x0000;
-       memset(ci->name, 0, 128);
 
        if (session->input) {
                ci->vendor  = session->input->id.vendor;
index cd8f6ea038414ce21794f05f219f37716eea43e0..c12eccfdfe016950805cc3fd32368e244b1aeace 100644 (file)
@@ -57,7 +57,7 @@
 
 #define VERSION "2.15"
 
-static int disable_ertm = 0;
+static int disable_ertm;
 
 static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
 static u8 l2cap_fixed_chan[8] = { 0x02, };
@@ -83,6 +83,18 @@ static struct sk_buff *l2cap_build_cmd(struct l2cap_conn *conn,
 static int l2cap_ertm_data_rcv(struct sock *sk, struct sk_buff *skb);
 
 /* ---- L2CAP timers ---- */
+static void l2cap_sock_set_timer(struct sock *sk, long timeout)
+{
+       BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout);
+       sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout);
+}
+
+static void l2cap_sock_clear_timer(struct sock *sk)
+{
+       BT_DBG("sock %p state %d", sk, sk->sk_state);
+       sk_stop_timer(sk, &sk->sk_timer);
+}
+
 static void l2cap_sock_timeout(unsigned long arg)
 {
        struct sock *sk = (struct sock *) arg;
@@ -92,6 +104,14 @@ static void l2cap_sock_timeout(unsigned long arg)
 
        bh_lock_sock(sk);
 
+       if (sock_owned_by_user(sk)) {
+               /* sk is owned by user. Try again later */
+               l2cap_sock_set_timer(sk, HZ / 5);
+               bh_unlock_sock(sk);
+               sock_put(sk);
+               return;
+       }
+
        if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)
                reason = ECONNREFUSED;
        else if (sk->sk_state == BT_CONNECT &&
@@ -108,18 +128,6 @@ static void l2cap_sock_timeout(unsigned long arg)
        sock_put(sk);
 }
 
-static void l2cap_sock_set_timer(struct sock *sk, long timeout)
-{
-       BT_DBG("sk %p state %d timeout %ld", sk, sk->sk_state, timeout);
-       sk_reset_timer(sk, &sk->sk_timer, jiffies + timeout);
-}
-
-static void l2cap_sock_clear_timer(struct sock *sk)
-{
-       BT_DBG("sock %p state %d", sk, sk->sk_state);
-       sk_stop_timer(sk, &sk->sk_timer);
-}
-
 /* ---- L2CAP channels ---- */
 static struct sock *__l2cap_get_chan_by_dcid(struct l2cap_chan_list *l, u16 cid)
 {
@@ -743,11 +751,13 @@ found:
 /* Find socket with psm and source bdaddr.
  * Returns closest match.
  */
-static struct sock *__l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src)
+static struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src)
 {
        struct sock *sk = NULL, *sk1 = NULL;
        struct hlist_node *node;
 
+       read_lock(&l2cap_sk_list.lock);
+
        sk_for_each(sk, node, &l2cap_sk_list.head) {
                if (state && sk->sk_state != state)
                        continue;
@@ -762,20 +772,10 @@ static struct sock *__l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src
                                sk1 = sk;
                }
        }
-       return node ? sk : sk1;
-}
 
-/* Find socket with given address (psm, src).
- * Returns locked socket */
-static inline struct sock *l2cap_get_sock_by_psm(int state, __le16 psm, bdaddr_t *src)
-{
-       struct sock *s;
-       read_lock(&l2cap_sk_list.lock);
-       s = __l2cap_get_sock_by_psm(state, psm, src);
-       if (s)
-               bh_lock_sock(s);
        read_unlock(&l2cap_sk_list.lock);
-       return s;
+
+       return node ? sk : sk1;
 }
 
 static void l2cap_sock_destruct(struct sock *sk)
@@ -2926,6 +2926,8 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
                goto sendresp;
        }
 
+       bh_lock_sock(parent);
+
        /* Check if the ACL is secure enough (if not SDP) */
        if (psm != cpu_to_le16(0x0001) &&
                                !hci_conn_check_link_mode(conn->hcon)) {
@@ -3078,6 +3080,14 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
                break;
 
        default:
+               /* don't delete l2cap channel if sk is owned by user */
+               if (sock_owned_by_user(sk)) {
+                       sk->sk_state = BT_DISCONN;
+                       l2cap_sock_clear_timer(sk);
+                       l2cap_sock_set_timer(sk, HZ / 5);
+                       break;
+               }
+
                l2cap_chan_del(sk, ECONNREFUSED);
                break;
        }
@@ -3283,6 +3293,15 @@ static inline int l2cap_disconnect_req(struct l2cap_conn *conn, struct l2cap_cmd
 
        sk->sk_shutdown = SHUTDOWN_MASK;
 
+       /* don't delete l2cap channel if sk is owned by user */
+       if (sock_owned_by_user(sk)) {
+               sk->sk_state = BT_DISCONN;
+               l2cap_sock_clear_timer(sk);
+               l2cap_sock_set_timer(sk, HZ / 5);
+               bh_unlock_sock(sk);
+               return 0;
+       }
+
        l2cap_chan_del(sk, ECONNRESET);
        bh_unlock_sock(sk);
 
@@ -3305,6 +3324,15 @@ static inline int l2cap_disconnect_rsp(struct l2cap_conn *conn, struct l2cap_cmd
        if (!sk)
                return 0;
 
+       /* don't delete l2cap channel if sk is owned by user */
+       if (sock_owned_by_user(sk)) {
+               sk->sk_state = BT_DISCONN;
+               l2cap_sock_clear_timer(sk);
+               l2cap_sock_set_timer(sk, HZ / 5);
+               bh_unlock_sock(sk);
+               return 0;
+       }
+
        l2cap_chan_del(sk, 0);
        bh_unlock_sock(sk);
 
@@ -4134,11 +4162,10 @@ static inline void l2cap_data_channel_rrframe(struct sock *sk, u16 rx_control)
                        __mod_retrans_timer();
 
                pi->conn_state &= ~L2CAP_CONN_REMOTE_BUSY;
-               if (pi->conn_state & L2CAP_CONN_SREJ_SENT) {
+               if (pi->conn_state & L2CAP_CONN_SREJ_SENT)
                        l2cap_send_ack(pi);
-               } else {
+               else
                        l2cap_ertm_send(sk);
-               }
        }
 }
 
@@ -4430,6 +4457,8 @@ static inline int l2cap_conless_channel(struct l2cap_conn *conn, __le16 psm, str
        if (!sk)
                goto drop;
 
+       bh_lock_sock(sk);
+
        BT_DBG("sk %p, len %d", sk, skb->len);
 
        if (sk->sk_state != BT_BOUND && sk->sk_state != BT_CONNECTED)
@@ -4841,8 +4870,10 @@ static int __init l2cap_init(void)
                return err;
 
        _busy_wq = create_singlethread_workqueue("l2cap");
-       if (!_busy_wq)
-               goto error;
+       if (!_busy_wq) {
+               proto_unregister(&l2cap_proto);
+               return -ENOMEM;
+       }
 
        err = bt_sock_register(BTPROTO_L2CAP, &l2cap_sock_family_ops);
        if (err < 0) {
@@ -4870,6 +4901,7 @@ static int __init l2cap_init(void)
        return 0;
 
 error:
+       destroy_workqueue(_busy_wq);
        proto_unregister(&l2cap_proto);
        return err;
 }
index fa642aa652bdba0d4b0b3f47c77dc9e55571c19f..c1e2bbafb549eb39d475bf577a8fc57099b83a4f 100644 (file)
@@ -41,7 +41,7 @@
 #include <linux/slab.h>
 
 #include <net/sock.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
 
 #define VERSION "1.11"
 
-static int disable_cfc = 0;
+static int disable_cfc;
+static int l2cap_ertm;
 static int channel_mtu = -1;
 static unsigned int l2cap_mtu = RFCOMM_MAX_L2CAP_MTU;
-static int l2cap_ertm = 0;
 
 static struct task_struct *rfcomm_thread;
 
@@ -1901,7 +1901,7 @@ static inline void rfcomm_check_connection(struct rfcomm_session *s)
 
        BT_DBG("%p state %ld", s, s->state);
 
-       switch(sk->sk_state) {
+       switch (sk->sk_state) {
        case BT_CONNECTED:
                s->state = BT_CONNECT;
 
index aec505f934dff30d8f711a13e3d2ef95ae5f8016..66cc1f0c3df85c5f5b18c8f179ef8434d23f4cf8 100644 (file)
@@ -45,7 +45,7 @@
 #include <net/sock.h>
 
 #include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -140,11 +140,13 @@ static struct sock *__rfcomm_get_sock_by_addr(u8 channel, bdaddr_t *src)
 /* Find socket with channel and source bdaddr.
  * Returns closest match.
  */
-static struct sock *__rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
+static struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
 {
        struct sock *sk = NULL, *sk1 = NULL;
        struct hlist_node *node;
 
+       read_lock(&rfcomm_sk_list.lock);
+
        sk_for_each(sk, node, &rfcomm_sk_list.head) {
                if (state && sk->sk_state != state)
                        continue;
@@ -159,19 +161,10 @@ static struct sock *__rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t
                                sk1 = sk;
                }
        }
-       return node ? sk : sk1;
-}
 
-/* Find socket with given address (channel, src).
- * Returns locked socket */
-static inline struct sock *rfcomm_get_sock_by_channel(int state, u8 channel, bdaddr_t *src)
-{
-       struct sock *s;
-       read_lock(&rfcomm_sk_list.lock);
-       s = __rfcomm_get_sock_by_channel(state, channel, src);
-       if (s) bh_lock_sock(s);
        read_unlock(&rfcomm_sk_list.lock);
-       return s;
+
+       return node ? sk : sk1;
 }
 
 static void rfcomm_sock_destruct(struct sock *sk)
@@ -895,7 +888,8 @@ static int rfcomm_sock_shutdown(struct socket *sock, int how)
 
        BT_DBG("sock %p, sk %p", sock, sk);
 
-       if (!sk) return 0;
+       if (!sk)
+               return 0;
 
        lock_sock(sk);
        if (!sk->sk_shutdown) {
@@ -945,6 +939,8 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
        if (!parent)
                return 0;
 
+       bh_lock_sock(parent);
+
        /* Check for backlog size */
        if (sk_acceptq_is_full(parent)) {
                BT_DBG("backlog full %d", parent->sk_ack_backlog);
index a9b81f5dacd14c942d46e46c4bdcacc9f2070ac8..2575c2db64047021080131d47d37a9f5ad49584a 100644 (file)
@@ -58,9 +58,9 @@ struct rfcomm_dev {
 
        bdaddr_t                src;
        bdaddr_t                dst;
-       u8                      channel;
+       u8                      channel;
 
-       uint                    modem_status;
+       uint                    modem_status;
 
        struct rfcomm_dlc       *dlc;
        struct tty_struct       *tty;
@@ -69,7 +69,7 @@ struct rfcomm_dev {
 
        struct device           *tty_dev;
 
-       atomic_t                wmem_alloc;
+       atomic_t                wmem_alloc;
 
        struct sk_buff_head     pending;
 };
@@ -431,7 +431,8 @@ static int rfcomm_release_dev(void __user *arg)
 
        BT_DBG("dev_id %d flags 0x%x", req.dev_id, req.flags);
 
-       if (!(dev = rfcomm_dev_get(req.dev_id)))
+       dev = rfcomm_dev_get(req.dev_id);
+       if (!dev)
                return -ENODEV;
 
        if (dev->flags != NOCAP_FLAGS && !capable(CAP_NET_ADMIN)) {
@@ -470,7 +471,8 @@ static int rfcomm_get_dev_list(void __user *arg)
 
        size = sizeof(*dl) + dev_num * sizeof(*di);
 
-       if (!(dl = kmalloc(size, GFP_KERNEL)))
+       dl = kmalloc(size, GFP_KERNEL);
+       if (!dl)
                return -ENOMEM;
 
        di = dl->dev_info;
@@ -513,7 +515,8 @@ static int rfcomm_get_dev_info(void __user *arg)
        if (copy_from_user(&di, arg, sizeof(di)))
                return -EFAULT;
 
-       if (!(dev = rfcomm_dev_get(di.id)))
+       dev = rfcomm_dev_get(di.id);
+       if (!dev)
                return -ENODEV;
 
        di.flags   = dev->flags;
@@ -561,7 +564,8 @@ static void rfcomm_dev_data_ready(struct rfcomm_dlc *dlc, struct sk_buff *skb)
                return;
        }
 
-       if (!(tty = dev->tty) || !skb_queue_empty(&dev->pending)) {
+       tty = dev->tty;
+       if (!tty || !skb_queue_empty(&dev->pending)) {
                skb_queue_tail(&dev->pending, skb);
                return;
        }
@@ -796,7 +800,8 @@ static int rfcomm_tty_write(struct tty_struct *tty, const unsigned char *buf, in
 
                memcpy(skb_put(skb, size), buf + sent, size);
 
-               if ((err = rfcomm_dlc_send(dlc, skb)) < 0) {
+               err = rfcomm_dlc_send(dlc, skb);
+               if (err < 0) {
                        kfree_skb(skb);
                        break;
                }
@@ -892,7 +897,7 @@ static void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
 
        /* Parity on/off and when on, odd/even */
        if (((old->c_cflag & PARENB) != (new->c_cflag & PARENB)) ||
-                       ((old->c_cflag & PARODD) != (new->c_cflag & PARODD)) ) {
+                       ((old->c_cflag & PARODD) != (new->c_cflag & PARODD))) {
                changes |= RFCOMM_RPN_PM_PARITY;
                BT_DBG("Parity change detected.");
        }
@@ -937,11 +942,10 @@ static void rfcomm_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
        /* POSIX does not support 1.5 stop bits and RFCOMM does not
         * support 2 stop bits. So a request for 2 stop bits gets
         * translated to 1.5 stop bits */
-       if (new->c_cflag & CSTOPB) {
+       if (new->c_cflag & CSTOPB)
                stop_bits = RFCOMM_RPN_STOP_15;
-       } else {
+       else
                stop_bits = RFCOMM_RPN_STOP_1;
-       }
 
        /* Handle number of data bits [5-8] */
        if ((old->c_cflag & CSIZE) != (new->c_cflag & CSIZE))
index d0927d1fdadaba4887dbac40064c4328541b9b00..960c6d1637da0d3ee23cc998e5890b84123f76c9 100644 (file)
@@ -44,7 +44,7 @@
 #include <net/sock.h>
 
 #include <asm/system.h>
-#include <asm/uaccess.h>
+#include <linux/uaccess.h>
 
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
@@ -52,7 +52,7 @@
 
 #define VERSION "0.6"
 
-static int disable_esco = 0;
+static int disable_esco;
 
 static const struct proto_ops sco_sock_ops;
 
@@ -138,16 +138,17 @@ static inline struct sock *sco_chan_get(struct sco_conn *conn)
 
 static int sco_conn_del(struct hci_conn *hcon, int err)
 {
-       struct sco_conn *conn;
+       struct sco_conn *conn = hcon->sco_data;
        struct sock *sk;
 
-       if (!(conn = hcon->sco_data))
+       if (!conn)
                return 0;
 
        BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
 
        /* Kill socket */
-       if ((sk = sco_chan_get(conn))) {
+       sk = sco_chan_get(conn);
+       if (sk) {
                bh_lock_sock(sk);
                sco_sock_clear_timer(sk);
                sco_chan_del(sk, err);
@@ -185,7 +186,8 @@ static int sco_connect(struct sock *sk)
 
        BT_DBG("%s -> %s", batostr(src), batostr(dst));
 
-       if (!(hdev = hci_get_route(dst, src)))
+       hdev = hci_get_route(dst, src);
+       if (!hdev)
                return -EHOSTUNREACH;
 
        hci_dev_lock_bh(hdev);
@@ -510,7 +512,8 @@ static int sco_sock_connect(struct socket *sock, struct sockaddr *addr, int alen
        /* Set destination address and psm */
        bacpy(&bt_sk(sk)->dst, &sa->sco_bdaddr);
 
-       if ((err = sco_connect(sk)))
+       err = sco_connect(sk);
+       if (err)
                goto done;
 
        err = bt_sock_wait_state(sk, BT_CONNECTED,
@@ -828,13 +831,14 @@ static void sco_chan_del(struct sock *sk, int err)
 
 static void sco_conn_ready(struct sco_conn *conn)
 {
-       struct sock *parent, *sk;
+       struct sock *parent;
+       struct sock *sk = conn->sk;
 
        BT_DBG("conn %p", conn);
 
        sco_conn_lock(conn);
 
-       if ((sk = conn->sk)) {
+       if (sk) {
                sco_sock_clear_timer(sk);
                bh_lock_sock(sk);
                sk->sk_state = BT_CONNECTED;
@@ -882,7 +886,7 @@ static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
        int lm = 0;
 
        if (type != SCO_LINK && type != ESCO_LINK)
-               return 0;
+               return -EINVAL;
 
        BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
 
@@ -908,7 +912,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
        BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
 
        if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
-               return 0;
+               return -EINVAL;
 
        if (!status) {
                struct sco_conn *conn;
@@ -927,7 +931,7 @@ static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
        BT_DBG("hcon %p reason %d", hcon, reason);
 
        if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
-               return 0;
+               return -EINVAL;
 
        sco_conn_del(hcon, bt_err(reason));
 
index 17cb0b633576eb96582b2b0ff22030bef02c3830..556443566e9c417bbb07da73d0cafd750d11de73 100644 (file)
@@ -141,7 +141,7 @@ static int br_change_mtu(struct net_device *dev, int new_mtu)
 
 #ifdef CONFIG_BRIDGE_NETFILTER
        /* remember the MTU in the rtable for PMTU */
-       br->fake_rtable.dst.metrics[RTAX_MTU - 1] = new_mtu;
+       dst_metric_set(&br->fake_rtable.dst, RTAX_MTU, new_mtu);
 #endif
 
        return 0;
index 6e13920939113b07e7ae1bbed452323e261865d2..16f5c333596a4d8076cfa994cc91ba03c9690f47 100644 (file)
@@ -124,7 +124,7 @@ void br_netfilter_rtable_init(struct net_bridge *br)
        atomic_set(&rt->dst.__refcnt, 1);
        rt->dst.dev = br->dev;
        rt->dst.path = &rt->dst;
-       rt->dst.metrics[RTAX_MTU - 1] = 1500;
+       dst_metric_set(&rt->dst, RTAX_MTU, 1500);
        rt->dst.flags   = DST_NOXFRM;
        rt->dst.ops = &fake_dst_ops;
 }
index 153bdec408359938c26e27bc4ce560387361f1b0..e87ef435e11b862351d1863a3d3682539e8fbc37 100644 (file)
@@ -1,9 +1,6 @@
 #
 # Makefile for CEPH filesystem.
 #
-
-ifneq ($(KERNELRELEASE),)
-
 obj-$(CONFIG_CEPH_LIB) += libceph.o
 
 libceph-y := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \
@@ -16,22 +13,3 @@ libceph-y := ceph_common.o messenger.o msgpool.o buffer.o pagelist.o \
        ceph_fs.o ceph_strings.o ceph_hash.o \
        pagevec.o
 
-else
-#Otherwise we were called directly from the command
-# line; invoke the kernel build system.
-
-KERNELDIR ?= /lib/modules/$(shell uname -r)/build
-PWD := $(shell pwd)
-
-default: all
-
-all:
-       $(MAKE) -C $(KERNELDIR) M=$(PWD) CONFIG_CEPH_LIB=m modules
-
-modules_install:
-       $(MAKE) -C $(KERNELDIR) M=$(PWD) CONFIG_CEPH_LIB=m modules_install
-
-clean:
-       $(MAKE) -C $(KERNELDIR) M=$(PWD) clean
-
-endif
index 53d8abfa25d5ede4b487c88a5341b376c4921c26..bf3e6a13c215cd61cd7372e85ba19e7fc7974e9a 100644 (file)
@@ -19,7 +19,7 @@ struct ceph_buffer *ceph_buffer_new(size_t len, gfp_t gfp)
        if (b->vec.iov_base) {
                b->is_vmalloc = false;
        } else {
-               b->vec.iov_base = __vmalloc(len, gfp, PAGE_KERNEL);
+               b->vec.iov_base = __vmalloc(len, gfp | __GFP_HIGHMEM, PAGE_KERNEL);
                if (!b->vec.iov_base) {
                        kfree(b);
                        return NULL;
index cd1e039c87559a236db754e738917b5e34666aaa..18ac112ea7ae7abeaef244b33752d1d3d9d2e460 100644 (file)
@@ -177,7 +177,7 @@ struct sk_buff *__skb_recv_datagram(struct sock *sk, unsigned flags,
                 * interrupt level will suddenly eat the receive_queue.
                 *
                 * Look at current nfs client by the way...
-                * However, this function was corrent in any case. 8)
+                * However, this function was correct in any case. 8)
                 */
                unsigned long cpu_flags;
 
index cd2437495428dd2316af7e55e4e41cfdf12b6132..d28b3a023bb2101f4884a03957e6856d1c2efe05 100644 (file)
@@ -743,34 +743,31 @@ struct net_device *dev_get_by_index(struct net *net, int ifindex)
 EXPORT_SYMBOL(dev_get_by_index);
 
 /**
- *     dev_getbyhwaddr - find a device by its hardware address
+ *     dev_getbyhwaddr_rcu - find a device by its hardware address
  *     @net: the applicable net namespace
  *     @type: media type of device
  *     @ha: hardware address
  *
  *     Search for an interface by MAC address. Returns NULL if the device
- *     is not found or a pointer to the device. The caller must hold the
- *     rtnl semaphore. The returned device has not had its ref count increased
+ *     is not found or a pointer to the device. The caller must hold RCU
+ *     The returned device has not had its ref count increased
  *     and the caller must therefore be careful about locking
  *
- *     BUGS:
- *     If the API was consistent this would be __dev_get_by_hwaddr
  */
 
-struct net_device *dev_getbyhwaddr(struct net *net, unsigned short type, char *ha)
+struct net_device *dev_getbyhwaddr_rcu(struct net *net, unsigned short type,
+                                      const char *ha)
 {
        struct net_device *dev;
 
-       ASSERT_RTNL();
-
-       for_each_netdev(net, dev)
+       for_each_netdev_rcu(net, dev)
                if (dev->type == type &&
                    !memcmp(dev->dev_addr, ha, dev->addr_len))
                        return dev;
 
        return NULL;
 }
-EXPORT_SYMBOL(dev_getbyhwaddr);
+EXPORT_SYMBOL(dev_getbyhwaddr_rcu);
 
 struct net_device *__dev_getfirstbyhwtype(struct net *net, unsigned short type)
 {
@@ -2025,9 +2022,6 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
        int rc = NETDEV_TX_OK;
 
        if (likely(!skb->next)) {
-               if (!list_empty(&ptype_all))
-                       dev_queue_xmit_nit(skb, dev);
-
                /*
                 * If device doesnt need skb->dst, release it right now while
                 * its hot in this cpu cache
@@ -2035,6 +2029,9 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
                if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
                        skb_dst_drop(skb);
 
+               if (!list_empty(&ptype_all))
+                       dev_queue_xmit_nit(skb, dev);
+
                skb_orphan_try(skb);
 
                if (vlan_tx_tag_present(skb) &&
@@ -5041,10 +5038,13 @@ unsigned long netdev_fix_features(unsigned long features, const char *name)
        }
 
        if (features & NETIF_F_UFO) {
-               if (!(features & NETIF_F_GEN_CSUM)) {
+               /* maybe split UFO into V4 and V6? */
+               if (!((features & NETIF_F_GEN_CSUM) ||
+                   (features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))
+                           == (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))) {
                        if (name)
                                printk(KERN_ERR "%s: Dropping NETIF_F_UFO "
-                                      "since no NETIF_F_HW_CSUM feature.\n",
+                                      "since no checksum offload features.\n",
                                       name);
                        features &= ~NETIF_F_UFO;
                }
@@ -5109,11 +5109,21 @@ static int netif_alloc_rx_queues(struct net_device *dev)
 }
 #endif
 
+static void netdev_init_one_queue(struct net_device *dev,
+                                 struct netdev_queue *queue, void *_unused)
+{
+       /* Initialize queue lock */
+       spin_lock_init(&queue->_xmit_lock);
+       netdev_set_xmit_lockdep_class(&queue->_xmit_lock, dev->type);
+       queue->xmit_lock_owner = -1;
+       netdev_queue_numa_node_write(queue, -1);
+       queue->dev = dev;
+}
+
 static int netif_alloc_netdev_queues(struct net_device *dev)
 {
        unsigned int count = dev->num_tx_queues;
        struct netdev_queue *tx;
-       int i;
 
        BUG_ON(count < 1);
 
@@ -5125,27 +5135,10 @@ static int netif_alloc_netdev_queues(struct net_device *dev)
        }
        dev->_tx = tx;
 
-       for (i = 0; i < count; i++) {
-               netdev_queue_numa_node_write(&tx[i], -1);
-               tx[i].dev = dev;
-       }
-       return 0;
-}
-
-static void netdev_init_one_queue(struct net_device *dev,
-                                 struct netdev_queue *queue,
-                                 void *_unused)
-{
-       /* Initialize queue lock */
-       spin_lock_init(&queue->_xmit_lock);
-       netdev_set_xmit_lockdep_class(&queue->_xmit_lock, dev->type);
-       queue->xmit_lock_owner = -1;
-}
-
-static void netdev_init_queues(struct net_device *dev)
-{
        netdev_for_each_tx_queue(dev, netdev_init_one_queue, NULL);
        spin_lock_init(&dev->tx_global_lock);
+
+       return 0;
 }
 
 /**
@@ -5184,8 +5177,6 @@ int register_netdevice(struct net_device *dev)
 
        dev->iflink = -1;
 
-       netdev_init_queues(dev);
-
        /* Init, if this function is available */
        if (dev->netdev_ops->ndo_init) {
                ret = dev->netdev_ops->ndo_init(dev);
index 956a9f4971cbc2e7f81c4ab5d8c8a8b909d00bf1..d5bc288188830970a4e0439f7e26b4b131082f00 100644 (file)
@@ -1171,7 +1171,9 @@ static int ethtool_set_ufo(struct net_device *dev, char __user *useraddr)
                return -EFAULT;
        if (edata.data && !(dev->features & NETIF_F_SG))
                return -EINVAL;
-       if (edata.data && !(dev->features & NETIF_F_HW_CSUM))
+       if (edata.data && !((dev->features & NETIF_F_GEN_CSUM) ||
+               (dev->features & (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM))
+                       == (NETIF_F_IP_CSUM|NETIF_F_IPV6_CSUM)))
                return -EINVAL;
        return dev->ethtool_ops->set_ufo(dev, edata.data);
 }
index a44d27f9f0f0aa4975d95b8e8c56bebb3f0fda6b..e8a6ac411ffb3a5e6ead2fb3e20daa21143af23a 100644 (file)
@@ -88,7 +88,7 @@ enum {
 };
 
 /* No hurry in this branch */
-static void *__load_pointer(struct sk_buff *skb, int k)
+static void *__load_pointer(const struct sk_buff *skb, int k, unsigned int size)
 {
        u8 *ptr = NULL;
 
@@ -97,12 +97,12 @@ static void *__load_pointer(struct sk_buff *skb, int k)
        else if (k >= SKF_LL_OFF)
                ptr = skb_mac_header(skb) + k - SKF_LL_OFF;
 
-       if (ptr >= skb->head && ptr < skb_tail_pointer(skb))
+       if (ptr >= skb->head && ptr + size <= skb_tail_pointer(skb))
                return ptr;
        return NULL;
 }
 
-static inline void *load_pointer(struct sk_buff *skb, int k,
+static inline void *load_pointer(const struct sk_buff *skb, int k,
                                 unsigned int size, void *buffer)
 {
        if (k >= 0)
@@ -110,7 +110,7 @@ static inline void *load_pointer(struct sk_buff *skb, int k,
        else {
                if (k >= SKF_AD_OFF)
                        return NULL;
-               return __load_pointer(skb, k);
+               return __load_pointer(skb, k, size);
        }
 }
 
@@ -160,17 +160,16 @@ EXPORT_SYMBOL(sk_filter);
  * and last instruction guaranteed to be a RET, we dont need to check
  * flen. (We used to pass to this function the length of filter)
  */
-unsigned int sk_run_filter(struct sk_buff *skb, const struct sock_filter *fentry)
+unsigned int sk_run_filter(const struct sk_buff *skb,
+                          const struct sock_filter *fentry)
 {
        void *ptr;
        u32 A = 0;                      /* Accumulator */
        u32 X = 0;                      /* Index Register */
        u32 mem[BPF_MEMWORDS];          /* Scratch Memory Store */
-       unsigned long memvalid = 0;
        u32 tmp;
        int k;
 
-       BUILD_BUG_ON(BPF_MEMWORDS > BITS_PER_LONG);
        /*
         * Process array of filter instructions.
         */
@@ -318,12 +317,10 @@ load_b:
                        X = K;
                        continue;
                case BPF_S_LD_MEM:
-                       A = (memvalid & (1UL << K)) ?
-                               mem[K] : 0;
+                       A = mem[K];
                        continue;
                case BPF_S_LDX_MEM:
-                       X = (memvalid & (1UL << K)) ?
-                               mem[K] : 0;
+                       X = mem[K];
                        continue;
                case BPF_S_MISC_TAX:
                        X = A;
@@ -336,11 +333,9 @@ load_b:
                case BPF_S_RET_A:
                        return A;
                case BPF_S_ST:
-                       memvalid |= 1UL << K;
                        mem[K] = A;
                        continue;
                case BPF_S_STX:
-                       memvalid |= 1UL << K;
                        mem[K] = X;
                        continue;
                default:
@@ -375,6 +370,12 @@ load_b:
                                return 0;
                        A = skb->dev->type;
                        continue;
+               case SKF_AD_RXHASH:
+                       A = skb->rxhash;
+                       continue;
+               case SKF_AD_CPU:
+                       A = raw_smp_processor_id();
+                       continue;
                case SKF_AD_NLATTR: {
                        struct nlattr *nla;
 
@@ -419,6 +420,66 @@ load_b:
 }
 EXPORT_SYMBOL(sk_run_filter);
 
+/*
+ * Security :
+ * A BPF program is able to use 16 cells of memory to store intermediate
+ * values (check u32 mem[BPF_MEMWORDS] in sk_run_filter())
+ * As we dont want to clear mem[] array for each packet going through
+ * sk_run_filter(), we check that filter loaded by user never try to read
+ * a cell if not previously written, and we check all branches to be sure
+ * a malicious user doesnt try to abuse us.
+ */
+static int check_load_and_stores(struct sock_filter *filter, int flen)
+{
+       u16 *masks, memvalid = 0; /* one bit per cell, 16 cells */
+       int pc, ret = 0;
+
+       BUILD_BUG_ON(BPF_MEMWORDS > 16);
+       masks = kmalloc(flen * sizeof(*masks), GFP_KERNEL);
+       if (!masks)
+               return -ENOMEM;
+       memset(masks, 0xff, flen * sizeof(*masks));
+
+       for (pc = 0; pc < flen; pc++) {
+               memvalid &= masks[pc];
+
+               switch (filter[pc].code) {
+               case BPF_S_ST:
+               case BPF_S_STX:
+                       memvalid |= (1 << filter[pc].k);
+                       break;
+               case BPF_S_LD_MEM:
+               case BPF_S_LDX_MEM:
+                       if (!(memvalid & (1 << filter[pc].k))) {
+                               ret = -EINVAL;
+                               goto error;
+                       }
+                       break;
+               case BPF_S_JMP_JA:
+                       /* a jump must set masks on target */
+                       masks[pc + 1 + filter[pc].k] &= memvalid;
+                       memvalid = ~0;
+                       break;
+               case BPF_S_JMP_JEQ_K:
+               case BPF_S_JMP_JEQ_X:
+               case BPF_S_JMP_JGE_K:
+               case BPF_S_JMP_JGE_X:
+               case BPF_S_JMP_JGT_K:
+               case BPF_S_JMP_JGT_X:
+               case BPF_S_JMP_JSET_X:
+               case BPF_S_JMP_JSET_K:
+                       /* a jump must set masks on targets */
+                       masks[pc + 1 + filter[pc].jt] &= memvalid;
+                       masks[pc + 1 + filter[pc].jf] &= memvalid;
+                       memvalid = ~0;
+                       break;
+               }
+       }
+error:
+       kfree(masks);
+       return ret;
+}
+
 /**
  *     sk_chk_filter - verify socket filter code
  *     @filter: filter to verify
@@ -547,30 +608,23 @@ int sk_chk_filter(struct sock_filter *filter, int flen)
        switch (filter[flen - 1].code) {
        case BPF_S_RET_K:
        case BPF_S_RET_A:
-               return 0;
+               return check_load_and_stores(filter, flen);
        }
        return -EINVAL;
 }
 EXPORT_SYMBOL(sk_chk_filter);
 
 /**
- *     sk_filter_rcu_release - Release a socket filter by rcu_head
+ *     sk_filter_release_rcu - Release a socket filter by rcu_head
  *     @rcu: rcu_head that contains the sk_filter to free
  */
-static void sk_filter_rcu_release(struct rcu_head *rcu)
+void sk_filter_release_rcu(struct rcu_head *rcu)
 {
        struct sk_filter *fp = container_of(rcu, struct sk_filter, rcu);
 
-       sk_filter_release(fp);
-}
-
-static void sk_filter_delayed_uncharge(struct sock *sk, struct sk_filter *fp)
-{
-       unsigned int size = sk_filter_len(fp);
-
-       atomic_sub(size, &sk->sk_omem_alloc);
-       call_rcu_bh(&fp->rcu, sk_filter_rcu_release);
+       kfree(fp);
 }
+EXPORT_SYMBOL(sk_filter_release_rcu);
 
 /**
  *     sk_attach_filter - attach a socket filter
@@ -614,7 +668,7 @@ int sk_attach_filter(struct sock_fprog *fprog, struct sock *sk)
        rcu_assign_pointer(sk->sk_filter, fp);
 
        if (old_fp)
-               sk_filter_delayed_uncharge(sk, old_fp);
+               sk_filter_uncharge(sk, old_fp);
        return 0;
 }
 EXPORT_SYMBOL_GPL(sk_attach_filter);
@@ -628,7 +682,7 @@ int sk_detach_filter(struct sock *sk)
                                           sock_owned_by_user(sk));
        if (filter) {
                rcu_assign_pointer(sk->sk_filter, NULL);
-               sk_filter_delayed_uncharge(sk, filter);
+               sk_filter_uncharge(sk, filter);
                ret = 0;
        }
        return ret;
index 41d99435f62d3004fd7ca14524dff45a32fcf7a3..182236b2510aeb16e6e0e2026264d683edf93e7e 100644 (file)
@@ -46,9 +46,7 @@ int reqsk_queue_alloc(struct request_sock_queue *queue,
        nr_table_entries = roundup_pow_of_two(nr_table_entries + 1);
        lopt_size += nr_table_entries * sizeof(struct request_sock *);
        if (lopt_size > PAGE_SIZE)
-               lopt = __vmalloc(lopt_size,
-                       GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO,
-                       PAGE_KERNEL);
+               lopt = vzalloc(lopt_size);
        else
                lopt = kzalloc(lopt_size, GFP_KERNEL);
        if (lopt == NULL)
index 104f8444754aa160fe7922458980ddb57485a2a5..8814a9a52f47c3c73a1a65b8b20a8c5cd4d07e46 100644 (file)
@@ -778,6 +778,28 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
 
        size = SKB_DATA_ALIGN(size);
 
+       /* Check if we can avoid taking references on fragments if we own
+        * the last reference on skb->head. (see skb_release_data())
+        */
+       if (!skb->cloned)
+               fastpath = true;
+       else {
+               int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;
+
+               fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
+       }
+
+       if (fastpath &&
+           size + sizeof(struct skb_shared_info) <= ksize(skb->head)) {
+               memmove(skb->head + size, skb_shinfo(skb),
+                       offsetof(struct skb_shared_info,
+                                frags[skb_shinfo(skb)->nr_frags]));
+               memmove(skb->head + nhead, skb->head,
+                       skb_tail_pointer(skb) - skb->head);
+               off = nhead;
+               goto adjust_others;
+       }
+
        data = kmalloc(size + sizeof(struct skb_shared_info), gfp_mask);
        if (!data)
                goto nodata;
@@ -791,17 +813,6 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
               skb_shinfo(skb),
               offsetof(struct skb_shared_info, frags[skb_shinfo(skb)->nr_frags]));
 
-       /* Check if we can avoid taking references on fragments if we own
-        * the last reference on skb->head. (see skb_release_data())
-        */
-       if (!skb->cloned)
-               fastpath = true;
-       else {
-               int delta = skb->nohdr ? (1 << SKB_DATAREF_SHIFT) + 1 : 1;
-
-               fastpath = atomic_read(&skb_shinfo(skb)->dataref) == delta;
-       }
-
        if (fastpath) {
                kfree(skb->head);
        } else {
@@ -816,6 +827,7 @@ int pskb_expand_head(struct sk_buff *skb, int nhead, int ntail,
        off = (data + nhead) - skb->head;
 
        skb->head     = data;
+adjust_others:
        skb->data    += off;
 #ifdef NET_SKBUFF_DATA_USES_OFFSET
        skb->end      = size;
index fb6080111461546953b34979db77f5e2d516e060..bcdb6ff6e6214cc0204fbc75dc8e222a87db93e0 100644 (file)
@@ -992,17 +992,18 @@ static inline void sock_lock_init(struct sock *sk)
 /*
  * Copy all fields from osk to nsk but nsk->sk_refcnt must not change yet,
  * even temporarly, because of RCU lookups. sk_node should also be left as is.
+ * We must not copy fields between sk_dontcopy_begin and sk_dontcopy_end
  */
 static void sock_copy(struct sock *nsk, const struct sock *osk)
 {
 #ifdef CONFIG_SECURITY_NETWORK
        void *sptr = nsk->sk_security;
 #endif
-       BUILD_BUG_ON(offsetof(struct sock, sk_copy_start) !=
-                    sizeof(osk->sk_node) + sizeof(osk->sk_refcnt) +
-                    sizeof(osk->sk_tx_queue_mapping));
-       memcpy(&nsk->sk_copy_start, &osk->sk_copy_start,
-              osk->sk_prot->obj_size - offsetof(struct sock, sk_copy_start));
+       memcpy(nsk, osk, offsetof(struct sock, sk_dontcopy_begin));
+
+       memcpy(&nsk->sk_dontcopy_end, &osk->sk_dontcopy_end,
+              osk->sk_prot->obj_size - offsetof(struct sock, sk_dontcopy_end));
+
 #ifdef CONFIG_SECURITY_NETWORK
        nsk->sk_security = sptr;
        security_sk_clone(osk, nsk);
index dac7ed687f609c83e7be6681d871d9444658006e..b124d28ff1c886f969789aab5330d03b16222e0f 100644 (file)
@@ -26,7 +26,7 @@ static struct sock_filter ptp_filter[] = {
        PTP_FILTER
 };
 
-static unsigned int classify(struct sk_buff *skb)
+static unsigned int classify(const struct sk_buff *skb)
 {
        if (likely(skb->dev &&
                   skb->dev->phydev &&
index 2991efcc8deab0137acd4454ea09780a52d79a1a..5c8362b037ed12accc21fd85f58396f75fb2d870 100644 (file)
@@ -1,7 +1,7 @@
 obj-$(CONFIG_IP_DCCP) += dccp.o dccp_ipv4.o
 
-dccp-y := ccid.o feat.o input.o minisocks.o options.o output.o proto.o timer.o
-
+dccp-y := ccid.o feat.o input.o minisocks.o options.o output.o proto.o timer.o \
+         qpolicy.o
 #
 # CCID algorithms to be used by dccp.ko
 #
index 19fafd597465fac2ac7e40ff77b862a91884ed6b..48ad5d9da7cbe036dfbb62e75220e3c5f19c39f9 100644 (file)
@@ -243,6 +243,19 @@ extern void dccp_reqsk_send_ack(struct sock *sk, struct sk_buff *skb,
 extern void dccp_send_sync(struct sock *sk, const u64 seq,
                           const enum dccp_pkt_type pkt_type);
 
+/*
+ * TX Packet Dequeueing Interface
+ */
+extern void            dccp_qpolicy_push(struct sock *sk, struct sk_buff *skb);
+extern bool            dccp_qpolicy_full(struct sock *sk);
+extern void            dccp_qpolicy_drop(struct sock *sk, struct sk_buff *skb);
+extern struct sk_buff  *dccp_qpolicy_top(struct sock *sk);
+extern struct sk_buff  *dccp_qpolicy_pop(struct sock *sk);
+extern bool            dccp_qpolicy_param_ok(struct sock *sk, __be32 param);
+
+/*
+ * TX Packet Output and TX Timers
+ */
 extern void   dccp_write_xmit(struct sock *sk);
 extern void   dccp_write_space(struct sock *sk);
 extern void   dccp_flush_write_queue(struct sock *sk, long *time_budget);
index 7d230d14ce22307b80cd4cf53e41e6563fab7063..15af247ea007a9e77f484a21c3cfe10d6796ff16 100644 (file)
@@ -241,7 +241,8 @@ static int dccp_check_seqno(struct sock *sk, struct sk_buff *skb)
                dccp_update_gsr(sk, seqno);
 
                if (dh->dccph_type != DCCP_PKT_SYNC &&
-                   (ackno != DCCP_PKT_WITHOUT_ACK_SEQ))
+                   ackno != DCCP_PKT_WITHOUT_ACK_SEQ &&
+                   after48(ackno, dp->dccps_gar))
                        dp->dccps_gar = ackno;
        } else {
                unsigned long now = jiffies;
index d96dd9d362ae1162e7e82e1f22fc7338904b9a1c..784d302105439434ef7182e9a4f7b7d167a44baa 100644 (file)
@@ -242,7 +242,7 @@ static void dccp_xmit_packet(struct sock *sk)
 {
        int err, len;
        struct dccp_sock *dp = dccp_sk(sk);
-       struct sk_buff *skb = skb_dequeue(&sk->sk_write_queue);
+       struct sk_buff *skb = dccp_qpolicy_pop(sk);
 
        if (unlikely(skb == NULL))
                return;
@@ -345,7 +345,7 @@ void dccp_write_xmit(struct sock *sk)
        struct dccp_sock *dp = dccp_sk(sk);
        struct sk_buff *skb;
 
-       while ((skb = skb_peek(&sk->sk_write_queue))) {
+       while ((skb = dccp_qpolicy_top(sk))) {
                int rc = ccid_hc_tx_send_packet(dp->dccps_hc_tx_ccid, sk, skb);
 
                switch (ccid_packet_dequeue_eval(rc)) {
@@ -359,8 +359,7 @@ void dccp_write_xmit(struct sock *sk)
                        dccp_xmit_packet(sk);
                        break;
                case CCID_PACKET_ERR:
-                       skb_dequeue(&sk->sk_write_queue);
-                       kfree_skb(skb);
+                       dccp_qpolicy_drop(sk, skb);
                        dccp_pr_debug("packet discarded due to err=%d\n", rc);
                }
        }
index ef343d53fcea22edf7d7bb2be677f349ec63f547..152975d942d9a59a7c26756d0f22419b9e298425 100644 (file)
@@ -185,6 +185,7 @@ int dccp_init_sock(struct sock *sk, const __u8 ctl_sock_initialized)
        dp->dccps_role          = DCCP_ROLE_UNDEFINED;
        dp->dccps_service       = DCCP_SERVICE_CODE_IS_ABSENT;
        dp->dccps_l_ack_ratio   = dp->dccps_r_ack_ratio = 1;
+       dp->dccps_tx_qlen       = sysctl_dccp_tx_qlen;
 
        dccp_init_xmit_timers(sk);
 
@@ -532,6 +533,20 @@ static int do_dccp_setsockopt(struct sock *sk, int level, int optname,
        case DCCP_SOCKOPT_RECV_CSCOV:
                err = dccp_setsockopt_cscov(sk, val, true);
                break;
+       case DCCP_SOCKOPT_QPOLICY_ID:
+               if (sk->sk_state != DCCP_CLOSED)
+                       err = -EISCONN;
+               else if (val < 0 || val >= DCCPQ_POLICY_MAX)
+                       err = -EINVAL;
+               else
+                       dp->dccps_qpolicy = val;
+               break;
+       case DCCP_SOCKOPT_QPOLICY_TXQLEN:
+               if (val < 0)
+                       err = -EINVAL;
+               else
+                       dp->dccps_tx_qlen = val;
+               break;
        default:
                err = -ENOPROTOOPT;
                break;
@@ -639,6 +654,12 @@ static int do_dccp_getsockopt(struct sock *sk, int level, int optname,
        case DCCP_SOCKOPT_RECV_CSCOV:
                val = dp->dccps_pcrlen;
                break;
+       case DCCP_SOCKOPT_QPOLICY_ID:
+               val = dp->dccps_qpolicy;
+               break;
+       case DCCP_SOCKOPT_QPOLICY_TXQLEN:
+               val = dp->dccps_tx_qlen;
+               break;
        case 128 ... 191:
                return ccid_hc_rx_getsockopt(dp->dccps_hc_rx_ccid, sk, optname,
                                             len, (u32 __user *)optval, optlen);
@@ -681,6 +702,47 @@ int compat_dccp_getsockopt(struct sock *sk, int level, int optname,
 EXPORT_SYMBOL_GPL(compat_dccp_getsockopt);
 #endif
 
+static int dccp_msghdr_parse(struct msghdr *msg, struct sk_buff *skb)
+{
+       struct cmsghdr *cmsg = CMSG_FIRSTHDR(msg);
+
+       /*
+        * Assign an (opaque) qpolicy priority value to skb->priority.
+        *
+        * We are overloading this skb field for use with the qpolicy subystem.
+        * The skb->priority is normally used for the SO_PRIORITY option, which
+        * is initialised from sk_priority. Since the assignment of sk_priority
+        * to skb->priority happens later (on layer 3), we overload this field
+        * for use with queueing priorities as long as the skb is on layer 4.
+        * The default priority value (if nothing is set) is 0.
+        */
+       skb->priority = 0;
+
+       for (; cmsg != NULL; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+
+               if (!CMSG_OK(msg, cmsg))
+                       return -EINVAL;
+
+               if (cmsg->cmsg_level != SOL_DCCP)
+                       continue;
+
+               if (cmsg->cmsg_type <= DCCP_SCM_QPOLICY_MAX &&
+                   !dccp_qpolicy_param_ok(skb->sk, cmsg->cmsg_type))
+                       return -EINVAL;
+
+               switch (cmsg->cmsg_type) {
+               case DCCP_SCM_PRIORITY:
+                       if (cmsg->cmsg_len != CMSG_LEN(sizeof(__u32)))
+                               return -EINVAL;
+                       skb->priority = *(__u32 *)CMSG_DATA(cmsg);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       }
+       return 0;
+}
+
 int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
                 size_t len)
 {
@@ -696,8 +758,7 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
 
        lock_sock(sk);
 
-       if (sysctl_dccp_tx_qlen &&
-           (sk->sk_write_queue.qlen >= sysctl_dccp_tx_qlen)) {
+       if (dccp_qpolicy_full(sk)) {
                rc = -EAGAIN;
                goto out_release;
        }
@@ -725,7 +786,11 @@ int dccp_sendmsg(struct kiocb *iocb, struct sock *sk, struct msghdr *msg,
        if (rc != 0)
                goto out_discard;
 
-       skb_queue_tail(&sk->sk_write_queue, skb);
+       rc = dccp_msghdr_parse(msg, skb);
+       if (rc != 0)
+               goto out_discard;
+
+       dccp_qpolicy_push(sk, skb);
        /*
         * The xmit_timer is set if the TX CCID is rate-based and will expire
         * when congestion control permits to release further packets into the
diff --git a/net/dccp/qpolicy.c b/net/dccp/qpolicy.c
new file mode 100644 (file)
index 0000000..63c30bf
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ *  net/dccp/qpolicy.c
+ *
+ *  Policy-based packet dequeueing interface for DCCP.
+ *
+ *  Copyright (c) 2008 Tomasz Grobelny <tomasz@grobelny.oswiecenia.net>
+ *
+ *  This program is free software; you can redistribute it and/or
+ *  modify it under the terms of the GNU General Public License v2
+ *  as published by the Free Software Foundation.
+ */
+#include "dccp.h"
+
+/*
+ *     Simple Dequeueing Policy:
+ *     If tx_qlen is different from 0, enqueue up to tx_qlen elements.
+ */
+static void qpolicy_simple_push(struct sock *sk, struct sk_buff *skb)
+{
+       skb_queue_tail(&sk->sk_write_queue, skb);
+}
+
+static bool qpolicy_simple_full(struct sock *sk)
+{
+       return dccp_sk(sk)->dccps_tx_qlen &&
+              sk->sk_write_queue.qlen >= dccp_sk(sk)->dccps_tx_qlen;
+}
+
+static struct sk_buff *qpolicy_simple_top(struct sock *sk)
+{
+       return skb_peek(&sk->sk_write_queue);
+}
+
+/*
+ *     Priority-based Dequeueing Policy:
+ *     If tx_qlen is different from 0 and the queue has reached its upper bound
+ *     of tx_qlen elements, replace older packets lowest-priority-first.
+ */
+static struct sk_buff *qpolicy_prio_best_skb(struct sock *sk)
+{
+       struct sk_buff *skb, *best = NULL;
+
+       skb_queue_walk(&sk->sk_write_queue, skb)
+               if (best == NULL || skb->priority > best->priority)
+                       best = skb;
+       return best;
+}
+
+static struct sk_buff *qpolicy_prio_worst_skb(struct sock *sk)
+{
+       struct sk_buff *skb, *worst = NULL;
+
+       skb_queue_walk(&sk->sk_write_queue, skb)
+               if (worst == NULL || skb->priority < worst->priority)
+                       worst = skb;
+       return worst;
+}
+
+static bool qpolicy_prio_full(struct sock *sk)
+{
+       if (qpolicy_simple_full(sk))
+               dccp_qpolicy_drop(sk, qpolicy_prio_worst_skb(sk));
+       return false;
+}
+
+/**
+ * struct dccp_qpolicy_operations  -  TX Packet Dequeueing Interface
+ * @push: add a new @skb to the write queue
+ * @full: indicates that no more packets will be admitted
+ * @top:  peeks at whatever the queueing policy defines as its `top'
+ */
+static struct dccp_qpolicy_operations {
+       void            (*push) (struct sock *sk, struct sk_buff *skb);
+       bool            (*full) (struct sock *sk);
+       struct sk_buff* (*top)  (struct sock *sk);
+       __be32          params;
+
+} qpol_table[DCCPQ_POLICY_MAX] = {
+       [DCCPQ_POLICY_SIMPLE] = {
+               .push   = qpolicy_simple_push,
+               .full   = qpolicy_simple_full,
+               .top    = qpolicy_simple_top,
+               .params = 0,
+       },
+       [DCCPQ_POLICY_PRIO] = {
+               .push   = qpolicy_simple_push,
+               .full   = qpolicy_prio_full,
+               .top    = qpolicy_prio_best_skb,
+               .params = DCCP_SCM_PRIORITY,
+       },
+};
+
+/*
+ *     Externally visible interface
+ */
+void dccp_qpolicy_push(struct sock *sk, struct sk_buff *skb)
+{
+       qpol_table[dccp_sk(sk)->dccps_qpolicy].push(sk, skb);
+}
+
+bool dccp_qpolicy_full(struct sock *sk)
+{
+       return qpol_table[dccp_sk(sk)->dccps_qpolicy].full(sk);
+}
+
+void dccp_qpolicy_drop(struct sock *sk, struct sk_buff *skb)
+{
+       if (skb != NULL) {
+               skb_unlink(skb, &sk->sk_write_queue);
+               kfree_skb(skb);
+       }
+}
+
+struct sk_buff *dccp_qpolicy_top(struct sock *sk)
+{
+       return qpol_table[dccp_sk(sk)->dccps_qpolicy].top(sk);
+}
+
+struct sk_buff *dccp_qpolicy_pop(struct sock *sk)
+{
+       struct sk_buff *skb = dccp_qpolicy_top(sk);
+
+       if (skb != NULL) {
+               /* Clear any skb fields that we used internally */
+               skb->priority = 0;
+               skb_unlink(skb, &sk->sk_write_queue);
+       }
+       return skb;
+}
+
+bool dccp_qpolicy_param_ok(struct sock *sk, __be32 param)
+{
+       /* check if exactly one bit is set */
+       if (!param || (param & (param - 1)))
+               return false;
+       return (qpol_table[dccp_sk(sk)->dccps_qpolicy].params & param) == param;
+}
index 9ecef9968c3940026deefba772fa568af7237bcc..0065e7e14af4eafa8e613a2712c98ca16e7c1d6e 100644 (file)
@@ -1556,6 +1556,8 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
                        if (r_len > sizeof(struct linkinfo_dn))
                                r_len = sizeof(struct linkinfo_dn);
 
+                       memset(&link, 0, sizeof(link));
+
                        switch(sock->state) {
                                case SS_CONNECTING:
                                        link.idn_linkstate = LL_CONNECTING;
index 8280e43c88610460664199061488f5186de692cd..e2e926841fe6255e75f128f45919ba78fad2aa8f 100644 (file)
@@ -240,13 +240,13 @@ static void dn_dst_update_pmtu(struct dst_entry *dst, u32 mtu)
 
        if (dst_metric(dst, RTAX_MTU) > mtu && mtu >= min_mtu) {
                if (!(dst_metric_locked(dst, RTAX_MTU))) {
-                       dst->metrics[RTAX_MTU-1] = mtu;
+                       dst_metric_set(dst, RTAX_MTU, mtu);
                        dst_set_expires(dst, dn_rt_mtu_expires);
                }
                if (!(dst_metric_locked(dst, RTAX_ADVMSS))) {
                        u32 mss = mtu - DN_MAX_NSP_DATA_HEADER;
                        if (dst_metric(dst, RTAX_ADVMSS) > mss)
-                               dst->metrics[RTAX_ADVMSS-1] = mss;
+                               dst_metric_set(dst, RTAX_ADVMSS, mss);
                }
        }
 }
@@ -806,8 +806,7 @@ static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res)
                if (DN_FIB_RES_GW(*res) &&
                    DN_FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
                        rt->rt_gateway = DN_FIB_RES_GW(*res);
-               memcpy(rt->dst.metrics, fi->fib_metrics,
-                      sizeof(rt->dst.metrics));
+               dst_import_metrics(&rt->dst, fi->fib_metrics);
        }
        rt->rt_type = res->type;
 
@@ -820,11 +819,11 @@ static int dn_rt_set_next_hop(struct dn_route *rt, struct dn_fib_res *res)
 
        if (dst_metric(&rt->dst, RTAX_MTU) == 0 ||
            dst_metric(&rt->dst, RTAX_MTU) > rt->dst.dev->mtu)
-               rt->dst.metrics[RTAX_MTU-1] = rt->dst.dev->mtu;
+               dst_metric_set(&rt->dst, RTAX_MTU, rt->dst.dev->mtu);
        mss = dn_mss_from_pmtu(dev, dst_mtu(&rt->dst));
        if (dst_metric(&rt->dst, RTAX_ADVMSS) == 0 ||
            dst_metric(&rt->dst, RTAX_ADVMSS) > mss)
-               rt->dst.metrics[RTAX_ADVMSS-1] = mss;
+               dst_metric_set(&rt->dst, RTAX_ADVMSS, mss);
        return 0;
 }
 
@@ -1502,7 +1501,7 @@ static int dn_rt_fill_info(struct sk_buff *skb, u32 pid, u32 seq,
        RTA_PUT(skb, RTA_PREFSRC, 2, &rt->rt_local_src);
        if (rt->rt_daddr != rt->rt_gateway)
                RTA_PUT(skb, RTA_GATEWAY, 2, &rt->rt_gateway);
-       if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0)
+       if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
                goto rtattr_failure;
        expires = rt->dst.expires ? rt->dst.expires - jiffies : 0;
        if (rtnl_put_cacheinfo(skb, &rt->dst, 0, 0, 0, expires,
index f8c1ae4b41f03641f7bb7db11feb88893df65519..f180371fa415de9f17a7911e391a272eb09b55ac 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/skbuff.h>
 #include <linux/udp.h>
 #include <linux/slab.h>
+#include <linux/vmalloc.h>
 #include <net/sock.h>
 #include <net/inet_common.h>
 #include <linux/stat.h>
@@ -276,12 +277,12 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
 #endif
 #ifdef CONFIG_ECONET_AUNUDP
        struct msghdr udpmsg;
-       struct iovec iov[msg->msg_iovlen+1];
+       struct iovec iov[2];
        struct aunhdr ah;
        struct sockaddr_in udpdest;
        __kernel_size_t size;
-       int i;
        mm_segment_t oldfs;
+       char *userbuf;
 #endif
 
        /*
@@ -297,23 +298,14 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
 
        mutex_lock(&econet_mutex);
 
-       if (saddr == NULL) {
-               struct econet_sock *eo = ec_sk(sk);
-
-               addr.station = eo->station;
-               addr.net     = eo->net;
-               port         = eo->port;
-               cb           = eo->cb;
-       } else {
-               if (msg->msg_namelen < sizeof(struct sockaddr_ec)) {
-                       mutex_unlock(&econet_mutex);
-                       return -EINVAL;
-               }
-               addr.station = saddr->addr.station;
-               addr.net = saddr->addr.net;
-               port = saddr->port;
-               cb = saddr->cb;
-       }
+        if (saddr == NULL || msg->msg_namelen < sizeof(struct sockaddr_ec)) {
+                mutex_unlock(&econet_mutex);
+                return -EINVAL;
+        }
+        addr.station = saddr->addr.station;
+        addr.net = saddr->addr.net;
+        port = saddr->port;
+        cb = saddr->cb;
 
        /* Look for a device with the right network number. */
        dev = net2dev_map[addr.net];
@@ -328,17 +320,17 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
                }
        }
 
-       if (len + 15 > dev->mtu) {
-               mutex_unlock(&econet_mutex);
-               return -EMSGSIZE;
-       }
-
        if (dev->type == ARPHRD_ECONET) {
                /* Real hardware Econet.  We're not worthy etc. */
 #ifdef CONFIG_ECONET_NATIVE
                unsigned short proto = 0;
                int res;
 
+               if (len + 15 > dev->mtu) {
+                       mutex_unlock(&econet_mutex);
+                       return -EMSGSIZE;
+               }
+
                dev_hold(dev);
 
                skb = sock_alloc_send_skb(sk, len+LL_ALLOCATED_SPACE(dev),
@@ -351,7 +343,6 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
 
                eb = (struct ec_cb *)&skb->cb;
 
-               /* BUG: saddr may be NULL */
                eb->cookie = saddr->cookie;
                eb->sec = *saddr;
                eb->sent = ec_tx_done;
@@ -415,6 +406,11 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
                return -ENETDOWN;               /* No socket - can't send */
        }
 
+       if (len > 32768) {
+               err = -E2BIG;
+               goto error;
+       }
+
        /* Make up a UDP datagram and hand it off to some higher intellect. */
 
        memset(&udpdest, 0, sizeof(udpdest));
@@ -446,36 +442,26 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
 
        /* tack our header on the front of the iovec */
        size = sizeof(struct aunhdr);
-       /*
-        * XXX: that is b0rken.  We can't mix userland and kernel pointers
-        * in iovec, since on a lot of platforms copy_from_user() will
-        * *not* work with the kernel and userland ones at the same time,
-        * regardless of what we do with set_fs().  And we are talking about
-        * econet-over-ethernet here, so "it's only ARM anyway" doesn't
-        * apply.  Any suggestions on fixing that code?         -- AV
-        */
        iov[0].iov_base = (void *)&ah;
        iov[0].iov_len = size;
-       for (i = 0; i < msg->msg_iovlen; i++) {
-               void __user *base = msg->msg_iov[i].iov_base;
-               size_t iov_len = msg->msg_iov[i].iov_len;
-               /* Check it now since we switch to KERNEL_DS later. */
-               if (!access_ok(VERIFY_READ, base, iov_len)) {
-                       mutex_unlock(&econet_mutex);
-                       return -EFAULT;
-               }
-               iov[i+1].iov_base = base;
-               iov[i+1].iov_len = iov_len;
-               size += iov_len;
+
+       userbuf = vmalloc(len);
+       if (userbuf == NULL) {
+               err = -ENOMEM;
+               goto error;
        }
 
+       iov[1].iov_base = userbuf;
+       iov[1].iov_len = len;
+       err = memcpy_fromiovec(userbuf, msg->msg_iov, len);
+       if (err)
+               goto error_free_buf;
+
        /* Get a skbuff (no data, just holds our cb information) */
        if ((skb = sock_alloc_send_skb(sk, 0,
                                       msg->msg_flags & MSG_DONTWAIT,
-                                      &err)) == NULL) {
-               mutex_unlock(&econet_mutex);
-               return err;
-       }
+                                      &err)) == NULL)
+               goto error_free_buf;
 
        eb = (struct ec_cb *)&skb->cb;
 
@@ -491,7 +477,7 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
        udpmsg.msg_name = (void *)&udpdest;
        udpmsg.msg_namelen = sizeof(udpdest);
        udpmsg.msg_iov = &iov[0];
-       udpmsg.msg_iovlen = msg->msg_iovlen + 1;
+       udpmsg.msg_iovlen = 2;
        udpmsg.msg_control = NULL;
        udpmsg.msg_controllen = 0;
        udpmsg.msg_flags=0;
@@ -499,9 +485,13 @@ static int econet_sendmsg(struct kiocb *iocb, struct socket *sock,
        oldfs = get_fs(); set_fs(KERNEL_DS);    /* More privs :-) */
        err = sock_sendmsg(udpsock, &udpmsg, size);
        set_fs(oldfs);
+
+error_free_buf:
+       vfree(userbuf);
 #else
        err = -EPROTOTYPE;
 #endif
+       error:
        mutex_unlock(&econet_mutex);
 
        return err;
@@ -671,6 +661,11 @@ static int ec_dev_ioctl(struct socket *sock, unsigned int cmd, void __user *arg)
        err = 0;
        switch (cmd) {
        case SIOCSIFADDR:
+               if (!capable(CAP_NET_ADMIN)) {
+                       err = -EPERM;
+                       break;
+               }
+
                edev = dev->ec_ptr;
                if (edev == NULL) {
                        /* Magic up a new one. */
index 93c91b633a566729bc48acedc766ae3db20f3bc2..6df6ecf4970876b54ef16acac3a971fdaf1d333c 100644 (file)
@@ -52,11 +52,11 @@ struct net_device *ieee802154_get_dev(struct net *net,
 
        switch (addr->addr_type) {
        case IEEE802154_ADDR_LONG:
-               rtnl_lock();
-               dev = dev_getbyhwaddr(net, ARPHRD_IEEE802154, addr->hwaddr);
+               rcu_read_lock();
+               dev = dev_getbyhwaddr_rcu(net, ARPHRD_IEEE802154, addr->hwaddr);
                if (dev)
                        dev_hold(dev);
-               rtnl_unlock();
+               rcu_read_unlock();
                break;
        case IEEE802154_ADDR_SHORT:
                if (addr->pan_id == 0xffff ||
index 7833f17b648a149b8d21e134b2eee0c6d619a97c..a2fc7b961dbcd9e467b024aff1b2ec02a20e7861 100644 (file)
@@ -883,7 +883,7 @@ static int arp_process(struct sk_buff *skb)
 
                        dont_send = arp_ignore(in_dev, sip, tip);
                        if (!dont_send && IN_DEV_ARPFILTER(in_dev))
-                               dont_send |= arp_filter(sip, tip, dev);
+                               dont_send = arp_filter(sip, tip, dev);
                        if (!dont_send) {
                                n = neigh_event_ns(&arp_tbl, sha, &sip, dev);
                                if (n) {
@@ -1017,13 +1017,14 @@ static int arp_req_set_proxy(struct net *net, struct net_device *dev, int on)
                IPV4_DEVCONF_ALL(net, PROXY_ARP) = on;
                return 0;
        }
-       if (__in_dev_get_rtnl(dev)) {
-               IN_DEV_CONF_SET(__in_dev_get_rtnl(dev), PROXY_ARP, on);
+       if (__in_dev_get_rcu(dev)) {
+               IN_DEV_CONF_SET(__in_dev_get_rcu(dev), PROXY_ARP, on);
                return 0;
        }
        return -ENXIO;
 }
 
+/* must be called with rcu_read_lock() */
 static int arp_req_set_public(struct net *net, struct arpreq *r,
                struct net_device *dev)
 {
@@ -1033,7 +1034,7 @@ static int arp_req_set_public(struct net *net, struct arpreq *r,
        if (mask && mask != htonl(0xFFFFFFFF))
                return -EINVAL;
        if (!dev && (r->arp_flags & ATF_COM)) {
-               dev = dev_getbyhwaddr(net, r->arp_ha.sa_family,
+               dev = dev_getbyhwaddr_rcu(net, r->arp_ha.sa_family,
                                      r->arp_ha.sa_data);
                if (!dev)
                        return -ENODEV;
@@ -1225,10 +1226,10 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
        if (!(r.arp_flags & ATF_NETMASK))
                ((struct sockaddr_in *)&r.arp_netmask)->sin_addr.s_addr =
                                                           htonl(0xFFFFFFFFUL);
-       rtnl_lock();
+       rcu_read_lock();
        if (r.arp_dev[0]) {
                err = -ENODEV;
-               dev = __dev_get_by_name(net, r.arp_dev);
+               dev = dev_get_by_name_rcu(net, r.arp_dev);
                if (dev == NULL)
                        goto out;
 
@@ -1252,12 +1253,12 @@ int arp_ioctl(struct net *net, unsigned int cmd, void __user *arg)
                break;
        case SIOCGARP:
                err = arp_req_get(&r, dev);
-               if (!err && copy_to_user(arg, &r, sizeof(r)))
-                       err = -EFAULT;
                break;
        }
 out:
-       rtnl_unlock();
+       rcu_read_unlock();
+       if (cmd == SIOCGARP && !err && copy_to_user(arg, &r, sizeof(r)))
+               err = -EFAULT;
        return err;
 }
 
index d9f71bae45c40ddf0231c12164dea85d32c2b883..3b067704ab3852e5e51363ead5cbe9013fb5741e 100644 (file)
@@ -1258,7 +1258,7 @@ errout:
 
 static size_t inet_get_link_af_size(const struct net_device *dev)
 {
-       struct in_device *in_dev = __in_dev_get_rcu(dev);
+       struct in_device *in_dev = __in_dev_get_rtnl(dev);
 
        if (!in_dev)
                return 0;
@@ -1268,7 +1268,7 @@ static size_t inet_get_link_af_size(const struct net_device *dev)
 
 static int inet_fill_link_af(struct sk_buff *skb, const struct net_device *dev)
 {
-       struct in_device *in_dev = __in_dev_get_rcu(dev);
+       struct in_device *in_dev = __in_dev_get_rtnl(dev);
        struct nlattr *nla;
        int i;
 
@@ -1295,7 +1295,7 @@ static int inet_validate_link_af(const struct net_device *dev,
        struct nlattr *a, *tb[IFLA_INET_MAX+1];
        int err, rem;
 
-       if (dev && !__in_dev_get_rcu(dev))
+       if (dev && !__in_dev_get_rtnl(dev))
                return -EAFNOSUPPORT;
 
        err = nla_parse_nested(tb, IFLA_INET_MAX, nla, inet_af_policy);
@@ -1319,7 +1319,7 @@ static int inet_validate_link_af(const struct net_device *dev,
 
 static int inet_set_link_af(struct net_device *dev, const struct nlattr *nla)
 {
-       struct in_device *in_dev = __in_dev_get_rcu(dev);
+       struct in_device *in_dev = __in_dev_get_rtnl(dev);
        struct nlattr *a, *tb[IFLA_INET_MAX+1];
        int rem;
 
index 200eb538fbb3f77101fe9646893dddbd9e83117b..0f280348e0fdad70adb37f3b33bdbe6fedd99025 100644 (file)
@@ -365,7 +365,7 @@ static struct tnode *tnode_alloc(size_t size)
        if (size <= PAGE_SIZE)
                return kzalloc(size, GFP_KERNEL);
        else
-               return __vmalloc(size, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+               return vzalloc(size);
 }
 
 static void __tnode_vfree(struct work_struct *arg)
index 06f5f8f482f0e092d86571b75846a60ea865d612..25e318153f143366894ec111dc5e6cb89d980c9b 100644 (file)
@@ -55,7 +55,6 @@ EXPORT_SYMBOL(inet_get_local_port_range);
 int inet_csk_bind_conflict(const struct sock *sk,
                           const struct inet_bind_bucket *tb)
 {
-       const __be32 sk_rcv_saddr = inet_rcv_saddr(sk);
        struct sock *sk2;
        struct hlist_node *node;
        int reuse = sk->sk_reuse;
@@ -75,9 +74,9 @@ int inet_csk_bind_conflict(const struct sock *sk,
                     sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) {
                        if (!reuse || !sk2->sk_reuse ||
                            sk2->sk_state == TCP_LISTEN) {
-                               const __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
-                               if (!sk2_rcv_saddr || !sk_rcv_saddr ||
-                                   sk2_rcv_saddr == sk_rcv_saddr)
+                               const __be32 sk2_rcv_saddr = sk_rcv_saddr(sk2);
+                               if (!sk2_rcv_saddr || !sk_rcv_saddr(sk) ||
+                                   sk2_rcv_saddr == sk_rcv_saddr(sk))
                                        break;
                        }
                }
index 1b344f30b463fab9ed70a8f19a19d348d7c626f7..3c0369a3a663693ac24e6acdd2730909ae5ddf4a 100644 (file)
@@ -133,8 +133,7 @@ int __inet_inherit_port(struct sock *sk, struct sock *child)
                        }
                }
        }
-       sk_add_bind_node(child, &tb->owners);
-       inet_csk(child)->icsk_bind_hash = tb;
+       inet_bind_hash(child, tb, port);
        spin_unlock(&head->lock);
 
        return 0;
index 258c98d5fa79fb861fce41e45da19c6201e3a18a..ff4e7a4e33ed21896c872a45a210b440e7f3c9bf 100644 (file)
@@ -818,7 +818,7 @@ static netdev_tx_t ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev
                             !ipv4_is_multicast(tunnel->parms.iph.daddr)) ||
                            rt6->rt6i_dst.plen == 128) {
                                rt6->rt6i_flags |= RTF_MODIFIED;
-                               skb_dst(skb)->metrics[RTAX_MTU-1] = mtu;
+                               dst_metric_set(skb_dst(skb), RTAX_MTU, mtu);
                        }
                }
 
index 1b48eb1ed4531d3fd037e7ee9aa6367b6cb575f3..b14ec7d03b6e70b9a5a1823261ac18cb40462035 100644 (file)
@@ -253,6 +253,7 @@ static const struct snmp_mib snmp4_net_list[] = {
        SNMP_MIB_ITEM("TCPMinTTLDrop", LINUX_MIB_TCPMINTTLDROP),
        SNMP_MIB_ITEM("TCPDeferAcceptDrop", LINUX_MIB_TCPDEFERACCEPTDROP),
        SNMP_MIB_ITEM("IPReversePathFilter", LINUX_MIB_IPRPFILTER),
+       SNMP_MIB_ITEM("TCPTimeWaitOverflow", LINUX_MIB_TCPTIMEWAITOVERFLOW),
        SNMP_MIB_SENTINEL
 };
 
index 3843c2dfde82cfaf90be1784d3fded834b027baf..26ac396eaa5ef0bdd20fadc9997b3391fdb81849 100644 (file)
@@ -1686,11 +1686,14 @@ unsigned short ip_rt_frag_needed(struct net *net, struct iphdr *iph,
                                        if (mtu < dst_mtu(&rth->dst)) {
                                                dst_confirm(&rth->dst);
                                                if (mtu < ip_rt_min_pmtu) {
+                                                       u32 lock = dst_metric(&rth->dst,
+                                                                             RTAX_LOCK);
                                                        mtu = ip_rt_min_pmtu;
-                                                       rth->dst.metrics[RTAX_LOCK-1] |=
-                                                               (1 << RTAX_MTU);
+                                                       lock |= (1 << RTAX_MTU);
+                                                       dst_metric_set(&rth->dst, RTAX_LOCK,
+                                                                      lock);
                                                }
-                                               rth->dst.metrics[RTAX_MTU-1] = mtu;
+                                               dst_metric_set(&rth->dst, RTAX_MTU, mtu);
                                                dst_set_expires(&rth->dst,
                                                        ip_rt_mtu_expires);
                                        }
@@ -1708,10 +1711,11 @@ static void ip_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
        if (dst_mtu(dst) > mtu && mtu >= 68 &&
            !(dst_metric_locked(dst, RTAX_MTU))) {
                if (mtu < ip_rt_min_pmtu) {
+                       u32 lock = dst_metric(dst, RTAX_LOCK);
                        mtu = ip_rt_min_pmtu;
-                       dst->metrics[RTAX_LOCK-1] |= (1 << RTAX_MTU);
+                       dst_metric_set(dst, RTAX_LOCK, lock | (1 << RTAX_MTU));
                }
-               dst->metrics[RTAX_MTU-1] = mtu;
+               dst_metric_set(dst, RTAX_MTU, mtu);
                dst_set_expires(dst, ip_rt_mtu_expires);
                call_netevent_notifiers(NETEVENT_PMTU_UPDATE, dst);
        }
@@ -1796,36 +1800,37 @@ static void set_class_tag(struct rtable *rt, u32 tag)
 
 static void rt_set_nexthop(struct rtable *rt, struct fib_result *res, u32 itag)
 {
+       struct dst_entry *dst = &rt->dst;
        struct fib_info *fi = res->fi;
 
        if (fi) {
                if (FIB_RES_GW(*res) &&
                    FIB_RES_NH(*res).nh_scope == RT_SCOPE_LINK)
                        rt->rt_gateway = FIB_RES_GW(*res);
-               memcpy(rt->dst.metrics, fi->fib_metrics,
-                      sizeof(rt->dst.metrics));
+               dst_import_metrics(dst, fi->fib_metrics);
                if (fi->fib_mtu == 0) {
-                       rt->dst.metrics[RTAX_MTU-1] = rt->dst.dev->mtu;
-                       if (dst_metric_locked(&rt->dst, RTAX_MTU) &&
+                       dst_metric_set(dst, RTAX_MTU, dst->dev->mtu);
+                       if (dst_metric_locked(dst, RTAX_MTU) &&
                            rt->rt_gateway != rt->rt_dst &&
-                           rt->dst.dev->mtu > 576)
-                               rt->dst.metrics[RTAX_MTU-1] = 576;
+                           dst->dev->mtu > 576)
+                               dst_metric_set(dst, RTAX_MTU, 576);
                }
 #ifdef CONFIG_NET_CLS_ROUTE
-               rt->dst.tclassid = FIB_RES_NH(*res).nh_tclassid;
+               dst->tclassid = FIB_RES_NH(*res).nh_tclassid;
 #endif
        } else
-               rt->dst.metrics[RTAX_MTU-1]= rt->dst.dev->mtu;
-
-       if (dst_metric(&rt->dst, RTAX_HOPLIMIT) == 0)
-               rt->dst.metrics[RTAX_HOPLIMIT-1] = sysctl_ip_default_ttl;
-       if (dst_mtu(&rt->dst) > IP_MAX_MTU)
-               rt->dst.metrics[RTAX_MTU-1] = IP_MAX_MTU;
-       if (dst_metric(&rt->dst, RTAX_ADVMSS) == 0)
-               rt->dst.metrics[RTAX_ADVMSS-1] = max_t(unsigned int, rt->dst.dev->mtu - 40,
-                                      ip_rt_min_advmss);
-       if (dst_metric(&rt->dst, RTAX_ADVMSS) > 65535 - 40)
-               rt->dst.metrics[RTAX_ADVMSS-1] = 65535 - 40;
+               dst_metric_set(dst, RTAX_MTU, dst->dev->mtu);
+
+       if (dst_metric(dst, RTAX_HOPLIMIT) == 0)
+               dst_metric_set(dst, RTAX_HOPLIMIT, sysctl_ip_default_ttl);
+       if (dst_mtu(dst) > IP_MAX_MTU)
+               dst_metric_set(dst, RTAX_MTU, IP_MAX_MTU);
+       if (dst_metric(dst, RTAX_ADVMSS) == 0)
+               dst_metric_set(dst, RTAX_ADVMSS,
+                              max_t(unsigned int, dst->dev->mtu - 40,
+                                    ip_rt_min_advmss));
+       if (dst_metric(dst, RTAX_ADVMSS) > 65535 - 40)
+               dst_metric_set(dst, RTAX_ADVMSS, 65535 - 40);
 
 #ifdef CONFIG_NET_CLS_ROUTE
 #ifdef CONFIG_IP_MULTIPLE_TABLES
@@ -2720,7 +2725,7 @@ static int ipv4_dst_blackhole(struct net *net, struct rtable **rp, struct flowi
                new->__use = 1;
                new->input = dst_discard;
                new->output = dst_discard;
-               memcpy(new->metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32));
+               dst_copy_metrics(new, &ort->dst);
 
                new->dev = ort->dst.dev;
                if (new->dev)
@@ -2827,7 +2832,7 @@ static int rt_fill_info(struct net *net,
        if (rt->rt_dst != rt->rt_gateway)
                NLA_PUT_BE32(skb, RTA_GATEWAY, rt->rt_gateway);
 
-       if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0)
+       if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
                goto nla_put_failure;
 
        if (rt->fl.mark)
index e91911d7aae26656f940a747a6d0ccb91739f39a..1b4ec21497a49756025965e4e17e4bc9466f4f5c 100644 (file)
@@ -26,6 +26,8 @@ static int zero;
 static int tcp_retr1_max = 255;
 static int ip_local_port_range_min[] = { 1, 1 };
 static int ip_local_port_range_max[] = { 65535, 65535 };
+static int tcp_adv_win_scale_min = -31;
+static int tcp_adv_win_scale_max = 31;
 
 /* Update system visible IP port range */
 static void set_local_port_range(int range[2])
@@ -426,7 +428,9 @@ 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_minmax,
+               .extra1         = &tcp_adv_win_scale_min,
+               .extra2         = &tcp_adv_win_scale_max,
        },
        {
                .procname       = "tcp_tw_reuse",
index 2bb46d55f40cf0e680b420f6d80d7d745b6e1634..6c11eece262cf77a377a9fa901f4031c46745205 100644 (file)
@@ -2244,7 +2244,7 @@ static int do_tcp_setsockopt(struct sock *sk, int level,
                /* Values greater than interface MTU won't take effect. However
                 * at the point when this call is done we typically don't yet
                 * know which interface is going to be used */
-               if (val < 64 || val > MAX_TCP_WINDOW) {
+               if (val < TCP_MIN_MSS || val > MAX_TCP_WINDOW) {
                        err = -EINVAL;
                        break;
                }
index 6d8ab1c4efc3ea59c4848c74ae367f872cd6505e..824e8c8a17adc8bfc8faf6c6839074d54f027fe4 100644 (file)
@@ -734,7 +734,7 @@ void tcp_update_metrics(struct sock *sk)
                         * Reset our results.
                         */
                        if (!(dst_metric_locked(dst, RTAX_RTT)))
-                               dst->metrics[RTAX_RTT - 1] = 0;
+                               dst_metric_set(dst, RTAX_RTT, 0);
                        return;
                }
 
@@ -776,34 +776,38 @@ void tcp_update_metrics(struct sock *sk)
                        if (dst_metric(dst, RTAX_SSTHRESH) &&
                            !dst_metric_locked(dst, RTAX_SSTHRESH) &&
                            (tp->snd_cwnd >> 1) > dst_metric(dst, RTAX_SSTHRESH))
-                               dst->metrics[RTAX_SSTHRESH-1] = tp->snd_cwnd >> 1;
+                               dst_metric_set(dst, RTAX_SSTHRESH, tp->snd_cwnd >> 1);
                        if (!dst_metric_locked(dst, RTAX_CWND) &&
                            tp->snd_cwnd > dst_metric(dst, RTAX_CWND))
-                               dst->metrics[RTAX_CWND - 1] = tp->snd_cwnd;
+                               dst_metric_set(dst, RTAX_CWND, tp->snd_cwnd);
                } else if (tp->snd_cwnd > tp->snd_ssthresh &&
                           icsk->icsk_ca_state == TCP_CA_Open) {
                        /* Cong. avoidance phase, cwnd is reliable. */
                        if (!dst_metric_locked(dst, RTAX_SSTHRESH))
-                               dst->metrics[RTAX_SSTHRESH-1] =
-                                       max(tp->snd_cwnd >> 1, tp->snd_ssthresh);
+                               dst_metric_set(dst, RTAX_SSTHRESH,
+                                              max(tp->snd_cwnd >> 1, tp->snd_ssthresh));
                        if (!dst_metric_locked(dst, RTAX_CWND))
-                               dst->metrics[RTAX_CWND-1] = (dst_metric(dst, RTAX_CWND) + tp->snd_cwnd) >> 1;
+                               dst_metric_set(dst, RTAX_CWND,
+                                              (dst_metric(dst, RTAX_CWND) +
+                                               tp->snd_cwnd) >> 1);
                } else {
                        /* Else slow start did not finish, cwnd is non-sense,
                           ssthresh may be also invalid.
                         */
                        if (!dst_metric_locked(dst, RTAX_CWND))
-                               dst->metrics[RTAX_CWND-1] = (dst_metric(dst, RTAX_CWND) + tp->snd_ssthresh) >> 1;
+                               dst_metric_set(dst, RTAX_CWND,
+                                              (dst_metric(dst, RTAX_CWND) +
+                                               tp->snd_ssthresh) >> 1);
                        if (dst_metric(dst, RTAX_SSTHRESH) &&
                            !dst_metric_locked(dst, RTAX_SSTHRESH) &&
                            tp->snd_ssthresh > dst_metric(dst, RTAX_SSTHRESH))
-                               dst->metrics[RTAX_SSTHRESH-1] = tp->snd_ssthresh;
+                               dst_metric_set(dst, RTAX_SSTHRESH, tp->snd_ssthresh);
                }
 
                if (!dst_metric_locked(dst, RTAX_REORDERING)) {
                        if (dst_metric(dst, RTAX_REORDERING) < tp->reordering &&
                            tp->reordering != sysctl_tcp_reordering)
-                               dst->metrics[RTAX_REORDERING-1] = tp->reordering;
+                               dst_metric_set(dst, RTAX_REORDERING, tp->reordering);
                }
        }
 }
index dd555051ec8be951a3da76cf5645343bf810584b..4fc3387aa9942a0b69b5a25c91745caaa4d46389 100644 (file)
@@ -2013,7 +2013,9 @@ get_req:
        }
 get_sk:
        sk_nulls_for_each_from(sk, node) {
-               if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) {
+               if (!net_eq(sock_net(sk), net))
+                       continue;
+               if (sk->sk_family == st->family) {
                        cur = sk;
                        goto out;
                }
index 3527b51d615956b87eb8b1f0ee2de5982da1f588..80b1f80759abff53b0bf7e3438c72bbc2aa85162 100644 (file)
@@ -392,7 +392,7 @@ void tcp_time_wait(struct sock *sk, int state, int timeo)
                 * socket up.  We've got bigger problems than
                 * non-graceful socket closings.
                 */
-               LIMIT_NETDEBUG(KERN_INFO "TCP: time wait bucket table overflow\n");
+               NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPTIMEWAITOVERFLOW);
        }
 
        tcp_update_metrics(sk);
index 749b6498588e8389c96c555730a34d4f7d424321..97041f24cd2764741648c16e206d170c422a67d8 100644 (file)
@@ -231,11 +231,10 @@ void tcp_select_initial_window(int __space, __u32 mss,
                /* when initializing use the value from init_rcv_wnd
                 * rather than the default from above
                 */
-               if (init_rcv_wnd &&
-                   (*rcv_wnd > init_rcv_wnd * mss))
-                       *rcv_wnd = init_rcv_wnd * mss;
-               else if (*rcv_wnd > init_cwnd * mss)
-                       *rcv_wnd = init_cwnd * mss;
+               if (init_rcv_wnd)
+                       *rcv_wnd = min(*rcv_wnd, init_rcv_wnd * mss);
+               else
+                       *rcv_wnd = min(*rcv_wnd, init_cwnd * mss);
        }
 
        /* Set the clamp no higher than max representable value */
@@ -386,27 +385,30 @@ struct tcp_out_options {
  */
 static u8 tcp_cookie_size_check(u8 desired)
 {
-       if (desired > 0) {
+       int cookie_size;
+
+       if (desired > 0)
                /* previously specified */
                return desired;
-       }
-       if (sysctl_tcp_cookie_size <= 0) {
+
+       cookie_size = ACCESS_ONCE(sysctl_tcp_cookie_size);
+       if (cookie_size <= 0)
                /* no default specified */
                return 0;
-       }
-       if (sysctl_tcp_cookie_size <= TCP_COOKIE_MIN) {
+
+       if (cookie_size <= TCP_COOKIE_MIN)
                /* value too small, specify minimum */
                return TCP_COOKIE_MIN;
-       }
-       if (sysctl_tcp_cookie_size >= TCP_COOKIE_MAX) {
+
+       if (cookie_size >= TCP_COOKIE_MAX)
                /* value too large, specify maximum */
                return TCP_COOKIE_MAX;
-       }
-       if (0x1 & sysctl_tcp_cookie_size) {
+
+       if (cookie_size & 1)
                /* 8-bit multiple, illegal, fix it */
-               return (u8)(sysctl_tcp_cookie_size + 0x1);
-       }
-       return (u8)sysctl_tcp_cookie_size;
+               cookie_size++;
+
+       return (u8)cookie_size;
 }
 
 /* Write previously computed TCP options to the packet.
@@ -1516,6 +1518,7 @@ static int tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb)
        struct tcp_sock *tp = tcp_sk(sk);
        const struct inet_connection_sock *icsk = inet_csk(sk);
        u32 send_win, cong_win, limit, in_flight;
+       int win_divisor;
 
        if (TCP_SKB_CB(skb)->flags & TCPHDR_FIN)
                goto send_now;
@@ -1547,13 +1550,14 @@ static int tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb)
        if ((skb != tcp_write_queue_tail(sk)) && (limit >= skb->len))
                goto send_now;
 
-       if (sysctl_tcp_tso_win_divisor) {
+       win_divisor = ACCESS_ONCE(sysctl_tcp_tso_win_divisor);
+       if (win_divisor) {
                u32 chunk = min(tp->snd_wnd, tp->snd_cwnd * tp->mss_cache);
 
                /* If at least some fraction of a window is available,
                 * just use it.
                 */
-               chunk /= sysctl_tcp_tso_win_divisor;
+               chunk /= win_divisor;
                if (limit >= chunk)
                        goto send_now;
        } else {
index b1155554bb183fff1acc381ea3c17b3cdcd67034..4f4483e697bd09e541624dca9c58a3afa5cdbbe3 100644 (file)
@@ -1173,6 +1173,8 @@ static void ip6_tnl_link_config(struct ip6_tnl *t)
                                sizeof (struct ipv6hdr);
 
                        dev->mtu = rt->rt6i_dev->mtu - sizeof (struct ipv6hdr);
+                       if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
+                               dev->mtu-=8;
 
                        if (dev->mtu < IPV6_MIN_MTU)
                                dev->mtu = IPV6_MIN_MTU;
@@ -1361,12 +1363,17 @@ static const struct net_device_ops ip6_tnl_netdev_ops = {
 
 static void ip6_tnl_dev_setup(struct net_device *dev)
 {
+       struct ip6_tnl *t;
+
        dev->netdev_ops = &ip6_tnl_netdev_ops;
        dev->destructor = ip6_dev_free;
 
        dev->type = ARPHRD_TUNNEL6;
        dev->hard_header_len = LL_MAX_HEADER + sizeof (struct ipv6hdr);
        dev->mtu = ETH_DATA_LEN - sizeof (struct ipv6hdr);
+       t = netdev_priv(dev);
+       if (!(t->parms.flags & IP6_TNL_F_IGN_ENCAP_LIMIT))
+               dev->mtu-=8;
        dev->flags |= IFF_NOARP;
        dev->addr_len = sizeof(struct in6_addr);
        dev->features |= NETIF_F_NETNS_LOCAL;
index e18f8413020311019d187652021ca11a604361b0..2342545a5ee9bfe125ff3030bac07cafcb24a00b 100644 (file)
@@ -1259,7 +1259,8 @@ static void ndisc_router_discovery(struct sk_buff *skb)
        if (ra_msg->icmph.icmp6_hop_limit) {
                in6_dev->cnf.hop_limit = ra_msg->icmph.icmp6_hop_limit;
                if (rt)
-                       rt->dst.metrics[RTAX_HOPLIMIT-1] = ra_msg->icmph.icmp6_hop_limit;
+                       dst_metric_set(&rt->dst, RTAX_HOPLIMIT,
+                                      ra_msg->icmph.icmp6_hop_limit);
        }
 
 skip_defrtr:
@@ -1377,7 +1378,7 @@ skip_linkparms:
                        in6_dev->cnf.mtu6 = mtu;
 
                        if (rt)
-                               rt->dst.metrics[RTAX_MTU-1] = mtu;
+                               dst_metric_set(&rt->dst, RTAX_MTU, mtu);
 
                        rt6_mtu_change(skb->dev, mtu);
                }
index 026caef0326caa90aee54a147d54014a20a0c039..4aed0812b512e0bf9cc628086b9de2b33667d518 100644 (file)
@@ -129,7 +129,6 @@ static struct rt6_info ip6_null_entry_template = {
                .__use          = 1,
                .obsolete       = -1,
                .error          = -ENETUNREACH,
-               .metrics        = { [RTAX_HOPLIMIT - 1] = 255, },
                .input          = ip6_pkt_discard,
                .output         = ip6_pkt_discard_out,
        },
@@ -150,7 +149,6 @@ static struct rt6_info ip6_prohibit_entry_template = {
                .__use          = 1,
                .obsolete       = -1,
                .error          = -EACCES,
-               .metrics        = { [RTAX_HOPLIMIT - 1] = 255, },
                .input          = ip6_pkt_prohibit,
                .output         = ip6_pkt_prohibit_out,
        },
@@ -166,7 +164,6 @@ static struct rt6_info ip6_blk_hole_entry_template = {
                .__use          = 1,
                .obsolete       = -1,
                .error          = -EINVAL,
-               .metrics        = { [RTAX_HOPLIMIT - 1] = 255, },
                .input          = dst_discard,
                .output         = dst_discard,
        },
@@ -844,7 +841,7 @@ int ip6_dst_blackhole(struct sock *sk, struct dst_entry **dstp, struct flowi *fl
                new->input = dst_discard;
                new->output = dst_discard;
 
-               memcpy(new->metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32));
+               dst_copy_metrics(new, &ort->dst);
                new->dev = ort->dst.dev;
                if (new->dev)
                        dev_hold(new->dev);
@@ -928,10 +925,12 @@ static void ip6_rt_update_pmtu(struct dst_entry *dst, u32 mtu)
        if (mtu < dst_mtu(dst) && rt6->rt6i_dst.plen == 128) {
                rt6->rt6i_flags |= RTF_MODIFIED;
                if (mtu < IPV6_MIN_MTU) {
+                       u32 features = dst_metric(dst, RTAX_FEATURES);
                        mtu = IPV6_MIN_MTU;
-                       dst->metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
+                       features |= RTAX_FEATURE_ALLFRAG;
+                       dst_metric_set(dst, RTAX_FEATURES, features);
                }
-               dst->metrics[RTAX_MTU-1] = mtu;
+               dst_metric_set(dst, RTAX_MTU, mtu);
                call_netevent_notifiers(NETEVENT_PMTU_UPDATE, dst);
        }
 }
@@ -989,9 +988,9 @@ struct dst_entry *icmp6_dst_alloc(struct net_device *dev,
        rt->rt6i_idev     = idev;
        rt->rt6i_nexthop  = neigh;
        atomic_set(&rt->dst.__refcnt, 1);
-       rt->dst.metrics[RTAX_HOPLIMIT-1] = 255;
-       rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
-       rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst));
+       dst_metric_set(&rt->dst, RTAX_HOPLIMIT, 255);
+       dst_metric_set(&rt->dst, RTAX_MTU, ipv6_get_mtu(rt->rt6i_dev));
+       dst_metric_set(&rt->dst, RTAX_ADVMSS, ipv6_advmss(net, dst_mtu(&rt->dst)));
        rt->dst.output  = ip6_output;
 
 #if 0  /* there's no chance to use these for ndisc */
@@ -1305,17 +1304,17 @@ install_route:
                                        goto out;
                                }
 
-                               rt->dst.metrics[type - 1] = nla_get_u32(nla);
+                               dst_metric_set(&rt->dst, type, nla_get_u32(nla));
                        }
                }
        }
 
        if (dst_metric(&rt->dst, RTAX_HOPLIMIT) == 0)
-               rt->dst.metrics[RTAX_HOPLIMIT-1] = -1;
+               dst_metric_set(&rt->dst, RTAX_HOPLIMIT, -1);
        if (!dst_mtu(&rt->dst))
-               rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(dev);
+               dst_metric_set(&rt->dst, RTAX_MTU, ipv6_get_mtu(dev));
        if (!dst_metric(&rt->dst, RTAX_ADVMSS))
-               rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst));
+               dst_metric_set(&rt->dst, RTAX_ADVMSS, ipv6_advmss(net, dst_mtu(&rt->dst)));
        rt->dst.dev = dev;
        rt->rt6i_idev = idev;
        rt->rt6i_table = table;
@@ -1541,9 +1540,9 @@ void rt6_redirect(struct in6_addr *dest, struct in6_addr *src,
        ipv6_addr_copy(&nrt->rt6i_gateway, (struct in6_addr*)neigh->primary_key);
        nrt->rt6i_nexthop = neigh_clone(neigh);
        /* Reset pmtu, it may be better */
-       nrt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(neigh->dev);
-       nrt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(dev_net(neigh->dev),
-                                                       dst_mtu(&nrt->dst));
+       dst_metric_set(&nrt->dst, RTAX_MTU, ipv6_get_mtu(neigh->dev));
+       dst_metric_set(&nrt->dst, RTAX_ADVMSS, ipv6_advmss(dev_net(neigh->dev),
+                                                          dst_mtu(&nrt->dst)));
 
        if (ip6_ins_rt(nrt))
                goto out;
@@ -1602,9 +1601,12 @@ static void rt6_do_pmtu_disc(struct in6_addr *daddr, struct in6_addr *saddr,
           would return automatically.
         */
        if (rt->rt6i_flags & RTF_CACHE) {
-               rt->dst.metrics[RTAX_MTU-1] = pmtu;
-               if (allfrag)
-                       rt->dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
+               dst_metric_set(&rt->dst, RTAX_MTU, pmtu);
+               if (allfrag) {
+                       u32 features = dst_metric(&rt->dst, RTAX_FEATURES);
+                       features |= RTAX_FEATURE_ALLFRAG;
+                       dst_metric_set(&rt->dst, RTAX_FEATURES, features);
+               }
                dst_set_expires(&rt->dst, net->ipv6.sysctl.ip6_rt_mtu_expires);
                rt->rt6i_flags |= RTF_MODIFIED|RTF_EXPIRES;
                goto out;
@@ -1621,9 +1623,12 @@ static void rt6_do_pmtu_disc(struct in6_addr *daddr, struct in6_addr *saddr,
                nrt = rt6_alloc_clone(rt, daddr);
 
        if (nrt) {
-               nrt->dst.metrics[RTAX_MTU-1] = pmtu;
-               if (allfrag)
-                       nrt->dst.metrics[RTAX_FEATURES-1] |= RTAX_FEATURE_ALLFRAG;
+               dst_metric_set(&nrt->dst, RTAX_MTU, pmtu);
+               if (allfrag) {
+                       u32 features = dst_metric(&nrt->dst, RTAX_FEATURES);
+                       features |= RTAX_FEATURE_ALLFRAG;
+                       dst_metric_set(&nrt->dst, RTAX_FEATURES, features);
+               }
 
                /* According to RFC 1981, detecting PMTU increase shouldn't be
                 * happened within 5 mins, the recommended timer is 10 mins.
@@ -1674,7 +1679,7 @@ static struct rt6_info * ip6_rt_copy(struct rt6_info *ort)
                rt->dst.input = ort->dst.input;
                rt->dst.output = ort->dst.output;
 
-               memcpy(rt->dst.metrics, ort->dst.metrics, RTAX_MAX*sizeof(u32));
+               dst_copy_metrics(&rt->dst, &ort->dst);
                rt->dst.error = ort->dst.error;
                rt->dst.dev = ort->dst.dev;
                if (rt->dst.dev)
@@ -1966,9 +1971,9 @@ struct rt6_info *addrconf_dst_alloc(struct inet6_dev *idev,
        rt->dst.output = ip6_output;
        rt->rt6i_dev = net->loopback_dev;
        rt->rt6i_idev = idev;
-       rt->dst.metrics[RTAX_MTU-1] = ipv6_get_mtu(rt->rt6i_dev);
-       rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, dst_mtu(&rt->dst));
-       rt->dst.metrics[RTAX_HOPLIMIT-1] = -1;
+       dst_metric_set(&rt->dst, RTAX_MTU, ipv6_get_mtu(rt->rt6i_dev));
+       dst_metric_set(&rt->dst, RTAX_ADVMSS, ipv6_advmss(net, dst_mtu(&rt->dst)));
+       dst_metric_set(&rt->dst, RTAX_HOPLIMIT, -1);
        rt->dst.obsolete = -1;
 
        rt->rt6i_flags = RTF_UP | RTF_NONEXTHOP;
@@ -2068,8 +2073,8 @@ static int rt6_mtu_change_route(struct rt6_info *rt, void *p_arg)
            (dst_mtu(&rt->dst) >= arg->mtu ||
             (dst_mtu(&rt->dst) < arg->mtu &&
              dst_mtu(&rt->dst) == idev->cnf.mtu6))) {
-               rt->dst.metrics[RTAX_MTU-1] = arg->mtu;
-               rt->dst.metrics[RTAX_ADVMSS-1] = ipv6_advmss(net, arg->mtu);
+               dst_metric_set(&rt->dst, RTAX_MTU, arg->mtu);
+               dst_metric_set(&rt->dst, RTAX_ADVMSS, ipv6_advmss(net, arg->mtu));
        }
        return 0;
 }
@@ -2295,7 +2300,7 @@ static int rt6_fill_node(struct net *net,
                        NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf);
        }
 
-       if (rtnetlink_put_metrics(skb, rt->dst.metrics) < 0)
+       if (rtnetlink_put_metrics(skb, dst_metrics_ptr(&rt->dst)) < 0)
                goto nla_put_failure;
 
        if (rt->dst.neighbour)
@@ -2686,6 +2691,7 @@ static int __net_init ip6_route_net_init(struct net *net)
        net->ipv6.ip6_null_entry->dst.path =
                (struct dst_entry *)net->ipv6.ip6_null_entry;
        net->ipv6.ip6_null_entry->dst.ops = &net->ipv6.ip6_dst_ops;
+       dst_metric_set(&net->ipv6.ip6_null_entry->dst, RTAX_HOPLIMIT, 255);
 
 #ifdef CONFIG_IPV6_MULTIPLE_TABLES
        net->ipv6.ip6_prohibit_entry = kmemdup(&ip6_prohibit_entry_template,
@@ -2696,6 +2702,7 @@ static int __net_init ip6_route_net_init(struct net *net)
        net->ipv6.ip6_prohibit_entry->dst.path =
                (struct dst_entry *)net->ipv6.ip6_prohibit_entry;
        net->ipv6.ip6_prohibit_entry->dst.ops = &net->ipv6.ip6_dst_ops;
+       dst_metric_set(&net->ipv6.ip6_prohibit_entry->dst, RTAX_HOPLIMIT, 255);
 
        net->ipv6.ip6_blk_hole_entry = kmemdup(&ip6_blk_hole_entry_template,
                                               sizeof(*net->ipv6.ip6_blk_hole_entry),
@@ -2705,6 +2712,7 @@ static int __net_init ip6_route_net_init(struct net *net)
        net->ipv6.ip6_blk_hole_entry->dst.path =
                (struct dst_entry *)net->ipv6.ip6_blk_hole_entry;
        net->ipv6.ip6_blk_hole_entry->dst.ops = &net->ipv6.ip6_dst_ops;
+       dst_metric_set(&net->ipv6.ip6_blk_hole_entry->dst, RTAX_HOPLIMIT, 255);
 #endif
 
        net->ipv6.sysctl.flush_delay = 0;
index 6e48a80d0f25a234551226b3b62719822fe74e84..8ce38f10a547e68fee50a9151cfb8727770bceda 100644 (file)
@@ -606,8 +606,9 @@ static int ipip6_rcv(struct sk_buff *skb)
                return 0;
        }
 
-       icmp_send(skb, ICMP_DEST_UNREACH, ICMP_PORT_UNREACH, 0);
+       /* no tunnel matched,  let upstream know, ipsec may handle it */
        rcu_read_unlock();
+       return 1;
 out:
        kfree_skb(skb);
        return 0;
index b541a4e009fba179d939cfe71b4d083168831728..7aad12770867bde1478e2e516b61b3dcddf5aa54 100644 (file)
@@ -54,8 +54,8 @@ int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2)
 {
        const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr;
        const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2);
-       __be32 sk1_rcv_saddr = inet_sk(sk)->inet_rcv_saddr;
-       __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2);
+       __be32 sk1_rcv_saddr = sk_rcv_saddr(sk);
+       __be32 sk2_rcv_saddr = sk_rcv_saddr(sk2);
        int sk_ipv6only = ipv6_only_sock(sk);
        int sk2_ipv6only = inet_v6_ipv6only(sk2);
        int addr_type = ipv6_addr_type(sk_rcv_saddr6);
index 04635e88e8ed3ef25b0bdac9170506ee390c93b6..110efb704c9b93eca1d86db0d252592f117de6b0 100644 (file)
@@ -672,4 +672,8 @@ MODULE_LICENSE("GPL");
 MODULE_AUTHOR("James Chapman <jchapman@katalix.com>");
 MODULE_DESCRIPTION("L2TP over IP");
 MODULE_VERSION("1.0");
-MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, SOCK_DGRAM, IPPROTO_L2TP);
+
+/* Use the value of SOCK_DGRAM (2) directory, because __stringify does't like
+ * enums
+ */
+MODULE_ALIAS_NET_PF_PROTO_TYPE(PF_INET, 2, IPPROTO_L2TP);
index 582612998211d24aa8d4aea919eed1ba1e994db3..dfd3a648a55107bda2ff14adb6f9e91c06449240 100644 (file)
@@ -316,9 +316,9 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
        if (unlikely(addr->sllc_family != AF_LLC))
                goto out;
        rc = -ENODEV;
-       rtnl_lock();
+       rcu_read_lock();
        if (sk->sk_bound_dev_if) {
-               llc->dev = dev_get_by_index(&init_net, sk->sk_bound_dev_if);
+               llc->dev = dev_get_by_index_rcu(&init_net, sk->sk_bound_dev_if);
                if (llc->dev) {
                        if (!addr->sllc_arphrd)
                                addr->sllc_arphrd = llc->dev->type;
@@ -329,14 +329,15 @@ static int llc_ui_bind(struct socket *sock, struct sockaddr *uaddr, int addrlen)
                            !llc_mac_match(addr->sllc_mac,
                                           llc->dev->dev_addr)) {
                                rc = -EINVAL;
-                               dev_put(llc->dev);
                                llc->dev = NULL;
                        }
                }
        } else
-               llc->dev = dev_getbyhwaddr(&init_net, addr->sllc_arphrd,
+               llc->dev = dev_getbyhwaddr_rcu(&init_net, addr->sllc_arphrd,
                                           addr->sllc_mac);
-       rtnl_unlock();
+       if (llc->dev)
+               dev_hold(llc->dev);
+       rcu_read_unlock();
        if (!llc->dev)
                goto out;
        if (!addr->sllc_sap) {
index 720b7a84af590f0660d4862c717113daaf0c65af..f138b195d657cf038ad68fde631fb5caebbeccf7 100644 (file)
@@ -129,9 +129,7 @@ static void sta_rx_agg_reorder_timer_expired(unsigned long data)
                        timer_to_tid[0]);
 
        rcu_read_lock();
-       spin_lock(&sta->lock);
        ieee80211_release_reorder_timeout(sta, *ptid);
-       spin_unlock(&sta->lock);
        rcu_read_unlock();
 }
 
@@ -256,7 +254,7 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
        }
 
        /* prepare A-MPDU MLME for Rx aggregation */
-       tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_ATOMIC);
+       tid_agg_rx = kmalloc(sizeof(struct tid_ampdu_rx), GFP_KERNEL);
        if (!tid_agg_rx) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                if (net_ratelimit())
@@ -280,9 +278,9 @@ void ieee80211_process_addba_request(struct ieee80211_local *local,
 
        /* prepare reordering buffer */
        tid_agg_rx->reorder_buf =
-               kcalloc(buf_size, sizeof(struct sk_buff *), GFP_ATOMIC);
+               kcalloc(buf_size, sizeof(struct sk_buff *), GFP_KERNEL);
        tid_agg_rx->reorder_time =
-               kcalloc(buf_size, sizeof(unsigned long), GFP_ATOMIC);
+               kcalloc(buf_size, sizeof(unsigned long), GFP_KERNEL);
        if (!tid_agg_rx->reorder_buf || !tid_agg_rx->reorder_time) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                if (net_ratelimit())
index 0c544074479e22efda3a89cbf73fd02d7248a0b5..db134b500caae153c11fd00309f022c348cce86b 100644 (file)
@@ -1551,27 +1551,54 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
        return ieee80211_wk_cancel_remain_on_channel(sdata, cookie);
 }
 
+static enum work_done_result
+ieee80211_offchan_tx_done(struct ieee80211_work *wk, struct sk_buff *skb)
+{
+       /*
+        * Use the data embedded in the work struct for reporting
+        * here so if the driver mangled the SKB before dropping
+        * it (which is the only way we really should get here)
+        * then we don't report mangled data.
+        *
+        * If there was no wait time, then by the time we get here
+        * the driver will likely not have reported the status yet,
+        * so in that case userspace will have to deal with it.
+        */
+
+       if (wk->offchan_tx.wait && wk->offchan_tx.frame)
+               cfg80211_mgmt_tx_status(wk->sdata->dev,
+                                       (unsigned long) wk->offchan_tx.frame,
+                                       wk->ie, wk->ie_len, false, GFP_KERNEL);
+
+       return WORK_DONE_DESTROY;
+}
+
 static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
-                            struct ieee80211_channel *chan,
+                            struct ieee80211_channel *chan, bool offchan,
                             enum nl80211_channel_type channel_type,
-                            bool channel_type_valid,
+                            bool channel_type_valid, unsigned int wait,
                             const u8 *buf, size_t len, u64 *cookie)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
        struct sta_info *sta;
+       struct ieee80211_work *wk;
        const struct ieee80211_mgmt *mgmt = (void *)buf;
        u32 flags = IEEE80211_TX_INTFL_NL80211_FRAME_TX |
                    IEEE80211_TX_CTL_REQ_TX_STATUS;
+       bool is_offchan = false;
 
        /* Check that we are on the requested channel for transmission */
        if (chan != local->tmp_channel &&
            chan != local->oper_channel)
-               return -EBUSY;
+               is_offchan = true;
        if (channel_type_valid &&
            (channel_type != local->tmp_channel_type &&
             channel_type != local->_oper_channel_type))
+               is_offchan = true;
+
+       if (is_offchan && !offchan)
                return -EBUSY;
 
        switch (sdata->vif.type) {
@@ -1605,12 +1632,70 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct net_device *dev,
        IEEE80211_SKB_CB(skb)->flags = flags;
 
        skb->dev = sdata->dev;
-       ieee80211_tx_skb(sdata, skb);
 
        *cookie = (unsigned long) skb;
+
+       /*
+        * Can transmit right away if the channel was the
+        * right one and there's no wait involved... If a
+        * wait is involved, we might otherwise not be on
+        * the right channel for long enough!
+        */
+       if (!is_offchan && !wait && !sdata->vif.bss_conf.idle) {
+               ieee80211_tx_skb(sdata, skb);
+               return 0;
+       }
+
+       wk = kzalloc(sizeof(*wk) + len, GFP_KERNEL);
+       if (!wk) {
+               kfree_skb(skb);
+               return -ENOMEM;
+       }
+
+       wk->type = IEEE80211_WORK_OFFCHANNEL_TX;
+       wk->chan = chan;
+       wk->sdata = sdata;
+       wk->done = ieee80211_offchan_tx_done;
+       wk->offchan_tx.frame = skb;
+       wk->offchan_tx.wait = wait;
+       wk->ie_len = len;
+       memcpy(wk->ie, buf, len);
+
+       ieee80211_add_work(wk);
        return 0;
 }
 
+static int ieee80211_mgmt_tx_cancel_wait(struct wiphy *wiphy,
+                                        struct net_device *dev,
+                                        u64 cookie)
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_work *wk;
+       int ret = -ENOENT;
+
+       mutex_lock(&local->mtx);
+       list_for_each_entry(wk, &local->work_list, list) {
+               if (wk->sdata != sdata)
+                       continue;
+
+               if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
+                       continue;
+
+               if (cookie != (unsigned long) wk->offchan_tx.frame)
+                       continue;
+
+               wk->timeout = jiffies;
+
+               ieee80211_queue_work(&local->hw, &local->work_work);
+               ret = 0;
+               break;
+       }
+       mutex_unlock(&local->mtx);
+
+       return ret;
+}
+
 static void ieee80211_mgmt_frame_register(struct wiphy *wiphy,
                                          struct net_device *dev,
                                          u16 frame_type, bool reg)
@@ -1695,6 +1780,7 @@ struct cfg80211_ops mac80211_config_ops = {
        .remain_on_channel = ieee80211_remain_on_channel,
        .cancel_remain_on_channel = ieee80211_cancel_remain_on_channel,
        .mgmt_tx = ieee80211_mgmt_tx,
+       .mgmt_tx_cancel_wait = ieee80211_mgmt_tx_cancel_wait,
        .set_cqm_rssi_config = ieee80211_set_cqm_rssi_config,
        .mgmt_frame_register = ieee80211_mgmt_frame_register,
        .set_antenna = ieee80211_set_antenna,
index f0fce37f4069b06c7e92db28cf4e2e1dfee4c54d..8bb5af85f46910306890a49e751b090d0912c36e 100644 (file)
@@ -112,34 +112,35 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
        char buf[71 + STA_TID_NUM * 40], *p = buf;
        int i;
        struct sta_info *sta = file->private_data;
+       struct tid_ampdu_rx *tid_rx;
+       struct tid_ampdu_tx *tid_tx;
+
+       rcu_read_lock();
 
-       spin_lock_bh(&sta->lock);
        p += scnprintf(p, sizeof(buf) + buf - p, "next dialog_token: %#02x\n",
                        sta->ampdu_mlme.dialog_token_allocator + 1);
        p += scnprintf(p, sizeof(buf) + buf - p,
                       "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tpending\n");
+
        for (i = 0; i < STA_TID_NUM; i++) {
+               tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[i]);
+               tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[i]);
+
                p += scnprintf(p, sizeof(buf) + buf - p, "%02d", i);
-               p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x",
-                               !!sta->ampdu_mlme.tid_rx[i]);
+               p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", !!tid_rx);
                p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x",
-                               sta->ampdu_mlme.tid_rx[i] ?
-                               sta->ampdu_mlme.tid_rx[i]->dialog_token : 0);
+                               tid_rx ? tid_rx->dialog_token : 0);
                p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.3x",
-                               sta->ampdu_mlme.tid_rx[i] ?
-                               sta->ampdu_mlme.tid_rx[i]->ssn : 0);
+                               tid_rx ? tid_rx->ssn : 0);
 
-               p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x",
-                               !!sta->ampdu_mlme.tid_tx[i]);
+               p += scnprintf(p, sizeof(buf) + buf - p, "\t\t%x", !!tid_tx);
                p += scnprintf(p, sizeof(buf) + buf - p, "\t%#.2x",
-                               sta->ampdu_mlme.tid_tx[i] ?
-                               sta->ampdu_mlme.tid_tx[i]->dialog_token : 0);
+                               tid_tx ? tid_tx->dialog_token : 0);
                p += scnprintf(p, sizeof(buf) + buf - p, "\t%03d",
-                               sta->ampdu_mlme.tid_tx[i] ?
-                               skb_queue_len(&sta->ampdu_mlme.tid_tx[i]->pending) : 0);
+                               tid_tx ? skb_queue_len(&tid_tx->pending) : 0);
                p += scnprintf(p, sizeof(buf) + buf - p, "\n");
        }
-       spin_unlock_bh(&sta->lock);
+       rcu_read_unlock();
 
        return simple_read_from_buffer(userbuf, count, ppos, buf, p - buf);
 }
index 5bc0745368fec3dcf178b5d3c6af6d92005f2045..66b0b52b828d171db80f0cd3110e2f8a759d1151 100644 (file)
@@ -260,6 +260,7 @@ enum ieee80211_work_type {
        IEEE80211_WORK_ASSOC_BEACON_WAIT,
        IEEE80211_WORK_ASSOC,
        IEEE80211_WORK_REMAIN_ON_CHANNEL,
+       IEEE80211_WORK_OFFCHANNEL_TX,
 };
 
 /**
@@ -320,6 +321,10 @@ struct ieee80211_work {
                struct {
                        u32 duration;
                } remain;
+               struct {
+                       struct sk_buff *frame;
+                       u32 wait;
+               } offchan_tx;
        };
 
        int ie_len;
index d2fcd22ab06d5987b228c3e1fbe99f75da4b440d..6289525c09985857b90c3c49930b9cd4f72bc7c4 100644 (file)
@@ -538,6 +538,8 @@ static void ieee80211_release_reorder_frame(struct ieee80211_hw *hw,
 {
        struct sk_buff *skb = tid_agg_rx->reorder_buf[index];
 
+       lockdep_assert_held(&tid_agg_rx->reorder_lock);
+
        if (!skb)
                goto no_frame;
 
@@ -557,6 +559,8 @@ static void ieee80211_release_reorder_frames(struct ieee80211_hw *hw,
 {
        int index;
 
+       lockdep_assert_held(&tid_agg_rx->reorder_lock);
+
        while (seq_less(tid_agg_rx->head_seq_num, head_seq_num)) {
                index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
                                                        tid_agg_rx->buf_size;
@@ -581,6 +585,8 @@ static void ieee80211_sta_reorder_release(struct ieee80211_hw *hw,
 {
        int index, j;
 
+       lockdep_assert_held(&tid_agg_rx->reorder_lock);
+
        /* release the buffer until next missing frame */
        index = seq_sub(tid_agg_rx->head_seq_num, tid_agg_rx->ssn) %
                                                tid_agg_rx->buf_size;
@@ -683,10 +689,11 @@ static bool ieee80211_sta_manage_reorder_buf(struct ieee80211_hw *hw,
        int index;
        bool ret = true;
 
+       spin_lock(&tid_agg_rx->reorder_lock);
+
        buf_size = tid_agg_rx->buf_size;
        head_seq_num = tid_agg_rx->head_seq_num;
 
-       spin_lock(&tid_agg_rx->reorder_lock);
        /* frame with out of date sequence number */
        if (seq_less(mpdu_seq_num, head_seq_num)) {
                dev_kfree_skb(skb);
@@ -1870,9 +1877,8 @@ ieee80211_rx_h_data(struct ieee80211_rx_data *rx)
        dev->stats.rx_packets++;
        dev->stats.rx_bytes += rx->skb->len;
 
-       if (ieee80211_is_data(hdr->frame_control) &&
-           !is_multicast_ether_addr(hdr->addr1) &&
-           local->hw.conf.dynamic_ps_timeout > 0 && local->ps_sdata) {
+       if (local->ps_sdata && local->hw.conf.dynamic_ps_timeout > 0 &&
+           !is_multicast_ether_addr(((struct ethhdr *)rx->skb->data)->h_dest)) {
                        mod_timer(&local->dynamic_ps_timer, jiffies +
                         msecs_to_jiffies(local->hw.conf.dynamic_ps_timeout));
        }
@@ -1921,9 +1927,12 @@ ieee80211_rx_h_ctrl(struct ieee80211_rx_data *rx, struct sk_buff_head *frames)
                        mod_timer(&tid_agg_rx->session_timer,
                                  TU_TO_EXP_TIME(tid_agg_rx->timeout));
 
+               spin_lock(&tid_agg_rx->reorder_lock);
                /* release stored frames up to start of BAR */
                ieee80211_release_reorder_frames(hw, tid_agg_rx, start_seq_num,
                                                 frames);
+               spin_unlock(&tid_agg_rx->reorder_lock);
+
                kfree_skb(skb);
                return RX_QUEUED;
        }
@@ -2245,6 +2254,10 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
                break;
        case cpu_to_le16(IEEE80211_STYPE_DEAUTH):
        case cpu_to_le16(IEEE80211_STYPE_DISASSOC):
+               if (is_multicast_ether_addr(mgmt->da) &&
+                   !is_broadcast_ether_addr(mgmt->da))
+                       return RX_DROP_MONITOR;
+
                /* process only for station */
                if (sdata->vif.type != NL80211_IFTYPE_STATION)
                        return RX_DROP_MONITOR;
@@ -2515,9 +2528,8 @@ static void ieee80211_invoke_rx_handlers(struct ieee80211_rx_data *rx)
 }
 
 /*
- * This function makes calls into the RX path. Therefore the
- * caller must hold the sta_info->lock and everything has to
- * be under rcu_read_lock protection as well.
+ * This function makes calls into the RX path, therefore
+ * it has to be invoked under RCU read lock.
  */
 void ieee80211_release_reorder_timeout(struct sta_info *sta, int tid)
 {
@@ -2739,6 +2751,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
 
                        if (ieee80211_prepare_and_rx_handle(&rx, skb, true))
                                return;
+                       goto out;
                }
        }
 
@@ -2778,6 +2791,7 @@ static void __ieee80211_rx_handle_packet(struct ieee80211_hw *hw,
                        return;
        }
 
+ out:
        dev_kfree_skb(skb);
 }
 
index b562d9b6a7023f84ce3659645ee4663b5aa04605..05f11302443b11482d27f010620df023769f5fb7 100644 (file)
@@ -81,13 +81,14 @@ enum ieee80211_sta_info_flags {
  * @stop_initiator: initiator of a session stop
  * @tx_stop: TX DelBA frame when stopping
  *
- * This structure is protected by RCU and the per-station
- * spinlock. Assignments to the array holding it must hold
- * the spinlock, only the TX path can access it under RCU
- * lock-free if, and only if, the state has  the flag
- * %HT_AGG_STATE_OPERATIONAL set. Otherwise, the TX path
- * must also acquire the spinlock and re-check the state,
- * see comments in the tx code touching it.
+ * This structure's lifetime is managed by RCU, assignments to
+ * the array holding it must hold the aggregation mutex.
+ *
+ * The TX path can access it under RCU lock-free if, and
+ * only if, the state has the flag %HT_AGG_STATE_OPERATIONAL
+ * set. Otherwise, the TX path must also acquire the spinlock
+ * and re-check the state, see comments in the tx code
+ * touching it.
  */
 struct tid_ampdu_tx {
        struct rcu_head rcu_head;
@@ -115,15 +116,13 @@ struct tid_ampdu_tx {
  * @rcu_head: RCU head used for freeing this struct
  * @reorder_lock: serializes access to reorder buffer, see below.
  *
- * This structure is protected by RCU and the per-station
- * spinlock. Assignments to the array holding it must hold
- * the spinlock.
+ * This structure's lifetime is managed by RCU, assignments to
+ * the array holding it must hold the aggregation mutex.
  *
- * The @reorder_lock is used to protect the variables and
- * arrays such as @reorder_buf, @reorder_time, @head_seq_num,
- * @stored_mpdu_num and @reorder_time from being corrupted by
- * concurrent access of the RX path and the expired frame
- * release timer.
+ * The @reorder_lock is used to protect the members of this
+ * struct, except for @timeout, @buf_size and @dialog_token,
+ * which are constant across the lifetime of the struct (the
+ * dialog token being used only for debugging).
  */
 struct tid_ampdu_rx {
        struct rcu_head rcu_head;
index bed7e32ed9085fd1c5a605618c6168910fa1cc25..4958710a7d9244a701e813c5a40e318392aa8241 100644 (file)
@@ -321,10 +321,23 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                                        msecs_to_jiffies(10));
        }
 
-       if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX)
+       if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
+               struct ieee80211_work *wk;
+
+               rcu_read_lock();
+               list_for_each_entry_rcu(wk, &local->work_list, list) {
+                       if (wk->type != IEEE80211_WORK_OFFCHANNEL_TX)
+                               continue;
+                       if (wk->offchan_tx.frame != skb)
+                               continue;
+                       wk->offchan_tx.frame = NULL;
+                       break;
+               }
+               rcu_read_unlock();
                cfg80211_mgmt_tx_status(
                        skb->dev, (unsigned long) skb, skb->data, skb->len,
                        !!(info->flags & IEEE80211_TX_STAT_ACK), GFP_ATOMIC);
+       }
 
        /* this was a transmitted frame, but now we want to reuse it */
        skb_orphan(skb);
index e69483647f33c03f9958dfaa60d3d7c1e276dd9a..2ba7426568252b78064eb498f5e0b46e038d2623 100644 (file)
@@ -1595,7 +1595,12 @@ static void ieee80211_xmit(struct ieee80211_sub_if_data *sdata,
                                                list) {
                                if (!ieee80211_sdata_running(tmp_sdata))
                                        continue;
-                               if (tmp_sdata->vif.type != NL80211_IFTYPE_AP)
+                               if (tmp_sdata->vif.type ==
+                                   NL80211_IFTYPE_MONITOR ||
+                                   tmp_sdata->vif.type ==
+                                   NL80211_IFTYPE_AP_VLAN ||
+                                       tmp_sdata->vif.type ==
+                                   NL80211_IFTYPE_WDS)
                                        continue;
                                if (compare_ether_addr(tmp_sdata->vif.addr,
                                                       hdr->addr2) == 0) {
index ae344d1ba0560480665e1b939b15b058f5fddc4c..2b5c3f267198d256ec2a40c99c8e0539027ad71a 100644 (file)
@@ -560,6 +560,25 @@ ieee80211_remain_on_channel_timeout(struct ieee80211_work *wk)
        return WORK_ACT_TIMEOUT;
 }
 
+static enum work_action __must_check
+ieee80211_offchannel_tx(struct ieee80211_work *wk)
+{
+       if (!wk->started) {
+               wk->timeout = jiffies + msecs_to_jiffies(wk->offchan_tx.wait);
+
+               /*
+                * After this, offchan_tx.frame remains but now is no
+                * longer a valid pointer -- we still need it as the
+                * cookie for canceling this work.
+                */
+               ieee80211_tx_skb(wk->sdata, wk->offchan_tx.frame);
+
+               return WORK_ACT_NONE;
+       }
+
+       return WORK_ACT_TIMEOUT;
+}
+
 static enum work_action __must_check
 ieee80211_assoc_beacon_wait(struct ieee80211_work *wk)
 {
@@ -955,6 +974,9 @@ static void ieee80211_work_work(struct work_struct *work)
                case IEEE80211_WORK_REMAIN_ON_CHANNEL:
                        rma = ieee80211_remain_on_channel_timeout(wk);
                        break;
+               case IEEE80211_WORK_OFFCHANNEL_TX:
+                       rma = ieee80211_offchannel_tx(wk);
+                       break;
                case IEEE80211_WORK_ASSOC_BEACON_WAIT:
                        rma = ieee80211_assoc_beacon_wait(wk);
                        break;
index 422705d62b5baa0e0796300a6ab2adc51e7d6e8c..246a04a1323483467158b1003abba9f88a03cb1f 100644 (file)
@@ -167,7 +167,6 @@ static int packet_set_ring(struct sock *sk, struct tpacket_req *req,
 #define PGV_FROM_VMALLOC 1
 struct pgv {
        char *buffer;
-       unsigned char flags;
 };
 
 struct packet_ring_buffer {
@@ -224,6 +223,13 @@ struct packet_skb_cb {
 
 #define PACKET_SKB_CB(__skb)   ((struct packet_skb_cb *)((__skb)->cb))
 
+static inline __pure struct page *pgv_to_page(void *addr)
+{
+       if (is_vmalloc_addr(addr))
+               return vmalloc_to_page(addr);
+       return virt_to_page(addr);
+}
+
 static void __packet_set_status(struct packet_sock *po, void *frame, int status)
 {
        union {
@@ -236,11 +242,11 @@ static void __packet_set_status(struct packet_sock *po, void *frame, int status)
        switch (po->tp_version) {
        case TPACKET_V1:
                h.h1->tp_status = status;
-               flush_dcache_page(virt_to_page(&h.h1->tp_status));
+               flush_dcache_page(pgv_to_page(&h.h1->tp_status));
                break;
        case TPACKET_V2:
                h.h2->tp_status = status;
-               flush_dcache_page(virt_to_page(&h.h2->tp_status));
+               flush_dcache_page(pgv_to_page(&h.h2->tp_status));
                break;
        default:
                pr_err("TPACKET version not supported\n");
@@ -263,10 +269,10 @@ static int __packet_get_status(struct packet_sock *po, void *frame)
        h.raw = frame;
        switch (po->tp_version) {
        case TPACKET_V1:
-               flush_dcache_page(virt_to_page(&h.h1->tp_status));
+               flush_dcache_page(pgv_to_page(&h.h1->tp_status));
                return h.h1->tp_status;
        case TPACKET_V2:
-               flush_dcache_page(virt_to_page(&h.h2->tp_status));
+               flush_dcache_page(pgv_to_page(&h.h2->tp_status));
                return h.h2->tp_status;
        default:
                pr_err("TPACKET version not supported\n");
@@ -511,7 +517,8 @@ out_free:
        return err;
 }
 
-static inline unsigned int run_filter(struct sk_buff *skb, struct sock *sk,
+static inline unsigned int run_filter(const struct sk_buff *skb,
+                                     const struct sock *sk,
                                      unsigned int res)
 {
        struct sk_filter *filter;
@@ -526,15 +533,15 @@ static inline unsigned int run_filter(struct sk_buff *skb, struct sock *sk,
 }
 
 /*
  This function makes lazy skb cloning in hope that most of packets
  are discarded by BPF.
-
  Note tricky part: we DO mangle shared skb! skb->data, skb->len
  and skb->cb are mangled. It works because (and until) packets
  falling here are owned by current CPU. Output packets are cloned
  by dev_queue_xmit_nit(), input packets are processed by net_bh
  sequencially, so that if we return skb to original state on exit,
  we will not harm anyone.
* This function makes lazy skb cloning in hope that most of packets
* are discarded by BPF.
+ *
* Note tricky part: we DO mangle shared skb! skb->data, skb->len
* and skb->cb are mangled. It works because (and until) packets
* falling here are owned by current CPU. Output packets are cloned
* by dev_queue_xmit_nit(), input packets are processed by net_bh
* sequencially, so that if we return skb to original state on exit,
* we will not harm anyone.
  */
 
 static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
@@ -560,11 +567,11 @@ static int packet_rcv(struct sk_buff *skb, struct net_device *dev,
 
        if (dev->header_ops) {
                /* The device has an explicit notion of ll header,
-                  exported to higher levels.
-
-                  Otherwise, the device hides datails of it frame
-                  structure, so that corresponding packet head
-                  never delivered to user.
+                * exported to higher levels.
+                *
+                * Otherwise, the device hides details of its frame
+                * structure, so that corresponding packet head is
+                * never delivered to user.
                 */
                if (sk->sk_type != SOCK_DGRAM)
                        skb_push(skb, skb->data - skb_mac_header(skb));
@@ -799,17 +806,15 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
 
        __packet_set_status(po, h.raw, status);
        smp_mb();
+#if ARCH_IMPLEMENTS_FLUSH_DCACHE_PAGE == 1
        {
-               struct page *p_start, *p_end;
-               u8 *h_end = h.raw + macoff + snaplen - 1;
-
-               p_start = virt_to_page(h.raw);
-               p_end = virt_to_page(h_end);
-               while (p_start <= p_end) {
-                       flush_dcache_page(p_start);
-                       p_start++;
-               }
+               u8 *start, *end;
+
+               end = (u8 *)PAGE_ALIGN((unsigned long)h.raw + macoff + snaplen);
+               for (start = h.raw; start < end; start += PAGE_SIZE)
+                       flush_dcache_page(pgv_to_page(start));
        }
+#endif
 
        sk->sk_data_ready(sk, 0);
 
@@ -915,7 +920,6 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
        }
 
        err = -EFAULT;
-       page = virt_to_page(data);
        offset = offset_in_page(data);
        len_max = PAGE_SIZE - offset;
        len = ((to_write > len_max) ? len_max : to_write);
@@ -934,11 +938,11 @@ static int tpacket_fill_skb(struct packet_sock *po, struct sk_buff *skb,
                        return -EFAULT;
                }
 
+               page = pgv_to_page(data);
+               data += len;
                flush_dcache_page(page);
                get_page(page);
-               skb_fill_page_desc(skb,
-                               nr_frags,
-                               page++, offset, len);
+               skb_fill_page_desc(skb, nr_frags, page, offset, len);
                to_write -= len;
                offset = 0;
                len_max = PAGE_SIZE;
@@ -2340,7 +2344,7 @@ static void free_pg_vec(struct pgv *pg_vec, unsigned int order,
 
        for (i = 0; i < len; i++) {
                if (likely(pg_vec[i].buffer)) {
-                       if (pg_vec[i].flags & PGV_FROM_VMALLOC)
+                       if (is_vmalloc_addr(pg_vec[i].buffer))
                                vfree(pg_vec[i].buffer);
                        else
                                free_pages((unsigned long)pg_vec[i].buffer,
@@ -2351,8 +2355,7 @@ static void free_pg_vec(struct pgv *pg_vec, unsigned int order,
        kfree(pg_vec);
 }
 
-static inline char *alloc_one_pg_vec_page(unsigned long order,
-                                         unsigned char *flags)
+static inline char *alloc_one_pg_vec_page(unsigned long order)
 {
        char *buffer = NULL;
        gfp_t gfp_flags = GFP_KERNEL | __GFP_COMP |
@@ -2366,7 +2369,6 @@ static inline char *alloc_one_pg_vec_page(unsigned long order,
        /*
         * __get_free_pages failed, fall back to vmalloc
         */
-       *flags |= PGV_FROM_VMALLOC;
        buffer = vzalloc((1 << order) * PAGE_SIZE);
 
        if (buffer)
@@ -2375,7 +2377,6 @@ static inline char *alloc_one_pg_vec_page(unsigned long order,
        /*
         * vmalloc failed, lets dig into swap here
         */
-       *flags = 0;
        gfp_flags &= ~__GFP_NORETRY;
        buffer = (char *)__get_free_pages(gfp_flags, order);
        if (buffer)
@@ -2398,8 +2399,7 @@ static struct pgv *alloc_pg_vec(struct tpacket_req *req, int order)
                goto out;
 
        for (i = 0; i < block_nr; i++) {
-               pg_vec[i].buffer = alloc_one_pg_vec_page(order,
-                                                        &pg_vec[i].flags);
+               pg_vec[i].buffer = alloc_one_pg_vec_page(order);
                if (unlikely(!pg_vec[i].buffer))
                        goto out_free_pgvec;
        }
@@ -2409,7 +2409,6 @@ out:
 
 out_free_pgvec:
        free_pg_vec(pg_vec, order, block_nr);
-       kfree(pg_vec);
        pg_vec = NULL;
        goto out;
 }
@@ -2583,13 +2582,8 @@ static int packet_mmap(struct file *file, struct socket *sock,
                        void *kaddr = rb->pg_vec[i].buffer;
                        int pg_num;
 
-                       for (pg_num = 0; pg_num < rb->pg_vec_pages;
-                                       pg_num++) {
-                               if (rb->pg_vec[i].flags & PGV_FROM_VMALLOC)
-                                       page = vmalloc_to_page(kaddr);
-                               else
-                                       page = virt_to_page(kaddr);
-
+                       for (pg_num = 0; pg_num < rb->pg_vec_pages; pg_num++) {
+                               page = pgv_to_page(kaddr);
                                err = vm_insert_page(vma, start, page);
                                if (unlikely(err))
                                        goto out;
index 6bd554323a342d4db49be267766b87492bd2e584..842c7f3650b94b1fb1f33b2c0a32665e6f4bf252 100644 (file)
@@ -6047,7 +6047,7 @@ static struct sk_buff *sctp_skb_recv_datagram(struct sock *sk, int flags,
                 * will suddenly eat the receive_queue.
                 *
                 *  Look at current nfs client by the way...
-                *  However, this function was corrent in any case. 8)
+                *  However, this function was correct in any case. 8)
                 */
                if (flags & MSG_PEEK) {
                        spin_lock_bh(&sk->sk_receive_queue.lock);
index 7ff31c60186ab0ae0ff42f7d739894b38f6db8dc..417d7a6c36cf4a5256d17f0b2eb03f8b25e61eca 100644 (file)
@@ -1344,9 +1344,25 @@ static void unix_destruct_scm(struct sk_buff *skb)
        sock_wfree(skb);
 }
 
+#define MAX_RECURSION_LEVEL 4
+
 static int unix_attach_fds(struct scm_cookie *scm, struct sk_buff *skb)
 {
        int i;
+       unsigned char max_level = 0;
+       int unix_sock_count = 0;
+
+       for (i = scm->fp->count - 1; i >= 0; i--) {
+               struct sock *sk = unix_get_socket(scm->fp->fp[i]);
+
+               if (sk) {
+                       unix_sock_count++;
+                       max_level = max(max_level,
+                                       unix_sk(sk)->recursion_level);
+               }
+       }
+       if (unlikely(max_level > MAX_RECURSION_LEVEL))
+               return -ETOOMANYREFS;
 
        /*
         * Need to duplicate file references for the sake of garbage
@@ -1357,9 +1373,11 @@ 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--)
-               unix_inflight(scm->fp->fp[i]);
-       return 0;
+       if (unix_sock_count) {
+               for (i = scm->fp->count - 1; i >= 0; i--)
+                       unix_inflight(scm->fp->fp[i]);
+       }
+       return max_level;
 }
 
 static int unix_scm_to_skb(struct scm_cookie *scm, struct sk_buff *skb, bool send_fds)
@@ -1394,6 +1412,7 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
        struct sk_buff *skb;
        long timeo;
        struct scm_cookie tmp_scm;
+       int max_level;
 
        if (NULL == siocb->scm)
                siocb->scm = &tmp_scm;
@@ -1432,8 +1451,9 @@ static int unix_dgram_sendmsg(struct kiocb *kiocb, struct socket *sock,
                goto out;
 
        err = unix_scm_to_skb(siocb->scm, skb, true);
-       if (err)
+       if (err < 0)
                goto out_free;
+       max_level = err + 1;
        unix_get_secdata(siocb->scm, skb);
 
        skb_reset_transport_header(skb);
@@ -1515,6 +1535,8 @@ restart:
        if (sock_flag(other, SOCK_RCVTSTAMP))
                __net_timestamp(skb);
        skb_queue_tail(&other->sk_receive_queue, skb);
+       if (max_level > unix_sk(other)->recursion_level)
+               unix_sk(other)->recursion_level = max_level;
        unix_state_unlock(other);
        other->sk_data_ready(other, len);
        sock_put(other);
@@ -1545,6 +1567,7 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
        int sent = 0;
        struct scm_cookie tmp_scm;
        bool fds_sent = false;
+       int max_level;
 
        if (NULL == siocb->scm)
                siocb->scm = &tmp_scm;
@@ -1608,10 +1631,11 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
 
                /* Only send the fds in the first buffer */
                err = unix_scm_to_skb(siocb->scm, skb, !fds_sent);
-               if (err) {
+               if (err < 0) {
                        kfree_skb(skb);
                        goto out_err;
                }
+               max_level = err + 1;
                fds_sent = true;
 
                err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
@@ -1627,6 +1651,8 @@ static int unix_stream_sendmsg(struct kiocb *kiocb, struct socket *sock,
                        goto pipe_err_free;
 
                skb_queue_tail(&other->sk_receive_queue, skb);
+               if (max_level > unix_sk(other)->recursion_level)
+                       unix_sk(other)->recursion_level = max_level;
                unix_state_unlock(other);
                other->sk_data_ready(other, size);
                sent += size;
@@ -1847,6 +1873,7 @@ static int unix_stream_recvmsg(struct kiocb *iocb, struct socket *sock,
                unix_state_lock(sk);
                skb = skb_dequeue(&sk->sk_receive_queue);
                if (skb == NULL) {
+                       unix_sk(sk)->recursion_level = 0;
                        if (copied >= target)
                                goto unlock;
 
index c8df6fda0b1fcf124b65812f600710a3b3f17069..f89f83bf828ee0e713ded75c84da22a1c1b2426e 100644 (file)
@@ -96,7 +96,7 @@ static DECLARE_WAIT_QUEUE_HEAD(unix_gc_wait);
 unsigned int unix_tot_inflight;
 
 
-static struct sock *unix_get_socket(struct file *filp)
+struct sock *unix_get_socket(struct file *filp)
 {
        struct sock *u_sock = NULL;
        struct inode *inode = filp->f_path.dentry->d_inode;
@@ -259,9 +259,16 @@ static void inc_inflight_move_tail(struct unix_sock *u)
 }
 
 static bool gc_in_progress = false;
+#define UNIX_INFLIGHT_TRIGGER_GC 16000
 
 void wait_for_unix_gc(void)
 {
+       /*
+        * If number of inflight sockets is insane,
+        * force a garbage collect right now.
+        */
+       if (unix_tot_inflight > UNIX_INFLIGHT_TRIGGER_GC && !gc_in_progress)
+               unix_gc();
        wait_event(unix_gc_wait, gc_in_progress == false);
 }
 
index 6583cca0e2ee52a8bec5403cb2a77d59e945d983..ee80ad8dc655ad980c1a6d8d932a37c546985c98 100644 (file)
@@ -341,9 +341,9 @@ void cfg80211_mlme_unregister_socket(struct wireless_dev *wdev, u32 nlpid);
 void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev);
 int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          struct net_device *dev,
-                         struct ieee80211_channel *chan,
+                         struct ieee80211_channel *chan, bool offchan,
                          enum nl80211_channel_type channel_type,
-                         bool channel_type_valid,
+                         bool channel_type_valid, unsigned int wait,
                          const u8 *buf, size_t len, u64 *cookie);
 
 /* SME */
index 6980a0c315b237e66916305530e82a4154b6da6a..d7680f2a4c5bd0e1ef4f3fabc9ca58914cf50f7f 100644 (file)
@@ -864,9 +864,9 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
 
 int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          struct net_device *dev,
-                         struct ieee80211_channel *chan,
+                         struct ieee80211_channel *chan, bool offchan,
                          enum nl80211_channel_type channel_type,
-                         bool channel_type_valid,
+                         bool channel_type_valid, unsigned int wait,
                          const u8 *buf, size_t len, u64 *cookie)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
@@ -946,8 +946,9 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                return -EINVAL;
 
        /* Transmit the Action frame as requested by user space */
-       return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, channel_type,
-                                 channel_type_valid, buf, len, cookie);
+       return rdev->ops->mgmt_tx(&rdev->wiphy, dev, chan, offchan,
+                                 channel_type, channel_type_valid,
+                                 wait, buf, len, cookie);
 }
 
 bool cfg80211_rx_mgmt(struct net_device *dev, int freq, const u8 *buf,
index 67ff7e92cb99df7bd6a987417b00956d58c8cdeb..960be4e650f05ead403c7ae7f9dc672f9cca25aa 100644 (file)
@@ -163,16 +163,13 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_CQM] = { .type = NLA_NESTED, },
        [NL80211_ATTR_LOCAL_STATE_CHANGE] = { .type = NLA_FLAG },
        [NL80211_ATTR_AP_ISOLATE] = { .type = NLA_U8 },
-
        [NL80211_ATTR_WIPHY_TX_POWER_SETTING] = { .type = NLA_U32 },
        [NL80211_ATTR_WIPHY_TX_POWER_LEVEL] = { .type = NLA_U32 },
-
        [NL80211_ATTR_FRAME_TYPE] = { .type = NLA_U16 },
-
        [NL80211_ATTR_WIPHY_ANTENNA_TX] = { .type = NLA_U32 },
        [NL80211_ATTR_WIPHY_ANTENNA_RX] = { .type = NLA_U32 },
-
        [NL80211_ATTR_MCAST_RATE] = { .type = NLA_U32 },
+       [NL80211_ATTR_OFFCHANNEL_TX_OK] = { .type = NLA_FLAG },
 };
 
 /* policy for the key attributes */
@@ -677,6 +674,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        CMD(remain_on_channel, REMAIN_ON_CHANNEL);
        CMD(set_bitrate_mask, SET_TX_BITRATE_MASK);
        CMD(mgmt_tx, FRAME);
+       CMD(mgmt_tx_cancel_wait, FRAME_WAIT_CANCEL);
        if (dev->wiphy.flags & WIPHY_FLAG_NETNS_OK) {
                i++;
                NLA_PUT_U32(msg, i, NL80211_CMD_SET_WIPHY_NETNS);
@@ -698,6 +696,10 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
 
        nla_nest_end(msg, nl_cmds);
 
+       /* for now at least assume all drivers have it */
+       if (dev->ops->mgmt_tx)
+               NLA_PUT_FLAG(msg, NL80211_ATTR_OFFCHANNEL_TX_OK);
+
        if (mgmt_stypes) {
                u16 stypes;
                struct nlattr *nl_ftypes, *nl_ifs;
@@ -4244,6 +4246,8 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        void *hdr;
        u64 cookie;
        struct sk_buff *msg;
+       unsigned int wait = 0;
+       bool offchan;
 
        if (!info->attrs[NL80211_ATTR_FRAME] ||
            !info->attrs[NL80211_ATTR_WIPHY_FREQ])
@@ -4260,6 +4264,12 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
            dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
                return -EOPNOTSUPP;
 
+       if (info->attrs[NL80211_ATTR_DURATION]) {
+               if (!rdev->ops->mgmt_tx_cancel_wait)
+                       return -EINVAL;
+               wait = nla_get_u32(info->attrs[NL80211_ATTR_DURATION]);
+       }
+
        if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
                channel_type = nla_get_u32(
                        info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
@@ -4271,6 +4281,8 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
                channel_type_valid = true;
        }
 
+       offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
+
        freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
        chan = rdev_freq_to_chan(rdev, freq, channel_type);
        if (chan == NULL)
@@ -4287,8 +4299,8 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
                err = PTR_ERR(hdr);
                goto free_msg;
        }
-       err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, channel_type,
-                                   channel_type_valid,
+       err = cfg80211_mlme_mgmt_tx(rdev, dev, chan, offchan, channel_type,
+                                   channel_type_valid, wait,
                                    nla_data(info->attrs[NL80211_ATTR_FRAME]),
                                    nla_len(info->attrs[NL80211_ATTR_FRAME]),
                                    &cookie);
@@ -4307,6 +4319,31 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
        return err;
 }
 
+static int nl80211_tx_mgmt_cancel_wait(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+       u64 cookie;
+
+       if (!info->attrs[NL80211_ATTR_COOKIE])
+               return -EINVAL;
+
+       if (!rdev->ops->mgmt_tx_cancel_wait)
+               return -EOPNOTSUPP;
+
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_STATION &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_CLIENT &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_AP_VLAN &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_P2P_GO)
+               return -EOPNOTSUPP;
+
+       cookie = nla_get_u64(info->attrs[NL80211_ATTR_COOKIE]);
+
+       return rdev->ops->mgmt_tx_cancel_wait(&rdev->wiphy, dev, cookie);
+}
+
 static int nl80211_set_power_save(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
@@ -4879,6 +4916,14 @@ static struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_FRAME_WAIT_CANCEL,
+               .doit = nl80211_tx_mgmt_cancel_wait,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV_UP |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
        {
                .cmd = NL80211_CMD_SET_POWER_SAVE,
                .doit = nl80211_set_power_save,
index 4c81f6abb65b80dd608267baa35fefacaa2eb12d..4cbc942f762a9308ed37016b9aaf5fd3db06ce56 100644 (file)
@@ -398,6 +398,7 @@ void __exit x25_link_free(void)
        list_for_each_safe(entry, tmp, &x25_neigh_list) {
                nb = list_entry(entry, struct x25_neigh, node);
                __x25_remove_neigh(nb);
+               dev_put(nb->dev);
        }
        write_unlock_bh(&x25_neigh_list_lock);
 }
index a2023ec52329ef66b95e14dc94f7086e5683e534..1e98bc0fe0a54bbca2a7fc1f94ab9344af0fbded 100644 (file)
@@ -19,7 +19,7 @@ struct hlist_head *xfrm_hash_alloc(unsigned int sz)
        if (sz <= PAGE_SIZE)
                n = kzalloc(sz, GFP_KERNEL);
        else if (hashdist)
-               n = __vmalloc(sz, GFP_KERNEL | __GFP_ZERO, PAGE_KERNEL);
+               n = vzalloc(sz);
        else
                n = (struct hlist_head *)
                        __get_free_pages(GFP_KERNEL | __GFP_NOWARN | __GFP_ZERO,
index 044e77898512b43d772f43659388aee51db19012..6e50ccd8c5325d31b16c912d0687a752b852c4d4 100644 (file)
@@ -1433,7 +1433,7 @@ static struct dst_entry *xfrm_bundle_create(struct xfrm_policy *policy,
                }
 
                xdst->route = dst;
-               memcpy(&dst1->metrics, &dst->metrics, sizeof(dst->metrics));
+               dst_copy_metrics(dst1, dst);
 
                if (xfrm[i]->props.mode != XFRM_MODE_TRANSPORT) {
                        family = xfrm[i]->props.family;
@@ -2271,7 +2271,7 @@ static void xfrm_init_pmtu(struct dst_entry *dst)
                if (pmtu > route_mtu_cached)
                        pmtu = route_mtu_cached;
 
-               dst->metrics[RTAX_MTU-1] = pmtu;
+               dst_metric_set(dst, RTAX_MTU, pmtu);
        } while ((dst = dst->next));
 }
 
@@ -2349,7 +2349,7 @@ static int xfrm_bundle_ok(struct xfrm_policy *pol, struct xfrm_dst *first,
                mtu = xfrm_state_mtu(dst->xfrm, mtu);
                if (mtu > last->route_mtu_cached)
                        mtu = last->route_mtu_cached;
-               dst->metrics[RTAX_MTU-1] = mtu;
+               dst_metric_set(dst, RTAX_MTU, mtu);
 
                if (last == first)
                        break;