Merge branch 'batman-adv/next' of git://git.open-mesh.org/ecsv/linux-merge
authorDavid S. Miller <davem@davemloft.net>
Thu, 9 Jun 2011 21:56:13 +0000 (14:56 -0700)
committerDavid S. Miller <davem@davemloft.net>
Thu, 9 Jun 2011 21:56:13 +0000 (14:56 -0700)
517 files changed:
Documentation/kernel-parameters.txt
Documentation/networking/ip-sysctl.txt
Documentation/virtual/lguest/Makefile
Documentation/virtual/lguest/lguest.c
arch/arm/mach-shmobile/board-ap4evb.c
arch/arm/mach-shmobile/board-mackerel.c
arch/arm/mach-shmobile/clock-sh7372.c
arch/blackfin/lib/strncpy.S
arch/ia64/include/asm/unistd.h
arch/ia64/kernel/entry.S
arch/powerpc/platforms/powermac/pic.c
arch/sh/Kconfig
arch/sh/boards/mach-ap325rxa/setup.c
arch/sh/boards/mach-ecovec24/setup.c
arch/sh/include/asm/pgtable.h
arch/sh/include/asm/ptrace.h
arch/sh/include/asm/tlb.h
arch/sh/include/cpu-sh4/cpu/sh7722.h
arch/sh/include/cpu-sh4/cpu/sh7724.h
arch/sh/include/cpu-sh4/cpu/sh7757.h
arch/sh/kernel/process_32.c
arch/sh/mm/consistent.c
arch/x86/kernel/Makefile
arch/x86/kernel/process.c
arch/x86/kernel/smpboot.c
arch/x86/lguest/boot.c
block/blk-ioc.c
block/cfq-iosched.c
drivers/atm/eni.h
drivers/atm/firestream.c
drivers/atm/horizon.c
drivers/atm/idt77252.c
drivers/atm/iphase.c
drivers/atm/zatm.c
drivers/bcma/Kconfig
drivers/bcma/Makefile
drivers/bcma/bcma_private.h
drivers/bcma/driver_pci.c
drivers/bcma/host_pci.c
drivers/bcma/main.c
drivers/bcma/sprom.c [new file with mode: 0644]
drivers/block/nbd.c
drivers/block/paride/pcd.c
drivers/block/virtio_blk.c
drivers/block/xen-blkback/blkback.c
drivers/block/xen-blkback/xenbus.c
drivers/bluetooth/hci_ldisc.c
drivers/cdrom/viocd.c
drivers/char/virtio_console.c
drivers/clocksource/sh_cmt.c
drivers/clocksource/sh_tmu.c
drivers/dma/shdma.c
drivers/ide/ide-cd.c
drivers/infiniband/hw/amso1100/c2.c
drivers/infiniband/ulp/iser/iscsi_iser.h
drivers/input/serio/serport.c
drivers/isdn/gigaset/ser-gigaset.c
drivers/isdn/hardware/mISDN/avmfritz.c
drivers/isdn/hardware/mISDN/hfcmulti.c
drivers/isdn/hardware/mISDN/hfcpci.c
drivers/isdn/hardware/mISDN/mISDNinfineon.c
drivers/isdn/hardware/mISDN/mISDNipac.c
drivers/isdn/hardware/mISDN/netjet.c
drivers/isdn/hardware/mISDN/speedfax.c
drivers/isdn/hardware/mISDN/w6692.c
drivers/isdn/hisax/hisax.h
drivers/isdn/hisax/hisax_fcpcipnp.c
drivers/media/dvb/b2c2/flexcop-common.h
drivers/media/dvb/dm1105/dm1105.c
drivers/media/dvb/mantis/mantis_common.h
drivers/media/dvb/pluto2/pluto2.c
drivers/misc/kgdbts.c
drivers/misc/ti-st/st_core.c
drivers/net/3c503.c
drivers/net/3c509.c
drivers/net/3c59x.c
drivers/net/8139cp.c
drivers/net/8139too.c
drivers/net/8390.h
drivers/net/ac3200.c
drivers/net/acenic.h
drivers/net/amd8111e.c
drivers/net/arcnet/arc-rimi.c
drivers/net/arcnet/com20020-isa.c
drivers/net/arcnet/com20020-pci.c
drivers/net/arcnet/com20020.c
drivers/net/arcnet/com90io.c
drivers/net/arcnet/com90xx.c
drivers/net/arm/at91_ether.c
drivers/net/arm/ep93xx_eth.c
drivers/net/arm/ks8695net.c
drivers/net/atl1c/atl1c.h
drivers/net/atl1e/atl1e.h
drivers/net/b44.c
drivers/net/benet/be_cmds.c
drivers/net/benet/be_cmds.h
drivers/net/benet/be_main.c
drivers/net/bmac.c
drivers/net/bnx2.c
drivers/net/bnx2x/bnx2x.h
drivers/net/bnx2x/bnx2x_cmn.c
drivers/net/bnx2x/bnx2x_cmn.h
drivers/net/bnx2x/bnx2x_ethtool.c
drivers/net/bnx2x/bnx2x_hsi.h
drivers/net/bnx2x/bnx2x_link.c
drivers/net/bnx2x/bnx2x_link.h
drivers/net/bnx2x/bnx2x_main.c
drivers/net/bnx2x/bnx2x_reg.h
drivers/net/bonding/bond_main.c
drivers/net/caif/Kconfig
drivers/net/caif/Makefile
drivers/net/caif/caif_hsi.c [new file with mode: 0644]
drivers/net/caif/caif_serial.c
drivers/net/can/Kconfig
drivers/net/can/at91_can.c
drivers/net/can/flexcan.c
drivers/net/can/sja1000/sja1000.h
drivers/net/can/slcan.c
drivers/net/cassini.c
drivers/net/cnic.c
drivers/net/cxgb4/cxgb4_main.c
drivers/net/cxgb4vf/adapter.h
drivers/net/davinci_emac.c
drivers/net/depca.c
drivers/net/dm9000.c
drivers/net/dnet.c
drivers/net/e100.c
drivers/net/e1000e/ethtool.c
drivers/net/e1000e/netdev.c
drivers/net/e2100.c
drivers/net/enic/enic.h
drivers/net/enic/enic_main.c
drivers/net/es3210.c
drivers/net/ethoc.c
drivers/net/fec_mpc52xx.c
drivers/net/greth.c
drivers/net/hamradio/6pack.c
drivers/net/hamradio/baycom_ser_fdx.c
drivers/net/hamradio/baycom_ser_hdx.c
drivers/net/hamradio/mkiss.c
drivers/net/hp-plus.c
drivers/net/hp.c
drivers/net/hp100.c
drivers/net/ibmlana.c
drivers/net/ibmveth.c
drivers/net/ifb.c
drivers/net/ipg.c
drivers/net/irda/ali-ircc.c
drivers/net/irda/donauboe.c
drivers/net/irda/irtty-sir.c
drivers/net/irda/nsc-ircc.c
drivers/net/irda/pxaficp_ir.c
drivers/net/irda/sir_dev.c
drivers/net/irda/smsc-ircc2.c
drivers/net/irda/via-ircc.c
drivers/net/irda/via-ircc.h
drivers/net/irda/vlsi_ir.c
drivers/net/irda/w83977af_ir.c
drivers/net/iseries_veth.c
drivers/net/ixgbe/ixgbe_82599.c
drivers/net/ixgbe/ixgbe_common.c
drivers/net/ixgbe/ixgbe_ethtool.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixp2000/ixpdev.c
drivers/net/jme.h
drivers/net/ks8842.c
drivers/net/ks8851.c
drivers/net/ks8851_mll.c
drivers/net/ksz884x.c
drivers/net/ll_temac_main.c
drivers/net/lne390.c
drivers/net/macb.c
drivers/net/mace.c
drivers/net/macvlan.c
drivers/net/myri10ge/myri10ge.c
drivers/net/ne3210.c
drivers/net/netx-eth.c
drivers/net/netxen/netxen_nic_hw.c
drivers/net/netxen/netxen_nic_init.c
drivers/net/netxen/netxen_nic_main.c
drivers/net/niu.c
drivers/net/ns83820.c
drivers/net/ppp_async.c
drivers/net/ppp_synctty.c
drivers/net/ps3_gelic_net.c
drivers/net/qlge/qlge.h
drivers/net/qlge/qlge_ethtool.c
drivers/net/r8169.c
drivers/net/sc92031.c
drivers/net/sfc/nic.c
drivers/net/sis190.c
drivers/net/skge.h
drivers/net/sky2.c
drivers/net/slhc.c
drivers/net/slip.c
drivers/net/smc-mca.c
drivers/net/smc-ultra.c
drivers/net/smsc911x.c
drivers/net/smsc9420.c
drivers/net/spider_net.c
drivers/net/starfire.c
drivers/net/stmmac/stmmac_ethtool.c
drivers/net/sungem.c
drivers/net/sungem.h
drivers/net/tg3.c
drivers/net/tlan.c
drivers/net/tokenring/3c359.c
drivers/net/tokenring/ibmtr.c
drivers/net/tokenring/madgemc.c
drivers/net/tsi108_eth.c
drivers/net/tulip/de2104x.c
drivers/net/tulip/de4x5.c
drivers/net/tulip/pnic.c
drivers/net/tulip/tulip_core.c
drivers/net/tun.c
drivers/net/usb/catc.c
drivers/net/usb/cdc_ncm.c
drivers/net/usb/ipheth.c
drivers/net/veth.c
drivers/net/via-velocity.c
drivers/net/virtio_net.c
drivers/net/vmxnet3/vmxnet3_drv.c
drivers/net/vmxnet3/vmxnet3_ethtool.c
drivers/net/vmxnet3/vmxnet3_int.h
drivers/net/vxge/vxge-config.h
drivers/net/vxge/vxge-main.c
drivers/net/wan/cycx_main.c
drivers/net/wan/dscc4.c
drivers/net/wan/farsync.c
drivers/net/wan/wanxl.c
drivers/net/wan/x25_asy.c
drivers/net/wireless/adm8211.c
drivers/net/wireless/ath/ath.h
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/reset.c
drivers/net/wireless/ath/ath9k/Kconfig
drivers/net/wireless/ath/ath9k/ar9002_calib.c
drivers/net/wireless/ath/ath9k/ar9002_mac.c
drivers/net/wireless/ath/ath9k/ar9003_eeprom.c
drivers/net/wireless/ath/ath9k/ar9003_mac.c
drivers/net/wireless/ath/ath9k/ar9003_paprd.c
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/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/eeprom_9287.c
drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
drivers/net/wireless/ath/ath9k/hw-ops.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/rc.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/atmel.c
drivers/net/wireless/b43/Kconfig
drivers/net/wireless/b43/Makefile
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/bus.c [new file with mode: 0644]
drivers/net/wireless/b43/bus.h [new file with mode: 0644]
drivers/net/wireless/b43/dma.c
drivers/net/wireless/b43/leds.c
drivers/net/wireless/b43/lo.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/main.h
drivers/net/wireless/b43/phy_a.c
drivers/net/wireless/b43/phy_common.c
drivers/net/wireless/b43/phy_g.c
drivers/net/wireless/b43/phy_lp.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/b43/pio.c
drivers/net/wireless/b43/rfkill.c
drivers/net/wireless/b43/sdio.c
drivers/net/wireless/b43/sysfs.c
drivers/net/wireless/b43/tables_lpphy.c
drivers/net/wireless/b43/wa.c
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/b43legacy/dma.c
drivers/net/wireless/b43legacy/main.c
drivers/net/wireless/b43legacy/xmit.c
drivers/net/wireless/hostap/hostap_wlan.h
drivers/net/wireless/ipw2x00/ipw2200.h
drivers/net/wireless/ipw2x00/libipw_wx.c
drivers/net/wireless/iwlegacy/iwl-4965-lib.c
drivers/net/wireless/iwlegacy/iwl-4965-rs.c
drivers/net/wireless/iwlegacy/iwl-4965.c
drivers/net/wireless/iwlegacy/iwl-dev.h
drivers/net/wireless/iwlegacy/iwl-eeprom.c
drivers/net/wireless/iwlwifi/iwl-1000.c
drivers/net/wireless/iwlwifi/iwl-2000.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-6000.c
drivers/net/wireless/iwlwifi/iwl-agn-hcmd.c
drivers/net/wireless/iwlwifi/iwl-agn-lib.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
drivers/net/wireless/iwlwifi/iwl-agn-tx.c
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-agn.h
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-rx.c
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwmc3200wifi/fw.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/cmd.c
drivers/net/wireless/libertas/cmdresp.c
drivers/net/wireless/libertas/debugfs.c
drivers/net/wireless/libertas/ethtool.c
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/libertas/if_spi.c
drivers/net/wireless/libertas/main.c
drivers/net/wireless/libertas/mesh.c
drivers/net/wireless/libertas/rx.c
drivers/net/wireless/libertas/tx.c
drivers/net/wireless/libertas_tf/cmd.c
drivers/net/wireless/libertas_tf/main.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mac80211_hwsim.h [new file with mode: 0644]
drivers/net/wireless/mwifiex/11n_aggr.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/sdio.c
drivers/net/wireless/mwifiex/sdio.h
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/orinoco/main.c
drivers/net/wireless/p54/p54pci.h
drivers/net/wireless/prism54/islpci_dev.c
drivers/net/wireless/prism54/islpci_dev.h
drivers/net/wireless/prism54/islpci_hotplug.c
drivers/net/wireless/rt2x00/Kconfig
drivers/net/wireless/rt2x00/rt2800.h
drivers/net/wireless/rt2x00/rt2800lib.c
drivers/net/wireless/rt2x00/rt2800lib.h
drivers/net/wireless/rt2x00/rt2800pci.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00.h
drivers/net/wireless/rt2x00/rt2x00config.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00queue.c
drivers/net/wireless/rtl818x/rtl8180/dev.c
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/efuse.c
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/ps.c
drivers/net/wireless/rtlwifi/regd.c
drivers/net/wireless/rtlwifi/rtl8192c/fw_common.c
drivers/net/wireless/rtlwifi/rtl8192c/phy_common.c
drivers/net/wireless/rtlwifi/rtl8192ce/hw.c
drivers/net/wireless/rtlwifi/rtl8192ce/phy.c
drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
drivers/net/wireless/rtlwifi/rtl8192cu/mac.c
drivers/net/wireless/rtlwifi/rtl8192cu/phy.c
drivers/net/wireless/rtlwifi/rtl8192se/dm.c
drivers/net/wireless/rtlwifi/rtl8192se/fw.c
drivers/net/wireless/rtlwifi/rtl8192se/hw.c
drivers/net/wireless/rtlwifi/rtl8192se/phy.c
drivers/net/wireless/rtlwifi/rtl8192se/trx.c
drivers/net/wireless/rtlwifi/wifi.h
drivers/net/wireless/wl1251/sdio.c
drivers/net/wireless/wl1251/spi.c
drivers/net/wireless/wl12xx/boot.c
drivers/net/wireless/wl12xx/conf.h
drivers/net/wireless/wl12xx/event.c
drivers/net/wireless/wl12xx/event.h
drivers/net/wireless/wl12xx/init.c
drivers/net/wireless/wl12xx/io.h
drivers/net/wireless/wl12xx/main.c
drivers/net/wireless/wl12xx/scan.c
drivers/net/wireless/wl12xx/scan.h
drivers/net/wireless/wl12xx/spi.c
drivers/net/wireless/wl12xx/wl12xx.h
drivers/net/wireless/zd1211rw/zd_usb.c
drivers/net/xilinx_emaclite.c
drivers/net/znet.c
drivers/pci/dmar.c
drivers/pci/intel-iommu.c
drivers/pci/iova.c
drivers/s390/net/ctcm_mpc.h
drivers/scsi/scsi_scan.c
drivers/scsi/scsi_sysfs.c
drivers/ssb/driver_pcicore.c
drivers/tty/n_gsm.c
drivers/tty/n_hdlc.c
drivers/tty/n_r3964.c
drivers/tty/n_tty.c
drivers/tty/tty_buffer.c
drivers/tty/vt/selection.c
drivers/vhost/net.c
drivers/vhost/test.c
drivers/vhost/vhost.c
drivers/vhost/vhost.h
drivers/virtio/virtio_balloon.c
drivers/virtio/virtio_ring.c
fs/autofs4/root.c
fs/block_dev.c
fs/namei.c
fs/partitions/check.c
fs/ubifs/io.c
fs/ubifs/journal.c
fs/ubifs/orphan.c
fs/ubifs/recovery.c
fs/ubifs/replay.c
fs/ubifs/shrinker.c
fs/ubifs/super.c
fs/ubifs/tnc.c
fs/ubifs/ubifs.h
include/asm-generic/unistd.h
include/linux/arcdevice.h
include/linux/bcma/bcma.h
include/linux/bcma/bcma_driver_chipcommon.h
include/linux/blkdev.h
include/linux/cordic.h [new file with mode: 0644]
include/linux/crc8.h [new file with mode: 0644]
include/linux/dccp.h
include/linux/dma_remapping.h
include/linux/ethtool.h
include/linux/genhd.h
include/linux/ieee80211.h
include/linux/if_packet.h
include/linux/mtd/physmap.h
include/linux/netdevice.h
include/linux/tcp.h
include/linux/tty_ldisc.h
include/linux/virtio.h
include/linux/virtio_9p.h
include/linux/virtio_balloon.h
include/linux/virtio_blk.h
include/linux/virtio_config.h
include/linux/virtio_console.h
include/linux/virtio_ids.h
include/linux/virtio_net.h
include/linux/virtio_pci.h
include/linux/virtio_ring.h
include/net/bluetooth/hci_core.h
include/net/caif/caif_hsi.h [new file with mode: 0644]
include/net/cfg80211.h
include/net/inetpeer.h
include/net/ip.h
include/net/mac80211.h
include/net/sctp/command.h
include/net/sctp/sctp.h
include/net/sctp/structs.h
include/net/sctp/user.h
include/net/sock.h
include/net/tcp.h
include/trace/events/net.h
kernel/rcutree.c
kernel/rcutree_plugin.h
lib/Kconfig
lib/Kconfig.debug
lib/Makefile
lib/cordic.c [new file with mode: 0644]
lib/crc8.c [new file with mode: 0644]
mm/page_alloc.c
net/8021q/vlan.c
net/8021q/vlan_dev.c
net/8021q/vlanproc.c
net/atm/pppoatm.c
net/batman-adv/hard-interface.c
net/bluetooth/hci_core.c
net/bluetooth/l2cap_core.c
net/caif/chnl_net.c
net/can/bcm.c
net/core/dev.c
net/core/ethtool.c
net/ipv4/af_inet.c
net/ipv4/inetpeer.c
net/ipv4/ip_options.c
net/ipv4/syncookies.c
net/ipv4/sysctl_net_ipv4.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_minisocks.c
net/ipv6/addrconf.c
net/ipv6/syncookies.c
net/ipv6/tcp_ipv6.c
net/mac80211/agg-rx.c
net/mac80211/cfg.c
net/mac80211/ht.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/mlme.c
net/mac80211/rc80211_minstrel.c
net/mac80211/rc80211_minstrel.h
net/mac80211/rc80211_minstrel_ht.c
net/mac80211/scan.c
net/mac80211/sta_info.h
net/mac80211/tx.c
net/packet/af_packet.c
net/rds/ib.h
net/rds/iw.h
net/sched/sch_atm.c
net/sctp/associola.c
net/sctp/bind_addr.c
net/sctp/ipv6.c
net/sctp/outqueue.c
net/sctp/protocol.c
net/sctp/sm_make_chunk.c
net/sctp/sm_sideeffect.c
net/sctp/sm_statefuns.c
net/sctp/socket.c
net/sctp/sysctl.c
net/sunrpc/auth.c
net/sunrpc/xprtrdma/svc_rdma_transport.c
net/sunrpc/xprtrdma/verbs.c
net/wireless/nl80211.c
net/wireless/scan.c
security/apparmor/lsm.c
sound/soc/codecs/cx20442.c
tools/testing/ktest/ktest.pl
tools/virtio/virtio_test.c

index 5438a2d..d9a203b 100644 (file)
@@ -999,7 +999,10 @@ bytes respectively. Such letter suffixes can also be entirely omitted.
                        With this option on every unmap_single operation will
                        result in a hardware IOTLB flush operation as opposed
                        to batching them for performance.
-
+               sp_off [Default Off]
+                       By default, super page will be supported if Intel IOMMU
+                       has the capability. With this option, super page will
+                       not be supported.
        intremap=       [X86-64, Intel-IOMMU]
                        Format: { on (default) | off | nosid }
                        on      enable Interrupt Remapping (default)
index d3d653a..3dcb26c 100644 (file)
@@ -106,16 +106,6 @@ inet_peer_maxttl - INTEGER
        when the number of entries in the pool is very small).
        Measured in seconds.
 
-inet_peer_gc_mintime - INTEGER
-       Minimum interval between garbage collection passes.  This interval is
-       in effect under high memory pressure on the pool.
-       Measured in seconds.
-
-inet_peer_gc_maxtime - INTEGER
-       Minimum interval between garbage collection passes.  This interval is
-       in effect under low (or absent) memory pressure on the pool.
-       Measured in seconds.
-
 TCP variables:
 
 somaxconn - INTEGER
index bebac6b..0ac3420 100644 (file)
@@ -1,5 +1,5 @@
 # This creates the demonstration utility "lguest" which runs a Linux guest.
-# Missing headers?  Add "-I../../include -I../../arch/x86/include"
+# Missing headers?  Add "-I../../../include -I../../../arch/x86/include"
 CFLAGS:=-m32 -Wall -Wmissing-declarations -Wmissing-prototypes -O3 -U_FORTIFY_SOURCE
 
 all: lguest
index d9da7e1..cd9d6af 100644 (file)
@@ -49,7 +49,7 @@
 #include <linux/virtio_rng.h>
 #include <linux/virtio_ring.h>
 #include <asm/bootparam.h>
-#include "../../include/linux/lguest_launcher.h"
+#include "../../../include/linux/lguest_launcher.h"
 /*L:110
  * We can ignore the 42 include files we need for this program, but I do want
  * to draw attention to the use of kernel-style types.
@@ -135,9 +135,6 @@ struct device {
        /* Is it operational */
        bool running;
 
-       /* Does Guest want an intrrupt on empty? */
-       bool irq_on_empty;
-
        /* Device-specific data. */
        void *priv;
 };
@@ -637,10 +634,7 @@ static void trigger_irq(struct virtqueue *vq)
 
        /* If they don't want an interrupt, don't send one... */
        if (vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT) {
-               /* ... unless they've asked us to force one on empty. */
-               if (!vq->dev->irq_on_empty
-                   || lg_last_avail(vq) != vq->vring.avail->idx)
-                       return;
+               return;
        }
 
        /* Send the Guest an interrupt tell them we used something up. */
@@ -1057,15 +1051,6 @@ static void create_thread(struct virtqueue *vq)
        close(vq->eventfd);
 }
 
-static bool accepted_feature(struct device *dev, unsigned int bit)
-{
-       const u8 *features = get_feature_bits(dev) + dev->feature_len;
-
-       if (dev->feature_len < bit / CHAR_BIT)
-               return false;
-       return features[bit / CHAR_BIT] & (1 << (bit % CHAR_BIT));
-}
-
 static void start_device(struct device *dev)
 {
        unsigned int i;
@@ -1079,8 +1064,6 @@ static void start_device(struct device *dev)
                verbose(" %02x", get_feature_bits(dev)
                        [dev->feature_len+i]);
 
-       dev->irq_on_empty = accepted_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY);
-
        for (vq = dev->vq; vq; vq = vq->next) {
                if (vq->service)
                        create_thread(vq);
@@ -1564,7 +1547,6 @@ static void setup_tun_net(char *arg)
        /* Set up the tun device. */
        configure_device(ipfd, tapif, ip);
 
-       add_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY);
        /* Expect Guest to handle everything except UFO */
        add_feature(dev, VIRTIO_NET_F_CSUM);
        add_feature(dev, VIRTIO_NET_F_GUEST_CSUM);
index 08acb6e..f6b687f 100644 (file)
@@ -249,6 +249,29 @@ static int slot_cn7_get_cd(struct platform_device *pdev)
 {
        return !gpio_get_value(GPIO_PORT41);
 }
+/* MERAM */
+static struct sh_mobile_meram_info meram_info = {
+       .addr_mode      = SH_MOBILE_MERAM_MODE1,
+};
+
+static struct resource meram_resources[] = {
+       [0] = {
+               .name   = "MERAM",
+               .start  = 0xe8000000,
+               .end    = 0xe81fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device meram_device = {
+       .name           = "sh_mobile_meram",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(meram_resources),
+       .resource       = meram_resources,
+       .dev            = {
+               .platform_data = &meram_info,
+       },
+};
 
 /* SH_MMCIF */
 static struct resource sh_mmcif_resources[] = {
@@ -447,13 +470,29 @@ const static struct fb_videomode ap4evb_lcdc_modes[] = {
 #endif
        },
 };
+static struct sh_mobile_meram_cfg lcd_meram_cfg = {
+       .icb[0] = {
+               .marker_icb     = 28,
+               .cache_icb      = 24,
+               .meram_offset   = 0x0,
+               .meram_size     = 0x40,
+       },
+       .icb[1] = {
+               .marker_icb     = 29,
+               .cache_icb      = 25,
+               .meram_offset   = 0x40,
+               .meram_size     = 0x40,
+       },
+};
 
 static struct sh_mobile_lcdc_info lcdc_info = {
+       .meram_dev = &meram_info,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
                .bpp = 16,
                .lcd_cfg = ap4evb_lcdc_modes,
                .num_cfg = ARRAY_SIZE(ap4evb_lcdc_modes),
+               .meram_cfg = &lcd_meram_cfg,
        }
 };
 
@@ -724,15 +763,31 @@ static struct platform_device fsi_device = {
 static struct platform_device fsi_ak4643_device = {
        .name           = "sh_fsi2_a_ak4643",
 };
+static struct sh_mobile_meram_cfg hdmi_meram_cfg = {
+       .icb[0] = {
+               .marker_icb     = 30,
+               .cache_icb      = 26,
+               .meram_offset   = 0x80,
+               .meram_size     = 0x100,
+       },
+       .icb[1] = {
+               .marker_icb     = 31,
+               .cache_icb      = 27,
+               .meram_offset   = 0x180,
+               .meram_size     = 0x100,
+       },
+};
 
 static struct sh_mobile_lcdc_info sh_mobile_lcdc1_info = {
        .clock_source = LCDC_CLK_EXTERNAL,
+       .meram_dev = &meram_info,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
                .bpp = 16,
                .interface_type = RGB24,
                .clock_divider = 1,
                .flags = LCDC_FLAGS_DWPOL,
+               .meram_cfg = &hdmi_meram_cfg,
        }
 };
 
@@ -961,6 +1016,7 @@ static struct platform_device *ap4evb_devices[] __initdata = {
        &csi2_device,
        &ceu_device,
        &ap4evb_camera,
+       &meram_device,
 };
 
 static void __init hdmi_init_pm_clock(void)
index 448ddbe..776f205 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/mtd/mtd.h>
 #include <linux/mtd/partitions.h>
 #include <linux/mtd/physmap.h>
+#include <linux/pm_runtime.h>
 #include <linux/smsc911x.h>
 #include <linux/sh_intc.h>
 #include <linux/tca6416_keypad.h>
@@ -314,6 +315,30 @@ static struct platform_device smc911x_device = {
        },
 };
 
+/* MERAM */
+static struct sh_mobile_meram_info mackerel_meram_info = {
+       .addr_mode      = SH_MOBILE_MERAM_MODE1,
+};
+
+static struct resource meram_resources[] = {
+       [0] = {
+               .name   = "MERAM",
+               .start  = 0xe8000000,
+               .end    = 0xe81fffff,
+               .flags  = IORESOURCE_MEM,
+       },
+};
+
+static struct platform_device meram_device = {
+       .name           = "sh_mobile_meram",
+       .id             = 0,
+       .num_resources  = ARRAY_SIZE(meram_resources),
+       .resource       = meram_resources,
+       .dev            = {
+               .platform_data = &mackerel_meram_info,
+       },
+};
+
 /* LCDC */
 static struct fb_videomode mackerel_lcdc_modes[] = {
        {
@@ -342,7 +367,23 @@ static int mackerel_get_brightness(void *board_data)
        return gpio_get_value(GPIO_PORT31);
 }
 
+static struct sh_mobile_meram_cfg lcd_meram_cfg = {
+       .icb[0] = {
+               .marker_icb     = 28,
+               .cache_icb      = 24,
+               .meram_offset   = 0x0,
+               .meram_size     = 0x40,
+       },
+       .icb[1] = {
+               .marker_icb     = 29,
+               .cache_icb      = 25,
+               .meram_offset   = 0x40,
+               .meram_size     = 0x40,
+       },
+};
+
 static struct sh_mobile_lcdc_info lcdc_info = {
+       .meram_dev = &mackerel_meram_info,
        .clock_source = LCDC_CLK_BUS,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
@@ -362,6 +403,7 @@ static struct sh_mobile_lcdc_info lcdc_info = {
                        .name = "sh_mobile_lcdc_bl",
                        .max_brightness = 1,
                },
+               .meram_cfg = &lcd_meram_cfg,
        }
 };
 
@@ -388,8 +430,23 @@ static struct platform_device lcdc_device = {
        },
 };
 
+static struct sh_mobile_meram_cfg hdmi_meram_cfg = {
+       .icb[0] = {
+               .marker_icb     = 30,
+               .cache_icb      = 26,
+               .meram_offset   = 0x80,
+               .meram_size     = 0x100,
+       },
+       .icb[1] = {
+               .marker_icb     = 31,
+               .cache_icb      = 27,
+               .meram_offset   = 0x180,
+               .meram_size     = 0x100,
+       },
+};
 /* HDMI */
 static struct sh_mobile_lcdc_info hdmi_lcdc_info = {
+       .meram_dev = &mackerel_meram_info,
        .clock_source = LCDC_CLK_EXTERNAL,
        .ch[0] = {
                .chan = LCDC_CHAN_MAINLCD,
@@ -397,6 +454,7 @@ static struct sh_mobile_lcdc_info hdmi_lcdc_info = {
                .interface_type = RGB24,
                .clock_divider = 1,
                .flags = LCDC_FLAGS_DWPOL,
+               .meram_cfg = &hdmi_meram_cfg,
        }
 };
 
@@ -856,6 +914,17 @@ static int slot_cn7_get_cd(struct platform_device *pdev)
 }
 
 /* SDHI0 */
+static irqreturn_t mackerel_sdhi0_gpio_cd(int irq, void *arg)
+{
+       struct device *dev = arg;
+       struct sh_mobile_sdhi_info *info = dev->platform_data;
+       struct tmio_mmc_data *pdata = info->pdata;
+
+       tmio_mmc_cd_wakeup(pdata);
+
+       return IRQ_HANDLED;
+}
+
 static struct sh_mobile_sdhi_info sdhi0_info = {
        .dma_slave_tx   = SHDMA_SLAVE_SDHI0_TX,
        .dma_slave_rx   = SHDMA_SLAVE_SDHI0_RX,
@@ -1150,6 +1219,7 @@ static struct platform_device *mackerel_devices[] __initdata = {
        &mackerel_camera,
        &hdmi_lcdc_device,
        &hdmi_device,
+       &meram_device,
 };
 
 /* Keypad Initialization */
@@ -1238,6 +1308,7 @@ static void __init mackerel_init(void)
 {
        u32 srcr4;
        struct clk *clk;
+       int ret;
 
        sh7372_pinmux_init();
 
@@ -1343,6 +1414,13 @@ static void __init mackerel_init(void)
        gpio_request(GPIO_FN_SDHID0_1, NULL);
        gpio_request(GPIO_FN_SDHID0_0, NULL);
 
+       ret = request_irq(evt2irq(0x3340), mackerel_sdhi0_gpio_cd,
+                         IRQF_TRIGGER_FALLING, "sdhi0 cd", &sdhi0_device.dev);
+       if (!ret)
+               sdhi0_info.tmio_flags |= TMIO_MMC_HAS_COLD_CD;
+       else
+               pr_err("Cannot get IRQ #%d: %d\n", evt2irq(0x3340), ret);
+
 #if !defined(CONFIG_MMC_SH_MMCIF) && !defined(CONFIG_MMC_SH_MMCIF_MODULE)
        /* enable SDHI1 */
        gpio_request(GPIO_FN_SDHICMD1, NULL);
index d17eb66..c0800d8 100644 (file)
@@ -509,6 +509,7 @@ enum { MSTP001,
        MSTP118, MSTP117, MSTP116, MSTP113,
        MSTP106, MSTP101, MSTP100,
        MSTP223,
+       MSTP218, MSTP217, MSTP216,
        MSTP207, MSTP206, MSTP204, MSTP203, MSTP202, MSTP201, MSTP200,
        MSTP329, MSTP328, MSTP323, MSTP322, MSTP314, MSTP313, MSTP312,
        MSTP423, MSTP415, MSTP413, MSTP411, MSTP410, MSTP406, MSTP403,
@@ -534,6 +535,9 @@ static struct clk mstp_clks[MSTP_NR] = {
        [MSTP101] = MSTP(&div4_clks[DIV4_M1], SMSTPCR1, 1, 0), /* VPU */
        [MSTP100] = MSTP(&div4_clks[DIV4_B], SMSTPCR1, 0, 0), /* LCDC0 */
        [MSTP223] = MSTP(&div6_clks[DIV6_SPU], SMSTPCR2, 23, 0), /* SPU2 */
+       [MSTP218] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 18, 0), /* DMAC1 */
+       [MSTP217] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 17, 0), /* DMAC2 */
+       [MSTP216] = MSTP(&div4_clks[DIV4_HP], SMSTPCR2, 16, 0), /* DMAC3 */
        [MSTP207] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 7, 0), /* SCIFA5 */
        [MSTP206] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 6, 0), /* SCIFB */
        [MSTP204] = MSTP(&div6_clks[DIV6_SUB], SMSTPCR2, 4, 0), /* SCIFA0 */
@@ -626,6 +630,9 @@ static struct clk_lookup lookups[] = {
        CLKDEV_DEV_ID("sh_mobile_lcdc_fb.0", &mstp_clks[MSTP100]), /* LCDC0 */
        CLKDEV_DEV_ID("uio_pdrv_genirq.6", &mstp_clks[MSTP223]), /* SPU2DSP0 */
        CLKDEV_DEV_ID("uio_pdrv_genirq.7", &mstp_clks[MSTP223]), /* SPU2DSP1 */
+       CLKDEV_DEV_ID("sh-dma-engine.0", &mstp_clks[MSTP218]), /* DMAC1 */
+       CLKDEV_DEV_ID("sh-dma-engine.1", &mstp_clks[MSTP217]), /* DMAC2 */
+       CLKDEV_DEV_ID("sh-dma-engine.2", &mstp_clks[MSTP216]), /* DMAC3 */
        CLKDEV_DEV_ID("sh-sci.5", &mstp_clks[MSTP207]), /* SCIFA5 */
        CLKDEV_DEV_ID("sh-sci.6", &mstp_clks[MSTP206]), /* SCIFB */
        CLKDEV_DEV_ID("sh-sci.0", &mstp_clks[MSTP204]), /* SCIFA0 */
index f3931d5..2c07ddd 100644 (file)
@@ -25,7 +25,7 @@
 
 ENTRY(_strncpy)
        CC = R2 == 0;
-       if CC JUMP 4f;
+       if CC JUMP 6f;
 
        P2 = R2 ;       /* size */
        P0 = R0 ;       /* dst*/
index 1cf0f49..7c928da 100644 (file)
 #define __NR_clock_adjtime             1328
 #define __NR_syncfs                    1329
 #define __NR_setns                     1330
+#define __NR_sendmmsg                  1331
 
 #ifdef __KERNEL__
 
 
-#define NR_syscalls                    307 /* length of syscall table */
+#define NR_syscalls                    308 /* length of syscall table */
 
 /*
  * The following defines stop scripts/checksyscalls.sh from complaining about
index 9ca8019..97dd2ab 100644 (file)
@@ -1776,6 +1776,7 @@ sys_call_table:
        data8 sys_clock_adjtime
        data8 sys_syncfs
        data8 sys_setns                         // 1330
+       data8 sys_sendmmsg
 
        .org sys_call_table + 8*NR_syscalls     // guard against failures to increase NR_syscalls
 #endif /* __IA64_ASM_PARAVIRTUALIZED_NATIVE */
index 9089b04..7667db4 100644 (file)
@@ -715,7 +715,8 @@ static struct syscore_ops pmacpic_syscore_ops = {
 
 static int __init init_pmacpic_syscore(void)
 {
-       register_syscore_ops(&pmacpic_syscore_ops);
+       if (pmac_irq_hw[0])
+               register_syscore_ops(&pmacpic_syscore_ops);
        return 0;
 }
 
index 74495a5..f03338c 100644 (file)
@@ -161,7 +161,7 @@ config ARCH_HAS_CPU_IDLE_WAIT
 
 config NO_IOPORT
        def_bool !PCI
-       depends on !SH_CAYMAN && !SH_SH4202_MICRODEV
+       depends on !SH_CAYMAN && !SH_SH4202_MICRODEV && !SH_SHMIN
 
 config IO_TRAPPED
        bool
index 618bd56..969421f 100644 (file)
@@ -359,37 +359,31 @@ static struct soc_camera_link camera_link = {
        .priv           = &camera_info,
 };
 
-static void dummy_release(struct device *dev)
+static struct platform_device *camera_device;
+
+static void ap325rxa_camera_release(struct device *dev)
 {
+       soc_camera_platform_release(&camera_device);
 }
 
-static struct platform_device camera_device = {
-       .name           = "soc_camera_platform",
-       .dev            = {
-               .platform_data  = &camera_info,
-               .release        = dummy_release,
-       },
-};
-
 static int ap325rxa_camera_add(struct soc_camera_link *icl,
                               struct device *dev)
 {
-       if (icl != &camera_link || camera_probe() <= 0)
-               return -ENODEV;
+       int ret = soc_camera_platform_add(icl, dev, &camera_device, &camera_link,
+                                         ap325rxa_camera_release, 0);
+       if (ret < 0)
+               return ret;
 
-       camera_info.dev = dev;
+       ret = camera_probe();
+       if (ret < 0)
+               soc_camera_platform_del(icl, camera_device, &camera_link);
 
-       return platform_device_register(&camera_device);
+       return ret;
 }
 
 static void ap325rxa_camera_del(struct soc_camera_link *icl)
 {
-       if (icl != &camera_link)
-               return;
-
-       platform_device_unregister(&camera_device);
-       memset(&camera_device.dev.kobj, 0,
-              sizeof(camera_device.dev.kobj));
+       soc_camera_platform_del(icl, camera_device, &camera_link);
 }
 #endif /* CONFIG_I2C */
 
index bb13d0e..3a32741 100644 (file)
@@ -885,6 +885,9 @@ static struct platform_device sh_mmcif_device = {
        },
        .num_resources  = ARRAY_SIZE(sh_mmcif_resources),
        .resource       = sh_mmcif_resources,
+       .archdata = {
+               .hwblk_id = HWBLK_MMC,
+       },
 };
 #endif
 
index db85916..9210e93 100644 (file)
@@ -18,6 +18,7 @@
 #include <asm/pgtable-2level.h>
 #endif
 #include <asm/page.h>
+#include <asm/mmu.h>
 
 #ifndef __ASSEMBLY__
 #include <asm/addrspace.h>
index 40725b4..88bd6be 100644 (file)
@@ -41,7 +41,9 @@
 
 #define user_mode(regs)                        (((regs)->sr & 0x40000000)==0)
 #define kernel_stack_pointer(_regs)    ((unsigned long)(_regs)->regs[15])
-#define GET_USP(regs) ((regs)->regs[15])
+
+#define GET_FP(regs)   ((regs)->regs[14])
+#define GET_USP(regs)  ((regs)->regs[15])
 
 extern void show_regs(struct pt_regs *);
 
@@ -131,7 +133,7 @@ extern void ptrace_triggered(struct perf_event *bp, int nmi,
 
 static inline unsigned long profile_pc(struct pt_regs *regs)
 {
-       unsigned long pc = instruction_pointer(regs);
+       unsigned long pc = regs->pc;
 
        if (virt_addr_uncached(pc))
                return CAC_ADDR(pc);
index 6c308d8..ec88bfc 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/pagemap.h>
 
 #ifdef CONFIG_MMU
+#include <linux/swap.h>
 #include <asm/pgalloc.h>
 #include <asm/tlbflush.h>
 #include <asm/mmu_context.h>
index 7a5b8a3..bd06227 100644 (file)
@@ -236,6 +236,7 @@ enum {
 };
 
 enum {
+       SHDMA_SLAVE_INVALID,
        SHDMA_SLAVE_SCIF0_TX,
        SHDMA_SLAVE_SCIF0_RX,
        SHDMA_SLAVE_SCIF1_TX,
index 7eb4359..3daef8e 100644 (file)
@@ -285,6 +285,7 @@ enum {
 };
 
 enum {
+       SHDMA_SLAVE_INVALID,
        SHDMA_SLAVE_SCIF0_TX,
        SHDMA_SLAVE_SCIF0_RX,
        SHDMA_SLAVE_SCIF1_TX,
index 05b8196..41f9f8b 100644 (file)
@@ -252,6 +252,7 @@ enum {
 };
 
 enum {
+       SHDMA_SLAVE_INVALID,
        SHDMA_SLAVE_SDHI_TX,
        SHDMA_SLAVE_SDHI_RX,
        SHDMA_SLAVE_MMCIF_TX,
index 762a139..b473f0c 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/fs.h>
 #include <linux/ftrace.h>
 #include <linux/hw_breakpoint.h>
+#include <linux/prefetch.h>
 #include <asm/uaccess.h>
 #include <asm/mmu_context.h>
 #include <asm/system.h>
index 40733a9..f251b5f 100644 (file)
@@ -82,7 +82,7 @@ void dma_cache_sync(struct device *dev, void *vaddr, size_t size,
        void *addr;
 
        addr = __in_29bit_mode() ?
-              (void *)P1SEGADDR((unsigned long)vaddr) : vaddr;
+              (void *)CAC_ADDR((unsigned long)vaddr) : vaddr;
 
        switch (direction) {
        case DMA_FROM_DEVICE:           /* invalidate only */
index f5abe3a..90b06d4 100644 (file)
@@ -8,6 +8,7 @@ CPPFLAGS_vmlinux.lds += -U$(UTS_MACHINE)
 
 ifdef CONFIG_FUNCTION_TRACER
 # Do not profile debug and lowlevel utilities
+CFLAGS_REMOVE_tsc.o = -pg
 CFLAGS_REMOVE_rtc.o = -pg
 CFLAGS_REMOVE_paravirt-spinlocks.o = -pg
 CFLAGS_REMOVE_pvclock.o = -pg
@@ -28,6 +29,7 @@ CFLAGS_paravirt.o     := $(nostackp)
 GCOV_PROFILE_vsyscall_64.o     := n
 GCOV_PROFILE_hpet.o            := n
 GCOV_PROFILE_tsc.o             := n
+GCOV_PROFILE_vread_tsc_64.o    := n
 GCOV_PROFILE_paravirt.o                := n
 
 # vread_tsc_64 is hot and should be fully optimized:
index 426a5b6..2e4928d 100644 (file)
@@ -642,7 +642,7 @@ static int __init idle_setup(char *str)
                boot_option_idle_override = IDLE_POLL;
        } else if (!strcmp(str, "mwait")) {
                boot_option_idle_override = IDLE_FORCE_MWAIT;
-               WARN_ONCE(1, "\idle=mwait\" will be removed in 2012\"\n");
+               WARN_ONCE(1, "\"idle=mwait\" will be removed in 2012\n");
        } else if (!strcmp(str, "halt")) {
                /*
                 * When the boot option of idle=halt is added, halt is
index eefd967..33a0c11 100644 (file)
@@ -1332,7 +1332,7 @@ static inline void mwait_play_dead(void)
        void *mwait_ptr;
        struct cpuinfo_x86 *c = __this_cpu_ptr(&cpu_info);
 
-       if (!this_cpu_has(X86_FEATURE_MWAIT) && mwait_usable(c))
+       if (!(this_cpu_has(X86_FEATURE_MWAIT) && mwait_usable(c)))
                return;
        if (!this_cpu_has(X86_FEATURE_CLFLSH))
                return;
index e191c09..db832fd 100644 (file)
@@ -993,6 +993,7 @@ static void lguest_time_irq(unsigned int irq, struct irq_desc *desc)
 static void lguest_time_init(void)
 {
        /* Set up the timer interrupt (0) to go to our simple timer routine */
+       lguest_setup_irq(0);
        irq_set_handler(0, lguest_time_irq);
 
        clocksource_register_hz(&lguest_clock, NSEC_PER_SEC);
index c898049..342eae9 100644 (file)
@@ -21,7 +21,7 @@ static void cfq_dtor(struct io_context *ioc)
        if (!hlist_empty(&ioc->cic_list)) {
                struct cfq_io_context *cic;
 
-               cic = list_entry(ioc->cic_list.first, struct cfq_io_context,
+               cic = hlist_entry(ioc->cic_list.first, struct cfq_io_context,
                                                                cic_list);
                cic->dtor(ioc);
        }
@@ -57,7 +57,7 @@ static void cfq_exit(struct io_context *ioc)
        if (!hlist_empty(&ioc->cic_list)) {
                struct cfq_io_context *cic;
 
-               cic = list_entry(ioc->cic_list.first, struct cfq_io_context,
+               cic = hlist_entry(ioc->cic_list.first, struct cfq_io_context,
                                                                cic_list);
                cic->exit(ioc);
        }
index 7c52d68..3c7b537 100644 (file)
@@ -185,7 +185,7 @@ struct cfq_group {
        int nr_cfqq;
 
        /*
-        * Per group busy queus average. Useful for workload slice calc. We
+        * Per group busy queues average. Useful for workload slice calc. We
         * create the array for each prio class but at run time it is used
         * only for RT and BE class and slot for IDLE class remains unused.
         * This is primarily done to avoid confusion and a gcc warning.
@@ -369,16 +369,16 @@ CFQ_CFQQ_FNS(wait_busy);
 #define cfq_log_cfqq(cfqd, cfqq, fmt, args...) \
        blk_add_trace_msg((cfqd)->queue, "cfq%d%c %s " fmt, (cfqq)->pid, \
                        cfq_cfqq_sync((cfqq)) ? 'S' : 'A', \
-                       blkg_path(&(cfqq)->cfqg->blkg), ##args);
+                       blkg_path(&(cfqq)->cfqg->blkg), ##args)
 
 #define cfq_log_cfqg(cfqd, cfqg, fmt, args...)                         \
        blk_add_trace_msg((cfqd)->queue, "%s " fmt,                     \
-                               blkg_path(&(cfqg)->blkg), ##args);      \
+                               blkg_path(&(cfqg)->blkg), ##args)       \
 
 #else
 #define cfq_log_cfqq(cfqd, cfqq, fmt, args...) \
        blk_add_trace_msg((cfqd)->queue, "cfq%d " fmt, (cfqq)->pid, ##args)
-#define cfq_log_cfqg(cfqd, cfqg, fmt, args...)         do {} while (0);
+#define cfq_log_cfqg(cfqd, cfqg, fmt, args...)         do {} while (0)
 #endif
 #define cfq_log(cfqd, fmt, args...)    \
        blk_add_trace_msg((cfqd)->queue, "cfq " fmt, ##args)
@@ -3786,9 +3786,6 @@ new_queue:
        return 0;
 
 queue_fail:
-       if (cic)
-               put_io_context(cic->ioc);
-
        cfq_schedule_dispatch(cfqd);
        spin_unlock_irqrestore(q->queue_lock, flags);
        cfq_log(cfqd, "set_request fail");
index e4c9525..493a693 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/atm.h>
 #include <linux/atmdev.h>
+#include <linux/interrupt.h>
 #include <linux/sonet.h>
 #include <linux/skbuff.h>
 #include <linux/time.h>
index ef7a658..7c7b571 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/ioport.h> /* for request_region */
 #include <linux/uio.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/capability.h>
 #include <linux/bitops.h>
 #include <linux/slab.h>
index d58e3fc..2875061 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/delay.h>
 #include <linux/uio.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
index 1f8d724..be0dbfe 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/atm.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/bitops.h>
 #include <linux/wait.h>
 #include <linux/jiffies.h>
index dee4f01..957106f 100644 (file)
@@ -53,6 +53,7 @@
 #include <linux/delay.h>  
 #include <linux/uio.h>  
 #include <linux/init.h>  
+#include <linux/interrupt.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
 #include <asm/system.h>  
index 6249179..7f8c513 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/delay.h>
 #include <linux/uio.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
 #include <linux/atm_zatm.h>
 #include <linux/capability.h>
index 353781b..83e9adf 100644 (file)
@@ -13,6 +13,11 @@ config BCMA
          Bus driver for Broadcom specific Advanced Microcontroller Bus
          Architecture.
 
+# Support for Block-I/O. SELECT this from the driver that needs it.
+config BCMA_BLOCKIO
+       bool
+       depends on BCMA
+
 config BCMA_HOST_PCI_POSSIBLE
        bool
        depends on BCMA && PCI = y
index 0d56245..cde0182 100644 (file)
@@ -1,4 +1,4 @@
-bcma-y                                 += main.o scan.o core.o
+bcma-y                                 += main.o scan.o core.o sprom.o
 bcma-y                                 += driver_chipcommon.o driver_chipcommon_pmu.o
 bcma-y                                 += driver_pci.o
 bcma-$(CONFIG_BCMA_HOST_PCI)           += host_pci.o
index 2f72e9c..12a75ab 100644 (file)
@@ -19,6 +19,9 @@ extern void bcma_bus_unregister(struct bcma_bus *bus);
 /* scan.c */
 int bcma_bus_scan(struct bcma_bus *bus);
 
+/* sprom.c */
+int bcma_sprom_get(struct bcma_bus *bus);
+
 #ifdef CONFIG_BCMA_HOST_PCI
 /* host_pci.c */
 extern int __init bcma_host_pci_init(void);
index e757e4e..789d68b 100644 (file)
@@ -161,3 +161,26 @@ void bcma_core_pci_init(struct bcma_drv_pci *pc)
 {
        bcma_pcicore_serdes_workaround(pc);
 }
+
+int bcma_core_pci_irq_ctl(struct bcma_drv_pci *pc, struct bcma_device *core,
+                         bool enable)
+{
+       struct pci_dev *pdev = pc->core->bus->host_pci;
+       u32 coremask, tmp;
+       int err;
+
+       err = pci_read_config_dword(pdev, BCMA_PCI_IRQMASK, &tmp);
+       if (err)
+               goto out;
+
+       coremask = BIT(core->core_index) << 8;
+       if (enable)
+               tmp |= coremask;
+       else
+               tmp &= ~coremask;
+
+       err = pci_write_config_dword(pdev, BCMA_PCI_IRQMASK, tmp);
+
+out:
+       return err;
+}
index 471a040..2a526bc 100644 (file)
@@ -65,6 +65,54 @@ static void bcma_host_pci_write32(struct bcma_device *core, u16 offset,
        iowrite32(value, core->bus->mmio + offset);
 }
 
+#ifdef CONFIG_BCMA_BLOCKIO
+void bcma_host_pci_block_read(struct bcma_device *core, void *buffer,
+                             size_t count, u16 offset, u8 reg_width)
+{
+       void __iomem *addr = core->bus->mmio + offset;
+       if (core->bus->mapped_core != core)
+               bcma_host_pci_switch_core(core);
+       switch (reg_width) {
+       case sizeof(u8):
+               ioread8_rep(addr, buffer, count);
+               break;
+       case sizeof(u16):
+               WARN_ON(count & 1);
+               ioread16_rep(addr, buffer, count >> 1);
+               break;
+       case sizeof(u32):
+               WARN_ON(count & 3);
+               ioread32_rep(addr, buffer, count >> 2);
+               break;
+       default:
+               WARN_ON(1);
+       }
+}
+
+void bcma_host_pci_block_write(struct bcma_device *core, const void *buffer,
+                              size_t count, u16 offset, u8 reg_width)
+{
+       void __iomem *addr = core->bus->mmio + offset;
+       if (core->bus->mapped_core != core)
+               bcma_host_pci_switch_core(core);
+       switch (reg_width) {
+       case sizeof(u8):
+               iowrite8_rep(addr, buffer, count);
+               break;
+       case sizeof(u16):
+               WARN_ON(count & 1);
+               iowrite16_rep(addr, buffer, count >> 1);
+               break;
+       case sizeof(u32):
+               WARN_ON(count & 3);
+               iowrite32_rep(addr, buffer, count >> 2);
+               break;
+       default:
+               WARN_ON(1);
+       }
+}
+#endif
+
 static u32 bcma_host_pci_aread32(struct bcma_device *core, u16 offset)
 {
        if (core->bus->mapped_core != core)
@@ -87,6 +135,10 @@ const struct bcma_host_ops bcma_host_pci_ops = {
        .write8         = bcma_host_pci_write8,
        .write16        = bcma_host_pci_write16,
        .write32        = bcma_host_pci_write32,
+#ifdef CONFIG_BCMA_BLOCKIO
+       .block_read     = bcma_host_pci_block_read,
+       .block_write    = bcma_host_pci_block_write,
+#endif
        .aread32        = bcma_host_pci_aread32,
        .awrite32       = bcma_host_pci_awrite32,
 };
index be52344..11e96dc 100644 (file)
@@ -89,6 +89,8 @@ static int bcma_register_cores(struct bcma_bus *bus)
                switch (bus->hosttype) {
                case BCMA_HOSTTYPE_PCI:
                        core->dev.parent = &bus->host_pci->dev;
+                       core->dma_dev = &bus->host_pci->dev;
+                       core->irq = bus->host_pci->irq;
                        break;
                case BCMA_HOSTTYPE_NONE:
                case BCMA_HOSTTYPE_SDIO:
@@ -144,6 +146,13 @@ int bcma_bus_register(struct bcma_bus *bus)
                bcma_core_pci_init(&bus->drv_pci);
        }
 
+       /* Try to get SPROM */
+       err = bcma_sprom_get(bus);
+       if (err) {
+               pr_err("Failed to get SPROM: %d\n", err);
+               return -ENOENT;
+       }
+
        /* Register found cores */
        bcma_register_cores(bus);
 
diff --git a/drivers/bcma/sprom.c b/drivers/bcma/sprom.c
new file mode 100644 (file)
index 0000000..ffbb0e3
--- /dev/null
@@ -0,0 +1,162 @@
+/*
+ * Broadcom specific AMBA
+ * SPROM reading
+ *
+ * Licensed under the GNU/GPL. See COPYING for details.
+ */
+
+#include "bcma_private.h"
+
+#include <linux/bcma/bcma.h>
+#include <linux/bcma/bcma_regs.h>
+#include <linux/pci.h>
+#include <linux/io.h>
+#include <linux/dma-mapping.h>
+#include <linux/slab.h>
+
+#define SPOFF(offset)  ((offset) / sizeof(u16))
+
+/**************************************************
+ * R/W ops.
+ **************************************************/
+
+static void bcma_sprom_read(struct bcma_bus *bus, u16 *sprom)
+{
+       int i;
+       for (i = 0; i < SSB_SPROMSIZE_WORDS_R4; i++)
+               sprom[i] = bcma_read16(bus->drv_cc.core,
+                                      BCMA_CC_SPROM + (i * 2));
+}
+
+/**************************************************
+ * Validation.
+ **************************************************/
+
+static inline u8 bcma_crc8(u8 crc, u8 data)
+{
+       /* Polynomial:   x^8 + x^7 + x^6 + x^4 + x^2 + 1   */
+       static const u8 t[] = {
+               0x00, 0xF7, 0xB9, 0x4E, 0x25, 0xD2, 0x9C, 0x6B,
+               0x4A, 0xBD, 0xF3, 0x04, 0x6F, 0x98, 0xD6, 0x21,
+               0x94, 0x63, 0x2D, 0xDA, 0xB1, 0x46, 0x08, 0xFF,
+               0xDE, 0x29, 0x67, 0x90, 0xFB, 0x0C, 0x42, 0xB5,
+               0x7F, 0x88, 0xC6, 0x31, 0x5A, 0xAD, 0xE3, 0x14,
+               0x35, 0xC2, 0x8C, 0x7B, 0x10, 0xE7, 0xA9, 0x5E,
+               0xEB, 0x1C, 0x52, 0xA5, 0xCE, 0x39, 0x77, 0x80,
+               0xA1, 0x56, 0x18, 0xEF, 0x84, 0x73, 0x3D, 0xCA,
+               0xFE, 0x09, 0x47, 0xB0, 0xDB, 0x2C, 0x62, 0x95,
+               0xB4, 0x43, 0x0D, 0xFA, 0x91, 0x66, 0x28, 0xDF,
+               0x6A, 0x9D, 0xD3, 0x24, 0x4F, 0xB8, 0xF6, 0x01,
+               0x20, 0xD7, 0x99, 0x6E, 0x05, 0xF2, 0xBC, 0x4B,
+               0x81, 0x76, 0x38, 0xCF, 0xA4, 0x53, 0x1D, 0xEA,
+               0xCB, 0x3C, 0x72, 0x85, 0xEE, 0x19, 0x57, 0xA0,
+               0x15, 0xE2, 0xAC, 0x5B, 0x30, 0xC7, 0x89, 0x7E,
+               0x5F, 0xA8, 0xE6, 0x11, 0x7A, 0x8D, 0xC3, 0x34,
+               0xAB, 0x5C, 0x12, 0xE5, 0x8E, 0x79, 0x37, 0xC0,
+               0xE1, 0x16, 0x58, 0xAF, 0xC4, 0x33, 0x7D, 0x8A,
+               0x3F, 0xC8, 0x86, 0x71, 0x1A, 0xED, 0xA3, 0x54,
+               0x75, 0x82, 0xCC, 0x3B, 0x50, 0xA7, 0xE9, 0x1E,
+               0xD4, 0x23, 0x6D, 0x9A, 0xF1, 0x06, 0x48, 0xBF,
+               0x9E, 0x69, 0x27, 0xD0, 0xBB, 0x4C, 0x02, 0xF5,
+               0x40, 0xB7, 0xF9, 0x0E, 0x65, 0x92, 0xDC, 0x2B,
+               0x0A, 0xFD, 0xB3, 0x44, 0x2F, 0xD8, 0x96, 0x61,
+               0x55, 0xA2, 0xEC, 0x1B, 0x70, 0x87, 0xC9, 0x3E,
+               0x1F, 0xE8, 0xA6, 0x51, 0x3A, 0xCD, 0x83, 0x74,
+               0xC1, 0x36, 0x78, 0x8F, 0xE4, 0x13, 0x5D, 0xAA,
+               0x8B, 0x7C, 0x32, 0xC5, 0xAE, 0x59, 0x17, 0xE0,
+               0x2A, 0xDD, 0x93, 0x64, 0x0F, 0xF8, 0xB6, 0x41,
+               0x60, 0x97, 0xD9, 0x2E, 0x45, 0xB2, 0xFC, 0x0B,
+               0xBE, 0x49, 0x07, 0xF0, 0x9B, 0x6C, 0x22, 0xD5,
+               0xF4, 0x03, 0x4D, 0xBA, 0xD1, 0x26, 0x68, 0x9F,
+       };
+       return t[crc ^ data];
+}
+
+static u8 bcma_sprom_crc(const u16 *sprom)
+{
+       int word;
+       u8 crc = 0xFF;
+
+       for (word = 0; word < SSB_SPROMSIZE_WORDS_R4 - 1; word++) {
+               crc = bcma_crc8(crc, sprom[word] & 0x00FF);
+               crc = bcma_crc8(crc, (sprom[word] & 0xFF00) >> 8);
+       }
+       crc = bcma_crc8(crc, sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & 0x00FF);
+       crc ^= 0xFF;
+
+       return crc;
+}
+
+static int bcma_sprom_check_crc(const u16 *sprom)
+{
+       u8 crc;
+       u8 expected_crc;
+       u16 tmp;
+
+       crc = bcma_sprom_crc(sprom);
+       tmp = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_CRC;
+       expected_crc = tmp >> SSB_SPROM_REVISION_CRC_SHIFT;
+       if (crc != expected_crc)
+               return -EPROTO;
+
+       return 0;
+}
+
+static int bcma_sprom_valid(const u16 *sprom)
+{
+       u16 revision;
+       int err;
+
+       err = bcma_sprom_check_crc(sprom);
+       if (err)
+               return err;
+
+       revision = sprom[SSB_SPROMSIZE_WORDS_R4 - 1] & SSB_SPROM_REVISION_REV;
+       if (revision != 8) {
+               pr_err("Unsupported SPROM revision: %d\n", revision);
+               return -ENOENT;
+       }
+
+       return 0;
+}
+
+/**************************************************
+ * SPROM extraction.
+ **************************************************/
+
+static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
+{
+       u16 v;
+       int i;
+
+       for (i = 0; i < 3; i++) {
+               v = sprom[SPOFF(SSB_SPROM8_IL0MAC) + i];
+               *(((__be16 *)bus->sprom.il0mac) + i) = cpu_to_be16(v);
+       }
+}
+
+int bcma_sprom_get(struct bcma_bus *bus)
+{
+       u16 *sprom;
+       int err = 0;
+
+       if (!bus->drv_cc.core)
+               return -EOPNOTSUPP;
+
+       sprom = kcalloc(SSB_SPROMSIZE_WORDS_R4, sizeof(u16),
+                       GFP_KERNEL);
+       if (!sprom)
+               return -ENOMEM;
+
+       bcma_sprom_read(bus, sprom);
+
+       err = bcma_sprom_valid(sprom);
+       if (err)
+               goto out;
+
+       bcma_sprom_extract_r8(bus, sprom);
+
+out:
+       kfree(sprom);
+       return err;
+}
index e6fc716..f533f33 100644 (file)
@@ -192,7 +192,8 @@ static int sock_xmit(struct nbd_device *lo, int send, void *buf, int size,
                        if (lo->xmit_timeout)
                                del_timer_sync(&ti);
                } else
-                       result = kernel_recvmsg(sock, &msg, &iov, 1, size, 0);
+                       result = kernel_recvmsg(sock, &msg, &iov, 1, size,
+                                               msg.msg_flags);
 
                if (signal_pending(current)) {
                        siginfo_t info;
@@ -753,9 +754,26 @@ static int __init nbd_init(void)
                return -ENOMEM;
 
        part_shift = 0;
-       if (max_part > 0)
+       if (max_part > 0) {
                part_shift = fls(max_part);
 
+               /*
+                * Adjust max_part according to part_shift as it is exported
+                * to user space so that user can know the max number of
+                * partition kernel should be able to manage.
+                *
+                * Note that -1 is required because partition 0 is reserved
+                * for the whole disk.
+                */
+               max_part = (1UL << part_shift) - 1;
+       }
+
+       if ((1UL << part_shift) > DISK_MAX_PARTS)
+               return -EINVAL;
+
+       if (nbds_max > 1UL << (MINORBITS - part_shift))
+               return -EINVAL;
+
        for (i = 0; i < nbds_max; i++) {
                struct gendisk *disk = alloc_disk(1 << part_shift);
                if (!disk)
index a0aabd9..46b8136 100644 (file)
@@ -321,7 +321,6 @@ static void pcd_init_units(void)
                strcpy(disk->disk_name, cd->name);      /* umm... */
                disk->fops = &pcd_bdops;
                disk->flags = GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
-               disk->events = DISK_EVENT_MEDIA_CHANGE;
        }
 }
 
index 6ecf89c..079c088 100644 (file)
@@ -6,10 +6,13 @@
 #include <linux/virtio.h>
 #include <linux/virtio_blk.h>
 #include <linux/scatterlist.h>
+#include <linux/string_helpers.h>
+#include <scsi/scsi_cmnd.h>
 
 #define PART_BITS 4
 
 static int major, index;
+struct workqueue_struct *virtblk_wq;
 
 struct virtio_blk
 {
@@ -26,6 +29,9 @@ struct virtio_blk
 
        mempool_t *pool;
 
+       /* Process context for config space updates */
+       struct work_struct config_work;
+
        /* What host tells us, plus 2 for header & tailer. */
        unsigned int sg_elems;
 
@@ -141,7 +147,7 @@ static bool do_req(struct request_queue *q, struct virtio_blk *vblk,
        num = blk_rq_map_sg(q, vbr->req, vblk->sg + out);
 
        if (vbr->req->cmd_type == REQ_TYPE_BLOCK_PC) {
-               sg_set_buf(&vblk->sg[num + out + in++], vbr->req->sense, 96);
+               sg_set_buf(&vblk->sg[num + out + in++], vbr->req->sense, SCSI_SENSE_BUFFERSIZE);
                sg_set_buf(&vblk->sg[num + out + in++], &vbr->in_hdr,
                           sizeof(vbr->in_hdr));
        }
@@ -291,6 +297,46 @@ static ssize_t virtblk_serial_show(struct device *dev,
 }
 DEVICE_ATTR(serial, S_IRUGO, virtblk_serial_show, NULL);
 
+static void virtblk_config_changed_work(struct work_struct *work)
+{
+       struct virtio_blk *vblk =
+               container_of(work, struct virtio_blk, config_work);
+       struct virtio_device *vdev = vblk->vdev;
+       struct request_queue *q = vblk->disk->queue;
+       char cap_str_2[10], cap_str_10[10];
+       u64 capacity, size;
+
+       /* Host must always specify the capacity. */
+       vdev->config->get(vdev, offsetof(struct virtio_blk_config, capacity),
+                         &capacity, sizeof(capacity));
+
+       /* If capacity is too big, truncate with warning. */
+       if ((sector_t)capacity != capacity) {
+               dev_warn(&vdev->dev, "Capacity %llu too large: truncating\n",
+                        (unsigned long long)capacity);
+               capacity = (sector_t)-1;
+       }
+
+       size = capacity * queue_logical_block_size(q);
+       string_get_size(size, STRING_UNITS_2, cap_str_2, sizeof(cap_str_2));
+       string_get_size(size, STRING_UNITS_10, cap_str_10, sizeof(cap_str_10));
+
+       dev_notice(&vdev->dev,
+                 "new size: %llu %d-byte logical blocks (%s/%s)\n",
+                 (unsigned long long)capacity,
+                 queue_logical_block_size(q),
+                 cap_str_10, cap_str_2);
+
+       set_capacity(vblk->disk, capacity);
+}
+
+static void virtblk_config_changed(struct virtio_device *vdev)
+{
+       struct virtio_blk *vblk = vdev->priv;
+
+       queue_work(virtblk_wq, &vblk->config_work);
+}
+
 static int __devinit virtblk_probe(struct virtio_device *vdev)
 {
        struct virtio_blk *vblk;
@@ -327,6 +373,7 @@ static int __devinit virtblk_probe(struct virtio_device *vdev)
        vblk->vdev = vdev;
        vblk->sg_elems = sg_elems;
        sg_init_table(vblk->sg, vblk->sg_elems);
+       INIT_WORK(&vblk->config_work, virtblk_config_changed_work);
 
        /* We expect one virtqueue, for output. */
        vblk->vq = virtio_find_single_vq(vdev, blk_done, "requests");
@@ -477,6 +524,8 @@ static void __devexit virtblk_remove(struct virtio_device *vdev)
 {
        struct virtio_blk *vblk = vdev->priv;
 
+       flush_work(&vblk->config_work);
+
        /* Nothing should be pending. */
        BUG_ON(!list_empty(&vblk->reqs));
 
@@ -508,27 +557,47 @@ static unsigned int features[] = {
  * Use __refdata to avoid this warning.
  */
 static struct virtio_driver __refdata virtio_blk = {
-       .feature_table = features,
-       .feature_table_size = ARRAY_SIZE(features),
-       .driver.name =  KBUILD_MODNAME,
-       .driver.owner = THIS_MODULE,
-       .id_table =     id_table,
-       .probe =        virtblk_probe,
-       .remove =       __devexit_p(virtblk_remove),
+       .feature_table          = features,
+       .feature_table_size     = ARRAY_SIZE(features),
+       .driver.name            = KBUILD_MODNAME,
+       .driver.owner           = THIS_MODULE,
+       .id_table               = id_table,
+       .probe                  = virtblk_probe,
+       .remove                 = __devexit_p(virtblk_remove),
+       .config_changed         = virtblk_config_changed,
 };
 
 static int __init init(void)
 {
+       int error;
+
+       virtblk_wq = alloc_workqueue("virtio-blk", 0, 0);
+       if (!virtblk_wq)
+               return -ENOMEM;
+
        major = register_blkdev(0, "virtblk");
-       if (major < 0)
-               return major;
-       return register_virtio_driver(&virtio_blk);
+       if (major < 0) {
+               error = major;
+               goto out_destroy_workqueue;
+       }
+
+       error = register_virtio_driver(&virtio_blk);
+       if (error)
+               goto out_unregister_blkdev;
+       return 0;
+
+out_unregister_blkdev:
+       unregister_blkdev(major, "virtblk");
+out_destroy_workqueue:
+       destroy_workqueue(virtblk_wq);
+       return error;
 }
 
 static void __exit fini(void)
 {
        unregister_blkdev(major, "virtblk");
        unregister_virtio_driver(&virtio_blk);
+       destroy_workqueue(virtblk_wq);
 }
 module_init(init);
 module_exit(fini);
index c73910c..5cf2993 100644 (file)
@@ -809,11 +809,13 @@ static int __init xen_blkif_init(void)
  failed_init:
        kfree(blkbk->pending_reqs);
        kfree(blkbk->pending_grant_handles);
-       for (i = 0; i < mmap_pages; i++) {
-               if (blkbk->pending_pages[i])
-                       __free_page(blkbk->pending_pages[i]);
+       if (blkbk->pending_pages) {
+               for (i = 0; i < mmap_pages; i++) {
+                       if (blkbk->pending_pages[i])
+                               __free_page(blkbk->pending_pages[i]);
+               }
+               kfree(blkbk->pending_pages);
        }
-       kfree(blkbk->pending_pages);
        kfree(blkbk);
        blkbk = NULL;
        return rc;
index 3457082..6cc0db1 100644 (file)
@@ -357,14 +357,13 @@ static int xen_vbd_create(struct xen_blkif *blkif, blkif_vdev_t handle,
        }
 
        vbd->bdev = bdev;
-       vbd->size = vbd_sz(vbd);
-
        if (vbd->bdev->bd_disk == NULL) {
                DPRINTK("xen_vbd_create: device %08x doesn't exist.\n",
                        vbd->pdevice);
                xen_vbd_free(vbd);
                return -ENOENT;
        }
+       vbd->size = vbd_sz(vbd);
 
        if (vbd->bdev->bd_disk->flags & GENHD_FL_CD || cdrom)
                vbd->type |= VDISK_CDROM;
index b3f0199..48ad2a7 100644 (file)
@@ -355,29 +355,24 @@ static void hci_uart_tty_wakeup(struct tty_struct *tty)
  *             flags        pointer to flags for data
  *             count        count of received data in bytes
  *     
- * Return Value:    Number of bytes received
+ * Return Value:    None
  */
-static unsigned int hci_uart_tty_receive(struct tty_struct *tty,
-               const u8 *data, char *flags, int count)
+static void hci_uart_tty_receive(struct tty_struct *tty, const u8 *data, char *flags, int count)
 {
        struct hci_uart *hu = (void *)tty->disc_data;
-       int received;
 
        if (!hu || tty != hu->tty)
-               return -ENODEV;
+               return;
 
        if (!test_bit(HCI_UART_PROTO_SET, &hu->flags))
-               return -EINVAL;
+               return;
 
        spin_lock(&hu->rx_lock);
-       received = hu->proto->recv(hu, (void *) data, count);
-       if (received > 0)
-               hu->hdev->stat.byte_rx += received;
+       hu->proto->recv(hu, (void *) data, count);
+       hu->hdev->stat.byte_rx += count;
        spin_unlock(&hu->rx_lock);
 
        tty_unthrottle(tty);
-
-       return received;
 }
 
 static int hci_uart_register_dev(struct hci_uart *hu)
index ae15a4d..7878da8 100644 (file)
@@ -627,7 +627,6 @@ static int viocd_probe(struct vio_dev *vdev, const struct vio_device_id *id)
        gendisk->fops = &viocd_fops;
        gendisk->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE |
                         GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
-       gendisk->events = DISK_EVENT_MEDIA_CHANGE;
        set_capacity(gendisk, 0);
        gendisk->private_data = d;
        d->viocd_disk = gendisk;
index 838568a..fb68b12 100644 (file)
@@ -1677,17 +1677,12 @@ static int __devinit virtcons_probe(struct virtio_device *vdev)
        portdev->config.max_nr_ports = 1;
        if (virtio_has_feature(vdev, VIRTIO_CONSOLE_F_MULTIPORT)) {
                multiport = true;
-               vdev->features[0] |= 1 << VIRTIO_CONSOLE_F_MULTIPORT;
-
                vdev->config->get(vdev, offsetof(struct virtio_console_config,
                                                 max_nr_ports),
                                  &portdev->config.max_nr_ports,
                                  sizeof(portdev->config.max_nr_ports));
        }
 
-       /* Let the Host know we support multiple ports.*/
-       vdev->config->finalize_features(vdev);
-
        err = init_vqs(portdev);
        if (err < 0) {
                dev_err(&vdev->dev, "Error %d initializing vqs\n", err);
index 036e586..dc7c033 100644 (file)
@@ -24,7 +24,6 @@
 #include <linux/ioport.h>
 #include <linux/io.h>
 #include <linux/clk.h>
-#include <linux/pm_runtime.h>
 #include <linux/irq.h>
 #include <linux/err.h>
 #include <linux/clocksource.h>
@@ -153,12 +152,10 @@ static int sh_cmt_enable(struct sh_cmt_priv *p, unsigned long *rate)
 {
        int ret;
 
-       /* wake up device and enable clock */
-       pm_runtime_get_sync(&p->pdev->dev);
+       /* enable clock */
        ret = clk_enable(p->clk);
        if (ret) {
                dev_err(&p->pdev->dev, "cannot enable clock\n");
-               pm_runtime_put_sync(&p->pdev->dev);
                return ret;
        }
 
@@ -190,9 +187,8 @@ static void sh_cmt_disable(struct sh_cmt_priv *p)
        /* disable interrupts in CMT block */
        sh_cmt_write(p, CMCSR, 0);
 
-       /* stop clock and mark device as idle */
+       /* stop clock */
        clk_disable(p->clk);
-       pm_runtime_put_sync(&p->pdev->dev);
 }
 
 /* private flags */
@@ -664,7 +660,6 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev)
 
        if (p) {
                dev_info(&pdev->dev, "kept as earlytimer\n");
-               pm_runtime_enable(&pdev->dev);
                return 0;
        }
 
@@ -679,9 +674,6 @@ static int __devinit sh_cmt_probe(struct platform_device *pdev)
                kfree(p);
                platform_set_drvdata(pdev, NULL);
        }
-
-       if (!is_early_platform_device(pdev))
-               pm_runtime_enable(&pdev->dev);
        return ret;
 }
 
index 1729628..8081357 100644 (file)
@@ -25,7 +25,6 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 #include <linux/clk.h>
-#include <linux/pm_runtime.h>
 #include <linux/irq.h>
 #include <linux/err.h>
 #include <linux/clocksource.h>
@@ -110,12 +109,10 @@ static int sh_tmu_enable(struct sh_tmu_priv *p)
 {
        int ret;
 
-       /* wake up device and enable clock */
-       pm_runtime_get_sync(&p->pdev->dev);
+       /* enable clock */
        ret = clk_enable(p->clk);
        if (ret) {
                dev_err(&p->pdev->dev, "cannot enable clock\n");
-               pm_runtime_put_sync(&p->pdev->dev);
                return ret;
        }
 
@@ -144,9 +141,8 @@ static void sh_tmu_disable(struct sh_tmu_priv *p)
        /* disable interrupts in TMU block */
        sh_tmu_write(p, TCR, 0x0000);
 
-       /* stop clock and mark device as idle */
+       /* stop clock */
        clk_disable(p->clk);
-       pm_runtime_put_sync(&p->pdev->dev);
 }
 
 static void sh_tmu_set_next(struct sh_tmu_priv *p, unsigned long delta,
@@ -415,7 +411,6 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev)
 
        if (p) {
                dev_info(&pdev->dev, "kept as earlytimer\n");
-               pm_runtime_enable(&pdev->dev);
                return 0;
        }
 
@@ -430,9 +425,6 @@ static int __devinit sh_tmu_probe(struct platform_device *pdev)
                kfree(p);
                platform_set_drvdata(pdev, NULL);
        }
-
-       if (!is_early_platform_device(pdev))
-               pm_runtime_enable(&pdev->dev);
        return ret;
 }
 
index 636e409..2a638f9 100644 (file)
@@ -343,7 +343,7 @@ static int sh_dmae_alloc_chan_resources(struct dma_chan *chan)
 
                dmae_set_dmars(sh_chan, cfg->mid_rid);
                dmae_set_chcr(sh_chan, cfg->chcr);
-       } else if ((sh_dmae_readl(sh_chan, CHCR) & 0xf00) != 0x400) {
+       } else {
                dmae_init(sh_chan);
        }
 
@@ -1144,6 +1144,8 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
        /* platform data */
        shdev->pdata = pdata;
 
+       platform_set_drvdata(pdev, shdev);
+
        pm_runtime_enable(&pdev->dev);
        pm_runtime_get_sync(&pdev->dev);
 
@@ -1256,7 +1258,6 @@ static int __init sh_dmae_probe(struct platform_device *pdev)
 
        pm_runtime_put(&pdev->dev);
 
-       platform_set_drvdata(pdev, shdev);
        dma_async_device_register(&shdev->common);
 
        return err;
@@ -1278,6 +1279,8 @@ rst_err:
 
        if (dmars)
                iounmap(shdev->dmars);
+
+       platform_set_drvdata(pdev, NULL);
 emapdmars:
        iounmap(shdev->chan_reg);
        synchronize_rcu();
@@ -1316,6 +1319,8 @@ static int __exit sh_dmae_remove(struct platform_device *pdev)
                iounmap(shdev->dmars);
        iounmap(shdev->chan_reg);
 
+       platform_set_drvdata(pdev, NULL);
+
        synchronize_rcu();
        kfree(shdev);
 
index 6e5123b..144d272 100644 (file)
@@ -1782,7 +1782,6 @@ static int ide_cd_probe(ide_drive_t *drive)
        ide_cd_read_toc(drive, &sense);
        g->fops = &idecd_ops;
        g->flags |= GENHD_FL_REMOVABLE | GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE;
-       g->events = DISK_EVENT_MEDIA_CHANGE;
        add_disk(g);
        return 0;
 
index 0cfc455..444470a 100644 (file)
@@ -36,6 +36,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/inetdevice.h>
+#include <linux/interrupt.h>
 #include <linux/delay.h>
 #include <linux/ethtool.h>
 #include <linux/mii.h>
index 2f02ab0..342cbc1 100644 (file)
@@ -45,6 +45,7 @@
 #include <scsi/libiscsi.h>
 #include <scsi/scsi_transport_iscsi.h>
 
+#include <linux/interrupt.h>
 #include <linux/wait.h>
 #include <linux/sched.h>
 #include <linux/list.h>
index f369896..8755f5f 100644 (file)
@@ -120,21 +120,17 @@ static void serport_ldisc_close(struct tty_struct *tty)
  * 'interrupt' routine.
  */
 
-static unsigned int serport_ldisc_receive(struct tty_struct *tty,
-               const unsigned char *cp, char *fp, int count)
+static void serport_ldisc_receive(struct tty_struct *tty, const unsigned char *cp, char *fp, int count)
 {
        struct serport *serport = (struct serport*) tty->disc_data;
        unsigned long flags;
        unsigned int ch_flags;
-       int ret = 0;
        int i;
 
        spin_lock_irqsave(&serport->lock, flags);
 
-       if (!test_bit(SERPORT_ACTIVE, &serport->flags)) {
-               ret = -EINVAL;
+       if (!test_bit(SERPORT_ACTIVE, &serport->flags))
                goto out;
-       }
 
        for (i = 0; i < count; i++) {
                switch (fp[i]) {
@@ -156,8 +152,6 @@ static unsigned int serport_ldisc_receive(struct tty_struct *tty,
 
 out:
        spin_unlock_irqrestore(&serport->lock, flags);
-
-       return ret == 0 ? count : ret;
 }
 
 /*
index 1d44d47..86a5c4f 100644 (file)
@@ -674,7 +674,7 @@ gigaset_tty_ioctl(struct tty_struct *tty, struct file *file,
  *     cflags  buffer containing error flags for received characters (ignored)
  *     count   number of received characters
  */
-static unsigned int
+static void
 gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
                    char *cflags, int count)
 {
@@ -683,12 +683,12 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
        struct inbuf_t *inbuf;
 
        if (!cs)
-               return -ENODEV;
+               return;
        inbuf = cs->inbuf;
        if (!inbuf) {
                dev_err(cs->dev, "%s: no inbuf\n", __func__);
                cs_put(cs);
-               return -EINVAL;
+               return;
        }
 
        tail = inbuf->tail;
@@ -725,8 +725,6 @@ gigaset_tty_receive(struct tty_struct *tty, const unsigned char *buf,
        gig_dbg(DEBUG_INTR, "%s-->BH", __func__);
        gigaset_schedule_event(cs);
        cs_put(cs);
-
-       return count;
 }
 
 /*
index 472a2af..861b651 100644 (file)
@@ -20,6 +20,7 @@
  * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
  *
  */
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
index f6f3c87..a440d7f 100644 (file)
 
 #define HFC_MULTI_VERSION      "2.03"
 
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
index b01a7be..3261de1 100644 (file)
@@ -44,6 +44,7 @@
  *
  */
 
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
index bc0529a..6218775 100644 (file)
@@ -38,6 +38,7 @@
  *
  */
 
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
index 64ecc6f..d2ffb1d 100644 (file)
@@ -20,6 +20,7 @@
  *
  */
 
+#include <linux/irqreturn.h>
 #include <linux/slab.h>
 #include <linux/module.h>
 #include <linux/mISDNhw.h>
index db25b6b..5ef9f11 100644 (file)
@@ -20,6 +20,7 @@
  *
  */
 
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
index 9e07246..4d0d41e 100644 (file)
@@ -22,6 +22,7 @@
  *
  */
 
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/pci.h>
index 9e84870..e10e028 100644 (file)
@@ -21,6 +21,7 @@
  *
  */
 
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
index de1c669..0a5c42a 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/mm.h>
 #include <linux/mman.h>
+#include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/timer.h>
 #include <linux/wait.h>
index 8b0a7d8..478ebab 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/isapnp.h>
 #include <linux/kmod.h>
index 9e2148a..437912e 100644 (file)
@@ -6,6 +6,7 @@
 #ifndef __FLEXCOP_COMMON_H__
 #define __FLEXCOP_COMMON_H__
 
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/mutex.h>
 
index b2b0c45..55e6533 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/proc_fs.h>
index bd400d2..49dbca1 100644 (file)
@@ -21,6 +21,7 @@
 #ifndef __MANTIS_COMMON_H
 #define __MANTIS_COMMON_H
 
+#include <linux/interrupt.h>
 #include <linux/mutex.h>
 #include <linux/workqueue.h>
 
index 7cb79ec..80fb510 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-algo-bit.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/pci.h>
index b0c5631..8cebec5 100644 (file)
@@ -304,7 +304,10 @@ static int check_and_rewind_pc(char *put_str, char *arg)
                return 1;
        }
        /* Readjust the instruction pointer if needed */
-       instruction_pointer_set(&kgdbts_regs, ip + offset);
+       ip += offset;
+#ifdef GDB_ADJUSTS_BREAK_OFFSET
+       instruction_pointer_set(&kgdbts_regs, ip);
+#endif
        return 0;
 }
 
index 1a05fe0..f91f82e 100644 (file)
@@ -747,8 +747,8 @@ static void st_tty_close(struct tty_struct *tty)
        pr_debug("%s: done ", __func__);
 }
 
-static unsigned int st_tty_receive(struct tty_struct *tty,
-               const unsigned char *data, char *tty_flags, int count)
+static void st_tty_receive(struct tty_struct *tty, const unsigned char *data,
+                          char *tty_flags, int count)
 {
 #ifdef VERBOSE
        print_hex_dump(KERN_DEBUG, ">in>", DUMP_PREFIX_NONE,
@@ -761,8 +761,6 @@ static unsigned int st_tty_receive(struct tty_struct *tty,
         */
        st_recv(tty->disc_data, data, count);
        pr_debug("done %s", __func__);
-
-       return count;
 }
 
 /* wake-up function called in from the TTY layer
index d84f6e8..554a26c 100644 (file)
@@ -49,6 +49,7 @@ static const char version[] =
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/ethtool.h>
 
 #include <asm/uaccess.h>
index 5f25889..44b28b2 100644 (file)
@@ -185,7 +185,7 @@ static int max_interrupt_work = 10;
 static int nopnp;
 #endif
 
-static int el3_common_init(struct net_device *dev);
+static int __devinit el3_common_init(struct net_device *dev);
 static void el3_common_remove(struct net_device *dev);
 static ushort id_read_eeprom(int index);
 static ushort read_eeprom(int ioaddr, int index);
@@ -395,7 +395,7 @@ static struct isa_driver el3_isa_driver = {
 static int isa_registered;
 
 #ifdef CONFIG_PNP
-static const struct pnp_device_id el3_pnp_ids[] __devinitconst = {
+static struct pnp_device_id el3_pnp_ids[] = {
        { .id = "TCM5090" }, /* 3Com Etherlink III (TP) */
        { .id = "TCM5091" }, /* 3Com Etherlink III */
        { .id = "TCM5094" }, /* 3Com Etherlink III (combo) */
@@ -478,7 +478,7 @@ static int pnp_registered;
 #endif /* CONFIG_PNP */
 
 #ifdef CONFIG_EISA
-static const struct eisa_device_id el3_eisa_ids[] __devinitconst = {
+static struct eisa_device_id el3_eisa_ids[] = {
                { "TCM5090" },
                { "TCM5091" },
                { "TCM5092" },
@@ -508,7 +508,7 @@ static int eisa_registered;
 #ifdef CONFIG_MCA
 static int el3_mca_probe(struct device *dev);
 
-static const short el3_mca_adapter_ids[] __devinitconst = {
+static short el3_mca_adapter_ids[] __initdata = {
                0x627c,
                0x627d,
                0x62db,
@@ -517,7 +517,7 @@ static const short el3_mca_adapter_ids[] __devinitconst = {
                0x0000
 };
 
-static const char *const el3_mca_adapter_names[] __devinitconst = {
+static char *el3_mca_adapter_names[] __initdata = {
                "3Com 3c529 EtherLink III (10base2)",
                "3Com 3c529 EtherLink III (10baseT)",
                "3Com 3c529 EtherLink III (test mode)",
@@ -601,7 +601,7 @@ static void el3_common_remove (struct net_device *dev)
 }
 
 #ifdef CONFIG_MCA
-static int __devinit el3_mca_probe(struct device *device)
+static int __init el3_mca_probe(struct device *device)
 {
        /* Based on Erik Nygren's (nygren@mit.edu) 3c529 patch,
         * heavily modified by Chris Beauregard
@@ -671,7 +671,7 @@ static int __devinit el3_mca_probe(struct device *device)
 #endif /* CONFIG_MCA */
 
 #ifdef CONFIG_EISA
-static int __devinit el3_eisa_probe (struct device *device)
+static int __init el3_eisa_probe (struct device *device)
 {
        short i;
        int ioaddr, irq, if_port;
index 99f43d2..8cc2256 100644 (file)
@@ -901,14 +901,14 @@ static const struct dev_pm_ops vortex_pm_ops = {
 #endif /* !CONFIG_PM */
 
 #ifdef CONFIG_EISA
-static const struct eisa_device_id vortex_eisa_ids[] __devinitconst = {
+static struct eisa_device_id vortex_eisa_ids[] = {
        { "TCM5920", CH_3C592 },
        { "TCM5970", CH_3C597 },
        { "" }
 };
 MODULE_DEVICE_TABLE(eisa, vortex_eisa_ids);
 
-static int __devinit vortex_eisa_probe(struct device *device)
+static int __init vortex_eisa_probe(struct device *device)
 {
        void __iomem *ioaddr;
        struct eisa_device *edev;
index 10c4505..73b10b0 100644 (file)
@@ -60,6 +60,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <linux/delay.h>
index 98517a3..ed6355c 100644 (file)
 #include <linux/compiler.h>
 #include <linux/pci.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/rtnetlink.h>
index 3d9e8fb..58a12e4 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/if_ether.h>
 #include <linux/ioport.h>
+#include <linux/irqreturn.h>
 #include <linux/skbuff.h>
 
 #define TX_PAGES 12    /* Two Tx slots */
index 5181e93..f07b2e9 100644 (file)
@@ -32,6 +32,7 @@ static const char version[] =
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 
 #include <asm/system.h>
 #include <asm/io.h>
index 0681da7..fd25a3b 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef _ACENIC_H_
 #define _ACENIC_H_
+#include <linux/interrupt.h>
 
 
 /*
index 241b185..db6d2da 100644 (file)
@@ -75,6 +75,7 @@ Revision History:
 #include <linux/compiler.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/netdevice.h>
@@ -1958,7 +1959,7 @@ static int __devinit amd8111e_probe_one(struct pci_dev *pdev,
                                                 IPG_CONVERGE_JIFFIES;
                lp->ipg_data.ipg = DEFAULT_IPG;
                lp->ipg_data.ipg_state = CSTATE;
-       };
+       }
 
        /*  display driver and device information */
 
index 9efbbba..25197b6 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/netdevice.h>
 #include <linux/bootmem.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <asm/io.h>
 #include <linux/arcdevice.h>
 
index 3727282..45c61a2 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/delay.h>
 #include <linux/netdevice.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/bootmem.h>
 #include <linux/arcdevice.h>
 #include <linux/com20020.h>
index 48a1dbf..d427493 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/errno.h>
 #include <linux/netdevice.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/arcdevice.h>
 #include <linux/com20020.h>
index c9e4594..7bfb91f 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/delay.h>
 #include <linux/netdevice.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/arcdevice.h>
 #include <linux/com20020.h>
 
index eb27976..487d780 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/netdevice.h>
 #include <linux/bootmem.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <asm/io.h>
 #include <linux/arcdevice.h>
 
index f3b46f7..b80fbe4 100644 (file)
@@ -27,6 +27,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/netdevice.h>
index e07b314..29dc435 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/mii.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
index 5a77001..a167add 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/moduleparam.h>
 #include <linux/platform_device.h>
 #include <linux/delay.h>
index a7b0caa..bb62b3f 100644 (file)
@@ -21,6 +21,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 #include <linux/crc32.h>
index 925929d..dfe4370 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <linux/version.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/module.h>
index 490d3b3..9ac37e3 100644 (file)
@@ -25,6 +25,7 @@
 
 #include <linux/version.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/types.h>
 #include <linux/errno.h>
 #include <linux/module.h>
index a69331e..085560e 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
 #include <linux/ssb/ssb.h>
 #include <linux/slab.h>
index 81654ae..0c12c2d 100644 (file)
@@ -799,12 +799,12 @@ static u32 be_encoded_q_len(int q_len)
        return len_encoded;
 }
 
-int be_cmd_mccq_create(struct be_adapter *adapter,
+int be_cmd_mccq_ext_create(struct be_adapter *adapter,
                        struct be_queue_info *mccq,
                        struct be_queue_info *cq)
 {
        struct be_mcc_wrb *wrb;
-       struct be_cmd_req_mcc_create *req;
+       struct be_cmd_req_mcc_ext_create *req;
        struct be_dma_mem *q_mem = &mccq->dma_mem;
        void *ctxt;
        int status;
@@ -859,6 +859,67 @@ int be_cmd_mccq_create(struct be_adapter *adapter,
        return status;
 }
 
+int be_cmd_mccq_org_create(struct be_adapter *adapter,
+                       struct be_queue_info *mccq,
+                       struct be_queue_info *cq)
+{
+       struct be_mcc_wrb *wrb;
+       struct be_cmd_req_mcc_create *req;
+       struct be_dma_mem *q_mem = &mccq->dma_mem;
+       void *ctxt;
+       int status;
+
+       if (mutex_lock_interruptible(&adapter->mbox_lock))
+               return -1;
+
+       wrb = wrb_from_mbox(adapter);
+       req = embedded_payload(wrb);
+       ctxt = &req->context;
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0,
+                       OPCODE_COMMON_MCC_CREATE);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+                       OPCODE_COMMON_MCC_CREATE, sizeof(*req));
+
+       req->num_pages = cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
+
+       AMAP_SET_BITS(struct amap_mcc_context_be, valid, ctxt, 1);
+       AMAP_SET_BITS(struct amap_mcc_context_be, ring_size, ctxt,
+                       be_encoded_q_len(mccq->len));
+       AMAP_SET_BITS(struct amap_mcc_context_be, cq_id, ctxt, cq->id);
+
+       be_dws_cpu_to_le(ctxt, sizeof(req->context));
+
+       be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
+
+       status = be_mbox_notify_wait(adapter);
+       if (!status) {
+               struct be_cmd_resp_mcc_create *resp = embedded_payload(wrb);
+               mccq->id = le16_to_cpu(resp->id);
+               mccq->created = true;
+       }
+
+       mutex_unlock(&adapter->mbox_lock);
+       return status;
+}
+
+int be_cmd_mccq_create(struct be_adapter *adapter,
+                       struct be_queue_info *mccq,
+                       struct be_queue_info *cq)
+{
+       int status;
+
+       status = be_cmd_mccq_ext_create(adapter, mccq, cq);
+       if (status && !lancer_chip(adapter)) {
+               dev_warn(&adapter->pdev->dev, "Upgrade to F/W ver 2.102.235.0 "
+                       "or newer to avoid conflicting priorities between NIC "
+                       "and FCoE traffic");
+               status = be_cmd_mccq_org_create(adapter, mccq, cq);
+       }
+       return status;
+}
+
 int be_cmd_txq_create(struct be_adapter *adapter,
                        struct be_queue_info *txq,
                        struct be_queue_info *cq)
index 8148cc6..d08289e 100644 (file)
@@ -431,6 +431,14 @@ struct amap_mcc_context_lancer {
 } __packed;
 
 struct be_cmd_req_mcc_create {
+       struct be_cmd_req_hdr hdr;
+       u16 num_pages;
+       u16 cq_id;
+       u8 context[sizeof(struct amap_mcc_context_be) / 8];
+       struct phys_addr pages[8];
+} __packed;
+
+struct be_cmd_req_mcc_ext_create {
        struct be_cmd_req_hdr hdr;
        u16 num_pages;
        u16 cq_id;
index a485f7f..9ba197b 100644 (file)
@@ -362,8 +362,8 @@ static void populate_lancer_stats(struct be_adapter *adapter)
        drvs->rx_priority_pause_frames = 0;
        drvs->pmem_fifo_overflow_drop = 0;
        drvs->rx_pause_frames =
-               make_64bit_val(pport_stats->rx_pause_frames_lo,
-                                pport_stats->rx_pause_frames_hi);
+               make_64bit_val(pport_stats->rx_pause_frames_hi,
+                                pport_stats->rx_pause_frames_lo);
        drvs->rx_crc_errors = make_64bit_val(pport_stats->rx_crc_errors_hi,
                                                pport_stats->rx_crc_errors_lo);
        drvs->rx_control_frames =
@@ -3396,6 +3396,11 @@ static int __devinit be_probe(struct pci_dev *pdev,
        }
 
        dev_info(&pdev->dev, "%s port %d\n", nic_name(pdev), adapter->port_num);
+       /* By default all priorities are enabled.
+        * Needed in case of no GRP5 evt support
+        */
+       adapter->vlan_prio_bmap = 0xff;
+
        schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
        return 0;
 
index a1b8c8b..d2e58e2 100644 (file)
@@ -7,6 +7,7 @@
  * May 1999, Al Viro: proper release of /proc/net/bmac entry, switched to
  * dynamic procfs inode.
  */
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
index 57d3293..74580bb 100644 (file)
@@ -416,6 +416,9 @@ struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev)
        struct bnx2 *bp = netdev_priv(dev);
        struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
 
+       if (!cp->max_iscsi_conn)
+               return NULL;
+
        cp->drv_owner = THIS_MODULE;
        cp->chip_id = bp->chip_id;
        cp->pdev = bp->pdev;
@@ -8177,6 +8180,10 @@ bnx2_init_board(struct pci_dev *pdev, struct net_device *dev)
        bp->timer.data = (unsigned long) bp;
        bp->timer.function = bnx2_timer;
 
+#ifdef BCM_CNIC
+       bp->cnic_eth_dev.max_iscsi_conn =
+               bnx2_reg_rd_ind(bp, BNX2_FW_MAX_ISCSI_CONN);
+#endif
        pci_save_state(pdev);
 
        return 0;
index 668a578..480e02d 100644 (file)
@@ -1492,7 +1492,7 @@ void bnx2x_invalidate_e1h_mc_list(struct bnx2x *bp);
 void bnx2x_invalidate_uc_list(struct bnx2x *bp);
 
 void bnx2x_update_coalesce(struct bnx2x *bp);
-int bnx2x_get_link_cfg_idx(struct bnx2x *bp);
+int bnx2x_get_cur_phy_idx(struct bnx2x *bp);
 
 static inline u32 reg_poll(struct bnx2x *bp, u32 reg, u32 expected, int ms,
                           int wait)
index 2890443..831c6ec 100644 (file)
@@ -17,6 +17,7 @@
 
 #include <linux/etherdevice.h>
 #include <linux/if_vlan.h>
+#include <linux/interrupt.h>
 #include <linux/ip.h>
 #include <net/ipv6.h>
 #include <net/ip6_checksum.h>
@@ -2803,6 +2804,55 @@ static int bnx2x_reload_if_running(struct net_device *dev)
        return bnx2x_nic_load(bp, LOAD_NORMAL);
 }
 
+int bnx2x_get_cur_phy_idx(struct bnx2x *bp)
+{
+       u32 sel_phy_idx = 0;
+       if (bp->link_params.num_phys <= 1)
+               return INT_PHY;
+
+       if (bp->link_vars.link_up) {
+               sel_phy_idx = EXT_PHY1;
+               /* In case link is SERDES, check if the EXT_PHY2 is the one */
+               if ((bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) &&
+                   (bp->link_params.phy[EXT_PHY2].supported & SUPPORTED_FIBRE))
+                       sel_phy_idx = EXT_PHY2;
+       } else {
+
+               switch (bnx2x_phy_selection(&bp->link_params)) {
+               case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
+               case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
+               case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
+                      sel_phy_idx = EXT_PHY1;
+                      break;
+               case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
+               case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
+                      sel_phy_idx = EXT_PHY2;
+                      break;
+               }
+       }
+
+       return sel_phy_idx;
+
+}
+int bnx2x_get_link_cfg_idx(struct bnx2x *bp)
+{
+       u32 sel_phy_idx = bnx2x_get_cur_phy_idx(bp);
+       /*
+        * The selected actived PHY is always after swapping (in case PHY
+        * swapping is enabled). So when swapping is enabled, we need to reverse
+        * the configuration
+        */
+
+       if (bp->link_params.multi_phy_config &
+           PORT_HW_CFG_PHY_SWAPPED_ENABLED) {
+               if (sel_phy_idx == EXT_PHY1)
+                       sel_phy_idx = EXT_PHY2;
+               else if (sel_phy_idx == EXT_PHY2)
+                       sel_phy_idx = EXT_PHY1;
+       }
+       return LINK_CONFIG_IDX(sel_phy_idx);
+}
+
 /* called with rtnl_lock */
 int bnx2x_change_mtu(struct net_device *dev, int new_mtu)
 {
index 1a3545b..19f8638 100644 (file)
@@ -1063,6 +1063,8 @@ static inline void bnx2x_init_fcoe_fp(struct bnx2x *bp)
 }
 #endif
 
+int bnx2x_get_link_cfg_idx(struct bnx2x *bp);
+
 static inline void __storm_memset_struct(struct bnx2x *bp,
                                         u32 addr, size_t size, u32 *data)
 {
index 727fe89..2957353 100644 (file)
@@ -162,6 +162,33 @@ static const struct {
 };
 
 #define BNX2X_NUM_STATS                ARRAY_SIZE(bnx2x_stats_arr)
+static int bnx2x_get_port_type(struct bnx2x *bp)
+{
+       int port_type;
+       u32 phy_idx = bnx2x_get_cur_phy_idx(bp);
+       switch (bp->link_params.phy[phy_idx].media_type) {
+       case ETH_PHY_SFP_FIBER:
+       case ETH_PHY_XFP_FIBER:
+       case ETH_PHY_KR:
+       case ETH_PHY_CX4:
+               port_type = PORT_FIBRE;
+               break;
+       case ETH_PHY_DA_TWINAX:
+               port_type = PORT_DA;
+               break;
+       case ETH_PHY_BASE_T:
+               port_type = PORT_TP;
+               break;
+       case ETH_PHY_NOT_PRESENT:
+               port_type = PORT_NONE;
+               break;
+       case ETH_PHY_UNSPECIFIED:
+       default:
+               port_type = PORT_OTHER;
+               break;
+       }
+       return port_type;
+}
 
 static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
@@ -188,12 +215,7 @@ static int bnx2x_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        if (IS_MF(bp))
                ethtool_cmd_speed_set(cmd, bnx2x_get_mf_speed(bp));
 
-       if (bp->port.supported[cfg_idx] & SUPPORTED_TP)
-               cmd->port = PORT_TP;
-       else if (bp->port.supported[cfg_idx] & SUPPORTED_FIBRE)
-               cmd->port = PORT_FIBRE;
-       else
-               BNX2X_ERR("XGXS PHY Failure detected\n");
+       cmd->port = bnx2x_get_port_type(bp);
 
        cmd->phy_address = bp->mdio.prtad;
        cmd->transceiver = XCVR_INTERNAL;
index cdf19fe..b8b4b2f 100644 (file)
@@ -263,7 +263,20 @@ struct port_hw_cfg {                           /* port 0: 0x12c  port 1: 0x2bc */
 #define PORT_HW_CFG_FAULT_MODULE_LED_GPIO2                   0x00000200
 #define PORT_HW_CFG_FAULT_MODULE_LED_GPIO3                   0x00000300
 #define PORT_HW_CFG_FAULT_MODULE_LED_DISABLED                0x00000400
-       u32 Reserved01[12];                                 /* 0x158 */
+
+       u32 Reserved01[10];                                 /* 0x158 */
+
+       u32 aeu_int_mask;                                       /* 0x190 */
+
+       u32 media_type;                                 /* 0x194 */
+#define PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK                     0x000000FF
+#define PORT_HW_CFG_MEDIA_TYPE_PHY0_SHIFT                    0
+
+#define PORT_HW_CFG_MEDIA_TYPE_PHY1_MASK                     0x0000FF00
+#define PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT                    8
+
+#define PORT_HW_CFG_MEDIA_TYPE_PHY2_MASK                     0x00FF0000
+#define PORT_HW_CFG_MEDIA_TYPE_PHY2_SHIFT                    16
        /*  for external PHY, or forced mode or during AN */
        u16 xgxs_config_rx[4];                              /* 0x198 */
 
@@ -417,6 +430,7 @@ struct port_hw_cfg {                            /* port 0: 0x12c  port 1: 0x2bc */
 #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM84823     0x00000b00
 #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM54640     0x00000c00
 #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM84833     0x00000d00
+#define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_BCM8722     0x00000f00
 #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_FAILURE     0x0000fd00
 #define PORT_HW_CFG_XGXS_EXT_PHY2_TYPE_NOT_CONN     0x0000ff00
 
@@ -453,6 +467,7 @@ struct port_hw_cfg {                            /* port 0: 0x12c  port 1: 0x2bc */
 #define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_SHIFT      24
 #define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT     0x00000000
 #define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_BCM5482     0x01000000
+#define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT_SD   0x02000000
 #define PORT_HW_CFG_SERDES_EXT_PHY_TYPE_NOT_CONN    0xff000000
 
 #define PORT_HW_CFG_SERDES_EXT_PHY_ADDR_MASK       0x00ff0000
@@ -473,6 +488,7 @@ struct port_hw_cfg {                            /* port 0: 0x12c  port 1: 0x2bc */
 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC   0x00000a00
 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823     0x00000b00
 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833     0x00000d00
+#define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722      0x00000f00
 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_FAILURE      0x0000fd00
 #define PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN     0x0000ff00
 
index 076e11f..15b5bc1 100644 (file)
@@ -342,7 +342,7 @@ void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw,
        REG_WR(bp, PBF_REG_COS1_WEIGHT, cos1_credit_weight);
 }
 
-u8 bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos)
+int bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos)
 {
        /* ETS disabled configuration*/
        struct bnx2x *bp = params->bp;
@@ -464,6 +464,29 @@ void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars,
 /******************************************************************/
 /*                     MAC/PBF section                           */
 /******************************************************************/
+static void bnx2x_set_mdio_clk(struct bnx2x *bp, u32 chip_id, u8 port)
+{
+       u32 mode, emac_base;
+       /**
+        * Set clause 45 mode, slow down the MDIO clock to 2.5MHz
+        * (a value of 49==0x31) and make sure that the AUTO poll is off
+        */
+
+       if (CHIP_IS_E2(bp))
+               emac_base = GRCBASE_EMAC0;
+       else
+               emac_base = (port) ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
+       mode = REG_RD(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE);
+       mode &= ~(EMAC_MDIO_MODE_AUTO_POLL |
+                 EMAC_MDIO_MODE_CLOCK_CNT);
+       mode |= (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT);
+
+       mode |= (EMAC_MDIO_MODE_CLAUSE_45);
+       REG_WR(bp, emac_base + EMAC_REG_EMAC_MDIO_MODE, mode);
+
+       udelay(40);
+}
+
 static void bnx2x_emac_init(struct link_params *params,
                            struct link_vars *vars)
 {
@@ -495,7 +518,7 @@ static void bnx2x_emac_init(struct link_params *params,
                }
                timeout--;
        } while (val & EMAC_MODE_RESET);
-
+       bnx2x_set_mdio_clk(bp, params->chip_id, port);
        /* Set mac address */
        val = ((params->mac_addr[0] << 8) |
                params->mac_addr[1]);
@@ -508,8 +531,8 @@ static void bnx2x_emac_init(struct link_params *params,
        EMAC_WR(bp, EMAC_REG_EMAC_MAC_MATCH + 4, val);
 }
 
-static u8 bnx2x_emac_enable(struct link_params *params,
-                           struct link_vars *vars, u8 lb)
+static int bnx2x_emac_enable(struct link_params *params,
+                            struct link_vars *vars, u8 lb)
 {
        struct bnx2x *bp = params->bp;
        u8 port = params->port;
@@ -1002,9 +1025,9 @@ void bnx2x_update_pfc(struct link_params *params,
        REG_WR(bp, NIG_REG_BMAC0_PAUSE_OUT_EN + params->port*4, val);
 }
 
-static u8 bnx2x_bmac1_enable(struct link_params *params,
-                            struct link_vars *vars,
-                            u8 is_lb)
+static int bnx2x_bmac1_enable(struct link_params *params,
+                             struct link_vars *vars,
+                             u8 is_lb)
 {
        struct bnx2x *bp = params->bp;
        u8 port = params->port;
@@ -1066,9 +1089,9 @@ static u8 bnx2x_bmac1_enable(struct link_params *params,
        return 0;
 }
 
-static u8 bnx2x_bmac2_enable(struct link_params *params,
-                            struct link_vars *vars,
-                            u8 is_lb)
+static int bnx2x_bmac2_enable(struct link_params *params,
+                             struct link_vars *vars,
+                             u8 is_lb)
 {
        struct bnx2x *bp = params->bp;
        u8 port = params->port;
@@ -1131,11 +1154,12 @@ static u8 bnx2x_bmac2_enable(struct link_params *params,
        return 0;
 }
 
-static u8 bnx2x_bmac_enable(struct link_params *params,
-                           struct link_vars *vars,
-                           u8 is_lb)
+static int bnx2x_bmac_enable(struct link_params *params,
+                            struct link_vars *vars,
+                            u8 is_lb)
 {
-       u8 rc, port = params->port;
+       int rc = 0;
+       u8 port = params->port;
        struct bnx2x *bp = params->bp;
        u32 val;
        /* reset and unreset the BigMac */
@@ -1218,8 +1242,8 @@ static void bnx2x_bmac_rx_disable(struct bnx2x *bp, u8 port)
        }
 }
 
-static u8 bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
-                          u32 line_speed)
+static int bnx2x_pbf_update(struct link_params *params, u32 flow_ctrl,
+                           u32 line_speed)
 {
        struct bnx2x *bp = params->bp;
        u8 port = params->port;
@@ -1351,149 +1375,119 @@ static u32 bnx2x_get_emac_base(struct bnx2x *bp,
 /******************************************************************/
 /*                     CL45 access functions                     */
 /******************************************************************/
-static u8 bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
-                          u8 devad, u16 reg, u16 val)
+static int bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
+                          u8 devad, u16 reg, u16 *ret_val)
 {
-       u32 tmp, saved_mode;
-       u8 i, rc = 0;
-       /*
-        * Set clause 45 mode, slow down the MDIO clock to 2.5MHz
-        * (a value of 49==0x31) and make sure that the AUTO poll is off
-        */
-
-       saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
-       tmp = saved_mode & ~(EMAC_MDIO_MODE_AUTO_POLL |
-                            EMAC_MDIO_MODE_CLOCK_CNT);
-       tmp |= (EMAC_MDIO_MODE_CLAUSE_45 |
-               (49 << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
-       REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, tmp);
-       REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
-       udelay(40);
+       u32 val;
+       u16 i;
+       int rc = 0;
 
        /* address */
-
-       tmp = ((phy->addr << 21) | (devad << 16) | reg |
+       val = ((phy->addr << 21) | (devad << 16) | reg |
               EMAC_MDIO_COMM_COMMAND_ADDRESS |
               EMAC_MDIO_COMM_START_BUSY);
-       REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
+       REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
 
        for (i = 0; i < 50; i++) {
                udelay(10);
 
-               tmp = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
-               if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
+               val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
+               if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
                        udelay(5);
                        break;
                }
        }
-       if (tmp & EMAC_MDIO_COMM_START_BUSY) {
-               DP(NETIF_MSG_LINK, "write phy register failed\n");
+       if (val & EMAC_MDIO_COMM_START_BUSY) {
+               DP(NETIF_MSG_LINK, "read phy register failed\n");
                netdev_err(bp->dev,  "MDC/MDIO access timeout\n");
+               *ret_val = 0;
                rc = -EFAULT;
        } else {
                /* data */
-               tmp = ((phy->addr << 21) | (devad << 16) | val |
-                      EMAC_MDIO_COMM_COMMAND_WRITE_45 |
+               val = ((phy->addr << 21) | (devad << 16) |
+                      EMAC_MDIO_COMM_COMMAND_READ_45 |
                       EMAC_MDIO_COMM_START_BUSY);
-               REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
+               REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
 
                for (i = 0; i < 50; i++) {
                        udelay(10);
 
-                       tmp = REG_RD(bp, phy->mdio_ctrl +
+                       val = REG_RD(bp, phy->mdio_ctrl +
                                     EMAC_REG_EMAC_MDIO_COMM);
-                       if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
-                               udelay(5);
+                       if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
+                               *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
                                break;
                        }
                }
-               if (tmp & EMAC_MDIO_COMM_START_BUSY) {
-                       DP(NETIF_MSG_LINK, "write phy register failed\n");
+               if (val & EMAC_MDIO_COMM_START_BUSY) {
+                       DP(NETIF_MSG_LINK, "read phy register failed\n");
                        netdev_err(bp->dev,  "MDC/MDIO access timeout\n");
+                       *ret_val = 0;
                        rc = -EFAULT;
                }
        }
 
-       /* Restore the saved mode */
-       REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
-
        return rc;
 }
 
-static u8 bnx2x_cl45_read(struct bnx2x *bp, struct bnx2x_phy *phy,
-                         u8 devad, u16 reg, u16 *ret_val)
+static int bnx2x_cl45_write(struct bnx2x *bp, struct bnx2x_phy *phy,
+                           u8 devad, u16 reg, u16 val)
 {
-       u32 val, saved_mode;
-       u16 i;
-       u8 rc = 0;
-       /*
-        * Set clause 45 mode, slow down the MDIO clock to 2.5MHz
-        * (a value of 49==0x31) and make sure that the AUTO poll is off
-        */
-
-       saved_mode = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
-       val = saved_mode & ~((EMAC_MDIO_MODE_AUTO_POLL |
-                             EMAC_MDIO_MODE_CLOCK_CNT));
-       val |= (EMAC_MDIO_MODE_CLAUSE_45 |
-               (49L << EMAC_MDIO_MODE_CLOCK_CNT_BITSHIFT));
-       REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, val);
-       REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE);
-       udelay(40);
+       u32 tmp;
+       u8 i;
+       int rc = 0;
 
        /* address */
-       val = ((phy->addr << 21) | (devad << 16) | reg |
+
+       tmp = ((phy->addr << 21) | (devad << 16) | reg |
               EMAC_MDIO_COMM_COMMAND_ADDRESS |
               EMAC_MDIO_COMM_START_BUSY);
-       REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
+       REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
 
        for (i = 0; i < 50; i++) {
                udelay(10);
 
-               val = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
-               if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
+               tmp = REG_RD(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM);
+               if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
                        udelay(5);
                        break;
                }
        }
-       if (val & EMAC_MDIO_COMM_START_BUSY) {
-               DP(NETIF_MSG_LINK, "read phy register failed\n");
+       if (tmp & EMAC_MDIO_COMM_START_BUSY) {
+               DP(NETIF_MSG_LINK, "write phy register failed\n");
                netdev_err(bp->dev,  "MDC/MDIO access timeout\n");
-               *ret_val = 0;
                rc = -EFAULT;
 
        } else {
                /* data */
-               val = ((phy->addr << 21) | (devad << 16) |
-                      EMAC_MDIO_COMM_COMMAND_READ_45 |
+               tmp = ((phy->addr << 21) | (devad << 16) | val |
+                      EMAC_MDIO_COMM_COMMAND_WRITE_45 |
                       EMAC_MDIO_COMM_START_BUSY);
-               REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, val);
+               REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_COMM, tmp);
 
                for (i = 0; i < 50; i++) {
                        udelay(10);
 
-                       val = REG_RD(bp, phy->mdio_ctrl +
+                       tmp = REG_RD(bp, phy->mdio_ctrl +
                                     EMAC_REG_EMAC_MDIO_COMM);
-                       if (!(val & EMAC_MDIO_COMM_START_BUSY)) {
-                               *ret_val = (u16)(val & EMAC_MDIO_COMM_DATA);
+                       if (!(tmp & EMAC_MDIO_COMM_START_BUSY)) {
+                               udelay(5);
                                break;
                        }
                }
-               if (val & EMAC_MDIO_COMM_START_BUSY) {
-                       DP(NETIF_MSG_LINK, "read phy register failed\n");
+               if (tmp & EMAC_MDIO_COMM_START_BUSY) {
+                       DP(NETIF_MSG_LINK, "write phy register failed\n");
                        netdev_err(bp->dev,  "MDC/MDIO access timeout\n");
-                       *ret_val = 0;
                        rc = -EFAULT;
                }
        }
 
-       /* Restore the saved mode */
-       REG_WR(bp, phy->mdio_ctrl + EMAC_REG_EMAC_MDIO_MODE, saved_mode);
 
        return rc;
 }
 
-u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr,
-                 u8 devad, u16 reg, u16 *ret_val)
+int bnx2x_phy_read(struct link_params *params, u8 phy_addr,
+                  u8 devad, u16 reg, u16 *ret_val)
 {
        u8 phy_index;
        /*
@@ -1510,8 +1504,8 @@ u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr,
        return -EINVAL;
 }
 
-u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr,
-                  u8 devad, u16 reg, u16 val)
+int bnx2x_phy_write(struct link_params *params, u8 phy_addr,
+                   u8 devad, u16 reg, u16 val)
 {
        u8 phy_index;
        /*
@@ -1528,8 +1522,8 @@ u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr,
        return -EINVAL;
 }
 
-static void bnx2x_set_aer_mmd_xgxs(struct link_params *params,
-                                  struct bnx2x_phy *phy)
+static void bnx2x_set_aer_mmd(struct link_params *params,
+                             struct bnx2x_phy *phy)
 {
        u32 ser_lane;
        u16 offset, aer_val;
@@ -1538,20 +1532,17 @@ static void bnx2x_set_aer_mmd_xgxs(struct link_params *params,
                     PORT_HW_CFG_LANE_SWAP_CFG_MASTER_MASK) >>
                     PORT_HW_CFG_LANE_SWAP_CFG_MASTER_SHIFT);
 
-       offset = phy->addr + ser_lane;
+       offset = (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ?
+               (phy->addr + ser_lane) : 0;
+
        if (CHIP_IS_E2(bp))
                aer_val = 0x3800 + offset - 1;
        else
                aer_val = 0x3800 + offset;
+       DP(NETIF_MSG_LINK, "Set AER to 0x%x\n", aer_val);
        CL22_WR_OVER_CL45(bp, phy, MDIO_REG_BANK_AER_BLOCK,
                          MDIO_AER_BLOCK_AER_REG, aer_val);
-}
-static void bnx2x_set_aer_mmd_serdes(struct bnx2x *bp,
-                                    struct bnx2x_phy *phy)
-{
-       CL22_WR_OVER_CL45(bp, phy,
-                         MDIO_REG_BANK_AER_BLOCK,
-                         MDIO_AER_BLOCK_AER_REG, 0x3800);
+
 }
 
 /******************************************************************/
@@ -1611,20 +1602,188 @@ static void bnx2x_xgxs_deassert(struct link_params *params)
               params->phy[INT_PHY].def_md_devad);
 }
 
+static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
+                                    struct link_params *params, u16 *ieee_fc)
+{
+       struct bnx2x *bp = params->bp;
+       *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
+       /**
+        * resolve pause mode and advertisement Please refer to Table
+        * 28B-3 of the 802.3ab-1999 spec
+        */
+
+       switch (phy->req_flow_ctrl) {
+       case BNX2X_FLOW_CTRL_AUTO:
+               if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH)
+                       *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
+               else
+                       *ieee_fc |=
+                       MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
+               break;
+
+       case BNX2X_FLOW_CTRL_TX:
+               *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
+               break;
+
+       case BNX2X_FLOW_CTRL_RX:
+       case BNX2X_FLOW_CTRL_BOTH:
+               *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
+               break;
+
+       case BNX2X_FLOW_CTRL_NONE:
+       default:
+               *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
+               break;
+       }
+       DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
+}
+
+static void set_phy_vars(struct link_params *params,
+                        struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       u8 actual_phy_idx, phy_index, link_cfg_idx;
+       u8 phy_config_swapped = params->multi_phy_config &
+                       PORT_HW_CFG_PHY_SWAPPED_ENABLED;
+       for (phy_index = INT_PHY; phy_index < params->num_phys;
+             phy_index++) {
+               link_cfg_idx = LINK_CONFIG_IDX(phy_index);
+               actual_phy_idx = phy_index;
+               if (phy_config_swapped) {
+                       if (phy_index == EXT_PHY1)
+                               actual_phy_idx = EXT_PHY2;
+                       else if (phy_index == EXT_PHY2)
+                               actual_phy_idx = EXT_PHY1;
+               }
+               params->phy[actual_phy_idx].req_flow_ctrl =
+                       params->req_flow_ctrl[link_cfg_idx];
+
+               params->phy[actual_phy_idx].req_line_speed =
+                       params->req_line_speed[link_cfg_idx];
+
+               params->phy[actual_phy_idx].speed_cap_mask =
+                       params->speed_cap_mask[link_cfg_idx];
+
+               params->phy[actual_phy_idx].req_duplex =
+                       params->req_duplex[link_cfg_idx];
+
+               if (params->req_line_speed[link_cfg_idx] ==
+                   SPEED_AUTO_NEG)
+                       vars->link_status |= LINK_STATUS_AUTO_NEGOTIATE_ENABLED;
 
+               DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
+                          " speed_cap_mask %x\n",
+                          params->phy[actual_phy_idx].req_flow_ctrl,
+                          params->phy[actual_phy_idx].req_line_speed,
+                          params->phy[actual_phy_idx].speed_cap_mask);
+       }
+}
+
+static void bnx2x_ext_phy_set_pause(struct link_params *params,
+                                   struct bnx2x_phy *phy,
+                                   struct link_vars *vars)
+{
+       u16 val;
+       struct bnx2x *bp = params->bp;
+       /* read modify write pause advertizing */
+       bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
+
+       val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
+
+       /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
+       bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
+       if ((vars->ieee_fc &
+           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
+           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
+               val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
+       }
+       if ((vars->ieee_fc &
+           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
+           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
+               val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
+       }
+       DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val);
+       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val);
+}
+
+static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
+{                                              /*  LD      LP   */
+       switch (pause_result) {                 /* ASYM P ASYM P */
+       case 0xb:                               /*   1  0   1  1 */
+               vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
+               break;
+
+       case 0xe:                               /*   1  1   1  0 */
+               vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
+               break;
+
+       case 0x5:                               /*   0  1   0  1 */
+       case 0x7:                               /*   0  1   1  1 */
+       case 0xd:                               /*   1  1   0  1 */
+       case 0xf:                               /*   1  1   1  1 */
+               vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
+               break;
+
+       default:
+               break;
+       }
+       if (pause_result & (1<<0))
+               vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE;
+       if (pause_result & (1<<1))
+               vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
+}
+
+static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
+                                  struct link_params *params,
+                                  struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       u16 ld_pause;           /* local */
+       u16 lp_pause;           /* link partner */
+       u16 pause_result;
+       u8 ret = 0;
+       /* read twice */
+
+       vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+
+       if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
+               vars->flow_ctrl = phy->req_flow_ctrl;
+       else if (phy->req_line_speed != SPEED_AUTO_NEG)
+               vars->flow_ctrl = params->req_fc_auto_adv;
+       else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
+               ret = 1;
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_AN_DEVAD,
+                               MDIO_AN_REG_ADV_PAUSE, &ld_pause);
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_AN_DEVAD,
+                               MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
+               pause_result = (ld_pause &
+                               MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
+               pause_result |= (lp_pause &
+                                MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
+               DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
+                  pause_result);
+               bnx2x_pause_resolve(vars, pause_result);
+       }
+       return ret;
+}
 void bnx2x_link_status_update(struct link_params *params,
                              struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        u8 link_10g;
        u8 port = params->port;
+       u32 sync_offset, media_types;
+       /* Update PHY configuration */
+       set_phy_vars(params, vars);
 
        vars->link_status = REG_RD(bp, params->shmem_base +
                                   offsetof(struct shmem_region,
                                            port_mb[port].link_status));
 
        vars->link_up = (vars->link_status & LINK_STATUS_LINK_UP);
-
+       vars->phy_flags = PHY_XGXS_FLAG;
        if (vars->link_up) {
                DP(NETIF_MSG_LINK, "phy link up\n");
 
@@ -1731,8 +1890,32 @@ void bnx2x_link_status_update(struct link_params *params,
                vars->mac_type = MAC_TYPE_NONE;
        }
 
-       DP(NETIF_MSG_LINK, "link_status 0x%x  phy_link_up %x\n",
-                vars->link_status, vars->phy_link_up);
+       /* Sync media type */
+       sync_offset = params->shmem_base +
+                       offsetof(struct shmem_region,
+                                dev_info.port_hw_config[port].media_type);
+       media_types = REG_RD(bp, sync_offset);
+
+       params->phy[INT_PHY].media_type =
+               (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) >>
+               PORT_HW_CFG_MEDIA_TYPE_PHY0_SHIFT;
+       params->phy[EXT_PHY1].media_type =
+               (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY1_MASK) >>
+               PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT;
+       params->phy[EXT_PHY2].media_type =
+               (media_types & PORT_HW_CFG_MEDIA_TYPE_PHY2_MASK) >>
+               PORT_HW_CFG_MEDIA_TYPE_PHY2_SHIFT;
+       DP(NETIF_MSG_LINK, "media_types = 0x%x\n", media_types);
+
+       /* Sync AEU offset */
+       sync_offset = params->shmem_base +
+                       offsetof(struct shmem_region,
+                                dev_info.port_hw_config[port].aeu_int_mask);
+
+       vars->aeu_int_mask = REG_RD(bp, sync_offset);
+
+       DP(NETIF_MSG_LINK, "link_status 0x%x  phy_link_up %x int_mask 0x%x\n",
+                vars->link_status, vars->phy_link_up, vars->aeu_int_mask);
        DP(NETIF_MSG_LINK, "line_speed %x  duplex %x  flow_ctrl 0x%x\n",
                 vars->line_speed, vars->duplex, vars->flow_ctrl);
 }
@@ -1759,9 +1942,9 @@ static void bnx2x_set_master_ln(struct link_params *params,
                          (new_master_ln | ser_lane));
 }
 
-static u8 bnx2x_reset_unicore(struct link_params *params,
-                             struct bnx2x_phy *phy,
-                             u8 set_serdes)
+static int bnx2x_reset_unicore(struct link_params *params,
+                              struct bnx2x_phy *phy,
+                              u8 set_serdes)
 {
        struct bnx2x *bp = params->bp;
        u16 mii_control;
@@ -2059,8 +2242,8 @@ static void bnx2x_program_serdes(struct bnx2x_phy *phy,
 
 }
 
-static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x_phy *phy,
-                                            struct link_params *params)
+static void bnx2x_set_brcm_cl37_advertisement(struct bnx2x_phy *phy,
+                                             struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
        u16 val = 0;
@@ -2081,44 +2264,9 @@ static void bnx2x_set_brcm_cl37_advertisment(struct bnx2x_phy *phy,
                          MDIO_OVER_1G_UP3, 0x400);
 }
 
-static void bnx2x_calc_ieee_aneg_adv(struct bnx2x_phy *phy,
-                                    struct link_params *params, u16 *ieee_fc)
-{
-       struct bnx2x *bp = params->bp;
-       *ieee_fc = MDIO_COMBO_IEEE0_AUTO_NEG_ADV_FULL_DUPLEX;
-       /*
-        * Resolve pause mode and advertisement.
-        * Please refer to Table 28B-3 of the 802.3ab-1999 spec
-        */
-
-       switch (phy->req_flow_ctrl) {
-       case BNX2X_FLOW_CTRL_AUTO:
-               if (params->req_fc_auto_adv == BNX2X_FLOW_CTRL_BOTH)
-                       *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
-               else
-                       *ieee_fc |=
-                       MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
-               break;
-       case BNX2X_FLOW_CTRL_TX:
-               *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC;
-               break;
-
-       case BNX2X_FLOW_CTRL_RX:
-       case BNX2X_FLOW_CTRL_BOTH:
-               *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH;
-               break;
-
-       case BNX2X_FLOW_CTRL_NONE:
-       default:
-               *ieee_fc |= MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_NONE;
-               break;
-       }
-       DP(NETIF_MSG_LINK, "ieee_fc = 0x%x\n", *ieee_fc);
-}
-
-static void bnx2x_set_ieee_aneg_advertisment(struct bnx2x_phy *phy,
-                                            struct link_params *params,
-                                            u16 ieee_fc)
+static void bnx2x_set_ieee_aneg_advertisement(struct bnx2x_phy *phy,
+                                             struct link_params *params,
+                                             u16 ieee_fc)
 {
        struct bnx2x *bp = params->bp;
        u16 val;
@@ -2248,39 +2396,12 @@ static void bnx2x_initialize_sgmii_process(struct bnx2x_phy *phy,
 }
 
 
-/*
- * link management
- */
-
-static void bnx2x_pause_resolve(struct link_vars *vars, u32 pause_result)
-{                                              /*  LD      LP   */
-       switch (pause_result) {                 /* ASYM P ASYM P */
-       case 0xb:                               /*   1  0   1  1 */
-               vars->flow_ctrl = BNX2X_FLOW_CTRL_TX;
-               break;
-
-       case 0xe:                               /*   1  1   1  0 */
-               vars->flow_ctrl = BNX2X_FLOW_CTRL_RX;
-               break;
-
-       case 0x5:                               /*   0  1   0  1 */
-       case 0x7:                               /*   0  1   1  1 */
-       case 0xd:                               /*   1  1   0  1 */
-       case 0xf:                               /*   1  1   1  1 */
-               vars->flow_ctrl = BNX2X_FLOW_CTRL_BOTH;
-               break;
-
-       default:
-               break;
-       }
-       if (pause_result & (1<<0))
-               vars->link_status |= LINK_STATUS_LINK_PARTNER_SYMMETRIC_PAUSE;
-       if (pause_result & (1<<1))
-               vars->link_status |= LINK_STATUS_LINK_PARTNER_ASYMMETRIC_PAUSE;
-}
-
-static u8 bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
-                                           struct link_params *params)
+/*
+ * link management
+ */
+
+static int bnx2x_direct_parallel_detect_used(struct bnx2x_phy *phy,
+                                            struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
        u16 pd_10g, status2_1000x;
@@ -2383,7 +2504,7 @@ static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
                                         struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
-       u16 rx_status, ustat_val, cl37_fsm_recieved;
+       u16 rx_status, ustat_val, cl37_fsm_received;
        DP(NETIF_MSG_LINK, "bnx2x_check_fallback_to_cl37\n");
        /* Step 1: Make sure signal is detected */
        CL22_RD_OVER_CL45(bp, phy,
@@ -2421,15 +2542,15 @@ static void bnx2x_check_fallback_to_cl37(struct bnx2x_phy *phy,
        CL22_RD_OVER_CL45(bp, phy,
                          MDIO_REG_BANK_REMOTE_PHY,
                          MDIO_REMOTE_PHY_MISC_RX_STATUS,
-                         &cl37_fsm_recieved);
-       if ((cl37_fsm_recieved &
+                         &cl37_fsm_received);
+       if ((cl37_fsm_received &
             (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
             MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) !=
            (MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_OVER1G_MSG |
              MDIO_REMOTE_PHY_MISC_RX_STATUS_CL37_FSM_RECEIVED_BRCM_OUI_MSG)) {
                DP(NETIF_MSG_LINK, "No CL37 FSM were received. "
                             "misc_rx_status(0x8330) = 0x%x\n",
-                        cl37_fsm_recieved);
+                        cl37_fsm_received);
                return;
        }
        /*
@@ -2463,13 +2584,13 @@ static void bnx2x_xgxs_an_resolve(struct bnx2x_phy *phy,
                        LINK_STATUS_PARALLEL_DETECTION_USED;
 }
 
-static u8 bnx2x_link_settings_status(struct bnx2x_phy *phy,
-                                    struct link_params *params,
-                                    struct link_vars *vars)
+static int bnx2x_link_settings_status(struct bnx2x_phy *phy,
+                                     struct link_params *params,
+                                     struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        u16 new_line_speed, gp_status;
-       u8 rc = 0;
+       int rc = 0;
 
        /* Read gp_status */
        CL22_RD_OVER_CL45(bp, phy,
@@ -2642,8 +2763,8 @@ static void bnx2x_set_gmii_tx_driver(struct link_params *params)
        }
 }
 
-static u8 bnx2x_emac_program(struct link_params *params,
-                            struct link_vars *vars)
+static int bnx2x_emac_program(struct link_params *params,
+                             struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        u8 port = params->port;
@@ -2713,9 +2834,9 @@ static void bnx2x_set_preemphasis(struct bnx2x_phy *phy,
        }
 }
 
-static void bnx2x_init_internal_phy(struct bnx2x_phy *phy,
-                                   struct link_params *params,
-                                   struct link_vars *vars)
+static void bnx2x_xgxs_config_init(struct bnx2x_phy *phy,
+                                  struct link_params *params,
+                                  struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        u8 enable_cl73 = (SINGLE_MEDIA_DIRECT(params) ||
@@ -2742,11 +2863,11 @@ static void bnx2x_init_internal_phy(struct bnx2x_phy *phy,
                        DP(NETIF_MSG_LINK, "not SGMII, AN\n");
 
                        /* AN enabled */
-                       bnx2x_set_brcm_cl37_advertisment(phy, params);
+                       bnx2x_set_brcm_cl37_advertisement(phy, params);
 
                        /* program duplex & pause advertisement (for aneg) */
-                       bnx2x_set_ieee_aneg_advertisment(phy, params,
-                                                        vars->ieee_fc);
+                       bnx2x_set_ieee_aneg_advertisement(phy, params,
+                                                         vars->ieee_fc);
 
                        /* enable autoneg */
                        bnx2x_set_autoneg(phy, params, vars, enable_cl73);
@@ -2762,29 +2883,12 @@ static void bnx2x_init_internal_phy(struct bnx2x_phy *phy,
        }
 }
 
-static u8 bnx2x_init_serdes(struct bnx2x_phy *phy,
-                           struct link_params *params,
-                           struct link_vars *vars)
-{
-       u8 rc;
-       vars->phy_flags |= PHY_SGMII_FLAG;
-       bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
-       bnx2x_set_aer_mmd_serdes(params->bp, phy);
-       rc = bnx2x_reset_unicore(params, phy, 1);
-       /* reset the SerDes and wait for reset bit return low */
-       if (rc != 0)
-               return rc;
-       bnx2x_set_aer_mmd_serdes(params->bp, phy);
-
-       return rc;
-}
-
-static u8 bnx2x_init_xgxs(struct bnx2x_phy *phy,
+static int bnx2x_prepare_xgxs(struct bnx2x_phy *phy,
                          struct link_params *params,
                          struct link_vars *vars)
 {
-       u8 rc;
-       vars->phy_flags = PHY_XGXS_FLAG;
+       int rc;
+       vars->phy_flags |= PHY_XGXS_FLAG;
        if ((phy->req_line_speed &&
             ((phy->req_line_speed == SPEED_100) ||
              (phy->req_line_speed == SPEED_10))) ||
@@ -2792,26 +2896,28 @@ static u8 bnx2x_init_xgxs(struct bnx2x_phy *phy,
             (phy->speed_cap_mask >=
              PORT_HW_CFG_SPEED_CAPABILITY_D0_10M_FULL) &&
             (phy->speed_cap_mask <
-             PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)
-            ))
+             PORT_HW_CFG_SPEED_CAPABILITY_D0_1G)) ||
+           (phy->type == PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT_SD))
                vars->phy_flags |= PHY_SGMII_FLAG;
        else
                vars->phy_flags &= ~PHY_SGMII_FLAG;
 
        bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
-       bnx2x_set_aer_mmd_xgxs(params, phy);
-       bnx2x_set_master_ln(params, phy);
+       bnx2x_set_aer_mmd(params, phy);
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT)
+               bnx2x_set_master_ln(params, phy);
 
        rc = bnx2x_reset_unicore(params, phy, 0);
        /* reset the SerDes and wait for reset bit return low */
        if (rc != 0)
                return rc;
 
-       bnx2x_set_aer_mmd_xgxs(params, phy);
-
+       bnx2x_set_aer_mmd(params, phy);
        /* setting the masterLn_def again after the reset */
-       bnx2x_set_master_ln(params, phy);
-       bnx2x_set_swap_lanes(params, phy);
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) {
+               bnx2x_set_master_ln(params, phy);
+               bnx2x_set_swap_lanes(params, phy);
+       }
 
        return rc;
 }
@@ -2972,7 +3078,7 @@ static void bnx2x_link_int_ack(struct link_params *params,
        }
 }
 
-static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len)
+static int bnx2x_format_ver(u32 num, u8 *str, u16 *len)
 {
        u8 *str_ptr = str;
        u32 mask = 0xf0000000;
@@ -3011,19 +3117,19 @@ static u8 bnx2x_format_ver(u32 num, u8 *str, u16 *len)
 }
 
 
-static u8 bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
+static int bnx2x_null_format_ver(u32 spirom_ver, u8 *str, u16 *len)
 {
        str[0] = '\0';
        (*len)--;
        return 0;
 }
 
-u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
-                             u8 *version, u16 len)
+int bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
+                                u8 *version, u16 len)
 {
        struct bnx2x *bp;
        u32 spirom_ver = 0;
-       u8 status = 0;
+       int status = 0;
        u8 *ver_p = version;
        u16 remain_len = len;
        if (version == NULL || params == NULL)
@@ -3088,7 +3194,7 @@ static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
                                 0x6041);
                msleep(200);
                /* set aer mmd back */
-               bnx2x_set_aer_mmd_xgxs(params, phy);
+               bnx2x_set_aer_mmd(params, phy);
 
                /* and md_devad */
                REG_WR(bp, NIG_REG_XGXS0_CTRL_MD_DEVAD + port*0x18, md_devad);
@@ -3107,12 +3213,13 @@ static void bnx2x_set_xgxs_loopback(struct bnx2x_phy *phy,
        }
 }
 
-u8 bnx2x_set_led(struct link_params *params,
-                struct link_vars *vars, u8 mode, u32 speed)
+int bnx2x_set_led(struct link_params *params,
+                 struct link_vars *vars, u8 mode, u32 speed)
 {
        u8 port = params->port;
        u16 hw_led_mode = params->hw_led_mode;
-       u8 rc = 0, phy_idx;
+       int rc = 0;
+       u8 phy_idx;
        u32 tmp;
        u32 emac_base = port ? GRCBASE_EMAC1 : GRCBASE_EMAC0;
        struct bnx2x *bp = params->bp;
@@ -3146,8 +3253,10 @@ u8 bnx2x_set_led(struct link_params *params,
                if (!vars->link_up)
                        break;
        case LED_MODE_ON:
-               if (params->phy[EXT_PHY1].type ==
-                   PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727 &&
+               if (((params->phy[EXT_PHY1].type ==
+                         PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) ||
+                        (params->phy[EXT_PHY1].type ==
+                         PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722)) &&
                    CHIP_IS_E2(bp) && params->num_phys == 2) {
                        /*
                         * This is a work-around for E2+8727 Configurations
@@ -3214,8 +3323,8 @@ u8 bnx2x_set_led(struct link_params *params,
  * This function comes to reflect the actual link state read DIRECTLY from the
  * HW
  */
-u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars,
-                  u8 is_serdes)
+int bnx2x_test_link(struct link_params *params, struct link_vars *vars,
+                   u8 is_serdes)
 {
        struct bnx2x *bp = params->bp;
        u16 gp_status = 0, phy_index = 0;
@@ -3245,7 +3354,9 @@ u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars,
                        serdes_phy_type = ((params->phy[phy_index].media_type ==
                                            ETH_PHY_SFP_FIBER) ||
                                           (params->phy[phy_index].media_type ==
-                                           ETH_PHY_XFP_FIBER));
+                                           ETH_PHY_XFP_FIBER) ||
+                                          (params->phy[phy_index].media_type ==
+                                           ETH_PHY_DA_TWINAX));
 
                        if (is_serdes != serdes_phy_type)
                                continue;
@@ -3263,10 +3374,10 @@ u8 bnx2x_test_link(struct link_params *params, struct link_vars *vars,
        return -ESRCH;
 }
 
-static u8 bnx2x_link_initialize(struct link_params *params,
-                               struct link_vars *vars)
+static int bnx2x_link_initialize(struct link_params *params,
+                                struct link_vars *vars)
 {
-       u8 rc = 0;
+       int rc = 0;
        u8 phy_index, non_ext_phy;
        struct bnx2x *bp = params->bp;
        /*
@@ -3283,11 +3394,7 @@ static u8 bnx2x_link_initialize(struct link_params *params,
         * to first.
         */
 
-       if (params->phy[INT_PHY].config_init)
-               params->phy[INT_PHY].config_init(
-                       &params->phy[INT_PHY],
-                       params, vars);
-
+       bnx2x_prepare_xgxs(&params->phy[INT_PHY], params, vars);
        /* init ext phy and enable link state int */
        non_ext_phy = (SINGLE_MEDIA_DIRECT(params) ||
                       (params->loopback_mode == LOOPBACK_XGXS));
@@ -3298,11 +3405,18 @@ static u8 bnx2x_link_initialize(struct link_params *params,
                struct bnx2x_phy *phy = &params->phy[INT_PHY];
                if (vars->line_speed == SPEED_AUTO_NEG)
                        bnx2x_set_parallel_detection(phy, params);
-               bnx2x_init_internal_phy(phy, params, vars);
+                       if (params->phy[INT_PHY].config_init)
+                               params->phy[INT_PHY].config_init(phy,
+                                                                params,
+                                                                vars);
        }
 
        /* Init external phy*/
-       if (!non_ext_phy)
+       if (non_ext_phy) {
+               if (params->phy[INT_PHY].supported &
+                   SUPPORTED_FIBRE)
+                       vars->link_status |= LINK_STATUS_SERDES_LINK;
+       } else {
                for (phy_index = EXT_PHY1; phy_index < params->num_phys;
                      phy_index++) {
                        /*
@@ -3311,17 +3425,22 @@ static u8 bnx2x_link_initialize(struct link_params *params,
                         * need to initialize the first phy, since they are
                         * connected.
                         */
+                       if (params->phy[phy_index].supported &
+                           SUPPORTED_FIBRE)
+                               vars->link_status |= LINK_STATUS_SERDES_LINK;
+
                        if (phy_index == EXT_PHY2 &&
                            (bnx2x_phy_selection(params) ==
                             PORT_HW_CFG_PHY_SELECTION_FIRST_PHY)) {
-                               DP(NETIF_MSG_LINK, "Ignoring second phy\n");
+                               DP(NETIF_MSG_LINK, "Not initializing"
+                                               " second phy\n");
                                continue;
                        }
                        params->phy[phy_index].config_init(
                                &params->phy[phy_index],
                                params, vars);
                }
-
+       }
        /* Reset the interrupt indication after phy was initialized */
        bnx2x_bits_dis(bp, NIG_REG_STATUS_INTERRUPT_PORT0 +
                       params->port*4,
@@ -3329,6 +3448,7 @@ static u8 bnx2x_link_initialize(struct link_params *params,
                        NIG_STATUS_XGXS0_LINK_STATUS |
                        NIG_STATUS_SERDES0_LINK_STATUS |
                        NIG_MASK_MI_INT));
+       bnx2x_update_mng(params, vars->link_status);
        return rc;
 }
 
@@ -3359,8 +3479,8 @@ static void bnx2x_common_ext_link_reset(struct bnx2x_phy *phy,
        DP(NETIF_MSG_LINK, "reset external PHY\n");
 }
 
-static u8 bnx2x_update_link_down(struct link_params *params,
-                              struct link_vars *vars)
+static int bnx2x_update_link_down(struct link_params *params,
+                                 struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        u8 port = params->port;
@@ -3372,7 +3492,12 @@ static u8 bnx2x_update_link_down(struct link_params *params,
        vars->mac_type = MAC_TYPE_NONE;
 
        /* update shared memory */
-       vars->link_status = 0;
+       vars->link_status &= ~(LINK_STATUS_SPEED_AND_DUPLEX_MASK |
+                              LINK_STATUS_LINK_UP |
+                              LINK_STATUS_AUTO_NEGOTIATE_COMPLETE |
+                              LINK_STATUS_RX_FLOW_CONTROL_FLAG_MASK |
+                              LINK_STATUS_TX_FLOW_CONTROL_FLAG_MASK |
+                              LINK_STATUS_PARALLEL_DETECTION_FLAG_MASK);
        vars->line_speed = 0;
        bnx2x_update_mng(params, vars->link_status);
 
@@ -3391,13 +3516,13 @@ static u8 bnx2x_update_link_down(struct link_params *params,
        return 0;
 }
 
-static u8 bnx2x_update_link_up(struct link_params *params,
-                            struct link_vars *vars,
-                            u8 link_10g)
+static int bnx2x_update_link_up(struct link_params *params,
+                               struct link_vars *vars,
+                               u8 link_10g)
 {
        struct bnx2x *bp = params->bp;
        u8 port = params->port;
-       u8 rc = 0;
+       int rc = 0;
 
        vars->link_status |= LINK_STATUS_LINK_UP;
 
@@ -3451,17 +3576,18 @@ static u8 bnx2x_update_link_up(struct link_params *params,
  *   external phy needs to be up, and at least one of the 2
  *   external phy link must be up.
  */
-u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
+int bnx2x_link_update(struct link_params *params, struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        struct link_vars phy_vars[MAX_PHYS];
        u8 port = params->port;
        u8 link_10g, phy_index;
-       u8 ext_phy_link_up = 0, cur_link_up, rc = 0;
+       u8 ext_phy_link_up = 0, cur_link_up;
+       int rc = 0;
        u8 is_mi_int = 0;
        u16 ext_phy_line_speed = 0, prev_line_speed = vars->line_speed;
        u8 active_external_phy = INT_PHY;
-       vars->link_status = 0;
+
        for (phy_index = INT_PHY; phy_index < params->num_phys;
              phy_index++) {
                phy_vars[phy_index].flow_ctrl = 0;
@@ -3470,6 +3596,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
                phy_vars[phy_index].duplex = DUPLEX_FULL;
                phy_vars[phy_index].phy_link_up = 0;
                phy_vars[phy_index].link_up = 0;
+               phy_vars[phy_index].fault_detected = 0;
        }
 
        DP(NETIF_MSG_LINK, "port %x, XGXS?%x, int_status 0x%x\n",
@@ -3494,7 +3621,7 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
         * Step 1:
         * Check external link change only for external phys, and apply
         * priority selection between them in case the link on both phys
-        * is up. Note that the instead of the common vars, a temporary
+        * is up. Note that instead of the common vars, a temporary
         * vars argument is used since each phy may have different link/
         * speed/duplex result
         */
@@ -3601,6 +3728,8 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
                if (params->phy[active_external_phy].supported &
                    SUPPORTED_FIBRE)
                        vars->link_status |= LINK_STATUS_SERDES_LINK;
+               else
+                       vars->link_status &= ~LINK_STATUS_SERDES_LINK;
                DP(NETIF_MSG_LINK, "Active external phy selected: %x\n",
                           active_external_phy);
        }
@@ -3671,18 +3800,21 @@ u8 bnx2x_link_update(struct link_params *params, struct link_vars *vars)
                                vars->phy_flags |= PHY_SGMII_FLAG;
                        else
                                vars->phy_flags &= ~PHY_SGMII_FLAG;
-                       bnx2x_init_internal_phy(&params->phy[INT_PHY],
-                                               params,
+
+                       if (params->phy[INT_PHY].config_init)
+                               params->phy[INT_PHY].config_init(
+                                       &params->phy[INT_PHY], params,
                                                vars);
                }
        }
        /*
         * Link is up only if both local phy and external phy (in case of
-        * non-direct board) are up
+        * non-direct board) are up and no fault detected on active PHY.
         */
        vars->link_up = (vars->phy_link_up &&
                         (ext_phy_link_up ||
-                         SINGLE_MEDIA_DIRECT(params)));
+                         SINGLE_MEDIA_DIRECT(params)) &&
+                        (phy_vars[active_external_phy].fault_detected == 0));
 
        if (vars->link_up)
                rc = bnx2x_update_link_up(params, vars, link_10g);
@@ -3729,69 +3861,6 @@ static void bnx2x_save_bcm_spirom_ver(struct bnx2x *bp,
                                  phy->ver_addr);
 }
 
-static void bnx2x_ext_phy_set_pause(struct link_params *params,
-                                   struct bnx2x_phy *phy,
-                                   struct link_vars *vars)
-{
-       u16 val;
-       struct bnx2x *bp = params->bp;
-       /* read modify write pause advertizing */
-       bnx2x_cl45_read(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, &val);
-
-       val &= ~MDIO_AN_REG_ADV_PAUSE_BOTH;
-
-       /* Please refer to Table 28B-3 of 802.3ab-1999 spec. */
-       bnx2x_calc_ieee_aneg_adv(phy, params, &vars->ieee_fc);
-       if ((vars->ieee_fc &
-           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) ==
-           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_ASYMMETRIC) {
-               val |= MDIO_AN_REG_ADV_PAUSE_ASYMMETRIC;
-       }
-       if ((vars->ieee_fc &
-           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) ==
-           MDIO_COMBO_IEEE0_AUTO_NEG_ADV_PAUSE_BOTH) {
-               val |= MDIO_AN_REG_ADV_PAUSE_PAUSE;
-       }
-       DP(NETIF_MSG_LINK, "Ext phy AN advertize 0x%x\n", val);
-       bnx2x_cl45_write(bp, phy, MDIO_AN_DEVAD, MDIO_AN_REG_ADV_PAUSE, val);
-}
-
-static u8 bnx2x_ext_phy_resolve_fc(struct bnx2x_phy *phy,
-                                  struct link_params *params,
-                                  struct link_vars *vars)
-{
-       struct bnx2x *bp = params->bp;
-       u16 ld_pause;           /* local */
-       u16 lp_pause;           /* link partner */
-       u16 pause_result;
-       u8 ret = 0;
-       /* read twice */
-
-       vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
-
-       if (phy->req_flow_ctrl != BNX2X_FLOW_CTRL_AUTO)
-               vars->flow_ctrl = phy->req_flow_ctrl;
-       else if (phy->req_line_speed != SPEED_AUTO_NEG)
-               vars->flow_ctrl = params->req_fc_auto_adv;
-       else if (vars->link_status & LINK_STATUS_AUTO_NEGOTIATE_COMPLETE) {
-               ret = 1;
-               bnx2x_cl45_read(bp, phy,
-                               MDIO_AN_DEVAD,
-                               MDIO_AN_REG_ADV_PAUSE, &ld_pause);
-               bnx2x_cl45_read(bp, phy,
-                               MDIO_AN_DEVAD,
-                               MDIO_AN_REG_LP_AUTO_NEG, &lp_pause);
-               pause_result = (ld_pause &
-                               MDIO_AN_REG_ADV_PAUSE_MASK) >> 8;
-               pause_result |= (lp_pause &
-                                MDIO_AN_REG_ADV_PAUSE_MASK) >> 10;
-               DP(NETIF_MSG_LINK, "Ext PHY pause result 0x%x\n",
-                  pause_result);
-               bnx2x_pause_resolve(vars, pause_result);
-       }
-       return ret;
-}
-
 static void bnx2x_ext_phy_10G_an_resolve(struct bnx2x *bp,
                                       struct bnx2x_phy *phy,
                                       struct link_vars *vars)
@@ -3845,13 +3914,13 @@ static void bnx2x_8073_resolve_fc(struct bnx2x_phy *phy,
                           pause_result);
        }
 }
-static u8 bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
-                                             struct bnx2x_phy *phy,
-                                             u8 port)
+static int bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
+                                            struct bnx2x_phy *phy,
+                                            u8 port)
 {
        u32 count = 0;
        u16 fw_ver1, fw_msgout;
-       u8 rc = 0;
+       int rc = 0;
 
        /* Boot port from external ROM  */
        /* EDC grst */
@@ -3926,7 +3995,7 @@ static u8 bnx2x_8073_8727_external_rom_boot(struct bnx2x *bp,
 /******************************************************************/
 /*                     BCM8073 PHY SECTION                       */
 /******************************************************************/
-static u8 bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
+static int bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
 {
        /* This is only required for 8073A1, version 102 only */
        u16 val;
@@ -3952,7 +4021,7 @@ static u8 bnx2x_8073_is_snr_needed(struct bnx2x *bp, struct bnx2x_phy *phy)
        return 1;
 }
 
-static u8 bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
+static int bnx2x_8073_xaui_wa(struct bnx2x *bp, struct bnx2x_phy *phy)
 {
        u16 val, cnt, cnt1 ;
 
@@ -4059,9 +4128,9 @@ static void bnx2x_8073_set_pause_cl37(struct link_params *params,
        msleep(500);
 }
 
-static u8 bnx2x_8073_config_init(struct bnx2x_phy *phy,
-                                struct link_params *params,
-                                struct link_vars *vars)
+static int bnx2x_8073_config_init(struct bnx2x_phy *phy,
+                                 struct link_params *params,
+                                 struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        u16 val = 0, tmp1;
@@ -4367,9 +4436,9 @@ static void bnx2x_8073_link_reset(struct bnx2x_phy *phy,
 /******************************************************************/
 /*                     BCM8705 PHY SECTION                       */
 /******************************************************************/
-static u8 bnx2x_8705_config_init(struct bnx2x_phy *phy,
-                                struct link_params *params,
-                                struct link_vars *vars)
+static int bnx2x_8705_config_init(struct bnx2x_phy *phy,
+                                 struct link_params *params,
+                                 struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        DP(NETIF_MSG_LINK, "init 8705\n");
@@ -4500,9 +4569,9 @@ static void bnx2x_sfp_set_transmitter(struct link_params *params,
        }
 }
 
-static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
-                                           struct link_params *params,
-                                           u16 addr, u8 byte_cnt, u8 *o_buf)
+static int bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
+                                            struct link_params *params,
+                                            u16 addr, u8 byte_cnt, u8 *o_buf)
 {
        struct bnx2x *bp = params->bp;
        u16 val = 0;
@@ -4566,9 +4635,9 @@ static u8 bnx2x_8726_read_sfp_module_eeprom(struct bnx2x_phy *phy,
        return -EINVAL;
 }
 
-static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
-                                           struct link_params *params,
-                                           u16 addr, u8 byte_cnt, u8 *o_buf)
+static int bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
+                                            struct link_params *params,
+                                            u16 addr, u8 byte_cnt, u8 *o_buf)
 {
        struct bnx2x *bp = params->bp;
        u16 val, i;
@@ -4653,27 +4722,35 @@ static u8 bnx2x_8727_read_sfp_module_eeprom(struct bnx2x_phy *phy,
        return -EINVAL;
 }
 
-u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
-                               struct link_params *params, u16 addr,
-                               u8 byte_cnt, u8 *o_buf)
+int bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
+                                struct link_params *params, u16 addr,
+                                u8 byte_cnt, u8 *o_buf)
 {
-       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
-               return bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
-                                                        byte_cnt, o_buf);
-       else if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
-               return bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
-                                                        byte_cnt, o_buf);
-       return -EINVAL;
+       int rc = -EINVAL;
+       switch (phy->type) {
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+               rc = bnx2x_8726_read_sfp_module_eeprom(phy, params, addr,
+                                                      byte_cnt, o_buf);
+       break;
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
+               rc = bnx2x_8727_read_sfp_module_eeprom(phy, params, addr,
+                                                      byte_cnt, o_buf);
+       break;
+       }
+       return rc;
 }
 
-static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy,
-                            struct link_params *params,
-                            u16 *edc_mode)
+static int bnx2x_get_edc_mode(struct bnx2x_phy *phy,
+                             struct link_params *params,
+                             u16 *edc_mode)
 {
        struct bnx2x *bp = params->bp;
+       u32 sync_offset = 0, phy_idx, media_types;
        u8 val, check_limiting_mode = 0;
        *edc_mode = EDC_MODE_LIMITING;
 
+       phy->media_type = ETH_PHY_UNSPECIFIED;
        /* First check for copper cable */
        if (bnx2x_read_sfp_module_eeprom(phy,
                                         params,
@@ -4688,7 +4765,7 @@ static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy,
        case SFP_EEPROM_CON_TYPE_VAL_COPPER:
        {
                u8 copper_module_type;
-
+               phy->media_type = ETH_PHY_DA_TWINAX;
                /*
                 * Check if its active cable (includes SFP+ module)
                 * of passive cable
@@ -4697,8 +4774,7 @@ static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy,
                                               params,
                                               SFP_EEPROM_FC_TX_TECH_ADDR,
                                               1,
-                                              &copper_module_type) !=
-                   0) {
+                                              &copper_module_type) != 0) {
                        DP(NETIF_MSG_LINK,
                                "Failed to read copper-cable-type"
                                " from SFP+ EEPROM\n");
@@ -4723,6 +4799,7 @@ static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy,
                break;
        }
        case SFP_EEPROM_CON_TYPE_VAL_LC:
+               phy->media_type = ETH_PHY_SFP_FIBER;
                DP(NETIF_MSG_LINK, "Optic module detected\n");
                check_limiting_mode = 1;
                break;
@@ -4731,7 +4808,22 @@ static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy,
                         val);
                return -EINVAL;
        }
-
+       sync_offset = params->shmem_base +
+               offsetof(struct shmem_region,
+                        dev_info.port_hw_config[params->port].media_type);
+       media_types = REG_RD(bp, sync_offset);
+       /* Update media type for non-PMF sync */
+       for (phy_idx = INT_PHY; phy_idx < MAX_PHYS; phy_idx++) {
+               if (&(params->phy[phy_idx]) == phy) {
+                       media_types &= ~(PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK <<
+                               (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx));
+                       media_types |= ((phy->media_type &
+                                       PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) <<
+                               (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT * phy_idx));
+                       break;
+               }
+       }
+       REG_WR(bp, sync_offset, media_types);
        if (check_limiting_mode) {
                u8 options[SFP_EEPROM_OPTIONS_SIZE];
                if (bnx2x_read_sfp_module_eeprom(phy,
@@ -4755,8 +4847,8 @@ static u8 bnx2x_get_edc_mode(struct bnx2x_phy *phy,
  * This function read the relevant field from the module (SFP+), and verify it
  * is compliant with this board
  */
-static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
-                                 struct link_params *params)
+static int bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
+                                  struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
        u32 val, cmd;
@@ -4825,8 +4917,8 @@ static u8 bnx2x_verify_sfp_module(struct bnx2x_phy *phy,
        return -EINVAL;
 }
 
-static u8 bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
-                                               struct link_params *params)
+static int bnx2x_wait_for_sfp_module_initialized(struct bnx2x_phy *phy,
+                                                struct link_params *params)
 
 {
        u8 val;
@@ -4868,15 +4960,14 @@ static void bnx2x_8727_power_module(struct bnx2x *bp,
         */
        if (phy->flags & FLAGS_NOC)
                return;
-       if (!(phy->flags &
-             FLAGS_NOC) && is_power_up)
+       if (is_power_up)
                val = (1<<4);
        else
                /*
                 * Set GPIO control to OUTPUT, and set the power bit
                 * to according to the is_power_up
                 */
-               val = ((!(is_power_up)) << 1);
+               val = (1<<1);
 
        bnx2x_cl45_write(bp, phy,
                         MDIO_PMA_DEVAD,
@@ -4884,9 +4975,9 @@ static void bnx2x_8727_power_module(struct bnx2x *bp,
                         val);
 }
 
-static u8 bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
-                                      struct bnx2x_phy *phy,
-                                      u16 edc_mode)
+static int bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
+                                       struct bnx2x_phy *phy,
+                                       u16 edc_mode)
 {
        u16 cur_limiting_mode;
 
@@ -4934,9 +5025,9 @@ static u8 bnx2x_8726_set_limiting_mode(struct bnx2x *bp,
        return 0;
 }
 
-static u8 bnx2x_8727_set_limiting_mode(struct bnx2x *bp,
-                                      struct bnx2x_phy *phy,
-                                      u16 edc_mode)
+static int bnx2x_8727_set_limiting_mode(struct bnx2x *bp,
+                                       struct bnx2x_phy *phy,
+                                       u16 edc_mode)
 {
        u16 phy_identifier;
        u16 rom_ver2_val;
@@ -5021,12 +5112,44 @@ static void bnx2x_set_sfp_module_fault_led(struct link_params *params,
        }
 }
 
-static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
-                                    struct link_params *params)
+static void bnx2x_power_sfp_module(struct link_params *params,
+                                  struct bnx2x_phy *phy,
+                                  u8 power)
+{
+       struct bnx2x *bp = params->bp;
+       DP(NETIF_MSG_LINK, "Setting SFP+ power to %x\n", power);
+
+       switch (phy->type) {
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
+               bnx2x_8727_power_module(params->bp, phy, power);
+               break;
+       default:
+               break;
+       }
+}
+
+static void bnx2x_set_limiting_mode(struct link_params *params,
+                                   struct bnx2x_phy *phy,
+                                   u16 edc_mode)
+{
+       switch (phy->type) {
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+               bnx2x_8726_set_limiting_mode(params->bp, phy, edc_mode);
+               break;
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
+               bnx2x_8727_set_limiting_mode(params->bp, phy, edc_mode);
+               break;
+       }
+}
+
+int bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
+                              struct link_params *params)
 {
        struct bnx2x *bp = params->bp;
        u16 edc_mode;
-       u8 rc = 0;
+       int rc = 0;
 
        u32 val = REG_RD(bp, params->shmem_base +
                             offsetof(struct shmem_region, dev_info.
@@ -5034,7 +5157,8 @@ static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
 
        DP(NETIF_MSG_LINK, "SFP+ module plugged in/out detected on port %d\n",
                 params->port);
-
+       /* Power up module */
+       bnx2x_power_sfp_module(params, phy, 1);
        if (bnx2x_get_edc_mode(phy, params, &edc_mode) != 0) {
                DP(NETIF_MSG_LINK, "Failed to get valid module type\n");
                return -EINVAL;
@@ -5046,12 +5170,11 @@ static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
                bnx2x_set_sfp_module_fault_led(params,
                                               MISC_REGISTERS_GPIO_HIGH);
 
-               if ((phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727) &&
-                   ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
-                    PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN)) {
-                       /* Shutdown SFP+ module */
+               /* Check if need to power down the SFP+ module */
+               if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
+                    PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_POWER_DOWN) {
                        DP(NETIF_MSG_LINK, "Shutdown SFP+ module!!\n");
-                       bnx2x_8727_power_module(bp, phy, 0);
+                       bnx2x_power_sfp_module(params, phy, 0);
                        return rc;
                }
        } else {
@@ -5059,18 +5182,12 @@ static u8 bnx2x_sfp_module_detection(struct bnx2x_phy *phy,
                bnx2x_set_sfp_module_fault_led(params, MISC_REGISTERS_GPIO_LOW);
        }
 
-       /* power up the SFP module */
-       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727)
-               bnx2x_8727_power_module(bp, phy, 1);
-
        /*
         * Check and set limiting mode / LRM mode on 8726. On 8727 it
         * is done automatically
         */
-       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726)
-               bnx2x_8726_set_limiting_mode(bp, phy, edc_mode);
-       else
-               bnx2x_8727_set_limiting_mode(bp, phy, edc_mode);
+       bnx2x_set_limiting_mode(params, phy, edc_mode);
+
        /*
         * Enable transmit for this module if the module is approved, or
         * if unapproved modules should also enable the Tx laser
@@ -5100,7 +5217,7 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
 
        /* Call the handling function in case module is detected */
        if (gpio_val == 0) {
-
+               bnx2x_power_sfp_module(params, phy, 1);
                bnx2x_set_gpio_int(bp, MISC_REGISTERS_GPIO_3,
                                   MISC_REGISTERS_GPIO_INT_OUTPUT_CLR,
                                   port);
@@ -5122,12 +5239,36 @@ void bnx2x_handle_module_detect_int(struct link_params *params)
                 * Module was plugged out.
                 * Disable transmit for this module
                 */
+               phy->media_type = ETH_PHY_NOT_PRESENT;
                if ((val & PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_MASK) ==
                    PORT_FEAT_CFG_OPT_MDL_ENFRCMNT_DISABLE_TX_LASER)
                        bnx2x_sfp_set_transmitter(params, phy, 0);
        }
 }
 
+/******************************************************************/
+/*             Used by 8706 and 8727                             */
+/******************************************************************/
+static void bnx2x_sfp_mask_fault(struct bnx2x *bp,
+                                struct bnx2x_phy *phy,
+                                u16 alarm_status_offset,
+                                u16 alarm_ctrl_offset)
+{
+       u16 alarm_status, val;
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, alarm_status_offset,
+                       &alarm_status);
+       bnx2x_cl45_read(bp, phy,
+                       MDIO_PMA_DEVAD, alarm_status_offset,
+                       &alarm_status);
+       /* Mask or enable the fault event. */
+       bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, alarm_ctrl_offset, &val);
+       if (alarm_status & (1<<0))
+               val &= ~(1<<0);
+       else
+               val |= (1<<0);
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, alarm_ctrl_offset, val);
+}
 /******************************************************************/
 /*             common BCM8706/BCM8726 PHY SECTION                */
 /******************************************************************/
@@ -5142,6 +5283,10 @@ static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
        /* Clear RX Alarm*/
        bnx2x_cl45_read(bp, phy,
                        MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM, &val2);
+
+       bnx2x_sfp_mask_fault(bp, phy, MDIO_PMA_REG_TX_ALARM,
+                            MDIO_PMA_REG_TX_ALARM_CTRL);
+
        /* clear LASI indication*/
        bnx2x_cl45_read(bp, phy,
                        MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
@@ -5173,6 +5318,17 @@ static u8 bnx2x_8706_8726_read_status(struct bnx2x_phy *phy,
                bnx2x_ext_phy_resolve_fc(phy, params, vars);
                vars->duplex = DUPLEX_FULL;
        }
+
+       /* Capture 10G link fault. Read twice to clear stale value. */
+       if (vars->line_speed == SPEED_10000) {
+               bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
+                           MDIO_PMA_REG_TX_ALARM, &val1);
+               bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
+                           MDIO_PMA_REG_TX_ALARM, &val1);
+               if (val1 & (1<<0))
+                       vars->fault_detected = 1;
+       }
+
        return link_up;
 }
 
@@ -5228,7 +5384,11 @@ static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
                                 MDIO_PMA_DEVAD,
                                 MDIO_PMA_REG_DIGITAL_CTRL, 0x400);
                bnx2x_cl45_write(bp, phy,
-                                MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 1);
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_TX_ALARM_CTRL,
+                                0);
+               /* Arm LASI for link and Tx fault. */
+               bnx2x_cl45_write(bp, phy,
+                                MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, 3);
        } else {
                /* Force 1Gbps using autoneg with 1G advertisement */
 
@@ -5281,9 +5441,9 @@ static u8 bnx2x_8706_config_init(struct bnx2x_phy *phy,
        return 0;
 }
 
-static u8 bnx2x_8706_read_status(struct bnx2x_phy *phy,
-                                struct link_params *params,
-                                struct link_vars *vars)
+static int bnx2x_8706_read_status(struct bnx2x_phy *phy,
+                                 struct link_params *params,
+                                 struct link_vars *vars)
 {
        return bnx2x_8706_8726_read_status(phy, params, vars);
 }
@@ -5358,13 +5518,11 @@ static u8 bnx2x_8726_read_status(struct bnx2x_phy *phy,
 }
 
 
-static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy,
-                                struct link_params *params,
-                                struct link_vars *vars)
+static int bnx2x_8726_config_init(struct bnx2x_phy *phy,
+                                 struct link_params *params,
+                                 struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
-       u32 val;
-       u32 swap_val, swap_override, aeu_gpio_mask, offset;
        DP(NETIF_MSG_LINK, "Initializing BCM8726\n");
 
        bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, MDIO_PMA_REG_CTRL, 1<<15);
@@ -5443,30 +5601,6 @@ static u8 bnx2x_8726_config_init(struct bnx2x_phy *phy,
                                 phy->tx_preemphasis[1]);
        }
 
-       /* Set GPIO3 to trigger SFP+ module insertion/removal */
-       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
-                      MISC_REGISTERS_GPIO_INPUT_HI_Z, params->port);
-
-       /* The GPIO should be swapped if the swap register is set and active */
-       swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
-       swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
-
-       /* Select function upon port-swap configuration */
-       if (params->port == 0) {
-               offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
-               aeu_gpio_mask = (swap_val && swap_override) ?
-                       AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1 :
-                       AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0;
-       } else {
-               offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
-               aeu_gpio_mask = (swap_val && swap_override) ?
-                       AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0 :
-                       AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1;
-       }
-       val = REG_RD(bp, offset);
-       /* add GPIO3 to group */
-       val |= aeu_gpio_mask;
-       REG_WR(bp, offset, val);
        return 0;
 
 }
@@ -5548,9 +5682,9 @@ static void bnx2x_8727_hw_reset(struct bnx2x_phy *phy,
                       MISC_REGISTERS_GPIO_OUTPUT_LOW, port);
 }
 
-static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy,
-                                struct link_params *params,
-                                struct link_vars *vars)
+static int bnx2x_8727_config_init(struct bnx2x_phy *phy,
+                                 struct link_params *params,
+                                 struct link_vars *vars)
 {
        u32 tx_en_mode;
        u16 tmp1, val, mod_abs, tmp2;
@@ -5561,14 +5695,17 @@ static u8 bnx2x_8727_config_init(struct bnx2x_phy *phy,
 
        bnx2x_wait_reset_complete(bp, phy, params);
        rx_alarm_ctrl_val = (1<<2) | (1<<5) ;
-       lasi_ctrl_val = 0x0004;
+       /* Should be 0x6 to enable XS on Tx side. */
+       lasi_ctrl_val = 0x0006;
 
        DP(NETIF_MSG_LINK, "Initializing BCM8727\n");
        /* enable LASI */
        bnx2x_cl45_write(bp, phy,
                         MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM_CTRL,
                         rx_alarm_ctrl_val);
-
+       bnx2x_cl45_write(bp, phy,
+                        MDIO_PMA_DEVAD, MDIO_PMA_REG_TX_ALARM_CTRL,
+                        0);
        bnx2x_cl45_write(bp, phy,
                         MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_CTRL, lasi_ctrl_val);
 
@@ -5730,7 +5867,7 @@ static void bnx2x_8727_handle_mod_abs(struct bnx2x_phy *phy,
                /* Module is absent */
                DP(NETIF_MSG_LINK, "MOD_ABS indication "
                            "show module is absent\n");
-
+               phy->media_type = ETH_PHY_NOT_PRESENT;
                /*
                 * 1. Set mod_abs to detect next module
                 *    presence event
@@ -5805,7 +5942,7 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
 
 {
        struct bnx2x *bp = params->bp;
-       u8 link_up = 0;
+       u8 link_up = 0, oc_port = params->port;
        u16 link_status = 0;
        u16 rx_alarm_status, lasi_ctrl, val1;
 
@@ -5816,13 +5953,16 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
        if (!lasi_ctrl)
                return 0;
 
-       /* Check the LASI */
+       /* Check the LASI on Rx */
        bnx2x_cl45_read(bp, phy,
                        MDIO_PMA_DEVAD, MDIO_PMA_REG_RX_ALARM,
                        &rx_alarm_status);
        vars->line_speed = 0;
        DP(NETIF_MSG_LINK, "8727 RX_ALARM_STATUS  0x%x\n", rx_alarm_status);
 
+       bnx2x_sfp_mask_fault(bp, phy, MDIO_PMA_REG_TX_ALARM,
+                            MDIO_PMA_REG_TX_ALARM_CTRL);
+
        bnx2x_cl45_read(bp, phy,
                        MDIO_PMA_DEVAD, MDIO_PMA_REG_LASI_STATUS, &val1);
 
@@ -5843,8 +5983,10 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
                                &val1);
 
                if ((val1 & (1<<8)) == 0) {
+                       if (!CHIP_IS_E1x(bp))
+                               oc_port = BP_PATH(bp) + (params->port << 1);
                        DP(NETIF_MSG_LINK, "8727 Power fault has been detected"
-                                      " on port %d\n", params->port);
+                                      " on port %d\n", oc_port);
                        netdev_err(bp->dev, "Error:  Power fault on Port %d has"
                                            " been detected and the power to "
                                            "that SFP+ module has been removed"
@@ -5852,7 +5994,7 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
                                            " Please remove the SFP+ module and"
                                            " restart the system to clear this"
                                            " error.\n",
-                        params->port);
+                        oc_port);
                        /* Disable all RX_ALARMs except for mod_abs */
                        bnx2x_cl45_write(bp, phy,
                                         MDIO_PMA_DEVAD,
@@ -5915,6 +6057,20 @@ static u8 bnx2x_8727_read_status(struct bnx2x_phy *phy,
                DP(NETIF_MSG_LINK, "port %x: External link is down\n",
                           params->port);
        }
+
+       /* Capture 10G link fault. */
+       if (vars->line_speed == SPEED_10000) {
+               bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
+                           MDIO_PMA_REG_TX_ALARM, &val1);
+
+               bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD,
+                           MDIO_PMA_REG_TX_ALARM, &val1);
+
+               if (val1 & (1<<0)) {
+                       vars->fault_detected = 1;
+               }
+       }
+
        if (link_up) {
                bnx2x_ext_phy_resolve_fc(phy, params, vars);
                vars->duplex = DUPLEX_FULL;
@@ -5958,111 +6114,106 @@ static void bnx2x_8727_link_reset(struct bnx2x_phy *phy,
 static void bnx2x_save_848xx_spirom_version(struct bnx2x_phy *phy,
                                           struct link_params *params)
 {
-       u16 val, fw_ver1, fw_ver2, cnt, adj;
+       u16 val, fw_ver1, fw_ver2, cnt;
+       u8 port;
        struct bnx2x *bp = params->bp;
 
-       adj = 0;
-       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
-               adj = -1;
+       port = params->port;
 
        /* For the 32 bits registers in 848xx, access via MDIO2ARM interface.*/
        /* (1) set register 0xc200_0014(SPI_BRIDGE_CTRL_2) to 0x03000000 */
-       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819 + adj, 0x0014);
-       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A + adj, 0xc200);
-       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B + adj, 0x0000);
-       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C + adj, 0x0300);
-       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817 + adj, 0x0009);
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0014);
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81B, 0x0000);
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81C, 0x0300);
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x0009);
 
        for (cnt = 0; cnt < 100; cnt++) {
-               bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818 + adj, &val);
+               bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
                if (val & 1)
                        break;
                udelay(5);
        }
        if (cnt == 100) {
                DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(1)\n");
-               bnx2x_save_spirom_version(bp, params->port, 0,
+               bnx2x_save_spirom_version(bp, port, 0,
                                          phy->ver_addr);
                return;
        }
 
 
        /* 2) read register 0xc200_0000 (SPI_FW_STATUS) */
-       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819 + adj, 0x0000);
-       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A + adj, 0xc200);
-       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817 + adj, 0x000A);
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA819, 0x0000);
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA81A, 0xc200);
+       bnx2x_cl45_write(bp, phy, MDIO_PMA_DEVAD, 0xA817, 0x000A);
        for (cnt = 0; cnt < 100; cnt++) {
-               bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818 + adj, &val);
+               bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA818, &val);
                if (val & 1)
                        break;
                udelay(5);
        }
        if (cnt == 100) {
                DP(NETIF_MSG_LINK, "Unable to read 848xx phy fw version(2)\n");
-               bnx2x_save_spirom_version(bp, params->port, 0,
+               bnx2x_save_spirom_version(bp, port, 0,
                                          phy->ver_addr);
                return;
        }
 
        /* lower 16 bits of the register SPI_FW_STATUS */
-       bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B + adj, &fw_ver1);
+       bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81B, &fw_ver1);
        /* upper 16 bits of register SPI_FW_STATUS */
-       bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C + adj, &fw_ver2);
+       bnx2x_cl45_read(bp, phy, MDIO_PMA_DEVAD, 0xA81C, &fw_ver2);
 
-       bnx2x_save_spirom_version(bp, params->port, (fw_ver2<<16) | fw_ver1,
+       bnx2x_save_spirom_version(bp, port, (fw_ver2<<16) | fw_ver1,
                                  phy->ver_addr);
 }
 
 static void bnx2x_848xx_set_led(struct bnx2x *bp,
                                struct bnx2x_phy *phy)
 {
-       u16 val, adj;
-
-       adj = 0;
-       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
-               adj = -1;
+       u16 val;
 
        /* PHYC_CTL_LED_CTL */
        bnx2x_cl45_read(bp, phy,
                        MDIO_PMA_DEVAD,
-                       MDIO_PMA_REG_8481_LINK_SIGNAL + adj, &val);
+                       MDIO_PMA_REG_8481_LINK_SIGNAL, &val);
        val &= 0xFE00;
        val |= 0x0092;
 
        bnx2x_cl45_write(bp, phy,
                         MDIO_PMA_DEVAD,
-                        MDIO_PMA_REG_8481_LINK_SIGNAL + adj, val);
+                        MDIO_PMA_REG_8481_LINK_SIGNAL, val);
 
        bnx2x_cl45_write(bp, phy,
                         MDIO_PMA_DEVAD,
-                        MDIO_PMA_REG_8481_LED1_MASK + adj,
+                        MDIO_PMA_REG_8481_LED1_MASK,
                         0x80);
 
        bnx2x_cl45_write(bp, phy,
                         MDIO_PMA_DEVAD,
-                        MDIO_PMA_REG_8481_LED2_MASK + adj,
+                        MDIO_PMA_REG_8481_LED2_MASK,
                         0x18);
 
        /* Select activity source by Tx and Rx, as suggested by PHY AE */
        bnx2x_cl45_write(bp, phy,
                         MDIO_PMA_DEVAD,
-                        MDIO_PMA_REG_8481_LED3_MASK + adj,
+                        MDIO_PMA_REG_8481_LED3_MASK,
                         0x0006);
 
        /* Select the closest activity blink rate to that in 10/100/1000 */
        bnx2x_cl45_write(bp, phy,
                        MDIO_PMA_DEVAD,
-                       MDIO_PMA_REG_8481_LED3_BLINK + adj,
+                       MDIO_PMA_REG_8481_LED3_BLINK,
                        0);
 
        bnx2x_cl45_read(bp, phy,
                        MDIO_PMA_DEVAD,
-                       MDIO_PMA_REG_84823_CTL_LED_CTL_1 + adj, &val);
+                       MDIO_PMA_REG_84823_CTL_LED_CTL_1, &val);
        val |= MDIO_PMA_REG_84823_LED3_STRETCH_EN; /* stretch_en for LED3*/
 
        bnx2x_cl45_write(bp, phy,
                         MDIO_PMA_DEVAD,
-                        MDIO_PMA_REG_84823_CTL_LED_CTL_1 + adj, val);
+                        MDIO_PMA_REG_84823_CTL_LED_CTL_1, val);
 
        /* 'Interrupt Mask' */
        bnx2x_cl45_write(bp, phy,
@@ -6070,12 +6221,19 @@ static void bnx2x_848xx_set_led(struct bnx2x *bp,
                         0xFFFB, 0xFFFD);
 }
 
-static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
-                                     struct link_params *params,
-                                     struct link_vars *vars)
+static int bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
+                                      struct link_params *params,
+                                      struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        u16 autoneg_val, an_1000_val, an_10_100_val;
+       u16 tmp_req_line_speed;
+
+       tmp_req_line_speed = phy->req_line_speed;
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
+               if (phy->req_line_speed == SPEED_10000)
+                       phy->req_line_speed = SPEED_AUTO_NEG;
+
        /*
         * This phy uses the NIG latch mechanism since link indication
         * arrives through its LED4 and not via its LASI signal, so we
@@ -6179,10 +6337,10 @@ static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
            (phy->speed_cap_mask &
             PORT_HW_CFG_SPEED_CAPABILITY_D0_10G)) ||
                (phy->req_line_speed == SPEED_10000)) {
-               DP(NETIF_MSG_LINK, "Advertising 10G\n");
-               /* Restart autoneg for 10G*/
+                       DP(NETIF_MSG_LINK, "Advertising 10G\n");
+                       /* Restart autoneg for 10G*/
 
-               bnx2x_cl45_write(bp, phy,
+                       bnx2x_cl45_write(bp, phy,
                                 MDIO_AN_DEVAD, MDIO_AN_REG_CTRL,
                                 0x3200);
        } else if (phy->req_line_speed != SPEED_10 &&
@@ -6195,12 +6353,14 @@ static u8 bnx2x_848xx_cmn_config_init(struct bnx2x_phy *phy,
        /* Save spirom version */
        bnx2x_save_848xx_spirom_version(phy, params);
 
+       phy->req_line_speed = tmp_req_line_speed;
+
        return 0;
 }
 
-static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
-                                struct link_params *params,
-                                struct link_vars *vars)
+static int bnx2x_8481_config_init(struct bnx2x_phy *phy,
+                                 struct link_params *params,
+                                 struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        /* Restore normal power mode*/
@@ -6215,33 +6375,109 @@ static u8 bnx2x_8481_config_init(struct bnx2x_phy *phy,
        return bnx2x_848xx_cmn_config_init(phy, params, vars);
 }
 
-static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
-                                 struct link_params *params,
-                                 struct link_vars *vars)
+
+#define PHY84833_HDSHK_WAIT 300
+static int bnx2x_84833_pair_swap_cfg(struct bnx2x_phy *phy,
+                                  struct link_params *params,
+                                  struct link_vars *vars)
+{
+       u32 idx;
+       u16 val;
+       u16 data = 0x01b1;
+       struct bnx2x *bp = params->bp;
+       /* Do pair swap */
+
+
+       /* Write CMD_OPEN_OVERRIDE to STATUS reg */
+       bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
+                       MDIO_84833_TOP_CFG_SCRATCH_REG2,
+                       PHY84833_CMD_OPEN_OVERRIDE);
+       for (idx = 0; idx < PHY84833_HDSHK_WAIT; idx++) {
+               bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
+                               MDIO_84833_TOP_CFG_SCRATCH_REG2, &val);
+               if (val == PHY84833_CMD_OPEN_FOR_CMDS)
+                       break;
+               msleep(1);
+       }
+       if (idx >= PHY84833_HDSHK_WAIT) {
+               DP(NETIF_MSG_LINK, "Pairswap: FW not ready.\n");
+               return -EINVAL;
+       }
+
+       bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
+                       MDIO_84833_TOP_CFG_SCRATCH_REG4,
+                       data);
+       /* Issue pair swap command */
+       bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
+                       MDIO_84833_TOP_CFG_SCRATCH_REG0,
+                       PHY84833_DIAG_CMD_PAIR_SWAP_CHANGE);
+       for (idx = 0; idx < PHY84833_HDSHK_WAIT; idx++) {
+               bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
+                               MDIO_84833_TOP_CFG_SCRATCH_REG2, &val);
+               if ((val == PHY84833_CMD_COMPLETE_PASS) ||
+                       (val == PHY84833_CMD_COMPLETE_ERROR))
+                       break;
+               msleep(1);
+       }
+       if ((idx >= PHY84833_HDSHK_WAIT) ||
+               (val == PHY84833_CMD_COMPLETE_ERROR)) {
+               DP(NETIF_MSG_LINK, "Pairswap: override failed.\n");
+               return -EINVAL;
+       }
+       bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
+                       MDIO_84833_TOP_CFG_SCRATCH_REG2,
+                       PHY84833_CMD_CLEAR_COMPLETE);
+       DP(NETIF_MSG_LINK, "Pairswap OK, val=0x%x\n", data);
+       return 0;
+}
+
+static int bnx2x_848x3_config_init(struct bnx2x_phy *phy,
+                                  struct link_params *params,
+                                  struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
        u8 port, initialize = 1;
-       u16 val, adj;
+       u16 val;
        u16 temp;
        u32 actual_phy_selection, cms_enable;
-       u8 rc = 0;
-
-       /* This is just for MDIO_CTL_REG_84823_MEDIA register. */
-       adj = 0;
-       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
-               adj = 3;
+       int rc = 0;
 
        msleep(1);
-       if (CHIP_IS_E2(bp))
+
+       if (!(CHIP_IS_E1(bp)))
                port = BP_PATH(bp);
        else
                port = params->port;
-       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
-                      MISC_REGISTERS_GPIO_OUTPUT_HIGH,
-                      port);
+
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) {
+               bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
+                              MISC_REGISTERS_GPIO_OUTPUT_HIGH,
+                              port);
+       } else {
+               bnx2x_cl45_write(bp, phy,
+                               MDIO_PMA_DEVAD,
+                               MDIO_PMA_REG_CTRL, 0x8000);
+       }
+
        bnx2x_wait_reset_complete(bp, phy, params);
        /* Wait for GPHY to come out of reset */
        msleep(50);
+
+       /* Bring PHY out of super isolate mode */
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833) {
+               bnx2x_cl45_read(bp, phy,
+                               MDIO_CTL_DEVAD,
+                               MDIO_84833_TOP_CFG_XGPHY_STRAP1, &val);
+               val &= ~MDIO_84833_SUPER_ISOLATE;
+               bnx2x_cl45_write(bp, phy,
+                               MDIO_CTL_DEVAD,
+                               MDIO_84833_TOP_CFG_XGPHY_STRAP1, val);
+               bnx2x_wait_reset_complete(bp, phy, params);
+       }
+
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
+               bnx2x_84833_pair_swap_cfg(phy, params, vars);
+
        /*
         * BCM84823 requires that XGXS links up first @ 10G for normal behavior
         */
@@ -6254,7 +6490,7 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
        /* Set dual-media configuration according to configuration */
 
        bnx2x_cl45_read(bp, phy, MDIO_CTL_DEVAD,
-                       MDIO_CTL_REG_84823_MEDIA + adj, &val);
+                       MDIO_CTL_REG_84823_MEDIA, &val);
        val &= ~(MDIO_CTL_REG_84823_MEDIA_MAC_MASK |
                 MDIO_CTL_REG_84823_MEDIA_LINE_MASK |
                 MDIO_CTL_REG_84823_MEDIA_COPPER_CORE_DOWN |
@@ -6287,7 +6523,7 @@ static u8 bnx2x_848x3_config_init(struct bnx2x_phy *phy,
                val |= MDIO_CTL_REG_84823_MEDIA_FIBER_1G;
 
        bnx2x_cl45_write(bp, phy, MDIO_CTL_DEVAD,
-                        MDIO_CTL_REG_84823_MEDIA + adj, val);
+                        MDIO_CTL_REG_84823_MEDIA, val);
        DP(NETIF_MSG_LINK, "Multi_phy config = 0x%x, Media control = 0x%x\n",
                   params->multi_phy_config, val);
 
@@ -6318,20 +6554,16 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
                                  struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
-       u16 val, val1, val2, adj;
+       u16 val, val1, val2;
        u8 link_up = 0;
 
-       /* Reg offset adjustment for 84833 */
-       adj = 0;
-       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833)
-               adj = -1;
 
        /* Check 10G-BaseT link status */
        /* Check PMD signal ok */
        bnx2x_cl45_read(bp, phy,
                        MDIO_AN_DEVAD, 0xFFFA, &val1);
        bnx2x_cl45_read(bp, phy,
-                       MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL + adj,
+                       MDIO_PMA_DEVAD, MDIO_PMA_REG_8481_PMD_SIGNAL,
                        &val2);
        DP(NETIF_MSG_LINK, "BCM848xx: PMD_SIGNAL 1.a811 = 0x%x\n", val2);
 
@@ -6403,9 +6635,10 @@ static u8 bnx2x_848xx_read_status(struct bnx2x_phy *phy,
        return link_up;
 }
 
-static u8 bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
+
+static int bnx2x_848xx_format_ver(u32 raw_ver, u8 *str, u16 *len)
 {
-       u8 status = 0;
+       int status = 0;
        u32 spirom_ver;
        spirom_ver = ((raw_ver & 0xF80) >> 7) << 16 | (raw_ver & 0x7F);
        status = bnx2x_format_ver(spirom_ver, str, len);
@@ -6435,13 +6668,21 @@ static void bnx2x_848x3_link_reset(struct bnx2x_phy *phy,
 {
        struct bnx2x *bp = params->bp;
        u8 port;
-       if (CHIP_IS_E2(bp))
+
+       if (!(CHIP_IS_E1(bp)))
                port = BP_PATH(bp);
        else
                port = params->port;
-       bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
-                      MISC_REGISTERS_GPIO_OUTPUT_LOW,
-                      port);
+
+       if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823) {
+               bnx2x_set_gpio(bp, MISC_REGISTERS_GPIO_3,
+                              MISC_REGISTERS_GPIO_OUTPUT_LOW,
+                              port);
+       } else {
+               bnx2x_cl45_write(bp, phy,
+                               MDIO_PMA_DEVAD,
+                               MDIO_PMA_REG_CTRL, 0x800);
+       }
 }
 
 static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
@@ -6449,11 +6690,17 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
 {
        struct bnx2x *bp = params->bp;
        u16 val;
+       u8 port;
+
+       if (!(CHIP_IS_E1(bp)))
+               port = BP_PATH(bp);
+       else
+               port = params->port;
 
        switch (mode) {
        case LED_MODE_OFF:
 
-               DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OFF\n", params->port);
+               DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OFF\n", port);
 
                if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
                    SHARED_HW_CFG_LED_EXTPHY1) {
@@ -6489,7 +6736,7 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
        case LED_MODE_FRONT_PANEL_OFF:
 
                DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE FRONT PANEL OFF\n",
-                  params->port);
+                  port);
 
                if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
                    SHARED_HW_CFG_LED_EXTPHY1) {
@@ -6524,7 +6771,7 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
                break;
        case LED_MODE_ON:
 
-               DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", params->port);
+               DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE ON\n", port);
 
                if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
                    SHARED_HW_CFG_LED_EXTPHY1) {
@@ -6571,7 +6818,7 @@ static void bnx2x_848xx_set_link_led(struct bnx2x_phy *phy,
 
        case LED_MODE_OPER:
 
-               DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OPER\n", params->port);
+               DP(NETIF_MSG_LINK, "Port 0x%x: LED MODE OPER\n", port);
 
                if ((params->hw_led_mode << SHARED_HW_CFG_LED_MODE_SHIFT) ==
                    SHARED_HW_CFG_LED_EXTPHY1) {
@@ -6646,9 +6893,9 @@ static void bnx2x_7101_config_loopback(struct bnx2x_phy *phy,
                         MDIO_XS_DEVAD, MDIO_XS_SFX7101_XGXS_TEST1, 0x100);
 }
 
-static u8 bnx2x_7101_config_init(struct bnx2x_phy *phy,
-                                struct link_params *params,
-                                struct link_vars *vars)
+static int bnx2x_7101_config_init(struct bnx2x_phy *phy,
+                                 struct link_params *params,
+                                 struct link_vars *vars)
 {
        u16 fw_ver1, fw_ver2, val;
        struct bnx2x *bp = params->bp;
@@ -6721,8 +6968,7 @@ static u8 bnx2x_7101_read_status(struct bnx2x_phy *phy,
        return link_up;
 }
 
-
-static u8 bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
+static int bnx2x_7101_format_ver(u32 spirom_ver, u8 *str, u16 *len)
 {
        if (*len < 5)
                return -EINVAL;
@@ -6800,9 +7046,8 @@ static void bnx2x_7101_set_link_led(struct bnx2x_phy *phy,
 static struct bnx2x_phy phy_null = {
        .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN,
        .addr           = 0,
-       .flags          = FLAGS_INIT_XGXS_FIRST,
        .def_md_devad   = 0,
-       .reserved       = 0,
+       .flags          = FLAGS_INIT_XGXS_FIRST,
        .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .mdio_ctrl      = 0,
@@ -6827,9 +7072,8 @@ static struct bnx2x_phy phy_null = {
 static struct bnx2x_phy phy_serdes = {
        .type           = PORT_HW_CFG_SERDES_EXT_PHY_TYPE_DIRECT,
        .addr           = 0xff,
-       .flags          = 0,
        .def_md_devad   = 0,
-       .reserved       = 0,
+       .flags          = 0,
        .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .mdio_ctrl      = 0,
@@ -6843,14 +7087,14 @@ static struct bnx2x_phy phy_serdes = {
                           SUPPORTED_Autoneg |
                           SUPPORTED_Pause |
                           SUPPORTED_Asym_Pause),
-       .media_type     = ETH_PHY_UNSPECIFIED,
+       .media_type     = ETH_PHY_BASE_T,
        .ver_addr       = 0,
        .req_flow_ctrl  = 0,
        .req_line_speed = 0,
        .speed_cap_mask = 0,
        .req_duplex     = 0,
        .rsrv           = 0,
-       .config_init    = (config_init_t)bnx2x_init_serdes,
+       .config_init    = (config_init_t)bnx2x_xgxs_config_init,
        .read_status    = (read_status_t)bnx2x_link_settings_status,
        .link_reset     = (link_reset_t)bnx2x_int_link_reset,
        .config_loopback = (config_loopback_t)NULL,
@@ -6863,9 +7107,8 @@ static struct bnx2x_phy phy_serdes = {
 static struct bnx2x_phy phy_xgxs = {
        .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT,
        .addr           = 0xff,
-       .flags          = 0,
        .def_md_devad   = 0,
-       .reserved       = 0,
+       .flags          = 0,
        .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .mdio_ctrl      = 0,
@@ -6880,14 +7123,14 @@ static struct bnx2x_phy phy_xgxs = {
                           SUPPORTED_Autoneg |
                           SUPPORTED_Pause |
                           SUPPORTED_Asym_Pause),
-       .media_type     = ETH_PHY_UNSPECIFIED,
+       .media_type     = ETH_PHY_CX4,
        .ver_addr       = 0,
        .req_flow_ctrl  = 0,
        .req_line_speed = 0,
        .speed_cap_mask = 0,
        .req_duplex     = 0,
        .rsrv           = 0,
-       .config_init    = (config_init_t)bnx2x_init_xgxs,
+       .config_init    = (config_init_t)bnx2x_xgxs_config_init,
        .read_status    = (read_status_t)bnx2x_link_settings_status,
        .link_reset     = (link_reset_t)bnx2x_int_link_reset,
        .config_loopback = (config_loopback_t)bnx2x_set_xgxs_loopback,
@@ -6900,9 +7143,8 @@ static struct bnx2x_phy phy_xgxs = {
 static struct bnx2x_phy phy_7101 = {
        .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_SFX7101,
        .addr           = 0xff,
-       .flags          = FLAGS_FAN_FAILURE_DET_REQ,
        .def_md_devad   = 0,
-       .reserved       = 0,
+       .flags          = FLAGS_FAN_FAILURE_DET_REQ,
        .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .mdio_ctrl      = 0,
@@ -6930,9 +7172,8 @@ static struct bnx2x_phy phy_7101 = {
 static struct bnx2x_phy phy_8073 = {
        .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073,
        .addr           = 0xff,
-       .flags          = FLAGS_HW_LOCK_REQUIRED,
        .def_md_devad   = 0,
-       .reserved       = 0,
+       .flags          = FLAGS_HW_LOCK_REQUIRED,
        .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .mdio_ctrl      = 0,
@@ -6943,7 +7184,7 @@ static struct bnx2x_phy phy_8073 = {
                           SUPPORTED_Autoneg |
                           SUPPORTED_Pause |
                           SUPPORTED_Asym_Pause),
-       .media_type     = ETH_PHY_UNSPECIFIED,
+       .media_type     = ETH_PHY_KR,
        .ver_addr       = 0,
        .req_flow_ctrl  = 0,
        .req_line_speed = 0,
@@ -6962,9 +7203,8 @@ static struct bnx2x_phy phy_8073 = {
 static struct bnx2x_phy phy_8705 = {
        .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705,
        .addr           = 0xff,
-       .flags          = FLAGS_INIT_XGXS_FIRST,
        .def_md_devad   = 0,
-       .reserved       = 0,
+       .flags          = FLAGS_INIT_XGXS_FIRST,
        .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .mdio_ctrl      = 0,
@@ -6991,9 +7231,8 @@ static struct bnx2x_phy phy_8705 = {
 static struct bnx2x_phy phy_8706 = {
        .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706,
        .addr           = 0xff,
-       .flags          = FLAGS_INIT_XGXS_FIRST,
        .def_md_devad   = 0,
-       .reserved       = 0,
+       .flags          = FLAGS_INIT_XGXS_FIRST,
        .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .mdio_ctrl      = 0,
@@ -7022,10 +7261,9 @@ static struct bnx2x_phy phy_8706 = {
 static struct bnx2x_phy phy_8726 = {
        .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
        .addr           = 0xff,
+       .def_md_devad   = 0,
        .flags          = (FLAGS_HW_LOCK_REQUIRED |
                           FLAGS_INIT_XGXS_FIRST),
-       .def_md_devad   = 0,
-       .reserved       = 0,
        .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .mdio_ctrl      = 0,
@@ -7035,7 +7273,7 @@ static struct bnx2x_phy phy_8726 = {
                           SUPPORTED_FIBRE |
                           SUPPORTED_Pause |
                           SUPPORTED_Asym_Pause),
-       .media_type     = ETH_PHY_SFP_FIBER,
+       .media_type     = ETH_PHY_NOT_PRESENT,
        .ver_addr       = 0,
        .req_flow_ctrl  = 0,
        .req_line_speed = 0,
@@ -7055,9 +7293,8 @@ static struct bnx2x_phy phy_8726 = {
 static struct bnx2x_phy phy_8727 = {
        .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727,
        .addr           = 0xff,
-       .flags          = FLAGS_FAN_FAILURE_DET_REQ,
        .def_md_devad   = 0,
-       .reserved       = 0,
+       .flags          = FLAGS_FAN_FAILURE_DET_REQ,
        .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .mdio_ctrl      = 0,
@@ -7066,7 +7303,7 @@ static struct bnx2x_phy phy_8727 = {
                           SUPPORTED_FIBRE |
                           SUPPORTED_Pause |
                           SUPPORTED_Asym_Pause),
-       .media_type     = ETH_PHY_SFP_FIBER,
+       .media_type     = ETH_PHY_NOT_PRESENT,
        .ver_addr       = 0,
        .req_flow_ctrl  = 0,
        .req_line_speed = 0,
@@ -7085,10 +7322,9 @@ static struct bnx2x_phy phy_8727 = {
 static struct bnx2x_phy phy_8481 = {
        .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481,
        .addr           = 0xff,
+       .def_md_devad   = 0,
        .flags          = FLAGS_FAN_FAILURE_DET_REQ |
                          FLAGS_REARM_LATCH_SIGNAL,
-       .def_md_devad   = 0,
-       .reserved       = 0,
        .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .mdio_ctrl      = 0,
@@ -7122,10 +7358,9 @@ static struct bnx2x_phy phy_8481 = {
 static struct bnx2x_phy phy_84823 = {
        .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84823,
        .addr           = 0xff,
+       .def_md_devad   = 0,
        .flags          = FLAGS_FAN_FAILURE_DET_REQ |
                          FLAGS_REARM_LATCH_SIGNAL,
-       .def_md_devad   = 0,
-       .reserved       = 0,
        .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .mdio_ctrl      = 0,
@@ -7159,10 +7394,9 @@ static struct bnx2x_phy phy_84823 = {
 static struct bnx2x_phy phy_84833 = {
        .type           = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM84833,
        .addr           = 0xff,
+       .def_md_devad   = 0,
        .flags          = FLAGS_FAN_FAILURE_DET_REQ |
                            FLAGS_REARM_LATCH_SIGNAL,
-       .def_md_devad   = 0,
-       .reserved       = 0,
        .rx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .tx_preemphasis = {0xffff, 0xffff, 0xffff, 0xffff},
        .mdio_ctrl      = 0,
@@ -7259,8 +7493,8 @@ static u32 bnx2x_get_ext_phy_config(struct bnx2x *bp, u32 shmem_base,
 
        return ext_phy_config;
 }
-static u8 bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
-                                struct bnx2x_phy *phy)
+static int bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
+                                 struct bnx2x_phy *phy)
 {
        u32 phy_addr;
        u32 chip_id;
@@ -7302,12 +7536,12 @@ static u8 bnx2x_populate_int_phy(struct bnx2x *bp, u32 shmem_base, u8 port,
        return 0;
 }
 
-static u8 bnx2x_populate_ext_phy(struct bnx2x *bp,
-                                u8 phy_index,
-                                u32 shmem_base,
-                                u32 shmem2_base,
-                                u8 port,
-                                struct bnx2x_phy *phy)
+static int bnx2x_populate_ext_phy(struct bnx2x *bp,
+                                 u8 phy_index,
+                                 u32 shmem_base,
+                                 u32 shmem2_base,
+                                 u8 port,
+                                 struct bnx2x_phy *phy)
 {
        u32 ext_phy_config, phy_type, config2;
        u32 mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_BOTH;
@@ -7336,6 +7570,7 @@ static u8 bnx2x_populate_ext_phy(struct bnx2x *bp,
                *phy = phy_8727;
                phy->flags |= FLAGS_NOC;
                break;
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
                mdc_mdio_access = SHARED_HW_CFG_MDC_MDIO_ACCESS1_EMAC1;
                *phy = phy_8727;
@@ -7410,10 +7645,10 @@ static u8 bnx2x_populate_ext_phy(struct bnx2x *bp,
        return 0;
 }
 
-static u8 bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
-                            u32 shmem2_base, u8 port, struct bnx2x_phy *phy)
+static int bnx2x_populate_phy(struct bnx2x *bp, u8 phy_index, u32 shmem_base,
+                             u32 shmem2_base, u8 port, struct bnx2x_phy *phy)
 {
-       u8 status = 0;
+       int status = 0;
        phy->type = PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN;
        if (phy_index == INT_PHY)
                return bnx2x_populate_int_phy(bp, shmem_base, port, phy);
@@ -7527,10 +7762,10 @@ u32 bnx2x_phy_selection(struct link_params *params)
 }
 
 
-u8 bnx2x_phy_probe(struct link_params *params)
+int bnx2x_phy_probe(struct link_params *params)
 {
        u8 phy_index, actual_phy_idx, link_cfg_idx;
-       u32 phy_config_swapped;
+       u32 phy_config_swapped, sync_offset, media_types;
        struct bnx2x *bp = params->bp;
        struct bnx2x_phy *phy;
        params->num_phys = 0;
@@ -7567,6 +7802,26 @@ u8 bnx2x_phy_probe(struct link_params *params)
                if (phy->type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_NOT_CONN)
                        break;
 
+               sync_offset = params->shmem_base +
+                       offsetof(struct shmem_region,
+                       dev_info.port_hw_config[params->port].media_type);
+               media_types = REG_RD(bp, sync_offset);
+
+               /*
+                * Update media type for non-PMF sync only for the first time
+                * In case the media type changes afterwards, it will be updated
+                * using the update_status function
+                */
+               if ((media_types & (PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK <<
+                                   (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT *
+                                    actual_phy_idx))) == 0) {
+                       media_types |= ((phy->media_type &
+                                       PORT_HW_CFG_MEDIA_TYPE_PHY0_MASK) <<
+                               (PORT_HW_CFG_MEDIA_TYPE_PHY1_SHIFT *
+                                actual_phy_idx));
+               }
+               REG_WR(bp, sync_offset, media_types);
+
                bnx2x_phy_def_cfg(params, phy, phy_index);
                params->num_phys++;
        }
@@ -7575,77 +7830,10 @@ u8 bnx2x_phy_probe(struct link_params *params)
        return 0;
 }
 
-static void set_phy_vars(struct link_params *params)
-{
-       struct bnx2x *bp = params->bp;
-       u8 actual_phy_idx, phy_index, link_cfg_idx;
-       u8 phy_config_swapped = params->multi_phy_config &
-                       PORT_HW_CFG_PHY_SWAPPED_ENABLED;
-       for (phy_index = INT_PHY; phy_index < params->num_phys;
-             phy_index++) {
-               link_cfg_idx = LINK_CONFIG_IDX(phy_index);
-               actual_phy_idx = phy_index;
-               if (phy_config_swapped) {
-                       if (phy_index == EXT_PHY1)
-                               actual_phy_idx = EXT_PHY2;
-                       else if (phy_index == EXT_PHY2)
-                               actual_phy_idx = EXT_PHY1;
-               }
-               params->phy[actual_phy_idx].req_flow_ctrl =
-                       params->req_flow_ctrl[link_cfg_idx];
-
-               params->phy[actual_phy_idx].req_line_speed =
-                       params->req_line_speed[link_cfg_idx];
-
-               params->phy[actual_phy_idx].speed_cap_mask =
-                       params->speed_cap_mask[link_cfg_idx];
-
-               params->phy[actual_phy_idx].req_duplex =
-                       params->req_duplex[link_cfg_idx];
-
-               DP(NETIF_MSG_LINK, "req_flow_ctrl %x, req_line_speed %x,"
-                          " speed_cap_mask %x\n",
-                          params->phy[actual_phy_idx].req_flow_ctrl,
-                          params->phy[actual_phy_idx].req_line_speed,
-                          params->phy[actual_phy_idx].speed_cap_mask);
-       }
-}
-
-u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
+void bnx2x_init_bmac_loopback(struct link_params *params,
+                             struct link_vars *vars)
 {
        struct bnx2x *bp = params->bp;
-       DP(NETIF_MSG_LINK, "Phy Initialization started\n");
-       DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n",
-                  params->req_line_speed[0], params->req_flow_ctrl[0]);
-       DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n",
-                  params->req_line_speed[1], params->req_flow_ctrl[1]);
-       vars->link_status = 0;
-       vars->phy_link_up = 0;
-       vars->link_up = 0;
-       vars->line_speed = 0;
-       vars->duplex = DUPLEX_FULL;
-       vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
-       vars->mac_type = MAC_TYPE_NONE;
-       vars->phy_flags = 0;
-
-       /* disable attentions */
-       bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
-                      (NIG_MASK_XGXS0_LINK_STATUS |
-                       NIG_MASK_XGXS0_LINK10G |
-                       NIG_MASK_SERDES0_LINK_STATUS |
-                       NIG_MASK_MI_INT));
-
-       bnx2x_emac_init(params, vars);
-
-       if (params->num_phys == 0) {
-               DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
-               return -EINVAL;
-       }
-       set_phy_vars(params);
-
-       DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
-       if (params->loopback_mode == LOOPBACK_BMAC) {
-
                vars->link_up = 1;
                vars->line_speed = SPEED_10000;
                vars->duplex = DUPLEX_FULL;
@@ -7660,9 +7848,12 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
                bnx2x_bmac_enable(params, vars, 1);
 
                REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
+}
 
-       } else if (params->loopback_mode == LOOPBACK_EMAC) {
-
+void bnx2x_init_emac_loopback(struct link_params *params,
+                             struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
                vars->link_up = 1;
                vars->line_speed = SPEED_1000;
                vars->duplex = DUPLEX_FULL;
@@ -7676,29 +7867,32 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
                bnx2x_emac_enable(params, vars, 1);
                bnx2x_emac_program(params, vars);
                REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
+}
 
-       } else if ((params->loopback_mode == LOOPBACK_XGXS) ||
-                  (params->loopback_mode == LOOPBACK_EXT_PHY)) {
-
+void bnx2x_init_xgxs_loopback(struct link_params *params,
+                             struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
                vars->link_up = 1;
                vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
                vars->duplex = DUPLEX_FULL;
-               if (params->req_line_speed[0] == SPEED_1000) {
+       if (params->req_line_speed[0] == SPEED_1000)
                        vars->line_speed = SPEED_1000;
-                       vars->mac_type = MAC_TYPE_EMAC;
-               } else {
+       else
                        vars->line_speed = SPEED_10000;
-                       vars->mac_type = MAC_TYPE_BMAC;
-               }
 
-               bnx2x_xgxs_deassert(params);
-               bnx2x_link_initialize(params, vars);
 
-               if (params->req_line_speed[0] == SPEED_1000) {
-                       bnx2x_emac_program(params, vars);
-                       bnx2x_emac_enable(params, vars, 0);
-               } else
-                       bnx2x_bmac_enable(params, vars, 0);
+       bnx2x_xgxs_deassert(params);
+       bnx2x_link_initialize(params, vars);
+
+       if (params->req_line_speed[0] == SPEED_1000) {
+               bnx2x_emac_program(params, vars);
+               bnx2x_emac_enable(params, vars, 0);
+
+       } else
+               bnx2x_bmac_enable(params, vars, 0);
+
+
                if (params->loopback_mode == LOOPBACK_XGXS) {
                        /* set 10G XGXS loopback */
                        params->phy[INT_PHY].config_loopback(
@@ -7718,11 +7912,55 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
                }
                REG_WR(bp, NIG_REG_EGRESS_DRAIN0_MODE + params->port*4, 0);
 
-               bnx2x_set_led(params, vars,
-                             LED_MODE_OPER, vars->line_speed);
-       } else
-       /* No loopback */
-       {
+       bnx2x_set_led(params, vars, LED_MODE_OPER, vars->line_speed);
+}
+
+int bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
+{
+       struct bnx2x *bp = params->bp;
+       DP(NETIF_MSG_LINK, "Phy Initialization started\n");
+       DP(NETIF_MSG_LINK, "(1) req_speed %d, req_flowctrl %d\n",
+                  params->req_line_speed[0], params->req_flow_ctrl[0]);
+       DP(NETIF_MSG_LINK, "(2) req_speed %d, req_flowctrl %d\n",
+                  params->req_line_speed[1], params->req_flow_ctrl[1]);
+       vars->link_status = 0;
+       vars->phy_link_up = 0;
+       vars->link_up = 0;
+       vars->line_speed = 0;
+       vars->duplex = DUPLEX_FULL;
+       vars->flow_ctrl = BNX2X_FLOW_CTRL_NONE;
+       vars->mac_type = MAC_TYPE_NONE;
+       vars->phy_flags = 0;
+
+       /* disable attentions */
+       bnx2x_bits_dis(bp, NIG_REG_MASK_INTERRUPT_PORT0 + params->port*4,
+                      (NIG_MASK_XGXS0_LINK_STATUS |
+                       NIG_MASK_XGXS0_LINK10G |
+                       NIG_MASK_SERDES0_LINK_STATUS |
+                       NIG_MASK_MI_INT));
+
+       bnx2x_emac_init(params, vars);
+
+       if (params->num_phys == 0) {
+               DP(NETIF_MSG_LINK, "No phy found for initialization !!\n");
+               return -EINVAL;
+       }
+       set_phy_vars(params, vars);
+
+       DP(NETIF_MSG_LINK, "Num of phys on board: %d\n", params->num_phys);
+       switch (params->loopback_mode) {
+       case LOOPBACK_BMAC:
+               bnx2x_init_bmac_loopback(params, vars);
+               break;
+       case LOOPBACK_EMAC:
+               bnx2x_init_emac_loopback(params, vars);
+               break;
+       case LOOPBACK_XGXS:
+       case LOOPBACK_EXT_PHY:
+               bnx2x_init_xgxs_loopback(params, vars);
+               break;
+       default:
+               /* No loopback */
                if (params->switch_cfg == SWITCH_CFG_10G)
                        bnx2x_xgxs_deassert(params);
                else
@@ -7731,11 +7969,13 @@ u8 bnx2x_phy_init(struct link_params *params, struct link_vars *vars)
                bnx2x_link_initialize(params, vars);
                msleep(30);
                bnx2x_link_int_enable(params);
+               break;
        }
        return 0;
 }
-u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
-                   u8 reset_ext_phy)
+
+int bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
+                    u8 reset_ext_phy)
 {
        struct bnx2x *bp = params->bp;
        u8 phy_index, port = params->port, clear_latch_ind = 0;
@@ -7807,10 +8047,10 @@ u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
 /****************************************************************************/
 /*                             Common function                             */
 /****************************************************************************/
-static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
-                                    u32 shmem_base_path[],
-                                    u32 shmem2_base_path[], u8 phy_index,
-                                    u32 chip_id)
+static int bnx2x_8073_common_init_phy(struct bnx2x *bp,
+                                     u32 shmem_base_path[],
+                                     u32 shmem2_base_path[], u8 phy_index,
+                                     u32 chip_id)
 {
        struct bnx2x_phy phy[PORT_MAX];
        struct bnx2x_phy *phy_blk[PORT_MAX];
@@ -7933,10 +8173,10 @@ static u8 bnx2x_8073_common_init_phy(struct bnx2x *bp,
        }
        return 0;
 }
-static u8 bnx2x_8726_common_init_phy(struct bnx2x *bp,
-                                    u32 shmem_base_path[],
-                                    u32 shmem2_base_path[], u8 phy_index,
-                                    u32 chip_id)
+static int bnx2x_8726_common_init_phy(struct bnx2x *bp,
+                                     u32 shmem_base_path[],
+                                     u32 shmem2_base_path[], u8 phy_index,
+                                     u32 chip_id)
 {
        u32 val;
        s8 port;
@@ -8027,10 +8267,11 @@ static void bnx2x_get_ext_phy_reset_gpio(struct bnx2x *bp, u32 shmem_base,
                break;
        }
 }
-static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp,
-                                    u32 shmem_base_path[],
-                                    u32 shmem2_base_path[], u8 phy_index,
-                                    u32 chip_id)
+
+static int bnx2x_8727_common_init_phy(struct bnx2x *bp,
+                                     u32 shmem_base_path[],
+                                     u32 shmem2_base_path[], u8 phy_index,
+                                     u32 chip_id)
 {
        s8 port, reset_gpio;
        u32 swap_val, swap_override;
@@ -8123,11 +8364,11 @@ static u8 bnx2x_8727_common_init_phy(struct bnx2x *bp,
        return 0;
 }
 
-static u8 bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[],
-                                   u32 shmem2_base_path[], u8 phy_index,
-                                   u32 ext_phy_type, u32 chip_id)
+static int bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[],
+                                    u32 shmem2_base_path[], u8 phy_index,
+                                    u32 ext_phy_type, u32 chip_id)
 {
-       u8 rc = 0;
+       int rc = 0;
 
        switch (ext_phy_type) {
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8073:
@@ -8135,7 +8376,7 @@ static u8 bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[],
                                                shmem2_base_path,
                                                phy_index, chip_id);
                break;
-
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8722:
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727:
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8727_NOC:
                rc = bnx2x_8727_common_init_phy(bp, shmem_base_path,
@@ -8169,13 +8410,15 @@ static u8 bnx2x_ext_phy_common_init(struct bnx2x *bp, u32 shmem_base_path[],
        return rc;
 }
 
-u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
-                        u32 shmem2_base_path[], u32 chip_id)
+int bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
+                         u32 shmem2_base_path[], u32 chip_id)
 {
-       u8 rc = 0;
+       int rc = 0;
        u32 phy_ver;
        u8 phy_index;
        u32 ext_phy_type, ext_phy_config;
+       bnx2x_set_mdio_clk(bp, chip_id, PORT_0);
+       bnx2x_set_mdio_clk(bp, chip_id, PORT_1);
        DP(NETIF_MSG_LINK, "Begin common phy init\n");
 
        /* Check if common init was already done */
@@ -8255,3 +8498,66 @@ void bnx2x_hw_reset_phy(struct link_params *params)
                }
        }
 }
+
+void bnx2x_init_mod_abs_int(struct bnx2x *bp, struct link_vars *vars,
+                           u32 chip_id, u32 shmem_base, u32 shmem2_base,
+                           u8 port)
+{
+       u8 gpio_num = 0xff, gpio_port = 0xff, phy_index;
+       u32 val;
+       u32 offset, aeu_mask, swap_val, swap_override, sync_offset;
+
+       {
+               struct bnx2x_phy phy;
+               for (phy_index = EXT_PHY1; phy_index < MAX_PHYS;
+                     phy_index++) {
+                       if (bnx2x_populate_phy(bp, phy_index, shmem_base,
+                                              shmem2_base, port, &phy)
+                           != 0) {
+                               DP(NETIF_MSG_LINK, "populate phy failed\n");
+                               return;
+                       }
+                       if (phy.type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) {
+                               gpio_num = MISC_REGISTERS_GPIO_3;
+                               gpio_port = port;
+                               break;
+                       }
+               }
+       }
+
+       if (gpio_num == 0xff)
+               return;
+
+       /* Set GPIO3 to trigger SFP+ module insertion/removal */
+       bnx2x_set_gpio(bp, gpio_num, MISC_REGISTERS_GPIO_INPUT_HI_Z, gpio_port);
+
+       swap_val = REG_RD(bp, NIG_REG_PORT_SWAP);
+       swap_override = REG_RD(bp, NIG_REG_STRAP_OVERRIDE);
+       gpio_port ^= (swap_val && swap_override);
+
+       vars->aeu_int_mask = AEU_INPUTS_ATTN_BITS_GPIO0_FUNCTION_0 <<
+               (gpio_num + (gpio_port << 2));
+
+       sync_offset = shmem_base +
+               offsetof(struct shmem_region,
+                        dev_info.port_hw_config[port].aeu_int_mask);
+       REG_WR(bp, sync_offset, vars->aeu_int_mask);
+
+       DP(NETIF_MSG_LINK, "Setting MOD_ABS (GPIO%d_P%d) AEU to 0x%x\n",
+                      gpio_num, gpio_port, vars->aeu_int_mask);
+
+       if (port == 0)
+               offset = MISC_REG_AEU_ENABLE1_FUNC_0_OUT_0;
+       else
+               offset = MISC_REG_AEU_ENABLE1_FUNC_1_OUT_0;
+
+       /* Open appropriate AEU for interrupts */
+       aeu_mask = REG_RD(bp, offset);
+       aeu_mask |= vars->aeu_int_mask;
+       REG_WR(bp, offset, aeu_mask);
+
+       /* Enable the GPIO to trigger interrupt */
+       val = REG_RD(bp, MISC_REG_GPIO_EVENT_EN);
+       val |= 1 << (gpio_num + (gpio_port << 2));
+       REG_WR(bp, MISC_REG_GPIO_EVENT_EN, val);
+}
index 92f36b6..a106d8c 100644 (file)
@@ -121,8 +121,8 @@ struct bnx2x_phy {
 
        /* Loaded during init */
        u8 addr;
-
-       u8 flags;
+       u8 def_md_devad;
+       u16 flags;
        /* Require HW lock */
 #define FLAGS_HW_LOCK_REQUIRED         (1<<0)
        /* No Over-Current detection */
@@ -134,8 +134,6 @@ struct bnx2x_phy {
 #define FLAGS_REARM_LATCH_SIGNAL       (1<<6)
 #define FLAGS_SFP_NOT_APPROVED         (1<<7)
 
-       u8 def_md_devad;
-       u8 reserved;
        /* preemphasis values for the rx side */
        u16 rx_preemphasis[4];
 
@@ -153,6 +151,8 @@ struct bnx2x_phy {
 #define        ETH_PHY_XFP_FIBER   0x2
 #define        ETH_PHY_DA_TWINAX   0x3
 #define        ETH_PHY_BASE_T      0x4
+#define        ETH_PHY_KR          0xf0
+#define        ETH_PHY_CX4         0xf1
 #define        ETH_PHY_NOT_PRESENT 0xff
 
        /* The address in which version is located*/
@@ -274,45 +274,50 @@ struct link_vars {
 
        /* The same definitions as the shmem parameter */
        u32 link_status;
+       u8 fault_detected;
+       u8 rsrv1;
+       u16 rsrv2;
+       u32 aeu_int_mask;
 };
 
 /***********************************************************/
 /*                         Functions                       */
 /***********************************************************/
-u8 bnx2x_phy_init(struct link_params *input, struct link_vars *output);
+int bnx2x_phy_init(struct link_params *params, struct link_vars *vars);
 
 /* Reset the link. Should be called when driver or interface goes down
    Before calling phy firmware upgrade, the reset_ext_phy should be set
    to 0 */
-u8 bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
-                 u8 reset_ext_phy);
+int bnx2x_link_reset(struct link_params *params, struct link_vars *vars,
+                    u8 reset_ext_phy);
 
 /* bnx2x_link_update should be called upon link interrupt */
-u8 bnx2x_link_update(struct link_params *input, struct link_vars *output);
+int bnx2x_link_update(struct link_params *params, struct link_vars *vars);
 
 /* use the following phy functions to read/write from external_phy
   In order to use it to read/write internal phy registers, use
   DEFAULT_PHY_DEV_ADDR as devad, and (_bank + (_addr & 0xf)) as
   the register */
-u8 bnx2x_phy_read(struct link_params *params, u8 phy_addr,
-                 u8 devad, u16 reg, u16 *ret_val);
+int bnx2x_phy_read(struct link_params *params, u8 phy_addr,
+                  u8 devad, u16 reg, u16 *ret_val);
+
+int bnx2x_phy_write(struct link_params *params, u8 phy_addr,
+                   u8 devad, u16 reg, u16 val);
 
-u8 bnx2x_phy_write(struct link_params *params, u8 phy_addr,
-                  u8 devad, u16 reg, u16 val);
 /* Reads the link_status from the shmem,
    and update the link vars accordingly */
 void bnx2x_link_status_update(struct link_params *input,
                            struct link_vars *output);
 /* returns string representing the fw_version of the external phy */
-u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
-                             u8 *version, u16 len);
+int bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
+                                u8 *version, u16 len);
 
 /* Set/Unset the led
    Basically, the CLC takes care of the led for the link, but in case one needs
    to set/unset the led unnaturally, set the "mode" to LED_MODE_OPER to
    blink the led, and LED_MODE_OFF to set the led off.*/
-u8 bnx2x_set_led(struct link_params *params, struct link_vars *vars,
-                u8 mode, u32 speed);
+int bnx2x_set_led(struct link_params *params,
+                 struct link_vars *vars, u8 mode, u32 speed);
 #define LED_MODE_OFF                   0
 #define LED_MODE_ON                    1
 #define LED_MODE_OPER                  2
@@ -324,12 +329,12 @@ void bnx2x_handle_module_detect_int(struct link_params *params);
 
 /* Get the actual link status. In case it returns 0, link is up,
        otherwise link is down*/
-u8 bnx2x_test_link(struct link_params *input, struct link_vars *vars,
-                  u8 is_serdes);
+int bnx2x_test_link(struct link_params *params, struct link_vars *vars,
+                   u8 is_serdes);
 
 /* One-time initialization for external phy after power up */
-u8 bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
-                        u32 shmem2_base_path[], u32 chip_id);
+int bnx2x_common_init_phy(struct bnx2x *bp, u32 shmem_base_path[],
+                         u32 shmem2_base_path[], u32 chip_id);
 
 /* Reset the external PHY using GPIO */
 void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port);
@@ -338,9 +343,9 @@ void bnx2x_ext_phy_hw_reset(struct bnx2x *bp, u8 port);
 void bnx2x_sfx7101_sp_sw_reset(struct bnx2x *bp, struct bnx2x_phy *phy);
 
 /* Read "byte_cnt" bytes from address "addr" from the SFP+ EEPROM */
-u8 bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
-                               struct link_params *params, u16 addr,
-                               u8 byte_cnt, u8 *o_buf);
+int bnx2x_read_sfp_module_eeprom(struct bnx2x_phy *phy,
+                                struct link_params *params, u16 addr,
+                                u8 byte_cnt, u8 *o_buf);
 
 void bnx2x_hw_reset_phy(struct link_params *params);
 
@@ -352,7 +357,8 @@ u8 bnx2x_hw_lock_required(struct bnx2x *bp, u32 shmem_base,
 u32 bnx2x_phy_selection(struct link_params *params);
 
 /* Probe the phys on board, and populate them in "params" */
-u8 bnx2x_phy_probe(struct link_params *params);
+int bnx2x_phy_probe(struct link_params *params);
+
 /* Checks if fan failure detection is required on one of the phys on board */
 u8 bnx2x_fan_failure_det_req(struct bnx2x *bp, u32 shmem_base,
                             u32 shmem2_base, u8 port);
@@ -390,10 +396,13 @@ void bnx2x_ets_bw_limit(const struct link_params *params, const u32 cos0_bw,
                        const u32 cos1_bw);
 
 /* Used to configure the ETS to strict */
-u8 bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos);
+int bnx2x_ets_strict(const struct link_params *params, const u8 strict_cos);
 
 /* Read pfc statistic*/
 void bnx2x_pfc_statistic(struct link_params *params, struct link_vars *vars,
                                                 u32 pfc_frames_sent[2],
                                                 u32 pfc_frames_received[2]);
+void bnx2x_init_mod_abs_int(struct bnx2x *bp, struct link_vars *vars,
+                           u32 chip_id, u32 shmem_base, u32 shmem2_base,
+                           u8 port);
 #endif /* BNX2X_LINK_H */
index 4b70311..2e89b6c 100644 (file)
@@ -1732,45 +1732,6 @@ static int bnx2x_set_spio(struct bnx2x *bp, int spio_num, u32 mode)
        return 0;
 }
 
-int bnx2x_get_link_cfg_idx(struct bnx2x *bp)
-{
-       u32 sel_phy_idx = 0;
-       if (bp->link_vars.link_up) {
-               sel_phy_idx = EXT_PHY1;
-               /* In case link is SERDES, check if the EXT_PHY2 is the one */
-               if ((bp->link_vars.link_status & LINK_STATUS_SERDES_LINK) &&
-                   (bp->link_params.phy[EXT_PHY2].supported & SUPPORTED_FIBRE))
-                       sel_phy_idx = EXT_PHY2;
-       } else {
-
-               switch (bnx2x_phy_selection(&bp->link_params)) {
-               case PORT_HW_CFG_PHY_SELECTION_HARDWARE_DEFAULT:
-               case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY:
-               case PORT_HW_CFG_PHY_SELECTION_FIRST_PHY_PRIORITY:
-                      sel_phy_idx = EXT_PHY1;
-                      break;
-               case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY:
-               case PORT_HW_CFG_PHY_SELECTION_SECOND_PHY_PRIORITY:
-                      sel_phy_idx = EXT_PHY2;
-                      break;
-               }
-       }
-       /*
-       * The selected actived PHY is always after swapping (in case PHY
-       * swapping is enabled). So when swapping is enabled, we need to reverse
-       * the configuration
-       */
-
-       if (bp->link_params.multi_phy_config &
-           PORT_HW_CFG_PHY_SWAPPED_ENABLED) {
-               if (sel_phy_idx == EXT_PHY1)
-                       sel_phy_idx = EXT_PHY2;
-               else if (sel_phy_idx == EXT_PHY2)
-                       sel_phy_idx = EXT_PHY1;
-       }
-       return LINK_CONFIG_IDX(sel_phy_idx);
-}
-
 void bnx2x_calc_fc_adv(struct bnx2x *bp)
 {
        u8 cfg_idx = bnx2x_get_link_cfg_idx(bp);
@@ -4491,6 +4452,10 @@ void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
 
 #endif
 
+       /* Initialize MOD_ABS interrupts */
+       bnx2x_init_mod_abs_int(bp, &bp->link_vars, bp->common.chip_id,
+                              bp->common.shmem_base, bp->common.shmem2_base,
+                              BP_PORT(bp));
        /* ensure status block indices were read */
        rmb();
 
index 86bba25..949e8bd 100644 (file)
 #define AEU_INPUTS_ATTN_BITS_DMAE_HW_INTERRUPT               (1<<11)
 #define AEU_INPUTS_ATTN_BITS_DOORBELLQ_HW_INTERRUPT          (1<<13)
 #define AEU_INPUTS_ATTN_BITS_DOORBELLQ_PARITY_ERROR          (1<<12)
+#define AEU_INPUTS_ATTN_BITS_GPIO0_FUNCTION_0                (1<<2)
 #define AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_0                (1<<5)
 #define AEU_INPUTS_ATTN_BITS_GPIO3_FUNCTION_1                (1<<9)
 #define AEU_INPUTS_ATTN_BITS_IGU_PARITY_ERROR                (1<<12)
@@ -6037,6 +6038,7 @@ Theotherbitsarereservedandshouldbezero*/
 #define MDIO_PMA_REG_BCM_CTRL          0x0096
 #define MDIO_PMA_REG_FEC_CTRL          0x00ab
 #define MDIO_PMA_REG_RX_ALARM_CTRL     0x9000
+#define MDIO_PMA_REG_TX_ALARM_CTRL     0x9001
 #define MDIO_PMA_REG_LASI_CTRL         0x9002
 #define MDIO_PMA_REG_RX_ALARM          0x9003
 #define MDIO_PMA_REG_TX_ALARM          0x9004
@@ -6201,6 +6203,29 @@ Theotherbitsarereservedandshouldbezero*/
 #define MDIO_PMA_REG_84823_CTL_LED_CTL_1               0xa8e3
 #define MDIO_PMA_REG_84823_LED3_STRETCH_EN             0x0080
 
+/* BCM84833 only */
+#define MDIO_84833_TOP_CFG_XGPHY_STRAP1                        0x401a
+#define MDIO_84833_SUPER_ISOLATE               0x8000
+/* These are mailbox register set used by 84833. */
+#define MDIO_84833_TOP_CFG_SCRATCH_REG0                        0x4005
+#define MDIO_84833_TOP_CFG_SCRATCH_REG1                        0x4006
+#define MDIO_84833_TOP_CFG_SCRATCH_REG2                        0x4007
+#define MDIO_84833_TOP_CFG_SCRATCH_REG3                        0x4008
+#define MDIO_84833_TOP_CFG_SCRATCH_REG4                        0x4009
+
+/* Mailbox command set used by 84833. */
+#define PHY84833_DIAG_CMD_PAIR_SWAP_CHANGE             0x2
+/* Mailbox status set used by 84833. */
+#define PHY84833_CMD_RECEIVED                          0x0001
+#define PHY84833_CMD_IN_PROGRESS                       0x0002
+#define PHY84833_CMD_COMPLETE_PASS                     0x0004
+#define PHY84833_CMD_COMPLETE_ERROR                    0x0008
+#define PHY84833_CMD_OPEN_FOR_CMDS                     0x0010
+#define PHY84833_CMD_SYSTEM_BOOT                       0x0020
+#define PHY84833_CMD_NOT_OPEN_FOR_CMDS                 0x0040
+#define PHY84833_CMD_CLEAR_COMPLETE                    0x0080
+#define PHY84833_CMD_OPEN_OVERRIDE                     0xa5a5
+
 #define IGU_FUNC_BASE                  0x0400
 
 #define IGU_ADDR_MSIX                  0x0000
index 17b4dd9..716c852 100644 (file)
@@ -629,15 +629,8 @@ static int bond_update_speed_duplex(struct slave *slave)
                return -1;
 
        slave_speed = ethtool_cmd_speed(&etool);
-       switch (slave_speed) {
-       case SPEED_10:
-       case SPEED_100:
-       case SPEED_1000:
-       case SPEED_10000:
-               break;
-       default:
+       if (slave_speed == 0 || slave_speed == ((__u32) -1))
                return -1;
-       }
 
        switch (etool.duplex) {
        case DUPLEX_FULL:
index 09ed3f4..abf4d7a 100644 (file)
@@ -38,3 +38,12 @@ config CAIF_SHM
        default n
        ---help---
        The CAIF shared memory protocol driver for the STE UX5500 platform.
+
+config CAIF_HSI
+       tristate "CAIF HSI transport driver"
+       depends on CAIF
+       default n
+       ---help---
+       The caif low level driver for CAIF over HSI.
+       Be aware that if you enable this then you also need to
+       enable a low-level HSI driver.
index 9560b9d..91dff86 100644 (file)
@@ -10,3 +10,6 @@ obj-$(CONFIG_CAIF_SPI_SLAVE) += cfspi_slave.o
 # Shared memory
 caif_shm-objs := caif_shmcore.o caif_shm_u5500.o
 obj-$(CONFIG_CAIF_SHM) += caif_shm.o
+
+# HSI interface
+obj-$(CONFIG_CAIF_HSI) += caif_hsi.o
diff --git a/drivers/net/caif/caif_hsi.c b/drivers/net/caif/caif_hsi.c
new file mode 100644 (file)
index 0000000..7a8ce61
--- /dev/null
@@ -0,0 +1,1220 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author:  Daniel Martensson / daniel.martensson@stericsson.com
+ *         Dmitry.Tarnyagin  / dmitry.tarnyagin@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2.
+ */
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/platform_device.h>
+#include <linux/netdevice.h>
+#include <linux/string.h>
+#include <linux/list.h>
+#include <linux/interrupt.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/if_arp.h>
+#include <linux/timer.h>
+#include <net/caif/caif_layer.h>
+#include <net/caif/caif_hsi.h>
+
+MODULE_LICENSE("GPL");
+MODULE_AUTHOR("Daniel Martensson<daniel.martensson@stericsson.com>");
+MODULE_DESCRIPTION("CAIF HSI driver");
+
+/* Returns the number of padding bytes for alignment. */
+#define PAD_POW2(x, pow) ((((x)&((pow)-1)) == 0) ? 0 :\
+                               (((pow)-((x)&((pow)-1)))))
+
+/*
+ * HSI padding options.
+ * Warning: must be a base of 2 (& operation used) and can not be zero !
+ */
+static int hsi_head_align = 4;
+module_param(hsi_head_align, int, S_IRUGO);
+MODULE_PARM_DESC(hsi_head_align, "HSI head alignment.");
+
+static int hsi_tail_align = 4;
+module_param(hsi_tail_align, int, S_IRUGO);
+MODULE_PARM_DESC(hsi_tail_align, "HSI tail alignment.");
+
+/*
+ * HSI link layer flowcontrol thresholds.
+ * Warning: A high threshold value migth increase throughput but it will at
+ * the same time prevent channel prioritization and increase the risk of
+ * flooding the modem. The high threshold should be above the low.
+ */
+static int hsi_high_threshold = 100;
+module_param(hsi_high_threshold, int, S_IRUGO);
+MODULE_PARM_DESC(hsi_high_threshold, "HSI high threshold (FLOW OFF).");
+
+static int hsi_low_threshold = 50;
+module_param(hsi_low_threshold, int, S_IRUGO);
+MODULE_PARM_DESC(hsi_low_threshold, "HSI high threshold (FLOW ON).");
+
+#define ON 1
+#define OFF 0
+
+/*
+ * Threshold values for the HSI packet queue. Flowcontrol will be asserted
+ * when the number of packets exceeds HIGH_WATER_MARK. It will not be
+ * de-asserted before the number of packets drops below LOW_WATER_MARK.
+ */
+#define LOW_WATER_MARK   hsi_low_threshold
+#define HIGH_WATER_MARK  hsi_high_threshold
+
+static LIST_HEAD(cfhsi_list);
+static spinlock_t cfhsi_list_lock;
+
+static void cfhsi_inactivity_tout(unsigned long arg)
+{
+       struct cfhsi *cfhsi = (struct cfhsi *)arg;
+
+       dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+               __func__);
+
+       /* Schedule power down work queue. */
+       if (!test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+               queue_work(cfhsi->wq, &cfhsi->wake_down_work);
+}
+
+static void cfhsi_abort_tx(struct cfhsi *cfhsi)
+{
+       struct sk_buff *skb;
+
+       for (;;) {
+               spin_lock_bh(&cfhsi->lock);
+               skb = skb_dequeue(&cfhsi->qhead);
+               if (!skb)
+                       break;
+
+               cfhsi->ndev->stats.tx_errors++;
+               cfhsi->ndev->stats.tx_dropped++;
+               spin_unlock_bh(&cfhsi->lock);
+               kfree_skb(skb);
+       }
+       cfhsi->tx_state = CFHSI_TX_STATE_IDLE;
+       if (!test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+               mod_timer(&cfhsi->timer, jiffies + CFHSI_INACTIVITY_TOUT);
+       spin_unlock_bh(&cfhsi->lock);
+}
+
+static int cfhsi_flush_fifo(struct cfhsi *cfhsi)
+{
+       char buffer[32]; /* Any reasonable value */
+       size_t fifo_occupancy;
+       int ret;
+
+       dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+               __func__);
+
+
+       ret = cfhsi->dev->cfhsi_wake_up(cfhsi->dev);
+       if (ret) {
+               dev_warn(&cfhsi->ndev->dev,
+                       "%s: can't wake up HSI interface: %d.\n",
+                       __func__, ret);
+               return ret;
+       }
+
+       do {
+               ret = cfhsi->dev->cfhsi_fifo_occupancy(cfhsi->dev,
+                               &fifo_occupancy);
+               if (ret) {
+                       dev_warn(&cfhsi->ndev->dev,
+                               "%s: can't get FIFO occupancy: %d.\n",
+                               __func__, ret);
+                       break;
+               } else if (!fifo_occupancy)
+                       /* No more data, exitting normally */
+                       break;
+
+               fifo_occupancy = min(sizeof(buffer), fifo_occupancy);
+               set_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits);
+               ret = cfhsi->dev->cfhsi_rx(buffer, fifo_occupancy,
+                               cfhsi->dev);
+               if (ret) {
+                       clear_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits);
+                       dev_warn(&cfhsi->ndev->dev,
+                               "%s: can't read data: %d.\n",
+                               __func__, ret);
+                       break;
+               }
+
+               ret = 5 * HZ;
+               wait_event_interruptible_timeout(cfhsi->flush_fifo_wait,
+                        !test_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits), ret);
+
+               if (ret < 0) {
+                       dev_warn(&cfhsi->ndev->dev,
+                               "%s: can't wait for flush complete: %d.\n",
+                               __func__, ret);
+                       break;
+               } else if (!ret) {
+                       ret = -ETIMEDOUT;
+                       dev_warn(&cfhsi->ndev->dev,
+                               "%s: timeout waiting for flush complete.\n",
+                               __func__);
+                       break;
+               }
+       } while (1);
+
+       cfhsi->dev->cfhsi_wake_down(cfhsi->dev);
+
+       return ret;
+}
+
+static int cfhsi_tx_frm(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
+{
+       int nfrms = 0;
+       int pld_len = 0;
+       struct sk_buff *skb;
+       u8 *pfrm = desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ;
+
+       skb = skb_dequeue(&cfhsi->qhead);
+       if (!skb)
+               return 0;
+
+       /* Check if we can embed a CAIF frame. */
+       if (skb->len < CFHSI_MAX_EMB_FRM_SZ) {
+               struct caif_payload_info *info;
+               int hpad = 0;
+               int tpad = 0;
+
+               /* Calculate needed head alignment and tail alignment. */
+               info = (struct caif_payload_info *)&skb->cb;
+
+               hpad = 1 + PAD_POW2((info->hdr_len + 1), hsi_head_align);
+               tpad = PAD_POW2((skb->len + hpad), hsi_tail_align);
+
+               /* Check if frame still fits with added alignment. */
+               if ((skb->len + hpad + tpad) <= CFHSI_MAX_EMB_FRM_SZ) {
+                       u8 *pemb = desc->emb_frm;
+                       desc->offset = CFHSI_DESC_SHORT_SZ;
+                       *pemb = (u8)(hpad - 1);
+                       pemb += hpad;
+
+                       /* Update network statistics. */
+                       cfhsi->ndev->stats.tx_packets++;
+                       cfhsi->ndev->stats.tx_bytes += skb->len;
+
+                       /* Copy in embedded CAIF frame. */
+                       skb_copy_bits(skb, 0, pemb, skb->len);
+                       consume_skb(skb);
+                       skb = NULL;
+               }
+       } else
+               /* Clear offset. */
+               desc->offset = 0;
+
+       /* Create payload CAIF frames. */
+       pfrm = desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ;
+       while (nfrms < CFHSI_MAX_PKTS) {
+               struct caif_payload_info *info;
+               int hpad = 0;
+               int tpad = 0;
+
+               if (!skb)
+                       skb = skb_dequeue(&cfhsi->qhead);
+
+               if (!skb)
+                       break;
+
+               /* Calculate needed head alignment and tail alignment. */
+               info = (struct caif_payload_info *)&skb->cb;
+
+               hpad = 1 + PAD_POW2((info->hdr_len + 1), hsi_head_align);
+               tpad = PAD_POW2((skb->len + hpad), hsi_tail_align);
+
+               /* Fill in CAIF frame length in descriptor. */
+               desc->cffrm_len[nfrms] = hpad + skb->len + tpad;
+
+               /* Fill head padding information. */
+               *pfrm = (u8)(hpad - 1);
+               pfrm += hpad;
+
+               /* Update network statistics. */
+               cfhsi->ndev->stats.tx_packets++;
+               cfhsi->ndev->stats.tx_bytes += skb->len;
+
+               /* Copy in CAIF frame. */
+               skb_copy_bits(skb, 0, pfrm, skb->len);
+
+               /* Update payload length. */
+               pld_len += desc->cffrm_len[nfrms];
+
+               /* Update frame pointer. */
+               pfrm += skb->len + tpad;
+               consume_skb(skb);
+               skb = NULL;
+
+               /* Update number of frames. */
+               nfrms++;
+       }
+
+       /* Unused length fields should be zero-filled (according to SPEC). */
+       while (nfrms < CFHSI_MAX_PKTS) {
+               desc->cffrm_len[nfrms] = 0x0000;
+               nfrms++;
+       }
+
+       /* Check if we can piggy-back another descriptor. */
+       skb = skb_peek(&cfhsi->qhead);
+       if (skb)
+               desc->header |= CFHSI_PIGGY_DESC;
+       else
+               desc->header &= ~CFHSI_PIGGY_DESC;
+
+       return CFHSI_DESC_SZ + pld_len;
+}
+
+static void cfhsi_tx_done_work(struct work_struct *work)
+{
+       struct cfhsi *cfhsi = NULL;
+       struct cfhsi_desc *desc = NULL;
+       int len = 0;
+       int res;
+
+       cfhsi = container_of(work, struct cfhsi, tx_done_work);
+       dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+               __func__);
+
+       if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+               return;
+
+       desc = (struct cfhsi_desc *)cfhsi->tx_buf;
+
+       do {
+               /*
+                * Send flow on if flow off has been previously signalled
+                * and number of packets is below low water mark.
+                */
+               spin_lock_bh(&cfhsi->lock);
+               if (cfhsi->flow_off_sent &&
+                               cfhsi->qhead.qlen <= cfhsi->q_low_mark &&
+                               cfhsi->cfdev.flowctrl) {
+
+                       cfhsi->flow_off_sent = 0;
+                       cfhsi->cfdev.flowctrl(cfhsi->ndev, ON);
+               }
+               spin_unlock_bh(&cfhsi->lock);
+
+               /* Create HSI frame. */
+               len = cfhsi_tx_frm(desc, cfhsi);
+               if (!len) {
+                       cfhsi->tx_state = CFHSI_TX_STATE_IDLE;
+                       /* Start inactivity timer. */
+                       mod_timer(&cfhsi->timer,
+                                       jiffies + CFHSI_INACTIVITY_TOUT);
+                       break;
+               }
+
+               /* Set up new transfer. */
+               res = cfhsi->dev->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->dev);
+               if (WARN_ON(res < 0)) {
+                       dev_err(&cfhsi->ndev->dev, "%s: TX error %d.\n",
+                               __func__, res);
+               }
+       } while (res < 0);
+}
+
+static void cfhsi_tx_done_cb(struct cfhsi_drv *drv)
+{
+       struct cfhsi *cfhsi;
+
+       cfhsi = container_of(drv, struct cfhsi, drv);
+       dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+               __func__);
+
+       if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+               return;
+
+       queue_work(cfhsi->wq, &cfhsi->tx_done_work);
+}
+
+static int cfhsi_rx_desc(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
+{
+       int xfer_sz = 0;
+       int nfrms = 0;
+       u16 *plen = NULL;
+       u8 *pfrm = NULL;
+
+       if ((desc->header & ~CFHSI_PIGGY_DESC) ||
+                       (desc->offset > CFHSI_MAX_EMB_FRM_SZ)) {
+               dev_err(&cfhsi->ndev->dev, "%s: Invalid descriptor.\n",
+                       __func__);
+               return 0;
+       }
+
+       /* Check for embedded CAIF frame. */
+       if (desc->offset) {
+               struct sk_buff *skb;
+               u8 *dst = NULL;
+               int len = 0, retries = 0;
+               pfrm = ((u8 *)desc) + desc->offset;
+
+               /* Remove offset padding. */
+               pfrm += *pfrm + 1;
+
+               /* Read length of CAIF frame (little endian). */
+               len = *pfrm;
+               len |= ((*(pfrm+1)) << 8) & 0xFF00;
+               len += 2;       /* Add FCS fields. */
+
+
+               /* Allocate SKB (OK even in IRQ context). */
+               skb = alloc_skb(len + 1, GFP_KERNEL);
+               while (!skb) {
+                       retries++;
+                       schedule_timeout(1);
+                       skb = alloc_skb(len + 1, GFP_KERNEL);
+                       if (skb) {
+                               printk(KERN_WARNING "%s: slept for %u "
+                                               "before getting memory\n",
+                                               __func__, retries);
+                               break;
+                       }
+                       if (retries > HZ) {
+                               printk(KERN_ERR "%s: slept for 1HZ and "
+                                               "did not get memory\n",
+                                               __func__);
+                               cfhsi->ndev->stats.rx_dropped++;
+                               goto drop_frame;
+                       }
+               }
+               caif_assert(skb != NULL);
+
+               dst = skb_put(skb, len);
+               memcpy(dst, pfrm, len);
+
+               skb->protocol = htons(ETH_P_CAIF);
+               skb_reset_mac_header(skb);
+               skb->dev = cfhsi->ndev;
+
+               /*
+                * We are called from a arch specific platform device.
+                * Unfortunately we don't know what context we're
+                * running in.
+                */
+               if (in_interrupt())
+                       netif_rx(skb);
+               else
+                       netif_rx_ni(skb);
+
+               /* Update network statistics. */
+               cfhsi->ndev->stats.rx_packets++;
+               cfhsi->ndev->stats.rx_bytes += len;
+       }
+
+drop_frame:
+       /* Calculate transfer length. */
+       plen = desc->cffrm_len;
+       while (nfrms < CFHSI_MAX_PKTS && *plen) {
+               xfer_sz += *plen;
+               plen++;
+               nfrms++;
+       }
+
+       /* Check for piggy-backed descriptor. */
+       if (desc->header & CFHSI_PIGGY_DESC)
+               xfer_sz += CFHSI_DESC_SZ;
+
+       if (xfer_sz % 4) {
+               dev_err(&cfhsi->ndev->dev,
+                               "%s: Invalid payload len: %d, ignored.\n",
+                       __func__, xfer_sz);
+               xfer_sz = 0;
+       }
+
+       return xfer_sz;
+}
+
+static int cfhsi_rx_pld(struct cfhsi_desc *desc, struct cfhsi *cfhsi)
+{
+       int rx_sz = 0;
+       int nfrms = 0;
+       u16 *plen = NULL;
+       u8 *pfrm = NULL;
+
+       /* Sanity check header and offset. */
+       if (WARN_ON((desc->header & ~CFHSI_PIGGY_DESC) ||
+                       (desc->offset > CFHSI_MAX_EMB_FRM_SZ))) {
+               dev_err(&cfhsi->ndev->dev, "%s: Invalid descriptor.\n",
+                       __func__);
+               return -EINVAL;
+       }
+
+       /* Set frame pointer to start of payload. */
+       pfrm = desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ;
+       plen = desc->cffrm_len;
+       while (nfrms < CFHSI_MAX_PKTS && *plen) {
+               struct sk_buff *skb;
+               u8 *dst = NULL;
+               u8 *pcffrm = NULL;
+               int len = 0, retries = 0;
+
+               if (WARN_ON(desc->cffrm_len[nfrms] > CFHSI_MAX_PAYLOAD_SZ)) {
+                       dev_err(&cfhsi->ndev->dev, "%s: Invalid payload.\n",
+                               __func__);
+                       return -EINVAL;
+               }
+
+               /* CAIF frame starts after head padding. */
+               pcffrm = pfrm + *pfrm + 1;
+
+               /* Read length of CAIF frame (little endian). */
+               len = *pcffrm;
+               len |= ((*(pcffrm + 1)) << 8) & 0xFF00;
+               len += 2;       /* Add FCS fields. */
+
+               /* Allocate SKB (OK even in IRQ context). */
+               skb = alloc_skb(len + 1, GFP_KERNEL);
+               while (!skb) {
+                       retries++;
+                       schedule_timeout(1);
+                       skb = alloc_skb(len + 1, GFP_KERNEL);
+                       if (skb) {
+                               printk(KERN_WARNING "%s: slept for %u "
+                                               "before getting memory\n",
+                                               __func__, retries);
+                               break;
+                       }
+                       if (retries > HZ) {
+                               printk(KERN_ERR "%s: slept for 1HZ "
+                                               "and did not get memory\n",
+                                               __func__);
+                               cfhsi->ndev->stats.rx_dropped++;
+                               goto drop_frame;
+                       }
+               }
+               caif_assert(skb != NULL);
+
+               dst = skb_put(skb, len);
+               memcpy(dst, pcffrm, len);
+
+               skb->protocol = htons(ETH_P_CAIF);
+               skb_reset_mac_header(skb);
+               skb->dev = cfhsi->ndev;
+
+               /*
+                * We're called from a platform device,
+                * and don't know the context we're running in.
+                */
+               if (in_interrupt())
+                       netif_rx(skb);
+               else
+                       netif_rx_ni(skb);
+
+               /* Update network statistics. */
+               cfhsi->ndev->stats.rx_packets++;
+               cfhsi->ndev->stats.rx_bytes += len;
+
+drop_frame:
+               pfrm += *plen;
+               rx_sz += *plen;
+               plen++;
+               nfrms++;
+       }
+
+       return rx_sz;
+}
+
+static void cfhsi_rx_done_work(struct work_struct *work)
+{
+       int res;
+       int desc_pld_len = 0;
+       struct cfhsi *cfhsi = NULL;
+       struct cfhsi_desc *desc = NULL;
+
+       cfhsi = container_of(work, struct cfhsi, rx_done_work);
+       desc = (struct cfhsi_desc *)cfhsi->rx_buf;
+
+       dev_dbg(&cfhsi->ndev->dev, "%s: Kick timer if pending.\n",
+               __func__);
+
+       if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+               return;
+
+       /* Update inactivity timer if pending. */
+       mod_timer_pending(&cfhsi->timer, jiffies + CFHSI_INACTIVITY_TOUT);
+
+       if (cfhsi->rx_state == CFHSI_RX_STATE_DESC) {
+               desc_pld_len = cfhsi_rx_desc(desc, cfhsi);
+       } else {
+               int pld_len;
+
+               pld_len = cfhsi_rx_pld(desc, cfhsi);
+
+               if ((pld_len > 0) && (desc->header & CFHSI_PIGGY_DESC)) {
+                       struct cfhsi_desc *piggy_desc;
+                       piggy_desc = (struct cfhsi_desc *)
+                               (desc->emb_frm + CFHSI_MAX_EMB_FRM_SZ +
+                                               pld_len);
+
+                       /* Extract piggy-backed descriptor. */
+                       desc_pld_len = cfhsi_rx_desc(piggy_desc, cfhsi);
+
+                       /*
+                        * Copy needed information from the piggy-backed
+                        * descriptor to the descriptor in the start.
+                        */
+                       memcpy((u8 *)desc, (u8 *)piggy_desc,
+                                       CFHSI_DESC_SHORT_SZ);
+               }
+       }
+
+       if (desc_pld_len) {
+               cfhsi->rx_state = CFHSI_RX_STATE_PAYLOAD;
+               cfhsi->rx_ptr = cfhsi->rx_buf + CFHSI_DESC_SZ;
+               cfhsi->rx_len = desc_pld_len;
+       } else {
+               cfhsi->rx_state = CFHSI_RX_STATE_DESC;
+               cfhsi->rx_ptr = cfhsi->rx_buf;
+               cfhsi->rx_len = CFHSI_DESC_SZ;
+       }
+       clear_bit(CFHSI_PENDING_RX, &cfhsi->bits);
+
+       if (test_bit(CFHSI_AWAKE, &cfhsi->bits)) {
+               /* Set up new transfer. */
+               dev_dbg(&cfhsi->ndev->dev, "%s: Start RX.\n",
+                       __func__);
+               res = cfhsi->dev->cfhsi_rx(cfhsi->rx_ptr, cfhsi->rx_len,
+                               cfhsi->dev);
+               if (WARN_ON(res < 0)) {
+                       dev_err(&cfhsi->ndev->dev, "%s: RX error %d.\n",
+                               __func__, res);
+                       cfhsi->ndev->stats.rx_errors++;
+                       cfhsi->ndev->stats.rx_dropped++;
+               }
+       }
+}
+
+static void cfhsi_rx_done_cb(struct cfhsi_drv *drv)
+{
+       struct cfhsi *cfhsi;
+
+       cfhsi = container_of(drv, struct cfhsi, drv);
+       dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+               __func__);
+
+       if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+               return;
+
+       set_bit(CFHSI_PENDING_RX, &cfhsi->bits);
+
+       if (test_and_clear_bit(CFHSI_FLUSH_FIFO, &cfhsi->bits))
+               wake_up_interruptible(&cfhsi->flush_fifo_wait);
+       else
+               queue_work(cfhsi->wq, &cfhsi->rx_done_work);
+}
+
+static void cfhsi_wake_up(struct work_struct *work)
+{
+       struct cfhsi *cfhsi = NULL;
+       int res;
+       int len;
+       long ret;
+
+       cfhsi = container_of(work, struct cfhsi, wake_up_work);
+
+       if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+               return;
+
+       if (unlikely(test_bit(CFHSI_AWAKE, &cfhsi->bits))) {
+               /* It happenes when wakeup is requested by
+                * both ends at the same time. */
+               clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
+               return;
+       }
+
+       /* Activate wake line. */
+       cfhsi->dev->cfhsi_wake_up(cfhsi->dev);
+
+       dev_dbg(&cfhsi->ndev->dev, "%s: Start waiting.\n",
+               __func__);
+
+       /* Wait for acknowledge. */
+       ret = CFHSI_WAKEUP_TOUT;
+       wait_event_interruptible_timeout(cfhsi->wake_up_wait,
+                                       test_bit(CFHSI_WAKE_UP_ACK,
+                                                       &cfhsi->bits), ret);
+       if (unlikely(ret < 0)) {
+               /* Interrupted by signal. */
+               dev_info(&cfhsi->ndev->dev, "%s: Signalled: %ld.\n",
+                       __func__, ret);
+               clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
+               cfhsi->dev->cfhsi_wake_down(cfhsi->dev);
+               return;
+       } else if (!ret) {
+               /* Wakeup timeout */
+               dev_err(&cfhsi->ndev->dev, "%s: Timeout.\n",
+                       __func__);
+               clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
+               cfhsi->dev->cfhsi_wake_down(cfhsi->dev);
+               return;
+       }
+       dev_dbg(&cfhsi->ndev->dev, "%s: Woken.\n",
+               __func__);
+
+       /* Clear power up bit. */
+       set_bit(CFHSI_AWAKE, &cfhsi->bits);
+       clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
+
+       /* Resume read operation. */
+       if (!test_bit(CFHSI_PENDING_RX, &cfhsi->bits)) {
+               dev_dbg(&cfhsi->ndev->dev, "%s: Start RX.\n",
+                       __func__);
+               res = cfhsi->dev->cfhsi_rx(cfhsi->rx_ptr,
+                               cfhsi->rx_len, cfhsi->dev);
+               if (WARN_ON(res < 0)) {
+                       dev_err(&cfhsi->ndev->dev, "%s: RX error %d.\n",
+                               __func__, res);
+               }
+       }
+
+       /* Clear power up acknowledment. */
+       clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits);
+
+       spin_lock_bh(&cfhsi->lock);
+
+       /* Resume transmit if queue is not empty. */
+       if (!skb_peek(&cfhsi->qhead)) {
+               dev_dbg(&cfhsi->ndev->dev, "%s: Peer wake, start timer.\n",
+                       __func__);
+               /* Start inactivity timer. */
+               mod_timer(&cfhsi->timer,
+                               jiffies + CFHSI_INACTIVITY_TOUT);
+               spin_unlock_bh(&cfhsi->lock);
+               return;
+       }
+
+       dev_dbg(&cfhsi->ndev->dev, "%s: Host wake.\n",
+               __func__);
+
+       spin_unlock_bh(&cfhsi->lock);
+
+       /* Create HSI frame. */
+       len = cfhsi_tx_frm((struct cfhsi_desc *)cfhsi->tx_buf, cfhsi);
+
+       if (likely(len > 0)) {
+               /* Set up new transfer. */
+               res = cfhsi->dev->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->dev);
+               if (WARN_ON(res < 0)) {
+                       dev_err(&cfhsi->ndev->dev, "%s: TX error %d.\n",
+                               __func__, res);
+                       cfhsi_abort_tx(cfhsi);
+               }
+       } else {
+               dev_err(&cfhsi->ndev->dev,
+                               "%s: Failed to create HSI frame: %d.\n",
+                               __func__, len);
+       }
+
+}
+
+static void cfhsi_wake_down(struct work_struct *work)
+{
+       long ret;
+       struct cfhsi *cfhsi = NULL;
+       size_t fifo_occupancy;
+
+       cfhsi = container_of(work, struct cfhsi, wake_down_work);
+       dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+               __func__);
+
+       if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+               return;
+
+       /* Check if there is something in FIFO. */
+       if (WARN_ON(cfhsi->dev->cfhsi_fifo_occupancy(cfhsi->dev,
+                                                       &fifo_occupancy)))
+               fifo_occupancy = 0;
+
+       if (fifo_occupancy) {
+               dev_dbg(&cfhsi->ndev->dev,
+                               "%s: %u words in RX FIFO, restart timer.\n",
+                               __func__, (unsigned) fifo_occupancy);
+               spin_lock_bh(&cfhsi->lock);
+               mod_timer(&cfhsi->timer,
+                               jiffies + CFHSI_INACTIVITY_TOUT);
+               spin_unlock_bh(&cfhsi->lock);
+               return;
+       }
+
+       /* Cancel pending RX requests */
+       cfhsi->dev->cfhsi_rx_cancel(cfhsi->dev);
+
+       /* Deactivate wake line. */
+       cfhsi->dev->cfhsi_wake_down(cfhsi->dev);
+
+       /* Wait for acknowledge. */
+       ret = CFHSI_WAKEUP_TOUT;
+       ret = wait_event_interruptible_timeout(cfhsi->wake_down_wait,
+                                       test_bit(CFHSI_WAKE_DOWN_ACK,
+                                                       &cfhsi->bits),
+                                       ret);
+       if (ret < 0) {
+               /* Interrupted by signal. */
+               dev_info(&cfhsi->ndev->dev, "%s: Signalled: %ld.\n",
+                       __func__, ret);
+               return;
+       } else if (!ret) {
+               /* Timeout */
+               dev_err(&cfhsi->ndev->dev, "%s: Timeout.\n",
+                       __func__);
+       }
+
+       /* Clear power down acknowledment. */
+       clear_bit(CFHSI_WAKE_DOWN_ACK, &cfhsi->bits);
+       clear_bit(CFHSI_AWAKE, &cfhsi->bits);
+
+       /* Check if there is something in FIFO. */
+       if (WARN_ON(cfhsi->dev->cfhsi_fifo_occupancy(cfhsi->dev,
+                                                       &fifo_occupancy)))
+               fifo_occupancy = 0;
+
+       if (fifo_occupancy) {
+               dev_dbg(&cfhsi->ndev->dev,
+                               "%s: %u words in RX FIFO, wakeup forced.\n",
+                               __func__, (unsigned) fifo_occupancy);
+               if (!test_and_set_bit(CFHSI_WAKE_UP, &cfhsi->bits))
+                       queue_work(cfhsi->wq, &cfhsi->wake_up_work);
+       } else
+               dev_dbg(&cfhsi->ndev->dev, "%s: Done.\n",
+                       __func__);
+}
+
+static void cfhsi_wake_up_cb(struct cfhsi_drv *drv)
+{
+       struct cfhsi *cfhsi = NULL;
+
+       cfhsi = container_of(drv, struct cfhsi, drv);
+       dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+               __func__);
+
+       set_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits);
+       wake_up_interruptible(&cfhsi->wake_up_wait);
+
+       if (test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))
+               return;
+
+       /* Schedule wake up work queue if the peer initiates. */
+       if (!test_and_set_bit(CFHSI_WAKE_UP, &cfhsi->bits))
+               queue_work(cfhsi->wq, &cfhsi->wake_up_work);
+}
+
+static void cfhsi_wake_down_cb(struct cfhsi_drv *drv)
+{
+       struct cfhsi *cfhsi = NULL;
+
+       cfhsi = container_of(drv, struct cfhsi, drv);
+       dev_dbg(&cfhsi->ndev->dev, "%s.\n",
+               __func__);
+
+       /* Initiating low power is only permitted by the host (us). */
+       set_bit(CFHSI_WAKE_DOWN_ACK, &cfhsi->bits);
+       wake_up_interruptible(&cfhsi->wake_down_wait);
+}
+
+static int cfhsi_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct cfhsi *cfhsi = NULL;
+       int start_xfer = 0;
+       int timer_active;
+
+       if (!dev)
+               return -EINVAL;
+
+       cfhsi = netdev_priv(dev);
+
+       spin_lock_bh(&cfhsi->lock);
+
+       skb_queue_tail(&cfhsi->qhead, skb);
+
+       /* Sanity check; xmit should not be called after unregister_netdev */
+       if (WARN_ON(test_bit(CFHSI_SHUTDOWN, &cfhsi->bits))) {
+               spin_unlock_bh(&cfhsi->lock);
+               cfhsi_abort_tx(cfhsi);
+               return -EINVAL;
+       }
+
+       /* Send flow off if number of packets is above high water mark. */
+       if (!cfhsi->flow_off_sent &&
+               cfhsi->qhead.qlen > cfhsi->q_high_mark &&
+               cfhsi->cfdev.flowctrl) {
+               cfhsi->flow_off_sent = 1;
+               cfhsi->cfdev.flowctrl(cfhsi->ndev, OFF);
+       }
+
+       if (cfhsi->tx_state == CFHSI_TX_STATE_IDLE) {
+               cfhsi->tx_state = CFHSI_TX_STATE_XFER;
+               start_xfer = 1;
+       }
+
+       spin_unlock_bh(&cfhsi->lock);
+
+       if (!start_xfer)
+               return 0;
+
+       /* Delete inactivity timer if started. */
+#ifdef CONFIG_SMP
+       timer_active = del_timer_sync(&cfhsi->timer);
+#else
+       timer_active = del_timer(&cfhsi->timer);
+#endif /* CONFIG_SMP */
+
+       if (timer_active) {
+               struct cfhsi_desc *desc = (struct cfhsi_desc *)cfhsi->tx_buf;
+               int len;
+               int res;
+
+               /* Create HSI frame. */
+               len = cfhsi_tx_frm(desc, cfhsi);
+               BUG_ON(!len);
+
+               /* Set up new transfer. */
+               res = cfhsi->dev->cfhsi_tx(cfhsi->tx_buf, len, cfhsi->dev);
+               if (WARN_ON(res < 0)) {
+                       dev_err(&cfhsi->ndev->dev, "%s: TX error %d.\n",
+                               __func__, res);
+                       cfhsi_abort_tx(cfhsi);
+               }
+       } else {
+               /* Schedule wake up work queue if the we initiate. */
+               if (!test_and_set_bit(CFHSI_WAKE_UP, &cfhsi->bits))
+                       queue_work(cfhsi->wq, &cfhsi->wake_up_work);
+       }
+
+       return 0;
+}
+
+static int cfhsi_open(struct net_device *dev)
+{
+       netif_wake_queue(dev);
+
+       return 0;
+}
+
+static int cfhsi_close(struct net_device *dev)
+{
+       netif_stop_queue(dev);
+
+       return 0;
+}
+
+static const struct net_device_ops cfhsi_ops = {
+       .ndo_open = cfhsi_open,
+       .ndo_stop = cfhsi_close,
+       .ndo_start_xmit = cfhsi_xmit
+};
+
+static void cfhsi_setup(struct net_device *dev)
+{
+       struct cfhsi *cfhsi = netdev_priv(dev);
+       dev->features = 0;
+       dev->netdev_ops = &cfhsi_ops;
+       dev->type = ARPHRD_CAIF;
+       dev->flags = IFF_POINTOPOINT | IFF_NOARP;
+       dev->mtu = CFHSI_MAX_PAYLOAD_SZ;
+       dev->tx_queue_len = 0;
+       dev->destructor = free_netdev;
+       skb_queue_head_init(&cfhsi->qhead);
+       cfhsi->cfdev.link_select = CAIF_LINK_HIGH_BANDW;
+       cfhsi->cfdev.use_frag = false;
+       cfhsi->cfdev.use_stx = false;
+       cfhsi->cfdev.use_fcs = false;
+       cfhsi->ndev = dev;
+}
+
+int cfhsi_probe(struct platform_device *pdev)
+{
+       struct cfhsi *cfhsi = NULL;
+       struct net_device *ndev;
+       struct cfhsi_dev *dev;
+       int res;
+
+       ndev = alloc_netdev(sizeof(struct cfhsi), "cfhsi%d", cfhsi_setup);
+       if (!ndev) {
+               dev_err(&pdev->dev, "%s: alloc_netdev failed.\n",
+                       __func__);
+               return -ENODEV;
+       }
+
+       cfhsi = netdev_priv(ndev);
+       cfhsi->ndev = ndev;
+       cfhsi->pdev = pdev;
+
+       /* Initialize state vaiables. */
+       cfhsi->tx_state = CFHSI_TX_STATE_IDLE;
+       cfhsi->rx_state = CFHSI_RX_STATE_DESC;
+
+       /* Set flow info */
+       cfhsi->flow_off_sent = 0;
+       cfhsi->q_low_mark = LOW_WATER_MARK;
+       cfhsi->q_high_mark = HIGH_WATER_MARK;
+
+       /* Assign the HSI device. */
+       dev = (struct cfhsi_dev *)pdev->dev.platform_data;
+       cfhsi->dev = dev;
+
+       /* Assign the driver to this HSI device. */
+       dev->drv = &cfhsi->drv;
+
+       /*
+        * Allocate a TX buffer with the size of a HSI packet descriptors
+        * and the necessary room for CAIF payload frames.
+        */
+       cfhsi->tx_buf = kzalloc(CFHSI_BUF_SZ_TX, GFP_KERNEL);
+       if (!cfhsi->tx_buf) {
+               dev_err(&ndev->dev, "%s: Failed to allocate TX buffer.\n",
+                       __func__);
+               res = -ENODEV;
+               goto err_alloc_tx;
+       }
+
+       /*
+        * Allocate a RX buffer with the size of two HSI packet descriptors and
+        * the necessary room for CAIF payload frames.
+        */
+       cfhsi->rx_buf = kzalloc(CFHSI_BUF_SZ_RX, GFP_KERNEL);
+       if (!cfhsi->rx_buf) {
+               dev_err(&ndev->dev, "%s: Failed to allocate RX buffer.\n",
+                       __func__);
+               res = -ENODEV;
+               goto err_alloc_rx;
+       }
+
+       /* Initialize recieve vaiables. */
+       cfhsi->rx_ptr = cfhsi->rx_buf;
+       cfhsi->rx_len = CFHSI_DESC_SZ;
+
+       /* Initialize spin locks. */
+       spin_lock_init(&cfhsi->lock);
+
+       /* Set up the driver. */
+       cfhsi->drv.tx_done_cb = cfhsi_tx_done_cb;
+       cfhsi->drv.rx_done_cb = cfhsi_rx_done_cb;
+
+       /* Initialize the work queues. */
+       INIT_WORK(&cfhsi->wake_up_work, cfhsi_wake_up);
+       INIT_WORK(&cfhsi->wake_down_work, cfhsi_wake_down);
+       INIT_WORK(&cfhsi->rx_done_work, cfhsi_rx_done_work);
+       INIT_WORK(&cfhsi->tx_done_work, cfhsi_tx_done_work);
+
+       /* Clear all bit fields. */
+       clear_bit(CFHSI_WAKE_UP_ACK, &cfhsi->bits);
+       clear_bit(CFHSI_WAKE_DOWN_ACK, &cfhsi->bits);
+       clear_bit(CFHSI_WAKE_UP, &cfhsi->bits);
+       clear_bit(CFHSI_AWAKE, &cfhsi->bits);
+       clear_bit(CFHSI_PENDING_RX, &cfhsi->bits);
+
+       /* Create work thread. */
+       cfhsi->wq = create_singlethread_workqueue(pdev->name);
+       if (!cfhsi->wq) {
+               dev_err(&ndev->dev, "%s: Failed to create work queue.\n",
+                       __func__);
+               res = -ENODEV;
+               goto err_create_wq;
+       }
+
+       /* Initialize wait queues. */
+       init_waitqueue_head(&cfhsi->wake_up_wait);
+       init_waitqueue_head(&cfhsi->wake_down_wait);
+       init_waitqueue_head(&cfhsi->flush_fifo_wait);
+
+       /* Setup the inactivity timer. */
+       init_timer(&cfhsi->timer);
+       cfhsi->timer.data = (unsigned long)cfhsi;
+       cfhsi->timer.function = cfhsi_inactivity_tout;
+
+       /* Add CAIF HSI device to list. */
+       spin_lock(&cfhsi_list_lock);
+       list_add_tail(&cfhsi->list, &cfhsi_list);
+       spin_unlock(&cfhsi_list_lock);
+
+       /* Activate HSI interface. */
+       res = cfhsi->dev->cfhsi_up(cfhsi->dev);
+       if (res) {
+               dev_err(&cfhsi->ndev->dev,
+                       "%s: can't activate HSI interface: %d.\n",
+                       __func__, res);
+               goto err_activate;
+       }
+
+       /* Flush FIFO */
+       res = cfhsi_flush_fifo(cfhsi);
+       if (res) {
+               dev_err(&ndev->dev, "%s: Can't flush FIFO: %d.\n",
+                       __func__, res);
+               goto err_net_reg;
+       }
+
+       cfhsi->drv.wake_up_cb = cfhsi_wake_up_cb;
+       cfhsi->drv.wake_down_cb = cfhsi_wake_down_cb;
+
+       /* Register network device. */
+       res = register_netdev(ndev);
+       if (res) {
+               dev_err(&ndev->dev, "%s: Registration error: %d.\n",
+                       __func__, res);
+               goto err_net_reg;
+       }
+
+       netif_stop_queue(ndev);
+
+       return res;
+
+ err_net_reg:
+       cfhsi->dev->cfhsi_down(cfhsi->dev);
+ err_activate:
+       destroy_workqueue(cfhsi->wq);
+ err_create_wq:
+       kfree(cfhsi->rx_buf);
+ err_alloc_rx:
+       kfree(cfhsi->tx_buf);
+ err_alloc_tx:
+       free_netdev(ndev);
+
+       return res;
+}
+
+static void cfhsi_shutdown(struct cfhsi *cfhsi, bool remove_platform_dev)
+{
+       u8 *tx_buf, *rx_buf;
+
+       /* Stop TXing */
+       netif_tx_stop_all_queues(cfhsi->ndev);
+
+       /* going to shutdown driver */
+       set_bit(CFHSI_SHUTDOWN, &cfhsi->bits);
+
+       if (remove_platform_dev) {
+               /* Flush workqueue */
+               flush_workqueue(cfhsi->wq);
+
+               /* Notify device. */
+               platform_device_unregister(cfhsi->pdev);
+       }
+
+       /* Flush workqueue */
+       flush_workqueue(cfhsi->wq);
+
+       /* Delete timer if pending */
+#ifdef CONFIG_SMP
+       del_timer_sync(&cfhsi->timer);
+#else
+       del_timer(&cfhsi->timer);
+#endif /* CONFIG_SMP */
+
+       /* Cancel pending RX request (if any) */
+       cfhsi->dev->cfhsi_rx_cancel(cfhsi->dev);
+
+       /* Flush again and destroy workqueue */
+       destroy_workqueue(cfhsi->wq);
+
+       /* Store bufferes: will be freed later. */
+       tx_buf = cfhsi->tx_buf;
+       rx_buf = cfhsi->rx_buf;
+
+       /* Flush transmit queues. */
+       cfhsi_abort_tx(cfhsi);
+
+       /* Deactivate interface */
+       cfhsi->dev->cfhsi_down(cfhsi->dev);
+
+       /* Finally unregister the network device. */
+       unregister_netdev(cfhsi->ndev);
+
+       /* Free buffers. */
+       kfree(tx_buf);
+       kfree(rx_buf);
+}
+
+int cfhsi_remove(struct platform_device *pdev)
+{
+       struct list_head *list_node;
+       struct list_head *n;
+       struct cfhsi *cfhsi = NULL;
+       struct cfhsi_dev *dev;
+
+       dev = (struct cfhsi_dev *)pdev->dev.platform_data;
+       spin_lock(&cfhsi_list_lock);
+       list_for_each_safe(list_node, n, &cfhsi_list) {
+               cfhsi = list_entry(list_node, struct cfhsi, list);
+               /* Find the corresponding device. */
+               if (cfhsi->dev == dev) {
+                       /* Remove from list. */
+                       list_del(list_node);
+                       spin_unlock(&cfhsi_list_lock);
+
+                       /* Shutdown driver. */
+                       cfhsi_shutdown(cfhsi, false);
+
+                       return 0;
+               }
+       }
+       spin_unlock(&cfhsi_list_lock);
+       return -ENODEV;
+}
+
+struct platform_driver cfhsi_plat_drv = {
+       .probe = cfhsi_probe,
+       .remove = cfhsi_remove,
+       .driver = {
+                  .name = "cfhsi",
+                  .owner = THIS_MODULE,
+                  },
+};
+
+static void __exit cfhsi_exit_module(void)
+{
+       struct list_head *list_node;
+       struct list_head *n;
+       struct cfhsi *cfhsi = NULL;
+
+       spin_lock(&cfhsi_list_lock);
+       list_for_each_safe(list_node, n, &cfhsi_list) {
+               cfhsi = list_entry(list_node, struct cfhsi, list);
+
+               /* Remove from list. */
+               list_del(list_node);
+               spin_unlock(&cfhsi_list_lock);
+
+               /* Shutdown driver. */
+               cfhsi_shutdown(cfhsi, true);
+
+               spin_lock(&cfhsi_list_lock);
+       }
+       spin_unlock(&cfhsi_list_lock);
+
+       /* Unregister platform driver. */
+       platform_driver_unregister(&cfhsi_plat_drv);
+}
+
+static int __init cfhsi_init_module(void)
+{
+       int result;
+
+       /* Initialize spin lock. */
+       spin_lock_init(&cfhsi_list_lock);
+
+       /* Register platform driver. */
+       result = platform_driver_register(&cfhsi_plat_drv);
+       if (result) {
+               printk(KERN_ERR "Could not register platform HSI driver: %d.\n",
+                       result);
+               goto err_dev_register;
+       }
+
+       return result;
+
+ err_dev_register:
+       return result;
+}
+
+module_init(cfhsi_init_module);
+module_exit(cfhsi_exit_module);
index 73c7e03..1cd0b59 100644 (file)
@@ -4,6 +4,7 @@
  * License terms: GNU General Public License (GPL) version 2
  */
 
+#include <linux/hardirq.h>
 #include <linux/init.h>
 #include <linux/version.h>
 #include <linux/module.h>
@@ -167,8 +168,8 @@ static inline void debugfs_tx(struct ser_device *ser, const u8 *data, int size)
 
 #endif
 
-static unsigned int ldisc_receive(struct tty_struct *tty,
-               const u8 *data, char *flags, int count)
+static void ldisc_receive(struct tty_struct *tty, const u8 *data,
+                       char *flags, int count)
 {
        struct sk_buff *skb = NULL;
        struct ser_device *ser;
@@ -215,8 +216,6 @@ static unsigned int ldisc_receive(struct tty_struct *tty,
        } else
                ++ser->dev->stats.rx_dropped;
        update_tty_status(ser);
-
-       return count;
 }
 
 static int handle_tx(struct ser_device *ser)
index 1d699e3..bbf06f7 100644 (file)
@@ -58,9 +58,10 @@ config CAN_CALC_BITTIMING
 
 config CAN_AT91
        tristate "Atmel AT91 onchip CAN controller"
-       depends on CAN_DEV && ARCH_AT91SAM9263
+       depends on CAN_DEV && (ARCH_AT91SAM9263 || ARCH_AT91SAM9X5)
        ---help---
-         This is a driver for the SoC CAN controller in Atmel's AT91SAM9263.
+         This is a driver for the SoC CAN controller in Atmel's AT91SAM9263
+         and AT91SAM9X5 processors.
 
 config CAN_TI_HECC
        depends on CAN_DEV && ARCH_OMAP3
index 74efb5a..121ede6 100644 (file)
 
 #include <mach/board.h>
 
-#define AT91_NAPI_WEIGHT       11
-
-/*
- * RX/TX Mailbox split
- * don't dare to touch
- */
-#define AT91_MB_RX_NUM         11
-#define AT91_MB_TX_SHIFT       2
-
-#define AT91_MB_RX_FIRST       1
-#define AT91_MB_RX_LAST                (AT91_MB_RX_FIRST + AT91_MB_RX_NUM - 1)
-
-#define AT91_MB_RX_MASK(i)     ((1 << (i)) - 1)
-#define AT91_MB_RX_SPLIT       8
-#define AT91_MB_RX_LOW_LAST    (AT91_MB_RX_SPLIT - 1)
-#define AT91_MB_RX_LOW_MASK    (AT91_MB_RX_MASK(AT91_MB_RX_SPLIT) & \
-                                ~AT91_MB_RX_MASK(AT91_MB_RX_FIRST))
-
-#define AT91_MB_TX_NUM         (1 << AT91_MB_TX_SHIFT)
-#define AT91_MB_TX_FIRST       (AT91_MB_RX_LAST + 1)
-#define AT91_MB_TX_LAST                (AT91_MB_TX_FIRST + AT91_MB_TX_NUM - 1)
-
-#define AT91_NEXT_PRIO_SHIFT   (AT91_MB_TX_SHIFT)
-#define AT91_NEXT_PRIO_MASK    (0xf << AT91_MB_TX_SHIFT)
-#define AT91_NEXT_MB_MASK      (AT91_MB_TX_NUM - 1)
-#define AT91_NEXT_MASK         ((AT91_MB_TX_NUM - 1) | AT91_NEXT_PRIO_MASK)
+#define AT91_MB_MASK(i)                ((1 << (i)) - 1)
 
 /* Common registers */
 enum at91_reg {
@@ -128,12 +103,6 @@ enum at91_mb_mode {
 };
 
 /* Interrupt mask bits */
-#define AT91_IRQ_MB_RX         ((1 << (AT91_MB_RX_LAST + 1)) \
-                                - (1 << AT91_MB_RX_FIRST))
-#define AT91_IRQ_MB_TX         ((1 << (AT91_MB_TX_LAST + 1)) \
-                                - (1 << AT91_MB_TX_FIRST))
-#define AT91_IRQ_MB_ALL                (AT91_IRQ_MB_RX | AT91_IRQ_MB_TX)
-
 #define AT91_IRQ_ERRA          (1 << 16)
 #define AT91_IRQ_WARN          (1 << 17)
 #define AT91_IRQ_ERRP          (1 << 18)
@@ -156,22 +125,51 @@ enum at91_mb_mode {
 
 #define AT91_IRQ_ALL           (0x1fffffff)
 
+enum at91_devtype {
+       AT91_DEVTYPE_SAM9263,
+       AT91_DEVTYPE_SAM9X5,
+};
+
+struct at91_devtype_data {
+       unsigned int rx_first;
+       unsigned int rx_split;
+       unsigned int rx_last;
+       unsigned int tx_shift;
+       enum at91_devtype type;
+};
+
 struct at91_priv {
-       struct can_priv         can;       /* must be the first member! */
-       struct net_device       *dev;
-       struct napi_struct      napi;
+       struct can_priv can;            /* must be the first member! */
+       struct net_device *dev;
+       struct napi_struct napi;
 
-       void __iomem            *reg_base;
+       void __iomem *reg_base;
 
-       u32                     reg_sr;
-       unsigned int            tx_next;
-       unsigned int            tx_echo;
-       unsigned int            rx_next;
+       u32 reg_sr;
+       unsigned int tx_next;
+       unsigned int tx_echo;
+       unsigned int rx_next;
+       struct at91_devtype_data devtype_data;
 
-       struct clk              *clk;
-       struct at91_can_data    *pdata;
+       struct clk *clk;
+       struct at91_can_data *pdata;
 
-       canid_t                 mb0_id;
+       canid_t mb0_id;
+};
+
+static const struct at91_devtype_data at91_devtype_data[] __devinitconst = {
+       [AT91_DEVTYPE_SAM9263] = {
+               .rx_first = 1,
+               .rx_split = 8,
+               .rx_last = 11,
+               .tx_shift = 2,
+       },
+       [AT91_DEVTYPE_SAM9X5] = {
+               .rx_first = 0,
+               .rx_split = 4,
+               .rx_last = 5,
+               .tx_shift = 1,
+       },
 };
 
 static struct can_bittiming_const at91_bittiming_const = {
@@ -186,19 +184,111 @@ static struct can_bittiming_const at91_bittiming_const = {
        .brp_inc        = 1,
 };
 
-static inline int get_tx_next_mb(const struct at91_priv *priv)
+#define AT91_IS(_model) \
+static inline int at91_is_sam##_model(const struct at91_priv *priv) \
+{ \
+       return priv->devtype_data.type == AT91_DEVTYPE_SAM##_model; \
+}
+
+AT91_IS(9263);
+AT91_IS(9X5);
+
+static inline unsigned int get_mb_rx_first(const struct at91_priv *priv)
+{
+       return priv->devtype_data.rx_first;
+}
+
+static inline unsigned int get_mb_rx_last(const struct at91_priv *priv)
+{
+       return priv->devtype_data.rx_last;
+}
+
+static inline unsigned int get_mb_rx_split(const struct at91_priv *priv)
+{
+       return priv->devtype_data.rx_split;
+}
+
+static inline unsigned int get_mb_rx_num(const struct at91_priv *priv)
+{
+       return get_mb_rx_last(priv) - get_mb_rx_first(priv) + 1;
+}
+
+static inline unsigned int get_mb_rx_low_last(const struct at91_priv *priv)
+{
+       return get_mb_rx_split(priv) - 1;
+}
+
+static inline unsigned int get_mb_rx_low_mask(const struct at91_priv *priv)
+{
+       return AT91_MB_MASK(get_mb_rx_split(priv)) &
+               ~AT91_MB_MASK(get_mb_rx_first(priv));
+}
+
+static inline unsigned int get_mb_tx_shift(const struct at91_priv *priv)
+{
+       return priv->devtype_data.tx_shift;
+}
+
+static inline unsigned int get_mb_tx_num(const struct at91_priv *priv)
+{
+       return 1 << get_mb_tx_shift(priv);
+}
+
+static inline unsigned int get_mb_tx_first(const struct at91_priv *priv)
+{
+       return get_mb_rx_last(priv) + 1;
+}
+
+static inline unsigned int get_mb_tx_last(const struct at91_priv *priv)
+{
+       return get_mb_tx_first(priv) + get_mb_tx_num(priv) - 1;
+}
+
+static inline unsigned int get_next_prio_shift(const struct at91_priv *priv)
+{
+       return get_mb_tx_shift(priv);
+}
+
+static inline unsigned int get_next_prio_mask(const struct at91_priv *priv)
+{
+       return 0xf << get_mb_tx_shift(priv);
+}
+
+static inline unsigned int get_next_mb_mask(const struct at91_priv *priv)
+{
+       return AT91_MB_MASK(get_mb_tx_shift(priv));
+}
+
+static inline unsigned int get_next_mask(const struct at91_priv *priv)
+{
+       return get_next_mb_mask(priv) | get_next_prio_mask(priv);
+}
+
+static inline unsigned int get_irq_mb_rx(const struct at91_priv *priv)
 {
-       return (priv->tx_next & AT91_NEXT_MB_MASK) + AT91_MB_TX_FIRST;
+       return AT91_MB_MASK(get_mb_rx_last(priv) + 1) &
+               ~AT91_MB_MASK(get_mb_rx_first(priv));
 }
 
-static inline int get_tx_next_prio(const struct at91_priv *priv)
+static inline unsigned int get_irq_mb_tx(const struct at91_priv *priv)
 {
-       return (priv->tx_next >> AT91_NEXT_PRIO_SHIFT) & 0xf;
+       return AT91_MB_MASK(get_mb_tx_last(priv) + 1) &
+               ~AT91_MB_MASK(get_mb_tx_first(priv));
 }
 
-static inline int get_tx_echo_mb(const struct at91_priv *priv)
+static inline unsigned int get_tx_next_mb(const struct at91_priv *priv)
 {
-       return (priv->tx_echo & AT91_NEXT_MB_MASK) + AT91_MB_TX_FIRST;
+       return (priv->tx_next & get_next_mb_mask(priv)) + get_mb_tx_first(priv);
+}
+
+static inline unsigned int get_tx_next_prio(const struct at91_priv *priv)
+{
+       return (priv->tx_next >> get_next_prio_shift(priv)) & 0xf;
+}
+
+static inline unsigned int get_tx_echo_mb(const struct at91_priv *priv)
+{
+       return (priv->tx_echo & get_next_mb_mask(priv)) + get_mb_tx_first(priv);
 }
 
 static inline u32 at91_read(const struct at91_priv *priv, enum at91_reg reg)
@@ -259,29 +349,29 @@ static void at91_setup_mailboxes(struct net_device *dev)
         * overflow.
         */
        reg_mid = at91_can_id_to_reg_mid(priv->mb0_id);
-       for (i = 0; i < AT91_MB_RX_FIRST; i++) {
+       for (i = 0; i < get_mb_rx_first(priv); i++) {
                set_mb_mode(priv, i, AT91_MB_MODE_DISABLED);
                at91_write(priv, AT91_MID(i), reg_mid);
                at91_write(priv, AT91_MCR(i), 0x0);     /* clear dlc */
        }
 
-       for (i = AT91_MB_RX_FIRST; i < AT91_MB_RX_LAST; i++)
+       for (i = get_mb_rx_first(priv); i < get_mb_rx_last(priv); i++)
                set_mb_mode(priv, i, AT91_MB_MODE_RX);
-       set_mb_mode(priv, AT91_MB_RX_LAST, AT91_MB_MODE_RX_OVRWR);
+       set_mb_mode(priv, get_mb_rx_last(priv), AT91_MB_MODE_RX_OVRWR);
 
        /* reset acceptance mask and id register */
-       for (i = AT91_MB_RX_FIRST; i <= AT91_MB_RX_LAST; i++) {
-               at91_write(priv, AT91_MAM(i), 0x0 );
+       for (i = get_mb_rx_first(priv); i <= get_mb_rx_last(priv); i++) {
+               at91_write(priv, AT91_MAM(i), 0x0);
                at91_write(priv, AT91_MID(i), AT91_MID_MIDE);
        }
 
        /* The last 4 mailboxes are used for transmitting. */
-       for (i = AT91_MB_TX_FIRST; i <= AT91_MB_TX_LAST; i++)
+       for (i = get_mb_tx_first(priv); i <= get_mb_tx_last(priv); i++)
                set_mb_mode_prio(priv, i, AT91_MB_MODE_TX, 0);
 
        /* Reset tx and rx helper pointers */
        priv->tx_next = priv->tx_echo = 0;
-       priv->rx_next = AT91_MB_RX_FIRST;
+       priv->rx_next = get_mb_rx_first(priv);
 }
 
 static int at91_set_bittiming(struct net_device *dev)
@@ -336,7 +426,7 @@ static void at91_chip_start(struct net_device *dev)
        priv->can.state = CAN_STATE_ERROR_ACTIVE;
 
        /* Enable interrupts */
-       reg_ier = AT91_IRQ_MB_RX | AT91_IRQ_ERRP | AT91_IRQ_ERR_FRAME;
+       reg_ier = get_irq_mb_rx(priv) | AT91_IRQ_ERRP | AT91_IRQ_ERR_FRAME;
        at91_write(priv, AT91_IDR, AT91_IRQ_ALL);
        at91_write(priv, AT91_IER, reg_ier);
 }
@@ -375,8 +465,8 @@ static void at91_chip_stop(struct net_device *dev, enum can_state state)
  * mailbox, but without the offset AT91_MB_TX_FIRST. The lower bits
  * encode the mailbox number, the upper 4 bits the mailbox priority:
  *
- * priv->tx_next = (prio << AT91_NEXT_PRIO_SHIFT) ||
- *                 (mb - AT91_MB_TX_FIRST);
+ * priv->tx_next = (prio << get_next_prio_shift(priv)) |
+ *                 (mb - get_mb_tx_first(priv));
  *
  */
 static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
@@ -417,7 +507,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
        stats->tx_bytes += cf->can_dlc;
 
        /* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */
-       can_put_echo_skb(skb, dev, mb - AT91_MB_TX_FIRST);
+       can_put_echo_skb(skb, dev, mb - get_mb_tx_first(priv));
 
        /*
         * we have to stop the queue and deliver all messages in case
@@ -430,7 +520,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
        priv->tx_next++;
        if (!(at91_read(priv, AT91_MSR(get_tx_next_mb(priv))) &
              AT91_MSR_MRDY) ||
-           (priv->tx_next & AT91_NEXT_MASK) == 0)
+           (priv->tx_next & get_next_mask(priv)) == 0)
                netif_stop_queue(dev);
 
        /* Enable interrupt for this mailbox */
@@ -447,7 +537,7 @@ static netdev_tx_t at91_start_xmit(struct sk_buff *skb, struct net_device *dev)
  */
 static inline void at91_activate_rx_low(const struct at91_priv *priv)
 {
-       u32 mask = AT91_MB_RX_LOW_MASK;
+       u32 mask = get_mb_rx_low_mask(priv);
        at91_write(priv, AT91_TCR, mask);
 }
 
@@ -513,17 +603,19 @@ static void at91_read_mb(struct net_device *dev, unsigned int mb,
                cf->can_id = (reg_mid >> 18) & CAN_SFF_MASK;
 
        reg_msr = at91_read(priv, AT91_MSR(mb));
-       if (reg_msr & AT91_MSR_MRTR)
-               cf->can_id |= CAN_RTR_FLAG;
        cf->can_dlc = get_can_dlc((reg_msr >> 16) & 0xf);
 
-       *(u32 *)(cf->data + 0) = at91_read(priv, AT91_MDL(mb));
-       *(u32 *)(cf->data + 4) = at91_read(priv, AT91_MDH(mb));
+       if (reg_msr & AT91_MSR_MRTR)
+               cf->can_id |= CAN_RTR_FLAG;
+       else {
+               *(u32 *)(cf->data + 0) = at91_read(priv, AT91_MDL(mb));
+               *(u32 *)(cf->data + 4) = at91_read(priv, AT91_MDH(mb));
+       }
 
        /* allow RX of extended frames */
        at91_write(priv, AT91_MID(mb), AT91_MID_MIDE);
 
-       if (unlikely(mb == AT91_MB_RX_LAST && reg_msr & AT91_MSR_MMI))
+       if (unlikely(mb == get_mb_rx_last(priv) && reg_msr & AT91_MSR_MMI))
                at91_rx_overflow_err(dev);
 }
 
@@ -561,8 +653,9 @@ static void at91_read_msg(struct net_device *dev, unsigned int mb)
  *
  * Theory of Operation:
  *
- * 11 of the 16 mailboxes on the chip are reserved for RX. we split
- * them into 2 groups. The lower group holds 7 and upper 4 mailboxes.
+ * About 3/4 of the mailboxes (get_mb_rx_first()...get_mb_rx_last())
+ * on the chip are reserved for RX. We split them into 2 groups. The
+ * lower group ranges from get_mb_rx_first() to get_mb_rx_low_last().
  *
  * Like it or not, but the chip always saves a received CAN message
  * into the first free mailbox it finds (starting with the
@@ -610,23 +703,23 @@ static int at91_poll_rx(struct net_device *dev, int quota)
        unsigned int mb;
        int received = 0;
 
-       if (priv->rx_next > AT91_MB_RX_LOW_LAST &&
-           reg_sr & AT91_MB_RX_LOW_MASK)
+       if (priv->rx_next > get_mb_rx_low_last(priv) &&
+           reg_sr & get_mb_rx_low_mask(priv))
                netdev_info(dev,
                        "order of incoming frames cannot be guaranteed\n");
 
  again:
-       for (mb = find_next_bit(addr, AT91_MB_RX_LAST + 1, priv->rx_next);
-            mb < AT91_MB_RX_LAST + 1 && quota > 0;
+       for (mb = find_next_bit(addr, get_mb_tx_first(priv), priv->rx_next);
+            mb < get_mb_tx_first(priv) && quota > 0;
             reg_sr = at91_read(priv, AT91_SR),
-            mb = find_next_bit(addr, AT91_MB_RX_LAST + 1, ++priv->rx_next)) {
+            mb = find_next_bit(addr, get_mb_tx_first(priv), ++priv->rx_next)) {
                at91_read_msg(dev, mb);
 
                /* reactivate mailboxes */
-               if (mb == AT91_MB_RX_LOW_LAST)
+               if (mb == get_mb_rx_low_last(priv))
                        /* all lower mailboxed, if just finished it */
                        at91_activate_rx_low(priv);
-               else if (mb > AT91_MB_RX_LOW_LAST)
+               else if (mb > get_mb_rx_low_last(priv))
                        /* only the mailbox we read */
                        at91_activate_rx_mb(priv, mb);
 
@@ -635,9 +728,9 @@ static int at91_poll_rx(struct net_device *dev, int quota)
        }
 
        /* upper group completed, look again in lower */
-       if (priv->rx_next > AT91_MB_RX_LOW_LAST &&
-           quota > 0 && mb > AT91_MB_RX_LAST) {
-               priv->rx_next = AT91_MB_RX_FIRST;
+       if (priv->rx_next > get_mb_rx_low_last(priv) &&
+           quota > 0 && mb > get_mb_rx_last(priv)) {
+               priv->rx_next = get_mb_rx_first(priv);
                goto again;
        }
 
@@ -720,7 +813,7 @@ static int at91_poll(struct napi_struct *napi, int quota)
        u32 reg_sr = at91_read(priv, AT91_SR);
        int work_done = 0;
 
-       if (reg_sr & AT91_IRQ_MB_RX)
+       if (reg_sr & get_irq_mb_rx(priv))
                work_done += at91_poll_rx(dev, quota - work_done);
 
        /*
@@ -734,7 +827,7 @@ static int at91_poll(struct napi_struct *napi, int quota)
        if (work_done < quota) {
                /* enable IRQs for frame errors and all mailboxes >= rx_next */
                u32 reg_ier = AT91_IRQ_ERR_FRAME;
-               reg_ier |= AT91_IRQ_MB_RX & ~AT91_MB_RX_MASK(priv->rx_next);
+               reg_ier |= get_irq_mb_rx(priv) & ~AT91_MB_MASK(priv->rx_next);
 
                napi_complete(napi);
                at91_write(priv, AT91_IER, reg_ier);
@@ -783,7 +876,7 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)
                if (likely(reg_msr & AT91_MSR_MRDY &&
                           ~reg_msr & AT91_MSR_MABT)) {
                        /* _NOTE_: subtract AT91_MB_TX_FIRST offset from mb! */
-                       can_get_echo_skb(dev, mb - AT91_MB_TX_FIRST);
+                       can_get_echo_skb(dev, mb - get_mb_tx_first(priv));
                        dev->stats.tx_packets++;
                }
        }
@@ -793,8 +886,8 @@ static void at91_irq_tx(struct net_device *dev, u32 reg_sr)
         * we get a TX int for the last can frame directly before a
         * wrap around.
         */
-       if ((priv->tx_next & AT91_NEXT_MASK) != 0 ||
-           (priv->tx_echo & AT91_NEXT_MASK) == 0)
+       if ((priv->tx_next & get_next_mask(priv)) != 0 ||
+           (priv->tx_echo & get_next_mask(priv)) == 0)
                netif_wake_queue(dev);
 }
 
@@ -906,6 +999,29 @@ static void at91_irq_err_state(struct net_device *dev,
        at91_write(priv, AT91_IER, reg_ier);
 }
 
+static int at91_get_state_by_bec(const struct net_device *dev,
+               enum can_state *state)
+{
+       struct can_berr_counter bec;
+       int err;
+
+       err = at91_get_berr_counter(dev, &bec);
+       if (err)
+               return err;
+
+       if (bec.txerr < 96 && bec.rxerr < 96)
+               *state = CAN_STATE_ERROR_ACTIVE;
+       else if (bec.txerr < 128 && bec.rxerr < 128)
+               *state = CAN_STATE_ERROR_WARNING;
+       else if (bec.txerr < 256 && bec.rxerr < 256)
+               *state = CAN_STATE_ERROR_PASSIVE;
+       else
+               *state = CAN_STATE_BUS_OFF;
+
+       return 0;
+}
+
+
 static void at91_irq_err(struct net_device *dev)
 {
        struct at91_priv *priv = netdev_priv(dev);
@@ -913,21 +1029,28 @@ static void at91_irq_err(struct net_device *dev)
        struct can_frame *cf;
        enum can_state new_state;
        u32 reg_sr;
+       int err;
 
-       reg_sr = at91_read(priv, AT91_SR);
-
-       /* we need to look at the unmasked reg_sr */
-       if (unlikely(reg_sr & AT91_IRQ_BOFF))
-               new_state = CAN_STATE_BUS_OFF;
-       else if (unlikely(reg_sr & AT91_IRQ_ERRP))
-               new_state = CAN_STATE_ERROR_PASSIVE;
-       else if (unlikely(reg_sr & AT91_IRQ_WARN))
-               new_state = CAN_STATE_ERROR_WARNING;
-       else if (likely(reg_sr & AT91_IRQ_ERRA))
-               new_state = CAN_STATE_ERROR_ACTIVE;
-       else {
-               netdev_err(dev, "BUG! hardware in undefined state\n");
-               return;
+       if (at91_is_sam9263(priv)) {
+               reg_sr = at91_read(priv, AT91_SR);
+
+               /* we need to look at the unmasked reg_sr */
+               if (unlikely(reg_sr & AT91_IRQ_BOFF))
+                       new_state = CAN_STATE_BUS_OFF;
+               else if (unlikely(reg_sr & AT91_IRQ_ERRP))
+                       new_state = CAN_STATE_ERROR_PASSIVE;
+               else if (unlikely(reg_sr & AT91_IRQ_WARN))
+                       new_state = CAN_STATE_ERROR_WARNING;
+               else if (likely(reg_sr & AT91_IRQ_ERRA))
+                       new_state = CAN_STATE_ERROR_ACTIVE;
+               else {
+                       netdev_err(dev, "BUG! hardware in undefined state\n");
+                       return;
+               }
+       } else {
+               err = at91_get_state_by_bec(dev, &new_state);
+               if (err)
+                       return;
        }
 
        /* state hasn't changed */
@@ -968,19 +1091,19 @@ static irqreturn_t at91_irq(int irq, void *dev_id)
        handled = IRQ_HANDLED;
 
        /* Receive or error interrupt? -> napi */
-       if (reg_sr & (AT91_IRQ_MB_RX | AT91_IRQ_ERR_FRAME)) {
+       if (reg_sr & (get_irq_mb_rx(priv) | AT91_IRQ_ERR_FRAME)) {
                /*
                 * The error bits are clear on read,
                 * save for later use.
                 */
                priv->reg_sr = reg_sr;
                at91_write(priv, AT91_IDR,
-                          AT91_IRQ_MB_RX | AT91_IRQ_ERR_FRAME);
+                          get_irq_mb_rx(priv) | AT91_IRQ_ERR_FRAME);
                napi_schedule(&priv->napi);
        }
 
        /* Transmission complete interrupt */
-       if (reg_sr & AT91_IRQ_MB_TX)
+       if (reg_sr & get_irq_mb_tx(priv))
                at91_irq_tx(dev, reg_sr);
 
        at91_irq_err(dev);
@@ -1123,6 +1246,8 @@ static struct attribute_group at91_sysfs_attr_group = {
 
 static int __devinit at91_can_probe(struct platform_device *pdev)
 {
+       const struct at91_devtype_data *devtype_data;
+       enum at91_devtype devtype;
        struct net_device *dev;
        struct at91_priv *priv;
        struct resource *res;
@@ -1130,6 +1255,9 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
        void __iomem *addr;
        int err, irq;
 
+       devtype = pdev->id_entry->driver_data;
+       devtype_data = &at91_devtype_data[devtype];
+
        clk = clk_get(&pdev->dev, "can_clk");
        if (IS_ERR(clk)) {
                dev_err(&pdev->dev, "no clock defined\n");
@@ -1157,7 +1285,8 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
                goto exit_release;
        }
 
-       dev = alloc_candev(sizeof(struct at91_priv), AT91_MB_TX_NUM);
+       dev = alloc_candev(sizeof(struct at91_priv),
+                          1 << devtype_data->tx_shift);
        if (!dev) {
                err = -ENOMEM;
                goto exit_iounmap;
@@ -1166,7 +1295,6 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
        dev->netdev_ops = &at91_netdev_ops;
        dev->irq = irq;
        dev->flags |= IFF_ECHO;
-       dev->sysfs_groups[0] = &at91_sysfs_attr_group;
 
        priv = netdev_priv(dev);
        priv->can.clock.freq = clk_get_rate(clk);
@@ -1174,13 +1302,18 @@ static int __devinit at91_can_probe(struct platform_device *pdev)
        priv->can.do_set_mode = at91_set_mode;
        priv->can.do_get_berr_counter = at91_get_berr_counter;
        priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
-       priv->reg_base = addr;
        priv->dev = dev;
+       priv->reg_base = addr;
+       priv->devtype_data = *devtype_data;
+       priv->devtype_data.type = devtype;
        priv->clk = clk;
        priv->pdata = pdev->dev.platform_data;
        priv->mb0_id = 0x7ff;
 
-       netif_napi_add(dev, &priv->napi, at91_poll, AT91_NAPI_WEIGHT);
+       netif_napi_add(dev, &priv->napi, at91_poll, get_mb_rx_num(priv));
+
+       if (at91_is_sam9263(priv))
+               dev->sysfs_groups[0] = &at91_sysfs_attr_group;
 
        dev_set_drvdata(&pdev->dev, dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
@@ -1230,13 +1363,26 @@ static int __devexit at91_can_remove(struct platform_device *pdev)
        return 0;
 }
 
+static const struct platform_device_id at91_can_id_table[] = {
+       {
+               .name = "at91_can",
+               .driver_data = AT91_DEVTYPE_SAM9263,
+       }, {
+               .name = "at91sam9x5_can",
+               .driver_data = AT91_DEVTYPE_SAM9X5,
+       }, {
+               /* sentinel */
+       }
+};
+
 static struct platform_driver at91_can_driver = {
-       .probe          = at91_can_probe,
-       .remove         = __devexit_p(at91_can_remove),
-       .driver         = {
-               .name   = KBUILD_MODNAME,
-               .owner  = THIS_MODULE,
+       .probe = at91_can_probe,
+       .remove = __devexit_p(at91_can_remove),
+       .driver = {
+               .name = KBUILD_MODNAME,
+               .owner = THIS_MODULE,
        },
+       .id_table = at91_can_id_table,
 };
 
 static int __init at91_can_module_init(void)
index d499056..1767811 100644 (file)
@@ -923,7 +923,7 @@ static int __devinit flexcan_probe(struct platform_device *pdev)
        mem_size = resource_size(mem);
        if (!request_mem_region(mem->start, mem_size, pdev->name)) {
                err = -EBUSY;
-               goto failed_req;
+               goto failed_get;
        }
 
        base = ioremap(mem->start, mem_size);
@@ -977,9 +977,8 @@ static int __devinit flexcan_probe(struct platform_device *pdev)
        iounmap(base);
  failed_map:
        release_mem_region(mem->start, mem_size);
- failed_req:
-       clk_put(clk);
  failed_get:
+       clk_put(clk);
  failed_clock:
        return err;
 }
index de8e778..78bd4ec 100644 (file)
@@ -47,6 +47,7 @@
 #ifndef SJA1000_DEV_H
 #define SJA1000_DEV_H
 
+#include <linux/irqreturn.h>
 #include <linux/can/dev.h>
 #include <linux/can/platform/sja1000.h>
 
index 75622d5..1b49df6 100644 (file)
@@ -425,17 +425,16 @@ static void slc_setup(struct net_device *dev)
  * in parallel
  */
 
-static unsigned int slcan_receive_buf(struct tty_struct *tty,
+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;
-       int bytes = count;
 
        if (!sl || sl->magic != SLCAN_MAGIC || !netif_running(sl->dev))
-               return -ENODEV;
+               return;
 
        /* Read the characters out of the buffer */
-       while (bytes--) {
+       while (count--) {
                if (fp && *fp++) {
                        if (!test_and_set_bit(SLF_ERROR, &sl->flags))
                                sl->dev->stats.rx_errors++;
@@ -444,8 +443,6 @@ static unsigned int slcan_receive_buf(struct tty_struct *tty,
                }
                slcan_unesc(sl, *cp++);
        }
-
-       return count;
 }
 
 /************************************
index 22ce03e..b414f5a 100644 (file)
@@ -75,6 +75,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/vmalloc.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
index 11a92af..363c7f3 100644 (file)
@@ -605,11 +605,12 @@ static int cnic_unregister_device(struct cnic_dev *dev, int ulp_type)
 }
 EXPORT_SYMBOL(cnic_unregister_driver);
 
-static int cnic_init_id_tbl(struct cnic_id_tbl *id_tbl, u32 size, u32 start_id)
+static int cnic_init_id_tbl(struct cnic_id_tbl *id_tbl, u32 size, u32 start_id,
+                           u32 next)
 {
        id_tbl->start = start_id;
        id_tbl->max = size;
-       id_tbl->next = 0;
+       id_tbl->next = next;
        spin_lock_init(&id_tbl->lock);
        id_tbl->table = kzalloc(DIV_ROUND_UP(size, 32) * 4, GFP_KERNEL);
        if (!id_tbl->table)
@@ -2778,13 +2779,10 @@ static u32 cnic_service_bnx2_queues(struct cnic_dev *dev)
 
                /* Tell compiler that status_blk fields can change. */
                barrier();
-               if (status_idx != *cp->kcq1.status_idx_ptr) {
-                       status_idx = (u16) *cp->kcq1.status_idx_ptr;
-                       /* status block index must be read first */
-                       rmb();
-                       cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
-               } else
-                       break;
+               status_idx = (u16) *cp->kcq1.status_idx_ptr;
+               /* status block index must be read first */
+               rmb();
+               cp->kwq_con_idx = *cp->kwq_con_idx_ptr;
        }
 
        CNIC_WR16(dev, cp->kcq1.io_addr, cp->kcq1.sw_prod_idx);
@@ -2908,8 +2906,6 @@ static u32 cnic_service_bnx2x_kcq(struct cnic_dev *dev, struct kcq_info *info)
 
                /* Tell compiler that sblk fields can change. */
                barrier();
-               if (last_status == *info->status_idx_ptr)
-                       break;
 
                last_status = *info->status_idx_ptr;
                /* status block index must be read before reading the KCQ */
@@ -3772,7 +3768,13 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
                break;
 
        case L4_KCQE_OPCODE_VALUE_CLOSE_RECEIVED:
-               cnic_cm_upcall(cp, csk, opcode);
+               /* after we already sent CLOSE_REQ */
+               if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags) &&
+                   !test_bit(SK_F_OFFLD_COMPLETE, &csk->flags) &&
+                   csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP)
+                       cp->close_conn(csk, L4_KCQE_OPCODE_VALUE_RESET_COMP);
+               else
+                       cnic_cm_upcall(cp, csk, opcode);
                break;
        }
        csk_put(csk);
@@ -3803,14 +3805,17 @@ static void cnic_cm_free_mem(struct cnic_dev *dev)
 static int cnic_cm_alloc_mem(struct cnic_dev *dev)
 {
        struct cnic_local *cp = dev->cnic_priv;
+       u32 port_id;
 
        cp->csk_tbl = kzalloc(sizeof(struct cnic_sock) * MAX_CM_SK_TBL_SZ,
                              GFP_KERNEL);
        if (!cp->csk_tbl)
                return -ENOMEM;
 
+       get_random_bytes(&port_id, sizeof(port_id));
+       port_id %= CNIC_LOCAL_PORT_RANGE;
        if (cnic_init_id_tbl(&cp->csk_port_tbl, CNIC_LOCAL_PORT_RANGE,
-                            CNIC_LOCAL_PORT_MIN)) {
+                            CNIC_LOCAL_PORT_MIN, port_id)) {
                cnic_cm_free_mem(dev);
                return -ENOMEM;
        }
@@ -3826,12 +3831,14 @@ static int cnic_ready_to_close(struct cnic_sock *csk, u32 opcode)
        }
 
        /* 1. If event opcode matches the expected event in csk->state
-        * 2. If the expected event is CLOSE_COMP, we accept any event
+        * 2. If the expected event is CLOSE_COMP or RESET_COMP, we accept any
+        *    event
         * 3. If the expected event is 0, meaning the connection was never
         *    never established, we accept the opcode from cm_abort.
         */
        if (opcode == csk->state || csk->state == 0 ||
-           csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP) {
+           csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP ||
+           csk->state == L4_KCQE_OPCODE_VALUE_RESET_COMP) {
                if (!test_and_set_bit(SK_F_CLOSING, &csk->flags)) {
                        if (csk->state == 0)
                                csk->state = opcode;
@@ -4218,14 +4225,6 @@ static void cnic_enable_bnx2_int(struct cnic_dev *dev)
                BNX2_PCICFG_INT_ACK_CMD_INDEX_VALID | cp->last_status_idx);
 }
 
-static void cnic_get_bnx2_iscsi_info(struct cnic_dev *dev)
-{
-       u32 max_conn;
-
-       max_conn = cnic_reg_rd_ind(dev, BNX2_FW_MAX_ISCSI_CONN);
-       dev->max_iscsi_conn = max_conn;
-}
-
 static void cnic_disable_bnx2_int_sync(struct cnic_dev *dev)
 {
        struct cnic_local *cp = dev->cnic_priv;
@@ -4550,8 +4549,6 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
                return err;
        }
 
-       cnic_get_bnx2_iscsi_info(dev);
-
        return 0;
 }
 
@@ -4826,7 +4823,7 @@ static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
        pfid = cp->pfid;
 
        ret = cnic_init_id_tbl(&cp->cid_tbl, MAX_ISCSI_TBL_SZ,
-                              cp->iscsi_start_cid);
+                              cp->iscsi_start_cid, 0);
 
        if (ret)
                return -ENOMEM;
@@ -4834,7 +4831,7 @@ static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
        if (BNX2X_CHIP_IS_E2(cp->chip_id)) {
                ret = cnic_init_id_tbl(&cp->fcoe_cid_tbl,
                                        BNX2X_FCOE_NUM_CONNECTIONS,
-                                       cp->fcoe_start_cid);
+                                       cp->fcoe_start_cid, 0);
 
                if (ret)
                        return -ENOMEM;
@@ -5217,6 +5214,8 @@ static struct cnic_dev *init_bnx2_cnic(struct net_device *dev)
        cdev->pcidev = pdev;
        cp->chip_id = ethdev->chip_id;
 
+       cdev->max_iscsi_conn = ethdev->max_iscsi_conn;
+
        cp->cnic_ops = &cnic_bnx2_ops;
        cp->start_hw = cnic_start_bnx2_hw;
        cp->stop_hw = cnic_stop_bnx2_hw;
@@ -5335,7 +5334,7 @@ static int cnic_netdev_event(struct notifier_block *this, unsigned long event,
 
        dev = cnic_from_netdev(netdev);
 
-       if (!dev && (event == NETDEV_REGISTER || event == NETDEV_UP)) {
+       if (!dev && (event == NETDEV_REGISTER || netif_running(netdev))) {
                /* Check for the hot-plug device */
                dev = is_cnic_dev(netdev);
                if (dev) {
@@ -5351,7 +5350,7 @@ static int cnic_netdev_event(struct notifier_block *this, unsigned long event,
                else if (event == NETDEV_UNREGISTER)
                        cnic_ulp_exit(dev);
 
-               if (event == NETDEV_UP) {
+               if (event == NETDEV_UP || (new_dev && netif_running(netdev))) {
                        if (cnic_register_netdev(dev) != 0) {
                                cnic_put(dev);
                                goto done;
index 7e3cfbe..c9957b7 100644 (file)
@@ -3704,7 +3704,7 @@ static int __devinit init_one(struct pci_dev *pdev,
        if (err) {
                dev_warn(&pdev->dev, "only %d net devices registered\n", i);
                err = 0;
-       };
+       }
 
        if (cxgb4_debugfs_root) {
                adapter->debugfs_root = debugfs_create_dir(pci_name(pdev),
index 4fd821a..6e9a8d9 100644 (file)
@@ -40,6 +40,7 @@
 #ifndef __CXGB4VF_ADAPTER_H__
 #define __CXGB4VF_ADAPTER_H__
 
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/spinlock.h>
 #include <linux/skbuff.h>
index 29a4f06..dcc4a17 100644 (file)
@@ -1781,8 +1781,8 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
        ndev = alloc_etherdev(sizeof(struct emac_priv));
        if (!ndev) {
                dev_err(&pdev->dev, "error allocating net_device\n");
-               clk_put(emac_clk);
-               return -ENOMEM;
+               rc = -ENOMEM;
+               goto free_clk;
        }
 
        platform_set_drvdata(pdev, ndev);
@@ -1796,7 +1796,8 @@ static int __devinit davinci_emac_probe(struct platform_device *pdev)
        pdata = pdev->dev.platform_data;
        if (!pdata) {
                dev_err(&pdev->dev, "no platform data\n");
-               return -ENODEV;
+               rc = -ENODEV;
+               goto probe_quit;
        }
 
        /* MAC addr and PHY mask , RMII enable info from platform_data */
@@ -1929,8 +1930,9 @@ no_dma:
        iounmap(priv->remap_addr);
 
 probe_quit:
-       clk_put(emac_clk);
        free_netdev(ndev);
+free_clk:
+       clk_put(emac_clk);
        return rc;
 }
 
index 1765405..8b0084d 100644 (file)
@@ -331,18 +331,18 @@ static struct {
                          "DE422",\
                          ""}
 
-static const char* const depca_signature[] __devinitconst = DEPCA_SIGNATURE;
+static char* __initdata depca_signature[] = DEPCA_SIGNATURE;
 
 enum depca_type {
        DEPCA, de100, de101, de200, de201, de202, de210, de212, de422, unknown
 };
 
-static const char depca_string[] = "depca";
+static char depca_string[] = "depca";
 
 static int depca_device_remove (struct device *device);
 
 #ifdef CONFIG_EISA
-static const struct eisa_device_id depca_eisa_ids[] __devinitconst = {
+static struct eisa_device_id depca_eisa_ids[] = {
        { "DEC4220", de422 },
        { "" }
 };
@@ -367,19 +367,19 @@ static struct eisa_driver depca_eisa_driver = {
 #define DE210_ID 0x628d
 #define DE212_ID 0x6def
 
-static const short depca_mca_adapter_ids[] __devinitconst = {
+static short depca_mca_adapter_ids[] = {
        DE210_ID,
        DE212_ID,
        0x0000
 };
 
-static const char *depca_mca_adapter_name[] = {
+static char *depca_mca_adapter_name[] = {
        "DEC EtherWORKS MC Adapter (DE210)",
        "DEC EtherWORKS MC Adapter (DE212)",
        NULL
 };
 
-static const enum depca_type depca_mca_adapter_type[] = {
+static enum depca_type depca_mca_adapter_type[] = {
        de210,
        de212,
        0
@@ -541,9 +541,10 @@ static void SetMulticastFilter(struct net_device *dev);
 static int load_packet(struct net_device *dev, struct sk_buff *skb);
 static void depca_dbg_open(struct net_device *dev);
 
-static const u_char de1xx_irq[] __devinitconst = { 2, 3, 4, 5, 7, 9, 0 };
-static const u_char de2xx_irq[] __devinitconst = { 5, 9, 10, 11, 15, 0 };
-static const u_char de422_irq[] __devinitconst = { 5, 9, 10, 11, 0 };
+static u_char de1xx_irq[] __initdata = { 2, 3, 4, 5, 7, 9, 0 };
+static u_char de2xx_irq[] __initdata = { 5, 9, 10, 11, 15, 0 };
+static u_char de422_irq[] __initdata = { 5, 9, 10, 11, 0 };
+static u_char *depca_irq;
 
 static int irq;
 static int io;
@@ -579,7 +580,7 @@ static const struct net_device_ops depca_netdev_ops = {
        .ndo_validate_addr      = eth_validate_addr,
 };
 
-static int __devinit depca_hw_init (struct net_device *dev, struct device *device)
+static int __init depca_hw_init (struct net_device *dev, struct device *device)
 {
        struct depca_private *lp;
        int i, j, offset, netRAM, mem_len, status = 0;
@@ -747,7 +748,6 @@ static int __devinit depca_hw_init (struct net_device *dev, struct device *devic
        if (dev->irq < 2) {
                unsigned char irqnum;
                unsigned long irq_mask, delay;
-               const u_char *depca_irq;
 
                irq_mask = probe_irq_on();
 
@@ -770,7 +770,6 @@ static int __devinit depca_hw_init (struct net_device *dev, struct device *devic
                        break;
 
                default:
-                       depca_irq = NULL;
                        break;  /* Not reached */
                }
 
@@ -1303,7 +1302,7 @@ static void SetMulticastFilter(struct net_device *dev)
        }
 }
 
-static int __devinit depca_common_init (u_long ioaddr, struct net_device **devp)
+static int __init depca_common_init (u_long ioaddr, struct net_device **devp)
 {
        int status = 0;
 
@@ -1334,7 +1333,7 @@ static int __devinit depca_common_init (u_long ioaddr, struct net_device **devp)
 /*
 ** Microchannel bus I/O device probe
 */
-static int __devinit depca_mca_probe(struct device *device)
+static int __init depca_mca_probe(struct device *device)
 {
        unsigned char pos[2];
        unsigned char where;
@@ -1458,7 +1457,7 @@ static int __devinit depca_mca_probe(struct device *device)
 ** ISA bus I/O device probe
 */
 
-static void __devinit depca_platform_probe (void)
+static void __init depca_platform_probe (void)
 {
        int i;
        struct platform_device *pldev;
@@ -1498,7 +1497,7 @@ static void __devinit depca_platform_probe (void)
        }
 }
 
-static enum depca_type __devinit depca_shmem_probe (ulong *mem_start)
+static enum depca_type __init depca_shmem_probe (ulong *mem_start)
 {
        u_long mem_base[] = DEPCA_RAM_BASE_ADDRESSES;
        enum depca_type adapter = unknown;
@@ -1559,7 +1558,7 @@ static int __devinit depca_isa_probe (struct platform_device *device)
 */
 
 #ifdef CONFIG_EISA
-static int __devinit depca_eisa_probe (struct device *device)
+static int __init depca_eisa_probe (struct device *device)
 {
        enum depca_type adapter = unknown;
        struct eisa_device *edev;
@@ -1630,7 +1629,7 @@ static int __devexit depca_device_remove (struct device *device)
 ** and Boot (readb) ROM. This will also give us a clue to the network RAM
 ** base address.
 */
-static int __devinit DepcaSignature(char *name, u_long base_addr)
+static int __init DepcaSignature(char *name, u_long base_addr)
 {
        u_int i, j, k;
        void __iomem *ptr;
index fbaff35..863e9c4 100644 (file)
@@ -24,6 +24,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/skbuff.h>
 #include <linux/spinlock.h>
 #include <linux/crc32.h>
@@ -1157,9 +1158,6 @@ dm9000_open(struct net_device *dev)
 
        irqflags |= IRQF_SHARED;
 
-       if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
-               return -EAGAIN;
-
        /* GPIO0 on pre-activate PHY, Reg 1F is not set by reset */
        iow(db, DM9000_GPR, 0); /* REG_1F bit0 activate phyxcer */
        mdelay(1); /* delay needs by DM9000B */
@@ -1168,6 +1166,9 @@ dm9000_open(struct net_device *dev)
        dm9000_reset(db);
        dm9000_init_dm9000(dev);
 
+       if (request_irq(dev->irq, dm9000_interrupt, irqflags, dev->name, dev))
+               return -EAGAIN;
+
        /* Init driver variable */
        db->dbug_cnt = 0;
 
index 8318ea0..b226910 100644 (file)
@@ -16,6 +16,7 @@
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/dma-mapping.h>
index e336c79..c1352c6 100644 (file)
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/hardirq.h>
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/kernel.h>
index 859d0d3..cb1a362 100644 (file)
@@ -28,6 +28,7 @@
 
 /* ethtool support for e1000 */
 
+#include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
 #include <linux/pci.h>
index 3310c3d..888bd9c 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/vmalloc.h>
 #include <linux/pagemap.h>
index 94ec973..d50a999 100644 (file)
@@ -44,6 +44,7 @@ static const char version[] =
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/delay.h>
 
 #include <asm/io.h>
index 38b351c..e0d2ad1 100644 (file)
@@ -32,7 +32,7 @@
 
 #define DRV_NAME               "enic"
 #define DRV_DESCRIPTION                "Cisco VIC Ethernet NIC Driver"
-#define DRV_VERSION            "2.1.1.13"
+#define DRV_VERSION            "2.1.1.16"
 #define DRV_COPYRIGHT          "Copyright 2008-2011 Cisco Systems, Inc"
 
 #define ENIC_BARS_MAX          6
@@ -74,6 +74,7 @@ struct enic {
        struct vnic_dev *vdev;
        struct timer_list notify_timer;
        struct work_struct reset;
+       struct work_struct change_mtu_work;
        struct msix_entry msix_entry[ENIC_INTR_MAX];
        struct enic_msix_entry msix[ENIC_INTR_MAX];
        u32 msg_enable;
index 2f433fb..c7797ec 100644 (file)
@@ -23,6 +23,7 @@
 #include <linux/errno.h>
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/workqueue.h>
 #include <linux/pci.h>
 #include <linux/netdevice.h>
@@ -423,11 +424,18 @@ static void enic_mtu_check(struct enic *enic)
 
        if (mtu && mtu != enic->port_mtu) {
                enic->port_mtu = mtu;
-               if (mtu < netdev->mtu)
-                       netdev_warn(netdev,
-                               "interface MTU (%d) set higher "
-                               "than switch port MTU (%d)\n",
-                               netdev->mtu, mtu);
+               if (enic_is_dynamic(enic)) {
+                       mtu = max_t(int, ENIC_MIN_MTU,
+                               min_t(int, ENIC_MAX_MTU, mtu));
+                       if (mtu != netdev->mtu)
+                               schedule_work(&enic->change_mtu_work);
+               } else {
+                       if (mtu < netdev->mtu)
+                               netdev_warn(netdev,
+                                       "interface MTU (%d) set higher "
+                                       "than switch port MTU (%d)\n",
+                                       netdev->mtu, mtu);
+               }
        }
 }
 
@@ -793,10 +801,10 @@ static netdev_tx_t enic_hard_start_xmit(struct sk_buff *skb,
 }
 
 /* dev_base_lock rwlock held, nominally process context */
-static struct net_device_stats *enic_get_stats(struct net_device *netdev)
+static struct rtnl_link_stats64 *enic_get_stats(struct net_device *netdev,
+                                               struct rtnl_link_stats64 *net_stats)
 {
        struct enic *enic = netdev_priv(netdev);
-       struct net_device_stats *net_stats = &netdev->stats;
        struct vnic_stats *stats;
 
        enic_dev_stats_dump(enic, &stats);
@@ -1560,7 +1568,7 @@ static void enic_notify_timer_start(struct enic *enic)
        default:
                /* Using intr for notification for INTx/MSI-X */
                break;
-       };
+       }
 }
 
 /* rtnl lock is held, process context */
@@ -1688,6 +1696,9 @@ static int enic_change_mtu(struct net_device *netdev, int new_mtu)
        if (new_mtu < ENIC_MIN_MTU || new_mtu > ENIC_MAX_MTU)
                return -EINVAL;
 
+       if (enic_is_dynamic(enic))
+               return -EOPNOTSUPP;
+
        if (running)
                enic_stop(netdev);
 
@@ -1704,6 +1715,55 @@ static int enic_change_mtu(struct net_device *netdev, int new_mtu)
        return 0;
 }
 
+static void enic_change_mtu_work(struct work_struct *work)
+{
+       struct enic *enic = container_of(work, struct enic, change_mtu_work);
+       struct net_device *netdev = enic->netdev;
+       int new_mtu = vnic_dev_mtu(enic->vdev);
+       int err;
+       unsigned int i;
+
+       new_mtu = max_t(int, ENIC_MIN_MTU, min_t(int, ENIC_MAX_MTU, new_mtu));
+
+       rtnl_lock();
+
+       /* Stop RQ */
+       del_timer_sync(&enic->notify_timer);
+
+       for (i = 0; i < enic->rq_count; i++)
+               napi_disable(&enic->napi[i]);
+
+       vnic_intr_mask(&enic->intr[0]);
+       enic_synchronize_irqs(enic);
+       err = vnic_rq_disable(&enic->rq[0]);
+       if (err) {
+               netdev_err(netdev, "Unable to disable RQ.\n");
+               return;
+       }
+       vnic_rq_clean(&enic->rq[0], enic_free_rq_buf);
+       vnic_cq_clean(&enic->cq[0]);
+       vnic_intr_clean(&enic->intr[0]);
+
+       /* Fill RQ with new_mtu-sized buffers */
+       netdev->mtu = new_mtu;
+       vnic_rq_fill(&enic->rq[0], enic_rq_alloc_buf);
+       /* Need at least one buffer on ring to get going */
+       if (vnic_rq_desc_used(&enic->rq[0]) == 0) {
+               netdev_err(netdev, "Unable to alloc receive buffers.\n");
+               return;
+       }
+
+       /* Start RQ */
+       vnic_rq_enable(&enic->rq[0]);
+       napi_enable(&enic->napi[0]);
+       vnic_intr_unmask(&enic->intr[0]);
+       enic_notify_timer_start(enic);
+
+       rtnl_unlock();
+
+       netdev_info(netdev, "interface MTU set as %d\n", netdev->mtu);
+}
+
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void enic_poll_controller(struct net_device *netdev)
 {
@@ -2057,7 +2117,7 @@ static const struct net_device_ops enic_netdev_dynamic_ops = {
        .ndo_open               = enic_open,
        .ndo_stop               = enic_stop,
        .ndo_start_xmit         = enic_hard_start_xmit,
-       .ndo_get_stats          = enic_get_stats,
+       .ndo_get_stats64        = enic_get_stats,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_rx_mode        = enic_set_rx_mode,
        .ndo_set_multicast_list = enic_set_rx_mode,
@@ -2079,7 +2139,7 @@ static const struct net_device_ops enic_netdev_ops = {
        .ndo_open               = enic_open,
        .ndo_stop               = enic_stop,
        .ndo_start_xmit         = enic_hard_start_xmit,
-       .ndo_get_stats          = enic_get_stats,
+       .ndo_get_stats64        = enic_get_stats,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = enic_set_mac_address,
        .ndo_set_rx_mode        = enic_set_rx_mode,
@@ -2345,6 +2405,7 @@ static int __devinit enic_probe(struct pci_dev *pdev,
        enic->notify_timer.data = (unsigned long)enic;
 
        INIT_WORK(&enic->reset, enic_reset);
+       INIT_WORK(&enic->change_mtu_work, enic_change_mtu_work);
 
        for (i = 0; i < enic->wq_count; i++)
                spin_lock_init(&enic->wq_lock[i]);
@@ -2427,6 +2488,7 @@ static void __devexit enic_remove(struct pci_dev *pdev)
                struct enic *enic = netdev_priv(netdev);
 
                cancel_work_sync(&enic->reset);
+               cancel_work_sync(&enic->change_mtu_work);
                unregister_netdev(netdev);
                enic_dev_deinit(enic);
                vnic_dev_close(enic->vdev);
index 0ba5e7b..7a09575 100644 (file)
@@ -54,6 +54,7 @@ static const char version[] =
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 
index a83dd31..9162c70 100644 (file)
@@ -13,6 +13,7 @@
 
 #include <linux/etherdevice.h>
 #include <linux/crc32.h>
+#include <linux/interrupt.h>
 #include <linux/io.h>
 #include <linux/mii.h>
 #include <linux/phy.h>
index 9f81b1a..eba0f69 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/slab.h>
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/crc32.h>
 #include <linux/hardirq.h>
 #include <linux/delay.h>
index f181304..69b86d7 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/module.h>
 #include <linux/uaccess.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
index 9920896..3e5d0b6 100644 (file)
@@ -456,7 +456,7 @@ out:
  * a block of 6pack data has been received, which can now be decapsulated
  * and sent on to some IP layer for further processing.
  */
-static unsigned int sixpack_receive_buf(struct tty_struct *tty,
+static void sixpack_receive_buf(struct tty_struct *tty,
        const unsigned char *cp, char *fp, int count)
 {
        struct sixpack *sp;
@@ -464,11 +464,11 @@ static unsigned int sixpack_receive_buf(struct tty_struct *tty,
        int count1;
 
        if (!count)
-               return 0;
+               return;
 
        sp = sp_get(tty);
        if (!sp)
-               return -ENODEV;
+               return;
 
        memcpy(buf, cp, count < sizeof(buf) ? count : sizeof(buf));
 
@@ -487,8 +487,6 @@ static unsigned int sixpack_receive_buf(struct tty_struct *tty,
 
        sp_put(sp);
        tty_unthrottle(tty);
-
-       return count1;
 }
 
 /*
index 99cdce3..a974727 100644 (file)
@@ -76,6 +76,7 @@
 #include <linux/ioport.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/hdlcdrv.h>
 #include <linux/baycom.h>
 #include <linux/jiffies.h>
index d92fe6c..e349d86 100644 (file)
@@ -66,6 +66,7 @@
 #include <linux/ioport.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <asm/uaccess.h>
 #include <asm/io.h>
 #include <linux/hdlcdrv.h>
index 0e4f235..4c62839 100644 (file)
@@ -923,14 +923,13 @@ static long mkiss_compat_ioctl(struct tty_struct *tty, struct file *file,
  * a block of data has been received, which can now be decapsulated
  * and sent on to the AX.25 layer for further processing.
  */
-static unsigned int mkiss_receive_buf(struct tty_struct *tty,
-               const unsigned char *cp, char *fp, int count)
+static void mkiss_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+       char *fp, int count)
 {
        struct mkiss *ax = mkiss_get(tty);
-       int bytes = count;
 
        if (!ax)
-               return -ENODEV;
+               return;
 
        /*
         * Argh! mtu change time! - costs us the packet part received
@@ -940,7 +939,7 @@ static unsigned int mkiss_receive_buf(struct tty_struct *tty,
                ax_changedmtu(ax);
 
        /* Read the characters out of the buffer */
-       while (bytes--) {
+       while (count--) {
                if (fp != NULL && *fp++) {
                        if (!test_and_set_bit(AXF_ERROR, &ax->flags))
                                ax->dev->stats.rx_errors++;
@@ -953,8 +952,6 @@ static unsigned int mkiss_receive_buf(struct tty_struct *tty,
 
        mkiss_put(ax);
        tty_unthrottle(tty);
-
-       return count;
 }
 
 /*
index 82bffc3..2991736 100644 (file)
@@ -30,6 +30,7 @@ static const char version[] =
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/delay.h>
 
 #include <asm/system.h>
index ef20143..18564d4 100644 (file)
@@ -30,6 +30,7 @@ static const char version[] =
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/delay.h>
 
 #include <asm/system.h>
index c52a1df..8e10d2f 100644 (file)
@@ -188,14 +188,14 @@ struct hp100_private {
  *  variables
  */
 #ifdef CONFIG_ISA
-static const char *const hp100_isa_tbl[] __devinitconst = {
+static const char *hp100_isa_tbl[] = {
        "HWPF150", /* HP J2573 rev A */
        "HWP1950", /* HP J2573 */
 };
 #endif
 
 #ifdef CONFIG_EISA
-static const struct eisa_device_id hp100_eisa_tbl[] __devinitconst = {
+static struct eisa_device_id hp100_eisa_tbl[] = {
        { "HWPF180" }, /* HP J2577 rev A */
        { "HWP1920" }, /* HP 27248B */
        { "HWP1940" }, /* HP J2577 */
@@ -336,7 +336,7 @@ static __devinit const char *hp100_read_id(int ioaddr)
 }
 
 #ifdef CONFIG_ISA
-static __devinit int hp100_isa_probe1(struct net_device *dev, int ioaddr)
+static __init int hp100_isa_probe1(struct net_device *dev, int ioaddr)
 {
        const char *sig;
        int i;
@@ -372,7 +372,7 @@ static __devinit int hp100_isa_probe1(struct net_device *dev, int ioaddr)
  * EISA and PCI are handled by device infrastructure.
  */
 
-static int  __devinit hp100_isa_probe(struct net_device *dev, int addr)
+static int  __init hp100_isa_probe(struct net_device *dev, int addr)
 {
        int err = -ENODEV;
 
@@ -396,7 +396,7 @@ static int  __devinit hp100_isa_probe(struct net_device *dev, int addr)
 #endif /* CONFIG_ISA */
 
 #if !defined(MODULE) && defined(CONFIG_ISA)
-struct net_device * __devinit hp100_probe(int unit)
+struct net_device * __init hp100_probe(int unit)
 {
        struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private));
        int err;
@@ -2843,7 +2843,7 @@ static void cleanup_dev(struct net_device *d)
 }
 
 #ifdef CONFIG_EISA
-static int __devinit hp100_eisa_probe (struct device *gendev)
+static int __init hp100_eisa_probe (struct device *gendev)
 {
        struct net_device *dev = alloc_etherdev(sizeof(struct hp100_private));
        struct eisa_device *edev = to_eisa_device(gendev);
index 136d754..a7d6cad 100644 (file)
@@ -895,12 +895,12 @@ static int ibmlana_irq;
 static int ibmlana_io;
 static int startslot;          /* counts through slots when probing multiple devices */
 
-static const short ibmlana_adapter_ids[] __devinitconst = {
+static short ibmlana_adapter_ids[] __initdata = {
        IBM_LANA_ID,
        0x0000
 };
 
-static const char *const ibmlana_adapter_names[] __devinitconst = {
+static char *ibmlana_adapter_names[] __devinitdata = {
        "IBM LAN Adapter/A",
        NULL
 };
index b388d78..838c5b6 100644 (file)
@@ -34,6 +34,7 @@
 #include <linux/etherdevice.h>
 #include <linux/skbuff.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/mm.h>
 #include <linux/pm.h>
 #include <linux/ethtool.h>
index 4fecaed..ce53f4a 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/moduleparam.h>
 #include <net/pkt_sched.h>
 #include <net/net_namespace.h>
index 58cd320..d4aa40a 100644 (file)
@@ -22,6 +22,7 @@
  */
 #include <linux/crc32.h>
 #include <linux/ethtool.h>
+#include <linux/interrupt.h>
 #include <linux/gfp.h>
 #include <linux/mii.h>
 #include <linux/mutex.h>
index d532dde..963067d 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/rtnetlink.h>
 #include <linux/serial_reg.h>
 #include <linux/dma-mapping.h>
index 174cafa..b45b2cc 100644 (file)
 #include <linux/delay.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/rtnetlink.h>
 
index 035861d..3352b24 100644 (file)
@@ -216,23 +216,23 @@ static int irtty_do_write(struct sir_dev *dev, const unsigned char *ptr, size_t
  * usbserial:  urb-complete-interrupt / softint
  */
 
-static unsigned int irtty_receive_buf(struct tty_struct *tty,
-               const unsigned char *cp, char *fp, int count)
+static void irtty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                             char *fp, int count) 
 {
        struct sir_dev *dev;
        struct sirtty_cb *priv = tty->disc_data;
        int     i;
 
-       IRDA_ASSERT(priv != NULL, return -ENODEV;);
-       IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return -EINVAL;);
+       IRDA_ASSERT(priv != NULL, return;);
+       IRDA_ASSERT(priv->magic == IRTTY_MAGIC, return;);
 
        if (unlikely(count==0))         /* yes, this happens */
-               return 0;
+               return;
 
        dev = priv->dev;
        if (!dev) {
                IRDA_WARNING("%s(), not ready yet!\n", __func__);
-               return -ENODEV;
+               return;
        }
 
        for (i = 0; i < count; i++) {
@@ -242,13 +242,11 @@ static unsigned int irtty_receive_buf(struct tty_struct *tty,
                if (fp && *fp++) { 
                        IRDA_DEBUG(0, "Framing or parity error!\n");
                        sirdev_receive(dev, NULL, 0);   /* notify sir_dev (updating stats) */
-                       return -EINVAL;
+                       return;
                }
        }
 
        sirdev_receive(dev, cp, count);
-
-       return count;
 }
 
 /*
index 7a963d4..b56636d 100644 (file)
@@ -52,6 +52,7 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/rtnetlink.h>
 #include <linux/dma-mapping.h>
 #include <linux/pnp.h>
index 001ed0a..b1d1ce3 100644 (file)
@@ -12,6 +12,7 @@
  * Infra-red driver (SIR/FIR) for the PXA2xx embedded microprocessor
  *
  */
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
index efe05bb..5039f08 100644 (file)
@@ -11,6 +11,7 @@
  *
  ********************************************************************/    
 
+#include <linux/hardirq.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/slab.h>
index 69b5707..d5072af 100644 (file)
@@ -49,6 +49,7 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/rtnetlink.h>
 #include <linux/serial_reg.h>
 #include <linux/dma-mapping.h>
@@ -222,19 +223,19 @@ static void smsc_ircc_set_transceiver_for_speed(struct smsc_ircc_cb *self, u32 s
 static void smsc_ircc_sir_wait_hw_transmitter_finish(struct smsc_ircc_cb *self);
 
 /* Probing */
-static int smsc_ircc_look_for_chips(void);
-static const struct smsc_chip * smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type);
-static int smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
-static int smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
-static int smsc_superio_fdc(unsigned short cfg_base);
-static int smsc_superio_lpc(unsigned short cfg_base);
+static int __init smsc_ircc_look_for_chips(void);
+static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type);
+static int __init smsc_superio_flat(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
+static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned short cfg_base, char *type);
+static int __init smsc_superio_fdc(unsigned short cfg_base);
+static int __init smsc_superio_lpc(unsigned short cfg_base);
 #ifdef CONFIG_PCI
-static int preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf);
-static int preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
-static void preconfigure_ali_port(struct pci_dev *dev,
+static int __init preconfigure_smsc_chip(struct smsc_ircc_subsystem_configuration *conf);
+static int __init preconfigure_through_82801(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
+static void __init preconfigure_ali_port(struct pci_dev *dev,
                                         unsigned short port);
-static int preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
-static int smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
+static int __init preconfigure_through_ali(struct pci_dev *dev, struct smsc_ircc_subsystem_configuration *conf);
+static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
                                                    unsigned short ircc_fir,
                                                    unsigned short ircc_sir,
                                                    unsigned char ircc_dma,
@@ -366,7 +367,7 @@ static inline void register_bank(int iobase, int bank)
 }
 
 /* PNP hotplug support */
-static const struct pnp_device_id smsc_ircc_pnp_table[] __devinitconst = {
+static const struct pnp_device_id smsc_ircc_pnp_table[] = {
        { .id = "SMCf010", .driver_data = 0 },
        /* and presumably others */
        { }
@@ -515,7 +516,7 @@ static const struct net_device_ops smsc_ircc_netdev_ops = {
  *    Try to open driver instance
  *
  */
-static int __devinit smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq)
+static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u8 dma, u8 irq)
 {
        struct smsc_ircc_cb *self;
        struct net_device *dev;
@@ -2273,7 +2274,7 @@ static int __init smsc_superio_paged(const struct smsc_chip *chips, unsigned sho
 }
 
 
-static int __devinit smsc_access(unsigned short cfg_base, unsigned char reg)
+static int __init smsc_access(unsigned short cfg_base, unsigned char reg)
 {
        IRDA_DEBUG(1, "%s\n", __func__);
 
@@ -2281,7 +2282,7 @@ static int __devinit smsc_access(unsigned short cfg_base, unsigned char reg)
        return inb(cfg_base) != reg ? -1 : 0;
 }
 
-static const struct smsc_chip * __devinit smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type)
+static const struct smsc_chip * __init smsc_ircc_probe(unsigned short cfg_base, u8 reg, const struct smsc_chip *chip, char *type)
 {
        u8 devid, xdevid, rev;
 
@@ -2406,7 +2407,7 @@ static int __init smsc_superio_lpc(unsigned short cfg_base)
 #ifdef CONFIG_PCI
 #define PCIID_VENDOR_INTEL 0x8086
 #define PCIID_VENDOR_ALI 0x10b9
-static const struct smsc_ircc_subsystem_configuration subsystem_configurations[] __devinitconst = {
+static struct smsc_ircc_subsystem_configuration subsystem_configurations[] __initdata = {
        /*
         * Subsystems needing entries:
         * 0x10b9:0x1533 0x103c:0x0850 HP nx9010 family
@@ -2532,7 +2533,7 @@ static const struct smsc_ircc_subsystem_configuration subsystem_configurations[]
  * (FIR port, SIR port, FIR DMA, FIR IRQ)
  * through the chip configuration port.
  */
-static int __devinit preconfigure_smsc_chip(struct
+static int __init preconfigure_smsc_chip(struct
                                         smsc_ircc_subsystem_configuration
                                         *conf)
 {
@@ -2633,7 +2634,7 @@ static int __devinit preconfigure_smsc_chip(struct
  * or Intel 82801DB/DBL (ICH4/ICH4-L) LPC Interface Bridge.
  * They all work the same way!
  */
-static int __devinit preconfigure_through_82801(struct pci_dev *dev,
+static int __init preconfigure_through_82801(struct pci_dev *dev,
                                             struct
                                             smsc_ircc_subsystem_configuration
                                             *conf)
@@ -2786,7 +2787,7 @@ static int __devinit preconfigure_through_82801(struct pci_dev *dev,
  * This is based on reverse-engineering since ALi does not
  * provide any data sheet for the 1533 chip.
  */
-static void __devinit preconfigure_ali_port(struct pci_dev *dev,
+static void __init preconfigure_ali_port(struct pci_dev *dev,
                                         unsigned short port)
 {
        unsigned char reg;
@@ -2824,7 +2825,7 @@ static void __devinit preconfigure_ali_port(struct pci_dev *dev,
        IRDA_MESSAGE("Activated ALi 1533 ISA bridge port 0x%04x.\n", port);
 }
 
-static int __devinit preconfigure_through_ali(struct pci_dev *dev,
+static int __init preconfigure_through_ali(struct pci_dev *dev,
                                           struct
                                           smsc_ircc_subsystem_configuration
                                           *conf)
@@ -2837,7 +2838,7 @@ static int __devinit preconfigure_through_ali(struct pci_dev *dev,
        return preconfigure_smsc_chip(conf);
 }
 
-static int __devinit smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
+static int __init smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
                                                    unsigned short ircc_fir,
                                                    unsigned short ircc_sir,
                                                    unsigned char ircc_dma,
@@ -2849,7 +2850,7 @@ static int __devinit smsc_ircc_preconfigure_subsystems(unsigned short ircc_cfg,
        int ret = 0;
 
        for_each_pci_dev(dev) {
-               const struct smsc_ircc_subsystem_configuration *conf;
+               struct smsc_ircc_subsystem_configuration *conf;
 
                /*
                 * Cache the subsystem vendor/device:
index f504b26..6d64790 100644 (file)
@@ -46,6 +46,7 @@ F02 Oct/28/02: Add SB device ID for 3147 and 3177.
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/rtnetlink.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
index c6f5848..f903a6a 100644 (file)
@@ -210,7 +210,7 @@ static void DisableDmaChannel(unsigned int channel)
                break;
        default:
                break;
-       };                      //Switch
+       }
 }
 
 static unsigned char ReadLPCReg(int iRegNum)
index c3d0738..9021d01 100644 (file)
@@ -36,6 +36,7 @@ MODULE_LICENSE("GPL");
 
 #include <linux/kernel.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/netdevice.h>
index 1f9c3f0..c436660 100644 (file)
@@ -47,6 +47,7 @@
 #include <linux/ioport.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/rtnetlink.h>
 #include <linux/dma-mapping.h>
 #include <linux/gfp.h>
index 9ece1fd..b6c296f 100644 (file)
@@ -538,7 +538,7 @@ static void veth_handle_ack(struct veth_lpevent *event)
        default:
                veth_error("Unknown ack type %d from LPAR %d.\n",
                                event->base_event.xSubtype, rlp);
-       };
+       }
 }
 
 static void veth_handle_int(struct veth_lpevent *event)
@@ -584,7 +584,7 @@ static void veth_handle_int(struct veth_lpevent *event)
        default:
                veth_error("Unknown interrupt type %d from LPAR %d.\n",
                                event->base_event.xSubtype, rlp);
-       };
+       }
 }
 
 static void veth_handle_event(struct HvLpEvent *event)
index 8ee6612..0d7bc91 100644 (file)
@@ -1157,7 +1157,7 @@ s32 ixgbe_init_fdir_signature_82599(struct ixgbe_hw *hw, u32 pballoc)
        default:
                /* bad value */
                return IXGBE_ERR_CONFIG;
-       };
+       }
 
        /* Move the flexible bytes to use the ethertype - shift 6 words */
        fdirctrl |= (0x6 << IXGBE_FDIRCTRL_FLEX_SHIFT);
@@ -1245,7 +1245,7 @@ s32 ixgbe_init_fdir_perfect_82599(struct ixgbe_hw *hw, u32 pballoc)
        default:
                /* bad value */
                return IXGBE_ERR_CONFIG;
-       };
+       }
 
        /* Turn perfect match filtering on */
        fdirctrl |= IXGBE_FDIRCTRL_PERFECT_MATCH;
index b894b42..de65643 100644 (file)
@@ -1292,7 +1292,7 @@ static s32 ixgbe_ready_eeprom(struct ixgbe_hw *hw)
 
                udelay(5);
                ixgbe_standby_eeprom(hw);
-       };
+       }
 
        /*
         * On some parts, SPI write time could vary from 0-20mSec on 3.3V
@@ -1374,7 +1374,7 @@ static void ixgbe_shift_out_eeprom_bits(struct ixgbe_hw *hw, u16 data,
                 * EEPROM
                 */
                mask = mask >> 1;
-       };
+       }
 
        /* We leave the "DI" bit set to "0" when we leave this routine. */
        eec &= ~IXGBE_EEC_DI;
index cb1555b..4950d03 100644 (file)
@@ -27,6 +27,7 @@
 
 /* ethtool support for ixgbe */
 
+#include <linux/interrupt.h>
 #include <linux/types.h>
 #include <linux/module.h>
 #include <linux/slab.h>
index 08e8e25..06cfaf3 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/vmalloc.h>
 #include <linux/string.h>
 #include <linux/in.h>
+#include <linux/interrupt.h>
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/pkt_sched.h>
index 78ddd8b..e122493 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/moduleparam.h>
 #include <linux/gfp.h>
 #include <asm/hardware/uengine.h>
index e9aaeca..0d5da06 100644 (file)
@@ -24,6 +24,7 @@
 
 #ifndef __JME_H_INCLUDED__
 #define __JME_H_INCLUDED__
+#include <linux/interrupt.h>
 
 #define DRV_NAME       "jme"
 #define DRV_VERSION    "1.0.8"
index 4d40626..4a6ae05 100644 (file)
@@ -23,6 +23,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/platform_device.h>
@@ -661,7 +662,7 @@ static void ks8842_rx_frame(struct net_device *netdev,
 
        /* check the status */
        if ((status & RXSR_VALID) && !(status & RXSR_ERROR)) {
-               struct sk_buff *skb = netdev_alloc_skb_ip_align(netdev, len);
+               struct sk_buff *skb = netdev_alloc_skb_ip_align(netdev, len + 3);
 
                if (skb) {
 
index bcd9ba6..f56743a 100644 (file)
@@ -13,6 +13,7 @@
 
 #define DEBUG
 
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
index 61631ca..aefbdd8 100644 (file)
@@ -23,6 +23,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
index 41ea592..2ac6c6c 100644 (file)
@@ -17,6 +17,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/ioport.h>
index b7948cc..e7b8afe 100644 (file)
@@ -48,6 +48,7 @@
 #include <linux/io.h>
 #include <linux/ip.h>
 #include <linux/slab.h>
+#include <linux/interrupt.h>
 
 #include "ll_temac.h"
 
index 8a1097c..f9888d2 100644 (file)
@@ -41,6 +41,7 @@ static const char *version =
 #include <linux/string.h>
 #include <linux/delay.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 
index 6c6a028..818f0b8 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/dma-mapping.h>
index 1c5221f..2074e97 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/string.h>
 #include <linux/timer.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/crc32.h>
 #include <linux/spinlock.h>
 #include <linux/bitrev.h>
index d6aeaa5..cc67cbe 100644 (file)
@@ -414,7 +414,8 @@ static struct lock_class_key macvlan_netdev_addr_lock_key;
 #define MACVLAN_FEATURES \
        (NETIF_F_SG | NETIF_F_ALL_CSUM | NETIF_F_HIGHDMA | NETIF_F_FRAGLIST | \
         NETIF_F_GSO | NETIF_F_TSO | NETIF_F_UFO | NETIF_F_GSO_ROBUST | \
-        NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM)
+        NETIF_F_TSO_ECN | NETIF_F_TSO6 | NETIF_F_GRO | NETIF_F_RXCSUM | \
+        NETIF_F_HW_VLAN_FILTER)
 
 #define MACVLAN_STATE_MASK \
        ((1<<__LINK_STATE_NOCARRIER) | (1<<__LINK_STATE_DORMANT))
@@ -509,6 +510,39 @@ static struct rtnl_link_stats64 *macvlan_dev_get_stats64(struct net_device *dev,
        return stats;
 }
 
+static void macvlan_vlan_rx_register(struct net_device *dev,
+                                    struct vlan_group *grp)
+{
+       struct macvlan_dev *vlan = netdev_priv(dev);
+       struct net_device *lowerdev = vlan->lowerdev;
+       const struct net_device_ops *ops = lowerdev->netdev_ops;
+
+       if (ops->ndo_vlan_rx_register)
+               ops->ndo_vlan_rx_register(lowerdev, grp);
+}
+
+static void macvlan_vlan_rx_add_vid(struct net_device *dev,
+                                   unsigned short vid)
+{
+       struct macvlan_dev *vlan = netdev_priv(dev);
+       struct net_device *lowerdev = vlan->lowerdev;
+       const struct net_device_ops *ops = lowerdev->netdev_ops;
+
+       if (ops->ndo_vlan_rx_add_vid)
+               ops->ndo_vlan_rx_add_vid(lowerdev, vid);
+}
+
+static void macvlan_vlan_rx_kill_vid(struct net_device *dev,
+                                    unsigned short vid)
+{
+       struct macvlan_dev *vlan = netdev_priv(dev);
+       struct net_device *lowerdev = vlan->lowerdev;
+       const struct net_device_ops *ops = lowerdev->netdev_ops;
+
+       if (ops->ndo_vlan_rx_kill_vid)
+               ops->ndo_vlan_rx_kill_vid(lowerdev, vid);
+}
+
 static void macvlan_ethtool_get_drvinfo(struct net_device *dev,
                                        struct ethtool_drvinfo *drvinfo)
 {
@@ -541,6 +575,9 @@ static const struct net_device_ops macvlan_netdev_ops = {
        .ndo_set_multicast_list = macvlan_set_multicast_list,
        .ndo_get_stats64        = macvlan_dev_get_stats64,
        .ndo_validate_addr      = eth_validate_addr,
+       .ndo_vlan_rx_register   = macvlan_vlan_rx_register,
+       .ndo_vlan_rx_add_vid    = macvlan_vlan_rx_add_vid,
+       .ndo_vlan_rx_kill_vid   = macvlan_vlan_rx_kill_vid,
 };
 
 void macvlan_common_setup(struct net_device *dev)
index bf84849..04e10f4 100644 (file)
@@ -377,7 +377,8 @@ static inline void put_be32(__be32 val, __be32 __iomem * p)
        __raw_writel((__force __u32) val, (__force void __iomem *)p);
 }
 
-static struct net_device_stats *myri10ge_get_stats(struct net_device *dev);
+static struct rtnl_link_stats64 *myri10ge_get_stats(struct net_device *dev,
+                                                   struct rtnl_link_stats64 *stats);
 
 static void set_fw_name(struct myri10ge_priv *mgp, char *name, bool allocated)
 {
@@ -1013,7 +1014,7 @@ static int myri10ge_reset(struct myri10ge_priv *mgp)
                cmd.data2 = i;
                status |= myri10ge_send_cmd(mgp, MXGEFW_CMD_SET_INTRQ_DMA,
                                            &cmd, 0);
-       };
+       }
 
        status |=
            myri10ge_send_cmd(mgp, MXGEFW_CMD_GET_IRQ_ACK_OFFSET, &cmd, 0);
@@ -1831,13 +1832,14 @@ myri10ge_get_ethtool_stats(struct net_device *netdev,
 {
        struct myri10ge_priv *mgp = netdev_priv(netdev);
        struct myri10ge_slice_state *ss;
+       struct rtnl_link_stats64 link_stats;
        int slice;
        int i;
 
        /* force stats update */
-       (void)myri10ge_get_stats(netdev);
+       (void)myri10ge_get_stats(netdev, &link_stats);
        for (i = 0; i < MYRI10GE_NET_STATS_LEN; i++)
-               data[i] = ((unsigned long *)&netdev->stats)[i];
+               data[i] = ((u64 *)&link_stats)[i];
 
        data[i++] = (unsigned int)mgp->tx_boundary;
        data[i++] = (unsigned int)mgp->wc_enabled;
@@ -2976,11 +2978,11 @@ drop:
        return NETDEV_TX_OK;
 }
 
-static struct net_device_stats *myri10ge_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *myri10ge_get_stats(struct net_device *dev,
+                                                   struct rtnl_link_stats64 *stats)
 {
        struct myri10ge_priv *mgp = netdev_priv(dev);
        struct myri10ge_slice_netstats *slice_stats;
-       struct net_device_stats *stats = &dev->stats;
        int i;
 
        spin_lock(&mgp->stats_lock);
@@ -3790,7 +3792,7 @@ static const struct net_device_ops myri10ge_netdev_ops = {
        .ndo_open               = myri10ge_open,
        .ndo_stop               = myri10ge_close,
        .ndo_start_xmit         = myri10ge_xmit,
-       .ndo_get_stats          = myri10ge_get_stats,
+       .ndo_get_stats64        = myri10ge_get_stats,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_change_mtu         = myri10ge_change_mtu,
        .ndo_fix_features       = myri10ge_fix_features,
index e8984b0..243ed2a 100644 (file)
@@ -80,20 +80,17 @@ static void ne3210_block_output(struct net_device *dev, int count, const unsigne
 
 #define NE3210_DEBUG   0x0
 
-static const unsigned char irq_map[] __devinitconst =
-       { 15, 12, 11, 10, 9, 7, 5, 3 };
-static const unsigned int shmem_map[] __devinitconst =
-       { 0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0 };
-static const char *const ifmap[] __devinitconst =
-       { "UTP", "?", "BNC", "AUI" };
-static const int ifmap_val[] __devinitconst = {
+static unsigned char irq_map[] __initdata = {15, 12, 11, 10, 9, 7, 5, 3};
+static unsigned int shmem_map[] __initdata = {0xff0, 0xfe0, 0xfff0, 0xd8, 0xffe0, 0xffc0, 0xd0, 0x0};
+static const char *ifmap[] __initdata = {"UTP", "?", "BNC", "AUI"};
+static int ifmap_val[] __initdata = {
                IF_PORT_10BASET,
                IF_PORT_UNKNOWN,
                IF_PORT_10BASE2,
                IF_PORT_AUI,
 };
 
-static int __devinit ne3210_eisa_probe (struct device *device)
+static int __init ne3210_eisa_probe (struct device *device)
 {
        unsigned long ioaddr, phys_mem;
        int i, retval, port_index;
@@ -316,7 +313,7 @@ static void ne3210_block_output(struct net_device *dev, int count,
        memcpy_toio(shmem, buf, count);
 }
 
-static const struct eisa_device_id ne3210_ids[] __devinitconst = {
+static struct eisa_device_id ne3210_ids[] = {
        { "EGL0101" },
        { "NVL1801" },
        { "" },
index 2e4b421..2dfee89 100644 (file)
@@ -18,6 +18,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
index 5cef718..3f89e57 100644 (file)
@@ -809,6 +809,9 @@ int netxen_config_hw_lro(struct netxen_adapter *adapter, int enable)
        u64 word;
        int rv = 0;
 
+       if (!test_bit(__NX_FW_ATTACHED, &adapter->state))
+               return 0;
+
        memset(&req, 0, sizeof(nx_nic_req_t));
 
        req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23);
@@ -959,6 +962,9 @@ int netxen_send_lro_cleanup(struct netxen_adapter *adapter)
        u64 word;
        int rv;
 
+       if (!test_bit(__NX_FW_ATTACHED, &adapter->state))
+               return 0;
+
        memset(&req, 0, sizeof(nx_nic_req_t));
        req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23);
 
index 7f99967..ca59b4f 100644 (file)
@@ -1279,7 +1279,7 @@ void netxen_free_dummy_dma(struct netxen_adapter *adapter)
 
                        if (--i == 0)
                                break;
-               };
+               }
        }
 
        if (i) {
index b644383..684cace 100644 (file)
@@ -92,7 +92,8 @@ static irqreturn_t netxen_msi_intr(int irq, void *data);
 static irqreturn_t netxen_msix_intr(int irq, void *data);
 
 static void netxen_config_indev_addr(struct net_device *dev, unsigned long);
-static struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev);
+static struct rtnl_link_stats64 *netxen_nic_get_stats(struct net_device *dev,
+                                                     struct rtnl_link_stats64 *stats);
 static int netxen_nic_set_mac(struct net_device *netdev, void *p);
 
 /*  PCI Device ID Table  */
@@ -520,7 +521,7 @@ static const struct net_device_ops netxen_netdev_ops = {
        .ndo_open          = netxen_nic_open,
        .ndo_stop          = netxen_nic_close,
        .ndo_start_xmit    = netxen_nic_xmit_frame,
-       .ndo_get_stats     = netxen_nic_get_stats,
+       .ndo_get_stats64   = netxen_nic_get_stats,
        .ndo_validate_addr = eth_validate_addr,
        .ndo_set_multicast_list = netxen_set_multicast_list,
        .ndo_set_mac_address    = netxen_nic_set_mac,
@@ -2110,10 +2111,10 @@ request_reset:
        clear_bit(__NX_RESETTING, &adapter->state);
 }
 
-static struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev)
+static struct rtnl_link_stats64 *netxen_nic_get_stats(struct net_device *netdev,
+                                                     struct rtnl_link_stats64 *stats)
 {
        struct netxen_adapter *adapter = netdev_priv(netdev);
-       struct net_device_stats *stats = &netdev->stats;
 
        stats->rx_packets = adapter->stats.rx_pkts + adapter->stats.lro_pkts;
        stats->tx_packets = adapter->stats.xmitfinished;
index cc25bff..1c7b790 100644 (file)
@@ -7,6 +7,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/dma-mapping.h>
 #include <linux/netdevice.h>
@@ -6248,9 +6249,10 @@ static void niu_sync_mac_stats(struct niu *np)
                niu_sync_bmac_stats(np);
 }
 
-static void niu_get_rx_stats(struct niu *np)
+static void niu_get_rx_stats(struct niu *np,
+                            struct rtnl_link_stats64 *stats)
 {
-       unsigned long pkts, dropped, errors, bytes;
+       u64 pkts, dropped, errors, bytes;
        struct rx_ring_info *rx_rings;
        int i;
 
@@ -6272,15 +6274,16 @@ static void niu_get_rx_stats(struct niu *np)
        }
 
 no_rings:
-       np->dev->stats.rx_packets = pkts;
-       np->dev->stats.rx_bytes = bytes;
-       np->dev->stats.rx_dropped = dropped;
-       np->dev->stats.rx_errors = errors;
+       stats->rx_packets = pkts;
+       stats->rx_bytes = bytes;
+       stats->rx_dropped = dropped;
+       stats->rx_errors = errors;
 }
 
-static void niu_get_tx_stats(struct niu *np)
+static void niu_get_tx_stats(struct niu *np,
+                            struct rtnl_link_stats64 *stats)
 {
-       unsigned long pkts, errors, bytes;
+       u64 pkts, errors, bytes;
        struct tx_ring_info *tx_rings;
        int i;
 
@@ -6299,20 +6302,22 @@ static void niu_get_tx_stats(struct niu *np)
        }
 
 no_rings:
-       np->dev->stats.tx_packets = pkts;
-       np->dev->stats.tx_bytes = bytes;
-       np->dev->stats.tx_errors = errors;
+       stats->tx_packets = pkts;
+       stats->tx_bytes = bytes;
+       stats->tx_errors = errors;
 }
 
-static struct net_device_stats *niu_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *niu_get_stats(struct net_device *dev,
+                                              struct rtnl_link_stats64 *stats)
 {
        struct niu *np = netdev_priv(dev);
 
        if (netif_running(dev)) {
-               niu_get_rx_stats(np);
-               niu_get_tx_stats(np);
+               niu_get_rx_stats(np, stats);
+               niu_get_tx_stats(np, stats);
        }
-       return &dev->stats;
+
+       return stats;
 }
 
 static void niu_load_hash_xmac(struct niu *np, u16 *hash)
@@ -9710,7 +9715,7 @@ static const struct net_device_ops niu_netdev_ops = {
        .ndo_open               = niu_open,
        .ndo_stop               = niu_close,
        .ndo_start_xmit         = niu_start_xmit,
-       .ndo_get_stats          = niu_get_stats,
+       .ndo_get_stats64        = niu_get_stats,
        .ndo_set_multicast_list = niu_set_rx_mode,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = niu_set_mac_addr,
index 3e4040f..d3afb45 100644 (file)
 #include <linux/delay.h>
 #include <linux/workqueue.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/ip.h>  /* for iph */
 #include <linux/in.h>  /* for IPPROTO_... */
 #include <linux/compiler.h>
index 53872d7..6436ba9 100644 (file)
@@ -30,6 +30,7 @@
 #include <linux/ppp_channel.h>
 #include <linux/spinlock.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/jiffies.h>
 #include <linux/slab.h>
 #include <asm/unaligned.h>
@@ -340,7 +341,7 @@ ppp_asynctty_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
 }
 
 /* May sleep, don't call from interrupt level or with interrupts disabled */
-static unsigned int
+static void
 ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
                  char *cflags, int count)
 {
@@ -348,7 +349,7 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
        unsigned long flags;
 
        if (!ap)
-               return -ENODEV;
+               return;
        spin_lock_irqsave(&ap->recv_lock, flags);
        ppp_async_input(ap, buf, cflags, count);
        spin_unlock_irqrestore(&ap->recv_lock, flags);
@@ -356,8 +357,6 @@ ppp_asynctty_receive(struct tty_struct *tty, const unsigned char *buf,
                tasklet_schedule(&ap->tsk);
        ap_put(ap);
        tty_unthrottle(tty);
-
-       return count;
 }
 
 static void
index 0815790..736a39e 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/spinlock.h>
 #include <linux/completion.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/slab.h>
 #include <asm/unaligned.h>
 #include <asm/uaccess.h>
@@ -381,7 +382,7 @@ ppp_sync_poll(struct tty_struct *tty, struct file *file, poll_table *wait)
 }
 
 /* May sleep, don't call from interrupt level or with interrupts disabled */
-static unsigned int
+static void
 ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
                  char *cflags, int count)
 {
@@ -389,7 +390,7 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
        unsigned long flags;
 
        if (!ap)
-               return -ENODEV;
+               return;
        spin_lock_irqsave(&ap->recv_lock, flags);
        ppp_sync_input(ap, buf, cflags, count);
        spin_unlock_irqrestore(&ap->recv_lock, flags);
@@ -397,8 +398,6 @@ ppp_sync_receive(struct tty_struct *tty, const unsigned char *buf,
                tasklet_schedule(&ap->tsk);
        sp_put(ap);
        tty_unthrottle(tty);
-
-       return count;
 }
 
 static void
index b1f251d..35e47c3 100644 (file)
@@ -28,6 +28,7 @@
 
 #undef DEBUG
 
+#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
 #include <linux/slab.h>
@@ -1009,7 +1010,7 @@ static int gelic_card_decode_one_descr(struct gelic_card *card)
                                netdev = card->netdev[i];
                                break;
                        }
-               };
+               }
                if (GELIC_PORT_MAX <= i) {
                        pr_info("%s: unknown packet vid=%x\n", __func__, vid);
                        goto refill;
index d328507..7d8483f 100644 (file)
@@ -7,6 +7,7 @@
 #ifndef _QLGE_H_
 #define _QLGE_H_
 
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/netdevice.h>
 #include <linux/rtnetlink.h>
index 19b00fa..9b67bfe 100644 (file)
@@ -650,8 +650,6 @@ static int ql_set_pauseparam(struct net_device *netdev,
                return -EINVAL;
 
        status = ql_mb_set_port_cfg(qdev);
-       if (status)
-               return status;
        return status;
 }
 
index ef1ce2e..7310824 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/ip.h>
 #include <linux/tcp.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/dma-mapping.h>
 #include <linux/pm_runtime.h>
 #include <linux/firmware.h>
index fa74314..9da4733 100644 (file)
@@ -22,6 +22,7 @@
  * matching, so you need to enable IFF_PROMISC when using it.
  */
 
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/delay.h>
index f2a2b94..bafa23a 100644 (file)
@@ -10,6 +10,7 @@
 
 #include <linux/bitops.h>
 #include <linux/delay.h>
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/module.h>
 #include <linux/seq_file.h>
index b436e00..8ad7bfb 100644 (file)
@@ -21,6 +21,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/netdevice.h>
index 598bf7a..a2eb341 100644 (file)
@@ -3,6 +3,7 @@
  */
 #ifndef _SKGE_H
 #define _SKGE_H
+#include <linux/interrupt.h>
 
 /* PCI config registers */
 #define PCI_DEV_REG1   0x40
index 3ee41da..d252cb1 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/pci.h>
+#include <linux/interrupt.h>
 #include <linux/ip.h>
 #include <linux/slab.h>
 #include <net/ip.h>
index ab9e3b7..0a0a664 100644 (file)
@@ -297,7 +297,7 @@ slhc_compress(struct slcompress *comp, unsigned char *icp, int isize,
                lcs = cs;
                cs = cs->next;
                comp->sls_o_searches++;
-       };
+       }
        /*
         * Didn't find it -- re-use oldest cstate.  Send an
         * uncompressed packet that tells the other side what
index 584809c..8ec1a9a 100644 (file)
@@ -670,17 +670,16 @@ static void sl_setup(struct net_device *dev)
  * in parallel
  */
 
-static unsigned int slip_receive_buf(struct tty_struct *tty,
-               const unsigned char *cp, char *fp, int count)
+static void slip_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                                                       char *fp, int count)
 {
        struct slip *sl = tty->disc_data;
-       int bytes = count;
 
        if (!sl || sl->magic != SLIP_MAGIC || !netif_running(sl->dev))
-               return -ENODEV;
+               return;
 
        /* Read the characters out of the buffer */
-       while (bytes--) {
+       while (count--) {
                if (fp && *fp++) {
                        if (!test_and_set_bit(SLF_ERROR, &sl->flags))
                                sl->dev->stats.rx_errors++;
@@ -694,8 +693,6 @@ static unsigned int slip_receive_buf(struct tty_struct *tty,
 #endif
                        slip_unesc(sl, *cp++);
        }
-
-       return count;
 }
 
 /************************************
index 0f29f26..34934fb 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 
@@ -156,7 +157,7 @@ static const struct {
    { 14, 15 }
 };
 
-static const short smc_mca_adapter_ids[] __devinitconst = {
+static short smc_mca_adapter_ids[] __initdata = {
        0x61c8,
        0x61c9,
        0x6fc0,
@@ -168,7 +169,7 @@ static const short smc_mca_adapter_ids[] __devinitconst = {
        0x0000
 };
 
-static const char *const smc_mca_adapter_names[] __devinitconst = {
+static char *smc_mca_adapter_names[] __initdata = {
        "SMC Ethercard PLUS Elite/A BNC/AUI (WD8013EP/A)",
        "SMC Ethercard PLUS Elite/A UTP/AUI (WD8013WP/A)",
        "WD Ethercard PLUS/A (WD8003E/A or WD8003ET/A)",
@@ -199,7 +200,7 @@ static const struct net_device_ops ultramca_netdev_ops = {
 #endif
 };
 
-static int __devinit ultramca_probe(struct device *gen_dev)
+static int __init ultramca_probe(struct device *gen_dev)
 {
        unsigned short ioaddr;
        struct net_device *dev;
index 235a3c6..ba44ede 100644 (file)
@@ -62,6 +62,7 @@ static const char version[] =
 #include <linux/errno.h>
 #include <linux/string.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/isapnp.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
index c6d47d1..0545976 100644 (file)
@@ -37,6 +37,7 @@
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
index 4c92ad8..5e5e64d 100644 (file)
@@ -19,6 +19,7 @@
  ***************************************************************************
  */
 
+#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
 #include <linux/phy.h>
index 949f124..9bc6c20 100644 (file)
@@ -31,6 +31,7 @@
 #include <linux/if_vlan.h>
 #include <linux/in.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/gfp.h>
 #include <linux/ioport.h>
 #include <linux/ip.h>
index 36045f3..860a508 100644 (file)
@@ -30,6 +30,7 @@
 #define DRV_VERSION    "2.1"
 #define DRV_RELDATE    "July  6, 2008"
 
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/pci.h>
index ae5213a..720c5a1 100644 (file)
@@ -24,6 +24,7 @@
 
 #include <linux/etherdevice.h>
 #include <linux/ethtool.h>
+#include <linux/interrupt.h>
 #include <linux/mii.h>
 #include <linux/phy.h>
 
index ab59300..71d4a03 100644 (file)
  * NAPI and NETPOLL support
  * (C) 2004 by Eric Lemoine (eric.lemoine@gmail.com)
  *
- * TODO:
- *  - Now that the driver was significantly simplified, I need to rework
- *    the locking. I'm sure we don't need _2_ spinlocks, and we probably
- *    can avoid taking most of them for so long period of time (and schedule
- *    instead). The main issues at this point are caused by the netdev layer
- *    though:
- *
- *    gem_change_mtu() and gem_set_multicast() are called with a read_lock()
- *    help by net/core/dev.c, thus they can't schedule. That means they can't
- *    call napi_disable() neither, thus force gem_poll() to keep a spinlock
- *    where it could have been dropped. change_mtu especially would love also to
- *    be able to msleep instead of horrid locked delays when resetting the HW,
- *    but that read_lock() makes it impossible, unless I defer it's action to
- *    the reset task, which means it'll be asynchronous (won't take effect until
- *    the system schedules a bit).
- *
- *    Also, it would probably be possible to also remove most of the long-life
- *    locking in open/resume code path (gem_reinit_chip) by beeing more careful
- *    about when we can start taking interrupts or get xmit() called...
  */
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
@@ -57,7 +38,6 @@
 #include <linux/workqueue.h>
 #include <linux/if_vlan.h>
 #include <linux/bitops.h>
-#include <linux/mutex.h>
 #include <linux/mm.h>
 #include <linux/gfp.h>
 
                         SUPPORTED_Pause | SUPPORTED_Autoneg)
 
 #define DRV_NAME       "sungem"
-#define DRV_VERSION    "0.98"
-#define DRV_RELDATE    "8/24/03"
-#define DRV_AUTHOR     "David S. Miller (davem@redhat.com)"
+#define DRV_VERSION    "1.0"
+#define DRV_AUTHOR     "David S. Miller <davem@redhat.com>"
 
 static char version[] __devinitdata =
-        DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " " DRV_AUTHOR "\n";
+        DRV_NAME ".c:v" DRV_VERSION " " DRV_AUTHOR "\n";
 
 MODULE_AUTHOR(DRV_AUTHOR);
 MODULE_DESCRIPTION("Sun GEM Gbit ethernet driver");
@@ -218,6 +197,7 @@ static inline void gem_disable_ints(struct gem *gp)
 {
        /* Disable all interrupts, including TXDONE */
        writel(GREG_STAT_NAPI | GREG_STAT_TXDONE, gp->regs + GREG_IMASK);
+       (void)readl(gp->regs + GREG_IMASK); /* write posting */
 }
 
 static void gem_get_cell(struct gem *gp)
@@ -247,6 +227,29 @@ static void gem_put_cell(struct gem *gp)
 #endif /* CONFIG_PPC_PMAC */
 }
 
+static inline void gem_netif_stop(struct gem *gp)
+{
+       gp->dev->trans_start = jiffies; /* prevent tx timeout */
+       napi_disable(&gp->napi);
+       netif_tx_disable(gp->dev);
+}
+
+static inline void gem_netif_start(struct gem *gp)
+{
+       /* NOTE: unconditional netif_wake_queue is only
+        * appropriate so long as all callers are assured to
+        * have free tx slots.
+        */
+       netif_wake_queue(gp->dev);
+       napi_enable(&gp->napi);
+}
+
+static void gem_schedule_reset(struct gem *gp)
+{
+       gp->reset_task_pending = 1;
+       schedule_work(&gp->reset_task);
+}
+
 static void gem_handle_mif_event(struct gem *gp, u32 reg_val, u32 changed_bits)
 {
        if (netif_msg_intr(gp))
@@ -604,56 +607,46 @@ static int gem_abnormal_irq(struct net_device *dev, struct gem *gp, u32 gem_stat
                                gp->dev->name);
                dev->stats.rx_errors++;
 
-               goto do_reset;
+               return 1;
        }
 
        if (gem_status & GREG_STAT_PCS) {
                if (gem_pcs_interrupt(dev, gp, gem_status))
-                       goto do_reset;
+                       return 1;
        }
 
        if (gem_status & GREG_STAT_TXMAC) {
                if (gem_txmac_interrupt(dev, gp, gem_status))
-                       goto do_reset;
+                       return 1;
        }
 
        if (gem_status & GREG_STAT_RXMAC) {
                if (gem_rxmac_interrupt(dev, gp, gem_status))
-                       goto do_reset;
+                       return 1;
        }
 
        if (gem_status & GREG_STAT_MAC) {
                if (gem_mac_interrupt(dev, gp, gem_status))
-                       goto do_reset;
+                       return 1;
        }
 
        if (gem_status & GREG_STAT_MIF) {
                if (gem_mif_interrupt(dev, gp, gem_status))
-                       goto do_reset;
+                       return 1;
        }
 
        if (gem_status & GREG_STAT_PCIERR) {
                if (gem_pci_interrupt(dev, gp, gem_status))
-                       goto do_reset;
+                       return 1;
        }
 
        return 0;
-
-do_reset:
-       gp->reset_task_pending = 1;
-       schedule_work(&gp->reset_task);
-
-       return 1;
 }
 
 static __inline__ void gem_tx(struct net_device *dev, struct gem *gp, u32 gem_status)
 {
        int entry, limit;
 
-       if (netif_msg_intr(gp))
-               printk(KERN_DEBUG "%s: tx interrupt, gem_status: 0x%x\n",
-                       gp->dev->name, gem_status);
-
        entry = gp->tx_old;
        limit = ((gem_status & GREG_STAT_TXNR) >> GREG_STAT_TXNR_SHIFT);
        while (entry != limit) {
@@ -697,13 +690,27 @@ static __inline__ void gem_tx(struct net_device *dev, struct gem *gp, u32 gem_st
                }
 
                dev->stats.tx_packets++;
-               dev_kfree_skb_irq(skb);
+               dev_kfree_skb(skb);
        }
        gp->tx_old = entry;
 
-       if (netif_queue_stopped(dev) &&
-           TX_BUFFS_AVAIL(gp) > (MAX_SKB_FRAGS + 1))
-               netif_wake_queue(dev);
+       /* Need to make the tx_old update visible to gem_start_xmit()
+        * before checking for netif_queue_stopped().  Without the
+        * memory barrier, there is a small possibility that gem_start_xmit()
+        * will miss it and cause the queue to be stopped forever.
+        */
+       smp_mb();
+
+       if (unlikely(netif_queue_stopped(dev) &&
+                    TX_BUFFS_AVAIL(gp) > (MAX_SKB_FRAGS + 1))) {
+               struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
+
+               __netif_tx_lock(txq, smp_processor_id());
+               if (netif_queue_stopped(dev) &&
+                   TX_BUFFS_AVAIL(gp) > (MAX_SKB_FRAGS + 1))
+                       netif_wake_queue(dev);
+               __netif_tx_unlock(txq);
+       }
 }
 
 static __inline__ void gem_post_rxds(struct gem *gp, int limit)
@@ -736,6 +743,21 @@ static __inline__ void gem_post_rxds(struct gem *gp, int limit)
        }
 }
 
+#define ALIGNED_RX_SKB_ADDR(addr) \
+        ((((unsigned long)(addr) + (64UL - 1UL)) & ~(64UL - 1UL)) - (unsigned long)(addr))
+static __inline__ struct sk_buff *gem_alloc_skb(struct net_device *dev, int size,
+                                               gfp_t gfp_flags)
+{
+       struct sk_buff *skb = alloc_skb(size + 64, gfp_flags);
+
+       if (likely(skb)) {
+               unsigned long offset = ALIGNED_RX_SKB_ADDR(skb->data);
+               skb_reserve(skb, offset);
+               skb->dev = dev;
+       }
+       return skb;
+}
+
 static int gem_rx(struct gem *gp, int work_to_do)
 {
        struct net_device *dev = gp->dev;
@@ -799,7 +821,7 @@ static int gem_rx(struct gem *gp, int work_to_do)
                if (len > RX_COPY_THRESHOLD) {
                        struct sk_buff *new_skb;
 
-                       new_skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), GFP_ATOMIC);
+                       new_skb = gem_alloc_skb(dev, RX_BUF_ALLOC_SIZE(gp), GFP_ATOMIC);
                        if (new_skb == NULL) {
                                drops++;
                                goto drop_it;
@@ -808,7 +830,6 @@ static int gem_rx(struct gem *gp, int work_to_do)
                                       RX_BUF_ALLOC_SIZE(gp),
                                       PCI_DMA_FROMDEVICE);
                        gp->rx_skbs[entry] = new_skb;
-                       new_skb->dev = gp->dev;
                        skb_put(new_skb, (gp->rx_buf_sz + RX_OFFSET));
                        rxd->buffer = cpu_to_le64(pci_map_page(gp->pdev,
                                                               virt_to_page(new_skb->data),
@@ -820,7 +841,7 @@ static int gem_rx(struct gem *gp, int work_to_do)
                        /* Trim the original skb for the netif. */
                        skb_trim(skb, len);
                } else {
-                       struct sk_buff *copy_skb = dev_alloc_skb(len + 2);
+                       struct sk_buff *copy_skb = netdev_alloc_skb(dev, len + 2);
 
                        if (copy_skb == NULL) {
                                drops++;
@@ -842,7 +863,7 @@ static int gem_rx(struct gem *gp, int work_to_do)
                skb->ip_summed = CHECKSUM_COMPLETE;
                skb->protocol = eth_type_trans(skb, gp->dev);
 
-               netif_receive_skb(skb);
+               napi_gro_receive(&gp->napi, skb);
 
                dev->stats.rx_packets++;
                dev->stats.rx_bytes += len;
@@ -865,28 +886,32 @@ static int gem_poll(struct napi_struct *napi, int budget)
 {
        struct gem *gp = container_of(napi, struct gem, napi);
        struct net_device *dev = gp->dev;
-       unsigned long flags;
        int work_done;
 
-       /*
-        * NAPI locking nightmare: See comment at head of driver
-        */
-       spin_lock_irqsave(&gp->lock, flags);
-
        work_done = 0;
        do {
                /* Handle anomalies */
-               if (gp->status & GREG_STAT_ABNORMAL) {
-                       if (gem_abnormal_irq(dev, gp, gp->status))
-                               break;
+               if (unlikely(gp->status & GREG_STAT_ABNORMAL)) {
+                       struct netdev_queue *txq = netdev_get_tx_queue(dev, 0);
+                       int reset;
+
+                       /* We run the abnormal interrupt handling code with
+                        * the Tx lock. It only resets the Rx portion of the
+                        * chip, but we need to guard it against DMA being
+                        * restarted by the link poll timer
+                        */
+                       __netif_tx_lock(txq, smp_processor_id());
+                       reset = gem_abnormal_irq(dev, gp, gp->status);
+                       __netif_tx_unlock(txq);
+                       if (reset) {
+                               gem_schedule_reset(gp);
+                               napi_complete(napi);
+                               return work_done;
+                       }
                }
 
                /* Run TX completion thread */
-               spin_lock(&gp->tx_lock);
                gem_tx(dev, gp, gp->status);
-               spin_unlock(&gp->tx_lock);
-
-               spin_unlock_irqrestore(&gp->lock, flags);
 
                /* Run RX thread. We don't use any locking here,
                 * code willing to do bad things - like cleaning the
@@ -898,16 +923,12 @@ static int gem_poll(struct napi_struct *napi, int budget)
                if (work_done >= budget)
                        return work_done;
 
-               spin_lock_irqsave(&gp->lock, flags);
-
                gp->status = readl(gp->regs + GREG_STAT);
        } while (gp->status & GREG_STAT_NAPI);
 
-       __napi_complete(napi);
+       napi_complete(napi);
        gem_enable_ints(gp);
 
-       spin_unlock_irqrestore(&gp->lock, flags);
-
        return work_done;
 }
 
@@ -915,32 +936,23 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id)
 {
        struct net_device *dev = dev_id;
        struct gem *gp = netdev_priv(dev);
-       unsigned long flags;
-
-       /* Swallow interrupts when shutting the chip down, though
-        * that shouldn't happen, we should have done free_irq() at
-        * this point...
-        */
-       if (!gp->running)
-               return IRQ_HANDLED;
-
-       spin_lock_irqsave(&gp->lock, flags);
 
        if (napi_schedule_prep(&gp->napi)) {
                u32 gem_status = readl(gp->regs + GREG_STAT);
 
-               if (gem_status == 0) {
+               if (unlikely(gem_status == 0)) {
                        napi_enable(&gp->napi);
-                       spin_unlock_irqrestore(&gp->lock, flags);
                        return IRQ_NONE;
                }
+               if (netif_msg_intr(gp))
+                       printk(KERN_DEBUG "%s: gem_interrupt() gem_status: 0x%x\n",
+                              gp->dev->name, gem_status);
+
                gp->status = gem_status;
                gem_disable_ints(gp);
                __napi_schedule(&gp->napi);
        }
 
-       spin_unlock_irqrestore(&gp->lock, flags);
-
        /* If polling was disabled at the time we received that
         * interrupt, we may return IRQ_HANDLED here while we
         * should return IRQ_NONE. No big deal...
@@ -951,10 +963,11 @@ static irqreturn_t gem_interrupt(int irq, void *dev_id)
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void gem_poll_controller(struct net_device *dev)
 {
-       /* gem_interrupt is safe to reentrance so no need
-        * to disable_irq here.
-        */
-       gem_interrupt(dev->irq, dev);
+       struct gem *gp = netdev_priv(dev);
+
+       disable_irq(gp->pdev->irq);
+       gem_interrupt(gp->pdev->irq, dev);
+       enable_irq(gp->pdev->irq);
 }
 #endif
 
@@ -963,10 +976,7 @@ static void gem_tx_timeout(struct net_device *dev)
        struct gem *gp = netdev_priv(dev);
 
        netdev_err(dev, "transmit timed out, resetting\n");
-       if (!gp->running) {
-               netdev_err(dev, "hrm.. hw not running !\n");
-               return;
-       }
+
        netdev_err(dev, "TX_STATE[%08x:%08x:%08x]\n",
                   readl(gp->regs + TXDMA_CFG),
                   readl(gp->regs + MAC_TXSTAT),
@@ -976,14 +986,7 @@ static void gem_tx_timeout(struct net_device *dev)
                   readl(gp->regs + MAC_RXSTAT),
                   readl(gp->regs + MAC_RXCFG));
 
-       spin_lock_irq(&gp->lock);
-       spin_lock(&gp->tx_lock);
-
-       gp->reset_task_pending = 1;
-       schedule_work(&gp->reset_task);
-
-       spin_unlock(&gp->tx_lock);
-       spin_unlock_irq(&gp->lock);
+       gem_schedule_reset(gp);
 }
 
 static __inline__ int gem_intme(int entry)
@@ -1001,7 +1004,6 @@ static netdev_tx_t gem_start_xmit(struct sk_buff *skb,
        struct gem *gp = netdev_priv(dev);
        int entry;
        u64 ctrl;
-       unsigned long flags;
 
        ctrl = 0;
        if (skb->ip_summed == CHECKSUM_PARTIAL) {
@@ -1013,21 +1015,12 @@ static netdev_tx_t gem_start_xmit(struct sk_buff *skb,
                        (csum_stuff_off << 21));
        }
 
-       if (!spin_trylock_irqsave(&gp->tx_lock, flags)) {
-               /* Tell upper layer to requeue */
-               return NETDEV_TX_LOCKED;
-       }
-       /* We raced with gem_do_stop() */
-       if (!gp->running) {
-               spin_unlock_irqrestore(&gp->tx_lock, flags);
-               return NETDEV_TX_BUSY;
-       }
-
-       /* This is a hard error, log it. */
-       if (TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1)) {
-               netif_stop_queue(dev);
-               spin_unlock_irqrestore(&gp->tx_lock, flags);
-               netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
+       if (unlikely(TX_BUFFS_AVAIL(gp) <= (skb_shinfo(skb)->nr_frags + 1))) {
+               /* This is a hard error, log it. */
+               if (!netif_queue_stopped(dev)) {
+                       netif_stop_queue(dev);
+                       netdev_err(dev, "BUG! Tx Ring full when queue awake!\n");
+               }
                return NETDEV_TX_BUSY;
        }
 
@@ -1104,17 +1097,23 @@ static netdev_tx_t gem_start_xmit(struct sk_buff *skb,
        }
 
        gp->tx_new = entry;
-       if (TX_BUFFS_AVAIL(gp) <= (MAX_SKB_FRAGS + 1))
+       if (unlikely(TX_BUFFS_AVAIL(gp) <= (MAX_SKB_FRAGS + 1))) {
                netif_stop_queue(dev);
 
+               /* netif_stop_queue() must be done before checking
+                * checking tx index in TX_BUFFS_AVAIL() below, because
+                * in gem_tx(), we update tx_old before checking for
+                * netif_queue_stopped().
+                */
+               smp_mb();
+               if (TX_BUFFS_AVAIL(gp) > (MAX_SKB_FRAGS + 1))
+                       netif_wake_queue(dev);
+       }
        if (netif_msg_tx_queued(gp))
                printk(KERN_DEBUG "%s: tx queued, slot %d, skblen %d\n",
                       dev->name, entry, skb->len);
        mb();
        writel(gp->tx_new, gp->regs + TXDMA_KICK);
-       spin_unlock_irqrestore(&gp->tx_lock, flags);
-
-       dev->trans_start = jiffies; /* NETIF_F_LLTX driver :( */
 
        return NETDEV_TX_OK;
 }
@@ -1184,7 +1183,6 @@ static void gem_pcs_reinit_adv(struct gem *gp)
 
 #define STOP_TRIES 32
 
-/* Must be invoked under gp->lock and gp->tx_lock. */
 static void gem_reset(struct gem *gp)
 {
        int limit;
@@ -1213,7 +1211,6 @@ static void gem_reset(struct gem *gp)
                gem_pcs_reinit_adv(gp);
 }
 
-/* Must be invoked under gp->lock and gp->tx_lock. */
 static void gem_start_dma(struct gem *gp)
 {
        u32 val;
@@ -1236,8 +1233,7 @@ static void gem_start_dma(struct gem *gp)
        writel(RX_RING_SIZE - 4, gp->regs + RXDMA_KICK);
 }
 
-/* Must be invoked under gp->lock and gp->tx_lock. DMA won't be
- * actually stopped before about 4ms tho ...
+/* DMA won't be actually stopped before about 4ms tho ...
  */
 static void gem_stop_dma(struct gem *gp)
 {
@@ -1259,7 +1255,6 @@ static void gem_stop_dma(struct gem *gp)
 }
 
 
-/* Must be invoked under gp->lock and gp->tx_lock. */
 // XXX dbl check what that function should do when called on PCS PHY
 static void gem_begin_auto_negotiation(struct gem *gp, struct ethtool_cmd *ep)
 {
@@ -1319,7 +1314,7 @@ start_aneg:
        /* If we are asleep, we don't try to actually setup the PHY, we
         * just store the settings
         */
-       if (gp->asleep) {
+       if (!netif_device_present(gp->dev)) {
                gp->phy_mii.autoneg = gp->want_autoneg = autoneg;
                gp->phy_mii.speed = speed;
                gp->phy_mii.duplex = duplex;
@@ -1345,13 +1340,12 @@ non_mii:
 
 /* A link-up condition has occurred, initialize and enable the
  * rest of the chip.
- *
- * Must be invoked under gp->lock and gp->tx_lock.
  */
 static int gem_set_link_modes(struct gem *gp)
 {
-       u32 val;
+       struct netdev_queue *txq = netdev_get_tx_queue(gp->dev, 0);
        int full_duplex, speed, pause;
+       u32 val;
 
        full_duplex = 0;
        speed = SPEED_10;
@@ -1375,8 +1369,11 @@ static int gem_set_link_modes(struct gem *gp)
        netif_info(gp, link, gp->dev, "Link is up at %d Mbps, %s-duplex\n",
                   speed, (full_duplex ? "full" : "half"));
 
-       if (!gp->running)
-               return 0;
+
+       /* We take the tx queue lock to avoid collisions between
+        * this code, the tx path and the NAPI-driven error path
+        */
+       __netif_tx_lock(txq, smp_processor_id());
 
        val = (MAC_TXCFG_EIPG0 | MAC_TXCFG_NGU);
        if (full_duplex) {
@@ -1425,18 +1422,6 @@ static int gem_set_link_modes(struct gem *gp)
                        pause = 1;
        }
 
-       if (netif_msg_link(gp)) {
-               if (pause) {
-                       netdev_info(gp->dev,
-                                   "Pause is enabled (rxfifo: %d off: %d on: %d)\n",
-                                   gp->rx_fifo_sz,
-                                   gp->rx_pause_off,
-                                   gp->rx_pause_on);
-               } else {
-                       netdev_info(gp->dev, "Pause is disabled\n");
-               }
-       }
-
        if (!full_duplex)
                writel(512, gp->regs + MAC_STIME);
        else
@@ -1450,10 +1435,23 @@ static int gem_set_link_modes(struct gem *gp)
 
        gem_start_dma(gp);
 
+       __netif_tx_unlock(txq);
+
+       if (netif_msg_link(gp)) {
+               if (pause) {
+                       netdev_info(gp->dev,
+                                   "Pause is enabled (rxfifo: %d off: %d on: %d)\n",
+                                   gp->rx_fifo_sz,
+                                   gp->rx_pause_off,
+                                   gp->rx_pause_on);
+               } else {
+                       netdev_info(gp->dev, "Pause is disabled\n");
+               }
+       }
+
        return 0;
 }
 
-/* Must be invoked under gp->lock and gp->tx_lock. */
 static int gem_mdio_link_not_up(struct gem *gp)
 {
        switch (gp->lstate) {
@@ -1501,20 +1499,12 @@ static int gem_mdio_link_not_up(struct gem *gp)
 static void gem_link_timer(unsigned long data)
 {
        struct gem *gp = (struct gem *) data;
+       struct net_device *dev = gp->dev;
        int restart_aneg = 0;
 
-       if (gp->asleep)
-               return;
-
-       spin_lock_irq(&gp->lock);
-       spin_lock(&gp->tx_lock);
-       gem_get_cell(gp);
-
-       /* If the reset task is still pending, we just
-        * reschedule the link timer
-        */
+       /* There's no point doing anything if we're going to be reset */
        if (gp->reset_task_pending)
-               goto restart;
+               return;
 
        if (gp->phy_type == phy_serialink ||
            gp->phy_type == phy_serdes) {
@@ -1528,7 +1518,7 @@ static void gem_link_timer(unsigned long data)
                                goto restart;
 
                        gp->lstate = link_up;
-                       netif_carrier_on(gp->dev);
+                       netif_carrier_on(dev);
                        (void)gem_set_link_modes(gp);
                }
                goto restart;
@@ -1544,12 +1534,12 @@ static void gem_link_timer(unsigned long data)
                        gp->last_forced_speed = gp->phy_mii.speed;
                        gp->timer_ticks = 5;
                        if (netif_msg_link(gp))
-                               netdev_info(gp->dev,
+                               netdev_info(dev,
                                            "Got link after fallback, retrying autoneg once...\n");
                        gp->phy_mii.def->ops->setup_aneg(&gp->phy_mii, gp->phy_mii.advertising);
                } else if (gp->lstate != link_up) {
                        gp->lstate = link_up;
-                       netif_carrier_on(gp->dev);
+                       netif_carrier_on(dev);
                        if (gem_set_link_modes(gp))
                                restart_aneg = 1;
                }
@@ -1559,11 +1549,11 @@ static void gem_link_timer(unsigned long data)
                 */
                if (gp->lstate == link_up) {
                        gp->lstate = link_down;
-                       netif_info(gp, link, gp->dev, "Link down\n");
-                       netif_carrier_off(gp->dev);
-                       gp->reset_task_pending = 1;
-                       schedule_work(&gp->reset_task);
-                       restart_aneg = 1;
+                       netif_info(gp, link, dev, "Link down\n");
+                       netif_carrier_off(dev);
+                       gem_schedule_reset(gp);
+                       /* The reset task will restart the timer */
+                       return;
                } else if (++gp->timer_ticks > 10) {
                        if (found_mii_phy(gp))
                                restart_aneg = gem_mdio_link_not_up(gp);
@@ -1573,17 +1563,12 @@ static void gem_link_timer(unsigned long data)
        }
        if (restart_aneg) {
                gem_begin_auto_negotiation(gp, NULL);
-               goto out_unlock;
+               return;
        }
 restart:
        mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10));
-out_unlock:
-       gem_put_cell(gp);
-       spin_unlock(&gp->tx_lock);
-       spin_unlock_irq(&gp->lock);
 }
 
-/* Must be invoked under gp->lock and gp->tx_lock. */
 static void gem_clean_rings(struct gem *gp)
 {
        struct gem_init_block *gb = gp->init_block;
@@ -1634,7 +1619,6 @@ static void gem_clean_rings(struct gem *gp)
        }
 }
 
-/* Must be invoked under gp->lock and gp->tx_lock. */
 static void gem_init_rings(struct gem *gp)
 {
        struct gem_init_block *gb = gp->init_block;
@@ -1653,7 +1637,7 @@ static void gem_init_rings(struct gem *gp)
                struct sk_buff *skb;
                struct gem_rxd *rxd = &gb->rxd[i];
 
-               skb = gem_alloc_skb(RX_BUF_ALLOC_SIZE(gp), GFP_ATOMIC);
+               skb = gem_alloc_skb(dev, RX_BUF_ALLOC_SIZE(gp), GFP_KERNEL);
                if (!skb) {
                        rxd->buffer = 0;
                        rxd->status_word = 0;
@@ -1661,7 +1645,6 @@ static void gem_init_rings(struct gem *gp)
                }
 
                gp->rx_skbs[i] = skb;
-               skb->dev = dev;
                skb_put(skb, (gp->rx_buf_sz + RX_OFFSET));
                dma_addr = pci_map_page(gp->pdev,
                                        virt_to_page(skb->data),
@@ -1737,7 +1720,7 @@ static void gem_init_phy(struct gem *gp)
 
        if (gp->phy_type == phy_mii_mdio0 ||
            gp->phy_type == phy_mii_mdio1) {
-               // XXX check for errors
+               /* Reset and detect MII PHY */
                mii_phy_probe(&gp->phy_mii, gp->mii_phy_addr);
 
                /* Init PHY */
@@ -1753,13 +1736,15 @@ static void gem_init_phy(struct gem *gp)
        gp->lstate = link_down;
        netif_carrier_off(gp->dev);
 
-       /* Can I advertise gigabit here ? I'd need BCM PHY docs... */
-       spin_lock_irq(&gp->lock);
+       /* Print things out */
+       if (gp->phy_type == phy_mii_mdio0 ||
+           gp->phy_type == phy_mii_mdio1)
+               netdev_info(gp->dev, "Found %s PHY\n",
+                           gp->phy_mii.def ? gp->phy_mii.def->name : "no");
+
        gem_begin_auto_negotiation(gp, NULL);
-       spin_unlock_irq(&gp->lock);
 }
 
-/* Must be invoked under gp->lock and gp->tx_lock. */
 static void gem_init_dma(struct gem *gp)
 {
        u64 desc_dma = (u64) gp->gblock_dvma;
@@ -1797,7 +1782,6 @@ static void gem_init_dma(struct gem *gp)
                       gp->regs + RXDMA_BLANK);
 }
 
-/* Must be invoked under gp->lock and gp->tx_lock. */
 static u32 gem_setup_multicast(struct gem *gp)
 {
        u32 rxcfg = 0;
@@ -1835,7 +1819,6 @@ static u32 gem_setup_multicast(struct gem *gp)
        return rxcfg;
 }
 
-/* Must be invoked under gp->lock and gp->tx_lock. */
 static void gem_init_mac(struct gem *gp)
 {
        unsigned char *e = &gp->dev->dev_addr[0];
@@ -1918,7 +1901,6 @@ static void gem_init_mac(struct gem *gp)
                writel(0, gp->regs + WOL_WAKECSR);
 }
 
-/* Must be invoked under gp->lock and gp->tx_lock. */
 static void gem_init_pause_thresholds(struct gem *gp)
 {
                u32 cfg;
@@ -2079,7 +2061,6 @@ static int gem_check_invariants(struct gem *gp)
        return 0;
 }
 
-/* Must be invoked under gp->lock and gp->tx_lock. */
 static void gem_reinit_chip(struct gem *gp)
 {
        /* Reset the chip */
@@ -2100,11 +2081,9 @@ static void gem_reinit_chip(struct gem *gp)
 }
 
 
-/* Must be invoked with no lock held. */
 static void gem_stop_phy(struct gem *gp, int wol)
 {
        u32 mifcfg;
-       unsigned long flags;
 
        /* Let the chip settle down a bit, it seems that helps
         * for sleep mode on some models
@@ -2150,15 +2129,9 @@ static void gem_stop_phy(struct gem *gp, int wol)
        writel(0, gp->regs + RXDMA_CFG);
 
        if (!wol) {
-               spin_lock_irqsave(&gp->lock, flags);
-               spin_lock(&gp->tx_lock);
                gem_reset(gp);
                writel(MAC_TXRST_CMD, gp->regs + MAC_TXRST);
                writel(MAC_RXRST_CMD, gp->regs + MAC_RXRST);
-               spin_unlock(&gp->tx_lock);
-               spin_unlock_irqrestore(&gp->lock, flags);
-
-               /* No need to take the lock here */
 
                if (found_mii_phy(gp) && gp->phy_mii.def->ops->suspend)
                        gp->phy_mii.def->ops->suspend(&gp->phy_mii);
@@ -2175,54 +2148,55 @@ static void gem_stop_phy(struct gem *gp, int wol)
        }
 }
 
-
 static int gem_do_start(struct net_device *dev)
 {
        struct gem *gp = netdev_priv(dev);
-       unsigned long flags;
-
-       spin_lock_irqsave(&gp->lock, flags);
-       spin_lock(&gp->tx_lock);
+       int rc;
 
        /* Enable the cell */
        gem_get_cell(gp);
 
-       /* Init & setup chip hardware */
-       gem_reinit_chip(gp);
-
-       gp->running = 1;
-
-       napi_enable(&gp->napi);
+       /* Make sure PCI access and bus master are enabled */
+       rc = pci_enable_device(gp->pdev);
+       if (rc) {
+               netdev_err(dev, "Failed to enable chip on PCI bus !\n");
 
-       if (gp->lstate == link_up) {
-               netif_carrier_on(gp->dev);
-               gem_set_link_modes(gp);
+               /* Put cell and forget it for now, it will be considered as
+                * still asleep, a new sleep cycle may bring it back
+                */
+               gem_put_cell(gp);
+               return -ENXIO;
        }
+       pci_set_master(gp->pdev);
 
-       netif_wake_queue(gp->dev);
-
-       spin_unlock(&gp->tx_lock);
-       spin_unlock_irqrestore(&gp->lock, flags);
+       /* Init & setup chip hardware */
+       gem_reinit_chip(gp);
 
-       if (request_irq(gp->pdev->irq, gem_interrupt,
-                                  IRQF_SHARED, dev->name, (void *)dev)) {
+       /* An interrupt might come in handy */
+       rc = request_irq(gp->pdev->irq, gem_interrupt,
+                        IRQF_SHARED, dev->name, (void *)dev);
+       if (rc) {
                netdev_err(dev, "failed to request irq !\n");
 
-               spin_lock_irqsave(&gp->lock, flags);
-               spin_lock(&gp->tx_lock);
-
-               napi_disable(&gp->napi);
-
-               gp->running =  0;
                gem_reset(gp);
                gem_clean_rings(gp);
                gem_put_cell(gp);
+               return rc;
+       }
+
+       /* Mark us as attached again if we come from resume(), this has
+        * no effect if we weren't detatched and needs to be done now.
+        */
+       netif_device_attach(dev);
 
-               spin_unlock(&gp->tx_lock);
-               spin_unlock_irqrestore(&gp->lock, flags);
+       /* Restart NAPI & queues */
+       gem_netif_start(gp);
 
-               return -EAGAIN;
-       }
+       /* Detect & init PHY, start autoneg etc... this will
+        * eventually result in starting DMA operations when
+        * the link is up
+        */
+       gem_init_phy(gp);
 
        return 0;
 }
@@ -2230,22 +2204,30 @@ static int gem_do_start(struct net_device *dev)
 static void gem_do_stop(struct net_device *dev, int wol)
 {
        struct gem *gp = netdev_priv(dev);
-       unsigned long flags;
-
-       spin_lock_irqsave(&gp->lock, flags);
-       spin_lock(&gp->tx_lock);
 
-       gp->running = 0;
+       /* Stop NAPI and stop tx queue */
+       gem_netif_stop(gp);
 
-       /* Stop netif queue */
-       netif_stop_queue(dev);
-
-       /* Make sure ints are disabled */
+       /* Make sure ints are disabled. We don't care about
+        * synchronizing as NAPI is disabled, thus a stray
+        * interrupt will do nothing bad (our irq handler
+        * just schedules NAPI)
+        */
        gem_disable_ints(gp);
 
-       /* We can drop the lock now */
-       spin_unlock(&gp->tx_lock);
-       spin_unlock_irqrestore(&gp->lock, flags);
+       /* Stop the link timer */
+       del_timer_sync(&gp->link_timer);
+
+       /* We cannot cancel the reset task while holding the
+        * rtnl lock, we'd get an A->B / B->A deadlock stituation
+        * if we did. This is not an issue however as the reset
+        * task is synchronized vs. us (rtnl_lock) and will do
+        * nothing if the device is down or suspended. We do
+        * still clear reset_task_pending to avoid a spurrious
+        * reset later on in case we do resume before it gets
+        * scheduled.
+        */
+       gp->reset_task_pending = 0;
 
        /* If we are going to sleep with WOL */
        gem_stop_dma(gp);
@@ -2260,79 +2242,79 @@ static void gem_do_stop(struct net_device *dev, int wol)
        /* No irq needed anymore */
        free_irq(gp->pdev->irq, (void *) dev);
 
+       /* Shut the PHY down eventually and setup WOL */
+       gem_stop_phy(gp, wol);
+
+       /* Make sure bus master is disabled */
+       pci_disable_device(gp->pdev);
+
        /* Cell not needed neither if no WOL */
-       if (!wol) {
-               spin_lock_irqsave(&gp->lock, flags);
+       if (!wol)
                gem_put_cell(gp);
-               spin_unlock_irqrestore(&gp->lock, flags);
-       }
 }
 
 static void gem_reset_task(struct work_struct *work)
 {
        struct gem *gp = container_of(work, struct gem, reset_task);
 
-       mutex_lock(&gp->pm_mutex);
+       /* Lock out the network stack (essentially shield ourselves
+        * against a racing open, close, control call, or suspend
+        */
+       rtnl_lock();
 
-       if (gp->opened)
-               napi_disable(&gp->napi);
+       /* Skip the reset task if suspended or closed, or if it's
+        * been cancelled by gem_do_stop (see comment there)
+        */
+       if (!netif_device_present(gp->dev) ||
+           !netif_running(gp->dev) ||
+           !gp->reset_task_pending) {
+               rtnl_unlock();
+               return;
+       }
 
-       spin_lock_irq(&gp->lock);
-       spin_lock(&gp->tx_lock);
+       /* Stop the link timer */
+       del_timer_sync(&gp->link_timer);
 
-       if (gp->running) {
-               netif_stop_queue(gp->dev);
+       /* Stop NAPI and tx */
+       gem_netif_stop(gp);
 
-               /* Reset the chip & rings */
-               gem_reinit_chip(gp);
-               if (gp->lstate == link_up)
-                       gem_set_link_modes(gp);
-               netif_wake_queue(gp->dev);
-       }
+       /* Reset the chip & rings */
+       gem_reinit_chip(gp);
+       if (gp->lstate == link_up)
+               gem_set_link_modes(gp);
 
-       gp->reset_task_pending = 0;
+       /* Restart NAPI and Tx */
+       gem_netif_start(gp);
 
-       spin_unlock(&gp->tx_lock);
-       spin_unlock_irq(&gp->lock);
+       /* We are back ! */
+       gp->reset_task_pending = 0;
 
-       if (gp->opened)
-               napi_enable(&gp->napi);
+       /* If the link is not up, restart autoneg, else restart the
+        * polling timer
+        */
+       if (gp->lstate != link_up)
+               gem_begin_auto_negotiation(gp, NULL);
+       else
+               mod_timer(&gp->link_timer, jiffies + ((12 * HZ) / 10));
 
-       mutex_unlock(&gp->pm_mutex);
+       rtnl_unlock();
 }
 
-
 static int gem_open(struct net_device *dev)
 {
-       struct gem *gp = netdev_priv(dev);
-       int rc = 0;
-
-       mutex_lock(&gp->pm_mutex);
-
-       /* We need the cell enabled */
-       if (!gp->asleep)
-               rc = gem_do_start(dev);
-       gp->opened = (rc == 0);
-
-       mutex_unlock(&gp->pm_mutex);
-
-       return rc;
+       /* We allow open while suspended, we just do nothing,
+        * the chip will be initialized in resume()
+        */
+       if (netif_device_present(dev))
+               return gem_do_start(dev);
+       return 0;
 }
 
 static int gem_close(struct net_device *dev)
 {
-       struct gem *gp = netdev_priv(dev);
-
-       mutex_lock(&gp->pm_mutex);
-
-       napi_disable(&gp->napi);
-
-       gp->opened = 0;
-       if (!gp->asleep)
+       if (netif_device_present(dev))
                gem_do_stop(dev, 0);
 
-       mutex_unlock(&gp->pm_mutex);
-
        return 0;
 }
 
@@ -2341,59 +2323,35 @@ static int gem_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
        struct gem *gp = netdev_priv(dev);
-       unsigned long flags;
-
-       mutex_lock(&gp->pm_mutex);
 
-       netdev_info(dev, "suspending, WakeOnLan %s\n",
-                   (gp->wake_on_lan && gp->opened) ? "enabled" : "disabled");
-
-       /* Keep the cell enabled during the entire operation */
-       spin_lock_irqsave(&gp->lock, flags);
-       spin_lock(&gp->tx_lock);
-       gem_get_cell(gp);
-       spin_unlock(&gp->tx_lock);
-       spin_unlock_irqrestore(&gp->lock, flags);
-
-       /* If the driver is opened, we stop the MAC */
-       if (gp->opened) {
-               napi_disable(&gp->napi);
+       /* Lock the network stack first to avoid racing with open/close,
+        * reset task and setting calls
+        */
+       rtnl_lock();
 
-               /* Stop traffic, mark us closed */
+       /* Not running, mark ourselves non-present, no need for
+        * a lock here
+        */
+       if (!netif_running(dev)) {
                netif_device_detach(dev);
+               rtnl_unlock();
+               return 0;
+       }
+       netdev_info(dev, "suspending, WakeOnLan %s\n",
+                   (gp->wake_on_lan && netif_running(dev)) ?
+                   "enabled" : "disabled");
 
-               /* Switch off MAC, remember WOL setting */
-               gp->asleep_wol = gp->wake_on_lan;
-               gem_do_stop(dev, gp->asleep_wol);
-       } else
-               gp->asleep_wol = 0;
-
-       /* Mark us asleep */
-       gp->asleep = 1;
-       wmb();
-
-       /* Stop the link timer */
-       del_timer_sync(&gp->link_timer);
-
-       /* Now we release the mutex to not block the reset task who
-        * can take it too. We are marked asleep, so there will be no
-        * conflict here
+       /* Tell the network stack we're gone. gem_do_stop() below will
+        * synchronize with TX, stop NAPI etc...
         */
-       mutex_unlock(&gp->pm_mutex);
+       netif_device_detach(dev);
 
-       /* Wait for the pending reset task to complete */
-       flush_work_sync(&gp->reset_task);
-
-       /* Shut the PHY down eventually and setup WOL */
-       gem_stop_phy(gp, gp->asleep_wol);
-
-       /* Make sure bus master is disabled */
-       pci_disable_device(gp->pdev);
+       /* Switch off chip, remember WOL setting */
+       gp->asleep_wol = gp->wake_on_lan;
+       gem_do_stop(dev, gp->asleep_wol);
 
-       /* Release the cell, no need to take a lock at this point since
-        * nothing else can happen now
-        */
-       gem_put_cell(gp);
+       /* Unlock the network stack */
+       rtnl_unlock();
 
        return 0;
 }
@@ -2402,53 +2360,23 @@ static int gem_resume(struct pci_dev *pdev)
 {
        struct net_device *dev = pci_get_drvdata(pdev);
        struct gem *gp = netdev_priv(dev);
-       unsigned long flags;
-
-       netdev_info(dev, "resuming\n");
 
-       mutex_lock(&gp->pm_mutex);
+       /* See locking comment in gem_suspend */
+       rtnl_lock();
 
-       /* Keep the cell enabled during the entire operation, no need to
-        * take a lock here tho since nothing else can happen while we are
-        * marked asleep
+       /* Not running, mark ourselves present, no need for
+        * a lock here
         */
-       gem_get_cell(gp);
-
-       /* Make sure PCI access and bus master are enabled */
-       if (pci_enable_device(gp->pdev)) {
-               netdev_err(dev, "Can't re-enable chip !\n");
-               /* Put cell and forget it for now, it will be considered as
-                * still asleep, a new sleep cycle may bring it back
-                */
-               gem_put_cell(gp);
-               mutex_unlock(&gp->pm_mutex);
+       if (!netif_running(dev)) {
+               netif_device_attach(dev);
+               rtnl_unlock();
                return 0;
        }
-       pci_set_master(gp->pdev);
-
-       /* Reset everything */
-       gem_reset(gp);
-
-       /* Mark us woken up */
-       gp->asleep = 0;
-       wmb();
 
-       /* Bring the PHY back. Again, lock is useless at this point as
-        * nothing can be happening until we restart the whole thing
+       /* Restart chip. If that fails there isn't much we can do, we
+        * leave things stopped.
         */
-       gem_init_phy(gp);
-
-       /* If we were opened, bring everything back */
-       if (gp->opened) {
-               /* Restart MAC */
-               gem_do_start(dev);
-
-               /* Re-attach net device */
-               netif_device_attach(dev);
-       }
-
-       spin_lock_irqsave(&gp->lock, flags);
-       spin_lock(&gp->tx_lock);
+       gem_do_start(dev);
 
        /* If we had WOL enabled, the cell clock was never turned off during
         * sleep, so we end up beeing unbalanced. Fix that here
@@ -2456,15 +2384,8 @@ static int gem_resume(struct pci_dev *pdev)
        if (gp->asleep_wol)
                gem_put_cell(gp);
 
-       /* This function doesn't need to hold the cell, it will be held if the
-        * driver is open by gem_do_start().
-        */
-       gem_put_cell(gp);
-
-       spin_unlock(&gp->tx_lock);
-       spin_unlock_irqrestore(&gp->lock, flags);
-
-       mutex_unlock(&gp->pm_mutex);
+       /* Unlock the network stack */
+       rtnl_unlock();
 
        return 0;
 }
@@ -2474,33 +2395,35 @@ static struct net_device_stats *gem_get_stats(struct net_device *dev)
 {
        struct gem *gp = netdev_priv(dev);
 
-       spin_lock_irq(&gp->lock);
-       spin_lock(&gp->tx_lock);
-
        /* I have seen this being called while the PM was in progress,
-        * so we shield against this
+        * so we shield against this. Let's also not poke at registers
+        * while the reset task is going on.
+        *
+        * TODO: Move stats collection elsewhere (link timer ?) and
+        * make this a nop to avoid all those synchro issues
         */
-       if (gp->running) {
-               dev->stats.rx_crc_errors += readl(gp->regs + MAC_FCSERR);
-               writel(0, gp->regs + MAC_FCSERR);
+       if (!netif_device_present(dev) || !netif_running(dev))
+               goto bail;
 
-               dev->stats.rx_frame_errors += readl(gp->regs + MAC_AERR);
-               writel(0, gp->regs + MAC_AERR);
+       /* Better safe than sorry... */
+       if (WARN_ON(!gp->cell_enabled))
+               goto bail;
 
-               dev->stats.rx_length_errors += readl(gp->regs + MAC_LERR);
-               writel(0, gp->regs + MAC_LERR);
+       dev->stats.rx_crc_errors += readl(gp->regs + MAC_FCSERR);
+       writel(0, gp->regs + MAC_FCSERR);
 
-               dev->stats.tx_aborted_errors += readl(gp->regs + MAC_ECOLL);
-               dev->stats.collisions +=
-                       (readl(gp->regs + MAC_ECOLL) +
-                        readl(gp->regs + MAC_LCOLL));
-               writel(0, gp->regs + MAC_ECOLL);
-               writel(0, gp->regs + MAC_LCOLL);
-       }
+       dev->stats.rx_frame_errors += readl(gp->regs + MAC_AERR);
+       writel(0, gp->regs + MAC_AERR);
 
-       spin_unlock(&gp->tx_lock);
-       spin_unlock_irq(&gp->lock);
+       dev->stats.rx_length_errors += readl(gp->regs + MAC_LERR);
+       writel(0, gp->regs + MAC_LERR);
 
+       dev->stats.tx_aborted_errors += readl(gp->regs + MAC_ECOLL);
+       dev->stats.collisions +=
+               (readl(gp->regs + MAC_ECOLL) + readl(gp->regs + MAC_LCOLL));
+       writel(0, gp->regs + MAC_ECOLL);
+       writel(0, gp->regs + MAC_LCOLL);
+ bail:
        return &dev->stats;
 }
 
@@ -2513,22 +2436,19 @@ static int gem_set_mac_address(struct net_device *dev, void *addr)
        if (!is_valid_ether_addr(macaddr->sa_data))
                return -EADDRNOTAVAIL;
 
-       if (!netif_running(dev) || !netif_device_present(dev)) {
-               /* We'll just catch it later when the
-                * device is up'd or resumed.
-                */
-               memcpy(dev->dev_addr, macaddr->sa_data, dev->addr_len);
+       memcpy(dev->dev_addr, macaddr->sa_data, dev->addr_len);
+
+       /* We'll just catch it later when the device is up'd or resumed */
+       if (!netif_running(dev) || !netif_device_present(dev))
                return 0;
-       }
 
-       mutex_lock(&gp->pm_mutex);
-       memcpy(dev->dev_addr, macaddr->sa_data, dev->addr_len);
-       if (gp->running) {
-               writel((e[4] << 8) | e[5], gp->regs + MAC_ADDR0);
-               writel((e[2] << 8) | e[3], gp->regs + MAC_ADDR1);
-               writel((e[0] << 8) | e[1], gp->regs + MAC_ADDR2);
-       }
-       mutex_unlock(&gp->pm_mutex);
+       /* Better safe than sorry... */
+       if (WARN_ON(!gp->cell_enabled))
+               return 0;
+
+       writel((e[4] << 8) | e[5], gp->regs + MAC_ADDR0);
+       writel((e[2] << 8) | e[3], gp->regs + MAC_ADDR1);
+       writel((e[0] << 8) | e[1], gp->regs + MAC_ADDR2);
 
        return 0;
 }
@@ -2539,14 +2459,12 @@ static void gem_set_multicast(struct net_device *dev)
        u32 rxcfg, rxcfg_new;
        int limit = 10000;
 
+       if (!netif_running(dev) || !netif_device_present(dev))
+               return;
 
-       spin_lock_irq(&gp->lock);
-       spin_lock(&gp->tx_lock);
-
-       if (!gp->running)
-               goto bail;
-
-       netif_stop_queue(dev);
+       /* Better safe than sorry... */
+       if (gp->reset_task_pending || WARN_ON(!gp->cell_enabled))
+               return;
 
        rxcfg = readl(gp->regs + MAC_RXCFG);
        rxcfg_new = gem_setup_multicast(gp);
@@ -2566,12 +2484,6 @@ static void gem_set_multicast(struct net_device *dev)
        rxcfg |= rxcfg_new;
 
        writel(rxcfg, gp->regs + MAC_RXCFG);
-
-       netif_wake_queue(dev);
-
- bail:
-       spin_unlock(&gp->tx_lock);
-       spin_unlock_irq(&gp->lock);
 }
 
 /* Jumbo-grams don't seem to work :-( */
@@ -2589,26 +2501,21 @@ static int gem_change_mtu(struct net_device *dev, int new_mtu)
        if (new_mtu < GEM_MIN_MTU || new_mtu > GEM_MAX_MTU)
                return -EINVAL;
 
-       if (!netif_running(dev) || !netif_device_present(dev)) {
-               /* We'll just catch it later when the
-                * device is up'd or resumed.
-                */
-               dev->mtu = new_mtu;
+       dev->mtu = new_mtu;
+
+       /* We'll just catch it later when the device is up'd or resumed */
+       if (!netif_running(dev) || !netif_device_present(dev))
                return 0;
-       }
 
-       mutex_lock(&gp->pm_mutex);
-       spin_lock_irq(&gp->lock);
-       spin_lock(&gp->tx_lock);
-       dev->mtu = new_mtu;
-       if (gp->running) {
-               gem_reinit_chip(gp);
-               if (gp->lstate == link_up)
-                       gem_set_link_modes(gp);
-       }
-       spin_unlock(&gp->tx_lock);
-       spin_unlock_irq(&gp->lock);
-       mutex_unlock(&gp->pm_mutex);
+       /* Better safe than sorry... */
+       if (WARN_ON(!gp->cell_enabled))
+               return 0;
+
+       gem_netif_stop(gp);
+       gem_reinit_chip(gp);
+       if (gp->lstate == link_up)
+               gem_set_link_modes(gp);
+       gem_netif_start(gp);
 
        return 0;
 }
@@ -2640,7 +2547,6 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                cmd->phy_address = 0; /* XXX fixed PHYAD */
 
                /* Return current PHY settings */
-               spin_lock_irq(&gp->lock);
                cmd->autoneg = gp->want_autoneg;
                ethtool_cmd_speed_set(cmd, gp->phy_mii.speed);
                cmd->duplex = gp->phy_mii.duplex;
@@ -2652,7 +2558,6 @@ static int gem_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                 */
                if (cmd->advertising == 0)
                        cmd->advertising = cmd->supported;
-               spin_unlock_irq(&gp->lock);
        } else { // XXX PCS ?
                cmd->supported =
                        (SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full |
@@ -2706,11 +2611,10 @@ static int gem_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                return -EINVAL;
 
        /* Apply settings and restart link process. */
-       spin_lock_irq(&gp->lock);
-       gem_get_cell(gp);
-       gem_begin_auto_negotiation(gp, cmd);
-       gem_put_cell(gp);
-       spin_unlock_irq(&gp->lock);
+       if (netif_device_present(gp->dev)) {
+               del_timer_sync(&gp->link_timer);
+               gem_begin_auto_negotiation(gp, cmd);
+       }
 
        return 0;
 }
@@ -2722,12 +2626,11 @@ static int gem_nway_reset(struct net_device *dev)
        if (!gp->want_autoneg)
                return -EINVAL;
 
-       /* Restart link process. */
-       spin_lock_irq(&gp->lock);
-       gem_get_cell(gp);
-       gem_begin_auto_negotiation(gp, NULL);
-       gem_put_cell(gp);
-       spin_unlock_irq(&gp->lock);
+       /* Restart link process  */
+       if (netif_device_present(gp->dev)) {
+               del_timer_sync(&gp->link_timer);
+               gem_begin_auto_negotiation(gp, NULL);
+       }
 
        return 0;
 }
@@ -2791,16 +2694,11 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
        struct gem *gp = netdev_priv(dev);
        struct mii_ioctl_data *data = if_mii(ifr);
        int rc = -EOPNOTSUPP;
-       unsigned long flags;
 
-       /* Hold the PM mutex while doing ioctl's or we may collide
-        * with power management.
+       /* For SIOCGMIIREG and SIOCSMIIREG the core checks for us that
+        * netif_device_present() is true and holds rtnl_lock for us
+        * so we have nothing to worry about
         */
-       mutex_lock(&gp->pm_mutex);
-
-       spin_lock_irqsave(&gp->lock, flags);
-       gem_get_cell(gp);
-       spin_unlock_irqrestore(&gp->lock, flags);
 
        switch (cmd) {
        case SIOCGMIIPHY:               /* Get address of MII PHY in use. */
@@ -2808,32 +2706,17 @@ static int gem_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
                /* Fallthrough... */
 
        case SIOCGMIIREG:               /* Read MII PHY register. */
-               if (!gp->running)
-                       rc = -EAGAIN;
-               else {
-                       data->val_out = __phy_read(gp, data->phy_id & 0x1f,
-                                                  data->reg_num & 0x1f);
-                       rc = 0;
-               }
+               data->val_out = __phy_read(gp, data->phy_id & 0x1f,
+                                          data->reg_num & 0x1f);
+               rc = 0;
                break;
 
        case SIOCSMIIREG:               /* Write MII PHY register. */
-               if (!gp->running)
-                       rc = -EAGAIN;
-               else {
-                       __phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f,
-                                   data->val_in);
-                       rc = 0;
-               }
+               __phy_write(gp, data->phy_id & 0x1f, data->reg_num & 0x1f,
+                           data->val_in);
+               rc = 0;
                break;
-       };
-
-       spin_lock_irqsave(&gp->lock, flags);
-       gem_put_cell(gp);
-       spin_unlock_irqrestore(&gp->lock, flags);
-
-       mutex_unlock(&gp->pm_mutex);
-
+       }
        return rc;
 }
 
@@ -2921,23 +2804,9 @@ static void gem_remove_one(struct pci_dev *pdev)
 
                unregister_netdev(dev);
 
-               /* Stop the link timer */
-               del_timer_sync(&gp->link_timer);
-
-               /* We shouldn't need any locking here */
-               gem_get_cell(gp);
-
-               /* Cancel reset task */
+               /* Ensure reset task is truely gone */
                cancel_work_sync(&gp->reset_task);
 
-               /* Shut the PHY down */
-               gem_stop_phy(gp, 0);
-
-               gem_put_cell(gp);
-
-               /* Make sure bus master is disabled */
-               pci_disable_device(gp->pdev);
-
                /* Free resources */
                pci_free_consistent(pdev,
                                    sizeof(struct gem_init_block),
@@ -3043,10 +2912,6 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
 
        gp->msg_enable = DEFAULT_MSG;
 
-       spin_lock_init(&gp->lock);
-       spin_lock_init(&gp->tx_lock);
-       mutex_init(&gp->pm_mutex);
-
        init_timer(&gp->link_timer);
        gp->link_timer.function = gem_link_timer;
        gp->link_timer.data = (unsigned long) gp;
@@ -3122,14 +2987,11 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
        /* Set that now, in case PM kicks in now */
        pci_set_drvdata(pdev, dev);
 
-       /* Detect & init PHY, start autoneg, we release the cell now
-        * too, it will be managed by whoever needs it
-        */
-       gem_init_phy(gp);
-
-       spin_lock_irq(&gp->lock);
-       gem_put_cell(gp);
-       spin_unlock_irq(&gp->lock);
+       /* We can do scatter/gather and HW checksum */
+       dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM;
+       dev->features |= dev->hw_features | NETIF_F_RXCSUM;
+       if (pci_using_dac)
+               dev->features |= NETIF_F_HIGHDMA;
 
        /* Register with kernel */
        if (register_netdev(dev)) {
@@ -3138,20 +3000,15 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
                goto err_out_free_consistent;
        }
 
+       /* Undo the get_cell with appropriate locking (we could use
+        * ndo_init/uninit but that would be even more clumsy imho)
+        */
+       rtnl_lock();
+       gem_put_cell(gp);
+       rtnl_unlock();
+
        netdev_info(dev, "Sun GEM (PCI) 10/100/1000BaseT Ethernet %pM\n",
                    dev->dev_addr);
-
-       if (gp->phy_type == phy_mii_mdio0 ||
-           gp->phy_type == phy_mii_mdio1)
-               netdev_info(dev, "Found %s PHY\n",
-                           gp->phy_mii.def ? gp->phy_mii.def->name : "no");
-
-       /* GEM can do it all... */
-       dev->hw_features = NETIF_F_SG | NETIF_F_HW_CSUM;
-       dev->features |= dev->hw_features | NETIF_F_RXCSUM | NETIF_F_LLTX;
-       if (pci_using_dac)
-               dev->features |= NETIF_F_HIGHDMA;
-
        return 0;
 
 err_out_free_consistent:
index d225077..835ce1b 100644 (file)
@@ -973,23 +973,14 @@ enum link_state {
 };
 
 struct gem {
-       spinlock_t              lock;
-       spinlock_t              tx_lock;
        void __iomem            *regs;
        int                     rx_new, rx_old;
        int                     tx_new, tx_old;
 
        unsigned int has_wol : 1;       /* chip supports wake-on-lan */
-       unsigned int asleep : 1;        /* chip asleep, protected by pm_mutex */
        unsigned int asleep_wol : 1;    /* was asleep with WOL enabled */
-       unsigned int opened : 1;        /* driver opened, protected by pm_mutex */
-       unsigned int running : 1;       /* chip running, protected by lock */
 
-       /* cell enable count, protected by lock */
        int                     cell_enabled;
-
-       struct mutex            pm_mutex;
-
        u32                     msg_enable;
        u32                     status;
 
@@ -1033,20 +1024,4 @@ struct gem {
 #define found_mii_phy(gp) ((gp->phy_type == phy_mii_mdio0 || gp->phy_type == phy_mii_mdio1) && \
                           gp->phy_mii.def && gp->phy_mii.def->ops)
 
-#define ALIGNED_RX_SKB_ADDR(addr) \
-        ((((unsigned long)(addr) + (64UL - 1UL)) & ~(64UL - 1UL)) - (unsigned long)(addr))
-static __inline__ struct sk_buff *gem_alloc_skb(int size,
-                                               gfp_t gfp_flags)
-{
-       struct sk_buff *skb = alloc_skb(size + 64, gfp_flags);
-
-       if (skb) {
-               int offset = (int) ALIGNED_RX_SKB_ADDR(skb->data);
-               if (offset)
-                       skb_reserve(skb, offset);
-       }
-
-       return skb;
-}
-
 #endif /* _SUNGEM_H */
index f4b01c6..c8a145d 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/delay.h>
 #include <linux/in.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/pci.h>
 #include <linux/netdevice.h>
@@ -5774,7 +5775,7 @@ static void tg3_skb_error_unmap(struct tg3_napi *tnapi,
                         dma_unmap_addr(txb, mapping),
                         skb_headlen(skb),
                         PCI_DMA_TODEVICE);
-       for (i = 0; i <= last; i++) {
+       for (i = 0; i < last; i++) {
                skb_frag_t *frag = &skb_shinfo(skb)->frags[i];
 
                entry = NEXT_TX(entry);
index ace6404..145871b 100644 (file)
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/hardirq.h>
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/eisa.h>
 #include <linux/pci.h>
index ff32bef..b6162fe 100644 (file)
@@ -304,7 +304,7 @@ static int __devinit xl_probe(struct pci_dev *pdev,
 
        if ((i = pci_request_regions(pdev,"3c359"))) { 
                return i ; 
-       } ; 
+       }
 
        /* 
         * Allowing init_trdev to allocate the private data will align
@@ -1773,7 +1773,9 @@ static void xl_wait_misr_flags(struct net_device *dev)
        if (readb(xl_mmio + MMIO_MACDATA) != 0) {  /* Misr not clear */
                for (i=0; i<6; i++) { 
                        writel(MEM_BYTE_READ | 0xDFFE0 | i, xl_mmio + MMIO_MAC_ACCESS_CMD) ; 
-                       while (readb(xl_mmio + MMIO_MACDATA) != 0 ) {} ; /* Empty Loop */
+                       while (readb(xl_mmio + MMIO_MACDATA) != 0) {
+                               ;       /* Empty Loop */
+                       }
                } 
        }
 
index 4786497..e257a00 100644 (file)
@@ -123,6 +123,7 @@ in the event that chatty debug messages are desired - jjs 12/30/98 */
 /* some 95 OS send many non UI frame; this allow removing the warning */
 #define TR_FILTERNONUI 1
 
+#include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/netdevice.h>
 #include <linux/ip.h>
@@ -177,7 +178,7 @@ static char __devinit *adapter_def(char type)
        case 0xD: return "16/4 Adapter/A (short) | 16/4 ISA-16 Adapter";
        case 0xC: return "Auto 16/4 Adapter";
        default: return "adapter (unknown type)";
-       };
+       }
 };
 
 #define TRC_INIT 0x01          /*  Trace initialization & PROBEs */
index 1313aa1..2bedc0a 100644 (file)
@@ -727,7 +727,7 @@ static int __devexit madgemc_remove(struct device *device)
        return 0;
 }
 
-static const short madgemc_adapter_ids[] __devinitconst = {
+static short madgemc_adapter_ids[] __initdata = {
        0x002d,
        0x0000
 };
index 5c633a3..64cb9ac 100644 (file)
@@ -33,6 +33,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/net.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
index e2f6923..ce90efc 100644 (file)
@@ -38,6 +38,7 @@
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
 #include <linux/ethtool.h>
index 45144d5..efaa1d6 100644 (file)
@@ -1995,7 +1995,7 @@ SetMulticastFilter(struct net_device *dev)
 
 static u_char de4x5_irq[] = EISA_ALLOWED_IRQ_LIST;
 
-static int __devinit de4x5_eisa_probe (struct device *gendev)
+static int __init de4x5_eisa_probe (struct device *gendev)
 {
        struct eisa_device *edev;
        u_long iobase;
@@ -2097,7 +2097,7 @@ static int __devexit de4x5_eisa_remove (struct device *device)
        return 0;
 }
 
-static const struct eisa_device_id de4x5_eisa_ids[] __devinitconst = {
+static struct eisa_device_id de4x5_eisa_ids[] = {
         { "DEC4250", 0 },      /* 0 is the board name index... */
         { "" }
 };
index aa4d9da..52d898b 100644 (file)
@@ -13,6 +13,7 @@
        Please submit bugs to http://bugzilla.kernel.org/ .
 */
 
+#include <linux/interrupt.h>
 #include <linux/kernel.h>
 #include <linux/jiffies.h>
 #include "tulip.h"
index 82f8764..1246998 100644 (file)
@@ -28,6 +28,7 @@
 #include <linux/slab.h>
 #include "tulip.h"
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/etherdevice.h>
 #include <linux/delay.h>
 #include <linux/mii.h>
index 74e9405..ef68e13 100644 (file)
@@ -550,9 +550,9 @@ static unsigned int tun_chr_poll(struct file *file, poll_table * wait)
 
 /* prepad is the amount to reserve at front.  len is length after that.
  * linear is a hint as to how much to copy (usually headers). */
-static inline struct sk_buff *tun_alloc_skb(struct tun_struct *tun,
-                                           size_t prepad, size_t len,
-                                           size_t linear, int noblock)
+static struct sk_buff *tun_alloc_skb(struct tun_struct *tun,
+                                    size_t prepad, size_t len,
+                                    size_t linear, int noblock)
 {
        struct sock *sk = tun->socket.sk;
        struct sk_buff *skb;
@@ -578,13 +578,13 @@ static inline struct sk_buff *tun_alloc_skb(struct tun_struct *tun,
 }
 
 /* Get packet from user space buffer */
-static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
-                                      const struct iovec *iv, size_t count,
-                                      int noblock)
+static ssize_t tun_get_user(struct tun_struct *tun,
+                           const struct iovec *iv, size_t count,
+                           int noblock)
 {
        struct tun_pi pi = { 0, cpu_to_be16(ETH_P_IP) };
        struct sk_buff *skb;
-       size_t len = count, align = 0;
+       size_t len = count, align = NET_SKB_PAD;
        struct virtio_net_hdr gso = { 0 };
        int offset = 0;
 
@@ -614,7 +614,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
        }
 
        if ((tun->flags & TUN_TYPE_MASK) == TUN_TAP_DEV) {
-               align = NET_IP_ALIGN;
+               align += NET_IP_ALIGN;
                if (unlikely(len < ETH_HLEN ||
                             (gso.hdr_len && gso.hdr_len < ETH_HLEN)))
                        return -EINVAL;
@@ -666,7 +666,7 @@ static __inline__ ssize_t tun_get_user(struct tun_struct *tun,
        case TUN_TAP_DEV:
                skb->protocol = eth_type_trans(skb, tun->dev);
                break;
-       };
+       }
 
        if (gso.gso_type != VIRTIO_NET_HDR_GSO_NONE) {
                pr_debug("GSO!\n");
@@ -729,9 +729,9 @@ static ssize_t tun_chr_aio_write(struct kiocb *iocb, const struct iovec *iv,
 }
 
 /* Put packet to the user space buffer */
-static __inline__ ssize_t tun_put_user(struct tun_struct *tun,
-                                      struct sk_buff *skb,
-                                      const struct iovec *iv, int len)
+static ssize_t tun_put_user(struct tun_struct *tun,
+                           struct sk_buff *skb,
+                           const struct iovec *iv, int len)
 {
        struct tun_pi pi = { 0, skb->protocol };
        ssize_t total = 0;
@@ -817,7 +817,8 @@ static ssize_t tun_do_read(struct tun_struct *tun,
 
        tun_debug(KERN_INFO, tun, "tun_chr_read\n");
 
-       add_wait_queue(&tun->wq.wait, &wait);
+       if (unlikely(!noblock))
+               add_wait_queue(&tun->wq.wait, &wait);
        while (len) {
                current->state = TASK_INTERRUPTIBLE;
 
@@ -848,7 +849,8 @@ static ssize_t tun_do_read(struct tun_struct *tun,
        }
 
        current->state = TASK_RUNNING;
-       remove_wait_queue(&tun->wq.wait, &wait);
+       if (unlikely(!noblock))
+               remove_wait_queue(&tun->wq.wait, &wait);
 
        return ret;
 }
index d7221c4..8056f8a 100644 (file)
@@ -495,7 +495,7 @@ static void catc_ctrl_run(struct catc *catc)
        if (!q->dir && q->buf && q->len)
                memcpy(catc->ctrl_buf, q->buf, q->len);
 
-       if ((status = usb_submit_urb(catc->ctrl_urb, GFP_KERNEL)))
+       if ((status = usb_submit_urb(catc->ctrl_urb, GFP_ATOMIC)))
                err("submit(ctrl_urb) status %d", status);
 }
 
index cdd3ae4..f33ca6a 100644 (file)
@@ -54,7 +54,7 @@
 #include <linux/usb/usbnet.h>
 #include <linux/usb/cdc.h>
 
-#define        DRIVER_VERSION                          "24-May-2011"
+#define        DRIVER_VERSION                          "01-June-2011"
 
 /* CDC NCM subclass 3.2.1 */
 #define USB_CDC_NCM_NDP16_LENGTH_MIN           0x10
@@ -1234,6 +1234,7 @@ static struct usb_driver cdc_ncm_driver = {
        .disconnect = cdc_ncm_disconnect,
        .suspend = usbnet_suspend,
        .resume = usbnet_resume,
+       .reset_resume = usbnet_resume,
        .supports_autosuspend = 1,
 };
 
index 81126ff..15772b1 100644 (file)
@@ -409,12 +409,6 @@ static void ipheth_tx_timeout(struct net_device *net)
        usb_unlink_urb(dev->tx_urb);
 }
 
-static struct net_device_stats *ipheth_stats(struct net_device *net)
-{
-       struct ipheth_device *dev = netdev_priv(net);
-       return &dev->net->stats;
-}
-
 static u32 ipheth_ethtool_op_get_link(struct net_device *net)
 {
        struct ipheth_device *dev = netdev_priv(net);
@@ -426,11 +420,10 @@ static struct ethtool_ops ops = {
 };
 
 static const struct net_device_ops ipheth_netdev_ops = {
-       .ndo_open = &ipheth_open,
-       .ndo_stop = &ipheth_close,
-       .ndo_start_xmit = &ipheth_tx,
-       .ndo_tx_timeout = &ipheth_tx_timeout,
-       .ndo_get_stats = &ipheth_stats,
+       .ndo_open = ipheth_open,
+       .ndo_stop = ipheth_close,
+       .ndo_start_xmit = ipheth_tx,
+       .ndo_tx_timeout = ipheth_tx_timeout,
 };
 
 static int ipheth_probe(struct usb_interface *intf,
index 8461576..8730d64 100644 (file)
 #define MAX_MTU 65535          /* Max L3 MTU (arbitrary) */
 
 struct veth_net_stats {
-       unsigned long   rx_packets;
-       unsigned long   tx_packets;
-       unsigned long   rx_bytes;
-       unsigned long   tx_bytes;
-       unsigned long   tx_dropped;
-       unsigned long   rx_dropped;
+       u64     rx_packets;
+       u64     tx_packets;
+       u64     rx_bytes;
+       u64     tx_bytes;
+       u64     tx_dropped;
+       u64     rx_dropped;
 };
 
 struct veth_priv {
@@ -159,32 +159,27 @@ rx_drop:
  * general routines
  */
 
-static struct net_device_stats *veth_get_stats(struct net_device *dev)
+static struct rtnl_link_stats64 *veth_get_stats64(struct net_device *dev,
+                                                 struct rtnl_link_stats64 *tot)
 {
        struct veth_priv *priv;
        int cpu;
-       struct veth_net_stats *stats, total = {0};
+       struct veth_net_stats *stats;
 
        priv = netdev_priv(dev);
 
        for_each_possible_cpu(cpu) {
                stats = per_cpu_ptr(priv->stats, cpu);
 
-               total.rx_packets += stats->rx_packets;
-               total.tx_packets += stats->tx_packets;
-               total.rx_bytes   += stats->rx_bytes;
-               total.tx_bytes   += stats->tx_bytes;
-               total.tx_dropped += stats->tx_dropped;
-               total.rx_dropped += stats->rx_dropped;
+               tot->rx_packets += stats->rx_packets;
+               tot->tx_packets += stats->tx_packets;
+               tot->rx_bytes   += stats->rx_bytes;
+               tot->tx_bytes   += stats->tx_bytes;
+               tot->tx_dropped += stats->tx_dropped;
+               tot->rx_dropped += stats->rx_dropped;
        }
-       dev->stats.rx_packets = total.rx_packets;
-       dev->stats.tx_packets = total.tx_packets;
-       dev->stats.rx_bytes   = total.rx_bytes;
-       dev->stats.tx_bytes   = total.tx_bytes;
-       dev->stats.tx_dropped = total.tx_dropped;
-       dev->stats.rx_dropped = total.rx_dropped;
-
-       return &dev->stats;
+
+       return tot;
 }
 
 static int veth_open(struct net_device *dev)
@@ -254,7 +249,7 @@ static const struct net_device_ops veth_netdev_ops = {
        .ndo_stop            = veth_close,
        .ndo_start_xmit      = veth_xmit,
        .ndo_change_mtu      = veth_change_mtu,
-       .ndo_get_stats       = veth_get_stats,
+       .ndo_get_stats64     = veth_get_stats64,
        .ndo_set_mac_address = eth_mac_addr,
 };
 
index 06daa9d..f929242 100644 (file)
@@ -1887,7 +1887,7 @@ static void velocity_error(struct velocity_info *vptr, int status)
                else
                        netif_wake_queue(vptr->dev);
 
-       };
+       }
        if (status & ISR_MIBFI)
                velocity_update_hw_mibs(vptr);
        if (status & ISR_LSTEI)
index 0cb0b06..f685324 100644 (file)
@@ -609,7 +609,7 @@ static netdev_tx_t start_xmit(struct sk_buff *skb, struct net_device *dev)
         * before it gets out of hand.  Naturally, this wastes entries. */
        if (capacity < 2+MAX_SKB_FRAGS) {
                netif_stop_queue(dev);
-               if (unlikely(!virtqueue_enable_cb(vi->svq))) {
+               if (unlikely(!virtqueue_enable_cb_delayed(vi->svq))) {
                        /* More just got used, free them then recheck. */
                        capacity += free_old_xmit_skbs(vi);
                        if (capacity >= 2+MAX_SKB_FRAGS) {
index fa6e2ac..cea1b3c 100644 (file)
@@ -2864,7 +2864,7 @@ vmxnet3_probe_device(struct pci_dev *pdev,
                .ndo_set_mac_address = vmxnet3_set_mac_addr,
                .ndo_change_mtu = vmxnet3_change_mtu,
                .ndo_set_features = vmxnet3_set_features,
-               .ndo_get_stats = vmxnet3_get_stats,
+               .ndo_get_stats64 = vmxnet3_get_stats64,
                .ndo_tx_timeout = vmxnet3_tx_timeout,
                .ndo_set_multicast_list = vmxnet3_set_mc,
                .ndo_vlan_rx_register = vmxnet3_vlan_rx_register,
index dc959fe..bba7c15 100644 (file)
@@ -113,15 +113,15 @@ vmxnet3_global_stats[] = {
 };
 
 
-struct net_device_stats *
-vmxnet3_get_stats(struct net_device *netdev)
+struct rtnl_link_stats64 *
+vmxnet3_get_stats64(struct net_device *netdev,
+                  struct rtnl_link_stats64 *stats)
 {
        struct vmxnet3_adapter *adapter;
        struct vmxnet3_tq_driver_stats *drvTxStats;
        struct vmxnet3_rq_driver_stats *drvRxStats;
        struct UPT1_TxStats *devTxStats;
        struct UPT1_RxStats *devRxStats;
-       struct net_device_stats *net_stats = &netdev->stats;
        unsigned long flags;
        int i;
 
@@ -132,36 +132,36 @@ vmxnet3_get_stats(struct net_device *netdev)
        VMXNET3_WRITE_BAR1_REG(adapter, VMXNET3_REG_CMD, VMXNET3_CMD_GET_STATS);
        spin_unlock_irqrestore(&adapter->cmd_lock, flags);
 
-       memset(net_stats, 0, sizeof(*net_stats));
        for (i = 0; i < adapter->num_tx_queues; i++) {
                devTxStats = &adapter->tqd_start[i].stats;
                drvTxStats = &adapter->tx_queue[i].stats;
-               net_stats->tx_packets += devTxStats->ucastPktsTxOK +
-                                       devTxStats->mcastPktsTxOK +
-                                       devTxStats->bcastPktsTxOK;
-               net_stats->tx_bytes += devTxStats->ucastBytesTxOK +
-                                     devTxStats->mcastBytesTxOK +
-                                     devTxStats->bcastBytesTxOK;
-               net_stats->tx_errors += devTxStats->pktsTxError;
-               net_stats->tx_dropped += drvTxStats->drop_total;
+               stats->tx_packets += devTxStats->ucastPktsTxOK +
+                                    devTxStats->mcastPktsTxOK +
+                                    devTxStats->bcastPktsTxOK;
+               stats->tx_bytes += devTxStats->ucastBytesTxOK +
+                                  devTxStats->mcastBytesTxOK +
+                                  devTxStats->bcastBytesTxOK;
+               stats->tx_errors += devTxStats->pktsTxError;
+               stats->tx_dropped += drvTxStats->drop_total;
        }
 
        for (i = 0; i < adapter->num_rx_queues; i++) {
                devRxStats = &adapter->rqd_start[i].stats;
                drvRxStats = &adapter->rx_queue[i].stats;
-               net_stats->rx_packets += devRxStats->ucastPktsRxOK +
-                                       devRxStats->mcastPktsRxOK +
-                                       devRxStats->bcastPktsRxOK;
+               stats->rx_packets += devRxStats->ucastPktsRxOK +
+                                    devRxStats->mcastPktsRxOK +
+                                    devRxStats->bcastPktsRxOK;
 
-               net_stats->rx_bytes += devRxStats->ucastBytesRxOK +
-                                     devRxStats->mcastBytesRxOK +
-                                     devRxStats->bcastBytesRxOK;
+               stats->rx_bytes += devRxStats->ucastBytesRxOK +
+                                  devRxStats->mcastBytesRxOK +
+                                  devRxStats->bcastBytesRxOK;
 
-               net_stats->rx_errors += devRxStats->pktsRxError;
-               net_stats->rx_dropped += drvRxStats->drop_total;
-               net_stats->multicast +=  devRxStats->mcastPktsRxOK;
+               stats->rx_errors += devRxStats->pktsRxError;
+               stats->rx_dropped += drvRxStats->drop_total;
+               stats->multicast +=  devRxStats->mcastPktsRxOK;
        }
-       return net_stats;
+
+       return stats;
 }
 
 static int
index f50d36f..0e567c2 100644 (file)
@@ -323,7 +323,6 @@ struct vmxnet3_adapter {
        struct Vmxnet3_TxQueueDesc      *tqd_start;     /* all tx queue desc */
        struct Vmxnet3_RxQueueDesc      *rqd_start;     /* all rx queue desc */
        struct net_device               *netdev;
-       struct net_device_stats         net_stats;
        struct pci_dev                  *pdev;
 
        u8                      __iomem *hw_addr0; /* for BAR 0 */
@@ -407,7 +406,9 @@ vmxnet3_create_queues(struct vmxnet3_adapter *adapter,
                      u32 tx_ring_size, u32 rx_ring_size, u32 rx_ring2_size);
 
 extern void vmxnet3_set_ethtool_ops(struct net_device *netdev);
-extern struct net_device_stats *vmxnet3_get_stats(struct net_device *netdev);
+
+extern struct rtnl_link_stats64 *
+vmxnet3_get_stats64(struct net_device *dev, struct rtnl_link_stats64 *stats);
 
 extern char vmxnet3_driver_name[];
 #endif
index 359b9b9..6219006 100644 (file)
@@ -13,6 +13,7 @@
  ******************************************************************************/
 #ifndef VXGE_CONFIG_H
 #define VXGE_CONFIG_H
+#include <linux/hardirq.h>
 #include <linux/list.h>
 #include <linux/slab.h>
 
index 8ab870a..e658edd 100644 (file)
@@ -44,6 +44,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/if_vlan.h>
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/tcp.h>
index 859dba9..a0976d1 100644 (file)
@@ -50,6 +50,7 @@
 #include <linux/wanrouter.h>   /* WAN router definitions */
 #include <linux/cyclomx.h>     /* cyclomx common user API definitions */
 #include <linux/init.h>         /* __init (when not using as a module) */
+#include <linux/interrupt.h>
 
 unsigned int cycx_debug;
 
index acb9ea8..3590d58 100644 (file)
@@ -99,6 +99,7 @@
 #include <asm/irq.h>
 
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/string.h>
 
 #include <linux/if_arp.h>
index e050bd6..1eba06f 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/slab.h>
 #include <linux/ioport.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/if.h>
 #include <linux/hdlc.h>
 #include <asm/io.h>
index db73a7b..4ea89fe 100644 (file)
@@ -22,6 +22,7 @@
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/ioport.h>
 #include <linux/netdevice.h>
 #include <linux/hdlc.h>
index 40398bf..24297b2 100644 (file)
@@ -517,18 +517,17 @@ static int x25_asy_close(struct net_device *dev)
  * and sent on to some IP layer for further processing.
  */
 
-static unsigned int x25_asy_receive_buf(struct tty_struct *tty,
+static void x25_asy_receive_buf(struct tty_struct *tty,
                                const unsigned char *cp, char *fp, int count)
 {
        struct x25_asy *sl = tty->disc_data;
-       int bytes = count;
 
        if (!sl || sl->magic != X25_ASY_MAGIC || !netif_running(sl->dev))
                return;
 
 
        /* Read the characters out of the buffer */
-       while (bytes--) {
+       while (count--) {
                if (fp && *fp++) {
                        if (!test_and_set_bit(SLF_ERROR, &sl->flags))
                                sl->dev->stats.rx_errors++;
@@ -537,8 +536,6 @@ static unsigned int x25_asy_receive_buf(struct tty_struct *tty,
                }
                x25_asy_unesc(sl, *cp++);
        }
-
-       return count;
 }
 
 /*
index afe2cbc..43ebc44 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/if.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
index 7cf4317..17c4b56 100644 (file)
@@ -161,6 +161,7 @@ struct ath_common {
        const struct ath_bus_ops *bus_ops;
 
        bool btcoex_enabled;
+       bool disable_ani;
 };
 
 struct sk_buff *ath_rxbuf_alloc(struct ath_common *common,
index 2204762..b6c5d37 100644 (file)
@@ -72,6 +72,11 @@ static int modparam_all_channels;
 module_param_named(all_channels, modparam_all_channels, bool, S_IRUGO);
 MODULE_PARM_DESC(all_channels, "Expose all channels the device can use.");
 
+static int modparam_fastchanswitch;
+module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO);
+MODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios.");
+
+
 /* Module info */
 MODULE_AUTHOR("Jiri Slaby");
 MODULE_AUTHOR("Nick Kossifidis");
@@ -2686,6 +2691,7 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
        struct ath5k_hw *ah = sc->ah;
        struct ath_common *common = ath5k_hw_common(ah);
        int ret, ani_mode;
+       bool fast;
 
        ATH5K_DBG(sc, ATH5K_DEBUG_RESET, "resetting\n");
 
@@ -2705,7 +2711,10 @@ ath5k_reset(struct ath5k_softc *sc, struct ieee80211_channel *chan,
        ath5k_drain_tx_buffs(sc);
        if (chan)
                sc->curchan = chan;
-       ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, chan != NULL,
+
+       fast = ((chan != NULL) && modparam_fastchanswitch) ? 1 : 0;
+
+       ret = ath5k_hw_reset(ah, sc->opmode, sc->curchan, fast,
                                                                skip_pcu);
        if (ret) {
                ATH5K_ERR(sc, "can't reset hardware (%d)\n", ret);
index 3510de2..126a4ea 100644 (file)
@@ -1124,8 +1124,11 @@ int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode,
                        /* Non fatal, can happen eg.
                         * on mode change */
                        ret = 0;
-               } else
+               } else {
+                       ATH5K_DBG(ah->ah_sc, ATH5K_DEBUG_RESET,
+                               "fast chan change successful\n");
                        return 0;
+               }
        }
 
        /*
index d9ff841..d9c08c6 100644 (file)
@@ -26,7 +26,6 @@ config ATH9K
 config ATH9K_PCI
        bool "Atheros ath9k PCI/PCIe bus support"
        depends on ATH9K && PCI
-       default PCI
        ---help---
          This option enables the PCI bus support in ath9k.
 
index 015d974..2d4c091 100644 (file)
@@ -829,7 +829,7 @@ static bool ar9002_hw_init_cal(struct ath_hw *ah, struct ath9k_channel *chan)
        if (AR_SREV_9271(ah)) {
                if (!ar9285_hw_cl_cal(ah, chan))
                        return false;
-       } else if (AR_SREV_9285_12_OR_LATER(ah)) {
+       } else if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) {
                if (!ar9285_hw_clc(ah, chan))
                        return false;
        } else {
index 077e8a6..45b262f 100644 (file)
@@ -28,11 +28,6 @@ static void ar9002_hw_set_desc_link(void *ds, u32 ds_link)
        ((struct ath_desc*) ds)->ds_link = ds_link;
 }
 
-static void ar9002_hw_get_desc_link(void *ds, u32 **ds_link)
-{
-       *ds_link = &((struct ath_desc *)ds)->ds_link;
-}
-
 static bool ar9002_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
 {
        u32 isr = 0;
@@ -437,7 +432,6 @@ void ar9002_hw_attach_mac_ops(struct ath_hw *ah)
 
        ops->rx_enable = ar9002_hw_rx_enable;
        ops->set_desc_link = ar9002_hw_set_desc_link;
-       ops->get_desc_link = ar9002_hw_get_desc_link;
        ops->get_isr = ar9002_hw_get_isr;
        ops->fill_txdesc = ar9002_hw_fill_txdesc;
        ops->proc_txdesc = ar9002_hw_proc_txdesc;
index 0ca7635..ff8150e 100644 (file)
@@ -4645,10 +4645,16 @@ static void ar9003_hw_set_power_per_rate_table(struct ath_hw *ah,
        case 1:
                break;
        case 2:
-               scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+               if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN)
+                       scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+               else
+                       scaledPower = 0;
                break;
        case 3:
-               scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+               if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN)
+                       scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+               else
+                       scaledPower = 0;
                break;
        }
 
index 10d71f7..04e6be0 100644 (file)
@@ -43,13 +43,6 @@ static void ar9003_hw_set_desc_link(void *ds, u32 ds_link)
        ads->ctl10 |= ar9003_calc_ptr_chksum(ads);
 }
 
-static void ar9003_hw_get_desc_link(void *ds, u32 **ds_link)
-{
-       struct ar9003_txc *ads = ds;
-
-       *ds_link = &ads->link;
-}
-
 static bool ar9003_hw_get_isr(struct ath_hw *ah, enum ath9k_int *masked)
 {
        u32 isr = 0;
@@ -498,7 +491,6 @@ void ar9003_hw_attach_mac_ops(struct ath_hw *hw)
 
        ops->rx_enable = ar9003_hw_rx_enable;
        ops->set_desc_link = ar9003_hw_set_desc_link;
-       ops->get_desc_link = ar9003_hw_get_desc_link;
        ops->get_isr = ar9003_hw_get_isr;
        ops->fill_txdesc = ar9003_hw_fill_txdesc;
        ops->proc_txdesc = ar9003_hw_proc_txdesc;
index e4d6a87..2e7f0f2 100644 (file)
@@ -46,11 +46,10 @@ EXPORT_SYMBOL(ar9003_paprd_enable);
 
 static int ar9003_get_training_power_2g(struct ath_hw *ah)
 {
-       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
-       struct ar9300_modal_eep_header *hdr = &eep->modalHeader2G;
+       struct ath9k_channel *chan = ah->curchan;
        unsigned int power, scale, delta;
 
-       scale = MS(le32_to_cpu(hdr->papdRateMaskHt20), AR9300_PAPRD_SCALE_1);
+       scale = ar9003_get_paprd_scale_factor(ah, chan);
        power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE5,
                               AR_PHY_POWERTX_RATE5_POWERTXHT20_0);
 
@@ -67,20 +66,10 @@ static int ar9003_get_training_power_2g(struct ath_hw *ah)
 static int ar9003_get_training_power_5g(struct ath_hw *ah)
 {
        struct ath_common *common = ath9k_hw_common(ah);
-       struct ar9300_eeprom *eep = &ah->eeprom.ar9300_eep;
-       struct ar9300_modal_eep_header *hdr = &eep->modalHeader5G;
        struct ath9k_channel *chan = ah->curchan;
        unsigned int power, scale, delta;
 
-       if (chan->channel >= 5700)
-               scale = MS(le32_to_cpu(hdr->papdRateMaskHt20),
-                          AR9300_PAPRD_SCALE_1);
-       else if (chan->channel >= 5400)
-               scale = MS(le32_to_cpu(hdr->papdRateMaskHt40),
-                          AR9300_PAPRD_SCALE_2);
-       else
-               scale = MS(le32_to_cpu(hdr->papdRateMaskHt40),
-                          AR9300_PAPRD_SCALE_1);
+       scale = ar9003_get_paprd_scale_factor(ah, chan);
 
        if (IS_CHAN_HT40(chan))
                power = REG_READ_FIELD(ah, AR_PHY_POWERTX_RATE8,
@@ -119,15 +108,16 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
        else
                training_power = ar9003_get_training_power_5g(ah);
 
+       ath_dbg(common, ATH_DBG_CALIBRATE,
+               "Training power: %d, Target power: %d\n",
+               training_power, ah->paprd_target_power);
+
        if (training_power < 0) {
                ath_dbg(common, ATH_DBG_CALIBRATE,
                        "PAPRD target power delta out of range");
                return -ERANGE;
        }
        ah->paprd_training_power = training_power;
-       ath_dbg(common, ATH_DBG_CALIBRATE,
-               "Training power: %d, Target power: %d\n",
-               ah->paprd_training_power, ah->paprd_target_power);
 
        REG_RMW_FIELD(ah, AR_PHY_PAPRD_AM2AM, AR_PHY_PAPRD_AM2AM_MASK,
                      ah->paprd_ratemask);
index eee23ec..892c48b 100644 (file)
@@ -1381,3 +1381,25 @@ void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah)
                "==== BB update: done ====\n\n");
 }
 EXPORT_SYMBOL(ar9003_hw_bb_watchdog_dbg_info);
+
+void ar9003_hw_disable_phy_restart(struct ath_hw *ah)
+{
+       u32 val;
+
+       /* While receiving unsupported rate frame rx state machine
+        * gets into a state 0xb and if phy_restart happens in that
+        * state, BB would go hang. If RXSM is in 0xb state after
+        * first bb panic, ensure to disable the phy_restart.
+        */
+       if (!((MS(ah->bb_watchdog_last_status,
+                 AR_PHY_WATCHDOG_RX_OFDM_SM) == 0xb) ||
+           ah->bb_hang_rx_ofdm))
+               return;
+
+       ah->bb_hang_rx_ofdm = true;
+       val = REG_READ(ah, AR_PHY_RESTART);
+       val &= ~AR_PHY_RESTART_ENA;
+
+       REG_WRITE(ah, AR_PHY_RESTART, val);
+}
+EXPORT_SYMBOL(ar9003_hw_disable_phy_restart);
index f75068b..57933db 100644 (file)
@@ -19,6 +19,7 @@
 
 #include <linux/etherdevice.h>
 #include <linux/device.h>
+#include <linux/interrupt.h>
 #include <linux/leds.h>
 #include <linux/completion.h>
 
@@ -179,7 +180,7 @@ enum ATH_AGGR_STATUS {
 struct ath_txq {
        int mac80211_qnum; /* mac80211 queue number, -1 means not mac80211 Q */
        u32 axq_qnum; /* ath9k hardware queue number */
-       u32 *axq_link;
+       void *axq_link;
        struct list_head axq_q;
        spinlock_t axq_lock;
        u32 axq_depth;
@@ -188,7 +189,6 @@ struct ath_txq {
        bool axq_tx_inprogress;
        struct list_head axq_acq;
        struct list_head txq_fifo[ATH_TXFIFO_DEPTH];
-       struct list_head txq_fifo_pending;
        u8 txq_headidx;
        u8 txq_tailidx;
        int pending_frames;
@@ -428,6 +428,7 @@ void ath_hw_check(struct work_struct *work);
 void ath_hw_pll_work(struct work_struct *work);
 void ath_paprd_calibrate(struct work_struct *work);
 void ath_ani_calibrate(unsigned long data);
+void ath_start_ani(struct ath_common *common);
 
 /**********/
 /* BTCOEX */
@@ -669,12 +670,8 @@ int ath9k_init_device(u16 devid, struct ath_softc *sc, u16 subsysid,
                    const struct ath_bus_ops *bus_ops);
 void ath9k_deinit_device(struct ath_softc *sc);
 void ath9k_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
-int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
-                   struct ath9k_channel *hchan);
 
-void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw);
 void ath_radio_disable(struct ath_softc *sc, struct ieee80211_hw *hw);
-bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode);
 bool ath9k_uses_beacons(int type);
 
 #ifdef CONFIG_ATH9K_PCI
index d4d8cec..0174cdb 100644 (file)
@@ -496,7 +496,7 @@ static void ath_beacon_config_ap(struct ath_softc *sc,
        u32 nexttbtt, intval;
 
        /* NB: the beacon interval is kept internally in TU's */
-       intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD);
+       intval = TU_TO_USEC(conf->beacon_interval);
        intval /= ATH_BCBUF;    /* for staggered beacons */
        nexttbtt = intval;
 
@@ -543,7 +543,7 @@ static void ath_beacon_config_sta(struct ath_softc *sc,
        }
 
        memset(&bs, 0, sizeof(bs));
-       intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
+       intval = conf->beacon_interval;
 
        /*
         * Setup dtim and cfp parameters according to
@@ -652,22 +652,13 @@ static void ath_beacon_config_adhoc(struct ath_softc *sc,
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
-       u32 tsf, delta, intval, nexttbtt;
+       u32 tsf, intval, nexttbtt;
 
        ath9k_reset_beacon_status(sc);
 
-       tsf = ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE);
-       intval = TU_TO_USEC(conf->beacon_interval & ATH9K_BEACON_PERIOD);
-
-       if (!sc->beacon.bc_tstamp)
-               nexttbtt = tsf + intval;
-       else {
-               if (tsf > sc->beacon.bc_tstamp)
-                       delta = (tsf - sc->beacon.bc_tstamp);
-               else
-                       delta = (tsf + 1 + (~0U - sc->beacon.bc_tstamp));
-               nexttbtt = tsf + intval - (delta % intval);
-       }
+       intval = TU_TO_USEC(conf->beacon_interval);
+       tsf = roundup(ath9k_hw_gettsf32(ah) + TU_TO_USEC(FUDGE), intval);
+       nexttbtt = tsf + intval;
 
        ath_dbg(common, ATH_DBG_BEACON,
                "IBSS nexttbtt %u intval %u (%u)\n",
index d55ffd7..22d3a26 100644 (file)
@@ -176,6 +176,56 @@ static const struct file_operations fops_rx_chainmask = {
        .llseek = default_llseek,
 };
 
+static ssize_t read_file_disable_ani(struct file *file, char __user *user_buf,
+                            size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       char buf[32];
+       unsigned int len;
+
+       len = sprintf(buf, "%d\n", common->disable_ani);
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static ssize_t write_file_disable_ani(struct file *file,
+                                     const char __user *user_buf,
+                                     size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       struct ath_common *common = ath9k_hw_common(sc->sc_ah);
+       unsigned long disable_ani;
+       char buf[32];
+       ssize_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EFAULT;
+
+       buf[len] = '\0';
+       if (strict_strtoul(buf, 0, &disable_ani))
+               return -EINVAL;
+
+       common->disable_ani = !!disable_ani;
+
+       if (disable_ani) {
+               sc->sc_flags &= ~SC_OP_ANI_RUN;
+               del_timer_sync(&common->ani.timer);
+       } else {
+               sc->sc_flags |= SC_OP_ANI_RUN;
+               ath_start_ani(common);
+       }
+
+       return count;
+}
+
+static const struct file_operations fops_disable_ani = {
+       .read = read_file_disable_ani,
+       .write = write_file_disable_ani,
+       .open = ath9k_debugfs_open,
+       .owner = THIS_MODULE,
+       .llseek = default_llseek,
+};
 
 static ssize_t read_file_dma(struct file *file, char __user *user_buf,
                             size_t count, loff_t *ppos)
@@ -550,6 +600,7 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
 
        PR("MPDUs Queued:    ", queued);
        PR("MPDUs Completed: ", completed);
+       PR("MPDUs XRetried:  ", xretries);
        PR("Aggregates:      ", a_aggr);
        PR("AMPDUs Queued HW:", a_queued_hw);
        PR("AMPDUs Queued SW:", a_queued_sw);
@@ -587,7 +638,6 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
 
        PRQLE("axq_q empty:       ", axq_q);
        PRQLE("axq_acq empty:     ", axq_acq);
-       PRQLE("txq_fifo_pending:  ", txq_fifo_pending);
        for (i = 0; i < ATH_TXFIFO_DEPTH; i++) {
                snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i);
                PRQLE(tmp, txq_fifo[i]);
@@ -807,7 +857,10 @@ void ath_debug_stat_tx(struct ath_softc *sc, struct ath_buf *bf,
                else
                        TX_STAT_INC(qnum, a_completed);
        } else {
-               TX_STAT_INC(qnum, completed);
+               if (bf_isxretried(bf))
+                       TX_STAT_INC(qnum, xretries);
+               else
+                       TX_STAT_INC(qnum, completed);
        }
 
        if (ts->ts_status & ATH9K_TXERR_FIFO)
@@ -1160,6 +1213,8 @@ int ath9k_init_debug(struct ath_hw *ah)
                            sc->debug.debugfs_phy, sc, &fops_rx_chainmask);
        debugfs_create_file("tx_chainmask", S_IRUSR | S_IWUSR,
                            sc->debug.debugfs_phy, sc, &fops_tx_chainmask);
+       debugfs_create_file("disable_ani", S_IRUSR | S_IWUSR,
+                           sc->debug.debugfs_phy, sc, &fops_disable_ani);
        debugfs_create_file("regidx", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
                            sc, &fops_regidx);
        debugfs_create_file("regval", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
index 8ce6ad8..4a04510 100644 (file)
@@ -116,6 +116,7 @@ struct ath_tx_stats {
        u32 tx_bytes_all;
        u32 queued;
        u32 completed;
+       u32 xretries;
        u32 a_aggr;
        u32 a_queued_hw;
        u32 a_queued_sw;
index 7856f0d..343fc9f 100644 (file)
@@ -524,10 +524,16 @@ static void ath9k_hw_set_ar9287_power_per_rate_table(struct ath_hw *ah,
        case 1:
                break;
        case 2:
-               scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+               if (scaledPower > REDUCE_SCALED_POWER_BY_TWO_CHAIN)
+                       scaledPower -= REDUCE_SCALED_POWER_BY_TWO_CHAIN;
+               else
+                       scaledPower = 0;
                break;
        case 3:
-               scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+               if (scaledPower > REDUCE_SCALED_POWER_BY_THREE_CHAIN)
+                       scaledPower -= REDUCE_SCALED_POWER_BY_THREE_CHAIN;
+               else
+                       scaledPower = 0;
                break;
        }
        scaledPower = max((u16)0, scaledPower);
index aa6a731..57fe22b 100644 (file)
@@ -79,7 +79,7 @@ static void ath9k_htc_beacon_config_sta(struct ath9k_htc_priv *priv,
 
        memset(&bs, 0, sizeof(bs));
 
-       intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD;
+       intval = bss_conf->beacon_interval;
        bmiss_timeout = (ATH_DEFAULT_BMISS_LIMIT * bss_conf->beacon_interval);
 
        /*
@@ -194,7 +194,7 @@ static void ath9k_htc_beacon_config_ap(struct ath9k_htc_priv *priv,
        u8 cmd_rsp;
        u64 tsf;
 
-       intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD;
+       intval = bss_conf->beacon_interval;
        intval /= ATH9K_HTC_MAX_BCN_VIF;
        nexttbtt = intval;
 
@@ -250,7 +250,7 @@ static void ath9k_htc_beacon_config_adhoc(struct ath9k_htc_priv *priv,
        u8 cmd_rsp;
        u64 tsf;
 
-       intval = bss_conf->beacon_interval & ATH9K_BEACON_PERIOD;
+       intval = bss_conf->beacon_interval;
        nexttbtt = intval;
 
        /*
@@ -427,7 +427,7 @@ static int ath9k_htc_choose_bslot(struct ath9k_htc_priv *priv,
        u16 intval;
        int slot;
 
-       intval = priv->cur_beacon_conf.beacon_interval & ATH9K_BEACON_PERIOD;
+       intval = priv->cur_beacon_conf.beacon_interval;
 
        tsf = be64_to_cpu(swba->tsf);
        tsftu = TSF_TO_TU(tsf >> 32, tsf);
index 2f3e072..cb29e88 100644 (file)
@@ -39,11 +39,6 @@ static inline void ath9k_hw_set_desc_link(struct ath_hw *ah, void *ds,
        ath9k_hw_ops(ah)->set_desc_link(ds, link);
 }
 
-static inline void ath9k_hw_get_desc_link(struct ath_hw *ah, void *ds,
-                                         u32 **link)
-{
-       ath9k_hw_ops(ah)->get_desc_link(ds, link);
-}
 static inline bool ath9k_hw_calibrate(struct ath_hw *ah,
                                      struct ath9k_channel *chan,
                                      u8 rxchainmask,
index 72543ce..6de2655 100644 (file)
@@ -1555,9 +1555,12 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
        if (ah->btcoex_hw.enabled)
                ath9k_hw_btcoex_enable(ah);
 
-       if (AR_SREV_9300_20_OR_LATER(ah))
+       if (AR_SREV_9300_20_OR_LATER(ah)) {
                ar9003_hw_bb_watchdog_config(ah);
 
+               ar9003_hw_disable_phy_restart(ah);
+       }
+
        ath9k_hw_apply_gpio_override(ah);
 
        return 0;
@@ -1782,16 +1785,16 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
        REG_WRITE(ah, AR_NEXT_TBTT_TIMER, TU_TO_USEC(bs->bs_nexttbtt));
 
        REG_WRITE(ah, AR_BEACON_PERIOD,
-                 TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD));
+                 TU_TO_USEC(bs->bs_intval));
        REG_WRITE(ah, AR_DMA_BEACON_PERIOD,
-                 TU_TO_USEC(bs->bs_intval & ATH9K_BEACON_PERIOD));
+                 TU_TO_USEC(bs->bs_intval));
 
        REGWRITE_BUFFER_FLUSH(ah);
 
        REG_RMW_FIELD(ah, AR_RSSI_THR,
                      AR_RSSI_THR_BM_THR, bs->bs_bmissthreshold);
 
-       beaconintval = bs->bs_intval & ATH9K_BEACON_PERIOD;
+       beaconintval = bs->bs_intval;
 
        if (bs->bs_sleepduration > beaconintval)
                beaconintval = bs->bs_sleepduration;
index 57435ce..6a6fb54 100644 (file)
@@ -403,7 +403,6 @@ struct ath9k_beacon_state {
        u32 bs_nexttbtt;
        u32 bs_nextdtim;
        u32 bs_intval;
-#define ATH9K_BEACON_PERIOD       0x0000ffff
 #define ATH9K_TSFOOR_THRESHOLD    0x00004240 /* 16k us */
        u32 bs_dtimperiod;
        u16 bs_cfpperiod;
@@ -603,7 +602,6 @@ struct ath_hw_ops {
                                     int power_off);
        void (*rx_enable)(struct ath_hw *ah);
        void (*set_desc_link)(void *ds, u32 link);
-       void (*get_desc_link)(void *ds, u32 **link);
        bool (*calibrate)(struct ath_hw *ah,
                          struct ath9k_channel *chan,
                          u8 rxchainmask,
@@ -842,6 +840,7 @@ struct ath_hw {
 
        u32 bb_watchdog_last_status;
        u32 bb_watchdog_timeout_ms; /* in ms, 0 to disable */
+       u8 bb_hang_rx_ofdm; /* true if bb hang due to rx_ofdm */
 
        unsigned int paprd_target_power;
        unsigned int paprd_training_power;
@@ -990,6 +989,7 @@ void ar9002_hw_enable_wep_aggregation(struct ath_hw *ah);
 void ar9003_hw_bb_watchdog_config(struct ath_hw *ah);
 void ar9003_hw_bb_watchdog_read(struct ath_hw *ah);
 void ar9003_hw_bb_watchdog_dbg_info(struct ath_hw *ah);
+void ar9003_hw_disable_phy_restart(struct ath_hw *ah);
 void ar9003_paprd_enable(struct ath_hw *ah, bool val);
 void ar9003_paprd_populate_single_table(struct ath_hw *ah,
                                        struct ath9k_hw_cal_data *caldata,
index 45c585a..d4b166c 100644 (file)
@@ -519,7 +519,6 @@ static void ath9k_init_misc(struct ath_softc *sc)
 {
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        int i = 0;
-
        setup_timer(&common->ani.timer, ath_ani_calibrate, (unsigned long)sc);
 
        sc->config.txpowlimit = ATH_TXPOWER_MAX;
@@ -585,6 +584,7 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc, u16 subsysid,
        common->priv = sc;
        common->debug_mask = ath9k_debug;
        common->btcoex_enabled = ath9k_btcoex_enable == 1;
+       common->disable_ani = false;
        spin_lock_init(&common->cc_lock);
 
        spin_lock_init(&sc->sc_serial_rw);
index a198ee3..7f94533 100644 (file)
@@ -62,14 +62,12 @@ static bool ath9k_has_pending_frames(struct ath_softc *sc, struct ath_txq *txq)
 
        if (txq->axq_depth || !list_empty(&txq->axq_acq))
                pending = true;
-       else if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA)
-               pending = !list_empty(&txq->txq_fifo_pending);
 
        spin_unlock_bh(&txq->axq_lock);
        return pending;
 }
 
-bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode)
+static bool ath9k_setpower(struct ath_softc *sc, enum ath9k_power_mode mode)
 {
        unsigned long flags;
        bool ret;
@@ -136,7 +134,7 @@ void ath9k_ps_restore(struct ath_softc *sc)
        spin_unlock_irqrestore(&sc->sc_pm_lock, flags);
 }
 
-static void ath_start_ani(struct ath_common *common)
+void ath_start_ani(struct ath_common *common)
 {
        struct ath_hw *ah = common->ah;
        unsigned long timestamp = jiffies_to_msecs(jiffies);
@@ -219,7 +217,7 @@ static int ath_update_survey_stats(struct ath_softc *sc)
  * by reseting the chip.  To accomplish this we must first cleanup any pending
  * DMA, then restart stuff.
 */
-int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
+static int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
                    struct ath9k_channel *hchan)
 {
        struct ath_hw *ah = sc->sc_ah;
@@ -302,7 +300,8 @@ int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
                        ath_set_beacon(sc);
                ieee80211_queue_delayed_work(sc->hw, &sc->tx_complete_work, 0);
                ieee80211_queue_delayed_work(sc->hw, &sc->hw_pll_work, HZ/2);
-               ath_start_ani(common);
+               if (!common->disable_ani)
+                       ath_start_ani(common);
        }
 
  ps_restore:
@@ -394,12 +393,14 @@ void ath_paprd_calibrate(struct work_struct *work)
        if (!caldata)
                return;
 
+       ath9k_ps_wakeup(sc);
+
        if (ar9003_paprd_init_table(ah) < 0)
-               return;
+               goto fail_paprd;
 
        skb = alloc_skb(len, GFP_KERNEL);
        if (!skb)
-               return;
+               goto fail_paprd;
 
        skb_put(skb, len);
        memset(skb->data, 0, len);
@@ -411,7 +412,6 @@ void ath_paprd_calibrate(struct work_struct *work)
        memcpy(hdr->addr2, hw->wiphy->perm_addr, ETH_ALEN);
        memcpy(hdr->addr3, hw->wiphy->perm_addr, ETH_ALEN);
 
-       ath9k_ps_wakeup(sc);
        for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
                if (!(common->tx_chainmask & BIT(chain)))
                        continue;
@@ -515,24 +515,19 @@ void ath_ani_calibrate(unsigned long data)
                common->ani.checkani_timer = timestamp;
        }
 
-       /* Skip all processing if there's nothing to do. */
-       if (longcal || shortcal || aniflag) {
-               /* Call ANI routine if necessary */
-               if (aniflag) {
-                       spin_lock_irqsave(&common->cc_lock, flags);
-                       ath9k_hw_ani_monitor(ah, ah->curchan);
-                       ath_update_survey_stats(sc);
-                       spin_unlock_irqrestore(&common->cc_lock, flags);
-               }
+       /* Call ANI routine if necessary */
+       if (aniflag) {
+               spin_lock_irqsave(&common->cc_lock, flags);
+               ath9k_hw_ani_monitor(ah, ah->curchan);
+               ath_update_survey_stats(sc);
+               spin_unlock_irqrestore(&common->cc_lock, flags);
+       }
 
-               /* Perform calibration if necessary */
-               if (longcal || shortcal) {
-                       common->ani.caldone =
-                               ath9k_hw_calibrate(ah,
-                                                  ah->curchan,
-                                                  common->rx_chainmask,
-                                                  longcal);
-               }
+       /* Perform calibration if necessary */
+       if (longcal || shortcal) {
+               common->ani.caldone =
+                       ath9k_hw_calibrate(ah, ah->curchan,
+                                               common->rx_chainmask, longcal);
        }
 
        ath9k_ps_restore(sc);
@@ -670,7 +665,8 @@ void ath9k_tasklet(unsigned long data)
        u32 status = sc->intrstatus;
        u32 rxmask;
 
-       if (status & ATH9K_INT_FATAL) {
+       if ((status & ATH9K_INT_FATAL) ||
+           (status & ATH9K_INT_BB_WATCHDOG)) {
                ath_reset(sc, true);
                return;
        }
@@ -737,6 +733,7 @@ irqreturn_t ath_isr(int irq, void *dev)
 {
 #define SCHED_INTR (                           \
                ATH9K_INT_FATAL |               \
+               ATH9K_INT_BB_WATCHDOG |         \
                ATH9K_INT_RXORN |               \
                ATH9K_INT_RXEOL |               \
                ATH9K_INT_RX |                  \
@@ -866,7 +863,7 @@ chip_reset:
 #undef SCHED_INTR
 }
 
-void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
+static void ath_radio_enable(struct ath_softc *sc, struct ieee80211_hw *hw)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
@@ -972,6 +969,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
        sc->hw_busy_count = 0;
 
        /* Stop ANI */
+
        del_timer_sync(&common->ani.timer);
 
        ath9k_ps_wakeup(sc);
@@ -1021,7 +1019,9 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
        spin_unlock_bh(&sc->sc_pcu_lock);
 
        /* Start ANI */
-       ath_start_ani(common);
+       if (!common->disable_ani)
+               ath_start_ani(common);
+
        ath9k_ps_restore(sc);
 
        return r;
@@ -1410,10 +1410,14 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
        ath9k_hw_set_interrupts(ah, ah->imask);
 
        /* Set up ANI */
-       if ((iter_data.naps + iter_data.nadhocs) > 0) {
+       if (iter_data.naps > 0) {
                sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
-               sc->sc_flags |= SC_OP_ANI_RUN;
-               ath_start_ani(common);
+
+               if (!common->disable_ani) {
+                       sc->sc_flags |= SC_OP_ANI_RUN;
+                       ath_start_ani(common);
+               }
+
        } else {
                sc->sc_flags &= ~SC_OP_ANI_RUN;
                del_timer_sync(&common->ani.timer);
@@ -1950,50 +1954,38 @@ static void ath9k_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
        struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
        struct ath_vif *avp = (void *)vif->drv_priv;
 
-       switch (sc->sc_ah->opmode) {
-       case NL80211_IFTYPE_ADHOC:
-               /* There can be only one vif available */
+       /*
+        * Skip iteration if primary station vif's bss info
+        * was not changed
+        */
+       if (sc->sc_flags & SC_OP_PRIM_STA_VIF)
+               return;
+
+       if (bss_conf->assoc) {
+               sc->sc_flags |= SC_OP_PRIM_STA_VIF;
+               avp->primary_sta_vif = true;
                memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
                common->curaid = bss_conf->aid;
                ath9k_hw_write_associd(sc->sc_ah);
-               /* configure beacon */
-               if (bss_conf->enable_beacon)
-                       ath_beacon_config(sc, vif);
-               break;
-       case NL80211_IFTYPE_STATION:
-               /*
-                * Skip iteration if primary station vif's bss info
-                * was not changed
-                */
-               if (sc->sc_flags & SC_OP_PRIM_STA_VIF)
-                       break;
-
-               if (bss_conf->assoc) {
-                       sc->sc_flags |= SC_OP_PRIM_STA_VIF;
-                       avp->primary_sta_vif = true;
-                       memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
-                       common->curaid = bss_conf->aid;
-                       ath9k_hw_write_associd(sc->sc_ah);
-                       ath_dbg(common, ATH_DBG_CONFIG,
+               ath_dbg(common, ATH_DBG_CONFIG,
                                "Bss Info ASSOC %d, bssid: %pM\n",
                                bss_conf->aid, common->curbssid);
-                       ath_beacon_config(sc, vif);
-                       /*
-                        * Request a re-configuration of Beacon related timers
-                        * on the receipt of the first Beacon frame (i.e.,
-                        * after time sync with the AP).
-                        */
-                       sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
-                       /* Reset rssi stats */
-                       sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
-                       sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
+               ath_beacon_config(sc, vif);
+               /*
+                * Request a re-configuration of Beacon related timers
+                * on the receipt of the first Beacon frame (i.e.,
+                * after time sync with the AP).
+                */
+               sc->ps_flags |= PS_BEACON_SYNC | PS_WAIT_FOR_BEACON;
+               /* Reset rssi stats */
+               sc->last_rssi = ATH_RSSI_DUMMY_MARKER;
+               sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
 
+               if (!common->disable_ani) {
                        sc->sc_flags |= SC_OP_ANI_RUN;
                        ath_start_ani(common);
                }
-               break;
-       default:
-               break;
+
        }
 }
 
@@ -2003,6 +1995,9 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
        struct ieee80211_bss_conf *bss_conf = &vif->bss_conf;
        struct ath_vif *avp = (void *)vif->drv_priv;
 
+       if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
+               return;
+
        /* Reconfigure bss info */
        if (avp->primary_sta_vif && !bss_conf->assoc) {
                ath_dbg(common, ATH_DBG_CONFIG,
@@ -2021,8 +2016,7 @@ static void ath9k_config_bss(struct ath_softc *sc, struct ieee80211_vif *vif)
         * None of station vifs are associated.
         * Clear bssid & aid
         */
-       if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
-           !(sc->sc_flags & SC_OP_PRIM_STA_VIF)) {
+       if (!(sc->sc_flags & SC_OP_PRIM_STA_VIF)) {
                ath9k_hw_write_associd(sc->sc_ah);
                /* Stop ANI */
                sc->sc_flags &= ~SC_OP_ANI_RUN;
@@ -2052,6 +2046,26 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                        common->curbssid, common->curaid);
        }
 
+       if (changed & BSS_CHANGED_IBSS) {
+               /* There can be only one vif available */
+               memcpy(common->curbssid, bss_conf->bssid, ETH_ALEN);
+               common->curaid = bss_conf->aid;
+               ath9k_hw_write_associd(sc->sc_ah);
+
+               if (bss_conf->ibss_joined) {
+                       sc->sc_ah->stats.avgbrssi = ATH_RSSI_DUMMY_MARKER;
+
+                       if (!common->disable_ani) {
+                               sc->sc_flags |= SC_OP_ANI_RUN;
+                               ath_start_ani(common);
+                       }
+
+               } else {
+                       sc->sc_flags &= ~SC_OP_ANI_RUN;
+                       del_timer_sync(&common->ani.timer);
+               }
+       }
+
        /* Enable transmission of beacons (AP, IBSS, MESH) */
        if ((changed & BSS_CHANGED_BEACON) ||
            ((changed & BSS_CHANGED_BEACON_ENABLED) && bss_conf->enable_beacon)) {
@@ -2332,7 +2346,7 @@ static bool ath9k_tx_frames_pending(struct ieee80211_hw *hw)
        return false;
 }
 
-int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
+static int ath9k_tx_last_beacon(struct ieee80211_hw *hw)
 {
        struct ath_softc *sc = hw->priv;
        struct ath_hw *ah = sc->sc_ah;
index 1754221..ba7f36a 100644 (file)
@@ -689,7 +689,8 @@ static void ath_rc_rate_set_series(const struct ath_rate_table *rate_table,
 
        if (WLAN_RC_PHY_HT(rate_table->info[rix].phy)) {
                rate->flags |= IEEE80211_TX_RC_MCS;
-               if (WLAN_RC_PHY_40(rate_table->info[rix].phy))
+               if (WLAN_RC_PHY_40(rate_table->info[rix].phy) &&
+                   conf_is_ht40(&txrc->hw->conf))
                        rate->flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
                if (WLAN_RC_PHY_SGI(rate_table->info[rix].phy))
                        rate->flags |= IEEE80211_TX_RC_SHORT_GI;
index 3779b89..ec012b4 100644 (file)
@@ -53,7 +53,7 @@ static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
                                struct ath_txq *txq, struct list_head *bf_q,
                                struct ath_tx_status *ts, int txok, int sendbar);
 static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
-                            struct list_head *head);
+                            struct list_head *head, bool internal);
 static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf, int len);
 static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
                             struct ath_tx_status *ts, int nframes, int nbad,
@@ -377,8 +377,7 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                        bf_next = bf->bf_next;
 
                        bf->bf_state.bf_type |= BUF_XRETRY;
-                       if ((sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) ||
-                           !bf->bf_stale || bf_next != NULL)
+                       if (!bf->bf_stale || bf_next != NULL)
                                list_move_tail(&bf->list, &bf_head);
 
                        ath_tx_rc_status(sc, bf, ts, 1, 1, 0, false);
@@ -463,20 +462,14 @@ static void ath_tx_complete_aggr(struct ath_softc *sc, struct ath_txq *txq,
                        }
                }
 
-               if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) &&
-                   bf_next == NULL) {
-                       /*
-                        * Make sure the last desc is reclaimed if it
-                        * not a holding desc.
-                        */
-                       if (!bf_last->bf_stale)
-                               list_move_tail(&bf->list, &bf_head);
-                       else
-                               INIT_LIST_HEAD(&bf_head);
-               } else {
-                       BUG_ON(list_empty(bf_q));
+               /*
+                * Make sure the last desc is reclaimed if it
+                * not a holding desc.
+                */
+               if (!bf_last->bf_stale || bf_next != NULL)
                        list_move_tail(&bf->list, &bf_head);
-               }
+               else
+                       INIT_LIST_HEAD(&bf_head);
 
                if (!txpending || (tid->state & AGGR_CLEANUP)) {
                        /*
@@ -837,7 +830,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
                        bf->bf_state.bf_type &= ~BUF_AGGR;
                        ath9k_hw_clr11n_aggr(sc->sc_ah, bf->bf_desc);
                        ath_buf_set_rate(sc, bf, fi->framelen);
-                       ath_tx_txqaddbuf(sc, txq, &bf_q);
+                       ath_tx_txqaddbuf(sc, txq, &bf_q, false);
                        continue;
                }
 
@@ -849,7 +842,7 @@ static void ath_tx_sched_aggr(struct ath_softc *sc, struct ath_txq *txq,
                /* anchor last desc of aggregate */
                ath9k_hw_set11n_aggr_last(sc->sc_ah, bf->bf_lastbf->bf_desc);
 
-               ath_tx_txqaddbuf(sc, txq, &bf_q);
+               ath_tx_txqaddbuf(sc, txq, &bf_q, false);
                TX_STAT_INC(txq->axq_qnum, a_aggr);
 
        } while (txq->axq_ampdu_depth < ATH_AGGR_MIN_QDEPTH &&
@@ -1085,7 +1078,6 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
                txq->txq_headidx = txq->txq_tailidx = 0;
                for (i = 0; i < ATH_TXFIFO_DEPTH; i++)
                        INIT_LIST_HEAD(&txq->txq_fifo[i]);
-               INIT_LIST_HEAD(&txq->txq_fifo_pending);
        }
        return &sc->tx.txq[axq_qnum];
 }
@@ -1155,13 +1147,8 @@ static bool bf_is_ampdu_not_probing(struct ath_buf *bf)
     return bf_isampdu(bf) && !(info->flags & IEEE80211_TX_CTL_RATE_CTRL_PROBE);
 }
 
-/*
- * Drain a given TX queue (could be Beacon or Data)
- *
- * This assumes output has been stopped and
- * we do not need to block ath_tx_tasklet.
- */
-void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
+static void ath_drain_txq_list(struct ath_softc *sc, struct ath_txq *txq,
+                              struct list_head *list, bool retry_tx)
 {
        struct ath_buf *bf, *lastbf;
        struct list_head bf_head;
@@ -1170,93 +1157,63 @@ void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
        memset(&ts, 0, sizeof(ts));
        INIT_LIST_HEAD(&bf_head);
 
-       for (;;) {
-               spin_lock_bh(&txq->axq_lock);
+       while (!list_empty(list)) {
+               bf = list_first_entry(list, struct ath_buf, list);
 
-               if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
-                       if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
-                               txq->txq_headidx = txq->txq_tailidx = 0;
-                               spin_unlock_bh(&txq->axq_lock);
-                               break;
-                       } else {
-                               bf = list_first_entry(&txq->txq_fifo[txq->txq_tailidx],
-                                                     struct ath_buf, list);
-                       }
-               } else {
-                       if (list_empty(&txq->axq_q)) {
-                               txq->axq_link = NULL;
-                               spin_unlock_bh(&txq->axq_lock);
-                               break;
-                       }
-                       bf = list_first_entry(&txq->axq_q, struct ath_buf,
-                                             list);
-
-                       if (bf->bf_stale) {
-                               list_del(&bf->list);
-                               spin_unlock_bh(&txq->axq_lock);
+               if (bf->bf_stale) {
+                       list_del(&bf->list);
 
-                               ath_tx_return_buffer(sc, bf);
-                               continue;
-                       }
+                       ath_tx_return_buffer(sc, bf);
+                       continue;
                }
 
                lastbf = bf->bf_lastbf;
-
-               if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
-                       list_cut_position(&bf_head,
-                                         &txq->txq_fifo[txq->txq_tailidx],
-                                         &lastbf->list);
-                       INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
-               } else {
-                       /* remove ath_buf's of the same mpdu from txq */
-                       list_cut_position(&bf_head, &txq->axq_q, &lastbf->list);
-               }
+               list_cut_position(&bf_head, list, &lastbf->list);
 
                txq->axq_depth--;
                if (bf_is_ampdu_not_probing(bf))
                        txq->axq_ampdu_depth--;
-               spin_unlock_bh(&txq->axq_lock);
 
+               spin_unlock_bh(&txq->axq_lock);
                if (bf_isampdu(bf))
                        ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, 0,
                                             retry_tx);
                else
                        ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, 0, 0);
+               spin_lock_bh(&txq->axq_lock);
        }
+}
 
+/*
+ * Drain a given TX queue (could be Beacon or Data)
+ *
+ * This assumes output has been stopped and
+ * we do not need to block ath_tx_tasklet.
+ */
+void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
+{
        spin_lock_bh(&txq->axq_lock);
-       txq->axq_tx_inprogress = false;
-       spin_unlock_bh(&txq->axq_lock);
-
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
-               spin_lock_bh(&txq->axq_lock);
-               while (!list_empty(&txq->txq_fifo_pending)) {
-                       bf = list_first_entry(&txq->txq_fifo_pending,
-                                             struct ath_buf, list);
-                       list_cut_position(&bf_head,
-                                         &txq->txq_fifo_pending,
-                                         &bf->bf_lastbf->list);
-                       spin_unlock_bh(&txq->axq_lock);
+               int idx = txq->txq_tailidx;
 
-                       if (bf_isampdu(bf))
-                               ath_tx_complete_aggr(sc, txq, bf, &bf_head,
-                                                    &ts, 0, retry_tx);
-                       else
-                               ath_tx_complete_buf(sc, bf, txq, &bf_head,
-                                                   &ts, 0, 0);
-                       spin_lock_bh(&txq->axq_lock);
+               while (!list_empty(&txq->txq_fifo[idx])) {
+                       ath_drain_txq_list(sc, txq, &txq->txq_fifo[idx],
+                                          retry_tx);
+
+                       INCR(idx, ATH_TXFIFO_DEPTH);
                }
-               spin_unlock_bh(&txq->axq_lock);
+               txq->txq_tailidx = idx;
        }
 
+       txq->axq_link = NULL;
+       txq->axq_tx_inprogress = false;
+       ath_drain_txq_list(sc, txq, &txq->axq_q, retry_tx);
+
        /* flush any pending frames if aggregation is enabled */
-       if (sc->sc_flags & SC_OP_TXAGGR) {
-               if (!retry_tx) {
-                       spin_lock_bh(&txq->axq_lock);
-                       ath_txq_drain_pending_buffers(sc, txq);
-                       spin_unlock_bh(&txq->axq_lock);
-               }
-       }
+       if ((sc->sc_flags & SC_OP_TXAGGR) && !retry_tx)
+               ath_txq_drain_pending_buffers(sc, txq);
+
+       spin_unlock_bh(&txq->axq_lock);
 }
 
 bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
@@ -1370,11 +1327,13 @@ void ath_txq_schedule(struct ath_softc *sc, struct ath_txq *txq)
  * assume the descriptors are already chained together by caller.
  */
 static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
-                            struct list_head *head)
+                            struct list_head *head, bool internal)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_common *common = ath9k_hw_common(ah);
-       struct ath_buf *bf;
+       struct ath_buf *bf, *bf_last;
+       bool puttxbuf = false;
+       bool edma;
 
        /*
         * Insert the frame on the outbound list and
@@ -1384,51 +1343,49 @@ static void ath_tx_txqaddbuf(struct ath_softc *sc, struct ath_txq *txq,
        if (list_empty(head))
                return;
 
+       edma = !!(ah->caps.hw_caps & ATH9K_HW_CAP_EDMA);
        bf = list_first_entry(head, struct ath_buf, list);
+       bf_last = list_entry(head->prev, struct ath_buf, list);
 
        ath_dbg(common, ATH_DBG_QUEUE,
                "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
 
-       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
-               if (txq->axq_depth >= ATH_TXFIFO_DEPTH) {
-                       list_splice_tail_init(head, &txq->txq_fifo_pending);
-                       return;
-               }
-               if (!list_empty(&txq->txq_fifo[txq->txq_headidx]))
-                       ath_dbg(common, ATH_DBG_XMIT,
-                               "Initializing tx fifo %d which is non-empty\n",
-                               txq->txq_headidx);
-               INIT_LIST_HEAD(&txq->txq_fifo[txq->txq_headidx]);
-               list_splice_init(head, &txq->txq_fifo[txq->txq_headidx]);
+       if (edma && list_empty(&txq->txq_fifo[txq->txq_headidx])) {
+               list_splice_tail_init(head, &txq->txq_fifo[txq->txq_headidx]);
                INCR(txq->txq_headidx, ATH_TXFIFO_DEPTH);
-               TX_STAT_INC(txq->axq_qnum, puttxbuf);
-               ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
-               ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
-                       txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
+               puttxbuf = true;
        } else {
                list_splice_tail_init(head, &txq->axq_q);
 
-               if (txq->axq_link == NULL) {
-                       TX_STAT_INC(txq->axq_qnum, puttxbuf);
-                       ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
-                       ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
-                               txq->axq_qnum, ito64(bf->bf_daddr),
-                               bf->bf_desc);
-               } else {
-                       *txq->axq_link = bf->bf_daddr;
+               if (txq->axq_link) {
+                       ath9k_hw_set_desc_link(ah, txq->axq_link, bf->bf_daddr);
                        ath_dbg(common, ATH_DBG_XMIT,
                                "link[%u] (%p)=%llx (%p)\n",
                                txq->axq_qnum, txq->axq_link,
                                ito64(bf->bf_daddr), bf->bf_desc);
-               }
-               ath9k_hw_get_desc_link(ah, bf->bf_lastbf->bf_desc,
-                                      &txq->axq_link);
+               } else if (!edma)
+                       puttxbuf = true;
+
+               txq->axq_link = bf_last->bf_desc;
+       }
+
+       if (puttxbuf) {
+               TX_STAT_INC(txq->axq_qnum, puttxbuf);
+               ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
+               ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
+                       txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
+       }
+
+       if (!edma) {
                TX_STAT_INC(txq->axq_qnum, txstart);
                ath9k_hw_txstart(ah, txq->axq_qnum);
        }
-       txq->axq_depth++;
-       if (bf_is_ampdu_not_probing(bf))
-               txq->axq_ampdu_depth++;
+
+       if (!internal) {
+               txq->axq_depth++;
+               if (bf_is_ampdu_not_probing(bf))
+                       txq->axq_ampdu_depth++;
+       }
 }
 
 static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
@@ -1470,7 +1427,7 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
        TX_STAT_INC(txctl->txq->axq_qnum, a_queued_hw);
        bf->bf_lastbf = bf;
        ath_buf_set_rate(sc, bf, fi->framelen);
-       ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
+       ath_tx_txqaddbuf(sc, txctl->txq, &bf_head, false);
 }
 
 static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
@@ -1490,7 +1447,7 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
        bf->bf_lastbf = bf;
        fi = get_frame_info(bf->bf_mpdu);
        ath_buf_set_rate(sc, bf, fi->framelen);
-       ath_tx_txqaddbuf(sc, txq, bf_head);
+       ath_tx_txqaddbuf(sc, txq, bf_head, false);
        TX_STAT_INC(txq->axq_qnum, queued);
 }
 
@@ -2077,6 +2034,38 @@ static void ath_tx_rc_status(struct ath_softc *sc, struct ath_buf *bf,
        tx_info->status.rates[tx_rateindex].count = ts->ts_longretry + 1;
 }
 
+static void ath_tx_process_buffer(struct ath_softc *sc, struct ath_txq *txq,
+                                 struct ath_tx_status *ts, struct ath_buf *bf,
+                                 struct list_head *bf_head)
+{
+       int txok;
+
+       txq->axq_depth--;
+       txok = !(ts->ts_status & ATH9K_TXERR_MASK);
+       txq->axq_tx_inprogress = false;
+       if (bf_is_ampdu_not_probing(bf))
+               txq->axq_ampdu_depth--;
+
+       spin_unlock_bh(&txq->axq_lock);
+
+       if (!bf_isampdu(bf)) {
+               /*
+                * This frame is sent out as a single frame.
+                * Use hardware retry status for this frame.
+                */
+               if (ts->ts_status & ATH9K_TXERR_XRETRY)
+                       bf->bf_state.bf_type |= BUF_XRETRY;
+               ath_tx_rc_status(sc, bf, ts, 1, txok ? 0 : 1, txok, true);
+               ath_tx_complete_buf(sc, bf, txq, bf_head, ts, txok, 0);
+       } else
+               ath_tx_complete_aggr(sc, txq, bf, bf_head, ts, txok, true);
+
+       spin_lock_bh(&txq->axq_lock);
+
+       if (sc->sc_flags & SC_OP_TXAGGR)
+               ath_txq_schedule(sc, txq);
+}
+
 static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 {
        struct ath_hw *ah = sc->sc_ah;
@@ -2085,20 +2074,18 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
        struct list_head bf_head;
        struct ath_desc *ds;
        struct ath_tx_status ts;
-       int txok;
        int status;
 
        ath_dbg(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
                txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
                txq->axq_link);
 
+       spin_lock_bh(&txq->axq_lock);
        for (;;) {
-               spin_lock_bh(&txq->axq_lock);
                if (list_empty(&txq->axq_q)) {
                        txq->axq_link = NULL;
                        if (sc->sc_flags & SC_OP_TXAGGR)
                                ath_txq_schedule(sc, txq);
-                       spin_unlock_bh(&txq->axq_lock);
                        break;
                }
                bf = list_first_entry(&txq->axq_q, struct ath_buf, list);
@@ -2114,13 +2101,11 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
                bf_held = NULL;
                if (bf->bf_stale) {
                        bf_held = bf;
-                       if (list_is_last(&bf_held->list, &txq->axq_q)) {
-                               spin_unlock_bh(&txq->axq_lock);
+                       if (list_is_last(&bf_held->list, &txq->axq_q))
                                break;
-                       } else {
-                               bf = list_entry(bf_held->list.next,
-                                               struct ath_buf, list);
-                       }
+
+                       bf = list_entry(bf_held->list.next, struct ath_buf,
+                                       list);
                }
 
                lastbf = bf->bf_lastbf;
@@ -2128,10 +2113,9 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
 
                memset(&ts, 0, sizeof(ts));
                status = ath9k_hw_txprocdesc(ah, ds, &ts);
-               if (status == -EINPROGRESS) {
-                       spin_unlock_bh(&txq->axq_lock);
+               if (status == -EINPROGRESS)
                        break;
-               }
+
                TX_STAT_INC(txq->axq_qnum, txprocdesc);
 
                /*
@@ -2145,42 +2129,14 @@ static void ath_tx_processq(struct ath_softc *sc, struct ath_txq *txq)
                        list_cut_position(&bf_head,
                                &txq->axq_q, lastbf->list.prev);
 
-               txq->axq_depth--;
-               txok = !(ts.ts_status & ATH9K_TXERR_MASK);
-               txq->axq_tx_inprogress = false;
-               if (bf_held)
+               if (bf_held) {
                        list_del(&bf_held->list);
-
-               if (bf_is_ampdu_not_probing(bf))
-                       txq->axq_ampdu_depth--;
-
-               spin_unlock_bh(&txq->axq_lock);
-
-               if (bf_held)
                        ath_tx_return_buffer(sc, bf_held);
-
-               if (!bf_isampdu(bf)) {
-                       /*
-                        * This frame is sent out as a single frame.
-                        * Use hardware retry status for this frame.
-                        */
-                       if (ts.ts_status & ATH9K_TXERR_XRETRY)
-                               bf->bf_state.bf_type |= BUF_XRETRY;
-                       ath_tx_rc_status(sc, bf, &ts, 1, txok ? 0 : 1, txok, true);
                }
 
-               if (bf_isampdu(bf))
-                       ath_tx_complete_aggr(sc, txq, bf, &bf_head, &ts, txok,
-                                            true);
-               else
-                       ath_tx_complete_buf(sc, bf, txq, &bf_head, &ts, txok, 0);
-
-               spin_lock_bh(&txq->axq_lock);
-
-               if (sc->sc_flags & SC_OP_TXAGGR)
-                       ath_txq_schedule(sc, txq);
-               spin_unlock_bh(&txq->axq_lock);
+               ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
        }
+       spin_unlock_bh(&txq->axq_lock);
 }
 
 static void ath_tx_complete_poll_work(struct work_struct *work)
@@ -2237,17 +2193,16 @@ void ath_tx_tasklet(struct ath_softc *sc)
 
 void ath_tx_edma_tasklet(struct ath_softc *sc)
 {
-       struct ath_tx_status txs;
+       struct ath_tx_status ts;
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ath_hw *ah = sc->sc_ah;
        struct ath_txq *txq;
        struct ath_buf *bf, *lastbf;
        struct list_head bf_head;
        int status;
-       int txok;
 
        for (;;) {
-               status = ath9k_hw_txprocdesc(ah, NULL, (void *)&txs);
+               status = ath9k_hw_txprocdesc(ah, NULL, (void *)&ts);
                if (status == -EINPROGRESS)
                        break;
                if (status == -EIO) {
@@ -2257,12 +2212,13 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
                }
 
                /* Skip beacon completions */
-               if (txs.qid == sc->beacon.beaconq)
+               if (ts.qid == sc->beacon.beaconq)
                        continue;
 
-               txq = &sc->tx.txq[txs.qid];
+               txq = &sc->tx.txq[ts.qid];
 
                spin_lock_bh(&txq->axq_lock);
+
                if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
                        spin_unlock_bh(&txq->axq_lock);
                        return;
@@ -2275,41 +2231,21 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
                INIT_LIST_HEAD(&bf_head);
                list_cut_position(&bf_head, &txq->txq_fifo[txq->txq_tailidx],
                                  &lastbf->list);
-               INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
-               txq->axq_depth--;
-               txq->axq_tx_inprogress = false;
-               if (bf_is_ampdu_not_probing(bf))
-                       txq->axq_ampdu_depth--;
-               spin_unlock_bh(&txq->axq_lock);
 
-               txok = !(txs.ts_status & ATH9K_TXERR_MASK);
-
-               if (!bf_isampdu(bf)) {
-                       if (txs.ts_status & ATH9K_TXERR_XRETRY)
-                               bf->bf_state.bf_type |= BUF_XRETRY;
-                       ath_tx_rc_status(sc, bf, &txs, 1, txok ? 0 : 1, txok, true);
-               }
-
-               if (bf_isampdu(bf))
-                       ath_tx_complete_aggr(sc, txq, bf, &bf_head, &txs,
-                                            txok, true);
-               else
-                       ath_tx_complete_buf(sc, bf, txq, &bf_head,
-                                           &txs, txok, 0);
+               if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
+                       INCR(txq->txq_tailidx, ATH_TXFIFO_DEPTH);
 
-               spin_lock_bh(&txq->axq_lock);
+                       if (!list_empty(&txq->axq_q)) {
+                               struct list_head bf_q;
 
-               if (!list_empty(&txq->txq_fifo_pending)) {
-                       INIT_LIST_HEAD(&bf_head);
-                       bf = list_first_entry(&txq->txq_fifo_pending,
-                                             struct ath_buf, list);
-                       list_cut_position(&bf_head,
-                                         &txq->txq_fifo_pending,
-                                         &bf->bf_lastbf->list);
-                       ath_tx_txqaddbuf(sc, txq, &bf_head);
-               } else if (sc->sc_flags & SC_OP_TXAGGR)
-                       ath_txq_schedule(sc, txq);
+                               INIT_LIST_HEAD(&bf_q);
+                               txq->axq_link = NULL;
+                               list_splice_tail_init(&txq->axq_q, &bf_q);
+                               ath_tx_txqaddbuf(sc, txq, &bf_q, true);
+                       }
+               }
 
+               ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
                spin_unlock_bh(&txq->axq_lock);
        }
 }
index 39a11e8..7e45ca2 100644 (file)
@@ -40,6 +40,7 @@
 ******************************************************************************/
 
 #include <linux/init.h>
+#include <linux/interrupt.h>
 
 #include <linux/kernel.h>
 #include <linux/ptrace.h>
index 480595f..fe26bf4 100644 (file)
@@ -26,6 +26,11 @@ config B43
          This driver can be built as a module (recommended) that will be called "b43".
          If unsure, say M.
 
+config B43_BCMA
+       bool "Support for BCMA bus"
+       depends on B43 && BCMA && BROKEN
+       default y
+
 # Auto-select SSB PCI-HOST support, if possible
 config B43_PCI_AUTOSELECT
        bool
index cef334a..95f7c00 100644 (file)
@@ -1,4 +1,5 @@
 b43-y                          += main.o
+b43-y                          += bus.o
 b43-y                          += tables.o
 b43-$(CONFIG_B43_PHY_N)                += tables_nphy.o
 b43-$(CONFIG_B43_PHY_N)                += radio_2055.o
index 25a78cf..1cb2dde 100644 (file)
@@ -5,12 +5,14 @@
 #include <linux/spinlock.h>
 #include <linux/interrupt.h>
 #include <linux/hw_random.h>
+#include <linux/bcma/bcma.h>
 #include <linux/ssb/ssb.h>
 #include <net/mac80211.h>
 
 #include "debugfs.h"
 #include "leds.h"
 #include "rfkill.h"
+#include "bus.h"
 #include "lo.h"
 #include "phy_common.h"
 
@@ -414,6 +416,17 @@ enum {
 #define B43_MACCMD_CCA                 0x00000008      /* Clear channel assessment */
 #define B43_MACCMD_BGNOISE             0x00000010      /* Background noise */
 
+/* BCMA 802.11 core specific IO Control (BCMA_IOCTL) flags */
+#define B43_BCMA_IOCTL_PHY_CLKEN       0x00000004      /* PHY Clock Enable */
+#define B43_BCMA_IOCTL_PHY_RESET       0x00000008      /* PHY Reset */
+#define B43_BCMA_IOCTL_MACPHYCLKEN     0x00000010      /* MAC PHY Clock Control Enable */
+#define B43_BCMA_IOCTL_PLLREFSEL       0x00000020      /* PLL Frequency Reference Select */
+#define B43_BCMA_IOCTL_PHY_BW          0x000000C0      /* PHY band width and clock speed mask (N-PHY+ only?) */
+#define  B43_BCMA_IOCTL_PHY_BW_10MHZ   0x00000000      /* 10 MHz bandwidth, 40 MHz PHY */
+#define  B43_BCMA_IOCTL_PHY_BW_20MHZ   0x00000040      /* 20 MHz bandwidth, 80 MHz PHY */
+#define  B43_BCMA_IOCTL_PHY_BW_40MHZ   0x00000080      /* 40 MHz bandwidth, 160 MHz PHY */
+#define B43_BCMA_IOCTL_GMODE           0x00002000      /* G Mode Enable */
+
 /* 802.11 core specific TM State Low (SSB_TMSLOW) flags */
 #define B43_TMSLOW_GMODE               0x20000000      /* G Mode Enable */
 #define B43_TMSLOW_PHY_BANDWIDTH       0x00C00000      /* PHY band width and clock speed mask (N-PHY only) */
@@ -707,7 +720,8 @@ enum {
 
 /* Data structure for one wireless device (802.11 core) */
 struct b43_wldev {
-       struct ssb_device *sdev;
+       struct ssb_device *sdev; /* TODO: remove when b43_bus_dev is ready */
+       struct b43_bus_dev *dev;
        struct b43_wl *wl;
 
        /* The device initialization status.
@@ -879,36 +893,59 @@ static inline enum ieee80211_band b43_current_band(struct b43_wl *wl)
        return wl->hw->conf.channel->band;
 }
 
+static inline int b43_bus_may_powerdown(struct b43_wldev *wldev)
+{
+       return wldev->dev->bus_may_powerdown(wldev->dev);
+}
+static inline int b43_bus_powerup(struct b43_wldev *wldev, bool dynamic_pctl)
+{
+       return wldev->dev->bus_powerup(wldev->dev, dynamic_pctl);
+}
+static inline int b43_device_is_enabled(struct b43_wldev *wldev)
+{
+       return wldev->dev->device_is_enabled(wldev->dev);
+}
+static inline void b43_device_enable(struct b43_wldev *wldev,
+                                    u32 core_specific_flags)
+{
+       wldev->dev->device_enable(wldev->dev, core_specific_flags);
+}
+static inline void b43_device_disable(struct b43_wldev *wldev,
+                                     u32 core_specific_flags)
+{
+       wldev->dev->device_disable(wldev->dev, core_specific_flags);
+}
+
 static inline u16 b43_read16(struct b43_wldev *dev, u16 offset)
 {
-       return ssb_read16(dev->sdev, offset);
+       return dev->dev->read16(dev->dev, offset);
 }
 
 static inline void b43_write16(struct b43_wldev *dev, u16 offset, u16 value)
 {
-       ssb_write16(dev->sdev, offset, value);
+       dev->dev->write16(dev->dev, offset, value);
 }
 
 static inline u32 b43_read32(struct b43_wldev *dev, u16 offset)
 {
-       return ssb_read32(dev->sdev, offset);
+       return dev->dev->read32(dev->dev, offset);
 }
 
 static inline void b43_write32(struct b43_wldev *dev, u16 offset, u32 value)
 {
-       ssb_write32(dev->sdev, offset, value);
+       dev->dev->write32(dev->dev, offset, value);
 }
 
 static inline void b43_block_read(struct b43_wldev *dev, void *buffer,
                                 size_t count, u16 offset, u8 reg_width)
 {
-       ssb_block_read(dev->sdev, buffer, count, offset, reg_width);
+       dev->dev->block_read(dev->dev, buffer, count, offset, reg_width);
 }
 
 static inline void b43_block_write(struct b43_wldev *dev, const void *buffer,
                                   size_t count, u16 offset, u8 reg_width)
 {
-       ssb_block_write(dev->sdev, buffer, count, offset, reg_width);
+       dev->dev->block_write(dev->dev, buffer, count, offset, reg_width);
 }
 
 static inline bool b43_using_pio_transfers(struct b43_wldev *dev)
diff --git a/drivers/net/wireless/b43/bus.c b/drivers/net/wireless/b43/bus.c
new file mode 100644 (file)
index 0000000..6c63aec
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+
+  Broadcom B43 wireless driver
+  Bus abstraction layer
+
+  This program is free software; you can redistribute it and/or modify
+  it under the terms of the GNU General Public License as published by
+  the Free Software Foundation; either version 2 of the License, or
+  (at your option) any later version.
+
+  This program is distributed in the hope that it will be useful,
+  but WITHOUT ANY WARRANTY; without even the implied warranty of
+  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+  GNU General Public License for more details.
+
+  You should have received a copy of the GNU General Public License
+  along with this program; see the file COPYING.  If not, write to
+  the Free Software Foundation, Inc., 51 Franklin Steet, Fifth Floor,
+  Boston, MA 02110-1301, USA.
+
+*/
+
+#include "b43.h"
+#include "bus.h"
+
+
+/* SSB */
+
+static inline int b43_bus_ssb_bus_may_powerdown(struct b43_bus_dev *dev)
+{
+       return ssb_bus_may_powerdown(dev->sdev->bus);
+}
+static inline int b43_bus_ssb_bus_powerup(struct b43_bus_dev *dev,
+                                         bool dynamic_pctl)
+{
+       return ssb_bus_powerup(dev->sdev->bus, dynamic_pctl);
+}
+static inline int b43_bus_ssb_device_is_enabled(struct b43_bus_dev *dev)
+{
+       return ssb_device_is_enabled(dev->sdev);
+}
+static inline void b43_bus_ssb_device_enable(struct b43_bus_dev *dev,
+                                            u32 core_specific_flags)
+{
+       ssb_device_enable(dev->sdev, core_specific_flags);
+}
+static inline void b43_bus_ssb_device_disable(struct b43_bus_dev *dev,
+                                             u32 core_specific_flags)
+{
+       ssb_device_disable(dev->sdev, core_specific_flags);
+}
+
+static inline u16 b43_bus_ssb_read16(struct b43_bus_dev *dev, u16 offset)
+{
+       return ssb_read16(dev->sdev, offset);
+}
+static inline u32 b43_bus_ssb_read32(struct b43_bus_dev *dev, u16 offset)
+{
+       return ssb_read32(dev->sdev, offset);
+}
+static inline
+void b43_bus_ssb_write16(struct b43_bus_dev *dev, u16 offset, u16 value)
+{
+       ssb_write16(dev->sdev, offset, value);
+}
+static inline
+void b43_bus_ssb_write32(struct b43_bus_dev *dev, u16 offset, u32 value)
+{
+       ssb_write32(dev->sdev, offset, value);
+}
+static inline
+void b43_bus_ssb_block_read(struct b43_bus_dev *dev, void *buffer,
+                           size_t count, u16 offset, u8 reg_width)
+{
+       ssb_block_read(dev->sdev, buffer, count, offset, reg_width);
+}
+static inline
+void b43_bus_ssb_block_write(struct b43_bus_dev *dev, const void *buffer,
+                            size_t count, u16 offset, u8 reg_width)
+{
+       ssb_block_write(dev->sdev, buffer, count, offset, reg_width);
+}
+
+struct b43_bus_dev *b43_bus_dev_ssb_init(struct ssb_device *sdev)
+{
+       struct b43_bus_dev *dev = kzalloc(sizeof(*dev), GFP_KERNEL);
+
+       dev->bus_type = B43_BUS_SSB;
+       dev->sdev = sdev;
+
+       dev->bus_may_powerdown = b43_bus_ssb_bus_may_powerdown;
+       dev->bus_powerup = b43_bus_ssb_bus_powerup;
+       dev->device_is_enabled = b43_bus_ssb_device_is_enabled;
+       dev->device_enable = b43_bus_ssb_device_enable;
+       dev->device_disable = b43_bus_ssb_device_disable;
+
+       dev->read16 = b43_bus_ssb_read16;
+       dev->read32 = b43_bus_ssb_read32;
+       dev->write16 = b43_bus_ssb_write16;
+       dev->write32 = b43_bus_ssb_write32;
+       dev->block_read = b43_bus_ssb_block_read;
+       dev->block_write = b43_bus_ssb_block_write;
+
+       dev->dev = sdev->dev;
+       dev->dma_dev = sdev->dma_dev;
+       dev->irq = sdev->irq;
+
+       dev->board_vendor = sdev->bus->boardinfo.vendor;
+       dev->board_type = sdev->bus->boardinfo.type;
+       dev->board_rev = sdev->bus->boardinfo.rev;
+
+       dev->chip_id = sdev->bus->chip_id;
+       dev->chip_rev = sdev->bus->chip_rev;
+       dev->chip_pkg = sdev->bus->chip_package;
+
+       dev->bus_sprom = &sdev->bus->sprom;
+
+       dev->core_id = sdev->id.coreid;
+       dev->core_rev = sdev->id.revision;
+
+       return dev;
+}
diff --git a/drivers/net/wireless/b43/bus.h b/drivers/net/wireless/b43/bus.h
new file mode 100644 (file)
index 0000000..79a5ab4
--- /dev/null
@@ -0,0 +1,62 @@
+#ifndef B43_BUS_H_
+#define B43_BUS_H_
+
+enum b43_bus_type {
+       B43_BUS_SSB,
+};
+
+struct b43_bus_dev {
+       enum b43_bus_type bus_type;
+       union {
+               struct ssb_device *sdev;
+       };
+
+       int (*bus_may_powerdown)(struct b43_bus_dev *dev);
+       int (*bus_powerup)(struct b43_bus_dev *dev, bool dynamic_pctl);
+       int (*device_is_enabled)(struct b43_bus_dev *dev);
+       void (*device_enable)(struct b43_bus_dev *dev,
+                             u32 core_specific_flags);
+       void (*device_disable)(struct b43_bus_dev *dev,
+                              u32 core_specific_flags);
+
+       u16 (*read16)(struct b43_bus_dev *dev, u16 offset);
+       u32 (*read32)(struct b43_bus_dev *dev, u16 offset);
+       void (*write16)(struct b43_bus_dev *dev, u16 offset, u16 value);
+       void (*write32)(struct b43_bus_dev *dev, u16 offset, u32 value);
+       void (*block_read)(struct b43_bus_dev *dev, void *buffer,
+                          size_t count, u16 offset, u8 reg_width);
+       void (*block_write)(struct b43_bus_dev *dev, const void *buffer,
+                           size_t count, u16 offset, u8 reg_width);
+
+       struct device *dev;
+       struct device *dma_dev;
+       unsigned int irq;
+
+       u16 board_vendor;
+       u16 board_type;
+       u16 board_rev;
+
+       u16 chip_id;
+       u8 chip_rev;
+       u8 chip_pkg;
+
+       struct ssb_sprom *bus_sprom;
+
+       u16 core_id;
+       u8 core_rev;
+};
+
+static inline bool b43_bus_host_is_pcmcia(struct b43_bus_dev *dev)
+{
+       return (dev->bus_type == B43_BUS_SSB &&
+               dev->sdev->bus->bustype == SSB_BUSTYPE_PCMCIA);
+}
+static inline bool b43_bus_host_is_sdio(struct b43_bus_dev *dev)
+{
+       return (dev->bus_type == B43_BUS_SSB &&
+               dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO);
+}
+
+struct b43_bus_dev *b43_bus_dev_ssb_init(struct ssb_device *sdev);
+
+#endif /* B43_BUS_H_ */
index 47d44bc..d02cf83 100644 (file)
@@ -333,10 +333,10 @@ static inline
        dma_addr_t dmaaddr;
 
        if (tx) {
-               dmaaddr = dma_map_single(ring->dev->sdev->dma_dev,
+               dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
                                         buf, len, DMA_TO_DEVICE);
        } else {
-               dmaaddr = dma_map_single(ring->dev->sdev->dma_dev,
+               dmaaddr = dma_map_single(ring->dev->dev->dma_dev,
                                         buf, len, DMA_FROM_DEVICE);
        }
 
@@ -348,10 +348,10 @@ static inline
                          dma_addr_t addr, size_t len, int tx)
 {
        if (tx) {
-               dma_unmap_single(ring->dev->sdev->dma_dev,
+               dma_unmap_single(ring->dev->dev->dma_dev,
                                 addr, len, DMA_TO_DEVICE);
        } else {
-               dma_unmap_single(ring->dev->sdev->dma_dev,
+               dma_unmap_single(ring->dev->dev->dma_dev,
                                 addr, len, DMA_FROM_DEVICE);
        }
 }
@@ -361,7 +361,7 @@ static inline
                                 dma_addr_t addr, size_t len)
 {
        B43_WARN_ON(ring->tx);
-       dma_sync_single_for_cpu(ring->dev->sdev->dma_dev,
+       dma_sync_single_for_cpu(ring->dev->dev->dma_dev,
                                    addr, len, DMA_FROM_DEVICE);
 }
 
@@ -370,7 +370,7 @@ static inline
                                    dma_addr_t addr, size_t len)
 {
        B43_WARN_ON(ring->tx);
-       dma_sync_single_for_device(ring->dev->sdev->dma_dev,
+       dma_sync_single_for_device(ring->dev->dev->dma_dev,
                                   addr, len, DMA_FROM_DEVICE);
 }
 
@@ -401,7 +401,7 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
         */
        if (ring->type == B43_DMA_64BIT)
                flags |= GFP_DMA;
-       ring->descbase = dma_alloc_coherent(ring->dev->sdev->dma_dev,
+       ring->descbase = dma_alloc_coherent(ring->dev->dev->dma_dev,
                                            B43_DMA_RINGMEMSIZE,
                                            &(ring->dmabase), flags);
        if (!ring->descbase) {
@@ -415,7 +415,7 @@ static int alloc_ringmemory(struct b43_dmaring *ring)
 
 static void free_ringmemory(struct b43_dmaring *ring)
 {
-       dma_free_coherent(ring->dev->sdev->dma_dev, B43_DMA_RINGMEMSIZE,
+       dma_free_coherent(ring->dev->dev->dma_dev, B43_DMA_RINGMEMSIZE,
                          ring->descbase, ring->dmabase);
 }
 
@@ -523,7 +523,7 @@ static bool b43_dma_mapping_error(struct b43_dmaring *ring,
                                  dma_addr_t addr,
                                  size_t buffersize, bool dma_to_device)
 {
-       if (unlikely(dma_mapping_error(ring->dev->sdev->dma_dev, addr)))
+       if (unlikely(dma_mapping_error(ring->dev->dev->dma_dev, addr)))
                return 1;
 
        switch (ring->type) {
@@ -757,14 +757,14 @@ static void dmacontroller_cleanup(struct b43_dmaring *ring)
 
 static void free_all_descbuffers(struct b43_dmaring *ring)
 {
-       struct b43_dmadesc_generic *desc;
        struct b43_dmadesc_meta *meta;
        int i;
 
        if (!ring->used_slots)
                return;
        for (i = 0; i < ring->nr_slots; i++) {
-               desc = ring->ops->idx2desc(ring, i, &meta);
+               /* get meta - ignore returned value */
+               ring->ops->idx2desc(ring, i, &meta);
 
                if (!meta->skb || b43_dma_ptr_is_poisoned(meta->skb)) {
                        B43_WARN_ON(!ring->tx);
@@ -869,7 +869,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                        goto err_kfree_meta;
 
                /* test for ability to dma to txhdr_cache */
-               dma_test = dma_map_single(dev->sdev->dma_dev,
+               dma_test = dma_map_single(dev->dev->dma_dev,
                                          ring->txhdr_cache,
                                          b43_txhdr_size(dev),
                                          DMA_TO_DEVICE);
@@ -884,7 +884,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                        if (!ring->txhdr_cache)
                                goto err_kfree_meta;
 
-                       dma_test = dma_map_single(dev->sdev->dma_dev,
+                       dma_test = dma_map_single(dev->dev->dma_dev,
                                                  ring->txhdr_cache,
                                                  b43_txhdr_size(dev),
                                                  DMA_TO_DEVICE);
@@ -898,7 +898,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                        }
                }
 
-               dma_unmap_single(dev->sdev->dma_dev,
+               dma_unmap_single(dev->dev->dma_dev,
                                 dma_test, b43_txhdr_size(dev),
                                 DMA_TO_DEVICE);
        }
@@ -1013,9 +1013,9 @@ static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask)
        /* Try to set the DMA mask. If it fails, try falling back to a
         * lower mask, as we can always also support a lower one. */
        while (1) {
-               err = dma_set_mask(dev->sdev->dma_dev, mask);
+               err = dma_set_mask(dev->dev->dma_dev, mask);
                if (!err) {
-                       err = dma_set_coherent_mask(dev->sdev->dma_dev, mask);
+                       err = dma_set_coherent_mask(dev->dev->dma_dev, mask);
                        if (!err)
                                break;
                }
@@ -1085,7 +1085,7 @@ int b43_dma_init(struct b43_wldev *dev)
                goto err_destroy_mcast;
 
        /* No support for the TX status DMA ring. */
-       B43_WARN_ON(dev->sdev->id.revision < 5);
+       B43_WARN_ON(dev->dev->core_rev < 5);
 
        b43dbg(dev->wl, "%u-bit DMA initialized\n",
               (unsigned int)type);
@@ -1388,7 +1388,6 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
 {
        const struct b43_dma_ops *ops;
        struct b43_dmaring *ring;
-       struct b43_dmadesc_generic *desc;
        struct b43_dmadesc_meta *meta;
        int slot, firstused;
        bool frame_succeed;
@@ -1416,7 +1415,8 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
        ops = ring->ops;
        while (1) {
                B43_WARN_ON(slot < 0 || slot >= ring->nr_slots);
-               desc = ops->idx2desc(ring, slot, &meta);
+               /* get meta - ignore returned value */
+               ops->idx2desc(ring, slot, &meta);
 
                if (b43_dma_ptr_is_poisoned(meta->skb)) {
                        b43dbg(dev->wl, "Poisoned TX slot %d (first=%d) "
index 0cafafe..b56ed41 100644 (file)
@@ -138,7 +138,7 @@ static int b43_register_led(struct b43_wldev *dev, struct b43_led *led,
        led->led_dev.default_trigger = default_trigger;
        led->led_dev.brightness_set = b43_led_brightness_set;
 
-       err = led_classdev_register(dev->sdev->dev, &led->led_dev);
+       err = led_classdev_register(dev->dev->dev, &led->led_dev);
        if (err) {
                b43warn(dev->wl, "LEDs: Failed to register %s\n", name);
                led->wl = NULL;
@@ -215,13 +215,12 @@ static void b43_led_get_sprominfo(struct b43_wldev *dev,
                                  enum b43_led_behaviour *behaviour,
                                  bool *activelow)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
        u8 sprom[4];
 
-       sprom[0] = bus->sprom.gpio0;
-       sprom[1] = bus->sprom.gpio1;
-       sprom[2] = bus->sprom.gpio2;
-       sprom[3] = bus->sprom.gpio3;
+       sprom[0] = dev->dev->bus_sprom->gpio0;
+       sprom[1] = dev->dev->bus_sprom->gpio1;
+       sprom[2] = dev->dev->bus_sprom->gpio2;
+       sprom[3] = dev->dev->bus_sprom->gpio3;
 
        if (sprom[led_index] == 0xFF) {
                /* There is no LED information in the SPROM
@@ -231,12 +230,12 @@ static void b43_led_get_sprominfo(struct b43_wldev *dev,
                case 0:
                        *behaviour = B43_LED_ACTIVITY;
                        *activelow = 1;
-                       if (bus->boardinfo.vendor == PCI_VENDOR_ID_COMPAQ)
+                       if (dev->dev->board_vendor == PCI_VENDOR_ID_COMPAQ)
                                *behaviour = B43_LED_RADIO_ALL;
                        break;
                case 1:
                        *behaviour = B43_LED_RADIO_B;
-                       if (bus->boardinfo.vendor == PCI_VENDOR_ID_ASUSTEK)
+                       if (dev->dev->board_vendor == PCI_VENDOR_ID_ASUSTEK)
                                *behaviour = B43_LED_ASSOC;
                        break;
                case 2:
index 2ef7d4b..a3dc8bb 100644 (file)
@@ -98,7 +98,7 @@ static u16 lo_measure_feedthrough(struct b43_wldev *dev,
                rfover |= pga;
                rfover |= lna;
                rfover |= trsw_rx;
-               if ((dev->sdev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA)
+               if ((dev->dev->bus_sprom->boardflags_lo & B43_BFL_EXTLNA)
                    && phy->rev > 6)
                        rfover |= B43_PHY_RFOVERVAL_EXTLNA;
 
@@ -301,14 +301,12 @@ static void lo_measure_gain_values(struct b43_wldev *dev,
                max_rx_gain = 0;
 
        if (has_loopback_gain(phy)) {
-               int trsw_rx = 0;
                int trsw_rx_gain;
 
                if (use_trsw_rx) {
                        trsw_rx_gain = gphy->trsw_rx_gain / 2;
                        if (max_rx_gain >= trsw_rx_gain) {
                                trsw_rx_gain = max_rx_gain - trsw_rx_gain;
-                               trsw_rx = 0x20;
                        }
                } else
                        trsw_rx_gain = max_rx_gain;
@@ -387,7 +385,7 @@ struct lo_g_saved_values {
 static void lo_measure_setup(struct b43_wldev *dev,
                             struct lo_g_saved_values *sav)
 {
-       struct ssb_sprom *sprom = &dev->sdev->bus->sprom;
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_g *gphy = phy->g;
        struct b43_txpower_lo_control *lo = gphy->lo_control;
index eb41596..cae3146 100644 (file)
@@ -113,6 +113,16 @@ static int b43_modparam_pio = B43_PIO_DEFAULT;
 module_param_named(pio, b43_modparam_pio, int, 0644);
 MODULE_PARM_DESC(pio, "Use PIO accesses by default: 0=DMA, 1=PIO");
 
+#ifdef CONFIG_B43_BCMA
+static const struct bcma_device_id b43_bcma_tbl[] = {
+       BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x17, BCMA_ANY_CLASS),
+       BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x18, BCMA_ANY_CLASS),
+       BCMA_CORE(BCMA_MANUF_BCM, BCMA_CORE_80211, 0x1D, BCMA_ANY_CLASS),
+       BCMA_CORETABLE_END
+};
+MODULE_DEVICE_TABLE(bcma, b43_bcma_tbl);
+#endif
+
 static const struct ssb_device_id b43_ssb_tbl[] = {
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 5),
        SSB_DEVICE(SSB_VENDOR_BROADCOM, SSB_DEV_80211, 6),
@@ -548,7 +558,7 @@ void b43_tsf_read(struct b43_wldev *dev, u64 *tsf)
 {
        u32 low, high;
 
-       B43_WARN_ON(dev->sdev->id.revision < 3);
+       B43_WARN_ON(dev->dev->core_rev < 3);
 
        /* The hardware guarantees us an atomic read, if we
         * read the low register first. */
@@ -586,7 +596,7 @@ static void b43_tsf_write_locked(struct b43_wldev *dev, u64 tsf)
 {
        u32 low, high;
 
-       B43_WARN_ON(dev->sdev->id.revision < 3);
+       B43_WARN_ON(dev->dev->core_rev < 3);
 
        low = tsf;
        high = (tsf >> 32);
@@ -714,7 +724,7 @@ void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on)
                b43_ram_write(dev, i * 4, buffer[i]);
 
        b43_write16(dev, 0x0568, 0x0000);
-       if (dev->sdev->id.revision < 11)
+       if (dev->dev->core_rev < 11)
                b43_write16(dev, 0x07C0, 0x0000);
        else
                b43_write16(dev, 0x07C0, 0x0100);
@@ -1132,7 +1142,7 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
        b43_write32(dev, B43_MMIO_MACCTL, macctl);
        /* Commit write */
        b43_read32(dev, B43_MMIO_MACCTL);
-       if (awake && dev->sdev->id.revision >= 5) {
+       if (awake && dev->dev->core_rev >= 5) {
                /* Wait for the microcode to wake up. */
                for (i = 0; i < 100; i++) {
                        ucstat = b43_shm_read16(dev, B43_SHM_SHARED,
@@ -1144,35 +1154,39 @@ void b43_power_saving_ctl_bits(struct b43_wldev *dev, unsigned int ps_flags)
        }
 }
 
-static void b43_ssb_wireless_core_reset(struct b43_wldev *dev, u32 flags)
+static void b43_ssb_wireless_core_reset(struct b43_wldev *dev, bool gmode)
 {
+       struct ssb_device *sdev = dev->dev->sdev;
        u32 tmslow;
+       u32 flags = 0;
 
+       if (gmode)
+               flags |= B43_TMSLOW_GMODE;
        flags |= B43_TMSLOW_PHYCLKEN;
        flags |= B43_TMSLOW_PHYRESET;
        if (dev->phy.type == B43_PHYTYPE_N)
                flags |= B43_TMSLOW_PHY_BANDWIDTH_20MHZ; /* Make 20 MHz def */
-       ssb_device_enable(dev->sdev, flags);
+       b43_device_enable(dev, flags);
        msleep(2);              /* Wait for the PLL to turn on. */
 
        /* Now take the PHY out of Reset again */
-       tmslow = ssb_read32(dev->sdev, SSB_TMSLOW);
+       tmslow = ssb_read32(sdev, SSB_TMSLOW);
        tmslow |= SSB_TMSLOW_FGC;
        tmslow &= ~B43_TMSLOW_PHYRESET;
-       ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
-       ssb_read32(dev->sdev, SSB_TMSLOW);      /* flush */
+       ssb_write32(sdev, SSB_TMSLOW, tmslow);
+       ssb_read32(sdev, SSB_TMSLOW);   /* flush */
        msleep(1);
        tmslow &= ~SSB_TMSLOW_FGC;
-       ssb_write32(dev->sdev, SSB_TMSLOW, tmslow);
-       ssb_read32(dev->sdev, SSB_TMSLOW);      /* flush */
+       ssb_write32(sdev, SSB_TMSLOW, tmslow);
+       ssb_read32(sdev, SSB_TMSLOW);   /* flush */
        msleep(1);
 }
 
-void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
+void b43_wireless_core_reset(struct b43_wldev *dev, bool gmode)
 {
        u32 macctl;
 
-       b43_ssb_wireless_core_reset(dev, flags);
+       b43_ssb_wireless_core_reset(dev, gmode);
 
        /* Turn Analog ON, but only if we already know the PHY-type.
         * This protects against very early setup where we don't know the
@@ -1183,7 +1197,7 @@ void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags)
 
        macctl = b43_read32(dev, B43_MMIO_MACCTL);
        macctl &= ~B43_MACCTL_GMODE;
-       if (flags & B43_TMSLOW_GMODE)
+       if (gmode)
                macctl |= B43_MACCTL_GMODE;
        macctl |= B43_MACCTL_IHR_ENABLED;
        b43_write32(dev, B43_MMIO_MACCTL, macctl);
@@ -1221,7 +1235,7 @@ static void drain_txstatus_queue(struct b43_wldev *dev)
 {
        u32 dummy;
 
-       if (dev->sdev->id.revision < 5)
+       if (dev->dev->core_rev < 5)
                return;
        /* Read all entries from the microcode TXstatus FIFO
         * and throw them away.
@@ -1427,9 +1441,9 @@ u8 b43_ieee80211_antenna_sanitize(struct b43_wldev *dev,
 
        /* Get the mask of available antennas. */
        if (dev->phy.gmode)
-               antenna_mask = dev->sdev->bus->sprom.ant_available_bg;
+               antenna_mask = dev->dev->bus_sprom->ant_available_bg;
        else
-               antenna_mask = dev->sdev->bus->sprom.ant_available_a;
+               antenna_mask = dev->dev->bus_sprom->ant_available_a;
 
        if (!(antenna_mask & (1 << (antenna_nr - 1)))) {
                /* This antenna is not available. Fall back to default. */
@@ -1644,7 +1658,7 @@ static void b43_beacon_update_trigger_work(struct work_struct *work)
        mutex_lock(&wl->mutex);
        dev = wl->current_dev;
        if (likely(dev && (b43_status(dev) >= B43_STAT_INITIALIZED))) {
-               if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
+               if (b43_bus_host_is_sdio(dev->dev)) {
                        /* wl->mutex is enough. */
                        b43_do_beacon_update_trigger_work(dev);
                        mmiowb();
@@ -1689,7 +1703,7 @@ static void b43_update_templates(struct b43_wl *wl)
 static void b43_set_beacon_int(struct b43_wldev *dev, u16 beacon_int)
 {
        b43_time_lock(dev);
-       if (dev->sdev->id.revision >= 3) {
+       if (dev->dev->core_rev >= 3) {
                b43_write32(dev, B43_MMIO_TSF_CFP_REP, (beacon_int << 16));
                b43_write32(dev, B43_MMIO_TSF_CFP_START, (beacon_int << 10));
        } else {
@@ -2063,7 +2077,7 @@ int b43_do_request_fw(struct b43_request_fw_context *ctx,
                B43_WARN_ON(1);
                return -ENOSYS;
        }
-       err = request_firmware(&blob, ctx->fwname, ctx->dev->sdev->dev);
+       err = request_firmware(&blob, ctx->fwname, ctx->dev->dev->dev);
        if (err == -ENOENT) {
                snprintf(ctx->errors[ctx->req_type],
                         sizeof(ctx->errors[ctx->req_type]),
@@ -2113,7 +2127,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
 {
        struct b43_wldev *dev = ctx->dev;
        struct b43_firmware *fw = &ctx->dev->fw;
-       const u8 rev = ctx->dev->sdev->id.revision;
+       const u8 rev = ctx->dev->dev->core_rev;
        const char *filename;
        u32 tmshigh;
        int err;
@@ -2157,7 +2171,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
        switch (dev->phy.type) {
        case B43_PHYTYPE_A:
                if ((rev >= 5) && (rev <= 10)) {
-                       tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
+                       tmshigh = ssb_read32(dev->dev->sdev, SSB_TMSHIGH);
                        if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
                                filename = "a0g1initvals5";
                        else
@@ -2202,7 +2216,7 @@ static int b43_try_request_fw(struct b43_request_fw_context *ctx)
        switch (dev->phy.type) {
        case B43_PHYTYPE_A:
                if ((rev >= 5) && (rev <= 10)) {
-                       tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
+                       tmshigh = ssb_read32(dev->dev->sdev, SSB_TMSHIGH);
                        if (tmshigh & B43_TMSHIGH_HAVE_2GHZ_PHY)
                                filename = "a0g1bsinitvals5";
                        else
@@ -2448,7 +2462,7 @@ static int b43_upload_microcode(struct b43_wldev *dev)
 
        snprintf(wiphy->fw_version, sizeof(wiphy->fw_version), "%u.%u",
                        dev->fw.rev, dev->fw.patch);
-       wiphy->hw_version = dev->sdev->id.coreid;
+       wiphy->hw_version = dev->dev->core_id;
 
        if (b43_is_old_txhdr_format(dev)) {
                /* We're over the deadline, but we keep support for old fw
@@ -2566,7 +2580,7 @@ out:
  */
 static struct ssb_device *b43_ssb_gpio_dev(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
+       struct ssb_bus *bus = dev->dev->sdev->bus;
 
 #ifdef CONFIG_SSB_DRIVER_PCICORE
        return (bus->chipco.dev ? bus->chipco.dev : bus->pcicore.dev);
@@ -2588,7 +2602,7 @@ static int b43_gpio_init(struct b43_wldev *dev)
 
        mask = 0x0000001F;
        set = 0x0000000F;
-       if (dev->sdev->bus->chip_id == 0x4301) {
+       if (dev->dev->chip_id == 0x4301) {
                mask |= 0x0060;
                set |= 0x0060;
        }
@@ -2599,14 +2613,14 @@ static int b43_gpio_init(struct b43_wldev *dev)
                mask |= 0x0180;
                set |= 0x0180;
        }
-       if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL) {
+       if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL) {
                b43_write16(dev, B43_MMIO_GPIO_MASK,
                            b43_read16(dev, B43_MMIO_GPIO_MASK)
                            | 0x0200);
                mask |= 0x0200;
                set |= 0x0200;
        }
-       if (dev->sdev->id.revision >= 2)
+       if (dev->dev->core_rev >= 2)
                mask |= 0x0010; /* FIXME: This is redundant. */
 
        gpiodev = b43_ssb_gpio_dev(dev);
@@ -2741,15 +2755,15 @@ static void b43_adjust_opmode(struct b43_wldev *dev)
        /* Workaround: On old hardware the HW-MAC-address-filter
         * doesn't work properly, so always run promisc in filter
         * it in software. */
-       if (dev->sdev->id.revision <= 4)
+       if (dev->dev->core_rev <= 4)
                ctl |= B43_MACCTL_PROMISC;
 
        b43_write32(dev, B43_MMIO_MACCTL, ctl);
 
        cfp_pretbtt = 2;
        if ((ctl & B43_MACCTL_INFRA) && !(ctl & B43_MACCTL_AP)) {
-               if (dev->sdev->bus->chip_id == 0x4306 &&
-                   dev->sdev->bus->chip_rev == 3)
+               if (dev->dev->chip_id == 0x4306 &&
+                   dev->dev->chip_rev == 3)
                        cfp_pretbtt = 100;
                else
                        cfp_pretbtt = 50;
@@ -2907,7 +2921,7 @@ static int b43_chip_init(struct b43_wldev *dev)
                b43_write16(dev, 0x005E, value16);
        }
        b43_write32(dev, 0x0100, 0x01000000);
-       if (dev->sdev->id.revision < 5)
+       if (dev->dev->core_rev < 5)
                b43_write32(dev, 0x010C, 0x01000000);
 
        b43_write32(dev, B43_MMIO_MACCTL, b43_read32(dev, B43_MMIO_MACCTL)
@@ -2922,7 +2936,7 @@ static int b43_chip_init(struct b43_wldev *dev)
        /* Initially set the wireless operation mode. */
        b43_adjust_opmode(dev);
 
-       if (dev->sdev->id.revision < 3) {
+       if (dev->dev->core_rev < 3) {
                b43_write16(dev, 0x060E, 0x0000);
                b43_write16(dev, 0x0610, 0x8000);
                b43_write16(dev, 0x0604, 0x0000);
@@ -3105,7 +3119,7 @@ static int b43_validate_chipaccess(struct b43_wldev *dev)
        b43_shm_write32(dev, B43_SHM_SHARED, 0, backup0);
        b43_shm_write32(dev, B43_SHM_SHARED, 4, backup4);
 
-       if ((dev->sdev->id.revision >= 3) && (dev->sdev->id.revision <= 10)) {
+       if ((dev->dev->core_rev >= 3) && (dev->dev->core_rev <= 10)) {
                /* The 32bit register shadows the two 16bit registers
                 * with update sideeffects. Validate this. */
                b43_write16(dev, B43_MMIO_TSF_CFP_START, 0xAAAA);
@@ -3954,7 +3968,7 @@ redo:
 
        /* Disable interrupts on the device. */
        b43_set_status(dev, B43_STAT_INITIALIZED);
-       if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
+       if (b43_bus_host_is_sdio(dev->dev)) {
                /* wl->mutex is locked. That is enough. */
                b43_write32(dev, B43_MMIO_GEN_IRQ_MASK, 0);
                b43_read32(dev, B43_MMIO_GEN_IRQ_MASK); /* Flush */
@@ -3967,11 +3981,11 @@ redo:
        /* Synchronize and free the interrupt handlers. Unlock to avoid deadlocks. */
        orig_dev = dev;
        mutex_unlock(&wl->mutex);
-       if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
+       if (b43_bus_host_is_sdio(dev->dev)) {
                b43_sdio_free_irq(dev);
        } else {
-               synchronize_irq(dev->sdev->irq);
-               free_irq(dev->sdev->irq, dev);
+               synchronize_irq(dev->dev->irq);
+               free_irq(dev->dev->irq, dev);
        }
        mutex_lock(&wl->mutex);
        dev = wl->current_dev;
@@ -4004,19 +4018,19 @@ static int b43_wireless_core_start(struct b43_wldev *dev)
        B43_WARN_ON(b43_status(dev) != B43_STAT_INITIALIZED);
 
        drain_txstatus_queue(dev);
-       if (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) {
+       if (b43_bus_host_is_sdio(dev->dev)) {
                err = b43_sdio_request_irq(dev, b43_sdio_interrupt_handler);
                if (err) {
                        b43err(dev->wl, "Cannot request SDIO IRQ\n");
                        goto out;
                }
        } else {
-               err = request_threaded_irq(dev->sdev->irq, b43_interrupt_handler,
+               err = request_threaded_irq(dev->dev->irq, b43_interrupt_handler,
                                           b43_interrupt_thread_handler,
                                           IRQF_SHARED, KBUILD_MODNAME, dev);
                if (err) {
                        b43err(dev->wl, "Cannot request IRQ-%d\n",
-                              dev->sdev->irq);
+                              dev->dev->irq);
                        goto out;
                }
        }
@@ -4085,7 +4099,7 @@ static int b43_phy_versioning(struct b43_wldev *dev)
 #endif
        default:
                unsupported = 1;
-       };
+       }
        if (unsupported) {
                b43err(dev->wl, "FOUND UNSUPPORTED PHY "
                       "(Analog %u, Type %u, Revision %u)\n",
@@ -4096,10 +4110,10 @@ static int b43_phy_versioning(struct b43_wldev *dev)
               analog_type, phy_type, phy_rev);
 
        /* Get RADIO versioning */
-       if (dev->sdev->bus->chip_id == 0x4317) {
-               if (dev->sdev->bus->chip_rev == 0)
+       if (dev->dev->chip_id == 0x4317) {
+               if (dev->dev->chip_rev == 0)
                        tmp = 0x3205017F;
-               else if (dev->sdev->bus->chip_rev == 1)
+               else if (dev->dev->chip_rev == 1)
                        tmp = 0x4205017F;
                else
                        tmp = 0x5205017F;
@@ -4204,7 +4218,7 @@ static void setup_struct_wldev_for_init(struct b43_wldev *dev)
 
 static void b43_bluetooth_coext_enable(struct b43_wldev *dev)
 {
-       struct ssb_sprom *sprom = &dev->sdev->bus->sprom;
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
        u64 hf;
 
        if (!modparam_btcoex)
@@ -4231,16 +4245,21 @@ static void b43_bluetooth_coext_disable(struct b43_wldev *dev)
 
 static void b43_imcfglo_timeouts_workaround(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
+       struct ssb_bus *bus;
        u32 tmp;
 
+       if (dev->dev->bus_type != B43_BUS_SSB)
+               return;
+
+       bus = dev->dev->sdev->bus;
+
        if ((bus->chip_id == 0x4311 && bus->chip_rev == 2) ||
            (bus->chip_id == 0x4312)) {
-               tmp = ssb_read32(dev->sdev, SSB_IMCFGLO);
+               tmp = ssb_read32(dev->dev->sdev, SSB_IMCFGLO);
                tmp &= ~SSB_IMCFGLO_REQTO;
                tmp &= ~SSB_IMCFGLO_SERTO;
                tmp |= 0x3;
-               ssb_write32(dev->sdev, SSB_IMCFGLO, tmp);
+               ssb_write32(dev->dev->sdev, SSB_IMCFGLO, tmp);
                ssb_commit_settings(bus);
        }
 }
@@ -4310,29 +4329,26 @@ static void b43_wireless_core_exit(struct b43_wldev *dev)
                dev->wl->current_beacon = NULL;
        }
 
-       ssb_device_disable(dev->sdev, 0);
-       ssb_bus_may_powerdown(dev->sdev->bus);
+       b43_device_disable(dev, 0);
+       b43_bus_may_powerdown(dev);
 }
 
 /* Initialize a wireless core */
 static int b43_wireless_core_init(struct b43_wldev *dev)
 {
        struct ssb_bus *bus = dev->sdev->bus;
-       struct ssb_sprom *sprom = &bus->sprom;
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
        struct b43_phy *phy = &dev->phy;
        int err;
        u64 hf;
-       u32 tmp;
 
        B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
 
-       err = ssb_bus_powerup(bus, 0);
+       err = b43_bus_powerup(dev, 0);
        if (err)
                goto out;
-       if (!ssb_device_is_enabled(dev->sdev)) {
-               tmp = phy->gmode ? B43_TMSLOW_GMODE : 0;
-               b43_wireless_core_reset(dev, tmp);
-       }
+       if (!b43_device_is_enabled(dev))
+               b43_wireless_core_reset(dev, phy->gmode);
 
        /* Reset all data structures. */
        setup_struct_wldev_for_init(dev);
@@ -4352,7 +4368,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        if (err)
                goto err_busdown;
        b43_shm_write16(dev, B43_SHM_SHARED,
-                       B43_SHM_SH_WLCOREREV, dev->sdev->id.revision);
+                       B43_SHM_SH_WLCOREREV, dev->dev->core_rev);
        hf = b43_hf_read(dev);
        if (phy->type == B43_PHYTYPE_G) {
                hf |= B43_HF_SYMW;
@@ -4399,8 +4415,8 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        /* Maximum Contention Window */
        b43_shm_write16(dev, B43_SHM_SCRATCH, B43_SHM_SC_MAXCONT, 0x3FF);
 
-       if ((dev->sdev->bus->bustype == SSB_BUSTYPE_PCMCIA) ||
-           (dev->sdev->bus->bustype == SSB_BUSTYPE_SDIO) ||
+       if (b43_bus_host_is_pcmcia(dev->dev) ||
+           b43_bus_host_is_sdio(dev->dev) ||
            dev->use_pio) {
                dev->__using_pio_transfers = 1;
                err = b43_pio_init(dev);
@@ -4414,7 +4430,7 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
        b43_set_synth_pu_delay(dev, 1);
        b43_bluetooth_coext_enable(dev);
 
-       ssb_bus_powerup(bus, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW));
+       b43_bus_powerup(dev, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW));
        b43_upload_card_macaddress(dev);
        b43_security_init(dev);
 
@@ -4431,7 +4447,7 @@ out:
 err_chip_exit:
        b43_chip_exit(dev);
 err_busdown:
-       ssb_bus_may_powerdown(bus);
+       b43_bus_may_powerdown(dev);
        B43_WARN_ON(b43_status(dev) != B43_STAT_UNINIT);
        return err;
 }
@@ -4741,7 +4757,6 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
        struct pci_dev *pdev = (bus->bustype == SSB_BUSTYPE_PCI) ? bus->host_pci : NULL;
        int err;
        bool have_2ghz_phy = 0, have_5ghz_phy = 0;
-       u32 tmp;
 
        /* Do NOT do any device initialization here.
         * Do it in wireless_core_init() instead.
@@ -4750,13 +4765,13 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
         * that in core_init(), too.
         */
 
-       err = ssb_bus_powerup(bus, 0);
+       err = b43_bus_powerup(dev, 0);
        if (err) {
                b43err(wl, "Bus powerup failed\n");
                goto out;
        }
        /* Get the PHY type. */
-       if (dev->sdev->id.revision >= 5) {
+       if (dev->dev->core_rev >= 5) {
                u32 tmshigh;
 
                tmshigh = ssb_read32(dev->sdev, SSB_TMSHIGH);
@@ -4767,8 +4782,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
 
        dev->phy.gmode = have_2ghz_phy;
        dev->phy.radio_on = 1;
-       tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
-       b43_wireless_core_reset(dev, tmp);
+       b43_wireless_core_reset(dev, dev->phy.gmode);
 
        err = b43_phy_versioning(dev);
        if (err)
@@ -4816,8 +4830,7 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
                goto err_powerdown;
 
        dev->phy.gmode = have_2ghz_phy;
-       tmp = dev->phy.gmode ? B43_TMSLOW_GMODE : 0;
-       b43_wireless_core_reset(dev, tmp);
+       b43_wireless_core_reset(dev, dev->phy.gmode);
 
        err = b43_validate_chipaccess(dev);
        if (err)
@@ -4832,8 +4845,8 @@ static int b43_wireless_core_attach(struct b43_wldev *dev)
        INIT_WORK(&dev->restart_work, b43_chip_reset);
 
        dev->phy.ops->switch_analog(dev, 0);
-       ssb_device_disable(dev->sdev, 0);
-       ssb_bus_may_powerdown(bus);
+       b43_device_disable(dev, 0);
+       b43_bus_may_powerdown(dev);
 
 out:
        return err;
@@ -4841,11 +4854,11 @@ out:
 err_phy_free:
        b43_phy_free(dev);
 err_powerdown:
-       ssb_bus_may_powerdown(bus);
+       b43_bus_may_powerdown(dev);
        return err;
 }
 
-static void b43_one_core_detach(struct ssb_device *dev)
+static void b43_one_core_detach(struct b43_bus_dev *dev)
 {
        struct b43_wldev *wldev;
        struct b43_wl *wl;
@@ -4853,17 +4866,17 @@ static void b43_one_core_detach(struct ssb_device *dev)
        /* Do not cancel ieee80211-workqueue based work here.
         * See comment in b43_remove(). */
 
-       wldev = ssb_get_drvdata(dev);
+       wldev = ssb_get_drvdata(dev->sdev);
        wl = wldev->wl;
        b43_debugfs_remove_device(wldev);
        b43_wireless_core_detach(wldev);
        list_del(&wldev->list);
        wl->nr_devs--;
-       ssb_set_drvdata(dev, NULL);
+       ssb_set_drvdata(dev->sdev, NULL);
        kfree(wldev);
 }
 
-static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
+static int b43_one_core_attach(struct b43_bus_dev *dev, struct b43_wl *wl)
 {
        struct b43_wldev *wldev;
        int err = -ENOMEM;
@@ -4873,7 +4886,8 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
                goto out;
 
        wldev->use_pio = b43_modparam_pio;
-       wldev->sdev = dev;
+       wldev->dev = dev;
+       wldev->sdev = dev->sdev; /* TODO: Remove when not needed */
        wldev->wl = wl;
        b43_set_status(wldev, B43_STAT_UNINIT);
        wldev->bad_frames_preempt = modparam_bad_frames_preempt;
@@ -4885,7 +4899,7 @@ static int b43_one_core_attach(struct ssb_device *dev, struct b43_wl *wl)
 
        list_add(&wldev->list, &wl->devlist);
        wl->nr_devs++;
-       ssb_set_drvdata(dev, wldev);
+       ssb_set_drvdata(dev->sdev, wldev);
        b43_debugfs_add_device(wldev);
 
       out:
@@ -4926,11 +4940,11 @@ static void b43_sprom_fixup(struct ssb_bus *bus)
        }
 }
 
-static void b43_wireless_exit(struct ssb_device *dev, struct b43_wl *wl)
+static void b43_wireless_exit(struct b43_bus_dev *dev, struct b43_wl *wl)
 {
        struct ieee80211_hw *hw = wl->hw;
 
-       ssb_set_devtypedata(dev, NULL);
+       ssb_set_devtypedata(dev->sdev, NULL);
        ieee80211_free_hw(hw);
 }
 
@@ -4982,24 +4996,48 @@ static struct b43_wl *b43_wireless_init(struct ssb_device *dev)
        return wl;
 }
 
-static int b43_ssb_probe(struct ssb_device *dev, const struct ssb_device_id *id)
+#ifdef CONFIG_B43_BCMA
+static int b43_bcma_probe(struct bcma_device *core)
+{
+       b43err(NULL, "BCMA is not supported yet!");
+       return -EOPNOTSUPP;
+}
+
+static void b43_bcma_remove(struct bcma_device *core)
+{
+       /* TODO */
+}
+
+static struct bcma_driver b43_bcma_driver = {
+       .name           = KBUILD_MODNAME,
+       .id_table       = b43_bcma_tbl,
+       .probe          = b43_bcma_probe,
+       .remove         = b43_bcma_remove,
+};
+#endif
+
+static
+int b43_ssb_probe(struct ssb_device *sdev, const struct ssb_device_id *id)
 {
+       struct b43_bus_dev *dev;
        struct b43_wl *wl;
        int err;
        int first = 0;
 
-       wl = ssb_get_devtypedata(dev);
+       dev = b43_bus_dev_ssb_init(sdev);
+
+       wl = ssb_get_devtypedata(sdev);
        if (!wl) {
                /* Probing the first core. Must setup common struct b43_wl */
                first = 1;
-               b43_sprom_fixup(dev->bus);
-               wl = b43_wireless_init(dev);
+               b43_sprom_fixup(sdev->bus);
+               wl = b43_wireless_init(sdev);
                if (IS_ERR(wl)) {
                        err = PTR_ERR(wl);
                        goto out;
                }
-               ssb_set_devtypedata(dev, wl);
-               B43_WARN_ON(ssb_get_devtypedata(dev) != wl);
+               ssb_set_devtypedata(sdev, wl);
+               B43_WARN_ON(ssb_get_devtypedata(sdev) != wl);
        }
        err = b43_one_core_attach(dev, wl);
        if (err)
@@ -5023,10 +5061,10 @@ static int b43_ssb_probe(struct ssb_device *dev, const struct ssb_device_id *id)
        return err;
 }
 
-static void b43_ssb_remove(struct ssb_device *dev)
+static void b43_ssb_remove(struct ssb_device *sdev)
 {
-       struct b43_wl *wl = ssb_get_devtypedata(dev);
-       struct b43_wldev *wldev = ssb_get_drvdata(dev);
+       struct b43_wl *wl = ssb_get_devtypedata(sdev);
+       struct b43_wldev *wldev = ssb_get_drvdata(sdev);
 
        /* We must cancel any work here before unregistering from ieee80211,
         * as the ieee80211 unreg will destroy the workqueue. */
@@ -5042,14 +5080,14 @@ static void b43_ssb_remove(struct ssb_device *dev)
                ieee80211_unregister_hw(wl->hw);
        }
 
-       b43_one_core_detach(dev);
+       b43_one_core_detach(wldev->dev);
 
        if (list_empty(&wl->devlist)) {
                b43_leds_unregister(wl);
                /* Last core on the chip unregistered.
                 * We can destroy common struct b43_wl.
                 */
-               b43_wireless_exit(dev, wl);
+               b43_wireless_exit(wldev->dev, wl);
        }
 }
 
@@ -5108,14 +5146,23 @@ static int __init b43_init(void)
        err = b43_sdio_init();
        if (err)
                goto err_pcmcia_exit;
-       err = ssb_driver_register(&b43_ssb_driver);
+#ifdef CONFIG_B43_BCMA
+       err = bcma_driver_register(&b43_bcma_driver);
        if (err)
                goto err_sdio_exit;
+#endif
+       err = ssb_driver_register(&b43_ssb_driver);
+       if (err)
+               goto err_bcma_driver_exit;
        b43_print_driverinfo();
 
        return err;
 
+err_bcma_driver_exit:
+#ifdef CONFIG_B43_BCMA
+       bcma_driver_unregister(&b43_bcma_driver);
 err_sdio_exit:
+#endif
        b43_sdio_exit();
 err_pcmcia_exit:
        b43_pcmcia_exit();
@@ -5127,6 +5174,9 @@ err_dfs_exit:
 static void __exit b43_exit(void)
 {
        ssb_driver_unregister(&b43_ssb_driver);
+#ifdef CONFIG_B43_BCMA
+       bcma_driver_unregister(&b43_bcma_driver);
+#endif
        b43_sdio_exit();
        b43_pcmcia_exit();
        b43_debugfs_exit();
index a0d327f..e4ebce9 100644 (file)
@@ -121,7 +121,7 @@ void b43_hf_write(struct b43_wldev *dev, u64 value);
 
 void b43_dummy_transmission(struct b43_wldev *dev, bool ofdm, bool pa_on);
 
-void b43_wireless_core_reset(struct b43_wldev *dev, u32 flags);
+void b43_wireless_core_reset(struct b43_wldev *dev, bool gmode);
 
 void b43_controller_restart(struct b43_wldev *dev, const char *reason);
 
index b01c8ce..73ace55 100644 (file)
@@ -265,7 +265,6 @@ static void hardware_pctl_init_aphy(struct b43_wldev *dev)
 
 void b43_phy_inita(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy *phy = &dev->phy;
 
        /* This lowlevel A-PHY init is also called from G-PHY init.
@@ -296,9 +295,9 @@ void b43_phy_inita(struct b43_wldev *dev)
 
                b43_radio_init2060(dev);
 
-               if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
-                   ((bus->boardinfo.type == SSB_BOARD_BU4306) ||
-                    (bus->boardinfo.type == SSB_BOARD_BU4309))) {
+               if ((dev->dev->board_vendor == SSB_BOARDVENDOR_BCM) &&
+                   ((dev->dev->board_type == SSB_BOARD_BU4306) ||
+                    (dev->dev->board_type == SSB_BOARD_BU4309))) {
                        ; //TODO: A PHY LO
                }
 
@@ -311,7 +310,7 @@ void b43_phy_inita(struct b43_wldev *dev)
        }
 
        if ((phy->type == B43_PHYTYPE_G) &&
-           (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) {
+           (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL)) {
                b43_phy_maskset(dev, B43_PHY_OFDM(0x6E), 0xE000, 0x3CF);
        }
 }
@@ -323,17 +322,17 @@ static int b43_aphy_init_tssi2dbm_table(struct b43_wldev *dev)
        struct b43_phy_a *aphy = phy->a;
        s16 pab0, pab1, pab2;
 
-       pab0 = (s16) (dev->sdev->bus->sprom.pa1b0);
-       pab1 = (s16) (dev->sdev->bus->sprom.pa1b1);
-       pab2 = (s16) (dev->sdev->bus->sprom.pa1b2);
+       pab0 = (s16) (dev->dev->bus_sprom->pa1b0);
+       pab1 = (s16) (dev->dev->bus_sprom->pa1b1);
+       pab2 = (s16) (dev->dev->bus_sprom->pa1b2);
 
        if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
            pab0 != -1 && pab1 != -1 && pab2 != -1) {
                /* The pabX values are set in SPROM. Use them. */
-               if ((s8) dev->sdev->bus->sprom.itssi_a != 0 &&
-                   (s8) dev->sdev->bus->sprom.itssi_a != -1)
+               if ((s8) dev->dev->bus_sprom->itssi_a != 0 &&
+                   (s8) dev->dev->bus_sprom->itssi_a != -1)
                        aphy->tgt_idle_tssi =
-                           (s8) (dev->sdev->bus->sprom.itssi_a);
+                           (s8) (dev->dev->bus_sprom->itssi_a);
                else
                        aphy->tgt_idle_tssi = 62;
                aphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0,
index e46b2f4..425af28 100644 (file)
@@ -168,7 +168,7 @@ void b43_phy_lock(struct b43_wldev *dev)
        B43_WARN_ON(dev->phy.phy_locked);
        dev->phy.phy_locked = 1;
 #endif
-       B43_WARN_ON(dev->sdev->id.revision < 3);
+       B43_WARN_ON(dev->dev->core_rev < 3);
 
        if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))
                b43_power_saving_ctl_bits(dev, B43_PS_AWAKE);
@@ -180,7 +180,7 @@ void b43_phy_unlock(struct b43_wldev *dev)
        B43_WARN_ON(!dev->phy.phy_locked);
        dev->phy.phy_locked = 0;
 #endif
-       B43_WARN_ON(dev->sdev->id.revision < 3);
+       B43_WARN_ON(dev->dev->core_rev < 3);
 
        if (!b43_is_mode(dev->wl, NL80211_IFTYPE_AP))
                b43_power_saving_ctl_bits(dev, 0);
@@ -368,8 +368,8 @@ void b43_phy_txpower_check(struct b43_wldev *dev, unsigned int flags)
        /* The next check will be needed in two seconds, or later. */
        phy->next_txpwr_check_time = round_jiffies(now + (HZ * 2));
 
-       if ((dev->sdev->bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
-           (dev->sdev->bus->boardinfo.type == SSB_BOARD_BU4306))
+       if ((dev->dev->board_vendor == SSB_BOARDVENDOR_BCM) &&
+           (dev->dev->board_type == SSB_BOARD_BU4306))
                return; /* No software txpower adjustment needed */
 
        result = phy->ops->recalc_txpower(dev, !!(flags & B43_TXPWR_IGNORE_TSSI));
index 1758a28..83532d1 100644 (file)
@@ -718,7 +718,7 @@ static void b43_calc_nrssi_threshold(struct b43_wldev *dev)
        B43_WARN_ON(phy->type != B43_PHYTYPE_G);
 
        if (!phy->gmode ||
-           !(dev->sdev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
+           !(dev->dev->bus_sprom->boardflags_lo & B43_BFL_RSSI)) {
                tmp16 = b43_nrssi_hw_read(dev, 0x20);
                if (tmp16 >= 0x20)
                        tmp16 -= 0x40;
@@ -1114,7 +1114,7 @@ static u16 radio2050_rfover_val(struct b43_wldev *dev,
 {
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_g *gphy = phy->g;
-       struct ssb_sprom *sprom = &(dev->sdev->bus->sprom);
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
 
        if (!phy->gmode)
                return 0;
@@ -1491,7 +1491,6 @@ static u16 b43_radio_init2050(struct b43_wldev *dev)
 
 static void b43_phy_initb5(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_g *gphy = phy->g;
        u16 offset, value;
@@ -1500,8 +1499,8 @@ static void b43_phy_initb5(struct b43_wldev *dev)
        if (phy->analog == 1) {
                b43_radio_set(dev, 0x007A, 0x0050);
        }
-       if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) &&
-           (bus->boardinfo.type != SSB_BOARD_BU4306)) {
+       if ((dev->dev->board_vendor != SSB_BOARDVENDOR_BCM) &&
+           (dev->dev->board_type != SSB_BOARD_BU4306)) {
                value = 0x2120;
                for (offset = 0x00A8; offset < 0x00C7; offset++) {
                        b43_phy_write(dev, offset, value);
@@ -1620,7 +1619,7 @@ static void b43_phy_initb6(struct b43_wldev *dev)
                b43_radio_write16(dev, 0x5A, 0x88);
                b43_radio_write16(dev, 0x5B, 0x6B);
                b43_radio_write16(dev, 0x5C, 0x0F);
-               if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_ALTIQ) {
+               if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_ALTIQ) {
                        b43_radio_write16(dev, 0x5D, 0xFA);
                        b43_radio_write16(dev, 0x5E, 0xD8);
                } else {
@@ -1787,7 +1786,7 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
        b43_phy_set(dev, B43_PHY_RFOVER, 0x0100);
        b43_phy_mask(dev, B43_PHY_RFOVERVAL, 0xCFFF);
 
-       if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) {
+       if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_EXTLNA) {
                if (phy->rev >= 7) {
                        b43_phy_set(dev, B43_PHY_RFOVER, 0x0800);
                        b43_phy_set(dev, B43_PHY_RFOVERVAL, 0x8000);
@@ -1922,7 +1921,6 @@ static void b43_hardware_pctl_init_gphy(struct b43_wldev *dev)
 /* Initialize B/G PHY power control */
 static void b43_phy_init_pctl(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_g *gphy = phy->g;
        struct b43_rfatt old_rfatt;
@@ -1931,8 +1929,8 @@ static void b43_phy_init_pctl(struct b43_wldev *dev)
 
        B43_WARN_ON(phy->type != B43_PHYTYPE_G);
 
-       if ((bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM) &&
-           (bus->boardinfo.type == SSB_BOARD_BU4306))
+       if ((dev->dev->board_vendor == SSB_BOARDVENDOR_BCM) &&
+           (dev->dev->board_type == SSB_BOARD_BU4306))
                return;
 
        b43_phy_write(dev, 0x0028, 0x8018);
@@ -2053,7 +2051,7 @@ static void b43_phy_initg(struct b43_wldev *dev)
        if (phy->rev >= 6) {
                b43_phy_maskset(dev, B43_PHY_CCK(0x36), 0x0FFF, (gphy->lo_control->tx_bias << 12));
        }
-       if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
+       if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL)
                b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
        else
                b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x807F);
@@ -2066,7 +2064,7 @@ static void b43_phy_initg(struct b43_wldev *dev)
                b43_phy_write(dev, B43_PHY_LO_MASK, 0x8078);
        }
 
-       if (!(dev->sdev->bus->sprom.boardflags_lo & B43_BFL_RSSI)) {
+       if (!(dev->dev->bus_sprom->boardflags_lo & B43_BFL_RSSI)) {
                /* The specs state to update the NRSSI LT with
                 * the value 0x7FFFFFFF here. I think that is some weird
                 * compiler optimization in the original driver.
@@ -2088,8 +2086,8 @@ static void b43_phy_initg(struct b43_wldev *dev)
        /* FIXME: The spec says in the following if, the 0 should be replaced
           'if OFDM may not be used in the current locale'
           but OFDM is legal everywhere */
-       if ((dev->sdev->bus->chip_id == 0x4306
-            && dev->sdev->bus->chip_package == 2) || 0) {
+       if ((dev->dev->chip_id == 0x4306
+            && dev->dev->chip_pkg == 2) || 0) {
                b43_phy_mask(dev, B43_PHY_CRS0, 0xBFFF);
                b43_phy_mask(dev, B43_PHY_OFDM(0xC3), 0x7FFF);
        }
@@ -2105,7 +2103,7 @@ void b43_gphy_channel_switch(struct b43_wldev *dev,
        b43_write16(dev, B43_MMIO_CHANNEL, channel2freq_bg(channel));
 
        if (channel == 14) {
-               if (dev->sdev->bus->sprom.country_code ==
+               if (dev->dev->bus_sprom->country_code ==
                    SSB_SPROM1CCODE_JAPAN)
                        b43_hf_write(dev,
                                     b43_hf_read(dev) & ~B43_HF_ACPR);
@@ -2136,17 +2134,17 @@ static void default_baseband_attenuation(struct b43_wldev *dev,
 static void default_radio_attenuation(struct b43_wldev *dev,
                                      struct b43_rfatt *rf)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
+       struct b43_bus_dev *bdev = dev->dev;
        struct b43_phy *phy = &dev->phy;
 
        rf->with_padmix = 0;
 
-       if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
-           bus->boardinfo.type == SSB_BOARD_BCM4309G) {
-               if (bus->boardinfo.rev < 0x43) {
+       if (dev->dev->board_vendor == SSB_BOARDVENDOR_BCM &&
+           dev->dev->board_type == SSB_BOARD_BCM4309G) {
+               if (dev->dev->board_rev < 0x43) {
                        rf->att = 2;
                        return;
-               } else if (bus->boardinfo.rev < 0x51) {
+               } else if (dev->dev->board_rev < 0x51) {
                        rf->att = 3;
                        return;
                }
@@ -2172,21 +2170,21 @@ static void default_radio_attenuation(struct b43_wldev *dev,
                        return;
                case 1:
                        if (phy->type == B43_PHYTYPE_G) {
-                               if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
-                                   && bus->boardinfo.type == SSB_BOARD_BCM4309G
-                                   && bus->boardinfo.rev >= 30)
+                               if (bdev->board_vendor == SSB_BOARDVENDOR_BCM
+                                   && bdev->board_type == SSB_BOARD_BCM4309G
+                                   && bdev->board_rev >= 30)
                                        rf->att = 3;
-                               else if (bus->boardinfo.vendor ==
+                               else if (bdev->board_vendor ==
                                         SSB_BOARDVENDOR_BCM
-                                        && bus->boardinfo.type ==
+                                        && bdev->board_type ==
                                         SSB_BOARD_BU4306)
                                        rf->att = 3;
                                else
                                        rf->att = 1;
                        } else {
-                               if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
-                                   && bus->boardinfo.type == SSB_BOARD_BCM4309G
-                                   && bus->boardinfo.rev >= 30)
+                               if (bdev->board_vendor == SSB_BOARDVENDOR_BCM
+                                   && bdev->board_type == SSB_BOARD_BCM4309G
+                                   && bdev->board_rev >= 30)
                                        rf->att = 7;
                                else
                                        rf->att = 6;
@@ -2194,16 +2192,16 @@ static void default_radio_attenuation(struct b43_wldev *dev,
                        return;
                case 2:
                        if (phy->type == B43_PHYTYPE_G) {
-                               if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM
-                                   && bus->boardinfo.type == SSB_BOARD_BCM4309G
-                                   && bus->boardinfo.rev >= 30)
+                               if (bdev->board_vendor == SSB_BOARDVENDOR_BCM
+                                   && bdev->board_type == SSB_BOARD_BCM4309G
+                                   && bdev->board_rev >= 30)
                                        rf->att = 3;
-                               else if (bus->boardinfo.vendor ==
+                               else if (bdev->board_vendor ==
                                         SSB_BOARDVENDOR_BCM
-                                        && bus->boardinfo.type ==
+                                        && bdev->board_type ==
                                         SSB_BOARD_BU4306)
                                        rf->att = 5;
-                               else if (bus->chip_id == 0x4320)
+                               else if (bdev->chip_id == 0x4320)
                                        rf->att = 4;
                                else
                                        rf->att = 3;
@@ -2384,11 +2382,11 @@ static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev)
        struct b43_phy_g *gphy = phy->g;
        s16 pab0, pab1, pab2;
 
-       pab0 = (s16) (dev->sdev->bus->sprom.pa0b0);
-       pab1 = (s16) (dev->sdev->bus->sprom.pa0b1);
-       pab2 = (s16) (dev->sdev->bus->sprom.pa0b2);
+       pab0 = (s16) (dev->dev->bus_sprom->pa0b0);
+       pab1 = (s16) (dev->dev->bus_sprom->pa0b1);
+       pab2 = (s16) (dev->dev->bus_sprom->pa0b2);
 
-       B43_WARN_ON((dev->sdev->bus->chip_id == 0x4301) &&
+       B43_WARN_ON((dev->dev->chip_id == 0x4301) &&
                    (phy->radio_ver != 0x2050)); /* Not supported anymore */
 
        gphy->dyn_tssi_tbl = 0;
@@ -2396,10 +2394,10 @@ static int b43_gphy_init_tssi2dbm_table(struct b43_wldev *dev)
        if (pab0 != 0 && pab1 != 0 && pab2 != 0 &&
            pab0 != -1 && pab1 != -1 && pab2 != -1) {
                /* The pabX values are set in SPROM. Use them. */
-               if ((s8) dev->sdev->bus->sprom.itssi_bg != 0 &&
-                   (s8) dev->sdev->bus->sprom.itssi_bg != -1) {
+               if ((s8) dev->dev->bus_sprom->itssi_bg != 0 &&
+                   (s8) dev->dev->bus_sprom->itssi_bg != -1) {
                        gphy->tgt_idle_tssi =
-                               (s8) (dev->sdev->bus->sprom.itssi_bg);
+                               (s8) (dev->dev->bus_sprom->itssi_bg);
                } else
                        gphy->tgt_idle_tssi = 62;
                gphy->tssi2dbm = b43_generate_dyn_tssi2dbm_tab(dev, pab0,
@@ -2537,7 +2535,7 @@ static int b43_gphy_op_prepare_hardware(struct b43_wldev *dev)
                b43_wireless_core_reset(dev, 0);
                b43_phy_initg(dev);
                phy->gmode = 1;
-               b43_wireless_core_reset(dev, B43_TMSLOW_GMODE);
+               b43_wireless_core_reset(dev, 1);
        }
 
        return 0;
@@ -2840,7 +2838,7 @@ static void b43_gphy_op_adjust_txpower(struct b43_wldev *dev)
                                    B43_TXCTL_TXMIX;
                                rfatt += 2;
                                bbatt += 2;
-                       } else if (dev->sdev->bus->sprom.
+                       } else if (dev->dev->bus_sprom->
                                   boardflags_lo &
                                   B43_BFL_PACTRL) {
                                bbatt += 4 * (rfatt - 2);
@@ -2914,14 +2912,14 @@ static enum b43_txpwr_result b43_gphy_op_recalc_txpower(struct b43_wldev *dev,
        estimated_pwr = b43_gphy_estimate_power_out(dev, average_tssi);
 
        B43_WARN_ON(phy->type != B43_PHYTYPE_G);
-       max_pwr = dev->sdev->bus->sprom.maxpwr_bg;
-       if (dev->sdev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
+       max_pwr = dev->dev->bus_sprom->maxpwr_bg;
+       if (dev->dev->bus_sprom->boardflags_lo & B43_BFL_PACTRL)
                max_pwr -= 3; /* minus 0.75 */
        if (unlikely(max_pwr >= INT_TO_Q52(30/*dBm*/))) {
                b43warn(dev->wl,
                        "Invalid max-TX-power value in SPROM.\n");
                max_pwr = INT_TO_Q52(20); /* fake it */
-               dev->sdev->bus->sprom.maxpwr_bg = max_pwr;
+               dev->dev->bus_sprom->maxpwr_bg = max_pwr;
        }
 
        /* Get desired power (in Q5.2) */
@@ -3014,7 +3012,7 @@ static void b43_gphy_op_pwork_60sec(struct b43_wldev *dev)
 {
        struct b43_phy *phy = &dev->phy;
 
-       if (!(dev->sdev->bus->sprom.boardflags_lo & B43_BFL_RSSI))
+       if (!(dev->dev->bus_sprom->boardflags_lo & B43_BFL_RSSI))
                return;
 
        b43_mac_suspend(dev);
index 012c8da..daec1d9 100644 (file)
@@ -85,39 +85,39 @@ static void b43_lpphy_op_free(struct b43_wldev *dev)
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/LP/ReadBandSrom */
 static void lpphy_read_band_sprom(struct b43_wldev *dev)
 {
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
        struct b43_phy_lp *lpphy = dev->phy.lp;
-       struct ssb_bus *bus = dev->sdev->bus;
        u16 cckpo, maxpwr;
        u32 ofdmpo;
        int i;
 
        if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
-               lpphy->tx_isolation_med_band = bus->sprom.tri2g;
-               lpphy->bx_arch = bus->sprom.bxa2g;
-               lpphy->rx_pwr_offset = bus->sprom.rxpo2g;
-               lpphy->rssi_vf = bus->sprom.rssismf2g;
-               lpphy->rssi_vc = bus->sprom.rssismc2g;
-               lpphy->rssi_gs = bus->sprom.rssisav2g;
-               lpphy->txpa[0] = bus->sprom.pa0b0;
-               lpphy->txpa[1] = bus->sprom.pa0b1;
-               lpphy->txpa[2] = bus->sprom.pa0b2;
-               maxpwr = bus->sprom.maxpwr_bg;
+               lpphy->tx_isolation_med_band = sprom->tri2g;
+               lpphy->bx_arch = sprom->bxa2g;
+               lpphy->rx_pwr_offset = sprom->rxpo2g;
+               lpphy->rssi_vf = sprom->rssismf2g;
+               lpphy->rssi_vc = sprom->rssismc2g;
+               lpphy->rssi_gs = sprom->rssisav2g;
+               lpphy->txpa[0] = sprom->pa0b0;
+               lpphy->txpa[1] = sprom->pa0b1;
+               lpphy->txpa[2] = sprom->pa0b2;
+               maxpwr = sprom->maxpwr_bg;
                lpphy->max_tx_pwr_med_band = maxpwr;
-               cckpo = bus->sprom.cck2gpo;
+               cckpo = sprom->cck2gpo;
                /*
                 * We don't read SPROM's opo as specs say. On rev8 SPROMs
                 * opo == ofdm2gpo and we don't know any SSB with LP-PHY
                 * and SPROM rev below 8.
                 */
-               B43_WARN_ON(bus->sprom.revision < 8);
-               ofdmpo = bus->sprom.ofdm2gpo;
+               B43_WARN_ON(sprom->revision < 8);
+               ofdmpo = sprom->ofdm2gpo;
                if (cckpo) {
                        for (i = 0; i < 4; i++) {
                                lpphy->tx_max_rate[i] =
                                        maxpwr - (ofdmpo & 0xF) * 2;
                                ofdmpo >>= 4;
                        }
-                       ofdmpo = bus->sprom.ofdm2gpo;
+                       ofdmpo = sprom->ofdm2gpo;
                        for (i = 4; i < 15; i++) {
                                lpphy->tx_max_rate[i] =
                                        maxpwr - (ofdmpo & 0xF) * 2;
@@ -131,39 +131,39 @@ static void lpphy_read_band_sprom(struct b43_wldev *dev)
                                lpphy->tx_max_rate[i] = maxpwr - ofdmpo;
                }
        } else { /* 5GHz */
-               lpphy->tx_isolation_low_band = bus->sprom.tri5gl;
-               lpphy->tx_isolation_med_band = bus->sprom.tri5g;
-               lpphy->tx_isolation_hi_band = bus->sprom.tri5gh;
-               lpphy->bx_arch = bus->sprom.bxa5g;
-               lpphy->rx_pwr_offset = bus->sprom.rxpo5g;
-               lpphy->rssi_vf = bus->sprom.rssismf5g;
-               lpphy->rssi_vc = bus->sprom.rssismc5g;
-               lpphy->rssi_gs = bus->sprom.rssisav5g;
-               lpphy->txpa[0] = bus->sprom.pa1b0;
-               lpphy->txpa[1] = bus->sprom.pa1b1;
-               lpphy->txpa[2] = bus->sprom.pa1b2;
-               lpphy->txpal[0] = bus->sprom.pa1lob0;
-               lpphy->txpal[1] = bus->sprom.pa1lob1;
-               lpphy->txpal[2] = bus->sprom.pa1lob2;
-               lpphy->txpah[0] = bus->sprom.pa1hib0;
-               lpphy->txpah[1] = bus->sprom.pa1hib1;
-               lpphy->txpah[2] = bus->sprom.pa1hib2;
-               maxpwr = bus->sprom.maxpwr_al;
-               ofdmpo = bus->sprom.ofdm5glpo;
+               lpphy->tx_isolation_low_band = sprom->tri5gl;
+               lpphy->tx_isolation_med_band = sprom->tri5g;
+               lpphy->tx_isolation_hi_band = sprom->tri5gh;
+               lpphy->bx_arch = sprom->bxa5g;
+               lpphy->rx_pwr_offset = sprom->rxpo5g;
+               lpphy->rssi_vf = sprom->rssismf5g;
+               lpphy->rssi_vc = sprom->rssismc5g;
+               lpphy->rssi_gs = sprom->rssisav5g;
+               lpphy->txpa[0] = sprom->pa1b0;
+               lpphy->txpa[1] = sprom->pa1b1;
+               lpphy->txpa[2] = sprom->pa1b2;
+               lpphy->txpal[0] = sprom->pa1lob0;
+               lpphy->txpal[1] = sprom->pa1lob1;
+               lpphy->txpal[2] = sprom->pa1lob2;
+               lpphy->txpah[0] = sprom->pa1hib0;
+               lpphy->txpah[1] = sprom->pa1hib1;
+               lpphy->txpah[2] = sprom->pa1hib2;
+               maxpwr = sprom->maxpwr_al;
+               ofdmpo = sprom->ofdm5glpo;
                lpphy->max_tx_pwr_low_band = maxpwr;
                for (i = 4; i < 12; i++) {
                        lpphy->tx_max_ratel[i] = maxpwr - (ofdmpo & 0xF) * 2;
                        ofdmpo >>= 4;
                }
-               maxpwr = bus->sprom.maxpwr_a;
-               ofdmpo = bus->sprom.ofdm5gpo;
+               maxpwr = sprom->maxpwr_a;
+               ofdmpo = sprom->ofdm5gpo;
                lpphy->max_tx_pwr_med_band = maxpwr;
                for (i = 4; i < 12; i++) {
                        lpphy->tx_max_rate[i] = maxpwr - (ofdmpo & 0xF) * 2;
                        ofdmpo >>= 4;
                }
-               maxpwr = bus->sprom.maxpwr_ah;
-               ofdmpo = bus->sprom.ofdm5ghpo;
+               maxpwr = sprom->maxpwr_ah;
+               ofdmpo = sprom->ofdm5ghpo;
                lpphy->max_tx_pwr_hi_band = maxpwr;
                for (i = 4; i < 12; i++) {
                        lpphy->tx_max_rateh[i] = maxpwr - (ofdmpo & 0xF) * 2;
@@ -214,7 +214,8 @@ static void lpphy_table_init(struct b43_wldev *dev)
 
 static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
+       struct ssb_bus *bus = dev->dev->sdev->bus;
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
        struct b43_phy_lp *lpphy = dev->phy.lp;
        u16 tmp, tmp2;
 
@@ -242,9 +243,9 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
        b43_phy_maskset(dev, B43_LPPHY_CRS_ED_THRESH, 0x00FF, 0xAD00);
        b43_phy_maskset(dev, B43_LPPHY_INPUT_PWRDB,
                        0xFF00, lpphy->rx_pwr_offset);
-       if ((bus->sprom.boardflags_lo & B43_BFL_FEM) &&
+       if ((sprom->boardflags_lo & B43_BFL_FEM) &&
           ((b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ||
-          (bus->sprom.boardflags_hi & B43_BFH_PAREF))) {
+          (sprom->boardflags_hi & B43_BFH_PAREF))) {
                ssb_pmu_set_ldo_voltage(&bus->chipco, LDO_PAREF, 0x28);
                ssb_pmu_set_ldo_paref(&bus->chipco, true);
                if (dev->phy.rev == 0) {
@@ -260,7 +261,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
        }
        tmp = lpphy->rssi_vf | lpphy->rssi_vc << 4 | 0xA000;
        b43_phy_write(dev, B43_LPPHY_AFE_RSSI_CTL_0, tmp);
-       if (bus->sprom.boardflags_hi & B43_BFH_RSSIINV)
+       if (sprom->boardflags_hi & B43_BFH_RSSIINV)
                b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x0AAA);
        else
                b43_phy_maskset(dev, B43_LPPHY_AFE_RSSI_CTL_1, 0xF000, 0x02AA);
@@ -268,7 +269,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
        b43_phy_maskset(dev, B43_LPPHY_RX_RADIO_CTL,
                        0xFFF9, (lpphy->bx_arch << 1));
        if (dev->phy.rev == 1 &&
-          (bus->sprom.boardflags_hi & B43_BFH_FEM_BT)) {
+          (sprom->boardflags_hi & B43_BFH_FEM_BT)) {
                b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x000A);
                b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0x3F00, 0x0900);
                b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x000A);
@@ -286,8 +287,8 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
                b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xFFC0, 0x000A);
                b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_8, 0xC0FF, 0x0B00);
        } else if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ ||
-                 (bus->boardinfo.type == 0x048A) || ((dev->phy.rev == 0) &&
-                 (bus->sprom.boardflags_lo & B43_BFL_FEM))) {
+                 (dev->dev->board_type == 0x048A) || ((dev->phy.rev == 0) &&
+                 (sprom->boardflags_lo & B43_BFL_FEM))) {
                b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0001);
                b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0400);
                b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0001);
@@ -297,7 +298,7 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
                b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0002);
                b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0A00);
        } else if (dev->phy.rev == 1 ||
-                 (bus->sprom.boardflags_lo & B43_BFL_FEM)) {
+                 (sprom->boardflags_lo & B43_BFL_FEM)) {
                b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xFFC0, 0x0004);
                b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_1, 0xC0FF, 0x0800);
                b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_2, 0xFFC0, 0x0004);
@@ -316,15 +317,15 @@ static void lpphy_baseband_rev0_1_init(struct b43_wldev *dev)
                b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xFFC0, 0x0006);
                b43_phy_maskset(dev, B43_LPPHY_TR_LOOKUP_4, 0xC0FF, 0x0700);
        }
-       if (dev->phy.rev == 1 && (bus->sprom.boardflags_hi & B43_BFH_PAREF)) {
+       if (dev->phy.rev == 1 && (sprom->boardflags_hi & B43_BFH_PAREF)) {
                b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_5, B43_LPPHY_TR_LOOKUP_1);
                b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_6, B43_LPPHY_TR_LOOKUP_2);
                b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_7, B43_LPPHY_TR_LOOKUP_3);
                b43_phy_copy(dev, B43_LPPHY_TR_LOOKUP_8, B43_LPPHY_TR_LOOKUP_4);
        }
-       if ((bus->sprom.boardflags_hi & B43_BFH_FEM_BT) &&
-           (bus->chip_id == 0x5354) &&
-           (bus->chip_package == SSB_CHIPPACK_BCM4712S)) {
+       if ((sprom->boardflags_hi & B43_BFH_FEM_BT) &&
+           (dev->dev->chip_id == 0x5354) &&
+           (dev->dev->chip_pkg == SSB_CHIPPACK_BCM4712S)) {
                b43_phy_set(dev, B43_LPPHY_CRSGAIN_CTL, 0x0006);
                b43_phy_write(dev, B43_LPPHY_GPIO_SELECT, 0x0005);
                b43_phy_write(dev, B43_LPPHY_GPIO_OUTEN, 0xFFFF);
@@ -412,7 +413,6 @@ static void lpphy_restore_dig_flt_state(struct b43_wldev *dev)
 
 static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
        struct b43_phy_lp *lpphy = dev->phy.lp;
 
        b43_phy_write(dev, B43_LPPHY_AFE_DAC_CTL, 0x50);
@@ -432,7 +432,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
        b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x4000);
        b43_phy_mask(dev, B43_LPPHY_CRSGAIN_CTL, ~0x2000);
        b43_phy_set(dev, B43_PHY_OFDM(0x10A), 0x1);
-       if (bus->boardinfo.rev >= 0x18) {
+       if (dev->dev->board_rev >= 0x18) {
                b43_lptab_write(dev, B43_LPTAB32(17, 65), 0xEC);
                b43_phy_maskset(dev, B43_PHY_OFDM(0x10A), 0xFF01, 0x14);
        } else {
@@ -449,7 +449,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
        b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFC1F, 0xA0);
        b43_phy_maskset(dev, B43_LPPHY_GAINDIRECTMISMATCH, 0xE0FF, 0x300);
        b43_phy_maskset(dev, B43_LPPHY_HIGAINDB, 0x00FF, 0x2A00);
-       if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) {
+       if ((dev->dev->chip_id == 0x4325) && (dev->dev->chip_rev == 0)) {
                b43_phy_maskset(dev, B43_LPPHY_LOWGAINDB, 0x00FF, 0x2100);
                b43_phy_maskset(dev, B43_LPPHY_VERYLOWGAINDB, 0xFF00, 0xA);
        } else {
@@ -467,7 +467,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
        b43_phy_maskset(dev, B43_LPPHY_CLIPCTRTHRESH, 0xFFE0, 0x12);
        b43_phy_maskset(dev, B43_LPPHY_GAINMISMATCH, 0x0FFF, 0x9000);
 
-       if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) {
+       if ((dev->dev->chip_id == 0x4325) && (dev->dev->chip_rev == 0)) {
                b43_lptab_write(dev, B43_LPTAB16(0x08, 0x14), 0);
                b43_lptab_write(dev, B43_LPTAB16(0x08, 0x12), 0x40);
        }
@@ -492,7 +492,7 @@ static void lpphy_baseband_rev2plus_init(struct b43_wldev *dev)
                      0x2000 | ((u16)lpphy->rssi_gs << 10) |
                      ((u16)lpphy->rssi_vc << 4) | lpphy->rssi_vf);
 
-       if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) {
+       if ((dev->dev->chip_id == 0x4325) && (dev->dev->chip_rev == 0)) {
                b43_phy_set(dev, B43_LPPHY_AFE_ADC_CTL_0, 0x1C);
                b43_phy_maskset(dev, B43_LPPHY_AFE_CTL, 0x00FF, 0x8800);
                b43_phy_maskset(dev, B43_LPPHY_AFE_ADC_CTL_1, 0xFC3C, 0x0400);
@@ -519,7 +519,7 @@ struct b2062_freqdata {
 static void lpphy_2062_init(struct b43_wldev *dev)
 {
        struct b43_phy_lp *lpphy = dev->phy.lp;
-       struct ssb_bus *bus = dev->sdev->bus;
+       struct ssb_bus *bus = dev->dev->sdev->bus;
        u32 crystalfreq, tmp, ref;
        unsigned int i;
        const struct b2062_freqdata *fd = NULL;
@@ -697,7 +697,7 @@ static void lpphy_radio_init(struct b43_wldev *dev)
                lpphy_sync_stx(dev);
                b43_phy_write(dev, B43_PHY_OFDM(0xF0), 0x5F80);
                b43_phy_write(dev, B43_PHY_OFDM(0xF1), 0);
-               if (dev->sdev->bus->chip_id == 0x4325) {
+               if (dev->dev->chip_id == 0x4325) {
                        // TODO SSB PMU recalibration
                }
        }
@@ -1289,7 +1289,7 @@ finish:
 
 static void lpphy_rev2plus_rc_calib(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
+       struct ssb_bus *bus = dev->dev->sdev->bus;
        u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
        u8 tmp = b43_radio_read(dev, B2063_RX_BB_SP8) & 0xFF;
        int i;
@@ -1840,7 +1840,6 @@ static void lpphy_papd_cal(struct b43_wldev *dev, struct lpphy_tx_gains gains,
 static void lpphy_papd_cal_txpwr(struct b43_wldev *dev)
 {
        struct b43_phy_lp *lpphy = dev->phy.lp;
-       struct ssb_bus *bus = dev->sdev->bus;
        struct lpphy_tx_gains gains, oldgains;
        int old_txpctl, old_afe_ovr, old_rf, old_bbmult;
 
@@ -1854,7 +1853,7 @@ static void lpphy_papd_cal_txpwr(struct b43_wldev *dev)
 
        lpphy_set_tx_power_control(dev, B43_LPPHY_TXPCTL_OFF);
 
-       if (bus->chip_id == 0x4325 && bus->chip_rev == 0)
+       if (dev->dev->chip_id == 0x4325 && dev->dev->chip_rev == 0)
                lpphy_papd_cal(dev, gains, 0, 1, 30);
        else
                lpphy_papd_cal(dev, gains, 0, 1, 65);
@@ -1870,7 +1869,6 @@ static int lpphy_rx_iq_cal(struct b43_wldev *dev, bool noise, bool tx,
                            bool rx, bool pa, struct lpphy_tx_gains *gains)
 {
        struct b43_phy_lp *lpphy = dev->phy.lp;
-       struct ssb_bus *bus = dev->sdev->bus;
        const struct lpphy_rx_iq_comp *iqcomp = NULL;
        struct lpphy_tx_gains nogains, oldgains;
        u16 tmp;
@@ -1879,7 +1877,7 @@ static int lpphy_rx_iq_cal(struct b43_wldev *dev, bool noise, bool tx,
        memset(&nogains, 0, sizeof(nogains));
        memset(&oldgains, 0, sizeof(oldgains));
 
-       if (bus->chip_id == 0x5354) {
+       if (dev->dev->chip_id == 0x5354) {
                for (i = 0; i < ARRAY_SIZE(lpphy_5354_iq_table); i++) {
                        if (lpphy_5354_iq_table[i].chan == lpphy->channel) {
                                iqcomp = &lpphy_5354_iq_table[i];
@@ -2408,11 +2406,9 @@ static const struct b206x_channel b2063_chantbl[] = {
 
 static void lpphy_b2062_reset_pll_bias(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
-
        b43_radio_write(dev, B2062_S_RFPLL_CTL2, 0xFF);
        udelay(20);
-       if (bus->chip_id == 0x5354) {
+       if (dev->dev->chip_id == 0x5354) {
                b43_radio_write(dev, B2062_N_COMM1, 4);
                b43_radio_write(dev, B2062_S_RFPLL_CTL2, 4);
        } else {
@@ -2432,7 +2428,7 @@ static int lpphy_b2062_tune(struct b43_wldev *dev,
                            unsigned int channel)
 {
        struct b43_phy_lp *lpphy = dev->phy.lp;
-       struct ssb_bus *bus = dev->sdev->bus;
+       struct ssb_bus *bus = dev->dev->sdev->bus;
        const struct b206x_channel *chandata = NULL;
        u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
        u32 tmp1, tmp2, tmp3, tmp4, tmp5, tmp6, tmp7, tmp8, tmp9;
@@ -2522,7 +2518,7 @@ static void lpphy_b2063_vco_calib(struct b43_wldev *dev)
 static int lpphy_b2063_tune(struct b43_wldev *dev,
                            unsigned int channel)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
+       struct ssb_bus *bus = dev->dev->sdev->bus;
 
        static const struct b206x_channel *chandata = NULL;
        u32 crystal_freq = bus->chipco.pmu.crystalfreq * 1000;
@@ -2670,6 +2666,11 @@ static int b43_lpphy_op_init(struct b43_wldev *dev)
 {
        int err;
 
+       if (dev->dev->bus_type != B43_BUS_SSB) {
+               b43err(dev->wl, "LP-PHY is supported only on SSB!\n");
+               return -EOPNOTSUPP;
+       }
+
        lpphy_read_band_sprom(dev); //FIXME should this be in prepare_structs?
        lpphy_baseband_init(dev);
        lpphy_radio_init(dev);
index 9ed6515..ad14f3b 100644 (file)
@@ -299,7 +299,7 @@ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
 static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
 {
        struct b43_phy_n *nphy = dev->phy.n;
-       struct ssb_sprom *sprom = &(dev->sdev->bus->sprom);
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
 
        u8 txpi[2], bbmult, i;
        u16 tmp, radio_gain, dac_gain;
@@ -423,16 +423,15 @@ static void b43_radio_init2055_pre(struct b43_wldev *dev)
 static void b43_radio_init2055_post(struct b43_wldev *dev)
 {
        struct b43_phy_n *nphy = dev->phy.n;
-       struct ssb_sprom *sprom = &(dev->sdev->bus->sprom);
-       struct ssb_boardinfo *binfo = &(dev->sdev->bus->boardinfo);
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
        int i;
        u16 val;
        bool workaround = false;
 
        if (sprom->revision < 4)
-               workaround = (binfo->vendor != PCI_VENDOR_ID_BROADCOM &&
-                               binfo->type == 0x46D &&
-                               binfo->rev >= 0x41);
+               workaround = (dev->dev->board_vendor != PCI_VENDOR_ID_BROADCOM
+                             && dev->dev->board_type == 0x46D
+                             && dev->dev->board_rev >= 0x41);
        else
                workaround =
                        !(sprom->boardflags2_lo & B43_BFL2_RXBB_INT_REG_DIS);
@@ -983,7 +982,7 @@ static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val)
 {
        u16 tmp;
 
-       if (dev->sdev->id.revision == 16)
+       if (dev->dev->core_rev == 16)
                b43_mac_suspend(dev);
 
        tmp = b43_phy_read(dev, B43_NPHY_CLASSCTL);
@@ -993,7 +992,7 @@ static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val)
        tmp |= (val & mask);
        b43_phy_maskset(dev, B43_NPHY_CLASSCTL, 0xFFF8, tmp);
 
-       if (dev->sdev->id.revision == 16)
+       if (dev->dev->core_rev == 16)
                b43_mac_enable(dev);
 
        return tmp;
@@ -1168,7 +1167,7 @@ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev)
 static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
 {
        struct b43_phy_n *nphy = dev->phy.n;
-       struct ssb_sprom *sprom = &(dev->sdev->bus->sprom);
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
 
        /* PHY rev 0, 1, 2 */
        u8 i, j;
@@ -1373,7 +1372,7 @@ static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
 /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Workarounds */
 static void b43_nphy_workarounds(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_n *nphy = phy->n;
 
@@ -1443,9 +1442,9 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)
 
                /* N PHY WAR TX Chain Update with hw_phytxchain as argument */
 
-               if ((bus->sprom.boardflags2_lo & B43_BFL2_APLL_WAR &&
+               if ((sprom->boardflags2_lo & B43_BFL2_APLL_WAR &&
                    b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ||
-                   (bus->sprom.boardflags2_lo & B43_BFL2_GPLL_WAR &&
+                   (sprom->boardflags2_lo & B43_BFL2_GPLL_WAR &&
                    b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ))
                        tmp32 = 0x00088888;
                else
@@ -1503,8 +1502,8 @@ static void b43_nphy_workarounds(struct b43_wldev *dev)
                b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
                b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
 
-               if (bus->sprom.boardflags2_lo & 0x100 &&
-                   bus->boardinfo.type == 0x8B) {
+               if (sprom->boardflags2_lo & 0x100 &&
+                   dev->dev->board_type == 0x8B) {
                        delays1[0] = 0x1;
                        delays1[5] = 0x14;
                }
@@ -3093,7 +3092,7 @@ static int b43_nphy_cal_tx_iq_lo(struct b43_wldev *dev,
        int freq;
        bool avoid = false;
        u8 length;
-       u16 tmp, core, type, count, max, numb, last, cmd;
+       u16 tmp, core, type, count, max, numb, last = 0, cmd;
        const u16 *table;
        bool phy6or5x;
 
@@ -3586,7 +3585,7 @@ static void b43_nphy_set_rx_core_state(struct b43_wldev *dev, u8 mask)
  */
 int b43_phy_initn(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_n *nphy = phy->n;
        u8 tx_pwr_state;
@@ -3599,7 +3598,7 @@ int b43_phy_initn(struct b43_wldev *dev)
        bool do_cal = false;
 
        if ((dev->phy.rev >= 3) &&
-          (bus->sprom.boardflags_lo & B43_BFL_EXTLNA) &&
+          (sprom->boardflags_lo & B43_BFL_EXTLNA) &&
           (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)) {
                chipco_set32(&dev->sdev->bus->chipco, SSB_CHIPCO_CHIPCTL, 0x40);
        }
@@ -3639,9 +3638,9 @@ int b43_phy_initn(struct b43_wldev *dev)
        b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_20M, 0x20);
        b43_phy_write(dev, B43_NPHY_AFESEQ_TX2RX_PUD_40M, 0x20);
 
-       if (bus->sprom.boardflags2_lo & 0x100 ||
-           (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
-            bus->boardinfo.type == 0x8B))
+       if (sprom->boardflags2_lo & 0x100 ||
+           (dev->dev->board_vendor == PCI_VENDOR_ID_APPLE &&
+            dev->dev->board_type == 0x8B))
                b43_phy_write(dev, B43_NPHY_TXREALFD, 0xA0);
        else
                b43_phy_write(dev, B43_NPHY_TXREALFD, 0xB8);
index 72ab94d..44da620 100644 (file)
@@ -111,7 +111,7 @@ static u16 index_to_pioqueue_base(struct b43_wldev *dev,
                B43_MMIO_PIO11_BASE5,
        };
 
-       if (dev->sdev->id.revision >= 11) {
+       if (dev->dev->core_rev >= 11) {
                B43_WARN_ON(index >= ARRAY_SIZE(bases_rev11));
                return bases_rev11[index];
        }
@@ -121,14 +121,14 @@ static u16 index_to_pioqueue_base(struct b43_wldev *dev,
 
 static u16 pio_txqueue_offset(struct b43_wldev *dev)
 {
-       if (dev->sdev->id.revision >= 11)
+       if (dev->dev->core_rev >= 11)
                return 0x18;
        return 0;
 }
 
 static u16 pio_rxqueue_offset(struct b43_wldev *dev)
 {
-       if (dev->sdev->id.revision >= 11)
+       if (dev->dev->core_rev >= 11)
                return 0x38;
        return 8;
 }
@@ -144,7 +144,7 @@ static struct b43_pio_txqueue *b43_setup_pioqueue_tx(struct b43_wldev *dev,
        if (!q)
                return NULL;
        q->dev = dev;
-       q->rev = dev->sdev->id.revision;
+       q->rev = dev->dev->core_rev;
        q->mmio_base = index_to_pioqueue_base(dev, index) +
                       pio_txqueue_offset(dev);
        q->index = index;
@@ -178,7 +178,7 @@ static struct b43_pio_rxqueue *b43_setup_pioqueue_rx(struct b43_wldev *dev,
        if (!q)
                return NULL;
        q->dev = dev;
-       q->rev = dev->sdev->id.revision;
+       q->rev = dev->dev->core_rev;
        q->mmio_base = index_to_pioqueue_base(dev, index) +
                       pio_rxqueue_offset(dev);
 
index a617efe..59c3afe 100644 (file)
@@ -37,17 +37,16 @@ void b43_rfkill_poll(struct ieee80211_hw *hw)
 {
        struct b43_wl *wl = hw_to_b43_wl(hw);
        struct b43_wldev *dev = wl->current_dev;
-       struct ssb_bus *bus = dev->sdev->bus;
        bool enabled;
        bool brought_up = false;
 
        mutex_lock(&wl->mutex);
        if (unlikely(b43_status(dev) < B43_STAT_INITIALIZED)) {
-               if (ssb_bus_powerup(bus, 0)) {
+               if (b43_bus_powerup(dev, 0)) {
                        mutex_unlock(&wl->mutex);
                        return;
                }
-               ssb_device_enable(dev->sdev, 0);
+               b43_device_enable(dev, 0);
                brought_up = true;
        }
 
@@ -63,8 +62,8 @@ void b43_rfkill_poll(struct ieee80211_hw *hw)
        }
 
        if (brought_up) {
-               ssb_device_disable(dev->sdev, 0);
-               ssb_bus_may_powerdown(bus);
+               b43_device_disable(dev, 0);
+               b43_bus_may_powerdown(dev);
        }
 
        mutex_unlock(&wl->mutex);
index 808e25b..e6c733d 100644 (file)
@@ -66,7 +66,7 @@ static void b43_sdio_interrupt_dispatcher(struct sdio_func *func)
 int b43_sdio_request_irq(struct b43_wldev *dev,
                         void (*handler)(struct b43_wldev *dev))
 {
-       struct ssb_bus *bus = dev->sdev->bus;
+       struct ssb_bus *bus = dev->dev->sdev->bus;
        struct sdio_func *func = bus->host_sdio;
        struct b43_sdio *sdio = sdio_get_drvdata(func);
        int err;
@@ -82,7 +82,7 @@ int b43_sdio_request_irq(struct b43_wldev *dev,
 
 void b43_sdio_free_irq(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
+       struct ssb_bus *bus = dev->dev->sdev->bus;
        struct sdio_func *func = bus->host_sdio;
        struct b43_sdio *sdio = sdio_get_drvdata(func);
 
index 57af619..f1ae4e0 100644 (file)
@@ -140,7 +140,7 @@ static DEVICE_ATTR(interference, 0644,
 
 int b43_sysfs_register(struct b43_wldev *wldev)
 {
-       struct device *dev = wldev->sdev->dev;
+       struct device *dev = wldev->dev->dev;
 
        B43_WARN_ON(b43_status(wldev) != B43_STAT_INITIALIZED);
 
@@ -149,7 +149,7 @@ int b43_sysfs_register(struct b43_wldev *wldev)
 
 void b43_sysfs_unregister(struct b43_wldev *wldev)
 {
-       struct device *dev = wldev->sdev->dev;
+       struct device *dev = wldev->dev->dev;
 
        device_remove_file(dev, &dev_attr_interference);
 }
index 59df3c6..6748c5a 100644 (file)
@@ -2304,7 +2304,6 @@ void lpphy_rev0_1_table_init(struct b43_wldev *dev)
 
 void lpphy_rev2plus_table_init(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
        int i;
 
        B43_WARN_ON(dev->phy.rev < 2);
@@ -2341,7 +2340,7 @@ void lpphy_rev2plus_table_init(struct b43_wldev *dev)
        b43_lptab_write_bulk(dev, B43_LPTAB32(10, 0),
                ARRAY_SIZE(lpphy_papd_mult_table), lpphy_papd_mult_table);
 
-       if ((bus->chip_id == 0x4325) && (bus->chip_rev == 0)) {
+       if ((dev->dev->chip_id == 0x4325) && (dev->dev->chip_rev == 0)) {
                b43_lptab_write_bulk(dev, B43_LPTAB32(13, 0),
                        ARRAY_SIZE(lpphy_a0_gain_idx_table), lpphy_a0_gain_idx_table);
                b43_lptab_write_bulk(dev, B43_LPTAB16(14, 0),
@@ -2416,12 +2415,12 @@ void lpphy_write_gain_table_bulk(struct b43_wldev *dev, int offset, int count,
 
 void lpphy_init_tx_gain_table(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
 
        switch (dev->phy.rev) {
        case 0:
-               if ((bus->sprom.boardflags_hi & B43_BFH_NOPA) ||
-                   (bus->sprom.boardflags_lo & B43_BFL_HGPA))
+               if ((sprom->boardflags_hi & B43_BFH_NOPA) ||
+                   (sprom->boardflags_lo & B43_BFL_HGPA))
                        lpphy_write_gain_table_bulk(dev, 0, 128,
                                        lpphy_rev0_nopa_tx_gain_table);
                else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
@@ -2432,8 +2431,8 @@ void lpphy_init_tx_gain_table(struct b43_wldev *dev)
                                        lpphy_rev0_5ghz_tx_gain_table);
                break;
        case 1:
-               if ((bus->sprom.boardflags_hi & B43_BFH_NOPA) ||
-                   (bus->sprom.boardflags_lo & B43_BFL_HGPA))
+               if ((sprom->boardflags_hi & B43_BFH_NOPA) ||
+                   (sprom->boardflags_lo & B43_BFL_HGPA))
                        lpphy_write_gain_table_bulk(dev, 0, 128,
                                        lpphy_rev1_nopa_tx_gain_table);
                else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
@@ -2444,7 +2443,7 @@ void lpphy_init_tx_gain_table(struct b43_wldev *dev)
                                        lpphy_rev1_5ghz_tx_gain_table);
                break;
        default:
-               if (bus->sprom.boardflags_hi & B43_BFH_NOPA)
+               if (sprom->boardflags_hi & B43_BFH_NOPA)
                        lpphy_write_gain_table_bulk(dev, 0, 128,
                                        lpphy_rev2_nopa_tx_gain_table);
                else if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
index 8f4db44..5d00d0e 100644 (file)
@@ -458,17 +458,15 @@ static void b43_wa_rssi_adc(struct b43_wldev *dev)
 
 static void b43_wa_boards_a(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
-
-       if (bus->boardinfo.vendor == SSB_BOARDVENDOR_BCM &&
-           bus->boardinfo.type == SSB_BOARD_BU4306 &&
-           bus->boardinfo.rev < 0x30) {
+       if (dev->dev->board_vendor == SSB_BOARDVENDOR_BCM &&
+           dev->dev->board_type == SSB_BOARD_BU4306 &&
+           dev->dev->board_rev < 0x30) {
                b43_phy_write(dev, 0x0010, 0xE000);
                b43_phy_write(dev, 0x0013, 0x0140);
                b43_phy_write(dev, 0x0014, 0x0280);
        } else {
-               if (bus->boardinfo.type == SSB_BOARD_MP4318 &&
-                   bus->boardinfo.rev < 0x20) {
+               if (dev->dev->board_type == SSB_BOARD_MP4318 &&
+                   dev->dev->board_rev < 0x20) {
                        b43_phy_write(dev, 0x0013, 0x0210);
                        b43_phy_write(dev, 0x0014, 0x0840);
                } else {
@@ -486,19 +484,19 @@ static void b43_wa_boards_a(struct b43_wldev *dev)
 
 static void b43_wa_boards_g(struct b43_wldev *dev)
 {
-       struct ssb_bus *bus = dev->sdev->bus;
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
        struct b43_phy *phy = &dev->phy;
 
-       if (bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM ||
-           bus->boardinfo.type != SSB_BOARD_BU4306 ||
-           bus->boardinfo.rev != 0x17) {
+       if (dev->dev->board_vendor != SSB_BOARDVENDOR_BCM ||
+           dev->dev->board_type != SSB_BOARD_BU4306 ||
+           dev->dev->board_rev != 0x17) {
                if (phy->rev < 2) {
                        b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 1, 0x0002);
                        b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX_R1, 2, 0x0001);
                } else {
                        b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 1, 0x0002);
                        b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 2, 0x0001);
-                       if ((bus->sprom.boardflags_lo & B43_BFL_EXTLNA) &&
+                       if ((sprom->boardflags_lo & B43_BFL_EXTLNA) &&
                            (phy->rev >= 7)) {
                                b43_phy_mask(dev, B43_PHY_EXTG(0x11), 0xF7FF);
                                b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0020, 0x0001);
@@ -510,7 +508,7 @@ static void b43_wa_boards_g(struct b43_wldev *dev)
                        }
                }
        }
-       if (bus->sprom.boardflags_lo & B43_BFL_FEM) {
+       if (sprom->boardflags_lo & B43_BFL_FEM) {
                b43_phy_write(dev, B43_PHY_GTABCTL, 0x3120);
                b43_phy_write(dev, B43_PHY_GTABDATA, 0xC480);
        }
index c8f99ae..488b898 100644 (file)
@@ -547,7 +547,7 @@ static s8 b43_rssi_postprocess(struct b43_wldev *dev,
                        else
                                tmp -= 3;
                } else {
-                       if (dev->sdev->bus->sprom.
+                       if (dev->dev->bus_sprom->
                            boardflags_lo & B43_BFL_RSSI) {
                                if (in_rssi > 63)
                                        in_rssi = 63;
index e03e01d..c33934a 100644 (file)
@@ -817,14 +817,13 @@ static void dmacontroller_cleanup(struct b43legacy_dmaring *ring)
 
 static void free_all_descbuffers(struct b43legacy_dmaring *ring)
 {
-       struct b43legacy_dmadesc_generic *desc;
        struct b43legacy_dmadesc_meta *meta;
        int i;
 
        if (!ring->used_slots)
                return;
        for (i = 0; i < ring->nr_slots; i++) {
-               desc = ring->ops->idx2desc(ring, i, &meta);
+               ring->ops->idx2desc(ring, i, &meta);
 
                if (!meta->skb) {
                        B43legacy_WARN_ON(!ring->tx);
@@ -1371,10 +1370,8 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev,
                     struct sk_buff *skb)
 {
        struct b43legacy_dmaring *ring;
-       struct ieee80211_hdr *hdr;
        int err = 0;
        unsigned long flags;
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
 
        ring = priority_to_txring(dev, skb_get_queue_mapping(skb));
        spin_lock_irqsave(&ring->lock, flags);
@@ -1401,8 +1398,6 @@ int b43legacy_dma_tx(struct b43legacy_wldev *dev,
 
        /* dma_tx_fragment might reallocate the skb, so invalidate pointers pointing
         * into the skb data or cb now. */
-       hdr = NULL;
-       info = NULL;
        err = dma_tx_fragment(ring, &skb);
        if (unlikely(err == -ENOKEY)) {
                /* Drop this packet, as we don't have the encryption key
@@ -1435,7 +1430,6 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
 {
        const struct b43legacy_dma_ops *ops;
        struct b43legacy_dmaring *ring;
-       struct b43legacy_dmadesc_generic *desc;
        struct b43legacy_dmadesc_meta *meta;
        int retry_limit;
        int slot;
@@ -1450,7 +1444,7 @@ void b43legacy_dma_handle_txstatus(struct b43legacy_wldev *dev,
        ops = ring->ops;
        while (1) {
                B43legacy_WARN_ON(!(slot >= 0 && slot < ring->nr_slots));
-               desc = ops->idx2desc(ring, slot, &meta);
+               ops->idx2desc(ring, slot, &meta);
 
                if (meta->skb)
                        unmap_descbuffer(ring, meta->dmaaddr,
index 1ab8861..d6db6c1 100644 (file)
@@ -1564,10 +1564,10 @@ static int b43legacy_request_firmware(struct b43legacy_wldev *dev)
        struct b43legacy_firmware *fw = &dev->fw;
        const u8 rev = dev->dev->id.revision;
        const char *filename;
-       u32 tmshigh;
        int err;
 
-       tmshigh = ssb_read32(dev->dev, SSB_TMSHIGH);
+       /* do dummy read */
+       ssb_read32(dev->dev, SSB_TMSHIGH);
        if (!fw->ucode) {
                if (rev == 2)
                        filename = "ucode2";
@@ -2634,11 +2634,9 @@ static int b43legacy_op_dev_config(struct ieee80211_hw *hw,
        unsigned long flags;
        unsigned int new_phymode = 0xFFFF;
        int antenna_tx;
-       int antenna_rx;
        int err = 0;
 
        antenna_tx = B43legacy_ANTENNA_DEFAULT;
-       antenna_rx = B43legacy_ANTENNA_DEFAULT;
 
        mutex_lock(&wl->mutex);
        dev = wl->current_dev;
@@ -2775,14 +2773,12 @@ static void b43legacy_op_bss_info_changed(struct ieee80211_hw *hw,
 {
        struct b43legacy_wl *wl = hw_to_b43legacy_wl(hw);
        struct b43legacy_wldev *dev;
-       struct b43legacy_phy *phy;
        unsigned long flags;
 
        mutex_lock(&wl->mutex);
        B43legacy_WARN_ON(wl->vif != vif);
 
        dev = wl->current_dev;
-       phy = &dev->phy;
 
        /* Disable IRQs while reconfiguring the device.
         * This makes it possible to drop the spinlock throughout
@@ -2974,7 +2970,7 @@ static int b43legacy_phy_versioning(struct b43legacy_wldev *dev)
                break;
        default:
                unsupported = 1;
-       };
+       }
        if (unsupported) {
                b43legacyerr(dev->wl, "FOUND UNSUPPORTED PHY "
                       "(Analog %u, Type %u, Revision %u)\n",
index 3a95541..6c174f3 100644 (file)
@@ -321,11 +321,9 @@ static int generate_txhdr_fw3(struct b43legacy_wldev *dev,
                struct ieee80211_hdr *hdr;
                int rts_rate;
                int rts_rate_fb;
-               int rts_rate_ofdm;
                int rts_rate_fb_ofdm;
 
                rts_rate = ieee80211_get_rts_cts_rate(dev->wl->hw, info)->hw_value;
-               rts_rate_ofdm = b43legacy_is_ofdm_rate(rts_rate);
                rts_rate_fb = b43legacy_calc_fallback_rate(rts_rate);
                rts_rate_fb_ofdm = b43legacy_is_ofdm_rate(rts_rate_fb);
                if (rts_rate_fb_ofdm)
index 88dc6a5..7bb0b4b 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef HOSTAP_WLAN_H
 #define HOSTAP_WLAN_H
 
+#include <linux/interrupt.h>
 #include <linux/wireless.h>
 #include <linux/netdevice.h>
 #include <linux/mutex.h>
index 91795b5..ecb561d 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/module.h>
 #include <linux/moduleparam.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/mutex.h>
 
 #include <linux/pci.h>
index d7bd6cf..6623e50 100644 (file)
@@ -30,6 +30,7 @@
 
 ******************************************************************************/
 
+#include <linux/hardirq.h>
 #include <linux/kmod.h>
 #include <linux/slab.h>
 #include <linux/module.h>
index 7e5e85a..a7a4739 100644 (file)
@@ -628,11 +628,11 @@ void iwl4965_rx_reply_rx(struct iwl_priv *priv,
 
        /* rx_status carries information about the packet to mac80211 */
        rx_status.mactime = le64_to_cpu(phy_res->timestamp);
+       rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
+                               IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
        rx_status.freq =
                ieee80211_channel_to_frequency(le16_to_cpu(phy_res->channel),
                                                        rx_status.band);
-       rx_status.band = (phy_res->phy_flags & RX_RES_PHY_FLAGS_BAND_24_MSK) ?
-                               IEEE80211_BAND_2GHZ : IEEE80211_BAND_5GHZ;
        rx_status.rate_idx =
                iwl4965_hwrate_to_mac80211_idx(rate_n_flags, rx_status.band);
        rx_status.flag = 0;
index 24d1499..9b65153 100644 (file)
@@ -2275,6 +2275,9 @@ iwl4965_rs_get_rate(void *priv_r, struct ieee80211_sta *sta, void *priv_sta,
        if (rate_control_send_low(sta, priv_sta, txrc))
                return;
 
+       if (!lq_sta)
+               return;
+
        rate_idx  = lq_sta->last_txrate_idx;
 
        if (lq_sta->last_rate_n_flags & RATE_MCS_HT_MSK) {
index f5433c7..3a022bc 100644 (file)
@@ -496,7 +496,7 @@ static s32 iwl4965_get_tx_atten_grp(u16 channel)
            channel <= CALIB_IWL_TX_ATTEN_GR4_LCH)
                return CALIB_CH_GROUP_4;
 
-       return -1;
+       return -EINVAL;
 }
 
 static u32 iwl4965_get_sub_band(const struct iwl_priv *priv, u32 channel)
@@ -915,7 +915,7 @@ static int iwl4965_fill_txpower_tbl(struct iwl_priv *priv, u8 band, u16 channel,
        if (txatten_grp < 0) {
                IWL_ERR(priv, "Can't find txatten group for channel %d.\n",
                          channel);
-               return -EINVAL;
+               return txatten_grp;
        }
 
        IWL_DEBUG_TXPOWER(priv, "channel %d belongs to txatten group %d\n",
@@ -1185,8 +1185,6 @@ static int iwl4965_send_rxon_assoc(struct iwl_priv *priv,
 
        ret = iwl_legacy_send_cmd_pdu_async(priv, REPLY_RXON_ASSOC,
                                     sizeof(rxon_assoc), &rxon_assoc, NULL);
-       if (ret)
-               return ret;
 
        return ret;
 }
@@ -1237,7 +1235,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *c
 
                memcpy(active_rxon, &ctx->staging, sizeof(*active_rxon));
                iwl_legacy_print_rx_config_cmd(priv, ctx);
-               return 0;
+               goto set_tx_power;
        }
 
        /* If we are currently associated and the new config requires
@@ -1317,6 +1315,7 @@ static int iwl4965_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *c
 
        iwl4965_init_sensitivity(priv);
 
+set_tx_power:
        /* If we issue a new RXON command which required a tune then we must
         * send a new TXPOWER command or we won't be able to Tx any frames */
        ret = iwl_legacy_set_tx_power(priv, priv->tx_power_next, true);
@@ -1543,7 +1542,7 @@ static void iwl4965_temperature_calib(struct iwl_priv *priv)
        s32 temp;
 
        temp = iwl4965_hw_get_temperature(priv);
-       if (temp < 0)
+       if (IWL_TX_POWER_TEMPERATURE_OUT_OF_RANGE(temp))
                return;
 
        if (priv->temperature != temp) {
index be0106c..416448a 100644 (file)
@@ -32,6 +32,7 @@
 #ifndef __iwl_legacy_dev_h__
 #define __iwl_legacy_dev_h__
 
+#include <linux/interrupt.h>
 #include <linux/pci.h> /* for struct pci_device_id */
 #include <linux/kernel.h>
 #include <linux/leds.h>
index cb346d1..5bf3f49 100644 (file)
@@ -316,7 +316,6 @@ static void iwl_legacy_init_band_reference(const struct iwl_priv *priv,
                break;
        default:
                BUG();
-               return;
        }
 }
 
index 61d4a11..7aa240e 100644 (file)
@@ -174,7 +174,6 @@ static struct iwl_lib_ops iwl1000_lib = {
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_setup_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-       .send_tx_power = iwlagn_send_tx_power,
        .update_chain_flags = iwl_update_chain_flags,
        .apm_ops = {
                .init = iwl_apm_init,
@@ -223,6 +222,7 @@ static struct iwl_base_params iwl1000_base_params = {
 static struct iwl_ht_params iwl1000_ht_params = {
        .ht_greenfield_support = true,
        .use_rts_for_aggregation = true, /* use rts/cts protection */
+       .smps_mode = IEEE80211_SMPS_STATIC,
 };
 
 #define IWL_DEVICE_1000                                                \
index 86feec8..5484ab7 100644 (file)
@@ -177,88 +177,13 @@ static int iwl2000_hw_set_hw_params(struct iwl_priv *priv)
        return 0;
 }
 
-static int iwl2030_hw_channel_switch(struct iwl_priv *priv,
-                                    struct ieee80211_channel_switch *ch_switch)
-{
-       /*
-        * MULTI-FIXME
-        * See iwl_mac_channel_switch.
-        */
-       struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
-       struct iwl6000_channel_switch_cmd cmd;
-       const struct iwl_channel_info *ch_info;
-       u32 switch_time_in_usec, ucode_switch_time;
-       u16 ch;
-       u32 tsf_low;
-       u8 switch_count;
-       u16 beacon_interval = le16_to_cpu(ctx->timing.beacon_interval);
-       struct ieee80211_vif *vif = ctx->vif;
-       struct iwl_host_cmd hcmd = {
-               .id = REPLY_CHANNEL_SWITCH,
-               .len = { sizeof(cmd), },
-               .flags = CMD_SYNC,
-               .data = { &cmd, },
-       };
-
-       cmd.band = priv->band == IEEE80211_BAND_2GHZ;
-       ch = ch_switch->channel->hw_value;
-       IWL_DEBUG_11H(priv, "channel switch from %u to %u\n",
-               ctx->active.channel, ch);
-       cmd.channel = cpu_to_le16(ch);
-       cmd.rxon_flags = ctx->staging.flags;
-       cmd.rxon_filter_flags = ctx->staging.filter_flags;
-       switch_count = ch_switch->count;
-       tsf_low = ch_switch->timestamp & 0x0ffffffff;
-       /*
-        * calculate the ucode channel switch time
-        * adding TSF as one of the factor for when to switch
-        */
-       if ((priv->ucode_beacon_time > tsf_low) && beacon_interval) {
-               if (switch_count > ((priv->ucode_beacon_time - tsf_low) /
-                   beacon_interval)) {
-                       switch_count -= (priv->ucode_beacon_time -
-                               tsf_low) / beacon_interval;
-               } else
-                       switch_count = 0;
-       }
-       if (switch_count <= 1)
-               cmd.switch_time = cpu_to_le32(priv->ucode_beacon_time);
-       else {
-               switch_time_in_usec =
-                       vif->bss_conf.beacon_int * switch_count * TIME_UNIT;
-               ucode_switch_time = iwl_usecs_to_beacons(priv,
-                                               switch_time_in_usec,
-                                               beacon_interval);
-               cmd.switch_time = iwl_add_beacon_time(priv,
-                                               priv->ucode_beacon_time,
-                                               ucode_switch_time,
-                                               beacon_interval);
-       }
-       IWL_DEBUG_11H(priv, "uCode time for the switch is 0x%x\n",
-                     cmd.switch_time);
-       ch_info = iwl_get_channel_info(priv, priv->band, ch);
-       if (ch_info)
-               cmd.expect_beacon = is_channel_radar(ch_info);
-       else {
-               IWL_ERR(priv, "invalid channel switch from %u to %u\n",
-                       ctx->active.channel, ch);
-               return -EFAULT;
-       }
-       priv->switch_rxon.channel = cmd.channel;
-       priv->switch_rxon.switch_in_progress = true;
-
-       return iwl_send_cmd_sync(priv, &hcmd);
-}
-
 static struct iwl_lib_ops iwl2000_lib = {
        .set_hw_params = iwl2000_hw_set_hw_params,
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_bt_setup_deferred_work,
        .cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-       .send_tx_power = iwlagn_send_tx_power,
        .update_chain_flags = iwl_update_chain_flags,
-       .set_channel_switch = iwl2030_hw_channel_switch,
        .apm_ops = {
                .init = iwl_apm_init,
                .config = iwl2000_nic_config,
index a70b8cf..4353a65 100644 (file)
@@ -331,8 +331,6 @@ static int iwl5000_hw_channel_switch(struct iwl_priv *priv,
                        ctx->active.channel, ch);
                return -EFAULT;
        }
-       priv->switch_rxon.channel = cmd.channel;
-       priv->switch_rxon.switch_in_progress = true;
 
        return iwl_send_cmd_sync(priv, &hcmd);
 }
@@ -342,7 +340,6 @@ static struct iwl_lib_ops iwl5000_lib = {
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_setup_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-       .send_tx_power = iwlagn_send_tx_power,
        .update_chain_flags = iwl_update_chain_flags,
        .set_channel_switch = iwl5000_hw_channel_switch,
        .apm_ops = {
@@ -373,7 +370,6 @@ static struct iwl_lib_ops iwl5150_lib = {
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_setup_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-       .send_tx_power = iwlagn_send_tx_power,
        .update_chain_flags = iwl_update_chain_flags,
        .set_channel_switch = iwl5000_hw_channel_switch,
        .apm_ops = {
@@ -425,7 +421,6 @@ static struct iwl_base_params iwl5000_base_params = {
 };
 static struct iwl_ht_params iwl5000_ht_params = {
        .ht_greenfield_support = true,
-       .use_rts_for_aggregation = true, /* use rts/cts protection */
 };
 
 #define IWL_DEVICE_5000                                                \
index f8c710d..6e5ce44 100644 (file)
@@ -270,8 +270,6 @@ static int iwl6000_hw_channel_switch(struct iwl_priv *priv,
                        ctx->active.channel, ch);
                return -EFAULT;
        }
-       priv->switch_rxon.channel = cmd.channel;
-       priv->switch_rxon.switch_in_progress = true;
 
        return iwl_send_cmd_sync(priv, &hcmd);
 }
@@ -281,7 +279,6 @@ static struct iwl_lib_ops iwl6000_lib = {
        .rx_handler_setup = iwlagn_rx_handler_setup,
        .setup_deferred_work = iwlagn_setup_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-       .send_tx_power = iwlagn_send_tx_power,
        .update_chain_flags = iwl_update_chain_flags,
        .set_channel_switch = iwl6000_hw_channel_switch,
        .apm_ops = {
@@ -314,7 +311,6 @@ static struct iwl_lib_ops iwl6030_lib = {
        .setup_deferred_work = iwlagn_bt_setup_deferred_work,
        .cancel_deferred_work = iwlagn_bt_cancel_deferred_work,
        .is_valid_rtc_data_addr = iwlagn_hw_valid_rtc_data_addr,
-       .send_tx_power = iwlagn_send_tx_power,
        .update_chain_flags = iwl_update_chain_flags,
        .set_channel_switch = iwl6000_hw_channel_switch,
        .apm_ops = {
@@ -603,19 +599,27 @@ struct iwl_cfg iwl6050_2abg_cfg = {
        IWL_DEVICE_6050,
 };
 
+#define IWL_DEVICE_6150                                                \
+       .fw_name_pre = IWL6050_FW_PRE,                          \
+       .ucode_api_max = IWL6050_UCODE_API_MAX,                 \
+       .ucode_api_min = IWL6050_UCODE_API_MIN,                 \
+       .ops = &iwl6150_ops,                                    \
+       .eeprom_ver = EEPROM_6150_EEPROM_VERSION,               \
+       .eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION,       \
+       .base_params = &iwl6050_base_params,                    \
+       .need_dc_calib = true,                                  \
+       .led_mode = IWL_LED_BLINK,                              \
+       .internal_wimax_coex = true
+
 struct iwl_cfg iwl6150_bgn_cfg = {
        .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,
-       .eeprom_ver = EEPROM_6150_EEPROM_VERSION,
-       .eeprom_calib_ver = EEPROM_6150_TX_POWER_VERSION,
-       .ops = &iwl6150_ops,
-       .base_params = &iwl6050_base_params,
+       IWL_DEVICE_6150,
        .ht_params = &iwl6000_ht_params,
-       .need_dc_calib = true,
-       .led_mode = IWL_LED_RF_STATE,
-       .internal_wimax_coex = true,
+};
+
+struct iwl_cfg iwl6150_bg_cfg = {
+       .name = "Intel(R) Centrino(R) Wireless-N + WiMAX 6150 BG",
+       IWL_DEVICE_6150,
 };
 
 struct iwl_cfg iwl6000_3agn_cfg = {
index b12c72d..23eee0c 100644 (file)
@@ -163,17 +163,9 @@ static void iwlagn_tx_cmd_protection(struct iwl_priv *priv,
                                     __le16 fc, __le32 *tx_flags)
 {
        if (info->control.rates[0].flags & IEEE80211_TX_RC_USE_RTS_CTS ||
-           info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT) {
+           info->control.rates[0].flags & IEEE80211_TX_RC_USE_CTS_PROTECT ||
+           info->flags & IEEE80211_TX_CTL_AMPDU)
                *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
-               return;
-       }
-
-       if (priv->cfg->ht_params &&
-           priv->cfg->ht_params->use_rts_for_aggregation &&
-           info->flags & IEEE80211_TX_CTL_AMPDU) {
-               *tx_flags |= TX_CMD_FLG_PROT_REQUIRE_MSK;
-               return;
-       }
 }
 
 /* Calc max signal level (dBm) among 3 possible receivers */
@@ -310,7 +302,6 @@ static int iwlagn_set_pan_params(struct iwl_priv *priv)
 }
 
 struct iwl_hcmd_ops iwlagn_hcmd = {
-       .commit_rxon = iwlagn_commit_rxon,
        .set_rxon_chain = iwlagn_set_rxon_chain,
        .set_tx_ant = iwlagn_send_tx_ant_config,
        .send_bt_config = iwl_send_bt_config,
@@ -318,7 +309,6 @@ struct iwl_hcmd_ops iwlagn_hcmd = {
 };
 
 struct iwl_hcmd_ops iwlagn_bt_hcmd = {
-       .commit_rxon = iwlagn_commit_rxon,
        .set_rxon_chain = iwlagn_set_rxon_chain,
        .set_tx_ant = iwlagn_send_tx_ant_config,
        .send_bt_config = iwlagn_send_advance_bt_config,
@@ -332,5 +322,4 @@ struct iwl_hcmd_utils_ops iwlagn_hcmd_utils = {
        .tx_cmd_protection = iwlagn_tx_cmd_protection,
        .calc_rssi = iwlagn_calc_rssi,
        .request_scan = iwlagn_request_scan,
-       .post_scan = iwlagn_post_scan,
 };
index f803fb6..677f73c 100644 (file)
@@ -408,9 +408,9 @@ static void iwlagn_rx_reply_tx(struct iwl_priv *priv,
        unsigned long flags;
 
        if ((index >= txq->q.n_bd) || (iwl_queue_used(&txq->q, index) == 0)) {
-               IWL_ERR(priv, "Read index for DMA queue txq_id (%d) index %d "
-                         "is out of range [0-%d] %d %d\n", txq_id,
-                         index, txq->q.n_bd, txq->q.write_ptr,
+               IWL_ERR(priv, "%s: Read index for DMA queue txq_id (%d) "
+                         "index %d is out of range [0-%d] %d %d\n", __func__,
+                         txq_id, index, txq->q.n_bd, txq->q.write_ptr,
                          txq->q.read_ptr);
                return;
        }
@@ -1797,6 +1797,7 @@ static void iwlagn_bt_traffic_change_work(struct work_struct *work)
                priv->cfg->ops->lib->update_chain_flags(priv);
 
        if (smps_request != -1) {
+               priv->current_ht_config.smps = smps_request;
                for_each_context(priv, ctx) {
                        if (ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION)
                                ieee80211_request_smps(ctx->vif, smps_request);
index 592b0cf..85e0828 100644 (file)
@@ -426,7 +426,7 @@ static int rs_tl_turn_on_agg_for_tid(struct iwl_priv *priv,
                        ieee80211_stop_tx_ba_session(sta, tid);
                }
        } else {
-               IWL_ERR(priv, "Aggregation not enabled for tid %d "
+               IWL_DEBUG_HT(priv, "Aggregation not enabled for tid %d "
                        "because load = %u\n", tid, load);
        }
        return ret;
index a95ad84..a7c66c4 100644 (file)
@@ -81,6 +81,21 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
        return ret;
 }
 
+static int iwlagn_disconn_pan(struct iwl_priv *priv,
+                             struct iwl_rxon_context *ctx,
+                             struct iwl_rxon_cmd *send)
+{
+       __le32 old_filter = send->filter_flags;
+       int ret;
+
+       send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
+       ret = iwl_send_cmd_pdu(priv, ctx->rxon_cmd, sizeof(*send), send);
+
+       send->filter_flags = old_filter;
+
+       return ret;
+}
+
 static void iwlagn_update_qos(struct iwl_priv *priv,
                              struct iwl_rxon_context *ctx)
 {
@@ -163,9 +178,6 @@ static int iwlagn_send_rxon_assoc(struct iwl_priv *priv,
 
        ret = iwl_send_cmd_pdu_async(priv, ctx->rxon_assoc_cmd,
                                     sizeof(rxon_assoc), &rxon_assoc, NULL);
-       if (ret)
-               return ret;
-
        return ret;
 }
 
@@ -175,10 +187,21 @@ static int iwlagn_rxon_disconn(struct iwl_priv *priv,
        int ret;
        struct iwl_rxon_cmd *active = (void *)&ctx->active;
 
-       if (ctx->ctxid == IWL_RXON_CTX_BSS)
+       if (ctx->ctxid == IWL_RXON_CTX_BSS) {
                ret = iwlagn_disable_bss(priv, ctx, &ctx->staging);
-       else
+       } else {
                ret = iwlagn_disable_pan(priv, ctx, &ctx->staging);
+               if (ret)
+                       return ret;
+               if (ctx->vif) {
+                       ret = iwl_send_rxon_timing(priv, ctx);
+                       if (ret) {
+                               IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
+                               return ret;
+                       }
+                       ret = iwlagn_disconn_pan(priv, ctx, &ctx->staging);
+               }
+       }
        if (ret)
                return ret;
 
@@ -205,10 +228,12 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv,
        struct iwl_rxon_cmd *active = (void *)&ctx->active;
 
        /* RXON timing must be before associated RXON */
-       ret = iwl_send_rxon_timing(priv, ctx);
-       if (ret) {
-               IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
-               return ret;
+       if (ctx->ctxid == IWL_RXON_CTX_BSS) {
+               ret = iwl_send_rxon_timing(priv, ctx);
+               if (ret) {
+                       IWL_ERR(priv, "Failed to send timing (%d)!\n", ret);
+                       return ret;
+               }
        }
        /* QoS info may be cleared by previous un-assoc RXON */
        iwlagn_update_qos(priv, ctx);
@@ -263,6 +288,12 @@ static int iwlagn_rxon_connect(struct iwl_priv *priv,
                IWL_ERR(priv, "Error sending TX power (%d)\n", ret);
                return ret;
        }
+
+       if ((ctx->vif && ctx->vif->type == NL80211_IFTYPE_STATION) &&
+           priv->cfg->ht_params->smps_mode)
+               ieee80211_request_smps(ctx->vif,
+                                      priv->cfg->ht_params->smps_mode);
+
        return 0;
 }
 
@@ -325,6 +356,14 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
                        return 0;
        }
 
+       /*
+        * force CTS-to-self frames protection if RTS-CTS is not preferred
+        * one aggregation protection method
+        */
+       if (!(priv->cfg->ht_params &&
+             priv->cfg->ht_params->use_rts_for_aggregation))
+               ctx->staging.flags |= RXON_FLG_SELF_CTS_EN;
+
        if ((ctx->vif && ctx->vif->bss_conf.use_short_slot) ||
            !(ctx->staging.flags & RXON_FLG_BAND_24G_MSK))
                ctx->staging.flags |= RXON_FLG_SHORT_SLOT_MSK;
@@ -342,10 +381,10 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
         * receive commit_rxon request
         * abort any previous channel switch if still in process
         */
-       if (priv->switch_rxon.switch_in_progress &&
-           (priv->switch_rxon.channel != ctx->staging.channel)) {
+       if (test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status) &&
+           (priv->switch_channel != ctx->staging.channel)) {
                IWL_DEBUG_11H(priv, "abort channel switch on %d\n",
-                     le16_to_cpu(priv->switch_rxon.channel));
+                             le16_to_cpu(priv->switch_channel));
                iwl_chswitch_done(priv, false);
        }
 
@@ -362,13 +401,16 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
                }
 
                memcpy(active, &ctx->staging, sizeof(*active));
-               return 0;
-       }
+               /*
+                * We do not commit tx power settings while channel changing,
+                * do it now if after settings changed.
+                */
+               iwl_set_tx_power(priv, priv->tx_power_next, false);
 
-       if (priv->cfg->ops->hcmd->set_pan_params) {
-               ret = priv->cfg->ops->hcmd->set_pan_params(priv);
-               if (ret)
-                       return ret;
+               /* make sure we are in the right PS state */
+               iwl_power_update_mode(priv, true);
+
+               return 0;
        }
 
        iwl_set_rxon_hwcrypto(priv, ctx, !iwlagn_mod_params.sw_crypto);
@@ -392,6 +434,12 @@ int iwlagn_commit_rxon(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
        if (ret)
                return ret;
 
+       if (priv->cfg->ops->hcmd->set_pan_params) {
+               ret = priv->cfg->ops->hcmd->set_pan_params(priv);
+               if (ret)
+                       return ret;
+       }
+
        if (new_assoc)
                return iwlagn_rxon_connect(priv, ctx);
 
@@ -756,6 +804,13 @@ void iwlagn_post_scan(struct iwl_priv *priv)
 {
        struct iwl_rxon_context *ctx;
 
+       /*
+        * We do not commit power settings while scan is pending,
+        * do it now if the settings changed.
+        */
+       iwl_power_set_mode(priv, &priv->power_data.sleep_cmd_next, false);
+       iwl_set_tx_power(priv, priv->tx_power_next, false);
+
        /*
         * Since setting the RXON may have been deferred while
         * performing the scan, fire one off if needed
index 4974cd7..8bd48f6 100644 (file)
@@ -1033,8 +1033,8 @@ int iwlagn_tx_agg_start(struct iwl_priv *priv, struct ieee80211_vif *vif,
        if (unlikely(tx_fifo < 0))
                return tx_fifo;
 
-       IWL_WARN(priv, "%s on ra = %pM tid = %d\n",
-                       __func__, sta->addr, tid);
+       IWL_DEBUG_HT(priv, "TX AGG request on ra = %pM tid = %d\n",
+                    sta->addr, tid);
 
        sta_id = iwl_sta_id(sta);
        if (sta_id == IWL_INVALID_STATION) {
@@ -1236,9 +1236,9 @@ int iwlagn_tx_queue_reclaim(struct iwl_priv *priv, int txq_id, int index)
        struct ieee80211_hdr *hdr;
 
        if ((index >= q->n_bd) || (iwl_queue_used(q, index) == 0)) {
-               IWL_ERR(priv, "Read index for DMA queue txq id (%d), index %d, "
-                         "is out of range [0-%d] %d %d.\n", txq_id,
-                         index, q->n_bd, q->write_ptr, q->read_ptr);
+               IWL_ERR(priv, "%s: Read index for DMA queue txq id (%d), "
+                         "index %d is out of range [0-%d] %d %d.\n", __func__,
+                         txq_id, index, q->n_bd, q->write_ptr, q->read_ptr);
                return 0;
        }
 
index 11c6c11..099c279 100644 (file)
@@ -97,7 +97,7 @@ void iwl_update_chain_flags(struct iwl_priv *priv)
                for_each_context(priv, ctx) {
                        priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
                        if (ctx->active.rx_chain != ctx->staging.rx_chain)
-                               iwlcore_commit_rxon(priv, ctx);
+                               iwlagn_commit_rxon(priv, ctx);
                }
        }
 }
@@ -274,7 +274,7 @@ static void iwl_bg_bt_full_concurrency(struct work_struct *work)
        for_each_context(priv, ctx) {
                if (priv->cfg->ops->hcmd->set_rxon_chain)
                        priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
-               iwlcore_commit_rxon(priv, ctx);
+               iwlagn_commit_rxon(priv, ctx);
        }
 
        priv->cfg->ops->hcmd->send_bt_config(priv);
@@ -2056,7 +2056,7 @@ int iwl_alive_start(struct iwl_priv *priv)
        set_bit(STATUS_READY, &priv->status);
 
        /* Configure the adapter for unassociated operation */
-       ret = iwlcore_commit_rxon(priv, ctx);
+       ret = iwlagn_commit_rxon(priv, ctx);
        if (ret)
                return ret;
 
@@ -2420,6 +2420,77 @@ unlock:
  *
  *****************************************************************************/
 
+static const struct ieee80211_iface_limit iwlagn_sta_ap_limits[] = {
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_AP),
+       },
+};
+
+static const struct ieee80211_iface_limit iwlagn_2sta_limits[] = {
+       {
+               .max = 2,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+};
+
+static const struct ieee80211_iface_limit iwlagn_p2p_sta_go_limits[] = {
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_P2P_GO) |
+                        BIT(NL80211_IFTYPE_AP),
+       },
+};
+
+static const struct ieee80211_iface_limit iwlagn_p2p_2sta_limits[] = {
+       {
+               .max = 2,
+               .types = BIT(NL80211_IFTYPE_STATION),
+       },
+       {
+               .max = 1,
+               .types = BIT(NL80211_IFTYPE_P2P_CLIENT),
+       },
+};
+
+static const struct ieee80211_iface_combination
+iwlagn_iface_combinations_dualmode[] = {
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .beacon_int_infra_match = true,
+         .limits = iwlagn_sta_ap_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_sta_ap_limits),
+       },
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .limits = iwlagn_2sta_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_2sta_limits),
+       },
+};
+
+static const struct ieee80211_iface_combination
+iwlagn_iface_combinations_p2p[] = {
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .beacon_int_infra_match = true,
+         .limits = iwlagn_p2p_sta_go_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_p2p_sta_go_limits),
+       },
+       { .num_different_channels = 1,
+         .max_interfaces = 2,
+         .limits = iwlagn_p2p_2sta_limits,
+         .n_limits = ARRAY_SIZE(iwlagn_p2p_2sta_limits),
+       },
+};
+
 /*
  * Not a mac80211 entry point function, but it fits in with all the
  * other mac80211 functions grouped here.
@@ -2460,6 +2531,18 @@ static int iwl_mac_setup_register(struct iwl_priv *priv,
                hw->wiphy->interface_modes |= ctx->exclusive_interface_modes;
        }
 
+       BUILD_BUG_ON(NUM_IWL_RXON_CTX != 2);
+
+       if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_P2P_CLIENT)) {
+               hw->wiphy->iface_combinations = iwlagn_iface_combinations_p2p;
+               hw->wiphy->n_iface_combinations =
+                       ARRAY_SIZE(iwlagn_iface_combinations_p2p);
+       } else if (hw->wiphy->interface_modes & BIT(NL80211_IFTYPE_AP)) {
+               hw->wiphy->iface_combinations = iwlagn_iface_combinations_dualmode;
+               hw->wiphy->n_iface_combinations =
+                       ARRAY_SIZE(iwlagn_iface_combinations_dualmode);
+       }
+
        hw->wiphy->max_remain_on_channel_duration = 1000;
 
        hw->wiphy->flags |= WIPHY_FLAG_CUSTOM_REGULATORY |
@@ -2711,12 +2794,9 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
                        ret = 0;
                if (priv->cfg->ht_params &&
                    priv->cfg->ht_params->use_rts_for_aggregation) {
-                       struct iwl_station_priv *sta_priv =
-                               (void *) sta->drv_priv;
                        /*
                         * switch off RTS/CTS if it was previously enabled
                         */
-
                        sta_priv->lq_sta.lq.general_params.flags &=
                                ~LINK_QUAL_FLAGS_SET_STA_TLC_RTS_MSK;
                        iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
@@ -2764,6 +2844,9 @@ static int iwlagn_mac_ampdu_action(struct ieee80211_hw *hw,
 
                iwl_send_lq_cmd(priv, iwl_rxon_ctx_from_vif(vif),
                                &sta_priv->lq_sta.lq, CMD_ASYNC, false);
+
+               IWL_INFO(priv, "Tx aggregation enabled on ra = %pM tid = %d\n",
+                        sta->addr, tid);
                ret = 0;
                break;
        }
@@ -2833,7 +2916,6 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
         */
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        u16 ch;
-       unsigned long flags = 0;
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
@@ -2843,73 +2925,73 @@ static void iwlagn_mac_channel_switch(struct ieee80211_hw *hw,
                goto out;
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status) ||
-           test_bit(STATUS_SCANNING, &priv->status))
+           test_bit(STATUS_SCANNING, &priv->status) ||
+           test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
                goto out;
 
        if (!iwl_is_associated_ctx(ctx))
                goto out;
 
-       /* channel switch in progress */
-       if (priv->switch_rxon.switch_in_progress == true)
+       if (!priv->cfg->ops->lib->set_channel_switch)
                goto out;
 
-       if (priv->cfg->ops->lib->set_channel_switch) {
+       ch = channel->hw_value;
+       if (le16_to_cpu(ctx->active.channel) == ch)
+               goto out;
 
-               ch = channel->hw_value;
-               if (le16_to_cpu(ctx->active.channel) != ch) {
-                       ch_info = iwl_get_channel_info(priv,
-                                                      channel->band,
-                                                      ch);
-                       if (!is_channel_valid(ch_info)) {
-                               IWL_DEBUG_MAC80211(priv, "invalid channel\n");
-                               goto out;
-                       }
-                       spin_lock_irqsave(&priv->lock, flags);
-
-                       priv->current_ht_config.smps = conf->smps_mode;
-
-                       /* Configure HT40 channels */
-                       ctx->ht.enabled = conf_is_ht(conf);
-                       if (ctx->ht.enabled) {
-                               if (conf_is_ht40_minus(conf)) {
-                                       ctx->ht.extension_chan_offset =
-                                               IEEE80211_HT_PARAM_CHA_SEC_BELOW;
-                                       ctx->ht.is_40mhz = true;
-                               } else if (conf_is_ht40_plus(conf)) {
-                                       ctx->ht.extension_chan_offset =
-                                               IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
-                                       ctx->ht.is_40mhz = true;
-                               } else {
-                                       ctx->ht.extension_chan_offset =
-                                               IEEE80211_HT_PARAM_CHA_SEC_NONE;
-                                       ctx->ht.is_40mhz = false;
-                               }
-                       } else
-                               ctx->ht.is_40mhz = false;
+       ch_info = iwl_get_channel_info(priv, channel->band, ch);
+       if (!is_channel_valid(ch_info)) {
+               IWL_DEBUG_MAC80211(priv, "invalid channel\n");
+               goto out;
+       }
 
-                       if ((le16_to_cpu(ctx->staging.channel) != ch))
-                               ctx->staging.flags = 0;
+       spin_lock_irq(&priv->lock);
 
-                       iwl_set_rxon_channel(priv, channel, ctx);
-                       iwl_set_rxon_ht(priv, ht_conf);
-                       iwl_set_flags_for_band(priv, ctx, channel->band,
-                                              ctx->vif);
-                       spin_unlock_irqrestore(&priv->lock, flags);
+       priv->current_ht_config.smps = conf->smps_mode;
 
-                       iwl_set_rate(priv);
-                       /*
-                        * at this point, staging_rxon has the
-                        * configuration for channel switch
-                        */
-                       if (priv->cfg->ops->lib->set_channel_switch(priv,
-                                                                   ch_switch))
-                               priv->switch_rxon.switch_in_progress = false;
+       /* Configure HT40 channels */
+       ctx->ht.enabled = conf_is_ht(conf);
+       if (ctx->ht.enabled) {
+               if (conf_is_ht40_minus(conf)) {
+                       ctx->ht.extension_chan_offset =
+                               IEEE80211_HT_PARAM_CHA_SEC_BELOW;
+                       ctx->ht.is_40mhz = true;
+               } else if (conf_is_ht40_plus(conf)) {
+                       ctx->ht.extension_chan_offset =
+                               IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+                       ctx->ht.is_40mhz = true;
+               } else {
+                       ctx->ht.extension_chan_offset =
+                               IEEE80211_HT_PARAM_CHA_SEC_NONE;
+                       ctx->ht.is_40mhz = false;
                }
+       } else
+               ctx->ht.is_40mhz = false;
+
+       if ((le16_to_cpu(ctx->staging.channel) != ch))
+               ctx->staging.flags = 0;
+
+       iwl_set_rxon_channel(priv, channel, ctx);
+       iwl_set_rxon_ht(priv, ht_conf);
+       iwl_set_flags_for_band(priv, ctx, channel->band, ctx->vif);
+
+       spin_unlock_irq(&priv->lock);
+
+       iwl_set_rate(priv);
+       /*
+        * at this point, staging_rxon has the
+        * configuration for channel switch
+        */
+       set_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
+       priv->switch_channel = cpu_to_le16(ch);
+       if (priv->cfg->ops->lib->set_channel_switch(priv, ch_switch)) {
+               clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status);
+               priv->switch_channel = 0;
+               ieee80211_chswitch_done(ctx->vif, false);
        }
+
 out:
        mutex_unlock(&priv->mutex);
-       if (!priv->switch_rxon.switch_in_progress)
-               ieee80211_chswitch_done(ctx->vif, false);
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
@@ -3018,7 +3100,7 @@ static void iwlagn_disable_roc(struct iwl_priv *priv)
 
        priv->_agn.hw_roc_channel = NULL;
 
-       iwlcore_commit_rxon(priv, ctx);
+       iwlagn_commit_rxon(priv, ctx);
 
        ctx->is_active = false;
 }
@@ -3061,7 +3143,7 @@ static int iwl_mac_remain_on_channel(struct ieee80211_hw *hw,
        priv->_agn.hw_roc_channel = channel;
        priv->_agn.hw_roc_chantype = channel_type;
        priv->_agn.hw_roc_duration = DIV_ROUND_UP(duration * 1000, 1024);
-       iwlcore_commit_rxon(priv, &priv->contexts[IWL_RXON_CTX_PAN]);
+       iwlagn_commit_rxon(priv, &priv->contexts[IWL_RXON_CTX_PAN]);
        queue_delayed_work(priv->workqueue, &priv->_agn.hw_roc_work,
                           msecs_to_jiffies(duration + 20));
 
@@ -3618,8 +3700,8 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        destroy_workqueue(priv->workqueue);
        priv->workqueue = NULL;
        free_irq(priv->pci_dev->irq, priv);
-       iwl_free_isr_ict(priv);
  out_disable_msi:
+       iwl_free_isr_ict(priv);
        pci_disable_msi(priv->pci_dev);
        iwl_uninit_drv(priv);
  out_free_eeprom:
@@ -3831,11 +3913,11 @@ static DEFINE_PCI_DEVICE_TABLE(iwl_hw_card_ids) = {
 
 /* 6150 WiFi/WiMax Series */
        {IWL_PCI_DEVICE(0x0885, 0x1305, iwl6150_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0885, 0x1306, iwl6150_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0885, 0x1307, iwl6150_bg_cfg)},
        {IWL_PCI_DEVICE(0x0885, 0x1325, iwl6150_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0885, 0x1326, iwl6150_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0885, 0x1327, iwl6150_bg_cfg)},
        {IWL_PCI_DEVICE(0x0886, 0x1315, iwl6150_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0886, 0x1316, iwl6150_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0886, 0x1317, iwl6150_bg_cfg)},
 
 /* 1000 Series WiFi */
        {IWL_PCI_DEVICE(0x0083, 0x1205, iwl1000_bgn_cfg)},
index 2495fe7..d171684 100644 (file)
@@ -89,6 +89,7 @@ extern struct iwl_cfg iwl6000_3agn_cfg;
 extern struct iwl_cfg iwl6050_2agn_cfg;
 extern struct iwl_cfg iwl6050_2abg_cfg;
 extern struct iwl_cfg iwl6150_bgn_cfg;
+extern struct iwl_cfg iwl6150_bg_cfg;
 extern struct iwl_cfg iwl1000_bgn_cfg;
 extern struct iwl_cfg iwl1000_bg_cfg;
 extern struct iwl_cfg iwl100_bgn_cfg;
index 4653dea..5416b12 100644 (file)
@@ -843,12 +843,8 @@ void iwl_chswitch_done(struct iwl_priv *priv, bool is_success)
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
                return;
 
-       if (priv->switch_rxon.switch_in_progress) {
+       if (test_and_clear_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
                ieee80211_chswitch_done(ctx->vif, is_success);
-               mutex_lock(&priv->mutex);
-               priv->switch_rxon.switch_in_progress = false;
-               mutex_unlock(&priv->mutex);
-       }
 }
 
 #ifdef CONFIG_IWLWIFI_DEBUG
@@ -1131,9 +1127,6 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
        if (priv->tx_power_user_lmt == tx_power && !force)
                return 0;
 
-       if (!priv->cfg->ops->lib->send_tx_power)
-               return -EOPNOTSUPP;
-
        if (tx_power < IWLAGN_TX_POWER_TARGET_POWER_MIN) {
                IWL_WARN(priv,
                         "Requested user TXPOWER %d below lower limit %d.\n",
@@ -1167,7 +1160,7 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
        prev_tx_power = priv->tx_power_user_lmt;
        priv->tx_power_user_lmt = tx_power;
 
-       ret = priv->cfg->ops->lib->send_tx_power(priv);
+       ret = iwlagn_send_tx_power(priv);
 
        /* if fail to set tx_power, restore the orig. tx power */
        if (ret) {
@@ -1282,7 +1275,7 @@ static int iwl_set_mode(struct iwl_priv *priv, struct iwl_rxon_context *ctx)
        if (priv->cfg->ops->hcmd->set_rxon_chain)
                priv->cfg->ops->hcmd->set_rxon_chain(priv, ctx);
 
-       return iwlcore_commit_rxon(priv, ctx);
+       return iwlagn_commit_rxon(priv, ctx);
 }
 
 static int iwl_setup_interface(struct iwl_priv *priv,
index 3bb76f6..05ea88a 100644 (file)
@@ -90,7 +90,6 @@ struct iwl_cmd;
 #define IWL_CMD(x) case x: return #x
 
 struct iwl_hcmd_ops {
-       int (*commit_rxon)(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
        void (*set_rxon_chain)(struct iwl_priv *priv,
                               struct iwl_rxon_context *ctx);
        int (*set_tx_ant)(struct iwl_priv *priv, u8 valid_tx_ant);
@@ -112,7 +111,6 @@ struct iwl_hcmd_utils_ops {
        int  (*calc_rssi)(struct iwl_priv *priv,
                          struct iwl_rx_phy_res *rx_resp);
        int (*request_scan)(struct iwl_priv *priv, struct ieee80211_vif *vif);
-       void (*post_scan)(struct iwl_priv *priv);
 };
 
 struct iwl_apm_ops {
@@ -141,7 +139,6 @@ struct iwl_lib_ops {
        struct iwl_apm_ops apm_ops;
 
        /* power */
-       int (*send_tx_power) (struct iwl_priv *priv);
        void (*update_chain_flags)(struct iwl_priv *priv);
 
        /* eeprom operations (as defined in iwl-eeprom.h) */
@@ -225,7 +222,7 @@ struct iwl_base_params {
  * @ampdu_factor: Maximum A-MPDU length factor
  * @ampdu_density: Minimum A-MPDU spacing
  * @bt_sco_disable: uCode should not response to BT in SCO/ESCO mode
-*/
+ */
 struct iwl_bt_params {
        bool advanced_bt_coexist;
        u8 bt_init_traffic_load;
@@ -238,10 +235,11 @@ struct iwl_bt_params {
 };
 /*
  * @use_rts_for_aggregation: use rts/cts protection for HT traffic
-*/
+ */
 struct iwl_ht_params {
        const bool ht_greenfield_support; /* if used set to true */
        bool use_rts_for_aggregation;
+       enum ieee80211_smps_mode smps_mode;
 };
 
 /**
@@ -560,6 +558,7 @@ void iwlcore_free_geos(struct iwl_priv *priv);
 #define STATUS_POWER_PMI       16
 #define STATUS_FW_ERROR                17
 #define STATUS_DEVICE_ENABLED  18
+#define STATUS_CHANNEL_SWITCH_PENDING 19
 
 
 static inline int iwl_is_ready(struct iwl_priv *priv)
@@ -612,11 +611,7 @@ void iwl_apm_stop(struct iwl_priv *priv);
 int iwl_apm_init(struct iwl_priv *priv);
 
 int iwl_send_rxon_timing(struct iwl_priv *priv, struct iwl_rxon_context *ctx);
-static inline int iwlcore_commit_rxon(struct iwl_priv *priv,
-                                     struct iwl_rxon_context *ctx)
-{
-       return priv->cfg->ops->hcmd->commit_rxon(priv, ctx);
-}
+
 static inline const struct ieee80211_supported_band *iwl_get_hw_mode(
                        struct iwl_priv *priv, enum ieee80211_band band)
 {
index 22a6e3e..7ad98d8 100644 (file)
@@ -31,6 +31,7 @@
 #ifndef __iwl_dev_h__
 #define __iwl_dev_h__
 
+#include <linux/interrupt.h>
 #include <linux/pci.h> /* for struct pci_device_id */
 #include <linux/kernel.h>
 #include <linux/wait.h>
@@ -981,17 +982,6 @@ struct traffic_stats {
 #endif
 };
 
-/*
- * iwl_switch_rxon: "channel switch" structure
- *
- * @ switch_in_progress: channel switch in progress
- * @ channel: new channel
- */
-struct iwl_switch_rxon {
-       bool switch_in_progress;
-       __le16 channel;
-};
-
 /*
  * schedule the timer to wake up every UCODE_TRACE_PERIOD milliseconds
  * to perform continuous uCode event logging operation if enabled
@@ -1287,7 +1277,7 @@ struct iwl_priv {
 
        struct iwl_rxon_context contexts[NUM_IWL_RXON_CTX];
 
-       struct iwl_switch_rxon switch_rxon;
+       __le16 switch_channel;
 
        struct {
                u32 error_event_table;
index 0053e9e..b774517 100644 (file)
@@ -250,19 +250,19 @@ static void iwl_rx_csa(struct iwl_priv *priv, struct iwl_rx_mem_buffer *rxb)
        struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
        struct iwl_rxon_cmd *rxon = (void *)&ctx->active;
 
-       if (priv->switch_rxon.switch_in_progress) {
-               if (!le32_to_cpu(csa->status) &&
-                   (csa->channel == priv->switch_rxon.channel)) {
-                       rxon->channel = csa->channel;
-                       ctx->staging.channel = csa->channel;
-                       IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
-                             le16_to_cpu(csa->channel));
-                       iwl_chswitch_done(priv, true);
-               } else {
-                       IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
+       if (!test_bit(STATUS_CHANNEL_SWITCH_PENDING, &priv->status))
+               return;
+
+       if (!le32_to_cpu(csa->status) && csa->channel == priv->switch_channel) {
+               rxon->channel = csa->channel;
+               ctx->staging.channel = csa->channel;
+               IWL_DEBUG_11H(priv, "CSA notif: channel %d\n",
                              le16_to_cpu(csa->channel));
-                       iwl_chswitch_done(priv, false);
-               }
+               iwl_chswitch_done(priv, true);
+       } else {
+               IWL_ERR(priv, "CSA notif (fail) : channel %d\n",
+                       le16_to_cpu(csa->channel));
+               iwl_chswitch_done(priv, false);
        }
 }
 
index d60d630..438eecd 100644 (file)
@@ -36,6 +36,7 @@
 #include "iwl-sta.h"
 #include "iwl-io.h"
 #include "iwl-helpers.h"
+#include "iwl-agn.h"
 
 /* For active scan, listen ACTIVE_DWELL_TIME (msec) on each channel after
  * sending probe req.  This should be set long enough to hear probe responses
@@ -600,14 +601,7 @@ out_settings:
        if (!iwl_is_ready_rf(priv))
                goto out;
 
-       /*
-        * We do not commit power settings while scan is pending,
-        * do it now if the settings changed.
-        */
-       iwl_power_set_mode(priv, &priv->power_data.sleep_cmd_next, false);
-       iwl_set_tx_power(priv, priv->tx_power_next, false);
-
-       priv->cfg->ops->utils->post_scan(priv);
+       iwlagn_post_scan(priv);
 
 out:
        mutex_unlock(&priv->mutex);
index 686e176..1084fe0 100644 (file)
@@ -753,9 +753,9 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id, int idx)
        int nfreed = 0;
 
        if ((idx >= q->n_bd) || (iwl_queue_used(q, idx) == 0)) {
-               IWL_ERR(priv, "Read index for DMA queue txq id (%d), index %d, "
-                         "is out of range [0-%d] %d %d.\n", txq_id,
-                         idx, q->n_bd, q->write_ptr, q->read_ptr);
+               IWL_ERR(priv, "%s: Read index for DMA queue txq id (%d), "
+                         "index %d is out of range [0-%d] %d %d.\n", __func__,
+                         txq_id, idx, q->n_bd, q->write_ptr, q->read_ptr);
                return;
        }
 
index 4906709..6f1afe6 100644 (file)
@@ -187,7 +187,7 @@ static int iwm_load_img(struct iwm_priv *iwm, const char *img_name)
                if (ret < 0)
                        goto err_release_fw;
                opcode_idx++;
-       };
+       }
 
        /* Read firmware version */
        fw_offset = iwm_fw_op_offset(iwm, fw, IWM_HDR_REC_OP_SW_VER, 0);
index 5d637af..b456a53 100644 (file)
@@ -8,6 +8,7 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/hardirq.h>
 #include <linux/sched.h>
 #include <linux/wait.h>
 #include <linux/slab.h>
index 84566db..9dcf967 100644 (file)
@@ -3,6 +3,7 @@
  * It prepares command and sends it to firmware when it is ready.
  */
 
+#include <linux/hardirq.h>
 #include <linux/kfifo.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
@@ -994,6 +995,8 @@ static void lbs_submit_command(struct lbs_private *priv,
        cmd = cmdnode->cmdbuf;
 
        spin_lock_irqsave(&priv->driver_lock, flags);
+       priv->seqnum++;
+       cmd->seqnum = cpu_to_le16(priv->seqnum);
        priv->cur_cmd = cmdnode;
        spin_unlock_irqrestore(&priv->driver_lock, flags);
 
@@ -1621,11 +1624,9 @@ struct cmd_ctrl_node *__lbs_cmd_async(struct lbs_private *priv,
        /* Copy the incoming command to the buffer */
        memcpy(cmdnode->cmdbuf, in_cmd, in_cmd_size);
 
-       /* Set sequence number, clean result, move to buffer */
-       priv->seqnum++;
+       /* Set command, clean result, move to buffer */
        cmdnode->cmdbuf->command = cpu_to_le16(command);
        cmdnode->cmdbuf->size    = cpu_to_le16(in_cmd_size);
-       cmdnode->cmdbuf->seqnum  = cpu_to_le16(priv->seqnum);
        cmdnode->cmdbuf->result  = 0;
 
        lbs_deb_host("PREP_CMD: command 0x%04x\n", command);
index 207fc36..2ffe5a1 100644 (file)
@@ -3,6 +3,7 @@
  * responses as well as events generated by firmware.
  */
 
+#include <linux/hardirq.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/sched.h>
index 23250f6..1af1827 100644 (file)
@@ -1,6 +1,7 @@
 #include <linux/dcache.h>
 #include <linux/debugfs.h>
 #include <linux/delay.h>
+#include <linux/hardirq.h>
 #include <linux/mm.h>
 #include <linux/string.h>
 #include <linux/slab.h>
index 29dbce4..4dfb3bf 100644 (file)
@@ -1,3 +1,4 @@
+#include <linux/hardirq.h>
 #include <linux/netdevice.h>
 #include <linux/ethtool.h>
 #include <linux/delay.h>
index a7b5cb0..224e985 100644 (file)
@@ -907,7 +907,7 @@ static void if_sdio_interrupt(struct sdio_func *func)
        card = sdio_get_drvdata(func);
 
        cause = sdio_readb(card->func, IF_SDIO_H_INT_STATUS, &ret);
-       if (ret)
+       if (ret || !cause)
                goto out;
 
        lbs_deb_sdio("interrupt: 0x%X\n", (unsigned)cause);
@@ -1008,10 +1008,6 @@ static int if_sdio_probe(struct sdio_func *func,
        if (ret)
                goto release;
 
-       ret = sdio_claim_irq(func, if_sdio_interrupt);
-       if (ret)
-               goto disable;
-
        /* For 1-bit transfers to the 8686 model, we need to enable the
         * interrupt flag in the CCCR register. Set the MMC_QUIRK_LENIENT_FN0
         * bit to allow access to non-vendor registers. */
@@ -1082,6 +1078,21 @@ static int if_sdio_probe(struct sdio_func *func,
        else
                card->rx_unit = 0;
 
+       /*
+        * Set up the interrupt handler late.
+        *
+        * If we set it up earlier, the (buggy) hardware generates a spurious
+        * interrupt, even before the interrupt has been enabled, with
+        * CCCR_INTx = 0.
+        *
+        * We register the interrupt handler late so that we can handle any
+        * spurious interrupts, and also to avoid generation of that known
+        * spurious interrupt in the first place.
+        */
+       ret = sdio_claim_irq(func, if_sdio_interrupt);
+       if (ret)
+               goto disable;
+
        /*
         * Enable interrupts now that everything is set up
         */
index 463352c..4fa0be9 100644 (file)
@@ -19,6 +19,8 @@
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/hardirq.h>
+#include <linux/interrupt.h>
 #include <linux/moduleparam.h>
 #include <linux/firmware.h>
 #include <linux/jiffies.h>
index 8c40949..cf3d2c8 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/moduleparam.h>
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
+#include <linux/hardirq.h>
 #include <linux/netdevice.h>
 #include <linux/if_arp.h>
 #include <linux/kthread.h>
index 24cf066..7969d10 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <linux/delay.h>
 #include <linux/etherdevice.h>
+#include <linux/hardirq.h>
 #include <linux/netdevice.h>
 #include <linux/if_ether.h>
 #include <linux/if_arp.h>
index fdb0448..bfb8898 100644 (file)
@@ -5,6 +5,7 @@
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/etherdevice.h>
+#include <linux/hardirq.h>
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <net/cfg80211.h>
index bbb95f8..f19495b 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * This file contains the handling of TX in wlan driver.
  */
+#include <linux/hardirq.h>
 #include <linux/netdevice.h>
 #include <linux/etherdevice.h>
 #include <linux/sched.h>
index 8945afd..13557fe 100644 (file)
@@ -9,6 +9,7 @@
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/hardirq.h>
 #include <linux/slab.h>
 
 #include "libertas_tf.h"
index d400508..5beb581 100644 (file)
@@ -9,6 +9,7 @@
  */
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
+#include <linux/hardirq.h>
 #include <linux/slab.h>
 
 #include <linux/etherdevice.h>
index 9d4a40e..7e1fa96 100644 (file)
@@ -1,6 +1,7 @@
 /*
  * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211
  * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2011, Javier Lopez <jlopex@gmail.com>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License version 2 as
 #include <linux/rtnetlink.h>
 #include <linux/etherdevice.h>
 #include <linux/debugfs.h>
+#include <net/genetlink.h>
+#include "mac80211_hwsim.h"
+
+#define WARN_QUEUE 100
+#define MAX_QUEUE 200
 
 MODULE_AUTHOR("Jouni Malinen");
 MODULE_DESCRIPTION("Software simulator of 802.11 radio(s) for mac80211");
 MODULE_LICENSE("GPL");
 
+int wmediumd_pid;
 static int radios = 2;
 module_param(radios, int, 0444);
 MODULE_PARM_DESC(radios, "Number of simulated radios");
@@ -302,6 +309,7 @@ struct mac80211_hwsim_data {
        struct dentry *debugfs;
        struct dentry *debugfs_ps;
 
+       struct sk_buff_head pending;    /* packets pending */
        /*
         * Only radios in the same group can communicate together (the
         * channel has to match too). Each bit represents a group. A
@@ -322,6 +330,32 @@ struct hwsim_radiotap_hdr {
        __le16 rt_chbitmask;
 } __packed;
 
+/* MAC80211_HWSIM netlinf family */
+static struct genl_family hwsim_genl_family = {
+       .id = GENL_ID_GENERATE,
+       .hdrsize = 0,
+       .name = "MAC80211_HWSIM",
+       .version = 1,
+       .maxattr = HWSIM_ATTR_MAX,
+};
+
+/* MAC80211_HWSIM netlink policy */
+
+static struct nla_policy hwsim_genl_policy[HWSIM_ATTR_MAX + 1] = {
+       [HWSIM_ATTR_ADDR_RECEIVER] = { .type = NLA_UNSPEC,
+                                      .len = 6*sizeof(u8) },
+       [HWSIM_ATTR_ADDR_TRANSMITTER] = { .type = NLA_UNSPEC,
+                                         .len = 6*sizeof(u8) },
+       [HWSIM_ATTR_FRAME] = { .type = NLA_BINARY,
+                              .len = IEEE80211_MAX_DATA_LEN },
+       [HWSIM_ATTR_FLAGS] = { .type = NLA_U32 },
+       [HWSIM_ATTR_RX_RATE] = { .type = NLA_U32 },
+       [HWSIM_ATTR_SIGNAL] = { .type = NLA_U32 },
+       [HWSIM_ATTR_TX_INFO] = { .type = NLA_UNSPEC,
+                                .len = IEEE80211_TX_MAX_RATES*sizeof(
+                                       struct hwsim_tx_rate)},
+       [HWSIM_ATTR_COOKIE] = { .type = NLA_U64 },
+};
 
 static netdev_tx_t hwsim_mon_xmit(struct sk_buff *skb,
                                        struct net_device *dev)
@@ -478,9 +512,89 @@ static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data,
        return md.ret;
 }
 
+static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
+                                      struct sk_buff *my_skb,
+                                      int dst_pid)
+{
+       struct sk_buff *skb;
+       struct mac80211_hwsim_data *data = hw->priv;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) my_skb->data;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(my_skb);
+       void *msg_head;
+       unsigned int hwsim_flags = 0;
+       int i;
+       struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES];
+
+       if (data->idle) {
+               wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n");
+               dev_kfree_skb(my_skb);
+               return;
+       }
+
+       if (data->ps != PS_DISABLED)
+               hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+       /* If the queue contains MAX_QUEUE skb's drop some */
+       if (skb_queue_len(&data->pending) >= MAX_QUEUE) {
+               /* Droping until WARN_QUEUE level */
+               while (skb_queue_len(&data->pending) >= WARN_QUEUE)
+                       skb_dequeue(&data->pending);
+       }
+
+       skb = genlmsg_new(NLMSG_GOODSIZE, GFP_ATOMIC);
+       if (skb == NULL)
+               goto nla_put_failure;
+
+       msg_head = genlmsg_put(skb, 0, 0, &hwsim_genl_family, 0,
+                              HWSIM_CMD_FRAME);
+       if (msg_head == NULL) {
+               printk(KERN_DEBUG "mac80211_hwsim: problem with msg_head\n");
+               goto nla_put_failure;
+       }
+
+       NLA_PUT(skb, HWSIM_ATTR_ADDR_TRANSMITTER,
+                    sizeof(struct mac_address), data->addresses[1].addr);
 
-static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
-                                   struct sk_buff *skb)
+       /* We get the skb->data */
+       NLA_PUT(skb, HWSIM_ATTR_FRAME, my_skb->len, my_skb->data);
+
+       /* We get the flags for this transmission, and we translate them to
+          wmediumd flags  */
+
+       if (info->flags & IEEE80211_TX_CTL_REQ_TX_STATUS)
+               hwsim_flags |= HWSIM_TX_CTL_REQ_TX_STATUS;
+
+       if (info->flags & IEEE80211_TX_CTL_NO_ACK)
+               hwsim_flags |= HWSIM_TX_CTL_NO_ACK;
+
+       NLA_PUT_U32(skb, HWSIM_ATTR_FLAGS, hwsim_flags);
+
+       /* We get the tx control (rate and retries) info*/
+
+       for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+               tx_attempts[i].idx = info->status.rates[i].idx;
+               tx_attempts[i].count = info->status.rates[i].count;
+       }
+
+       NLA_PUT(skb, HWSIM_ATTR_TX_INFO,
+                    sizeof(struct hwsim_tx_rate)*IEEE80211_TX_MAX_RATES,
+                    tx_attempts);
+
+       /* We create a cookie to identify this skb */
+       NLA_PUT_U64(skb, HWSIM_ATTR_COOKIE, (unsigned long) my_skb);
+
+       genlmsg_end(skb, msg_head);
+       genlmsg_unicast(&init_net, skb, dst_pid);
+
+       /* Enqueue the packet */
+       skb_queue_tail(&data->pending, my_skb);
+       return;
+
+nla_put_failure:
+       printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__);
+}
+
+static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
+                                         struct sk_buff *skb)
 {
        struct mac80211_hwsim_data *data = hw->priv, *data2;
        bool ack = false;
@@ -540,11 +654,11 @@ static bool mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
        return ack;
 }
 
-
 static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        bool ack;
        struct ieee80211_tx_info *txi;
+       int _pid;
 
        mac80211_hwsim_monitor_rx(hw, skb);
 
@@ -554,7 +668,15 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                return;
        }
 
-       ack = mac80211_hwsim_tx_frame(hw, skb);
+       /* wmediumd mode check */
+       _pid = wmediumd_pid;
+
+       if (_pid)
+               return mac80211_hwsim_tx_frame_nl(hw, skb, _pid);
+
+       /* NO wmediumd detected, perfect medium simulation */
+       ack = mac80211_hwsim_tx_frame_no_nl(hw, skb);
+
        if (ack && skb->len >= 16) {
                struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
                mac80211_hwsim_monitor_ack(hw, hdr->addr2);
@@ -635,6 +757,7 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
        struct ieee80211_hw *hw = arg;
        struct sk_buff *skb;
        struct ieee80211_tx_info *info;
+       int _pid;
 
        hwsim_check_magic(vif);
 
@@ -649,7 +772,14 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
        info = IEEE80211_SKB_CB(skb);
 
        mac80211_hwsim_monitor_rx(hw, skb);
-       mac80211_hwsim_tx_frame(hw, skb);
+
+       /* wmediumd mode check */
+       _pid = wmediumd_pid;
+
+       if (_pid)
+               return mac80211_hwsim_tx_frame_nl(hw, skb, _pid);
+
+       mac80211_hwsim_tx_frame_no_nl(hw, skb);
        dev_kfree_skb(skb);
 }
 
@@ -966,12 +1096,7 @@ static int mac80211_hwsim_ampdu_action(struct ieee80211_hw *hw,
 
 static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop)
 {
-       /*
-        * In this special case, there's nothing we need to
-        * do because hwsim does transmission synchronously.
-        * In the future, when it does transmissions via
-        * userspace, we may need to do something.
-        */
+       /* Not implemented, queues only on kernel side */
 }
 
 struct hw_scan_done {
@@ -1119,6 +1244,7 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
        struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
        struct sk_buff *skb;
        struct ieee80211_pspoll *pspoll;
+       int _pid;
 
        if (!vp->assoc)
                return;
@@ -1137,8 +1263,15 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
        pspoll->aid = cpu_to_le16(0xc000 | vp->aid);
        memcpy(pspoll->bssid, vp->bssid, ETH_ALEN);
        memcpy(pspoll->ta, mac, ETH_ALEN);
-       if (!mac80211_hwsim_tx_frame(data->hw, skb))
-               printk(KERN_DEBUG "%s: PS-Poll frame not ack'ed\n", __func__);
+
+       /* wmediumd mode check */
+       _pid = wmediumd_pid;
+
+       if (_pid)
+               return mac80211_hwsim_tx_frame_nl(data->hw, skb, _pid);
+
+       if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb))
+               printk(KERN_DEBUG "%s: PS-poll frame not ack'ed\n", __func__);
        dev_kfree_skb(skb);
 }
 
@@ -1149,6 +1282,7 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
        struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
        struct sk_buff *skb;
        struct ieee80211_hdr *hdr;
+       int _pid;
 
        if (!vp->assoc)
                return;
@@ -1168,7 +1302,14 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
        memcpy(hdr->addr1, vp->bssid, ETH_ALEN);
        memcpy(hdr->addr2, mac, ETH_ALEN);
        memcpy(hdr->addr3, vp->bssid, ETH_ALEN);
-       if (!mac80211_hwsim_tx_frame(data->hw, skb))
+
+       /* wmediumd mode check */
+       _pid = wmediumd_pid;
+
+       if (_pid)
+               return mac80211_hwsim_tx_frame_nl(data->hw, skb, _pid);
+
+       if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb))
                printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__);
        dev_kfree_skb(skb);
 }
@@ -1248,6 +1389,273 @@ DEFINE_SIMPLE_ATTRIBUTE(hwsim_fops_group,
                        hwsim_fops_group_read, hwsim_fops_group_write,
                        "%llx\n");
 
+struct mac80211_hwsim_data *get_hwsim_data_ref_from_addr(
+                            struct mac_address *addr)
+{
+       struct mac80211_hwsim_data *data;
+       bool _found = false;
+
+       spin_lock_bh(&hwsim_radio_lock);
+       list_for_each_entry(data, &hwsim_radios, list) {
+               if (memcmp(data->addresses[1].addr, addr,
+                         sizeof(struct mac_address)) == 0) {
+                       _found = true;
+                       break;
+               }
+       }
+       spin_unlock_bh(&hwsim_radio_lock);
+
+       if (!_found)
+               return NULL;
+
+       return data;
+}
+
+static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
+                                          struct genl_info *info)
+{
+
+       struct ieee80211_hdr *hdr;
+       struct mac80211_hwsim_data *data2;
+       struct ieee80211_tx_info *txi;
+       struct hwsim_tx_rate *tx_attempts;
+       struct sk_buff __user *ret_skb;
+       struct sk_buff *skb, *tmp;
+       struct mac_address *src;
+       unsigned int hwsim_flags;
+
+       int i;
+       bool found = false;
+
+       if (!info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER] ||
+          !info->attrs[HWSIM_ATTR_FLAGS] ||
+          !info->attrs[HWSIM_ATTR_COOKIE] ||
+          !info->attrs[HWSIM_ATTR_TX_INFO])
+               goto out;
+
+       src = (struct mac_address *)nla_data(
+                                  info->attrs[HWSIM_ATTR_ADDR_TRANSMITTER]);
+       hwsim_flags = nla_get_u32(info->attrs[HWSIM_ATTR_FLAGS]);
+
+       ret_skb = (struct sk_buff __user *)
+                 (unsigned long) nla_get_u64(info->attrs[HWSIM_ATTR_COOKIE]);
+
+       data2 = get_hwsim_data_ref_from_addr(src);
+
+       if (data2 == NULL)
+               goto out;
+
+       /* look for the skb matching the cookie passed back from user */
+       skb_queue_walk_safe(&data2->pending, skb, tmp) {
+               if (skb == ret_skb) {
+                       skb_unlink(skb, &data2->pending);
+                       found = true;
+                       break;
+               }
+       }
+
+       /* not found */
+       if (!found)
+               goto out;
+
+       /* Tx info received because the frame was broadcasted on user space,
+        so we get all the necessary info: tx attempts and skb control buff */
+
+       tx_attempts = (struct hwsim_tx_rate *)nla_data(
+                      info->attrs[HWSIM_ATTR_TX_INFO]);
+
+       /* now send back TX status */
+       txi = IEEE80211_SKB_CB(skb);
+
+       if (txi->control.vif)
+               hwsim_check_magic(txi->control.vif);
+       if (txi->control.sta)
+               hwsim_check_sta_magic(txi->control.sta);
+
+       ieee80211_tx_info_clear_status(txi);
+
+       for (i = 0; i < IEEE80211_TX_MAX_RATES; i++) {
+               txi->status.rates[i].idx = tx_attempts[i].idx;
+               txi->status.rates[i].count = tx_attempts[i].count;
+               /*txi->status.rates[i].flags = 0;*/
+       }
+
+       txi->status.ack_signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
+
+       if (!(hwsim_flags & HWSIM_TX_CTL_NO_ACK) &&
+          (hwsim_flags & HWSIM_TX_STAT_ACK)) {
+               if (skb->len >= 16) {
+                       hdr = (struct ieee80211_hdr *) skb->data;
+                       mac80211_hwsim_monitor_ack(data2->hw, hdr->addr2);
+               }
+       }
+       ieee80211_tx_status_irqsafe(data2->hw, skb);
+       return 0;
+out:
+       return -EINVAL;
+
+}
+
+static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
+                                         struct genl_info *info)
+{
+
+       struct mac80211_hwsim_data  *data2;
+       struct ieee80211_rx_status rx_status;
+       struct mac_address *dst;
+       int frame_data_len;
+       char *frame_data;
+       struct sk_buff *skb = NULL;
+
+       if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] ||
+          !info->attrs[HWSIM_ATTR_FRAME] ||
+          !info->attrs[HWSIM_ATTR_RX_RATE] ||
+          !info->attrs[HWSIM_ATTR_SIGNAL])
+               goto out;
+
+       dst = (struct mac_address *)nla_data(
+                                  info->attrs[HWSIM_ATTR_ADDR_RECEIVER]);
+
+       frame_data_len = nla_len(info->attrs[HWSIM_ATTR_FRAME]);
+       frame_data = (char *)nla_data(info->attrs[HWSIM_ATTR_FRAME]);
+
+       /* Allocate new skb here */
+       skb = alloc_skb(frame_data_len, GFP_KERNEL);
+       if (skb == NULL)
+               goto err;
+
+       if (frame_data_len <= IEEE80211_MAX_DATA_LEN) {
+               /* Copy the data */
+               memcpy(skb_put(skb, frame_data_len), frame_data,
+                      frame_data_len);
+       } else
+               goto err;
+
+       data2 = get_hwsim_data_ref_from_addr(dst);
+
+       if (data2 == NULL)
+               goto out;
+
+       /* check if radio is configured properly */
+
+       if (data2->idle || !data2->started || !data2->channel)
+               goto out;
+
+       /*A frame is received from user space*/
+       memset(&rx_status, 0, sizeof(rx_status));
+       rx_status.freq = data2->channel->center_freq;
+       rx_status.band = data2->channel->band;
+       rx_status.rate_idx = nla_get_u32(info->attrs[HWSIM_ATTR_RX_RATE]);
+       rx_status.signal = nla_get_u32(info->attrs[HWSIM_ATTR_SIGNAL]);
+
+       memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+       ieee80211_rx_irqsafe(data2->hw, skb);
+
+       return 0;
+err:
+       printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__);
+       goto out;
+out:
+       dev_kfree_skb(skb);
+       return -EINVAL;
+}
+
+static int hwsim_register_received_nl(struct sk_buff *skb_2,
+                                     struct genl_info *info)
+{
+       if (info == NULL)
+               goto out;
+
+       wmediumd_pid = info->snd_pid;
+
+       printk(KERN_DEBUG "mac80211_hwsim: received a REGISTER, "
+       "switching to wmediumd mode with pid %d\n", info->snd_pid);
+
+       return 0;
+out:
+       printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__);
+       return -EINVAL;
+}
+
+/* Generic Netlink operations array */
+static struct genl_ops hwsim_ops[] = {
+       {
+               .cmd = HWSIM_CMD_REGISTER,
+               .policy = hwsim_genl_policy,
+               .doit = hwsim_register_received_nl,
+               .flags = GENL_ADMIN_PERM,
+       },
+       {
+               .cmd = HWSIM_CMD_FRAME,
+               .policy = hwsim_genl_policy,
+               .doit = hwsim_cloned_frame_received_nl,
+       },
+       {
+               .cmd = HWSIM_CMD_TX_INFO_FRAME,
+               .policy = hwsim_genl_policy,
+               .doit = hwsim_tx_info_frame_received_nl,
+       },
+};
+
+static int mac80211_hwsim_netlink_notify(struct notifier_block *nb,
+                                        unsigned long state,
+                                        void *_notify)
+{
+       struct netlink_notify *notify = _notify;
+
+       if (state != NETLINK_URELEASE)
+               return NOTIFY_DONE;
+
+       if (notify->pid == wmediumd_pid) {
+               printk(KERN_INFO "mac80211_hwsim: wmediumd released netlink"
+                      " socket, switching to perfect channel medium\n");
+               wmediumd_pid = 0;
+       }
+       return NOTIFY_DONE;
+
+}
+
+static struct notifier_block hwsim_netlink_notifier = {
+       .notifier_call = mac80211_hwsim_netlink_notify,
+};
+
+static int hwsim_init_netlink(void)
+{
+       int rc;
+       printk(KERN_INFO "mac80211_hwsim: initializing netlink\n");
+
+       wmediumd_pid = 0;
+
+       rc = genl_register_family_with_ops(&hwsim_genl_family,
+               hwsim_ops, ARRAY_SIZE(hwsim_ops));
+       if (rc)
+               goto failure;
+
+       rc = netlink_register_notifier(&hwsim_netlink_notifier);
+       if (rc)
+               goto failure;
+
+       return 0;
+
+failure:
+       printk(KERN_DEBUG "mac80211_hwsim: error occured in %s\n", __func__);
+       return -EINVAL;
+}
+
+static void hwsim_exit_netlink(void)
+{
+       int ret;
+
+       printk(KERN_INFO "mac80211_hwsim: closing netlink\n");
+       /* unregister the notifier */
+       netlink_unregister_notifier(&hwsim_netlink_notifier);
+       /* unregister the family */
+       ret = genl_unregister_family(&hwsim_genl_family);
+       if (ret)
+               printk(KERN_DEBUG "mac80211_hwsim: "
+                      "unregister family %i\n", ret);
+}
+
 static int __init init_mac80211_hwsim(void)
 {
        int i, err = 0;
@@ -1298,6 +1706,7 @@ static int __init init_mac80211_hwsim(void)
                        goto failed_drvdata;
                }
                data->dev->driver = &mac80211_hwsim_driver;
+               skb_queue_head_init(&data->pending);
 
                SET_IEEE80211_DEV(hw, data->dev);
                addr[3] = i >> 8;
@@ -1379,6 +1788,10 @@ static int __init init_mac80211_hwsim(void)
                data->group = 1;
                mutex_init(&data->mutex);
 
+               /* Enable frame retransmissions for lossy channels */
+               hw->max_rates = 4;
+               hw->max_rate_tries = 11;
+
                /* Work to be done prior to ieee80211_register_hw() */
                switch (regtest) {
                case HWSIM_REGTEST_DISABLED:
@@ -1515,12 +1928,29 @@ static int __init init_mac80211_hwsim(void)
        if (hwsim_mon == NULL)
                goto failed;
 
-       err = register_netdev(hwsim_mon);
+       rtnl_lock();
+
+       err = dev_alloc_name(hwsim_mon, hwsim_mon->name);
        if (err < 0)
                goto failed_mon;
 
+
+       err = register_netdevice(hwsim_mon);
+       if (err < 0)
+               goto failed_mon;
+
+       rtnl_unlock();
+
+       err = hwsim_init_netlink();
+       if (err < 0)
+               goto failed_nl;
+
        return 0;
 
+failed_nl:
+       printk(KERN_DEBUG "mac_80211_hwsim: failed initializing netlink\n");
+       return err;
+
 failed_mon:
        rtnl_unlock();
        free_netdev(hwsim_mon);
@@ -1541,6 +1971,8 @@ static void __exit exit_mac80211_hwsim(void)
 {
        printk(KERN_DEBUG "mac80211_hwsim: unregister radios\n");
 
+       hwsim_exit_netlink();
+
        mac80211_hwsim_free();
        unregister_netdev(hwsim_mon);
 }
diff --git a/drivers/net/wireless/mac80211_hwsim.h b/drivers/net/wireless/mac80211_hwsim.h
new file mode 100644 (file)
index 0000000..afaad5a
--- /dev/null
@@ -0,0 +1,133 @@
+/*
+ * mac80211_hwsim - software simulator of 802.11 radio(s) for mac80211
+ * Copyright (c) 2008, Jouni Malinen <j@w1.fi>
+ * Copyright (c) 2011, Javier Lopez <jlopex@gmail.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#ifndef __MAC80211_HWSIM_H
+#define __MAC80211_HWSIM_H
+
+/**
+ * enum hwsim_tx_control_flags - flags to describe transmission info/status
+ *
+ * These flags are used to give the wmediumd extra information in order to
+ * modify its behavior for each frame
+ *
+ * @HWSIM_TX_CTL_REQ_TX_STATUS: require TX status callback for this frame.
+ * @HWSIM_TX_CTL_NO_ACK: tell the wmediumd not to wait for an ack
+ * @HWSIM_TX_STAT_ACK: Frame was acknowledged
+ *
+ */
+enum hwsim_tx_control_flags {
+       HWSIM_TX_CTL_REQ_TX_STATUS              = BIT(0),
+       HWSIM_TX_CTL_NO_ACK                     = BIT(1),
+       HWSIM_TX_STAT_ACK                       = BIT(2),
+};
+
+/**
+ * DOC: Frame transmission/registration support
+ *
+ * Frame transmission and registration support exists to allow userspace
+ * entities such as wmediumd to receive and process all broadcasted
+ * frames from a mac80211_hwsim radio device.
+ *
+ * This allow user space applications to decide if the frame should be
+ * dropped or not and implement a wireless medium simulator at user space.
+ *
+ * Registration is done by sending a register message to the driver and
+ * will be automatically unregistered if the user application doesn't
+ * responds to sent frames.
+ * Once registered the user application has to take responsibility of
+ * broadcasting the frames to all listening mac80211_hwsim radio
+ * interfaces.
+ *
+ * For more technical details, see the corresponding command descriptions
+ * below.
+ */
+
+/**
+ * enum hwsim_commands - supported hwsim commands
+ *
+ * @HWSIM_CMD_UNSPEC: unspecified command to catch errors
+ *
+ * @HWSIM_CMD_REGISTER: request to register and received all broadcasted
+ *     frames by any mac80211_hwsim radio device.
+ * @HWSIM_CMD_FRAME: send/receive a broadcasted frame from/to kernel/user
+ * space, uses:
+ *     %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_ADDR_RECEIVER,
+ *     %HWSIM_ATTR_FRAME, %HWSIM_ATTR_FLAGS, %HWSIM_ATTR_RX_RATE,
+ *     %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE
+ * @HWSIM_CMD_TX_INFO_FRAME: Transmission info report from user space to
+ * kernel, uses:
+ *     %HWSIM_ATTR_ADDR_TRANSMITTER, %HWSIM_ATTR_FLAGS,
+ *     %HWSIM_ATTR_TX_INFO, %HWSIM_ATTR_SIGNAL, %HWSIM_ATTR_COOKIE
+ * @__HWSIM_CMD_MAX: enum limit
+ */
+enum {
+       HWSIM_CMD_UNSPEC,
+       HWSIM_CMD_REGISTER,
+       HWSIM_CMD_FRAME,
+       HWSIM_CMD_TX_INFO_FRAME,
+       __HWSIM_CMD_MAX,
+};
+#define HWSIM_CMD_MAX (_HWSIM_CMD_MAX - 1)
+
+/**
+ * enum hwsim_attrs - hwsim netlink attributes
+ *
+ * @HWSIM_ATTR_UNSPEC: unspecified attribute to catch errors
+ *
+ * @HWSIM_ATTR_ADDR_RECEIVER: MAC address of the radio device that
+ *     the frame is broadcasted to
+ * @HWSIM_ATTR_ADDR_TRANSMITTER: MAC address of the radio device that
+ *     the frame was broadcasted from
+ * @HWSIM_ATTR_FRAME: Data array
+ * @HWSIM_ATTR_FLAGS: mac80211 transmission flags, used to process
+       properly the frame at user space
+ * @HWSIM_ATTR_RX_RATE: estimated rx rate index for this frame at user
+       space
+ * @HWSIM_ATTR_SIGNAL: estimated RX signal for this frame at user
+       space
+ * @HWSIM_ATTR_TX_INFO: ieee80211_tx_rate array
+ * @HWSIM_ATTR_COOKIE: sk_buff cookie to identify the frame
+ * @__HWSIM_ATTR_MAX: enum limit
+ */
+
+
+enum {
+       HWSIM_ATTR_UNSPEC,
+       HWSIM_ATTR_ADDR_RECEIVER,
+       HWSIM_ATTR_ADDR_TRANSMITTER,
+       HWSIM_ATTR_FRAME,
+       HWSIM_ATTR_FLAGS,
+       HWSIM_ATTR_RX_RATE,
+       HWSIM_ATTR_SIGNAL,
+       HWSIM_ATTR_TX_INFO,
+       HWSIM_ATTR_COOKIE,
+       __HWSIM_ATTR_MAX,
+};
+#define HWSIM_ATTR_MAX (__HWSIM_ATTR_MAX - 1)
+
+/**
+ * struct hwsim_tx_rate - rate selection/status
+ *
+ * @idx: rate index to attempt to send with
+ * @count: number of tries in this rate before going to the next rate
+ *
+ * A value of -1 for @idx indicates an invalid rate and, if used
+ * in an array of retry rates, that no more rates should be tried.
+ *
+ * When used for transmit status reporting, the driver should
+ * always report the rate and number of retries used.
+ *
+ */
+struct hwsim_tx_rate {
+       s8 idx;
+       u8 count;
+} __packed;
+
+#endif /* __MAC80211_HWSIM_H */
index f807447..1a453a6 100644 (file)
@@ -164,12 +164,13 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
        struct mwifiex_tx_param tx_param;
        struct txpd *ptx_pd = NULL;
 
-       if (skb_queue_empty(&pra_list->skb_head)) {
+       skb_src = skb_peek(&pra_list->skb_head);
+       if (!skb_src) {
                spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
                                       ra_list_flags);
                return 0;
        }
-       skb_src = skb_peek(&pra_list->skb_head);
+
        tx_info_src = MWIFIEX_SKB_TXCB(skb_src);
        skb_aggr = dev_alloc_skb(adapter->tx_buf_size);
        if (!skb_aggr) {
@@ -184,17 +185,15 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
        tx_info_aggr->bss_index = tx_info_src->bss_index;
        skb_aggr->priority = skb_src->priority;
 
-       while (skb_src && ((skb_headroom(skb_aggr) + skb_src->len
-                                       + LLC_SNAP_LEN)
-                               <= adapter->tx_buf_size)) {
+       do {
+               /* Check if AMSDU can accommodate this MSDU */
+               if (skb_tailroom(skb_aggr) < (skb_src->len + LLC_SNAP_LEN))
+                       break;
 
-               if (!skb_queue_empty(&pra_list->skb_head))
-                       skb_src = skb_dequeue(&pra_list->skb_head);
-               else
-                       skb_src = NULL;
+               skb_src = skb_dequeue(&pra_list->skb_head);
 
-               if (skb_src)
-                       pra_list->total_pkts_size -= skb_src->len;
+               pra_list->total_pkts_size -= skb_src->len;
+               pra_list->total_pkts--;
 
                atomic_dec(&priv->wmm.tx_pkts_queued);
 
@@ -212,11 +211,15 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
                        return -1;
                }
 
-               if (!skb_queue_empty(&pra_list->skb_head))
-                       skb_src = skb_peek(&pra_list->skb_head);
-               else
-                       skb_src = NULL;
-       }
+               if (skb_tailroom(skb_aggr) < pad) {
+                       pad = 0;
+                       break;
+               }
+               skb_put(skb_aggr, pad);
+
+               skb_src = skb_peek(&pra_list->skb_head);
+
+       } while (skb_src);
 
        spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, ra_list_flags);
 
@@ -230,11 +233,19 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
 
        skb_push(skb_aggr, headroom);
 
-       tx_param.next_pkt_len = ((pra_list->total_pkts_size) ?
-                                (((pra_list->total_pkts_size) >
-                                  adapter->tx_buf_size) ? adapter->
-                                 tx_buf_size : pra_list->total_pkts_size +
-                                 LLC_SNAP_LEN + sizeof(struct txpd)) : 0);
+       /*
+        * Padding per MSDU will affect the length of next
+        * packet and hence the exact length of next packet
+        * is uncertain here.
+        *
+        * Also, aggregation of transmission buffer, while
+        * downloading the data to the card, wont gain much
+        * on the AMSDU packets as the AMSDU packets utilizes
+        * the transmission buffer space to the maximum
+        * (adapter->tx_buf_size).
+        */
+       tx_param.next_pkt_len = 0;
+
        ret = adapter->if_ops.host_to_card(adapter, MWIFIEX_TYPE_DATA,
                                             skb_aggr->data,
                                             skb_aggr->len, &tx_param);
@@ -258,6 +269,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
                skb_queue_tail(&pra_list->skb_head, skb_aggr);
 
                pra_list->total_pkts_size += skb_aggr->len;
+               pra_list->total_pkts++;
 
                atomic_inc(&priv->wmm.tx_pkts_queued);
 
index f058225..4f43443 100644 (file)
@@ -35,8 +35,6 @@ static struct mwifiex_bss_attr mwifiex_bss_sta[] = {
 
 static int drv_mode = DRV_MODE_STA;
 
-static char fw_name[32] = DEFAULT_FW_NAME;
-
 /* Supported drv_mode table */
 static struct mwifiex_drv_mode mwifiex_drv_mode_tbl[] = {
        {
@@ -384,20 +382,8 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
 
        memset(&fw, 0, sizeof(struct mwifiex_fw_image));
 
-       switch (adapter->revision_id) {
-       case SD8787_W0:
-       case SD8787_W1:
-               strcpy(fw_name, SD8787_W1_FW_NAME);
-               break;
-       case SD8787_A0:
-       case SD8787_A1:
-               strcpy(fw_name, SD8787_AX_FW_NAME);
-               break;
-       default:
-               break;
-       }
-
-       err = request_firmware(&adapter->firmware, fw_name, adapter->dev);
+       err = request_firmware(&adapter->firmware, adapter->fw_name,
+                              adapter->dev);
        if (err < 0) {
                dev_err(adapter->dev, "request_firmware() returned"
                                " error code %#x\n", err);
index 8316b3c..57b183a 100644 (file)
@@ -48,15 +48,6 @@ enum {
 
 #define DRV_MODE_STA       0x1
 
-#define SD8787_W0   0x30
-#define SD8787_W1   0x31
-#define SD8787_A0   0x40
-#define SD8787_A1   0x41
-
-#define DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin"
-#define SD8787_W1_FW_NAME "mrvl/sd8787_uapsta_w1.bin"
-#define SD8787_AX_FW_NAME "mrvl/sd8787_uapsta.bin"
-
 struct mwifiex_drv_mode {
        u16 drv_mode;
        u16 intf_num;
@@ -190,6 +181,7 @@ struct mwifiex_ra_list_tbl {
        struct sk_buff_head skb_head;
        u8 ra[ETH_ALEN];
        u32 total_pkts_size;
+       u32 total_pkts;
        u32 is_11n_enabled;
 };
 
@@ -576,10 +568,10 @@ struct mwifiex_adapter {
        u8 priv_num;
        struct mwifiex_drv_mode *drv_mode;
        const struct firmware *firmware;
+       char fw_name[32];
        struct device *dev;
        bool surprise_removed;
        u32 fw_release_number;
-       u32 revision_id;
        u16 init_wait_q_woken;
        wait_queue_head_t init_wait_q;
        void *card;
index d425dbd..4327b6d 100644 (file)
@@ -1531,6 +1531,7 @@ static int mwifiex_register_dev(struct mwifiex_adapter *adapter)
        sdio_set_drvdata(func, card);
 
        adapter->dev = &func->dev;
+       strcpy(adapter->fw_name, SD8787_DEFAULT_FW_NAME);
 
        return 0;
 
@@ -1552,7 +1553,6 @@ disable_func:
  *        the first interrupt got from bootloader
  *      - Disable host interrupt mask register
  *      - Get SDIO port
- *      - Get revision ID
  *      - Initialize SDIO variables in card
  *      - Allocate MP registers
  *      - Allocate MPA Tx and Rx buffers
@@ -1576,10 +1576,6 @@ static int mwifiex_init_sdio(struct mwifiex_adapter *adapter)
        /* Get SDIO ioport */
        mwifiex_init_sdio_ioport(adapter);
 
-       /* Get revision ID */
-#define REV_ID_REG     0x5c
-       mwifiex_read_reg(adapter, REV_ID_REG, &adapter->revision_id);
-
        /* Initialize SDIO variables in card */
        card->mp_rd_bitmap = 0;
        card->mp_wr_bitmap = 0;
@@ -1751,4 +1747,4 @@ MODULE_AUTHOR("Marvell International Ltd.");
 MODULE_DESCRIPTION("Marvell WiFi-Ex SDIO Driver version " SDIO_VERSION);
 MODULE_VERSION(SDIO_VERSION);
 MODULE_LICENSE("GPL v2");
-MODULE_FIRMWARE("sd8787.bin");
+MODULE_FIRMWARE("mrvl/sd8787_uapsta.bin");
index a0e9bc5..c925376 100644 (file)
@@ -28,6 +28,8 @@
 
 #include "main.h"
 
+#define SD8787_DEFAULT_FW_NAME "mrvl/sd8787_uapsta.bin"
+
 #define BLOCK_MODE     1
 #define BYTE_MODE      0
 
 /* Rx unit register */
 #define CARD_RX_UNIT_REG               0x63
 
-/* Event header Len*/
-#define MWIFIEX_EVENT_HEADER_LEN           8
+/* Event header len w/o 4 bytes of interface header */
+#define MWIFIEX_EVENT_HEADER_LEN           4
 
 /* Max retry number of CMD53 write */
 #define MAX_WRITE_IOMEM_RETRY          2
index 91634da..67b2d0b 100644 (file)
@@ -121,6 +121,7 @@ mwifiex_wmm_allocate_ralist_node(struct mwifiex_adapter *adapter, u8 *ra)
        memcpy(ra_list->ra, ra, ETH_ALEN);
 
        ra_list->total_pkts_size = 0;
+       ra_list->total_pkts = 0;
 
        dev_dbg(adapter->dev, "info: allocated ra_list %p\n", ra_list);
 
@@ -645,6 +646,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_adapter *adapter,
        skb_queue_tail(&ra_list->skb_head, skb);
 
        ra_list->total_pkts_size += skb->len;
+       ra_list->total_pkts++;
 
        atomic_inc(&priv->wmm.tx_pkts_queued);
 
@@ -970,28 +972,6 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
        return NULL;
 }
 
-/*
- * This function gets the number of packets in the Tx queue of a
- * particular RA list.
- */
-static int
-mwifiex_num_pkts_in_txq(struct mwifiex_private *priv,
-                       struct mwifiex_ra_list_tbl *ptr, int max_buf_size)
-{
-       int count = 0, total_size = 0;
-       struct sk_buff *skb, *tmp;
-
-       skb_queue_walk_safe(&ptr->skb_head, skb, tmp) {
-               total_size += skb->len;
-               if (total_size < max_buf_size)
-                       ++count;
-               else
-                       break;
-       }
-
-       return count;
-}
-
 /*
  * This function sends a single packet to firmware for transmission.
  */
@@ -1019,6 +999,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
        dev_dbg(adapter->dev, "data: dequeuing the packet %p %p\n", ptr, skb);
 
        ptr->total_pkts_size -= skb->len;
+       ptr->total_pkts--;
 
        if (!skb_queue_empty(&ptr->skb_head))
                skb_next = skb_peek(&ptr->skb_head);
@@ -1044,6 +1025,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
                skb_queue_tail(&ptr->skb_head, skb);
 
                ptr->total_pkts_size += skb->len;
+               ptr->total_pkts++;
                tx_info->flags |= MWIFIEX_BUF_FLAG_REQUEUED_PKT;
                spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
                                       ra_list_flags);
@@ -1231,9 +1213,9 @@ mwifiex_dequeue_tx_packet(struct mwifiex_adapter *adapter)
                }
 /* Minimum number of AMSDU */
 #define MIN_NUM_AMSDU 2
+
                if (mwifiex_is_amsdu_allowed(priv, tid) &&
-                   (mwifiex_num_pkts_in_txq(priv, ptr, adapter->tx_buf_size) >=
-                    MIN_NUM_AMSDU))
+                               (ptr->total_pkts >= MIN_NUM_AMSDU))
                        mwifiex_11n_aggregate_pkt(priv, ptr, INTF_HEADER_LEN,
                                                  ptr_index, flags);
                        /* ra_list_spinlock has been freed in
index 3226118..8ff43c2 100644 (file)
@@ -10,6 +10,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/kernel.h>
 #include <linux/sched.h>
index 62c6b2b..b0f233f 100644 (file)
@@ -1958,7 +1958,7 @@ irqreturn_t orinoco_interrupt(int irq, void *dev_id)
 
                evstat = hermes_read_regn(hw, EVSTAT);
                events = evstat & hw->inten;
-       };
+       }
 
        orinoco_unlock(priv, &flags);
        return IRQ_HANDLED;
index ee9bc62..7aa509f 100644 (file)
@@ -1,5 +1,6 @@
 #ifndef P54PCI_H
 #define P54PCI_H
+#include <linux/interrupt.h>
 
 /*
  * Defines for PCI based mac80211 Prism54 driver
index ec2c75d..5d0f615 100644 (file)
@@ -18,6 +18,7 @@
  *
  */
 
+#include <linux/hardirq.h>
 #include <linux/module.h>
 #include <linux/slab.h>
 
index c4d0f19..c404038 100644 (file)
@@ -22,6 +22,7 @@
 #ifndef _ISLPCI_DEV_H
 #define _ISLPCI_DEV_H
 
+#include <linux/irqreturn.h>
 #include <linux/netdevice.h>
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
index b5e64d7..9e68e0c 100644 (file)
@@ -17,6 +17,7 @@
  *
  */
 
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/pci.h>
 #include <linux/delay.h>
index 9def1e5..a0a7854 100644 (file)
@@ -83,14 +83,12 @@ config RT2800PCI_RT33XX
 config RT2800PCI_RT35XX
        bool "rt2800pci - Include support for rt35xx devices (EXPERIMENTAL)"
        depends on EXPERIMENTAL
-       default n
+       default y
        ---help---
          This adds support for rt35xx wireless chipset family to the
          rt2800pci driver.
          Supported chips: RT3060, RT3062, RT3562, RT3592
 
-         Support for these devices is non-functional at the moment and is
-         intended for testers and developers.
 
 config RT2800PCI_RT53XX
        bool "rt2800pci - Include support for rt53xx devices (EXPERIMENTAL)"
@@ -154,19 +152,15 @@ config RT2800USB_RT33XX
 config RT2800USB_RT35XX
        bool "rt2800usb - Include support for rt35xx devices (EXPERIMENTAL)"
        depends on EXPERIMENTAL
-       default n
+       default y
        ---help---
          This adds support for rt35xx wireless chipset family to the
          rt2800usb driver.
          Supported chips: RT3572
 
-         Support for these devices is non-functional at the moment and is
-         intended for testers and developers.
-
 config RT2800USB_RT53XX
        bool "rt2800usb - Include support for rt53xx devices (EXPERIMENTAL)"
        depends on EXPERIMENTAL
-       default y
        ---help---
          This adds support for rt53xx wireless chipset family to the
          rt2800pci driver.
index f67bc9b..c69a7d7 100644 (file)
@@ -1740,6 +1740,7 @@ struct mac_iveiv_entry {
 /*
  * BBP 3: RX Antenna
  */
+#define BBP3_RX_ADC                            FIELD8(0x03)
 #define BBP3_RX_ANTENNA                        FIELD8(0x18)
 #define BBP3_HT40_MINUS                        FIELD8(0x20)
 
@@ -1783,22 +1784,34 @@ struct mac_iveiv_entry {
 #define RFCSR1_TX0_PD                  FIELD8(0x08)
 #define RFCSR1_RX1_PD                  FIELD8(0x10)
 #define RFCSR1_TX1_PD                  FIELD8(0x20)
+#define RFCSR1_RX2_PD                  FIELD8(0x40)
+#define RFCSR1_TX2_PD                  FIELD8(0x80)
 
 /*
  * RFCSR 2:
  */
 #define RFCSR2_RESCAL_EN               FIELD8(0x80)
 
+/*
+ * FRCSR 5:
+ */
+#define RFCSR5_R1                      FIELD8(0x0c)
+
 /*
  * RFCSR 6:
  */
 #define RFCSR6_R1                      FIELD8(0x03)
 #define RFCSR6_R2                      FIELD8(0x40)
+#define RFCSR6_TXDIV           FIELD8(0x0c)
 
 /*
  * RFCSR 7:
  */
 #define RFCSR7_RF_TUNING               FIELD8(0x01)
+#define RFCSR7_R02                             FIELD8(0x07)
+#define RFCSR7_R3                              FIELD8(0x08)
+#define RFCSR7_R45                             FIELD8(0x30)
+#define RFCSR7_R67                             FIELD8(0xc0)
 
 /*
  * RFCSR 11:
@@ -1809,11 +1822,13 @@ struct mac_iveiv_entry {
  * RFCSR 12:
  */
 #define RFCSR12_TX_POWER               FIELD8(0x1f)
+#define RFCSR12_DR0                            FIELD8(0xe0)
 
 /*
  * RFCSR 13:
  */
 #define RFCSR13_TX_POWER               FIELD8(0x1f)
+#define RFCSR13_DR0                            FIELD8(0xe0)
 
 /*
  * RFCSR 15:
@@ -2256,6 +2271,7 @@ struct mac_iveiv_entry {
 #define MCU_ANT_SELECT                 0X73
 #define MCU_BBP_SIGNAL                 0x80
 #define MCU_POWER_SAVE                 0x83
+#define MCU_BAND_SELECT                0x91
 
 /*
  * MCU mailbox tokens
index 2a6aa85..84ab7d1 100644 (file)
@@ -401,7 +401,8 @@ int rt2800_load_firmware(struct rt2x00_dev *rt2x00dev,
                return -EBUSY;
 
        if (rt2x00_is_pci(rt2x00dev)) {
-               if (rt2x00_rt(rt2x00dev, RT5390)) {
+               if (rt2x00_rt(rt2x00dev, RT3572) ||
+                   rt2x00_rt(rt2x00dev, RT5390)) {
                        rt2800_register_read(rt2x00dev, AUX_CTRL, &reg);
                        rt2x00_set_field32(&reg, AUX_CTRL_FORCE_PCIE_CLK, 1);
                        rt2x00_set_field32(&reg, AUX_CTRL_WAKE_PCIE_EN, 1);
@@ -600,49 +601,6 @@ void rt2800_process_rxwi(struct queue_entry *entry,
 }
 EXPORT_SYMBOL_GPL(rt2800_process_rxwi);
 
-static bool rt2800_txdone_entry_check(struct queue_entry *entry, u32 reg)
-{
-       __le32 *txwi;
-       u32 word;
-       int wcid, ack, pid;
-       int tx_wcid, tx_ack, tx_pid;
-
-       wcid    = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
-       ack     = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
-       pid     = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
-
-       /*
-        * This frames has returned with an IO error,
-        * so the status report is not intended for this
-        * frame.
-        */
-       if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) {
-               rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
-               return false;
-       }
-
-       /*
-        * Validate if this TX status report is intended for
-        * this entry by comparing the WCID/ACK/PID fields.
-        */
-       txwi = rt2800_drv_get_txwi(entry);
-
-       rt2x00_desc_read(txwi, 1, &word);
-       tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
-       tx_ack  = rt2x00_get_field32(word, TXWI_W1_ACK);
-       tx_pid  = rt2x00_get_field32(word, TXWI_W1_PACKETID);
-
-       if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) {
-               WARNING(entry->queue->rt2x00dev,
-                       "TX status report missed for queue %d entry %d\n",
-               entry->queue->qid, entry->entry_idx);
-               rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN);
-               return false;
-       }
-
-       return true;
-}
-
 void rt2800_txdone_entry(struct queue_entry *entry, u32 status)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
@@ -725,45 +683,6 @@ void rt2800_txdone_entry(struct queue_entry *entry, u32 status)
 }
 EXPORT_SYMBOL_GPL(rt2800_txdone_entry);
 
-void rt2800_txdone(struct rt2x00_dev *rt2x00dev)
-{
-       struct data_queue *queue;
-       struct queue_entry *entry;
-       u32 reg;
-       u8 qid;
-
-       while (kfifo_get(&rt2x00dev->txstatus_fifo, &reg)) {
-
-               /* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus
-                * qid is guaranteed to be one of the TX QIDs
-                */
-               qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
-               queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
-               if (unlikely(!queue)) {
-                       WARNING(rt2x00dev, "Got TX status for an unavailable "
-                                          "queue %u, dropping\n", qid);
-                       continue;
-               }
-
-               /*
-                * Inside each queue, we process each entry in a chronological
-                * order. We first check that the queue is not empty.
-                */
-               entry = NULL;
-               while (!rt2x00queue_empty(queue)) {
-                       entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
-                       if (rt2800_txdone_entry_check(entry, reg))
-                               break;
-               }
-
-               if (!entry || rt2x00queue_empty(queue))
-                       break;
-
-               rt2800_txdone_entry(entry, reg);
-       }
-}
-EXPORT_SYMBOL_GPL(rt2800_txdone);
-
 void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc)
 {
        struct rt2x00_dev *rt2x00dev = entry->queue->rt2x00dev;
@@ -1355,7 +1274,7 @@ static void rt2800_config_ht_opmode(struct rt2x00_dev *rt2x00dev,
                        gf20_rate = gf40_rate = 0x0003;
                }
                break;
-       };
+       }
 
        /* check for STAs not supporting greenfield mode */
        if (any_sta_nongf)
@@ -1433,6 +1352,40 @@ void rt2800_config_erp(struct rt2x00_dev *rt2x00dev, struct rt2x00lib_erp *erp,
 }
 EXPORT_SYMBOL_GPL(rt2800_config_erp);
 
+static void rt2800_config_3572bt_ant(struct rt2x00_dev *rt2x00dev)
+{
+       u32 reg;
+       u16 eeprom;
+       u8 led_ctrl, led_g_mode, led_r_mode;
+
+       rt2800_register_read(rt2x00dev, GPIO_SWITCH, &reg);
+       if (rt2x00dev->curr_band == IEEE80211_BAND_5GHZ) {
+               rt2x00_set_field32(&reg, GPIO_SWITCH_0, 1);
+               rt2x00_set_field32(&reg, GPIO_SWITCH_1, 1);
+       } else {
+               rt2x00_set_field32(&reg, GPIO_SWITCH_0, 0);
+               rt2x00_set_field32(&reg, GPIO_SWITCH_1, 0);
+       }
+       rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg);
+
+       rt2800_register_read(rt2x00dev, LED_CFG, &reg);
+       led_g_mode = rt2x00_get_field32(reg, LED_CFG_LED_POLAR) ? 3 : 0;
+       led_r_mode = rt2x00_get_field32(reg, LED_CFG_LED_POLAR) ? 0 : 3;
+       if (led_g_mode != rt2x00_get_field32(reg, LED_CFG_G_LED_MODE) ||
+           led_r_mode != rt2x00_get_field32(reg, LED_CFG_R_LED_MODE)) {
+               rt2x00_eeprom_read(rt2x00dev, EEPROM_FREQ, &eeprom);
+               led_ctrl = rt2x00_get_field16(eeprom, EEPROM_FREQ_LED_MODE);
+               if (led_ctrl == 0 || led_ctrl > 0x40) {
+                       rt2x00_set_field32(&reg, LED_CFG_G_LED_MODE, led_g_mode);
+                       rt2x00_set_field32(&reg, LED_CFG_R_LED_MODE, led_r_mode);
+                       rt2800_register_write(rt2x00dev, LED_CFG, reg);
+               } else {
+                       rt2800_mcu_request(rt2x00dev, MCU_BAND_SELECT, 0xff,
+                                          (led_g_mode << 2) | led_r_mode, 1);
+               }
+       }
+}
+
 static void rt2800_set_ant_diversity(struct rt2x00_dev *rt2x00dev,
                                     enum antenna ant)
 {
@@ -1463,6 +1416,10 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant)
        rt2800_bbp_read(rt2x00dev, 1, &r1);
        rt2800_bbp_read(rt2x00dev, 3, &r3);
 
+       if (rt2x00_rt(rt2x00dev, RT3572) &&
+           test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags))
+               rt2800_config_3572bt_ant(rt2x00dev);
+
        /*
         * Configure the TX antenna.
         */
@@ -1471,7 +1428,11 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant)
                rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);
                break;
        case 2:
-               rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2);
+               if (rt2x00_rt(rt2x00dev, RT3572) &&
+                   test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags))
+                       rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 1);
+               else
+                       rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 2);
                break;
        case 3:
                rt2x00_set_field8(&r1, BBP1_TX_ANTENNA, 0);
@@ -1496,7 +1457,15 @@ void rt2800_config_ant(struct rt2x00_dev *rt2x00dev, struct antenna_setup *ant)
                rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 0);
                break;
        case 2:
-               rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 1);
+               if (rt2x00_rt(rt2x00dev, RT3572) &&
+                   test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) {
+                       rt2x00_set_field8(&r3, BBP3_RX_ADC, 1);
+                       rt2x00_set_field8(&r3, BBP3_RX_ANTENNA,
+                               rt2x00dev->curr_band == IEEE80211_BAND_5GHZ);
+                       rt2800_set_ant_diversity(rt2x00dev, ANTENNA_B);
+               } else {
+                       rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 1);
+               }
                break;
        case 3:
                rt2x00_set_field8(&r3, BBP3_RX_ANTENNA, 2);
@@ -1630,6 +1599,161 @@ static void rt2800_config_channel_rf3xxx(struct rt2x00_dev *rt2x00dev,
        rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);
 }
 
+static void rt2800_config_channel_rf3052(struct rt2x00_dev *rt2x00dev,
+                                        struct ieee80211_conf *conf,
+                                        struct rf_channel *rf,
+                                        struct channel_info *info)
+{
+       u8 rfcsr;
+       u32 reg;
+
+       if (rf->channel <= 14) {
+               rt2800_bbp_write(rt2x00dev, 25, 0x15);
+               rt2800_bbp_write(rt2x00dev, 26, 0x85);
+       } else {
+               rt2800_bbp_write(rt2x00dev, 25, 0x09);
+               rt2800_bbp_write(rt2x00dev, 26, 0xff);
+       }
+
+       rt2800_rfcsr_write(rt2x00dev, 2, rf->rf1);
+       rt2800_rfcsr_write(rt2x00dev, 3, rf->rf3);
+
+       rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR6_R1, rf->rf2);
+       if (rf->channel <= 14)
+               rt2x00_set_field8(&rfcsr, RFCSR6_TXDIV, 2);
+       else
+               rt2x00_set_field8(&rfcsr, RFCSR6_TXDIV, 1);
+       rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 5, &rfcsr);
+       if (rf->channel <= 14)
+               rt2x00_set_field8(&rfcsr, RFCSR5_R1, 1);
+       else
+               rt2x00_set_field8(&rfcsr, RFCSR5_R1, 2);
+       rt2800_rfcsr_write(rt2x00dev, 5, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 12, &rfcsr);
+       if (rf->channel <= 14) {
+               rt2x00_set_field8(&rfcsr, RFCSR12_DR0, 3);
+               rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER,
+                               (info->default_power1 & 0x3) |
+                               ((info->default_power1 & 0xC) << 1));
+       } else {
+               rt2x00_set_field8(&rfcsr, RFCSR12_DR0, 7);
+               rt2x00_set_field8(&rfcsr, RFCSR12_TX_POWER,
+                               (info->default_power1 & 0x3) |
+                               ((info->default_power1 & 0xC) << 1));
+       }
+       rt2800_rfcsr_write(rt2x00dev, 12, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 13, &rfcsr);
+       if (rf->channel <= 14) {
+               rt2x00_set_field8(&rfcsr, RFCSR13_DR0, 3);
+               rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER,
+                               (info->default_power2 & 0x3) |
+                               ((info->default_power2 & 0xC) << 1));
+       } else {
+               rt2x00_set_field8(&rfcsr, RFCSR13_DR0, 7);
+               rt2x00_set_field8(&rfcsr, RFCSR13_TX_POWER,
+                               (info->default_power2 & 0x3) |
+                               ((info->default_power2 & 0xC) << 1));
+       }
+       rt2800_rfcsr_write(rt2x00dev, 13, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 1, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR1_RF_BLOCK_EN, 1);
+       rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 0);
+       rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 0);
+       rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 0);
+       rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 0);
+       if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags)) {
+               if (rf->channel <= 14) {
+                       rt2x00_set_field8(&rfcsr, RFCSR1_RX0_PD, 1);
+                       rt2x00_set_field8(&rfcsr, RFCSR1_TX0_PD, 1);
+               }
+               rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 1);
+               rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 1);
+       } else {
+               switch (rt2x00dev->default_ant.tx_chain_num) {
+               case 1:
+                       rt2x00_set_field8(&rfcsr, RFCSR1_TX1_PD, 1);
+               case 2:
+                       rt2x00_set_field8(&rfcsr, RFCSR1_TX2_PD, 1);
+                       break;
+               }
+
+               switch (rt2x00dev->default_ant.rx_chain_num) {
+               case 1:
+                       rt2x00_set_field8(&rfcsr, RFCSR1_RX1_PD, 1);
+               case 2:
+                       rt2x00_set_field8(&rfcsr, RFCSR1_RX2_PD, 1);
+                       break;
+               }
+       }
+       rt2800_rfcsr_write(rt2x00dev, 1, rfcsr);
+
+       rt2800_rfcsr_read(rt2x00dev, 23, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR23_FREQ_OFFSET, rt2x00dev->freq_offset);
+       rt2800_rfcsr_write(rt2x00dev, 23, rfcsr);
+
+       rt2800_rfcsr_write(rt2x00dev, 24,
+                             rt2x00dev->calibration[conf_is_ht40(conf)]);
+       rt2800_rfcsr_write(rt2x00dev, 31,
+                             rt2x00dev->calibration[conf_is_ht40(conf)]);
+
+       if (rf->channel <= 14) {
+               rt2800_rfcsr_write(rt2x00dev, 7, 0xd8);
+               rt2800_rfcsr_write(rt2x00dev, 9, 0xc3);
+               rt2800_rfcsr_write(rt2x00dev, 10, 0xf1);
+               rt2800_rfcsr_write(rt2x00dev, 11, 0xb9);
+               rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
+               rt2800_rfcsr_write(rt2x00dev, 16, 0x4c);
+               rt2800_rfcsr_write(rt2x00dev, 17, 0x23);
+               rt2800_rfcsr_write(rt2x00dev, 19, 0x93);
+               rt2800_rfcsr_write(rt2x00dev, 20, 0xb3);
+               rt2800_rfcsr_write(rt2x00dev, 25, 0x15);
+               rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
+               rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 29, 0x9b);
+       } else {
+               rt2800_rfcsr_write(rt2x00dev, 7, 0x14);
+               rt2800_rfcsr_write(rt2x00dev, 9, 0xc0);
+               rt2800_rfcsr_write(rt2x00dev, 10, 0xf1);
+               rt2800_rfcsr_write(rt2x00dev, 11, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 15, 0x43);
+               rt2800_rfcsr_write(rt2x00dev, 16, 0x7a);
+               rt2800_rfcsr_write(rt2x00dev, 17, 0x23);
+               if (rf->channel <= 64) {
+                       rt2800_rfcsr_write(rt2x00dev, 19, 0xb7);
+                       rt2800_rfcsr_write(rt2x00dev, 20, 0xf6);
+                       rt2800_rfcsr_write(rt2x00dev, 25, 0x3d);
+               } else if (rf->channel <= 128) {
+                       rt2800_rfcsr_write(rt2x00dev, 19, 0x74);
+                       rt2800_rfcsr_write(rt2x00dev, 20, 0xf4);
+                       rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
+               } else {
+                       rt2800_rfcsr_write(rt2x00dev, 19, 0x72);
+                       rt2800_rfcsr_write(rt2x00dev, 20, 0xf3);
+                       rt2800_rfcsr_write(rt2x00dev, 25, 0x01);
+               }
+               rt2800_rfcsr_write(rt2x00dev, 26, 0x87);
+               rt2800_rfcsr_write(rt2x00dev, 27, 0x01);
+               rt2800_rfcsr_write(rt2x00dev, 29, 0x9f);
+       }
+
+       rt2800_register_read(rt2x00dev, GPIO_CTRL_CFG, &reg);
+       rt2x00_set_field32(&reg, GPIO_CTRL_CFG_GPIOD_BIT7, 0);
+       if (rf->channel <= 14)
+               rt2x00_set_field32(&reg, GPIO_CTRL_CFG_BIT7, 1);
+       else
+               rt2x00_set_field32(&reg, GPIO_CTRL_CFG_BIT7, 0);
+       rt2800_register_write(rt2x00dev, GPIO_CTRL_CFG, reg);
+
+       rt2800_rfcsr_read(rt2x00dev, 7, &rfcsr);
+       rt2x00_set_field8(&rfcsr, RFCSR7_RF_TUNING, 1);
+       rt2800_rfcsr_write(rt2x00dev, 7, rfcsr);
+}
 
 #define RT5390_POWER_BOUND     0x27
 #define RT5390_FREQ_OFFSET_BOUND       0x5f
@@ -1748,9 +1872,10 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
            rt2x00_rf(rt2x00dev, RF3020) ||
            rt2x00_rf(rt2x00dev, RF3021) ||
            rt2x00_rf(rt2x00dev, RF3022) ||
-           rt2x00_rf(rt2x00dev, RF3052) ||
            rt2x00_rf(rt2x00dev, RF3320))
                rt2800_config_channel_rf3xxx(rt2x00dev, conf, rf, info);
+       else if (rt2x00_rf(rt2x00dev, RF3052))
+               rt2800_config_channel_rf3052(rt2x00dev, conf, rf, info);
        else if (rt2x00_rf(rt2x00dev, RF5370) ||
                 rt2x00_rf(rt2x00dev, RF5390))
                rt2800_config_channel_rf53xx(rt2x00dev, conf, rf, info);
@@ -1777,7 +1902,10 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
                        }
                }
        } else {
-               rt2800_bbp_write(rt2x00dev, 82, 0xf2);
+               if (rt2x00_rt(rt2x00dev, RT3572))
+                       rt2800_bbp_write(rt2x00dev, 82, 0x94);
+               else
+                       rt2800_bbp_write(rt2x00dev, 82, 0xf2);
 
                if (test_bit(CAPABILITY_EXTERNAL_LNA_A, &rt2x00dev->cap_flags))
                        rt2800_bbp_write(rt2x00dev, 75, 0x46);
@@ -1791,12 +1919,17 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&reg, TX_BAND_CFG_BG, rf->channel <= 14);
        rt2800_register_write(rt2x00dev, TX_BAND_CFG, reg);
 
+       if (rt2x00_rt(rt2x00dev, RT3572))
+               rt2800_rfcsr_write(rt2x00dev, 8, 0);
+
        tx_pin = 0;
 
        /* Turn on unused PA or LNA when not using 1T or 1R */
        if (rt2x00dev->default_ant.tx_chain_num == 2) {
-               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN, 1);
-               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN, 1);
+               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A1_EN,
+                                  rf->channel > 14);
+               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G1_EN,
+                                  rf->channel <= 14);
        }
 
        /* Turn on unused PA or LNA when not using 1T or 1R */
@@ -1809,11 +1942,18 @@ static void rt2800_config_channel(struct rt2x00_dev *rt2x00dev,
        rt2x00_set_field32(&tx_pin, TX_PIN_CFG_LNA_PE_G0_EN, 1);
        rt2x00_set_field32(&tx_pin, TX_PIN_CFG_RFTR_EN, 1);
        rt2x00_set_field32(&tx_pin, TX_PIN_CFG_TRSW_EN, 1);
-       rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, rf->channel <= 14);
+       if (test_bit(CAPABILITY_BT_COEXIST, &rt2x00dev->cap_flags))
+               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN, 1);
+       else
+               rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_G0_EN,
+                                  rf->channel <= 14);
        rt2x00_set_field32(&tx_pin, TX_PIN_CFG_PA_PE_A0_EN, rf->channel > 14);
 
        rt2800_register_write(rt2x00dev, TX_PIN_CFG, tx_pin);
 
+       if (rt2x00_rt(rt2x00dev, RT3572))
+               rt2800_rfcsr_write(rt2x00dev, 8, 0x80);
+
        rt2800_bbp_read(rt2x00dev, 4, &bbp);
        rt2x00_set_field8(&bbp, BBP4_BANDWIDTH, 2 * conf_is_ht40(conf));
        rt2800_bbp_write(rt2x00dev, 4, bbp);
@@ -2413,6 +2553,9 @@ static int rt2800_init_registers(struct rt2x00_dev *rt2x00dev)
                rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
                rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00000000);
                rt2800_register_write(rt2x00dev, TX_SW_CFG2, 0x00000030);
+       } else if (rt2x00_rt(rt2x00dev, RT3572)) {
+               rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000400);
+               rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
        } else if (rt2x00_rt(rt2x00dev, RT5390)) {
                rt2800_register_write(rt2x00dev, TX_SW_CFG0, 0x00000404);
                rt2800_register_write(rt2x00dev, TX_SW_CFG1, 0x00080606);
@@ -2799,6 +2942,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
        }
 
        if (rt2800_is_305x_soc(rt2x00dev) ||
+           rt2x00_rt(rt2x00dev, RT3572) ||
            rt2x00_rt(rt2x00dev, RT5390))
                rt2800_bbp_write(rt2x00dev, 31, 0x08);
 
@@ -2828,6 +2972,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
            rt2x00_rt(rt2x00dev, RT3071) ||
            rt2x00_rt(rt2x00dev, RT3090) ||
            rt2x00_rt(rt2x00dev, RT3390) ||
+           rt2x00_rt(rt2x00dev, RT3572) ||
            rt2x00_rt(rt2x00dev, RT5390)) {
                rt2800_bbp_write(rt2x00dev, 79, 0x13);
                rt2800_bbp_write(rt2x00dev, 80, 0x05);
@@ -2868,6 +3013,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
            rt2x00_rt_rev_gte(rt2x00dev, RT3071, REV_RT3071E) ||
            rt2x00_rt_rev_gte(rt2x00dev, RT3090, REV_RT3090E) ||
            rt2x00_rt_rev_gte(rt2x00dev, RT3390, REV_RT3390E) ||
+           rt2x00_rt(rt2x00dev, RT3572) ||
            rt2x00_rt(rt2x00dev, RT5390) ||
            rt2800_is_305x_soc(rt2x00dev))
                rt2800_bbp_write(rt2x00dev, 103, 0xc0);
@@ -2895,6 +3041,7 @@ static int rt2800_init_bbp(struct rt2x00_dev *rt2x00dev)
        if (rt2x00_rt(rt2x00dev, RT3071) ||
            rt2x00_rt(rt2x00dev, RT3090) ||
            rt2x00_rt(rt2x00dev, RT3390) ||
+           rt2x00_rt(rt2x00dev, RT3572) ||
            rt2x00_rt(rt2x00dev, RT5390)) {
                rt2800_bbp_read(rt2x00dev, 138, &value);
 
@@ -3031,6 +3178,7 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
            !rt2x00_rt(rt2x00dev, RT3071) &&
            !rt2x00_rt(rt2x00dev, RT3090) &&
            !rt2x00_rt(rt2x00dev, RT3390) &&
+           !rt2x00_rt(rt2x00dev, RT3572) &&
            !rt2x00_rt(rt2x00dev, RT5390) &&
            !rt2800_is_305x_soc(rt2x00dev))
                return 0;
@@ -3109,6 +3257,38 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
                rt2800_rfcsr_write(rt2x00dev, 29, 0x8f);
                rt2800_rfcsr_write(rt2x00dev, 30, 0x20);
                rt2800_rfcsr_write(rt2x00dev, 31, 0x0f);
+       } else if (rt2x00_rt(rt2x00dev, RT3572)) {
+               rt2800_rfcsr_write(rt2x00dev, 0, 0x70);
+               rt2800_rfcsr_write(rt2x00dev, 1, 0x81);
+               rt2800_rfcsr_write(rt2x00dev, 2, 0xf1);
+               rt2800_rfcsr_write(rt2x00dev, 3, 0x02);
+               rt2800_rfcsr_write(rt2x00dev, 4, 0x4c);
+               rt2800_rfcsr_write(rt2x00dev, 5, 0x05);
+               rt2800_rfcsr_write(rt2x00dev, 6, 0x4a);
+               rt2800_rfcsr_write(rt2x00dev, 7, 0xd8);
+               rt2800_rfcsr_write(rt2x00dev, 9, 0xc3);
+               rt2800_rfcsr_write(rt2x00dev, 10, 0xf1);
+               rt2800_rfcsr_write(rt2x00dev, 11, 0xb9);
+               rt2800_rfcsr_write(rt2x00dev, 12, 0x70);
+               rt2800_rfcsr_write(rt2x00dev, 13, 0x65);
+               rt2800_rfcsr_write(rt2x00dev, 14, 0xa0);
+               rt2800_rfcsr_write(rt2x00dev, 15, 0x53);
+               rt2800_rfcsr_write(rt2x00dev, 16, 0x4c);
+               rt2800_rfcsr_write(rt2x00dev, 17, 0x23);
+               rt2800_rfcsr_write(rt2x00dev, 18, 0xac);
+               rt2800_rfcsr_write(rt2x00dev, 19, 0x93);
+               rt2800_rfcsr_write(rt2x00dev, 20, 0xb3);
+               rt2800_rfcsr_write(rt2x00dev, 21, 0xd0);
+               rt2800_rfcsr_write(rt2x00dev, 22, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 23, 0x3c);
+               rt2800_rfcsr_write(rt2x00dev, 24, 0x16);
+               rt2800_rfcsr_write(rt2x00dev, 25, 0x15);
+               rt2800_rfcsr_write(rt2x00dev, 26, 0x85);
+               rt2800_rfcsr_write(rt2x00dev, 27, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 28, 0x00);
+               rt2800_rfcsr_write(rt2x00dev, 29, 0x9b);
+               rt2800_rfcsr_write(rt2x00dev, 30, 0x09);
+               rt2800_rfcsr_write(rt2x00dev, 31, 0x10);
        } else if (rt2800_is_305x_soc(rt2x00dev)) {
                rt2800_rfcsr_write(rt2x00dev, 0, 0x50);
                rt2800_rfcsr_write(rt2x00dev, 1, 0x01);
@@ -3258,6 +3438,19 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
                rt2800_register_read(rt2x00dev, GPIO_SWITCH, &reg);
                rt2x00_set_field32(&reg, GPIO_SWITCH_5, 0);
                rt2800_register_write(rt2x00dev, GPIO_SWITCH, reg);
+       } else if (rt2x00_rt(rt2x00dev, RT3572)) {
+               rt2800_rfcsr_read(rt2x00dev, 6, &rfcsr);
+               rt2x00_set_field8(&rfcsr, RFCSR6_R2, 1);
+               rt2800_rfcsr_write(rt2x00dev, 6, rfcsr);
+
+               rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
+               rt2x00_set_field32(&reg, LDO_CFG0_LDO_CORE_VLEVEL, 3);
+               rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
+               rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
+               msleep(1);
+               rt2800_register_read(rt2x00dev, LDO_CFG0, &reg);
+               rt2x00_set_field32(&reg, LDO_CFG0_BGSEL, 1);
+               rt2800_register_write(rt2x00dev, LDO_CFG0, reg);
        }
 
        /*
@@ -3270,7 +3463,8 @@ static int rt2800_init_rfcsr(struct rt2x00_dev *rt2x00dev)
                        rt2800_init_rx_filter(rt2x00dev, true, 0x27, 0x19);
        } else if (rt2x00_rt(rt2x00dev, RT3071) ||
                   rt2x00_rt(rt2x00dev, RT3090) ||
-                  rt2x00_rt(rt2x00dev, RT3390)) {
+                  rt2x00_rt(rt2x00dev, RT3390) ||
+                  rt2x00_rt(rt2x00dev, RT3572)) {
                rt2x00dev->calibration[0] =
                        rt2800_init_rx_filter(rt2x00dev, false, 0x07, 0x13);
                rt2x00dev->calibration[1] =
index f2d1594..69deb31 100644 (file)
@@ -152,7 +152,6 @@ void rt2800_write_tx_data(struct queue_entry *entry,
                          struct txentry_desc *txdesc);
 void rt2800_process_rxwi(struct queue_entry *entry, struct rxdone_entry_desc *txdesc);
 
-void rt2800_txdone(struct rt2x00_dev *rt2x00dev);
 void rt2800_txdone_entry(struct queue_entry *entry, u32 status);
 
 void rt2800_write_beacon(struct queue_entry *entry, struct txentry_desc *txdesc);
index cc4a54f..9ccc537 100644 (file)
@@ -219,7 +219,7 @@ static void rt2800pci_start_queue(struct data_queue *queue)
                break;
        default:
                break;
-       };
+       }
 }
 
 static void rt2800pci_kick_queue(struct data_queue *queue)
@@ -501,7 +501,9 @@ static int rt2800pci_init_registers(struct rt2x00_dev *rt2x00dev)
        rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e1f);
        rt2x00pci_register_write(rt2x00dev, PBF_SYS_CTRL, 0x00000e00);
 
-       if (rt2x00_rt(rt2x00dev, RT5390)) {
+       if (rt2x00_is_pcie(rt2x00dev) &&
+           (rt2x00_rt(rt2x00dev, RT3572) ||
+            rt2x00_rt(rt2x00dev, RT5390))) {
                rt2x00pci_register_read(rt2x00dev, AUX_CTRL, &reg);
                rt2x00_set_field32(&reg, AUX_CTRL_FORCE_PCIE_CLK, 1);
                rt2x00_set_field32(&reg, AUX_CTRL_WAKE_PCIE_EN, 1);
index ba82c97..6e92298 100644 (file)
@@ -457,6 +457,87 @@ static int rt2800usb_get_tx_data_len(struct queue_entry *entry)
 /*
  * TX control handlers
  */
+static bool rt2800usb_txdone_entry_check(struct queue_entry *entry, u32 reg)
+{
+       __le32 *txwi;
+       u32 word;
+       int wcid, ack, pid;
+       int tx_wcid, tx_ack, tx_pid;
+
+       wcid    = rt2x00_get_field32(reg, TX_STA_FIFO_WCID);
+       ack     = rt2x00_get_field32(reg, TX_STA_FIFO_TX_ACK_REQUIRED);
+       pid     = rt2x00_get_field32(reg, TX_STA_FIFO_PID_TYPE);
+
+       /*
+        * This frames has returned with an IO error,
+        * so the status report is not intended for this
+        * frame.
+        */
+       if (test_bit(ENTRY_DATA_IO_FAILED, &entry->flags)) {
+               rt2x00lib_txdone_noinfo(entry, TXDONE_FAILURE);
+               return false;
+       }
+
+       /*
+        * Validate if this TX status report is intended for
+        * this entry by comparing the WCID/ACK/PID fields.
+        */
+       txwi = rt2800usb_get_txwi(entry);
+
+       rt2x00_desc_read(txwi, 1, &word);
+       tx_wcid = rt2x00_get_field32(word, TXWI_W1_WIRELESS_CLI_ID);
+       tx_ack  = rt2x00_get_field32(word, TXWI_W1_ACK);
+       tx_pid  = rt2x00_get_field32(word, TXWI_W1_PACKETID);
+
+       if ((wcid != tx_wcid) || (ack != tx_ack) || (pid != tx_pid)) {
+               WARNING(entry->queue->rt2x00dev,
+                       "TX status report missed for queue %d entry %d\n",
+               entry->queue->qid, entry->entry_idx);
+               rt2x00lib_txdone_noinfo(entry, TXDONE_UNKNOWN);
+               return false;
+       }
+
+       return true;
+}
+
+static void rt2800usb_txdone(struct rt2x00_dev *rt2x00dev)
+{
+       struct data_queue *queue;
+       struct queue_entry *entry;
+       u32 reg;
+       u8 qid;
+
+       while (kfifo_get(&rt2x00dev->txstatus_fifo, &reg)) {
+
+               /* TX_STA_FIFO_PID_QUEUE is a 2-bit field, thus
+                * qid is guaranteed to be one of the TX QIDs
+                */
+               qid = rt2x00_get_field32(reg, TX_STA_FIFO_PID_QUEUE);
+               queue = rt2x00queue_get_tx_queue(rt2x00dev, qid);
+               if (unlikely(!queue)) {
+                       WARNING(rt2x00dev, "Got TX status for an unavailable "
+                                          "queue %u, dropping\n", qid);
+                       continue;
+               }
+
+               /*
+                * Inside each queue, we process each entry in a chronological
+                * order. We first check that the queue is not empty.
+                */
+               entry = NULL;
+               while (!rt2x00queue_empty(queue)) {
+                       entry = rt2x00queue_get_entry(queue, Q_INDEX_DONE);
+                       if (rt2800usb_txdone_entry_check(entry, reg))
+                               break;
+               }
+
+               if (!entry || rt2x00queue_empty(queue))
+                       break;
+
+               rt2800_txdone_entry(entry, reg);
+       }
+}
+
 static void rt2800usb_work_txdone(struct work_struct *work)
 {
        struct rt2x00_dev *rt2x00dev =
@@ -464,7 +545,7 @@ static void rt2800usb_work_txdone(struct work_struct *work)
        struct data_queue *queue;
        struct queue_entry *entry;
 
-       rt2800_txdone(rt2x00dev);
+       rt2800usb_txdone(rt2x00dev);
 
        /*
         * Process any trailing TX status reports for IO failures,
index c446db6..4efaf88 100644 (file)
@@ -29,6 +29,7 @@
 #define RT2X00_H
 
 #include <linux/bitops.h>
+#include <linux/interrupt.h>
 #include <linux/skbuff.h>
 #include <linux/workqueue.h>
 #include <linux/firmware.h>
index 555180d..b704e5b 100644 (file)
@@ -250,7 +250,8 @@ void rt2x00lib_config(struct rt2x00_dev *rt2x00dev,
        if (ieee80211_flags & IEEE80211_CONF_CHANGE_CHANNEL)
                rt2x00link_reset_tuner(rt2x00dev, false);
 
-       if (test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) &&
+       if (test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags) &&
+           test_bit(REQUIRE_PS_AUTOWAKE, &rt2x00dev->cap_flags) &&
            (ieee80211_flags & IEEE80211_CONF_CHANGE_PS) &&
            (conf->flags & IEEE80211_CONF_PS)) {
                beacon_diff = (long)jiffies - (long)rt2x00dev->last_beacon;
index c018d67..939821b 100644 (file)
@@ -146,6 +146,9 @@ static void rt2x00lib_autowakeup(struct work_struct *work)
        struct rt2x00_dev *rt2x00dev =
            container_of(work, struct rt2x00_dev, autowakeup_work.work);
 
+       if (!test_bit(DEVICE_STATE_PRESENT, &rt2x00dev->flags))
+               return;
+
        if (rt2x00dev->ops->lib->set_device_state(rt2x00dev, STATE_AWAKE))
                ERROR(rt2x00dev, "Device failed to wakeup.\n");
        clear_bit(CONFIG_POWERSAVING, &rt2x00dev->flags);
@@ -1160,6 +1163,7 @@ void rt2x00lib_remove_dev(struct rt2x00_dev *rt2x00dev)
         * Stop all work.
         */
        cancel_work_sync(&rt2x00dev->intf_work);
+       cancel_delayed_work_sync(&rt2x00dev->autowakeup_work);
        if (rt2x00_is_usb(rt2x00dev)) {
                del_timer_sync(&rt2x00dev->txstatus_timer);
                cancel_work_sync(&rt2x00dev->rxdone_work);
index ab8c16f..c7fc9de 100644 (file)
@@ -206,7 +206,6 @@ static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry,
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(entry->skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)entry->skb->data;
        struct rt2x00_intf *intf = vif_to_intf(tx_info->control.vif);
-       unsigned long irqflags;
 
        if (!(tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ))
                return;
@@ -227,14 +226,14 @@ static void rt2x00queue_create_tx_descriptor_seq(struct queue_entry *entry,
         * sequence counting per-frame, since those will override the
         * sequence counter given by mac80211.
         */
-       spin_lock_irqsave(&intf->seqlock, irqflags);
+       spin_lock(&intf->seqlock);
 
        if (test_bit(ENTRY_TXD_FIRST_FRAGMENT, &txdesc->flags))
                intf->seqno += 0x10;
        hdr->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
        hdr->seq_ctrl |= cpu_to_le16(intf->seqno);
 
-       spin_unlock_irqrestore(&intf->seqlock, irqflags);
+       spin_unlock(&intf->seqlock);
 
 }
 
index 80db5ca..66b29dc 100644 (file)
@@ -16,6 +16,7 @@
  */
 
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include <linux/delay.h>
index ccb6da3..fb5e43b 100644 (file)
@@ -888,7 +888,6 @@ int rtl_tx_agg_stop(struct ieee80211_hw *hw,
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-       struct rtl_tid_data *tid_data;
        struct rtl_sta_info *sta_entry = NULL;
 
        if (sta == NULL)
@@ -906,7 +905,6 @@ int rtl_tx_agg_stop(struct ieee80211_hw *hw,
                return -EINVAL;
 
        sta_entry = (struct rtl_sta_info *)sta->drv_priv;
-       tid_data = &sta_entry->tids[tid];
        sta_entry->tids[tid].agg.agg_state = RTL_AGG_STOP;
 
        ieee80211_stop_tx_ba_cb_irqsafe(mac->vif, sta->addr, tid);
@@ -918,7 +916,6 @@ int rtl_tx_agg_oper(struct ieee80211_hw *hw,
                struct ieee80211_sta *sta, u16 tid)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_tid_data *tid_data;
        struct rtl_sta_info *sta_entry = NULL;
 
        if (sta == NULL)
@@ -936,7 +933,6 @@ int rtl_tx_agg_oper(struct ieee80211_hw *hw,
                return -EINVAL;
 
        sta_entry = (struct rtl_sta_info *)sta->drv_priv;
-       tid_data = &sta_entry->tids[tid];
        sta_entry->tids[tid].agg.agg_state = RTL_AGG_OPERATIONAL;
 
        return 0;
index 50de6f5..0b56232 100644 (file)
@@ -925,7 +925,7 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct pgpkt_struct target_pkt;
        u8 write_state = PG_STATE_HEADER;
-       int continual = true, dataempty = true, result = true;
+       int continual = true, result = true;
        u16 efuse_addr = 0;
        u8 efuse_data;
        u8 target_word_cnts = 0;
@@ -953,7 +953,6 @@ static int efuse_pg_packet_write(struct ieee80211_hw *hw,
               (EFUSE_MAX_SIZE - EFUSE_OOB_PROTECT_BYTES))) {
 
                if (write_state == PG_STATE_HEADER) {
-                       dataempty = true;
                        badworden = 0x0F;
                        RTPRINT(rtlpriv, FEEPROM, EFUSE_PG,
                                ("efuse PG_STATE_HEADER\n"));
@@ -1176,13 +1175,12 @@ static u16 efuse_get_current_size(struct ieee80211_hw *hw)
 {
        int continual = true;
        u16 efuse_addr = 0;
-       u8 hoffset, hworden;
+       u8 hworden;
        u8 efuse_data, word_cnts;
 
        while (continual && efuse_one_byte_read(hw, efuse_addr, &efuse_data)
               && (efuse_addr < EFUSE_MAX_SIZE)) {
                if (efuse_data != 0xFF) {
-                       hoffset = (efuse_data >> 4) & 0x0F;
                        hworden = efuse_data & 0x0F;
                        word_cnts = efuse_calculate_word_cnts(hworden);
                        efuse_addr = efuse_addr + (word_cnts * 2) + 1;
index a409528..fc44005 100644 (file)
@@ -622,7 +622,7 @@ tx_status_ok:
        if (((rtlpriv->link_info.num_rx_inperiod +
                rtlpriv->link_info.num_tx_inperiod) > 8) ||
                (rtlpriv->link_info.num_rx_inperiod > 2)) {
-               rtl_lps_leave(hw);
+               tasklet_schedule(&rtlpriv->works.ips_leave_tasklet);
        }
 }
 
@@ -644,22 +644,23 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
                .noise = -98,
                .rate = 0,
        };
+       int index = rtlpci->rx_ring[rx_queue_idx].idx;
 
        /*RX NORMAL PKT */
        while (count--) {
                /*rx descriptor */
                struct rtl_rx_desc *pdesc = &rtlpci->rx_ring[rx_queue_idx].desc[
-                               rtlpci->rx_ring[rx_queue_idx].idx];
+                               index];
                /*rx pkt */
                struct sk_buff *skb = rtlpci->rx_ring[rx_queue_idx].rx_buf[
-                               rtlpci->rx_ring[rx_queue_idx].idx];
+                               index];
 
                own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc,
                                                       false, HW_DESC_OWN);
 
                if (own) {
                        /*wait data to be filled by hardware */
-                       return;
+                       break;
                } else {
                        struct ieee80211_hdr *hdr;
                        __le16 fc;
@@ -669,11 +670,6 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
                                                         &rx_status,
                                                         (u8 *) pdesc, skb);
 
-                       pci_unmap_single(rtlpci->pdev,
-                                        *((dma_addr_t *) skb->cb),
-                                        rtlpci->rxbuffersize,
-                                        PCI_DMA_FROMDEVICE);
-
                        skb_put(skb, rtlpriv->cfg->ops->get_desc((u8 *) pdesc,
                                                         false,
                                                         HW_DESC_RXPKT_LEN));
@@ -690,7 +686,22 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
                        hdr = rtl_get_hdr(skb);
                        fc = rtl_get_fc(skb);
 
-                       if (!stats.crc || !stats.hwerror) {
+                       /* try for new buffer - if allocation fails, drop
+                        * frame and reuse old buffer
+                        */
+                       new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
+                       if (unlikely(!new_skb)) {
+                               RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
+                                        DBG_DMESG,
+                                        ("can't alloc skb for rx\n"));
+                               goto done;
+                       }
+                       pci_unmap_single(rtlpci->pdev,
+                                        *((dma_addr_t *) skb->cb),
+                                        rtlpci->rxbuffersize,
+                                        PCI_DMA_FROMDEVICE);
+
+                       if (!stats.crc && !stats.hwerror) {
                                memcpy(IEEE80211_SKB_RXCB(skb), &rx_status,
                                       sizeof(rx_status));
 
@@ -755,23 +766,12 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
                        if (((rtlpriv->link_info.num_rx_inperiod +
                                rtlpriv->link_info.num_tx_inperiod) > 8) ||
                                (rtlpriv->link_info.num_rx_inperiod > 2)) {
-                               rtl_lps_leave(hw);
+                               tasklet_schedule(&rtlpriv->works.ips_leave_tasklet);
                        }
 
-                       new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
-                       if (unlikely(!new_skb)) {
-                               RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
-                                        DBG_DMESG,
-                                        ("can't alloc skb for rx\n"));
-                               goto done;
-                       }
                        skb = new_skb;
-                       /*skb->dev = dev; */
 
-                       rtlpci->rx_ring[rx_queue_idx].rx_buf[rtlpci->
-                                                            rx_ring
-                                                            [rx_queue_idx].
-                                                            idx] = skb;
+                       rtlpci->rx_ring[rx_queue_idx].rx_buf[index] = skb;
                        *((dma_addr_t *) skb->cb) =
                            pci_map_single(rtlpci->pdev, skb_tail_pointer(skb),
                                           rtlpci->rxbuffersize,
@@ -784,23 +784,22 @@ done:
                rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false,
                                            HW_DESC_RXBUFF_ADDR,
                                            (u8 *)&bufferaddress);
-               rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN,
-                                           (u8 *)&tmp_one);
                rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false,
                                            HW_DESC_RXPKT_LEN,
                                            (u8 *)&rtlpci->rxbuffersize);
 
-               if (rtlpci->rx_ring[rx_queue_idx].idx ==
-                   rtlpci->rxringcount - 1)
+               if (index == rtlpci->rxringcount - 1)
                        rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false,
                                                    HW_DESC_RXERO,
                                                    (u8 *)&tmp_one);
 
-               rtlpci->rx_ring[rx_queue_idx].idx =
-                   (rtlpci->rx_ring[rx_queue_idx].idx + 1) %
-                   rtlpci->rxringcount;
+               rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN,
+                                           (u8 *)&tmp_one);
+
+               index = (index + 1) % rtlpci->rxringcount;
        }
 
+       rtlpci->rx_ring[rx_queue_idx].idx = index;
 }
 
 static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
@@ -938,6 +937,11 @@ static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw)
        _rtl_pci_tx_chk_waitq(hw);
 }
 
+static void _rtl_pci_ips_leave_tasklet(struct ieee80211_hw *hw)
+{
+       rtl_lps_leave(hw);
+}
+
 static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1036,6 +1040,9 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw,
        tasklet_init(&rtlpriv->works.irq_prepare_bcn_tasklet,
                     (void (*)(unsigned long))_rtl_pci_prepare_bcn_tasklet,
                     (unsigned long)hw);
+       tasklet_init(&rtlpriv->works.ips_leave_tasklet,
+                    (void (*)(unsigned long))_rtl_pci_ips_leave_tasklet,
+                    (unsigned long)hw);
 }
 
 static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
@@ -1113,6 +1120,13 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
 
                rtlpci->rx_ring[rx_queue_idx].idx = 0;
 
+               /* If amsdu_8k is disabled, set buffersize to 4096. This
+                * change will reduce memory fragmentation.
+                */
+               if (rtlpci->rxbuffersize > 4096 &&
+                   rtlpriv->rtlhal.disable_amsdu_8k)
+                       rtlpci->rxbuffersize = 4096;
+
                for (i = 0; i < rtlpci->rxringcount; i++) {
                        struct sk_buff *skb =
                            dev_alloc_skb(rtlpci->rxbuffersize);
@@ -1498,6 +1512,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw)
 
        synchronize_irq(rtlpci->pdev->irq);
        tasklet_kill(&rtlpriv->works.irq_tasklet);
+       tasklet_kill(&rtlpriv->works.ips_leave_tasklet);
 
        flush_workqueue(rtlpriv->works.rtl_wq);
        destroy_workqueue(rtlpriv->works.rtl_wq);
@@ -1572,6 +1587,7 @@ static void rtl_pci_stop(struct ieee80211_hw *hw)
        set_hal_stop(rtlhal);
 
        rtlpriv->cfg->ops->disable_interrupt(hw);
+       tasklet_kill(&rtlpriv->works.ips_leave_tasklet);
 
        spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags);
        while (ppsc->rfchange_inprogress) {
index 39b0297..d14c13d 100644 (file)
@@ -68,6 +68,7 @@ bool rtl_ps_disable_nic(struct ieee80211_hw *hw)
 
        /*<2> Disable Interrupt */
        rtlpriv->cfg->ops->disable_interrupt(hw);
+       tasklet_kill(&rtlpriv->works.irq_tasklet);
 
        /*<3> Disable Adapter */
        rtlpriv->cfg->ops->hw_disable(hw);
@@ -82,10 +83,8 @@ bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
-       enum rf_pwrstate rtstate;
        bool actionallowed = false;
        u16 rfwait_cnt = 0;
-       unsigned long flag;
 
        /*protect_or_not = true; */
 
@@ -98,10 +97,9 @@ bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
         *should wait to be executed.
         */
        while (true) {
-               spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
+               spin_lock(&rtlpriv->locks.rf_ps_lock);
                if (ppsc->rfchange_inprogress) {
-                       spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock,
-                                              flag);
+                       spin_unlock(&rtlpriv->locks.rf_ps_lock);
 
                        RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
                                 ("RF Change in progress!"
@@ -122,15 +120,12 @@ bool rtl_ps_set_rf_state(struct ieee80211_hw *hw,
                        }
                } else {
                        ppsc->rfchange_inprogress = true;
-                       spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock,
-                                              flag);
+                       spin_unlock(&rtlpriv->locks.rf_ps_lock);
                        break;
                }
        }
 
 no_protect:
-       rtstate = ppsc->rfpwr_state;
-
        switch (state_toset) {
        case ERFON:
                ppsc->rfoff_reason &= (~changesource);
@@ -173,9 +168,9 @@ no_protect:
                rtlpriv->cfg->ops->set_rf_power_state(hw, state_toset);
 
        if (!protect_or_not) {
-               spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
+               spin_lock(&rtlpriv->locks.rf_ps_lock);
                ppsc->rfchange_inprogress = false;
-               spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+               spin_unlock(&rtlpriv->locks.rf_ps_lock);
        }
 
        return actionallowed;
@@ -289,12 +284,11 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw)
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
        enum rf_pwrstate rtstate;
-       unsigned long flags;
 
        if (mac->opmode != NL80211_IFTYPE_STATION)
                return;
 
-       spin_lock_irqsave(&rtlpriv->locks.ips_lock, flags);
+       spin_lock(&rtlpriv->locks.ips_lock);
 
        if (ppsc->inactiveps) {
                rtstate = ppsc->rfpwr_state;
@@ -310,7 +304,7 @@ void rtl_ips_nic_on(struct ieee80211_hw *hw)
                }
        }
 
-       spin_unlock_irqrestore(&rtlpriv->locks.ips_lock, flags);
+       spin_unlock(&rtlpriv->locks.ips_lock);
 }
 
 /*for FW LPS*/
@@ -428,7 +422,6 @@ void rtl_lps_enter(struct ieee80211_hw *hw)
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
        struct rtl_priv *rtlpriv = rtl_priv(hw);
-       unsigned long flag;
 
        if (!ppsc->fwctrl_lps)
                return;
@@ -449,7 +442,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw)
        if (mac->link_state != MAC80211_LINKED)
                return;
 
-       spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
+       spin_lock(&rtlpriv->locks.lps_lock);
 
        /* Idle for a while if we connect to AP a while ago. */
        if (mac->cnt_after_linked >= 2) {
@@ -461,7 +454,7 @@ void rtl_lps_enter(struct ieee80211_hw *hw)
                }
        }
 
-       spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
+       spin_unlock(&rtlpriv->locks.lps_lock);
 }
 
 /*Leave the leisure power save mode.*/
@@ -470,9 +463,8 @@ void rtl_lps_leave(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-       unsigned long flag;
 
-       spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
+       spin_lock(&rtlpriv->locks.lps_lock);
 
        if (ppsc->fwctrl_lps) {
                if (ppsc->dot11_psmode != EACTIVE) {
@@ -493,7 +485,7 @@ void rtl_lps_leave(struct ieee80211_hw *hw)
                        rtl_lps_set_psmode(hw, EACTIVE);
                }
        }
-       spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
+       spin_unlock(&rtlpriv->locks.lps_lock);
 }
 
 /* For sw LPS*/
@@ -582,7 +574,6 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-       unsigned long flag;
 
        if (!rtlpriv->psc.swctrl_lps)
                return;
@@ -595,9 +586,9 @@ void rtl_swlps_rf_awake(struct ieee80211_hw *hw)
                RT_CLEAR_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM);
        }
 
-       spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
+       spin_lock(&rtlpriv->locks.lps_lock);
        rtl_ps_set_rf_state(hw, ERFON, RF_CHANGE_BY_PS, false);
-       spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
+       spin_unlock(&rtlpriv->locks.lps_lock);
 }
 
 void rtl_swlps_rfon_wq_callback(void *data)
@@ -614,7 +605,6 @@ void rtl_swlps_rf_sleep(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
-       unsigned long flag;
        u8 sleep_intv;
 
        if (!rtlpriv->psc.sw_ps_enabled)
@@ -631,16 +621,16 @@ void rtl_swlps_rf_sleep(struct ieee80211_hw *hw)
        if (rtlpriv->link_info.busytraffic)
                return;
 
-       spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flag);
+       spin_lock(&rtlpriv->locks.rf_ps_lock);
        if (rtlpriv->psc.rfchange_inprogress) {
-               spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+               spin_unlock(&rtlpriv->locks.rf_ps_lock);
                return;
        }
-       spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
+       spin_unlock(&rtlpriv->locks.rf_ps_lock);
 
-       spin_lock_irqsave(&rtlpriv->locks.lps_lock, flag);
+       spin_lock(&rtlpriv->locks.lps_lock);
        rtl_ps_set_rf_state(hw, ERFSLEEP, RF_CHANGE_BY_PS, false);
-       spin_unlock_irqrestore(&rtlpriv->locks.lps_lock, flag);
+       spin_unlock(&rtlpriv->locks.lps_lock);
 
        if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_ASPM &&
                !RT_IN_PS_LEVEL(ppsc, RT_PS_LEVEL_ASPM)) {
index 8f6718f..9fedb1f 100644 (file)
@@ -303,22 +303,6 @@ static void _rtl_reg_apply_world_flags(struct wiphy *wiphy,
        return;
 }
 
-static void _rtl_dump_channel_map(struct wiphy *wiphy)
-{
-       enum ieee80211_band band;
-       struct ieee80211_supported_band *sband;
-       struct ieee80211_channel *ch;
-       unsigned int i;
-
-       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
-               if (!wiphy->bands[band])
-                       continue;
-               sband = wiphy->bands[band];
-               for (i = 0; i < sband->n_channels; i++)
-                       ch = &sband->channels[i];
-       }
-}
-
 static int _rtl_reg_notifier_apply(struct wiphy *wiphy,
                                   struct regulatory_request *request,
                                   struct rtl_regulatory *reg)
@@ -336,8 +320,6 @@ static int _rtl_reg_notifier_apply(struct wiphy *wiphy,
                break;
        }
 
-       _rtl_dump_channel_map(wiphy);
-
        return 0;
 }
 
index 50303e1..f9f2370 100644 (file)
@@ -546,7 +546,6 @@ static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        struct rtl8192_tx_ring *ring;
        struct rtl_tx_desc *pdesc;
-       u8 own;
        unsigned long flags;
        struct sk_buff *pskb = NULL;
 
@@ -559,7 +558,6 @@ static bool _rtl92c_cmd_send_packet(struct ieee80211_hw *hw,
        spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 
        pdesc = &ring->desc[0];
-       own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
 
        rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
 
index d2cc815..3b11642 100644 (file)
@@ -1253,10 +1253,9 @@ static void _rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw,
 
        const u32 retrycount = 2;
 
-       u32 bbvalue;
-
        if (t == 0) {
-               bbvalue = rtl_get_bbreg(hw, 0x800, MASKDWORD);
+               /* dummy read */
+               rtl_get_bbreg(hw, 0x800, MASKDWORD);
 
                _rtl92c_phy_save_adda_registers(hw, adda_reg,
                                                rtlphy->adda_backup, 16);
@@ -1762,8 +1761,7 @@ void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
        long result[4][8];
        u8 i, final_candidate;
        bool patha_ok, pathb_ok;
-       long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4,
-           reg_ecc, reg_tmp = 0;
+       long reg_e94, reg_e9c, reg_ea4, reg_eb4, reg_ebc, reg_ec4, reg_tmp = 0;
        bool is12simular, is13simular, is23simular;
        bool start_conttx = false, singletone = false;
        u32 iqk_bb_reg[10] = {
@@ -1841,21 +1839,17 @@ void rtl92c_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
                reg_e94 = result[i][0];
                reg_e9c = result[i][1];
                reg_ea4 = result[i][2];
-               reg_eac = result[i][3];
                reg_eb4 = result[i][4];
                reg_ebc = result[i][5];
                reg_ec4 = result[i][6];
-               reg_ecc = result[i][7];
        }
        if (final_candidate != 0xff) {
                rtlphy->reg_e94 = reg_e94 = result[final_candidate][0];
                rtlphy->reg_e9c = reg_e9c = result[final_candidate][1];
                reg_ea4 = result[final_candidate][2];
-               reg_eac = result[final_candidate][3];
                rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4];
                rtlphy->reg_ebc = reg_ebc = result[final_candidate][5];
                reg_ec4 = result[final_candidate][6];
-               reg_ecc = result[final_candidate][7];
                patha_ok = pathb_ok = true;
        } else {
                rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100;
index defb437..944f55e 100644 (file)
@@ -763,11 +763,9 @@ static void _rtl92ce_hw_configure(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
        u8 reg_bw_opmode;
-       u32 reg_ratr, reg_prsr;
+       u32 reg_prsr;
 
        reg_bw_opmode = BW_OPMODE_20MHZ;
-       reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG |
-           RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
        reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
 
        rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8);
@@ -1196,6 +1194,7 @@ void rtl92ce_disable_interrupt(struct ieee80211_hw *hw)
        rtl_write_dword(rtlpriv, REG_HIMR, IMR8190_DISABLED);
        rtl_write_dword(rtlpriv, REG_HIMRE, IMR8190_DISABLED);
        rtlpci->irq_enabled = false;
+       synchronize_irq(rtlpci->pdev->irq);
 }
 
 static void _rtl92ce_poweroff_adapter(struct ieee80211_hw *hw)
@@ -1969,7 +1968,7 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-       enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate;
+       enum rf_pwrstate e_rfpowerstate_toset;
        u8 u1tmp;
        bool actuallyset = false;
        unsigned long flag;
@@ -1989,8 +1988,6 @@ bool rtl92ce_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
                spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
        }
 
-       cur_rfstate = ppsc->rfpwr_state;
-
        rtl_write_byte(rtlpriv, REG_MAC_PINMUX_CFG, rtl_read_byte(rtlpriv,
                       REG_MAC_PINMUX_CFG)&~(BIT(3)));
 
index abe0fcc..592a10a 100644 (file)
@@ -46,13 +46,12 @@ u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw,
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        u32 original_value, readback_value, bitshift;
        struct rtl_phy *rtlphy = &(rtlpriv->phy);
-       unsigned long flags;
 
        RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), "
                                               "rfpath(%#x), bitmask(%#x)\n",
                                               regaddr, rfpath, bitmask));
 
-       spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+       spin_lock(&rtlpriv->locks.rf_lock);
 
        if (rtlphy->rf_mode != RF_OP_BY_FW) {
                original_value = _rtl92c_phy_rf_serial_read(hw,
@@ -65,7 +64,7 @@ u32 rtl92c_phy_query_rf_reg(struct ieee80211_hw *hw,
        bitshift = _rtl92c_phy_calculate_bit_shift(bitmask);
        readback_value = (original_value & bitmask) >> bitshift;
 
-       spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+       spin_unlock(&rtlpriv->locks.rf_lock);
 
        RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
                 ("regaddr(%#x), rfpath(%#x), "
@@ -120,13 +119,12 @@ void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw,
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_phy *rtlphy = &(rtlpriv->phy);
        u32 original_value, bitshift;
-       unsigned long flags;
 
        RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
                 ("regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
                  regaddr, bitmask, data, rfpath));
 
-       spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+       spin_lock(&rtlpriv->locks.rf_lock);
 
        if (rtlphy->rf_mode != RF_OP_BY_FW) {
                if (bitmask != RFREG_OFFSET_MASK) {
@@ -153,7 +151,7 @@ void rtl92ce_phy_set_rf_reg(struct ieee80211_hw *hw,
                _rtl92c_phy_fw_rf_serial_write(hw, rfpath, regaddr, data);
        }
 
-       spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+       spin_unlock(&rtlpriv->locks.rf_lock);
 
        RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), "
                                               "bitmask(%#x), data(%#x), "
@@ -281,7 +279,6 @@ bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
 {
 
        int i;
-       bool rtstatus = true;
        u32 *radioa_array_table;
        u32 *radiob_array_table;
        u16 radioa_arraylen, radiob_arraylen;
@@ -308,7 +305,6 @@ bool rtl92c_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
                         ("Radio_B:RTL8192CE_RADIOB_1TARRAY\n"));
        }
        RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, ("Radio No %x\n", rfpath));
-       rtstatus = true;
        switch (rfpath) {
        case RF90_PATH_A:
                for (i = 0; i < radioa_arraylen; i = i + 2) {
@@ -521,7 +517,6 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
        u8 i, queue_id;
        struct rtl8192_tx_ring *ring = NULL;
 
-       ppsc->set_rfpowerstate_inprogress = true;
        switch (rfpwr_state) {
        case ERFON:{
                        if ((ppsc->rfpwr_state == ERFOFF) &&
@@ -617,7 +612,6 @@ static bool _rtl92ce_phy_set_rf_power_state(struct ieee80211_hw *hw,
        }
        if (bresult)
                ppsc->rfpwr_state = rfpwr_state;
-       ppsc->set_rfpowerstate_inprogress = false;
        return bresult;
 }
 
index 54b2bd5..2492cc2 100644 (file)
@@ -592,7 +592,6 @@ static void _rtl92ce_translate_rx_signal_stuff(struct ieee80211_hw *hw,
        struct ieee80211_hdr *hdr;
        u8 *tmp_buf;
        u8 *praddr;
-       u8 *psaddr;
        __le16 fc;
        u16 type, c_fc;
        bool packet_matchbssid, packet_toself, packet_beacon;
@@ -604,7 +603,6 @@ static void _rtl92ce_translate_rx_signal_stuff(struct ieee80211_hw *hw,
        c_fc = le16_to_cpu(fc);
        type = WLAN_FC_GET_TYPE(fc);
        praddr = hdr->addr1;
-       psaddr = hdr->addr2;
 
        packet_matchbssid =
            ((IEEE80211_FTYPE_CTL != type) &&
@@ -932,6 +930,7 @@ void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
        if (istx == true) {
                switch (desc_name) {
                case HW_DESC_OWN:
+                       wmb();
                        SET_TX_DESC_OWN(pdesc, 1);
                        break;
                case HW_DESC_TX_NEXTDESC_ADDR:
@@ -945,6 +944,7 @@ void rtl92ce_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
        } else {
                switch (desc_name) {
                case HW_DESC_RXOWN:
+                       wmb();
                        SET_RX_DESC_OWN(pdesc, 1);
                        break;
                case HW_DESC_RXBUFF_ADDR:
index f8514cb..4e057df 100644 (file)
@@ -1113,7 +1113,6 @@ void rtl92c_translate_rx_signal_stuff(struct ieee80211_hw *hw,
        struct ieee80211_hdr *hdr;
        u8 *tmp_buf;
        u8 *praddr;
-       u8 *psaddr;
        __le16 fc;
        u16 type, cpu_fc;
        bool packet_matchbssid, packet_toself, packet_beacon;
@@ -1124,7 +1123,6 @@ void rtl92c_translate_rx_signal_stuff(struct ieee80211_hw *hw,
        cpu_fc = le16_to_cpu(fc);
        type = WLAN_FC_GET_TYPE(fc);
        praddr = hdr->addr1;
-       psaddr = hdr->addr2;
        packet_matchbssid =
            ((IEEE80211_FTYPE_CTL != type) &&
             (!compare_ether_addr(mac->bssid,
index 9a3d023..7285290 100644 (file)
@@ -470,7 +470,6 @@ static bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw,
        u8 i, queue_id;
        struct rtl8192_tx_ring *ring = NULL;
 
-       ppsc->set_rfpowerstate_inprogress = true;
        switch (rfpwr_state) {
        case ERFON:
                if ((ppsc->rfpwr_state == ERFOFF) &&
@@ -590,7 +589,6 @@ static bool _rtl92cu_phy_set_rf_power_state(struct ieee80211_hw *hw,
        }
        if (bresult)
                ppsc->rfpwr_state = rfpwr_state;
-       ppsc->set_rfpowerstate_inprogress = false;
        return bresult;
 }
 
index da86db8..609c7ec 100644 (file)
@@ -222,7 +222,6 @@ static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw)
        u32 low_rssi_thresh = 0;
        u32 middle_rssi_thresh = 0;
        u32 high_rssi_thresh = 0;
-       u8 rssi_level;
        struct ieee80211_sta *sta = NULL;
 
        if (is_hal_stop(rtlhal))
@@ -272,18 +271,14 @@ static void _rtl92s_dm_refresh_rateadaptive_mask(struct ieee80211_hw *hw)
                if (rtlpriv->dm.undecorated_smoothed_pwdb >
                    (long)high_rssi_thresh) {
                        ra->ratr_state = DM_RATR_STA_HIGH;
-                       rssi_level = 1;
                } else if (rtlpriv->dm.undecorated_smoothed_pwdb >
                           (long)middle_rssi_thresh) {
                        ra->ratr_state = DM_RATR_STA_LOW;
-                       rssi_level = 3;
                } else if (rtlpriv->dm.undecorated_smoothed_pwdb >
                           (long)low_rssi_thresh) {
                        ra->ratr_state = DM_RATR_STA_LOW;
-                       rssi_level = 5;
                } else {
                        ra->ratr_state = DM_RATR_STA_ULTRALOW;
-                       rssi_level = 6;
                }
 
                if (ra->pre_ratr_state != ra->ratr_state) {
index 3b5af01..6f91a14 100644 (file)
@@ -358,7 +358,6 @@ int rtl92s_download_fw(struct ieee80211_hw *hw)
        struct fw_priv *pfw_priv = NULL;
        u8 *puc_mappedfile = NULL;
        u32 ul_filelength = 0;
-       u32 file_length = 0;
        u8 fwhdr_size = RT_8192S_FIRMWARE_HDR_SIZE;
        u8 fwstatus = FW_STATUS_INIT;
        bool rtstatus = true;
@@ -370,7 +369,6 @@ int rtl92s_download_fw(struct ieee80211_hw *hw)
        firmware->fwstatus = FW_STATUS_INIT;
 
        puc_mappedfile = firmware->sz_fw_tmpbuffer;
-       file_length = firmware->sz_fw_tmpbufferlen;
 
        /* 1. Retrieve FW header. */
        firmware->pfwheader = (struct fw_hdr *) puc_mappedfile;
index 2e9005d..35dd12d 100644 (file)
@@ -884,12 +884,10 @@ static void _rtl92se_hw_configure(struct ieee80211_hw *hw)
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
        u8 reg_bw_opmode = 0;
-       u32 reg_ratr = 0, reg_rrsr = 0;
+       u32 reg_rrsr = 0;
        u8 regtmp = 0;
 
        reg_bw_opmode = BW_OPMODE_20MHZ;
-       reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG | RATE_ALL_OFDM_1SS |
-                               RATE_ALL_OFDM_2SS;
        reg_rrsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
 
        regtmp = rtl_read_byte(rtlpriv, INIRTSMCS_SEL);
@@ -1122,14 +1120,12 @@ static int _rtl92se_set_media_status(struct ieee80211_hw *hw,
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        u8 bt_msr = rtl_read_byte(rtlpriv, MSR);
-       enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
        u32 temp;
        bt_msr &= ~MSR_LINK_MASK;
 
        switch (type) {
        case NL80211_IFTYPE_UNSPECIFIED:
                bt_msr |= (MSR_LINK_NONE << MSR_LINK_SHIFT);
-               ledaction = LED_CTL_LINK;
                RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
                         ("Set Network type to NO LINK!\n"));
                break;
@@ -1140,7 +1136,6 @@ static int _rtl92se_set_media_status(struct ieee80211_hw *hw,
                break;
        case NL80211_IFTYPE_STATION:
                bt_msr |= (MSR_LINK_MANAGED << MSR_LINK_SHIFT);
-               ledaction = LED_CTL_LINK;
                RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
                         ("Set Network type to STA!\n"));
                break;
@@ -1231,6 +1226,7 @@ void rtl92se_disable_interrupt(struct ieee80211_hw *hw)
        rtl_write_dword(rtlpriv, INTA_MASK + 4, 0);
 
        rtlpci->irq_enabled = false;
+       synchronize_irq(rtlpci->pdev->irq);
 }
 
 
@@ -2271,7 +2267,7 @@ bool rtl92se_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-       enum rf_pwrstate rfpwr_toset, cur_rfstate;
+       enum rf_pwrstate rfpwr_toset /*, cur_rfstate */;
        unsigned long flag = 0;
        bool actuallyset = false;
        bool turnonbypowerdomain = false;
@@ -2292,7 +2288,7 @@ bool rtl92se_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
                spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flag);
        }
 
-       cur_rfstate = ppsc->rfpwr_state;
+       /* cur_rfstate = ppsc->rfpwr_state;*/
 
        /* because after _rtl92s_phy_set_rfhalt, all power
         * closed, so we must open some power for GPIO check,
index 63b45e6..7ee2dac 100644 (file)
@@ -180,19 +180,18 @@ u32 rtl92s_phy_query_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        u32 original_value, readback_value, bitshift;
-       unsigned long flags;
 
        RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), rfpath(%#x), "
                 "bitmask(%#x)\n", regaddr, rfpath, bitmask));
 
-       spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+       spin_lock(&rtlpriv->locks.rf_lock);
 
        original_value = _rtl92s_phy_rf_serial_read(hw, rfpath, regaddr);
 
        bitshift = _rtl92s_phy_calculate_bit_shift(bitmask);
        readback_value = (original_value & bitmask) >> bitshift;
 
-       spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+       spin_unlock(&rtlpriv->locks.rf_lock);
 
        RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), rfpath(%#x), "
                 "bitmask(%#x), original_value(%#x)\n", regaddr, rfpath,
@@ -207,7 +206,6 @@ void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_phy *rtlphy = &(rtlpriv->phy);
        u32 original_value, bitshift;
-       unsigned long flags;
 
        if (!((rtlphy->rf_pathmap >> rfpath) & 0x1))
                return;
@@ -215,7 +213,7 @@ void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
        RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x),"
                 " data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath));
 
-       spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+       spin_lock(&rtlpriv->locks.rf_lock);
 
        if (bitmask != RFREG_OFFSET_MASK) {
                original_value = _rtl92s_phy_rf_serial_read(hw, rfpath,
@@ -226,7 +224,7 @@ void rtl92s_phy_set_rf_reg(struct ieee80211_hw *hw, enum radio_path rfpath,
 
        _rtl92s_phy_rf_serial_write(hw, rfpath, regaddr, data);
 
-       spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+       spin_unlock(&rtlpriv->locks.rf_lock);
 
        RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, ("regaddr(%#x), bitmask(%#x), "
                 "data(%#x), rfpath(%#x)\n", regaddr, bitmask, data, rfpath));
@@ -263,7 +261,6 @@ void rtl92s_phy_set_bw_mode(struct ieee80211_hw *hw,
        struct rtl_phy *rtlphy = &(rtlpriv->phy);
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
        u8 reg_bw_opmode;
-       u8 reg_prsr_rsc;
 
        RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, ("Switch to %s bandwidth\n",
                  rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
@@ -277,7 +274,8 @@ void rtl92s_phy_set_bw_mode(struct ieee80211_hw *hw,
        rtlphy->set_bwmode_inprogress = true;
 
        reg_bw_opmode = rtl_read_byte(rtlpriv, BW_OPMODE);
-       reg_prsr_rsc = rtl_read_byte(rtlpriv, RRSR + 2);
+       /* dummy read */
+       rtl_read_byte(rtlpriv, RRSR + 2);
 
        switch (rtlphy->current_chan_bw) {
        case HT_CHANNEL_WIDTH_20:
@@ -546,8 +544,6 @@ bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw,
        if (rfpwr_state == ppsc->rfpwr_state)
                return false;
 
-       ppsc->set_rfpowerstate_inprogress = true;
-
        switch (rfpwr_state) {
        case ERFON:{
                        if ((ppsc->rfpwr_state == ERFOFF) &&
@@ -659,8 +655,6 @@ bool rtl92s_phy_set_rf_power_state(struct ieee80211_hw *hw,
        if (bresult)
                ppsc->rfpwr_state = rfpwr_state;
 
-       ppsc->set_rfpowerstate_inprogress = false;
-
        return bresult;
 }
 
index 5cf4423..d509cf6 100644 (file)
@@ -581,7 +581,6 @@ static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw,
        struct ieee80211_hdr *hdr;
        u8 *tmp_buf;
        u8 *praddr;
-       u8 *psaddr;
        __le16 fc;
        u16 type, cfc;
        bool packet_matchbssid, packet_toself, packet_beacon;
@@ -593,7 +592,6 @@ static void _rtl92se_translate_rx_signal_stuff(struct ieee80211_hw *hw,
        cfc = le16_to_cpu(fc);
        type = WLAN_FC_GET_TYPE(fc);
        praddr = hdr->addr1;
-       psaddr = hdr->addr2;
 
        packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) &&
             (!compare_ether_addr(mac->bssid, (cfc & IEEE80211_FCTL_TODS) ?
@@ -875,6 +873,7 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
                SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len));
                SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping));
 
+               wmb();
                SET_TX_DESC_OWN(pdesc, 1);
        } else { /* H2C Command Desc format (Host TXCMD) */
                /* 92SE must set as 1 for firmware download HW DMA error */
@@ -893,6 +892,7 @@ void rtl92se_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
                SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16)(skb->len));
                SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, cpu_to_le32(mapping));
 
+               wmb();
                SET_TX_DESC_OWN(pdesc, 1);
 
        }
@@ -903,6 +903,7 @@ void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
        if (istx == true) {
                switch (desc_name) {
                case HW_DESC_OWN:
+                       wmb();
                        SET_TX_DESC_OWN(pdesc, 1);
                        break;
                case HW_DESC_TX_NEXTDESC_ADDR:
@@ -916,6 +917,7 @@ void rtl92se_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
        } else {
                switch (desc_name) {
                case HW_DESC_RXOWN:
+                       wmb();
                        SET_RX_STATUS_DESC_OWN(pdesc, 1);
                        break;
                case HW_DESC_RXBUFF_ADDR:
index 693395e..9d003e0 100644 (file)
@@ -1188,7 +1188,6 @@ struct rtl_efuse {
 
 struct rtl_ps_ctl {
        bool pwrdomain_protect;
-       bool set_rfpowerstate_inprogress;
        bool in_powersavemode;
        bool rfchange_inprogress;
        bool swrf_processing;
@@ -1536,6 +1535,7 @@ struct rtl_works {
        /* For SW LPS */
        struct delayed_work ps_work;
        struct delayed_work ps_rfon_wq;
+       struct tasklet_struct ips_leave_tasklet;
 };
 
 struct rtl_debug {
index f51a024..f786942 100644 (file)
@@ -19,6 +19,7 @@
  * Copyright (C) 2008 Google Inc
  * Copyright (C) 2009 Bob Copeland (me@bobcopeland.com)
  */
+#include <linux/interrupt.h>
 #include <linux/module.h>
 #include <linux/mod_devicetable.h>
 #include <linux/mmc/sdio_func.h>
index af6448c..eaa5f95 100644 (file)
@@ -19,6 +19,7 @@
  *
  */
 
+#include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/slab.h>
index b07f8b7..7ccec07 100644 (file)
@@ -485,7 +485,8 @@ static int wl1271_boot_run_firmware(struct wl1271 *wl)
        if (wl->bss_type == BSS_TYPE_AP_BSS)
                wl->event_mask |= STA_REMOVE_COMPLETE_EVENT_ID;
        else
-               wl->event_mask |= DUMMY_PACKET_EVENT_ID;
+               wl->event_mask |= DUMMY_PACKET_EVENT_ID |
+                       BA_SESSION_RX_CONSTRAINT_EVENT_ID;
 
        ret = wl1271_event_unmask(wl);
        if (ret < 0) {
index 1ab6c86..c83fefb 100644 (file)
@@ -1157,6 +1157,9 @@ struct conf_sched_scan_settings {
        /* time to wait on the channel for passive scans (in TUs) */
        u32 dwell_time_passive;
 
+       /* time to wait on the channel for DFS scans (in TUs) */
+       u32 dwell_time_dfs;
+
        /* number of probe requests to send on each channel in active scans */
        u8 num_probe_reqs;
 
index c3c554c..94bbd00 100644 (file)
@@ -168,6 +168,21 @@ static void wl1271_event_rssi_trigger(struct wl1271 *wl,
        wl->last_rssi_event = event;
 }
 
+static void wl1271_stop_ba_event(struct wl1271 *wl, u8 ba_allowed)
+{
+       /* Convert the value to bool */
+       wl->ba_allowed = !!ba_allowed;
+
+       /*
+        * Return in case:
+        * there are not BA open or the event indication is to allowed BA
+        */
+       if ((!wl->ba_rx_bitmap) || (wl->ba_allowed))
+               return;
+
+       ieee80211_stop_rx_ba_session(wl->vif, wl->ba_rx_bitmap, wl->bssid);
+}
+
 static void wl1271_event_mbox_dump(struct event_mailbox *mbox)
 {
        wl1271_debug(DEBUG_EVENT, "MBOX DUMP:");
@@ -252,6 +267,14 @@ static int wl1271_event_process(struct wl1271 *wl, struct event_mailbox *mbox)
                        wl1271_event_rssi_trigger(wl, mbox);
        }
 
+       if ((vector & BA_SESSION_RX_CONSTRAINT_EVENT_ID) && !is_ap) {
+               wl1271_debug(DEBUG_EVENT, "BA_SESSION_RX_CONSTRAINT_EVENT_ID. "
+                            "ba_allowed = 0x%x", mbox->ba_allowed);
+
+               if (wl->vif)
+                       wl1271_stop_ba_event(wl, mbox->ba_allowed);
+       }
+
        if ((vector & DUMMY_PACKET_EVENT_ID) && !is_ap) {
                wl1271_debug(DEBUG_EVENT, "DUMMY_PACKET_ID_EVENT_ID");
                if (wl->vif)
index b6cf06e..ce99adf 100644 (file)
@@ -71,7 +71,7 @@ enum {
        HEALTH_CHECK_REPLY_EVENT_ID              = BIT(27),
        PERIODIC_SCAN_COMPLETE_EVENT_ID          = BIT(28),
        PERIODIC_SCAN_REPORT_EVENT_ID            = BIT(29),
-       BA_SESSION_TEAR_DOWN_EVENT_ID            = BIT(30),
+       BA_SESSION_RX_CONSTRAINT_EVENT_ID        = BIT(30),
        EVENT_MBOX_ALL_EVENT_ID                  = 0x7fffffff,
 };
 
@@ -122,7 +122,20 @@ struct event_mailbox {
        __le16 sta_aging_status;
        __le16 sta_tx_retry_exceeded;
 
-       u8 reserved_5[24];
+       /*
+        * Bitmap, Each bit set represents the Role ID for which this constraint
+        * is set. Range: 0 - FF, FF means ANY role
+        */
+       u8 ba_role_id;
+       /*
+        * Bitmap, Each bit set represents the Link ID for which this constraint
+        * is set. Not applicable if ba_role_id is set to ANY role (FF).
+        * Range: 0 - FFFF, FFFF means ANY link in that role
+        */
+       u8 ba_link_id;
+       u8 ba_allowed;
+
+       u8 reserved_5[21];
 } __packed;
 
 int wl1271_event_unmask(struct wl1271 *wl);
index a8f4f15..f5c2c9e 100644 (file)
@@ -541,6 +541,7 @@ static int wl1271_set_ba_policies(struct wl1271 *wl)
 
        /* Reset the BA RX indicators */
        wl->ba_rx_bitmap = 0;
+       wl->ba_allowed = true;
 
        /* validate that FW support BA */
        wl1271_check_ba_support(wl);
index beed621..20b0031 100644 (file)
@@ -25,6 +25,7 @@
 #ifndef __IO_H__
 #define __IO_H__
 
+#include <linux/irqreturn.h>
 #include "reg.h"
 
 #define HW_ACCESS_MEMORY_MAX_RANGE     0x1FFC0
index bc00e52..f37f0b8 100644 (file)
@@ -311,6 +311,7 @@ static struct conf_drv_settings default_conf = {
                .min_dwell_time_active = 8,
                .max_dwell_time_active = 30,
                .dwell_time_passive    = 100,
+               .dwell_time_dfs        = 150,
                .num_probe_reqs        = 2,
                .rssi_threshold        = -90,
                .snr_threshold         = 0,
@@ -3353,9 +3354,12 @@ static int wl1271_op_ampdu_action(struct ieee80211_hw *hw,
        if (ret < 0)
                goto out;
 
+       wl1271_debug(DEBUG_MAC80211, "mac80211 ampdu: Rx tid %d action %d",
+                    tid, action);
+
        switch (action) {
        case IEEE80211_AMPDU_RX_START:
-               if (wl->ba_support) {
+               if ((wl->ba_support) && (wl->ba_allowed)) {
                        ret = wl1271_acx_set_ba_receiver_session(wl, tid, *ssn,
                                                                 true);
                        if (!ret)
index f37e5a3..56f76ab 100644 (file)
@@ -331,16 +331,22 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
        struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
        int i, j;
        u32 flags;
+       bool force_passive = !req->n_ssids;
 
        for (i = 0, j = start;
             i < req->n_channels && j < MAX_CHANNELS_ALL_BANDS;
             i++) {
                flags = req->channels[i]->flags;
 
-               if (!(flags & IEEE80211_CHAN_DISABLED) &&
-                   ((flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive) &&
-                   ((flags & IEEE80211_CHAN_RADAR) == radar) &&
-                   (req->channels[i]->band == band)) {
+               if (force_passive)
+                       flags |= IEEE80211_CHAN_PASSIVE_SCAN;
+
+               if ((req->channels[i]->band == band) &&
+                   !(flags & IEEE80211_CHAN_DISABLED) &&
+                   (!!(flags & IEEE80211_CHAN_RADAR) == radar) &&
+                   /* if radar is set, we ignore the passive flag */
+                   (radar ||
+                    !!(flags & IEEE80211_CHAN_PASSIVE_SCAN) == passive)) {
                        wl1271_debug(DEBUG_SCAN, "band %d, center_freq %d ",
                                     req->channels[i]->band,
                                     req->channels[i]->center_freq);
@@ -350,7 +356,12 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
                        wl1271_debug(DEBUG_SCAN, "max_power %d",
                                     req->channels[i]->max_power);
 
-                       if (flags & IEEE80211_CHAN_PASSIVE_SCAN) {
+                       if (flags & IEEE80211_CHAN_RADAR) {
+                               channels[j].flags |= SCAN_CHANNEL_FLAGS_DFS;
+                               channels[j].passive_duration =
+                                       cpu_to_le16(c->dwell_time_dfs);
+                       }
+                       else if (flags & IEEE80211_CHAN_PASSIVE_SCAN) {
                                channels[j].passive_duration =
                                        cpu_to_le16(c->dwell_time_passive);
                        } else {
@@ -359,7 +370,7 @@ wl1271_scan_get_sched_scan_channels(struct wl1271 *wl,
                                channels[j].max_duration =
                                        cpu_to_le16(c->max_dwell_time_active);
                        }
-                       channels[j].tx_power_att = req->channels[j]->max_power;
+                       channels[j].tx_power_att = req->channels[i]->max_power;
                        channels[j].channel = req->channels[i]->hw_value;
 
                        j++;
@@ -386,7 +397,11 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
                                                    IEEE80211_BAND_2GHZ,
                                                    false, false, idx);
-       idx += cfg->active[0];
+       /*
+        * 5GHz channels always start at position 14, not immediately
+        * after the last 2.4GHz channel
+        */
+       idx = 14;
 
        cfg->passive[1] =
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
@@ -394,22 +409,23 @@ wl1271_scan_sched_scan_channels(struct wl1271 *wl,
                                                    false, true, idx);
        idx += cfg->passive[1];
 
-       cfg->active[1] =
+       cfg->dfs =
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
                                                    IEEE80211_BAND_5GHZ,
-                                                   false, false, 14);
-       idx += cfg->active[1];
+                                                   true, true, idx);
+       idx += cfg->dfs;
 
-       cfg->dfs =
+       cfg->active[1] =
                wl1271_scan_get_sched_scan_channels(wl, req, cfg->channels,
                                                    IEEE80211_BAND_5GHZ,
-                                                   true, false, idx);
-       idx += cfg->dfs;
+                                                   false, false, idx);
+       idx += cfg->active[1];
 
        wl1271_debug(DEBUG_SCAN, "    2.4GHz: active %d passive %d",
                     cfg->active[0], cfg->passive[0]);
        wl1271_debug(DEBUG_SCAN, "    5GHz: active %d passive %d",
                     cfg->active[1], cfg->passive[1]);
+       wl1271_debug(DEBUG_SCAN, "    DFS: %d", cfg->dfs);
 
        return idx;
 }
@@ -421,6 +437,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
        struct wl1271_cmd_sched_scan_config *cfg = NULL;
        struct conf_sched_scan_settings *c = &wl->conf.sched_scan;
        int i, total_channels, ret;
+       bool force_passive = !req->n_ssids;
 
        wl1271_debug(DEBUG_CMD, "cmd sched_scan scan config");
 
@@ -444,7 +461,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
        for (i = 0; i < SCAN_MAX_CYCLE_INTERVALS; i++)
                cfg->intervals[i] = cpu_to_le32(req->interval);
 
-       if (req->ssids[0].ssid_len && req->ssids[0].ssid) {
+       if (!force_passive && req->ssids[0].ssid_len && req->ssids[0].ssid) {
                cfg->filter_type = SCAN_SSID_FILTER_SPECIFIC;
                cfg->ssid_len = req->ssids[0].ssid_len;
                memcpy(cfg->ssid, req->ssids[0].ssid,
@@ -461,7 +478,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
                goto out;
        }
 
-       if (cfg->active[0]) {
+       if (!force_passive && cfg->active[0]) {
                ret = wl1271_cmd_build_probe_req(wl, req->ssids[0].ssid,
                                                 req->ssids[0].ssid_len,
                                                 ies->ie[IEEE80211_BAND_2GHZ],
@@ -473,7 +490,7 @@ int wl1271_scan_sched_scan_config(struct wl1271 *wl,
                }
        }
 
-       if (cfg->active[1]) {
+       if (!force_passive && cfg->active[1]) {
                ret = wl1271_cmd_build_probe_req(wl,  req->ssids[0].ssid,
                                                 req->ssids[0].ssid_len,
                                                 ies->ie[IEEE80211_BAND_5GHZ],
index c833195..a0b6c5d 100644 (file)
@@ -137,6 +137,9 @@ enum {
        SCAN_BSS_TYPE_ANY,
 };
 
+#define SCAN_CHANNEL_FLAGS_DFS         BIT(0)
+#define SCAN_CHANNEL_FLAGS_DFS_ENABLED BIT(1)
+
 struct conn_scan_ch_params {
        __le16 min_duration;
        __le16 max_duration;
index 51662bb..beebf64 100644 (file)
@@ -21,6 +21,7 @@
  *
  */
 
+#include <linux/interrupt.h>
 #include <linux/irq.h>
 #include <linux/module.h>
 #include <linux/crc7.h>
index fbe8f46..3bc794a 100644 (file)
@@ -564,6 +564,7 @@ struct wl1271 {
        /* RX BA constraint value */
        bool ba_support;
        u8 ba_rx_bitmap;
+       bool ba_allowed;
 
        int tcxo_clock;
 
index 0e81994..631194d 100644 (file)
@@ -1533,6 +1533,31 @@ static void __exit usb_exit(void)
 module_init(usb_init);
 module_exit(usb_exit);
 
+static int zd_ep_regs_out_msg(struct usb_device *udev, void *data, int len,
+                             int *actual_length, int timeout)
+{
+       /* In USB 2.0 mode EP_REGS_OUT endpoint is interrupt type. However in
+        * USB 1.1 mode endpoint is bulk. Select correct type URB by endpoint
+        * descriptor.
+        */
+       struct usb_host_endpoint *ep;
+       unsigned int pipe;
+
+       pipe = usb_sndintpipe(udev, EP_REGS_OUT);
+       ep = usb_pipe_endpoint(udev, pipe);
+       if (!ep)
+               return -EINVAL;
+
+       if (usb_endpoint_xfer_int(&ep->desc)) {
+               return usb_interrupt_msg(udev, pipe, data, len,
+                                        actual_length, timeout);
+       } else {
+               pipe = usb_sndbulkpipe(udev, EP_REGS_OUT);
+               return usb_bulk_msg(udev, pipe, data, len, actual_length,
+                                   timeout);
+       }
+}
+
 static int usb_int_regs_length(unsigned int count)
 {
        return sizeof(struct usb_int_regs) + count * sizeof(struct reg_data);
@@ -1648,15 +1673,14 @@ int zd_usb_ioread16v(struct zd_usb *usb, u16 *values,
 
        udev = zd_usb_to_usbdev(usb);
        prepare_read_regs_int(usb);
-       r = usb_interrupt_msg(udev, usb_sndintpipe(udev, EP_REGS_OUT),
-                             req, req_len, &actual_req_len, 50 /* ms */);
+       r = zd_ep_regs_out_msg(udev, req, req_len, &actual_req_len, 50 /*ms*/);
        if (r) {
                dev_dbg_f(zd_usb_dev(usb),
-                       "error in usb_interrupt_msg(). Error number %d\n", r);
+                       "error in zd_ep_regs_out_msg(). Error number %d\n", r);
                goto error;
        }
        if (req_len != actual_req_len) {
-               dev_dbg_f(zd_usb_dev(usb), "error in usb_interrupt_msg()\n"
+               dev_dbg_f(zd_usb_dev(usb), "error in zd_ep_regs_out_msg()\n"
                        " req_len %d != actual_req_len %d\n",
                        req_len, actual_req_len);
                r = -EIO;
@@ -1818,9 +1842,17 @@ int zd_usb_iowrite16v_async(struct zd_usb *usb, const struct zd_ioreq16 *ioreqs,
                rw->value = cpu_to_le16(ioreqs[i].value);
        }
 
-       usb_fill_int_urb(urb, udev, usb_sndintpipe(udev, EP_REGS_OUT),
-                        req, req_len, iowrite16v_urb_complete, usb,
-                        ep->desc.bInterval);
+       /* In USB 2.0 mode endpoint is interrupt type. However in USB 1.1 mode
+        * endpoint is bulk. Select correct type URB by endpoint descriptor.
+        */
+       if (usb_endpoint_xfer_int(&ep->desc))
+               usb_fill_int_urb(urb, udev, usb_sndintpipe(udev, EP_REGS_OUT),
+                                req, req_len, iowrite16v_urb_complete, usb,
+                                ep->desc.bInterval);
+       else
+               usb_fill_bulk_urb(urb, udev, usb_sndbulkpipe(udev, EP_REGS_OUT),
+                                 req, req_len, iowrite16v_urb_complete, usb);
+
        urb->transfer_flags |= URB_FREE_BUFFER;
 
        /* Submit previous URB */
@@ -1924,15 +1956,14 @@ int zd_usb_rfwrite(struct zd_usb *usb, u32 value, u8 bits)
        }
 
        udev = zd_usb_to_usbdev(usb);
-       r = usb_interrupt_msg(udev, usb_sndintpipe(udev, EP_REGS_OUT),
-                             req, req_len, &actual_req_len, 50 /* ms */);
+       r = zd_ep_regs_out_msg(udev, req, req_len, &actual_req_len, 50 /*ms*/);
        if (r) {
                dev_dbg_f(zd_usb_dev(usb),
-                       "error in usb_interrupt_msg(). Error number %d\n", r);
+                       "error in zd_ep_regs_out_msg(). Error number %d\n", r);
                goto out;
        }
        if (req_len != actual_req_len) {
-               dev_dbg_f(zd_usb_dev(usb), "error in usb_interrupt_msg()"
+               dev_dbg_f(zd_usb_dev(usb), "error in zd_ep_regs_out_msg()"
                        " req_len %d != actual_req_len %d\n",
                        req_len, actual_req_len);
                r = -EIO;
index 372572c..9cb4cdc 100644 (file)
@@ -26,6 +26,7 @@
 #include <linux/of_mdio.h>
 #include <linux/of_net.h>
 #include <linux/phy.h>
+#include <linux/interrupt.h>
 
 #define DRIVER_NAME "xilinx_emaclite"
 
index ec2800f..8b88817 100644 (file)
@@ -731,7 +731,7 @@ static void znet_rx(struct net_device *dev)
                cur_frame_end_offset -= ((count + 1)>>1) + 3;
                if (cur_frame_end_offset < 0)
                  cur_frame_end_offset += RX_BUF_SIZE/2;
-       };
+       }
 
        /* Now step  forward through the list. */
        do {
index 12e02bf..3dc9bef 100644 (file)
@@ -698,12 +698,7 @@ int __init detect_intel_iommu(void)
        {
 #ifdef CONFIG_INTR_REMAP
                struct acpi_table_dmar *dmar;
-               /*
-                * for now we will disable dma-remapping when interrupt
-                * remapping is enabled.
-                * When support for queued invalidation for IOTLB invalidation
-                * is added, we will not need this any more.
-                */
+
                dmar = (struct acpi_table_dmar *) dmar_tbl;
                if (ret && cpu_has_x2apic && dmar->flags & 0x1)
                        printk(KERN_INFO
index 6af6b62..59f17ac 100644 (file)
@@ -47,6 +47,8 @@
 #define ROOT_SIZE              VTD_PAGE_SIZE
 #define CONTEXT_SIZE           VTD_PAGE_SIZE
 
+#define IS_BRIDGE_HOST_DEVICE(pdev) \
+                           ((pdev->class >> 8) == PCI_CLASS_BRIDGE_HOST)
 #define IS_GFX_DEVICE(pdev) ((pdev->class >> 16) == PCI_BASE_CLASS_DISPLAY)
 #define IS_ISA_DEVICE(pdev) ((pdev->class >> 8) == PCI_CLASS_BRIDGE_ISA)
 #define IS_AZALIA(pdev) ((pdev)->vendor == 0x8086 && (pdev)->device == 0x3a3e)
@@ -116,6 +118,11 @@ static inline unsigned long align_to_level(unsigned long pfn, int level)
        return (pfn + level_size(level) - 1) & level_mask(level);
 }
 
+static inline unsigned long lvl_to_nr_pages(unsigned int lvl)
+{
+       return  1 << ((lvl - 1) * LEVEL_STRIDE);
+}
+
 /* VT-d pages must always be _smaller_ than MM pages. Otherwise things
    are never going to work. */
 static inline unsigned long dma_to_mm_pfn(unsigned long dma_pfn)
@@ -142,6 +149,12 @@ static struct intel_iommu **g_iommus;
 static void __init check_tylersburg_isoch(void);
 static int rwbf_quirk;
 
+/*
+ * set to 1 to panic kernel if can't successfully enable VT-d
+ * (used when kernel is launched w/ TXT)
+ */
+static int force_on = 0;
+
 /*
  * 0: Present
  * 1-11: Reserved
@@ -338,6 +351,9 @@ struct dmar_domain {
        int             iommu_coherency;/* indicate coherency of iommu access */
        int             iommu_snooping; /* indicate snooping control feature*/
        int             iommu_count;    /* reference count of iommu */
+       int             iommu_superpage;/* Level of superpages supported:
+                                          0 == 4KiB (no superpages), 1 == 2MiB,
+                                          2 == 1GiB, 3 == 512GiB, 4 == 1TiB */
        spinlock_t      iommu_lock;     /* protect iommu set in domain */
        u64             max_addr;       /* maximum mapped address */
 };
@@ -387,6 +403,7 @@ int dmar_disabled = 1;
 static int dmar_map_gfx = 1;
 static int dmar_forcedac;
 static int intel_iommu_strict;
+static int intel_iommu_superpage = 1;
 
 #define DUMMY_DEVICE_DOMAIN_INFO ((struct device_domain_info *)(-1))
 static DEFINE_SPINLOCK(device_domain_lock);
@@ -417,6 +434,10 @@ static int __init intel_iommu_setup(char *str)
                        printk(KERN_INFO
                                "Intel-IOMMU: disable batched IOTLB flush\n");
                        intel_iommu_strict = 1;
+               } else if (!strncmp(str, "sp_off", 6)) {
+                       printk(KERN_INFO
+                               "Intel-IOMMU: disable supported super page\n");
+                       intel_iommu_superpage = 0;
                }
 
                str += strcspn(str, ",");
@@ -555,11 +576,32 @@ static void domain_update_iommu_snooping(struct dmar_domain *domain)
        }
 }
 
+static void domain_update_iommu_superpage(struct dmar_domain *domain)
+{
+       int i, mask = 0xf;
+
+       if (!intel_iommu_superpage) {
+               domain->iommu_superpage = 0;
+               return;
+       }
+
+       domain->iommu_superpage = 4; /* 1TiB */
+
+       for_each_set_bit(i, &domain->iommu_bmp, g_num_of_iommus) {
+               mask |= cap_super_page_val(g_iommus[i]->cap);
+               if (!mask) {
+                       break;
+               }
+       }
+       domain->iommu_superpage = fls(mask);
+}
+
 /* Some capabilities may be different across iommus */
 static void domain_update_iommu_cap(struct dmar_domain *domain)
 {
        domain_update_iommu_coherency(domain);
        domain_update_iommu_snooping(domain);
+       domain_update_iommu_superpage(domain);
 }
 
 static struct intel_iommu *device_to_iommu(int segment, u8 bus, u8 devfn)
@@ -689,23 +731,31 @@ out:
 }
 
 static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
-                                     unsigned long pfn)
+                                     unsigned long pfn, int large_level)
 {
        int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
        struct dma_pte *parent, *pte = NULL;
        int level = agaw_to_level(domain->agaw);
-       int offset;
+       int offset, target_level;
 
        BUG_ON(!domain->pgd);
        BUG_ON(addr_width < BITS_PER_LONG && pfn >> addr_width);
        parent = domain->pgd;
 
+       /* Search pte */
+       if (!large_level)
+               target_level = 1;
+       else
+               target_level = large_level;
+
        while (level > 0) {
                void *tmp_page;
 
                offset = pfn_level_offset(pfn, level);
                pte = &parent[offset];
-               if (level == 1)
+               if (!large_level && (pte->val & DMA_PTE_LARGE_PAGE))
+                       break;
+               if (level == target_level)
                        break;
 
                if (!dma_pte_present(pte)) {
@@ -733,10 +783,11 @@ static struct dma_pte *pfn_to_dma_pte(struct dmar_domain *domain,
        return pte;
 }
 
+
 /* return address's pte at specific level */
 static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
                                         unsigned long pfn,
-                                        int level)
+                                        int level, int *large_page)
 {
        struct dma_pte *parent, *pte = NULL;
        int total = agaw_to_level(domain->agaw);
@@ -749,8 +800,16 @@ static struct dma_pte *dma_pfn_level_pte(struct dmar_domain *domain,
                if (level == total)
                        return pte;
 
-               if (!dma_pte_present(pte))
+               if (!dma_pte_present(pte)) {
+                       *large_page = total;
                        break;
+               }
+
+               if (pte->val & DMA_PTE_LARGE_PAGE) {
+                       *large_page = total;
+                       return pte;
+               }
+
                parent = phys_to_virt(dma_pte_addr(pte));
                total--;
        }
@@ -763,6 +822,7 @@ static void dma_pte_clear_range(struct dmar_domain *domain,
                                unsigned long last_pfn)
 {
        int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
+       unsigned int large_page = 1;
        struct dma_pte *first_pte, *pte;
 
        BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
@@ -771,14 +831,15 @@ static void dma_pte_clear_range(struct dmar_domain *domain,
 
        /* we don't need lock here; nobody else touches the iova range */
        do {
-               first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1);
+               large_page = 1;
+               first_pte = pte = dma_pfn_level_pte(domain, start_pfn, 1, &large_page);
                if (!pte) {
-                       start_pfn = align_to_level(start_pfn + 1, 2);
+                       start_pfn = align_to_level(start_pfn + 1, large_page + 1);
                        continue;
                }
-               do { 
+               do {
                        dma_clear_pte(pte);
-                       start_pfn++;
+                       start_pfn += lvl_to_nr_pages(large_page);
                        pte++;
                } while (start_pfn <= last_pfn && !first_pte_in_page(pte));
 
@@ -798,6 +859,7 @@ static void dma_pte_free_pagetable(struct dmar_domain *domain,
        int total = agaw_to_level(domain->agaw);
        int level;
        unsigned long tmp;
+       int large_page = 2;
 
        BUG_ON(addr_width < BITS_PER_LONG && start_pfn >> addr_width);
        BUG_ON(addr_width < BITS_PER_LONG && last_pfn >> addr_width);
@@ -813,7 +875,10 @@ static void dma_pte_free_pagetable(struct dmar_domain *domain,
                        return;
 
                do {
-                       first_pte = pte = dma_pfn_level_pte(domain, tmp, level);
+                       large_page = level;
+                       first_pte = pte = dma_pfn_level_pte(domain, tmp, level, &large_page);
+                       if (large_page > level)
+                               level = large_page + 1;
                        if (!pte) {
                                tmp = align_to_level(tmp + 1, level + 1);
                                continue;
@@ -1397,6 +1462,7 @@ static int domain_init(struct dmar_domain *domain, int guest_width)
        else
                domain->iommu_snooping = 0;
 
+       domain->iommu_superpage = fls(cap_super_page_val(iommu->cap));
        domain->iommu_count = 1;
        domain->nid = iommu->node;
 
@@ -1417,6 +1483,10 @@ static void domain_exit(struct dmar_domain *domain)
        if (!domain)
                return;
 
+       /* Flush any lazy unmaps that may reference this domain */
+       if (!intel_iommu_strict)
+               flush_unmaps_timeout(0);
+
        domain_remove_dev_info(domain);
        /* destroy iovas */
        put_iova_domain(&domain->iovad);
@@ -1648,6 +1718,34 @@ static inline unsigned long aligned_nrpages(unsigned long host_addr,
        return PAGE_ALIGN(host_addr + size) >> VTD_PAGE_SHIFT;
 }
 
+/* Return largest possible superpage level for a given mapping */
+static inline int hardware_largepage_caps(struct dmar_domain *domain,
+                                         unsigned long iov_pfn,
+                                         unsigned long phy_pfn,
+                                         unsigned long pages)
+{
+       int support, level = 1;
+       unsigned long pfnmerge;
+
+       support = domain->iommu_superpage;
+
+       /* To use a large page, the virtual *and* physical addresses
+          must be aligned to 2MiB/1GiB/etc. Lower bits set in either
+          of them will mean we have to use smaller pages. So just
+          merge them and check both at once. */
+       pfnmerge = iov_pfn | phy_pfn;
+
+       while (support && !(pfnmerge & ~VTD_STRIDE_MASK)) {
+               pages >>= VTD_STRIDE_SHIFT;
+               if (!pages)
+                       break;
+               pfnmerge >>= VTD_STRIDE_SHIFT;
+               level++;
+               support--;
+       }
+       return level;
+}
+
 static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
                            struct scatterlist *sg, unsigned long phys_pfn,
                            unsigned long nr_pages, int prot)
@@ -1656,6 +1754,8 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
        phys_addr_t uninitialized_var(pteval);
        int addr_width = agaw_to_width(domain->agaw) - VTD_PAGE_SHIFT;
        unsigned long sg_res;
+       unsigned int largepage_lvl = 0;
+       unsigned long lvl_pages = 0;
 
        BUG_ON(addr_width < BITS_PER_LONG && (iov_pfn + nr_pages - 1) >> addr_width);
 
@@ -1671,7 +1771,7 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
                pteval = ((phys_addr_t)phys_pfn << VTD_PAGE_SHIFT) | prot;
        }
 
-       while (nr_pages--) {
+       while (nr_pages > 0) {
                uint64_t tmp;
 
                if (!sg_res) {
@@ -1679,11 +1779,21 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
                        sg->dma_address = ((dma_addr_t)iov_pfn << VTD_PAGE_SHIFT) + sg->offset;
                        sg->dma_length = sg->length;
                        pteval = page_to_phys(sg_page(sg)) | prot;
+                       phys_pfn = pteval >> VTD_PAGE_SHIFT;
                }
+
                if (!pte) {
-                       first_pte = pte = pfn_to_dma_pte(domain, iov_pfn);
+                       largepage_lvl = hardware_largepage_caps(domain, iov_pfn, phys_pfn, sg_res);
+
+                       first_pte = pte = pfn_to_dma_pte(domain, iov_pfn, largepage_lvl);
                        if (!pte)
                                return -ENOMEM;
+                       /* It is large page*/
+                       if (largepage_lvl > 1)
+                               pteval |= DMA_PTE_LARGE_PAGE;
+                       else
+                               pteval &= ~(uint64_t)DMA_PTE_LARGE_PAGE;
+
                }
                /* We don't need lock here, nobody else
                 * touches the iova range
@@ -1699,16 +1809,38 @@ static int __domain_mapping(struct dmar_domain *domain, unsigned long iov_pfn,
                        }
                        WARN_ON(1);
                }
+
+               lvl_pages = lvl_to_nr_pages(largepage_lvl);
+
+               BUG_ON(nr_pages < lvl_pages);
+               BUG_ON(sg_res < lvl_pages);
+
+               nr_pages -= lvl_pages;
+               iov_pfn += lvl_pages;
+               phys_pfn += lvl_pages;
+               pteval += lvl_pages * VTD_PAGE_SIZE;
+               sg_res -= lvl_pages;
+
+               /* If the next PTE would be the first in a new page, then we
+                  need to flush the cache on the entries we've just written.
+                  And then we'll need to recalculate 'pte', so clear it and
+                  let it get set again in the if (!pte) block above.
+
+                  If we're done (!nr_pages) we need to flush the cache too.
+
+                  Also if we've been setting superpages, we may need to
+                  recalculate 'pte' and switch back to smaller pages for the
+                  end of the mapping, if the trailing size is not enough to
+                  use another superpage (i.e. sg_res < lvl_pages). */
                pte++;
-               if (!nr_pages || first_pte_in_page(pte)) {
+               if (!nr_pages || first_pte_in_page(pte) ||
+                   (largepage_lvl > 1 && sg_res < lvl_pages)) {
                        domain_flush_cache(domain, first_pte,
                                           (void *)pte - (void *)first_pte);
                        pte = NULL;
                }
-               iov_pfn++;
-               pteval += VTD_PAGE_SIZE;
-               sg_res--;
-               if (!sg_res)
+
+               if (!sg_res && nr_pages)
                        sg = sg_next(sg);
        }
        return 0;
@@ -2016,7 +2148,7 @@ static inline int iommu_prepare_rmrr_dev(struct dmar_rmrr_unit *rmrr,
        if (pdev->dev.archdata.iommu == DUMMY_DEVICE_DOMAIN_INFO)
                return 0;
        return iommu_prepare_identity_map(pdev, rmrr->base_address,
-               rmrr->end_address + 1);
+               rmrr->end_address);
 }
 
 #ifdef CONFIG_DMAR_FLOPPY_WA
@@ -2030,7 +2162,7 @@ static inline void iommu_prepare_isa(void)
                return;
 
        printk(KERN_INFO "IOMMU: Prepare 0-16MiB unity mapping for LPC\n");
-       ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024);
+       ret = iommu_prepare_identity_map(pdev, 0, 16*1024*1024 - 1);
 
        if (ret)
                printk(KERN_ERR "IOMMU: Failed to create 0-16MiB identity map; "
@@ -2106,10 +2238,10 @@ static int identity_mapping(struct pci_dev *pdev)
        if (likely(!iommu_identity_mapping))
                return 0;
 
+       info = pdev->dev.archdata.iommu;
+       if (info && info != DUMMY_DEVICE_DOMAIN_INFO)
+               return (info->domain == si_domain);
 
-       list_for_each_entry(info, &si_domain->devices, link)
-               if (info->dev == pdev)
-                       return 1;
        return 0;
 }
 
@@ -2187,8 +2319,19 @@ static int iommu_should_identity_map(struct pci_dev *pdev, int startup)
         * Assume that they will -- if they turn out not to be, then we can 
         * take them out of the 1:1 domain later.
         */
-       if (!startup)
-               return pdev->dma_mask > DMA_BIT_MASK(32);
+       if (!startup) {
+               /*
+                * If the device's dma_mask is less than the system's memory
+                * size then this is not a candidate for identity mapping.
+                */
+               u64 dma_mask = pdev->dma_mask;
+
+               if (pdev->dev.coherent_dma_mask &&
+                   pdev->dev.coherent_dma_mask < dma_mask)
+                       dma_mask = pdev->dev.coherent_dma_mask;
+
+               return dma_mask >= dma_get_required_mask(&pdev->dev);
+       }
 
        return 1;
 }
@@ -2203,6 +2346,9 @@ static int __init iommu_prepare_static_identity_mapping(int hw)
                return -EFAULT;
 
        for_each_pci_dev(pdev) {
+               /* Skip Host/PCI Bridge devices */
+               if (IS_BRIDGE_HOST_DEVICE(pdev))
+                       continue;
                if (iommu_should_identity_map(pdev, 1)) {
                        printk(KERN_INFO "IOMMU: %s identity mapping for device %s\n",
                               hw ? "hardware" : "software", pci_name(pdev));
@@ -2218,7 +2364,7 @@ static int __init iommu_prepare_static_identity_mapping(int hw)
        return 0;
 }
 
-static int __init init_dmars(int force_on)
+static int __init init_dmars(void)
 {
        struct dmar_drhd_unit *drhd;
        struct dmar_rmrr_unit *rmrr;
@@ -2592,8 +2738,7 @@ static dma_addr_t __intel_map_single(struct device *hwdev, phys_addr_t paddr,
        iommu = domain_get_iommu(domain);
        size = aligned_nrpages(paddr, size);
 
-       iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size),
-                               pdev->dma_mask);
+       iova = intel_alloc_iova(hwdev, domain, dma_to_mm_pfn(size), dma_mask);
        if (!iova)
                goto error;
 
@@ -3118,7 +3263,17 @@ static int init_iommu_hw(void)
                if (iommu->qi)
                        dmar_reenable_qi(iommu);
 
-       for_each_active_iommu(iommu, drhd) {
+       for_each_iommu(iommu, drhd) {
+               if (drhd->ignored) {
+                       /*
+                        * we always have to disable PMRs or DMA may fail on
+                        * this device
+                        */
+                       if (force_on)
+                               iommu_disable_protect_mem_regions(iommu);
+                       continue;
+               }
+       
                iommu_flush_write_buffer(iommu);
 
                iommu_set_root_entry(iommu);
@@ -3127,7 +3282,8 @@ static int init_iommu_hw(void)
                                           DMA_CCMD_GLOBAL_INVL);
                iommu->flush.flush_iotlb(iommu, 0, 0, 0,
                                         DMA_TLB_GLOBAL_FLUSH);
-               iommu_enable_translation(iommu);
+               if (iommu_enable_translation(iommu))
+                       return 1;
                iommu_disable_protect_mem_regions(iommu);
        }
 
@@ -3194,7 +3350,10 @@ static void iommu_resume(void)
        unsigned long flag;
 
        if (init_iommu_hw()) {
-               WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
+               if (force_on)
+                       panic("tboot: IOMMU setup failed, DMAR can not resume!\n");
+               else
+                       WARN(1, "IOMMU setup failed, DMAR can not resume!\n");
                return;
        }
 
@@ -3271,7 +3430,6 @@ static struct notifier_block device_nb = {
 int __init intel_iommu_init(void)
 {
        int ret = 0;
-       int force_on = 0;
 
        /* VT-d is required for a TXT/tboot launch, so enforce that */
        force_on = tboot_force_iommu();
@@ -3309,7 +3467,7 @@ int __init intel_iommu_init(void)
 
        init_no_remapping_devices();
 
-       ret = init_dmars(force_on);
+       ret = init_dmars();
        if (ret) {
                if (force_on)
                        panic("tboot: Failed to initialize DMARs\n");
@@ -3380,8 +3538,8 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain,
        spin_lock_irqsave(&device_domain_lock, flags);
        list_for_each_safe(entry, tmp, &domain->devices) {
                info = list_entry(entry, struct device_domain_info, link);
-               /* No need to compare PCI domain; it has to be the same */
-               if (info->bus == pdev->bus->number &&
+               if (info->segment == pci_domain_nr(pdev->bus) &&
+                   info->bus == pdev->bus->number &&
                    info->devfn == pdev->devfn) {
                        list_del(&info->link);
                        list_del(&info->global);
@@ -3419,10 +3577,13 @@ static void domain_remove_one_dev_info(struct dmar_domain *domain,
                domain_update_iommu_cap(domain);
                spin_unlock_irqrestore(&domain->iommu_lock, tmp_flags);
 
-               spin_lock_irqsave(&iommu->lock, tmp_flags);
-               clear_bit(domain->id, iommu->domain_ids);
-               iommu->domains[domain->id] = NULL;
-               spin_unlock_irqrestore(&iommu->lock, tmp_flags);
+               if (!(domain->flags & DOMAIN_FLAG_VIRTUAL_MACHINE) &&
+                   !(domain->flags & DOMAIN_FLAG_STATIC_IDENTITY)) {
+                       spin_lock_irqsave(&iommu->lock, tmp_flags);
+                       clear_bit(domain->id, iommu->domain_ids);
+                       iommu->domains[domain->id] = NULL;
+                       spin_unlock_irqrestore(&iommu->lock, tmp_flags);
+               }
        }
 
        spin_unlock_irqrestore(&device_domain_lock, flags);
@@ -3505,6 +3666,7 @@ static int md_domain_init(struct dmar_domain *domain, int guest_width)
        domain->iommu_count = 0;
        domain->iommu_coherency = 0;
        domain->iommu_snooping = 0;
+       domain->iommu_superpage = 0;
        domain->max_addr = 0;
        domain->nid = -1;
 
@@ -3720,7 +3882,7 @@ static phys_addr_t intel_iommu_iova_to_phys(struct iommu_domain *domain,
        struct dma_pte *pte;
        u64 phys = 0;
 
-       pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT);
+       pte = pfn_to_dma_pte(dmar_domain, iova >> VTD_PAGE_SHIFT, 0);
        if (pte)
                phys = dma_pte_addr(pte);
 
index 9606e59..c5c274a 100644 (file)
@@ -63,8 +63,16 @@ __cached_rbnode_delete_update(struct iova_domain *iovad, struct iova *free)
        curr = iovad->cached32_node;
        cached_iova = container_of(curr, struct iova, node);
 
-       if (free->pfn_lo >= cached_iova->pfn_lo)
-               iovad->cached32_node = rb_next(&free->node);
+       if (free->pfn_lo >= cached_iova->pfn_lo) {
+               struct rb_node *node = rb_next(&free->node);
+               struct iova *iova = container_of(node, struct iova, node);
+
+               /* only cache if it's below 32bit pfn */
+               if (node && iova->pfn_lo < iovad->dma_32bit_pfn)
+                       iovad->cached32_node = node;
+               else
+                       iovad->cached32_node = NULL;
+       }
 }
 
 /* Computes the padding size required, to make the
index 5336120..1fa07b0 100644 (file)
@@ -12,6 +12,7 @@
 #ifndef _CTC_MPC_H_
 #define _CTC_MPC_H_
 
+#include <linux/interrupt.h>
 #include <linux/skbuff.h>
 #include "fsm.h"
 
index 58584dc..44e8ca3 100644 (file)
@@ -297,7 +297,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
                kfree(sdev);
                goto out;
        }
-
+       blk_get_queue(sdev->request_queue);
        sdev->request_queue->queuedata = sdev;
        scsi_adjust_queue_depth(sdev, 0, sdev->host->cmd_per_lun);
 
index e639125..e0bd3f7 100644 (file)
@@ -322,6 +322,7 @@ static void scsi_device_dev_release_usercontext(struct work_struct *work)
                kfree(evt);
        }
 
+       blk_put_queue(sdev->request_queue);
        /* NULL queue means the device can't be used */
        sdev->request_queue = NULL;
 
index 82feb34..2a20dab 100644 (file)
@@ -539,10 +539,12 @@ void ssb_pcicore_init(struct ssb_pcicore *pc)
        if (!pc->hostmode)
                ssb_pcicore_init_clientmode(pc);
 
-       /* Additional always once-executed workarounds */
-       ssb_pcicore_serdes_workaround(pc);
-       /* TODO: ASPM */
-       /* TODO: Clock Request Update */
+       /* Additional PCIe always once-executed workarounds */
+       if (dev->id.coreid == SSB_DEV_PCIE) {
+               ssb_pcicore_serdes_workaround(pc);
+               /* TODO: ASPM */
+               /* TODO: Clock Request Update */
+       }
 }
 
 static u32 ssb_pcie_read(struct ssb_pcicore *pc, u32 address)
index a4c42a7..09e8c7d 100644 (file)
@@ -2128,8 +2128,8 @@ static void gsmld_detach_gsm(struct tty_struct *tty, struct gsm_mux *gsm)
        gsm->tty = NULL;
 }
 
-static unsigned int gsmld_receive_buf(struct tty_struct *tty,
-               const unsigned char *cp, char *fp, int count)
+static void gsmld_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                             char *fp, int count)
 {
        struct gsm_mux *gsm = tty->disc_data;
        const unsigned char *dp;
@@ -2162,8 +2162,6 @@ static unsigned int gsmld_receive_buf(struct tty_struct *tty,
        }
        /* FASYNC if needed ? */
        /* If clogged call tty_throttle(tty); */
-
-       return count;
 }
 
 /**
index cac6663..cea5603 100644 (file)
@@ -188,8 +188,8 @@ static unsigned int n_hdlc_tty_poll(struct tty_struct *tty, struct file *filp,
                                    poll_table *wait);
 static int n_hdlc_tty_open(struct tty_struct *tty);
 static void n_hdlc_tty_close(struct tty_struct *tty);
-static unsigned int n_hdlc_tty_receive(struct tty_struct *tty,
-               const __u8 *cp, char *fp, int count);
+static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *cp,
+                              char *fp, int count);
 static void n_hdlc_tty_wakeup(struct tty_struct *tty);
 
 #define bset(p,b)      ((p)[(b) >> 5] |= (1 << ((b) & 0x1f)))
@@ -509,8 +509,8 @@ static void n_hdlc_tty_wakeup(struct tty_struct *tty)
  * Called by tty low level driver when receive data is available. Data is
  * interpreted as one HDLC frame.
  */
-static unsigned int n_hdlc_tty_receive(struct tty_struct *tty,
-               const __u8 *data, char *flags, int count)
+static void n_hdlc_tty_receive(struct tty_struct *tty, const __u8 *data,
+                              char *flags, int count)
 {
        register struct n_hdlc *n_hdlc = tty2n_hdlc (tty);
        register struct n_hdlc_buf *buf;
@@ -521,20 +521,20 @@ static unsigned int n_hdlc_tty_receive(struct tty_struct *tty,
                
        /* This can happen if stuff comes in on the backup tty */
        if (!n_hdlc || tty != n_hdlc->tty)
-               return -ENODEV;
+               return;
                
        /* verify line is using HDLC discipline */
        if (n_hdlc->magic != HDLC_MAGIC) {
                printk("%s(%d) line not using HDLC discipline\n",
                        __FILE__,__LINE__);
-               return -EINVAL;
+               return;
        }
        
        if ( count>maxframe ) {
                if (debuglevel >= DEBUG_LEVEL_INFO)     
                        printk("%s(%d) rx count>maxframesize, data discarded\n",
                               __FILE__,__LINE__);
-               return -EINVAL;
+               return;
        }
 
        /* get a free HDLC buffer */    
@@ -550,7 +550,7 @@ static unsigned int n_hdlc_tty_receive(struct tty_struct *tty,
                if (debuglevel >= DEBUG_LEVEL_INFO)     
                        printk("%s(%d) no more rx buffers, data discarded\n",
                               __FILE__,__LINE__);
-               return -EINVAL;
+               return;
        }
                
        /* copy received data to HDLC buffer */
@@ -565,8 +565,6 @@ static unsigned int n_hdlc_tty_receive(struct tty_struct *tty,
        if (n_hdlc->tty->fasync != NULL)
                kill_fasync (&n_hdlc->tty->fasync, SIGIO, POLL_IN);
 
-       return count;
-
 }      /* end of n_hdlc_tty_receive() */
 
 /**
index a4bc39c..5c6c314 100644 (file)
@@ -139,8 +139,8 @@ static int r3964_ioctl(struct tty_struct *tty, struct file *file,
 static void r3964_set_termios(struct tty_struct *tty, struct ktermios *old);
 static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
                struct poll_table_struct *wait);
-static unsigned int r3964_receive_buf(struct tty_struct *tty,
-               const unsigned char *cp, char *fp, int count);
+static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+               char *fp, int count);
 
 static struct tty_ldisc_ops tty_ldisc_N_R3964 = {
        .owner = THIS_MODULE,
@@ -1239,8 +1239,8 @@ static unsigned int r3964_poll(struct tty_struct *tty, struct file *file,
        return result;
 }
 
-static unsigned int r3964_receive_buf(struct tty_struct *tty,
-               const unsigned char *cp, char *fp, int count)
+static void r3964_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                       char *fp, int count)
 {
        struct r3964_info *pInfo = tty->disc_data;
        const unsigned char *p;
@@ -1257,8 +1257,6 @@ static unsigned int r3964_receive_buf(struct tty_struct *tty,
                }
 
        }
-
-       return count;
 }
 
 MODULE_LICENSE("GPL");
index 95d0a9c..0ad3288 100644 (file)
@@ -81,6 +81,38 @@ static inline int tty_put_user(struct tty_struct *tty, unsigned char x,
        return put_user(x, ptr);
 }
 
+/**
+ *     n_tty_set__room -       receive space
+ *     @tty: terminal
+ *
+ *     Called by the driver to find out how much data it is
+ *     permitted to feed to the line discipline without any being lost
+ *     and thus to manage flow control. Not serialized. Answers for the
+ *     "instant".
+ */
+
+static void n_tty_set_room(struct tty_struct *tty)
+{
+       /* tty->read_cnt is not read locked ? */
+       int     left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
+       int old_left;
+
+       /*
+        * If we are doing input canonicalization, and there are no
+        * pending newlines, let characters through without limit, so
+        * that erase characters will be handled.  Other excess
+        * characters will be beeped.
+        */
+       if (left <= 0)
+               left = tty->icanon && !tty->canon_data;
+       old_left = tty->receive_room;
+       tty->receive_room = left;
+
+       /* Did this open up the receive buffer? We may need to flip */
+       if (left && !old_left)
+               schedule_work(&tty->buf.work);
+}
+
 static void put_tty_queue_nolock(unsigned char c, struct tty_struct *tty)
 {
        if (tty->read_cnt < N_TTY_BUF_SIZE) {
@@ -152,6 +184,7 @@ static void reset_buffer_flags(struct tty_struct *tty)
 
        tty->canon_head = tty->canon_data = tty->erasing = 0;
        memset(&tty->read_flags, 0, sizeof tty->read_flags);
+       n_tty_set_room(tty);
        check_unthrottle(tty);
 }
 
@@ -1327,19 +1360,17 @@ static void n_tty_write_wakeup(struct tty_struct *tty)
  *     calls one at a time and in order (or using flush_to_ldisc)
  */
 
-static unsigned int n_tty_receive_buf(struct tty_struct *tty,
-               const unsigned char *cp, char *fp, int count)
+static void n_tty_receive_buf(struct tty_struct *tty, const unsigned char *cp,
+                             char *fp, int count)
 {
        const unsigned char *p;
        char *f, flags = TTY_NORMAL;
        int     i;
        char    buf[64];
        unsigned long cpuflags;
-       int left;
-       int ret = 0;
 
        if (!tty->read_buf)
-               return 0;
+               return;
 
        if (tty->real_raw) {
                spin_lock_irqsave(&tty->read_lock, cpuflags);
@@ -1349,7 +1380,6 @@ static unsigned int n_tty_receive_buf(struct tty_struct *tty,
                memcpy(tty->read_buf + tty->read_head, cp, i);
                tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
                tty->read_cnt += i;
-               ret += i;
                cp += i;
                count -= i;
 
@@ -1359,10 +1389,8 @@ static unsigned int n_tty_receive_buf(struct tty_struct *tty,
                memcpy(tty->read_buf + tty->read_head, cp, i);
                tty->read_head = (tty->read_head + i) & (N_TTY_BUF_SIZE-1);
                tty->read_cnt += i;
-               ret += i;
                spin_unlock_irqrestore(&tty->read_lock, cpuflags);
        } else {
-               ret = count;
                for (i = count, p = cp, f = fp; i; i--, p++) {
                        if (f)
                                flags = *f++;
@@ -1390,6 +1418,8 @@ static unsigned int n_tty_receive_buf(struct tty_struct *tty,
                        tty->ops->flush_chars(tty);
        }
 
+       n_tty_set_room(tty);
+
        if ((!tty->icanon && (tty->read_cnt >= tty->minimum_to_wake)) ||
                L_EXTPROC(tty)) {
                kill_fasync(&tty->fasync, SIGIO, POLL_IN);
@@ -1402,12 +1432,8 @@ static unsigned int n_tty_receive_buf(struct tty_struct *tty,
         * mode.  We don't want to throttle the driver if we're in
         * canonical mode and don't have a newline yet!
         */
-       left = N_TTY_BUF_SIZE - tty->read_cnt - 1;
-
-       if (left < TTY_THRESHOLD_THROTTLE)
+       if (tty->receive_room < TTY_THRESHOLD_THROTTLE)
                tty_throttle(tty);
-
-       return ret;
 }
 
 int is_ignored(int sig)
@@ -1451,6 +1477,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
        if (test_bit(TTY_HW_COOK_IN, &tty->flags)) {
                tty->raw = 1;
                tty->real_raw = 1;
+               n_tty_set_room(tty);
                return;
        }
        if (I_ISTRIP(tty) || I_IUCLC(tty) || I_IGNCR(tty) ||
@@ -1503,6 +1530,7 @@ static void n_tty_set_termios(struct tty_struct *tty, struct ktermios *old)
                else
                        tty->real_raw = 0;
        }
+       n_tty_set_room(tty);
        /* The termios change make the tty ready for I/O */
        wake_up_interruptible(&tty->write_wait);
        wake_up_interruptible(&tty->read_wait);
@@ -1784,6 +1812,8 @@ do_it_again:
                                retval = -ERESTARTSYS;
                                break;
                        }
+                       /* FIXME: does n_tty_set_room need locking ? */
+                       n_tty_set_room(tty);
                        timeout = schedule_timeout(timeout);
                        continue;
                }
@@ -1855,8 +1885,10 @@ do_it_again:
                 * longer than TTY_THRESHOLD_UNTHROTTLE in canonical mode,
                 * we won't get any more characters.
                 */
-               if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE)
+               if (n_tty_chars_in_buffer(tty) <= TTY_THRESHOLD_UNTHROTTLE) {
+                       n_tty_set_room(tty);
                        check_unthrottle(tty);
+               }
 
                if (b - buf >= minimum)
                        break;
@@ -1878,6 +1910,7 @@ do_it_again:
        } else if (test_and_clear_bit(TTY_PUSH, &tty->flags))
                 goto do_it_again;
 
+       n_tty_set_room(tty);
        return retval;
 }
 
index 46de2e0..f1a7918 100644 (file)
@@ -416,7 +416,6 @@ static void flush_to_ldisc(struct work_struct *work)
                struct tty_buffer *head, *tail = tty->buf.tail;
                int seen_tail = 0;
                while ((head = tty->buf.head) != NULL) {
-                       int copied;
                        int count;
                        char *char_buf;
                        unsigned char *flag_buf;
@@ -443,19 +442,17 @@ static void flush_to_ldisc(struct work_struct *work)
                           line discipline as we want to empty the queue */
                        if (test_bit(TTY_FLUSHPENDING, &tty->flags))
                                break;
+                       if (!tty->receive_room || seen_tail)
+                               break;
+                       if (count > tty->receive_room)
+                               count = tty->receive_room;
                        char_buf = head->char_buf_ptr + head->read;
                        flag_buf = head->flag_buf_ptr + head->read;
+                       head->read += count;
                        spin_unlock_irqrestore(&tty->buf.lock, flags);
-                       copied = disc->ops->receive_buf(tty, char_buf,
+                       disc->ops->receive_buf(tty, char_buf,
                                                        flag_buf, count);
                        spin_lock_irqsave(&tty->buf.lock, flags);
-
-                       head->read += copied;
-
-                       if (copied == 0 || seen_tail) {
-                               schedule_work(&tty->buf.work);
-                               break;
-                       }
                }
                clear_bit(TTY_FLUSHING, &tty->flags);
        }
index 67b1d0d..fb864e7 100644 (file)
@@ -332,7 +332,8 @@ int paste_selection(struct tty_struct *tty)
                        continue;
                }
                count = sel_buffer_lth - pasted;
-               count = tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
+               count = min(count, tty->receive_room);
+               tty->ldisc->ops->receive_buf(tty, sel_buffer + pasted,
                                                                NULL, count);
                pasted += count;
        }
index 2f7c76a..e224a92 100644 (file)
@@ -144,7 +144,7 @@ static void handle_tx(struct vhost_net *net)
        }
 
        mutex_lock(&vq->mutex);
-       vhost_disable_notify(vq);
+       vhost_disable_notify(&net->dev, vq);
 
        if (wmem < sock->sk->sk_sndbuf / 2)
                tx_poll_stop(net);
@@ -166,8 +166,8 @@ static void handle_tx(struct vhost_net *net)
                                set_bit(SOCK_ASYNC_NOSPACE, &sock->flags);
                                break;
                        }
-                       if (unlikely(vhost_enable_notify(vq))) {
-                               vhost_disable_notify(vq);
+                       if (unlikely(vhost_enable_notify(&net->dev, vq))) {
+                               vhost_disable_notify(&net->dev, vq);
                                continue;
                        }
                        break;
@@ -315,7 +315,7 @@ static void handle_rx(struct vhost_net *net)
                return;
 
        mutex_lock(&vq->mutex);
-       vhost_disable_notify(vq);
+       vhost_disable_notify(&net->dev, vq);
        vhost_hlen = vq->vhost_hlen;
        sock_hlen = vq->sock_hlen;
 
@@ -334,10 +334,10 @@ static void handle_rx(struct vhost_net *net)
                        break;
                /* OK, now we need to know about added descriptors. */
                if (!headcount) {
-                       if (unlikely(vhost_enable_notify(vq))) {
+                       if (unlikely(vhost_enable_notify(&net->dev, vq))) {
                                /* They have slipped one in as we were
                                 * doing that: check again. */
-                               vhost_disable_notify(vq);
+                               vhost_disable_notify(&net->dev, vq);
                                continue;
                        }
                        /* Nothing new?  Wait for eventfd to tell us
index 099f302..734e1d7 100644 (file)
@@ -49,7 +49,7 @@ static void handle_vq(struct vhost_test *n)
                return;
 
        mutex_lock(&vq->mutex);
-       vhost_disable_notify(vq);
+       vhost_disable_notify(&n->dev, vq);
 
        for (;;) {
                head = vhost_get_vq_desc(&n->dev, vq, vq->iov,
@@ -61,8 +61,8 @@ static void handle_vq(struct vhost_test *n)
                        break;
                /* Nothing new?  Wait for eventfd to tell us they refilled. */
                if (head == vq->num) {
-                       if (unlikely(vhost_enable_notify(vq))) {
-                               vhost_disable_notify(vq);
+                       if (unlikely(vhost_enable_notify(&n->dev, vq))) {
+                               vhost_disable_notify(&n->dev, vq);
                                continue;
                        }
                        break;
index 7aa4eea..ea966b3 100644 (file)
@@ -37,6 +37,9 @@ enum {
        VHOST_MEMORY_F_LOG = 0x1,
 };
 
+#define vhost_used_event(vq) ((u16 __user *)&vq->avail->ring[vq->num])
+#define vhost_avail_event(vq) ((u16 __user *)&vq->used->ring[vq->num])
+
 static void vhost_poll_func(struct file *file, wait_queue_head_t *wqh,
                            poll_table *pt)
 {
@@ -161,6 +164,8 @@ static void vhost_vq_reset(struct vhost_dev *dev,
        vq->last_avail_idx = 0;
        vq->avail_idx = 0;
        vq->last_used_idx = 0;
+       vq->signalled_used = 0;
+       vq->signalled_used_valid = false;
        vq->used_flags = 0;
        vq->log_used = false;
        vq->log_addr = -1ull;
@@ -489,16 +494,17 @@ static int memory_access_ok(struct vhost_dev *d, struct vhost_memory *mem,
        return 1;
 }
 
-static int vq_access_ok(unsigned int num,
+static int vq_access_ok(struct vhost_dev *d, unsigned int num,
                        struct vring_desc __user *desc,
                        struct vring_avail __user *avail,
                        struct vring_used __user *used)
 {
+       size_t s = vhost_has_feature(d, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
        return access_ok(VERIFY_READ, desc, num * sizeof *desc) &&
               access_ok(VERIFY_READ, avail,
-                        sizeof *avail + num * sizeof *avail->ring) &&
+                        sizeof *avail + num * sizeof *avail->ring + s) &&
               access_ok(VERIFY_WRITE, used,
-                       sizeof *used + num * sizeof *used->ring);
+                       sizeof *used + num * sizeof *used->ring + s);
 }
 
 /* Can we log writes? */
@@ -514,9 +520,11 @@ int vhost_log_access_ok(struct vhost_dev *dev)
 
 /* Verify access for write logging. */
 /* Caller should have vq mutex and device mutex */
-static int vq_log_access_ok(struct vhost_virtqueue *vq, void __user *log_base)
+static int vq_log_access_ok(struct vhost_dev *d, struct vhost_virtqueue *vq,
+                           void __user *log_base)
 {
        struct vhost_memory *mp;
+       size_t s = vhost_has_feature(d, VIRTIO_RING_F_EVENT_IDX) ? 2 : 0;
 
        mp = rcu_dereference_protected(vq->dev->memory,
                                       lockdep_is_held(&vq->mutex));
@@ -524,15 +532,15 @@ static int vq_log_access_ok(struct vhost_virtqueue *vq, void __user *log_base)
                            vhost_has_feature(vq->dev, VHOST_F_LOG_ALL)) &&
                (!vq->log_used || log_access_ok(log_base, vq->log_addr,
                                        sizeof *vq->used +
-                                       vq->num * sizeof *vq->used->ring));
+                                       vq->num * sizeof *vq->used->ring + s));
 }
 
 /* Can we start vq? */
 /* Caller should have vq mutex and device mutex */
 int vhost_vq_access_ok(struct vhost_virtqueue *vq)
 {
-       return vq_access_ok(vq->num, vq->desc, vq->avail, vq->used) &&
-               vq_log_access_ok(vq, vq->log_base);
+       return vq_access_ok(vq->dev, vq->num, vq->desc, vq->avail, vq->used) &&
+               vq_log_access_ok(vq->dev, vq, vq->log_base);
 }
 
 static long vhost_set_memory(struct vhost_dev *d, struct vhost_memory __user *m)
@@ -577,6 +585,7 @@ static int init_used(struct vhost_virtqueue *vq,
 
        if (r)
                return r;
+       vq->signalled_used_valid = false;
        return get_user(vq->last_used_idx, &used->idx);
 }
 
@@ -674,7 +683,7 @@ static long vhost_set_vring(struct vhost_dev *d, int ioctl, void __user *argp)
                 * If it is not, we don't as size might not have been setup.
                 * We will verify when backend is configured. */
                if (vq->private_data) {
-                       if (!vq_access_ok(vq->num,
+                       if (!vq_access_ok(d, vq->num,
                                (void __user *)(unsigned long)a.desc_user_addr,
                                (void __user *)(unsigned long)a.avail_user_addr,
                                (void __user *)(unsigned long)a.used_user_addr)) {
@@ -818,7 +827,7 @@ long vhost_dev_ioctl(struct vhost_dev *d, unsigned int ioctl, unsigned long arg)
                        vq = d->vqs + i;
                        mutex_lock(&vq->mutex);
                        /* If ring is inactive, will check when it's enabled. */
-                       if (vq->private_data && !vq_log_access_ok(vq, base))
+                       if (vq->private_data && !vq_log_access_ok(d, vq, base))
                                r = -EFAULT;
                        else
                                vq->log_base = base;
@@ -1219,6 +1228,10 @@ int vhost_get_vq_desc(struct vhost_dev *dev, struct vhost_virtqueue *vq,
 
        /* On success, increment avail index. */
        vq->last_avail_idx++;
+
+       /* Assume notifications from guest are disabled at this point,
+        * if they aren't we would need to update avail_event index. */
+       BUG_ON(!(vq->used_flags & VRING_USED_F_NO_NOTIFY));
        return head;
 }
 
@@ -1267,6 +1280,12 @@ int vhost_add_used(struct vhost_virtqueue *vq, unsigned int head, int len)
                        eventfd_signal(vq->log_ctx, 1);
        }
        vq->last_used_idx++;
+       /* If the driver never bothers to signal in a very long while,
+        * used index might wrap around. If that happens, invalidate
+        * signalled_used index we stored. TODO: make sure driver
+        * signals at least once in 2^16 and remove this. */
+       if (unlikely(vq->last_used_idx == vq->signalled_used))
+               vq->signalled_used_valid = false;
        return 0;
 }
 
@@ -1275,6 +1294,7 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq,
                            unsigned count)
 {
        struct vring_used_elem __user *used;
+       u16 old, new;
        int start;
 
        start = vq->last_used_idx % vq->num;
@@ -1292,7 +1312,14 @@ static int __vhost_add_used_n(struct vhost_virtqueue *vq,
                           ((void __user *)used - (void __user *)vq->used),
                          count * sizeof *used);
        }
-       vq->last_used_idx += count;
+       old = vq->last_used_idx;
+       new = (vq->last_used_idx += count);
+       /* If the driver never bothers to signal in a very long while,
+        * used index might wrap around. If that happens, invalidate
+        * signalled_used index we stored. TODO: make sure driver
+        * signals at least once in 2^16 and remove this. */
+       if (unlikely((u16)(new - vq->signalled_used) < (u16)(new - old)))
+               vq->signalled_used_valid = false;
        return 0;
 }
 
@@ -1331,29 +1358,47 @@ int vhost_add_used_n(struct vhost_virtqueue *vq, struct vring_used_elem *heads,
        return r;
 }
 
-/* This actually signals the guest, using eventfd. */
-void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
+static bool vhost_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 {
-       __u16 flags;
-
+       __u16 old, new, event;
+       bool v;
        /* Flush out used index updates. This is paired
         * with the barrier that the Guest executes when enabling
         * interrupts. */
        smp_mb();
 
-       if (__get_user(flags, &vq->avail->flags)) {
-               vq_err(vq, "Failed to get flags");
-               return;
+       if (vhost_has_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY) &&
+           unlikely(vq->avail_idx == vq->last_avail_idx))
+               return true;
+
+       if (!vhost_has_feature(dev, VIRTIO_RING_F_EVENT_IDX)) {
+               __u16 flags;
+               if (__get_user(flags, &vq->avail->flags)) {
+                       vq_err(vq, "Failed to get flags");
+                       return true;
+               }
+               return !(flags & VRING_AVAIL_F_NO_INTERRUPT);
        }
+       old = vq->signalled_used;
+       v = vq->signalled_used_valid;
+       new = vq->signalled_used = vq->last_used_idx;
+       vq->signalled_used_valid = true;
 
-       /* If they don't want an interrupt, don't signal, unless empty. */
-       if ((flags & VRING_AVAIL_F_NO_INTERRUPT) &&
-           (vq->avail_idx != vq->last_avail_idx ||
-            !vhost_has_feature(dev, VIRTIO_F_NOTIFY_ON_EMPTY)))
-               return;
+       if (unlikely(!v))
+               return true;
 
+       if (get_user(event, vhost_used_event(vq))) {
+               vq_err(vq, "Failed to get used event idx");
+               return true;
+       }
+       return vring_need_event(event, new, old);
+}
+
+/* This actually signals the guest, using eventfd. */
+void vhost_signal(struct vhost_dev *dev, struct vhost_virtqueue *vq)
+{
        /* Signal the Guest tell them we used something up. */
-       if (vq->call_ctx)
+       if (vq->call_ctx && vhost_notify(dev, vq))
                eventfd_signal(vq->call_ctx, 1);
 }
 
@@ -1376,7 +1421,7 @@ void vhost_add_used_and_signal_n(struct vhost_dev *dev,
 }
 
 /* OK, now we need to know about added descriptors. */
-bool vhost_enable_notify(struct vhost_virtqueue *vq)
+bool vhost_enable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 {
        u16 avail_idx;
        int r;
@@ -1384,11 +1429,34 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq)
        if (!(vq->used_flags & VRING_USED_F_NO_NOTIFY))
                return false;
        vq->used_flags &= ~VRING_USED_F_NO_NOTIFY;
-       r = put_user(vq->used_flags, &vq->used->flags);
-       if (r) {
-               vq_err(vq, "Failed to enable notification at %p: %d\n",
-                      &vq->used->flags, r);
-               return false;
+       if (!vhost_has_feature(dev, VIRTIO_RING_F_EVENT_IDX)) {
+               r = put_user(vq->used_flags, &vq->used->flags);
+               if (r) {
+                       vq_err(vq, "Failed to enable notification at %p: %d\n",
+                              &vq->used->flags, r);
+                       return false;
+               }
+       } else {
+               r = put_user(vq->avail_idx, vhost_avail_event(vq));
+               if (r) {
+                       vq_err(vq, "Failed to update avail event index at %p: %d\n",
+                              vhost_avail_event(vq), r);
+                       return false;
+               }
+       }
+       if (unlikely(vq->log_used)) {
+               void __user *used;
+               /* Make sure data is seen before log. */
+               smp_wmb();
+               used = vhost_has_feature(dev, VIRTIO_RING_F_EVENT_IDX) ?
+                       &vq->used->flags : vhost_avail_event(vq);
+               /* Log used flags or event index entry write. Both are 16 bit
+                * fields. */
+               log_write(vq->log_base, vq->log_addr +
+                          (used - (void __user *)vq->used),
+                         sizeof(u16));
+               if (vq->log_ctx)
+                       eventfd_signal(vq->log_ctx, 1);
        }
        /* They could have slipped one in as we were doing that: make
         * sure it's written, then check again. */
@@ -1404,15 +1472,17 @@ bool vhost_enable_notify(struct vhost_virtqueue *vq)
 }
 
 /* We don't need to be notified again. */
-void vhost_disable_notify(struct vhost_virtqueue *vq)
+void vhost_disable_notify(struct vhost_dev *dev, struct vhost_virtqueue *vq)
 {
        int r;
 
        if (vq->used_flags & VRING_USED_F_NO_NOTIFY)
                return;
        vq->used_flags |= VRING_USED_F_NO_NOTIFY;
-       r = put_user(vq->used_flags, &vq->used->flags);
-       if (r)
-               vq_err(vq, "Failed to enable notification at %p: %d\n",
-                      &vq->used->flags, r);
+       if (!vhost_has_feature(dev, VIRTIO_RING_F_EVENT_IDX)) {
+               r = put_user(vq->used_flags, &vq->used->flags);
+               if (r)
+                       vq_err(vq, "Failed to enable notification at %p: %d\n",
+                              &vq->used->flags, r);
+       }
 }
index b3363ae..8e03379 100644 (file)
@@ -84,6 +84,12 @@ struct vhost_virtqueue {
        /* Used flags */
        u16 used_flags;
 
+       /* Last used index value we have signalled on */
+       u16 signalled_used;
+
+       /* Last used index value we have signalled on */
+       bool signalled_used_valid;
+
        /* Log writes to used structure. */
        bool log_used;
        u64 log_addr;
@@ -149,8 +155,8 @@ void vhost_add_used_and_signal(struct vhost_dev *, struct vhost_virtqueue *,
 void vhost_add_used_and_signal_n(struct vhost_dev *, struct vhost_virtqueue *,
                               struct vring_used_elem *heads, unsigned count);
 void vhost_signal(struct vhost_dev *, struct vhost_virtqueue *);
-void vhost_disable_notify(struct vhost_virtqueue *);
-bool vhost_enable_notify(struct vhost_virtqueue *);
+void vhost_disable_notify(struct vhost_dev *, struct vhost_virtqueue *);
+bool vhost_enable_notify(struct vhost_dev *, struct vhost_virtqueue *);
 
 int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
                    unsigned int log_num, u64 len);
@@ -162,11 +168,12 @@ int vhost_log_write(struct vhost_virtqueue *vq, struct vhost_log *log,
        } while (0)
 
 enum {
-       VHOST_FEATURES = (1 << VIRTIO_F_NOTIFY_ON_EMPTY) |
-                        (1 << VIRTIO_RING_F_INDIRECT_DESC) |
-                        (1 << VHOST_F_LOG_ALL) |
-                        (1 << VHOST_NET_F_VIRTIO_NET_HDR) |
-                        (1 << VIRTIO_NET_F_MRG_RXBUF),
+       VHOST_FEATURES = (1ULL << VIRTIO_F_NOTIFY_ON_EMPTY) |
+                        (1ULL << VIRTIO_RING_F_INDIRECT_DESC) |
+                        (1ULL << VIRTIO_RING_F_EVENT_IDX) |
+                        (1ULL << VHOST_F_LOG_ALL) |
+                        (1ULL << VHOST_NET_F_VIRTIO_NET_HDR) |
+                        (1ULL << VIRTIO_NET_F_MRG_RXBUF),
 };
 
 static inline int vhost_has_feature(struct vhost_dev *dev, int bit)
index 0f1da45..e058ace 100644 (file)
@@ -40,9 +40,6 @@ struct virtio_balloon
        /* Waiting for host to ack the pages we released. */
        struct completion acked;
 
-       /* Do we have to tell Host *before* we reuse pages? */
-       bool tell_host_first;
-
        /* The pages we've told the Host we're not using. */
        unsigned int num_pages;
        struct list_head pages;
@@ -151,13 +148,14 @@ static void leak_balloon(struct virtio_balloon *vb, size_t num)
                vb->num_pages--;
        }
 
-       if (vb->tell_host_first) {
-               tell_host(vb, vb->deflate_vq);
-               release_pages_by_pfn(vb->pfns, vb->num_pfns);
-       } else {
-               release_pages_by_pfn(vb->pfns, vb->num_pfns);
-               tell_host(vb, vb->deflate_vq);
-       }
+
+       /*
+        * Note that if
+        * virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
+        * is true, we *have* to do it in this order
+        */
+       tell_host(vb, vb->deflate_vq);
+       release_pages_by_pfn(vb->pfns, vb->num_pfns);
 }
 
 static inline void update_stat(struct virtio_balloon *vb, int idx,
@@ -325,9 +323,6 @@ static int virtballoon_probe(struct virtio_device *vdev)
                goto out_del_vqs;
        }
 
-       vb->tell_host_first
-               = virtio_has_feature(vdev, VIRTIO_BALLOON_F_MUST_TELL_HOST);
-
        return 0;
 
 out_del_vqs:
index b0043fb..68b9136 100644 (file)
@@ -82,6 +82,9 @@ struct vring_virtqueue
        /* Host supports indirect buffers */
        bool indirect;
 
+       /* Host publishes avail event idx */
+       bool event;
+
        /* Number of free buffers */
        unsigned int num_free;
        /* Head of free buffer list. */
@@ -237,18 +240,22 @@ EXPORT_SYMBOL_GPL(virtqueue_add_buf_gfp);
 void virtqueue_kick(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
+       u16 new, old;
        START_USE(vq);
        /* Descriptors and available array need to be set before we expose the
         * new available array entries. */
        virtio_wmb();
 
-       vq->vring.avail->idx += vq->num_added;
+       old = vq->vring.avail->idx;
+       new = vq->vring.avail->idx = old + vq->num_added;
        vq->num_added = 0;
 
        /* Need to update avail index before checking if we should notify */
        virtio_mb();
 
-       if (!(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY))
+       if (vq->event ?
+           vring_need_event(vring_avail_event(&vq->vring), new, old) :
+           !(vq->vring.used->flags & VRING_USED_F_NO_NOTIFY))
                /* Prod other side to tell it about changes. */
                vq->notify(&vq->vq);
 
@@ -324,6 +331,14 @@ void *virtqueue_get_buf(struct virtqueue *_vq, unsigned int *len)
        ret = vq->data[i];
        detach_buf(vq, i);
        vq->last_used_idx++;
+       /* If we expect an interrupt for the next entry, tell host
+        * by writing event index and flush out the write before
+        * the read in the next get_buf call. */
+       if (!(vq->vring.avail->flags & VRING_AVAIL_F_NO_INTERRUPT)) {
+               vring_used_event(&vq->vring) = vq->last_used_idx;
+               virtio_mb();
+       }
+
        END_USE(vq);
        return ret;
 }
@@ -345,7 +360,11 @@ bool virtqueue_enable_cb(struct virtqueue *_vq)
 
        /* We optimistically turn back on interrupts, then check if there was
         * more to do. */
+       /* Depending on the VIRTIO_RING_F_EVENT_IDX feature, we need to
+        * either clear the flags bit or point the event index at the next
+        * entry. Always do both to keep code simple. */
        vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
+       vring_used_event(&vq->vring) = vq->last_used_idx;
        virtio_mb();
        if (unlikely(more_used(vq))) {
                END_USE(vq);
@@ -357,6 +376,33 @@ bool virtqueue_enable_cb(struct virtqueue *_vq)
 }
 EXPORT_SYMBOL_GPL(virtqueue_enable_cb);
 
+bool virtqueue_enable_cb_delayed(struct virtqueue *_vq)
+{
+       struct vring_virtqueue *vq = to_vvq(_vq);
+       u16 bufs;
+
+       START_USE(vq);
+
+       /* We optimistically turn back on interrupts, then check if there was
+        * more to do. */
+       /* Depending on the VIRTIO_RING_F_USED_EVENT_IDX feature, we need to
+        * either clear the flags bit or point the event index at the next
+        * entry. Always do both to keep code simple. */
+       vq->vring.avail->flags &= ~VRING_AVAIL_F_NO_INTERRUPT;
+       /* TODO: tune this threshold */
+       bufs = (u16)(vq->vring.avail->idx - vq->last_used_idx) * 3 / 4;
+       vring_used_event(&vq->vring) = vq->last_used_idx + bufs;
+       virtio_mb();
+       if (unlikely((u16)(vq->vring.used->idx - vq->last_used_idx) > bufs)) {
+               END_USE(vq);
+               return false;
+       }
+
+       END_USE(vq);
+       return true;
+}
+EXPORT_SYMBOL_GPL(virtqueue_enable_cb_delayed);
+
 void *virtqueue_detach_unused_buf(struct virtqueue *_vq)
 {
        struct vring_virtqueue *vq = to_vvq(_vq);
@@ -438,6 +484,7 @@ struct virtqueue *vring_new_virtqueue(unsigned int num,
 #endif
 
        vq->indirect = virtio_has_feature(vdev, VIRTIO_RING_F_INDIRECT_DESC);
+       vq->event = virtio_has_feature(vdev, VIRTIO_RING_F_EVENT_IDX);
 
        /* No callback?  Tell other side not to bother us. */
        if (!callback)
@@ -472,6 +519,8 @@ void vring_transport_features(struct virtio_device *vdev)
                switch (i) {
                case VIRTIO_RING_F_INDIRECT_DESC:
                        break;
+               case VIRTIO_RING_F_EVENT_IDX:
+                       break;
                default:
                        /* We don't understand this bit. */
                        clear_bit(i, vdev->features);
index 87d95a8..f55ae23 100644 (file)
@@ -583,8 +583,6 @@ static int autofs4_dir_unlink(struct inode *dir, struct dentry *dentry)
        if (!autofs4_oz_mode(sbi) && !capable(CAP_SYS_ADMIN))
                return -EACCES;
 
-       dentry_unhash(dentry);
-
        if (atomic_dec_and_test(&ino->count)) {
                p_ino = autofs4_dentry_ino(dentry->d_parent);
                if (p_ino && dentry->d_parent != dentry)
index 1f2b199..1a2421f 100644 (file)
@@ -1272,8 +1272,8 @@ int blkdev_get(struct block_device *bdev, fmode_t mode, void *holder)
                 * individual writeable reference is too fragile given the
                 * way @mode is used in blkdev_get/put().
                 */
-               if ((disk->flags & GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE) &&
-                   !res && (mode & FMODE_WRITE) && !bdev->bd_write_holder) {
+               if (!res && (mode & FMODE_WRITE) && !bdev->bd_write_holder &&
+                   (disk->flags & GENHD_FL_BLOCK_EVENTS_ON_EXCL_WRITE)) {
                        bdev->bd_write_holder = true;
                        disk_block_events(disk);
                }
index 1ab641f..e2e4e8d 100644 (file)
@@ -2579,6 +2579,7 @@ int vfs_rmdir(struct inode *dir, struct dentry *dentry)
        if (error)
                goto out;
 
+       shrink_dcache_parent(dentry);
        error = dir->i_op->rmdir(dir, dentry);
        if (error)
                goto out;
@@ -2993,6 +2994,8 @@ static int vfs_rename_dir(struct inode *old_dir, struct dentry *old_dentry,
        if (d_mountpoint(old_dentry) || d_mountpoint(new_dentry))
                goto out;
 
+       if (target)
+               shrink_dcache_parent(new_dentry);
        error = old_dir->i_op->rename(old_dir, old_dentry, new_dir, new_dentry);
        if (error)
                goto out;
index f82e762..d545e97 100644 (file)
@@ -255,13 +255,7 @@ ssize_t part_discard_alignment_show(struct device *dev,
                                   struct device_attribute *attr, char *buf)
 {
        struct hd_struct *p = dev_to_part(dev);
-       struct gendisk *disk = dev_to_disk(dev);
-       unsigned int alignment = 0;
-
-       if (disk->queue)
-               alignment = queue_limit_discard_alignment(&disk->queue->limits,
-                                                               p->start_sect);
-       return sprintf(buf, "%u\n", alignment);
+       return sprintf(buf, "%u\n", p->discard_alignment);
 }
 
 ssize_t part_stat_show(struct device *dev,
@@ -455,6 +449,8 @@ struct hd_struct *add_partition(struct gendisk *disk, int partno,
        p->start_sect = start;
        p->alignment_offset =
                queue_limit_alignment_offset(&disk->queue->limits, start);
+       p->discard_alignment =
+               queue_limit_discard_alignment(&disk->queue->limits, start);
        p->nr_sects = len;
        p->partno = partno;
        p->policy = get_disk_ro(disk);
index 166951e..3be645e 100644 (file)
@@ -581,6 +581,7 @@ int ubifs_wbuf_write_nolock(struct ubifs_wbuf *wbuf, void *buf, int len)
        ubifs_assert(wbuf->size % c->min_io_size == 0);
        ubifs_assert(mutex_is_locked(&wbuf->io_mutex));
        ubifs_assert(!c->ro_media && !c->ro_mount);
+       ubifs_assert(!c->space_fixup);
        if (c->leb_size - wbuf->offs >= c->max_write_size)
                ubifs_assert(!((wbuf->offs + wbuf->size) % c->max_write_size));
 
@@ -759,6 +760,7 @@ int ubifs_write_node(struct ubifs_info *c, void *buf, int len, int lnum,
        ubifs_assert(lnum >= 0 && lnum < c->leb_cnt && offs >= 0);
        ubifs_assert(offs % c->min_io_size == 0 && offs < c->leb_size);
        ubifs_assert(!c->ro_media && !c->ro_mount);
+       ubifs_assert(!c->space_fixup);
 
        if (c->ro_error)
                return -EROFS;
index 34b1679..cef0460 100644 (file)
@@ -669,6 +669,7 @@ out_free:
 
 out_release:
        release_head(c, BASEHD);
+       kfree(dent);
 out_ro:
        ubifs_ro_mode(c, err);
        if (last_reference)
index bd644bf..a5422ff 100644 (file)
@@ -674,7 +674,7 @@ static int kill_orphans(struct ubifs_info *c)
                if (IS_ERR(sleb)) {
                        if (PTR_ERR(sleb) == -EUCLEAN)
                                sleb = ubifs_recover_leb(c, lnum, 0,
-                                                        c->sbuf, 0);
+                                                        c->sbuf, -1);
                        if (IS_ERR(sleb)) {
                                err = PTR_ERR(sleb);
                                break;
index 731d9e2..783d8e0 100644 (file)
@@ -564,19 +564,15 @@ static int fix_unclean_leb(struct ubifs_info *c, struct ubifs_scan_leb *sleb,
 }
 
 /**
- * drop_last_node - drop the last node or group of nodes.
+ * drop_last_group - drop the last group of nodes.
  * @sleb: scanned LEB information
  * @offs: offset of dropped nodes is returned here
- * @grouped: non-zero if whole group of nodes have to be dropped
  *
  * This is a helper function for 'ubifs_recover_leb()' which drops the last
- * node of the scanned LEB or the last group of nodes if @grouped is not zero.
- * This function returns %1 if a node was dropped and %0 otherwise.
+ * group of nodes of the scanned LEB.
  */
-static int drop_last_node(struct ubifs_scan_leb *sleb, int *offs, int grouped)
+static void drop_last_group(struct ubifs_scan_leb *sleb, int *offs)
 {
-       int dropped = 0;
-
        while (!list_empty(&sleb->nodes)) {
                struct ubifs_scan_node *snod;
                struct ubifs_ch *ch;
@@ -585,17 +581,40 @@ static int drop_last_node(struct ubifs_scan_leb *sleb, int *offs, int grouped)
                                  list);
                ch = snod->node;
                if (ch->group_type != UBIFS_IN_NODE_GROUP)
-                       return dropped;
-               dbg_rcvry("dropping node at %d:%d", sleb->lnum, snod->offs);
+                       break;
+
+               dbg_rcvry("dropping grouped node at %d:%d",
+                         sleb->lnum, snod->offs);
+               *offs = snod->offs;
+               list_del(&snod->list);
+               kfree(snod);
+               sleb->nodes_cnt -= 1;
+       }
+}
+
+/**
+ * drop_last_node - drop the last node.
+ * @sleb: scanned LEB information
+ * @offs: offset of dropped nodes is returned here
+ * @grouped: non-zero if whole group of nodes have to be dropped
+ *
+ * This is a helper function for 'ubifs_recover_leb()' which drops the last
+ * node of the scanned LEB.
+ */
+static void drop_last_node(struct ubifs_scan_leb *sleb, int *offs)
+{
+       struct ubifs_scan_node *snod;
+
+       if (!list_empty(&sleb->nodes)) {
+               snod = list_entry(sleb->nodes.prev, struct ubifs_scan_node,
+                                 list);
+
+               dbg_rcvry("dropping last node at %d:%d", sleb->lnum, snod->offs);
                *offs = snod->offs;
                list_del(&snod->list);
                kfree(snod);
                sleb->nodes_cnt -= 1;
-               dropped = 1;
-               if (!grouped)
-                       break;
        }
-       return dropped;
 }
 
 /**
@@ -604,7 +623,8 @@ static int drop_last_node(struct ubifs_scan_leb *sleb, int *offs, int grouped)
  * @lnum: LEB number
  * @offs: offset
  * @sbuf: LEB-sized buffer to use
- * @grouped: nodes may be grouped for recovery
+ * @jhead: journal head number this LEB belongs to (%-1 if the LEB does not
+ *         belong to any journal head)
  *
  * This function does a scan of a LEB, but caters for errors that might have
  * been caused by the unclean unmount from which we are attempting to recover.
@@ -612,13 +632,14 @@ static int drop_last_node(struct ubifs_scan_leb *sleb, int *offs, int grouped)
  * found, and a negative error code in case of failure.
  */
 struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
-                                        int offs, void *sbuf, int grouped)
+                                        int offs, void *sbuf, int jhead)
 {
        int ret = 0, err, len = c->leb_size - offs, start = offs, min_io_unit;
+       int grouped = jhead == -1 ? 0 : c->jheads[jhead].grouped;
        struct ubifs_scan_leb *sleb;
        void *buf = sbuf + offs;
 
-       dbg_rcvry("%d:%d", lnum, offs);
+       dbg_rcvry("%d:%d, jhead %d, grouped %d", lnum, offs, jhead, grouped);
 
        sleb = ubifs_start_scan(c, lnum, offs, sbuf);
        if (IS_ERR(sleb))
@@ -635,7 +656,7 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
                 * Scan quietly until there is an error from which we cannot
                 * recover
                 */
-               ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 0);
+               ret = ubifs_scan_a_node(c, buf, len, lnum, offs, 1);
                if (ret == SCANNED_A_NODE) {
                        /* A valid node, and not a padding node */
                        struct ubifs_ch *ch = buf;
@@ -695,59 +716,62 @@ struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
                 * If nodes are grouped, always drop the incomplete group at
                 * the end.
                 */
-               drop_last_node(sleb, &offs, 1);
+               drop_last_group(sleb, &offs);
 
-       /*
-        * While we are in the middle of the same min. I/O unit keep dropping
-        * nodes. So basically, what we want is to make sure that the last min.
-        * I/O unit where we saw the corruption is dropped completely with all
-        * the uncorrupted node which may possibly sit there.
-        *
-        * In other words, let's name the min. I/O unit where the corruption
-        * starts B, and the previous min. I/O unit A. The below code tries to
-        * deal with a situation when half of B contains valid nodes or the end
-        * of a valid node, and the second half of B contains corrupted data or
-        * garbage. This means that UBIFS had been writing to B just before the
-        * power cut happened. I do not know how realistic is this scenario
-        * that half of the min. I/O unit had been written successfully and the
-        * other half not, but this is possible in our 'failure mode emulation'
-        * infrastructure at least.
-        *
-        * So what is the problem, why we need to drop those nodes? Whey can't
-        * we just clean-up the second half of B by putting a padding node
-        * there? We can, and this works fine with one exception which was
-        * reproduced with power cut emulation testing and happens extremely
-        * rarely. The description follows, but it is worth noting that that is
-        * only about the GC head, so we could do this trick only if the bud
-        * belongs to the GC head, but it does not seem to be worth an
-        * additional "if" statement.
-        *
-        * So, imagine the file-system is full, we run GC which is moving valid
-        * nodes from LEB X to LEB Y (obviously, LEB Y is the current GC head
-        * LEB). The @c->gc_lnum is -1, which means that GC will retain LEB X
-        * and will try to continue. Imagine that LEB X is currently the
-        * dirtiest LEB, and the amount of used space in LEB Y is exactly the
-        * same as amount of free space in LEB X.
-        *
-        * And a power cut happens when nodes are moved from LEB X to LEB Y. We
-        * are here trying to recover LEB Y which is the GC head LEB. We find
-        * the min. I/O unit B as described above. Then we clean-up LEB Y by
-        * padding min. I/O unit. And later 'ubifs_rcvry_gc_commit()' function
-        * fails, because it cannot find a dirty LEB which could be GC'd into
-        * LEB Y! Even LEB X does not match because the amount of valid nodes
-        * there does not fit the free space in LEB Y any more! And this is
-        * because of the padding node which we added to LEB Y. The
-        * user-visible effect of this which I once observed and analysed is
-        * that we cannot mount the file-system with -ENOSPC error.
-        *
-        * So obviously, to make sure that situation does not happen we should
-        * free min. I/O unit B in LEB Y completely and the last used min. I/O
-        * unit in LEB Y should be A. This is basically what the below code
-        * tries to do.
-        */
-       while (min_io_unit == round_down(offs, c->min_io_size) &&
-              min_io_unit != offs &&
-              drop_last_node(sleb, &offs, grouped));
+       if (jhead == GCHD) {
+               /*
+                * If this LEB belongs to the GC head then while we are in the
+                * middle of the same min. I/O unit keep dropping nodes. So
+                * basically, what we want is to make sure that the last min.
+                * I/O unit where we saw the corruption is dropped completely
+                * with all the uncorrupted nodes which may possibly sit there.
+                *
+                * In other words, let's name the min. I/O unit where the
+                * corruption starts B, and the previous min. I/O unit A. The
+                * below code tries to deal with a situation when half of B
+                * contains valid nodes or the end of a valid node, and the
+                * second half of B contains corrupted data or garbage. This
+                * means that UBIFS had been writing to B just before the power
+                * cut happened. I do not know how realistic is this scenario
+                * that half of the min. I/O unit had been written successfully
+                * and the other half not, but this is possible in our 'failure
+                * mode emulation' infrastructure at least.
+                *
+                * So what is the problem, why we need to drop those nodes? Why
+                * can't we just clean-up the second half of B by putting a
+                * padding node there? We can, and this works fine with one
+                * exception which was reproduced with power cut emulation
+                * testing and happens extremely rarely.
+                *
+                * Imagine the file-system is full, we run GC which starts
+                * moving valid nodes from LEB X to LEB Y (obviously, LEB Y is
+                * the current GC head LEB). The @c->gc_lnum is -1, which means
+                * that GC will retain LEB X and will try to continue. Imagine
+                * that LEB X is currently the dirtiest LEB, and the amount of
+                * used space in LEB Y is exactly the same as amount of free
+                * space in LEB X.
+                *
+                * And a power cut happens when nodes are moved from LEB X to
+                * LEB Y. We are here trying to recover LEB Y which is the GC
+                * head LEB. We find the min. I/O unit B as described above.
+                * Then we clean-up LEB Y by padding min. I/O unit. And later
+                * 'ubifs_rcvry_gc_commit()' function fails, because it cannot
+                * find a dirty LEB which could be GC'd into LEB Y! Even LEB X
+                * does not match because the amount of valid nodes there does
+                * not fit the free space in LEB Y any more! And this is
+                * because of the padding node which we added to LEB Y. The
+                * user-visible effect of this which I once observed and
+                * analysed is that we cannot mount the file-system with
+                * -ENOSPC error.
+                *
+                * So obviously, to make sure that situation does not happen we
+                * should free min. I/O unit B in LEB Y completely and the last
+                * used min. I/O unit in LEB Y should be A. This is basically
+                * what the below code tries to do.
+                */
+               while (offs > min_io_unit)
+                       drop_last_node(sleb, &offs);
+       }
 
        buf = sbuf + offs;
        len = c->leb_size - offs;
@@ -881,7 +905,7 @@ struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
                }
                ubifs_scan_destroy(sleb);
        }
-       return ubifs_recover_leb(c, lnum, offs, sbuf, 0);
+       return ubifs_recover_leb(c, lnum, offs, sbuf, -1);
 }
 
 /**
index 6617280..5e97161 100644 (file)
@@ -557,8 +557,7 @@ static int replay_bud(struct ubifs_info *c, struct bud_entry *b)
                 * these LEBs could possibly be written to at the power cut
                 * time.
                 */
-               sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf,
-                                        b->bud->jhead != GCHD);
+               sleb = ubifs_recover_leb(c, lnum, offs, c->sbuf, b->bud->jhead);
        else
                sleb = ubifs_scan(c, lnum, offs, c->sbuf, 0);
        if (IS_ERR(sleb))
index ca953a9..9e1d056 100644 (file)
@@ -284,7 +284,11 @@ int ubifs_shrinker(struct shrinker *shrink, struct shrink_control *sc)
        long clean_zn_cnt = atomic_long_read(&ubifs_clean_zn_cnt);
 
        if (nr == 0)
-               return clean_zn_cnt;
+               /*
+                * Due to the way UBIFS updates the clean znode counter it may
+                * temporarily be negative.
+                */
+               return clean_zn_cnt >= 0 ? clean_zn_cnt : 1;
 
        if (!clean_zn_cnt) {
                /*
index 1ab0d22..b5aeb5a 100644 (file)
@@ -811,15 +811,18 @@ static int alloc_wbufs(struct ubifs_info *c)
 
                c->jheads[i].wbuf.sync_callback = &bud_wbuf_callback;
                c->jheads[i].wbuf.jhead = i;
+               c->jheads[i].grouped = 1;
        }
 
        c->jheads[BASEHD].wbuf.dtype = UBI_SHORTTERM;
        /*
         * Garbage Collector head likely contains long-term data and
-        * does not need to be synchronized by timer.
+        * does not need to be synchronized by timer. Also GC head nodes are
+        * not grouped.
         */
        c->jheads[GCHD].wbuf.dtype = UBI_LONGTERM;
        c->jheads[GCHD].wbuf.no_timer = 1;
+       c->jheads[GCHD].grouped = 0;
 
        return 0;
 }
@@ -1284,12 +1287,25 @@ static int mount_ubifs(struct ubifs_info *c)
        if ((c->mst_node->flags & cpu_to_le32(UBIFS_MST_DIRTY)) != 0) {
                ubifs_msg("recovery needed");
                c->need_recovery = 1;
-               if (!c->ro_mount) {
-                       err = ubifs_recover_inl_heads(c, c->sbuf);
-                       if (err)
-                               goto out_master;
-               }
-       } else if (!c->ro_mount) {
+       }
+
+       if (c->need_recovery && !c->ro_mount) {
+               err = ubifs_recover_inl_heads(c, c->sbuf);
+               if (err)
+                       goto out_master;
+       }
+
+       err = ubifs_lpt_init(c, 1, !c->ro_mount);
+       if (err)
+               goto out_master;
+
+       if (!c->ro_mount && c->space_fixup) {
+               err = ubifs_fixup_free_space(c);
+               if (err)
+                       goto out_master;
+       }
+
+       if (!c->ro_mount) {
                /*
                 * Set the "dirty" flag so that if we reboot uncleanly we
                 * will notice this immediately on the next mount.
@@ -1297,13 +1313,9 @@ static int mount_ubifs(struct ubifs_info *c)
                c->mst_node->flags |= cpu_to_le32(UBIFS_MST_DIRTY);
                err = ubifs_write_master(c);
                if (err)
-                       goto out_master;
+                       goto out_lpt;
        }
 
-       err = ubifs_lpt_init(c, 1, !c->ro_mount);
-       if (err)
-               goto out_lpt;
-
        err = dbg_check_idx_size(c, c->bi.old_idx_sz);
        if (err)
                goto out_lpt;
@@ -1396,12 +1408,6 @@ static int mount_ubifs(struct ubifs_info *c)
        } else
                ubifs_assert(c->lst.taken_empty_lebs > 0);
 
-       if (!c->ro_mount && c->space_fixup) {
-               err = ubifs_fixup_free_space(c);
-               if (err)
-                       goto out_infos;
-       }
-
        err = dbg_check_filesystem(c);
        if (err)
                goto out_infos;
index 8119b1f..91b4213 100644 (file)
@@ -2876,12 +2876,13 @@ static void tnc_destroy_cnext(struct ubifs_info *c)
  */
 void ubifs_tnc_close(struct ubifs_info *c)
 {
-       long clean_freed;
-
        tnc_destroy_cnext(c);
        if (c->zroot.znode) {
-               clean_freed = ubifs_destroy_tnc_subtree(c->zroot.znode);
-               atomic_long_sub(clean_freed, &ubifs_clean_zn_cnt);
+               long n;
+
+               ubifs_destroy_tnc_subtree(c->zroot.znode);
+               n = atomic_long_read(&c->clean_zn_cnt);
+               atomic_long_sub(n, &ubifs_clean_zn_cnt);
        }
        kfree(c->gap_lebs);
        kfree(c->ilebs);
index a70d7b4..f79983d 100644 (file)
@@ -722,12 +722,14 @@ struct ubifs_bud {
  * struct ubifs_jhead - journal head.
  * @wbuf: head's write-buffer
  * @buds_list: list of bud LEBs belonging to this journal head
+ * @grouped: non-zero if UBIFS groups nodes when writing to this journal head
  *
  * Note, the @buds list is protected by the @c->buds_lock.
  */
 struct ubifs_jhead {
        struct ubifs_wbuf wbuf;
        struct list_head buds_list;
+       unsigned int grouped:1;
 };
 
 /**
@@ -1742,7 +1744,7 @@ struct inode *ubifs_iget(struct super_block *sb, unsigned long inum);
 int ubifs_recover_master_node(struct ubifs_info *c);
 int ubifs_write_rcvrd_mst_node(struct ubifs_info *c);
 struct ubifs_scan_leb *ubifs_recover_leb(struct ubifs_info *c, int lnum,
-                                        int offs, void *sbuf, int grouped);
+                                        int offs, void *sbuf, int jhead);
 struct ubifs_scan_leb *ubifs_recover_log_leb(struct ubifs_info *c, int lnum,
                                             int offs, void *sbuf);
 int ubifs_recover_inl_heads(const struct ubifs_info *c, void *sbuf);
index ae90e0f..4f76959 100644 (file)
@@ -683,9 +683,11 @@ __SC_COMP(__NR_clock_adjtime, sys_clock_adjtime, compat_sys_clock_adjtime)
 __SYSCALL(__NR_syncfs, sys_syncfs)
 #define __NR_setns 268
 __SYSCALL(__NR_setns, sys_setns)
+#define __NR_sendmmsg 269
+__SC_COMP(__NR_sendmmsg, sys_sendmmsg, compat_sys_sendmmsg)
 
 #undef __NR_syscalls
-#define __NR_syscalls 269
+#define __NR_syscalls 270
 
 /*
  * All syscalls below here should go away really,
index 7d650a0..7216b0d 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/if_arcnet.h>
 
 #ifdef __KERNEL__
+#include  <linux/irqreturn.h>
 
 #ifndef bool
 #define bool int
index 08763e4..6ff080e 100644 (file)
@@ -6,6 +6,7 @@
 
 #include <linux/bcma/bcma_driver_chipcommon.h>
 #include <linux/bcma/bcma_driver_pci.h>
+#include <linux/ssb/ssb.h> /* SPROM sharing */
 
 #include "bcma_regs.h"
 
@@ -31,6 +32,12 @@ struct bcma_host_ops {
        void (*write8)(struct bcma_device *core, u16 offset, u8 value);
        void (*write16)(struct bcma_device *core, u16 offset, u16 value);
        void (*write32)(struct bcma_device *core, u16 offset, u32 value);
+#ifdef CONFIG_BCMA_BLOCKIO
+       void (*block_read)(struct bcma_device *core, void *buffer,
+                          size_t count, u16 offset, u8 reg_width);
+       void (*block_write)(struct bcma_device *core, const void *buffer,
+                           size_t count, u16 offset, u8 reg_width);
+#endif
        /* Agent ops */
        u32 (*aread32)(struct bcma_device *core, u16 offset);
        void (*awrite32)(struct bcma_device *core, u16 offset, u32 value);
@@ -117,6 +124,8 @@ struct bcma_device {
        struct bcma_device_id id;
 
        struct device dev;
+       struct device *dma_dev;
+       unsigned int irq;
        bool dev_registered;
 
        u8 core_index;
@@ -179,6 +188,10 @@ struct bcma_bus {
 
        struct bcma_drv_cc drv_cc;
        struct bcma_drv_pci drv_pci;
+
+       /* We decided to share SPROM struct with SSB as long as we do not need
+        * any hacks for BCMA. This simplifies drivers code. */
+       struct ssb_sprom sprom;
 };
 
 extern inline u32 bcma_read8(struct bcma_device *core, u16 offset)
@@ -208,6 +221,18 @@ void bcma_write32(struct bcma_device *core, u16 offset, u32 value)
 {
        core->bus->ops->write32(core, offset, value);
 }
+#ifdef CONFIG_BCMA_BLOCKIO
+extern inline void bcma_block_read(struct bcma_device *core, void *buffer,
+                                  size_t count, u16 offset, u8 reg_width)
+{
+       core->bus->ops->block_read(core, buffer, count, offset, reg_width);
+}
+extern inline void bcma_block_write(struct bcma_device *core, const void *buffer,
+                                   size_t count, u16 offset, u8 reg_width)
+{
+       core->bus->ops->block_write(core, buffer, count, offset, reg_width);
+}
+#endif
 extern inline u32 bcma_aread32(struct bcma_device *core, u16 offset)
 {
        return core->bus->ops->aread32(core, offset);
index 083c3b6..9c5b69f 100644 (file)
 #define BCMA_CC_REGCTL_DATA            0x065C
 #define BCMA_CC_PLLCTL_ADDR            0x0660
 #define BCMA_CC_PLLCTL_DATA            0x0664
+#define BCMA_CC_SPROM                  0x0830 /* SPROM beginning */
 
 /* Data for the PMU, if available.
  * Check availability with ((struct bcma_chipcommon)->capabilities & BCMA_CC_CAP_PMU)
index ae9091a..1a23722 100644 (file)
@@ -1282,8 +1282,8 @@ queue_max_integrity_segments(struct request_queue *q)
 #define blk_get_integrity(a)                   (0)
 #define blk_integrity_compare(a, b)            (0)
 #define blk_integrity_register(a, b)           (0)
-#define blk_integrity_unregister(a)            do { } while (0);
-#define blk_queue_max_integrity_segments(a, b) do { } while (0);
+#define blk_integrity_unregister(a)            do { } while (0)
+#define blk_queue_max_integrity_segments(a, b) do { } while (0)
 #define queue_max_integrity_segments(a)                (0)
 #define blk_integrity_merge_rq(a, b, c)                (0)
 #define blk_integrity_merge_bio(a, b, c)       (0)
diff --git a/include/linux/cordic.h b/include/linux/cordic.h
new file mode 100644 (file)
index 0000000..f932093
--- /dev/null
@@ -0,0 +1,48 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * 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.
+ */
+#ifndef __CORDIC_H_
+#define __CORDIC_H_
+
+#include <linux/types.h>
+
+/**
+ * struct cordic_iq - i/q coordinate.
+ *
+ * @i: real part of coordinate (in phase).
+ * @q: imaginary part of coordinate (quadrature).
+ */
+struct cordic_iq {
+       s32 i;
+       s32 q;
+};
+
+/**
+ * cordic_calc_iq() - calculates the i/q coordinate for given angle.
+ *
+ * @theta: angle in degrees for which i/q coordinate is to be calculated.
+ * @coord: function output parameter holding the i/q coordinate.
+ *
+ * The function calculates the i/q coordinate for a given angle using
+ * cordic algorithm. The coordinate consists of a real (i) and an
+ * imaginary (q) part. The real part is essentially the cosine of the
+ * angle and the imaginary part is the sine of the angle. The returned
+ * values are scaled by 2^16 for precision. The range for theta is
+ * for -180 degrees to +180 degrees. Passed values outside this range are
+ * converted before doing the actual calculation.
+ */
+struct cordic_iq cordic_calc_iq(s32 theta);
+
+#endif /* __CORDIC_H_ */
diff --git a/include/linux/crc8.h b/include/linux/crc8.h
new file mode 100644 (file)
index 0000000..13c8dab
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * 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.
+ */
+#ifndef __CRC8_H_
+#define __CRC8_H_
+
+#include <linux/types.h>
+
+/* see usage of this value in crc8() description */
+#define CRC8_INIT_VALUE                0xFF
+
+/*
+ * Return value of crc8() indicating valid message+crc. This is true
+ * if a CRC is inverted before transmission. The CRC computed over the
+ * whole received bitstream is _table[x], where x is the bit pattern
+ * of the modification (almost always 0xff).
+ */
+#define CRC8_GOOD_VALUE(_table)        (_table[0xFF])
+
+/* required table size for crc8 algorithm */
+#define CRC8_TABLE_SIZE                        256
+
+/* helper macro assuring right table size is used */
+#define DECLARE_CRC8_TABLE(_table) \
+       static u8 _table[CRC8_TABLE_SIZE]
+
+/**
+ * crc8_populate_lsb - fill crc table for given polynomial in regular bit order.
+ *
+ * @table:     table to be filled.
+ * @polynomial:        polynomial for which table is to be filled.
+ *
+ * This function fills the provided table according the polynomial provided for
+ * regular bit order (lsb first). Polynomials in CRC algorithms are typically
+ * represented as shown below.
+ *
+ *     poly = x^8 + x^7 + x^6 + x^4 + x^2 + 1
+ *
+ * For lsb first direction x^7 maps to the lsb. So the polynomial is as below.
+ *
+ * - lsb first: poly = 10101011(1) = 0xAB
+ */
+void crc8_populate_lsb(u8 table[CRC8_TABLE_SIZE], u8 polynomial);
+
+/**
+ * crc8_populate_msb - fill crc table for given polynomial in reverse bit order.
+ *
+ * @table:     table to be filled.
+ * @polynomial:        polynomial for which table is to be filled.
+ *
+ * This function fills the provided table according the polynomial provided for
+ * reverse bit order (msb first). Polynomials in CRC algorithms are typically
+ * represented as shown below.
+ *
+ *     poly = x^8 + x^7 + x^6 + x^4 + x^2 + 1
+ *
+ * For msb first direction x^7 maps to the msb. So the polynomial is as below.
+ *
+ * - msb first: poly = (1)11010101 = 0xD5
+ */
+void crc8_populate_msb(u8 table[CRC8_TABLE_SIZE], u8 polynomial);
+
+/**
+ * crc8() - calculate a crc8 over the given input data.
+ *
+ * @table:     crc table used for calculation.
+ * @pdata:     pointer to data buffer.
+ * @nbytes:    number of bytes in data buffer.
+ * @crc:       previous returned crc8 value.
+ *
+ * The CRC8 is calculated using the polynomial given in crc8_populate_msb()
+ * or crc8_populate_lsb().
+ *
+ * The caller provides the initial value (either %CRC8_INIT_VALUE
+ * or the previous returned value) to allow for processing of
+ * discontiguous blocks of data.  When generating the CRC the
+ * caller is responsible for complementing the final return value
+ * and inserting it into the byte stream.  When validating a byte
+ * stream (including CRC8), a final return value of %CRC8_GOOD_VALUE
+ * indicates the byte stream data can be considered valid.
+ *
+ * Reference:
+ * "A Painless Guide to CRC Error Detection Algorithms", ver 3, Aug 1993
+ * Williams, Ross N., ross<at>ross.net
+ * (see URL http://www.ross.net/crc/download/crc_v3.txt).
+ */
+u8 crc8(const u8 table[CRC8_TABLE_SIZE], u8 *pdata, size_t nbytes, u8 crc);
+
+#endif /* __CRC8_H_ */
index d638e85..710c043 100644 (file)
@@ -236,6 +236,7 @@ enum dccp_packet_dequeueing_policy {
 #ifdef __KERNEL__
 
 #include <linux/in.h>
+#include <linux/interrupt.h>
 #include <linux/ktime.h>
 #include <linux/list.h>
 #include <linux/uio.h>
index 5619f85..bbd8661 100644 (file)
@@ -9,8 +9,12 @@
 #define VTD_PAGE_MASK          (((u64)-1) << VTD_PAGE_SHIFT)
 #define VTD_PAGE_ALIGN(addr)   (((addr) + VTD_PAGE_SIZE - 1) & VTD_PAGE_MASK)
 
+#define VTD_STRIDE_SHIFT        (9)
+#define VTD_STRIDE_MASK         (((u64)-1) << VTD_STRIDE_SHIFT)
+
 #define DMA_PTE_READ (1)
 #define DMA_PTE_WRITE (2)
+#define DMA_PTE_LARGE_PAGE (1 << 7)
 #define DMA_PTE_SNP (1 << 11)
 
 #define CONTEXT_TT_MULTI_LEVEL 0
index c6a850a..dfd3493 100644 (file)
@@ -287,7 +287,7 @@ enum ethtool_stringset {
        ETH_SS_TEST             = 0,
        ETH_SS_STATS,
        ETH_SS_PRIV_FLAGS,
-       ETH_SS_NTUPLE_FILTERS,
+       ETH_SS_NTUPLE_FILTERS,  /* Do not use, GRXNTUPLE is now deprecated */
        ETH_SS_FEATURES,
 };
 
@@ -714,18 +714,6 @@ enum ethtool_sfeatures_retval_bits {
 /* needed by dev_disable_lro() */
 extern int __ethtool_set_flags(struct net_device *dev, u32 flags);
 
-struct ethtool_rx_ntuple_flow_spec_container {
-       struct ethtool_rx_ntuple_flow_spec fs;
-       struct list_head list;
-};
-
-struct ethtool_rx_ntuple_list {
-#define ETHTOOL_MAX_NTUPLE_LIST_ENTRY 1024
-#define ETHTOOL_MAX_NTUPLE_STRING_PER_ENTRY 14
-       struct list_head        list;
-       unsigned int            count;
-};
-
 /**
  * enum ethtool_phys_id_state - indicator state for physical identification
  * @ETHTOOL_ID_INACTIVE: Physical ID indicator should be deactivated
@@ -758,7 +746,6 @@ u32 ethtool_op_get_ufo(struct net_device *dev);
 int ethtool_op_set_ufo(struct net_device *dev, u32 data);
 u32 ethtool_op_get_flags(struct net_device *dev);
 int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported);
-void ethtool_ntuple_flush(struct net_device *dev);
 bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported);
 
 /**
@@ -865,7 +852,6 @@ bool ethtool_invalid_flags(struct net_device *dev, u32 data, u32 supported);
  *     error code or zero.
  * @set_rx_ntuple: Set an RX n-tuple rule.  Returns a negative error code
  *     or zero.
- * @get_rx_ntuple: Deprecated.
  * @get_rxfh_indir: Get the contents of the RX flow hash indirection table.
  *     Returns a negative error code or zero.
  * @set_rxfh_indir: Set the contents of the RX flow hash indirection table.
@@ -944,7 +930,6 @@ struct ethtool_ops {
        int     (*reset)(struct net_device *, u32 *);
        int     (*set_rx_ntuple)(struct net_device *,
                                 struct ethtool_rx_ntuple *);
-       int     (*get_rx_ntuple)(struct net_device *, u32 stringset, void *);
        int     (*get_rxfh_indir)(struct net_device *,
                                  struct ethtool_rxfh_indir *);
        int     (*set_rxfh_indir)(struct net_device *,
@@ -1017,7 +1002,7 @@ struct ethtool_ops {
 #define ETHTOOL_FLASHDEV       0x00000033 /* Flash firmware to device */
 #define ETHTOOL_RESET          0x00000034 /* Reset hardware */
 #define ETHTOOL_SRXNTUPLE      0x00000035 /* Add an n-tuple filter to device */
-#define ETHTOOL_GRXNTUPLE      0x00000036 /* Get n-tuple filters from device */
+#define ETHTOOL_GRXNTUPLE      0x00000036 /* deprecated */
 #define ETHTOOL_GSSET_INFO     0x00000037 /* Get string set info */
 #define ETHTOOL_GRXFHINDIR     0x00000038 /* Get RX flow hash indir'n table */
 #define ETHTOOL_SRXFHINDIR     0x00000039 /* Set RX flow hash indir'n table */
index b78956b..300d758 100644 (file)
@@ -100,6 +100,7 @@ struct hd_struct {
        sector_t start_sect;
        sector_t nr_sects;
        sector_t alignment_offset;
+       unsigned int discard_alignment;
        struct device __dev;
        struct kobject *holder_dir;
        int policy, partno;
index b2eee58..bf56b6f 100644 (file)
@@ -1003,8 +1003,12 @@ struct ieee80211_ht_info {
 #define WLAN_CAPABILITY_ESS            (1<<0)
 #define WLAN_CAPABILITY_IBSS           (1<<1)
 
-/* A mesh STA sets the ESS and IBSS capability bits to zero */
-#define WLAN_CAPABILITY_IS_MBSS(cap)   \
+/*
+ * A mesh STA sets the ESS and IBSS capability bits to zero.
+ * however, this holds true for p2p probe responses (in the p2p_find
+ * phase) as well.
+ */
+#define WLAN_CAPABILITY_IS_STA_BSS(cap)        \
        (!((cap) & (WLAN_CAPABILITY_ESS | WLAN_CAPABILITY_IBSS)))
 
 #define WLAN_CAPABILITY_CF_POLLABLE    (1<<2)
index 72bfa5a..6d66ce1 100644 (file)
@@ -70,6 +70,7 @@ struct tpacket_auxdata {
 #define TP_STATUS_COPY         0x2
 #define TP_STATUS_LOSING       0x4
 #define TP_STATUS_CSUMNOTREADY 0x8
+#define TP_STATUS_VLAN_VALID   0x10 /* auxdata has valid tp_vlan_tci */
 
 /* Tx ring - header status */
 #define TP_STATUS_AVAILABLE    0x0
index d40bfa1..e5f21d2 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/mtd/partitions.h>
 
 struct map_info;
+struct platform_device;
 
 struct physmap_flash_data {
        unsigned int            width;
index ca333e7..6469fa9 100644 (file)
@@ -1348,9 +1348,6 @@ struct net_device {
        /* max exchange id for FCoE LRO by ddp */
        unsigned int            fcoe_ddp_xid;
 #endif
-       /* n-tuple filter list attached to this device */
-       struct ethtool_rx_ntuple_list ethtool_ntuple_list;
-
        /* phy device may attach itself for hardware timestamping */
        struct phy_device *phydev;
 
@@ -1563,7 +1560,6 @@ struct packet_type {
        struct list_head        list;
 };
 
-#include <linux/interrupt.h>
 #include <linux/notifier.h>
 
 extern rwlock_t                                dev_base_lock;          /* Device list lock */
index e64f4c6..531ede8 100644 (file)
@@ -282,6 +282,7 @@ struct tcp_request_sock {
 #endif
        u32                             rcv_isn;
        u32                             snt_isn;
+       u32                             snt_synack; /* synack sent time */
 };
 
 static inline struct tcp_request_sock *tcp_rsk(const struct request_sock *req)
index 5b07792..ff7dc08 100644 (file)
@@ -76,7 +76,7 @@
  *     tty device.  It is solely the responsibility of the line
  *     discipline to handle poll requests.
  *
- * unsigned int (*receive_buf)(struct tty_struct *, const unsigned char *cp,
+ * void        (*receive_buf)(struct tty_struct *, const unsigned char *cp,
  *                    char *fp, int count);
  *
  *     This function is called by the low-level tty driver to send
@@ -84,8 +84,7 @@
  *     processing.  <cp> is a pointer to the buffer of input
  *     character received by the device.  <fp> is a pointer to a
  *     pointer of flag bytes which indicate whether a character was
- *     received with a parity error, etc. Returns the amount of bytes
- *     received.
+ *     received with a parity error, etc.
  * 
  * void        (*write_wakeup)(struct tty_struct *);
  *
@@ -141,8 +140,8 @@ struct tty_ldisc_ops {
        /*
         * The following routines are called from below.
         */
-       unsigned int (*receive_buf)(struct tty_struct *,
-                       const unsigned char *cp, char *fp, int count);
+       void    (*receive_buf)(struct tty_struct *, const unsigned char *cp,
+                              char *fp, int count);
        void    (*write_wakeup)(struct tty_struct *);
        void    (*dcd_change)(struct tty_struct *, unsigned int,
                                struct pps_event_time *);
index aff5b4f..7108857 100644 (file)
@@ -51,6 +51,13 @@ struct virtqueue {
  *     This re-enables callbacks; it returns "false" if there are pending
  *     buffers in the queue, to detect a possible race between the driver
  *     checking for more work, and enabling callbacks.
+ * virtqueue_enable_cb_delayed: restart callbacks after disable_cb.
+ *     vq: the struct virtqueue we're talking about.
+ *     This re-enables callbacks but hints to the other side to delay
+ *     interrupts until most of the available buffers have been processed;
+ *     it returns "false" if there are many pending buffers in the queue,
+ *     to detect a possible race between the driver checking for more work,
+ *     and enabling callbacks.
  * virtqueue_detach_unused_buf: detach first unused buffer
  *     vq: the struct virtqueue we're talking about.
  *     Returns NULL or the "data" token handed to add_buf
@@ -86,6 +93,8 @@ void virtqueue_disable_cb(struct virtqueue *vq);
 
 bool virtqueue_enable_cb(struct virtqueue *vq);
 
+bool virtqueue_enable_cb_delayed(struct virtqueue *vq);
+
 void *virtqueue_detach_unused_buf(struct virtqueue *vq);
 
 /**
index e68b439..277c4ad 100644 (file)
@@ -1,7 +1,30 @@
 #ifndef _LINUX_VIRTIO_9P_H
 #define _LINUX_VIRTIO_9P_H
 /* This header is BSD licensed so anyone can use the definitions to implement
- * compatible drivers/servers. */
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM 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/types.h>
 #include <linux/virtio_ids.h>
 #include <linux/virtio_config.h>
index a50ecd1..652dc8b 100644 (file)
@@ -1,7 +1,30 @@
 #ifndef _LINUX_VIRTIO_BALLOON_H
 #define _LINUX_VIRTIO_BALLOON_H
 /* This header is BSD licensed so anyone can use the definitions to implement
- * compatible drivers/servers. */
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM 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/virtio_ids.h>
 #include <linux/virtio_config.h>
 
index 167720d..e0edb40 100644 (file)
@@ -1,7 +1,30 @@
 #ifndef _LINUX_VIRTIO_BLK_H
 #define _LINUX_VIRTIO_BLK_H
 /* This header is BSD licensed so anyone can use the definitions to implement
- * compatible drivers/servers. */
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM 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/types.h>
 #include <linux/virtio_ids.h>
 #include <linux/virtio_config.h>
index 800617b..39c88c5 100644 (file)
@@ -1,7 +1,30 @@
 #ifndef _LINUX_VIRTIO_CONFIG_H
 #define _LINUX_VIRTIO_CONFIG_H
 /* This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
- * anyone can use the definitions to implement compatible drivers/servers. */
+ * anyone can use the definitions to implement compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM 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. */
 
 /* Virtio devices use a standardized configuration space to define their
  * features and pass configuration information, but each implementation can
index e4d3335..bdf4b00 100644 (file)
@@ -5,7 +5,31 @@
 #include <linux/virtio_config.h>
 /*
  * This header, excluding the #ifdef __KERNEL__ part, is BSD licensed so
- * anyone can use the definitions to implement compatible drivers/servers.
+ * anyone can use the definitions to implement compatible drivers/servers:
+ *
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM 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.
  *
  * Copyright (C) Red Hat, Inc., 2009, 2010, 2011
  * Copyright (C) Amit Shah <amit.shah@redhat.com>, 2009, 2010, 2011
index 06660c0..85bb0bb 100644 (file)
@@ -5,7 +5,29 @@
  *
  * This header is BSD licensed so anyone can use the definitions to implement
  * compatible drivers/servers.
- */
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM 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. */
 
 #define VIRTIO_ID_NET          1 /* virtio net */
 #define VIRTIO_ID_BLOCK                2 /* virtio block */
index 085e422..136040b 100644 (file)
@@ -1,7 +1,30 @@
 #ifndef _LINUX_VIRTIO_NET_H
 #define _LINUX_VIRTIO_NET_H
 /* This header is BSD licensed so anyone can use the definitions to implement
- * compatible drivers/servers. */
+ * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM 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/types.h>
 #include <linux/virtio_ids.h>
 #include <linux/virtio_config.h>
index 9a3d7c4..ea66f3f 100644 (file)
  *
  * This header is BSD licensed so anyone can use the definitions to implement
  * compatible drivers/servers.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM OR CONTRIBUTORS BE LIABLE
+ * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+ * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+ * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+ * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+ * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
  */
 
 #ifndef _LINUX_VIRTIO_PCI_H
index e4d144b..4a32cb6 100644 (file)
@@ -7,6 +7,29 @@
  * This header is BSD licensed so anyone can use the definitions to implement
  * compatible drivers/servers.
  *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. Neither the name of IBM nor the names of its contributors
+ *    may be used to endorse or promote products derived from this software
+ *    without specific prior written permission.
+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+ * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ * ARE DISCLAIMED.  IN NO EVENT SHALL IBM 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.
+ *
  * Copyright Rusty Russell IBM Corporation 2007. */
 #include <linux/types.h>
 
 /* We support indirect buffer descriptors */
 #define VIRTIO_RING_F_INDIRECT_DESC    28
 
+/* The Guest publishes the used index for which it expects an interrupt
+ * at the end of the avail ring. Host should ignore the avail->flags field. */
+/* The Host publishes the avail index for which it expects a kick
+ * at the end of the used ring. Guest should ignore the used->flags field. */
+#define VIRTIO_RING_F_EVENT_IDX                29
+
 /* Virtio ring descriptors: 16 bytes.  These can chain together via "next". */
 struct vring_desc {
        /* Address (guest-physical). */
@@ -83,6 +112,7 @@ struct vring {
  *     __u16 avail_flags;
  *     __u16 avail_idx;
  *     __u16 available[num];
+ *     __u16 used_event_idx;
  *
  *     // Padding to the next align boundary.
  *     char pad[];
@@ -91,8 +121,14 @@ struct vring {
  *     __u16 used_flags;
  *     __u16 used_idx;
  *     struct vring_used_elem used[num];
+ *     __u16 avail_event_idx;
  * };
  */
+/* We publish the used event index at the end of the available ring, and vice
+ * versa. They are at the end for backwards compatibility. */
+#define vring_used_event(vr) ((vr)->avail->ring[(vr)->num])
+#define vring_avail_event(vr) (*(__u16 *)&(vr)->used->ring[(vr)->num])
+
 static inline void vring_init(struct vring *vr, unsigned int num, void *p,
                              unsigned long align)
 {
@@ -107,7 +143,21 @@ static inline unsigned vring_size(unsigned int num, unsigned long align)
 {
        return ((sizeof(struct vring_desc) * num + sizeof(__u16) * (2 + num)
                 + align - 1) & ~(align - 1))
-               + sizeof(__u16) * 2 + sizeof(struct vring_used_elem) * num;
+               + sizeof(__u16) * 3 + sizeof(struct vring_used_elem) * num;
+}
+
+/* The following is used with USED_EVENT_IDX and AVAIL_EVENT_IDX */
+/* Assuming a given event_idx value from the other size, if
+ * we have just incremented index from old to new_idx,
+ * should we trigger an event? */
+static inline int vring_need_event(__u16 event_idx, __u16 new_idx, __u16 old)
+{
+       /* Note: Xen has similar logic for notification hold-off
+        * in include/xen/interface/io/ring.h with req_event and req_prod
+        * corresponding to event_idx + 1 and new_idx respectively.
+        * Note also that req_event and req_prod in Xen start at 1,
+        * event indexes in virtio start at 0. */
+       return (__u16)(new_idx - event_idx - 1) < (__u16)(new_idx - old);
 }
 
 #ifdef __KERNEL__
index 6c994c0..7851c05 100644 (file)
@@ -25,6 +25,7 @@
 #ifndef __HCI_CORE_H
 #define __HCI_CORE_H
 
+#include <linux/interrupt.h>
 #include <net/bluetooth/hci.h>
 
 /* HCI upper protocols */
diff --git a/include/net/caif/caif_hsi.h b/include/net/caif/caif_hsi.h
new file mode 100644 (file)
index 0000000..c5dedd8
--- /dev/null
@@ -0,0 +1,145 @@
+/*
+ * Copyright (C) ST-Ericsson AB 2010
+ * Contact: Sjur Brendeland / sjur.brandeland@stericsson.com
+ * Author:  Daniel Martensson / daniel.martensson@stericsson.com
+ *         Dmitry.Tarnyagin  / dmitry.tarnyagin@stericsson.com
+ * License terms: GNU General Public License (GPL) version 2
+ */
+
+#ifndef CAIF_HSI_H_
+#define CAIF_HSI_H_
+
+#include <net/caif/caif_layer.h>
+#include <net/caif/caif_device.h>
+#include <linux/atomic.h>
+
+/*
+ * Maximum number of CAIF frames that can reside in the same HSI frame.
+ */
+#define CFHSI_MAX_PKTS 15
+
+/*
+ * Maximum number of bytes used for the frame that can be embedded in the
+ * HSI descriptor.
+ */
+#define CFHSI_MAX_EMB_FRM_SZ 96
+
+/*
+ * Decides if HSI buffers should be prefilled with 0xFF pattern for easier
+ * debugging. Both TX and RX buffers will be filled before the transfer.
+ */
+#define CFHSI_DBG_PREFILL              0
+
+/* Structure describing a HSI packet descriptor. */
+#pragma pack(1) /* Byte alignment. */
+struct cfhsi_desc {
+       u8 header;
+       u8 offset;
+       u16 cffrm_len[CFHSI_MAX_PKTS];
+       u8 emb_frm[CFHSI_MAX_EMB_FRM_SZ];
+};
+#pragma pack() /* Default alignment. */
+
+/* Size of the complete HSI packet descriptor. */
+#define CFHSI_DESC_SZ (sizeof(struct cfhsi_desc))
+
+/*
+ * Size of the complete HSI packet descriptor excluding the optional embedded
+ * CAIF frame.
+ */
+#define CFHSI_DESC_SHORT_SZ (CFHSI_DESC_SZ - CFHSI_MAX_EMB_FRM_SZ)
+
+/*
+ * Maximum bytes transferred in one transfer.
+ */
+/* TODO: 4096 is temporary... */
+#define CFHSI_MAX_PAYLOAD_SZ (CFHSI_MAX_PKTS * 4096)
+
+/* Size of the complete HSI TX buffer. */
+#define CFHSI_BUF_SZ_TX (CFHSI_DESC_SZ + CFHSI_MAX_PAYLOAD_SZ)
+
+/* Size of the complete HSI RX buffer. */
+#define CFHSI_BUF_SZ_RX ((2 * CFHSI_DESC_SZ) + CFHSI_MAX_PAYLOAD_SZ)
+
+/* Bitmasks for the HSI descriptor. */
+#define CFHSI_PIGGY_DESC               (0x01 << 7)
+
+#define CFHSI_TX_STATE_IDLE                    0
+#define CFHSI_TX_STATE_XFER                    1
+
+#define CFHSI_RX_STATE_DESC                    0
+#define CFHSI_RX_STATE_PAYLOAD                 1
+
+/* Bitmasks for power management. */
+#define CFHSI_WAKE_UP                          0
+#define CFHSI_WAKE_UP_ACK                      1
+#define CFHSI_WAKE_DOWN_ACK                    2
+#define CFHSI_AWAKE                            3
+#define CFHSI_PENDING_RX                       4
+#define CFHSI_SHUTDOWN                         6
+#define CFHSI_FLUSH_FIFO                       7
+
+#ifndef CFHSI_INACTIVITY_TOUT
+#define CFHSI_INACTIVITY_TOUT                  (1 * HZ)
+#endif /* CFHSI_INACTIVITY_TOUT */
+
+#ifndef CFHSI_WAKEUP_TOUT
+#define CFHSI_WAKEUP_TOUT                      (3 * HZ)
+#endif /* CFHSI_WAKEUP_TOUT */
+
+
+/* Structure implemented by the CAIF HSI driver. */
+struct cfhsi_drv {
+       void (*tx_done_cb) (struct cfhsi_drv *drv);
+       void (*rx_done_cb) (struct cfhsi_drv *drv);
+       void (*wake_up_cb) (struct cfhsi_drv *drv);
+       void (*wake_down_cb) (struct cfhsi_drv *drv);
+};
+
+/* Structure implemented by HSI device. */
+struct cfhsi_dev {
+       int (*cfhsi_up) (struct cfhsi_dev *dev);
+       int (*cfhsi_down) (struct cfhsi_dev *dev);
+       int (*cfhsi_tx) (u8 *ptr, int len, struct cfhsi_dev *dev);
+       int (*cfhsi_rx) (u8 *ptr, int len, struct cfhsi_dev *dev);
+       int (*cfhsi_wake_up) (struct cfhsi_dev *dev);
+       int (*cfhsi_wake_down) (struct cfhsi_dev *dev);
+       int (*cfhsi_fifo_occupancy)(struct cfhsi_dev *dev, size_t *occupancy);
+       int (*cfhsi_rx_cancel)(struct cfhsi_dev *dev);
+       struct cfhsi_drv *drv;
+};
+
+/* Structure implemented by CAIF HSI drivers. */
+struct cfhsi {
+       struct caif_dev_common cfdev;
+       struct net_device *ndev;
+       struct platform_device *pdev;
+       struct sk_buff_head qhead;
+       struct cfhsi_drv drv;
+       struct cfhsi_dev *dev;
+       int tx_state;
+       int rx_state;
+       int rx_len;
+       u8 *rx_ptr;
+       u8 *tx_buf;
+       u8 *rx_buf;
+       spinlock_t lock;
+       int flow_off_sent;
+       u32 q_low_mark;
+       u32 q_high_mark;
+       struct list_head list;
+       struct work_struct wake_up_work;
+       struct work_struct wake_down_work;
+       struct work_struct rx_done_work;
+       struct work_struct tx_done_work;
+       struct workqueue_struct *wq;
+       wait_queue_head_t wake_up_wait;
+       wait_queue_head_t wake_down_wait;
+       wait_queue_head_t flush_fifo_wait;
+       struct timer_list timer;
+       unsigned long bits;
+};
+
+extern struct platform_driver cfhsi_driver;
+
+#endif         /* CAIF_HSI_H_ */
index 0589f55..6cb2543 100644 (file)
@@ -1284,6 +1284,12 @@ struct cfg80211_wowlan {
  *     frame on another channel
  *
  * @testmode_cmd: run a test mode command
+ * @testmode_dump: Implement a test mode dump. The cb->args[2] and up may be
+ *     used by the function, but 0 and 1 must not be touched. Additionally,
+ *     return error codes other than -ENOBUFS and -ENOENT will terminate the
+ *     dump and return to userspace with an error, so be careful. If any data
+ *     was passed in from userspace then the data/len arguments will be present
+ *     and point to the data contained in %NL80211_ATTR_TESTDATA.
  *
  * @set_bitrate_mask: set the bitrate mask configuration
  *
@@ -1433,6 +1439,9 @@ struct cfg80211_ops {
 
 #ifdef CONFIG_NL80211_TESTMODE
        int     (*testmode_cmd)(struct wiphy *wiphy, void *data, int len);
+       int     (*testmode_dump)(struct wiphy *wiphy, struct sk_buff *skb,
+                                struct netlink_callback *cb,
+                                void *data, int len);
 #endif
 
        int     (*set_bitrate_mask)(struct wiphy *wiphy,
@@ -2849,8 +2858,10 @@ struct sk_buff *cfg80211_testmode_alloc_event_skb(struct wiphy *wiphy,
 void cfg80211_testmode_event(struct sk_buff *skb, gfp_t gfp);
 
 #define CFG80211_TESTMODE_CMD(cmd)     .testmode_cmd = (cmd),
+#define CFG80211_TESTMODE_DUMP(cmd)    .testmode_dump = (cmd),
 #else
 #define CFG80211_TESTMODE_CMD(cmd)
+#define CFG80211_TESTMODE_DUMP(cmd)
 #endif
 
 /**
index 8a159cc..39d1230 100644 (file)
@@ -32,13 +32,17 @@ struct inet_peer {
        struct inet_peer __rcu  *avl_left, *avl_right;
        struct inetpeer_addr    daddr;
        __u32                   avl_height;
-       struct list_head        unused;
-       __u32                   dtime;          /* the time of last use of not
-                                                * referenced entries */
-       atomic_t                refcnt;
+
+       u32                     metrics[RTAX_MAX];
+       u32                     rate_tokens;    /* rate limiting for ICMP */
+       unsigned long           rate_last;
+       unsigned long           pmtu_expires;
+       u32                     pmtu_orig;
+       u32                     pmtu_learned;
+       struct inetpeer_addr_base redirect_learned;
        /*
         * Once inet_peer is queued for deletion (refcnt == -1), following fields
-        * are not available: rid, ip_id_count, tcp_ts, tcp_ts_stamp, metrics
+        * are not available: rid, ip_id_count, tcp_ts, tcp_ts_stamp
         * We can share memory with rcu_head to help keep inet_peer small.
         */
        union {
@@ -47,16 +51,14 @@ struct inet_peer {
                        atomic_t                        ip_id_count;    /* IP ID for the next packet */
                        __u32                           tcp_ts;
                        __u32                           tcp_ts_stamp;
-                       u32                             metrics[RTAX_MAX];
-                       u32                             rate_tokens;    /* rate limiting for ICMP */
-                       unsigned long                   rate_last;
-                       unsigned long                   pmtu_expires;
-                       u32                             pmtu_orig;
-                       u32                             pmtu_learned;
-                       struct inetpeer_addr_base       redirect_learned;
                };
                struct rcu_head         rcu;
+               struct inet_peer        *gc_next;
        };
+
+       /* following fields might be frequently dirtied */
+       __u32                   dtime;  /* the time of last use of not referenced entries */
+       atomic_t                refcnt;
 };
 
 void                   inet_initpeers(void) __init;
index 66dd491..e9ea7c7 100644 (file)
@@ -228,8 +228,6 @@ extern struct ctl_path net_ipv4_ctl_path[];
 extern int inet_peer_threshold;
 extern int inet_peer_minttl;
 extern int inet_peer_maxttl;
-extern int inet_peer_gc_mintime;
-extern int inet_peer_gc_maxtime;
 
 /* From ip_output.c */
 extern int sysctl_ip_dynaddr;
index e6d6a66..3b31ec9 100644 (file)
@@ -1816,6 +1816,7 @@ enum ieee80211_ampdu_mlme_action {
  *
  * @testmode_cmd: Implement a cfg80211 test mode command.
  *     The callback can sleep.
+ * @testmode_dump: Implement a cfg80211 test mode dump. The callback can sleep.
  *
  * @flush: Flush all pending frames from the hardware queue, making sure
  *     that the hardware queues are empty. If the parameter @drop is set
@@ -1936,6 +1937,9 @@ struct ieee80211_ops {
        void (*set_coverage_class)(struct ieee80211_hw *hw, u8 coverage_class);
 #ifdef CONFIG_NL80211_TESTMODE
        int (*testmode_cmd)(struct ieee80211_hw *hw, void *data, int len);
+       int (*testmode_dump)(struct ieee80211_hw *hw, struct sk_buff *skb,
+                            struct netlink_callback *cb,
+                            void *data, int len);
 #endif
        void (*flush)(struct ieee80211_hw *hw, bool drop);
        void (*channel_switch)(struct ieee80211_hw *hw,
@@ -2965,6 +2969,23 @@ void ieee80211_ready_on_channel(struct ieee80211_hw *hw);
  */
 void ieee80211_remain_on_channel_expired(struct ieee80211_hw *hw);
 
+/**
+ * ieee80211_stop_rx_ba_session - callback to stop existing BA sessions
+ *
+ * in order not to harm the system performance and user experience, the device
+ * may request not to allow any rx ba session and tear down existing rx ba
+ * sessions based on system constraints such as periodic BT activity that needs
+ * to limit wlan activity (eg.sco or a2dp)."
+ * in such cases, the intention is to limit the duration of the rx ppdu and
+ * therefore prevent the peer device to use a-mpdu aggregation.
+ *
+ * @vif: &struct ieee80211_vif pointer from the add_interface callback.
+ * @ba_rx_bitmap: Bit map of open rx ba per tid
+ * @addr: & to bssid mac address
+ */
+void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
+                                 const u8 *addr);
+
 /* Rate control API */
 
 /**
index 2b44764..dd6847e 100644 (file)
@@ -107,6 +107,7 @@ typedef enum {
        SCTP_CMD_UPDATE_INITTAG, /* Update peer inittag */
        SCTP_CMD_SEND_MSG,       /* Send the whole use message */
        SCTP_CMD_SEND_NEXT_ASCONF, /* Send the next ASCONF after ACK */
+       SCTP_CMD_PURGE_ASCONF_QUEUE, /* Purge all asconf queues.*/
        SCTP_CMD_LAST
 } sctp_verb_t;
 
index b2c2366..6a72a58 100644 (file)
@@ -120,6 +120,7 @@ extern int sctp_copy_local_addr_list(struct sctp_bind_addr *,
                                     int flags);
 extern struct sctp_pf *sctp_get_pf_specific(sa_family_t family);
 extern int sctp_register_pf(struct sctp_pf *, sa_family_t);
+extern void sctp_addr_wq_mgmt(struct sctp_sockaddr_entry *, int);
 
 /*
  * sctp/socket.c
@@ -134,6 +135,7 @@ void sctp_sock_rfree(struct sk_buff *skb);
 void sctp_copy_sock(struct sock *newsk, struct sock *sk,
                    struct sctp_association *asoc);
 extern struct percpu_counter sctp_sockets_allocated;
+extern int sctp_asconf_mgmt(struct sctp_sock *, struct sctp_sockaddr_entry *);
 
 /*
  * sctp/primitive.c
@@ -285,20 +287,21 @@ do {                                                      \
                pr_cont(fmt, ##args);                   \
 } while (0)
 #define SCTP_DEBUG_PRINTK_IPADDR(fmt_lead, fmt_trail,                  \
-                                args_lead, saddr, args_trail...)       \
+                                args_lead, addr, args_trail...)        \
 do {                                                                   \
+       const union sctp_addr *_addr = (addr);                          \
        if (sctp_debug_flag) {                                          \
-               if (saddr->sa.sa_family == AF_INET6) {                  \
+               if (_addr->sa.sa_family == AF_INET6) {                  \
                        printk(KERN_DEBUG                               \
                               pr_fmt(fmt_lead "%pI6" fmt_trail),       \
                               args_lead,                               \
-                              &saddr->v6.sin6_addr,                    \
+                              &_addr->v6.sin6_addr,                    \
                               args_trail);                             \
                } else {                                                \
                        printk(KERN_DEBUG                               \
                               pr_fmt(fmt_lead "%pI4" fmt_trail),       \
                               args_lead,                               \
-                              &saddr->v4.sin_addr.s_addr,              \
+                              &_addr->v4.sin_addr.s_addr,              \
                               args_trail);                             \
                }                                                       \
        }                                                               \
@@ -598,7 +601,7 @@ static inline int ipver2af(__u8 ipver)
                return AF_INET6;
        default:
                return 0;
-       };
+       }
 }
 
 /* Convert from an address parameter type to an address family.  */
@@ -611,7 +614,7 @@ static inline int param_type2af(__be16 type)
                return AF_INET6;
        default:
                return 0;
-       };
+       }
 }
 
 /* Perform some sanity checks. */
index 795f488..31d7ea2 100644 (file)
@@ -205,6 +205,11 @@ extern struct sctp_globals {
         * It is a list of sctp_sockaddr_entry.
         */
        struct list_head local_addr_list;
+       int default_auto_asconf;
+       struct list_head addr_waitq;
+       struct timer_list addr_wq_timer;
+       struct list_head auto_asconf_splist;
+       spinlock_t addr_wq_lock;
 
        /* Lock that protects the local_addr_list writers */
        spinlock_t addr_list_lock;
@@ -264,6 +269,11 @@ extern struct sctp_globals {
 #define sctp_port_hashtable            (sctp_globals.port_hashtable)
 #define sctp_local_addr_list           (sctp_globals.local_addr_list)
 #define sctp_local_addr_lock           (sctp_globals.addr_list_lock)
+#define sctp_auto_asconf_splist                (sctp_globals.auto_asconf_splist)
+#define sctp_addr_waitq                        (sctp_globals.addr_waitq)
+#define sctp_addr_wq_timer             (sctp_globals.addr_wq_timer)
+#define sctp_addr_wq_lock              (sctp_globals.addr_wq_lock)
+#define sctp_default_auto_asconf       (sctp_globals.default_auto_asconf)
 #define sctp_scope_policy              (sctp_globals.ipv4_scope_policy)
 #define sctp_addip_enable              (sctp_globals.addip_enable)
 #define sctp_addip_noauth              (sctp_globals.addip_noauth_enable)
@@ -341,6 +351,8 @@ struct sctp_sock {
        atomic_t pd_mode;
        /* Receive to here while partial delivery is in effect. */
        struct sk_buff_head pd_lobby;
+       struct list_head auto_asconf_list;
+       int do_auto_asconf;
 };
 
 static inline struct sctp_sock *sctp_sk(const struct sock *sk)
@@ -792,6 +804,8 @@ struct sctp_sockaddr_entry {
        __u8 valid;
 };
 
+#define SCTP_ADDRESS_TICK_DELAY        500
+
 typedef struct sctp_chunk *(sctp_packet_phandler_t)(struct sctp_association *);
 
 /* This structure holds lists of chunks as we are assembling for
@@ -1236,6 +1250,7 @@ sctp_scope_t sctp_scope(const union sctp_addr *);
 int sctp_in_scope(const union sctp_addr *addr, const sctp_scope_t scope);
 int sctp_is_any(struct sock *sk, const union sctp_addr *addr);
 int sctp_addr_is_valid(const union sctp_addr *addr);
+int sctp_is_ep_boundall(struct sock *sk);
 
 
 /* What type of endpoint?  */
@@ -1898,6 +1913,8 @@ struct sctp_association {
         * after reaching 4294967295.
         */
        __u32 addip_serial;
+       union sctp_addr *asconf_addr_del_pending;
+       int src_out_of_asoc_ok;
 
        /* SCTP AUTH: list of the endpoint shared keys.  These
         * keys are provided out of band by the user applicaton
@@ -1993,7 +2010,7 @@ void sctp_assoc_clean_asconf_ack_cache(const struct sctp_association *asoc);
 struct sctp_chunk *sctp_assoc_lookup_asconf_ack(
                                        const struct sctp_association *asoc,
                                        __be32 serial);
-
+void sctp_asconf_queue_teardown(struct sctp_association *asoc);
 
 int sctp_cmp_addr_exact(const union sctp_addr *ss1,
                        const union sctp_addr *ss2);
index 32fd512..0842ef0 100644 (file)
@@ -92,6 +92,7 @@ typedef __s32 sctp_assoc_t;
 #define SCTP_LOCAL_AUTH_CHUNKS 27      /* Read only */
 #define SCTP_GET_ASSOC_NUMBER  28      /* Read only */
 #define SCTP_GET_ASSOC_ID_LIST 29      /* Read only */
+#define SCTP_AUTO_ASCONF       30
 
 /* Internal Socket Options. Some of the sctp library functions are
  * implemented using these socket options.
index f2046e4..ebbc0ba 100644 (file)
@@ -40,6 +40,7 @@
 #ifndef _SOCK_H
 #define _SOCK_H
 
+#include <linux/hardirq.h>
 #include <linux/kernel.h>
 #include <linux/list.h>
 #include <linux/list_nulls.h>
index cda30ea..149a415 100644 (file)
@@ -122,7 +122,13 @@ extern void tcp_time_wait(struct sock *sk, int state, int timeo);
 #endif
 #define TCP_RTO_MAX    ((unsigned)(120*HZ))
 #define TCP_RTO_MIN    ((unsigned)(HZ/5))
-#define TCP_TIMEOUT_INIT ((unsigned)(3*HZ))    /* RFC 1122 initial RTO value   */
+#define TCP_TIMEOUT_INIT ((unsigned)(1*HZ))    /* RFC2988bis initial RTO value */
+#define TCP_TIMEOUT_FALLBACK ((unsigned)(3*HZ))        /* RFC 1122 initial RTO value, now
+                                                * used as a fallback RTO for the
+                                                * initial data transmission if no
+                                                * valid RTT sample has been acquired,
+                                                * most likely due to retrans in 3WHS.
+                                                */
 
 #define TCP_RESOURCE_PROBE_INTERVAL ((unsigned)(HZ/2U)) /* Maximal interval between probes
                                                         * for local resources.
@@ -295,7 +301,7 @@ static inline void tcp_synq_overflow(struct sock *sk)
 static inline int tcp_synq_no_recent_overflow(const struct sock *sk)
 {
        unsigned long last_overflow = tcp_sk(sk)->rx_opt.ts_recent_stamp;
-       return time_after(jiffies, last_overflow + TCP_TIMEOUT_INIT);
+       return time_after(jiffies, last_overflow + TCP_TIMEOUT_FALLBACK);
 }
 
 extern struct proto tcp_prot;
@@ -508,6 +514,7 @@ extern void tcp_initialize_rcv_mss(struct sock *sk);
 extern int tcp_mtu_to_mss(struct sock *sk, int pmtu);
 extern int tcp_mss_to_mtu(struct sock *sk, int mss);
 extern void tcp_mtup_init(struct sock *sk);
+extern void tcp_valid_rtt_meas(struct sock *sk, u32 seq_rtt);
 
 static inline void tcp_bound_rto(const struct sock *sk)
 {
index 5f247f5..f99645d 100644 (file)
 TRACE_EVENT(net_dev_xmit,
 
        TP_PROTO(struct sk_buff *skb,
-                int rc),
+                int rc,
+                struct net_device *dev,
+                unsigned int skb_len),
 
-       TP_ARGS(skb, rc),
+       TP_ARGS(skb, rc, dev, skb_len),
 
        TP_STRUCT__entry(
                __field(        void *,         skbaddr         )
                __field(        unsigned int,   len             )
                __field(        int,            rc              )
-               __string(       name,           skb->dev->name  )
+               __string(       name,           dev->name       )
        ),
 
        TP_fast_assign(
                __entry->skbaddr = skb;
-               __entry->len = skb->len;
+               __entry->len = skb_len;
                __entry->rc = rc;
-               __assign_str(name, skb->dev->name);
+               __assign_str(name, dev->name);
        ),
 
        TP_printk("dev=%s skbaddr=%p len=%u rc=%d",
index 77a7671..89419ff 100644 (file)
@@ -1648,7 +1648,6 @@ static int __cpuinit rcu_spawn_one_cpu_kthread(int cpu)
        if (IS_ERR(t))
                return PTR_ERR(t);
        kthread_bind(t, cpu);
-       set_task_state(t, TASK_INTERRUPTIBLE);
        per_cpu(rcu_cpu_kthread_cpu, cpu) = cpu;
        WARN_ON_ONCE(per_cpu(rcu_cpu_kthread_task, cpu) != NULL);
        per_cpu(rcu_cpu_kthread_task, cpu) = t;
@@ -1756,7 +1755,6 @@ static int __cpuinit rcu_spawn_one_node_kthread(struct rcu_state *rsp,
                if (IS_ERR(t))
                        return PTR_ERR(t);
                raw_spin_lock_irqsave(&rnp->lock, flags);
-               set_task_state(t, TASK_INTERRUPTIBLE);
                rnp->node_kthread_task = t;
                raw_spin_unlock_irqrestore(&rnp->lock, flags);
                sp.sched_priority = 99;
@@ -1765,6 +1763,8 @@ static int __cpuinit rcu_spawn_one_node_kthread(struct rcu_state *rsp,
        return rcu_spawn_one_boost_kthread(rsp, rnp, rnp_index);
 }
 
+static void rcu_wake_one_boost_kthread(struct rcu_node *rnp);
+
 /*
  * Spawn all kthreads -- called as soon as the scheduler is running.
  */
@@ -1772,18 +1772,30 @@ static int __init rcu_spawn_kthreads(void)
 {
        int cpu;
        struct rcu_node *rnp;
+       struct task_struct *t;
 
        rcu_kthreads_spawnable = 1;
        for_each_possible_cpu(cpu) {
                per_cpu(rcu_cpu_has_work, cpu) = 0;
-               if (cpu_online(cpu))
+               if (cpu_online(cpu)) {
                        (void)rcu_spawn_one_cpu_kthread(cpu);
+                       t = per_cpu(rcu_cpu_kthread_task, cpu);
+                       if (t)
+                               wake_up_process(t);
+               }
        }
        rnp = rcu_get_root(rcu_state);
        (void)rcu_spawn_one_node_kthread(rcu_state, rnp);
+       if (rnp->node_kthread_task)
+               wake_up_process(rnp->node_kthread_task);
        if (NUM_RCU_NODES > 1) {
-               rcu_for_each_leaf_node(rcu_state, rnp)
+               rcu_for_each_leaf_node(rcu_state, rnp) {
                        (void)rcu_spawn_one_node_kthread(rcu_state, rnp);
+                       t = rnp->node_kthread_task;
+                       if (t)
+                               wake_up_process(t);
+                       rcu_wake_one_boost_kthread(rnp);
+               }
        }
        return 0;
 }
@@ -2188,14 +2200,14 @@ rcu_init_percpu_data(int cpu, struct rcu_state *rsp, int preemptible)
        raw_spin_unlock_irqrestore(&rsp->onofflock, flags);
 }
 
-static void __cpuinit rcu_online_cpu(int cpu)
+static void __cpuinit rcu_prepare_cpu(int cpu)
 {
        rcu_init_percpu_data(cpu, &rcu_sched_state, 0);
        rcu_init_percpu_data(cpu, &rcu_bh_state, 0);
        rcu_preempt_init_percpu_data(cpu);
 }
 
-static void __cpuinit rcu_online_kthreads(int cpu)
+static void __cpuinit rcu_prepare_kthreads(int cpu)
 {
        struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, cpu);
        struct rcu_node *rnp = rdp->mynode;
@@ -2208,6 +2220,31 @@ static void __cpuinit rcu_online_kthreads(int cpu)
        }
 }
 
+/*
+ * kthread_create() creates threads in TASK_UNINTERRUPTIBLE state,
+ * but the RCU threads are woken on demand, and if demand is low this
+ * could be a while triggering the hung task watchdog.
+ *
+ * In order to avoid this, poke all tasks once the CPU is fully
+ * up and running.
+ */
+static void __cpuinit rcu_online_kthreads(int cpu)
+{
+       struct rcu_data *rdp = per_cpu_ptr(rcu_state->rda, cpu);
+       struct rcu_node *rnp = rdp->mynode;
+       struct task_struct *t;
+
+       t = per_cpu(rcu_cpu_kthread_task, cpu);
+       if (t)
+               wake_up_process(t);
+
+       t = rnp->node_kthread_task;
+       if (t)
+               wake_up_process(t);
+
+       rcu_wake_one_boost_kthread(rnp);
+}
+
 /*
  * Handle CPU online/offline notification events.
  */
@@ -2221,10 +2258,11 @@ static int __cpuinit rcu_cpu_notify(struct notifier_block *self,
        switch (action) {
        case CPU_UP_PREPARE:
        case CPU_UP_PREPARE_FROZEN:
-               rcu_online_cpu(cpu);
-               rcu_online_kthreads(cpu);
+               rcu_prepare_cpu(cpu);
+               rcu_prepare_kthreads(cpu);
                break;
        case CPU_ONLINE:
+               rcu_online_kthreads(cpu);
        case CPU_DOWN_FAILED:
                rcu_node_kthread_setaffinity(rnp, -1);
                rcu_cpu_kthread_setrt(cpu, 1);
index a767b7d..c8bff30 100644 (file)
@@ -1295,7 +1295,6 @@ static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
        if (IS_ERR(t))
                return PTR_ERR(t);
        raw_spin_lock_irqsave(&rnp->lock, flags);
-       set_task_state(t, TASK_INTERRUPTIBLE);
        rnp->boost_kthread_task = t;
        raw_spin_unlock_irqrestore(&rnp->lock, flags);
        sp.sched_priority = RCU_KTHREAD_PRIO;
@@ -1303,6 +1302,12 @@ static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
        return 0;
 }
 
+static void __cpuinit rcu_wake_one_boost_kthread(struct rcu_node *rnp)
+{
+       if (rnp->boost_kthread_task)
+               wake_up_process(rnp->boost_kthread_task);
+}
+
 #else /* #ifdef CONFIG_RCU_BOOST */
 
 static void rcu_initiate_boost(struct rcu_node *rnp, unsigned long flags)
@@ -1326,6 +1331,10 @@ static int __cpuinit rcu_spawn_one_boost_kthread(struct rcu_state *rsp,
        return 0;
 }
 
+static void __cpuinit rcu_wake_one_boost_kthread(struct rcu_node *rnp)
+{
+}
+
 #endif /* #else #ifdef CONFIG_RCU_BOOST */
 
 #ifndef CONFIG_SMP
index 830181c..32f3e5a 100644 (file)
@@ -79,6 +79,13 @@ config LIBCRC32C
          require M here.  See Castagnoli93.
          Module will be libcrc32c.
 
+config CRC8
+       tristate "CRC8 function"
+       help
+         This option provides CRC8 function. Drivers may select this
+         when they need to do cyclic redundancy check according CRC8
+         algorithm. Module will be called crc8.
+
 config AUDIT_GENERIC
        bool
        depends on AUDIT && !AUDIT_ARCH
@@ -262,4 +269,11 @@ config AVERAGE
 
          If unsure, say N.
 
+config CORDIC
+       tristate "Cordic function"
+       help
+         The option provides arithmetic function using cordic algorithm
+         so its calculations are in fixed point. Modules can select this
+         when they require this function. Module will be called cordic.
+
 endmenu
index 28afa4c..dd373c8 100644 (file)
@@ -697,7 +697,7 @@ config DEBUG_BUGVERBOSE
        bool "Verbose BUG() reporting (adds 70K)" if DEBUG_KERNEL && EXPERT
        depends on BUG
        depends on ARM || AVR32 || M32R || M68K || SPARC32 || SPARC64 || \
-                  FRV || SUPERH || GENERIC_BUG || BLACKFIN || MN10300
+                  FRV || SUPERH || GENERIC_BUG || BLACKFIN || MN10300 || TILE
        default y
        help
          Say Y here to make BUG() panics output the file name and line number
index 6b597fd..892f4e2 100644 (file)
@@ -61,6 +61,7 @@ obj-$(CONFIG_CRC_ITU_T)       += crc-itu-t.o
 obj-$(CONFIG_CRC32)    += crc32.o
 obj-$(CONFIG_CRC7)     += crc7.o
 obj-$(CONFIG_LIBCRC32C)        += libcrc32c.o
+obj-$(CONFIG_CRC8)     += crc8.o
 obj-$(CONFIG_GENERIC_ALLOCATOR) += genalloc.o
 
 obj-$(CONFIG_ZLIB_INFLATE) += zlib_inflate/
@@ -112,6 +113,8 @@ obj-$(CONFIG_AVERAGE) += average.o
 
 obj-$(CONFIG_CPU_RMAP) += cpu_rmap.o
 
+obj-$(CONFIG_CORDIC) += cordic.o
+
 hostprogs-y    := gen_crc32table
 clean-files    := crc32table.h
 
diff --git a/lib/cordic.c b/lib/cordic.c
new file mode 100644 (file)
index 0000000..aa27a88
--- /dev/null
@@ -0,0 +1,101 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * 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/module.h>
+#include <linux/cordic.h>
+
+#define CORDIC_ANGLE_GEN       39797
+#define CORDIC_PRECISION_SHIFT 16
+#define        CORDIC_NUM_ITER         (CORDIC_PRECISION_SHIFT + 2)
+
+#define        FIXED(X)        ((s32)((X) << CORDIC_PRECISION_SHIFT))
+#define        FLOAT(X)        (((X) >= 0) \
+               ? ((((X) >> (CORDIC_PRECISION_SHIFT - 1)) + 1) >> 1) \
+               : -((((-(X)) >> (CORDIC_PRECISION_SHIFT - 1)) + 1) >> 1))
+
+static const s32 arctan_table[] = {
+       2949120,
+       1740967,
+       919879,
+       466945,
+       234379,
+       117304,
+       58666,
+       29335,
+       14668,
+       7334,
+       3667,
+       1833,
+       917,
+       458,
+       229,
+       115,
+       57,
+       29
+};
+
+/*
+ * cordic_calc_iq() - calculates the i/q coordinate for given angle
+ *
+ * theta: angle in degrees for which i/q coordinate is to be calculated
+ * coord: function output parameter holding the i/q coordinate
+ */
+struct cordic_iq cordic_calc_iq(s32 theta)
+{
+       struct cordic_iq coord;
+       s32 angle, valtmp;
+       unsigned iter;
+       int signx = 1;
+       int signtheta;
+
+       coord.i = CORDIC_ANGLE_GEN;
+       coord.q = 0;
+       angle = 0;
+
+       theta = FIXED(theta);
+       signtheta = (theta < 0) ? -1 : 1;
+       theta = ((theta + FIXED(180) * signtheta) % FIXED(360)) -
+               FIXED(180) * signtheta;
+
+       if (FLOAT(theta) > 90) {
+               theta -= FIXED(180);
+               signx = -1;
+       } else if (FLOAT(theta) < -90) {
+               theta += FIXED(180);
+               signx = -1;
+       }
+
+       for (iter = 0; iter < CORDIC_NUM_ITER; iter++) {
+               if (theta > angle) {
+                       valtmp = coord.i - (coord.q >> iter);
+                       coord.q += (coord.i >> iter);
+                       angle += arctan_table[iter];
+               } else {
+                       valtmp = coord.i + (coord.q >> iter);
+                       coord.q -= (coord.i >> iter);
+                       angle -= arctan_table[iter];
+               }
+               coord.i = valtmp;
+       }
+
+       coord.i *= signx;
+       coord.q *= signx;
+       return coord;
+}
+EXPORT_SYMBOL(cordic_calc_iq);
+
+MODULE_DESCRIPTION("Cordic functions");
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_LICENSE("Dual BSD/GPL");
diff --git a/lib/crc8.c b/lib/crc8.c
new file mode 100644 (file)
index 0000000..87b59ca
--- /dev/null
@@ -0,0 +1,86 @@
+/*
+ * Copyright (c) 2011 Broadcom Corporation
+ *
+ * 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.
+ */
+
+#define pr_fmt(fmt)            KBUILD_MODNAME ": " fmt
+
+#include <linux/module.h>
+#include <linux/crc8.h>
+#include <linux/printk.h>
+
+/*
+ * crc8_populate_msb - fill crc table for given polynomial in reverse bit order.
+ *
+ * table:      table to be filled.
+ * polynomial: polynomial for which table is to be filled.
+ */
+void crc8_populate_msb(u8 table[CRC8_TABLE_SIZE], u8 polynomial)
+{
+       int i, j;
+       const u8 msbit = 0x80;
+       u8 t = msbit;
+
+       table[0] = 0;
+
+       for (i = 1; i < CRC8_TABLE_SIZE; i *= 2) {
+               t = (t << 1) ^ (t & msbit ? polynomial : 0);
+               for (j = 0; j < i; j++)
+                       table[i+j] = table[j] ^ t;
+       }
+}
+EXPORT_SYMBOL(crc8_populate_msb);
+
+/*
+ * crc8_populate_lsb - fill crc table for given polynomial in regular bit order.
+ *
+ * table:      table to be filled.
+ * polynomial: polynomial for which table is to be filled.
+ */
+void crc8_populate_lsb(u8 table[CRC8_TABLE_SIZE], u8 polynomial)
+{
+       int i, j;
+       u8 t = 1;
+
+       table[0] = 0;
+
+       for (i = (CRC8_TABLE_SIZE >> 1); i; i >>= 1) {
+               t = (t >> 1) ^ (t & 1 ? polynomial : 0);
+               for (j = 0; j < CRC8_TABLE_SIZE; j += 2*i)
+                       table[i+j] = table[j] ^ t;
+       }
+}
+EXPORT_SYMBOL(crc8_populate_lsb);
+
+/*
+ * crc8 - calculate a crc8 over the given input data.
+ *
+ * table: crc table used for calculation.
+ * pdata: pointer to data buffer.
+ * nbytes: number of bytes in data buffer.
+ * crc:        previous returned crc8 value.
+ */
+u8 crc8(const u8 table[CRC8_TABLE_SIZE], u8 *pdata, size_t nbytes, u8 crc)
+{
+       /* loop over the buffer data */
+       while (nbytes-- > 0)
+               crc = table[(crc ^ *pdata++) & 0xff];
+
+       return crc;
+}
+EXPORT_SYMBOL(crc8);
+
+MODULE_DESCRIPTION("CRC8 (by Williams, Ross N.) function");
+MODULE_AUTHOR("Broadcom Corporation");
+MODULE_LICENSE("Dual BSD/GPL");
index a4e1db3..4e8985a 100644 (file)
@@ -2247,10 +2247,6 @@ __alloc_pages_nodemask(gfp_t gfp_mask, unsigned int order,
 
        if (should_fail_alloc_page(gfp_mask, order))
                return NULL;
-#ifndef CONFIG_ZONE_DMA
-       if (WARN_ON_ONCE(gfp_mask & __GFP_DMA))
-               return NULL;
-#endif
 
        /*
         * Check the zones suitable for the gfp_mask contain at least one
index c7a581a..cfa9afe 100644 (file)
@@ -18,6 +18,8 @@
  *             2 of the License, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/capability.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
@@ -149,13 +151,13 @@ int vlan_check_real_dev(struct net_device *real_dev, u16 vlan_id)
        const struct net_device_ops *ops = real_dev->netdev_ops;
 
        if (real_dev->features & NETIF_F_VLAN_CHALLENGED) {
-               pr_info("8021q: VLANs not supported on %s\n", name);
+               pr_info("VLANs not supported on %s\n", name);
                return -EOPNOTSUPP;
        }
 
        if ((real_dev->features & NETIF_F_HW_VLAN_FILTER) &&
            (!ops->ndo_vlan_rx_add_vid || !ops->ndo_vlan_rx_kill_vid)) {
-               pr_info("8021q: Device %s has buggy VLAN hw accel\n", name);
+               pr_info("Device %s has buggy VLAN hw accel\n", name);
                return -EOPNOTSUPP;
        }
 
@@ -344,13 +346,12 @@ static void __vlan_device_event(struct net_device *dev, unsigned long event)
        case NETDEV_CHANGENAME:
                vlan_proc_rem_dev(dev);
                if (vlan_proc_add_dev(dev) < 0)
-                       pr_warning("8021q: failed to change proc name for %s\n",
-                                       dev->name);
+                       pr_warn("failed to change proc name for %s\n",
+                               dev->name);
                break;
        case NETDEV_REGISTER:
                if (vlan_proc_add_dev(dev) < 0)
-                       pr_warning("8021q: failed to add proc entry for %s\n",
-                                       dev->name);
+                       pr_warn("failed to add proc entry for %s\n", dev->name);
                break;
        case NETDEV_UNREGISTER:
                vlan_proc_rem_dev(dev);
@@ -374,7 +375,7 @@ static int vlan_device_event(struct notifier_block *unused, unsigned long event,
        if ((event == NETDEV_UP) &&
            (dev->features & NETIF_F_HW_VLAN_FILTER) &&
            dev->netdev_ops->ndo_vlan_rx_add_vid) {
-               pr_info("8021q: adding VLAN 0 to HW filter on device %s\n",
+               pr_info("adding VLAN 0 to HW filter on device %s\n",
                        dev->name);
                dev->netdev_ops->ndo_vlan_rx_add_vid(dev, 0);
        }
index f247f5b..1c9aa8c 100644 (file)
@@ -20,6 +20,8 @@
  *             2 of the License, or (at your option) any later version.
  */
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/skbuff.h>
@@ -55,7 +57,7 @@ static int vlan_dev_rebuild_header(struct sk_buff *skb)
                return arp_find(veth->h_dest, skb);
 #endif
        default:
-               pr_debug("%s: unable to resolve type %X addresses.\n",
+               pr_debug("%s: unable to resolve type %X addresses\n",
                         dev->name, ntohs(veth->h_vlan_encapsulated_proto));
 
                memcpy(veth->h_source, dev->dev_addr, ETH_ALEN);
@@ -165,7 +167,7 @@ static netdev_tx_t vlan_dev_hard_start_xmit(struct sk_buff *skb,
                u64_stats_update_begin(&stats->syncp);
                stats->tx_packets++;
                stats->tx_bytes += len;
-               u64_stats_update_begin(&stats->syncp);
+               u64_stats_update_end(&stats->syncp);
        } else {
                this_cpu_inc(vlan_dev_info(dev)->vlan_pcpu_stats->tx_dropped);
        }
index d940c49..016d7f4 100644 (file)
@@ -17,6 +17,8 @@
  * Jan 20, 1998        Ben Greear     Initial Version
  *****************************************************************************/
 
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
 #include <linux/module.h>
 #include <linux/errno.h>
 #include <linux/kernel.h>
@@ -155,7 +157,7 @@ int __net_init vlan_proc_init(struct net *net)
        return 0;
 
 err:
-       pr_err("%s: can't create entry in proc filesystem!\n", __func__);
+       pr_err("can't create entry in proc filesystem!\n");
        vlan_proc_cleanup(net);
        return -ENOBUFS;
 }
index e9aced0..db4a11c 100644 (file)
@@ -37,6 +37,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/skbuff.h>
 #include <linux/slab.h>
 #include <linux/atm.h>
index b55e861..abb4901 100644 (file)
@@ -568,7 +568,7 @@ static int hard_if_event(struct notifier_block *this,
                break;
        default:
                break;
-       };
+       }
 
 hardif_put:
        hardif_free_ref(hard_iface);
index 815269b..e937ada 100644 (file)
@@ -1519,7 +1519,7 @@ int hci_recv_fragment(struct hci_dev *hdev, int type, void *data, int count)
 
                data += (count - rem);
                count = rem;
-       };
+       }
 
        return rem;
 }
@@ -1554,7 +1554,7 @@ int hci_recv_stream_fragment(struct hci_dev *hdev, void *data, int count)
 
                data += (count - rem);
                count = rem;
-       };
+       }
 
        return rem;
 }
index a86f9ba..e64a1c2 100644 (file)
@@ -906,7 +906,7 @@ static struct l2cap_chan *l2cap_global_chan_by_psm(int state, __le16 psm, bdaddr
                if (c->psm == psm) {
                        /* Exact match. */
                        if (!bacmp(&bt_sk(sk)->src, src)) {
-                               read_unlock_bh(&chan_list_lock);
+                               read_unlock(&chan_list_lock);
                                return c;
                        }
 
index 649ebac..c628a57 100644 (file)
@@ -9,6 +9,7 @@
 
 #include <linux/version.h>
 #include <linux/fs.h>
+#include <linux/hardirq.h>
 #include <linux/init.h>
 #include <linux/module.h>
 #include <linux/netdevice.h>
@@ -139,17 +140,14 @@ static void close_work(struct work_struct *work)
        struct chnl_net *dev = NULL;
        struct list_head *list_node;
        struct list_head *_tmp;
-       /* May be called with or without RTNL lock held */
-       int islocked = rtnl_is_locked();
-       if (!islocked)
-               rtnl_lock();
+
+       rtnl_lock();
        list_for_each_safe(list_node, _tmp, &chnl_net_list) {
                dev = list_entry(list_node, struct chnl_net, list_field);
                if (dev->state == CAIF_SHUTDOWN)
                        dev_close(dev->netdev);
        }
-       if (!islocked)
-               rtnl_unlock();
+       rtnl_unlock();
 }
 static DECLARE_WORK(close_worker, close_work);
 
index 184a657..d6c8ae5 100644 (file)
@@ -43,6 +43,7 @@
 
 #include <linux/module.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/hrtimer.h>
 #include <linux/list.h>
 #include <linux/proc_fs.h>
index c7e305d..b3f52d2 100644 (file)
@@ -2096,6 +2096,7 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
 {
        const struct net_device_ops *ops = dev->netdev_ops;
        int rc = NETDEV_TX_OK;
+       unsigned int skb_len;
 
        if (likely(!skb->next)) {
                u32 features;
@@ -2146,8 +2147,9 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
                        }
                }
 
+               skb_len = skb->len;
                rc = ops->ndo_start_xmit(skb, dev);
-               trace_net_dev_xmit(skb, rc);
+               trace_net_dev_xmit(skb, rc, dev, skb_len);
                if (rc == NETDEV_TX_OK)
                        txq_trans_update(txq);
                return rc;
@@ -2167,8 +2169,9 @@ gso:
                if (dev->priv_flags & IFF_XMIT_DST_RELEASE)
                        skb_dst_drop(nskb);
 
+               skb_len = nskb->len;
                rc = ops->ndo_start_xmit(nskb, dev);
-               trace_net_dev_xmit(nskb, rc);
+               trace_net_dev_xmit(nskb, rc, dev, skb_len);
                if (unlikely(rc != NETDEV_TX_OK)) {
                        if (rc & ~NETDEV_TX_MASK)
                                goto out_kfree_gso_skb;
@@ -5864,8 +5867,6 @@ struct net_device *alloc_netdev_mqs(int sizeof_priv, const char *name,
 
        dev->gso_max_size = GSO_MAX_SIZE;
 
-       INIT_LIST_HEAD(&dev->ethtool_ntuple_list.list);
-       dev->ethtool_ntuple_list.count = 0;
        INIT_LIST_HEAD(&dev->napi_list);
        INIT_LIST_HEAD(&dev->unreg_list);
        INIT_LIST_HEAD(&dev->link_watch_list);
@@ -5929,9 +5930,6 @@ void free_netdev(struct net_device *dev)
        /* Flush device addresses */
        dev_addr_flush(dev);
 
-       /* Clear ethtool n-tuple list */
-       ethtool_ntuple_flush(dev);
-
        list_for_each_entry_safe(p, n, &dev->napi_list, dev_list)
                netif_napi_del(p);
 
index fd14116..b7c12a6 100644 (file)
@@ -169,18 +169,6 @@ int ethtool_op_set_flags(struct net_device *dev, u32 data, u32 supported)
 }
 EXPORT_SYMBOL(ethtool_op_set_flags);
 
-void ethtool_ntuple_flush(struct net_device *dev)
-{
-       struct ethtool_rx_ntuple_flow_spec_container *fsc, *f;
-
-       list_for_each_entry_safe(fsc, f, &dev->ethtool_ntuple_list.list, list) {
-               list_del(&fsc->list);
-               kfree(fsc);
-       }
-       dev->ethtool_ntuple_list.count = 0;
-}
-EXPORT_SYMBOL(ethtool_ntuple_flush);
-
 /* Handlers for each ethtool command */
 
 #define ETHTOOL_DEV_FEATURE_WORDS      1
@@ -865,34 +853,6 @@ out:
        return ret;
 }
 
-static void __rx_ntuple_filter_add(struct ethtool_rx_ntuple_list *list,
-                       struct ethtool_rx_ntuple_flow_spec *spec,
-                       struct ethtool_rx_ntuple_flow_spec_container *fsc)
-{
-
-       /* don't add filters forever */
-       if (list->count >= ETHTOOL_MAX_NTUPLE_LIST_ENTRY) {
-               /* free the container */
-               kfree(fsc);
-               return;
-       }
-
-       /* Copy the whole filter over */
-       fsc->fs.flow_type = spec->flow_type;
-       memcpy(&fsc->fs.h_u, &spec->h_u, sizeof(spec->h_u));
-       memcpy(&fsc->fs.m_u, &spec->m_u, sizeof(spec->m_u));
-
-       fsc->fs.vlan_tag = spec->vlan_tag;
-       fsc->fs.vlan_tag_mask = spec->vlan_tag_mask;
-       fsc->fs.data = spec->data;
-       fsc->fs.data_mask = spec->data_mask;
-       fsc->fs.action = spec->action;
-
-       /* add to the list */
-       list_add_tail_rcu(&fsc->list, &list->list);
-       list->count++;
-}
-
 /*
  * ethtool does not (or did not) set masks for flow parameters that are
  * not specified, so if both value and mask are 0 then this must be
@@ -930,8 +890,6 @@ static noinline_for_stack int ethtool_set_rx_ntuple(struct net_device *dev,
 {
        struct ethtool_rx_ntuple cmd;
        const struct ethtool_ops *ops = dev->ethtool_ops;
-       struct ethtool_rx_ntuple_flow_spec_container *fsc = NULL;
-       int ret;
 
        if (!ops->set_rx_ntuple)
                return -EOPNOTSUPP;
@@ -944,269 +902,7 @@ static noinline_for_stack int ethtool_set_rx_ntuple(struct net_device *dev,
 
        rx_ntuple_fix_masks(&cmd.fs);
 
-       /*
-        * Cache filter in dev struct for GET operation only if
-        * the underlying driver doesn't have its own GET operation, and
-        * only if the filter was added successfully.  First make sure we
-        * can allocate the filter, then continue if successful.
-        */
-       if (!ops->get_rx_ntuple) {
-               fsc = kmalloc(sizeof(*fsc), GFP_ATOMIC);
-               if (!fsc)
-                       return -ENOMEM;
-       }
-
-       ret = ops->set_rx_ntuple(dev, &cmd);
-       if (ret) {
-               kfree(fsc);
-               return ret;
-       }
-
-       if (!ops->get_rx_ntuple)
-               __rx_ntuple_filter_add(&dev->ethtool_ntuple_list, &cmd.fs, fsc);
-
-       return ret;
-}
-
-static int ethtool_get_rx_ntuple(struct net_device *dev, void __user *useraddr)
-{
-       struct ethtool_gstrings gstrings;
-       const struct ethtool_ops *ops = dev->ethtool_ops;
-       struct ethtool_rx_ntuple_flow_spec_container *fsc;
-       u8 *data;
-       char *p;
-       int ret, i, num_strings = 0;
-
-       if (!ops->get_sset_count)
-               return -EOPNOTSUPP;
-
-       if (copy_from_user(&gstrings, useraddr, sizeof(gstrings)))
-               return -EFAULT;
-
-       ret = ops->get_sset_count(dev, gstrings.string_set);
-       if (ret < 0)
-               return ret;
-
-       gstrings.len = ret;
-
-       data = kzalloc(gstrings.len * ETH_GSTRING_LEN, GFP_USER);
-       if (!data)
-               return -ENOMEM;
-
-       if (ops->get_rx_ntuple) {
-               /* driver-specific filter grab */
-               ret = ops->get_rx_ntuple(dev, gstrings.string_set, data);
-               goto copy;
-       }
-
-       /* default ethtool filter grab */
-       i = 0;
-       p = (char *)data;
-       list_for_each_entry(fsc, &dev->ethtool_ntuple_list.list, list) {
-               sprintf(p, "Filter %d:\n", i);
-               p += ETH_GSTRING_LEN;
-               num_strings++;
-
-               switch (fsc->fs.flow_type) {
-               case TCP_V4_FLOW:
-                       sprintf(p, "\tFlow Type: TCP\n");
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       break;
-               case UDP_V4_FLOW:
-                       sprintf(p, "\tFlow Type: UDP\n");
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       break;
-               case SCTP_V4_FLOW:
-                       sprintf(p, "\tFlow Type: SCTP\n");
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       break;
-               case AH_ESP_V4_FLOW:
-                       sprintf(p, "\tFlow Type: AH ESP\n");
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       break;
-               case ESP_V4_FLOW:
-                       sprintf(p, "\tFlow Type: ESP\n");
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       break;
-               case IP_USER_FLOW:
-                       sprintf(p, "\tFlow Type: Raw IP\n");
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       break;
-               case IPV4_FLOW:
-                       sprintf(p, "\tFlow Type: IPv4\n");
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       break;
-               default:
-                       sprintf(p, "\tFlow Type: Unknown\n");
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       goto unknown_filter;
-               }
-
-               /* now the rest of the filters */
-               switch (fsc->fs.flow_type) {
-               case TCP_V4_FLOW:
-               case UDP_V4_FLOW:
-               case SCTP_V4_FLOW:
-                       sprintf(p, "\tSrc IP addr: 0x%x\n",
-                               fsc->fs.h_u.tcp_ip4_spec.ip4src);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tSrc IP mask: 0x%x\n",
-                               fsc->fs.m_u.tcp_ip4_spec.ip4src);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tDest IP addr: 0x%x\n",
-                               fsc->fs.h_u.tcp_ip4_spec.ip4dst);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tDest IP mask: 0x%x\n",
-                               fsc->fs.m_u.tcp_ip4_spec.ip4dst);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tSrc Port: %d, mask: 0x%x\n",
-                               fsc->fs.h_u.tcp_ip4_spec.psrc,
-                               fsc->fs.m_u.tcp_ip4_spec.psrc);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tDest Port: %d, mask: 0x%x\n",
-                               fsc->fs.h_u.tcp_ip4_spec.pdst,
-                               fsc->fs.m_u.tcp_ip4_spec.pdst);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tTOS: %d, mask: 0x%x\n",
-                               fsc->fs.h_u.tcp_ip4_spec.tos,
-                               fsc->fs.m_u.tcp_ip4_spec.tos);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       break;
-               case AH_ESP_V4_FLOW:
-               case ESP_V4_FLOW:
-                       sprintf(p, "\tSrc IP addr: 0x%x\n",
-                               fsc->fs.h_u.ah_ip4_spec.ip4src);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tSrc IP mask: 0x%x\n",
-                               fsc->fs.m_u.ah_ip4_spec.ip4src);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tDest IP addr: 0x%x\n",
-                               fsc->fs.h_u.ah_ip4_spec.ip4dst);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tDest IP mask: 0x%x\n",
-                               fsc->fs.m_u.ah_ip4_spec.ip4dst);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tSPI: %d, mask: 0x%x\n",
-                               fsc->fs.h_u.ah_ip4_spec.spi,
-                               fsc->fs.m_u.ah_ip4_spec.spi);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tTOS: %d, mask: 0x%x\n",
-                               fsc->fs.h_u.ah_ip4_spec.tos,
-                               fsc->fs.m_u.ah_ip4_spec.tos);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       break;
-               case IP_USER_FLOW:
-                       sprintf(p, "\tSrc IP addr: 0x%x\n",
-                               fsc->fs.h_u.usr_ip4_spec.ip4src);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tSrc IP mask: 0x%x\n",
-                               fsc->fs.m_u.usr_ip4_spec.ip4src);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tDest IP addr: 0x%x\n",
-                               fsc->fs.h_u.usr_ip4_spec.ip4dst);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tDest IP mask: 0x%x\n",
-                               fsc->fs.m_u.usr_ip4_spec.ip4dst);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       break;
-               case IPV4_FLOW:
-                       sprintf(p, "\tSrc IP addr: 0x%x\n",
-                               fsc->fs.h_u.usr_ip4_spec.ip4src);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tSrc IP mask: 0x%x\n",
-                               fsc->fs.m_u.usr_ip4_spec.ip4src);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tDest IP addr: 0x%x\n",
-                               fsc->fs.h_u.usr_ip4_spec.ip4dst);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tDest IP mask: 0x%x\n",
-                               fsc->fs.m_u.usr_ip4_spec.ip4dst);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tL4 bytes: 0x%x, mask: 0x%x\n",
-                               fsc->fs.h_u.usr_ip4_spec.l4_4_bytes,
-                               fsc->fs.m_u.usr_ip4_spec.l4_4_bytes);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tTOS: %d, mask: 0x%x\n",
-                               fsc->fs.h_u.usr_ip4_spec.tos,
-                               fsc->fs.m_u.usr_ip4_spec.tos);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tIP Version: %d, mask: 0x%x\n",
-                               fsc->fs.h_u.usr_ip4_spec.ip_ver,
-                               fsc->fs.m_u.usr_ip4_spec.ip_ver);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       sprintf(p, "\tProtocol: %d, mask: 0x%x\n",
-                               fsc->fs.h_u.usr_ip4_spec.proto,
-                               fsc->fs.m_u.usr_ip4_spec.proto);
-                       p += ETH_GSTRING_LEN;
-                       num_strings++;
-                       break;
-               }
-               sprintf(p, "\tVLAN: %d, mask: 0x%x\n",
-                       fsc->fs.vlan_tag, fsc->fs.vlan_tag_mask);
-               p += ETH_GSTRING_LEN;
-               num_strings++;
-               sprintf(p, "\tUser-defined: 0x%Lx\n", fsc->fs.data);
-               p += ETH_GSTRING_LEN;
-               num_strings++;
-               sprintf(p, "\tUser-defined mask: 0x%Lx\n", fsc->fs.data_mask);
-               p += ETH_GSTRING_LEN;
-               num_strings++;
-               if (fsc->fs.action == ETHTOOL_RXNTUPLE_ACTION_DROP)
-                       sprintf(p, "\tAction: Drop\n");
-               else
-                       sprintf(p, "\tAction: Direct to queue %d\n",
-                               fsc->fs.action);
-               p += ETH_GSTRING_LEN;
-               num_strings++;
-unknown_filter:
-               i++;
-       }
-copy:
-       /* indicate to userspace how many strings we actually have */
-       gstrings.len = num_strings;
-       ret = -EFAULT;
-       if (copy_to_user(useraddr, &gstrings, sizeof(gstrings)))
-               goto out;
-       useraddr += sizeof(gstrings);
-       if (copy_to_user(useraddr, data, gstrings.len * ETH_GSTRING_LEN))
-               goto out;
-       ret = 0;
-
-out:
-       kfree(data);
-       return ret;
+       return ops->set_rx_ntuple(dev, &cmd);
 }
 
 static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
@@ -2101,9 +1797,6 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        case ETHTOOL_SRXNTUPLE:
                rc = ethtool_set_rx_ntuple(dev, useraddr);
                break;
-       case ETHTOOL_GRXNTUPLE:
-               rc = ethtool_get_rx_ntuple(dev, useraddr);
-               break;
        case ETHTOOL_GSSET_INFO:
                rc = ethtool_get_sset_info(dev, useraddr);
                break;
index cc14631..9c19260 100644 (file)
@@ -465,6 +465,9 @@ int inet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
        if (addr_len < sizeof(struct sockaddr_in))
                goto out;
 
+       if (addr->sin_family != AF_INET)
+               goto out;
+
        chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr);
 
        /* Not specified by any standard per-se, however it breaks too
index ce616d9..dafbf2c 100644 (file)
  *  1.  Nodes may appear in the tree only with the pool lock held.
  *  2.  Nodes may disappear from the tree only with the pool lock held
  *      AND reference count being 0.
- *  3.  Nodes appears and disappears from unused node list only under
- *      "inet_peer_unused_lock".
- *  4.  Global variable peer_total is modified under the pool lock.
- *  5.  struct inet_peer fields modification:
+ *  3.  Global variable peer_total is modified under the pool lock.
+ *  4.  struct inet_peer fields modification:
  *             avl_left, avl_right, avl_parent, avl_height: pool lock
- *             unused: unused node list lock
  *             refcnt: atomically against modifications on other CPU;
  *                usually under some other lock to prevent node disappearing
- *             dtime: unused node list lock
  *             daddr: unchangeable
  *             ip_id_count: atomic value (no lock needed)
  */
@@ -104,19 +100,6 @@ int inet_peer_threshold __read_mostly = 65536 + 128;       /* start to throw entries m
                                         * aggressively at this stage */
 int inet_peer_minttl __read_mostly = 120 * HZ; /* TTL under high load: 120 sec */
 int inet_peer_maxttl __read_mostly = 10 * 60 * HZ;     /* usual time to live: 10 min */
-int inet_peer_gc_mintime __read_mostly = 10 * HZ;
-int inet_peer_gc_maxtime __read_mostly = 120 * HZ;
-
-static struct {
-       struct list_head        list;
-       spinlock_t              lock;
-} unused_peers = {
-       .list                   = LIST_HEAD_INIT(unused_peers.list),
-       .lock                   = __SPIN_LOCK_UNLOCKED(unused_peers.lock),
-};
-
-static void peer_check_expire(unsigned long dummy);
-static DEFINE_TIMER(peer_periodic_timer, peer_check_expire, 0, 0);
 
 
 /* Called from ip_output.c:ip_init  */
@@ -142,21 +125,6 @@ void __init inet_initpeers(void)
                        0, SLAB_HWCACHE_ALIGN | SLAB_PANIC,
                        NULL);
 
-       /* All the timers, started at system startup tend
-          to synchronize. Perturb it a bit.
-        */
-       peer_periodic_timer.expires = jiffies
-               + net_random() % inet_peer_gc_maxtime
-               + inet_peer_gc_maxtime;
-       add_timer(&peer_periodic_timer);
-}
-
-/* Called with or without local BH being disabled. */
-static void unlink_from_unused(struct inet_peer *p)
-{
-       spin_lock_bh(&unused_peers.lock);
-       list_del_init(&p->unused);
-       spin_unlock_bh(&unused_peers.lock);
 }
 
 static int addr_compare(const struct inetpeer_addr *a,
@@ -203,20 +171,6 @@ static int addr_compare(const struct inetpeer_addr *a,
        u;                                                      \
 })
 
-static bool atomic_add_unless_return(atomic_t *ptr, int a, int u, int *newv)
-{
-       int cur, old = atomic_read(ptr);
-
-       while (old != u) {
-               *newv = old + a;
-               cur = atomic_cmpxchg(ptr, old, *newv);
-               if (cur == old)
-                       return true;
-               old = cur;
-       }
-       return false;
-}
-
 /*
  * Called with rcu_read_lock()
  * Because we hold no lock against a writer, its quite possible we fall
@@ -225,8 +179,7 @@ static bool atomic_add_unless_return(atomic_t *ptr, int a, int u, int *newv)
  * We exit from this function if number of links exceeds PEER_MAXDEPTH
  */
 static struct inet_peer *lookup_rcu(const struct inetpeer_addr *daddr,
-                                   struct inet_peer_base *base,
-                                   int *newrefcnt)
+                                   struct inet_peer_base *base)
 {
        struct inet_peer *u = rcu_dereference(base->root);
        int count = 0;
@@ -235,11 +188,9 @@ static struct inet_peer *lookup_rcu(const struct inetpeer_addr *daddr,
                int cmp = addr_compare(daddr, &u->daddr);
                if (cmp == 0) {
                        /* Before taking a reference, check if this entry was
-                        * deleted, unlink_from_pool() sets refcnt=-1 to make
-                        * distinction between an unused entry (refcnt=0) and
-                        * a freed one.
+                        * deleted (refcnt=-1)
                         */
-                       if (!atomic_add_unless_return(&u->refcnt, 1, -1, newrefcnt))
+                       if (!atomic_add_unless(&u->refcnt, 1, -1))
                                u = NULL;
                        return u;
                }
@@ -366,137 +317,96 @@ static void inetpeer_free_rcu(struct rcu_head *head)
        kmem_cache_free(peer_cachep, container_of(head, struct inet_peer, rcu));
 }
 
-/* May be called with local BH enabled. */
 static void unlink_from_pool(struct inet_peer *p, struct inet_peer_base *base,
                             struct inet_peer __rcu **stack[PEER_MAXDEPTH])
 {
-       int do_free;
-
-       do_free = 0;
-
-       write_seqlock_bh(&base->lock);
-       /* Check the reference counter.  It was artificially incremented by 1
-        * in cleanup() function to prevent sudden disappearing.  If we can
-        * atomically (because of lockless readers) take this last reference,
-        * it's safe to remove the node and free it later.
-        * We use refcnt=-1 to alert lockless readers this entry is deleted.
-        */
-       if (atomic_cmpxchg(&p->refcnt, 1, -1) == 1) {
-               struct inet_peer __rcu ***stackptr, ***delp;
-               if (lookup(&p->daddr, stack, base) != p)
-                       BUG();
-               delp = stackptr - 1; /* *delp[0] == p */
-               if (p->avl_left == peer_avl_empty_rcu) {
-                       *delp[0] = p->avl_right;
-                       --stackptr;
-               } else {
-                       /* look for a node to insert instead of p */
-                       struct inet_peer *t;
-                       t = lookup_rightempty(p, base);
-                       BUG_ON(rcu_deref_locked(*stackptr[-1], base) != t);
-                       **--stackptr = t->avl_left;
-                       /* t is removed, t->daddr > x->daddr for any
-                        * x in p->avl_left subtree.
-                        * Put t in the old place of p. */
-                       RCU_INIT_POINTER(*delp[0], t);
-                       t->avl_left = p->avl_left;
-                       t->avl_right = p->avl_right;
-                       t->avl_height = p->avl_height;
-                       BUG_ON(delp[1] != &p->avl_left);
-                       delp[1] = &t->avl_left; /* was &p->avl_left */
-               }
-               peer_avl_rebalance(stack, stackptr, base);
-               base->total--;
-               do_free = 1;
+       struct inet_peer __rcu ***stackptr, ***delp;
+
+       if (lookup(&p->daddr, stack, base) != p)
+               BUG();
+       delp = stackptr - 1; /* *delp[0] == p */
+       if (p->avl_left == peer_avl_empty_rcu) {
+               *delp[0] = p->avl_right;
+               --stackptr;
+       } else {
+               /* look for a node to insert instead of p */
+               struct inet_peer *t;
+               t = lookup_rightempty(p, base);
+               BUG_ON(rcu_deref_locked(*stackptr[-1], base) != t);
+               **--stackptr = t->avl_left;
+               /* t is removed, t->daddr > x->daddr for any
+                * x in p->avl_left subtree.
+                * Put t in the old place of p. */
+               RCU_INIT_POINTER(*delp[0], t);
+               t->avl_left = p->avl_left;
+               t->avl_right = p->avl_right;
+               t->avl_height = p->avl_height;
+               BUG_ON(delp[1] != &p->avl_left);
+               delp[1] = &t->avl_left; /* was &p->avl_left */
        }
-       write_sequnlock_bh(&base->lock);
-
-       if (do_free)
-               call_rcu(&p->rcu, inetpeer_free_rcu);
-       else
-               /* The node is used again.  Decrease the reference counter
-                * back.  The loop "cleanup -> unlink_from_unused
-                *   -> unlink_from_pool -> putpeer -> link_to_unused
-                *   -> cleanup (for the same node)"
-                * doesn't really exist because the entry will have a
-                * recent deletion time and will not be cleaned again soon.
-                */
-               inet_putpeer(p);
+       peer_avl_rebalance(stack, stackptr, base);
+       base->total--;
+       call_rcu(&p->rcu, inetpeer_free_rcu);
 }
 
 static struct inet_peer_base *family_to_base(int family)
 {
-       return (family == AF_INET ? &v4_peers : &v6_peers);
+       return family == AF_INET ? &v4_peers : &v6_peers;
 }
 
-static struct inet_peer_base *peer_to_base(struct inet_peer *p)
+/* perform garbage collect on all items stacked during a lookup */
+static int inet_peer_gc(struct inet_peer_base *base,
+                       struct inet_peer __rcu **stack[PEER_MAXDEPTH],
+                       struct inet_peer __rcu ***stackptr)
 {
-       return family_to_base(p->daddr.family);
-}
-
-/* May be called with local BH enabled. */
-static int cleanup_once(unsigned long ttl, struct inet_peer __rcu **stack[PEER_MAXDEPTH])
-{
-       struct inet_peer *p = NULL;
-
-       /* Remove the first entry from the list of unused nodes. */
-       spin_lock_bh(&unused_peers.lock);
-       if (!list_empty(&unused_peers.list)) {
-               __u32 delta;
+       struct inet_peer *p, *gchead = NULL;
+       __u32 delta, ttl;
+       int cnt = 0;
 
-               p = list_first_entry(&unused_peers.list, struct inet_peer, unused);
+       if (base->total >= inet_peer_threshold)
+               ttl = 0; /* be aggressive */
+       else
+               ttl = inet_peer_maxttl
+                               - (inet_peer_maxttl - inet_peer_minttl) / HZ *
+                                       base->total / inet_peer_threshold * HZ;
+       stackptr--; /* last stack slot is peer_avl_empty */
+       while (stackptr > stack) {
+               stackptr--;
+               p = rcu_deref_locked(**stackptr, base);
                delta = (__u32)jiffies - p->dtime;
-
-               if (delta < ttl) {
-                       /* Do not prune fresh entries. */
-                       spin_unlock_bh(&unused_peers.lock);
-                       return -1;
+               if (atomic_read(&p->refcnt) == 0 && delta >= ttl &&
+                   atomic_cmpxchg(&p->refcnt, 0, -1) == 0) {
+                       p->gc_next = gchead;
+                       gchead = p;
                }
-
-               list_del_init(&p->unused);
-
-               /* Grab an extra reference to prevent node disappearing
-                * before unlink_from_pool() call. */
-               atomic_inc(&p->refcnt);
        }
-       spin_unlock_bh(&unused_peers.lock);
-
-       if (p == NULL)
-               /* It means that the total number of USED entries has
-                * grown over inet_peer_threshold.  It shouldn't really
-                * happen because of entry limits in route cache. */
-               return -1;
-
-       unlink_from_pool(p, peer_to_base(p), stack);
-       return 0;
+       while ((p = gchead) != NULL) {
+               gchead = p->gc_next;
+               cnt++;
+               unlink_from_pool(p, base, stack);
+       }
+       return cnt;
 }
 
-/* Called with or without local BH being disabled. */
 struct inet_peer *inet_getpeer(struct inetpeer_addr *daddr, int create)
 {
        struct inet_peer __rcu **stack[PEER_MAXDEPTH], ***stackptr;
        struct inet_peer_base *base = family_to_base(daddr->family);
        struct inet_peer *p;
        unsigned int sequence;
-       int invalidated, newrefcnt = 0;
+       int invalidated, gccnt = 0;
 
-       /* Look up for the address quickly, lockless.
+       /* Attempt a lockless lookup first.
         * Because of a concurrent writer, we might not find an existing entry.
         */
        rcu_read_lock();
        sequence = read_seqbegin(&base->lock);
-       p = lookup_rcu(daddr, base, &newrefcnt);
+       p = lookup_rcu(daddr, base);
        invalidated = read_seqretry(&base->lock, sequence);
        rcu_read_unlock();
 
-       if (p) {
-found:         /* The existing node has been found.
-                * Remove the entry from unused list if it was there.
-                */
-               if (newrefcnt == 1)
-                       unlink_from_unused(p);
+       if (p)
                return p;
-       }
 
        /* If no writer did a change during our lookup, we can return early. */
        if (!create && !invalidated)
@@ -506,11 +416,17 @@ found:            /* The existing node has been found.
         * At least, nodes should be hot in our cache.
         */
        write_seqlock_bh(&base->lock);
+relookup:
        p = lookup(daddr, stack, base);
        if (p != peer_avl_empty) {
-               newrefcnt = atomic_inc_return(&p->refcnt);
+               atomic_inc(&p->refcnt);
                write_sequnlock_bh(&base->lock);
-               goto found;
+               return p;
+       }
+       if (!gccnt) {
+               gccnt = inet_peer_gc(base, stack, stackptr);
+               if (gccnt && create)
+                       goto relookup;
        }
        p = create ? kmem_cache_alloc(peer_cachep, GFP_ATOMIC) : NULL;
        if (p) {
@@ -525,7 +441,6 @@ found:              /* The existing node has been found.
                p->pmtu_expires = 0;
                p->pmtu_orig = 0;
                memset(&p->redirect_learned, 0, sizeof(p->redirect_learned));
-               INIT_LIST_HEAD(&p->unused);
 
 
                /* Link the node. */
@@ -534,63 +449,14 @@ found:            /* The existing node has been found.
        }
        write_sequnlock_bh(&base->lock);
 
-       if (base->total >= inet_peer_threshold)
-               /* Remove one less-recently-used entry. */
-               cleanup_once(0, stack);
-
        return p;
 }
-
-static int compute_total(void)
-{
-       return v4_peers.total + v6_peers.total;
-}
 EXPORT_SYMBOL_GPL(inet_getpeer);
 
-/* Called with local BH disabled. */
-static void peer_check_expire(unsigned long dummy)
-{
-       unsigned long now = jiffies;
-       int ttl, total;
-       struct inet_peer __rcu **stack[PEER_MAXDEPTH];
-
-       total = compute_total();
-       if (total >= inet_peer_threshold)
-               ttl = inet_peer_minttl;
-       else
-               ttl = inet_peer_maxttl
-                               - (inet_peer_maxttl - inet_peer_minttl) / HZ *
-                                       total / inet_peer_threshold * HZ;
-       while (!cleanup_once(ttl, stack)) {
-               if (jiffies != now)
-                       break;
-       }
-
-       /* Trigger the timer after inet_peer_gc_mintime .. inet_peer_gc_maxtime
-        * interval depending on the total number of entries (more entries,
-        * less interval). */
-       total = compute_total();
-       if (total >= inet_peer_threshold)
-               peer_periodic_timer.expires = jiffies + inet_peer_gc_mintime;
-       else
-               peer_periodic_timer.expires = jiffies
-                       + inet_peer_gc_maxtime
-                       - (inet_peer_gc_maxtime - inet_peer_gc_mintime) / HZ *
-                               total / inet_peer_threshold * HZ;
-       add_timer(&peer_periodic_timer);
-}
-
 void inet_putpeer(struct inet_peer *p)
 {
-       local_bh_disable();
-
-       if (atomic_dec_and_lock(&p->refcnt, &unused_peers.lock)) {
-               list_add_tail(&p->unused, &unused_peers.list);
-               p->dtime = (__u32)jiffies;
-               spin_unlock(&unused_peers.lock);
-       }
-
-       local_bh_enable();
+       p->dtime = (__u32)jiffies;
+       atomic_dec(&p->refcnt);
 }
 EXPORT_SYMBOL_GPL(inet_putpeer);
 
index c3118e1..ec93335 100644 (file)
@@ -14,6 +14,7 @@
 #include <linux/slab.h>
 #include <linux/types.h>
 #include <asm/uaccess.h>
+#include <asm/unaligned.h>
 #include <linux/skbuff.h>
 #include <linux/ip.h>
 #include <linux/icmp.h>
@@ -350,7 +351,7 @@ int ip_options_compile(struct net *net,
                                goto error;
                        }
                        if (optptr[2] <= optlen) {
-                               __be32 *timeptr = NULL;
+                               unsigned char *timeptr = NULL;
                                if (optptr[2]+3 > optptr[1]) {
                                        pp_ptr = optptr + 2;
                                        goto error;
@@ -359,7 +360,7 @@ int ip_options_compile(struct net *net,
                                      case IPOPT_TS_TSONLY:
                                        opt->ts = optptr - iph;
                                        if (skb)
-                                               timeptr = (__be32*)&optptr[optptr[2]-1];
+                                               timeptr = &optptr[optptr[2]-1];
                                        opt->ts_needtime = 1;
                                        optptr[2] += 4;
                                        break;
@@ -371,7 +372,7 @@ int ip_options_compile(struct net *net,
                                        opt->ts = optptr - iph;
                                        if (rt)  {
                                                memcpy(&optptr[optptr[2]-1], &rt->rt_spec_dst, 4);
-                                               timeptr = (__be32*)&optptr[optptr[2]+3];
+                                               timeptr = &optptr[optptr[2]+3];
                                        }
                                        opt->ts_needaddr = 1;
                                        opt->ts_needtime = 1;
@@ -389,7 +390,7 @@ int ip_options_compile(struct net *net,
                                                if (inet_addr_type(net, addr) == RTN_UNICAST)
                                                        break;
                                                if (skb)
-                                                       timeptr = (__be32*)&optptr[optptr[2]+3];
+                                                       timeptr = &optptr[optptr[2]+3];
                                        }
                                        opt->ts_needtime = 1;
                                        optptr[2] += 8;
@@ -403,10 +404,10 @@ int ip_options_compile(struct net *net,
                                }
                                if (timeptr) {
                                        struct timespec tv;
-                                       __be32  midtime;
+                                       u32  midtime;
                                        getnstimeofday(&tv);
-                                       midtime = htonl((tv.tv_sec % 86400) * MSEC_PER_SEC + tv.tv_nsec / NSEC_PER_MSEC);
-                                       memcpy(timeptr, &midtime, sizeof(__be32));
+                                       midtime = (tv.tv_sec % 86400) * MSEC_PER_SEC + tv.tv_nsec / NSEC_PER_MSEC;
+                                       put_unaligned_be32(midtime, timeptr);
                                        opt->is_changed = 1;
                                }
                        } else {
index 2646149..92bb943 100644 (file)
@@ -316,6 +316,7 @@ struct sock *cookie_v4_check(struct sock *sk, struct sk_buff *skb,
        ireq->wscale_ok         = tcp_opt.wscale_ok;
        ireq->tstamp_ok         = tcp_opt.saw_tstamp;
        req->ts_recent          = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0;
+       treq->snt_synack        = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsecr : 0;
 
        /* We throwed the options of the initial SYN away, so we hope
         * the ACK carries the same options again (see RFC1122 4.2.3.8)
index 57d0752..69fd720 100644 (file)
@@ -397,20 +397,6 @@ static struct ctl_table ipv4_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec_jiffies,
        },
-       {
-               .procname       = "inet_peer_gc_mintime",
-               .data           = &inet_peer_gc_mintime,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec_jiffies,
-       },
-       {
-               .procname       = "inet_peer_gc_maxtime",
-               .data           = &inet_peer_gc_maxtime,
-               .maxlen         = sizeof(int),
-               .mode           = 0644,
-               .proc_handler   = proc_dointvec_jiffies,
-       },
        {
                .procname       = "tcp_orphan_retries",
                .data           = &sysctl_tcp_orphan_retries,
index bef9f04..ea0d218 100644 (file)
@@ -880,6 +880,11 @@ static void tcp_init_metrics(struct sock *sk)
                tp->snd_ssthresh = dst_metric(dst, RTAX_SSTHRESH);
                if (tp->snd_ssthresh > tp->snd_cwnd_clamp)
                        tp->snd_ssthresh = tp->snd_cwnd_clamp;
+       } else {
+               /* ssthresh may have been reduced unnecessarily during.
+                * 3WHS. Restore it back to its initial default.
+                */
+               tp->snd_ssthresh = TCP_INFINITE_SSTHRESH;
        }
        if (dst_metric(dst, RTAX_REORDERING) &&
            tp->reordering != dst_metric(dst, RTAX_REORDERING)) {
@@ -887,10 +892,7 @@ static void tcp_init_metrics(struct sock *sk)
                tp->reordering = dst_metric(dst, RTAX_REORDERING);
        }
 
-       if (dst_metric(dst, RTAX_RTT) == 0)
-               goto reset;
-
-       if (!tp->srtt && dst_metric_rtt(dst, RTAX_RTT) < (TCP_TIMEOUT_INIT << 3))
+       if (dst_metric(dst, RTAX_RTT) == 0 || tp->srtt == 0)
                goto reset;
 
        /* Initial rtt is determined from SYN,SYN-ACK.
@@ -916,19 +918,26 @@ static void tcp_init_metrics(struct sock *sk)
                tp->mdev_max = tp->rttvar = max(tp->mdev, tcp_rto_min(sk));
        }
        tcp_set_rto(sk);
-       if (inet_csk(sk)->icsk_rto < TCP_TIMEOUT_INIT && !tp->rx_opt.saw_tstamp) {
 reset:
-               /* Play conservative. If timestamps are not
-                * supported, TCP will fail to recalculate correct
-                * rtt, if initial rto is too small. FORGET ALL AND RESET!
+       if (tp->srtt == 0) {
+               /* RFC2988bis: We've failed to get a valid RTT sample from
+                * 3WHS. This is most likely due to retransmission,
+                * including spurious one. Reset the RTO back to 3secs
+                * from the more aggressive 1sec to avoid more spurious
+                * retransmission.
                 */
-               if (!tp->rx_opt.saw_tstamp && tp->srtt) {
-                       tp->srtt = 0;
-                       tp->mdev = tp->mdev_max = tp->rttvar = TCP_TIMEOUT_INIT;
-                       inet_csk(sk)->icsk_rto = TCP_TIMEOUT_INIT;
-               }
+               tp->mdev = tp->mdev_max = tp->rttvar = TCP_TIMEOUT_FALLBACK;
+               inet_csk(sk)->icsk_rto = TCP_TIMEOUT_FALLBACK;
        }
-       tp->snd_cwnd = tcp_init_cwnd(tp, dst);
+       /* Cut cwnd down to 1 per RFC5681 if SYN or SYN-ACK has been
+        * retransmitted. In light of RFC2988bis' more aggressive 1sec
+        * initRTO, we only reset cwnd when more than 1 SYN/SYN-ACK
+        * retransmission has occurred.
+        */
+       if (tp->total_retrans > 1)
+               tp->snd_cwnd = 1;
+       else
+               tp->snd_cwnd = tcp_init_cwnd(tp, dst);
        tp->snd_cwnd_stamp = tcp_time_stamp;
 }
 
@@ -3112,12 +3121,13 @@ static void tcp_fastretrans_alert(struct sock *sk, int pkts_acked, int flag)
        tcp_xmit_retransmit_queue(sk);
 }
 
-static void tcp_valid_rtt_meas(struct sock *sk, u32 seq_rtt)
+void tcp_valid_rtt_meas(struct sock *sk, u32 seq_rtt)
 {
        tcp_rtt_estimator(sk, seq_rtt);
        tcp_set_rto(sk);
        inet_csk(sk)->icsk_backoff = 0;
 }
+EXPORT_SYMBOL(tcp_valid_rtt_meas);
 
 /* Read draft-ietf-tcplw-high-performance before mucking
  * with this code. (Supersedes RFC1323)
@@ -5806,12 +5816,6 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                                              tp->rx_opt.snd_wscale;
                                tcp_init_wl(tp, TCP_SKB_CB(skb)->seq);
 
-                               /* tcp_ack considers this ACK as duplicate
-                                * and does not calculate rtt.
-                                * Force it here.
-                                */
-                               tcp_ack_update_rtt(sk, 0, 0);
-
                                if (tp->rx_opt.tstamp_ok)
                                        tp->advmss -= TCPOLEN_TSTAMP_ALIGNED;
 
index a7d6671..617dee3 100644 (file)
@@ -429,8 +429,8 @@ void tcp_v4_err(struct sk_buff *icmp_skb, u32 info)
                        break;
 
                icsk->icsk_backoff--;
-               inet_csk(sk)->icsk_rto = __tcp_set_rto(tp) <<
-                                        icsk->icsk_backoff;
+               inet_csk(sk)->icsk_rto = (tp->srtt ? __tcp_set_rto(tp) :
+                       TCP_TIMEOUT_INIT) << icsk->icsk_backoff;
                tcp_bound_rto(sk);
 
                skb = tcp_write_queue_head(sk);
@@ -1384,6 +1384,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
                isn = tcp_v4_init_sequence(skb);
        }
        tcp_rsk(req)->snt_isn = isn;
+       tcp_rsk(req)->snt_synack = tcp_time_stamp;
 
        if (tcp_v4_send_synack(sk, dst, req,
                               (struct request_values *)&tmp_ext) ||
@@ -1458,6 +1459,10 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
                newtp->advmss = tcp_sk(sk)->rx_opt.user_mss;
 
        tcp_initialize_rcv_mss(newsk);
+       if (tcp_rsk(req)->snt_synack)
+               tcp_valid_rtt_meas(newsk,
+                   tcp_time_stamp - tcp_rsk(req)->snt_synack);
+       newtp->total_retrans = req->retrans;
 
 #ifdef CONFIG_TCP_MD5SIG
        /* Copy over the MD5 key from the original socket */
@@ -1854,7 +1859,7 @@ static int tcp_v4_init_sock(struct sock *sk)
         * algorithms that we must have the following bandaid to talk
         * efficiently to them.  -DaveM
         */
-       tp->snd_cwnd = 2;
+       tp->snd_cwnd = TCP_INIT_CWND;
 
        /* See draft-stevens-tcpca-spec-01 for discussion of the
         * initialization of these values.
index 80b1f80..d2fe4e0 100644 (file)
@@ -486,7 +486,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
                 * algorithms that we must have the following bandaid to talk
                 * efficiently to them.  -DaveM
                 */
-               newtp->snd_cwnd = 2;
+               newtp->snd_cwnd = TCP_INIT_CWND;
                newtp->snd_cwnd_cnt = 0;
                newtp->bytes_acked = 0;
 
@@ -720,6 +720,10 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
                NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPDEFERACCEPTDROP);
                return NULL;
        }
+       if (tmp_opt.saw_tstamp && tmp_opt.rcv_tsecr)
+               tcp_rsk(req)->snt_synack = tmp_opt.rcv_tsecr;
+       else if (req->retrans) /* don't take RTT sample if retrans && ~TS */
+               tcp_rsk(req)->snt_synack = 0;
 
        /* OK, ACK is valid, create big socket and
         * feed this segment to it. It will repeat all
index 498b927..3e36942 100644 (file)
@@ -1559,6 +1559,11 @@ static int addrconf_ifid_sit(u8 *eui, struct net_device *dev)
        return -1;
 }
 
+static int addrconf_ifid_gre(u8 *eui, struct net_device *dev)
+{
+       return __ipv6_isatap_ifid(eui, *(__be32 *)dev->dev_addr);
+}
+
 static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
 {
        switch (dev->type) {
@@ -1572,6 +1577,8 @@ static int ipv6_generate_eui64(u8 *eui, struct net_device *dev)
                return addrconf_ifid_infiniband(eui, dev);
        case ARPHRD_SIT:
                return addrconf_ifid_sit(eui, dev);
+       case ARPHRD_IPGRE:
+               return addrconf_ifid_gre(eui, dev);
        }
        return -1;
 }
@@ -2423,6 +2430,29 @@ static void addrconf_sit_config(struct net_device *dev)
 }
 #endif
 
+#if defined(CONFIG_NET_IPGRE) || defined(CONFIG_NET_IPGRE_MODULE)
+static void addrconf_gre_config(struct net_device *dev)
+{
+       struct inet6_dev *idev;
+       struct in6_addr addr;
+
+       pr_info("ipv6: addrconf_gre_config(%s)\n", dev->name);
+
+       ASSERT_RTNL();
+
+       if ((idev = ipv6_find_idev(dev)) == NULL) {
+               printk(KERN_DEBUG "init gre: add_dev failed\n");
+               return;
+       }
+
+       ipv6_addr_set(&addr,  htonl(0xFE800000), 0, 0, 0);
+       addrconf_prefix_route(&addr, 64, dev, 0, 0);
+
+       if (!ipv6_generate_eui64(addr.s6_addr + 8, dev))
+               addrconf_add_linklocal(idev, &addr);
+}
+#endif
+
 static inline int
 ipv6_inherit_linklocal(struct inet6_dev *idev, struct net_device *link_dev)
 {
@@ -2538,6 +2568,11 @@ static int addrconf_notify(struct notifier_block *this, unsigned long event,
                case ARPHRD_SIT:
                        addrconf_sit_config(dev);
                        break;
+#endif
+#if defined(CONFIG_NET_IPGRE) || defined(CONFIG_NET_IPGRE_MODULE)
+               case ARPHRD_IPGRE:
+                       addrconf_gre_config(dev);
+                       break;
 #endif
                case ARPHRD_TUNNEL6:
                        addrconf_ip6_tnl_config(dev);
index 8b9644a..89d5bf8 100644 (file)
@@ -223,6 +223,7 @@ struct sock *cookie_v6_check(struct sock *sk, struct sk_buff *skb)
        ireq->wscale_ok         = tcp_opt.wscale_ok;
        ireq->tstamp_ok         = tcp_opt.saw_tstamp;
        req->ts_recent          = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsval : 0;
+       treq->snt_synack        = tcp_opt.saw_tstamp ? tcp_opt.rcv_tsecr : 0;
        treq->rcv_isn = ntohl(th->seq) - 1;
        treq->snt_isn = cookie;
 
index d1fd287..a1ef61a 100644 (file)
@@ -1341,6 +1341,7 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
        }
 have_isn:
        tcp_rsk(req)->snt_isn = isn;
+       tcp_rsk(req)->snt_synack = tcp_time_stamp;
 
        security_inet_conn_request(sk, skb, req);
 
@@ -1509,6 +1510,10 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
        tcp_sync_mss(newsk, dst_mtu(dst));
        newtp->advmss = dst_metric_advmss(dst);
        tcp_initialize_rcv_mss(newsk);
+       if (tcp_rsk(req)->snt_synack)
+               tcp_valid_rtt_meas(newsk,
+                   tcp_time_stamp - tcp_rsk(req)->snt_synack);
+       newtp->total_retrans = req->retrans;
 
        newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
        newinet->inet_rcv_saddr = LOOPBACK4_IPV6;
index 9c0d76c..89b0b2c 100644 (file)
@@ -100,6 +100,21 @@ void __ieee80211_stop_rx_ba_session(struct sta_info *sta, u16 tid,
        mutex_unlock(&sta->ampdu_mlme.mtx);
 }
 
+void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
+                                 const u8 *addr)
+{
+       struct ieee80211_sub_if_data *sdata = vif_to_sdata(vif);
+       struct sta_info *sta = sta_info_get(sdata, addr);
+       int i;
+
+       for (i = 0; i < STA_TID_NUM; i++)
+               if (ba_rx_bitmap & BIT(i))
+                       set_bit(i, sta->ampdu_mlme.tid_rx_stop_requested);
+
+       ieee80211_queue_work(&sta->local->hw, &sta->ampdu_mlme.work);
+}
+EXPORT_SYMBOL(ieee80211_stop_rx_ba_session);
+
 /*
  * After accepting the AddBA Request we activated a timer,
  * resetting it after each frame that arrives from the originator.
index be70c70..6e56c6e 100644 (file)
@@ -1554,6 +1554,19 @@ static int ieee80211_testmode_cmd(struct wiphy *wiphy, void *data, int len)
 
        return local->ops->testmode_cmd(&local->hw, data, len);
 }
+
+static int ieee80211_testmode_dump(struct wiphy *wiphy,
+                                  struct sk_buff *skb,
+                                  struct netlink_callback *cb,
+                                  void *data, int len)
+{
+       struct ieee80211_local *local = wiphy_priv(wiphy);
+
+       if (!local->ops->testmode_dump)
+               return -EOPNOTSUPP;
+
+       return local->ops->testmode_dump(&local->hw, skb, cb, data, len);
+}
 #endif
 
 int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
@@ -2134,6 +2147,7 @@ struct cfg80211_ops mac80211_config_ops = {
        .set_wds_peer = ieee80211_set_wds_peer,
        .rfkill_poll = ieee80211_rfkill_poll,
        CFG80211_TESTMODE_CMD(ieee80211_testmode_cmd)
+       CFG80211_TESTMODE_DUMP(ieee80211_testmode_dump)
        .set_power_mgmt = ieee80211_set_power_mgmt,
        .set_bitrate_mask = ieee80211_set_bitrate_mask,
        .remain_on_channel = ieee80211_remain_on_channel,
index 591add2..7cfc286 100644 (file)
@@ -140,6 +140,12 @@ void ieee80211_ba_session_work(struct work_struct *work)
                                sta, tid, WLAN_BACK_RECIPIENT,
                                WLAN_REASON_QSTA_TIMEOUT, true);
 
+               if (test_and_clear_bit(tid,
+                                      sta->ampdu_mlme.tid_rx_stop_requested))
+                       ___ieee80211_stop_rx_ba_session(
+                               sta, tid, WLAN_BACK_RECIPIENT,
+                               WLAN_REASON_UNSPECIFIED, true);
+
                tid_tx = sta->ampdu_mlme.tid_start_tx[tid];
                if (tid_tx) {
                        /*
index 2025af5..090b0ec 100644 (file)
@@ -775,9 +775,6 @@ struct ieee80211_local {
 
        int tx_headroom; /* required headroom for hardware/radiotap */
 
-       /* count for keys needing tailroom space allocation */
-       int crypto_tx_tailroom_needed_cnt;
-
        /* Tasklet and skb queue to process calls from IRQ mode. All frames
         * added to skb_queue will be processed, but frames in
         * skb_queue_unreliable may be dropped if the total length of these
index 49d4f86..dee30ae 100644 (file)
@@ -1145,6 +1145,10 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
                                + IEEE80211_ENCRYPT_HEADROOM;
        ndev->needed_tailroom = IEEE80211_ENCRYPT_TAILROOM;
 
+       ret = dev_alloc_name(ndev, ndev->name);
+       if (ret < 0)
+               goto fail;
+
        ieee80211_assign_perm_addr(local, ndev, type);
        memcpy(ndev->dev_addr, ndev->perm_addr, ETH_ALEN);
        SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
index 31afd71..f825e2f 100644 (file)
@@ -101,11 +101,6 @@ static int ieee80211_key_enable_hw_accel(struct ieee80211_key *key)
 
        if (!ret) {
                key->flags |= KEY_FLAG_UPLOADED_TO_HARDWARE;
-
-               if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-                     (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
-                       key->local->crypto_tx_tailroom_needed_cnt--;
-
                return 0;
        }
 
@@ -161,10 +156,6 @@ static void ieee80211_key_disable_hw_accel(struct ieee80211_key *key)
                          key->conf.keyidx, sta ? sta->addr : bcast_addr, ret);
 
        key->flags &= ~KEY_FLAG_UPLOADED_TO_HARDWARE;
-
-       if (!((key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_MMIC) ||
-             (key->conf.flags & IEEE80211_KEY_FLAG_GENERATE_IV)))
-               key->local->crypto_tx_tailroom_needed_cnt++;
 }
 
 void ieee80211_key_removed(struct ieee80211_key_conf *key_conf)
@@ -403,10 +394,8 @@ static void __ieee80211_key_destroy(struct ieee80211_key *key)
                ieee80211_aes_key_free(key->u.ccmp.tfm);
        if (key->conf.cipher == WLAN_CIPHER_SUITE_AES_CMAC)
                ieee80211_aes_cmac_key_free(key->u.aes_cmac.tfm);
-       if (key->local) {
+       if (key->local)
                ieee80211_debugfs_key_remove(key);
-               key->local->crypto_tx_tailroom_needed_cnt--;
-       }
 
        kfree(key);
 }
@@ -468,8 +457,6 @@ int ieee80211_key_link(struct ieee80211_key *key,
 
        ieee80211_debugfs_key_add(key);
 
-       key->local->crypto_tx_tailroom_needed_cnt++;
-
        ret = ieee80211_key_enable_hw_accel(key);
 
        mutex_unlock(&sdata->local->key_mtx);
@@ -511,12 +498,8 @@ void ieee80211_enable_keys(struct ieee80211_sub_if_data *sdata)
 
        mutex_lock(&sdata->local->key_mtx);
 
-       sdata->local->crypto_tx_tailroom_needed_cnt = 0;
-
-       list_for_each_entry(key, &sdata->key_list, list) {
-               sdata->local->crypto_tx_tailroom_needed_cnt++;
+       list_for_each_entry(key, &sdata->key_list, list)
                ieee80211_key_enable_hw_accel(key);
-       }
 
        mutex_unlock(&sdata->local->key_mtx);
 }
index 4f6b267..456cccf 100644 (file)
@@ -232,6 +232,9 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
                WARN_ON(!ieee80211_set_channel_type(local, sdata, channel_type));
        }
 
+       ieee80211_stop_queues_by_reason(&sdata->local->hw,
+                                       IEEE80211_QUEUE_STOP_REASON_CSA);
+
        /* channel_type change automatically detected */
        ieee80211_hw_config(local, 0);
 
@@ -245,6 +248,9 @@ static u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
                rcu_read_unlock();
        }
 
+       ieee80211_wake_queues_by_reason(&sdata->local->hw,
+                                       IEEE80211_QUEUE_STOP_REASON_CSA);
+
        ht_opmode = le16_to_cpu(hti->operation_mode);
 
        /* if bss configuration changed store the new one */
@@ -1089,6 +1095,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
                local->hw.conf.flags &= ~IEEE80211_CONF_PS;
                config_changed |= IEEE80211_CONF_CHANGE_PS;
        }
+       local->ps_sdata = NULL;
 
        ieee80211_hw_config(local, config_changed);
 
index 8adac67..58a8955 100644 (file)
@@ -532,12 +532,21 @@ minstrel_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
        mp->hw = hw;
        mp->update_interval = 100;
 
+#ifdef CONFIG_MAC80211_DEBUGFS
+       mp->fixed_rate_idx = (u32) -1;
+       mp->dbg_fixed_rate = debugfs_create_u32("fixed_rate_idx",
+                       S_IRUGO | S_IWUGO, debugfsdir, &mp->fixed_rate_idx);
+#endif
+
        return mp;
 }
 
 static void
 minstrel_free(void *priv)
 {
+#ifdef CONFIG_MAC80211_DEBUGFS
+       debugfs_remove(((struct minstrel_priv *)priv)->dbg_fixed_rate);
+#endif
        kfree(priv);
 }
 
index 0f5a833..5d278ec 100644 (file)
@@ -78,6 +78,18 @@ struct minstrel_priv {
        unsigned int update_interval;
        unsigned int lookaround_rate;
        unsigned int lookaround_rate_mrr;
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       /*
+        * enable fixed rate processing per RC
+        *   - write static index to debugfs:ieee80211/phyX/rc/fixed_rate_idx
+        *   - write -1 to enable RC processing again
+        *   - setting will be applied on next update
+        */
+       u32 fixed_rate_idx;
+       struct dentry *dbg_fixed_rate;
+#endif
+
 };
 
 struct minstrel_debugfs_info {
index 333b511..66a1eeb 100644 (file)
@@ -609,6 +609,13 @@ minstrel_ht_get_rate(void *priv, struct ieee80211_sta *sta, void *priv_sta,
 
        info->flags |= mi->tx_flags;
        sample_idx = minstrel_get_sample_rate(mp, mi);
+
+#ifdef CONFIG_MAC80211_DEBUGFS
+       /* use fixed index if set */
+       if (mp->fixed_rate_idx != -1)
+               sample_idx = mp->fixed_rate_idx;
+#endif
+
        if (sample_idx >= 0) {
                sample = true;
                minstrel_ht_set_rate(mp, mi, &ar[0], sample_idx,
index 27af672..58ffa7d 100644 (file)
@@ -15,7 +15,6 @@
 #include <linux/if_arp.h>
 #include <linux/rtnetlink.h>
 #include <linux/pm_qos_params.h>
-#include <linux/slab.h>
 #include <net/sch_generic.h>
 #include <linux/slab.h>
 #include <net/mac80211.h>
index c6ae871..a06d64e 100644 (file)
@@ -158,6 +158,8 @@ struct tid_ampdu_rx {
  * @work: work struct for starting/stopping aggregation
  * @tid_rx_timer_expired: bitmap indicating on which TIDs the
  *     RX timer expired until the work for it runs
+ * @tid_rx_stop_requested:  bitmap indicating which BA sessions per TID the
+ *     driver requested to close until the work for it runs
  * @mtx: mutex to protect all TX data (except non-NULL assignments
  *     to tid_tx[idx], which are protected by the sta spinlock)
  */
@@ -166,6 +168,7 @@ struct sta_ampdu_mlme {
        /* rx */
        struct tid_ampdu_rx __rcu *tid_rx[STA_TID_NUM];
        unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)];
+       unsigned long tid_rx_stop_requested[BITS_TO_LONGS(STA_TID_NUM)];
        /* tx */
        struct work_struct work;
        struct tid_ampdu_tx __rcu *tid_tx[STA_TID_NUM];
index 64e0f75..3104c84 100644 (file)
@@ -1480,7 +1480,12 @@ static int ieee80211_skb_resize(struct ieee80211_local *local,
 {
        int tail_need = 0;
 
-       if (may_encrypt && local->crypto_tx_tailroom_needed_cnt) {
+       /*
+        * This could be optimised, devices that do full hardware
+        * crypto (including TKIP MMIC) need no tailroom... But we
+        * have no drivers for such devices currently.
+        */
+       if (may_encrypt) {
                tail_need = IEEE80211_ENCRYPT_TAILROOM;
                tail_need -= skb_tailroom(skb);
                tail_need = max_t(int, tail_need, 0);
index 925f715..67f6749 100644 (file)
@@ -798,7 +798,12 @@ static int tpacket_rcv(struct sk_buff *skb, struct net_device *dev,
                        getnstimeofday(&ts);
                h.h2->tp_sec = ts.tv_sec;
                h.h2->tp_nsec = ts.tv_nsec;
-               h.h2->tp_vlan_tci = vlan_tx_tag_get(skb);
+               if (vlan_tx_tag_present(skb)) {
+                       h.h2->tp_vlan_tci = vlan_tx_tag_get(skb);
+                       status |= TP_STATUS_VLAN_VALID;
+               } else {
+                       h.h2->tp_vlan_tci = 0;
+               }
                hdrlen = sizeof(*h.h2);
                break;
        default:
@@ -969,7 +974,8 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
        struct sk_buff *skb;
        struct net_device *dev;
        __be16 proto;
-       int ifindex, err, reserve = 0;
+       bool need_rls_dev = false;
+       int err, reserve = 0;
        void *ph;
        struct sockaddr_ll *saddr = (struct sockaddr_ll *)msg->msg_name;
        int tp_len, size_max;
@@ -981,7 +987,7 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
 
        err = -EBUSY;
        if (saddr == NULL) {
-               ifindex = po->ifindex;
+               dev = po->prot_hook.dev;
                proto   = po->num;
                addr    = NULL;
        } else {
@@ -992,12 +998,12 @@ static int tpacket_snd(struct packet_sock *po, struct msghdr *msg)
                                        + offsetof(struct sockaddr_ll,
                                                sll_addr)))
                        goto out;
-               ifindex = saddr->sll_ifindex;
                proto   = saddr->sll_protocol;
                addr    = saddr->sll_addr;
+               dev = dev_get_by_index(sock_net(&po->sk), saddr->sll_ifindex);
+               need_rls_dev = true;
        }
 
-       dev = dev_get_by_index(sock_net(&po->sk), ifindex);
        err = -ENXIO;
        if (unlikely(dev == NULL))
                goto out;
@@ -1083,7 +1089,8 @@ out_status:
        __packet_set_status(po, ph, status);
        kfree_skb(skb);
 out_put:
-       dev_put(dev);
+       if (need_rls_dev)
+               dev_put(dev);
 out:
        mutex_unlock(&po->pg_vec_lock);
        return err;
@@ -1121,8 +1128,9 @@ static int packet_snd(struct socket *sock,
        struct sk_buff *skb;
        struct net_device *dev;
        __be16 proto;
+       bool need_rls_dev = false;
        unsigned char *addr;
-       int ifindex, err, reserve = 0;
+       int err, reserve = 0;
        struct virtio_net_hdr vnet_hdr = { 0 };
        int offset = 0;
        int vnet_hdr_len;
@@ -1134,7 +1142,7 @@ static int packet_snd(struct socket *sock,
         */
 
        if (saddr == NULL) {
-               ifindex = po->ifindex;
+               dev = po->prot_hook.dev;
                proto   = po->num;
                addr    = NULL;
        } else {
@@ -1143,13 +1151,12 @@ static int packet_snd(struct socket *sock,
                        goto out;
                if (msg->msg_namelen < (saddr->sll_halen + offsetof(struct sockaddr_ll, sll_addr)))
                        goto out;
-               ifindex = saddr->sll_ifindex;
                proto   = saddr->sll_protocol;
                addr    = saddr->sll_addr;
+               dev = dev_get_by_index(sock_net(sk), saddr->sll_ifindex);
+               need_rls_dev = true;
        }
 
-
-       dev = dev_get_by_index(sock_net(sk), ifindex);
        err = -ENXIO;
        if (dev == NULL)
                goto out_unlock;
@@ -1280,14 +1287,15 @@ static int packet_snd(struct socket *sock,
        if (err > 0 && (err = net_xmit_errno(err)) != 0)
                goto out_unlock;
 
-       dev_put(dev);
+       if (need_rls_dev)
+               dev_put(dev);
 
        return len;
 
 out_free:
        kfree_skb(skb);
 out_unlock:
-       if (dev)
+       if (dev && need_rls_dev)
                dev_put(dev);
 out:
        return err;
@@ -1337,6 +1345,10 @@ static int packet_release(struct socket *sock)
                __dev_remove_pack(&po->prot_hook);
                __sock_put(sk);
        }
+       if (po->prot_hook.dev) {
+               dev_put(po->prot_hook.dev);
+               po->prot_hook.dev = NULL;
+       }
        spin_unlock(&po->bind_lock);
 
        packet_flush_mclist(sk);
@@ -1390,6 +1402,8 @@ static int packet_do_bind(struct sock *sk, struct net_device *dev, __be16 protoc
 
        po->num = protocol;
        po->prot_hook.type = protocol;
+       if (po->prot_hook.dev)
+               dev_put(po->prot_hook.dev);
        po->prot_hook.dev = dev;
 
        po->ifindex = dev ? dev->ifindex : 0;
@@ -1434,10 +1448,8 @@ static int packet_bind_spkt(struct socket *sock, struct sockaddr *uaddr,
        strlcpy(name, uaddr->sa_data, sizeof(name));
 
        dev = dev_get_by_name(sock_net(sk), name);
-       if (dev) {
+       if (dev)
                err = packet_do_bind(sk, dev, pkt_sk(sk)->num);
-               dev_put(dev);
-       }
        return err;
 }
 
@@ -1465,8 +1477,6 @@ static int packet_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len
                        goto out;
        }
        err = packet_do_bind(sk, dev, sll->sll_protocol ? : pkt_sk(sk)->num);
-       if (dev)
-               dev_put(dev);
 
 out:
        return err;
@@ -1725,8 +1735,12 @@ static int packet_recvmsg(struct kiocb *iocb, struct socket *sock,
                aux.tp_snaplen = skb->len;
                aux.tp_mac = 0;
                aux.tp_net = skb_network_offset(skb);
-               aux.tp_vlan_tci = vlan_tx_tag_get(skb);
-
+               if (vlan_tx_tag_present(skb)) {
+                       aux.tp_vlan_tci = vlan_tx_tag_get(skb);
+                       aux.tp_status |= TP_STATUS_VLAN_VALID;
+               } else {
+                       aux.tp_vlan_tci = 0;
+               }
                put_cmsg(msg, SOL_PACKET, PACKET_AUXDATA, sizeof(aux), &aux);
        }
 
@@ -2231,6 +2245,8 @@ static int packet_notifier(struct notifier_block *this, unsigned long msg, void
                                }
                                if (msg == NETDEV_UNREGISTER) {
                                        po->ifindex = -1;
+                                       if (po->prot_hook.dev)
+                                               dev_put(po->prot_hook.dev);
                                        po->prot_hook.dev = NULL;
                                }
                                spin_unlock(&po->bind_lock);
index 4297d92..edfaaaf 100644 (file)
@@ -3,6 +3,7 @@
 
 #include <rdma/ib_verbs.h>
 #include <rdma/rdma_cm.h>
+#include <linux/interrupt.h>
 #include <linux/pci.h>
 #include <linux/slab.h>
 #include "rds.h"
index 9015192..04ce3b1 100644 (file)
@@ -1,6 +1,7 @@
 #ifndef _RDS_IW_H
 #define _RDS_IW_H
 
+#include <linux/interrupt.h>
 #include <rdma/ib_verbs.h>
 #include <rdma/rdma_cm.h>
 #include "rds.h"
index 3f08158..e25e490 100644 (file)
@@ -5,6 +5,7 @@
 #include <linux/module.h>
 #include <linux/slab.h>
 #include <linux/init.h>
+#include <linux/interrupt.h>
 #include <linux/string.h>
 #include <linux/errno.h>
 #include <linux/skbuff.h>
index 525f97c..dc16b90 100644 (file)
@@ -280,6 +280,8 @@ static struct sctp_association *sctp_association_init(struct sctp_association *a
        asoc->peer.asconf_capable = 0;
        if (sctp_addip_noauth)
                asoc->peer.asconf_capable = 1;
+       asoc->asconf_addr_del_pending = NULL;
+       asoc->src_out_of_asoc_ok = 0;
 
        /* Create an input queue.  */
        sctp_inq_init(&asoc->base.inqueue);
@@ -444,15 +446,11 @@ void sctp_association_free(struct sctp_association *asoc)
 
        asoc->peer.transport_count = 0;
 
-       /* Free any cached ASCONF_ACK chunk. */
-       sctp_assoc_free_asconf_acks(asoc);
-
-       /* Free the ASCONF queue. */
-       sctp_assoc_free_asconf_queue(asoc);
+       sctp_asconf_queue_teardown(asoc);
 
-       /* Free any cached ASCONF chunk. */
-       if (asoc->addip_last_asconf)
-               sctp_chunk_free(asoc->addip_last_asconf);
+       /* Free pending address space being deleted */
+       if (asoc->asconf_addr_del_pending != NULL)
+               kfree(asoc->asconf_addr_del_pending);
 
        /* AUTH - Free the endpoint shared keys */
        sctp_auth_destroy_keys(&asoc->endpoint_shared_keys);
@@ -1646,3 +1644,16 @@ struct sctp_chunk *sctp_assoc_lookup_asconf_ack(
 
        return NULL;
 }
+
+void sctp_asconf_queue_teardown(struct sctp_association *asoc)
+{
+       /* Free any cached ASCONF_ACK chunk. */
+       sctp_assoc_free_asconf_acks(asoc);
+
+       /* Free the ASCONF queue. */
+       sctp_assoc_free_asconf_queue(asoc);
+
+       /* Free any cached ASCONF chunk. */
+       if (asoc->addip_last_asconf)
+               sctp_chunk_free(asoc->addip_last_asconf);
+}
index 83e3011..17d1573 100644 (file)
@@ -534,6 +534,21 @@ int sctp_in_scope(const union sctp_addr *addr, sctp_scope_t scope)
        return 0;
 }
 
+int sctp_is_ep_boundall(struct sock *sk)
+{
+       struct sctp_bind_addr *bp;
+       struct sctp_sockaddr_entry *addr;
+
+       bp = &sctp_sk(sk)->ep->base.bind_addr;
+       if (sctp_list_single_entry(&bp->address_list)) {
+               addr = list_entry(bp->address_list.next,
+                                 struct sctp_sockaddr_entry, list);
+               if (sctp_is_any(sk, &addr->a))
+                       return 1;
+       }
+       return 0;
+}
+
 /********************************************************************
  * 3rd Level Abstractions
  ********************************************************************/
index 0bb0d7c..aabaee4 100644 (file)
@@ -112,6 +112,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
                        addr->valid = 1;
                        spin_lock_bh(&sctp_local_addr_lock);
                        list_add_tail_rcu(&addr->list, &sctp_local_addr_list);
+                       sctp_addr_wq_mgmt(addr, SCTP_ADDR_NEW);
                        spin_unlock_bh(&sctp_local_addr_lock);
                }
                break;
@@ -122,6 +123,7 @@ static int sctp_inet6addr_event(struct notifier_block *this, unsigned long ev,
                        if (addr->a.sa.sa_family == AF_INET6 &&
                                        ipv6_addr_equal(&addr->a.v6.sin6_addr,
                                                &ifa->addr)) {
+                               sctp_addr_wq_mgmt(addr, SCTP_ADDR_DEL);
                                found = 1;
                                addr->valid = 0;
                                list_del_rcu(&addr->list);
index 1c88c89..edc7532 100644 (file)
@@ -754,6 +754,16 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
         */
 
        list_for_each_entry_safe(chunk, tmp, &q->control_chunk_list, list) {
+               /* RFC 5061, 5.3
+                * F1) This means that until such time as the ASCONF
+                * containing the add is acknowledged, the sender MUST
+                * NOT use the new IP address as a source for ANY SCTP
+                * packet except on carrying an ASCONF Chunk.
+                */
+               if (asoc->src_out_of_asoc_ok &&
+                   chunk->chunk_hdr->type != SCTP_CID_ASCONF)
+                       continue;
+
                list_del_init(&chunk->list);
 
                /* Pick the right transport to use. */
@@ -881,6 +891,9 @@ static int sctp_outq_flush(struct sctp_outq *q, int rtx_timeout)
                }
        }
 
+       if (q->asoc->src_out_of_asoc_ok)
+               goto sctp_flush_out;
+
        /* Is it OK to send data chunks?  */
        switch (asoc->state) {
        case SCTP_STATE_COOKIE_ECHOED:
index 67380a2..ab5ded2 100644 (file)
@@ -503,7 +503,9 @@ static void sctp_v4_get_dst(struct sctp_transport *t, union sctp_addr *saddr,
                sctp_v4_dst_saddr(&dst_saddr, fl4, htons(bp->port));
                rcu_read_lock();
                list_for_each_entry_rcu(laddr, &bp->address_list, list) {
-                       if (!laddr->valid || (laddr->state != SCTP_ADDR_SRC))
+                       if (!laddr->valid || (laddr->state == SCTP_ADDR_DEL) ||
+                           (laddr->state != SCTP_ADDR_SRC &&
+                           !asoc->src_out_of_asoc_ok))
                                continue;
                        if (sctp_v4_cmp_addr(&dst_saddr, &laddr->a))
                                goto out_unlock;
@@ -623,6 +625,143 @@ static void sctp_v4_ecn_capable(struct sock *sk)
        INET_ECN_xmit(sk);
 }
 
+void sctp_addr_wq_timeout_handler(unsigned long arg)
+{
+       struct sctp_sockaddr_entry *addrw, *temp;
+       struct sctp_sock *sp;
+
+       spin_lock_bh(&sctp_addr_wq_lock);
+
+       list_for_each_entry_safe(addrw, temp, &sctp_addr_waitq, list) {
+               SCTP_DEBUG_PRINTK_IPADDR("sctp_addrwq_timo_handler: the first ent in wq %p is ",
+                   " for cmd %d at entry %p\n", &sctp_addr_waitq, &addrw->a, addrw->state,
+                   addrw);
+
+#if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE)
+               /* Now we send an ASCONF for each association */
+               /* Note. we currently don't handle link local IPv6 addressees */
+               if (addrw->a.sa.sa_family == AF_INET6) {
+                       struct in6_addr *in6;
+
+                       if (ipv6_addr_type(&addrw->a.v6.sin6_addr) &
+                           IPV6_ADDR_LINKLOCAL)
+                               goto free_next;
+
+                       in6 = (struct in6_addr *)&addrw->a.v6.sin6_addr;
+                       if (ipv6_chk_addr(&init_net, in6, NULL, 0) == 0 &&
+                           addrw->state == SCTP_ADDR_NEW) {
+                               unsigned long timeo_val;
+
+                               SCTP_DEBUG_PRINTK("sctp_timo_handler: this is on DAD, trying %d sec later\n",
+                                   SCTP_ADDRESS_TICK_DELAY);
+                               timeo_val = jiffies;
+                               timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY);
+                               mod_timer(&sctp_addr_wq_timer, timeo_val);
+                               break;
+                       }
+               }
+#endif
+               list_for_each_entry(sp, &sctp_auto_asconf_splist, auto_asconf_list) {
+                       struct sock *sk;
+
+                       sk = sctp_opt2sk(sp);
+                       /* ignore bound-specific endpoints */
+                       if (!sctp_is_ep_boundall(sk))
+                               continue;
+                       sctp_bh_lock_sock(sk);
+                       if (sctp_asconf_mgmt(sp, addrw) < 0)
+                               SCTP_DEBUG_PRINTK("sctp_addrwq_timo_handler: sctp_asconf_mgmt failed\n");
+                       sctp_bh_unlock_sock(sk);
+               }
+free_next:
+               list_del(&addrw->list);
+               kfree(addrw);
+       }
+       spin_unlock_bh(&sctp_addr_wq_lock);
+}
+
+static void sctp_free_addr_wq(void)
+{
+       struct sctp_sockaddr_entry *addrw;
+       struct sctp_sockaddr_entry *temp;
+
+       spin_lock_bh(&sctp_addr_wq_lock);
+       del_timer(&sctp_addr_wq_timer);
+       list_for_each_entry_safe(addrw, temp, &sctp_addr_waitq, list) {
+               list_del(&addrw->list);
+               kfree(addrw);
+       }
+       spin_unlock_bh(&sctp_addr_wq_lock);
+}
+
+/* lookup the entry for the same address in the addr_waitq
+ * sctp_addr_wq MUST be locked
+ */
+static struct sctp_sockaddr_entry *sctp_addr_wq_lookup(struct sctp_sockaddr_entry *addr)
+{
+       struct sctp_sockaddr_entry *addrw;
+
+       list_for_each_entry(addrw, &sctp_addr_waitq, list) {
+               if (addrw->a.sa.sa_family != addr->a.sa.sa_family)
+                       continue;
+               if (addrw->a.sa.sa_family == AF_INET) {
+                       if (addrw->a.v4.sin_addr.s_addr ==
+                           addr->a.v4.sin_addr.s_addr)
+                               return addrw;
+               } else if (addrw->a.sa.sa_family == AF_INET6) {
+                       if (ipv6_addr_equal(&addrw->a.v6.sin6_addr,
+                           &addr->a.v6.sin6_addr))
+                               return addrw;
+               }
+       }
+       return NULL;
+}
+
+void sctp_addr_wq_mgmt(struct sctp_sockaddr_entry *addr, int cmd)
+{
+       struct sctp_sockaddr_entry *addrw;
+       unsigned long timeo_val;
+
+       /* first, we check if an opposite message already exist in the queue.
+        * If we found such message, it is removed.
+        * This operation is a bit stupid, but the DHCP client attaches the
+        * new address after a couple of addition and deletion of that address
+        */
+
+       spin_lock_bh(&sctp_addr_wq_lock);
+       /* Offsets existing events in addr_wq */
+       addrw = sctp_addr_wq_lookup(addr);
+       if (addrw) {
+               if (addrw->state != cmd) {
+                       SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt offsets existing entry for %d ",
+                           " in wq %p\n", addrw->state, &addrw->a,
+                           &sctp_addr_waitq);
+                       list_del(&addrw->list);
+                       kfree(addrw);
+               }
+               spin_unlock_bh(&sctp_addr_wq_lock);
+               return;
+       }
+
+       /* OK, we have to add the new address to the wait queue */
+       addrw = kmemdup(addr, sizeof(struct sctp_sockaddr_entry), GFP_ATOMIC);
+       if (addrw == NULL) {
+               spin_unlock_bh(&sctp_addr_wq_lock);
+               return;
+       }
+       addrw->state = cmd;
+       list_add_tail(&addrw->list, &sctp_addr_waitq);
+       SCTP_DEBUG_PRINTK_IPADDR("sctp_addr_wq_mgmt add new entry for cmd:%d ",
+           " in wq %p\n", addrw->state, &addrw->a, &sctp_addr_waitq);
+
+       if (!timer_pending(&sctp_addr_wq_timer)) {
+               timeo_val = jiffies;
+               timeo_val += msecs_to_jiffies(SCTP_ADDRESS_TICK_DELAY);
+               mod_timer(&sctp_addr_wq_timer, timeo_val);
+       }
+       spin_unlock_bh(&sctp_addr_wq_lock);
+}
+
 /* Event handler for inet address addition/deletion events.
  * The sctp_local_addr_list needs to be protocted by a spin lock since
  * multiple notifiers (say IPv4 and IPv6) may be running at the same
@@ -650,6 +789,7 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
                        addr->valid = 1;
                        spin_lock_bh(&sctp_local_addr_lock);
                        list_add_tail_rcu(&addr->list, &sctp_local_addr_list);
+                       sctp_addr_wq_mgmt(addr, SCTP_ADDR_NEW);
                        spin_unlock_bh(&sctp_local_addr_lock);
                }
                break;
@@ -660,6 +800,7 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
                        if (addr->a.sa.sa_family == AF_INET &&
                                        addr->a.v4.sin_addr.s_addr ==
                                        ifa->ifa_local) {
+                               sctp_addr_wq_mgmt(addr, SCTP_ADDR_DEL);
                                found = 1;
                                addr->valid = 0;
                                list_del_rcu(&addr->list);
@@ -1242,6 +1383,7 @@ SCTP_STATIC __init int sctp_init(void)
        /* Disable ADDIP by default. */
        sctp_addip_enable = 0;
        sctp_addip_noauth = 0;
+       sctp_default_auto_asconf = 0;
 
        /* Enable PR-SCTP by default. */
        sctp_prsctp_enable = 1;
@@ -1266,6 +1408,13 @@ SCTP_STATIC __init int sctp_init(void)
        spin_lock_init(&sctp_local_addr_lock);
        sctp_get_local_addr_list();
 
+       /* Initialize the address event list */
+       INIT_LIST_HEAD(&sctp_addr_waitq);
+       INIT_LIST_HEAD(&sctp_auto_asconf_splist);
+       spin_lock_init(&sctp_addr_wq_lock);
+       sctp_addr_wq_timer.expires = 0;
+       setup_timer(&sctp_addr_wq_timer, sctp_addr_wq_timeout_handler, 0);
+
        status = sctp_v4_protosw_init();
 
        if (status)
@@ -1337,6 +1486,7 @@ SCTP_STATIC __exit void sctp_exit(void)
        /* Unregister with inet6/inet layers. */
        sctp_v6_del_protocol();
        sctp_v4_del_protocol();
+       sctp_free_addr_wq();
 
        /* Free the control endpoint.  */
        inet_ctl_sock_destroy(sctp_ctl_sock);
index 58eb27f..3363d37 100644 (file)
@@ -2768,6 +2768,7 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
        int                     addr_param_len = 0;
        int                     totallen = 0;
        int                     i;
+       int                     del_pickup = 0;
 
        /* Get total length of all the address parameters. */
        addr_buf = addrs;
@@ -2780,6 +2781,13 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
                totallen += addr_param_len;
 
                addr_buf += af->sockaddr_len;
+               if (asoc->asconf_addr_del_pending && !del_pickup) {
+                       /* reuse the parameter length from the same scope one */
+                       totallen += paramlen;
+                       totallen += addr_param_len;
+                       del_pickup = 1;
+                       SCTP_DEBUG_PRINTK("mkasconf_update_ip: picked same-scope del_pending addr, totallen for all addresses is %d\n", totallen);
+               }
        }
 
        /* Create an asconf chunk with the required length. */
@@ -2802,6 +2810,17 @@ struct sctp_chunk *sctp_make_asconf_update_ip(struct sctp_association *asoc,
 
                addr_buf += af->sockaddr_len;
        }
+       if (flags == SCTP_PARAM_ADD_IP && del_pickup) {
+               addr = asoc->asconf_addr_del_pending;
+               af = sctp_get_af_specific(addr->v4.sin_family);
+               addr_param_len = af->to_addr_param(addr, &addr_param);
+               param.param_hdr.type = SCTP_PARAM_DEL_IP;
+               param.param_hdr.length = htons(paramlen + addr_param_len);
+               param.crr_id = i;
+
+               sctp_addto_chunk(retval, paramlen, &param);
+               sctp_addto_chunk(retval, addr_param_len, &addr_param);
+       }
        return retval;
 }
 
@@ -3014,7 +3033,7 @@ static __be16 sctp_process_asconf_param(struct sctp_association *asoc,
                 * an Error Cause TLV set to the new error code 'Request to
                 * Delete Source IP Address'
                 */
-               if (sctp_cmp_addr_exact(sctp_source(asconf), &addr))
+               if (sctp_cmp_addr_exact(&asconf->source, &addr))
                        return SCTP_ERROR_DEL_SRC_IP;
 
                /* Section 4.2.2
@@ -3224,6 +3243,11 @@ static void sctp_asconf_param_success(struct sctp_association *asoc,
        case SCTP_PARAM_DEL_IP:
                local_bh_disable();
                sctp_del_bind_addr(bp, &addr);
+               if (asoc->asconf_addr_del_pending != NULL &&
+                   sctp_cmp_addr_exact(asoc->asconf_addr_del_pending, &addr)) {
+                       kfree(asoc->asconf_addr_del_pending);
+                       asoc->asconf_addr_del_pending = NULL;
+               }
                local_bh_enable();
                list_for_each_entry(transport, &asoc->peer.transport_addr_list,
                                transports) {
@@ -3381,6 +3405,9 @@ int sctp_process_asconf_ack(struct sctp_association *asoc,
                asconf_len -= length;
        }
 
+       if (no_err && asoc->src_out_of_asoc_ok)
+               asoc->src_out_of_asoc_ok = 0;
+
        /* Free the cached last sent asconf chunk. */
        list_del_init(&asconf->transmitted_list);
        sctp_chunk_free(asconf);
index d612ca1..534c2e5 100644 (file)
@@ -1670,6 +1670,9 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
                case SCTP_CMD_SEND_NEXT_ASCONF:
                        sctp_cmd_send_asconf(asoc);
                        break;
+               case SCTP_CMD_PURGE_ASCONF_QUEUE:
+                       sctp_asconf_queue_teardown(asoc);
+                       break;
                default:
                        pr_warn("Impossible command: %u, %p\n",
                                cmd->verb, cmd->obj.ptr);
index 7f4a4f8..a297283 100644 (file)
@@ -1718,11 +1718,21 @@ static sctp_disposition_t sctp_sf_do_dupcook_a(const struct sctp_endpoint *ep,
                return SCTP_DISPOSITION_CONSUME;
        }
 
-       /* For now, fail any unsent/unacked data.  Consider the optional
-        * choice of resending of this data.
+       /* For now, stop pending T3-rtx and SACK timers, fail any unsent/unacked
+        * data. Consider the optional choice of resending of this data.
         */
+       sctp_add_cmd_sf(commands, SCTP_CMD_T3_RTX_TIMERS_STOP, SCTP_NULL());
+       sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
+                       SCTP_TO(SCTP_EVENT_TIMEOUT_SACK));
        sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_OUTQUEUE, SCTP_NULL());
 
+       /* Stop pending T4-rto timer, teardown ASCONF queue, ASCONF-ACK queue
+        * and ASCONF-ACK cache.
+        */
+       sctp_add_cmd_sf(commands, SCTP_CMD_TIMER_STOP,
+                       SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
+       sctp_add_cmd_sf(commands, SCTP_CMD_PURGE_ASCONF_QUEUE, SCTP_NULL());
+
        repl = sctp_make_cookie_ack(new_asoc, chunk);
        if (!repl)
                goto nomem;
index 6766913..e7e1b14 100644 (file)
@@ -583,10 +583,6 @@ static int sctp_send_asconf_add_ip(struct sock             *sk,
                        goto out;
                }
 
-               retval = sctp_send_asconf(asoc, chunk);
-               if (retval)
-                       goto out;
-
                /* Add the new addresses to the bind address list with
                 * use_as_src set to 0.
                 */
@@ -599,6 +595,23 @@ static int sctp_send_asconf_add_ip(struct sock             *sk,
                                                    SCTP_ADDR_NEW, GFP_ATOMIC);
                        addr_buf += af->sockaddr_len;
                }
+               if (asoc->src_out_of_asoc_ok) {
+                       struct sctp_transport *trans;
+
+                       list_for_each_entry(trans,
+                           &asoc->peer.transport_addr_list, transports) {
+                               /* Clear the source and route cache */
+                               dst_release(trans->dst);
+                               trans->cwnd = min(4*asoc->pathmtu, max_t(__u32,
+                                   2*asoc->pathmtu, 4380));
+                               trans->ssthresh = asoc->peer.i.a_rwnd;
+                               trans->rto = asoc->rto_initial;
+                               trans->rtt = trans->srtt = trans->rttvar = 0;
+                               sctp_transport_route(trans, NULL,
+                                   sctp_sk(asoc->base.sk));
+                       }
+               }
+               retval = sctp_send_asconf(asoc, chunk);
        }
 
 out:
@@ -715,7 +728,9 @@ static int sctp_send_asconf_del_ip(struct sock              *sk,
        struct sctp_sockaddr_entry *saddr;
        int                     i;
        int                     retval = 0;
+       int                     stored = 0;
 
+       chunk = NULL;
        if (!sctp_addip_enable)
                return retval;
 
@@ -766,8 +781,33 @@ static int sctp_send_asconf_del_ip(struct sock             *sk,
                bp = &asoc->base.bind_addr;
                laddr = sctp_find_unmatch_addr(bp, (union sctp_addr *)addrs,
                                               addrcnt, sp);
-               if (!laddr)
-                       continue;
+               if ((laddr == NULL) && (addrcnt == 1)) {
+                       if (asoc->asconf_addr_del_pending)
+                               continue;
+                       asoc->asconf_addr_del_pending =
+                           kzalloc(sizeof(union sctp_addr), GFP_ATOMIC);
+                       asoc->asconf_addr_del_pending->sa.sa_family =
+                                   addrs->sa_family;
+                       asoc->asconf_addr_del_pending->v4.sin_port =
+                                   htons(bp->port);
+                       if (addrs->sa_family == AF_INET) {
+                               struct sockaddr_in *sin;
+
+                               sin = (struct sockaddr_in *)addrs;
+                               asoc->asconf_addr_del_pending->v4.sin_addr.s_addr = sin->sin_addr.s_addr;
+                       } else if (addrs->sa_family == AF_INET6) {
+                               struct sockaddr_in6 *sin6;
+
+                               sin6 = (struct sockaddr_in6 *)addrs;
+                               ipv6_addr_copy(&asoc->asconf_addr_del_pending->v6.sin6_addr, &sin6->sin6_addr);
+                       }
+                       SCTP_DEBUG_PRINTK_IPADDR("send_asconf_del_ip: keep the last address asoc: %p ",
+                           " at %p\n", asoc, asoc->asconf_addr_del_pending,
+                           asoc->asconf_addr_del_pending);
+                       asoc->src_out_of_asoc_ok = 1;
+                       stored = 1;
+                       goto skip_mkasconf;
+               }
 
                /* We do not need RCU protection throughout this loop
                 * because this is done under a socket lock from the
@@ -780,6 +820,7 @@ static int sctp_send_asconf_del_ip(struct sock              *sk,
                        goto out;
                }
 
+skip_mkasconf:
                /* Reset use_as_src flag for the addresses in the bind address
                 * list that are to be deleted.
                 */
@@ -805,12 +846,37 @@ static int sctp_send_asconf_del_ip(struct sock            *sk,
                                             sctp_sk(asoc->base.sk));
                }
 
+               if (stored)
+                       /* We don't need to transmit ASCONF */
+                       continue;
                retval = sctp_send_asconf(asoc, chunk);
        }
 out:
        return retval;
 }
 
+/* set addr events to assocs in the endpoint.  ep and addr_wq must be locked */
+int sctp_asconf_mgmt(struct sctp_sock *sp, struct sctp_sockaddr_entry *addrw)
+{
+       struct sock *sk = sctp_opt2sk(sp);
+       union sctp_addr *addr;
+       struct sctp_af *af;
+
+       /* It is safe to write port space in caller. */
+       addr = &addrw->a;
+       addr->v4.sin_port = htons(sp->ep->base.bind_addr.port);
+       af = sctp_get_af_specific(addr->sa.sa_family);
+       if (!af)
+               return -EINVAL;
+       if (sctp_verify_addr(sk, addr, af->sockaddr_len))
+               return -EINVAL;
+
+       if (addrw->state == SCTP_ADDR_NEW)
+               return sctp_send_asconf_add_ip(sk, (struct sockaddr *)addr, 1);
+       else
+               return sctp_send_asconf_del_ip(sk, (struct sockaddr *)addr, 1);
+}
+
 /* Helper for tunneling sctp_bindx() requests through sctp_setsockopt()
  *
  * API 8.1
@@ -3334,6 +3400,46 @@ static int sctp_setsockopt_del_key(struct sock *sk,
 
 }
 
+/*
+ * 8.1.23 SCTP_AUTO_ASCONF
+ *
+ * This option will enable or disable the use of the automatic generation of
+ * ASCONF chunks to add and delete addresses to an existing association.  Note
+ * that this option has two caveats namely: a) it only affects sockets that
+ * are bound to all addresses available to the SCTP stack, and b) the system
+ * administrator may have an overriding control that turns the ASCONF feature
+ * off no matter what setting the socket option may have.
+ * This option expects an integer boolean flag, where a non-zero value turns on
+ * the option, and a zero value turns off the option.
+ * Note. In this implementation, socket operation overrides default parameter
+ * being set by sysctl as well as FreeBSD implementation
+ */
+static int sctp_setsockopt_auto_asconf(struct sock *sk, char __user *optval,
+                                       unsigned int optlen)
+{
+       int val;
+       struct sctp_sock *sp = sctp_sk(sk);
+
+       if (optlen < sizeof(int))
+               return -EINVAL;
+       if (get_user(val, (int __user *)optval))
+               return -EFAULT;
+       if (!sctp_is_ep_boundall(sk) && val)
+               return -EINVAL;
+       if ((val && sp->do_auto_asconf) || (!val && !sp->do_auto_asconf))
+               return 0;
+
+       if (val == 0 && sp->do_auto_asconf) {
+               list_del(&sp->auto_asconf_list);
+               sp->do_auto_asconf = 0;
+       } else if (val && !sp->do_auto_asconf) {
+               list_add_tail(&sp->auto_asconf_list,
+                   &sctp_auto_asconf_splist);
+               sp->do_auto_asconf = 1;
+       }
+       return 0;
+}
+
 
 /* API 6.2 setsockopt(), getsockopt()
  *
@@ -3481,6 +3587,9 @@ SCTP_STATIC int sctp_setsockopt(struct sock *sk, int level, int optname,
        case SCTP_AUTH_DELETE_KEY:
                retval = sctp_setsockopt_del_key(sk, optval, optlen);
                break;
+       case SCTP_AUTO_ASCONF:
+               retval = sctp_setsockopt_auto_asconf(sk, optval, optlen);
+               break;
        default:
                retval = -ENOPROTOOPT;
                break;
@@ -3763,6 +3872,12 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
        local_bh_disable();
        percpu_counter_inc(&sctp_sockets_allocated);
        sock_prot_inuse_add(sock_net(sk), sk->sk_prot, 1);
+       if (sctp_default_auto_asconf) {
+               list_add_tail(&sp->auto_asconf_list,
+                   &sctp_auto_asconf_splist);
+               sp->do_auto_asconf = 1;
+       } else
+               sp->do_auto_asconf = 0;
        local_bh_enable();
 
        return 0;
@@ -3771,13 +3886,17 @@ SCTP_STATIC int sctp_init_sock(struct sock *sk)
 /* Cleanup any SCTP per socket resources.  */
 SCTP_STATIC void sctp_destroy_sock(struct sock *sk)
 {
-       struct sctp_endpoint *ep;
+       struct sctp_sock *sp;
 
        SCTP_DEBUG_PRINTK("sctp_destroy_sock(sk: %p)\n", sk);
 
        /* Release our hold on the endpoint. */
-       ep = sctp_sk(sk)->ep;
-       sctp_endpoint_free(ep);
+       sp = sctp_sk(sk);
+       if (sp->do_auto_asconf) {
+               sp->do_auto_asconf = 0;
+               list_del(&sp->auto_asconf_list);
+       }
+       sctp_endpoint_free(sp->ep);
        local_bh_disable();
        percpu_counter_dec(&sctp_sockets_allocated);
        sock_prot_inuse_add(sock_net(sk), sk->sk_prot, -1);
@@ -5276,6 +5395,28 @@ static int sctp_getsockopt_assoc_number(struct sock *sk, int len,
        return 0;
 }
 
+/*
+ * 8.1.23 SCTP_AUTO_ASCONF
+ * See the corresponding setsockopt entry as description
+ */
+static int sctp_getsockopt_auto_asconf(struct sock *sk, int len,
+                                  char __user *optval, int __user *optlen)
+{
+       int val = 0;
+
+       if (len < sizeof(int))
+               return -EINVAL;
+
+       len = sizeof(int);
+       if (sctp_sk(sk)->do_auto_asconf && sctp_is_ep_boundall(sk))
+               val = 1;
+       if (put_user(len, optlen))
+               return -EFAULT;
+       if (copy_to_user(optval, &val, len))
+               return -EFAULT;
+       return 0;
+}
+
 /*
  * 8.2.6. Get the Current Identifiers of Associations
  *        (SCTP_GET_ASSOC_ID_LIST)
@@ -5460,6 +5601,9 @@ SCTP_STATIC int sctp_getsockopt(struct sock *sk, int level, int optname,
        case SCTP_GET_ASSOC_ID_LIST:
                retval = sctp_getsockopt_assoc_ids(sk, len, optval, optlen);
                break;
+       case SCTP_AUTO_ASCONF:
+               retval = sctp_getsockopt_auto_asconf(sk, len, optval, optlen);
+               break;
        default:
                retval = -ENOPROTOOPT;
                break;
@@ -6512,6 +6656,7 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
        struct sk_buff *skb, *tmp;
        struct sctp_ulpevent *event;
        struct sctp_bind_hashbucket *head;
+       struct list_head tmplist;
 
        /* Migrate socket buffer sizes and all the socket level options to the
         * new socket.
@@ -6519,7 +6664,12 @@ static void sctp_sock_migrate(struct sock *oldsk, struct sock *newsk,
        newsk->sk_sndbuf = oldsk->sk_sndbuf;
        newsk->sk_rcvbuf = oldsk->sk_rcvbuf;
        /* Brute force copy old sctp opt. */
-       inet_sk_copy_descendant(newsk, oldsk);
+       if (oldsp->do_auto_asconf) {
+               memcpy(&tmplist, &newsp->auto_asconf_list, sizeof(tmplist));
+               inet_sk_copy_descendant(newsk, oldsk);
+               memcpy(&newsp->auto_asconf_list, &tmplist, sizeof(tmplist));
+       } else
+               inet_sk_copy_descendant(newsk, oldsk);
 
        /* Restore the ep value that was overwritten with the above structure
         * copy.
index 50cb57f..6b39529 100644 (file)
@@ -182,6 +182,13 @@ static ctl_table sctp_table[] = {
                .mode           = 0644,
                .proc_handler   = proc_dointvec,
        },
+       {
+               .procname       = "default_auto_asconf",
+               .data           = &sctp_default_auto_asconf,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = proc_dointvec,
+       },
        {
                .procname       = "prsctp_enable",
                .data           = &sctp_prsctp_enable,
index cd6e4aa..727e506 100644 (file)
@@ -626,7 +626,7 @@ rpcauth_refreshcred(struct rpc_task *task)
                if (err < 0)
                        goto out;
                cred = task->tk_rqstp->rq_cred;
-       };
+       }
        dprintk("RPC: %5u refreshing %s cred %p\n",
                task->tk_pid, cred->cr_auth->au_ops->au_name, cred);
 
index c3c232a..a385430 100644 (file)
@@ -42,6 +42,7 @@
 #include <linux/sunrpc/svc_xprt.h>
 #include <linux/sunrpc/debug.h>
 #include <linux/sunrpc/rpc_rdma.h>
+#include <linux/interrupt.h>
 #include <linux/sched.h>
 #include <linux/slab.h>
 #include <linux/spinlock.h>
index 80f8da3..28236ba 100644 (file)
@@ -47,6 +47,7 @@
  *  o buffer memory
  */
 
+#include <linux/interrupt.h>
 #include <linux/pci.h> /* for Tavor hack below */
 #include <linux/slab.h>
 
index ec83f41..70cbc8c 100644 (file)
@@ -3406,12 +3406,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        i = 0;
        if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) {
                nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS], tmp) {
+                       request->ssids[i].ssid_len = nla_len(attr);
                        if (request->ssids[i].ssid_len > IEEE80211_MAX_SSID_LEN) {
                                err = -EINVAL;
                                goto out_free;
                        }
                        memcpy(request->ssids[i].ssid, nla_data(attr), nla_len(attr));
-                       request->ssids[i].ssid_len = nla_len(attr);
                        i++;
                }
        }
@@ -3572,6 +3572,7 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
        if (info->attrs[NL80211_ATTR_SCAN_SSIDS]) {
                nla_for_each_nested(attr, info->attrs[NL80211_ATTR_SCAN_SSIDS],
                                    tmp) {
+                       request->ssids[i].ssid_len = nla_len(attr);
                        if (request->ssids[i].ssid_len >
                            IEEE80211_MAX_SSID_LEN) {
                                err = -EINVAL;
@@ -3579,7 +3580,6 @@ static int nl80211_start_sched_scan(struct sk_buff *skb,
                        }
                        memcpy(request->ssids[i].ssid, nla_data(attr),
                               nla_len(attr));
-                       request->ssids[i].ssid_len = nla_len(attr);
                        i++;
                }
        }
@@ -3754,10 +3754,6 @@ static int nl80211_send_survey(struct sk_buff *msg, u32 pid, u32 seq,
        void *hdr;
        struct nlattr *infoattr;
 
-       /* Survey without a channel doesn't make sense */
-       if (!survey->channel)
-               return -EINVAL;
-
        hdr = nl80211hdr_put(msg, pid, seq, flags,
                             NL80211_CMD_NEW_SURVEY_RESULTS);
        if (!hdr)
@@ -3820,6 +3816,8 @@ static int nl80211_dump_survey(struct sk_buff *skb,
        }
 
        while (1) {
+               struct ieee80211_channel *chan;
+
                res = dev->ops->dump_survey(&dev->wiphy, netdev, survey_idx,
                                            &survey);
                if (res == -ENOENT)
@@ -3827,6 +3825,19 @@ static int nl80211_dump_survey(struct sk_buff *skb,
                if (res)
                        goto out_err;
 
+               /* Survey without a channel doesn't make sense */
+               if (!survey.channel) {
+                       res = -EINVAL;
+                       goto out;
+               }
+
+               chan = ieee80211_get_channel(&dev->wiphy,
+                                            survey.channel->center_freq);
+               if (!chan || chan->flags & IEEE80211_CHAN_DISABLED) {
+                       survey_idx++;
+                       continue;
+               }
+
                if (nl80211_send_survey(skb,
                                NETLINK_CB(cb->skb).pid,
                                cb->nlh->nlmsg_seq, NLM_F_MULTI,
@@ -4361,6 +4372,93 @@ static int nl80211_testmode_do(struct sk_buff *skb, struct genl_info *info)
        return err;
 }
 
+static int nl80211_testmode_dump(struct sk_buff *skb,
+                                struct netlink_callback *cb)
+{
+       struct cfg80211_registered_device *dev;
+       int err;
+       long phy_idx;
+       void *data = NULL;
+       int data_len = 0;
+
+       if (cb->args[0]) {
+               /*
+                * 0 is a valid index, but not valid for args[0],
+                * so we need to offset by 1.
+                */
+               phy_idx = cb->args[0] - 1;
+       } else {
+               err = nlmsg_parse(cb->nlh, GENL_HDRLEN + nl80211_fam.hdrsize,
+                                 nl80211_fam.attrbuf, nl80211_fam.maxattr,
+                                 nl80211_policy);
+               if (err)
+                       return err;
+               if (!nl80211_fam.attrbuf[NL80211_ATTR_WIPHY])
+                       return -EINVAL;
+               phy_idx = nla_get_u32(nl80211_fam.attrbuf[NL80211_ATTR_WIPHY]);
+               if (nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA])
+                       cb->args[1] =
+                               (long)nl80211_fam.attrbuf[NL80211_ATTR_TESTDATA];
+       }
+
+       if (cb->args[1]) {
+               data = nla_data((void *)cb->args[1]);
+               data_len = nla_len((void *)cb->args[1]);
+       }
+
+       mutex_lock(&cfg80211_mutex);
+       dev = cfg80211_rdev_by_wiphy_idx(phy_idx);
+       if (!dev) {
+               mutex_unlock(&cfg80211_mutex);
+               return -ENOENT;
+       }
+       cfg80211_lock_rdev(dev);
+       mutex_unlock(&cfg80211_mutex);
+
+       if (!dev->ops->testmode_dump) {
+               err = -EOPNOTSUPP;
+               goto out_err;
+       }
+
+       while (1) {
+               void *hdr = nl80211hdr_put(skb, NETLINK_CB(cb->skb).pid,
+                                          cb->nlh->nlmsg_seq, NLM_F_MULTI,
+                                          NL80211_CMD_TESTMODE);
+               struct nlattr *tmdata;
+
+               if (nla_put_u32(skb, NL80211_ATTR_WIPHY, dev->wiphy_idx) < 0) {
+                       genlmsg_cancel(skb, hdr);
+                       break;
+               }
+
+               tmdata = nla_nest_start(skb, NL80211_ATTR_TESTDATA);
+               if (!tmdata) {
+                       genlmsg_cancel(skb, hdr);
+                       break;
+               }
+               err = dev->ops->testmode_dump(&dev->wiphy, skb, cb,
+                                             data, data_len);
+               nla_nest_end(skb, tmdata);
+
+               if (err == -ENOBUFS || err == -ENOENT) {
+                       genlmsg_cancel(skb, hdr);
+                       break;
+               } else if (err) {
+                       genlmsg_cancel(skb, hdr);
+                       goto out_err;
+               }
+
+               genlmsg_end(skb, hdr);
+       }
+
+       err = skb->len;
+       /* see above */
+       cb->args[0] = phy_idx + 1;
+ out_err:
+       cfg80211_unlock_rdev(dev);
+       return err;
+}
+
 static struct sk_buff *
 __cfg80211_testmode_alloc_skb(struct cfg80211_registered_device *rdev,
                              int approxlen, u32 pid, u32 seq, gfp_t gfp)
@@ -5658,6 +5756,7 @@ static struct genl_ops nl80211_ops[] = {
        {
                .cmd = NL80211_CMD_TESTMODE,
                .doit = nl80211_testmode_do,
+               .dumpit = nl80211_testmode_dump,
                .policy = nl80211_policy,
                .flags = GENL_ADMIN_PERM,
                .internal_flags = NL80211_FLAG_NEED_WIPHY |
index 73a441d..7a6c676 100644 (file)
@@ -267,13 +267,35 @@ static bool is_bss(struct cfg80211_bss *a,
        return memcmp(ssidie + 2, ssid, ssid_len) == 0;
 }
 
+static bool is_mesh_bss(struct cfg80211_bss *a)
+{
+       const u8 *ie;
+
+       if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability))
+               return false;
+
+       ie = cfg80211_find_ie(WLAN_EID_MESH_ID,
+                             a->information_elements,
+                             a->len_information_elements);
+       if (!ie)
+               return false;
+
+       ie = cfg80211_find_ie(WLAN_EID_MESH_CONFIG,
+                             a->information_elements,
+                             a->len_information_elements);
+       if (!ie)
+               return false;
+
+       return true;
+}
+
 static bool is_mesh(struct cfg80211_bss *a,
                    const u8 *meshid, size_t meshidlen,
                    const u8 *meshcfg)
 {
        const u8 *ie;
 
-       if (!WLAN_CAPABILITY_IS_MBSS(a->capability))
+       if (!WLAN_CAPABILITY_IS_STA_BSS(a->capability))
                return false;
 
        ie = cfg80211_find_ie(WLAN_EID_MESH_ID,
@@ -311,7 +333,7 @@ static int cmp_bss(struct cfg80211_bss *a,
        if (a->channel != b->channel)
                return b->channel->center_freq - a->channel->center_freq;
 
-       if (WLAN_CAPABILITY_IS_MBSS(a->capability | b->capability)) {
+       if (is_mesh_bss(a) && is_mesh_bss(b)) {
                r = cmp_ies(WLAN_EID_MESH_ID,
                            a->information_elements,
                            a->len_information_elements,
@@ -457,7 +479,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
                    struct cfg80211_internal_bss *res)
 {
        struct cfg80211_internal_bss *found = NULL;
-       const u8 *meshid, *meshcfg;
 
        /*
         * The reference to "res" is donated to this function.
@@ -470,22 +491,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
 
        res->ts = jiffies;
 
-       if (WLAN_CAPABILITY_IS_MBSS(res->pub.capability)) {
-               /* must be mesh, verify */
-               meshid = cfg80211_find_ie(WLAN_EID_MESH_ID,
-                                         res->pub.information_elements,
-                                         res->pub.len_information_elements);
-               meshcfg = cfg80211_find_ie(WLAN_EID_MESH_CONFIG,
-                                          res->pub.information_elements,
-                                          res->pub.len_information_elements);
-               if (!meshid || !meshcfg ||
-                   meshcfg[1] != sizeof(struct ieee80211_meshconf_ie)) {
-                       /* bogus mesh */
-                       kref_put(&res->ref, bss_release);
-                       return NULL;
-               }
-       }
-
        spin_lock_bh(&dev->bss_lock);
 
        found = rb_find_bss(dev, res);
index ae3a698..ec1bcec 100644 (file)
@@ -593,7 +593,8 @@ static int apparmor_setprocattr(struct task_struct *task, char *name,
                        sa.aad.op = OP_SETPROCATTR;
                        sa.aad.info = name;
                        sa.aad.error = -EINVAL;
-                       return aa_audit(AUDIT_APPARMOR_DENIED, NULL, GFP_KERNEL,
+                       return aa_audit(AUDIT_APPARMOR_DENIED,
+                                       __aa_current_profile(), GFP_KERNEL,
                                        &sa, NULL);
                }
        } else if (strcmp(name, "exec") == 0) {
index f8c663d..d68ea53 100644 (file)
@@ -262,14 +262,14 @@ static int v253_hangup(struct tty_struct *tty)
 }
 
 /* Line discipline .receive_buf() */
-static unsigned int v253_receive(struct tty_struct *tty,
-                                const unsigned char *cp, char *fp, int count)
+static void v253_receive(struct tty_struct *tty,
+                               const unsigned char *cp, char *fp, int count)
 {
        struct snd_soc_codec *codec = tty->disc_data;
        struct cx20442_priv *cx20442;
 
        if (!codec)
-               return count;
+               return;
 
        cx20442 = snd_soc_codec_get_drvdata(codec);
 
@@ -281,8 +281,6 @@ static unsigned int v253_receive(struct tty_struct *tty,
                codec->hw_write = (hw_write_t)tty->ops->write;
                codec->card->pop_time = 1;
        }
-
-       return count;
 }
 
 /* Line discipline .write_wakeup() */
index 1fd29b2..cef28e6 100755 (executable)
@@ -788,7 +788,7 @@ sub wait_for_input
 
 sub reboot_to {
     if ($reboot_type eq "grub") {
-       run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch; reboot)'";
+       run_ssh "'(echo \"savedefault --default=$grub_number --once\" | grub --batch && reboot)'";
        return;
     }
 
@@ -1480,7 +1480,7 @@ sub process_config_ignore {
        or dodie "Failed to read $config";
 
     while (<IN>) {
-       if (/^(.*?(CONFIG\S*)(=.*| is not set))/) {
+       if (/^((CONFIG\S*)=.*)/) {
            $config_ignore{$2} = $1;
        }
     }
@@ -1638,7 +1638,7 @@ sub run_config_bisect {
        if (!$found) {
            # try the other half
            doprint "Top half produced no set configs, trying bottom half\n";
-           @tophalf = @start_list[$half .. $#start_list];
+           @tophalf = @start_list[$half + 1 .. $#start_list];
            create_config @tophalf;
            read_current_config \%current_config;
            foreach my $config (@tophalf) {
@@ -1690,7 +1690,7 @@ sub run_config_bisect {
        # remove half the configs we are looking at and see if
        # they are good.
        $half = int($#start_list / 2);
-    } while ($half > 0);
+    } while ($#start_list > 0);
 
     # we found a single config, try it again unless we are running manually
 
index df0c6d2..74d3331 100644 (file)
@@ -197,6 +197,14 @@ const struct option longopts[] = {
                .name = "help",
                .val = 'h',
        },
+       {
+               .name = "event-idx",
+               .val = 'E',
+       },
+       {
+               .name = "no-event-idx",
+               .val = 'e',
+       },
        {
                .name = "indirect",
                .val = 'I',
@@ -211,13 +219,17 @@ const struct option longopts[] = {
 
 static void help()
 {
-       fprintf(stderr, "Usage: virtio_test [--help] [--no-indirect]\n");
+       fprintf(stderr, "Usage: virtio_test [--help]"
+               " [--no-indirect]"
+               " [--no-event-idx]"
+               "\n");
 }
 
 int main(int argc, char **argv)
 {
        struct vdev_info dev;
-       unsigned long long features = 1ULL << VIRTIO_RING_F_INDIRECT_DESC;
+       unsigned long long features = (1ULL << VIRTIO_RING_F_INDIRECT_DESC) |
+               (1ULL << VIRTIO_RING_F_EVENT_IDX);
        int o;
 
        for (;;) {
@@ -228,6 +240,9 @@ int main(int argc, char **argv)
                case '?':
                        help();
                        exit(2);
+               case 'e':
+                       features &= ~(1ULL << VIRTIO_RING_F_EVENT_IDX);
+                       break;
                case 'h':
                        help();
                        goto done;