]> pilppa.org Git - linux-2.6-omap-h63xx.git/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6
authorDavid S. Miller <davem@davemloft.net>
Tue, 24 Mar 2009 20:24:36 +0000 (13:24 -0700)
committerDavid S. Miller <davem@davemloft.net>
Tue, 24 Mar 2009 20:24:36 +0000 (13:24 -0700)
1307 files changed:
CREDITS
Documentation/ABI/testing/sysfs-bus-pci
Documentation/ABI/testing/sysfs-firmware-memmap
Documentation/DocBook/Makefile
Documentation/DocBook/device-drivers.tmpl [new file with mode: 0644]
Documentation/DocBook/kernel-api.tmpl
Documentation/PCI/PCIEBUS-HOWTO.txt
Documentation/cgroups/cgroups.txt
Documentation/cgroups/cpusets.txt
Documentation/driver-model/device.txt
Documentation/dvb/README.flexcop [deleted file]
Documentation/dvb/technisat.txt
Documentation/filesystems/proc.txt
Documentation/filesystems/sysfs.txt
Documentation/hwmon/hpfall.c [new file with mode: 0644]
Documentation/hwmon/lis3lv02d
Documentation/kernel-parameters.txt
Documentation/networking/ip-sysctl.txt
Documentation/networking/ipv6.txt [new file with mode: 0644]
Documentation/networking/ixgbe.txt [new file with mode: 0644]
Documentation/networking/rds.txt [new file with mode: 0644]
Documentation/scsi/cxgb3i.txt
Documentation/tracers/mmiotrace.txt
MAINTAINERS
Makefile
README
arch/alpha/kernel/process.c
arch/alpha/kernel/smp.c
arch/arm/configs/at91sam9260ek_defconfig
arch/arm/configs/at91sam9261ek_defconfig
arch/arm/configs/at91sam9263ek_defconfig
arch/arm/configs/at91sam9rlek_defconfig
arch/arm/configs/qil-a9260_defconfig
arch/arm/kernel/elf.c
arch/arm/kernel/setup.c
arch/arm/mach-at91/at91cap9_devices.c
arch/arm/mach-at91/at91sam9260_devices.c
arch/arm/mach-at91/at91sam9261_devices.c
arch/arm/mach-at91/at91sam9263_devices.c
arch/arm/mach-at91/at91sam9rl_devices.c
arch/arm/mach-at91/gpio.c
arch/arm/mach-at91/include/mach/board.h
arch/arm/mach-at91/pm.c
arch/arm/mach-davinci/board-evm.c
arch/arm/mach-davinci/clock.c
arch/arm/mach-davinci/usb.c
arch/arm/mach-ep93xx/include/mach/gesbc9312.h [deleted file]
arch/arm/mach-ep93xx/include/mach/hardware.h
arch/arm/mach-kirkwood/common.c
arch/arm/mach-kirkwood/irq.c
arch/arm/mach-kirkwood/rd88f6281-setup.c
arch/arm/mach-mv78xx0/irq.c
arch/arm/mach-omap2/board-ldp.c
arch/arm/mach-omap2/clock.c
arch/arm/mach-orion5x/common.c
arch/arm/mach-orion5x/irq.c
arch/arm/mach-orion5x/rd88f5181l-fxo-setup.c
arch/arm/mach-orion5x/rd88f5181l-ge-setup.c
arch/arm/mach-orion5x/rd88f6183ap-ge-setup.c
arch/arm/mach-orion5x/wrt350n-v2-setup.c
arch/arm/mach-rpc/riscpc.c
arch/arm/mm/abort-ev6.S
arch/arm/mm/mmu.c
arch/arm/plat-orion/gpio.c
arch/arm/plat-orion/include/plat/gpio.h
arch/arm/plat-s3c64xx/irq-eint.c
arch/avr32/mach-at32ap/include/mach/board.h
arch/ia64/Kconfig
arch/ia64/configs/xen_domu_defconfig [new file with mode: 0644]
arch/ia64/include/asm/kvm.h
arch/ia64/include/asm/mmzone.h
arch/ia64/include/asm/sn/bte.h
arch/ia64/kernel/iosapic.c
arch/ia64/kernel/smpboot.c
arch/ia64/kernel/unwind.c
arch/ia64/kvm/kvm-ia64.c
arch/ia64/kvm/process.c
arch/ia64/mm/numa.c
arch/ia64/sn/kernel/bte.c
arch/ia64/xen/Kconfig
arch/ia64/xen/xen_pv_ops.c
arch/m68k/atari/ataints.c
arch/m68k/atari/atakeyb.c
arch/m68k/atari/config.c
arch/m68k/atari/debug.c
arch/m68k/atari/time.c
arch/m68k/include/asm/atarihw.h
arch/m68k/include/asm/atariints.h
arch/m68knommu/platform/520x/config.c
arch/m68knommu/platform/523x/config.c
arch/m68knommu/platform/5272/config.c
arch/m68knommu/platform/527x/config.c
arch/m68knommu/platform/528x/config.c
arch/m68knommu/platform/532x/config.c
arch/mips/Kconfig
arch/mips/alchemy/common/time.c
arch/mips/include/asm/seccomp.h
arch/mips/kernel/irq.c
arch/mips/kernel/linux32.c
arch/mips/kernel/scall32-o32.S
arch/mips/kernel/scall64-64.S
arch/mips/kernel/scall64-n32.S
arch/mips/kernel/scall64-o32.S
arch/mips/kernel/signal.c
arch/mips/kernel/signal32.c
arch/mips/kernel/syscall.c
arch/mips/mm/cache.c
arch/mn10300/Kconfig
arch/mn10300/unit-asb2305/pci.c
arch/powerpc/include/asm/compat.h
arch/powerpc/include/asm/pgtable-4k.h
arch/powerpc/include/asm/pgtable-64k.h
arch/powerpc/include/asm/pgtable-ppc32.h
arch/powerpc/include/asm/seccomp.h
arch/powerpc/kernel/align.c
arch/powerpc/kvm/powerpc.c
arch/powerpc/lib/copyuser_64.S
arch/powerpc/lib/memcpy_64.S
arch/powerpc/mm/numa.c
arch/powerpc/platforms/86xx/gef_sbc610.c
arch/powerpc/platforms/ps3/mm.c
arch/powerpc/sysdev/ppc4xx_pci.c
arch/s390/crypto/aes_s390.c
arch/s390/include/asm/cputime.h
arch/s390/include/asm/setup.h
arch/s390/kernel/setup.c
arch/s390/kvm/kvm-s390.c
arch/sh/boards/board-ap325rxa.c
arch/sh/kernel/cpu/sh2a/clock-sh7201.c
arch/sparc/include/asm/compat.h
arch/sparc/include/asm/seccomp.h
arch/sparc/kernel/chmc.c
arch/um/drivers/vde_user.c
arch/x86/Kconfig
arch/x86/Kconfig.debug
arch/x86/include/asm/iomap.h
arch/x86/include/asm/kvm.h
arch/x86/include/asm/mmzone_32.h
arch/x86/include/asm/mmzone_64.h
arch/x86/include/asm/page.h
arch/x86/include/asm/paravirt.h
arch/x86/include/asm/seccomp_32.h
arch/x86/include/asm/seccomp_64.h
arch/x86/kernel/acpi/wakeup_64.S
arch/x86/kernel/apic.c
arch/x86/kernel/apm_32.c
arch/x86/kernel/cpu/cpufreq/powernow-k8.c
arch/x86/kernel/cpu/mcheck/mce_64.c
arch/x86/kernel/cpu/mcheck/mce_amd_64.c
arch/x86/kernel/cpu/mcheck/mce_intel_64.c
arch/x86/kernel/hpet.c
arch/x86/kernel/olpc.c
arch/x86/kernel/paravirt.c
arch/x86/kernel/process_32.c
arch/x86/kernel/ptrace.c
arch/x86/kernel/time_64.c
arch/x86/kernel/traps.c
arch/x86/kernel/vmiclock_32.c
arch/x86/kvm/i8254.c
arch/x86/kvm/irq.c
arch/x86/kvm/irq.h
arch/x86/kvm/lapic.c
arch/x86/kvm/lapic.h
arch/x86/kvm/mmu.c
arch/x86/kvm/svm.c
arch/x86/kvm/vmx.c
arch/x86/kvm/x86.c
arch/x86/mach-default/setup.c
arch/x86/mach-voyager/setup.c
arch/x86/mach-voyager/voyager_smp.c
arch/x86/mm/init_64.c
arch/x86/mm/iomap_32.c
arch/x86/mm/ioremap.c
arch/x86/mm/kmmio.c
arch/x86/mm/numa_64.c
arch/x86/mm/pageattr.c
arch/x86/mm/pat.c
arch/x86/mm/testmmiotrace.c
arch/x86/oprofile/op_model_ppro.c
arch/x86/xen/enlighten.c
block/blk-merge.c
block/blk-timeout.c
block/blktrace.c
block/bsg.c
block/genhd.c
crypto/ahash.c
crypto/api.c
crypto/lrw.c
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/battery.c
drivers/acpi/ec.c
drivers/ata/libata-sff.c
drivers/ata/pata_amd.c
drivers/ata/pata_it821x.c
drivers/ata/pata_legacy.c
drivers/ata/pata_via.c
drivers/ata/sata_mv.c
drivers/ata/sata_nv.c
drivers/atm/firestream.c
drivers/atm/iphase.c
drivers/atm/lanai.c
drivers/atm/solos-attrlist.c [new file with mode: 0644]
drivers/atm/solos-pci.c
drivers/base/base.h
drivers/base/dd.c
drivers/base/power/main.c
drivers/base/sys.c
drivers/block/aoe/aoe.h
drivers/block/aoe/aoedev.c
drivers/block/aoe/aoenet.c
drivers/block/ataflop.c
drivers/block/cciss.c
drivers/block/floppy.c
drivers/block/paride/pg.c
drivers/block/xen-blkfront.c
drivers/bluetooth/bfusb.c
drivers/bluetooth/bt3c_cs.c
drivers/bluetooth/btusb.c
drivers/bluetooth/hci_h4.c
drivers/bluetooth/hci_ll.c
drivers/char/scc.h
drivers/char/sx.c
drivers/crypto/ixp4xx_crypto.c
drivers/crypto/padlock-aes.c
drivers/crypto/padlock-sha.c
drivers/dca/dca-sysfs.c
drivers/dma/dmaengine.c
drivers/dma/dw_dmac.c
drivers/dma/dw_dmac_regs.h
drivers/dma/iop-adma.c
drivers/dma/mv_xor.c
drivers/firmware/memmap.c
drivers/gpu/drm/Kconfig
drivers/gpu/drm/drm_bufs.c
drivers/gpu/drm/drm_crtc.c
drivers/gpu/drm/drm_crtc_helper.c
drivers/gpu/drm/drm_edid.c
drivers/gpu/drm/drm_fops.c
drivers/gpu/drm/drm_gem.c
drivers/gpu/drm/drm_irq.c
drivers/gpu/drm/drm_lock.c
drivers/gpu/drm/drm_stub.c
drivers/gpu/drm/i915/i915_dma.c
drivers/gpu/drm/i915/i915_drv.c
drivers/gpu/drm/i915/i915_drv.h
drivers/gpu/drm/i915/i915_gem.c
drivers/gpu/drm/i915/i915_gem_tiling.c
drivers/gpu/drm/i915/i915_irq.c
drivers/gpu/drm/i915/intel_bios.c
drivers/gpu/drm/i915/intel_display.c
drivers/gpu/drm/i915/intel_fb.c
drivers/gpu/drm/i915/intel_lvds.c
drivers/gpu/drm/i915/intel_sdvo.c
drivers/gpu/drm/i915/intel_tv.c
drivers/gpu/drm/radeon/radeon_cp.c
drivers/hid/hid-core.c
drivers/hid/hid-ids.h
drivers/hid/hidraw.c
drivers/hwmon/f71882fg.c
drivers/hwmon/hp_accel.c
drivers/hwmon/lis3lv02d.c
drivers/hwmon/lis3lv02d.h
drivers/hwmon/vt1211.c
drivers/hwmon/w83627ehf.c
drivers/i2c/busses/i2c-acorn.c
drivers/i2c/busses/i2c-amd8111.c
drivers/i2c/busses/i2c-ixp2000.c
drivers/i2c/busses/i2c-mv64xxx.c
drivers/i2c/busses/i2c-pxa.c
drivers/i2c/busses/scx200_i2c.c
drivers/i2c/i2c-core.c
drivers/i2c/i2c-dev.c
drivers/ide/Kconfig
drivers/ide/amd74xx.c
drivers/ide/atiixp.c
drivers/ide/ide-cd.c
drivers/ide/ide-cd.h
drivers/ide/ide-gd.c
drivers/ide/ide-gd.h
drivers/ide/ide-tape.c
drivers/ide/ide.c
drivers/ide/it821x.c
drivers/ieee1394/dma.h
drivers/ieee1394/ieee1394_core.c
drivers/ieee1394/ieee1394_transactions.c
drivers/ieee1394/ieee1394_transactions.h
drivers/ieee1394/iso.h
drivers/ieee1394/nodemgr.c
drivers/ieee1394/nodemgr.h
drivers/infiniband/hw/amso1100/c2.c
drivers/infiniband/hw/amso1100/c2.h
drivers/infiniband/hw/amso1100/c2_provider.c
drivers/infiniband/hw/nes/nes_nic.c
drivers/infiniband/ulp/ipoib/ipoib_main.c
drivers/input/keyboard/atkbd.c
drivers/input/keyboard/bf54x-keys.c
drivers/input/keyboard/corgikbd.c
drivers/input/keyboard/omap-keypad.c
drivers/input/keyboard/spitzkbd.c
drivers/input/mouse/Kconfig
drivers/input/mouse/elantech.c
drivers/input/mouse/pxa930_trkball.c
drivers/input/mouse/synaptics.c
drivers/input/serio/ambakmi.c
drivers/input/serio/gscps2.c
drivers/input/serio/sa1111ps2.c
drivers/input/touchscreen/atmel_tsadcc.c
drivers/input/touchscreen/corgi_ts.c
drivers/input/touchscreen/tsc2007.c
drivers/input/touchscreen/usbtouchscreen.c
drivers/isdn/act2000/act2000_isa.c
drivers/isdn/capi/capi.c
drivers/isdn/capi/kcapi_proc.c
drivers/isdn/gigaset/Kconfig
drivers/isdn/gigaset/bas-gigaset.c
drivers/isdn/gigaset/usb-gigaset.c
drivers/isdn/hardware/eicon/debug.c
drivers/isdn/hardware/eicon/message.c
drivers/isdn/hisax/callc.c
drivers/isdn/hisax/config.c
drivers/isdn/hisax/hfcscard.c
drivers/isdn/hisax/hisax.h
drivers/isdn/hisax/isdnl1.c
drivers/isdn/hisax/sedlbauer.c
drivers/isdn/hisax/teles0.c
drivers/isdn/hisax/teles3.c
drivers/isdn/mISDN/timerdev.c
drivers/isdn/pcbit/layer2.c
drivers/isdn/sc/shmem.c
drivers/md/dm-io.c
drivers/md/dm-kcopyd.c
drivers/md/md.c
drivers/md/raid1.c
drivers/md/raid10.c
drivers/media/common/tuners/tuner-simple.c
drivers/media/dvb/Kconfig
drivers/media/dvb/Makefile
drivers/media/dvb/b2c2/flexcop-hw-filter.c
drivers/media/dvb/b2c2/flexcop-pci.c
drivers/media/dvb/b2c2/flexcop.c
drivers/media/dvb/dvb-core/dmxdev.c
drivers/media/dvb/dvb-core/dvb_demux.c
drivers/media/dvb/firewire/Kconfig [new file with mode: 0644]
drivers/media/dvb/firewire/Makefile [new file with mode: 0644]
drivers/media/dvb/firewire/firedtv-1394.c [new file with mode: 0644]
drivers/media/dvb/firewire/firedtv-avc.c [new file with mode: 0644]
drivers/media/dvb/firewire/firedtv-ci.c [new file with mode: 0644]
drivers/media/dvb/firewire/firedtv-dvb.c [new file with mode: 0644]
drivers/media/dvb/firewire/firedtv-fe.c [new file with mode: 0644]
drivers/media/dvb/firewire/firedtv-rc.c [new file with mode: 0644]
drivers/media/dvb/firewire/firedtv.h [new file with mode: 0644]
drivers/media/radio/radio-si470x.c
drivers/media/video/em28xx/em28xx-audio.c
drivers/media/video/gspca/gspca.c
drivers/media/video/ivtv/ivtv-ioctl.c
drivers/media/video/pxa_camera.c
drivers/media/video/sh_mobile_ceu_camera.c
drivers/media/video/uvc/uvc_status.c
drivers/message/fusion/mptbase.c
drivers/mfd/htc-egpio.c
drivers/mfd/pcf50633-core.c
drivers/mfd/sm501.c
drivers/mfd/twl4030-core.c
drivers/mfd/wm8350-core.c
drivers/mfd/wm8350-regmap.c
drivers/misc/hpilo.c
drivers/mmc/card/block.c
drivers/mmc/card/mmc_test.c
drivers/mmc/host/atmel-mci.c
drivers/mmc/host/omap_hsmmc.c
drivers/mmc/host/s3cmci.c
drivers/mmc/host/sdhci-pci.c
drivers/mmc/host/sdhci.c
drivers/mmc/host/sdhci.h
drivers/mtd/chips/map_rom.c
drivers/mtd/devices/slram.c
drivers/mtd/lpddr/Kconfig
drivers/mtd/maps/Kconfig
drivers/mtd/maps/bfin-async-flash.c
drivers/mtd/maps/ck804xrom.c
drivers/mtd/maps/physmap.c
drivers/mtd/nand/atmel_nand.c
drivers/mtd/nand/orion_nand.c
drivers/net/3c59x.c
drivers/net/8139cp.c
drivers/net/8139too.c
drivers/net/Kconfig
drivers/net/Makefile
drivers/net/a2065.c
drivers/net/acenic.c
drivers/net/arm/Makefile
drivers/net/arm/etherh.c
drivers/net/arm/ks8695net.c
drivers/net/atl1c/Makefile [new file with mode: 0644]
drivers/net/atl1c/atl1c.h [new file with mode: 0644]
drivers/net/atl1c/atl1c_ethtool.c [new file with mode: 0644]
drivers/net/atl1c/atl1c_hw.c [new file with mode: 0644]
drivers/net/atl1c/atl1c_hw.h [new file with mode: 0644]
drivers/net/atl1c/atl1c_main.c [new file with mode: 0644]
drivers/net/b44.c
drivers/net/benet/Kconfig [new file with mode: 0644]
drivers/net/benet/Makefile [new file with mode: 0644]
drivers/net/benet/be.h [new file with mode: 0644]
drivers/net/benet/be_cmds.c [new file with mode: 0644]
drivers/net/benet/be_cmds.h [new file with mode: 0644]
drivers/net/benet/be_ethtool.c [new file with mode: 0644]
drivers/net/benet/be_hw.h [new file with mode: 0644]
drivers/net/benet/be_main.c [new file with mode: 0644]
drivers/net/bmac.c
drivers/net/bnx2.c
drivers/net/bnx2x.h
drivers/net/bnx2x_dump.h [new file with mode: 0644]
drivers/net/bnx2x_init.h
drivers/net/bnx2x_init_values.h
drivers/net/bnx2x_link.c
drivers/net/bnx2x_main.c
drivers/net/bnx2x_reg.h
drivers/net/bonding/bond_main.c
drivers/net/chelsio/sge.c
drivers/net/cxgb3/adapter.h
drivers/net/cxgb3/common.h
drivers/net/cxgb3/cxgb3_main.c
drivers/net/cxgb3/regs.h
drivers/net/cxgb3/sge.c
drivers/net/cxgb3/t3_hw.c
drivers/net/cxgb3/version.h
drivers/net/cxgb3/xgmac.c
drivers/net/dm9000.c
drivers/net/dnet.c [new file with mode: 0644]
drivers/net/dnet.h [new file with mode: 0644]
drivers/net/e100.c
drivers/net/e1000/e1000_main.c
drivers/net/e1000e/82571.c
drivers/net/e1000e/e1000.h
drivers/net/e1000e/ethtool.c
drivers/net/e1000e/hw.h
drivers/net/e1000e/netdev.c
drivers/net/ehea/ehea.h
drivers/net/ehea/ehea_main.c
drivers/net/eql.c
drivers/net/fealnx.c
drivers/net/fec.c
drivers/net/forcedeth.c
drivers/net/fsl_pq_mdio.c
drivers/net/gianfar.c
drivers/net/gianfar.h
drivers/net/gianfar_mii.c [deleted file]
drivers/net/hamachi.c
drivers/net/hamradio/bpqether.c
drivers/net/hp-plus.c
drivers/net/ibm_newemac/core.c
drivers/net/igb/Makefile
drivers/net/igb/e1000_82575.c
drivers/net/igb/e1000_82575.h
drivers/net/igb/e1000_defines.h
drivers/net/igb/e1000_hw.h
drivers/net/igb/e1000_mac.c
drivers/net/igb/e1000_mac.h
drivers/net/igb/e1000_mbx.c [new file with mode: 0644]
drivers/net/igb/e1000_mbx.h [new file with mode: 0644]
drivers/net/igb/e1000_regs.h
drivers/net/igb/igb.h
drivers/net/igb/igb_ethtool.c
drivers/net/igb/igb_main.c
drivers/net/irda/ali-ircc.c
drivers/net/irda/irda-usb.c
drivers/net/irda/kingsun-sir.c
drivers/net/irda/ks959-sir.c
drivers/net/irda/ksdazzle-sir.c
drivers/net/irda/mcs7780.c
drivers/net/irda/nsc-ircc.c
drivers/net/irda/sir_dev.c
drivers/net/irda/smsc-ircc2.c
drivers/net/irda/stir4200.c
drivers/net/irda/via-ircc.c
drivers/net/irda/vlsi_ir.c
drivers/net/irda/w83977af_ir.c
drivers/net/ixgb/ixgb_main.c
drivers/net/ixgbe/Makefile
drivers/net/ixgbe/ixgbe.h
drivers/net/ixgbe/ixgbe_82598.c
drivers/net/ixgbe/ixgbe_82599.c [new file with mode: 0644]
drivers/net/ixgbe/ixgbe_common.c
drivers/net/ixgbe/ixgbe_common.h
drivers/net/ixgbe/ixgbe_dcb.c
drivers/net/ixgbe/ixgbe_dcb.h
drivers/net/ixgbe/ixgbe_dcb_82599.c [new file with mode: 0644]
drivers/net/ixgbe/ixgbe_dcb_82599.h [new file with mode: 0644]
drivers/net/ixgbe/ixgbe_dcb_nl.c
drivers/net/ixgbe/ixgbe_ethtool.c
drivers/net/ixgbe/ixgbe_main.c
drivers/net/ixgbe/ixgbe_phy.c
drivers/net/ixgbe/ixgbe_phy.h
drivers/net/ixgbe/ixgbe_type.h
drivers/net/jme.c
drivers/net/jme.h
drivers/net/macvlan.c
drivers/net/mv643xx_eth.c
drivers/net/myri_sbus.c
drivers/net/natsemi.c
drivers/net/ne2k-pci.c
drivers/net/netxen/Makefile
drivers/net/netxen/netxen_nic.h
drivers/net/netxen/netxen_nic_ctx.c
drivers/net/netxen/netxen_nic_ethtool.c
drivers/net/netxen/netxen_nic_hdr.h
drivers/net/netxen/netxen_nic_hw.c
drivers/net/netxen/netxen_nic_hw.h
drivers/net/netxen/netxen_nic_init.c
drivers/net/netxen/netxen_nic_main.c
drivers/net/netxen/netxen_nic_niu.c
drivers/net/netxen/netxen_nic_phan_reg.h
drivers/net/niu.c
drivers/net/niu.h
drivers/net/ns83820.c
drivers/net/pcmcia/3c574_cs.c
drivers/net/pcmcia/3c589_cs.c
drivers/net/pcmcia/axnet_cs.c
drivers/net/pcmcia/fmvj18x_cs.c
drivers/net/pcmcia/nmclan_cs.c
drivers/net/pcmcia/pcnet_cs.c
drivers/net/pcmcia/smc91c92_cs.c
drivers/net/pcmcia/xirc2ps_cs.c
drivers/net/phy/mdio_bus.c
drivers/net/phy/phy.c
drivers/net/ppp_async.c
drivers/net/ppp_generic.c
drivers/net/ppp_synctty.c
drivers/net/pppoe.c
drivers/net/qlge/qlge.h
drivers/net/qlge/qlge_dbg.c
drivers/net/qlge/qlge_ethtool.c
drivers/net/qlge/qlge_main.c
drivers/net/qlge/qlge_mpi.c
drivers/net/r8169.c
drivers/net/rionet.c
drivers/net/sfc/boards.c
drivers/net/sfc/boards.h
drivers/net/sfc/efx.c
drivers/net/sfc/efx.h
drivers/net/sfc/ethtool.c
drivers/net/sfc/falcon.c
drivers/net/sfc/falcon.h
drivers/net/sfc/falcon_io.h
drivers/net/sfc/mdio_10g.c
drivers/net/sfc/mdio_10g.h
drivers/net/sfc/mtd.c
drivers/net/sfc/net_driver.h
drivers/net/sfc/phy.h
drivers/net/sfc/sfe4001.c
drivers/net/sfc/tenxpress.c
drivers/net/sfc/tx.c
drivers/net/sfc/workarounds.h
drivers/net/sfc/xfp_phy.c
drivers/net/sh_eth.c
drivers/net/sh_eth.h
drivers/net/sis900.c
drivers/net/smc911x.h
drivers/net/smsc911x.c
drivers/net/smsc911x.h
drivers/net/smsc9420.c
drivers/net/smsc9420.h
drivers/net/spider_net.c
drivers/net/starfire.c
drivers/net/sunbmac.c
drivers/net/sundance.c
drivers/net/sungem.c
drivers/net/sunlance.c
drivers/net/sunqe.c
drivers/net/sunvnet.c
drivers/net/tehuti.c
drivers/net/tehuti.h
drivers/net/tehuti_fw.h [deleted file]
drivers/net/tg3.c
drivers/net/tg3.h
drivers/net/tokenring/tmspci.c
drivers/net/tulip/de4x5.c
drivers/net/tulip/dmfe.c
drivers/net/tulip/interrupt.c
drivers/net/tulip/tulip.h
drivers/net/tulip/tulip_core.c
drivers/net/tulip/uli526x.c
drivers/net/tulip/winbond-840.c
drivers/net/typhoon-firmware.h [deleted file]
drivers/net/typhoon.c
drivers/net/ucc_geth.c
drivers/net/ucc_geth.h
drivers/net/usb/asix.c
drivers/net/usb/catc.c
drivers/net/usb/cdc_ether.c
drivers/net/usb/dm9601.c
drivers/net/usb/hso.c
drivers/net/usb/mcs7830.c
drivers/net/usb/rndis_host.c
drivers/net/usb/rtl8150.c
drivers/net/usb/smsc95xx.c
drivers/net/usb/usbnet.c
drivers/net/usb/zaurus.c
drivers/net/veth.c
drivers/net/via-rhine.c
drivers/net/via-velocity.c
drivers/net/virtio_net.c
drivers/net/wan/cosa.c
drivers/net/wan/cycx_x25.c
drivers/net/wan/dlci.c
drivers/net/wan/hdlc.c
drivers/net/wan/lapbether.c
drivers/net/wan/sbni.c
drivers/net/wan/x25_asy.c
drivers/net/wan/x25_asy.h
drivers/net/wimax/i2400m/Makefile
drivers/net/wimax/i2400m/control.c
drivers/net/wimax/i2400m/debug-levels.h
drivers/net/wimax/i2400m/driver.c
drivers/net/wimax/i2400m/fw.c
drivers/net/wimax/i2400m/i2400m.h
drivers/net/wimax/i2400m/netdev.c
drivers/net/wimax/i2400m/rx.c
drivers/net/wimax/i2400m/sdio.c
drivers/net/wimax/i2400m/sysfs.c [new file with mode: 0644]
drivers/net/wimax/i2400m/usb-notif.c
drivers/net/wimax/i2400m/usb.c
drivers/net/wireless/Kconfig
drivers/net/wireless/Makefile
drivers/net/wireless/airo.c
drivers/net/wireless/airo_cs.c
drivers/net/wireless/at76c50x-usb.c [new file with mode: 0644]
drivers/net/wireless/at76c50x-usb.h [new file with mode: 0644]
drivers/net/wireless/ath5k/Makefile
drivers/net/wireless/ath5k/ath5k.h
drivers/net/wireless/ath5k/attach.c
drivers/net/wireless/ath5k/base.c
drivers/net/wireless/ath5k/base.h
drivers/net/wireless/ath5k/debug.c
drivers/net/wireless/ath5k/eeprom.c
drivers/net/wireless/ath5k/led.c [new file with mode: 0644]
drivers/net/wireless/ath5k/pcu.c
drivers/net/wireless/ath5k/reset.c
drivers/net/wireless/ath9k/Makefile
drivers/net/wireless/ath9k/ahb.c
drivers/net/wireless/ath9k/ani.c
drivers/net/wireless/ath9k/ath9k.h
drivers/net/wireless/ath9k/beacon.c
drivers/net/wireless/ath9k/calib.c
drivers/net/wireless/ath9k/calib.h
drivers/net/wireless/ath9k/debug.c
drivers/net/wireless/ath9k/debug.h
drivers/net/wireless/ath9k/eeprom.c
drivers/net/wireless/ath9k/eeprom.h
drivers/net/wireless/ath9k/hw.c
drivers/net/wireless/ath9k/hw.h
drivers/net/wireless/ath9k/initvals.h
drivers/net/wireless/ath9k/mac.c
drivers/net/wireless/ath9k/mac.h
drivers/net/wireless/ath9k/main.c
drivers/net/wireless/ath9k/pci.c
drivers/net/wireless/ath9k/phy.c
drivers/net/wireless/ath9k/phy.h
drivers/net/wireless/ath9k/rc.c
drivers/net/wireless/ath9k/rc.h
drivers/net/wireless/ath9k/recv.c
drivers/net/wireless/ath9k/reg.h
drivers/net/wireless/ath9k/regd.c
drivers/net/wireless/ath9k/regd.h
drivers/net/wireless/ath9k/virtual.c [new file with mode: 0644]
drivers/net/wireless/ath9k/xmit.c
drivers/net/wireless/atmel.c
drivers/net/wireless/b43/b43.h
drivers/net/wireless/b43/debugfs.c
drivers/net/wireless/b43/dma.c
drivers/net/wireless/b43/dma.h
drivers/net/wireless/b43/lo.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/phy_a.c
drivers/net/wireless/b43/phy_g.c
drivers/net/wireless/b43/pio.c
drivers/net/wireless/b43/rfkill.c
drivers/net/wireless/b43/wa.c
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/hostap/hostap.h
drivers/net/wireless/hostap/hostap_80211.h
drivers/net/wireless/hostap/hostap_80211_rx.c
drivers/net/wireless/hostap/hostap_80211_tx.c
drivers/net/wireless/hostap/hostap_ap.c
drivers/net/wireless/hostap/hostap_ap.h
drivers/net/wireless/hostap/hostap_hw.c
drivers/net/wireless/hostap/hostap_info.c
drivers/net/wireless/hostap/hostap_ioctl.c
drivers/net/wireless/hostap/hostap_main.c
drivers/net/wireless/hostap/hostap_wlan.h
drivers/net/wireless/ipw2x00/Kconfig
drivers/net/wireless/ipw2x00/ieee80211.h [moved from include/net/ieee80211.h with 90% similarity]
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/ipw2x00/ipw2100.h
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/ipw2x00/ipw2200.h
drivers/net/wireless/ipw2x00/libipw_geo.c
drivers/net/wireless/ipw2x00/libipw_module.c
drivers/net/wireless/ipw2x00/libipw_rx.c
drivers/net/wireless/ipw2x00/libipw_tx.c
drivers/net/wireless/ipw2x00/libipw_wx.c
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/Makefile
drivers/net/wireless/iwlwifi/iwl-1000.c [moved from drivers/net/wireless/iwlwifi/iwl-100.c with 82% similarity]
drivers/net/wireless/iwlwifi/iwl-3945-led.c
drivers/net/wireless/iwlwifi/iwl-3945-led.h
drivers/net/wireless/iwlwifi/iwl-3945-rs.c
drivers/net/wireless/iwlwifi/iwl-3945.c
drivers/net/wireless/iwlwifi/iwl-5000.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.c
drivers/net/wireless/iwlwifi/iwl-agn-rs.h
drivers/net/wireless/iwlwifi/iwl-agn.c
drivers/net/wireless/iwlwifi/iwl-core.c
drivers/net/wireless/iwlwifi/iwl-core.h
drivers/net/wireless/iwlwifi/iwl-csr.h
drivers/net/wireless/iwlwifi/iwl-dev.h
drivers/net/wireless/iwlwifi/iwl-io.h
drivers/net/wireless/iwlwifi/iwl-led.h
drivers/net/wireless/iwlwifi/iwl-scan.c
drivers/net/wireless/iwlwifi/iwl-sta.c
drivers/net/wireless/iwlwifi/iwl-sta.h
drivers/net/wireless/iwlwifi/iwl-tx.c
drivers/net/wireless/iwlwifi/iwl3945-base.c
drivers/net/wireless/libertas/defs.h
drivers/net/wireless/libertas/dev.h
drivers/net/wireless/libertas/ethtool.c
drivers/net/wireless/libertas/if_cs.c
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/libertas/if_usb.c
drivers/net/wireless/libertas/main.c
drivers/net/wireless/libertas/persistcfg.c
drivers/net/wireless/libertas/rx.c
drivers/net/wireless/libertas/scan.c
drivers/net/wireless/libertas/tx.c
drivers/net/wireless/libertas/wext.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwl8k.c [new file with mode: 0644]
drivers/net/wireless/netwave_cs.c
drivers/net/wireless/orinoco/fw.c
drivers/net/wireless/orinoco/fw.h
drivers/net/wireless/orinoco/hermes_dld.c
drivers/net/wireless/orinoco/hermes_dld.h
drivers/net/wireless/orinoco/main.c
drivers/net/wireless/orinoco/orinoco.h
drivers/net/wireless/p54/p54.h
drivers/net/wireless/p54/p54common.c
drivers/net/wireless/p54/p54common.h
drivers/net/wireless/p54/p54pci.c
drivers/net/wireless/p54/p54spi.c
drivers/net/wireless/p54/p54usb.c
drivers/net/wireless/prism54/islpci_dev.c
drivers/net/wireless/prism54/islpci_dev.h
drivers/net/wireless/prism54/islpci_eth.c
drivers/net/wireless/ray_cs.c
drivers/net/wireless/rt2x00/rt2400pci.c
drivers/net/wireless/rt2x00/rt2400pci.h
drivers/net/wireless/rt2x00/rt2500pci.c
drivers/net/wireless/rt2x00/rt2500pci.h
drivers/net/wireless/rt2x00/rt2500usb.c
drivers/net/wireless/rt2x00/rt2500usb.h
drivers/net/wireless/rt2x00/rt2x00debug.c
drivers/net/wireless/rt2x00/rt2x00link.c
drivers/net/wireless/rt2x00/rt61pci.c
drivers/net/wireless/rt2x00/rt61pci.h
drivers/net/wireless/rt2x00/rt73usb.c
drivers/net/wireless/rt2x00/rt73usb.h
drivers/net/wireless/rtl818x/rtl8187_dev.c
drivers/net/wireless/strip.c
drivers/net/wireless/wavelan.c
drivers/net/wireless/wavelan_cs.c
drivers/net/wireless/wavelan_cs.p.h
drivers/net/wireless/wl3501.h
drivers/net/wireless/wl3501_cs.c
drivers/net/wireless/zd1201.c
drivers/net/wireless/zd1201.h
drivers/net/wireless/zd1211rw/zd_chip.c
drivers/net/wireless/zd1211rw/zd_chip.h
drivers/net/wireless/zd1211rw/zd_mac.c
drivers/net/yellowfin.c
drivers/parport/parport_atari.c
drivers/pci/dmar.c
drivers/pci/hotplug/pciehp.h
drivers/pci/hotplug/pciehp_core.c
drivers/pci/hotplug/pciehp_hpc.c
drivers/pci/intel-iommu.c
drivers/pci/intr_remapping.c
drivers/pci/msi.c
drivers/pci/pci.c
drivers/pci/pci.h
drivers/pci/pcie/aer/aerdrv_core.c
drivers/pci/pcie/portdrv_pci.c
drivers/pci/quirks.c
drivers/pci/rom.c
drivers/platform/x86/Kconfig
drivers/platform/x86/fujitsu-laptop.c
drivers/s390/char/sclp.c
drivers/s390/char/sclp_cmd.c
drivers/scsi/cxgb3i/cxgb3i.h
drivers/scsi/cxgb3i/cxgb3i_ddp.c
drivers/scsi/cxgb3i/cxgb3i_ddp.h
drivers/scsi/cxgb3i/cxgb3i_init.c
drivers/scsi/cxgb3i/cxgb3i_iscsi.c
drivers/scsi/cxgb3i/cxgb3i_offload.c
drivers/scsi/cxgb3i/cxgb3i_offload.h
drivers/scsi/cxgb3i/cxgb3i_pdu.c
drivers/scsi/cxgb3i/cxgb3i_pdu.h
drivers/scsi/hptiop.c
drivers/scsi/ibmvscsi/ibmvfc.c
drivers/scsi/ibmvscsi/ibmvfc.h
drivers/scsi/ibmvscsi/ibmvscsi.c
drivers/scsi/libiscsi.c
drivers/scsi/lpfc/lpfc_els.c
drivers/scsi/qla2xxx/qla_attr.c
drivers/scsi/qla2xxx/qla_def.h
drivers/scsi/qla2xxx/qla_devtbl.h
drivers/scsi/qla2xxx/qla_fw.h
drivers/scsi/qla2xxx/qla_gbl.h
drivers/scsi/qla2xxx/qla_init.c
drivers/scsi/qla2xxx/qla_isr.c
drivers/scsi/qla2xxx/qla_mbx.c
drivers/scsi/qla2xxx/qla_mid.c
drivers/scsi/qla2xxx/qla_os.c
drivers/scsi/qla2xxx/qla_sup.c
drivers/scsi/qla2xxx/qla_version.h
drivers/scsi/scsi_lib.c
drivers/scsi/scsi_scan.c
drivers/scsi/sd.c
drivers/scsi/sg.c
drivers/serial/8250.c
drivers/serial/8250_pci.c
drivers/serial/atmel_serial.c
drivers/serial/jsm/jsm_driver.c
drivers/serial/sh-sci.h
drivers/spi/spi_gpio.c
drivers/ssb/pci.c
drivers/ssb/sprom.c
drivers/ssb/ssb_private.h
drivers/staging/panel/panel.c
drivers/staging/rtl8187se/Kconfig
drivers/staging/rtl8187se/ieee80211/ieee80211_crypt.c
drivers/staging/rtl8187se/r8180_core.c
drivers/staging/winbond/wbusb.c
drivers/usb/class/cdc-acm.c
drivers/usb/core/hcd-pci.c
drivers/usb/core/hcd.h
drivers/usb/core/message.c
drivers/usb/gadget/Kconfig
drivers/usb/gadget/f_obex.c
drivers/usb/gadget/file_storage.c
drivers/usb/gadget/fsl_usb2_udc.c
drivers/usb/gadget/pxa25x_udc.c
drivers/usb/gadget/rndis.c
drivers/usb/host/ehci-hcd.c
drivers/usb/host/ehci-mem.c
drivers/usb/host/ehci-pci.c
drivers/usb/host/ehci-sched.c
drivers/usb/host/ehci.h
drivers/usb/host/ohci-pci.c
drivers/usb/host/uhci-hcd.c
drivers/usb/host/whci/asl.c
drivers/usb/host/whci/pzl.c
drivers/usb/musb/davinci.c
drivers/usb/musb/musb_core.c
drivers/usb/musb/musb_gadget.c
drivers/usb/musb/musb_host.c
drivers/usb/serial/option.c
drivers/usb/storage/unusual_devs.h
drivers/video/Kconfig
drivers/video/atafb.c
drivers/video/aty/aty128fb.c
drivers/video/pxafb.c
drivers/w1/slaves/Kconfig
drivers/w1/slaves/Makefile
drivers/w1/slaves/w1_ds2433.c
drivers/watchdog/Kconfig
drivers/watchdog/at91rm9200_wdt.c
drivers/watchdog/at91sam9_wdt.c
drivers/watchdog/iTCO_vendor_support.c
drivers/watchdog/iTCO_wdt.c
drivers/xen/manage.c
firmware/3com/typhoon.bin.ihex [new file with mode: 0644]
firmware/Makefile
firmware/WHENCE
firmware/cxgb3/t3fw-7.0.0.bin.ihex [deleted file]
firmware/cxgb3/t3fw-7.1.0.bin.ihex [new file with mode: 0644]
firmware/tehuti/bdx.bin.ihex [new file with mode: 0644]
fs/Makefile
fs/bio.c
fs/btrfs/btrfs_inode.h
fs/btrfs/ctree.c
fs/btrfs/ctree.h
fs/btrfs/disk-io.c
fs/btrfs/disk-io.h
fs/btrfs/extent-tree.c
fs/btrfs/extent_io.c
fs/btrfs/file.c
fs/btrfs/inode-map.c
fs/btrfs/inode.c
fs/btrfs/ioctl.c
fs/btrfs/locking.c
fs/btrfs/super.c
fs/btrfs/transaction.c
fs/btrfs/tree-log.c
fs/btrfs/volumes.c
fs/buffer.c
fs/cifs/CHANGES
fs/cifs/cifsfs.h
fs/cifs/cifsglob.h
fs/cifs/cifsproto.h
fs/cifs/cifssmb.c
fs/cifs/connect.c
fs/cifs/dir.c
fs/cifs/inode.c
fs/cifs/readdir.c
fs/cifs/sess.c
fs/compat_ioctl.c
fs/dcache.c
fs/ext4/balloc.c
fs/ext4/ext4.h
fs/ext4/ialloc.c
fs/ext4/inode.c
fs/ext4/mballoc.c
fs/ext4/migrate.c
fs/ext4/super.c
fs/jbd2/journal.c
fs/jbd2/transaction.c
fs/jffs2/background.c
fs/jffs2/readinode.c
fs/namespace.c
fs/notify/inotify/inotify.c
fs/ocfs2/alloc.c
fs/ocfs2/dlm/dlmmaster.c
fs/ocfs2/dlm/dlmthread.c
fs/ocfs2/dlm/dlmunlock.c
fs/ocfs2/dlmglue.c
fs/ocfs2/journal.h
fs/ocfs2/ocfs2.h
fs/ocfs2/super.c
fs/ocfs2/xattr.c
fs/proc/inode.c
fs/proc/page.c
fs/seq_file.c
fs/super.c
fs/timerfd.c
fs/xfs/linux-2.6/xfs_buf.c
include/asm-frv/pgtable.h
include/drm/drmP.h
include/drm/drm_crtc.h
include/drm/drm_crtc_helper.h
include/drm/drm_edid.h
include/linux/Kbuild
include/linux/bio.h
include/linux/blkdev.h
include/linux/blktrace_api.h
include/linux/dca.h
include/linux/dcbnl.h
include/linux/device.h
include/linux/dmaengine.h
include/linux/ethtool.h
include/linux/firmware-map.h
include/linux/fs.h
include/linux/gen_stats.h
include/linux/i2c-dev.h
include/linux/i2c.h
include/linux/ide.h
include/linux/if_vlan.h
include/linux/intel-iommu.h
include/linux/io-mapping.h
include/linux/jbd2.h
include/linux/kvm.h
include/linux/kvm_host.h
include/linux/mm.h
include/linux/mmzone.h
include/linux/neighbour.h
include/linux/net.h
include/linux/net_dropmon.h [new file with mode: 0644]
include/linux/netdevice.h
include/linux/netfilter/xt_NFLOG.h
include/linux/netlink.h
include/linux/netpoll.h
include/linux/nl80211.h
include/linux/pci_ids.h
include/linux/phy.h
include/linux/pm.h
include/linux/ppp_channel.h
include/linux/rcuclassic.h
include/linux/rcupdate.h
include/linux/rcupreempt.h
include/linux/rcutree.h
include/linux/rds.h [new file with mode: 0644]
include/linux/rtnetlink.h
include/linux/sched.h
include/linux/seq_file.h
include/linux/serial_core.h
include/linux/skbuff.h
include/linux/slab.h
include/linux/socket.h
include/linux/spi/spi_bitbang.h
include/linux/ssb/ssb.h
include/linux/tcp.h
include/linux/timerfd.h
include/linux/usb/usbnet.h
include/linux/user_namespace.h
include/linux/vmalloc.h
include/linux/wimax/debug.h
include/linux/wimax/i2400m.h
include/net/bluetooth/bluetooth.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/bluetooth/rfcomm.h
include/net/cfg80211.h
include/net/dsa.h
include/net/if_inet6.h
include/net/inet_frag.h
include/net/mac80211.h
include/net/net_namespace.h
include/net/netfilter/nf_conntrack_core.h
include/net/psnap.h
include/net/sch_generic.h
include/net/sctp/command.h
include/net/sctp/sctp.h
include/net/sock.h
include/net/tcp.h
include/net/wireless.h
include/trace/skb.h [new file with mode: 0644]
init/do_mounts.c
init/do_mounts_md.c
init/main.c
kernel/Makefile
kernel/cgroup.c
kernel/futex.c
kernel/kexec.c
kernel/posix-cpu-timers.c
kernel/power/Makefile
kernel/power/console.c
kernel/power/disk.c
kernel/power/main.c
kernel/power/swap.c
kernel/power/user.c
kernel/printk.c
kernel/rcuclassic.c
kernel/rcupdate.c
kernel/rcupreempt.c
kernel/rcutree.c
kernel/sched.c
kernel/seccomp.c
kernel/sys.c
kernel/trace/Kconfig
kernel/trace/ftrace.c
kernel/trace/trace_mmiotrace.c
kernel/trace/trace_selftest.c
kernel/user.c
kernel/user_namespace.c
lib/Kconfig.debug
mm/mlock.c
mm/page-writeback.c
mm/page_alloc.c
mm/page_io.c
mm/shmem.c
mm/swapfile.c
mm/util.c
mm/vmalloc.c
mm/vmscan.c
net/802/psnap.c
net/802/tr.c
net/8021q/vlan.c
net/8021q/vlan_core.c
net/8021q/vlan_dev.c
net/9p/trans_fd.c
net/Kconfig
net/Makefile
net/appletalk/ddp.c
net/atm/clip.c
net/atm/lec.c
net/atm/mpc.c
net/atm/mpc.h
net/ax25/af_ax25.c
net/bluetooth/af_bluetooth.c
net/bluetooth/cmtp/core.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/l2cap.c
net/bluetooth/rfcomm/core.c
net/bluetooth/rfcomm/sock.c
net/bluetooth/sco.c
net/bridge/br_netlink.c
net/can/af_can.c
net/core/Makefile
net/core/datagram.c
net/core/dev.c
net/core/drop_monitor.c [new file with mode: 0644]
net/core/ethtool.c
net/core/fib_rules.c
net/core/neighbour.c
net/core/net-sysfs.c
net/core/net-traces.c [new file with mode: 0644]
net/core/net_namespace.c
net/core/pktgen.c
net/core/rtnetlink.c
net/core/skbuff.c
net/core/sock.c
net/core/sysctl_net_core.c
net/dccp/ackvec.h
net/dccp/dccp.h
net/dccp/output.c
net/decnet/af_decnet.c
net/decnet/dn_dev.c
net/decnet/dn_route.c
net/decnet/dn_table.c
net/decnet/sysctl_net_decnet.c
net/dsa/Kconfig
net/dsa/dsa.c
net/dsa/dsa_priv.h
net/dsa/mv88e6060.c
net/dsa/mv88e6123_61_65.c
net/dsa/mv88e6131.c
net/dsa/slave.c
net/dsa/tag_dsa.c
net/dsa/tag_edsa.c
net/dsa/tag_trailer.c
net/econet/af_econet.c
net/ipv4/Kconfig
net/ipv4/af_inet.c
net/ipv4/arp.c
net/ipv4/cipso_ipv4.c
net/ipv4/devinet.c
net/ipv4/fib_frontend.c
net/ipv4/fib_semantics.c
net/ipv4/icmp.c
net/ipv4/inet_fragment.c
net/ipv4/ip_fragment.c
net/ipv4/ip_gre.c
net/ipv4/ipip.c
net/ipv4/tcp.c
net/ipv4/tcp_bic.c
net/ipv4/tcp_cong.c
net/ipv4/tcp_cubic.c
net/ipv4/tcp_htcp.c
net/ipv4/tcp_input.c
net/ipv4/tcp_ipv4.c
net/ipv4/tcp_minisocks.c
net/ipv4/tcp_output.c
net/ipv4/tcp_probe.c
net/ipv4/tcp_scalable.c
net/ipv4/tcp_timer.c
net/ipv4/tcp_veno.c
net/ipv4/tcp_yeah.c
net/ipv4/udp.c
net/ipv6/addrconf.c
net/ipv6/af_inet6.c
net/ipv6/inet6_hashtables.c
net/ipv6/ipv6_sockglue.c
net/ipv6/ndisc.c
net/ipv6/netfilter/nf_conntrack_proto_icmpv6.c
net/ipv6/netfilter/nf_conntrack_reasm.c
net/ipv6/reassembly.c
net/ipv6/route.c
net/ipv6/sit.c
net/ipv6/tcp_ipv6.c
net/ipv6/xfrm6_state.c
net/ipx/af_ipx.c
net/irda/irda_device.c
net/irda/irlan/irlan_eth.c
net/irda/irmod.c
net/iucv/af_iucv.c
net/key/af_key.c
net/llc/af_llc.c
net/llc/llc_conn.c
net/llc/llc_core.c
net/mac80211/Makefile
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/debugfs_netdev.c
net/mac80211/ht.c
net/mac80211/ibss.c [new file with mode: 0644]
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/main.c
net/mac80211/mlme.c
net/mac80211/rate.h
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/spectmgmt.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wext.c
net/mac80211/wme.c
net/mac80211/wme.h
net/netfilter/nf_conntrack_core.c
net/netfilter/nf_conntrack_netlink.c
net/netfilter/nf_conntrack_proto_tcp.c
net/netfilter/nfnetlink_log.c
net/netfilter/x_tables.c
net/netfilter/xt_recent.c
net/netlink/af_netlink.c
net/netrom/af_netrom.c
net/packet/af_packet.c
net/phonet/af_phonet.c
net/phonet/pn_netlink.c
net/rds/Kconfig [new file with mode: 0644]
net/rds/Makefile [new file with mode: 0644]
net/rds/af_rds.c [new file with mode: 0644]
net/rds/bind.c [new file with mode: 0644]
net/rds/cong.c [new file with mode: 0644]
net/rds/connection.c [new file with mode: 0644]
net/rds/ib.c [new file with mode: 0644]
net/rds/ib.h [new file with mode: 0644]
net/rds/ib_cm.c [new file with mode: 0644]
net/rds/ib_rdma.c [new file with mode: 0644]
net/rds/ib_recv.c [new file with mode: 0644]
net/rds/ib_ring.c [new file with mode: 0644]
net/rds/ib_send.c [new file with mode: 0644]
net/rds/ib_stats.c [new file with mode: 0644]
net/rds/ib_sysctl.c [new file with mode: 0644]
net/rds/info.c [new file with mode: 0644]
net/rds/info.h [new file with mode: 0644]
net/rds/iw.c [new file with mode: 0644]
net/rds/iw.h [new file with mode: 0644]
net/rds/iw_cm.c [new file with mode: 0644]
net/rds/iw_rdma.c [new file with mode: 0644]
net/rds/iw_recv.c [new file with mode: 0644]
net/rds/iw_ring.c [new file with mode: 0644]
net/rds/iw_send.c [new file with mode: 0644]
net/rds/iw_stats.c [new file with mode: 0644]
net/rds/iw_sysctl.c [new file with mode: 0644]
net/rds/loop.c [new file with mode: 0644]
net/rds/loop.h [new file with mode: 0644]
net/rds/message.c [new file with mode: 0644]
net/rds/page.c [new file with mode: 0644]
net/rds/rdma.c [new file with mode: 0644]
net/rds/rdma.h [new file with mode: 0644]
net/rds/rdma_transport.c [new file with mode: 0644]
net/rds/rdma_transport.h [new file with mode: 0644]
net/rds/rds.h [new file with mode: 0644]
net/rds/recv.c [new file with mode: 0644]
net/rds/send.c [new file with mode: 0644]
net/rds/stats.c [new file with mode: 0644]
net/rds/sysctl.c [new file with mode: 0644]
net/rds/threads.c [new file with mode: 0644]
net/rds/transport.c [new file with mode: 0644]
net/sched/act_police.c
net/sched/sch_cbq.c
net/sched/sch_drr.c
net/sched/sch_hfsc.c
net/sched/sch_htb.c
net/sched/sch_tbf.c
net/sctp/debug.c
net/sctp/endpointola.c
net/sctp/output.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/transport.c
net/tipc/bcast.c
net/tipc/bcast.h
net/tipc/dbg.c
net/tipc/node.c
net/unix/af_unix.c
net/wanrouter/wanmain.c
net/wanrouter/wanproc.c
net/wireless/Kconfig
net/wireless/core.c
net/wireless/core.h
net/wireless/lib80211_crypt_ccmp.c
net/wireless/lib80211_crypt_tkip.c
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/reg.c
net/wireless/reg.h
net/wireless/scan.c
net/wireless/sysfs.c
net/wireless/wext-compat.c
net/x25/af_x25.c
net/xfrm/xfrm_state.c
scripts/bootgraph.pl
scripts/checkpatch.pl
scripts/markup_oops.pl
scripts/mod/file2alias.c
scripts/package/mkspec
scripts/setlocalversion
scripts/tags.sh
security/selinux/netlabel.c
sound/core/jack.c
sound/core/oss/rate.c
sound/oss/dmasound/dmasound_atari.c
sound/pci/aw2/aw2-alsa.c
sound/pci/emu10k1/emu10k1_main.c
sound/pci/hda/hda_hwdep.c
sound/pci/hda/hda_intel.c
sound/pci/hda/patch_realtek.c
sound/pci/hda/patch_sigmatel.c
sound/pci/oxygen/virtuoso.c
sound/pci/pcxhr/pcxhr.h
sound/usb/usbaudio.c
sound/usb/usbmidi.c
virt/kvm/iommu.c
virt/kvm/kvm_main.c

diff --git a/CREDITS b/CREDITS
index 2b39168c06aabe35bc35c10753cb42438e65eaed..5e0736722afd547659c491ad2ee503e57336435d 100644 (file)
--- a/CREDITS
+++ b/CREDITS
@@ -2166,7 +2166,6 @@ D: Initial implementation of VC's, pty's and select()
 
 N: Pavel Machek
 E: pavel@ucw.cz
-E: pavel@suse.cz
 D: Softcursor for vga, hypertech cdrom support, vcsa bugfix, nbd
 D: sun4/330 port, capabilities for elf, speedup for rm on ext2, USB,
 D: work on suspend-to-ram/disk, killing duplicates from ioctl32
index ceddcff4082a0cfc2bdc692148ec455bb9e165f0..e638e15a8895abef445cedccb2df273f1e3ad0e1 100644 (file)
@@ -1,3 +1,46 @@
+What:          /sys/bus/pci/drivers/.../bind
+Date:          December 2003
+Contact:       linux-pci@vger.kernel.org
+Description:
+               Writing a device location to this file will cause
+               the driver to attempt to bind to the device found at
+               this location.  This is useful for overriding default
+               bindings.  The format for the location is: DDDD:BB:DD.F.
+               That is Domain:Bus:Device.Function and is the same as
+               found in /sys/bus/pci/devices/.  For example:
+               # echo 0000:00:19.0 > /sys/bus/pci/drivers/foo/bind
+               (Note: kernels before 2.6.28 may require echo -n).
+
+What:          /sys/bus/pci/drivers/.../unbind
+Date:          December 2003
+Contact:       linux-pci@vger.kernel.org
+Description:
+               Writing a device location to this file will cause the
+               driver to attempt to unbind from the device found at
+               this location.  This may be useful when overriding default
+               bindings.  The format for the location is: DDDD:BB:DD.F.
+               That is Domain:Bus:Device.Function and is the same as
+               found in /sys/bus/pci/devices/. For example:
+               # echo 0000:00:19.0 > /sys/bus/pci/drivers/foo/unbind
+               (Note: kernels before 2.6.28 may require echo -n).
+
+What:          /sys/bus/pci/drivers/.../new_id
+Date:          December 2003
+Contact:       linux-pci@vger.kernel.org
+Description:
+               Writing a device ID to this file will attempt to
+               dynamically add a new device ID to a PCI device driver.
+               This may allow the driver to support more hardware than
+               was included in the driver's static device ID support
+               table at compile time.  The format for the device ID is:
+               VVVV DDDD SVVV SDDD CCCC MMMM PPPP.  That is Vendor ID,
+               Device ID, Subsystem Vendor ID, Subsystem Device ID,
+               Class, Class Mask, and Private Driver Data.  The Vendor ID
+               and Device ID fields are required, the rest are optional.
+               Upon successfully adding an ID, the driver will probe
+               for the device and attempt to bind to it.  For example:
+               # echo "8086 10f5" > /sys/bus/pci/drivers/foo/new_id
+
 What:          /sys/bus/pci/devices/.../vpd
 Date:          February 2008
 Contact:       Ben Hutchings <bhutchings@solarflare.com>
index 0d99ee6ae02ec786aef9ed6373bc91d1f5d1fb19..eca0d65087dc4239352add5f2167a85ae7a179e8 100644 (file)
@@ -1,6 +1,6 @@
 What:          /sys/firmware/memmap/
 Date:          June 2008
-Contact:       Bernhard Walle <bwalle@suse.de>
+Contact:       Bernhard Walle <bernhard.walle@gmx.de>
 Description:
                On all platforms, the firmware provides a memory map which the
                kernel reads. The resources from that memory map are registered
index dc3154e49279b6f95935df1665b6f25ad0d4c1a1..1462ed86d40aec28e0d54e947c93ad43f22333ae 100644 (file)
@@ -6,7 +6,7 @@
 # To add a new book the only step required is to add the book to the
 # list of DOCBOOKS.
 
-DOCBOOKS := z8530book.xml mcabook.xml \
+DOCBOOKS := z8530book.xml mcabook.xml device-drivers.xml \
            kernel-hacking.xml kernel-locking.xml deviceiobook.xml \
            procfs-guide.xml writing_usb_driver.xml networking.xml \
            kernel-api.xml filesystems.xml lsm.xml usb.xml kgdb.xml \
diff --git a/Documentation/DocBook/device-drivers.tmpl b/Documentation/DocBook/device-drivers.tmpl
new file mode 100644 (file)
index 0000000..94a20fe
--- /dev/null
@@ -0,0 +1,418 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!DOCTYPE book PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN"
+       "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" []>
+
+<book id="LinuxDriversAPI">
+ <bookinfo>
+  <title>Linux Device Drivers</title>
+
+  <legalnotice>
+   <para>
+     This documentation is free software; you can redistribute
+     it and/or modify it under the terms of the GNU General Public
+     License as published by the Free Software Foundation; either
+     version 2 of the License, or (at your option) any later
+     version.
+   </para>
+
+   <para>
+     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.
+   </para>
+
+   <para>
+     You should have received a copy of the GNU General Public
+     License along with this program; if not, write to the Free
+     Software Foundation, Inc., 59 Temple Place, Suite 330, Boston,
+     MA 02111-1307 USA
+   </para>
+
+   <para>
+     For more details see the file COPYING in the source
+     distribution of Linux.
+   </para>
+  </legalnotice>
+ </bookinfo>
+
+<toc></toc>
+
+  <chapter id="Basics">
+     <title>Driver Basics</title>
+     <sect1><title>Driver Entry and Exit points</title>
+!Iinclude/linux/init.h
+     </sect1>
+
+     <sect1><title>Atomic and pointer manipulation</title>
+!Iarch/x86/include/asm/atomic_32.h
+!Iarch/x86/include/asm/unaligned.h
+     </sect1>
+
+     <sect1><title>Delaying, scheduling, and timer routines</title>
+!Iinclude/linux/sched.h
+!Ekernel/sched.c
+!Ekernel/timer.c
+     </sect1>
+     <sect1><title>High-resolution timers</title>
+!Iinclude/linux/ktime.h
+!Iinclude/linux/hrtimer.h
+!Ekernel/hrtimer.c
+     </sect1>
+     <sect1><title>Workqueues and Kevents</title>
+!Ekernel/workqueue.c
+     </sect1>
+     <sect1><title>Internal Functions</title>
+!Ikernel/exit.c
+!Ikernel/signal.c
+!Iinclude/linux/kthread.h
+!Ekernel/kthread.c
+     </sect1>
+
+     <sect1><title>Kernel objects manipulation</title>
+<!--
+X!Iinclude/linux/kobject.h
+-->
+!Elib/kobject.c
+     </sect1>
+
+     <sect1><title>Kernel utility functions</title>
+!Iinclude/linux/kernel.h
+!Ekernel/printk.c
+!Ekernel/panic.c
+!Ekernel/sys.c
+!Ekernel/rcupdate.c
+     </sect1>
+
+     <sect1><title>Device Resource Management</title>
+!Edrivers/base/devres.c
+     </sect1>
+
+  </chapter>
+
+  <chapter id="devdrivers">
+     <title>Device drivers infrastructure</title>
+     <sect1><title>Device Drivers Base</title>
+<!--
+X!Iinclude/linux/device.h
+-->
+!Edrivers/base/driver.c
+!Edrivers/base/core.c
+!Edrivers/base/class.c
+!Edrivers/base/firmware_class.c
+!Edrivers/base/transport_class.c
+<!-- Cannot be included, because
+     attribute_container_add_class_device_adapter
+ and attribute_container_classdev_to_container
+     exceed allowed 44 characters maximum
+X!Edrivers/base/attribute_container.c
+-->
+!Edrivers/base/sys.c
+<!--
+X!Edrivers/base/interface.c
+-->
+!Edrivers/base/platform.c
+!Edrivers/base/bus.c
+     </sect1>
+     <sect1><title>Device Drivers Power Management</title>
+!Edrivers/base/power/main.c
+     </sect1>
+     <sect1><title>Device Drivers ACPI Support</title>
+<!-- Internal functions only
+X!Edrivers/acpi/sleep/main.c
+X!Edrivers/acpi/sleep/wakeup.c
+X!Edrivers/acpi/motherboard.c
+X!Edrivers/acpi/bus.c
+-->
+!Edrivers/acpi/scan.c
+!Idrivers/acpi/scan.c
+<!-- No correct structured comments
+X!Edrivers/acpi/pci_bind.c
+-->
+     </sect1>
+     <sect1><title>Device drivers PnP support</title>
+!Idrivers/pnp/core.c
+<!-- No correct structured comments
+X!Edrivers/pnp/system.c
+ -->
+!Edrivers/pnp/card.c
+!Idrivers/pnp/driver.c
+!Edrivers/pnp/manager.c
+!Edrivers/pnp/support.c
+     </sect1>
+     <sect1><title>Userspace IO devices</title>
+!Edrivers/uio/uio.c
+!Iinclude/linux/uio_driver.h
+     </sect1>
+  </chapter>
+
+  <chapter id="parportdev">
+     <title>Parallel Port Devices</title>
+!Iinclude/linux/parport.h
+!Edrivers/parport/ieee1284.c
+!Edrivers/parport/share.c
+!Idrivers/parport/daisy.c
+  </chapter>
+
+  <chapter id="message_devices">
+       <title>Message-based devices</title>
+     <sect1><title>Fusion message devices</title>
+!Edrivers/message/fusion/mptbase.c
+!Idrivers/message/fusion/mptbase.c
+!Edrivers/message/fusion/mptscsih.c
+!Idrivers/message/fusion/mptscsih.c
+!Idrivers/message/fusion/mptctl.c
+!Idrivers/message/fusion/mptspi.c
+!Idrivers/message/fusion/mptfc.c
+!Idrivers/message/fusion/mptlan.c
+     </sect1>
+     <sect1><title>I2O message devices</title>
+!Iinclude/linux/i2o.h
+!Idrivers/message/i2o/core.h
+!Edrivers/message/i2o/iop.c
+!Idrivers/message/i2o/iop.c
+!Idrivers/message/i2o/config-osm.c
+!Edrivers/message/i2o/exec-osm.c
+!Idrivers/message/i2o/exec-osm.c
+!Idrivers/message/i2o/bus-osm.c
+!Edrivers/message/i2o/device.c
+!Idrivers/message/i2o/device.c
+!Idrivers/message/i2o/driver.c
+!Idrivers/message/i2o/pci.c
+!Idrivers/message/i2o/i2o_block.c
+!Idrivers/message/i2o/i2o_scsi.c
+!Idrivers/message/i2o/i2o_proc.c
+     </sect1>
+  </chapter>
+
+  <chapter id="snddev">
+     <title>Sound Devices</title>
+!Iinclude/sound/core.h
+!Esound/sound_core.c
+!Iinclude/sound/pcm.h
+!Esound/core/pcm.c
+!Esound/core/device.c
+!Esound/core/info.c
+!Esound/core/rawmidi.c
+!Esound/core/sound.c
+!Esound/core/memory.c
+!Esound/core/pcm_memory.c
+!Esound/core/init.c
+!Esound/core/isadma.c
+!Esound/core/control.c
+!Esound/core/pcm_lib.c
+!Esound/core/hwdep.c
+!Esound/core/pcm_native.c
+!Esound/core/memalloc.c
+<!-- FIXME: Removed for now since no structured comments in source
+X!Isound/sound_firmware.c
+-->
+  </chapter>
+
+  <chapter id="uart16x50">
+     <title>16x50 UART Driver</title>
+!Iinclude/linux/serial_core.h
+!Edrivers/serial/serial_core.c
+!Edrivers/serial/8250.c
+  </chapter>
+
+  <chapter id="fbdev">
+     <title>Frame Buffer Library</title>
+
+     <para>
+       The frame buffer drivers depend heavily on four data structures.
+       These structures are declared in include/linux/fb.h.  They are
+       fb_info, fb_var_screeninfo, fb_fix_screeninfo and fb_monospecs.
+       The last three can be made available to and from userland.
+     </para>
+
+     <para>
+       fb_info defines the current state of a particular video card.
+       Inside fb_info, there exists a fb_ops structure which is a
+       collection of needed functions to make fbdev and fbcon work.
+       fb_info is only visible to the kernel.
+     </para>
+
+     <para>
+       fb_var_screeninfo is used to describe the features of a video card
+       that are user defined.  With fb_var_screeninfo, things such as
+       depth and the resolution may be defined.
+     </para>
+
+     <para>
+       The next structure is fb_fix_screeninfo. This defines the
+       properties of a card that are created when a mode is set and can't
+       be changed otherwise.  A good example of this is the start of the
+       frame buffer memory.  This "locks" the address of the frame buffer
+       memory, so that it cannot be changed or moved.
+     </para>
+
+     <para>
+       The last structure is fb_monospecs. In the old API, there was
+       little importance for fb_monospecs. This allowed for forbidden things
+       such as setting a mode of 800x600 on a fix frequency monitor. With
+       the new API, fb_monospecs prevents such things, and if used
+       correctly, can prevent a monitor from being cooked.  fb_monospecs
+       will not be useful until kernels 2.5.x.
+     </para>
+
+     <sect1><title>Frame Buffer Memory</title>
+!Edrivers/video/fbmem.c
+     </sect1>
+<!--
+     <sect1><title>Frame Buffer Console</title>
+X!Edrivers/video/console/fbcon.c
+     </sect1>
+-->
+     <sect1><title>Frame Buffer Colormap</title>
+!Edrivers/video/fbcmap.c
+     </sect1>
+<!-- FIXME:
+  drivers/video/fbgen.c has no docs, which stuffs up the sgml.  Comment
+  out until somebody adds docs.  KAO
+     <sect1><title>Frame Buffer Generic Functions</title>
+X!Idrivers/video/fbgen.c
+     </sect1>
+KAO -->
+     <sect1><title>Frame Buffer Video Mode Database</title>
+!Idrivers/video/modedb.c
+!Edrivers/video/modedb.c
+     </sect1>
+     <sect1><title>Frame Buffer Macintosh Video Mode Database</title>
+!Edrivers/video/macmodes.c
+     </sect1>
+     <sect1><title>Frame Buffer Fonts</title>
+        <para>
+           Refer to the file drivers/video/console/fonts.c for more information.
+        </para>
+<!-- FIXME: Removed for now since no structured comments in source
+X!Idrivers/video/console/fonts.c
+-->
+     </sect1>
+  </chapter>
+
+  <chapter id="input_subsystem">
+     <title>Input Subsystem</title>
+!Iinclude/linux/input.h
+!Edrivers/input/input.c
+!Edrivers/input/ff-core.c
+!Edrivers/input/ff-memless.c
+  </chapter>
+
+  <chapter id="spi">
+      <title>Serial Peripheral Interface (SPI)</title>
+  <para>
+       SPI is the "Serial Peripheral Interface", widely used with
+       embedded systems because it is a simple and efficient
+       interface:  basically a multiplexed shift register.
+       Its three signal wires hold a clock (SCK, often in the range
+       of 1-20 MHz), a "Master Out, Slave In" (MOSI) data line, and
+       a "Master In, Slave Out" (MISO) data line.
+       SPI is a full duplex protocol; for each bit shifted out the
+       MOSI line (one per clock) another is shifted in on the MISO line.
+       Those bits are assembled into words of various sizes on the
+       way to and from system memory.
+       An additional chipselect line is usually active-low (nCS);
+       four signals are normally used for each peripheral, plus
+       sometimes an interrupt.
+  </para>
+  <para>
+       The SPI bus facilities listed here provide a generalized
+       interface to declare SPI busses and devices, manage them
+       according to the standard Linux driver model, and perform
+       input/output operations.
+       At this time, only "master" side interfaces are supported,
+       where Linux talks to SPI peripherals and does not implement
+       such a peripheral itself.
+       (Interfaces to support implementing SPI slaves would
+       necessarily look different.)
+  </para>
+  <para>
+       The programming interface is structured around two kinds of driver,
+       and two kinds of device.
+       A "Controller Driver" abstracts the controller hardware, which may
+       be as simple as a set of GPIO pins or as complex as a pair of FIFOs
+       connected to dual DMA engines on the other side of the SPI shift
+       register (maximizing throughput).  Such drivers bridge between
+       whatever bus they sit on (often the platform bus) and SPI, and
+       expose the SPI side of their device as a
+       <structname>struct spi_master</structname>.
+       SPI devices are children of that master, represented as a
+       <structname>struct spi_device</structname> and manufactured from
+       <structname>struct spi_board_info</structname> descriptors which
+       are usually provided by board-specific initialization code.
+       A <structname>struct spi_driver</structname> is called a
+       "Protocol Driver", and is bound to a spi_device using normal
+       driver model calls.
+  </para>
+  <para>
+       The I/O model is a set of queued messages.  Protocol drivers
+       submit one or more <structname>struct spi_message</structname>
+       objects, which are processed and completed asynchronously.
+       (There are synchronous wrappers, however.)  Messages are
+       built from one or more <structname>struct spi_transfer</structname>
+       objects, each of which wraps a full duplex SPI transfer.
+       A variety of protocol tweaking options are needed, because
+       different chips adopt very different policies for how they
+       use the bits transferred with SPI.
+  </para>
+!Iinclude/linux/spi/spi.h
+!Fdrivers/spi/spi.c spi_register_board_info
+!Edrivers/spi/spi.c
+  </chapter>
+
+  <chapter id="i2c">
+     <title>I<superscript>2</superscript>C and SMBus Subsystem</title>
+
+     <para>
+       I<superscript>2</superscript>C (or without fancy typography, "I2C")
+       is an acronym for the "Inter-IC" bus, a simple bus protocol which is
+       widely used where low data rate communications suffice.
+       Since it's also a licensed trademark, some vendors use another
+       name (such as "Two-Wire Interface", TWI) for the same bus.
+       I2C only needs two signals (SCL for clock, SDA for data), conserving
+       board real estate and minimizing signal quality issues.
+       Most I2C devices use seven bit addresses, and bus speeds of up
+       to 400 kHz; there's a high speed extension (3.4 MHz) that's not yet
+       found wide use.
+       I2C is a multi-master bus; open drain signaling is used to
+       arbitrate between masters, as well as to handshake and to
+       synchronize clocks from slower clients.
+     </para>
+
+     <para>
+       The Linux I2C programming interfaces support only the master
+       side of bus interactions, not the slave side.
+       The programming interface is structured around two kinds of driver,
+       and two kinds of device.
+       An I2C "Adapter Driver" abstracts the controller hardware; it binds
+       to a physical device (perhaps a PCI device or platform_device) and
+       exposes a <structname>struct i2c_adapter</structname> representing
+       each I2C bus segment it manages.
+       On each I2C bus segment will be I2C devices represented by a
+       <structname>struct i2c_client</structname>.  Those devices will
+       be bound to a <structname>struct i2c_driver</structname>,
+       which should follow the standard Linux driver model.
+       (At this writing, a legacy model is more widely used.)
+       There are functions to perform various I2C protocol operations; at
+       this writing all such functions are usable only from task context.
+     </para>
+
+     <para>
+       The System Management Bus (SMBus) is a sibling protocol.  Most SMBus
+       systems are also I2C conformant.  The electrical constraints are
+       tighter for SMBus, and it standardizes particular protocol messages
+       and idioms.  Controllers that support I2C can also support most
+       SMBus operations, but SMBus controllers don't support all the protocol
+       options that an I2C controller will.
+       There are functions to perform various SMBus protocol operations,
+       either using I2C primitives or by issuing SMBus commands to
+       i2c_adapter devices which don't support those I2C operations.
+     </para>
+
+!Iinclude/linux/i2c.h
+!Fdrivers/i2c/i2c-boardinfo.c i2c_register_board_info
+!Edrivers/i2c/i2c-core.c
+  </chapter>
+
+</book>
index 5818ff75786abf9a853706794f1f33f6238786cb..bc962cda650485aea9cddcced9823ef39a3252b6 100644 (file)
 
 <toc></toc>
 
-  <chapter id="Basics">
-     <title>Driver Basics</title>
-     <sect1><title>Driver Entry and Exit points</title>
-!Iinclude/linux/init.h
-     </sect1>
-
-     <sect1><title>Atomic and pointer manipulation</title>
-!Iarch/x86/include/asm/atomic_32.h
-!Iarch/x86/include/asm/unaligned.h
-     </sect1>
-
-     <sect1><title>Delaying, scheduling, and timer routines</title>
-!Iinclude/linux/sched.h
-!Ekernel/sched.c
-!Ekernel/timer.c
-     </sect1>
-     <sect1><title>High-resolution timers</title>
-!Iinclude/linux/ktime.h
-!Iinclude/linux/hrtimer.h
-!Ekernel/hrtimer.c
-     </sect1>
-     <sect1><title>Workqueues and Kevents</title>
-!Ekernel/workqueue.c
-     </sect1>
-     <sect1><title>Internal Functions</title>
-!Ikernel/exit.c
-!Ikernel/signal.c
-!Iinclude/linux/kthread.h
-!Ekernel/kthread.c
-     </sect1>
-
-     <sect1><title>Kernel objects manipulation</title>
-<!--
-X!Iinclude/linux/kobject.h
--->
-!Elib/kobject.c
-     </sect1>
-
-     <sect1><title>Kernel utility functions</title>
-!Iinclude/linux/kernel.h
-!Ekernel/printk.c
-!Ekernel/panic.c
-!Ekernel/sys.c
-!Ekernel/rcupdate.c
-     </sect1>
-
-     <sect1><title>Device Resource Management</title>
-!Edrivers/base/devres.c
-     </sect1>
-
-  </chapter>
-
   <chapter id="adt">
      <title>Data Types</title>
      <sect1><title>Doubly Linked Lists</title>
@@ -298,62 +246,6 @@ X!Earch/x86/kernel/mca_32.c
 !Ikernel/acct.c
   </chapter>
 
-  <chapter id="devdrivers">
-     <title>Device drivers infrastructure</title>
-     <sect1><title>Device Drivers Base</title>
-<!--
-X!Iinclude/linux/device.h
--->
-!Edrivers/base/driver.c
-!Edrivers/base/core.c
-!Edrivers/base/class.c
-!Edrivers/base/firmware_class.c
-!Edrivers/base/transport_class.c
-<!-- Cannot be included, because
-     attribute_container_add_class_device_adapter
- and attribute_container_classdev_to_container
-     exceed allowed 44 characters maximum
-X!Edrivers/base/attribute_container.c
--->
-!Edrivers/base/sys.c
-<!--
-X!Edrivers/base/interface.c
--->
-!Edrivers/base/platform.c
-!Edrivers/base/bus.c
-     </sect1>
-     <sect1><title>Device Drivers Power Management</title>
-!Edrivers/base/power/main.c
-     </sect1>
-     <sect1><title>Device Drivers ACPI Support</title>
-<!-- Internal functions only
-X!Edrivers/acpi/sleep/main.c
-X!Edrivers/acpi/sleep/wakeup.c
-X!Edrivers/acpi/motherboard.c
-X!Edrivers/acpi/bus.c
--->
-!Edrivers/acpi/scan.c
-!Idrivers/acpi/scan.c
-<!-- No correct structured comments
-X!Edrivers/acpi/pci_bind.c
--->
-     </sect1>
-     <sect1><title>Device drivers PnP support</title>
-!Idrivers/pnp/core.c
-<!-- No correct structured comments
-X!Edrivers/pnp/system.c
- -->
-!Edrivers/pnp/card.c
-!Idrivers/pnp/driver.c
-!Edrivers/pnp/manager.c
-!Edrivers/pnp/support.c
-     </sect1>
-     <sect1><title>Userspace IO devices</title>
-!Edrivers/uio/uio.c
-!Iinclude/linux/uio_driver.h
-     </sect1>
-  </chapter>
-
   <chapter id="blkdev">
      <title>Block Devices</title>
 !Eblock/blk-core.c
@@ -381,275 +273,6 @@ X!Edrivers/pnp/system.c
 !Edrivers/char/misc.c
   </chapter>
 
-  <chapter id="parportdev">
-     <title>Parallel Port Devices</title>
-!Iinclude/linux/parport.h
-!Edrivers/parport/ieee1284.c
-!Edrivers/parport/share.c
-!Idrivers/parport/daisy.c
-  </chapter>
-
-  <chapter id="message_devices">
-       <title>Message-based devices</title>
-     <sect1><title>Fusion message devices</title>
-!Edrivers/message/fusion/mptbase.c
-!Idrivers/message/fusion/mptbase.c
-!Edrivers/message/fusion/mptscsih.c
-!Idrivers/message/fusion/mptscsih.c
-!Idrivers/message/fusion/mptctl.c
-!Idrivers/message/fusion/mptspi.c
-!Idrivers/message/fusion/mptfc.c
-!Idrivers/message/fusion/mptlan.c
-     </sect1>
-     <sect1><title>I2O message devices</title>
-!Iinclude/linux/i2o.h
-!Idrivers/message/i2o/core.h
-!Edrivers/message/i2o/iop.c
-!Idrivers/message/i2o/iop.c
-!Idrivers/message/i2o/config-osm.c
-!Edrivers/message/i2o/exec-osm.c
-!Idrivers/message/i2o/exec-osm.c
-!Idrivers/message/i2o/bus-osm.c
-!Edrivers/message/i2o/device.c
-!Idrivers/message/i2o/device.c
-!Idrivers/message/i2o/driver.c
-!Idrivers/message/i2o/pci.c
-!Idrivers/message/i2o/i2o_block.c
-!Idrivers/message/i2o/i2o_scsi.c
-!Idrivers/message/i2o/i2o_proc.c
-     </sect1>
-  </chapter>
-
-  <chapter id="snddev">
-     <title>Sound Devices</title>
-!Iinclude/sound/core.h
-!Esound/sound_core.c
-!Iinclude/sound/pcm.h
-!Esound/core/pcm.c
-!Esound/core/device.c
-!Esound/core/info.c
-!Esound/core/rawmidi.c
-!Esound/core/sound.c
-!Esound/core/memory.c
-!Esound/core/pcm_memory.c
-!Esound/core/init.c
-!Esound/core/isadma.c
-!Esound/core/control.c
-!Esound/core/pcm_lib.c
-!Esound/core/hwdep.c
-!Esound/core/pcm_native.c
-!Esound/core/memalloc.c
-<!-- FIXME: Removed for now since no structured comments in source
-X!Isound/sound_firmware.c
--->
-  </chapter>
-
-  <chapter id="uart16x50">
-     <title>16x50 UART Driver</title>
-!Iinclude/linux/serial_core.h
-!Edrivers/serial/serial_core.c
-!Edrivers/serial/8250.c
-  </chapter>
-
-  <chapter id="fbdev">
-     <title>Frame Buffer Library</title>
-
-     <para>
-       The frame buffer drivers depend heavily on four data structures.  
-       These structures are declared in include/linux/fb.h.  They are 
-       fb_info, fb_var_screeninfo, fb_fix_screeninfo and fb_monospecs. 
-       The last three can be made available to and from userland. 
-     </para>
-
-     <para>
-       fb_info defines the current state of a particular video card. 
-       Inside fb_info, there exists a fb_ops structure which is a 
-       collection of needed functions to make fbdev and fbcon work.
-       fb_info is only visible to the kernel.
-     </para>
-
-     <para>
-       fb_var_screeninfo is used to describe the features of a video card 
-       that are user defined.  With fb_var_screeninfo, things such as
-       depth and the resolution may be defined.
-     </para>
-
-     <para>
-       The next structure is fb_fix_screeninfo. This defines the 
-       properties of a card that are created when a mode is set and can't 
-       be changed otherwise.  A good example of this is the start of the 
-       frame buffer memory.  This "locks" the address of the frame buffer
-       memory, so that it cannot be changed or moved.
-     </para>
-
-     <para>
-       The last structure is fb_monospecs. In the old API, there was 
-       little importance for fb_monospecs. This allowed for forbidden things 
-       such as setting a mode of 800x600 on a fix frequency monitor. With 
-       the new API, fb_monospecs prevents such things, and if used 
-       correctly, can prevent a monitor from being cooked.  fb_monospecs
-       will not be useful until kernels 2.5.x.
-     </para>
-
-     <sect1><title>Frame Buffer Memory</title>
-!Edrivers/video/fbmem.c
-     </sect1>
-<!--
-     <sect1><title>Frame Buffer Console</title>
-X!Edrivers/video/console/fbcon.c
-     </sect1>
--->
-     <sect1><title>Frame Buffer Colormap</title>
-!Edrivers/video/fbcmap.c
-     </sect1>
-<!-- FIXME:
-  drivers/video/fbgen.c has no docs, which stuffs up the sgml.  Comment
-  out until somebody adds docs.  KAO
-     <sect1><title>Frame Buffer Generic Functions</title>
-X!Idrivers/video/fbgen.c
-     </sect1>
-KAO -->
-     <sect1><title>Frame Buffer Video Mode Database</title>
-!Idrivers/video/modedb.c
-!Edrivers/video/modedb.c
-     </sect1>
-     <sect1><title>Frame Buffer Macintosh Video Mode Database</title>
-!Edrivers/video/macmodes.c
-     </sect1>
-     <sect1><title>Frame Buffer Fonts</title>
-        <para>
-           Refer to the file drivers/video/console/fonts.c for more information.
-        </para>
-<!-- FIXME: Removed for now since no structured comments in source
-X!Idrivers/video/console/fonts.c
--->
-     </sect1>
-  </chapter>
-
-  <chapter id="input_subsystem">
-     <title>Input Subsystem</title>
-!Iinclude/linux/input.h
-!Edrivers/input/input.c
-!Edrivers/input/ff-core.c
-!Edrivers/input/ff-memless.c
-  </chapter>
-
-  <chapter id="spi">
-      <title>Serial Peripheral Interface (SPI)</title>
-  <para>
-       SPI is the "Serial Peripheral Interface", widely used with
-       embedded systems because it is a simple and efficient
-       interface:  basically a multiplexed shift register.
-       Its three signal wires hold a clock (SCK, often in the range
-       of 1-20 MHz), a "Master Out, Slave In" (MOSI) data line, and
-       a "Master In, Slave Out" (MISO) data line.
-       SPI is a full duplex protocol; for each bit shifted out the
-       MOSI line (one per clock) another is shifted in on the MISO line.
-       Those bits are assembled into words of various sizes on the
-       way to and from system memory.
-       An additional chipselect line is usually active-low (nCS);
-       four signals are normally used for each peripheral, plus
-       sometimes an interrupt.
-  </para>
-  <para>
-       The SPI bus facilities listed here provide a generalized
-       interface to declare SPI busses and devices, manage them
-       according to the standard Linux driver model, and perform
-       input/output operations.
-       At this time, only "master" side interfaces are supported,
-       where Linux talks to SPI peripherals and does not implement
-       such a peripheral itself.
-       (Interfaces to support implementing SPI slaves would
-       necessarily look different.)
-  </para>
-  <para>
-       The programming interface is structured around two kinds of driver,
-       and two kinds of device.
-       A "Controller Driver" abstracts the controller hardware, which may
-       be as simple as a set of GPIO pins or as complex as a pair of FIFOs
-       connected to dual DMA engines on the other side of the SPI shift
-       register (maximizing throughput).  Such drivers bridge between
-       whatever bus they sit on (often the platform bus) and SPI, and
-       expose the SPI side of their device as a
-       <structname>struct spi_master</structname>.
-       SPI devices are children of that master, represented as a
-       <structname>struct spi_device</structname> and manufactured from
-       <structname>struct spi_board_info</structname> descriptors which
-       are usually provided by board-specific initialization code.
-       A <structname>struct spi_driver</structname> is called a
-       "Protocol Driver", and is bound to a spi_device using normal
-       driver model calls.
-  </para>
-  <para>
-       The I/O model is a set of queued messages.  Protocol drivers
-       submit one or more <structname>struct spi_message</structname>
-       objects, which are processed and completed asynchronously.
-       (There are synchronous wrappers, however.)  Messages are
-       built from one or more <structname>struct spi_transfer</structname>
-       objects, each of which wraps a full duplex SPI transfer.
-       A variety of protocol tweaking options are needed, because
-       different chips adopt very different policies for how they
-       use the bits transferred with SPI.
-  </para>
-!Iinclude/linux/spi/spi.h
-!Fdrivers/spi/spi.c spi_register_board_info
-!Edrivers/spi/spi.c
-  </chapter>
-
-  <chapter id="i2c">
-     <title>I<superscript>2</superscript>C and SMBus Subsystem</title>
-
-     <para>
-       I<superscript>2</superscript>C (or without fancy typography, "I2C")
-       is an acronym for the "Inter-IC" bus, a simple bus protocol which is
-       widely used where low data rate communications suffice.
-       Since it's also a licensed trademark, some vendors use another
-       name (such as "Two-Wire Interface", TWI) for the same bus.
-       I2C only needs two signals (SCL for clock, SDA for data), conserving
-       board real estate and minimizing signal quality issues.
-       Most I2C devices use seven bit addresses, and bus speeds of up
-       to 400 kHz; there's a high speed extension (3.4 MHz) that's not yet
-       found wide use.
-       I2C is a multi-master bus; open drain signaling is used to
-       arbitrate between masters, as well as to handshake and to
-       synchronize clocks from slower clients.
-     </para>
-
-     <para>
-       The Linux I2C programming interfaces support only the master
-       side of bus interactions, not the slave side.
-       The programming interface is structured around two kinds of driver,
-       and two kinds of device.
-       An I2C "Adapter Driver" abstracts the controller hardware; it binds
-       to a physical device (perhaps a PCI device or platform_device) and
-       exposes a <structname>struct i2c_adapter</structname> representing
-       each I2C bus segment it manages.
-       On each I2C bus segment will be I2C devices represented by a
-       <structname>struct i2c_client</structname>.  Those devices will
-       be bound to a <structname>struct i2c_driver</structname>,
-       which should follow the standard Linux driver model.
-       (At this writing, a legacy model is more widely used.)
-       There are functions to perform various I2C protocol operations; at
-       this writing all such functions are usable only from task context.
-     </para>
-
-     <para>
-       The System Management Bus (SMBus) is a sibling protocol.  Most SMBus
-       systems are also I2C conformant.  The electrical constraints are
-       tighter for SMBus, and it standardizes particular protocol messages
-       and idioms.  Controllers that support I2C can also support most
-       SMBus operations, but SMBus controllers don't support all the protocol
-       options that an I2C controller will.
-       There are functions to perform various SMBus protocol operations,
-       either using I2C primitives or by issuing SMBus commands to
-       i2c_adapter devices which don't support those I2C operations.
-     </para>
-
-!Iinclude/linux/i2c.h
-!Fdrivers/i2c/i2c-boardinfo.c i2c_register_board_info
-!Edrivers/i2c/i2c-core.c
-  </chapter>
-
   <chapter id="clk">
      <title>Clock Framework</title>
 
index 9a07e38631b0a0d1ed7956db151b667402725419..6bd5f372adec010d18bf0b15d6d5f62d185a4f18 100644 (file)
@@ -93,7 +93,7 @@ the PCI Express Port Bus driver from loading a service driver.
 
 int pcie_port_service_register(struct pcie_port_service_driver *new)
 
-This API replaces the Linux Driver Model's pci_module_init API. A
+This API replaces the Linux Driver Model's pci_register_driver API. A
 service driver should always calls pcie_port_service_register at
 module init. Note that after service driver being loaded, calls
 such as pci_enable_device(dev) and pci_set_master(dev) are no longer
index d9e5d6f41b927c09ce0c98e8dfd6a448bddee236..93feb8444489686b1a9874da9c964f388d5ed316 100644 (file)
@@ -252,10 +252,8 @@ cgroup file system directories.
 When a task is moved from one cgroup to another, it gets a new
 css_set pointer - if there's an already existing css_set with the
 desired collection of cgroups then that group is reused, else a new
-css_set is allocated. Note that the current implementation uses a
-linear search to locate an appropriate existing css_set, so isn't
-very efficient. A future version will use a hash table for better
-performance.
+css_set is allocated. The appropriate existing css_set is located by
+looking into a hash table.
 
 To allow access from a cgroup to the css_sets (and hence tasks)
 that comprise it, a set of cg_cgroup_link objects form a lattice;
index 5c86c258c7913dd9c97da4a3e4f7a0dd666745bc..0611e9528c7c236c3dbdeb3038e762664614dec5 100644 (file)
@@ -142,7 +142,7 @@ into the rest of the kernel, none in performance critical paths:
  - in fork and exit, to attach and detach a task from its cpuset.
  - in sched_setaffinity, to mask the requested CPUs by what's
    allowed in that tasks cpuset.
- - in sched.c migrate_all_tasks(), to keep migrating tasks within
+ - in sched.c migrate_live_tasks(), to keep migrating tasks within
    the CPUs allowed by their cpuset, if possible.
  - in the mbind and set_mempolicy system calls, to mask the requested
    Memory Nodes by what's allowed in that tasks cpuset.
@@ -175,6 +175,10 @@ files describing that cpuset:
  - mem_exclusive flag: is memory placement exclusive?
  - mem_hardwall flag:  is memory allocation hardwalled
  - memory_pressure: measure of how much paging pressure in cpuset
+ - memory_spread_page flag: if set, spread page cache evenly on allowed nodes
+ - memory_spread_slab flag: if set, spread slab cache evenly on allowed nodes
+ - sched_load_balance flag: if set, load balance within CPUs on that cpuset
+ - sched_relax_domain_level: the searching range when migrating tasks
 
 In addition, the root cpuset only has the following file:
  - memory_pressure_enabled flag: compute memory_pressure?
@@ -252,7 +256,7 @@ is causing.
 
 This is useful both on tightly managed systems running a wide mix of
 submitted jobs, which may choose to terminate or re-prioritize jobs that
-are trying to use more memory than allowed on the nodes assigned them,
+are trying to use more memory than allowed on the nodes assigned to them,
 and with tightly coupled, long running, massively parallel scientific
 computing jobs that will dramatically fail to meet required performance
 goals if they start to use more memory than allowed to them.
@@ -378,7 +382,7 @@ as cpusets and sched_setaffinity.
 The algorithmic cost of load balancing and its impact on key shared
 kernel data structures such as the task list increases more than
 linearly with the number of CPUs being balanced.  So the scheduler
-has support to  partition the systems CPUs into a number of sched
+has support to partition the systems CPUs into a number of sched
 domains such that it only load balances within each sched domain.
 Each sched domain covers some subset of the CPUs in the system;
 no two sched domains overlap; some CPUs might not be in any sched
@@ -485,17 +489,22 @@ of CPUs allowed to a cpuset having 'sched_load_balance' enabled.
 The internal kernel cpuset to scheduler interface passes from the
 cpuset code to the scheduler code a partition of the load balanced
 CPUs in the system. This partition is a set of subsets (represented
-as an array of cpumask_t) of CPUs, pairwise disjoint, that cover all
-the CPUs that must be load balanced.
-
-Whenever the 'sched_load_balance' flag changes, or CPUs come or go
-from a cpuset with this flag enabled, or a cpuset with this flag
-enabled is removed, the cpuset code builds a new such partition and
-passes it to the scheduler sched domain setup code, to have the sched
-domains rebuilt as necessary.
+as an array of struct cpumask) of CPUs, pairwise disjoint, that cover
+all the CPUs that must be load balanced.
+
+The cpuset code builds a new such partition and passes it to the
+scheduler sched domain setup code, to have the sched domains rebuilt
+as necessary, whenever:
+ - the 'sched_load_balance' flag of a cpuset with non-empty CPUs changes,
+ - or CPUs come or go from a cpuset with this flag enabled,
+ - or 'sched_relax_domain_level' value of a cpuset with non-empty CPUs
+   and with this flag enabled changes,
+ - or a cpuset with non-empty CPUs and with this flag enabled is removed,
+ - or a cpu is offlined/onlined.
 
 This partition exactly defines what sched domains the scheduler should
-setup - one sched domain for each element (cpumask_t) in the partition.
+setup - one sched domain for each element (struct cpumask) in the
+partition.
 
 The scheduler remembers the currently active sched domain partitions.
 When the scheduler routine partition_sched_domains() is invoked from
@@ -559,7 +568,7 @@ domain, the largest value among those is used.  Be careful, if one
 requests 0 and others are -1 then 0 is used.
 
 Note that modifying this file will have both good and bad effects,
-and whether it is acceptable or not will be depend on your situation.
+and whether it is acceptable or not depends on your situation.
 Don't modify this file if you are not sure.
 
 If your situation is:
@@ -600,19 +609,15 @@ to allocate a page of memory for that task.
 
 If a cpuset has its 'cpus' modified, then each task in that cpuset
 will have its allowed CPU placement changed immediately.  Similarly,
-if a tasks pid is written to a cpusets 'tasks' file, in either its
-current cpuset or another cpuset, then its allowed CPU placement is
-changed immediately.  If such a task had been bound to some subset
-of its cpuset using the sched_setaffinity() call, the task will be
-allowed to run on any CPU allowed in its new cpuset, negating the
-affect of the prior sched_setaffinity() call.
+if a tasks pid is written to another cpusets 'tasks' file, then its
+allowed CPU placement is changed immediately.  If such a task had been
+bound to some subset of its cpuset using the sched_setaffinity() call,
+the task will be allowed to run on any CPU allowed in its new cpuset,
+negating the effect of the prior sched_setaffinity() call.
 
 In summary, the memory placement of a task whose cpuset is changed is
 updated by the kernel, on the next allocation of a page for that task,
-but the processor placement is not updated, until that tasks pid is
-rewritten to the 'tasks' file of its cpuset.  This is done to avoid
-impacting the scheduler code in the kernel with a check for changes
-in a tasks processor placement.
+and the processor placement is updated immediately.
 
 Normally, once a page is allocated (given a physical page
 of main memory) then that page stays on whatever node it
@@ -681,10 +686,14 @@ and then start a subshell 'sh' in that cpuset:
   # The next line should display '/Charlie'
   cat /proc/self/cpuset
 
-In the future, a C library interface to cpusets will likely be
-available.  For now, the only way to query or modify cpusets is
-via the cpuset file system, using the various cd, mkdir, echo, cat,
-rmdir commands from the shell, or their equivalent from C.
+There are ways to query or modify cpusets:
+ - via the cpuset file system directly, using the various cd, mkdir, echo,
+   cat, rmdir commands from the shell, or their equivalent from C.
+ - via the C library libcpuset.
+ - via the C library libcgroup.
+   (http://sourceforge.net/proects/libcg/)
+ - via the python application cset.
+   (http://developer.novell.com/wiki/index.php/Cpuset)
 
 The sched_setaffinity calls can also be done at the shell prompt using
 SGI's runon or Robert Love's taskset.  The mbind and set_mempolicy
@@ -756,7 +765,7 @@ mount -t cpuset X /dev/cpuset
 
 is equivalent to
 
-mount -t cgroup -ocpuset X /dev/cpuset
+mount -t cgroup -ocpuset,noprefix X /dev/cpuset
 echo "/sbin/cpuset_release_agent" > /dev/cpuset/release_agent
 
 2.2 Adding/removing cpus
index a05ec50f8004dd65f29c87579612389f93660187..a7cbfff40d077047f76463377381b269b5d41fc4 100644 (file)
@@ -127,9 +127,11 @@ void unlock_device(struct device * dev);
 Attributes
 ~~~~~~~~~~
 struct device_attribute {
-        struct attribute        attr;
-        ssize_t (*show)(struct device * dev, char * buf, size_t count, loff_t off);
-        ssize_t (*store)(struct device * dev, const char * buf, size_t count, loff_t off);
+       struct attribute        attr;
+       ssize_t (*show)(struct device *dev, struct device_attribute *attr,
+                       char *buf);
+       ssize_t (*store)(struct device *dev, struct device_attribute *attr,
+                        const char *buf, size_t count);
 };
 
 Attributes of devices can be exported via drivers using a simple
diff --git a/Documentation/dvb/README.flexcop b/Documentation/dvb/README.flexcop
deleted file mode 100644 (file)
index 5515469..0000000
+++ /dev/null
@@ -1,205 +0,0 @@
-This README escorted the skystar2-driver rewriting procedure. It describes the
-state of the new flexcop-driver set and some internals are written down here
-too.
-
-This document hopefully describes things about the flexcop and its
-device-offsprings. Goal was to write an easy-to-write and easy-to-read set of
-drivers based on the skystar2.c and other information.
-
-Remark: flexcop-pci.c was a copy of skystar2.c, but every line has been
-touched and rewritten.
-
-History & News
-==============
-  2005-04-01 - correct USB ISOC transfers (thanks to Vadim Catana)
-
-
-
-
-General coding processing
-=========================
-
-We should proceed as follows (as long as no one complains):
-
-0) Think before start writing code!
-
-1) rewriting the skystar2.c with the help of the flexcop register descriptions
-and splitting up the files to a pci-bus-part and a flexcop-part.
-The new driver will be called b2c2-flexcop-pci.ko/b2c2-flexcop-usb.ko for the
-device-specific part and b2c2-flexcop.ko for the common flexcop-functions.
-
-2) Search for errors in the leftover of flexcop-pci.c (compare with pluto2.c
-and other pci drivers)
-
-3) make some beautification (see 'Improvements when rewriting (refactoring) is
-done')
-
-4) Testing the new driver and maybe substitute the skystar2.c with it, to reach
-a wider tester audience.
-
-5) creating an usb-bus-part using the already written flexcop code for the pci
-card.
-
-Idea: create a kernel-object for the flexcop and export all important
-functions. This option saves kernel-memory, but maybe a lot of functions have
-to be exported to kernel namespace.
-
-
-Current situation
-=================
-
-0) Done :)
-1) Done (some minor issues left)
-2) Done
-3) Not ready yet, more information is necessary
-4) next to be done (see the table below)
-5) USB driver is working (yes, there are some minor issues)
-
-What seems to be ready?
------------------------
-
-1) Rewriting
-1a) i2c is cut off from the flexcop-pci.c and seems to work
-1b) moved tuner and demod stuff from flexcop-pci.c to flexcop-tuner-fe.c
-1c) moved lnb and diseqc stuff from flexcop-pci.c to flexcop-tuner-fe.c
-1e) eeprom (reading MAC address)
-1d) sram (no dynamic sll size detection (commented out) (using default as JJ told me))
-1f) misc. register accesses for reading parameters (e.g. resetting, revision)
-1g) pid/mac filter (flexcop-hw-filter.c)
-1i) dvb-stuff initialization in flexcop.c (done)
-1h) dma stuff (now just using the size-irq, instead of all-together, to be done)
-1j) remove flexcop initialization from flexcop-pci.c completely (done)
-1l) use a well working dma IRQ method (done, see 'Known bugs and problems and TODO')
-1k) cleanup flexcop-files (remove unused EXPORT_SYMBOLs, make static from
-non-static where possible, moved code to proper places)
-
-2) Search for errors in the leftover of flexcop-pci.c (partially done)
-5a) add MAC address reading
-5c) feeding of ISOC data to the software demux (format of the isochronous data
-and speed optimization, no real error) (thanks to Vadim Catana)
-
-What to do in the near future?
---------------------------------------
-(no special order here)
-
-5) USB driver
-5b) optimize isoc-transfer (submitting/killing isoc URBs when transfer is starting)
-
-Testing changes
----------------
-
-O             = item is working
-P             = item is partially working
-X             = item is not working
-N             = item does not apply here
-<empty field> = item need to be examined
-
-       | PCI                               | USB
-item   | mt352 | nxt2002 | stv0299 | mt312 | mt352 | nxt2002 | stv0299 | mt312
--------+-------+---------+---------+-------+-------+---------+---------+-------
-1a)    | O     |         |         |       | N     | N       | N       | N
-1b)    | O     |         |         |       |       |         | O       |
-1c)    | N     | N       |         |       | N     | N       | O       |
-1d)    |                 O                 |                 O
-1e)    |                 O                 |                 O
-1f)    |                                   P
-1g)    |                                   O
-1h)    |                 P                 |
-1i)    |                 O                 |                 N
-1j)    |                 O                 |                 N
-1l)    |                 O                 |                 N
-2)     |                 O                 |                 N
-5a)    |                 N                 |                 O
-5b)*   |                 N                 |
-5c)    |                 N                 |                 O
-
-* - not done yet
-
-Known bugs and problems and TODO
---------------------------------
-
-1g/h/l) when pid filtering is enabled on the pci card
-
-DMA usage currently:
-  The DMA is splitted in 2 equal-sized subbuffers. The Flexcop writes to first
-  address and triggers an IRQ when it's full and starts writing to the second
-  address. When the second address is full, the IRQ is triggered again, and
-  the flexcop writes to first address again, and so on.
-  The buffersize of each address is currently 640*188 bytes.
-
-  Problem is, when using hw-pid-filtering and doing some low-bandwidth
-  operation (like scanning) the buffers won't be filled enough to trigger
-  the IRQ. That's why:
-
-  When PID filtering is activated, the timer IRQ is used. Every 1.97 ms the IRQ
-  is triggered.  Is the current write address of DMA1 different to the one
-  during the last IRQ, then the data is passed to the demuxer.
-
-  There is an additional DMA-IRQ-method: packet count IRQ. This isn't
-  implemented correctly yet.
-
-  The solution is to disable HW PID filtering, but I don't know how the DVB
-  API software demux behaves on slow systems with 45MBit/s TS.
-
-Solved bugs :)
---------------
-1g) pid-filtering (somehow pid index 4 and 5 (EMM_PID and ECM_PID) aren't
-working)
-SOLUTION: also index 0 was affected, because net_translation is done for
-these indexes by default
-
-5b) isochronous transfer does only work in the first attempt (for the Sky2PC
-USB, Air2PC is working) SOLUTION: the flexcop was going asleep and never really
-woke up again (don't know if this need fixes, see
-flexcop-fe-tuner.c:flexcop_sleep)
-
-NEWS: when the driver is loaded and unloaded and loaded again (w/o doing
-anything in the while the driver is loaded the first time), no transfers take
-place anymore.
-
-Improvements when rewriting (refactoring) is done
-=================================================
-
-- split sleeping of the flexcop (misc_204.ACPI3_sig = 1;) from lnb_control
-  (enable sleeping for other demods than dvb-s)
-- add support for CableStar (stv0297 Microtune 203x/ALPS) (almost done, incompatibilities with the Nexus-CA)
-
-Debugging
----------
-- add verbose debugging to skystar2.c (dump the reg_dw_data) and compare it
-  with this flexcop, this is important, because i2c is now using the
-  flexcop_ibi_value union from flexcop-reg.h (do you have a better idea for
-  that, please tell us so).
-
-Everything which is identical in the following table, can be put into a common
-flexcop-module.
-
-                 PCI                  USB
--------------------------------------------------------------------------------
-Different:
-Register access:  accessing IO memory  USB control message
-I2C bus:          I2C bus of the FC    USB control message
-Data transfer:    DMA                  isochronous transfer
-EEPROM transfer:  through i2c bus      not clear yet
-
-Identical:
-Streaming:                 accessing registers
-PID Filtering:             accessing registers
-Sram destinations:         accessing registers
-Tuner/Demod:                     I2C bus
-DVB-stuff:            can be written for common use
-
-Acknowledgements (just for the rewriting part)
-================
-
-Bjarne Steinsbo thought a lot in the first place of the pci part for this code
-sharing idea.
-
-Andreas Oberritter for providing a recent PCI initialization template
-(pluto2.c).
-
-Boleslaw Ciesielski for pointing out a problem with firmware loader.
-
-Vadim Catana for correcting the USB transfer.
-
-comments, critics and ideas to linux-dvb@linuxtv.org.
index cdf6ee4b2da1804e31d32a4bb77d86b12b588228..3f435ffb289c71d297d8e25bdffaa1d37d0ab2f8 100644 (file)
@@ -1,5 +1,5 @@
-How to set up the Technisat devices
-===================================
+How to set up the Technisat/B2C2 Flexcop devices
+================================================
 
 1) Find out what device you have
 ================================
@@ -16,54 +16,60 @@ DVB: registering frontend 0 (Conexant CX24123/CX24109)...
 
 If the Technisat is the only TV device in your box get rid of unnecessary modules and check this one:
 "Multimedia devices" => "Customise analog and hybrid tuner modules to build"
-In this directory uncheck every driver which is activated there.
+In this directory uncheck every driver which is activated there (except "Simple tuner support" for case 9 only).
 
 Then please activate:
 2a) Main module part:
 
 a.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters"
-b.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" => "Technisat/B2C2 Air/Sky/Cable2PC PCI" in case of a PCI card OR
+b.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" => "Technisat/B2C2 Air/Sky/Cable2PC PCI" in case of a PCI card
+OR
 c.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" => "Technisat/B2C2 Air/Sky/Cable2PC USB" in case of an USB 1.1 adapter
 d.)"Multimedia devices" => "DVB/ATSC adapters" => "Technisat/B2C2 FlexcopII(b) and FlexCopIII adapters" => "Enable debug for the B2C2 FlexCop drivers"
 Notice: d.) is helpful for troubleshooting
 
 2b) Frontend module part:
 
-1.) Revision 2.3:
+1.) SkyStar DVB-S Revision 2.3:
 a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
 b.)"Multimedia devices" => "Customise DVB frontends" => "Zarlink VP310/MT312/ZL10313 based"
 
-2.) Revision 2.6:
+2.) SkyStar DVB-S Revision 2.6:
 a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
 b.)"Multimedia devices" => "Customise DVB frontends" => "ST STV0299 based"
 
-3.) Revision 2.7:
+3.) SkyStar DVB-S Revision 2.7:
 a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
 b.)"Multimedia devices" => "Customise DVB frontends" => "Samsung S5H1420 based"
 c.)"Multimedia devices" => "Customise DVB frontends" => "Integrant ITD1000 Zero IF tuner for DVB-S/DSS"
 d.)"Multimedia devices" => "Customise DVB frontends" => "ISL6421 SEC controller"
 
-4.) Revision 2.8:
+4.) SkyStar DVB-S Revision 2.8:
 a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
 b.)"Multimedia devices" => "Customise DVB frontends" => "Conexant CX24113/CX24128 tuner for DVB-S/DSS"
 c.)"Multimedia devices" => "Customise DVB frontends" => "Conexant CX24123 based"
 d.)"Multimedia devices" => "Customise DVB frontends" => "ISL6421 SEC controller"
 
-5.) DVB-T card:
+5.) AirStar DVB-T card:
 a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
 b.)"Multimedia devices" => "Customise DVB frontends" => "Zarlink MT352 based"
 
-6.) DVB-C card:
+6.) CableStar DVB-C card:
 a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
 b.)"Multimedia devices" => "Customise DVB frontends" => "ST STV0297 based"
 
-7.) ATSC card 1st generation:
+7.) AirStar ATSC card 1st generation:
 a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
 b.)"Multimedia devices" => "Customise DVB frontends" => "Broadcom BCM3510"
 
-8.) ATSC card 2nd generation:
+8.) AirStar ATSC card 2nd generation:
 a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
 b.)"Multimedia devices" => "Customise DVB frontends" => "NxtWave Communications NXT2002/NXT2004 based"
-c.)"Multimedia devices" => "Customise DVB frontends" => "LG Electronics LGDT3302/LGDT3303 based"
+c.)"Multimedia devices" => "Customise DVB frontends" => "Generic I2C PLL based tuners"
 
-Author: Uwe Bugla <uwe.bugla@gmx.de> December 2008
+9.) AirStar ATSC card 3rd generation:
+a.)"Multimedia devices" => "Customise DVB frontends" => "Customise the frontend modules to build"
+b.)"Multimedia devices" => "Customise DVB frontends" => "LG Electronics LGDT3302/LGDT3303 based"
+c.)"Multimedia devices" => "Customise analog and hybrid tuner modules to build" => "Simple tuner support"
+
+Author: Uwe Bugla <uwe.bugla@gmx.de> February 2009
index a87be42f82117cb94c5320baeda799becbdc6933..830bad7cce0f946ba356e7aff283775d270063f1 100644 (file)
@@ -1478,6 +1478,13 @@ of problems on the network like duplicate address or bad checksums. Normally,
 this should be enabled, but if the problem persists the messages can be
 disabled.
 
+netdev_budget
+-------------
+
+Maximum number of packets taken from all interfaces in one polling cycle (NAPI
+poll). In one polling cycle interfaces which are registered to polling are
+probed in a round-robin manner. The limit of packets in one such probe can be
+set per-device via sysfs class/net/<device>/weight .
 
 netdev_max_backlog
 ------------------
index 9e9c348275a96fd362acf9916d2789be8a08c4c8..7e81e37c0b1ec0ccbea30a92ffbf70f495ffdbd0 100644 (file)
@@ -2,8 +2,10 @@
 sysfs - _The_ filesystem for exporting kernel objects. 
 
 Patrick Mochel <mochel@osdl.org>
+Mike Murphy <mamurph@cs.clemson.edu>
 
-10 January 2003
+Revised:    22 February 2009
+Original:   10 January 2003
 
 
 What it is:
@@ -64,12 +66,13 @@ An attribute definition is simply:
 
 struct attribute {
         char                    * name;
+        struct module          *owner;
         mode_t                  mode;
 };
 
 
-int sysfs_create_file(struct kobject * kobj, struct attribute * attr);
-void sysfs_remove_file(struct kobject * kobj, struct attribute * attr);
+int sysfs_create_file(struct kobject * kobj, const struct attribute * attr);
+void sysfs_remove_file(struct kobject * kobj, const struct attribute * attr);
 
 
 A bare attribute contains no means to read or write the value of the
@@ -80,9 +83,11 @@ a specific object type.
 For example, the driver model defines struct device_attribute like:
 
 struct device_attribute {
-        struct attribute        attr;
-        ssize_t (*show)(struct device * dev, char * buf);
-        ssize_t (*store)(struct device * dev, const char * buf);
+       struct attribute        attr;
+       ssize_t (*show)(struct device *dev, struct device_attribute *attr,
+                       char *buf);
+       ssize_t (*store)(struct device *dev, struct device_attribute *attr,
+                        const char *buf, size_t count);
 };
 
 int device_create_file(struct device *, struct device_attribute *);
@@ -90,12 +95,8 @@ void device_remove_file(struct device *, struct device_attribute *);
 
 It also defines this helper for defining device attributes: 
 
-#define DEVICE_ATTR(_name, _mode, _show, _store)      \
-struct device_attribute dev_attr_##_name = {            \
-        .attr = {.name  = __stringify(_name) , .mode   = _mode },      \
-        .show   = _show,                                \
-        .store  = _store,                               \
-};
+#define DEVICE_ATTR(_name, _mode, _show, _store) \
+struct device_attribute dev_attr_##_name = __ATTR(_name, _mode, _show, _store)
 
 For example, declaring
 
@@ -107,9 +108,9 @@ static struct device_attribute dev_attr_foo = {
        .attr   = {
                .name = "foo",
                .mode = S_IWUSR | S_IRUGO,
+               .show = show_foo,
+               .store = store_foo,
        },
-       .show = show_foo,
-       .store = store_foo,
 };
 
 
@@ -161,10 +162,12 @@ To read or write attributes, show() or store() methods must be
 specified when declaring the attribute. The method types should be as
 simple as those defined for device attributes:
 
-        ssize_t (*show)(struct device * dev, char * buf);
-        ssize_t (*store)(struct device * dev, const char * buf);
+ssize_t (*show)(struct device * dev, struct device_attribute * attr,
+                char * buf);
+ssize_t (*store)(struct device * dev, struct device_attribute * attr,
+                 const char * buf);
 
-IOW, they should take only an object and a buffer as parameters. 
+IOW, they should take only an object, an attribute, and a buffer as parameters.
 
 
 sysfs allocates a buffer of size (PAGE_SIZE) and passes it to the
@@ -299,14 +302,16 @@ The following interface layers currently exist in sysfs:
 Structure:
 
 struct device_attribute {
-        struct attribute        attr;
-        ssize_t (*show)(struct device * dev, char * buf);
-        ssize_t (*store)(struct device * dev, const char * buf);
+       struct attribute        attr;
+       ssize_t (*show)(struct device *dev, struct device_attribute *attr,
+                       char *buf);
+       ssize_t (*store)(struct device *dev, struct device_attribute *attr,
+                        const char *buf, size_t count);
 };
 
 Declaring:
 
-DEVICE_ATTR(_name, _str, _mode, _show, _store);
+DEVICE_ATTR(_name, _mode, _show, _store);
 
 Creation/Removal:
 
@@ -342,7 +347,8 @@ Structure:
 struct driver_attribute {
         struct attribute        attr;
         ssize_t (*show)(struct device_driver *, char * buf);
-        ssize_t (*store)(struct device_driver *, const char * buf);
+        ssize_t (*store)(struct device_driver *, const char * buf,
+                         size_t count);
 };
 
 Declaring:
diff --git a/Documentation/hwmon/hpfall.c b/Documentation/hwmon/hpfall.c
new file mode 100644 (file)
index 0000000..bbea1cc
--- /dev/null
@@ -0,0 +1,101 @@
+/* Disk protection for HP machines.
+ *
+ * Copyright 2008 Eric Piel
+ * Copyright 2009 Pavel Machek <pavel@suse.cz>
+ *
+ * GPLv2.
+ */
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <string.h>
+#include <stdint.h>
+#include <errno.h>
+#include <signal.h>
+
+void write_int(char *path, int i)
+{
+       char buf[1024];
+       int fd = open(path, O_RDWR);
+       if (fd < 0) {
+               perror("open");
+               exit(1);
+       }
+       sprintf(buf, "%d", i);
+       if (write(fd, buf, strlen(buf)) != strlen(buf)) {
+               perror("write");
+               exit(1);
+       }
+       close(fd);
+}
+
+void set_led(int on)
+{
+       write_int("/sys/class/leds/hp::hddprotect/brightness", on);
+}
+
+void protect(int seconds)
+{
+       write_int("/sys/block/sda/device/unload_heads", seconds*1000);
+}
+
+int on_ac(void)
+{
+//     /sys/class/power_supply/AC0/online
+}
+
+int lid_open(void)
+{
+//     /proc/acpi/button/lid/LID/state
+}
+
+void ignore_me(void)
+{
+       protect(0);
+       set_led(0);
+
+}
+
+int main(int argc, char* argv[])
+{
+       int fd, ret;
+
+       fd = open("/dev/freefall", O_RDONLY);
+       if (fd < 0) {
+               perror("open");
+               return EXIT_FAILURE;
+       }
+
+       signal(SIGALRM, ignore_me);
+
+       for (;;) {
+              unsigned char count;
+
+               ret = read(fd, &count, sizeof(count));
+              alarm(0);
+              if ((ret == -1) && (errno == EINTR)) {
+                      /* Alarm expired, time to unpark the heads */
+                      continue;
+              }
+
+               if (ret != sizeof(count)) {
+                       perror("read");
+                       break;
+               }
+
+              protect(21);
+              set_led(1);
+              if (1 || on_ac() || lid_open()) {
+                      alarm(2);
+              } else {
+                      alarm(20);
+              }
+       }
+
+       close(fd);
+       return EXIT_SUCCESS;
+}
index 0fcfc4a7ccdc0c9b7934a42054d60139e3320a4a..287f8c902656db40353954b967b06503d517dc70 100644 (file)
@@ -33,6 +33,14 @@ rate - reports the sampling rate of the accelerometer device in HZ
 This driver also provides an absolute input class device, allowing
 the laptop to act as a pinball machine-esque joystick.
 
+Another feature of the driver is misc device called "freefall" that
+acts similar to /dev/rtc and reacts on free-fall interrupts received
+from the device. It supports blocking operations, poll/select and
+fasync operation modes. You must read 1 bytes from the device.  The
+result is number of free-fall interrupts since the last successful
+read (or 255 if number of interrupts would not fit).
+
+
 Axes orientation
 ----------------
 
index b182626739ea7e7fb5c4ca98ce02b8bc76b21608..54f21a5c262b02ef6cb4718f72b8357693197cf3 100644 (file)
@@ -114,7 +114,7 @@ In addition, the following text indicates that the option:
 Parameters denoted with BOOT are actually interpreted by the boot
 loader, and have no meaning to the kernel directly.
 Do not modify the syntax of boot loader parameters without extreme
-need or coordination with <Documentation/x86/i386/boot.txt>.
+need or coordination with <Documentation/x86/boot.txt>.
 
 There are also arch-specific kernel-parameters not documented here.
 See for example <Documentation/x86/x86_64/boot-options.txt>.
@@ -134,7 +134,7 @@ and is between 256 and 4096 characters. It is defined in the file
 
        acpi=           [HW,ACPI,X86-64,i386]
                        Advanced Configuration and Power Interface
-                       Format: { force | off | ht | strict | noirq }
+                       Format: { force | off | ht | strict | noirq | rsdt }
                        force -- enable ACPI if default was off
                        off -- disable ACPI if default was on
                        noirq -- do not use ACPI for IRQ routing
@@ -868,8 +868,10 @@ and is between 256 and 4096 characters. It is defined in the file
        icn=            [HW,ISDN]
                        Format: <io>[,<membase>[,<icn_id>[,<icn_id2>]]]
 
-       ide=            [HW] (E)IDE subsystem
-                       Format: ide=nodma or ide=doubler
+       ide-core.nodma= [HW] (E)IDE subsystem
+                       Format: =0.0 to prevent dma on hda, =0.1 hdb =1.0 hdc
+                       .vlb_clock .pci_clock .noflush .noprobe .nowerr .cdrom
+                       .chs .ignore_cable are additional options
                        See Documentation/ide/ide.txt.
 
        idebus=         [HW] (E)IDE subsystem - VLB/PCI bus speed
@@ -2449,7 +2451,7 @@ and is between 256 and 4096 characters. It is defined in the file
                        See Documentation/fb/modedb.txt.
 
        vga=            [BOOT,X86-32] Select a particular video mode
-                       See Documentation/x86/i386/boot.txt and
+                       See Documentation/x86/boot.txt and
                        Documentation/svga.txt.
                        Use vga=ask for menu.
                        This is actually a boot loader parameter; the value is
index ff3f219ee4d7bc590ecea9a9144c094f78f07dbd..ec5de02f543f68c84b2f88712a478c827d033ffa 100644 (file)
@@ -2,7 +2,7 @@
 
 ip_forward - BOOLEAN
        0 - disabled (default)
-       not 0 - enabled 
+       not 0 - enabled
 
        Forward Packets between interfaces.
 
@@ -36,49 +36,49 @@ rt_cache_rebuild_count - INTEGER
 IP Fragmentation:
 
 ipfrag_high_thresh - INTEGER
-       Maximum memory used to reassemble IP fragments. When 
+       Maximum memory used to reassemble IP fragments. When
        ipfrag_high_thresh bytes of memory is allocated for this purpose,
        the fragment handler will toss packets until ipfrag_low_thresh
        is reached.
-       
+
 ipfrag_low_thresh - INTEGER
-       See ipfrag_high_thresh  
+       See ipfrag_high_thresh
 
 ipfrag_time - INTEGER
-       Time in seconds to keep an IP fragment in memory.       
+       Time in seconds to keep an IP fragment in memory.
 
 ipfrag_secret_interval - INTEGER
-       Regeneration interval (in seconds) of the hash secret (or lifetime 
+       Regeneration interval (in seconds) of the hash secret (or lifetime
        for the hash secret) for IP fragments.
        Default: 600
 
 ipfrag_max_dist - INTEGER
-       ipfrag_max_dist is a non-negative integer value which defines the 
-       maximum "disorder" which is allowed among fragments which share a 
-       common IP source address. Note that reordering of packets is 
-       not unusual, but if a large number of fragments arrive from a source 
-       IP address while a particular fragment queue remains incomplete, it 
-       probably indicates that one or more fragments belonging to that queue 
-       have been lost. When ipfrag_max_dist is positive, an additional check 
-       is done on fragments before they are added to a reassembly queue - if 
-       ipfrag_max_dist (or more) fragments have arrived from a particular IP 
-       address between additions to any IP fragment queue using that source 
-       address, it's presumed that one or more fragments in the queue are 
-       lost. The existing fragment queue will be dropped, and a new one 
+       ipfrag_max_dist is a non-negative integer value which defines the
+       maximum "disorder" which is allowed among fragments which share a
+       common IP source address. Note that reordering of packets is
+       not unusual, but if a large number of fragments arrive from a source
+       IP address while a particular fragment queue remains incomplete, it
+       probably indicates that one or more fragments belonging to that queue
+       have been lost. When ipfrag_max_dist is positive, an additional check
+       is done on fragments before they are added to a reassembly queue - if
+       ipfrag_max_dist (or more) fragments have arrived from a particular IP
+       address between additions to any IP fragment queue using that source
+       address, it's presumed that one or more fragments in the queue are
+       lost. The existing fragment queue will be dropped, and a new one
        started. An ipfrag_max_dist value of zero disables this check.
 
        Using a very small value, e.g. 1 or 2, for ipfrag_max_dist can
        result in unnecessarily dropping fragment queues when normal
-       reordering of packets occurs, which could lead to poor application 
-       performance. Using a very large value, e.g. 50000, increases the 
-       likelihood of incorrectly reassembling IP fragments that originate 
+       reordering of packets occurs, which could lead to poor application
+       performance. Using a very large value, e.g. 50000, increases the
+       likelihood of incorrectly reassembling IP fragments that originate
        from different IP datagrams, which could result in data corruption.
        Default: 64
 
 INET peer storage:
 
 inet_peer_threshold - INTEGER
-       The approximate size of the storage.  Starting from this threshold      
+       The approximate size of the storage.  Starting from this threshold
        entries will be thrown aggressively.  This threshold also determines
        entries' time-to-live and time intervals between garbage collection
        passes.  More entries, less time-to-live, less GC interval.
@@ -105,7 +105,7 @@ inet_peer_gc_maxtime - INTEGER
        in effect under low (or absent) memory pressure on the pool.
        Measured in seconds.
 
-TCP variables: 
+TCP variables:
 
 somaxconn - INTEGER
        Limit of socket listen() backlog, known in userspace as SOMAXCONN.
@@ -310,7 +310,7 @@ tcp_orphan_retries - INTEGER
 
 tcp_reordering - INTEGER
        Maximal reordering of packets in a TCP stream.
-       Default: 3      
+       Default: 3
 
 tcp_retrans_collapse - BOOLEAN
        Bug-to-bug compatibility with some broken printers.
@@ -521,7 +521,7 @@ IP Variables:
 
 ip_local_port_range - 2 INTEGERS
        Defines the local port range that is used by TCP and UDP to
-       choose the local port. The first number is the first, the 
+       choose the local port. The first number is the first, the
        second the last local port number. Default value depends on
        amount of memory available on the system:
        > 128Mb 32768-61000
@@ -594,12 +594,12 @@ icmp_errors_use_inbound_ifaddr - BOOLEAN
 
        If zero, icmp error messages are sent with the primary address of
        the exiting interface.
+
        If non-zero, the message will be sent with the primary address of
        the interface that received the packet that caused the icmp error.
        This is the behaviour network many administrators will expect from
        a router. And it can make debugging complicated network layouts
-       much easier. 
+       much easier.
 
        Note that if no primary address exists for the interface selected,
        then the primary address of the first non-loopback interface that
@@ -611,7 +611,7 @@ igmp_max_memberships - INTEGER
        Change the maximum number of multicast groups we can subscribe to.
        Default: 20
 
-conf/interface/*  changes special settings per interface (where "interface" is 
+conf/interface/*  changes special settings per interface (where "interface" is
                  the name of your network interface)
 conf/all/*       is special, changes the settings for all interfaces
 
@@ -625,11 +625,11 @@ log_martians - BOOLEAN
 accept_redirects - BOOLEAN
        Accept ICMP redirect messages.
        accept_redirects for the interface will be enabled if:
-       - both conf/{all,interface}/accept_redirects are TRUE in the case forwarding
-         for the interface is enabled
+       - both conf/{all,interface}/accept_redirects are TRUE in the case
+         forwarding for the interface is enabled
        or
-       - at least one of conf/{all,interface}/accept_redirects is TRUE in the case
-         forwarding for the interface is disabled
+       - at least one of conf/{all,interface}/accept_redirects is TRUE in the
+         case forwarding for the interface is disabled
        accept_redirects for the interface will be disabled otherwise
        default TRUE (host)
                FALSE (router)
@@ -640,8 +640,8 @@ forwarding - BOOLEAN
 mc_forwarding - BOOLEAN
        Do multicast routing. The kernel needs to be compiled with CONFIG_MROUTE
        and a multicast routing daemon is required.
-       conf/all/mc_forwarding must also be set to TRUE to enable multicast routing
-       for the interface
+       conf/all/mc_forwarding must also be set to TRUE to enable multicast
+       routing for the interface
 
 medium_id - INTEGER
        Integer value used to differentiate the devices by the medium they
@@ -649,7 +649,7 @@ medium_id - INTEGER
        the broadcast packets are received only on one of them.
        The default value 0 means that the device is the only interface
        to its medium, value of -1 means that medium is not known.
-       
+
        Currently, it is used to change the proxy_arp behavior:
        the proxy_arp feature is enabled for packets forwarded between
        two devices attached to different media.
@@ -699,16 +699,22 @@ accept_source_route - BOOLEAN
        default TRUE (router)
                FALSE (host)
 
-rp_filter - BOOLEAN
-       1 - do source validation by reversed path, as specified in RFC1812
-           Recommended option for single homed hosts and stub network
-           routers. Could cause troubles for complicated (not loop free)
-           networks running a slow unreliable protocol (sort of RIP),
-           or using static routes.
-
+rp_filter - INTEGER
        0 - No source validation.
-
-       conf/all/rp_filter must also be set to TRUE to do source validation
+       1 - Strict mode as defined in RFC3704 Strict Reverse Path
+           Each incoming packet is tested against the FIB and if the interface
+           is not the best reverse path the packet check will fail.
+           By default failed packets are discarded.
+       2 - Loose mode as defined in RFC3704 Loose Reverse Path
+           Each incoming packet's source address is also tested against the FIB
+           and if the source address is not reachable via any interface
+           the packet check will fail.
+
+       Current recommended practice in RFC3704 is to enable strict mode
+       to prevent IP spoofing from DDos attacks. If using asymmetric routing
+       or other complicated routing, then loose mode is recommended.
+
+       conf/all/rp_filter must also be set to non-zero to do source validation
        on the interface
 
        Default value is 0. Note that some distributions enable it
@@ -829,7 +835,7 @@ apply to IPv6 [XXX?].
 
 bindv6only - BOOLEAN
        Default value for IPV6_V6ONLY socket option,
-       which restricts use of the IPv6 socket to IPv6 communication 
+       which restricts use of the IPv6 socket to IPv6 communication
        only.
                TRUE: disable IPv4-mapped address feature
                FALSE: enable IPv4-mapped address feature
@@ -839,19 +845,19 @@ bindv6only - BOOLEAN
 IPv6 Fragmentation:
 
 ip6frag_high_thresh - INTEGER
-       Maximum memory used to reassemble IPv6 fragments. When 
+       Maximum memory used to reassemble IPv6 fragments. When
        ip6frag_high_thresh bytes of memory is allocated for this purpose,
        the fragment handler will toss packets until ip6frag_low_thresh
        is reached.
-       
+
 ip6frag_low_thresh - INTEGER
-       See ip6frag_high_thresh 
+       See ip6frag_high_thresh
 
 ip6frag_time - INTEGER
        Time in seconds to keep an IPv6 fragment in memory.
 
 ip6frag_secret_interval - INTEGER
-       Regeneration interval (in seconds) of the hash secret (or lifetime 
+       Regeneration interval (in seconds) of the hash secret (or lifetime
        for the hash secret) for IPv6 fragments.
        Default: 600
 
@@ -860,17 +866,17 @@ conf/default/*:
 
 
 conf/all/*:
-       Change all the interface-specific settings.  
+       Change all the interface-specific settings.
 
        [XXX:  Other special features than forwarding?]
 
 conf/all/forwarding - BOOLEAN
-       Enable global IPv6 forwarding between all interfaces.  
+       Enable global IPv6 forwarding between all interfaces.
 
-       IPv4 and IPv6 work differently here; e.g. netfilter must be used 
+       IPv4 and IPv6 work differently here; e.g. netfilter must be used
        to control which interfaces may forward packets and which not.
 
-       This also sets all interfaces' Host/Router setting 
+       This also sets all interfaces' Host/Router setting
        'forwarding' to the specified value.  See below for details.
 
        This referred to as global forwarding.
@@ -881,12 +887,12 @@ proxy_ndp - BOOLEAN
 conf/interface/*:
        Change special settings per interface.
 
-       The functional behaviour for certain settings is different 
+       The functional behaviour for certain settings is different
        depending on whether local forwarding is enabled or not.
 
 accept_ra - BOOLEAN
        Accept Router Advertisements; autoconfigure using them.
-       
+
        Functional default: enabled if local forwarding is disabled.
                            disabled if local forwarding is enabled.
 
@@ -932,7 +938,7 @@ accept_source_route - INTEGER
        Default: 0
 
 autoconf - BOOLEAN
-       Autoconfigure addresses using Prefix Information in Router 
+       Autoconfigure addresses using Prefix Information in Router
        Advertisements.
 
        Functional default: enabled if accept_ra_pinfo is enabled.
@@ -941,11 +947,11 @@ autoconf - BOOLEAN
 dad_transmits - INTEGER
        The amount of Duplicate Address Detection probes to send.
        Default: 1
-       
+
 forwarding - BOOLEAN
-       Configure interface-specific Host/Router behaviour.  
+       Configure interface-specific Host/Router behaviour.
 
-       Note: It is recommended to have the same setting on all 
+       Note: It is recommended to have the same setting on all
        interfaces; mixed router/host scenarios are rather uncommon.
 
        FALSE:
@@ -954,13 +960,13 @@ forwarding - BOOLEAN
 
        1. IsRouter flag is not set in Neighbour Advertisements.
        2. Router Solicitations are being sent when necessary.
-       3. If accept_ra is TRUE (default), accept Router 
+       3. If accept_ra is TRUE (default), accept Router
           Advertisements (and do autoconfiguration).
        4. If accept_redirects is TRUE (default), accept Redirects.
 
        TRUE:
 
-       If local forwarding is enabled, Router behaviour is assumed. 
+       If local forwarding is enabled, Router behaviour is assumed.
        This means exactly the reverse from the above:
 
        1. IsRouter flag is set in Neighbour Advertisements.
@@ -995,7 +1001,7 @@ router_solicitation_interval - INTEGER
        Default: 4
 
 router_solicitations - INTEGER
-       Number of Router Solicitations to send until assuming no 
+       Number of Router Solicitations to send until assuming no
        routers are present.
        Default: 3
 
@@ -1019,11 +1025,11 @@ temp_prefered_lft - INTEGER
 
 max_desync_factor - INTEGER
        Maximum value for DESYNC_FACTOR, which is a random value
-       that ensures that clients don't synchronize with each 
+       that ensures that clients don't synchronize with each
        other and generate new addresses at exactly the same time.
        value is in seconds.
        Default: 600
-       
+
 regen_max_retry - INTEGER
        Number of attempts before give up attempting to generate
        valid temporary addresses.
@@ -1031,13 +1037,15 @@ regen_max_retry - INTEGER
 
 max_addresses - INTEGER
        Number of maximum addresses per interface.  0 disables limitation.
-       It is recommended not set too large value (or 0) because it would 
-       be too easy way to crash kernel to allow to create too much of 
+       It is recommended not set too large value (or 0) because it would
+       be too easy way to crash kernel to allow to create too much of
        autoconfigured addresses.
        Default: 16
 
 disable_ipv6 - BOOLEAN
-       Disable IPv6 operation.
+       Disable IPv6 operation.  If accept_dad is set to 2, this value
+       will be dynamically set to TRUE if DAD fails for the link-local
+       address.
        Default: FALSE (enable IPv6 operation)
 
 accept_dad - INTEGER
diff --git a/Documentation/networking/ipv6.txt b/Documentation/networking/ipv6.txt
new file mode 100644 (file)
index 0000000..268e5c1
--- /dev/null
@@ -0,0 +1,35 @@
+
+Options for the ipv6 module are supplied as parameters at load time.
+
+Module options may be given as command line arguments to the insmod
+or modprobe command, but are usually specified in either the
+/etc/modules.conf or /etc/modprobe.conf configuration file, or in a
+distro-specific configuration file.
+
+The available ipv6 module parameters are listed below.  If a parameter
+is not specified the default value is used.
+
+The parameters are as follows:
+
+disable
+
+       Specifies whether to load the IPv6 module, but disable all
+       its functionality.  This might be used when another module
+       has a dependency on the IPv6 module being loaded, but no
+       IPv6 addresses or operations are desired.
+
+       The possible values and their effects are:
+
+       0
+               IPv6 is enabled.
+
+               This is the default value.
+
+       1
+               IPv6 is disabled.
+
+               No IPv6 addresses will be added to interfaces, and
+               it will not be possible to open an IPv6 socket.
+
+               A reboot is required to enable IPv6.
+
diff --git a/Documentation/networking/ixgbe.txt b/Documentation/networking/ixgbe.txt
new file mode 100644 (file)
index 0000000..eeb6868
--- /dev/null
@@ -0,0 +1,199 @@
+Linux Base Driver for 10 Gigabit PCI Express Intel(R) Network Connection
+========================================================================
+
+March 10, 2009
+
+
+Contents
+========
+
+- In This Release
+- Identifying Your Adapter
+- Building and Installation
+- Additional Configurations
+- Support
+
+
+
+In This Release
+===============
+
+This file describes the ixgbe Linux Base Driver for the 10 Gigabit PCI
+Express Intel(R) Network Connection.  This driver includes support for
+Itanium(R)2-based systems.
+
+For questions related to hardware requirements, refer to the documentation
+supplied with your 10 Gigabit adapter.  All hardware requirements listed apply
+to use with Linux.
+
+The following features are available in this kernel:
+ - Native VLANs
+ - Channel Bonding (teaming)
+ - SNMP
+ - Generic Receive Offload
+ - Data Center Bridging
+
+Channel Bonding documentation can be found in the Linux kernel source:
+/Documentation/networking/bonding.txt
+
+Ethtool, lspci, and ifconfig can be used to display device and driver
+specific information.
+
+
+Identifying Your Adapter
+========================
+
+This driver supports devices based on the 82598 controller and the 82599
+controller.
+
+For specific information on identifying which adapter you have, please visit:
+
+    http://support.intel.com/support/network/sb/CS-008441.htm
+
+
+Building and Installation
+=========================
+
+select m for "Intel(R) 10GbE PCI Express adapters support" located at:
+      Location:
+        -> Device Drivers
+          -> Network device support (NETDEVICES [=y])
+            -> Ethernet (10000 Mbit) (NETDEV_10000 [=y])
+
+1. make modules & make modules_install
+
+2. Load the module:
+
+# modprobe ixgbe
+
+   The insmod command can be used if the full
+   path to the driver module is specified.  For example:
+
+     insmod /lib/modules/<KERNEL VERSION>/kernel/drivers/net/ixgbe/ixgbe.ko
+
+   With 2.6 based kernels also make sure that older ixgbe drivers are
+   removed from the kernel, before loading the new module:
+
+     rmmod ixgbe; modprobe ixgbe
+
+3. Assign an IP address to the interface by entering the following, where
+   x is the interface number:
+
+     ifconfig ethx <IP_address>
+
+4. Verify that the interface works. Enter the following, where <IP_address>
+   is the IP address for another machine on the same subnet as the interface
+   that is being tested:
+
+     ping  <IP_address>
+
+
+Additional Configurations
+=========================
+
+  Viewing Link Messages
+  ---------------------
+  Link messages will not be displayed to the console if the distribution is
+  restricting system messages. In order to see network driver link messages on
+  your console, set dmesg to eight by entering the following:
+
+       dmesg -n 8
+
+  NOTE: This setting is not saved across reboots.
+
+
+  Jumbo Frames
+  ------------
+  The driver supports Jumbo Frames for all adapters. Jumbo Frames support is
+  enabled by changing the MTU to a value larger than the default of 1500.
+  The maximum value for the MTU is 16110.  Use the ifconfig command to
+  increase the MTU size.  For example:
+
+        ifconfig ethx mtu 9000 up
+
+  The maximum MTU setting for Jumbo Frames is 16110.  This value coincides
+  with the maximum Jumbo Frames size of 16128.
+
+  Generic Receive Offload, aka GRO
+  --------------------------------
+  The driver supports the in-kernel software implementation of GRO.  GRO has
+  shown that by coalescing Rx traffic into larger chunks of data, CPU
+  utilization can be significantly reduced when under large Rx load.  GRO is an
+  evolution of the previously-used LRO interface.  GRO is able to coalesce
+  other protocols besides TCP.  It's also safe to use with configurations that
+  are problematic for LRO, namely bridging and iSCSI.
+
+  GRO is enabled by default in the driver.  Future versions of ethtool will
+  support disabling and re-enabling GRO on the fly.
+
+
+  Data Center Bridging, aka DCB
+  -----------------------------
+
+  DCB is a configuration Quality of Service implementation in hardware.
+  It uses the VLAN priority tag (802.1p) to filter traffic.  That means
+  that there are 8 different priorities that traffic can be filtered into.
+  It also enables priority flow control which can limit or eliminate the
+  number of dropped packets during network stress.  Bandwidth can be
+  allocated to each of these priorities, which is enforced at the hardware
+  level.
+
+  To enable DCB support in ixgbe, you must enable the DCB netlink layer to
+  allow the userspace tools (see below) to communicate with the driver.
+  This can be found in the kernel configuration here:
+
+        -> Networking support
+          -> Networking options
+            -> Data Center Bridging support
+
+  Once this is selected, DCB support must be selected for ixgbe.  This can
+  be found here:
+
+        -> Device Drivers
+          -> Network device support (NETDEVICES [=y])
+            -> Ethernet (10000 Mbit) (NETDEV_10000 [=y])
+              -> Intel(R) 10GbE PCI Express adapters support
+                -> Data Center Bridging (DCB) Support
+
+  After these options are selected, you must rebuild your kernel and your
+  modules.
+
+  In order to use DCB, userspace tools must be downloaded and installed.
+  The dcbd tools can be found at:
+
+        http://e1000.sf.net
+
+
+  Ethtool
+  -------
+  The driver utilizes the ethtool interface for driver configuration and
+  diagnostics, as well as displaying statistical information.  Ethtool
+  version 3.0 or later is required for this functionality.
+
+  The latest release of ethtool can be found from
+  http://sourceforge.net/projects/gkernel.
+
+
+  NAPI
+  ----
+
+  NAPI (Rx polling mode) is supported in the ixgbe driver.  NAPI is enabled
+  by default in the driver.
+
+  See www.cyberus.ca/~hadi/usenix-paper.tgz for more information on NAPI.
+
+
+Support
+=======
+
+For general information, go to the Intel support website at:
+
+    http://support.intel.com
+
+or the Intel Wired Networking project hosted by Sourceforge at:
+
+    http://e1000.sourceforge.net
+
+If an issue is identified with the released source code on the supported
+kernel with a supported adapter, email the specific information related
+to the issue to e1000-devel@lists.sf.net
diff --git a/Documentation/networking/rds.txt b/Documentation/networking/rds.txt
new file mode 100644 (file)
index 0000000..c67077c
--- /dev/null
@@ -0,0 +1,356 @@
+
+Overview
+========
+
+This readme tries to provide some background on the hows and whys of RDS,
+and will hopefully help you find your way around the code.
+
+In addition, please see this email about RDS origins:
+http://oss.oracle.com/pipermail/rds-devel/2007-November/000228.html
+
+RDS Architecture
+================
+
+RDS provides reliable, ordered datagram delivery by using a single
+reliable connection between any two nodes in the cluster. This allows
+applications to use a single socket to talk to any other process in the
+cluster - so in a cluster with N processes you need N sockets, in contrast
+to N*N if you use a connection-oriented socket transport like TCP.
+
+RDS is not Infiniband-specific; it was designed to support different
+transports.  The current implementation used to support RDS over TCP as well
+as IB. Work is in progress to support RDS over iWARP, and using DCE to
+guarantee no dropped packets on Ethernet, it may be possible to use RDS over
+UDP in the future.
+
+The high-level semantics of RDS from the application's point of view are
+
+ *     Addressing
+        RDS uses IPv4 addresses and 16bit port numbers to identify
+        the end point of a connection. All socket operations that involve
+        passing addresses between kernel and user space generally
+        use a struct sockaddr_in.
+
+        The fact that IPv4 addresses are used does not mean the underlying
+        transport has to be IP-based. In fact, RDS over IB uses a
+        reliable IB connection; the IP address is used exclusively to
+        locate the remote node's GID (by ARPing for the given IP).
+
+        The port space is entirely independent of UDP, TCP or any other
+        protocol.
+
+ *     Socket interface
+        RDS sockets work *mostly* as you would expect from a BSD
+        socket. The next section will cover the details. At any rate,
+        all I/O is performed through the standard BSD socket API.
+        Some additions like zerocopy support are implemented through
+        control messages, while other extensions use the getsockopt/
+        setsockopt calls.
+
+        Sockets must be bound before you can send or receive data.
+        This is needed because binding also selects a transport and
+        attaches it to the socket. Once bound, the transport assignment
+        does not change. RDS will tolerate IPs moving around (eg in
+        a active-active HA scenario), but only as long as the address
+        doesn't move to a different transport.
+
+ *     sysctls
+        RDS supports a number of sysctls in /proc/sys/net/rds
+
+
+Socket Interface
+================
+
+  AF_RDS, PF_RDS, SOL_RDS
+        These constants haven't been assigned yet, because RDS isn't in
+        mainline yet. Currently, the kernel module assigns some constant
+        and publishes it to user space through two sysctl files
+                /proc/sys/net/rds/pf_rds
+                /proc/sys/net/rds/sol_rds
+
+  fd = socket(PF_RDS, SOCK_SEQPACKET, 0);
+        This creates a new, unbound RDS socket.
+
+  setsockopt(SOL_SOCKET): send and receive buffer size
+        RDS honors the send and receive buffer size socket options.
+        You are not allowed to queue more than SO_SNDSIZE bytes to
+        a socket. A message is queued when sendmsg is called, and
+        it leaves the queue when the remote system acknowledges
+        its arrival.
+
+        The SO_RCVSIZE option controls the maximum receive queue length.
+        This is a soft limit rather than a hard limit - RDS will
+        continue to accept and queue incoming messages, even if that
+        takes the queue length over the limit. However, it will also
+        mark the port as "congested" and send a congestion update to
+        the source node. The source node is supposed to throttle any
+        processes sending to this congested port.
+
+  bind(fd, &sockaddr_in, ...)
+        This binds the socket to a local IP address and port, and a
+        transport.
+
+  sendmsg(fd, ...)
+        Sends a message to the indicated recipient. The kernel will
+        transparently establish the underlying reliable connection
+        if it isn't up yet.
+
+        An attempt to send a message that exceeds SO_SNDSIZE will
+        return with -EMSGSIZE
+
+        An attempt to send a message that would take the total number
+        of queued bytes over the SO_SNDSIZE threshold will return
+        EAGAIN.
+
+        An attempt to send a message to a destination that is marked
+        as "congested" will return ENOBUFS.
+
+  recvmsg(fd, ...)
+        Receives a message that was queued to this socket. The sockets
+        recv queue accounting is adjusted, and if the queue length
+        drops below SO_SNDSIZE, the port is marked uncongested, and
+        a congestion update is sent to all peers.
+
+        Applications can ask the RDS kernel module to receive
+        notifications via control messages (for instance, there is a
+        notification when a congestion update arrived, or when a RDMA
+        operation completes). These notifications are received through
+        the msg.msg_control buffer of struct msghdr. The format of the
+        messages is described in manpages.
+
+  poll(fd)
+        RDS supports the poll interface to allow the application
+        to implement async I/O.
+
+        POLLIN handling is pretty straightforward. When there's an
+        incoming message queued to the socket, or a pending notification,
+        we signal POLLIN.
+
+        POLLOUT is a little harder. Since you can essentially send
+        to any destination, RDS will always signal POLLOUT as long as
+        there's room on the send queue (ie the number of bytes queued
+        is less than the sendbuf size).
+
+        However, the kernel will refuse to accept messages to
+        a destination marked congested - in this case you will loop
+        forever if you rely on poll to tell you what to do.
+        This isn't a trivial problem, but applications can deal with
+        this - by using congestion notifications, and by checking for
+        ENOBUFS errors returned by sendmsg.
+
+  setsockopt(SOL_RDS, RDS_CANCEL_SENT_TO, &sockaddr_in)
+        This allows the application to discard all messages queued to a
+        specific destination on this particular socket.
+
+        This allows the application to cancel outstanding messages if
+        it detects a timeout. For instance, if it tried to send a message,
+        and the remote host is unreachable, RDS will keep trying forever.
+        The application may decide it's not worth it, and cancel the
+        operation. In this case, it would use RDS_CANCEL_SENT_TO to
+        nuke any pending messages.
+
+
+RDMA for RDS
+============
+
+  see rds-rdma(7) manpage (available in rds-tools)
+
+
+Congestion Notifications
+========================
+
+  see rds(7) manpage
+
+
+RDS Protocol
+============
+
+  Message header
+
+    The message header is a 'struct rds_header' (see rds.h):
+    Fields:
+      h_sequence:
+          per-packet sequence number
+      h_ack:
+          piggybacked acknowledgment of last packet received
+      h_len:
+          length of data, not including header
+      h_sport:
+          source port
+      h_dport:
+          destination port
+      h_flags:
+          CONG_BITMAP - this is a congestion update bitmap
+          ACK_REQUIRED - receiver must ack this packet
+          RETRANSMITTED - packet has previously been sent
+      h_credit:
+          indicate to other end of connection that
+          it has more credits available (i.e. there is
+          more send room)
+      h_padding[4]:
+          unused, for future use
+      h_csum:
+          header checksum
+      h_exthdr:
+          optional data can be passed here. This is currently used for
+          passing RDMA-related information.
+
+  ACK and retransmit handling
+
+      One might think that with reliable IB connections you wouldn't need
+      to ack messages that have been received.  The problem is that IB
+      hardware generates an ack message before it has DMAed the message
+      into memory.  This creates a potential message loss if the HCA is
+      disabled for any reason between when it sends the ack and before
+      the message is DMAed and processed.  This is only a potential issue
+      if another HCA is available for fail-over.
+
+      Sending an ack immediately would allow the sender to free the sent
+      message from their send queue quickly, but could cause excessive
+      traffic to be used for acks. RDS piggybacks acks on sent data
+      packets.  Ack-only packets are reduced by only allowing one to be
+      in flight at a time, and by the sender only asking for acks when
+      its send buffers start to fill up. All retransmissions are also
+      acked.
+
+  Flow Control
+
+      RDS's IB transport uses a credit-based mechanism to verify that
+      there is space in the peer's receive buffers for more data. This
+      eliminates the need for hardware retries on the connection.
+
+  Congestion
+
+      Messages waiting in the receive queue on the receiving socket
+      are accounted against the sockets SO_RCVBUF option value.  Only
+      the payload bytes in the message are accounted for.  If the
+      number of bytes queued equals or exceeds rcvbuf then the socket
+      is congested.  All sends attempted to this socket's address
+      should return block or return -EWOULDBLOCK.
+
+      Applications are expected to be reasonably tuned such that this
+      situation very rarely occurs.  An application encountering this
+      "back-pressure" is considered a bug.
+
+      This is implemented by having each node maintain bitmaps which
+      indicate which ports on bound addresses are congested.  As the
+      bitmap changes it is sent through all the connections which
+      terminate in the local address of the bitmap which changed.
+
+      The bitmaps are allocated as connections are brought up.  This
+      avoids allocation in the interrupt handling path which queues
+      sages on sockets.  The dense bitmaps let transports send the
+      entire bitmap on any bitmap change reasonably efficiently.  This
+      is much easier to implement than some finer-grained
+      communication of per-port congestion.  The sender does a very
+      inexpensive bit test to test if the port it's about to send to
+      is congested or not.
+
+
+RDS Transport Layer
+==================
+
+  As mentioned above, RDS is not IB-specific. Its code is divided
+  into a general RDS layer and a transport layer.
+
+  The general layer handles the socket API, congestion handling,
+  loopback, stats, usermem pinning, and the connection state machine.
+
+  The transport layer handles the details of the transport. The IB
+  transport, for example, handles all the queue pairs, work requests,
+  CM event handlers, and other Infiniband details.
+
+
+RDS Kernel Structures
+=====================
+
+  struct rds_message
+    aka possibly "rds_outgoing", the generic RDS layer copies data to
+    be sent and sets header fields as needed, based on the socket API.
+    This is then queued for the individual connection and sent by the
+    connection's transport.
+  struct rds_incoming
+    a generic struct referring to incoming data that can be handed from
+    the transport to the general code and queued by the general code
+    while the socket is awoken. It is then passed back to the transport
+    code to handle the actual copy-to-user.
+  struct rds_socket
+    per-socket information
+  struct rds_connection
+    per-connection information
+  struct rds_transport
+    pointers to transport-specific functions
+  struct rds_statistics
+    non-transport-specific statistics
+  struct rds_cong_map
+    wraps the raw congestion bitmap, contains rbnode, waitq, etc.
+
+Connection management
+=====================
+
+  Connections may be in UP, DOWN, CONNECTING, DISCONNECTING, and
+  ERROR states.
+
+  The first time an attempt is made by an RDS socket to send data to
+  a node, a connection is allocated and connected. That connection is
+  then maintained forever -- if there are transport errors, the
+  connection will be dropped and re-established.
+
+  Dropping a connection while packets are queued will cause queued or
+  partially-sent datagrams to be retransmitted when the connection is
+  re-established.
+
+
+The send path
+=============
+
+  rds_sendmsg()
+    struct rds_message built from incoming data
+    CMSGs parsed (e.g. RDMA ops)
+    transport connection alloced and connected if not already
+    rds_message placed on send queue
+    send worker awoken
+  rds_send_worker()
+    calls rds_send_xmit() until queue is empty
+  rds_send_xmit()
+    transmits congestion map if one is pending
+    may set ACK_REQUIRED
+    calls transport to send either non-RDMA or RDMA message
+    (RDMA ops never retransmitted)
+  rds_ib_xmit()
+    allocs work requests from send ring
+    adds any new send credits available to peer (h_credits)
+    maps the rds_message's sg list
+    piggybacks ack
+    populates work requests
+    post send to connection's queue pair
+
+The recv path
+=============
+
+  rds_ib_recv_cq_comp_handler()
+    looks at write completions
+    unmaps recv buffer from device
+    no errors, call rds_ib_process_recv()
+    refill recv ring
+  rds_ib_process_recv()
+    validate header checksum
+    copy header to rds_ib_incoming struct if start of a new datagram
+    add to ibinc's fraglist
+    if competed datagram:
+      update cong map if datagram was cong update
+      call rds_recv_incoming() otherwise
+      note if ack is required
+  rds_recv_incoming()
+    drop duplicate packets
+    respond to pings
+    find the sock associated with this datagram
+    add to sock queue
+    wake up sock
+    do some congestion calculations
+  rds_recvmsg
+    copy data into user iovec
+    handle CMSGs
+    return to application
+
+
index 8141fa01978e0d7392390e68009c0b612ba0aa6f..7ac8032ee9b2a5f082554386c46df084fe993a5b 100644 (file)
@@ -4,7 +4,7 @@ Introduction
 ============
 
 The Chelsio T3 ASIC based Adapters (S310, S320, S302, S304, Mezz cards, etc.
-series of products) supports iSCSI acceleration and iSCSI Direct Data Placement
+series of products) support iSCSI acceleration and iSCSI Direct Data Placement
 (DDP) where the hardware handles the expensive byte touching operations, such
 as CRC computation and verification, and direct DMA to the final host memory
 destination:
@@ -31,9 +31,9 @@ destination:
          the TCP segments onto the wire. It handles TCP retransmission if
          needed.
 
-         On receving, S3 h/w recovers the iSCSI PDU by reassembling TCP
+         On receiving, S3 h/w recovers the iSCSI PDU by reassembling TCP
          segments, separating the header and data, calculating and verifying
-         the digests, then forwards the header to the host. The payload data,
+         the digests, then forwarding the header to the host. The payload data,
          if possible, will be directly placed into the pre-posted host DDP
          buffer. Otherwise, the payload data will be sent to the host too.
 
@@ -68,9 +68,8 @@ The following steps need to be taken to accelerates the open-iscsi initiator:
        sure the ip address is unique in the network.
 
 3. edit /etc/iscsi/iscsid.conf
-   The default setting for MaxRecvDataSegmentLength (131072) is too big,
-   replace "node.conn[0].iscsi.MaxRecvDataSegmentLength" to be a value no
-   bigger than 15360 (for example 8192):
+   The default setting for MaxRecvDataSegmentLength (131072) is too big;
+   replace with a value no bigger than 15360 (for example 8192):
 
        node.conn[0].iscsi.MaxRecvDataSegmentLength = 8192
 
index cde23b4a12a19a9306464ec1296cb4fee19eb9c0..5731c67abc558f4ac91d9f54d78bf88cacb8dad6 100644 (file)
@@ -78,12 +78,10 @@ to view your kernel log and look for "mmiotrace has lost events" warning. If
 events were lost, the trace is incomplete. You should enlarge the buffers and
 try again. Buffers are enlarged by first seeing how large the current buffers
 are:
-$ cat /debug/tracing/trace_entries
+$ cat /debug/tracing/buffer_size_kb
 gives you a number. Approximately double this number and write it back, for
 instance:
-$ echo 0 > /debug/tracing/tracing_enabled
-$ echo 128000 > /debug/tracing/trace_entries
-$ echo 1 > /debug/tracing/tracing_enabled
+$ echo 128000 > /debug/tracing/buffer_size_kb
 Then start again from the top.
 
 If you are doing a trace for a driver project, e.g. Nouveau, you should also
index db65b4e6d1324b65b58db7e70174d1ee9e1bfe93..27114518eb05b4f82957b1fd126447227225bfcc 100644 (file)
@@ -692,6 +692,13 @@ M: kernel@wantstofly.org
 L:     linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
 S:     Maintained
 
+ARM/NUVOTON W90X900 ARM ARCHITECTURE
+P:      Wan ZongShun
+M:      mcuos.com@gmail.com
+L:      linux-arm-kernel@lists.arm.linux.org.uk (subscribers-only)
+W:      http://www.mcuos.com
+S:      Maintained
+
 ARPD SUPPORT
 P:     Jonathan Layes
 L:     netdev@vger.kernel.org
@@ -1004,6 +1011,8 @@ L:        netdev@vger.kernel.org
 S:     Supported
 
 BROADCOM TG3 GIGABIT ETHERNET DRIVER
+P:     Matt Carlson
+M:     mcarlson@broadcom.com
 P:     Michael Chan
 M:     mchan@broadcom.com
 L:     netdev@vger.kernel.org
@@ -1905,10 +1914,10 @@ W:      http://gigaset307x.sourceforge.net/
 S:     Maintained
 
 HARD DRIVE ACTIVE PROTECTION SYSTEM (HDAPS) DRIVER
-P:     Robert Love
-M:     rlove@rlove.org
-M:     linux-kernel@vger.kernel.org
-W:     http://www.kernel.org/pub/linux/kernel/people/rml/hdaps/
+P:     Frank Seidel
+M:     frank@f-seidel.de
+L:     lm-sensors@lm-sensors.org
+W:     http://www.kernel.org/pub/linux/kernel/people/fseidel/hdaps/
 S:     Maintained
 
 GSPCA FINEPIX SUBDRIVER
@@ -2001,7 +2010,7 @@ S:        Maintained
 
 HIBERNATION (aka Software Suspend, aka swsusp)
 P:     Pavel Machek
-M:     pavel@suse.cz
+M:     pavel@ucw.cz
 P:     Rafael J. Wysocki
 M:     rjw@sisk.pl
 L:     linux-pm@lists.linux-foundation.org
@@ -2457,7 +2466,7 @@ S:        Maintained
 
 ISDN SUBSYSTEM
 P:     Karsten Keil
-M:     kkeil@suse.de
+M:     isdn@linux-pingi.de
 L:     isdn4linux@listserv.isdn4linux.de (subscribers-only)
 W:     http://www.isdn4linux.de
 T:     git kernel.org:/pub/scm/linux/kernel/kkeil/isdn-2.6.git
@@ -3327,8 +3336,8 @@ P:        Jeremy Fitzhardinge
 M:     jeremy@xensource.com
 P:     Chris Wright
 M:     chrisw@sous-sol.org
-P:     Zachary Amsden
-M:     zach@vmware.com
+P:     Alok Kataria
+M:     akataria@vmware.com
 P:     Rusty Russell
 M:     rusty@rustcorp.com.au
 L:     virtualization@lists.osdl.org
@@ -3632,6 +3641,12 @@ M:       florian.fainelli@telecomint.eu
 L:     netdev@vger.kernel.org
 S:     Maintained
 
+RDS - RELIABLE DATAGRAM SOCKETS
+P:     Andy Grover
+M:     andy.grover@oracle.com
+L:     rds-devel@oss.oracle.com
+S:     Supported
+
 READ-COPY UPDATE (RCU)
 P:     Dipankar Sarma
 M:     dipankar@in.ibm.com
@@ -3873,6 +3888,15 @@ L:       linux-ide@vger.kernel.org
 T:     git kernel.org:/pub/scm/linux/kernel/git/jgarzik/libata-dev.git
 S:     Supported
 
+SERVER ENGINES 10Gbps NIC - BladeEngine 2 DRIVER
+P:     Sathya Perla
+M:     sathyap@serverengines.com
+P:      Subbu Seetharaman
+M:      subbus@serverengines.com
+L:      netdev@vger.kernel.org
+W:      http://www.serverengines.com
+S:      Supported
+
 SFC NETWORK DRIVER
 P:     Steve Hodgson
 P:     Ben Hutchings
@@ -4172,7 +4196,7 @@ SUSPEND TO RAM
 P:     Len Brown
 M:     len.brown@intel.com
 P:     Pavel Machek
-M:     pavel@suse.cz
+M:     pavel@ucw.cz
 P:     Rafael J. Wysocki
 M:     rjw@sisk.pl
 L:     linux-pm@lists.linux-foundation.org
@@ -4924,11 +4948,11 @@ L:      zd1211-devs@lists.sourceforge.net (subscribers-only)
 S:     Maintained
 
 ZR36067 VIDEO FOR LINUX DRIVER
-P:     Ronald Bultje
-M:     rbultje@ronald.bitfreak.net
 L:     mjpeg-users@lists.sourceforge.net
+L:     linux-media@vger.kernel.org
 W:     http://mjpeg.sourceforge.net/driver-zoran/
-S:     Maintained
+T:     Mercurial http://linuxtv.org/hg/v4l-dvb
+S:     Odd Fixes
 
 ZS DECSTATION Z85C30 SERIAL DRIVER
 P:     Maciej W. Rozycki
index 22d758495ad29424f88361e9b1c782e1529bad94..d04ee0ad1dccce7ea2503637ffbe6d8753074ffe 100644 (file)
--- a/Makefile
+++ b/Makefile
@@ -1,7 +1,7 @@
 VERSION = 2
 PATCHLEVEL = 6
 SUBLEVEL = 29
-EXTRAVERSION = -rc5
+EXTRAVERSION = -rc7
 NAME = Erotic Pickled Herring
 
 # *DOCUMENTATION*
@@ -389,6 +389,7 @@ PHONY += outputmakefile
 # output directory.
 outputmakefile:
 ifneq ($(KBUILD_SRC),)
+       $(Q)ln -fsn $(srctree) source
        $(Q)$(CONFIG_SHELL) $(srctree)/scripts/mkmakefile \
            $(srctree) $(objtree) $(VERSION) $(PATCHLEVEL)
 endif
@@ -946,7 +947,6 @@ ifneq ($(KBUILD_SRC),)
            mkdir -p include2;                                          \
            ln -fsn $(srctree)/include/asm-$(SRCARCH) include2/asm;     \
        fi
-       ln -fsn $(srctree) source
 endif
 
 # prepare2 creates a makefile if using a separate output directory
diff --git a/README b/README
index 90a07658ede14840346eee6610648bcf4ec79997..d6c6c742c1d78aea9f64e4307e36e06a2a0959da 100644 (file)
--- a/README
+++ b/README
@@ -188,7 +188,7 @@ CONFIGURING the kernel:
                           values to random values.
 
    You can find more information on using the Linux kernel config tools
-   in Documentation/kbuild/make-configs.txt.
+   in Documentation/kbuild/kconfig.txt.
 
        NOTES on "make config":
        - having unnecessary drivers will make the kernel bigger, and can
index f238370c907d9f4c86ecbed9da7332ccf08908c3..8d0097f10208dad922760de0a72756a55272c722 100644 (file)
@@ -93,8 +93,8 @@ common_shutdown_1(void *generic_ptr)
        if (cpuid != boot_cpuid) {
                flags |= 0x00040000UL; /* "remain halted" */
                *pflags = flags;
-               cpu_clear(cpuid, cpu_present_map);
-               cpu_clear(cpuid, cpu_possible_map);
+               set_cpu_present(cpuid, false);
+               set_cpu_possible(cpuid, false);
                halt();
        }
 #endif
@@ -120,8 +120,8 @@ common_shutdown_1(void *generic_ptr)
 
 #ifdef CONFIG_SMP
        /* Wait for the secondaries to halt. */
-       cpu_clear(boot_cpuid, cpu_present_map);
-       cpu_clear(boot_cpuid, cpu_possible_map);
+       set_cpu_present(boot_cpuid, false);
+       set_cpu_possible(boot_cpuid, false);
        while (cpus_weight(cpu_present_map))
                barrier();
 #endif
index 00f1dc3dfd5f215e5e1068c89c2376afed7f7830..b1fe5674c3a1fb286c3af38559a52009ce054478 100644 (file)
@@ -120,12 +120,12 @@ void __cpuinit
 smp_callin(void)
 {
        int cpuid = hard_smp_processor_id();
-       cpumask_t mask = cpu_online_map;
 
-       if (cpu_test_and_set(cpuid, mask)) {
+       if (cpu_online(cpuid)) {
                printk("??, cpu 0x%x already present??\n", cpuid);
                BUG();
        }
+       set_cpu_online(cpuid, true);
 
        /* Turn on machine checks.  */
        wrmces(7);
@@ -436,8 +436,8 @@ setup_smp(void)
                                ((char *)cpubase + i*hwrpb->processor_size);
                        if ((cpu->flags & 0x1cc) == 0x1cc) {
                                smp_num_probed++;
-                               cpu_set(i, cpu_possible_map);
-                               cpu_set(i, cpu_present_map);
+                               set_cpu_possible(i, true);
+                               set_cpu_present(i, true);
                                cpu->pal_revision = boot_cpu_palrev;
                        }
 
@@ -470,8 +470,8 @@ smp_prepare_cpus(unsigned int max_cpus)
 
        /* Nothing to do on a UP box, or when told not to.  */
        if (smp_num_probed == 1 || max_cpus == 0) {
-               cpu_possible_map = cpumask_of_cpu(boot_cpuid);
-               cpu_present_map = cpumask_of_cpu(boot_cpuid);
+               init_cpu_possible(cpumask_of(boot_cpuid));
+               init_cpu_present(cpumask_of(boot_cpuid));
                printk(KERN_INFO "SMP mode deactivated.\n");
                return;
        }
index e0ee7060f9aadf607f8830bda764f4df66f16b96..98e2f3de4bc5819420c7f538fdfd2937a682e692 100644 (file)
@@ -608,7 +608,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 # Watchdog Device Drivers
 #
 # CONFIG_SOFT_WATCHDOG is not set
-CONFIG_AT91SAM9_WATCHDOG=y
+CONFIG_AT91SAM9X_WATCHDOG=y
 
 #
 # USB-based Watchdog Cards
index 01d1ef97d8be0e4ed395a9f87653f5269cb2c4f6..149456142392b84d2a12d9cdd92b08d0595175c3 100644 (file)
@@ -700,7 +700,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 # Watchdog Device Drivers
 #
 # CONFIG_SOFT_WATCHDOG is not set
-CONFIG_AT91SAM9_WATCHDOG=y
+CONFIG_AT91SAM9X_WATCHDOG=y
 
 #
 # USB-based Watchdog Cards
index 036a126725c16ad5b284442591e1154f3628bb44..21599f3c6275bc98fafe4331490cc17e853fef92 100644 (file)
@@ -710,7 +710,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 # Watchdog Device Drivers
 #
 # CONFIG_SOFT_WATCHDOG is not set
-CONFIG_AT91SAM9_WATCHDOG=y
+CONFIG_AT91SAM9X_WATCHDOG=y
 
 #
 # USB-based Watchdog Cards
index 237a2a6a8517b17583b8dd01009f27594ba0b534..e2df81a3e804199da7b3701924df98db70ede1a8 100644 (file)
@@ -606,7 +606,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 # Watchdog Device Drivers
 #
 # CONFIG_SOFT_WATCHDOG is not set
-CONFIG_AT91SAM9_WATCHDOG=y
+CONFIG_AT91SAM9X_WATCHDOG=y
 
 #
 # Sonics Silicon Backplane
index cd1d717903ac5dec800e566f0bf7a6bf6bdb5a22..9b32d0eb89bac0a93e09000f1ab2897ecc10b5bd 100644 (file)
@@ -727,7 +727,7 @@ CONFIG_WATCHDOG_NOWAYOUT=y
 # Watchdog Device Drivers
 #
 # CONFIG_SOFT_WATCHDOG is not set
-# CONFIG_AT91SAM9_WATCHDOG is not set
+# CONFIG_AT91SAM9X_WATCHDOG is not set
 
 #
 # USB-based Watchdog Cards
index 84849098c8e8139da19ae6b8d8fecd089539ee30..d4a0da1e48f40988bb7f92ce34664d86adb74a32 100644 (file)
@@ -74,9 +74,9 @@ EXPORT_SYMBOL(elf_set_personality);
  */
 int arm_elf_read_implies_exec(const struct elf32_hdr *x, int executable_stack)
 {
-       if (executable_stack != EXSTACK_ENABLE_X)
+       if (executable_stack != EXSTACK_DISABLE_X)
                return 1;
-       if (cpu_architecture() <= CPU_ARCH_ARMv6)
+       if (cpu_architecture() < CPU_ARCH_ARMv6)
                return 1;
        return 0;
 }
index 7049815d66d566e7d89c08fd3c25e33b8c48c995..68d6494c0389751d5584e94e833ae139ae53d76b 100644 (file)
@@ -233,12 +233,13 @@ static void __init cacheid_init(void)
        unsigned int cachetype = read_cpuid_cachetype();
        unsigned int arch = cpu_architecture();
 
-       if (arch >= CPU_ARCH_ARMv7) {
-               cacheid = CACHEID_VIPT_NONALIASING;
-               if ((cachetype & (3 << 14)) == 1 << 14)
-                       cacheid |= CACHEID_ASID_TAGGED;
-       } else if (arch >= CPU_ARCH_ARMv6) {
-               if (cachetype & (1 << 23))
+       if (arch >= CPU_ARCH_ARMv6) {
+               if ((cachetype & (7 << 29)) == 4 << 29) {
+                       /* ARMv7 register format */
+                       cacheid = CACHEID_VIPT_NONALIASING;
+                       if ((cachetype & (3 << 14)) == 1 << 14)
+                               cacheid |= CACHEID_ASID_TAGGED;
+               } else if (cachetype & (1 << 23))
                        cacheid = CACHEID_VIPT_ALIASING;
                else
                        cacheid = CACHEID_VIPT_NONALIASING;
index 9eca2209cde630dd656491ef5c964461f2c8b5b2..412aa49ad2fb432ca1e98fa7876f3d78234eb16b 100644 (file)
@@ -697,7 +697,7 @@ static void __init at91_add_device_rtt(void)
  *  Watchdog
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
+#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE)
 static struct platform_device at91cap9_wdt_device = {
        .name           = "at91_wdt",
        .id             = -1,
index fdde1ea21b0729738ade6357b728a634ff505fc6..d74c9ac007e75c1d91642d711c7ef19c93b320e1 100644 (file)
@@ -643,7 +643,7 @@ static void __init at91_add_device_rtt(void)
  *  Watchdog
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
+#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE)
 static struct platform_device at91sam9260_wdt_device = {
        .name           = "at91_wdt",
        .id             = -1,
index 17289756f80ffe8c5eb6d34bd561ea2fe119a0f5..59fc48311fb07d11760382e85e5ff386986a93f6 100644 (file)
@@ -621,7 +621,7 @@ static void __init at91_add_device_rtt(void)
  *  Watchdog
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
+#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE)
 static struct platform_device at91sam9261_wdt_device = {
        .name           = "at91_wdt",
        .id             = -1,
index b753cb879d8e6ae5ee7621492709fae1895eaebd..134af97ff3403f1c309b4b6c962665c860fa796d 100644 (file)
@@ -854,7 +854,7 @@ static void __init at91_add_device_rtt(void)
  *  Watchdog
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
+#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE)
 static struct platform_device at91sam9263_wdt_device = {
        .name           = "at91_wdt",
        .id             = -1,
index 145324f4ec5671fca146f160196dc54b5cd0cfb6..728186515cdf2a2b3db5a99fce5564336be92218 100644 (file)
@@ -609,7 +609,7 @@ static void __init at91_add_device_rtt(void)
  *  Watchdog
  * -------------------------------------------------------------------- */
 
-#if defined(CONFIG_AT91SAM9_WATCHDOG) || defined(CONFIG_AT91SAM9_WATCHDOG_MODULE)
+#if defined(CONFIG_AT91SAM9X_WATCHDOG) || defined(CONFIG_AT91SAM9X_WATCHDOG_MODULE)
 static struct platform_device at91sam9rl_wdt_device = {
        .name           = "at91_wdt",
        .id             = -1,
index 9b0447c3d59b15443539c44eb1cb3a23dedd3a3b..2f7d4977dce95b3c43c575d2696b30888af5e187 100644 (file)
@@ -490,7 +490,8 @@ postcore_initcall(at91_gpio_debugfs_init);
 
 /*--------------------------------------------------------------------------*/
 
-/* This lock class tells lockdep that GPIO irqs are in a different
+/*
+ * This lock class tells lockdep that GPIO irqs are in a different
  * category than their parents, so it won't report false recursion.
  */
 static struct lock_class_key gpio_lock_class;
@@ -509,9 +510,6 @@ void __init at91_gpio_irq_setup(void)
                unsigned        id = this->id;
                unsigned        i;
 
-               /* enable PIO controller's clock */
-               clk_enable(this->clock);
-
                __raw_writel(~0, this->regbase + PIO_IDR);
 
                for (i = 0, pin = this->chipbase; i < 32; i++, pin++) {
@@ -556,7 +554,14 @@ void __init at91_gpio_init(struct at91_gpio_bank *data, int nr_banks)
                data->chipbase = PIN_BASE + i * 32;
                data->regbase = data->offset + (void __iomem *)AT91_VA_BASE_SYS;
 
-               /* AT91SAM9263_ID_PIOCDE groups PIOC, PIOD, PIOE */
+               /* enable PIO controller's clock */
+               clk_enable(data->clock);
+
+               /*
+                * Some processors share peripheral ID between multiple GPIO banks.
+                *  SAM9263 (PIOC, PIOD, PIOE)
+                *  CAP9 (PIOA, PIOB, PIOC, PIOD)
+                */
                if (last && last->id == data->id)
                        last->next = data;
        }
index fb51f0e0a83fb933b718c80960a46cd60b831ce8..0b3ae21b4565abb471fbedd59c15c96a3e4450f5 100644 (file)
@@ -93,6 +93,7 @@ struct atmel_nand_data {
        u8              enable_pin;     /* chip enable */
        u8              det_pin;        /* card detect */
        u8              rdy_pin;        /* ready/busy */
+       u8              rdy_pin_active_low;     /* rdy_pin value is inverted */
        u8              ale;            /* address line number connected to ALE */
        u8              cle;            /* address line number connected to CLE */
        u8              bus_width_16;   /* buswidth is 16 bit */
index 9bb4f043aa22beb3fd08d0750cb75c155097b113..7ac812dc055a792476ffdc5a93e6568ae75e069a 100644 (file)
@@ -332,7 +332,6 @@ static int at91_pm_enter(suspend_state_t state)
                        at91_sys_read(AT91_AIC_IPR) & at91_sys_read(AT91_AIC_IMR));
 
 error:
-       sdram_selfrefresh_disable();
        target_state = PM_SUSPEND_ON;
        at91_irq_resume();
        at91_gpio_resume();
index a957d239a6838f20458525a2710fa094073f674e..38b6a9ce2a93cc8caecaa2d471e30c3198ce4421 100644 (file)
@@ -311,6 +311,9 @@ evm_u35_setup(struct i2c_client *client, int gpio, unsigned ngpio, void *c)
        gpio_request(gpio + 7, "nCF_SEL");
        gpio_direction_output(gpio + 7, 1);
 
+       /* irlml6401 sustains over 3A, switches 5V in under 8 msec */
+       setup_usb(500, 8);
+
        return 0;
 }
 
@@ -417,9 +420,6 @@ static __init void davinci_evm_init(void)
        platform_add_devices(davinci_evm_devices,
                             ARRAY_SIZE(davinci_evm_devices));
        evm_init_i2c();
-
-       /* irlml6401 sustains over 3A, switches 5V in under 8 msec */
-       setup_usb(500, 8);
 }
 
 static __init void davinci_evm_irq_init(void)
index 28f6dbc95bd7afe8303abf89d4efb479a71c488f..abb92b7eca0c4adf20284e35ad9dac81961a12ae 100644 (file)
@@ -230,6 +230,11 @@ static struct clk davinci_clks[] = {
                .rate = &commonrate,
                .lpsc = DAVINCI_LPSC_GPIO,
        },
+       {
+               .name = "usb",
+               .rate = &commonrate,
+               .lpsc = DAVINCI_LPSC_USB,
+       },
        {
                .name = "AEMIFCLK",
                .rate = &commonrate,
index 867ead2559adf9e6b0f41f12e8af6c40b2083cc1..69680784448a20a259f96ef059e2c4c375b0ea17 100644 (file)
@@ -47,6 +47,7 @@ static struct musb_hdrc_platform_data usb_data = {
 #elif defined(CONFIG_USB_MUSB_HOST)
        .mode           = MUSB_HOST,
 #endif
+       .clock          = "usb",
        .config         = &musb_config,
 };
 
diff --git a/arch/arm/mach-ep93xx/include/mach/gesbc9312.h b/arch/arm/mach-ep93xx/include/mach/gesbc9312.h
deleted file mode 100644 (file)
index 21fe2b9..0000000
+++ /dev/null
@@ -1,3 +0,0 @@
-/*
- * arch/arm/mach-ep93xx/include/mach/gesbc9312.h
- */
index 529807d182bf2c28a8b47350dec7c2eb942cb12d..2866297310b7c9e38f80a7992921481e7140d00b 100644 (file)
@@ -10,7 +10,6 @@
 
 #include "platform.h"
 
-#include "gesbc9312.h"
 #include "ts72xx.h"
 
 #endif
index b3404b7775b318d9beef5e617d9b3ac5e1cd405f..0d2074f51a593ff0e6294889b4ba26a0fa57fd07 100644 (file)
@@ -231,14 +231,17 @@ static struct platform_device kirkwood_switch_device = {
 
 void __init kirkwood_ge00_switch_init(struct dsa_platform_data *d, int irq)
 {
+       int i;
+
        if (irq != NO_IRQ) {
                kirkwood_switch_resources[0].start = irq;
                kirkwood_switch_resources[0].end = irq;
                kirkwood_switch_device.num_resources = 1;
        }
 
-       d->mii_bus = &kirkwood_ge00_shared.dev;
        d->netdev = &kirkwood_ge00.dev;
+       for (i = 0; i < d->nr_chips; i++)
+               d->chip[i].mii_bus = &kirkwood_ge00_shared.dev;
        kirkwood_switch_device.dev.platform_data = d;
 
        platform_device_register(&kirkwood_switch_device);
index efb86b700276bf965c611526e83d8973d20b7a90..06083b23bb446a6743a894afd0c605c5b2932274 100644 (file)
@@ -42,7 +42,7 @@ void __init kirkwood_init_irq(void)
        writel(0, GPIO_EDGE_CAUSE(32));
 
        for (i = IRQ_KIRKWOOD_GPIO_START; i < NR_IRQS; i++) {
-               set_irq_chip(i, &orion_gpio_irq_level_chip);
+               set_irq_chip(i, &orion_gpio_irq_chip);
                set_irq_handler(i, handle_level_irq);
                irq_desc[i].status |= IRQ_LEVEL;
                set_irq_flags(i, IRQF_VALID);
index 9a0e905d10cd04e6841f8dc7f5cc7bb6c57fa705..e1c0516c4df376cff50a40cf310be2cfb69d563e 100644 (file)
@@ -75,7 +75,7 @@ static struct mv643xx_eth_platform_data rd88f6281_ge00_data = {
        .duplex         = DUPLEX_FULL,
 };
 
-static struct dsa_platform_data rd88f6281_switch_data = {
+static struct dsa_chip_data rd88f6281_switch_chip_data = {
        .port_names[0]  = "lan1",
        .port_names[1]  = "lan2",
        .port_names[2]  = "lan3",
@@ -83,6 +83,11 @@ static struct dsa_platform_data rd88f6281_switch_data = {
        .port_names[5]  = "cpu",
 };
 
+static struct dsa_platform_data rd88f6281_switch_plat_data = {
+       .nr_chips       = 1,
+       .chip           = &rd88f6281_switch_chip_data,
+};
+
 static struct mv643xx_eth_platform_data rd88f6281_ge01_data = {
        .phy_addr       = MV643XX_ETH_PHY_ADDR(11),
 };
@@ -105,12 +110,12 @@ static void __init rd88f6281_init(void)
        kirkwood_ge00_init(&rd88f6281_ge00_data);
        kirkwood_pcie_id(&dev, &rev);
        if (rev == MV88F6281_REV_A0) {
-               rd88f6281_switch_data.sw_addr = 10;
+               rd88f6281_switch_chip_data.sw_addr = 10;
                kirkwood_ge01_init(&rd88f6281_ge01_data);
        } else {
-               rd88f6281_switch_data.port_names[4] = "wan";
+               rd88f6281_switch_chip_data.port_names[4] = "wan";
        }
-       kirkwood_ge00_switch_init(&rd88f6281_switch_data, NO_IRQ);
+       kirkwood_ge00_switch_init(&rd88f6281_switch_plat_data, NO_IRQ);
 
        kirkwood_rtc_init();
        kirkwood_sata_init(&rd88f6281_sata_data);
index e273418797b41cbaa309469fac12656aff97b986..30b7e4bcdbc7c7523affdb36f4884e819acf0420 100644 (file)
@@ -40,7 +40,7 @@ void __init mv78xx0_init_irq(void)
        writel(0, GPIO_EDGE_CAUSE(0));
 
        for (i = IRQ_MV78XX0_GPIO_START; i < NR_IRQS; i++) {
-               set_irq_chip(i, &orion_gpio_irq_level_chip);
+               set_irq_chip(i, &orion_gpio_irq_chip);
                set_irq_handler(i, handle_level_irq);
                irq_desc[i].status |= IRQ_LEVEL;
                set_irq_flags(i, IRQF_VALID);
index f6a13451d1fdd10ef9845e6dec4587c9660047b7..6031e179926bf66a5a45b8e560df5f63cb0d884c 100644 (file)
@@ -81,7 +81,7 @@ static inline void __init ldp_init_smc911x(void)
        }
 
        ldp_smc911x_resources[0].start = cs_mem_base + 0x0;
-       ldp_smc911x_resources[0].end   = cs_mem_base + 0xf;
+       ldp_smc911x_resources[0].end   = cs_mem_base + 0xff;
        udelay(100);
 
        eth_gpio = LDP_SMC911X_GPIO;
index ad721e0cbf7a1ded6c54ab2212efb4a5da1f281e..ce4d46a4a8381d2bd2b0cff19f840ae16ac2c153 100644 (file)
@@ -565,7 +565,7 @@ u32 omap2_clksel_to_divisor(struct clk *clk, u32 field_val)
  *
  * Given a struct clk of a rate-selectable clksel clock, and a clock divisor,
  * find the corresponding register field value.  The return register value is
- * the value before left-shifting.  Returns 0xffffffff on error
+ * the value before left-shifting.  Returns ~0 on error
  */
 u32 omap2_divisor_to_clksel(struct clk *clk, u32 div)
 {
@@ -577,7 +577,7 @@ u32 omap2_divisor_to_clksel(struct clk *clk, u32 div)
 
        clks = omap2_get_clksel_by_parent(clk, clk->parent);
        if (clks == NULL)
-               return 0;
+               return ~0;
 
        for (clkr = clks->rates; clkr->div; clkr++) {
                if ((clkr->flags & cpu_mask) && (clkr->div == div))
@@ -588,7 +588,7 @@ u32 omap2_divisor_to_clksel(struct clk *clk, u32 div)
                printk(KERN_ERR "clock: Could not find divisor %d for "
                       "clock %s parent %s\n", div, clk->name,
                       clk->parent->name);
-               return 0;
+               return ~0;
        }
 
        return clkr->val;
@@ -708,7 +708,7 @@ static u32 omap2_clksel_get_src_field(void __iomem **src_addr,
                return 0;
 
        for (clkr = clks->rates; clkr->div; clkr++) {
-               if (clkr->flags & (cpu_mask | DEFAULT_RATE))
+               if (clkr->flags & cpu_mask && clkr->flags & DEFAULT_RATE)
                        break; /* Found the default rate for this platform */
        }
 
@@ -746,7 +746,7 @@ int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
                return -EINVAL;
 
        if (clk->usecount > 0)
-               _omap2_clk_disable(clk);
+               omap2_clk_disable(clk);
 
        /* Set new source value (previous dividers if any in effect) */
        reg_val = __raw_readl(src_addr) & ~field_mask;
@@ -759,11 +759,11 @@ int omap2_clk_set_parent(struct clk *clk, struct clk *new_parent)
                wmb();
        }
 
-       if (clk->usecount > 0)
-               _omap2_clk_enable(clk);
-
        clk->parent = new_parent;
 
+       if (clk->usecount > 0)
+               omap2_clk_enable(clk);
+
        /* CLKSEL clocks follow their parents' rates, divided by a divisor */
        clk->rate = new_parent->rate;
 
index 0a623379789f03c4603cc43f33ebabcb2a8759b4..a4ecf625981ecb2887d87dd5b42f054e4e16fdc0 100644 (file)
@@ -219,14 +219,17 @@ static struct platform_device orion5x_switch_device = {
 
 void __init orion5x_eth_switch_init(struct dsa_platform_data *d, int irq)
 {
+       int i;
+
        if (irq != NO_IRQ) {
                orion5x_switch_resources[0].start = irq;
                orion5x_switch_resources[0].end = irq;
                orion5x_switch_device.num_resources = 1;
        }
 
-       d->mii_bus = &orion5x_eth_shared.dev;
        d->netdev = &orion5x_eth.dev;
+       for (i = 0; i < d->nr_chips; i++)
+               d->chip[i].mii_bus = &orion5x_eth_shared.dev;
        orion5x_switch_device.dev.platform_data = d;
 
        platform_device_register(&orion5x_switch_device);
index 0caae43301e54e472d82187680ed69fca4feda72..e03f7b45cb0d114ad0b0e343d424ba1122b03472 100644 (file)
@@ -44,7 +44,7 @@ void __init orion5x_init_irq(void)
         * User can use set_type() if he wants to use edge types handlers.
         */
        for (i = IRQ_ORION5X_GPIO_START; i < NR_IRQS; i++) {
-               set_irq_chip(i, &orion_gpio_irq_level_chip);
+               set_irq_chip(i, &orion_gpio_irq_chip);
                set_irq_handler(i, handle_level_irq);
                irq_desc[i].status |= IRQ_LEVEL;
                set_irq_flags(i, IRQF_VALID);
index 15f53235ee302dbff7c9615fbc746c250982105b..9c1ca41730ba4fc00d248029dedfb0d7bc8d8417 100644 (file)
@@ -94,7 +94,7 @@ static struct mv643xx_eth_platform_data rd88f5181l_fxo_eth_data = {
        .duplex         = DUPLEX_FULL,
 };
 
-static struct dsa_platform_data rd88f5181l_fxo_switch_data = {
+static struct dsa_chip_data rd88f5181l_fxo_switch_chip_data = {
        .port_names[0]  = "lan2",
        .port_names[1]  = "lan1",
        .port_names[2]  = "wan",
@@ -103,6 +103,11 @@ static struct dsa_platform_data rd88f5181l_fxo_switch_data = {
        .port_names[7]  = "lan3",
 };
 
+static struct dsa_platform_data rd88f5181l_fxo_switch_plat_data = {
+       .nr_chips       = 1,
+       .chip           = &rd88f5181l_fxo_switch_chip_data,
+};
+
 static void __init rd88f5181l_fxo_init(void)
 {
        /*
@@ -117,7 +122,7 @@ static void __init rd88f5181l_fxo_init(void)
         */
        orion5x_ehci0_init();
        orion5x_eth_init(&rd88f5181l_fxo_eth_data);
-       orion5x_eth_switch_init(&rd88f5181l_fxo_switch_data, NO_IRQ);
+       orion5x_eth_switch_init(&rd88f5181l_fxo_switch_plat_data, NO_IRQ);
        orion5x_uart0_init();
 
        orion5x_setup_dev_boot_win(RD88F5181L_FXO_NOR_BOOT_BASE,
index 8ad3934399d4fab8680fd0cc994305f4363925ee..ee1399ff0cedbe38aab1f8a4ff82dbdb921158be 100644 (file)
@@ -95,7 +95,7 @@ static struct mv643xx_eth_platform_data rd88f5181l_ge_eth_data = {
        .duplex         = DUPLEX_FULL,
 };
 
-static struct dsa_platform_data rd88f5181l_ge_switch_data = {
+static struct dsa_chip_data rd88f5181l_ge_switch_chip_data = {
        .port_names[0]  = "lan2",
        .port_names[1]  = "lan1",
        .port_names[2]  = "wan",
@@ -104,6 +104,11 @@ static struct dsa_platform_data rd88f5181l_ge_switch_data = {
        .port_names[7]  = "lan3",
 };
 
+static struct dsa_platform_data rd88f5181l_ge_switch_plat_data = {
+       .nr_chips       = 1,
+       .chip           = &rd88f5181l_ge_switch_chip_data,
+};
+
 static struct i2c_board_info __initdata rd88f5181l_ge_i2c_rtc = {
        I2C_BOARD_INFO("ds1338", 0x68),
 };
@@ -122,7 +127,8 @@ static void __init rd88f5181l_ge_init(void)
         */
        orion5x_ehci0_init();
        orion5x_eth_init(&rd88f5181l_ge_eth_data);
-       orion5x_eth_switch_init(&rd88f5181l_ge_switch_data, gpio_to_irq(8));
+       orion5x_eth_switch_init(&rd88f5181l_ge_switch_plat_data,
+                               gpio_to_irq(8));
        orion5x_i2c_init();
        orion5x_uart0_init();
 
index 262e25e4dace484fa826ddf60f8f226f1bf0bef6..7737cf9a8f5046a80911cd80b70a3f506d6fc057 100644 (file)
@@ -35,7 +35,7 @@ static struct mv643xx_eth_platform_data rd88f6183ap_ge_eth_data = {
        .duplex         = DUPLEX_FULL,
 };
 
-static struct dsa_platform_data rd88f6183ap_ge_switch_data = {
+static struct dsa_chip_data rd88f6183ap_ge_switch_chip_data = {
        .port_names[0]  = "lan1",
        .port_names[1]  = "lan2",
        .port_names[2]  = "lan3",
@@ -44,6 +44,11 @@ static struct dsa_platform_data rd88f6183ap_ge_switch_data = {
        .port_names[5]  = "cpu",
 };
 
+static struct dsa_platform_data rd88f6183ap_ge_switch_plat_data = {
+       .nr_chips       = 1,
+       .chip           = &rd88f6183ap_ge_switch_chip_data,
+};
+
 static struct mtd_partition rd88f6183ap_ge_partitions[] = {
        {
                .name   = "kernel",
@@ -89,7 +94,8 @@ static void __init rd88f6183ap_ge_init(void)
         */
        orion5x_ehci0_init();
        orion5x_eth_init(&rd88f6183ap_ge_eth_data);
-       orion5x_eth_switch_init(&rd88f6183ap_ge_switch_data, gpio_to_irq(3));
+       orion5x_eth_switch_init(&rd88f6183ap_ge_switch_plat_data,
+                               gpio_to_irq(3));
        spi_register_board_info(rd88f6183ap_ge_spi_slave_info,
                                ARRAY_SIZE(rd88f6183ap_ge_spi_slave_info));
        orion5x_spi_init();
index cc8f8920086505fb963efc6c232f617ed1082855..1b4ad9d5e2ebeedeab6804e47b52651cc3e6c74e 100644 (file)
@@ -106,7 +106,7 @@ static struct mv643xx_eth_platform_data wrt350n_v2_eth_data = {
        .duplex         = DUPLEX_FULL,
 };
 
-static struct dsa_platform_data wrt350n_v2_switch_data = {
+static struct dsa_chip_data wrt350n_v2_switch_chip_data = {
        .port_names[0]  = "lan2",
        .port_names[1]  = "lan1",
        .port_names[2]  = "wan",
@@ -115,6 +115,11 @@ static struct dsa_platform_data wrt350n_v2_switch_data = {
        .port_names[7]  = "lan4",
 };
 
+static struct dsa_platform_data wrt350n_v2_switch_plat_data = {
+       .nr_chips       = 1,
+       .chip           = &wrt350n_v2_switch_chip_data,
+};
+
 static void __init wrt350n_v2_init(void)
 {
        /*
@@ -129,7 +134,7 @@ static void __init wrt350n_v2_init(void)
         */
        orion5x_ehci0_init();
        orion5x_eth_init(&wrt350n_v2_eth_data);
-       orion5x_eth_switch_init(&wrt350n_v2_switch_data, NO_IRQ);
+       orion5x_eth_switch_init(&wrt350n_v2_switch_plat_data, NO_IRQ);
        orion5x_uart0_init();
 
        orion5x_setup_dev_boot_win(WRT350N_V2_NOR_BOOT_BASE,
index e88d417736af1225cdadca8825ff43e000958712..c7fc01e9d1f64bd9c5be760475f7d9537e497312 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/serial_8250.h>
 #include <linux/ata_platform.h>
 #include <linux/io.h>
+#include <linux/i2c.h>
 
 #include <asm/elf.h>
 #include <asm/mach-types.h>
@@ -201,8 +202,13 @@ static struct platform_device *devs[] __initdata = {
        &pata_device,
 };
 
+static struct i2c_board_info i2c_rtc = {
+       I2C_BOARD_INFO("pcf8583", 0x50)
+};
+
 static int __init rpc_init(void)
 {
+       i2c_register_board_info(0, &i2c_rtc, 1);
        return platform_add_devices(devs, ARRAY_SIZE(devs));
 }
 
index 8a7f65ba14b761cb81ceaa87689f1f0d9a91ed3f..94077fbd96b7691850275d71114eb2b9d328f5d3 100644 (file)
@@ -23,7 +23,8 @@ ENTRY(v6_early_abort)
 #ifdef CONFIG_CPU_32v6K
        clrex
 #else
-       strex   r0, r1, [sp]                    @ Clear the exclusive monitor
+       sub     r1, sp, #4                      @ Get unused stack location
+       strex   r0, r1, [r1]                    @ Clear the exclusive monitor
 #endif
        mrc     p15, 0, r1, c5, c0, 0           @ get FSR
        mrc     p15, 0, r0, c6, c0, 0           @ get FAR
index 9b36c5cb5e9f68306c017cf63f94ab55ccc1ce3f..d4d082c5c2d4ad2be9f1eb331cce837fff3de325 100644 (file)
@@ -693,7 +693,8 @@ static void __init sanity_check_meminfo(void)
                 * Check whether this memory bank would entirely overlap
                 * the vmalloc area.
                 */
-               if (__va(bank->start) >= VMALLOC_MIN) {
+               if (__va(bank->start) >= VMALLOC_MIN ||
+                   __va(bank->start) < PAGE_OFFSET) {
                        printk(KERN_NOTICE "Ignoring RAM at %.8lx-%.8lx "
                               "(vmalloc region overlap).\n",
                               bank->start, bank->start + bank->size - 1);
index 967186425ca1073ecea837206ebe22c081335693..0d12c21647663d5191167569354bd3af1d7d84b5 100644 (file)
@@ -265,51 +265,36 @@ EXPORT_SYMBOL(orion_gpio_set_blink);
  *        polarity    LEVEL          mask
  *
  ****************************************************************************/
-static void gpio_irq_edge_ack(u32 irq)
-{
-       int pin = irq_to_gpio(irq);
-
-       writel(~(1 << (pin & 31)), GPIO_EDGE_CAUSE(pin));
-}
-
-static void gpio_irq_edge_mask(u32 irq)
-{
-       int pin = irq_to_gpio(irq);
-       u32 u;
-
-       u = readl(GPIO_EDGE_MASK(pin));
-       u &= ~(1 << (pin & 31));
-       writel(u, GPIO_EDGE_MASK(pin));
-}
 
-static void gpio_irq_edge_unmask(u32 irq)
+static void gpio_irq_ack(u32 irq)
 {
-       int pin = irq_to_gpio(irq);
-       u32 u;
-
-       u = readl(GPIO_EDGE_MASK(pin));
-       u |= 1 << (pin & 31);
-       writel(u, GPIO_EDGE_MASK(pin));
+       int type = irq_desc[irq].status & IRQ_TYPE_SENSE_MASK;
+       if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
+               int pin = irq_to_gpio(irq);
+               writel(~(1 << (pin & 31)), GPIO_EDGE_CAUSE(pin));
+       }
 }
 
-static void gpio_irq_level_mask(u32 irq)
+static void gpio_irq_mask(u32 irq)
 {
        int pin = irq_to_gpio(irq);
-       u32 u;
-
-       u = readl(GPIO_LEVEL_MASK(pin));
+       int type = irq_desc[irq].status & IRQ_TYPE_SENSE_MASK;
+       u32 reg = (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) ?
+               GPIO_EDGE_MASK(pin) : GPIO_LEVEL_MASK(pin);
+       u32 u = readl(reg);
        u &= ~(1 << (pin & 31));
-       writel(u, GPIO_LEVEL_MASK(pin));
+       writel(u, reg);
 }
 
-static void gpio_irq_level_unmask(u32 irq)
+static void gpio_irq_unmask(u32 irq)
 {
        int pin = irq_to_gpio(irq);
-       u32 u;
-
-       u = readl(GPIO_LEVEL_MASK(pin));
+       int type = irq_desc[irq].status & IRQ_TYPE_SENSE_MASK;
+       u32 reg = (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) ?
+               GPIO_EDGE_MASK(pin) : GPIO_LEVEL_MASK(pin);
+       u32 u = readl(reg);
        u |= 1 << (pin & 31);
-       writel(u, GPIO_LEVEL_MASK(pin));
+       writel(u, reg);
 }
 
 static int gpio_irq_set_type(u32 irq, u32 type)
@@ -331,9 +316,9 @@ static int gpio_irq_set_type(u32 irq, u32 type)
         * Set edge/level type.
         */
        if (type & (IRQ_TYPE_EDGE_RISING | IRQ_TYPE_EDGE_FALLING)) {
-               desc->chip = &orion_gpio_irq_edge_chip;
+               desc->handle_irq = handle_edge_irq;
        } else if (type & (IRQ_TYPE_LEVEL_HIGH | IRQ_TYPE_LEVEL_LOW)) {
-               desc->chip = &orion_gpio_irq_level_chip;
+               desc->handle_irq = handle_level_irq;
        } else {
                printk(KERN_ERR "failed to set irq=%d (type=%d)\n", irq, type);
                return -EINVAL;
@@ -371,19 +356,11 @@ static int gpio_irq_set_type(u32 irq, u32 type)
        return 0;
 }
 
-struct irq_chip orion_gpio_irq_edge_chip = {
-       .name           = "orion_gpio_irq_edge",
-       .ack            = gpio_irq_edge_ack,
-       .mask           = gpio_irq_edge_mask,
-       .unmask         = gpio_irq_edge_unmask,
-       .set_type       = gpio_irq_set_type,
-};
-
-struct irq_chip orion_gpio_irq_level_chip = {
-       .name           = "orion_gpio_irq_level",
-       .mask           = gpio_irq_level_mask,
-       .mask_ack       = gpio_irq_level_mask,
-       .unmask         = gpio_irq_level_unmask,
+struct irq_chip orion_gpio_irq_chip = {
+       .name           = "orion_gpio",
+       .ack            = gpio_irq_ack,
+       .mask           = gpio_irq_mask,
+       .unmask         = gpio_irq_unmask,
        .set_type       = gpio_irq_set_type,
 };
 
index 54deaf274b5268a6983dae399f8285f4e4a92ea6..ec743e82c876cab82abd00a9c415c265258feea9 100644 (file)
@@ -31,8 +31,7 @@ void orion_gpio_set_blink(unsigned pin, int blink);
 /*
  * GPIO interrupt handling.
  */
-extern struct irq_chip orion_gpio_irq_edge_chip;
-extern struct irq_chip orion_gpio_irq_level_chip;
+extern struct irq_chip orion_gpio_irq_chip;
 void orion_gpio_irq_handler(int irqoff);
 
 
index 1f7cc0067f5cdd19fad4c487b2a2821687de3b92..ebb305ce7689f2aa0499f6d582ceebc453cddaf0 100644 (file)
@@ -55,7 +55,7 @@ static void s3c_irq_eint_unmask(unsigned int irq)
        u32 mask;
 
        mask = __raw_readl(S3C64XX_EINT0MASK);
-       mask |= eint_irq_to_bit(irq);
+       mask &= ~eint_irq_to_bit(irq);
        __raw_writel(mask, S3C64XX_EINT0MASK);
 }
 
index aafaf7a78886951ed50017c6d414e6b5758cff05..cff8e84f78f21b64e580034a999cefc48d7536b1 100644 (file)
@@ -116,6 +116,7 @@ struct atmel_nand_data {
        int     enable_pin;     /* chip enable */
        int     det_pin;        /* card detect */
        int     rdy_pin;        /* ready/busy */
+       u8      rdy_pin_active_low;     /* rdy_pin value is inverted */
        u8      ale;            /* address line number connected to ALE */
        u8      cle;            /* address line number connected to CLE */
        u8      bus_width_16;   /* buswidth is 16 bit */
index 6183aeccecf1f9d564cc2bc2832943a235ed3871..153e727a6e8ecffb23e70bdc39ef3314b34c0aae 100644 (file)
@@ -221,7 +221,11 @@ config IA64_HP_SIM
 
 config IA64_XEN_GUEST
        bool "Xen guest"
+       select SWIOTLB
        depends on XEN
+       help
+         Build a kernel that runs on Xen guest domain. At this moment only
+         16KB page size in supported.
 
 endchoice
 
@@ -479,8 +483,7 @@ config HOLES_IN_ZONE
        default y if VIRTUAL_MEM_MAP
 
 config HAVE_ARCH_EARLY_PFN_TO_NID
-       def_bool y
-       depends on NEED_MULTIPLE_NODES
+       def_bool NUMA && SPARSEMEM
 
 config HAVE_ARCH_NODEDATA_EXTENSION
        def_bool y
@@ -635,6 +638,17 @@ config DMAR
          and include PCI device scope covered by these DMA
          remapping devices.
 
+config DMAR_DEFAULT_ON
+       def_bool y
+       prompt "Enable DMA Remapping Devices by default"
+       depends on DMAR
+       help
+         Selecting this option will enable a DMAR device at boot time if
+         one is found. If this option is not selected, DMAR support can
+         be enabled by passing intel_iommu=on to the kernel. It is
+         recommended you say N here while the DMAR code remains
+         experimental.
+
 endmenu
 
 endif
diff --git a/arch/ia64/configs/xen_domu_defconfig b/arch/ia64/configs/xen_domu_defconfig
new file mode 100644 (file)
index 0000000..0bb0714
--- /dev/null
@@ -0,0 +1,1601 @@
+#
+# Automatically generated make config: don't edit
+# Linux kernel version: 2.6.29-rc1
+# Fri Jan 16 11:49:59 2009
+#
+CONFIG_DEFCONFIG_LIST="/lib/modules/$UNAME_RELEASE/.config"
+
+#
+# General setup
+#
+CONFIG_EXPERIMENTAL=y
+CONFIG_LOCK_KERNEL=y
+CONFIG_INIT_ENV_ARG_LIMIT=32
+CONFIG_LOCALVERSION=""
+CONFIG_LOCALVERSION_AUTO=y
+CONFIG_SWAP=y
+CONFIG_SYSVIPC=y
+CONFIG_SYSVIPC_SYSCTL=y
+CONFIG_POSIX_MQUEUE=y
+# CONFIG_BSD_PROCESS_ACCT is not set
+# CONFIG_TASKSTATS is not set
+# CONFIG_AUDIT is not set
+CONFIG_IKCONFIG=y
+CONFIG_IKCONFIG_PROC=y
+CONFIG_LOG_BUF_SHIFT=20
+CONFIG_HAVE_UNSTABLE_SCHED_CLOCK=y
+# CONFIG_GROUP_SCHED is not set
+
+#
+# Control Group support
+#
+# CONFIG_CGROUPS is not set
+CONFIG_SYSFS_DEPRECATED=y
+CONFIG_SYSFS_DEPRECATED_V2=y
+# CONFIG_RELAY is not set
+CONFIG_NAMESPACES=y
+# CONFIG_UTS_NS is not set
+# CONFIG_IPC_NS is not set
+# CONFIG_USER_NS is not set
+# CONFIG_PID_NS is not set
+CONFIG_BLK_DEV_INITRD=y
+CONFIG_INITRAMFS_SOURCE=""
+CONFIG_CC_OPTIMIZE_FOR_SIZE=y
+CONFIG_SYSCTL=y
+# CONFIG_EMBEDDED is not set
+CONFIG_SYSCTL_SYSCALL=y
+CONFIG_KALLSYMS=y
+CONFIG_KALLSYMS_ALL=y
+CONFIG_KALLSYMS_STRIP_GENERATED=y
+# CONFIG_KALLSYMS_EXTRA_PASS is not set
+CONFIG_HOTPLUG=y
+CONFIG_PRINTK=y
+CONFIG_BUG=y
+CONFIG_ELF_CORE=y
+CONFIG_COMPAT_BRK=y
+CONFIG_BASE_FULL=y
+CONFIG_FUTEX=y
+CONFIG_ANON_INODES=y
+CONFIG_EPOLL=y
+CONFIG_SIGNALFD=y
+CONFIG_TIMERFD=y
+CONFIG_EVENTFD=y
+CONFIG_SHMEM=y
+CONFIG_AIO=y
+CONFIG_VM_EVENT_COUNTERS=y
+CONFIG_PCI_QUIRKS=y
+CONFIG_SLUB_DEBUG=y
+# CONFIG_SLAB is not set
+CONFIG_SLUB=y
+# CONFIG_SLOB is not set
+# CONFIG_PROFILING is not set
+CONFIG_HAVE_OPROFILE=y
+# CONFIG_KPROBES is not set
+CONFIG_HAVE_KPROBES=y
+CONFIG_HAVE_KRETPROBES=y
+CONFIG_HAVE_ARCH_TRACEHOOK=y
+CONFIG_HAVE_DMA_ATTRS=y
+CONFIG_USE_GENERIC_SMP_HELPERS=y
+# CONFIG_HAVE_GENERIC_DMA_COHERENT is not set
+CONFIG_SLABINFO=y
+CONFIG_RT_MUTEXES=y
+CONFIG_BASE_SMALL=0
+CONFIG_MODULES=y
+# CONFIG_MODULE_FORCE_LOAD is not set
+CONFIG_MODULE_UNLOAD=y
+# CONFIG_MODULE_FORCE_UNLOAD is not set
+CONFIG_MODVERSIONS=y
+CONFIG_MODULE_SRCVERSION_ALL=y
+CONFIG_STOP_MACHINE=y
+CONFIG_BLOCK=y
+# CONFIG_BLK_DEV_IO_TRACE is not set
+# CONFIG_BLK_DEV_BSG is not set
+# CONFIG_BLK_DEV_INTEGRITY is not set
+
+#
+# IO Schedulers
+#
+CONFIG_IOSCHED_NOOP=y
+CONFIG_IOSCHED_AS=y
+CONFIG_IOSCHED_DEADLINE=y
+CONFIG_IOSCHED_CFQ=y
+CONFIG_DEFAULT_AS=y
+# CONFIG_DEFAULT_DEADLINE is not set
+# CONFIG_DEFAULT_CFQ is not set
+# CONFIG_DEFAULT_NOOP is not set
+CONFIG_DEFAULT_IOSCHED="anticipatory"
+CONFIG_CLASSIC_RCU=y
+# CONFIG_TREE_RCU is not set
+# CONFIG_PREEMPT_RCU is not set
+# CONFIG_TREE_RCU_TRACE is not set
+# CONFIG_PREEMPT_RCU_TRACE is not set
+CONFIG_FREEZER=y
+
+#
+# Processor type and features
+#
+CONFIG_IA64=y
+CONFIG_64BIT=y
+CONFIG_ZONE_DMA=y
+CONFIG_QUICKLIST=y
+CONFIG_MMU=y
+CONFIG_SWIOTLB=y
+CONFIG_IOMMU_HELPER=y
+CONFIG_RWSEM_XCHGADD_ALGORITHM=y
+CONFIG_HUGETLB_PAGE_SIZE_VARIABLE=y
+CONFIG_GENERIC_FIND_NEXT_BIT=y
+CONFIG_GENERIC_CALIBRATE_DELAY=y
+CONFIG_GENERIC_TIME=y
+CONFIG_GENERIC_TIME_VSYSCALL=y
+CONFIG_HAVE_SETUP_PER_CPU_AREA=y
+CONFIG_DMI=y
+CONFIG_EFI=y
+CONFIG_GENERIC_IOMAP=y
+CONFIG_SCHED_OMIT_FRAME_POINTER=y
+CONFIG_AUDIT_ARCH=y
+CONFIG_PARAVIRT_GUEST=y
+CONFIG_PARAVIRT=y
+CONFIG_XEN=y
+CONFIG_XEN_XENCOMM=y
+CONFIG_NO_IDLE_HZ=y
+# CONFIG_IA64_GENERIC is not set
+# CONFIG_IA64_DIG is not set
+# CONFIG_IA64_DIG_VTD is not set
+# CONFIG_IA64_HP_ZX1 is not set
+# CONFIG_IA64_HP_ZX1_SWIOTLB is not set
+# CONFIG_IA64_SGI_SN2 is not set
+# CONFIG_IA64_SGI_UV is not set
+# CONFIG_IA64_HP_SIM is not set
+CONFIG_IA64_XEN_GUEST=y
+# CONFIG_ITANIUM is not set
+CONFIG_MCKINLEY=y
+# CONFIG_IA64_PAGE_SIZE_4KB is not set
+# CONFIG_IA64_PAGE_SIZE_8KB is not set
+CONFIG_IA64_PAGE_SIZE_16KB=y
+# CONFIG_IA64_PAGE_SIZE_64KB is not set
+CONFIG_PGTABLE_3=y
+# CONFIG_PGTABLE_4 is not set
+CONFIG_HZ=250
+# CONFIG_HZ_100 is not set
+CONFIG_HZ_250=y
+# CONFIG_HZ_300 is not set
+# CONFIG_HZ_1000 is not set
+# CONFIG_SCHED_HRTICK is not set
+CONFIG_IA64_L1_CACHE_SHIFT=7
+CONFIG_IA64_CYCLONE=y
+CONFIG_IOSAPIC=y
+CONFIG_FORCE_MAX_ZONEORDER=17
+# CONFIG_VIRT_CPU_ACCOUNTING is not set
+CONFIG_SMP=y
+CONFIG_NR_CPUS=16
+CONFIG_HOTPLUG_CPU=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTPLUG=y
+CONFIG_ARCH_ENABLE_MEMORY_HOTREMOVE=y
+# CONFIG_SCHED_SMT is not set
+CONFIG_PERMIT_BSP_REMOVE=y
+CONFIG_FORCE_CPEI_RETARGET=y
+CONFIG_PREEMPT_NONE=y
+# CONFIG_PREEMPT_VOLUNTARY is not set
+# CONFIG_PREEMPT is not set
+CONFIG_SELECT_MEMORY_MODEL=y
+CONFIG_FLATMEM_MANUAL=y
+# CONFIG_DISCONTIGMEM_MANUAL is not set
+# CONFIG_SPARSEMEM_MANUAL is not set
+CONFIG_FLATMEM=y
+CONFIG_FLAT_NODE_MEM_MAP=y
+CONFIG_SPARSEMEM_VMEMMAP_ENABLE=y
+CONFIG_PAGEFLAGS_EXTENDED=y
+CONFIG_SPLIT_PTLOCK_CPUS=4
+CONFIG_MIGRATION=y
+CONFIG_PHYS_ADDR_T_64BIT=y
+CONFIG_ZONE_DMA_FLAG=1
+CONFIG_BOUNCE=y
+CONFIG_NR_QUICK=1
+CONFIG_VIRT_TO_BUS=y
+CONFIG_UNEVICTABLE_LRU=y
+CONFIG_ARCH_SELECT_MEMORY_MODEL=y
+CONFIG_ARCH_DISCONTIGMEM_ENABLE=y
+CONFIG_ARCH_FLATMEM_ENABLE=y
+CONFIG_ARCH_SPARSEMEM_ENABLE=y
+CONFIG_ARCH_POPULATES_NODE_MAP=y
+CONFIG_VIRTUAL_MEM_MAP=y
+CONFIG_HOLES_IN_ZONE=y
+# CONFIG_IA32_SUPPORT is not set
+# CONFIG_COMPAT_FOR_U64_ALIGNMENT is not set
+CONFIG_IA64_MCA_RECOVERY=y
+CONFIG_PERFMON=y
+CONFIG_IA64_PALINFO=y
+# CONFIG_IA64_MC_ERR_INJECT is not set
+# CONFIG_IA64_ESI is not set
+# CONFIG_IA64_HP_AML_NFW is not set
+CONFIG_KEXEC=y
+# CONFIG_CRASH_DUMP is not set
+
+#
+# Firmware Drivers
+#
+# CONFIG_FIRMWARE_MEMMAP is not set
+CONFIG_EFI_VARS=y
+CONFIG_EFI_PCDP=y
+CONFIG_DMIID=y
+CONFIG_BINFMT_ELF=y
+# CONFIG_CORE_DUMP_DEFAULT_ELF_HEADERS is not set
+# CONFIG_HAVE_AOUT is not set
+CONFIG_BINFMT_MISC=m
+
+#
+# Power management and ACPI options
+#
+CONFIG_PM=y
+# CONFIG_PM_DEBUG is not set
+CONFIG_PM_SLEEP=y
+CONFIG_SUSPEND=y
+CONFIG_SUSPEND_FREEZER=y
+CONFIG_ACPI=y
+CONFIG_ACPI_SLEEP=y
+CONFIG_ACPI_PROCFS=y
+CONFIG_ACPI_PROCFS_POWER=y
+CONFIG_ACPI_SYSFS_POWER=y
+CONFIG_ACPI_PROC_EVENT=y
+CONFIG_ACPI_BUTTON=m
+CONFIG_ACPI_FAN=m
+# CONFIG_ACPI_DOCK is not set
+CONFIG_ACPI_PROCESSOR=m
+CONFIG_ACPI_HOTPLUG_CPU=y
+CONFIG_ACPI_THERMAL=m
+# CONFIG_ACPI_CUSTOM_DSDT is not set
+CONFIG_ACPI_BLACKLIST_YEAR=0
+# CONFIG_ACPI_DEBUG is not set
+# CONFIG_ACPI_PCI_SLOT is not set
+CONFIG_ACPI_SYSTEM=y
+CONFIG_ACPI_CONTAINER=m
+
+#
+# CPU Frequency scaling
+#
+# CONFIG_CPU_FREQ is not set
+
+#
+# Bus options (PCI, PCMCIA)
+#
+CONFIG_PCI=y
+CONFIG_PCI_DOMAINS=y
+CONFIG_PCI_SYSCALL=y
+# CONFIG_PCIEPORTBUS is not set
+CONFIG_ARCH_SUPPORTS_MSI=y
+# CONFIG_PCI_MSI is not set
+CONFIG_PCI_LEGACY=y
+# CONFIG_PCI_DEBUG is not set
+# CONFIG_PCI_STUB is not set
+CONFIG_HOTPLUG_PCI=m
+# CONFIG_HOTPLUG_PCI_FAKE is not set
+CONFIG_HOTPLUG_PCI_ACPI=m
+# CONFIG_HOTPLUG_PCI_ACPI_IBM is not set
+# CONFIG_HOTPLUG_PCI_CPCI is not set
+# CONFIG_HOTPLUG_PCI_SHPC is not set
+# CONFIG_PCCARD is not set
+CONFIG_NET=y
+
+#
+# Networking options
+#
+# CONFIG_NET_NS is not set
+CONFIG_COMPAT_NET_DEV_OPS=y
+CONFIG_PACKET=y
+# CONFIG_PACKET_MMAP is not set
+CONFIG_UNIX=y
+CONFIG_XFRM=y
+# CONFIG_XFRM_USER is not set
+# CONFIG_XFRM_SUB_POLICY is not set
+# CONFIG_XFRM_MIGRATE is not set
+# CONFIG_XFRM_STATISTICS is not set
+# CONFIG_NET_KEY is not set
+CONFIG_INET=y
+CONFIG_IP_MULTICAST=y
+# CONFIG_IP_ADVANCED_ROUTER is not set
+CONFIG_IP_FIB_HASH=y
+# CONFIG_IP_PNP is not set
+# CONFIG_NET_IPIP is not set
+# CONFIG_NET_IPGRE is not set
+# CONFIG_IP_MROUTE is not set
+CONFIG_ARPD=y
+CONFIG_SYN_COOKIES=y
+# CONFIG_INET_AH is not set
+# CONFIG_INET_ESP is not set
+# CONFIG_INET_IPCOMP is not set
+# CONFIG_INET_XFRM_TUNNEL is not set
+# CONFIG_INET_TUNNEL is not set
+CONFIG_INET_XFRM_MODE_TRANSPORT=y
+CONFIG_INET_XFRM_MODE_TUNNEL=y
+CONFIG_INET_XFRM_MODE_BEET=y
+# CONFIG_INET_LRO is not set
+CONFIG_INET_DIAG=y
+CONFIG_INET_TCP_DIAG=y
+# CONFIG_TCP_CONG_ADVANCED is not set
+CONFIG_TCP_CONG_CUBIC=y
+CONFIG_DEFAULT_TCP_CONG="cubic"
+# CONFIG_TCP_MD5SIG is not set
+# CONFIG_IPV6 is not set
+# CONFIG_NETWORK_SECMARK is not set
+# CONFIG_NETFILTER is not set
+# CONFIG_IP_DCCP is not set
+# CONFIG_IP_SCTP is not set
+# CONFIG_TIPC is not set
+# CONFIG_ATM is not set
+# CONFIG_BRIDGE is not set
+# CONFIG_NET_DSA is not set
+# CONFIG_VLAN_8021Q is not set
+# CONFIG_DECNET is not set
+# CONFIG_LLC2 is not set
+# CONFIG_IPX is not set
+# CONFIG_ATALK is not set
+# CONFIG_X25 is not set
+# CONFIG_LAPB is not set
+# CONFIG_ECONET is not set
+# CONFIG_WAN_ROUTER is not set
+# CONFIG_NET_SCHED is not set
+# CONFIG_DCB is not set
+
+#
+# Network testing
+#
+# CONFIG_NET_PKTGEN is not set
+# CONFIG_HAMRADIO is not set
+# CONFIG_CAN is not set
+# CONFIG_IRDA is not set
+# CONFIG_BT is not set
+# CONFIG_AF_RXRPC is not set
+# CONFIG_PHONET is not set
+# CONFIG_WIRELESS is not set
+# CONFIG_WIMAX is not set
+# CONFIG_RFKILL is not set
+# CONFIG_NET_9P is not set
+
+#
+# Device Drivers
+#
+
+#
+# Generic Driver Options
+#
+CONFIG_UEVENT_HELPER_PATH="/sbin/hotplug"
+CONFIG_STANDALONE=y
+CONFIG_PREVENT_FIRMWARE_BUILD=y
+CONFIG_FW_LOADER=y
+CONFIG_FIRMWARE_IN_KERNEL=y
+CONFIG_EXTRA_FIRMWARE=""
+# CONFIG_DEBUG_DRIVER is not set
+# CONFIG_DEBUG_DEVRES is not set
+# CONFIG_SYS_HYPERVISOR is not set
+# CONFIG_CONNECTOR is not set
+# CONFIG_MTD is not set
+# CONFIG_PARPORT is not set
+CONFIG_PNP=y
+CONFIG_PNP_DEBUG_MESSAGES=y
+
+#
+# Protocols
+#
+CONFIG_PNPACPI=y
+CONFIG_BLK_DEV=y
+# CONFIG_BLK_CPQ_DA is not set
+# CONFIG_BLK_CPQ_CISS_DA is not set
+# CONFIG_BLK_DEV_DAC960 is not set
+# CONFIG_BLK_DEV_UMEM is not set
+# CONFIG_BLK_DEV_COW_COMMON is not set
+CONFIG_BLK_DEV_LOOP=m
+CONFIG_BLK_DEV_CRYPTOLOOP=m
+CONFIG_BLK_DEV_NBD=m
+# CONFIG_BLK_DEV_SX8 is not set
+# CONFIG_BLK_DEV_UB is not set
+CONFIG_BLK_DEV_RAM=y
+CONFIG_BLK_DEV_RAM_COUNT=16
+CONFIG_BLK_DEV_RAM_SIZE=4096
+# CONFIG_BLK_DEV_XIP is not set
+# CONFIG_CDROM_PKTCDVD is not set
+# CONFIG_ATA_OVER_ETH is not set
+CONFIG_XEN_BLKDEV_FRONTEND=y
+# CONFIG_BLK_DEV_HD is not set
+CONFIG_MISC_DEVICES=y
+# CONFIG_PHANTOM is not set
+# CONFIG_EEPROM_93CX6 is not set
+# CONFIG_SGI_IOC4 is not set
+# CONFIG_TIFM_CORE is not set
+# CONFIG_ICS932S401 is not set
+# CONFIG_ENCLOSURE_SERVICES is not set
+# CONFIG_HP_ILO is not set
+# CONFIG_C2PORT is not set
+CONFIG_HAVE_IDE=y
+CONFIG_IDE=y
+
+#
+# Please see Documentation/ide/ide.txt for help/info on IDE drives
+#
+CONFIG_IDE_TIMINGS=y
+CONFIG_IDE_ATAPI=y
+# CONFIG_BLK_DEV_IDE_SATA is not set
+CONFIG_IDE_GD=y
+CONFIG_IDE_GD_ATA=y
+# CONFIG_IDE_GD_ATAPI is not set
+CONFIG_BLK_DEV_IDECD=y
+CONFIG_BLK_DEV_IDECD_VERBOSE_ERRORS=y
+# CONFIG_BLK_DEV_IDETAPE is not set
+# CONFIG_BLK_DEV_IDEACPI is not set
+# CONFIG_IDE_TASK_IOCTL is not set
+CONFIG_IDE_PROC_FS=y
+
+#
+# IDE chipset support/bugfixes
+#
+# CONFIG_IDE_GENERIC is not set
+# CONFIG_BLK_DEV_PLATFORM is not set
+# CONFIG_BLK_DEV_IDEPNP is not set
+CONFIG_BLK_DEV_IDEDMA_SFF=y
+
+#
+# PCI IDE chipsets support
+#
+CONFIG_BLK_DEV_IDEPCI=y
+CONFIG_IDEPCI_PCIBUS_ORDER=y
+# CONFIG_BLK_DEV_OFFBOARD is not set
+CONFIG_BLK_DEV_GENERIC=y
+# CONFIG_BLK_DEV_OPTI621 is not set
+CONFIG_BLK_DEV_IDEDMA_PCI=y
+# CONFIG_BLK_DEV_AEC62XX is not set
+# CONFIG_BLK_DEV_ALI15X3 is not set
+# CONFIG_BLK_DEV_AMD74XX is not set
+CONFIG_BLK_DEV_CMD64X=y
+# CONFIG_BLK_DEV_TRIFLEX is not set
+# CONFIG_BLK_DEV_CS5520 is not set
+# CONFIG_BLK_DEV_CS5530 is not set
+# CONFIG_BLK_DEV_HPT366 is not set
+# CONFIG_BLK_DEV_JMICRON is not set
+# CONFIG_BLK_DEV_SC1200 is not set
+CONFIG_BLK_DEV_PIIX=y
+# CONFIG_BLK_DEV_IT8172 is not set
+# CONFIG_BLK_DEV_IT8213 is not set
+# CONFIG_BLK_DEV_IT821X is not set
+# CONFIG_BLK_DEV_NS87415 is not set
+# CONFIG_BLK_DEV_PDC202XX_OLD is not set
+# CONFIG_BLK_DEV_PDC202XX_NEW is not set
+# CONFIG_BLK_DEV_SVWKS is not set
+# CONFIG_BLK_DEV_SIIMAGE is not set
+# CONFIG_BLK_DEV_SLC90E66 is not set
+# CONFIG_BLK_DEV_TRM290 is not set
+# CONFIG_BLK_DEV_VIA82CXXX is not set
+# CONFIG_BLK_DEV_TC86C001 is not set
+CONFIG_BLK_DEV_IDEDMA=y
+
+#
+# SCSI device support
+#
+# CONFIG_RAID_ATTRS is not set
+CONFIG_SCSI=y
+CONFIG_SCSI_DMA=y
+# CONFIG_SCSI_TGT is not set
+CONFIG_SCSI_NETLINK=y
+CONFIG_SCSI_PROC_FS=y
+
+#
+# SCSI support type (disk, tape, CD-ROM)
+#
+CONFIG_BLK_DEV_SD=y
+CONFIG_CHR_DEV_ST=m
+# CONFIG_CHR_DEV_OSST is not set
+CONFIG_BLK_DEV_SR=m
+# CONFIG_BLK_DEV_SR_VENDOR is not set
+CONFIG_CHR_DEV_SG=m
+# CONFIG_CHR_DEV_SCH is not set
+
+#
+# Some SCSI devices (e.g. CD jukebox) support multiple LUNs
+#
+# CONFIG_SCSI_MULTI_LUN is not set
+# CONFIG_SCSI_CONSTANTS is not set
+# CONFIG_SCSI_LOGGING is not set
+# CONFIG_SCSI_SCAN_ASYNC is not set
+CONFIG_SCSI_WAIT_SCAN=m
+
+#
+# SCSI Transports
+#
+CONFIG_SCSI_SPI_ATTRS=y
+CONFIG_SCSI_FC_ATTRS=y
+# CONFIG_SCSI_ISCSI_ATTRS is not set
+# CONFIG_SCSI_SAS_LIBSAS is not set
+# CONFIG_SCSI_SRP_ATTRS is not set
+CONFIG_SCSI_LOWLEVEL=y
+# CONFIG_ISCSI_TCP is not set
+# CONFIG_SCSI_CXGB3_ISCSI is not set
+# CONFIG_BLK_DEV_3W_XXXX_RAID is not set
+# CONFIG_SCSI_3W_9XXX is not set
+# CONFIG_SCSI_ACARD is not set
+# CONFIG_SCSI_AACRAID is not set
+# CONFIG_SCSI_AIC7XXX is not set
+# CONFIG_SCSI_AIC7XXX_OLD is not set
+# CONFIG_SCSI_AIC79XX is not set
+# CONFIG_SCSI_AIC94XX is not set
+# CONFIG_SCSI_DPT_I2O is not set
+# CONFIG_SCSI_ADVANSYS is not set
+# CONFIG_SCSI_ARCMSR is not set
+# CONFIG_MEGARAID_NEWGEN is not set
+# CONFIG_MEGARAID_LEGACY is not set
+# CONFIG_MEGARAID_SAS is not set
+# CONFIG_SCSI_HPTIOP is not set
+# CONFIG_LIBFC is not set
+# CONFIG_FCOE is not set
+# CONFIG_SCSI_DMX3191D is not set
+# CONFIG_SCSI_FUTURE_DOMAIN is not set
+# CONFIG_SCSI_IPS is not set
+# CONFIG_SCSI_INITIO is not set
+# CONFIG_SCSI_INIA100 is not set
+# CONFIG_SCSI_MVSAS is not set
+# CONFIG_SCSI_STEX is not set
+CONFIG_SCSI_SYM53C8XX_2=y
+CONFIG_SCSI_SYM53C8XX_DMA_ADDRESSING_MODE=1
+CONFIG_SCSI_SYM53C8XX_DEFAULT_TAGS=16
+CONFIG_SCSI_SYM53C8XX_MAX_TAGS=64
+CONFIG_SCSI_SYM53C8XX_MMIO=y
+CONFIG_SCSI_QLOGIC_1280=y
+# CONFIG_SCSI_QLA_FC is not set
+# CONFIG_SCSI_QLA_ISCSI is not set
+# CONFIG_SCSI_LPFC is not set
+# CONFIG_SCSI_DC395x is not set
+# CONFIG_SCSI_DC390T is not set
+# CONFIG_SCSI_DEBUG is not set
+# CONFIG_SCSI_SRP is not set
+# CONFIG_SCSI_DH is not set
+# CONFIG_ATA is not set
+CONFIG_MD=y
+CONFIG_BLK_DEV_MD=m
+CONFIG_MD_LINEAR=m
+CONFIG_MD_RAID0=m
+CONFIG_MD_RAID1=m
+# CONFIG_MD_RAID10 is not set
+# CONFIG_MD_RAID456 is not set
+CONFIG_MD_MULTIPATH=m
+# CONFIG_MD_FAULTY is not set
+CONFIG_BLK_DEV_DM=m
+# CONFIG_DM_DEBUG is not set
+CONFIG_DM_CRYPT=m
+CONFIG_DM_SNAPSHOT=m
+CONFIG_DM_MIRROR=m
+CONFIG_DM_ZERO=m
+# CONFIG_DM_MULTIPATH is not set
+# CONFIG_DM_DELAY is not set
+# CONFIG_DM_UEVENT is not set
+CONFIG_FUSION=y
+CONFIG_FUSION_SPI=y
+CONFIG_FUSION_FC=y
+# CONFIG_FUSION_SAS is not set
+CONFIG_FUSION_MAX_SGE=128
+CONFIG_FUSION_CTL=y
+# CONFIG_FUSION_LOGGING is not set
+
+#
+# IEEE 1394 (FireWire) support
+#
+
+#
+# Enable only one of the two stacks, unless you know what you are doing
+#
+# CONFIG_FIREWIRE is not set
+# CONFIG_IEEE1394 is not set
+# CONFIG_I2O is not set
+CONFIG_NETDEVICES=y
+CONFIG_DUMMY=m
+# CONFIG_BONDING is not set
+# CONFIG_MACVLAN is not set
+# CONFIG_EQUALIZER is not set
+# CONFIG_TUN is not set
+# CONFIG_VETH is not set
+# CONFIG_NET_SB1000 is not set
+# CONFIG_ARCNET is not set
+CONFIG_PHYLIB=y
+
+#
+# MII PHY device drivers
+#
+# CONFIG_MARVELL_PHY is not set
+# CONFIG_DAVICOM_PHY is not set
+# CONFIG_QSEMI_PHY is not set
+# CONFIG_LXT_PHY is not set
+# CONFIG_CICADA_PHY is not set
+# CONFIG_VITESSE_PHY is not set
+# CONFIG_SMSC_PHY is not set
+# CONFIG_BROADCOM_PHY is not set
+# CONFIG_ICPLUS_PHY is not set
+# CONFIG_REALTEK_PHY is not set
+# CONFIG_NATIONAL_PHY is not set
+# CONFIG_STE10XP is not set
+# CONFIG_LSI_ET1011C_PHY is not set
+# CONFIG_FIXED_PHY is not set
+# CONFIG_MDIO_BITBANG is not set
+CONFIG_NET_ETHERNET=y
+CONFIG_MII=m
+# CONFIG_HAPPYMEAL is not set
+# CONFIG_SUNGEM is not set
+# CONFIG_CASSINI is not set
+# CONFIG_NET_VENDOR_3COM is not set
+CONFIG_NET_TULIP=y
+# CONFIG_DE2104X is not set
+CONFIG_TULIP=m
+# CONFIG_TULIP_MWI is not set
+# CONFIG_TULIP_MMIO is not set
+# CONFIG_TULIP_NAPI is not set
+# CONFIG_DE4X5 is not set
+# CONFIG_WINBOND_840 is not set
+# CONFIG_DM9102 is not set
+# CONFIG_ULI526X is not set
+# CONFIG_HP100 is not set
+# CONFIG_IBM_NEW_EMAC_ZMII is not set
+# CONFIG_IBM_NEW_EMAC_RGMII is not set
+# CONFIG_IBM_NEW_EMAC_TAH is not set
+# CONFIG_IBM_NEW_EMAC_EMAC4 is not set
+# CONFIG_IBM_NEW_EMAC_NO_FLOW_CTRL is not set
+# CONFIG_IBM_NEW_EMAC_MAL_CLR_ICINTSTAT is not set
+# CONFIG_IBM_NEW_EMAC_MAL_COMMON_ERR is not set
+CONFIG_NET_PCI=y
+# CONFIG_PCNET32 is not set
+# CONFIG_AMD8111_ETH is not set
+# CONFIG_ADAPTEC_STARFIRE is not set
+# CONFIG_B44 is not set
+# CONFIG_FORCEDETH is not set
+CONFIG_E100=m
+# CONFIG_FEALNX is not set
+# CONFIG_NATSEMI is not set
+# CONFIG_NE2K_PCI is not set
+# CONFIG_8139CP is not set
+# CONFIG_8139TOO is not set
+# CONFIG_R6040 is not set
+# CONFIG_SIS900 is not set
+# CONFIG_EPIC100 is not set
+# CONFIG_SMSC9420 is not set
+# CONFIG_SUNDANCE is not set
+# CONFIG_TLAN is not set
+# CONFIG_VIA_RHINE is not set
+# CONFIG_SC92031 is not set
+# CONFIG_ATL2 is not set
+CONFIG_NETDEV_1000=y
+# CONFIG_ACENIC is not set
+# CONFIG_DL2K is not set
+CONFIG_E1000=y
+# CONFIG_E1000E is not set
+# CONFIG_IP1000 is not set
+# CONFIG_IGB is not set
+# CONFIG_NS83820 is not set
+# CONFIG_HAMACHI is not set
+# CONFIG_YELLOWFIN is not set
+# CONFIG_R8169 is not set
+# CONFIG_SIS190 is not set
+# CONFIG_SKGE is not set
+# CONFIG_SKY2 is not set
+# CONFIG_VIA_VELOCITY is not set
+CONFIG_TIGON3=y
+# CONFIG_BNX2 is not set
+# CONFIG_QLA3XXX is not set
+# CONFIG_ATL1 is not set
+# CONFIG_ATL1E is not set
+# CONFIG_JME is not set
+CONFIG_NETDEV_10000=y
+# CONFIG_CHELSIO_T1 is not set
+CONFIG_CHELSIO_T3_DEPENDS=y
+# CONFIG_CHELSIO_T3 is not set
+# CONFIG_ENIC is not set
+# CONFIG_IXGBE is not set
+# CONFIG_IXGB is not set
+# CONFIG_S2IO is not set
+# CONFIG_MYRI10GE is not set
+# CONFIG_NETXEN_NIC is not set
+# CONFIG_NIU is not set
+# CONFIG_MLX4_EN is not set
+# CONFIG_MLX4_CORE is not set
+# CONFIG_TEHUTI is not set
+# CONFIG_BNX2X is not set
+# CONFIG_QLGE is not set
+# CONFIG_SFC is not set
+# CONFIG_TR is not set
+
+#
+# Wireless LAN
+#
+# CONFIG_WLAN_PRE80211 is not set
+# CONFIG_WLAN_80211 is not set
+# CONFIG_IWLWIFI_LEDS is not set
+
+#
+# Enable WiMAX (Networking options) to see the WiMAX drivers
+#
+
+#
+# USB Network Adapters
+#
+# CONFIG_USB_CATC is not set
+# CONFIG_USB_KAWETH is not set
+# CONFIG_USB_PEGASUS is not set
+# CONFIG_USB_RTL8150 is not set
+# CONFIG_USB_USBNET is not set
+# CONFIG_WAN is not set
+CONFIG_XEN_NETDEV_FRONTEND=y
+# CONFIG_FDDI is not set
+# CONFIG_HIPPI is not set
+# CONFIG_PPP is not set
+# CONFIG_SLIP is not set
+# CONFIG_NET_FC is not set
+CONFIG_NETCONSOLE=y
+# CONFIG_NETCONSOLE_DYNAMIC is not set
+CONFIG_NETPOLL=y
+# CONFIG_NETPOLL_TRAP is not set
+CONFIG_NET_POLL_CONTROLLER=y
+# CONFIG_ISDN is not set
+# CONFIG_PHONE is not set
+
+#
+# Input device support
+#
+CONFIG_INPUT=y
+# CONFIG_INPUT_FF_MEMLESS is not set
+# CONFIG_INPUT_POLLDEV is not set
+
+#
+# Userland interfaces
+#
+CONFIG_INPUT_MOUSEDEV=y
+CONFIG_INPUT_MOUSEDEV_PSAUX=y
+CONFIG_INPUT_MOUSEDEV_SCREEN_X=1024
+CONFIG_INPUT_MOUSEDEV_SCREEN_Y=768
+# CONFIG_INPUT_JOYDEV is not set
+# CONFIG_INPUT_EVDEV is not set
+# CONFIG_INPUT_EVBUG is not set
+
+#
+# Input Device Drivers
+#
+CONFIG_INPUT_KEYBOARD=y
+CONFIG_KEYBOARD_ATKBD=y
+# CONFIG_KEYBOARD_SUNKBD is not set
+# CONFIG_KEYBOARD_LKKBD is not set
+# CONFIG_KEYBOARD_XTKBD is not set
+# CONFIG_KEYBOARD_NEWTON is not set
+# CONFIG_KEYBOARD_STOWAWAY is not set
+CONFIG_INPUT_MOUSE=y
+CONFIG_MOUSE_PS2=y
+CONFIG_MOUSE_PS2_ALPS=y
+CONFIG_MOUSE_PS2_LOGIPS2PP=y
+CONFIG_MOUSE_PS2_SYNAPTICS=y
+CONFIG_MOUSE_PS2_LIFEBOOK=y
+CONFIG_MOUSE_PS2_TRACKPOINT=y
+# CONFIG_MOUSE_PS2_ELANTECH is not set
+# CONFIG_MOUSE_PS2_TOUCHKIT is not set
+# CONFIG_MOUSE_SERIAL is not set
+# CONFIG_MOUSE_APPLETOUCH is not set
+# CONFIG_MOUSE_BCM5974 is not set
+# CONFIG_MOUSE_VSXXXAA is not set
+# CONFIG_INPUT_JOYSTICK is not set
+# CONFIG_INPUT_TABLET is not set
+# CONFIG_INPUT_TOUCHSCREEN is not set
+# CONFIG_INPUT_MISC is not set
+
+#
+# Hardware I/O ports
+#
+CONFIG_SERIO=y
+CONFIG_SERIO_I8042=y
+# CONFIG_SERIO_SERPORT is not set
+# CONFIG_SERIO_PCIPS2 is not set
+CONFIG_SERIO_LIBPS2=y
+# CONFIG_SERIO_RAW is not set
+CONFIG_GAMEPORT=m
+# CONFIG_GAMEPORT_NS558 is not set
+# CONFIG_GAMEPORT_L4 is not set
+# CONFIG_GAMEPORT_EMU10K1 is not set
+# CONFIG_GAMEPORT_FM801 is not set
+
+#
+# Character devices
+#
+CONFIG_VT=y
+CONFIG_CONSOLE_TRANSLATIONS=y
+CONFIG_VT_CONSOLE=y
+CONFIG_HW_CONSOLE=y
+# CONFIG_VT_HW_CONSOLE_BINDING is not set
+CONFIG_DEVKMEM=y
+CONFIG_SERIAL_NONSTANDARD=y
+# CONFIG_COMPUTONE is not set
+# CONFIG_ROCKETPORT is not set
+# CONFIG_CYCLADES is not set
+# CONFIG_DIGIEPCA is not set
+# CONFIG_MOXA_INTELLIO is not set
+# CONFIG_MOXA_SMARTIO is not set
+# CONFIG_ISI is not set
+# CONFIG_SYNCLINKMP is not set
+# CONFIG_SYNCLINK_GT is not set
+# CONFIG_N_HDLC is not set
+# CONFIG_RISCOM8 is not set
+# CONFIG_SPECIALIX is not set
+# CONFIG_SX is not set
+# CONFIG_RIO is not set
+# CONFIG_STALDRV is not set
+# CONFIG_NOZOMI is not set
+
+#
+# Serial drivers
+#
+CONFIG_SERIAL_8250=y
+CONFIG_SERIAL_8250_CONSOLE=y
+CONFIG_SERIAL_8250_PCI=y
+CONFIG_SERIAL_8250_PNP=y
+CONFIG_SERIAL_8250_NR_UARTS=6
+CONFIG_SERIAL_8250_RUNTIME_UARTS=4
+CONFIG_SERIAL_8250_EXTENDED=y
+CONFIG_SERIAL_8250_SHARE_IRQ=y
+# CONFIG_SERIAL_8250_DETECT_IRQ is not set
+# CONFIG_SERIAL_8250_RSA is not set
+
+#
+# Non-8250 serial port support
+#
+CONFIG_SERIAL_CORE=y
+CONFIG_SERIAL_CORE_CONSOLE=y
+# CONFIG_SERIAL_JSM is not set
+CONFIG_UNIX98_PTYS=y
+# CONFIG_DEVPTS_MULTIPLE_INSTANCES is not set
+CONFIG_LEGACY_PTYS=y
+CONFIG_LEGACY_PTY_COUNT=256
+CONFIG_HVC_DRIVER=y
+CONFIG_HVC_IRQ=y
+CONFIG_HVC_XEN=y
+# CONFIG_IPMI_HANDLER is not set
+# CONFIG_HW_RANDOM is not set
+CONFIG_EFI_RTC=y
+# CONFIG_R3964 is not set
+# CONFIG_APPLICOM is not set
+CONFIG_RAW_DRIVER=m
+CONFIG_MAX_RAW_DEVS=256
+CONFIG_HPET=y
+CONFIG_HPET_MMAP=y
+# CONFIG_HANGCHECK_TIMER is not set
+# CONFIG_TCG_TPM is not set
+CONFIG_DEVPORT=y
+CONFIG_I2C=m
+CONFIG_I2C_BOARDINFO=y
+# CONFIG_I2C_CHARDEV is not set
+CONFIG_I2C_HELPER_AUTO=y
+CONFIG_I2C_ALGOBIT=m
+
+#
+# I2C Hardware Bus support
+#
+
+#
+# PC SMBus host controller drivers
+#
+# CONFIG_I2C_ALI1535 is not set
+# CONFIG_I2C_ALI1563 is not set
+# CONFIG_I2C_ALI15X3 is not set
+# CONFIG_I2C_AMD756 is not set
+# CONFIG_I2C_AMD8111 is not set
+# CONFIG_I2C_I801 is not set
+# CONFIG_I2C_ISCH is not set
+# CONFIG_I2C_PIIX4 is not set
+# CONFIG_I2C_NFORCE2 is not set
+# CONFIG_I2C_SIS5595 is not set
+# CONFIG_I2C_SIS630 is not set
+# CONFIG_I2C_SIS96X is not set
+# CONFIG_I2C_VIA is not set
+# CONFIG_I2C_VIAPRO is not set
+
+#
+# I2C system bus drivers (mostly embedded / system-on-chip)
+#
+# CONFIG_I2C_OCORES is not set
+# CONFIG_I2C_SIMTEC is not set
+
+#
+# External I2C/SMBus adapter drivers
+#
+# CONFIG_I2C_PARPORT_LIGHT is not set
+# CONFIG_I2C_TAOS_EVM is not set
+# CONFIG_I2C_TINY_USB is not set
+
+#
+# Graphics adapter I2C/DDC channel drivers
+#
+# CONFIG_I2C_VOODOO3 is not set
+
+#
+# Other I2C/SMBus bus drivers
+#
+# CONFIG_I2C_PCA_PLATFORM is not set
+# CONFIG_I2C_STUB is not set
+
+#
+# Miscellaneous I2C Chip support
+#
+# CONFIG_DS1682 is not set
+# CONFIG_AT24 is not set
+# CONFIG_SENSORS_EEPROM is not set
+# CONFIG_SENSORS_PCF8574 is not set
+# CONFIG_PCF8575 is not set
+# CONFIG_SENSORS_PCA9539 is not set
+# CONFIG_SENSORS_PCF8591 is not set
+# CONFIG_SENSORS_MAX6875 is not set
+# CONFIG_SENSORS_TSL2550 is not set
+# CONFIG_I2C_DEBUG_CORE is not set
+# CONFIG_I2C_DEBUG_ALGO is not set
+# CONFIG_I2C_DEBUG_BUS is not set
+# CONFIG_I2C_DEBUG_CHIP is not set
+# CONFIG_SPI is not set
+# CONFIG_W1 is not set
+CONFIG_POWER_SUPPLY=y
+# CONFIG_POWER_SUPPLY_DEBUG is not set
+# CONFIG_PDA_POWER is not set
+# CONFIG_BATTERY_DS2760 is not set
+# CONFIG_BATTERY_BQ27x00 is not set
+CONFIG_HWMON=y
+# CONFIG_HWMON_VID is not set
+# CONFIG_SENSORS_AD7414 is not set
+# CONFIG_SENSORS_AD7418 is not set
+# CONFIG_SENSORS_ADM1021 is not set
+# CONFIG_SENSORS_ADM1025 is not set
+# CONFIG_SENSORS_ADM1026 is not set
+# CONFIG_SENSORS_ADM1029 is not set
+# CONFIG_SENSORS_ADM1031 is not set
+# CONFIG_SENSORS_ADM9240 is not set
+# CONFIG_SENSORS_ADT7462 is not set
+# CONFIG_SENSORS_ADT7470 is not set
+# CONFIG_SENSORS_ADT7473 is not set
+# CONFIG_SENSORS_ATXP1 is not set
+# CONFIG_SENSORS_DS1621 is not set
+# CONFIG_SENSORS_I5K_AMB is not set
+# CONFIG_SENSORS_F71805F is not set
+# CONFIG_SENSORS_F71882FG is not set
+# CONFIG_SENSORS_F75375S is not set
+# CONFIG_SENSORS_GL518SM is not set
+# CONFIG_SENSORS_GL520SM is not set
+# CONFIG_SENSORS_IT87 is not set
+# CONFIG_SENSORS_LM63 is not set
+# CONFIG_SENSORS_LM75 is not set
+# CONFIG_SENSORS_LM77 is not set
+# CONFIG_SENSORS_LM78 is not set
+# CONFIG_SENSORS_LM80 is not set
+# CONFIG_SENSORS_LM83 is not set
+# CONFIG_SENSORS_LM85 is not set
+# CONFIG_SENSORS_LM87 is not set
+# CONFIG_SENSORS_LM90 is not set
+# CONFIG_SENSORS_LM92 is not set
+# CONFIG_SENSORS_LM93 is not set
+# CONFIG_SENSORS_LTC4245 is not set
+# CONFIG_SENSORS_MAX1619 is not set
+# CONFIG_SENSORS_MAX6650 is not set
+# CONFIG_SENSORS_PC87360 is not set
+# CONFIG_SENSORS_PC87427 is not set
+# CONFIG_SENSORS_SIS5595 is not set
+# CONFIG_SENSORS_DME1737 is not set
+# CONFIG_SENSORS_SMSC47M1 is not set
+# CONFIG_SENSORS_SMSC47M192 is not set
+# CONFIG_SENSORS_SMSC47B397 is not set
+# CONFIG_SENSORS_ADS7828 is not set
+# CONFIG_SENSORS_THMC50 is not set
+# CONFIG_SENSORS_VIA686A is not set
+# CONFIG_SENSORS_VT1211 is not set
+# CONFIG_SENSORS_VT8231 is not set
+# CONFIG_SENSORS_W83781D is not set
+# CONFIG_SENSORS_W83791D is not set
+# CONFIG_SENSORS_W83792D is not set
+# CONFIG_SENSORS_W83793 is not set
+# CONFIG_SENSORS_W83L785TS is not set
+# CONFIG_SENSORS_W83L786NG is not set
+# CONFIG_SENSORS_W83627HF is not set
+# CONFIG_SENSORS_W83627EHF is not set
+# CONFIG_SENSORS_LIS3LV02D is not set
+# CONFIG_HWMON_DEBUG_CHIP is not set
+CONFIG_THERMAL=m
+# CONFIG_THERMAL_HWMON is not set
+# CONFIG_WATCHDOG is not set
+CONFIG_SSB_POSSIBLE=y
+
+#
+# Sonics Silicon Backplane
+#
+# CONFIG_SSB is not set
+
+#
+# Multifunction device drivers
+#
+# CONFIG_MFD_CORE is not set
+# CONFIG_MFD_SM501 is not set
+# CONFIG_HTC_PASIC3 is not set
+# CONFIG_MFD_TMIO is not set
+# CONFIG_MFD_WM8400 is not set
+# CONFIG_MFD_WM8350_I2C is not set
+# CONFIG_MFD_PCF50633 is not set
+# CONFIG_REGULATOR is not set
+
+#
+# Multimedia devices
+#
+
+#
+# Multimedia core support
+#
+# CONFIG_VIDEO_DEV is not set
+# CONFIG_DVB_CORE is not set
+# CONFIG_VIDEO_MEDIA is not set
+
+#
+# Multimedia drivers
+#
+CONFIG_DAB=y
+# CONFIG_USB_DABUSB is not set
+
+#
+# Graphics support
+#
+CONFIG_AGP=m
+CONFIG_DRM=m
+CONFIG_DRM_TDFX=m
+CONFIG_DRM_R128=m
+CONFIG_DRM_RADEON=m
+CONFIG_DRM_MGA=m
+CONFIG_DRM_SIS=m
+# CONFIG_DRM_VIA is not set
+# CONFIG_DRM_SAVAGE is not set
+# CONFIG_VGASTATE is not set
+# CONFIG_VIDEO_OUTPUT_CONTROL is not set
+# CONFIG_FB is not set
+# CONFIG_BACKLIGHT_LCD_SUPPORT is not set
+
+#
+# Display device support
+#
+# CONFIG_DISPLAY_SUPPORT is not set
+
+#
+# Console display driver support
+#
+CONFIG_VGA_CONSOLE=y
+# CONFIG_VGACON_SOFT_SCROLLBACK is not set
+CONFIG_DUMMY_CONSOLE=y
+# CONFIG_SOUND is not set
+CONFIG_HID_SUPPORT=y
+CONFIG_HID=y
+# CONFIG_HID_DEBUG is not set
+# CONFIG_HIDRAW is not set
+
+#
+# USB Input Devices
+#
+CONFIG_USB_HID=y
+# CONFIG_HID_PID is not set
+# CONFIG_USB_HIDDEV is not set
+
+#
+# Special HID drivers
+#
+CONFIG_HID_COMPAT=y
+CONFIG_HID_A4TECH=y
+CONFIG_HID_APPLE=y
+CONFIG_HID_BELKIN=y
+CONFIG_HID_CHERRY=y
+CONFIG_HID_CHICONY=y
+CONFIG_HID_CYPRESS=y
+CONFIG_HID_EZKEY=y
+CONFIG_HID_GYRATION=y
+CONFIG_HID_LOGITECH=y
+# CONFIG_LOGITECH_FF is not set
+# CONFIG_LOGIRUMBLEPAD2_FF is not set
+CONFIG_HID_MICROSOFT=y
+CONFIG_HID_MONTEREY=y
+CONFIG_HID_NTRIG=y
+CONFIG_HID_PANTHERLORD=y
+# CONFIG_PANTHERLORD_FF is not set
+CONFIG_HID_PETALYNX=y
+CONFIG_HID_SAMSUNG=y
+CONFIG_HID_SONY=y
+CONFIG_HID_SUNPLUS=y
+# CONFIG_GREENASIA_FF is not set
+CONFIG_HID_TOPSEED=y
+# CONFIG_THRUSTMASTER_FF is not set
+# CONFIG_ZEROPLUS_FF is not set
+CONFIG_USB_SUPPORT=y
+CONFIG_USB_ARCH_HAS_HCD=y
+CONFIG_USB_ARCH_HAS_OHCI=y
+CONFIG_USB_ARCH_HAS_EHCI=y
+CONFIG_USB=y
+# CONFIG_USB_DEBUG is not set
+# CONFIG_USB_ANNOUNCE_NEW_DEVICES is not set
+
+#
+# Miscellaneous USB options
+#
+CONFIG_USB_DEVICEFS=y
+CONFIG_USB_DEVICE_CLASS=y
+# CONFIG_USB_DYNAMIC_MINORS is not set
+# CONFIG_USB_SUSPEND is not set
+# CONFIG_USB_OTG is not set
+# CONFIG_USB_MON is not set
+# CONFIG_USB_WUSB is not set
+# CONFIG_USB_WUSB_CBAF is not set
+
+#
+# USB Host Controller Drivers
+#
+# CONFIG_USB_C67X00_HCD is not set
+CONFIG_USB_EHCI_HCD=m
+# CONFIG_USB_EHCI_ROOT_HUB_TT is not set
+# CONFIG_USB_EHCI_TT_NEWSCHED is not set
+# CONFIG_USB_OXU210HP_HCD is not set
+# CONFIG_USB_ISP116X_HCD is not set
+# CONFIG_USB_ISP1760_HCD is not set
+CONFIG_USB_OHCI_HCD=m
+# CONFIG_USB_OHCI_BIG_ENDIAN_DESC is not set
+# CONFIG_USB_OHCI_BIG_ENDIAN_MMIO is not set
+CONFIG_USB_OHCI_LITTLE_ENDIAN=y
+CONFIG_USB_UHCI_HCD=y
+# CONFIG_USB_SL811_HCD is not set
+# CONFIG_USB_R8A66597_HCD is not set
+# CONFIG_USB_WHCI_HCD is not set
+# CONFIG_USB_HWA_HCD is not set
+
+#
+# USB Device Class drivers
+#
+# CONFIG_USB_ACM is not set
+# CONFIG_USB_PRINTER is not set
+# CONFIG_USB_WDM is not set
+# CONFIG_USB_TMC is not set
+
+#
+# NOTE: USB_STORAGE depends on SCSI but BLK_DEV_SD may also be needed;
+#
+
+#
+# see USB_STORAGE Help for more information
+#
+CONFIG_USB_STORAGE=m
+# CONFIG_USB_STORAGE_DEBUG is not set
+# CONFIG_USB_STORAGE_DATAFAB is not set
+# CONFIG_USB_STORAGE_FREECOM is not set
+# CONFIG_USB_STORAGE_ISD200 is not set
+# CONFIG_USB_STORAGE_USBAT is not set
+# CONFIG_USB_STORAGE_SDDR09 is not set
+# CONFIG_USB_STORAGE_SDDR55 is not set
+# CONFIG_USB_STORAGE_JUMPSHOT is not set
+# CONFIG_USB_STORAGE_ALAUDA is not set
+# CONFIG_USB_STORAGE_ONETOUCH is not set
+# CONFIG_USB_STORAGE_KARMA is not set
+# CONFIG_USB_STORAGE_CYPRESS_ATACB is not set
+# CONFIG_USB_LIBUSUAL is not set
+
+#
+# USB Imaging devices
+#
+# CONFIG_USB_MDC800 is not set
+# CONFIG_USB_MICROTEK is not set
+
+#
+# USB port drivers
+#
+# CONFIG_USB_SERIAL is not set
+
+#
+# USB Miscellaneous drivers
+#
+# CONFIG_USB_EMI62 is not set
+# CONFIG_USB_EMI26 is not set
+# CONFIG_USB_ADUTUX is not set
+# CONFIG_USB_SEVSEG is not set
+# CONFIG_USB_RIO500 is not set
+# CONFIG_USB_LEGOTOWER is not set
+# CONFIG_USB_LCD is not set
+# CONFIG_USB_BERRY_CHARGE is not set
+# CONFIG_USB_LED is not set
+# CONFIG_USB_CYPRESS_CY7C63 is not set
+# CONFIG_USB_CYTHERM is not set
+# CONFIG_USB_PHIDGET is not set
+# CONFIG_USB_IDMOUSE is not set
+# CONFIG_USB_FTDI_ELAN is not set
+# CONFIG_USB_APPLEDISPLAY is not set
+# CONFIG_USB_SISUSBVGA is not set
+# CONFIG_USB_LD is not set
+# CONFIG_USB_TRANCEVIBRATOR is not set
+# CONFIG_USB_IOWARRIOR is not set
+# CONFIG_USB_TEST is not set
+# CONFIG_USB_ISIGHTFW is not set
+# CONFIG_USB_VST is not set
+# CONFIG_USB_GADGET is not set
+
+#
+# OTG and related infrastructure
+#
+# CONFIG_UWB is not set
+# CONFIG_MMC is not set
+# CONFIG_MEMSTICK is not set
+# CONFIG_NEW_LEDS is not set
+# CONFIG_ACCESSIBILITY is not set
+# CONFIG_INFINIBAND is not set
+# CONFIG_RTC_CLASS is not set
+# CONFIG_DMADEVICES is not set
+# CONFIG_UIO is not set
+CONFIG_XEN_BALLOON=y
+CONFIG_XEN_SCRUB_PAGES=y
+CONFIG_XENFS=y
+CONFIG_XEN_COMPAT_XENFS=y
+# CONFIG_STAGING is not set
+# CONFIG_MSPEC is not set
+
+#
+# File systems
+#
+CONFIG_EXT2_FS=y
+CONFIG_EXT2_FS_XATTR=y
+CONFIG_EXT2_FS_POSIX_ACL=y
+CONFIG_EXT2_FS_SECURITY=y
+# CONFIG_EXT2_FS_XIP is not set
+CONFIG_EXT3_FS=y
+CONFIG_EXT3_FS_XATTR=y
+CONFIG_EXT3_FS_POSIX_ACL=y
+CONFIG_EXT3_FS_SECURITY=y
+# CONFIG_EXT4_FS is not set
+CONFIG_JBD=y
+CONFIG_FS_MBCACHE=y
+CONFIG_REISERFS_FS=y
+# CONFIG_REISERFS_CHECK is not set
+# CONFIG_REISERFS_PROC_INFO is not set
+CONFIG_REISERFS_FS_XATTR=y
+CONFIG_REISERFS_FS_POSIX_ACL=y
+CONFIG_REISERFS_FS_SECURITY=y
+# CONFIG_JFS_FS is not set
+CONFIG_FS_POSIX_ACL=y
+CONFIG_FILE_LOCKING=y
+CONFIG_XFS_FS=y
+# CONFIG_XFS_QUOTA is not set
+# CONFIG_XFS_POSIX_ACL is not set
+# CONFIG_XFS_RT is not set
+# CONFIG_XFS_DEBUG is not set
+# CONFIG_GFS2_FS is not set
+# CONFIG_OCFS2_FS is not set
+# CONFIG_BTRFS_FS is not set
+CONFIG_DNOTIFY=y
+CONFIG_INOTIFY=y
+CONFIG_INOTIFY_USER=y
+# CONFIG_QUOTA is not set
+CONFIG_AUTOFS_FS=y
+CONFIG_AUTOFS4_FS=y
+# CONFIG_FUSE_FS is not set
+
+#
+# CD-ROM/DVD Filesystems
+#
+CONFIG_ISO9660_FS=m
+CONFIG_JOLIET=y
+# CONFIG_ZISOFS is not set
+CONFIG_UDF_FS=m
+CONFIG_UDF_NLS=y
+
+#
+# DOS/FAT/NT Filesystems
+#
+CONFIG_FAT_FS=y
+# CONFIG_MSDOS_FS is not set
+CONFIG_VFAT_FS=y
+CONFIG_FAT_DEFAULT_CODEPAGE=437
+CONFIG_FAT_DEFAULT_IOCHARSET="iso8859-1"
+CONFIG_NTFS_FS=m
+# CONFIG_NTFS_DEBUG is not set
+# CONFIG_NTFS_RW is not set
+
+#
+# Pseudo filesystems
+#
+CONFIG_PROC_FS=y
+CONFIG_PROC_KCORE=y
+CONFIG_PROC_SYSCTL=y
+CONFIG_PROC_PAGE_MONITOR=y
+CONFIG_SYSFS=y
+CONFIG_TMPFS=y
+# CONFIG_TMPFS_POSIX_ACL is not set
+CONFIG_HUGETLBFS=y
+CONFIG_HUGETLB_PAGE=y
+# CONFIG_CONFIGFS_FS is not set
+CONFIG_MISC_FILESYSTEMS=y
+# CONFIG_ADFS_FS is not set
+# CONFIG_AFFS_FS is not set
+# CONFIG_HFS_FS is not set
+# CONFIG_HFSPLUS_FS is not set
+# CONFIG_BEFS_FS is not set
+# CONFIG_BFS_FS is not set
+# CONFIG_EFS_FS is not set
+# CONFIG_CRAMFS is not set
+# CONFIG_SQUASHFS is not set
+# CONFIG_VXFS_FS is not set
+# CONFIG_MINIX_FS is not set
+# CONFIG_OMFS_FS is not set
+# CONFIG_HPFS_FS is not set
+# CONFIG_QNX4FS_FS is not set
+# CONFIG_ROMFS_FS is not set
+# CONFIG_SYSV_FS is not set
+# CONFIG_UFS_FS is not set
+CONFIG_NETWORK_FILESYSTEMS=y
+CONFIG_NFS_FS=m
+CONFIG_NFS_V3=y
+# CONFIG_NFS_V3_ACL is not set
+CONFIG_NFS_V4=y
+CONFIG_NFSD=m
+CONFIG_NFSD_V3=y
+# CONFIG_NFSD_V3_ACL is not set
+CONFIG_NFSD_V4=y
+CONFIG_LOCKD=m
+CONFIG_LOCKD_V4=y
+CONFIG_EXPORTFS=m
+CONFIG_NFS_COMMON=y
+CONFIG_SUNRPC=m
+CONFIG_SUNRPC_GSS=m
+# CONFIG_SUNRPC_REGISTER_V4 is not set
+CONFIG_RPCSEC_GSS_KRB5=m
+# CONFIG_RPCSEC_GSS_SPKM3 is not set
+CONFIG_SMB_FS=m
+CONFIG_SMB_NLS_DEFAULT=y
+CONFIG_SMB_NLS_REMOTE="cp437"
+CONFIG_CIFS=m
+# CONFIG_CIFS_STATS is not set
+# CONFIG_CIFS_WEAK_PW_HASH is not set
+# CONFIG_CIFS_XATTR is not set
+# CONFIG_CIFS_DEBUG2 is not set
+# CONFIG_CIFS_EXPERIMENTAL is not set
+# CONFIG_NCP_FS is not set
+# CONFIG_CODA_FS is not set
+# CONFIG_AFS_FS is not set
+
+#
+# Partition Types
+#
+CONFIG_PARTITION_ADVANCED=y
+# CONFIG_ACORN_PARTITION is not set
+# CONFIG_OSF_PARTITION is not set
+# CONFIG_AMIGA_PARTITION is not set
+# CONFIG_ATARI_PARTITION is not set
+# CONFIG_MAC_PARTITION is not set
+CONFIG_MSDOS_PARTITION=y
+# CONFIG_BSD_DISKLABEL is not set
+# CONFIG_MINIX_SUBPARTITION is not set
+# CONFIG_SOLARIS_X86_PARTITION is not set
+# CONFIG_UNIXWARE_DISKLABEL is not set
+# CONFIG_LDM_PARTITION is not set
+CONFIG_SGI_PARTITION=y
+# CONFIG_ULTRIX_PARTITION is not set
+# CONFIG_SUN_PARTITION is not set
+# CONFIG_KARMA_PARTITION is not set
+CONFIG_EFI_PARTITION=y
+# CONFIG_SYSV68_PARTITION is not set
+CONFIG_NLS=y
+CONFIG_NLS_DEFAULT="iso8859-1"
+CONFIG_NLS_CODEPAGE_437=y
+CONFIG_NLS_CODEPAGE_737=m
+CONFIG_NLS_CODEPAGE_775=m
+CONFIG_NLS_CODEPAGE_850=m
+CONFIG_NLS_CODEPAGE_852=m
+CONFIG_NLS_CODEPAGE_855=m
+CONFIG_NLS_CODEPAGE_857=m
+CONFIG_NLS_CODEPAGE_860=m
+CONFIG_NLS_CODEPAGE_861=m
+CONFIG_NLS_CODEPAGE_862=m
+CONFIG_NLS_CODEPAGE_863=m
+CONFIG_NLS_CODEPAGE_864=m
+CONFIG_NLS_CODEPAGE_865=m
+CONFIG_NLS_CODEPAGE_866=m
+CONFIG_NLS_CODEPAGE_869=m
+CONFIG_NLS_CODEPAGE_936=m
+CONFIG_NLS_CODEPAGE_950=m
+CONFIG_NLS_CODEPAGE_932=m
+CONFIG_NLS_CODEPAGE_949=m
+CONFIG_NLS_CODEPAGE_874=m
+CONFIG_NLS_ISO8859_8=m
+CONFIG_NLS_CODEPAGE_1250=m
+CONFIG_NLS_CODEPAGE_1251=m
+# CONFIG_NLS_ASCII is not set
+CONFIG_NLS_ISO8859_1=y
+CONFIG_NLS_ISO8859_2=m
+CONFIG_NLS_ISO8859_3=m
+CONFIG_NLS_ISO8859_4=m
+CONFIG_NLS_ISO8859_5=m
+CONFIG_NLS_ISO8859_6=m
+CONFIG_NLS_ISO8859_7=m
+CONFIG_NLS_ISO8859_9=m
+CONFIG_NLS_ISO8859_13=m
+CONFIG_NLS_ISO8859_14=m
+CONFIG_NLS_ISO8859_15=m
+CONFIG_NLS_KOI8_R=m
+CONFIG_NLS_KOI8_U=m
+CONFIG_NLS_UTF8=m
+# CONFIG_DLM is not set
+
+#
+# Kernel hacking
+#
+# CONFIG_PRINTK_TIME is not set
+CONFIG_ENABLE_WARN_DEPRECATED=y
+CONFIG_ENABLE_MUST_CHECK=y
+CONFIG_FRAME_WARN=2048
+CONFIG_MAGIC_SYSRQ=y
+# CONFIG_UNUSED_SYMBOLS is not set
+# CONFIG_DEBUG_FS is not set
+# CONFIG_HEADERS_CHECK is not set
+CONFIG_DEBUG_KERNEL=y
+# CONFIG_DEBUG_SHIRQ is not set
+CONFIG_DETECT_SOFTLOCKUP=y
+# CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC is not set
+CONFIG_BOOTPARAM_SOFTLOCKUP_PANIC_VALUE=0
+CONFIG_SCHED_DEBUG=y
+# CONFIG_SCHEDSTATS is not set
+# CONFIG_TIMER_STATS is not set
+# CONFIG_DEBUG_OBJECTS is not set
+# CONFIG_SLUB_DEBUG_ON is not set
+# CONFIG_SLUB_STATS is not set
+# CONFIG_DEBUG_RT_MUTEXES is not set
+# CONFIG_RT_MUTEX_TESTER is not set
+# CONFIG_DEBUG_SPINLOCK is not set
+CONFIG_DEBUG_MUTEXES=y
+# CONFIG_DEBUG_SPINLOCK_SLEEP is not set
+# CONFIG_DEBUG_LOCKING_API_SELFTESTS is not set
+# CONFIG_DEBUG_KOBJECT is not set
+# CONFIG_DEBUG_INFO is not set
+# CONFIG_DEBUG_VM is not set
+# CONFIG_DEBUG_WRITECOUNT is not set
+CONFIG_DEBUG_MEMORY_INIT=y
+# CONFIG_DEBUG_LIST is not set
+# CONFIG_DEBUG_SG is not set
+# CONFIG_DEBUG_NOTIFIERS is not set
+# CONFIG_BOOT_PRINTK_DELAY is not set
+# CONFIG_RCU_TORTURE_TEST is not set
+# CONFIG_RCU_CPU_STALL_DETECTOR is not set
+# CONFIG_BACKTRACE_SELF_TEST is not set
+# CONFIG_DEBUG_BLOCK_EXT_DEVT is not set
+# CONFIG_FAULT_INJECTION is not set
+# CONFIG_SYSCTL_SYSCALL_CHECK is not set
+
+#
+# Tracers
+#
+# CONFIG_SCHED_TRACER is not set
+# CONFIG_CONTEXT_SWITCH_TRACER is not set
+# CONFIG_BOOT_TRACER is not set
+# CONFIG_TRACE_BRANCH_PROFILING is not set
+# CONFIG_DYNAMIC_PRINTK_DEBUG is not set
+# CONFIG_SAMPLES is not set
+CONFIG_IA64_GRANULE_16MB=y
+# CONFIG_IA64_GRANULE_64MB is not set
+# CONFIG_IA64_PRINT_HAZARDS is not set
+# CONFIG_DISABLE_VHPT is not set
+# CONFIG_IA64_DEBUG_CMPXCHG is not set
+# CONFIG_IA64_DEBUG_IRQ is not set
+
+#
+# Security options
+#
+# CONFIG_KEYS is not set
+# CONFIG_SECURITY is not set
+# CONFIG_SECURITYFS is not set
+# CONFIG_SECURITY_FILE_CAPABILITIES is not set
+CONFIG_CRYPTO=y
+
+#
+# Crypto core or helper
+#
+# CONFIG_CRYPTO_FIPS is not set
+CONFIG_CRYPTO_ALGAPI=y
+CONFIG_CRYPTO_ALGAPI2=y
+CONFIG_CRYPTO_AEAD2=y
+CONFIG_CRYPTO_BLKCIPHER=m
+CONFIG_CRYPTO_BLKCIPHER2=y
+CONFIG_CRYPTO_HASH=y
+CONFIG_CRYPTO_HASH2=y
+CONFIG_CRYPTO_RNG2=y
+CONFIG_CRYPTO_MANAGER=m
+CONFIG_CRYPTO_MANAGER2=y
+# CONFIG_CRYPTO_GF128MUL is not set
+# CONFIG_CRYPTO_NULL is not set
+# CONFIG_CRYPTO_CRYPTD is not set
+# CONFIG_CRYPTO_AUTHENC is not set
+# CONFIG_CRYPTO_TEST is not set
+
+#
+# Authenticated Encryption with Associated Data
+#
+# CONFIG_CRYPTO_CCM is not set
+# CONFIG_CRYPTO_GCM is not set
+# CONFIG_CRYPTO_SEQIV is not set
+
+#
+# Block modes
+#
+CONFIG_CRYPTO_CBC=m
+# CONFIG_CRYPTO_CTR is not set
+# CONFIG_CRYPTO_CTS is not set
+CONFIG_CRYPTO_ECB=m
+# CONFIG_CRYPTO_LRW is not set
+CONFIG_CRYPTO_PCBC=m
+# CONFIG_CRYPTO_XTS is not set
+
+#
+# Hash modes
+#
+# CONFIG_CRYPTO_HMAC is not set
+# CONFIG_CRYPTO_XCBC is not set
+
+#
+# Digest
+#
+# CONFIG_CRYPTO_CRC32C is not set
+# CONFIG_CRYPTO_MD4 is not set
+CONFIG_CRYPTO_MD5=y
+# CONFIG_CRYPTO_MICHAEL_MIC is not set
+# CONFIG_CRYPTO_RMD128 is not set
+# CONFIG_CRYPTO_RMD160 is not set
+# CONFIG_CRYPTO_RMD256 is not set
+# CONFIG_CRYPTO_RMD320 is not set
+# CONFIG_CRYPTO_SHA1 is not set
+# CONFIG_CRYPTO_SHA256 is not set
+# CONFIG_CRYPTO_SHA512 is not set
+# CONFIG_CRYPTO_TGR192 is not set
+# CONFIG_CRYPTO_WP512 is not set
+
+#
+# Ciphers
+#
+# CONFIG_CRYPTO_AES is not set
+# CONFIG_CRYPTO_ANUBIS is not set
+# CONFIG_CRYPTO_ARC4 is not set
+# CONFIG_CRYPTO_BLOWFISH is not set
+# CONFIG_CRYPTO_CAMELLIA is not set
+# CONFIG_CRYPTO_CAST5 is not set
+# CONFIG_CRYPTO_CAST6 is not set
+CONFIG_CRYPTO_DES=m
+# CONFIG_CRYPTO_FCRYPT is not set
+# CONFIG_CRYPTO_KHAZAD is not set
+# CONFIG_CRYPTO_SALSA20 is not set
+# CONFIG_CRYPTO_SEED is not set
+# CONFIG_CRYPTO_SERPENT is not set
+# CONFIG_CRYPTO_TEA is not set
+# CONFIG_CRYPTO_TWOFISH is not set
+
+#
+# Compression
+#
+# CONFIG_CRYPTO_DEFLATE is not set
+# CONFIG_CRYPTO_LZO is not set
+
+#
+# Random Number Generation
+#
+# CONFIG_CRYPTO_ANSI_CPRNG is not set
+CONFIG_CRYPTO_HW=y
+# CONFIG_CRYPTO_DEV_HIFN_795X is not set
+CONFIG_HAVE_KVM=y
+CONFIG_VIRTUALIZATION=y
+# CONFIG_KVM is not set
+# CONFIG_VIRTIO_PCI is not set
+# CONFIG_VIRTIO_BALLOON is not set
+
+#
+# Library routines
+#
+CONFIG_BITREVERSE=y
+CONFIG_GENERIC_FIND_LAST_BIT=y
+# CONFIG_CRC_CCITT is not set
+# CONFIG_CRC16 is not set
+# CONFIG_CRC_T10DIF is not set
+CONFIG_CRC_ITU_T=m
+CONFIG_CRC32=y
+# CONFIG_CRC7 is not set
+# CONFIG_LIBCRC32C is not set
+CONFIG_PLIST=y
+CONFIG_HAS_IOMEM=y
+CONFIG_HAS_IOPORT=y
+CONFIG_HAS_DMA=y
+CONFIG_GENERIC_HARDIRQS=y
+CONFIG_GENERIC_IRQ_PROBE=y
+CONFIG_GENERIC_PENDING_IRQ=y
+CONFIG_IRQ_PER_CPU=y
+# CONFIG_IOMMU_API is not set
index 68aa6da807c191fa74344c85b562b97f6d14694b..bfa86b6af7cd0774d652c99d800e822284f74c23 100644 (file)
 
 #include <linux/ioctl.h>
 
+/* Select x86 specific features in <linux/kvm.h> */
+#define __KVM_HAVE_IOAPIC
+#define __KVM_HAVE_DEVICE_ASSIGNMENT
+
 /* Architectural interrupt line count. */
 #define KVM_NR_INTERRUPTS 256
 
index 34efe88eb84948f042474988089fa6d1ef1f82f8..f2ca32069b3ff5e2b4f97925cabf6540f0d3dea7 100644 (file)
@@ -31,10 +31,6 @@ static inline int pfn_to_nid(unsigned long pfn)
 #endif
 }
 
-#ifdef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID
-extern int early_pfn_to_nid(unsigned long pfn);
-#endif
-
 #ifdef CONFIG_IA64_DIG /* DIG systems are small */
 # define MAX_PHYSNODE_ID       8
 # define NR_NODE_MEMBLKS       (MAX_NUMNODES * 8)
index 5efecf06c9a42efef99870084a3748e9bd3dfc15..96798d2da7c272fe4e9417f5329702d8f4559042 100644 (file)
@@ -39,7 +39,7 @@
 /* BTE status register only supports 16 bits for length field */
 #define BTE_LEN_BITS (16)
 #define BTE_LEN_MASK ((1 << BTE_LEN_BITS) - 1)
-#define BTE_MAX_XFER ((1 << BTE_LEN_BITS) * L1_CACHE_BYTES)
+#define BTE_MAX_XFER (BTE_LEN_MASK << L1_CACHE_SHIFT)
 
 
 /* Define hardware */
index 5cfd3d91001aed8043764c88778d2df3e91681cf..e13125058bedb03eb56d2ab291d7c3e3628c9c25 100644 (file)
@@ -507,7 +507,7 @@ static int iosapic_find_sharable_irq(unsigned long trigger, unsigned long pol)
        if (trigger == IOSAPIC_EDGE)
                return -EINVAL;
 
-       for (i = 0; i <= NR_IRQS; i++) {
+       for (i = 0; i < NR_IRQS; i++) {
                info = &iosapic_intr_info[i];
                if (info->trigger == trigger && info->polarity == pol &&
                    (info->dmode == IOSAPIC_FIXED ||
index 11463994a7d540b63de364b80d3077a5f51f6445..52290547c85ba89edd5ba3fa1a98985891803361 100644 (file)
@@ -736,14 +736,15 @@ int __cpu_disable(void)
                        return -EBUSY;
        }
 
+       cpu_clear(cpu, cpu_online_map);
+
        if (migrate_platform_irqs(cpu)) {
                cpu_set(cpu, cpu_online_map);
-               return (-EBUSY);
+               return -EBUSY;
        }
 
        remove_siblinginfo(cpu);
        fixup_irqs();
-       cpu_clear(cpu, cpu_online_map);
        local_flush_tlb_all();
        cpu_clear(cpu, cpu_callin_map);
        return 0;
index 67810b77d998768199b3978d288130968e837865..b6c0e63a0bf61535386fff325adaf5f3e40e2932 100644 (file)
@@ -2149,7 +2149,7 @@ unw_remove_unwind_table (void *handle)
 
        /* next, remove hash table entries for this table */
 
-       for (index = 0; index <= UNW_HASH_SIZE; ++index) {
+       for (index = 0; index < UNW_HASH_SIZE; ++index) {
                tmp = unw.cache + unw.hash[index];
                if (unw.hash[index] >= UNW_CACHE_SIZE
                    || tmp->ip < table->start || tmp->ip >= table->end)
index 4e586f6110aa08c4d2df47f8aa16a053748f8268..28f982045f29c6c1623c2ac06e032e904efb0720 100644 (file)
@@ -1337,6 +1337,10 @@ static void kvm_release_vm_pages(struct kvm *kvm)
        }
 }
 
+void kvm_arch_sync_events(struct kvm *kvm)
+{
+}
+
 void kvm_arch_destroy_vm(struct kvm *kvm)
 {
        kvm_iommu_unmap_guest(kvm);
index 552d07724207e213b5949e2dd15c00bc31c74dd3..230eae482f3262a443e2ef9acf5111820937b574 100644 (file)
@@ -455,13 +455,18 @@ fpswa_ret_t vmm_fp_emulate(int fp_fault, void *bundle, unsigned long *ipsr,
        if (!vmm_fpswa_interface)
                return (fpswa_ret_t) {-1, 0, 0, 0};
 
-       /*
-        * Just let fpswa driver to use hardware fp registers.
-        * No fp register is valid in memory.
-        */
        memset(&fp_state, 0, sizeof(fp_state_t));
 
        /*
+        * compute fp_state.  only FP registers f6 - f11 are used by the
+        * vmm, so set those bits in the mask and set the low volatile
+        * pointer to point to these registers.
+        */
+       fp_state.bitmask_low64 = 0xfc0;  /* bit6..bit11 */
+
+       fp_state.fp_state_low_volatile = (fp_state_low_volatile_t *) &regs->f6;
+
+   /*
         * unsigned long (*EFI_FPSWA) (
         *      unsigned long    trap_type,
         *      void             *Bundle,
@@ -545,10 +550,6 @@ void reflect_interruption(u64 ifa, u64 isr, u64 iim,
                status = vmm_handle_fpu_swa(0, regs, isr);
                if (!status)
                        return ;
-               else if (-EAGAIN == status) {
-                       vcpu_decrement_iip(vcpu);
-                       return ;
-               }
                break;
        }
 
index b73bf1838e57750fb69f3ae27d6950bcc9dc46c8..3efea7d0a351c5159d5e843406e744fe0948a33d 100644 (file)
@@ -58,7 +58,7 @@ paddr_to_nid(unsigned long paddr)
  * SPARSEMEM to allocate the SPARSEMEM sectionmap on the NUMA node where
  * the section resides.
  */
-int early_pfn_to_nid(unsigned long pfn)
+int __meminit __early_pfn_to_nid(unsigned long pfn)
 {
        int i, section = pfn >> PFN_SECTION_SHIFT, ssec, esec;
 
@@ -70,7 +70,7 @@ int early_pfn_to_nid(unsigned long pfn)
                        return node_memblk[i].nid;
        }
 
-       return 0;
+       return -1;
 }
 
 #ifdef CONFIG_MEMORY_HOTPLUG
index 9456d4034024aa97eed31518162e6ddb68e7a436..c6d6b62db66c99c05c4cc5ee8c84f19c4a768d5b 100644 (file)
@@ -97,9 +97,10 @@ bte_result_t bte_copy(u64 src, u64 dest, u64 len, u64 mode, void *notification)
                return BTE_SUCCESS;
        }
 
-       BUG_ON((len & L1_CACHE_MASK) ||
-                (src & L1_CACHE_MASK) || (dest & L1_CACHE_MASK));
-       BUG_ON(!(len < ((BTE_LEN_MASK + 1) << L1_CACHE_SHIFT)));
+       BUG_ON(len & L1_CACHE_MASK);
+       BUG_ON(src & L1_CACHE_MASK);
+       BUG_ON(dest & L1_CACHE_MASK);
+       BUG_ON(len > BTE_MAX_XFER);
 
        /*
         * Start with interface corresponding to cpu number
index f1683a20275b8caad1e6ae92c982a483a2f524ad..515e0826803a8f6eb349153658a4b59fdd56a21a 100644 (file)
@@ -8,8 +8,7 @@ config XEN
        depends on PARAVIRT && MCKINLEY && IA64_PAGE_SIZE_16KB && EXPERIMENTAL
        select XEN_XENCOMM
        select NO_IDLE_HZ
-
-       # those are required to save/restore.
+       # followings are required to save/restore.
        select ARCH_SUSPEND_POSSIBLE
        select SUSPEND
        select PM_SLEEP
index 04cd12350455f33a2a563be95c0a3e9ad5e3ea02..936cff3c96e0215f413054d038950fc8ecc22973 100644 (file)
@@ -153,7 +153,7 @@ xen_post_smp_prepare_boot_cpu(void)
        xen_setup_vcpu_info_placement();
 }
 
-static const struct pv_init_ops xen_init_ops __initdata = {
+static const struct pv_init_ops xen_init_ops __initconst = {
        .banner = xen_banner,
 
        .reserve_memory = xen_reserve_memory,
@@ -337,7 +337,7 @@ xen_iosapic_write(char __iomem *iosapic, unsigned int reg, u32 val)
        HYPERVISOR_physdev_op(PHYSDEVOP_apic_write, &apic_op);
 }
 
-static const struct pv_iosapic_ops xen_iosapic_ops __initdata = {
+static const struct pv_iosapic_ops xen_iosapic_ops __initconst = {
        .pcat_compat_init = xen_pcat_compat_init,
        .__get_irq_chip = xen_iosapic_get_irq_chip,
 
index dba4afabb444a41bb7c294475825726e607f1881..39478dd08e67dd8a5d34a76fecc21bc511e1f4b2 100644 (file)
@@ -187,8 +187,8 @@ __asm__ (__ALIGN_STR "\n"                                              \
 "      jbra    ret_from_interrupt\n"                                      \
         : : "i" (&kstat_cpu(0).irqs[n+8]), "i" (&irq_handler[n+8]),       \
             "n" (PT_OFF_SR), "n" (n),                                     \
-            "i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &mfp.int_mk_a)      \
-                       : (n & 16 ? &tt_mfp.int_mk_b : &mfp.int_mk_b)),    \
+            "i" (n & 8 ? (n & 16 ? &tt_mfp.int_mk_a : &st_mfp.int_mk_a)   \
+                       : (n & 16 ? &tt_mfp.int_mk_b : &st_mfp.int_mk_b)), \
             "m" (preempt_count()), "di" (HARDIRQ_OFFSET)                  \
 );                                                                        \
        for (;;);                       /* fake noreturn */                \
@@ -366,14 +366,14 @@ void __init atari_init_IRQ(void)
        /* Initialize the MFP(s) */
 
 #ifdef ATARI_USE_SOFTWARE_EOI
-       mfp.vec_adr  = 0x48;    /* Software EOI-Mode */
+       st_mfp.vec_adr  = 0x48; /* Software EOI-Mode */
 #else
-       mfp.vec_adr  = 0x40;    /* Automatic EOI-Mode */
+       st_mfp.vec_adr  = 0x40; /* Automatic EOI-Mode */
 #endif
-       mfp.int_en_a = 0x00;    /* turn off MFP-Ints */
-       mfp.int_en_b = 0x00;
-       mfp.int_mk_a = 0xff;    /* no Masking */
-       mfp.int_mk_b = 0xff;
+       st_mfp.int_en_a = 0x00; /* turn off MFP-Ints */
+       st_mfp.int_en_b = 0x00;
+       st_mfp.int_mk_a = 0xff; /* no Masking */
+       st_mfp.int_mk_b = 0xff;
 
        if (ATARIHW_PRESENT(TT_MFP)) {
 #ifdef ATARI_USE_SOFTWARE_EOI
index a5f33c059979077ea17229a97c36fe692041cb23..4add96d13b1964db9b97aa6103005b5f803a75ed 100644 (file)
@@ -609,10 +609,10 @@ int atari_keyb_init(void)
                                 ACIA_RHTID : 0);
 
        /* make sure the interrupt line is up */
-       } while ((mfp.par_dt_reg & 0x10) == 0);
+       } while ((st_mfp.par_dt_reg & 0x10) == 0);
 
        /* enable ACIA Interrupts */
-       mfp.active_edge &= ~0x10;
+       st_mfp.active_edge &= ~0x10;
        atari_turnon_irq(IRQ_MFP_ACIA);
 
        ikbd_self_test = 1;
index 49c28cdbea5c5bf6cc89d00be99eee339900838c..ae2d96e5d618eba94ed0428468ca2e9f025e983f 100644 (file)
@@ -258,7 +258,7 @@ void __init config_atari(void)
                        printk("STND_SHIFTER ");
                }
        }
-       if (hwreg_present(&mfp.par_dt_reg)) {
+       if (hwreg_present(&st_mfp.par_dt_reg)) {
                ATARIHW_SET(ST_MFP);
                printk("ST_MFP ");
        }
index 702b15ccfab7b0f5c2bd53d3f73f18cdfa8ae50e..28efdc33c1aeab89afde05ff5249ba5bdf2f20ac 100644 (file)
@@ -34,9 +34,9 @@ static struct console atari_console_driver = {
 
 static inline void ata_mfp_out(char c)
 {
-       while (!(mfp.trn_stat & 0x80))  /* wait for tx buf empty */
+       while (!(st_mfp.trn_stat & 0x80))       /* wait for tx buf empty */
                barrier();
-       mfp.usart_dta = c;
+       st_mfp.usart_dta = c;
 }
 
 static void atari_mfp_console_write(struct console *co, const char *str,
@@ -91,7 +91,7 @@ static int ata_par_out(char c)
        /* This a some-seconds timeout in case no printer is connected */
        unsigned long i = loops_per_jiffy > 1 ? loops_per_jiffy : 10000000/HZ;
 
-       while ((mfp.par_dt_reg & 1) && --i) /* wait for BUSY == L */
+       while ((st_mfp.par_dt_reg & 1) && --i) /* wait for BUSY == L */
                ;
        if (!i)
                return 0;
@@ -131,9 +131,9 @@ static void atari_par_console_write(struct console *co, const char *str,
 #if 0
 int atari_mfp_console_wait_key(struct console *co)
 {
-       while (!(mfp.rcv_stat & 0x80))  /* wait for rx buf filled */
+       while (!(st_mfp.rcv_stat & 0x80))       /* wait for rx buf filled */
                barrier();
-       return mfp.usart_dta;
+       return st_mfp.usart_dta;
 }
 
 int atari_scc_console_wait_key(struct console *co)
@@ -175,12 +175,12 @@ static void __init atari_init_mfp_port(int cflag)
                baud = B9600;           /* use default 9600bps for non-implemented rates */
        baud -= B1200;                  /* baud_table[] starts at 1200bps */
 
-       mfp.trn_stat &= ~0x01;          /* disable TX */
-       mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */
-       mfp.tim_ct_cd &= 0x70;          /* stop timer D */
-       mfp.tim_dt_d = baud_table[baud];
-       mfp.tim_ct_cd |= 0x01;          /* start timer D, 1:4 */
-       mfp.trn_stat |= 0x01;           /* enable TX */
+       st_mfp.trn_stat &= ~0x01;       /* disable TX */
+       st_mfp.usart_ctr = parity | csize | 0x88; /* 1:16 clk mode, 1 stop bit */
+       st_mfp.tim_ct_cd &= 0x70;       /* stop timer D */
+       st_mfp.tim_dt_d = baud_table[baud];
+       st_mfp.tim_ct_cd |= 0x01;       /* start timer D, 1:4 */
+       st_mfp.trn_stat |= 0x01;        /* enable TX */
 }
 
 #define SCC_WRITE(reg, val)                            \
index d076ff8d1b39138ba16b4483d2874a7d5b4bcaa9..a0531f34c617ca90df986902735e0b6ae5d26574 100644 (file)
@@ -27,9 +27,9 @@ void __init
 atari_sched_init(irq_handler_t timer_routine)
 {
     /* set Timer C data Register */
-    mfp.tim_dt_c = INT_TICKS;
+    st_mfp.tim_dt_c = INT_TICKS;
     /* start timer C, div = 1:100 */
-    mfp.tim_ct_cd = (mfp.tim_ct_cd & 15) | 0x60;
+    st_mfp.tim_ct_cd = (st_mfp.tim_ct_cd & 15) | 0x60;
     /* install interrupt service routine for MFP Timer C */
     if (request_irq(IRQ_MFP_TIMC, timer_routine, IRQ_TYPE_SLOW,
                    "timer", timer_routine))
@@ -46,11 +46,11 @@ unsigned long atari_gettimeoffset (void)
   unsigned long ticks, offset = 0;
 
   /* read MFP timer C current value */
-  ticks = mfp.tim_dt_c;
+  ticks = st_mfp.tim_dt_c;
   /* The probability of underflow is less than 2% */
   if (ticks > INT_TICKS - INT_TICKS / 50)
     /* Check for pending timer interrupt */
-    if (mfp.int_pn_b & (1 << 5))
+    if (st_mfp.int_pn_b & (1 << 5))
       offset = TICK_SIZE;
 
   ticks = INT_TICKS - ticks;
index 1412b4ab202f1e753324e734d42dc92bbb635e7e..a714e1aa072a0e4bf4981894ed2c00b71ce7ca6c 100644 (file)
@@ -113,7 +113,7 @@ extern struct atari_hw_present atari_hw_present;
  * of nops on various machines. Somebody claimed that the tstb takes 600 ns.
  */
 #define        MFPDELAY() \
-       __asm__ __volatile__ ( "tstb %0" : : "m" (mfp.par_dt_reg) : "cc" );
+       __asm__ __volatile__ ( "tstb %0" : : "m" (st_mfp.par_dt_reg) : "cc" );
 
 /* Do cache push/invalidate for DMA read/write. This function obeys the
  * snooping on some machines (Medusa) and processors: The Medusa itself can
@@ -565,7 +565,7 @@ struct MFP
   u_char char_dummy23;
   u_char usart_dta;
  };
-# define mfp ((*(volatile struct MFP*)MFP_BAS))
+# define st_mfp ((*(volatile struct MFP*)MFP_BAS))
 
 /* TT's second MFP */
 
index 5748e99f4e260a2c3337a6bb4808dfc62ab8c774..f597892e43a00a6699219298dca76e6f081c9161 100644 (file)
@@ -113,7 +113,7 @@ static inline int get_mfp_bit( unsigned irq, int type )
 {      unsigned char   mask, *reg;
 
        mask = 1 << (irq & 7);
-       reg = (unsigned char *)&mfp.int_en_a + type*4 +
+       reg = (unsigned char *)&st_mfp.int_en_a + type*4 +
                  ((irq & 8) >> 2) + (((irq-8) & 16) << 3);
        return( *reg & mask );
 }
@@ -123,7 +123,7 @@ static inline void set_mfp_bit( unsigned irq, int type )
 {      unsigned char   mask, *reg;
 
        mask = 1 << (irq & 7);
-       reg = (unsigned char *)&mfp.int_en_a + type*4 +
+       reg = (unsigned char *)&st_mfp.int_en_a + type*4 +
                  ((irq & 8) >> 2) + (((irq-8) & 16) << 3);
        __asm__ __volatile__ ( "orb %0,%1"
                              : : "di" (mask), "m" (*reg) : "memory" );
@@ -134,7 +134,7 @@ static inline void clear_mfp_bit( unsigned irq, int type )
 {      unsigned char   mask, *reg;
 
        mask = ~(1 << (irq & 7));
-       reg = (unsigned char *)&mfp.int_en_a + type*4 +
+       reg = (unsigned char *)&st_mfp.int_en_a + type*4 +
                  ((irq & 8) >> 2) + (((irq-8) & 16) << 3);
        if (type == MFP_PENDING || type == MFP_SERVICE)
                __asm__ __volatile__ ( "moveb %0,%1"
index 06d887cdcbfbcc2c8aaf441a5f2e5a1e8c5bcd1f..855fc6a79d72fc1b00af368b65002b27d8eca0f0 100644 (file)
@@ -49,8 +49,39 @@ static struct platform_device m520x_uart = {
        .dev.platform_data      = m520x_uart_platform,
 };
 
+static struct resource m520x_fec_resources[] = {
+       {
+               .start          = MCF_MBAR + 0x30000,
+               .end            = MCF_MBAR + 0x30000 + 0x7ff,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = 64 + 36,
+               .end            = 64 + 36,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 40,
+               .end            = 64 + 40,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 42,
+               .end            = 64 + 42,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m520x_fec = {
+       .name                   = "fec",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m520x_fec_resources),
+       .resource               = m520x_fec_resources,
+};
+
 static struct platform_device *m520x_devices[] __initdata = {
        &m520x_uart,
+       &m520x_fec,
 };
 
 /***************************************************************************/
@@ -103,6 +134,30 @@ static void __init m520x_uarts_init(void)
 
 /***************************************************************************/
 
+static void __init m520x_fec_init(void)
+{
+       u32 imr;
+       u8 v;
+
+       /* Unmask FEC interrupts at ColdFire interrupt controller */
+       writeb(0x4, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 36);
+       writeb(0x4, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 40);
+       writeb(0x4, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 42);
+
+       imr = readl(MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH);
+       imr &= ~0x0001FFF0;
+       writel(imr, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH);
+
+       /* Set multi-function pins to ethernet mode */
+       v = readb(MCF_IPSBAR + MCF_GPIO_PAR_FEC);
+       writeb(v | 0xf0, MCF_IPSBAR + MCF_GPIO_PAR_FEC);
+
+       v = readb(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C);
+       writeb(v | 0x0f, MCF_IPSBAR + MCF_GPIO_PAR_FECI2C);
+}
+
+/***************************************************************************/
+
 /*
  *  Program the vector to be an auto-vectored.
  */
@@ -118,6 +173,7 @@ void __init config_BSP(char *commandp, int size)
 {
        mach_reset = coldfire_reset;
        m520x_uarts_init();
+       m520x_fec_init();
 }
 
 /***************************************************************************/
index 13f02611ea23a8c866755af5b0fe8585e2d60de2..74133f27b30c4ce290fc4a9d21da49afc541fb9d 100644 (file)
@@ -50,8 +50,39 @@ static struct platform_device m523x_uart = {
        .dev.platform_data      = m523x_uart_platform,
 };
 
+static struct resource m523x_fec_resources[] = {
+       {
+               .start          = MCF_MBAR + 0x1000,
+               .end            = MCF_MBAR + 0x1000 + 0x7ff,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = 64 + 23,
+               .end            = 64 + 23,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 27,
+               .end            = 64 + 27,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 29,
+               .end            = 64 + 29,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m523x_fec = {
+       .name                   = "fec",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m523x_fec_resources),
+       .resource               = m523x_fec_resources,
+};
+
 static struct platform_device *m523x_devices[] __initdata = {
        &m523x_uart,
+       &m523x_fec,
 };
 
 /***************************************************************************/
@@ -83,6 +114,25 @@ static void __init m523x_uarts_init(void)
 
 /***************************************************************************/
 
+static void __init m523x_fec_init(void)
+{
+       u32 imr;
+
+       /* Unmask FEC interrupts at ColdFire interrupt controller */
+       writeb(0x28, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 23);
+       writeb(0x27, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 27);
+       writeb(0x26, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 29);
+
+       imr = readl(MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH);
+       imr &= ~0xf;
+       writel(imr, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH);
+       imr = readl(MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL);
+       imr &= ~0xff800001;
+       writel(imr, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL);
+}
+
+/***************************************************************************/
+
 void mcf_disableall(void)
 {
        *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH)) = 0xffffffff;
@@ -103,6 +153,7 @@ void __init config_BSP(char *commandp, int size)
        mcf_disableall();
        mach_reset = coldfire_reset;
        m523x_uarts_init();
+       m523x_fec_init();
 }
 
 /***************************************************************************/
index 230bae691a7f4be9060b01397efd7cc20a045ace..e049245f4092a77e114bfabc6a8647d042759f81 100644 (file)
@@ -55,8 +55,39 @@ static struct platform_device m5272_uart = {
        .dev.platform_data      = m5272_uart_platform,
 };
 
+static struct resource m5272_fec_resources[] = {
+       {
+               .start          = MCF_MBAR + 0x840,
+               .end            = MCF_MBAR + 0x840 + 0x1cf,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = 86,
+               .end            = 86,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 87,
+               .end            = 87,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 88,
+               .end            = 88,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m5272_fec = {
+       .name                   = "fec",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m5272_fec_resources),
+       .resource               = m5272_fec_resources,
+};
+
 static struct platform_device *m5272_devices[] __initdata = {
        &m5272_uart,
+       &m5272_fec,
 };
 
 /***************************************************************************/
@@ -91,6 +122,22 @@ static void __init m5272_uarts_init(void)
 
 /***************************************************************************/
 
+static void __init m5272_fec_init(void)
+{
+       u32 imr;
+
+       /* Unmask FEC interrupts at ColdFire interrupt controller */
+       imr = readl(MCF_MBAR + MCFSIM_ICR3);
+       imr = (imr & ~0x00000fff) | 0x00000ddd;
+       writel(imr, MCF_MBAR + MCFSIM_ICR3);
+
+       imr = readl(MCF_MBAR + MCFSIM_ICR1);
+       imr = (imr & ~0x0f000000) | 0x0d000000;
+       writel(imr, MCF_MBAR + MCFSIM_ICR1);
+}
+
+/***************************************************************************/
+
 void mcf_disableall(void)
 {
        volatile unsigned long  *icrp;
@@ -155,6 +202,7 @@ void __init config_BSP(char *commandp, int size)
 static int __init init_BSP(void)
 {
        m5272_uarts_init();
+       m5272_fec_init();
        platform_add_devices(m5272_devices, ARRAY_SIZE(m5272_devices));
        return 0;
 }
index 73cd1aef4a9020c64133ea3c6b39a30669b2f57d..49343fb157b0c50f242e1d362b9a74484ff662ac 100644 (file)
@@ -50,8 +50,73 @@ static struct platform_device m527x_uart = {
        .dev.platform_data      = m527x_uart_platform,
 };
 
+static struct resource m527x_fec0_resources[] = {
+       {
+               .start          = MCF_MBAR + 0x1000,
+               .end            = MCF_MBAR + 0x1000 + 0x7ff,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = 64 + 23,
+               .end            = 64 + 23,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 27,
+               .end            = 64 + 27,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 29,
+               .end            = 64 + 29,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct resource m527x_fec1_resources[] = {
+       {
+               .start          = MCF_MBAR + 0x1800,
+               .end            = MCF_MBAR + 0x1800 + 0x7ff,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = 128 + 23,
+               .end            = 128 + 23,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 128 + 27,
+               .end            = 128 + 27,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 128 + 29,
+               .end            = 128 + 29,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m527x_fec[] = {
+       {
+               .name           = "fec",
+               .id             = 0,
+               .num_resources  = ARRAY_SIZE(m527x_fec0_resources),
+               .resource       = m527x_fec0_resources,
+       },
+       {
+               .name           = "fec",
+               .id             = 1,
+               .num_resources  = ARRAY_SIZE(m527x_fec1_resources),
+               .resource       = m527x_fec1_resources,
+       },
+};
+
 static struct platform_device *m527x_devices[] __initdata = {
        &m527x_uart,
+       &m527x_fec[0],
+#ifdef CONFIG_FEC2
+       &m527x_fec[1],
+#endif
 };
 
 /***************************************************************************/
@@ -97,6 +162,51 @@ static void __init m527x_uarts_init(void)
 
 /***************************************************************************/
 
+static void __init m527x_fec_irq_init(int nr)
+{
+       unsigned long base;
+       u32 imr;
+
+       base = MCF_IPSBAR + (nr ? MCFICM_INTC1 : MCFICM_INTC0);
+
+       writeb(0x28, base + MCFINTC_ICR0 + 23);
+       writeb(0x27, base + MCFINTC_ICR0 + 27);
+       writeb(0x26, base + MCFINTC_ICR0 + 29);
+
+       imr = readl(base + MCFINTC_IMRH);
+       imr &= ~0xf;
+       writel(imr, base + MCFINTC_IMRH);
+       imr = readl(base + MCFINTC_IMRL);
+       imr &= ~0xff800001;
+       writel(imr, base + MCFINTC_IMRL);
+}
+
+static void __init m527x_fec_init(void)
+{
+       u16 par;
+       u8 v;
+
+       m527x_fec_irq_init(0);
+
+       /* Set multi-function pins to ethernet mode for fec0 */
+       par = readw(MCF_IPSBAR + 0x100082);
+       writew(par | 0xf00, MCF_IPSBAR + 0x100082);
+       v = readb(MCF_IPSBAR + 0x100078);
+       writeb(v | 0xc0, MCF_IPSBAR + 0x100078);
+
+#ifdef CONFIG_FEC2
+       m527x_fec_irq_init(1);
+
+       /* Set multi-function pins to ethernet mode for fec1 */
+       par = readw(MCF_IPSBAR + 0x100082);
+       writew(par | 0xa0, MCF_IPSBAR + 0x100082);
+       v = readb(MCF_IPSBAR + 0x100079);
+       writeb(v | 0xc0, MCF_IPSBAR + 0x100079);
+#endif
+}
+
+/***************************************************************************/
+
 void mcf_disableall(void)
 {
        *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH)) = 0xffffffff;
@@ -116,13 +226,14 @@ void __init config_BSP(char *commandp, int size)
 {
        mcf_disableall();
        mach_reset = coldfire_reset;
+       m527x_uarts_init();
+       m527x_fec_init();
 }
 
 /***************************************************************************/
 
 static int __init init_BSP(void)
 {
-       m527x_uarts_init();
        platform_add_devices(m527x_devices, ARRAY_SIZE(m527x_devices));
        return 0;
 }
index dfdb5c2ed8e6d35a3ce45b0827c03b61833c2eaf..2ffb549876f073bf07cb32851a918a757dc1d6e0 100644 (file)
@@ -285,8 +285,40 @@ static struct platform_device m528x_uart = {
        .dev.platform_data      = m528x_uart_platform,
 };
 
+static struct resource m528x_fec_resources[] = {
+       {
+               .start          = MCF_MBAR + 0x1000,
+               .end            = MCF_MBAR + 0x1000 + 0x7ff,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = 64 + 23,
+               .end            = 64 + 23,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 27,
+               .end            = 64 + 27,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 29,
+               .end            = 64 + 29,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m528x_fec = {
+       .name                   = "fec",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m528x_fec_resources),
+       .resource               = m528x_fec_resources,
+};
+
+
 static struct platform_device *m528x_devices[] __initdata = {
        &m528x_uart,
+       &m528x_fec,
 };
 
 /***************************************************************************/
@@ -327,6 +359,31 @@ static void __init m528x_uarts_init(void)
 
 /***************************************************************************/
 
+static void __init m528x_fec_init(void)
+{
+       u32 imr;
+       u16 v16;
+
+       /* Unmask FEC interrupts at ColdFire interrupt controller */
+       writeb(0x28, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 23);
+       writeb(0x27, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 27);
+       writeb(0x26, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_ICR0 + 29);
+
+       imr = readl(MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH);
+       imr &= ~0xf;
+       writel(imr, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH);
+       imr = readl(MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL);
+       imr &= ~0xff800001;
+       writel(imr, MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRL);
+
+       /* Set multi-function pins to ethernet mode for fec0 */
+       v16 = readw(MCF_IPSBAR + 0x100056);
+       writew(v16 | 0xf00, MCF_IPSBAR + 0x100056);
+       writeb(0xc0, MCF_IPSBAR + 0x100058);
+}
+
+/***************************************************************************/
+
 void mcf_disableall(void)
 {
        *((volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 + MCFINTC_IMRH)) = 0xffffffff;
@@ -386,6 +443,7 @@ void __init config_BSP(char *commandp, int size)
 static int __init init_BSP(void)
 {
        m528x_uarts_init();
+       m528x_fec_init();
        platform_add_devices(m528x_devices, ARRAY_SIZE(m528x_devices));
        return 0;
 }
index a347623d6ee6be4826732407d280ed89cab95eaf..591f2f801134b495f1dfbf9f49a4868e20319c7b 100644 (file)
@@ -61,8 +61,38 @@ static struct platform_device m532x_uart = {
        .dev.platform_data      = m532x_uart_platform,
 };
 
+static struct resource m532x_fec_resources[] = {
+       {
+               .start          = 0xfc030000,
+               .end            = 0xfc0307ff,
+               .flags          = IORESOURCE_MEM,
+       },
+       {
+               .start          = 64 + 36,
+               .end            = 64 + 36,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 40,
+               .end            = 64 + 40,
+               .flags          = IORESOURCE_IRQ,
+       },
+       {
+               .start          = 64 + 42,
+               .end            = 64 + 42,
+               .flags          = IORESOURCE_IRQ,
+       },
+};
+
+static struct platform_device m532x_fec = {
+       .name                   = "fec",
+       .id                     = 0,
+       .num_resources          = ARRAY_SIZE(m532x_fec_resources),
+       .resource               = m532x_fec_resources,
+};
 static struct platform_device *m532x_devices[] __initdata = {
        &m532x_uart,
+       &m532x_fec,
 };
 
 /***************************************************************************/
@@ -93,6 +123,24 @@ static void __init m532x_uarts_init(void)
        for (line = 0; (line < nrlines); line++)
                m532x_uart_init_line(line, m532x_uart_platform[line].irq);
 }
+/***************************************************************************/
+
+static void __init m532x_fec_init(void)
+{
+       /* Unmask FEC interrupts at ColdFire interrupt controller */
+       MCF_INTC0_ICR36 = 0x2;
+       MCF_INTC0_ICR40 = 0x2;
+       MCF_INTC0_ICR42 = 0x2;
+
+       MCF_INTC0_IMRH &= ~(MCF_INTC_IMRH_INT_MASK36 |
+               MCF_INTC_IMRH_INT_MASK40 | MCF_INTC_IMRH_INT_MASK42);
+
+       /* Set multi-function pins to ethernet mode for fec0 */
+       MCF_GPIO_PAR_FECI2C |= (MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC |
+               MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO);
+       MCF_GPIO_PAR_FEC = (MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC |
+               MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC);
+}
 
 /***************************************************************************/
 
@@ -150,6 +198,7 @@ void __init config_BSP(char *commandp, int size)
 static int __init init_BSP(void)
 {
        m532x_uarts_init();
+       m532x_fec_init();
        platform_add_devices(m532x_devices, ARRAY_SIZE(m532x_devices));
        return 0;
 }
index 600eef3f3ac7db71dc165946e657da08ee79a9ac..e61465a18c7e4b6e66ba35194b1b7ae0eda5ddb7 100644 (file)
@@ -603,7 +603,7 @@ config CAVIUM_OCTEON_SIMULATOR
        select SYS_SUPPORTS_64BIT_KERNEL
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_HIGHMEM
-       select CPU_CAVIUM_OCTEON
+       select SYS_HAS_CPU_CAVIUM_OCTEON
        help
          The Octeon simulator is software performance model of the Cavium
          Octeon Processor. It supports simulating Octeon processors on x86
@@ -618,7 +618,7 @@ config CAVIUM_OCTEON_REFERENCE_BOARD
        select SYS_SUPPORTS_BIG_ENDIAN
        select SYS_SUPPORTS_HIGHMEM
        select SYS_HAS_EARLY_PRINTK
-       select CPU_CAVIUM_OCTEON
+       select SYS_HAS_CPU_CAVIUM_OCTEON
        select SWAP_IO_SPACE
        help
          This option supports all of the Octeon reference boards from Cavium
@@ -1234,6 +1234,7 @@ config CPU_SB1
 
 config CPU_CAVIUM_OCTEON
        bool "Cavium Octeon processor"
+       depends on SYS_HAS_CPU_CAVIUM_OCTEON
        select IRQ_CPU
        select IRQ_CPU_OCTEON
        select CPU_HAS_PREFETCH
@@ -1314,6 +1315,9 @@ config SYS_HAS_CPU_RM9000
 config SYS_HAS_CPU_SB1
        bool
 
+config SYS_HAS_CPU_CAVIUM_OCTEON
+       bool
+
 #
 # CPU may reorder R->R, R->W, W->R, W->W
 # Reordering beyond LL and SC is handled in WEAK_REORDERING_BEYOND_LLSC
@@ -1387,6 +1391,7 @@ config 32BIT
 config 64BIT
        bool "64-bit kernel"
        depends on CPU_SUPPORTS_64BIT_KERNEL && SYS_SUPPORTS_64BIT_KERNEL
+       select HAVE_SYSCALL_WRAPPERS
        help
          Select this option if you want to build a 64-bit kernel.
 
index 6fd441d16af57e6af53fa410fee70dac5204d66c..f58d4ffb89456c1c1d6d3076906631946b1aba48 100644 (file)
@@ -118,7 +118,7 @@ void __init plat_time_init(void)
         * setup counter 1 (RTC) to tick at full speed
         */
        t = 0xffffff;
-       while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S) && t--)
+       while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_T1S) && --t)
                asm volatile ("nop");
        if (!t)
                goto cntr_err;
@@ -127,7 +127,7 @@ void __init plat_time_init(void)
        au_sync();
 
        t = 0xffffff;
-       while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S) && t--)
+       while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S) && --t)
                asm volatile ("nop");
        if (!t)
                goto cntr_err;
@@ -135,7 +135,7 @@ void __init plat_time_init(void)
        au_sync();
 
        t = 0xffffff;
-       while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S) && t--)
+       while ((au_readl(SYS_COUNTER_CNTRL) & SYS_CNTRL_C1S) && --t)
                asm volatile ("nop");
        if (!t)
                goto cntr_err;
index 36ed44070256243fe1bac9f7618154481fabd7ef..a6772e9507f5ac109d5422d66c1184dcbbc7839d 100644 (file)
@@ -1,6 +1,5 @@
 #ifndef __ASM_SECCOMP_H
 
-#include <linux/thread_info.h>
 #include <linux/unistd.h>
 
 #define __NR_seccomp_read __NR_read
index a0ff2b66e22b453f23d909959d3c37694cd5fd80..4b4007b3083a8f881cef80371e68a2a688c55f32 100644 (file)
@@ -111,7 +111,6 @@ int show_interrupts(struct seq_file *p, void *v)
                        seq_printf(p, "%10u ", kstat_cpu(j).irqs[i]);
 #endif
                seq_printf(p, " %14s", irq_desc[i].chip->name);
-               seq_printf(p, "-%-8s", irq_desc[i].name);
                seq_printf(p, "  %s", action->name);
 
                for (action=action->next; action; action = action->next)
index aa2c55e3b55ffda84dff352114a6bf904aa07580..2f8452b404c71be4a22bdf508dcedb54320d45c4 100644 (file)
@@ -32,6 +32,7 @@
 #include <linux/module.h>
 #include <linux/binfmts.h>
 #include <linux/security.h>
+#include <linux/syscalls.h>
 #include <linux/compat.h>
 #include <linux/vfs.h>
 #include <linux/ipc.h>
@@ -63,9 +64,9 @@
 #define merge_64(r1, r2) ((((r2) & 0xffffffffUL) << 32) + ((r1) & 0xffffffffUL))
 #endif
 
-asmlinkage unsigned long
-sys32_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
-         unsigned long flags, unsigned long fd, unsigned long pgoff)
+SYSCALL_DEFINE6(32_mmap2, unsigned long, addr, unsigned long, len,
+       unsigned long, prot, unsigned long, flags, unsigned long, fd,
+       unsigned long, pgoff)
 {
        struct file * file = NULL;
        unsigned long error;
@@ -121,21 +122,21 @@ struct rlimit32 {
        int     rlim_max;
 };
 
-asmlinkage long sys32_truncate64(const char __user * path,
-       unsigned long __dummy, int a2, int a3)
+SYSCALL_DEFINE4(32_truncate64, const char __user *, path,
+       unsigned long, __dummy, unsigned long, a2, unsigned long, a3)
 {
        return sys_truncate(path, merge_64(a2, a3));
 }
 
-asmlinkage long sys32_ftruncate64(unsigned int fd, unsigned long __dummy,
-       int a2, int a3)
+SYSCALL_DEFINE4(32_ftruncate64, unsigned long, fd, unsigned long, __dummy,
+       unsigned long, a2, unsigned long, a3)
 {
        return sys_ftruncate(fd, merge_64(a2, a3));
 }
 
-asmlinkage int sys32_llseek(unsigned int fd, unsigned int offset_high,
-                           unsigned int offset_low, loff_t __user * result,
-                           unsigned int origin)
+SYSCALL_DEFINE5(32_llseek, unsigned long, fd, unsigned long, offset_high,
+       unsigned long, offset_low, loff_t __user *, result,
+       unsigned long, origin)
 {
        return sys_llseek(fd, offset_high, offset_low, result, origin);
 }
@@ -144,20 +145,20 @@ asmlinkage int sys32_llseek(unsigned int fd, unsigned int offset_high,
    lseek back to original location.  They fail just like lseek does on
    non-seekable files.  */
 
-asmlinkage ssize_t sys32_pread(unsigned int fd, char __user * buf,
-                              size_t count, u32 unused, u64 a4, u64 a5)
+SYSCALL_DEFINE6(32_pread, unsigned long, fd, char __user *, buf, size_t, count,
+       unsigned long, unused, unsigned long, a4, unsigned long, a5)
 {
        return sys_pread64(fd, buf, count, merge_64(a4, a5));
 }
 
-asmlinkage ssize_t sys32_pwrite(unsigned int fd, const char __user * buf,
-                               size_t count, u32 unused, u64 a4, u64 a5)
+SYSCALL_DEFINE6(32_pwrite, unsigned int, fd, const char __user *, buf,
+       size_t, count, u32, unused, u64, a4, u64, a5)
 {
        return sys_pwrite64(fd, buf, count, merge_64(a4, a5));
 }
 
-asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid,
-       struct compat_timespec __user *interval)
+SYSCALL_DEFINE2(32_sched_rr_get_interval, compat_pid_t, pid,
+       struct compat_timespec __user *interval)
 {
        struct timespec t;
        int ret;
@@ -174,8 +175,8 @@ asmlinkage int sys32_sched_rr_get_interval(compat_pid_t pid,
 
 #ifdef CONFIG_SYSVIPC
 
-asmlinkage long
-sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth)
+SYSCALL_DEFINE6(32_ipc, u32, call, long, first, long, second, long, third,
+       unsigned long, ptr, unsigned long, fifth)
 {
        int version, err;
 
@@ -233,8 +234,8 @@ sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth)
 
 #else
 
-asmlinkage long
-sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth)
+SYSCALL_DEFINE6(32_ipc, u32, call, int, first, int, second, int, third,
+       u32, ptr, u32 fifth)
 {
        return -ENOSYS;
 }
@@ -242,7 +243,7 @@ sys32_ipc(u32 call, int first, int second, int third, u32 ptr, u32 fifth)
 #endif /* CONFIG_SYSVIPC */
 
 #ifdef CONFIG_MIPS32_N32
-asmlinkage long sysn32_semctl(int semid, int semnum, int cmd, u32 arg)
+SYSCALL_DEFINE4(n32_semctl, int, semid, int, semnum, int, cmd, u32, arg)
 {
        /* compat_sys_semctl expects a pointer to union semun */
        u32 __user *uptr = compat_alloc_user_space(sizeof(u32));
@@ -251,13 +252,14 @@ asmlinkage long sysn32_semctl(int semid, int semnum, int cmd, u32 arg)
        return compat_sys_semctl(semid, semnum, cmd, uptr);
 }
 
-asmlinkage long sysn32_msgsnd(int msqid, u32 msgp, unsigned msgsz, int msgflg)
+SYSCALL_DEFINE4(n32_msgsnd, int, msqid, u32, msgp, unsigned int, msgsz,
+       int, msgflg)
 {
        return compat_sys_msgsnd(msqid, msgsz, msgflg, compat_ptr(msgp));
 }
 
-asmlinkage long sysn32_msgrcv(int msqid, u32 msgp, size_t msgsz, int msgtyp,
-                             int msgflg)
+SYSCALL_DEFINE5(n32_msgrcv, int, msqid, u32, msgp, size_t, msgsz,
+       int, msgtyp, int, msgflg)
 {
        return compat_sys_msgrcv(msqid, msgsz, msgtyp, msgflg, IPC_64,
                                 compat_ptr(msgp));
@@ -277,7 +279,7 @@ struct sysctl_args32
 
 #ifdef CONFIG_SYSCTL_SYSCALL
 
-asmlinkage long sys32_sysctl(struct sysctl_args32 __user *args)
+SYSCALL_DEFINE1(32_sysctl, struct sysctl_args32 __user *, args)
 {
        struct sysctl_args32 tmp;
        int error;
@@ -316,9 +318,16 @@ asmlinkage long sys32_sysctl(struct sysctl_args32 __user *args)
        return error;
 }
 
+#else
+
+SYSCALL_DEFINE1(32_sysctl, struct sysctl_args32 __user *, args)
+{
+       return -ENOSYS;
+}
+
 #endif /* CONFIG_SYSCTL_SYSCALL */
 
-asmlinkage long sys32_newuname(struct new_utsname __user * name)
+SYSCALL_DEFINE1(32_newuname, struct new_utsname __user *, name)
 {
        int ret = 0;
 
@@ -334,7 +343,7 @@ asmlinkage long sys32_newuname(struct new_utsname __user * name)
        return ret;
 }
 
-asmlinkage int sys32_personality(unsigned long personality)
+SYSCALL_DEFINE1(32_personality, unsigned long, personality)
 {
        int ret;
        personality &= 0xffffffff;
@@ -357,7 +366,7 @@ struct ustat32 {
 
 extern asmlinkage long sys_ustat(dev_t dev, struct ustat __user * ubuf);
 
-asmlinkage int sys32_ustat(dev_t dev, struct ustat32 __user * ubuf32)
+SYSCALL_DEFINE2(32_ustat, dev_t, dev, struct ustat32 __user *, ubuf32)
 {
        int err;
        struct ustat tmp;
@@ -381,8 +390,8 @@ out:
        return err;
 }
 
-asmlinkage int sys32_sendfile(int out_fd, int in_fd, compat_off_t __user *offset,
-       s32 count)
+SYSCALL_DEFINE4(32_sendfile, long, out_fd, long, in_fd,
+       compat_off_t __user *, offset, s32, count)
 {
        mm_segment_t old_fs = get_fs();
        int ret;
index 51d1ba415b90adaab205ee6fafd784ef1aa97bd6..9ab70c3b5be6bac233e00568ac3ce9dd51f410e8 100644 (file)
@@ -399,7 +399,7 @@ einval:     li      v0, -ENOSYS
        sys     sys_swapon              2
        sys     sys_reboot              3
        sys     sys_old_readdir         3
-       sys     old_mmap                6       /* 4090 */
+       sys     sys_mips_mmap           6       /* 4090 */
        sys     sys_munmap              2
        sys     sys_truncate            2
        sys     sys_ftruncate           2
@@ -519,7 +519,7 @@ einval:     li      v0, -ENOSYS
        sys     sys_sendfile            4
        sys     sys_ni_syscall          0
        sys     sys_ni_syscall          0
-       sys     sys_mmap2               6       /* 4210 */
+       sys     sys_mips_mmap2          6       /* 4210 */
        sys     sys_truncate64          4
        sys     sys_ftruncate64         4
        sys     sys_stat64              2
index a9e1716189948c2b76eaa47aa985208277d00667..9b46986671545dea233ce1f96aca4f59e7eb912a 100644 (file)
@@ -207,7 +207,7 @@ sys_call_table:
        PTR     sys_newlstat
        PTR     sys_poll
        PTR     sys_lseek
-       PTR     old_mmap
+       PTR     sys_mips_mmap
        PTR     sys_mprotect                    /* 5010 */
        PTR     sys_munmap
        PTR     sys_brk
index 30f3b6317a83f1ec7d753cdb49b96d1aedce1186..7438e92f8a010566e183f986190b14de82e70bd7 100644 (file)
@@ -129,12 +129,12 @@ EXPORT(sysn32_call_table)
        PTR     sys_newlstat
        PTR     sys_poll
        PTR     sys_lseek
-       PTR     old_mmap
+       PTR     sys_mips_mmap
        PTR     sys_mprotect                    /* 6010 */
        PTR     sys_munmap
        PTR     sys_brk
-       PTR     sys32_rt_sigaction
-       PTR     sys32_rt_sigprocmask
+       PTR     sys_32_rt_sigaction
+       PTR     sys_32_rt_sigprocmask
        PTR     compat_sys_ioctl                /* 6015 */
        PTR     sys_pread64
        PTR     sys_pwrite64
@@ -159,7 +159,7 @@ EXPORT(sysn32_call_table)
        PTR     compat_sys_setitimer
        PTR     sys_alarm
        PTR     sys_getpid
-       PTR     sys32_sendfile
+       PTR     sys_32_sendfile
        PTR     sys_socket                      /* 6040 */
        PTR     sys_connect
        PTR     sys_accept
@@ -181,14 +181,14 @@ EXPORT(sysn32_call_table)
        PTR     sys_exit
        PTR     compat_sys_wait4
        PTR     sys_kill                        /* 6060 */
-       PTR     sys32_newuname
+       PTR     sys_32_newuname
        PTR     sys_semget
        PTR     sys_semop
-       PTR     sysn32_semctl
+       PTR     sys_n32_semctl
        PTR     sys_shmdt                       /* 6065 */
        PTR     sys_msgget
-       PTR     sysn32_msgsnd
-       PTR     sysn32_msgrcv
+       PTR     sys_n32_msgsnd
+       PTR     sys_n32_msgrcv
        PTR     compat_sys_msgctl
        PTR     compat_sys_fcntl                /* 6070 */
        PTR     sys_flock
@@ -245,15 +245,15 @@ EXPORT(sysn32_call_table)
        PTR     sys_getsid
        PTR     sys_capget
        PTR     sys_capset
-       PTR     sys32_rt_sigpending             /* 6125 */
+       PTR     sys_32_rt_sigpending            /* 6125 */
        PTR     compat_sys_rt_sigtimedwait
-       PTR     sys32_rt_sigqueueinfo
+       PTR     sys_32_rt_sigqueueinfo
        PTR     sysn32_rt_sigsuspend
        PTR     sys32_sigaltstack
        PTR     compat_sys_utime                /* 6130 */
        PTR     sys_mknod
-       PTR     sys32_personality
-       PTR     sys32_ustat
+       PTR     sys_32_personality
+       PTR     sys_32_ustat
        PTR     compat_sys_statfs
        PTR     compat_sys_fstatfs              /* 6135 */
        PTR     sys_sysfs
@@ -265,14 +265,14 @@ EXPORT(sysn32_call_table)
        PTR     sys_sched_getscheduler
        PTR     sys_sched_get_priority_max
        PTR     sys_sched_get_priority_min
-       PTR     sys32_sched_rr_get_interval     /* 6145 */
+       PTR     sys_32_sched_rr_get_interval    /* 6145 */
        PTR     sys_mlock
        PTR     sys_munlock
        PTR     sys_mlockall
        PTR     sys_munlockall
        PTR     sys_vhangup                     /* 6150 */
        PTR     sys_pivot_root
-       PTR     sys32_sysctl
+       PTR     sys_32_sysctl
        PTR     sys_prctl
        PTR     compat_sys_adjtimex
        PTR     compat_sys_setrlimit            /* 6155 */
index fefef4af8595493ec3c5414f3fb0fcaff14869b1..b0fef4ff9827610210ef3dc16d903d347491169d 100644 (file)
@@ -265,12 +265,12 @@ sys_call_table:
        PTR     sys_olduname
        PTR     sys_umask                       /* 4060 */
        PTR     sys_chroot
-       PTR     sys32_ustat
+       PTR     sys_32_ustat
        PTR     sys_dup2
        PTR     sys_getppid
        PTR     sys_getpgrp                     /* 4065 */
        PTR     sys_setsid
-       PTR     sys32_sigaction
+       PTR     sys_32_sigaction
        PTR     sys_sgetmask
        PTR     sys_ssetmask
        PTR     sys_setreuid                    /* 4070 */
@@ -293,7 +293,7 @@ sys_call_table:
        PTR     sys_swapon
        PTR     sys_reboot
        PTR     compat_sys_old_readdir
-       PTR     old_mmap                        /* 4090 */
+       PTR     sys_mips_mmap                   /* 4090 */
        PTR     sys_munmap
        PTR     sys_truncate
        PTR     sys_ftruncate
@@ -320,12 +320,12 @@ sys_call_table:
        PTR     compat_sys_wait4
        PTR     sys_swapoff                     /* 4115 */
        PTR     compat_sys_sysinfo
-       PTR     sys32_ipc
+       PTR     sys_32_ipc
        PTR     sys_fsync
        PTR     sys32_sigreturn
        PTR     sys32_clone                     /* 4120 */
        PTR     sys_setdomainname
-       PTR     sys32_newuname
+       PTR     sys_32_newuname
        PTR     sys_ni_syscall                  /* sys_modify_ldt */
        PTR     compat_sys_adjtimex
        PTR     sys_mprotect                    /* 4125 */
@@ -339,11 +339,11 @@ sys_call_table:
        PTR     sys_fchdir
        PTR     sys_bdflush
        PTR     sys_sysfs                       /* 4135 */
-       PTR     sys32_personality
+       PTR     sys_32_personality
        PTR     sys_ni_syscall                  /* for afs_syscall */
        PTR     sys_setfsuid
        PTR     sys_setfsgid
-       PTR     sys32_llseek                    /* 4140 */
+       PTR     sys_32_llseek                   /* 4140 */
        PTR     compat_sys_getdents
        PTR     compat_sys_select
        PTR     sys_flock
@@ -356,7 +356,7 @@ sys_call_table:
        PTR     sys_ni_syscall                  /* 4150 */
        PTR     sys_getsid
        PTR     sys_fdatasync
-       PTR     sys32_sysctl
+       PTR     sys_32_sysctl
        PTR     sys_mlock
        PTR     sys_munlock                     /* 4155 */
        PTR     sys_mlockall
@@ -368,7 +368,7 @@ sys_call_table:
        PTR     sys_sched_yield
        PTR     sys_sched_get_priority_max
        PTR     sys_sched_get_priority_min
-       PTR     sys32_sched_rr_get_interval     /* 4165 */
+       PTR     sys_32_sched_rr_get_interval    /* 4165 */
        PTR     compat_sys_nanosleep
        PTR     sys_mremap
        PTR     sys_accept
@@ -397,25 +397,25 @@ sys_call_table:
        PTR     sys_getresgid
        PTR     sys_prctl
        PTR     sys32_rt_sigreturn
-       PTR     sys32_rt_sigaction
-       PTR     sys32_rt_sigprocmask            /* 4195 */
-       PTR     sys32_rt_sigpending
+       PTR     sys_32_rt_sigaction
+       PTR     sys_32_rt_sigprocmask           /* 4195 */
+       PTR     sys_32_rt_sigpending
        PTR     compat_sys_rt_sigtimedwait
-       PTR     sys32_rt_sigqueueinfo
+       PTR     sys_32_rt_sigqueueinfo
        PTR     sys32_rt_sigsuspend
-       PTR     sys32_pread                     /* 4200 */
-       PTR     sys32_pwrite
+       PTR     sys_32_pread                    /* 4200 */
+       PTR     sys_32_pwrite
        PTR     sys_chown
        PTR     sys_getcwd
        PTR     sys_capget
        PTR     sys_capset                      /* 4205 */
        PTR     sys32_sigaltstack
-       PTR     sys32_sendfile
+       PTR     sys_32_sendfile
        PTR     sys_ni_syscall
        PTR     sys_ni_syscall
-       PTR     sys32_mmap2                     /* 4210 */
-       PTR     sys32_truncate64
-       PTR     sys32_ftruncate64
+       PTR     sys_mips_mmap2                  /* 4210 */
+       PTR     sys_32_truncate64
+       PTR     sys_32_ftruncate64
        PTR     sys_newstat
        PTR     sys_newlstat
        PTR     sys_newfstat                    /* 4215 */
@@ -481,7 +481,7 @@ sys_call_table:
        PTR     compat_sys_mq_notify            /* 4275 */
        PTR     compat_sys_mq_getsetattr
        PTR     sys_ni_syscall                  /* sys_vserver */
-       PTR     sys32_waitid
+       PTR     sys_32_waitid
        PTR     sys_ni_syscall                  /* available, was setaltroot */
        PTR     sys_add_key                     /* 4280 */
        PTR     sys_request_key
index a4e106c56ab5d1d6d28d8e823b66ea657f6a8aaa..830c5ef9932b389cbc4ad7f1410b750721a6b070 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/ptrace.h>
 #include <linux/unistd.h>
 #include <linux/compiler.h>
+#include <linux/syscalls.h>
 #include <linux/uaccess.h>
 
 #include <asm/abi.h>
@@ -338,8 +339,8 @@ asmlinkage int sys_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
 }
 
 #ifdef CONFIG_TRAD_SIGNALS
-asmlinkage int sys_sigaction(int sig, const struct sigaction __user *act,
-       struct sigaction __user *oact)
+SYSCALL_DEFINE3(sigaction, int, sig, const struct sigaction __user *, act,
+       struct sigaction __user *oact)
 {
        struct k_sigaction new_ka, old_ka;
        int ret;
index 652709b353adf045be0a1e526910844f467dff0b..2e74075ac0cadcc7c64b92fa98f3a0d7794ae479 100644 (file)
@@ -349,8 +349,8 @@ asmlinkage int sys32_rt_sigsuspend(nabi_no_regargs struct pt_regs regs)
        return -ERESTARTNOHAND;
 }
 
-asmlinkage int sys32_sigaction(int sig, const struct sigaction32 __user *act,
-                               struct sigaction32 __user *oact)
+SYSCALL_DEFINE3(32_sigaction, long, sig, const struct sigaction32 __user *, act,
+       struct sigaction32 __user *, oact)
 {
        struct k_sigaction new_ka, old_ka;
        int ret;
@@ -704,9 +704,9 @@ struct mips_abi mips_abi_32 = {
        .restart        = __NR_O32_restart_syscall
 };
 
-asmlinkage int sys32_rt_sigaction(int sig, const struct sigaction32 __user *act,
-                                 struct sigaction32 __user *oact,
-                                 unsigned int sigsetsize)
+SYSCALL_DEFINE4(32_rt_sigaction, int, sig,
+       const struct sigaction32 __user *, act,
+       struct sigaction32 __user *, oact, unsigned int, sigsetsize)
 {
        struct k_sigaction new_sa, old_sa;
        int ret = -EINVAL;
@@ -748,8 +748,8 @@ out:
        return ret;
 }
 
-asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
-       compat_sigset_t __user *oset, unsigned int sigsetsize)
+SYSCALL_DEFINE4(32_rt_sigprocmask, int, how, compat_sigset_t __user *, set,
+       compat_sigset_t __user *, oset, unsigned int, sigsetsize)
 {
        sigset_t old_set, new_set;
        int ret;
@@ -770,8 +770,8 @@ asmlinkage int sys32_rt_sigprocmask(int how, compat_sigset_t __user *set,
        return ret;
 }
 
-asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *uset,
-       unsigned int sigsetsize)
+SYSCALL_DEFINE2(32_rt_sigpending, compat_sigset_t __user *, uset,
+       unsigned int, sigsetsize)
 {
        int ret;
        sigset_t set;
@@ -787,7 +787,8 @@ asmlinkage int sys32_rt_sigpending(compat_sigset_t __user *uset,
        return ret;
 }
 
-asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *uinfo)
+SYSCALL_DEFINE3(32_rt_sigqueueinfo, int, pid, int, sig,
+       compat_siginfo_t __user *, uinfo)
 {
        siginfo_t info;
        int ret;
@@ -802,10 +803,9 @@ asmlinkage int sys32_rt_sigqueueinfo(int pid, int sig, compat_siginfo_t __user *
        return ret;
 }
 
-asmlinkage long
-sys32_waitid(int which, compat_pid_t pid,
-            compat_siginfo_t __user *uinfo, int options,
-            struct compat_rusage __user *uru)
+SYSCALL_DEFINE5(32_waitid, int, which, compat_pid_t, pid,
+            compat_siginfo_t __user *, uinfo, int, options,
+            struct compat_rusage __user *, uru)
 {
        siginfo_t info;
        struct rusage ru;
index 37970d9b2186eed4f26d8b736d731f35fb5d7b72..8cf3846440401b682b01cf26aaa93ba25699c68c 100644 (file)
@@ -152,9 +152,9 @@ out:
        return error;
 }
 
-asmlinkage unsigned long
-old_mmap(unsigned long addr, unsigned long len, int prot,
-       int flags, int fd, off_t offset)
+SYSCALL_DEFINE6(mips_mmap, unsigned long, addr, unsigned long, len,
+       unsigned long, prot, unsigned long, flags, unsigned long,
+       fd, off_t, offset)
 {
        unsigned long result;
 
@@ -168,9 +168,9 @@ out:
        return result;
 }
 
-asmlinkage unsigned long
-sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot,
-          unsigned long flags, unsigned long fd, unsigned long pgoff)
+SYSCALL_DEFINE6(mips_mmap2, unsigned long, addr, unsigned long, len,
+       unsigned long, prot, unsigned long, flags, unsigned long, fd,
+       unsigned long, pgoff)
 {
        if (pgoff & (~PAGE_MASK >> 12))
                return -EINVAL;
@@ -240,7 +240,7 @@ out:
 /*
  * Compacrapability ...
  */
-asmlinkage int sys_uname(struct old_utsname __user * name)
+SYSCALL_DEFINE1(uname, struct old_utsname __user *, name)
 {
        if (name && !copy_to_user(name, utsname(), sizeof (*name)))
                return 0;
@@ -250,7 +250,7 @@ asmlinkage int sys_uname(struct old_utsname __user * name)
 /*
  * Compacrapability ...
  */
-asmlinkage int sys_olduname(struct oldold_utsname __user * name)
+SYSCALL_DEFINE1(olduname, struct oldold_utsname __user *, name)
 {
        int error;
 
@@ -279,7 +279,7 @@ asmlinkage int sys_olduname(struct oldold_utsname __user * name)
        return error;
 }
 
-asmlinkage int sys_set_thread_area(unsigned long addr)
+SYSCALL_DEFINE1(set_thread_area, unsigned long, addr)
 {
        struct thread_info *ti = task_thread_info(current);
 
@@ -290,7 +290,7 @@ asmlinkage int sys_set_thread_area(unsigned long addr)
        return 0;
 }
 
-asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3)
+asmlinkage int _sys_sysmips(long cmd, long arg1, long arg2, long arg3)
 {
        switch (cmd) {
        case MIPS_ATOMIC_SET:
@@ -325,8 +325,8 @@ asmlinkage int _sys_sysmips(int cmd, long arg1, int arg2, int arg3)
  *
  * This is really horribly ugly.
  */
-asmlinkage int sys_ipc(unsigned int call, int first, int second,
-                      unsigned long third, void __user *ptr, long fifth)
+SYSCALL_DEFINE6(ipc, unsigned int, call, int, first, int, second,
+       unsigned long, third, void __user *, ptr, long, fifth)
 {
        int version, ret;
 
@@ -411,7 +411,7 @@ asmlinkage int sys_ipc(unsigned int call, int first, int second,
 /*
  * No implemented yet ...
  */
-asmlinkage int sys_cachectl(char *addr, int nbytes, int op)
+SYSCALL_DEFINE3(cachectl, char *, addr, int, nbytes, int, op)
 {
        return -ENOSYS;
 }
index 98ad0a82c29e84cd35303809e3c473c6a7531e10..694d51f523d1fd8d5cbf057534e6031bf36f5327 100644 (file)
@@ -13,6 +13,7 @@
 #include <linux/linkage.h>
 #include <linux/module.h>
 #include <linux/sched.h>
+#include <linux/syscalls.h>
 #include <linux/mm.h>
 
 #include <asm/cacheflush.h>
@@ -58,8 +59,8 @@ EXPORT_SYMBOL(_dma_cache_wback_inv);
  * We could optimize the case where the cache argument is not BCACHE but
  * that seems very atypical use ...
  */
-asmlinkage int sys_cacheflush(unsigned long addr,
-       unsigned long bytes, unsigned int cache)
+SYSCALL_DEFINE3(cacheflush, unsigned long, addr, unsigned long, bytes,
+       unsigned int, cache)
 {
        if (bytes == 0)
                return 0;
index 9a9f433588792f5030796b2686193f4983c98ce9..41d16822e616b0f61062f04ba3d3560a579cb946 100644 (file)
@@ -7,6 +7,7 @@ mainmenu "Linux Kernel Configuration"
 
 config MN10300
        def_bool y
+       select HAVE_OPROFILE
 
 config AM33
        def_bool y
index 1a86425fec42302a9f6558c6e40279ddcc85e2f2..07dbbcda3b2e5dc57f71ee2ba376f6da83010d63 100644 (file)
@@ -173,7 +173,7 @@ static int pci_ampci_write_config_byte(struct pci_bus *bus, unsigned int devfn,
                BRIDGEREGB(where) = value;
        } else {
                if (bus->number == 0 &&
-                   (devfn == PCI_DEVFN(2, 0) && devfn == PCI_DEVFN(3, 0))
+                   (devfn == PCI_DEVFN(2, 0) || devfn == PCI_DEVFN(3, 0))
                    )
                        __pcidebug("<= %02x", bus, devfn, where, value);
                CONFIG_ADDRESS = CONFIG_CMD(bus, devfn, where);
index d811a8cd7b58c9397200be83cf0ee333c313e037..4774c2f92232b8ce98177d555b4d2c592dc076e5 100644 (file)
@@ -210,5 +210,10 @@ struct compat_shmid64_ds {
        compat_ulong_t __unused6;
 };
 
+static inline int is_compat_task(void)
+{
+       return test_thread_flag(TIF_32BIT);
+}
+
 #endif /* __KERNEL__ */
 #endif /* _ASM_POWERPC_COMPAT_H */
index 6b18ba9d2d856fabc31e86dc9d6ebbb300aac63d..1dbca4e7de67d70b1d28ed52c370312f81c2e041 100644 (file)
@@ -60,7 +60,7 @@
 /* It should be preserving the high 48 bits and then specifically */
 /* preserving _PAGE_SECONDARY | _PAGE_GROUP_IX */
 #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | \
-                         _PAGE_HPTEFLAGS)
+                         _PAGE_HPTEFLAGS | _PAGE_SPECIAL)
 
 /* Bits to mask out from a PMD to get to the PTE page */
 #define PMD_MASKED_BITS                0
index 07b0d8f09cb60ecbad1a963193fa0cfec85a0155..7389003349a693a4f021f0144fc56d9d2e3fe4d2 100644 (file)
@@ -114,7 +114,7 @@ static inline struct subpage_prot_table *pgd_subpage_prot(pgd_t *pgd)
  * pgprot changes
  */
 #define _PAGE_CHG_MASK (PTE_RPN_MASK | _PAGE_HPTEFLAGS | _PAGE_DIRTY | \
-                         _PAGE_ACCESSED)
+                         _PAGE_ACCESSED | _PAGE_SPECIAL)
 
 /* Bits to mask out from a PMD to get to the PTE page */
 #define PMD_MASKED_BITS                0x1ff
index f69a4d97772904ea5c42beda4748a8d4cc085202..820b5f0a35ce309fcc1b2f662625d0205abfc8dc 100644 (file)
@@ -429,7 +429,8 @@ extern int icache_44x_need_flush;
 #define PMD_PAGE_SIZE(pmd)     bad_call_to_PMD_PAGE_SIZE()
 #endif
 
-#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY)
+#define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY | \
+                        _PAGE_SPECIAL)
 
 
 #define PAGE_PROT_BITS (_PAGE_GUARDED | _PAGE_COHERENT | _PAGE_NO_CACHE | \
index 853765eb1f6584e23edc6f1c8c3272814c0fa395..00c1d9133cfe12fa17db2d6f25a0f34c3e72ce20 100644 (file)
@@ -1,10 +1,6 @@
 #ifndef _ASM_POWERPC_SECCOMP_H
 #define _ASM_POWERPC_SECCOMP_H
 
-#ifdef __KERNEL__
-#include <linux/thread_info.h>
-#endif
-
 #include <linux/unistd.h>
 
 #define __NR_seccomp_read __NR_read
index 5af4e9b2dbe2c6dcdde0213809f0d74673e19252..73cb6a3229ae40f3da6a5b080f8757f486325872 100644 (file)
@@ -367,27 +367,24 @@ static int emulate_multiple(struct pt_regs *regs, unsigned char __user *addr,
 static int emulate_fp_pair(unsigned char __user *addr, unsigned int reg,
                           unsigned int flags)
 {
-       char *ptr = (char *) &current->thread.TS_FPR(reg);
-       int i, ret;
+       char *ptr0 = (char *) &current->thread.TS_FPR(reg);
+       char *ptr1 = (char *) &current->thread.TS_FPR(reg+1);
+       int i, ret, sw = 0;
 
        if (!(flags & F))
                return 0;
        if (reg & 1)
                return 0;       /* invalid form: FRS/FRT must be even */
-       if (!(flags & SW)) {
-               /* not byte-swapped - easy */
-               if (!(flags & ST))
-                       ret = __copy_from_user(ptr, addr, 16);
-               else
-                       ret = __copy_to_user(addr, ptr, 16);
-       } else {
-               /* each FPR value is byte-swapped separately */
-               ret = 0;
-               for (i = 0; i < 16; ++i) {
-                       if (!(flags & ST))
-                               ret |= __get_user(ptr[i^7], addr + i);
-                       else
-                               ret |= __put_user(ptr[i^7], addr + i);
+       if (flags & SW)
+               sw = 7;
+       ret = 0;
+       for (i = 0; i < 8; ++i) {
+               if (!(flags & ST)) {
+                       ret |= __get_user(ptr0[i^sw], addr + i);
+                       ret |= __get_user(ptr1[i^sw], addr + i + 8);
+               } else {
+                       ret |= __put_user(ptr0[i^sw], addr + i);
+                       ret |= __put_user(ptr1[i^sw], addr + i + 8);
                }
        }
        if (ret)
@@ -646,11 +643,16 @@ static int emulate_vsx(unsigned char __user *addr, unsigned int reg,
                       unsigned int areg, struct pt_regs *regs,
                       unsigned int flags, unsigned int length)
 {
-       char *ptr = (char *) &current->thread.TS_FPR(reg);
+       char *ptr;
        int ret = 0;
 
        flush_vsx_to_thread(current);
 
+       if (reg < 32)
+               ptr = (char *) &current->thread.TS_FPR(reg);
+       else
+               ptr = (char *) &current->thread.vr[reg - 32];
+
        if (flags & ST)
                ret = __copy_to_user(addr, ptr, length);
         else {
index 2822c8ccfaaf3ae036d6ce8da0fc16b4cf7c12a7..5f81256287f5967d1480e7abbbac2fbcab40ac9c 100644 (file)
@@ -125,6 +125,10 @@ static void kvmppc_free_vcpus(struct kvm *kvm)
        }
 }
 
+void kvm_arch_sync_events(struct kvm *kvm)
+{
+}
+
 void kvm_arch_destroy_vm(struct kvm *kvm)
 {
        kvmppc_free_vcpus(kvm);
index 70693a5c12a113d36d55a0dd1800a255589e73a0..693b14a778fa152f4c595b22e30ca52bc724bee5 100644 (file)
@@ -62,18 +62,19 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
 72:    std     r8,8(r3)
        beq+    3f
        addi    r3,r3,16
-23:    ld      r9,8(r4)
 .Ldo_tail:
        bf      cr7*4+1,1f
-       rotldi  r9,r9,32
+23:    lwz     r9,8(r4)
+       addi    r4,r4,4
 73:    stw     r9,0(r3)
        addi    r3,r3,4
 1:     bf      cr7*4+2,2f
-       rotldi  r9,r9,16
+44:    lhz     r9,8(r4)
+       addi    r4,r4,2
 74:    sth     r9,0(r3)
        addi    r3,r3,2
 2:     bf      cr7*4+3,3f
-       rotldi  r9,r9,8
+45:    lbz     r9,8(r4)
 75:    stb     r9,0(r3)
 3:     li      r3,0
        blr
@@ -141,11 +142,24 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
 6:     cmpwi   cr1,r5,8
        addi    r3,r3,32
        sld     r9,r9,r10
-       ble     cr1,.Ldo_tail
+       ble     cr1,7f
 34:    ld      r0,8(r4)
        srd     r7,r0,r11
        or      r9,r7,r9
-       b       .Ldo_tail
+7:
+       bf      cr7*4+1,1f
+       rotldi  r9,r9,32
+94:    stw     r9,0(r3)
+       addi    r3,r3,4
+1:     bf      cr7*4+2,2f
+       rotldi  r9,r9,16
+95:    sth     r9,0(r3)
+       addi    r3,r3,2
+2:     bf      cr7*4+3,3f
+       rotldi  r9,r9,8
+96:    stb     r9,0(r3)
+3:     li      r3,0
+       blr
 
 .Ldst_unaligned:
        PPC_MTOCRF      0x01,r6         /* put #bytes to 8B bdry into cr7 */
@@ -218,7 +232,6 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
 121:
 132:
        addi    r3,r3,8
-123:
 134:
 135:
 138:
@@ -226,6 +239,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
 140:
 141:
 142:
+123:
+144:
+145:
 
 /*
  * here we have had a fault on a load and r3 points to the first
@@ -309,6 +325,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
 187:
 188:
 189:   
+194:
+195:
+196:
 1:
        ld      r6,-24(r1)
        ld      r5,-8(r1)
@@ -329,7 +348,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
        .llong  72b,172b
        .llong  23b,123b
        .llong  73b,173b
+       .llong  44b,144b
        .llong  74b,174b
+       .llong  45b,145b
        .llong  75b,175b
        .llong  24b,124b
        .llong  25b,125b
@@ -347,6 +368,9 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
        .llong  79b,179b
        .llong  80b,180b
        .llong  34b,134b
+       .llong  94b,194b
+       .llong  95b,195b
+       .llong  96b,196b
        .llong  35b,135b
        .llong  81b,181b
        .llong  36b,136b
index fe2d34e5332d8250dd778ca77489631e2a4e9266..e178922b2c2129e808a427464ce8fccc34643309 100644 (file)
@@ -53,18 +53,19 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
 3:     std     r8,8(r3)
        beq     3f
        addi    r3,r3,16
-       ld      r9,8(r4)
 .Ldo_tail:
        bf      cr7*4+1,1f
-       rotldi  r9,r9,32
+       lwz     r9,8(r4)
+       addi    r4,r4,4
        stw     r9,0(r3)
        addi    r3,r3,4
 1:     bf      cr7*4+2,2f
-       rotldi  r9,r9,16
+       lhz     r9,8(r4)
+       addi    r4,r4,2
        sth     r9,0(r3)
        addi    r3,r3,2
 2:     bf      cr7*4+3,3f
-       rotldi  r9,r9,8
+       lbz     r9,8(r4)
        stb     r9,0(r3)
 3:     ld      r3,48(r1)       /* return dest pointer */
        blr
@@ -133,11 +134,24 @@ END_FTR_SECTION_IFCLR(CPU_FTR_UNALIGNED_LD_STD)
        cmpwi   cr1,r5,8
        addi    r3,r3,32
        sld     r9,r9,r10
-       ble     cr1,.Ldo_tail
+       ble     cr1,6f
        ld      r0,8(r4)
        srd     r7,r0,r11
        or      r9,r7,r9
-       b       .Ldo_tail
+6:
+       bf      cr7*4+1,1f
+       rotldi  r9,r9,32
+       stw     r9,0(r3)
+       addi    r3,r3,4
+1:     bf      cr7*4+2,2f
+       rotldi  r9,r9,16
+       sth     r9,0(r3)
+       addi    r3,r3,2
+2:     bf      cr7*4+3,3f
+       rotldi  r9,r9,8
+       stb     r9,0(r3)
+3:     ld      r3,48(r1)       /* return dest pointer */
+       blr
 
 .Ldst_unaligned:
        PPC_MTOCRF      0x01,r6         # put #bytes to 8B bdry into cr7
index 7393bd76d698406f85a70b423113c8e163afacae..5ac08b8ab654f50391ebc8087c57a2b84c48aa52 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/notifier.h>
 #include <linux/lmb.h>
 #include <linux/of.h>
+#include <linux/pfn.h>
 #include <asm/sparsemem.h>
 #include <asm/prom.h>
 #include <asm/system.h>
@@ -882,7 +883,7 @@ static void mark_reserved_regions_for_nid(int nid)
                unsigned long physbase = lmb.reserved.region[i].base;
                unsigned long size = lmb.reserved.region[i].size;
                unsigned long start_pfn = physbase >> PAGE_SHIFT;
-               unsigned long end_pfn = ((physbase + size) >> PAGE_SHIFT);
+               unsigned long end_pfn = PFN_UP(physbase + size);
                struct node_active_region node_ar;
                unsigned long node_end_pfn = node->node_start_pfn +
                                             node->node_spanned_pages;
@@ -908,7 +909,7 @@ static void mark_reserved_regions_for_nid(int nid)
                         */
                        if (end_pfn > node_ar.end_pfn)
                                reserve_size = (node_ar.end_pfn << PAGE_SHIFT)
-                                       - (start_pfn << PAGE_SHIFT);
+                                       - physbase;
                        /*
                         * Only worry about *this* node, others may not
                         * yet have valid NODE_DATA().
index fb371f5ce132c657ab910824d6d4c998b59c574d..d6b772ba3b8f8238ea3ecd5d27c2b77843b9dcda 100644 (file)
@@ -142,6 +142,10 @@ static void __init gef_sbc610_nec_fixup(struct pci_dev *pdev)
 {
        unsigned int val;
 
+       /* Do not do the fixup on other platforms! */
+       if (!machine_is(gef_sbc610))
+               return;
+
        printk(KERN_INFO "Running NEC uPD720101 Fixup\n");
 
        /* Ensure ports 1, 2, 3, 4 & 5 are enabled */
index 67de6bf3db3d243a6d542dec9b9028d7f9fcf111..d281cc0bca712fd24553ca34b9477d5c8e47b68e 100644 (file)
@@ -328,7 +328,7 @@ static int __init ps3_mm_add_memory(void)
        return result;
 }
 
-core_initcall(ps3_mm_add_memory);
+device_initcall(ps3_mm_add_memory);
 
 /*============================================================================*/
 /* dma routines                                                               */
index 77fae5f64f2e0741ff6900135f9337cfac6093b0..5558d932b4d5c87b84f5a3826577607fa5220514 100644 (file)
@@ -204,6 +204,23 @@ static int __init ppc4xx_setup_one_pci_PMM(struct pci_controller   *hose,
 {
        u32 ma, pcila, pciha;
 
+       /* Hack warning ! The "old" PCI 2.x cell only let us configure the low
+        * 32-bit of incoming PLB addresses. The top 4 bits of the 36-bit
+        * address are actually hard wired to a value that appears to depend
+        * on the specific SoC. For example, it's 0 on 440EP and 1 on 440EPx.
+        *
+        * The trick here is we just crop those top bits and ignore them when
+        * programming the chip. That means the device-tree has to be right
+        * for the specific part used (we don't print a warning if it's wrong
+        * but on the other hand, you'll crash quickly enough), but at least
+        * this code should work whatever the hard coded value is
+        */
+       plb_addr &= 0xffffffffull;
+
+       /* Note: Due to the above hack, the test below doesn't actually test
+        * if you address is above 4G, but it tests that address and
+        * (address + size) are both contained in the same 4G
+        */
        if ((plb_addr + size) > 0xffffffffull || !is_power_of_2(size) ||
            size < 0x1000 || (plb_addr & (size - 1)) != 0) {
                printk(KERN_WARNING "%s: Resource out of range\n",
index c42cd898f68bfdece3e98706e44ab048abe61038..6118890c946d89244e587cdc880726a1d7893073 100644 (file)
@@ -556,7 +556,7 @@ static void __exit aes_s390_fini(void)
 module_init(aes_s390_init);
 module_exit(aes_s390_fini);
 
-MODULE_ALIAS("aes");
+MODULE_ALIAS("aes-all");
 
 MODULE_DESCRIPTION("Rijndael (AES) Cipher Algorithm");
 MODULE_LICENSE("GPL");
index 521726430afac81fcb19e870e4765a44fa85e528..95b0f7db3c69dcb076c7969ceacba1f5ab2f82b0 100644 (file)
@@ -145,7 +145,7 @@ cputime_to_timeval(const cputime_t cputime, struct timeval *value)
        value->tv_usec = rp.subreg.even / 4096;
        value->tv_sec = rp.subreg.odd;
 #else
-       value->tv_usec = cputime % 4096000000ULL;
+       value->tv_usec = (cputime % 4096000000ULL) / 4096;
        value->tv_sec = cputime / 4096000000ULL;
 #endif
 }
index 2bd9faeb3919a0a3b7fae325769c3042db144d44..e8bd6ac22c996e40378654d7bdad1b9824ac826f 100644 (file)
@@ -43,6 +43,8 @@ struct mem_chunk {
 
 extern struct mem_chunk memory_chunk[];
 extern unsigned long real_memory_size;
+extern int memory_end_set;
+extern unsigned long memory_end;
 
 void detect_memory_layout(struct mem_chunk chunk[]);
 
index d825f4950e4e2f721e89de76fc98fe3dad91971b..c5cfb6185eaca51eb5e9ee3667d1c4d06ee22a52 100644 (file)
@@ -82,7 +82,9 @@ char elf_platform[ELF_PLATFORM_SIZE];
 
 struct mem_chunk __initdata memory_chunk[MEMORY_CHUNKS];
 volatile int __cpu_logical_map[NR_CPUS]; /* logical cpu to cpu address */
-static unsigned long __initdata memory_end;
+
+int __initdata memory_end_set;
+unsigned long __initdata memory_end;
 
 /*
  * This is set up by the setup-routine at boot-time
@@ -281,6 +283,7 @@ void (*pm_power_off)(void) = machine_power_off;
 static int __init early_parse_mem(char *p)
 {
        memory_end = memparse(p, &p);
+       memory_end_set = 1;
        return 0;
 }
 early_param("mem", early_parse_mem);
@@ -508,8 +511,10 @@ static void __init setup_memory_end(void)
        int i;
 
 #if defined(CONFIG_ZFCPDUMP) || defined(CONFIG_ZFCPDUMP_MODULE)
-       if (ipl_info.type == IPL_TYPE_FCP_DUMP)
+       if (ipl_info.type == IPL_TYPE_FCP_DUMP) {
                memory_end = ZFCPDUMP_HSA_SIZE;
+               memory_end_set = 1;
+       }
 #endif
        memory_size = 0;
        memory_end &= PAGE_MASK;
index be8497186b96d86472f1ae692c9c74e7c88515f4..0d33893e1e898448c05b7ec2573904a81850180b 100644 (file)
@@ -212,6 +212,10 @@ static void kvm_free_vcpus(struct kvm *kvm)
        }
 }
 
+void kvm_arch_sync_events(struct kvm *kvm)
+{
+}
+
 void kvm_arch_destroy_vm(struct kvm *kvm)
 {
        kvm_free_vcpus(kvm);
index 7c35787d29b45b22a41c58bb57491137df7f4db4..72da416f6162bbd10d022f5452708ec48d42910a 100644 (file)
@@ -22,7 +22,6 @@
 #include <linux/gpio.h>
 #include <linux/spi/spi.h>
 #include <linux/spi/spi_gpio.h>
-#include <media/ov772x.h>
 #include <media/soc_camera_platform.h>
 #include <media/sh_mobile_ceu.h>
 #include <video/sh_mobile_lcdc.h>
@@ -224,7 +223,6 @@ static void camera_power(int val)
 }
 
 #ifdef CONFIG_I2C
-/* support for the old ncm03j camera */
 static unsigned char camera_ncm03j_magic[] =
 {
        0x87, 0x00, 0x88, 0x08, 0x89, 0x01, 0x8A, 0xE8,
@@ -245,23 +243,6 @@ static unsigned char camera_ncm03j_magic[] =
        0x63, 0xD4, 0x64, 0xEA, 0xD6, 0x0F,
 };
 
-static int camera_probe(void)
-{
-       struct i2c_adapter *a = i2c_get_adapter(0);
-       struct i2c_msg msg;
-       int ret;
-
-       camera_power(1);
-       msg.addr = 0x6e;
-       msg.buf = camera_ncm03j_magic;
-       msg.len = 2;
-       msg.flags = 0;
-       ret = i2c_transfer(a, &msg, 1);
-       camera_power(0);
-
-       return ret;
-}
-
 static int camera_set_capture(struct soc_camera_platform_info *info,
                              int enable)
 {
@@ -313,35 +294,8 @@ static struct platform_device camera_device = {
                .platform_data  = &camera_info,
        },
 };
-
-static int __init camera_setup(void)
-{
-       if (camera_probe() > 0)
-               platform_device_register(&camera_device);
-
-       return 0;
-}
-late_initcall(camera_setup);
-
 #endif /* CONFIG_I2C */
 
-static int ov7725_power(struct device *dev, int mode)
-{
-       camera_power(0);
-       if (mode)
-               camera_power(1);
-
-       return 0;
-}
-
-static struct ov772x_camera_info ov7725_info = {
-       .buswidth  = SOCAM_DATAWIDTH_8,
-       .flags = OV772X_FLAG_VFLIP | OV772X_FLAG_HFLIP,
-       .link = {
-               .power  = ov7725_power,
-       },
-};
-
 static struct sh_mobile_ceu_info sh_mobile_ceu_info = {
        .flags = SOCAM_PCLK_SAMPLE_RISING | SOCAM_HSYNC_ACTIVE_HIGH |
        SOCAM_VSYNC_ACTIVE_HIGH | SOCAM_MASTER | SOCAM_DATAWIDTH_8,
@@ -392,6 +346,9 @@ static struct platform_device *ap325rxa_devices[] __initdata = {
        &ap325rxa_nor_flash_device,
        &lcdc_device,
        &ceu_device,
+#ifdef CONFIG_I2C
+       &camera_device,
+#endif
        &nand_flash_device,
        &sdcard_cn3_device,
 };
@@ -400,10 +357,6 @@ static struct i2c_board_info __initdata ap325rxa_i2c_devices[] = {
        {
                I2C_BOARD_INFO("pcf8563", 0x51),
        },
-       {
-               I2C_BOARD_INFO("ov772x", 0x21),
-               .platform_data = &ov7725_info,
-       },
 };
 
 static struct spi_board_info ap325rxa_spi_devices[] = {
index 020a96fe961a0b1cfa682cd919b22ab4f3af92cf..4a5e59732334ca70782a167c5eccaf4e133b9ffd 100644 (file)
@@ -18,8 +18,8 @@
 #include <asm/freq.h>
 #include <asm/io.h>
 
-const static int pll1rate[]={1,2,3,4,6,8};
-const static int pfc_divisors[]={1,2,3,4,6,8,12};
+static const int pll1rate[]={1,2,3,4,6,8};
+static const int pfc_divisors[]={1,2,3,4,6,8,12};
 #define ifc_divisors pfc_divisors
 
 #if (CONFIG_SH_CLK_MD == 0)
index f260b58f5ce9d34ac224d2781bf4e0ac277849d4..0e706257918f35397b10657be3b95538ef23e45b 100644 (file)
@@ -240,4 +240,9 @@ struct compat_shmid64_ds {
        unsigned int    __unused2;
 };
 
+static inline int is_compat_task(void)
+{
+       return test_thread_flag(TIF_32BIT);
+}
+
 #endif /* _ASM_SPARC64_COMPAT_H */
index 7fcd9968192bc0b26b1fe7d1c67a1e3f08b5359c..adca1bce41d4a2b96632a1dfdcdab457df916bf1 100644 (file)
@@ -1,11 +1,5 @@
 #ifndef _ASM_SECCOMP_H
 
-#include <linux/thread_info.h> /* already defines TIF_32BIT */
-
-#ifndef TIF_32BIT
-#error "unexpected TIF_32BIT on sparc64"
-#endif
-
 #include <linux/unistd.h>
 
 #define __NR_seccomp_read __NR_read
index 3b9f4d6e14a9d3119a939e7b5edfc3aec30c554b..e1a9598e2a4db8b0c0cc36aca1c7ac5addb1dbc5 100644 (file)
@@ -306,6 +306,7 @@ static int jbusmc_print_dimm(int syndrome_code,
                buf[1] = '?';
                buf[2] = '?';
                buf[3] = '\0';
+               return 0;
        }
        p = dp->controller;
        prop = &p->layout;
index 56533db25343129bcd60c152744966a2b84241cc..c5c43253e6ce4994778205e1853e2026f19a0cae 100644 (file)
@@ -78,7 +78,7 @@ void vde_init_libstuff(struct vde_data *vpri, struct vde_init *init)
 {
        struct vde_open_args *args;
 
-       vpri->args = kmalloc(sizeof(struct vde_open_args), UM_GFP_KERNEL);
+       vpri->args = uml_kmalloc(sizeof(struct vde_open_args), UM_GFP_KERNEL);
        if (vpri->args == NULL) {
                printk(UM_KERN_ERR "vde_init_libstuff - vde_open_args "
                       "allocation failed");
@@ -91,8 +91,8 @@ void vde_init_libstuff(struct vde_data *vpri, struct vde_init *init)
        args->group = init->group;
        args->mode = init->mode ? init->mode : 0700;
 
-       args->port ?  printk(UM_KERN_INFO "port %d", args->port) :
-               printk(UM_KERN_INFO "undefined port");
+       args->port ?  printk("port %d", args->port) :
+               printk("undefined port");
 }
 
 int vde_user_read(void *conn, void *buf, int len)
index 9c39095b33fc0d1dbdc7f92408314dae1ed38e87..bc2fbadff9f90fe681d9c30ae621d1ec94e348cf 100644 (file)
@@ -1803,7 +1803,7 @@ config DMAR
          remapping devices.
 
 config DMAR_DEFAULT_ON
-       def_bool n
+       def_bool y
        prompt "Enable DMA Remapping Devices by default"
        depends on DMAR
        help
index 10d6cc3fd052fd56c6817f2736e78a113bfa1046..e1983fa025d2a941f86c5ac6dc4012fc3b1d4e71 100644 (file)
@@ -174,28 +174,8 @@ config IOMMU_LEAK
          Add a simple leak tracer to the IOMMU code. This is useful when you
          are debugging a buggy device driver that leaks IOMMU mappings.
 
-config MMIOTRACE
-       bool "Memory mapped IO tracing"
-       depends on DEBUG_KERNEL && PCI
-       select TRACING
-       help
-         Mmiotrace traces Memory Mapped I/O access and is meant for
-         debugging and reverse engineering. It is called from the ioremap
-         implementation and works via page faults. Tracing is disabled by
-         default and can be enabled at run-time.
-
-         See Documentation/tracers/mmiotrace.txt.
-         If you are not helping to develop drivers, say N.
-
-config MMIOTRACE_TEST
-       tristate "Test module for mmiotrace"
-       depends on MMIOTRACE && m
-       help
-         This is a dumb module for testing mmiotrace. It is very dangerous
-         as it will write garbage to IO memory starting at a given address.
-         However, it should be safe to use on e.g. unused portion of VRAM.
-
-         Say N, unless you absolutely know what you are doing.
+config HAVE_MMIOTRACE_SUPPORT
+       def_bool y
 
 #
 # IO delay types:
index c1f06289b14b31b82834fa623c7ac744a7aa55be..86af26091d6c3c2146da4e5f6f3abbfd6cb165ba 100644 (file)
@@ -23,6 +23,9 @@
 #include <asm/pgtable.h>
 #include <asm/tlbflush.h>
 
+int
+is_io_mapping_possible(resource_size_t base, unsigned long size);
+
 void *
 iomap_atomic_prot_pfn(unsigned long pfn, enum km_type type, pgprot_t prot);
 
index d2e3bf3608af549cb544fddc17c590c139c80733..886c9402ec4583fd94fc9f6eb44aa8bda088ab3a 100644 (file)
@@ -9,6 +9,13 @@
 #include <linux/types.h>
 #include <linux/ioctl.h>
 
+/* Select x86 specific features in <linux/kvm.h> */
+#define __KVM_HAVE_PIT
+#define __KVM_HAVE_IOAPIC
+#define __KVM_HAVE_DEVICE_ASSIGNMENT
+#define __KVM_HAVE_MSI
+#define __KVM_HAVE_USER_NMI
+
 /* Architectural interrupt line count. */
 #define KVM_NR_INTERRUPTS 256
 
index 07f1af494ca5c011801c9260a088d2dd34a4ae8e..105fb90a063527d761ed47350d553ecb755bd3cb 100644 (file)
@@ -32,8 +32,6 @@ static inline void get_memcfg_numa(void)
        get_memcfg_numa_flat();
 }
 
-extern int early_pfn_to_nid(unsigned long pfn);
-
 extern void resume_map_numa_kva(pgd_t *pgd);
 
 #else /* !CONFIG_NUMA */
index a5b3817d4b9e621e2615ddd16435b83011206548..a29f48c2a3229fc5a8a23599fdf51bcfb94c3dea 100644 (file)
@@ -40,8 +40,6 @@ static inline __attribute__((pure)) int phys_to_nid(unsigned long addr)
 #define node_end_pfn(nid)       (NODE_DATA(nid)->node_start_pfn +      \
                                 NODE_DATA(nid)->node_spanned_pages)
 
-extern int early_pfn_to_nid(unsigned long pfn);
-
 #ifdef CONFIG_NUMA_EMU
 #define FAKE_NODE_MIN_SIZE     (64 * 1024 * 1024)
 #define FAKE_NODE_MIN_HASH_MASK        (~(FAKE_NODE_MIN_SIZE - 1UL))
index e9873a2e86951d10c7a5576e3b908956d0e3e6f8..776579119a009feb1b2854a9ea18a68183d63243 100644 (file)
@@ -57,7 +57,6 @@ typedef struct { pgdval_t pgd; } pgd_t;
 typedef struct { pgprotval_t pgprot; } pgprot_t;
 
 extern int page_is_ram(unsigned long pagenr);
-extern int pagerange_is_ram(unsigned long start, unsigned long end);
 extern int devmem_is_allowed(unsigned long pagenr);
 extern void map_devmem(unsigned long pfn, unsigned long size,
                       pgprot_t vma_prot);
index c09a1412758431271633f1af7793d708d59a24f2..e299287e8e3396d95b3169c5a9e9a1086e662a1a 100644 (file)
@@ -1352,14 +1352,7 @@ static inline void arch_leave_lazy_cpu_mode(void)
        PVOP_VCALL0(pv_cpu_ops.lazy_mode.leave);
 }
 
-static inline void arch_flush_lazy_cpu_mode(void)
-{
-       if (unlikely(paravirt_get_lazy_mode() == PARAVIRT_LAZY_CPU)) {
-               arch_leave_lazy_cpu_mode();
-               arch_enter_lazy_cpu_mode();
-       }
-}
-
+void arch_flush_lazy_cpu_mode(void);
 
 #define  __HAVE_ARCH_ENTER_LAZY_MMU_MODE
 static inline void arch_enter_lazy_mmu_mode(void)
@@ -1372,13 +1365,7 @@ static inline void arch_leave_lazy_mmu_mode(void)
        PVOP_VCALL0(pv_mmu_ops.lazy_mode.leave);
 }
 
-static inline void arch_flush_lazy_mmu_mode(void)
-{
-       if (unlikely(paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU)) {
-               arch_leave_lazy_mmu_mode();
-               arch_enter_lazy_mmu_mode();
-       }
-}
+void arch_flush_lazy_mmu_mode(void);
 
 static inline void __set_fixmap(unsigned /* enum fixed_addresses */ idx,
                                unsigned long phys, pgprot_t flags)
index a6ad87b352c448e8b1f2c2b3e3dd9591fe593248..b811d6f5780cd261a8e33a7799d3bd50aa46015b 100644 (file)
@@ -1,12 +1,6 @@
 #ifndef _ASM_X86_SECCOMP_32_H
 #define _ASM_X86_SECCOMP_32_H
 
-#include <linux/thread_info.h>
-
-#ifdef TIF_32BIT
-#error "unexpected TIF_32BIT on i386"
-#endif
-
 #include <linux/unistd.h>
 
 #define __NR_seccomp_read __NR_read
index 4171bb794e9e736bbfcb60588a4e9d81d1edcb31..84ec1bd161a5839bdce90c4f8ed80f53bd45f03e 100644 (file)
@@ -1,14 +1,6 @@
 #ifndef _ASM_X86_SECCOMP_64_H
 #define _ASM_X86_SECCOMP_64_H
 
-#include <linux/thread_info.h>
-
-#ifdef TIF_32BIT
-#error "unexpected TIF_32BIT on x86_64"
-#else
-#define TIF_32BIT TIF_IA32
-#endif
-
 #include <linux/unistd.h>
 #include <asm/ia32_unistd.h>
 
index bcc293423a7026cb28e8c659b693d464a8cfe28e..96258d9dc9743c094e0d42af3ff6201d960a6abb 100644 (file)
@@ -13,7 +13,6 @@
         * Hooray, we are in Long 64-bit mode (but still running in low memory)
         */
 ENTRY(wakeup_long64)
-wakeup_long64:
        movq    saved_magic, %rax
        movq    $0x123456789abcdef0, %rdx
        cmpq    %rdx, %rax
@@ -34,16 +33,12 @@ wakeup_long64:
 
        movq    saved_rip, %rax
        jmp     *%rax
+ENDPROC(wakeup_long64)
 
 bogus_64_magic:
        jmp     bogus_64_magic
 
-       .align 2
-       .p2align 4,,15
-.globl do_suspend_lowlevel
-       .type   do_suspend_lowlevel,@function
-do_suspend_lowlevel:
-.LFB5:
+ENTRY(do_suspend_lowlevel)
        subq    $8, %rsp
        xorl    %eax, %eax
        call    save_processor_state
@@ -67,7 +62,7 @@ do_suspend_lowlevel:
        pushfq
        popq    pt_regs_flags(%rax)
 
-       movq    $.L97, saved_rip(%rip)
+       movq    $resume_point, saved_rip(%rip)
 
        movq    %rsp, saved_rsp
        movq    %rbp, saved_rbp
@@ -78,14 +73,12 @@ do_suspend_lowlevel:
        addq    $8, %rsp
        movl    $3, %edi
        xorl    %eax, %eax
-       jmp     acpi_enter_sleep_state
-.L97:
-       .p2align 4,,7
-.L99:
-       .align 4
-       movl    $24, %eax
-       movw    %ax, %ds
+       call    acpi_enter_sleep_state
+       /* in case something went wrong, restore the machine status and go on */
+       jmp     resume_point
 
+       .align 4
+resume_point:
        /* We don't restore %rax, it must be 0 anyway */
        movq    $saved_context, %rax
        movq    saved_context_cr4(%rax), %rbx
@@ -117,12 +110,9 @@ do_suspend_lowlevel:
        xorl    %eax, %eax
        addq    $8, %rsp
        jmp     restore_processor_state
-.LFE5:
-.Lfe5:
-       .size   do_suspend_lowlevel, .Lfe5-do_suspend_lowlevel
-       
+ENDPROC(do_suspend_lowlevel)
+
 .data
-ALIGN
 ENTRY(saved_rbp)       .quad   0
 ENTRY(saved_rsi)       .quad   0
 ENTRY(saved_rdi)       .quad   0
index 115449f869ee368f567cfd38bc8605a47944078c..570f36e44e59671d7bdc0722a2370f1e8633fbe4 100644 (file)
@@ -862,7 +862,7 @@ void clear_local_APIC(void)
        }
 
        /* lets not touch this if we didn't frob it */
-#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(X86_MCE_INTEL)
+#if defined(CONFIG_X86_MCE_P4THERMAL) || defined(CONFIG_X86_MCE_INTEL)
        if (maxlvt >= 5) {
                v = apic_read(APIC_LVTTHMR);
                apic_write(APIC_LVTTHMR, v | APIC_LVT_MASKED);
index 98807bb095adadf6e03003beffff4c640161f33a..266ec6c18b6c6b9aea5696d796c7dc565105286b 100644 (file)
@@ -1192,6 +1192,7 @@ static int suspend(int vetoable)
        device_suspend(PMSG_SUSPEND);
        local_irq_disable();
        device_power_down(PMSG_SUSPEND);
+       sysdev_suspend(PMSG_SUSPEND);
 
        local_irq_enable();
 
@@ -1208,6 +1209,7 @@ static int suspend(int vetoable)
        if (err != APM_SUCCESS)
                apm_error("suspend", err);
        err = (err == APM_SUCCESS) ? 0 : -EIO;
+       sysdev_resume();
        device_power_up(PMSG_RESUME);
        local_irq_enable();
        device_resume(PMSG_RESUME);
@@ -1228,6 +1230,7 @@ static void standby(void)
 
        local_irq_disable();
        device_power_down(PMSG_SUSPEND);
+       sysdev_suspend(PMSG_SUSPEND);
        local_irq_enable();
 
        err = set_system_power_state(APM_STATE_STANDBY);
@@ -1235,6 +1238,7 @@ static void standby(void)
                apm_error("standby", err);
 
        local_irq_disable();
+       sysdev_resume();
        device_power_up(PMSG_RESUME);
        local_irq_enable();
 }
index fb039cd345d861ce97e8b7585dc4f399483f8a13..6428aa17b40e794683b5359ed0589dc3dbfbf592 100644 (file)
@@ -1157,8 +1157,7 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
        data->cpu = pol->cpu;
        data->currpstate = HW_PSTATE_INVALID;
 
-       rc = powernow_k8_cpu_init_acpi(data);
-       if (rc) {
+       if (powernow_k8_cpu_init_acpi(data)) {
                /*
                 * Use the PSB BIOS structure. This is only availabe on
                 * an UP version, and is deprecated by AMD.
@@ -1176,17 +1175,20 @@ static int __cpuinit powernowk8_cpu_init(struct cpufreq_policy *pol)
                               "ACPI maintainers and complain to your BIOS "
                               "vendor.\n");
 #endif
-                       goto err_out;
+                       kfree(data);
+                       return -ENODEV;
                }
                if (pol->cpu != 0) {
                        printk(KERN_ERR FW_BUG PFX "No ACPI _PSS objects for "
                               "CPU other than CPU0. Complain to your BIOS "
                               "vendor.\n");
-                       goto err_out;
+                       kfree(data);
+                       return -ENODEV;
                }
                rc = find_psb_table(data);
                if (rc) {
-                       goto err_out;
+                       kfree(data);
+                       return -ENODEV;
                }
                /* Take a crude guess here.
                 * That guess was in microseconds, so multiply with 1000 */
index 1c838032fd3732fde9bff776cbb63a2821115d60..fe79985ce0f2f6fb4ae23f3bc92a791994ed9f62 100644 (file)
@@ -295,11 +295,11 @@ void do_machine_check(struct pt_regs * regs, long error_code)
                 * If we know that the error was in user space, send a
                 * SIGBUS.  Otherwise, panic if tolerance is low.
                 *
-                * do_exit() takes an awful lot of locks and has a slight
+                * force_sig() takes an awful lot of locks and has a slight
                 * risk of deadlocking.
                 */
                if (user_space) {
-                       do_exit(SIGBUS);
+                       force_sig(SIGBUS, current);
                } else if (panic_on_oops || tolerant < 2) {
                        mce_panic("Uncorrected machine check",
                                &panicm, mcestart);
@@ -490,7 +490,7 @@ static void __cpuinit mce_cpu_quirks(struct cpuinfo_x86 *c)
 
 }
 
-static void __cpuinit mce_cpu_features(struct cpuinfo_x86 *c)
+static void mce_cpu_features(struct cpuinfo_x86 *c)
 {
        switch (c->x86_vendor) {
        case X86_VENDOR_INTEL:
@@ -734,6 +734,7 @@ __setup("mce=", mcheck_enable);
 static int mce_resume(struct sys_device *dev)
 {
        mce_init(NULL);
+       mce_cpu_features(&current_cpu_data);
        return 0;
 }
 
index 8ae8c4ff094d1910ad77ca398192b4f362731e59..f2ee0ae29bd6e00b7755ab0573deae02e17ae592 100644 (file)
@@ -121,7 +121,7 @@ static long threshold_restart_bank(void *_tr)
 }
 
 /* cpu init entry point, called from mce.c with preempt off */
-void __cpuinit mce_amd_feature_init(struct cpuinfo_x86 *c)
+void mce_amd_feature_init(struct cpuinfo_x86 *c)
 {
        unsigned int bank, block;
        unsigned int cpu = smp_processor_id();
index 4b48f251fd39ed540f99a2c91b6e7d66d93e1b56..f44c366243602b594566147a8447bfaa3d641013 100644 (file)
@@ -30,7 +30,7 @@ asmlinkage void smp_thermal_interrupt(void)
        irq_exit();
 }
 
-static void __cpuinit intel_init_thermal(struct cpuinfo_x86 *c)
+static void intel_init_thermal(struct cpuinfo_x86 *c)
 {
        u32 l, h;
        int tm2 = 0;
@@ -84,7 +84,7 @@ static void __cpuinit intel_init_thermal(struct cpuinfo_x86 *c)
        return;
 }
 
-void __cpuinit mce_intel_feature_init(struct cpuinfo_x86 *c)
+void mce_intel_feature_init(struct cpuinfo_x86 *c)
 {
        intel_init_thermal(c);
 }
index 388254f69a2ad13721f87797d7aa7790126655df..a00545fe5cdd1dae730fe18031b631bd1f57d8d5 100644 (file)
@@ -269,6 +269,8 @@ static void hpet_set_mode(enum clock_event_mode mode,
                now = hpet_readl(HPET_COUNTER);
                cmp = now + (unsigned long) delta;
                cfg = hpet_readl(HPET_Tn_CFG(timer));
+               /* Make sure we use edge triggered interrupts */
+               cfg &= ~HPET_TN_LEVEL;
                cfg |= HPET_TN_ENABLE | HPET_TN_PERIODIC |
                       HPET_TN_SETVAL | HPET_TN_32BIT;
                hpet_writel(cfg, HPET_Tn_CFG(timer));
index 7a13fac63a1f11ccd8cfe2cf72160117a0477cd2..4006c522adc780a0ce016b43b2d5a7ae93ca0f14 100644 (file)
@@ -203,7 +203,7 @@ static void __init platform_detect(void)
 static void __init platform_detect(void)
 {
        /* stopgap until OFW support is added to the kernel */
-       olpc_platform_info.boardrev = 0xc2;
+       olpc_platform_info.boardrev = olpc_board(0xc2);
 }
 #endif
 
index e4c8fb608873797c381f825cc874c5a4e0506e1b..c6520a4e85d4fe3479070d03867bfd65e50dd081 100644 (file)
@@ -268,6 +268,32 @@ enum paravirt_lazy_mode paravirt_get_lazy_mode(void)
        return __get_cpu_var(paravirt_lazy_mode);
 }
 
+void arch_flush_lazy_mmu_mode(void)
+{
+       preempt_disable();
+
+       if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_MMU) {
+               WARN_ON(preempt_count() == 1);
+               arch_leave_lazy_mmu_mode();
+               arch_enter_lazy_mmu_mode();
+       }
+
+       preempt_enable();
+}
+
+void arch_flush_lazy_cpu_mode(void)
+{
+       preempt_disable();
+
+       if (paravirt_get_lazy_mode() == PARAVIRT_LAZY_CPU) {
+               WARN_ON(preempt_count() == 1);
+               arch_leave_lazy_cpu_mode();
+               arch_enter_lazy_cpu_mode();
+       }
+
+       preempt_enable();
+}
+
 struct pv_info pv_info = {
        .name = "bare hardware",
        .paravirt_enabled = 0,
index a546f55c77b4639f5e3f5773a1599d81cc53432d..bd4da2af08aec72ff1933eea7164a2b3d8f73139 100644 (file)
@@ -104,9 +104,6 @@ void cpu_idle(void)
                        check_pgt_cache();
                        rmb();
 
-                       if (rcu_pending(cpu))
-                               rcu_check_callbacks(cpu, 0);
-
                        if (cpu_is_offline(cpu))
                                play_dead();
 
index 0a5df5f82fb9579b1be4e824aa499ac561d9ba10..06ca07f6ad86243884c7852c13334d9da9604acf 100644 (file)
@@ -810,12 +810,16 @@ static void ptrace_bts_untrace(struct task_struct *child)
 
 static void ptrace_bts_detach(struct task_struct *child)
 {
-       if (unlikely(child->bts)) {
-               ds_release_bts(child->bts);
-               child->bts = NULL;
-
-               ptrace_bts_free_buffer(child);
-       }
+       /*
+        * Ptrace_detach() races with ptrace_untrace() in case
+        * the child dies and is reaped by another thread.
+        *
+        * We only do the memory accounting at this point and
+        * leave the buffer deallocation and the bts tracer
+        * release to ptrace_bts_untrace() which will be called
+        * later on with tasklist_lock held.
+        */
+       release_locked_buffer(child->bts_buffer, child->bts_size);
 }
 #else
 static inline void ptrace_bts_fork(struct task_struct *tsk) {}
@@ -1384,7 +1388,7 @@ void send_sigtrap(struct task_struct *tsk, struct pt_regs *regs,
 #ifdef CONFIG_X86_32
 # define IS_IA32       1
 #elif defined CONFIG_IA32_EMULATION
-# define IS_IA32       test_thread_flag(TIF_IA32)
+# define IS_IA32       is_compat_task()
 #else
 # define IS_IA32       0
 #endif
index e6e695acd725739a645b5664f83a8356ff5b13a7..241ec3923f611bf03cb266362409924daabf1f6f 100644 (file)
@@ -115,7 +115,7 @@ unsigned long __init calibrate_cpu(void)
 
 static struct irqaction irq0 = {
        .handler        = timer_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING,
+       .flags          = IRQF_DISABLED | IRQF_IRQPOLL | IRQF_NOBALANCING | IRQF_TIMER,
        .mask           = CPU_MASK_NONE,
        .name           = "timer"
 };
index 7932338d7cb3112c7222121e513db0ca71190fa0..a9e7548e17906f885f28e4763128e749c7a76481 100644 (file)
@@ -99,6 +99,12 @@ static inline void preempt_conditional_sti(struct pt_regs *regs)
                local_irq_enable();
 }
 
+static inline void conditional_cli(struct pt_regs *regs)
+{
+       if (regs->flags & X86_EFLAGS_IF)
+               local_irq_disable();
+}
+
 static inline void preempt_conditional_cli(struct pt_regs *regs)
 {
        if (regs->flags & X86_EFLAGS_IF)
@@ -626,8 +632,10 @@ clear_dr7:
 
 #ifdef CONFIG_X86_32
 debug_vm86:
+       /* reenable preemption: handle_vm86_trap() might sleep */
+       dec_preempt_count();
        handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1);
-       preempt_conditional_cli(regs);
+       conditional_cli(regs);
        return;
 #endif
 
index c4c1f9e094027089373189f7e57cb7ede8149be9..e5b088fffa40f56f1418179efcd89ba480bcae6d 100644 (file)
@@ -202,7 +202,7 @@ static irqreturn_t vmi_timer_interrupt(int irq, void *dev_id)
 static struct irqaction vmi_clock_action  = {
        .name           = "vmi-timer",
        .handler        = vmi_timer_interrupt,
-       .flags          = IRQF_DISABLED | IRQF_NOBALANCING,
+       .flags          = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_TIMER,
        .mask           = CPU_MASK_ALL,
 };
 
@@ -283,10 +283,13 @@ void __devinit vmi_time_ap_init(void)
 #endif
 
 /** vmi clocksource */
+static struct clocksource clocksource_vmi;
 
 static cycle_t read_real_cycles(void)
 {
-       return vmi_timer_ops.get_cycle_counter(VMI_CYCLES_REAL);
+       cycle_t ret = (cycle_t)vmi_timer_ops.get_cycle_counter(VMI_CYCLES_REAL);
+       return ret >= clocksource_vmi.cycle_last ?
+               ret : clocksource_vmi.cycle_last;
 }
 
 static struct clocksource clocksource_vmi = {
index e665d1c623ca04f45444daf5324e6c6d6477612d..72bd275a9b5cee632b393448e325f371610f860b 100644 (file)
@@ -207,7 +207,7 @@ static int __pit_timer_fn(struct kvm_kpit_state *ps)
        hrtimer_add_expires_ns(&pt->timer, pt->period);
        pt->scheduled = hrtimer_get_expires_ns(&pt->timer);
        if (pt->period)
-               ps->channels[0].count_load_time = hrtimer_get_expires(&pt->timer);
+               ps->channels[0].count_load_time = ktime_get();
 
        return (pt->period == 0 ? 0 : 1);
 }
index c019b8edcdb76bab269ceb48f8bc96e02fae7817..cf17ed52f6fbbe33563668604df0fa814f3cf493 100644 (file)
@@ -87,13 +87,6 @@ void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu)
 }
 EXPORT_SYMBOL_GPL(kvm_inject_pending_timer_irqs);
 
-void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec)
-{
-       kvm_apic_timer_intr_post(vcpu, vec);
-       /* TODO: PIT, RTC etc. */
-}
-EXPORT_SYMBOL_GPL(kvm_timer_intr_post);
-
 void __kvm_migrate_timers(struct kvm_vcpu *vcpu)
 {
        __kvm_migrate_apic_timer(vcpu);
index 2bf32a03ceecf5837f6e30ef99b80067423632da..82579ee538d08b257f2a53a230cfb9cbf1a51986 100644 (file)
@@ -89,7 +89,6 @@ static inline int irqchip_in_kernel(struct kvm *kvm)
 
 void kvm_pic_reset(struct kvm_kpic_state *s);
 
-void kvm_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
 void kvm_inject_pending_timer_irqs(struct kvm_vcpu *vcpu);
 void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu);
 void kvm_apic_nmi_wd_deliver(struct kvm_vcpu *vcpu);
index afac68c0815c78e712edc789821029d05b1d2d2f..f0b67f2cdd695a71c636ddfbe45b9ec9248b0748 100644 (file)
 #include "kvm_cache_regs.h"
 #include "irq.h"
 
+#ifndef CONFIG_X86_64
+#define mod_64(x, y) ((x) - (y) * div64_u64(x, y))
+#else
+#define mod_64(x, y) ((x) % (y))
+#endif
+
 #define PRId64 "d"
 #define PRIx64 "llx"
 #define PRIu64 "u"
@@ -511,52 +517,22 @@ static void apic_send_ipi(struct kvm_lapic *apic)
 
 static u32 apic_get_tmcct(struct kvm_lapic *apic)
 {
-       u64 counter_passed;
-       ktime_t passed, now;
+       ktime_t remaining;
+       s64 ns;
        u32 tmcct;
 
        ASSERT(apic != NULL);
 
-       now = apic->timer.dev.base->get_time();
-       tmcct = apic_get_reg(apic, APIC_TMICT);
-
        /* if initial count is 0, current count should also be 0 */
-       if (tmcct == 0)
+       if (apic_get_reg(apic, APIC_TMICT) == 0)
                return 0;
 
-       if (unlikely(ktime_to_ns(now) <=
-               ktime_to_ns(apic->timer.last_update))) {
-               /* Wrap around */
-               passed = ktime_add(( {
-                                   (ktime_t) {
-                                   .tv64 = KTIME_MAX -
-                                   (apic->timer.last_update).tv64}; }
-                                  ), now);
-               apic_debug("time elapsed\n");
-       } else
-               passed = ktime_sub(now, apic->timer.last_update);
-
-       counter_passed = div64_u64(ktime_to_ns(passed),
-                                  (APIC_BUS_CYCLE_NS * apic->timer.divide_count));
-
-       if (counter_passed > tmcct) {
-               if (unlikely(!apic_lvtt_period(apic))) {
-                       /* one-shot timers stick at 0 until reset */
-                       tmcct = 0;
-               } else {
-                       /*
-                        * periodic timers reset to APIC_TMICT when they
-                        * hit 0. The while loop simulates this happening N
-                        * times. (counter_passed %= tmcct) would also work,
-                        * but might be slower or not work on 32-bit??
-                        */
-                       while (counter_passed > tmcct)
-                               counter_passed -= tmcct;
-                       tmcct -= counter_passed;
-               }
-       } else {
-               tmcct -= counter_passed;
-       }
+       remaining = hrtimer_expires_remaining(&apic->timer.dev);
+       if (ktime_to_ns(remaining) < 0)
+               remaining = ktime_set(0, 0);
+
+       ns = mod_64(ktime_to_ns(remaining), apic->timer.period);
+       tmcct = div64_u64(ns, (APIC_BUS_CYCLE_NS * apic->timer.divide_count));
 
        return tmcct;
 }
@@ -653,8 +629,6 @@ static void start_apic_timer(struct kvm_lapic *apic)
 {
        ktime_t now = apic->timer.dev.base->get_time();
 
-       apic->timer.last_update = now;
-
        apic->timer.period = apic_get_reg(apic, APIC_TMICT) *
                    APIC_BUS_CYCLE_NS * apic->timer.divide_count;
        atomic_set(&apic->timer.pending, 0);
@@ -1110,16 +1084,6 @@ void kvm_inject_apic_timer_irqs(struct kvm_vcpu *vcpu)
        }
 }
 
-void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec)
-{
-       struct kvm_lapic *apic = vcpu->arch.apic;
-
-       if (apic && apic_lvt_vector(apic, APIC_LVTT) == vec)
-               apic->timer.last_update = ktime_add_ns(
-                               apic->timer.last_update,
-                               apic->timer.period);
-}
-
 int kvm_get_apic_interrupt(struct kvm_vcpu *vcpu)
 {
        int vector = kvm_apic_has_interrupt(vcpu);
index 81858881287e6962c4ab4863191f8e71cfef7a1b..45ab6ee71209f586596447c0b1ad02feca125698 100644 (file)
@@ -12,7 +12,6 @@ struct kvm_lapic {
                atomic_t pending;
                s64 period;     /* unit: ns */
                u32 divide_count;
-               ktime_t last_update;
                struct hrtimer dev;
        } timer;
        struct kvm_vcpu *vcpu;
@@ -42,7 +41,6 @@ void kvm_set_apic_base(struct kvm_vcpu *vcpu, u64 data);
 void kvm_apic_post_state_restore(struct kvm_vcpu *vcpu);
 int kvm_lapic_enabled(struct kvm_vcpu *vcpu);
 int kvm_lapic_find_highest_irr(struct kvm_vcpu *vcpu);
-void kvm_apic_timer_intr_post(struct kvm_vcpu *vcpu, int vec);
 
 void kvm_lapic_set_vapic_addr(struct kvm_vcpu *vcpu, gpa_t vapic_addr);
 void kvm_lapic_sync_from_vapic(struct kvm_vcpu *vcpu);
index 83f11c7474a1d74ef996ca7245078e1b6dda7051..2d4477c7147372c28ed84f5a513ca553dc46979c 100644 (file)
@@ -1698,8 +1698,13 @@ static int set_spte(struct kvm_vcpu *vcpu, u64 *shadow_pte,
        if (largepage)
                spte |= PT_PAGE_SIZE_MASK;
        if (mt_mask) {
-               mt_mask = get_memory_type(vcpu, gfn) <<
-                         kvm_x86_ops->get_mt_mask_shift();
+               if (!kvm_is_mmio_pfn(pfn)) {
+                       mt_mask = get_memory_type(vcpu, gfn) <<
+                               kvm_x86_ops->get_mt_mask_shift();
+                       mt_mask |= VMX_EPT_IGMT_BIT;
+               } else
+                       mt_mask = MTRR_TYPE_UNCACHABLE <<
+                               kvm_x86_ops->get_mt_mask_shift();
                spte |= mt_mask;
        }
 
index 1452851ae2583b689f250a403ce6ee08075144c8..a9e769e4e2513b552d1a035884959a8a5280c84d 100644 (file)
@@ -1600,7 +1600,6 @@ static void svm_intr_assist(struct kvm_vcpu *vcpu)
        /* Okay, we can deliver the interrupt: grab it and update PIC state. */
        intr_vector = kvm_cpu_get_interrupt(vcpu);
        svm_inject_irq(svm, intr_vector);
-       kvm_timer_intr_post(vcpu, intr_vector);
 out:
        update_cr8_intercept(vcpu);
 }
index 6259d7467648e1209456abff3666ad9a4e4a3cb4..7611af576829d820eba8de4a79d389e8baef7759 100644 (file)
@@ -903,6 +903,7 @@ static int vmx_get_msr(struct kvm_vcpu *vcpu, u32 msr_index, u64 *pdata)
                data = vmcs_readl(GUEST_SYSENTER_ESP);
                break;
        default:
+               vmx_load_host_state(to_vmx(vcpu));
                msr = find_msr_entry(to_vmx(vcpu), msr_index);
                if (msr) {
                        data = msr->data;
@@ -3285,7 +3286,6 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu)
        }
        if (vcpu->arch.interrupt.pending) {
                vmx_inject_irq(vcpu, vcpu->arch.interrupt.nr);
-               kvm_timer_intr_post(vcpu, vcpu->arch.interrupt.nr);
                if (kvm_cpu_has_interrupt(vcpu))
                        enable_irq_window(vcpu);
        }
@@ -3687,8 +3687,7 @@ static int __init vmx_init(void)
        if (vm_need_ept()) {
                bypass_guest_pf = 0;
                kvm_mmu_set_base_ptes(VMX_EPT_READABLE_MASK |
-                       VMX_EPT_WRITABLE_MASK |
-                       VMX_EPT_IGMT_BIT);
+                       VMX_EPT_WRITABLE_MASK);
                kvm_mmu_set_mask_ptes(0ull, 0ull, 0ull, 0ull,
                                VMX_EPT_EXECUTABLE_MASK,
                                VMX_EPT_DEFAULT_MT << VMX_EPT_MT_EPTE_SHIFT);
index cc17546a2406af860329ea28d1ae85b7ebb4aa23..758b7a155ae9113559b5993b38abfc3cf603fe70 100644 (file)
@@ -967,7 +967,6 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_MMU_SHADOW_CACHE_CONTROL:
        case KVM_CAP_SET_TSS_ADDR:
        case KVM_CAP_EXT_CPUID:
-       case KVM_CAP_CLOCKSOURCE:
        case KVM_CAP_PIT:
        case KVM_CAP_NOP_IO_DELAY:
        case KVM_CAP_MP_STATE:
@@ -992,6 +991,9 @@ int kvm_dev_ioctl_check_extension(long ext)
        case KVM_CAP_IOMMU:
                r = iommu_found();
                break;
+       case KVM_CAP_CLOCKSOURCE:
+               r = boot_cpu_has(X86_FEATURE_CONSTANT_TSC);
+               break;
        default:
                r = 0;
                break;
@@ -4127,9 +4129,13 @@ static void kvm_free_vcpus(struct kvm *kvm)
 
 }
 
-void kvm_arch_destroy_vm(struct kvm *kvm)
+void kvm_arch_sync_events(struct kvm *kvm)
 {
        kvm_free_all_assigned_devices(kvm);
+}
+
+void kvm_arch_destroy_vm(struct kvm *kvm)
+{
        kvm_iommu_unmap_guest(kvm);
        kvm_free_pit(kvm);
        kfree(kvm->arch.vpic);
index a265a7c631901d111a9b907fa105754871a45e5b..50b5918711289a175287e0c8fb3b39f4c85a541e 100644 (file)
@@ -96,7 +96,7 @@ void __init trap_init_hook(void)
 
 static struct irqaction irq0  = {
        .handler = timer_interrupt,
-       .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL,
+       .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
        .mask = CPU_MASK_NONE,
        .name = "timer"
 };
index d914a7996a6684758f9ba1be29b6e012c88c21eb..8e5118371f0fac1cb3ff2e90d87e0c038c484aed 100644 (file)
@@ -56,7 +56,7 @@ void __init trap_init_hook(void)
 
 static struct irqaction irq0 = {
        .handler = timer_interrupt,
-       .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL,
+       .flags = IRQF_DISABLED | IRQF_NOBALANCING | IRQF_IRQPOLL | IRQF_TIMER,
        .mask = CPU_MASK_NONE,
        .name = "timer"
 };
index 7ffcdeec4631fa7b1adf54ec2bbbd71ee98402ba..b9cc84a2a4fc7ae200540e120518f20bd6408ba9 100644 (file)
@@ -65,7 +65,7 @@ static volatile unsigned long smp_invalidate_needed;
 
 /* Bitmask of CPUs present in the system - exported by i386_syms.c, used
  * by scheduler but indexed physically */
-cpumask_t phys_cpu_present_map = CPU_MASK_NONE;
+static cpumask_t voyager_phys_cpu_present_map = CPU_MASK_NONE;
 
 /* The internal functions */
 static void send_CPI(__u32 cpuset, __u8 cpi);
@@ -366,19 +366,19 @@ void __init find_smp_config(void)
        /* set up everything for just this CPU, we can alter
         * this as we start the other CPUs later */
        /* now get the CPU disposition from the extended CMOS */
-       cpus_addr(phys_cpu_present_map)[0] =
+       cpus_addr(voyager_phys_cpu_present_map)[0] =
            voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK);
-       cpus_addr(phys_cpu_present_map)[0] |=
+       cpus_addr(voyager_phys_cpu_present_map)[0] |=
            voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK + 1) << 8;
-       cpus_addr(phys_cpu_present_map)[0] |=
+       cpus_addr(voyager_phys_cpu_present_map)[0] |=
            voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK +
                                       2) << 16;
-       cpus_addr(phys_cpu_present_map)[0] |=
+       cpus_addr(voyager_phys_cpu_present_map)[0] |=
            voyager_extended_cmos_read(VOYAGER_PROCESSOR_PRESENT_MASK +
                                       3) << 24;
-       init_cpu_possible(&phys_cpu_present_map);
-       printk("VOYAGER SMP: phys_cpu_present_map = 0x%lx\n",
-              cpus_addr(phys_cpu_present_map)[0]);
+       init_cpu_possible(&voyager_phys_cpu_present_map);
+       printk("VOYAGER SMP: voyager_phys_cpu_present_map = 0x%lx\n",
+              cpus_addr(voyager_phys_cpu_present_map)[0]);
        /* Here we set up the VIC to enable SMP */
        /* enable the CPIs by writing the base vector to their register */
        outb(VIC_DEFAULT_CPI_BASE, VIC_CPI_BASE_REGISTER);
@@ -628,15 +628,15 @@ void __init smp_boot_cpus(void)
                /* now that the cat has probed the Voyager System Bus, sanity
                 * check the cpu map */
                if (((voyager_quad_processors | voyager_extended_vic_processors)
-                    & cpus_addr(phys_cpu_present_map)[0]) !=
-                   cpus_addr(phys_cpu_present_map)[0]) {
+                    & cpus_addr(voyager_phys_cpu_present_map)[0]) !=
+                   cpus_addr(voyager_phys_cpu_present_map)[0]) {
                        /* should panic */
                        printk("\n\n***WARNING*** "
                               "Sanity check of CPU present map FAILED\n");
                }
        } else if (voyager_level == 4)
                voyager_extended_vic_processors =
-                   cpus_addr(phys_cpu_present_map)[0];
+                   cpus_addr(voyager_phys_cpu_present_map)[0];
 
        /* this sets up the idle task to run on the current cpu */
        voyager_extended_cpus = 1;
@@ -670,7 +670,7 @@ void __init smp_boot_cpus(void)
        /* loop over all the extended VIC CPUs and boot them.  The
         * Quad CPUs must be bootstrapped by their extended VIC cpu */
        for (i = 0; i < nr_cpu_ids; i++) {
-               if (i == boot_cpu_id || !cpu_isset(i, phys_cpu_present_map))
+               if (i == boot_cpu_id || !cpu_isset(i, voyager_phys_cpu_present_map))
                        continue;
                do_boot_cpu(i);
                /* This udelay seems to be needed for the Quad boots
index e6d36b490250bed6952f2d93de3d1f337c3cf7f4..b1352250096e0d734ea4a03650e7d92ae8c2d8ba 100644 (file)
@@ -714,6 +714,8 @@ unsigned long __init_refok init_memory_mapping(unsigned long start,
        pos = start_pfn << PAGE_SHIFT;
        end_pfn = ((pos + (PMD_SIZE - 1)) >> PMD_SHIFT)
                        << (PMD_SHIFT - PAGE_SHIFT);
+       if (end_pfn > (end >> PAGE_SHIFT))
+               end_pfn = end >> PAGE_SHIFT;
        if (start_pfn < end_pfn) {
                nr_range = save_mr(mr, nr_range, start_pfn, end_pfn, 0);
                pos = end_pfn << PAGE_SHIFT;
index ca53224fc56c8eeb1c57feccdccf93e09c25b2cb..04102d42ff4250873a519620958855e9b50770ff 100644 (file)
 #include <asm/pat.h>
 #include <linux/module.h>
 
+int is_io_mapping_possible(resource_size_t base, unsigned long size)
+{
+#ifndef CONFIG_X86_PAE
+       /* There is no way to map greater than 1 << 32 address without PAE */
+       if (base + size > 0x100000000ULL)
+               return 0;
+#endif
+       return 1;
+}
+EXPORT_SYMBOL_GPL(is_io_mapping_possible);
+
 /* Map 'pfn' using fixed map 'type' and protections 'prot'
  */
 void *
index af750ab973b6943840e9de53e4716819da06c4a2..f45d5e29a72edf4e15616d48c0d174f7905ac417 100644 (file)
@@ -134,25 +134,6 @@ int page_is_ram(unsigned long pagenr)
        return 0;
 }
 
-int pagerange_is_ram(unsigned long start, unsigned long end)
-{
-       int ram_page = 0, not_rampage = 0;
-       unsigned long page_nr;
-
-       for (page_nr = (start >> PAGE_SHIFT); page_nr < (end >> PAGE_SHIFT);
-            ++page_nr) {
-               if (page_is_ram(page_nr))
-                       ram_page = 1;
-               else
-                       not_rampage = 1;
-
-               if (ram_page == not_rampage)
-                       return -1;
-       }
-
-       return ram_page;
-}
-
 /*
  * Fix up the linear direct mapping of the kernel to avoid cache attribute
  * conflicts.
index 93d82038af4b541853420a48502df0fc4c9c2407..9f205030d9aac6a6dbdb6f620b47fcba8b4acb2f 100644 (file)
@@ -32,11 +32,14 @@ struct kmmio_fault_page {
        struct list_head list;
        struct kmmio_fault_page *release_next;
        unsigned long page; /* location of the fault page */
+       bool old_presence; /* page presence prior to arming */
+       bool armed;
 
        /*
         * Number of times this page has been registered as a part
         * of a probe. If zero, page is disarmed and this may be freed.
-        * Used only by writers (RCU).
+        * Used only by writers (RCU) and post_kmmio_handler().
+        * Protected by kmmio_lock, when linked into kmmio_page_table.
         */
        int count;
 };
@@ -105,57 +108,85 @@ static struct kmmio_fault_page *get_kmmio_fault_page(unsigned long page)
        return NULL;
 }
 
-static void set_page_present(unsigned long addr, bool present,
-                                                       unsigned int *pglevel)
+static void set_pmd_presence(pmd_t *pmd, bool present, bool *old)
+{
+       pmdval_t v = pmd_val(*pmd);
+       *old = !!(v & _PAGE_PRESENT);
+       v &= ~_PAGE_PRESENT;
+       if (present)
+               v |= _PAGE_PRESENT;
+       set_pmd(pmd, __pmd(v));
+}
+
+static void set_pte_presence(pte_t *pte, bool present, bool *old)
+{
+       pteval_t v = pte_val(*pte);
+       *old = !!(v & _PAGE_PRESENT);
+       v &= ~_PAGE_PRESENT;
+       if (present)
+               v |= _PAGE_PRESENT;
+       set_pte_atomic(pte, __pte(v));
+}
+
+static int set_page_presence(unsigned long addr, bool present, bool *old)
 {
-       pteval_t pteval;
-       pmdval_t pmdval;
        unsigned int level;
-       pmd_t *pmd;
        pte_t *pte = lookup_address(addr, &level);
 
        if (!pte) {
                pr_err("kmmio: no pte for page 0x%08lx\n", addr);
-               return;
+               return -1;
        }
 
-       if (pglevel)
-               *pglevel = level;
-
        switch (level) {
        case PG_LEVEL_2M:
-               pmd = (pmd_t *)pte;
-               pmdval = pmd_val(*pmd) & ~_PAGE_PRESENT;
-               if (present)
-                       pmdval |= _PAGE_PRESENT;
-               set_pmd(pmd, __pmd(pmdval));
+               set_pmd_presence((pmd_t *)pte, present, old);
                break;
-
        case PG_LEVEL_4K:
-               pteval = pte_val(*pte) & ~_PAGE_PRESENT;
-               if (present)
-                       pteval |= _PAGE_PRESENT;
-               set_pte_atomic(pte, __pte(pteval));
+               set_pte_presence(pte, present, old);
                break;
-
        default:
                pr_err("kmmio: unexpected page level 0x%x.\n", level);
-               return;
+               return -1;
        }
 
        __flush_tlb_one(addr);
+       return 0;
 }
 
-/** Mark the given page as not present. Access to it will trigger a fault. */
-static void arm_kmmio_fault_page(unsigned long page, unsigned int *pglevel)
+/*
+ * Mark the given page as not present. Access to it will trigger a fault.
+ *
+ * Struct kmmio_fault_page is protected by RCU and kmmio_lock, but the
+ * protection is ignored here. RCU read lock is assumed held, so the struct
+ * will not disappear unexpectedly. Furthermore, the caller must guarantee,
+ * that double arming the same virtual address (page) cannot occur.
+ *
+ * Double disarming on the other hand is allowed, and may occur when a fault
+ * and mmiotrace shutdown happen simultaneously.
+ */
+static int arm_kmmio_fault_page(struct kmmio_fault_page *f)
 {
-       set_page_present(page & PAGE_MASK, false, pglevel);
+       int ret;
+       WARN_ONCE(f->armed, KERN_ERR "kmmio page already armed.\n");
+       if (f->armed) {
+               pr_warning("kmmio double-arm: page 0x%08lx, ref %d, old %d\n",
+                                       f->page, f->count, f->old_presence);
+       }
+       ret = set_page_presence(f->page, false, &f->old_presence);
+       WARN_ONCE(ret < 0, KERN_ERR "kmmio arming 0x%08lx failed.\n", f->page);
+       f->armed = true;
+       return ret;
 }
 
-/** Mark the given page as present. */
-static void disarm_kmmio_fault_page(unsigned long page, unsigned int *pglevel)
+/** Restore the given page to saved presence state. */
+static void disarm_kmmio_fault_page(struct kmmio_fault_page *f)
 {
-       set_page_present(page & PAGE_MASK, true, pglevel);
+       bool tmp;
+       int ret = set_page_presence(f->page, f->old_presence, &tmp);
+       WARN_ONCE(ret < 0,
+                       KERN_ERR "kmmio disarming 0x%08lx failed.\n", f->page);
+       f->armed = false;
 }
 
 /*
@@ -202,28 +233,32 @@ int kmmio_handler(struct pt_regs *regs, unsigned long addr)
 
        ctx = &get_cpu_var(kmmio_ctx);
        if (ctx->active) {
-               disarm_kmmio_fault_page(faultpage->page, NULL);
                if (addr == ctx->addr) {
                        /*
-                        * On SMP we sometimes get recursive probe hits on the
-                        * same address. Context is already saved, fall out.
+                        * A second fault on the same page means some other
+                        * condition needs handling by do_page_fault(), the
+                        * page really not being present is the most common.
                         */
-                       pr_debug("kmmio: duplicate probe hit on CPU %d, for "
-                                               "address 0x%08lx.\n",
-                                               smp_processor_id(), addr);
-                       ret = 1;
-                       goto no_kmmio_ctx;
-               }
-               /*
-                * Prevent overwriting already in-flight context.
-                * This should not happen, let's hope disarming at least
-                * prevents a panic.
-                */
-               pr_emerg("kmmio: recursive probe hit on CPU %d, "
+                       pr_debug("kmmio: secondary hit for 0x%08lx CPU %d.\n",
+                                       addr, smp_processor_id());
+
+                       if (!faultpage->old_presence)
+                               pr_info("kmmio: unexpected secondary hit for "
+                                       "address 0x%08lx on CPU %d.\n", addr,
+                                       smp_processor_id());
+               } else {
+                       /*
+                        * Prevent overwriting already in-flight context.
+                        * This should not happen, let's hope disarming at
+                        * least prevents a panic.
+                        */
+                       pr_emerg("kmmio: recursive probe hit on CPU %d, "
                                        "for address 0x%08lx. Ignoring.\n",
                                        smp_processor_id(), addr);
-               pr_emerg("kmmio: previous hit was at 0x%08lx.\n",
-                                       ctx->addr);
+                       pr_emerg("kmmio: previous hit was at 0x%08lx.\n",
+                                               ctx->addr);
+                       disarm_kmmio_fault_page(faultpage);
+               }
                goto no_kmmio_ctx;
        }
        ctx->active++;
@@ -244,7 +279,7 @@ int kmmio_handler(struct pt_regs *regs, unsigned long addr)
        regs->flags &= ~X86_EFLAGS_IF;
 
        /* Now we set present bit in PTE and single step. */
-       disarm_kmmio_fault_page(ctx->fpage->page, NULL);
+       disarm_kmmio_fault_page(ctx->fpage);
 
        /*
         * If another cpu accesses the same page while we are stepping,
@@ -275,7 +310,7 @@ static int post_kmmio_handler(unsigned long condition, struct pt_regs *regs)
        struct kmmio_context *ctx = &get_cpu_var(kmmio_ctx);
 
        if (!ctx->active) {
-               pr_debug("kmmio: spurious debug trap on CPU %d.\n",
+               pr_warning("kmmio: spurious debug trap on CPU %d.\n",
                                                        smp_processor_id());
                goto out;
        }
@@ -283,7 +318,11 @@ static int post_kmmio_handler(unsigned long condition, struct pt_regs *regs)
        if (ctx->probe && ctx->probe->post_handler)
                ctx->probe->post_handler(ctx->probe, condition, regs);
 
-       arm_kmmio_fault_page(ctx->fpage->page, NULL);
+       /* Prevent racing against release_kmmio_fault_page(). */
+       spin_lock(&kmmio_lock);
+       if (ctx->fpage->count)
+               arm_kmmio_fault_page(ctx->fpage);
+       spin_unlock(&kmmio_lock);
 
        regs->flags &= ~X86_EFLAGS_TF;
        regs->flags |= ctx->saved_flags;
@@ -315,20 +354,24 @@ static int add_kmmio_fault_page(unsigned long page)
        f = get_kmmio_fault_page(page);
        if (f) {
                if (!f->count)
-                       arm_kmmio_fault_page(f->page, NULL);
+                       arm_kmmio_fault_page(f);
                f->count++;
                return 0;
        }
 
-       f = kmalloc(sizeof(*f), GFP_ATOMIC);
+       f = kzalloc(sizeof(*f), GFP_ATOMIC);
        if (!f)
                return -1;
 
        f->count = 1;
        f->page = page;
-       list_add_rcu(&f->list, kmmio_page_list(f->page));
 
-       arm_kmmio_fault_page(f->page, NULL);
+       if (arm_kmmio_fault_page(f)) {
+               kfree(f);
+               return -1;
+       }
+
+       list_add_rcu(&f->list, kmmio_page_list(f->page));
 
        return 0;
 }
@@ -347,7 +390,7 @@ static void release_kmmio_fault_page(unsigned long page,
        f->count--;
        BUG_ON(f->count < 0);
        if (!f->count) {
-               disarm_kmmio_fault_page(f->page, NULL);
+               disarm_kmmio_fault_page(f);
                f->release_next = *release_list;
                *release_list = f;
        }
index 71a14f89f89e7367c72f2de85da6708acc83c069..f3516da035d141947d04ddfbd61bd56f74623fd3 100644 (file)
@@ -145,7 +145,7 @@ int __init compute_hash_shift(struct bootnode *nodes, int numnodes,
        return shift;
 }
 
-int early_pfn_to_nid(unsigned long pfn)
+int __meminit  __early_pfn_to_nid(unsigned long pfn)
 {
        return phys_to_nid(pfn << PAGE_SHIFT);
 }
index 84ba74820ad6436479a6456ec8d8e3a9a3c5c591..7be47d1a97e463590fe0565e72f36499d95949b5 100644 (file)
@@ -508,18 +508,13 @@ static int split_large_page(pte_t *kpte, unsigned long address)
 #endif
 
        /*
-        * Install the new, split up pagetable. Important details here:
+        * Install the new, split up pagetable.
         *
-        * On Intel the NX bit of all levels must be cleared to make a
-        * page executable. See section 4.13.2 of Intel 64 and IA-32
-        * Architectures Software Developer's Manual).
-        *
-        * Mark the entry present. The current mapping might be
-        * set to not present, which we preserved above.
+        * We use the standard kernel pagetable protections for the new
+        * pagetable protections, the actual ptes set above control the
+        * primary protection behavior:
         */
-       ref_prot = pte_pgprot(pte_mkexec(pte_clrhuge(*kpte)));
-       pgprot_val(ref_prot) |= _PAGE_PRESENT;
-       __set_pmd_pte(kpte, address, mk_pte(base, ref_prot));
+       __set_pmd_pte(kpte, address, mk_pte(base, __pgprot(_KERNPG_TABLE)));
        base = NULL;
 
 out_unlock:
@@ -575,7 +570,6 @@ static int __change_page_attr(struct cpa_data *cpa, int primary)
                address = cpa->vaddr[cpa->curpage];
        else
                address = *cpa->vaddr;
-
 repeat:
        kpte = lookup_address(address, &level);
        if (!kpte)
@@ -812,6 +806,13 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
 
        vm_unmap_aliases();
 
+       /*
+        * If we're called with lazy mmu updates enabled, the
+        * in-memory pte state may be stale.  Flush pending updates to
+        * bring them up to date.
+        */
+       arch_flush_lazy_mmu_mode();
+
        cpa.vaddr = addr;
        cpa.numpages = numpages;
        cpa.mask_set = mask_set;
@@ -854,6 +855,13 @@ static int change_page_attr_set_clr(unsigned long *addr, int numpages,
        } else
                cpa_flush_all(cache);
 
+       /*
+        * If we've been called with lazy mmu updates enabled, then
+        * make sure that everything gets flushed out before we
+        * return.
+        */
+       arch_flush_lazy_mmu_mode();
+
 out:
        return ret;
 }
index 7b61036427df69d11a33044d60bc85102931e385..e0ab173b6974ba4e7f150adf480fd6e603a5c20c 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/bootmem.h>
 #include <linux/debugfs.h>
 #include <linux/kernel.h>
+#include <linux/module.h>
 #include <linux/gfp.h>
 #include <linux/mm.h>
 #include <linux/fs.h>
@@ -211,6 +212,33 @@ chk_conflict(struct memtype *new, struct memtype *entry, unsigned long *type)
 static struct memtype *cached_entry;
 static u64 cached_start;
 
+static int pat_pagerange_is_ram(unsigned long start, unsigned long end)
+{
+       int ram_page = 0, not_rampage = 0;
+       unsigned long page_nr;
+
+       for (page_nr = (start >> PAGE_SHIFT); page_nr < (end >> PAGE_SHIFT);
+            ++page_nr) {
+               /*
+                * For legacy reasons, physical address range in the legacy ISA
+                * region is tracked as non-RAM. This will allow users of
+                * /dev/mem to map portions of legacy ISA region, even when
+                * some of those portions are listed(or not even listed) with
+                * different e820 types(RAM/reserved/..)
+                */
+               if (page_nr >= (ISA_END_ADDRESS >> PAGE_SHIFT) &&
+                   page_is_ram(page_nr))
+                       ram_page = 1;
+               else
+                       not_rampage = 1;
+
+               if (ram_page == not_rampage)
+                       return -1;
+       }
+
+       return ram_page;
+}
+
 /*
  * For RAM pages, mark the pages as non WB memory type using
  * PageNonWB (PG_arch_1). We allow only one set_memory_uc() or
@@ -336,20 +364,12 @@ int reserve_memtype(u64 start, u64 end, unsigned long req_type,
        if (new_type)
                *new_type = actual_type;
 
-       /*
-        * For legacy reasons, some parts of the physical address range in the
-        * legacy 1MB region is treated as non-RAM (even when listed as RAM in
-        * the e820 tables).  So we will track the memory attributes of this
-        * legacy 1MB region using the linear memtype_list always.
-        */
-       if (end >= ISA_END_ADDRESS) {
-               is_range_ram = pagerange_is_ram(start, end);
-               if (is_range_ram == 1)
-                       return reserve_ram_pages_type(start, end, req_type,
-                                                     new_type);
-               else if (is_range_ram < 0)
-                       return -EINVAL;
-       }
+       is_range_ram = pat_pagerange_is_ram(start, end);
+       if (is_range_ram == 1)
+               return reserve_ram_pages_type(start, end, req_type,
+                                             new_type);
+       else if (is_range_ram < 0)
+               return -EINVAL;
 
        new  = kmalloc(sizeof(struct memtype), GFP_KERNEL);
        if (!new)
@@ -446,19 +466,11 @@ int free_memtype(u64 start, u64 end)
        if (is_ISA_range(start, end - 1))
                return 0;
 
-       /*
-        * For legacy reasons, some parts of the physical address range in the
-        * legacy 1MB region is treated as non-RAM (even when listed as RAM in
-        * the e820 tables).  So we will track the memory attributes of this
-        * legacy 1MB region using the linear memtype_list always.
-        */
-       if (end >= ISA_END_ADDRESS) {
-               is_range_ram = pagerange_is_ram(start, end);
-               if (is_range_ram == 1)
-                       return free_ram_pages_type(start, end);
-               else if (is_range_ram < 0)
-                       return -EINVAL;
-       }
+       is_range_ram = pat_pagerange_is_ram(start, end);
+       if (is_range_ram == 1)
+               return free_ram_pages_type(start, end);
+       else if (is_range_ram < 0)
+               return -EINVAL;
 
        spin_lock(&memtype_lock);
        list_for_each_entry(entry, &memtype_list, nd) {
@@ -626,17 +638,13 @@ static int reserve_pfn_range(u64 paddr, unsigned long size, pgprot_t *vma_prot,
        unsigned long flags;
        unsigned long want_flags = (pgprot_val(*vma_prot) & _PAGE_CACHE_MASK);
 
-       is_ram = pagerange_is_ram(paddr, paddr + size);
+       is_ram = pat_pagerange_is_ram(paddr, paddr + size);
 
-       if (is_ram != 0) {
-               /*
-                * For mapping RAM pages, drivers need to call
-                * set_memory_[uc|wc|wb] directly, for reserve and free, before
-                * setting up the PTE.
-                */
-               WARN_ON_ONCE(1);
-               return 0;
-       }
+       /*
+        * reserve_pfn_range() doesn't support RAM pages.
+        */
+       if (is_ram != 0)
+               return -EINVAL;
 
        ret = reserve_memtype(paddr, paddr + size, want_flags, &flags);
        if (ret)
@@ -693,7 +701,7 @@ static void free_pfn_range(u64 paddr, unsigned long size)
 {
        int is_ram;
 
-       is_ram = pagerange_is_ram(paddr, paddr + size);
+       is_ram = pat_pagerange_is_ram(paddr, paddr + size);
        if (is_ram == 0)
                free_memtype(paddr, paddr + size);
 }
@@ -861,6 +869,7 @@ pgprot_t pgprot_writecombine(pgprot_t prot)
        else
                return pgprot_noncached(prot);
 }
+EXPORT_SYMBOL_GPL(pgprot_writecombine);
 
 #if defined(CONFIG_DEBUG_FS) && defined(CONFIG_X86_PAT)
 
index ab50a8d7402c8c7f4320f0fd803a22a2d9abf84a..427fd1b56df5540f6a871f31c99c92af4f3edacd 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Written by Pekka Paalanen, 2008 <pq@iki.fi>
+ * Written by Pekka Paalanen, 2008-2009 <pq@iki.fi>
  */
 #include <linux/module.h>
 #include <linux/io.h>
@@ -9,35 +9,74 @@
 
 static unsigned long mmio_address;
 module_param(mmio_address, ulong, 0);
-MODULE_PARM_DESC(mmio_address, "Start address of the mapping of 16 kB.");
+MODULE_PARM_DESC(mmio_address, " Start address of the mapping of 16 kB "
+                               "(or 8 MB if read_far is non-zero).");
+
+static unsigned long read_far = 0x400100;
+module_param(read_far, ulong, 0);
+MODULE_PARM_DESC(read_far, " Offset of a 32-bit read within 8 MB "
+                               "(default: 0x400100).");
+
+static unsigned v16(unsigned i)
+{
+       return i * 12 + 7;
+}
+
+static unsigned v32(unsigned i)
+{
+       return i * 212371 + 13;
+}
 
 static void do_write_test(void __iomem *p)
 {
        unsigned int i;
+       pr_info(MODULE_NAME ": write test.\n");
        mmiotrace_printk("Write test.\n");
+
        for (i = 0; i < 256; i++)
                iowrite8(i, p + i);
+
        for (i = 1024; i < (5 * 1024); i += 2)
-               iowrite16(i * 12 + 7, p + i);
+               iowrite16(v16(i), p + i);
+
        for (i = (5 * 1024); i < (16 * 1024); i += 4)
-               iowrite32(i * 212371 + 13, p + i);
+               iowrite32(v32(i), p + i);
 }
 
 static void do_read_test(void __iomem *p)
 {
        unsigned int i;
+       unsigned errs[3] = { 0 };
+       pr_info(MODULE_NAME ": read test.\n");
        mmiotrace_printk("Read test.\n");
+
        for (i = 0; i < 256; i++)
-               ioread8(p + i);
+               if (ioread8(p + i) != i)
+                       ++errs[0];
+
        for (i = 1024; i < (5 * 1024); i += 2)
-               ioread16(p + i);
+               if (ioread16(p + i) != v16(i))
+                       ++errs[1];
+
        for (i = (5 * 1024); i < (16 * 1024); i += 4)
-               ioread32(p + i);
+               if (ioread32(p + i) != v32(i))
+                       ++errs[2];
+
+       mmiotrace_printk("Read errors: 8-bit %d, 16-bit %d, 32-bit %d.\n",
+                                               errs[0], errs[1], errs[2]);
 }
 
-static void do_test(void)
+static void do_read_far_test(void __iomem *p)
 {
-       void __iomem *p = ioremap_nocache(mmio_address, 0x4000);
+       pr_info(MODULE_NAME ": read far test.\n");
+       mmiotrace_printk("Read far test.\n");
+
+       ioread32(p + read_far);
+}
+
+static void do_test(unsigned long size)
+{
+       void __iomem *p = ioremap_nocache(mmio_address, size);
        if (!p) {
                pr_err(MODULE_NAME ": could not ioremap, aborting.\n");
                return;
@@ -45,11 +84,15 @@ static void do_test(void)
        mmiotrace_printk("ioremap returned %p.\n", p);
        do_write_test(p);
        do_read_test(p);
+       if (read_far && read_far < size - 4)
+               do_read_far_test(p);
        iounmap(p);
 }
 
 static int __init init(void)
 {
+       unsigned long size = (read_far) ? (8 << 20) : (16 << 10);
+
        if (mmio_address == 0) {
                pr_err(MODULE_NAME ": you have to use the module argument "
                                                        "mmio_address.\n");
@@ -58,10 +101,11 @@ static int __init init(void)
                return -ENXIO;
        }
 
-       pr_warning(MODULE_NAME ": WARNING: mapping 16 kB @ 0x%08lx "
-                                       "in PCI address space, and writing "
-                                       "rubbish in there.\n", mmio_address);
-       do_test();
+       pr_warning(MODULE_NAME ": WARNING: mapping %lu kB @ 0x%08lx in PCI "
+               "address space, and writing 16 kB of rubbish in there.\n",
+                size >> 10, mmio_address);
+       do_test(size);
+       pr_info(MODULE_NAME ": All done.\n");
        return 0;
 }
 
index e9f80c744cf3409d72f77dd9044ec1dd90534609..10131fbdaadada1781bddde6749e83a4cb200a8f 100644 (file)
@@ -78,8 +78,18 @@ static void ppro_setup_ctrs(struct op_msrs const * const msrs)
        if (cpu_has_arch_perfmon) {
                union cpuid10_eax eax;
                eax.full = cpuid_eax(0xa);
-               if (counter_width < eax.split.bit_width)
-                       counter_width = eax.split.bit_width;
+
+               /*
+                * For Core2 (family 6, model 15), don't reset the
+                * counter width:
+                */
+               if (!(eax.split.version_id == 0 &&
+                       current_cpu_data.x86 == 6 &&
+                               current_cpu_data.x86_model == 15)) {
+
+                       if (counter_width < eax.split.bit_width)
+                               counter_width = eax.split.bit_width;
+               }
        }
 
        /* clear all counters */
index bea215230b20cdf4fc41ac5fd4e060dcbaec4ec1..b58e9633814923aa5e13cd2f491086830528db6a 100644 (file)
@@ -1672,6 +1672,9 @@ asmlinkage void __init xen_start_kernel(void)
           possible map and a non-dummy shared_info. */
        per_cpu(xen_vcpu, 0) = &HYPERVISOR_shared_info->vcpu_info[0];
 
+       local_irq_disable();
+       early_boot_irqs_off();
+
        xen_raw_console_write("mapping kernel into physical memory\n");
        pgd = xen_setup_kernel_pagetable(pgd, xen_start_info->nr_pages);
 
index b92f5b0866b0972b80e5b7f69e1fae046608a90b..a104593e70c38cdfdaebc1cf1214934e37ce3284 100644 (file)
@@ -38,72 +38,84 @@ void blk_recalc_rq_sectors(struct request *rq, int nsect)
        }
 }
 
-void blk_recalc_rq_segments(struct request *rq)
+static unsigned int __blk_recalc_rq_segments(struct request_queue *q,
+                                            struct bio *bio,
+                                            unsigned int *seg_size_ptr)
 {
-       int nr_phys_segs;
        unsigned int phys_size;
        struct bio_vec *bv, *bvprv = NULL;
-       int seg_size;
-       int cluster;
-       struct req_iterator iter;
-       int high, highprv = 1;
-       struct request_queue *q = rq->q;
+       int cluster, i, high, highprv = 1;
+       unsigned int seg_size, nr_phys_segs;
+       struct bio *fbio;
 
-       if (!rq->bio)
-               return;
+       if (!bio)
+               return 0;
 
+       fbio = bio;
        cluster = test_bit(QUEUE_FLAG_CLUSTER, &q->queue_flags);
        seg_size = 0;
        phys_size = nr_phys_segs = 0;
-       rq_for_each_segment(bv, rq, iter) {
-               /*
-                * the trick here is making sure that a high page is never
-                * considered part of another segment, since that might
-                * change with the bounce page.
-                */
-               high = page_to_pfn(bv->bv_page) > q->bounce_pfn;
-               if (high || highprv)
-                       goto new_segment;
-               if (cluster) {
-                       if (seg_size + bv->bv_len > q->max_segment_size)
-                               goto new_segment;
-                       if (!BIOVEC_PHYS_MERGEABLE(bvprv, bv))
-                               goto new_segment;
-                       if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bv))
+       for_each_bio(bio) {
+               bio_for_each_segment(bv, bio, i) {
+                       /*
+                        * the trick here is making sure that a high page is
+                        * never considered part of another segment, since that
+                        * might change with the bounce page.
+                        */
+                       high = page_to_pfn(bv->bv_page) > q->bounce_pfn;
+                       if (high || highprv)
                                goto new_segment;
+                       if (cluster) {
+                               if (seg_size + bv->bv_len > q->max_segment_size)
+                                       goto new_segment;
+                               if (!BIOVEC_PHYS_MERGEABLE(bvprv, bv))
+                                       goto new_segment;
+                               if (!BIOVEC_SEG_BOUNDARY(q, bvprv, bv))
+                                       goto new_segment;
+
+                               seg_size += bv->bv_len;
+                               bvprv = bv;
+                               continue;
+                       }
+new_segment:
+                       if (nr_phys_segs == 1 && seg_size >
+                           fbio->bi_seg_front_size)
+                               fbio->bi_seg_front_size = seg_size;
 
-                       seg_size += bv->bv_len;
+                       nr_phys_segs++;
                        bvprv = bv;
-                       continue;
+                       seg_size = bv->bv_len;
+                       highprv = high;
                }
-new_segment:
-               if (nr_phys_segs == 1 && seg_size > rq->bio->bi_seg_front_size)
-                       rq->bio->bi_seg_front_size = seg_size;
-
-               nr_phys_segs++;
-               bvprv = bv;
-               seg_size = bv->bv_len;
-               highprv = high;
        }
 
-       if (nr_phys_segs == 1 && seg_size > rq->bio->bi_seg_front_size)
+       if (seg_size_ptr)
+               *seg_size_ptr = seg_size;
+
+       return nr_phys_segs;
+}
+
+void blk_recalc_rq_segments(struct request *rq)
+{
+       unsigned int seg_size = 0, phys_segs;
+
+       phys_segs = __blk_recalc_rq_segments(rq->q, rq->bio, &seg_size);
+
+       if (phys_segs == 1 && seg_size > rq->bio->bi_seg_front_size)
                rq->bio->bi_seg_front_size = seg_size;
        if (seg_size > rq->biotail->bi_seg_back_size)
                rq->biotail->bi_seg_back_size = seg_size;
 
-       rq->nr_phys_segments = nr_phys_segs;
+       rq->nr_phys_segments = phys_segs;
 }
 
 void blk_recount_segments(struct request_queue *q, struct bio *bio)
 {
-       struct request rq;
        struct bio *nxt = bio->bi_next;
-       rq.q = q;
-       rq.bio = rq.biotail = bio;
+
        bio->bi_next = NULL;
-       blk_recalc_rq_segments(&rq);
+       bio->bi_phys_segments = __blk_recalc_rq_segments(q, bio, NULL);
        bio->bi_next = nxt;
-       bio->bi_phys_segments = rq.nr_phys_segments;
        bio->bi_flags |= (1 << BIO_SEG_VALID);
 }
 EXPORT_SYMBOL(blk_recount_segments);
index a09535377a94c0b84a59118533f5e4ddeaa1076d..bbbdc4b8ccf27a9d0d1f4a9648a930b89f8761a0 100644 (file)
@@ -209,12 +209,19 @@ void blk_abort_queue(struct request_queue *q)
 {
        unsigned long flags;
        struct request *rq, *tmp;
+       LIST_HEAD(list);
 
        spin_lock_irqsave(q->queue_lock, flags);
 
        elv_abort_queue(q);
 
-       list_for_each_entry_safe(rq, tmp, &q->timeout_list, timeout_list)
+       /*
+        * Splice entries to local list, to avoid deadlocking if entries
+        * get readded to the timeout list by error handling
+        */
+       list_splice_init(&q->timeout_list, &list);
+
+       list_for_each_entry_safe(rq, tmp, &list, timeout_list)
                blk_abort_request(rq);
 
        spin_unlock_irqrestore(q->queue_lock, flags);
index 39cc3bfe56e41055793a804e1461dad39045b264..7cf9d1ff45a015e0d8fe7be2546c6fb7f95f590e 100644 (file)
@@ -142,7 +142,7 @@ static void __blk_add_trace(struct blk_trace *bt, sector_t sector, int bytes,
 
        what |= ddir_act[rw & WRITE];
        what |= MASK_TC_BIT(rw, BARRIER);
-       what |= MASK_TC_BIT(rw, SYNC);
+       what |= MASK_TC_BIT(rw, SYNCIO);
        what |= MASK_TC_BIT(rw, AHEAD);
        what |= MASK_TC_BIT(rw, META);
        what |= MASK_TC_BIT(rw, DISCARD);
index d414bb5607e89f4e3a05466b2a488db5e79c98a3..0ce8806dd0c1a3786b6cd86ba8a90b743ca81b8d 100644 (file)
@@ -244,7 +244,8 @@ bsg_validate_sgv4_hdr(struct request_queue *q, struct sg_io_v4 *hdr, int *rw)
  * map sg_io_v4 to a request.
  */
 static struct request *
-bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm)
+bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm,
+           u8 *sense)
 {
        struct request_queue *q = bd->queue;
        struct request *rq, *next_rq = NULL;
@@ -306,6 +307,10 @@ bsg_map_hdr(struct bsg_device *bd, struct sg_io_v4 *hdr, fmode_t has_write_perm)
                if (ret)
                        goto out;
        }
+
+       rq->sense = sense;
+       rq->sense_len = 0;
+
        return rq;
 out:
        if (rq->cmd != rq->__cmd)
@@ -348,9 +353,6 @@ static void bsg_rq_end_io(struct request *rq, int uptodate)
 static void bsg_add_command(struct bsg_device *bd, struct request_queue *q,
                            struct bsg_command *bc, struct request *rq)
 {
-       rq->sense = bc->sense;
-       rq->sense_len = 0;
-
        /*
         * add bc command to busy queue and submit rq for io
         */
@@ -419,7 +421,7 @@ static int blk_complete_sgv4_hdr_rq(struct request *rq, struct sg_io_v4 *hdr,
 {
        int ret = 0;
 
-       dprintk("rq %p bio %p %u\n", rq, bio, rq->errors);
+       dprintk("rq %p bio %p 0x%x\n", rq, bio, rq->errors);
        /*
         * fill in all the output members
         */
@@ -635,7 +637,7 @@ static int __bsg_write(struct bsg_device *bd, const char __user *buf,
                /*
                 * get a request, fill in the blanks, and add to request queue
                 */
-               rq = bsg_map_hdr(bd, &bc->hdr, has_write_perm);
+               rq = bsg_map_hdr(bd, &bc->hdr, has_write_perm, bc->sense);
                if (IS_ERR(rq)) {
                        ret = PTR_ERR(rq);
                        rq = NULL;
@@ -922,11 +924,12 @@ static long bsg_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                struct request *rq;
                struct bio *bio, *bidi_bio = NULL;
                struct sg_io_v4 hdr;
+               u8 sense[SCSI_SENSE_BUFFERSIZE];
 
                if (copy_from_user(&hdr, uarg, sizeof(hdr)))
                        return -EFAULT;
 
-               rq = bsg_map_hdr(bd, &hdr, file->f_mode & FMODE_WRITE);
+               rq = bsg_map_hdr(bd, &hdr, file->f_mode & FMODE_WRITE, sense);
                if (IS_ERR(rq))
                        return PTR_ERR(rq);
 
index 397960cf26afcd61fc7c2bba2365944c8485c767..a9ec910974c1934675b887d2fc8c2d0703579b01 100644 (file)
@@ -256,6 +256,22 @@ void blkdev_show(struct seq_file *seqf, off_t offset)
 }
 #endif /* CONFIG_PROC_FS */
 
+/**
+ * register_blkdev - register a new block device
+ *
+ * @major: the requested major device number [1..255]. If @major=0, try to
+ *         allocate any unused major number.
+ * @name: the name of the new block device as a zero terminated string
+ *
+ * The @name must be unique within the system.
+ *
+ * The return value depends on the @major input parameter.
+ *  - if a major device number was requested in range [1..255] then the
+ *    function returns zero on success, or a negative error code
+ *  - if any unused major number was requested with @major=0 parameter
+ *    then the return value is the allocated major number in range
+ *    [1..255] or a negative error code otherwise
+ */
 int register_blkdev(unsigned int major, const char *name)
 {
        struct blk_major_name **n, *p;
@@ -1087,6 +1103,14 @@ dev_t blk_lookup_devt(const char *name, int partno)
                if (strcmp(dev_name(dev), name))
                        continue;
 
+               if (partno < disk->minors) {
+                       /* We need to return the right devno, even
+                        * if the partition doesn't exist yet.
+                        */
+                       devt = MKDEV(MAJOR(dev->devt),
+                                    MINOR(dev->devt) + partno);
+                       break;
+               }
                part = disk_get_part(disk, partno);
                if (part) {
                        devt = part_devt(part);
index ba5292d69ebd206cdbf9961e130cf089dc584dd2..b2d1ee32cfe829c774071367b5e40a9d5553dc3f 100644 (file)
@@ -214,7 +214,7 @@ static void crypto_ahash_show(struct seq_file *m, struct crypto_alg *alg)
        seq_printf(m, "async        : %s\n", alg->cra_flags & CRYPTO_ALG_ASYNC ?
                                             "yes" : "no");
        seq_printf(m, "blocksize    : %u\n", alg->cra_blocksize);
-       seq_printf(m, "digestsize   : %u\n", alg->cra_hash.digestsize);
+       seq_printf(m, "digestsize   : %u\n", alg->cra_ahash.digestsize);
 }
 
 const struct crypto_type crypto_ahash_type = {
index efe77df6863f4378f4f0da414591f940870b76ea..38a2bc02a98c7f6648f7a7a3388c6182b88c07f9 100644 (file)
@@ -215,8 +215,19 @@ struct crypto_alg *crypto_larval_lookup(const char *name, u32 type, u32 mask)
        mask &= ~(CRYPTO_ALG_LARVAL | CRYPTO_ALG_DEAD);
        type &= mask;
 
-       alg = try_then_request_module(crypto_alg_lookup(name, type, mask),
-                                     name);
+       alg = crypto_alg_lookup(name, type, mask);
+       if (!alg) {
+               char tmp[CRYPTO_MAX_ALG_NAME];
+
+               request_module(name);
+
+               if (!((type ^ CRYPTO_ALG_NEED_FALLBACK) & mask) &&
+                   snprintf(tmp, sizeof(tmp), "%s-all", name) < sizeof(tmp))
+                       request_module(tmp);
+
+               alg = crypto_alg_lookup(name, type, mask);
+       }
+
        if (alg)
                return crypto_is_larval(alg) ? crypto_larval_wait(alg) : alg;
 
index 8ef664e3bcd9a90c93a5436e551549e72df1ff82..358f80be2bf97d128ebd648887325a01ea051a70 100644 (file)
@@ -45,7 +45,13 @@ struct priv {
 
 static inline void setbit128_bbe(void *b, int bit)
 {
-       __set_bit(bit ^ 0x78, b);
+       __set_bit(bit ^ (0x80 -
+#ifdef __BIG_ENDIAN
+                        BITS_PER_LONG
+#else
+                        BITS_PER_BYTE
+#endif
+                       ), b);
 }
 
 static int setkey(struct crypto_tfm *parent, const u8 *key,
index a7799a99f2d9a192b2b98ed5e0bdb5d5c9796f56..8a851d0f438458392f03fce3c8ded88957f96124 100644 (file)
@@ -254,13 +254,6 @@ config ACPI_PCI_SLOT
          help you correlate PCI bus addresses with the physical geography
          of your slots. If you are unsure, say N.
 
-config ACPI_SYSTEM
-       bool
-       default y
-       help
-         This driver will enable your system to shut down using ACPI, and
-         dump your ACPI DSDT table using /proc/acpi/dsdt.
-
 config X86_PM_TIMER
        bool "Power Management Timer Support" if EMBEDDED
        depends on X86
index 65d90c720b5a63995179235af6683577e112cc44..b130ea0d0759a3f95c8b81d3c203e4bdea1c5820 100644 (file)
@@ -52,7 +52,7 @@ obj-$(CONFIG_ACPI_PROCESSOR)  += processor.o
 obj-$(CONFIG_ACPI_CONTAINER)   += container.o
 obj-$(CONFIG_ACPI_THERMAL)     += thermal.o
 obj-y                          += power.o
-obj-$(CONFIG_ACPI_SYSTEM)      += system.o event.o
+obj-y                          += system.o event.o
 obj-$(CONFIG_ACPI_DEBUG)       += debug.o
 obj-$(CONFIG_ACPI_NUMA)                += numa.o
 obj-$(CONFIG_ACPI_HOTPLUG_MEMORY)      += acpi_memhotplug.o
index 65132f9204596eb9908b8e0424531ec682a8b731..69cbc57c2d1cd248e7431bb40661e9ea139efbb7 100644 (file)
@@ -138,6 +138,29 @@ static int acpi_battery_technology(struct acpi_battery *battery)
 
 static int acpi_battery_get_state(struct acpi_battery *battery);
 
+static int acpi_battery_is_charged(struct acpi_battery *battery)
+{
+       /* either charging or discharging */
+       if (battery->state != 0)
+               return 0;
+
+       /* battery not reporting charge */
+       if (battery->capacity_now == ACPI_BATTERY_VALUE_UNKNOWN ||
+           battery->capacity_now == 0)
+               return 0;
+
+       /* good batteries update full_charge as the batteries degrade */
+       if (battery->full_charge_capacity == battery->capacity_now)
+               return 1;
+
+       /* fallback to using design values for broken batteries */
+       if (battery->design_capacity == battery->capacity_now)
+               return 1;
+
+       /* we don't do any sort of metric based on percentages */
+       return 0;
+}
+
 static int acpi_battery_get_property(struct power_supply *psy,
                                     enum power_supply_property psp,
                                     union power_supply_propval *val)
@@ -155,7 +178,7 @@ static int acpi_battery_get_property(struct power_supply *psy,
                        val->intval = POWER_SUPPLY_STATUS_DISCHARGING;
                else if (battery->state & 0x02)
                        val->intval = POWER_SUPPLY_STATUS_CHARGING;
-               else if (battery->state == 0)
+               else if (acpi_battery_is_charged(battery))
                        val->intval = POWER_SUPPLY_STATUS_FULL;
                else
                        val->intval = POWER_SUPPLY_STATUS_UNKNOWN;
index 5c2f5d343be6185fc552c0181c194429fdccb027..2fe15060dcdc2c3a51dd9f3ef20171e0b4e50c8e 100644 (file)
@@ -120,6 +120,8 @@ static struct acpi_ec {
        spinlock_t curr_lock;
 } *boot_ec, *first_ec;
 
+static int EC_FLAGS_MSI; /* Out-of-spec MSI controller */
+
 /* --------------------------------------------------------------------------
                              Transaction Management
    -------------------------------------------------------------------------- */
@@ -259,6 +261,8 @@ static int acpi_ec_transaction_unlocked(struct acpi_ec *ec,
                clear_bit(EC_FLAGS_GPE_MODE, &ec->flags);
                acpi_disable_gpe(NULL, ec->gpe);
        }
+       if (EC_FLAGS_MSI)
+               udelay(ACPI_EC_DELAY);
        /* start transaction */
        spin_lock_irqsave(&ec->curr_lock, tmp);
        /* following two actions should be kept atomic */
@@ -967,6 +971,11 @@ int __init acpi_ec_ecdt_probe(void)
        /*
         * Generate a boot ec context
         */
+       if (dmi_name_in_vendors("Micro-Star") ||
+           dmi_name_in_vendors("Notebook")) {
+               pr_info(PREFIX "Enabling special treatment for EC from MSI.\n");
+               EC_FLAGS_MSI = 1;
+       }
        status = acpi_get_table(ACPI_SIG_ECDT, 1,
                                (struct acpi_table_header **)&ecdt_ptr);
        if (ACPI_SUCCESS(status)) {
index 0b299b0f81721bbe1446169b8fa5b51c86eecd2d..714cb046b594200a17d096768f0d8a45f89a835a 100644 (file)
@@ -773,18 +773,32 @@ unsigned int ata_sff_data_xfer32(struct ata_device *dev, unsigned char *buf,
        else
                iowrite32_rep(data_addr, buf, words);
 
+       /* Transfer trailing bytes, if any */
        if (unlikely(slop)) {
-               __le32 pad;
+               unsigned char pad[4];
+
+               /* Point buf to the tail of buffer */
+               buf += buflen - slop;
+
+               /*
+                * Use io*_rep() accessors here as well to avoid pointlessly
+                * swapping bytes to and fro on the big endian machines...
+                */
                if (rw == READ) {
-                       pad = cpu_to_le32(ioread32(ap->ioaddr.data_addr));
-                       memcpy(buf + buflen - slop, &pad, slop);
+                       if (slop < 3)
+                               ioread16_rep(data_addr, pad, 1);
+                       else
+                               ioread32_rep(data_addr, pad, 1);
+                       memcpy(buf, pad, slop);
                } else {
-                       memcpy(&pad, buf + buflen - slop, slop);
-                       iowrite32(le32_to_cpu(pad), ap->ioaddr.data_addr);
+                       memcpy(pad, buf, slop);
+                       if (slop < 3)
+                               iowrite16_rep(data_addr, pad, 1);
+                       else
+                               iowrite32_rep(data_addr, pad, 1);
                }
-               words++;
        }
-       return words << 2;
+       return (buflen + 1) & ~1;
 }
 EXPORT_SYMBOL_GPL(ata_sff_data_xfer32);
 
index 63719ab9ea4448839d64d81faa187250ef21637d..115b1cd6dcf55c32afbe5ec2ab348b3f438db34f 100644 (file)
@@ -24,7 +24,7 @@
 #include <linux/libata.h>
 
 #define DRV_NAME "pata_amd"
-#define DRV_VERSION "0.3.11"
+#define DRV_VERSION "0.4.1"
 
 /**
  *     timing_setup            -       shared timing computation and load
@@ -145,6 +145,13 @@ static int amd_pre_reset(struct ata_link *link, unsigned long deadline)
        return ata_sff_prereset(link, deadline);
 }
 
+/**
+ *     amd_cable_detect        -       report cable type
+ *     @ap: port
+ *
+ *     AMD controller/BIOS setups record the cable type in word 0x42
+ */
+
 static int amd_cable_detect(struct ata_port *ap)
 {
        static const u32 bitmask[2] = {0x03, 0x0C};
@@ -157,6 +164,40 @@ static int amd_cable_detect(struct ata_port *ap)
        return ATA_CBL_PATA40;
 }
 
+/**
+ *     amd_fifo_setup          -       set the PIO FIFO for ATA/ATAPI
+ *     @ap: ATA interface
+ *     @adev: ATA device
+ *
+ *     Set the PCI fifo for this device according to the devices present
+ *     on the bus at this point in time. We need to turn the post write buffer
+ *     off for ATAPI devices as we may need to issue a word sized write to the
+ *     device as the final I/O
+ */
+
+static void amd_fifo_setup(struct ata_port *ap)
+{
+       struct ata_device *adev;
+       struct pci_dev *pdev = to_pci_dev(ap->host->dev);
+       static const u8 fifobit[2] = { 0xC0, 0x30};
+       u8 fifo = fifobit[ap->port_no];
+       u8 r;
+
+
+       ata_for_each_dev(adev, &ap->link, ENABLED) {
+               if (adev->class == ATA_DEV_ATAPI)
+                       fifo = 0;
+       }
+       if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7411) /* FIFO is broken */
+               fifo = 0;
+
+       /* On the later chips the read prefetch bits become no-op bits */
+       pci_read_config_byte(pdev, 0x41, &r);
+       r &= ~fifobit[ap->port_no];
+       r |= fifo;
+       pci_write_config_byte(pdev, 0x41, r);
+}
+
 /**
  *     amd33_set_piomode       -       set initial PIO mode data
  *     @ap: ATA interface
@@ -167,21 +208,25 @@ static int amd_cable_detect(struct ata_port *ap)
 
 static void amd33_set_piomode(struct ata_port *ap, struct ata_device *adev)
 {
+       amd_fifo_setup(ap);
        timing_setup(ap, adev, 0x40, adev->pio_mode, 1);
 }
 
 static void amd66_set_piomode(struct ata_port *ap, struct ata_device *adev)
 {
+       amd_fifo_setup(ap);
        timing_setup(ap, adev, 0x40, adev->pio_mode, 2);
 }
 
 static void amd100_set_piomode(struct ata_port *ap, struct ata_device *adev)
 {
+       amd_fifo_setup(ap);
        timing_setup(ap, adev, 0x40, adev->pio_mode, 3);
 }
 
 static void amd133_set_piomode(struct ata_port *ap, struct ata_device *adev)
 {
+       amd_fifo_setup(ap);
        timing_setup(ap, adev, 0x40, adev->pio_mode, 4);
 }
 
@@ -397,6 +442,16 @@ static struct ata_port_operations nv133_port_ops = {
        .set_dmamode    = nv133_set_dmamode,
 };
 
+static void amd_clear_fifo(struct pci_dev *pdev)
+{
+       u8 fifo;
+       /* Disable the FIFO, the FIFO logic will re-enable it as
+          appropriate */
+       pci_read_config_byte(pdev, 0x41, &fifo);
+       fifo &= 0x0F;
+       pci_write_config_byte(pdev, 0x41, fifo);
+}
+
 static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        static const struct ata_port_info info[10] = {
@@ -503,14 +558,8 @@ static int amd_init_one(struct pci_dev *pdev, const struct pci_device_id *id)
 
        if (type < 3)
                ata_pci_bmdma_clear_simplex(pdev);
-
-       /* Check for AMD7411 */
-       if (type == 3)
-               /* FIFO is broken */
-               pci_write_config_byte(pdev, 0x41, fifo & 0x0F);
-       else
-               pci_write_config_byte(pdev, 0x41, fifo | 0xF0);
-
+       if (pdev->vendor == PCI_VENDOR_ID_AMD)
+               amd_clear_fifo(pdev);
        /* Cable detection on Nvidia chips doesn't work too well,
         * cache BIOS programmed UDMA mode.
         */
@@ -536,18 +585,11 @@ static int amd_reinit_one(struct pci_dev *pdev)
                return rc;
 
        if (pdev->vendor == PCI_VENDOR_ID_AMD) {
-               u8 fifo;
-               pci_read_config_byte(pdev, 0x41, &fifo);
-               if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7411)
-                       /* FIFO is broken */
-                       pci_write_config_byte(pdev, 0x41, fifo & 0x0F);
-               else
-                       pci_write_config_byte(pdev, 0x41, fifo | 0xF0);
+               amd_clear_fifo(pdev);
                if (pdev->device == PCI_DEVICE_ID_AMD_VIPER_7409 ||
                    pdev->device == PCI_DEVICE_ID_AMD_COBRA_7401)
                        ata_pci_bmdma_clear_simplex(pdev);
        }
-
        ata_host_resume(host);
        return 0;
 }
index f1bb2f9fecbf347b50bb5d76253b6c6bb67e31b9..b05b86a912c5ddb7f7ae14a20bd15af76e61da54 100644 (file)
@@ -557,6 +557,9 @@ static unsigned int it821x_read_id(struct ata_device *adev,
                id[83] |= 0x4400;       /* Word 83 is valid and LBA48 */
                id[86] |= 0x0400;       /* LBA48 on */
                id[ATA_ID_MAJOR_VER] |= 0x1F;
+               /* Clear the serial number because it's different each boot
+                  which breaks validation on resume */
+               memset(&id[ATA_ID_SERNO], 0x20, ATA_ID_SERNO_LEN);
        }
        return err_mask;
 }
index 6c1d778b63a9cd58a06dc4772fcfc15f8350d428..e3bc1b436284bfa42ac977fe372c98340df24b2d 100644 (file)
@@ -283,9 +283,10 @@ static void pdc20230_set_piomode(struct ata_port *ap, struct ata_device *adev)
 static unsigned int pdc_data_xfer_vlb(struct ata_device *dev,
                        unsigned char *buf, unsigned int buflen, int rw)
 {
-       if (ata_id_has_dword_io(dev->id)) {
+       int slop = buflen & 3;
+       /* 32bit I/O capable *and* we need to write a whole number of dwords */
+       if (ata_id_has_dword_io(dev->id) && (slop == 0 || slop == 3)) {
                struct ata_port *ap = dev->link->ap;
-               int slop = buflen & 3;
                unsigned long flags;
 
                local_irq_save(flags);
@@ -735,7 +736,7 @@ static unsigned int vlb32_data_xfer(struct ata_device *adev, unsigned char *buf,
        struct ata_port *ap = adev->link->ap;
        int slop = buflen & 3;
 
-       if (ata_id_has_dword_io(adev->id)) {
+       if (ata_id_has_dword_io(adev->id) && (slop == 0 || slop == 3)) {
                if (rw == WRITE)
                        iowrite32_rep(ap->ioaddr.data_addr, buf, buflen >> 2);
                else
index 79a6c9a0b721b5caacb43c9785bebb877d16c9d1..ba556d3e696368ecea761e4440f82434695318f9 100644 (file)
@@ -110,7 +110,8 @@ static const struct via_isa_bridge {
        { "vt8237s",    PCI_DEVICE_ID_VIA_8237S,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
        { "vt8251",     PCI_DEVICE_ID_VIA_8251,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
        { "cx700",      PCI_DEVICE_ID_VIA_CX700,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_SATA_PATA },
-       { "vt6410",     PCI_DEVICE_ID_VIA_6410,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES},
+       { "vt6410",     PCI_DEVICE_ID_VIA_6410,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES },
+       { "vt6415",     PCI_DEVICE_ID_VIA_6415,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST | VIA_NO_ENABLES },
        { "vt8237a",    PCI_DEVICE_ID_VIA_8237A,    0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
        { "vt8237",     PCI_DEVICE_ID_VIA_8237,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
        { "vt8235",     PCI_DEVICE_ID_VIA_8235,     0x00, 0x2f, VIA_UDMA_133 | VIA_BAD_AST },
@@ -593,6 +594,7 @@ static int via_reinit_one(struct pci_dev *pdev)
 #endif
 
 static const struct pci_device_id via[] = {
+       { PCI_VDEVICE(VIA, 0x0415), },
        { PCI_VDEVICE(VIA, 0x0571), },
        { PCI_VDEVICE(VIA, 0x0581), },
        { PCI_VDEVICE(VIA, 0x1571), },
index 4ae1a4138b47078072bedf2e889338e6bd8a0cb2..7007edd2d4517fed1a5b75773622cae9da003e44 100644 (file)
@@ -3114,19 +3114,17 @@ static int mv_init_host(struct ata_host *host, unsigned int board_idx)
                writelfl(0, hc_mmio + HC_IRQ_CAUSE_OFS);
        }
 
-       if (!IS_SOC(hpriv)) {
-               /* Clear any currently outstanding host interrupt conditions */
-               writelfl(0, mmio + hpriv->irq_cause_ofs);
+       /* Clear any currently outstanding host interrupt conditions */
+       writelfl(0, mmio + hpriv->irq_cause_ofs);
 
-               /* and unmask interrupt generation for host regs */
-               writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
+       /* and unmask interrupt generation for host regs */
+       writelfl(hpriv->unmask_all_irqs, mmio + hpriv->irq_mask_ofs);
 
-               /*
-                * enable only global host interrupts for now.
-                * The per-port interrupts get done later as ports are set up.
-                */
-               mv_set_main_irq_mask(host, 0, PCI_ERR);
-       }
+       /*
+        * enable only global host interrupts for now.
+        * The per-port interrupts get done later as ports are set up.
+        */
+       mv_set_main_irq_mask(host, 0, PCI_ERR);
 done:
        return rc;
 }
index 444af0415ca167b67f91adbf6ae24a5507c78987..55a8eed3f3a35cb9fa64b9e67800a40d72d5d062 100644 (file)
@@ -421,19 +421,21 @@ static struct ata_port_operations nv_generic_ops = {
        .hardreset              = ATA_OP_NULL,
 };
 
-/* OSDL bz3352 reports that nf2/3 controllers can't determine device
- * signature reliably.  Also, the following thread reports detection
- * failure on cold boot with the standard debouncing timing.
+/* nf2 is ripe with hardreset related problems.
+ *
+ * kernel bz#3352 reports nf2/3 controllers can't determine device
+ * signature reliably.  The following thread reports detection failure
+ * on cold boot with the standard debouncing timing.
  *
  * http://thread.gmane.org/gmane.linux.ide/34098
  *
- * Debounce with hotplug timing and request follow-up SRST.
+ * And bz#12176 reports that hardreset simply doesn't work on nf2.
+ * Give up on it and just don't do hardreset.
  */
 static struct ata_port_operations nv_nf2_ops = {
-       .inherits               = &nv_common_ops,
+       .inherits               = &nv_generic_ops,
        .freeze                 = nv_nf2_freeze,
        .thaw                   = nv_nf2_thaw,
-       .hardreset              = nv_noclassify_hardreset,
 };
 
 /* For initial probing after boot and hot plugging, hardreset mostly
index 98099f526d82663343bf85bae33781616fe5e651..b119640e1ee9d0f6403aae0a3156405e6a72c7bc 100644 (file)
@@ -1690,17 +1690,17 @@ static int __devinit fs_init (struct fs_dev *dev)
                  | (0 * SARMODE0_SHADEN) /* We don't use shadow registers. */
                  | (1 * SARMODE0_INTMODE_READCLEAR)
                  | (1 * SARMODE0_CWRE)
-                 | IS_FS50(dev)?SARMODE0_PRPWT_FS50_5: 
-                                SARMODE0_PRPWT_FS155_3
+                 | (IS_FS50(dev) ? SARMODE0_PRPWT_FS50_5:
+                         SARMODE0_PRPWT_FS155_3)
                  | (1 * SARMODE0_CALSUP_1)
-                 | IS_FS50 (dev)?(0
+                 | (IS_FS50(dev) ? (0
                                   | SARMODE0_RXVCS_32
                                   | SARMODE0_ABRVCS_32 
                                   | SARMODE0_TXVCS_32):
                                  (0
                                   | SARMODE0_RXVCS_1k
                                   | SARMODE0_ABRVCS_1k 
-                                  | SARMODE0_TXVCS_1k));
+                                  | SARMODE0_TXVCS_1k)));
 
        /* 10ms * 100 is 1 second. That should be enough, as AN3:9 says it takes
           1ms. */
index e1c7611e9144cdcd0d6b50d0acf284da77a0a4d7..78c9736c3579beba974dc546cbd4bfbe8298bcf4 100644 (file)
@@ -977,9 +977,7 @@ static void xdump( u_char*  cp, int  length, char*  prefix )
             else
                 pBuf += sprintf( pBuf, "." );
                 }
-        sprintf( pBuf, "\n" );
-        // SPrint(prntBuf);
-        printk(prntBuf);
+        printk("%s\n", prntBuf);
         count += col;
         pBuf = prntBuf;
     }
index 144a49f152207402c044caca1c0c8dde47f10747..8733a2ea04c2b39a02fede69c6e4dbd69035cd3a 100644 (file)
@@ -901,7 +901,7 @@ static int __devinit eeprom_read(struct lanai_dev *lanai)
                clock_l(); udelay(5);
                for (i = 128; i != 0; i >>= 1) {   /* write command out */
                        tmp = (lanai->conf1 & ~CONFIG1_PROMDATA) |
-                           (data & i) ? CONFIG1_PROMDATA : 0;
+                           ((data & i) ? CONFIG1_PROMDATA : 0);
                        if (lanai->conf1 != tmp) {
                                set_config1(tmp);
                                udelay(5);      /* Let new data settle */
diff --git a/drivers/atm/solos-attrlist.c b/drivers/atm/solos-attrlist.c
new file mode 100644 (file)
index 0000000..efa2808
--- /dev/null
@@ -0,0 +1,70 @@
+SOLOS_ATTR_RO(DriverVersion)
+SOLOS_ATTR_RO(APIVersion)
+SOLOS_ATTR_RO(FirmwareVersion)
+// SOLOS_ATTR_RO(DspVersion)
+// SOLOS_ATTR_RO(CommonHandshake)
+SOLOS_ATTR_RO(Connected)
+SOLOS_ATTR_RO(OperationalMode)
+SOLOS_ATTR_RO(State)
+SOLOS_ATTR_RO(Watchdog)
+SOLOS_ATTR_RO(OperationProgress)
+SOLOS_ATTR_RO(LastFailed)
+SOLOS_ATTR_RO(TxBitRate)
+SOLOS_ATTR_RO(RxBitRate)
+// SOLOS_ATTR_RO(DeltACTATPds)
+// SOLOS_ATTR_RO(DeltACTATPus)
+SOLOS_ATTR_RO(TxATTNDR)
+SOLOS_ATTR_RO(RxATTNDR)
+SOLOS_ATTR_RO(AnnexType)
+SOLOS_ATTR_RO(GeneralFailure)
+SOLOS_ATTR_RO(InterleaveDpDn)
+SOLOS_ATTR_RO(InterleaveDpUp)
+SOLOS_ATTR_RO(RSCorrectedErrorsDn)
+SOLOS_ATTR_RO(RSUnCorrectedErrorsDn)
+SOLOS_ATTR_RO(RSCorrectedErrorsUp)
+SOLOS_ATTR_RO(RSUnCorrectedErrorsUp)
+SOLOS_ATTR_RO(InterleaveRDn)
+SOLOS_ATTR_RO(InterleaveRUp)
+SOLOS_ATTR_RO(ShowtimeStart)
+SOLOS_ATTR_RO(ATURVendor)
+SOLOS_ATTR_RO(ATUCCountry)
+SOLOS_ATTR_RO(ATURANSIRev)
+SOLOS_ATTR_RO(ATURANSISTD)
+SOLOS_ATTR_RO(ATUCANSIRev)
+SOLOS_ATTR_RO(ATUCANSIId)
+SOLOS_ATTR_RO(ATUCANSISTD)
+SOLOS_ATTR_RO(DataBoost)
+SOLOS_ATTR_RO(LocalITUCountryCode)
+SOLOS_ATTR_RO(LocalSEF)
+SOLOS_ATTR_RO(LocalEndLOS)
+SOLOS_ATTR_RO(LocalSNRMargin)
+SOLOS_ATTR_RO(LocalLineAttn)
+SOLOS_ATTR_RO(RawAttn)
+SOLOS_ATTR_RO(LocalTxPower)
+SOLOS_ATTR_RO(RemoteTxPower)
+SOLOS_ATTR_RO(RemoteSEF)
+SOLOS_ATTR_RO(RemoteLOS)
+SOLOS_ATTR_RO(RemoteLineAttn)
+SOLOS_ATTR_RO(RemoteSNRMargin)
+SOLOS_ATTR_RO(LineUpCount)
+SOLOS_ATTR_RO(SRACnt)
+SOLOS_ATTR_RO(SRACntUp)
+SOLOS_ATTR_RO(ProfileStatus)
+SOLOS_ATTR_RW(Action)
+SOLOS_ATTR_RW(ActivateLine)
+SOLOS_ATTR_RO(LineStatus)
+SOLOS_ATTR_RW(HostControl)
+SOLOS_ATTR_RW(AutoStart)
+SOLOS_ATTR_RW(Failsafe)
+SOLOS_ATTR_RW(ShowtimeLed)
+SOLOS_ATTR_RW(Retrain)
+SOLOS_ATTR_RW(Defaults)
+SOLOS_ATTR_RW(LineMode)
+SOLOS_ATTR_RW(Profile)
+SOLOS_ATTR_RW(DetectNoise)
+SOLOS_ATTR_RO(SupportedAnnexes)
+SOLOS_ATTR_RO(Status)
+SOLOS_ATTR_RO(TotalStart)
+SOLOS_ATTR_RO(RecentShowtimeStart)
+SOLOS_ATTR_RO(TotalRxBlocks)
+SOLOS_ATTR_RO(TotalTxBlocks)
index 89d7a6e94c9c8245298e8dbcb449f7bf7fc0a4e9..be204308cc1b1d6a222c85aa6d5fcde6063009f3 100644 (file)
@@ -9,6 +9,7 @@
  *
  * Authors: Nathan Williams <nathan@traverse.com.au>
  *          David Woodhouse <dwmw2@infradead.org>
+ *          Treker Chen <treker@xrio.com>
  *
  * This program is free software; you can redistribute it and/or
  * modify it under the terms of the GNU General Public License
 #include <linux/sysfs.h>
 #include <linux/device.h>
 #include <linux/kobject.h>
+#include <linux/firmware.h>
+#include <linux/ctype.h>
+#include <linux/swab.h>
 
-#define VERSION "0.04"
+#define VERSION "0.07"
 #define PTAG "solos-pci"
 
 #define CONFIG_RAM_SIZE        128
 #define IRQ_EN_ADDR    0x78
 #define FPGA_VER       0x74
 #define IRQ_CLEAR      0x70
-#define BUG_FLAG       0x6C
+#define WRITE_FLASH    0x6C
+#define PORTS          0x68
+#define FLASH_BLOCK    0x64
+#define FLASH_BUSY     0x60
+#define FPGA_MODE      0x5C
+#define FLASH_MODE     0x58
+#define TX_DMA_ADDR(port)      (0x40 + (4 * (port)))
+#define RX_DMA_ADDR(port)      (0x30 + (4 * (port)))
 
 #define DATA_RAM_SIZE  32768
 #define BUF_SIZE       4096
+#define FPGA_PAGE      528 /* FPGA flash page size*/
+#define SOLOS_PAGE     512 /* Solos flash page size*/
+#define FPGA_BLOCK     (FPGA_PAGE * 8) /* FPGA flash block size*/
+#define SOLOS_BLOCK    (SOLOS_PAGE * 8) /* Solos flash block size*/
 
 #define RX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2)
 #define TX_BUF(card, nr) ((card->buffers) + (nr)*BUF_SIZE*2 + BUF_SIZE)
 
-static int debug = 0;
+#define RX_DMA_SIZE    2048
+
+static int reset = 0;
 static int atmdebug = 0;
+static int firmware_upgrade = 0;
+static int fpga_upgrade = 0;
 
 struct pkt_hdr {
        __le16 size;
@@ -63,23 +82,48 @@ struct pkt_hdr {
        __le16 type;
 };
 
+struct solos_skb_cb {
+       struct atm_vcc *vcc;
+       uint32_t dma_addr;
+};
+
+
+#define SKB_CB(skb)            ((struct solos_skb_cb *)skb->cb)
+
 #define PKT_DATA       0
 #define PKT_COMMAND    1
 #define PKT_POPEN      3
 #define PKT_PCLOSE     4
+#define PKT_STATUS     5
 
 struct solos_card {
        void __iomem *config_regs;
        void __iomem *buffers;
        int nr_ports;
+       int tx_mask;
        struct pci_dev *dev;
        struct atm_dev *atmdev[4];
        struct tasklet_struct tlet;
        spinlock_t tx_lock;
        spinlock_t tx_queue_lock;
        spinlock_t cli_queue_lock;
+       spinlock_t param_queue_lock;
+       struct list_head param_queue;
        struct sk_buff_head tx_queue[4];
        struct sk_buff_head cli_queue[4];
+       struct sk_buff *tx_skb[4];
+       struct sk_buff *rx_skb[4];
+       wait_queue_head_t param_wq;
+       wait_queue_head_t fw_wq;
+       int using_dma;
+};
+
+
+struct solos_param {
+       struct list_head list;
+       pid_t pid;
+       int port;
+       struct sk_buff *response;
 };
 
 #define SOLOS_CHAN(atmdev) ((int)(unsigned long)(atmdev)->phy_data)
@@ -88,19 +132,22 @@ MODULE_AUTHOR("Traverse Technologies <support@traverse.com.au>");
 MODULE_DESCRIPTION("Solos PCI driver");
 MODULE_VERSION(VERSION);
 MODULE_LICENSE("GPL");
-MODULE_PARM_DESC(debug, "Enable Loopback");
+MODULE_PARM_DESC(reset, "Reset Solos chips on startup");
 MODULE_PARM_DESC(atmdebug, "Print ATM data");
-module_param(debug, int, 0444);
-module_param(atmdebug, int, 0444);
-
-static int opens;
+MODULE_PARM_DESC(firmware_upgrade, "Initiate Solos firmware upgrade");
+MODULE_PARM_DESC(fpga_upgrade, "Initiate FPGA upgrade");
+module_param(reset, int, 0444);
+module_param(atmdebug, int, 0644);
+module_param(firmware_upgrade, int, 0444);
+module_param(fpga_upgrade, int, 0444);
 
 static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
                       struct atm_vcc *vcc);
-static int fpga_tx(struct solos_card *);
+static uint32_t fpga_tx(struct solos_card *);
 static irqreturn_t solos_irq(int irq, void *dev_id);
 static struct atm_vcc* find_vcc(struct atm_dev *dev, short vpi, int vci);
 static int list_vccs(int vci);
+static void release_vccs(struct atm_dev *dev);
 static int atm_init(struct solos_card *);
 static void atm_remove(struct solos_card *);
 static int send_command(struct solos_card *card, int dev, const char *buf, size_t size);
@@ -115,6 +162,264 @@ static inline void solos_pop(struct atm_vcc *vcc, struct sk_buff *skb)
                 dev_kfree_skb_any(skb);
 }
 
+static ssize_t solos_param_show(struct device *dev, struct device_attribute *attr,
+                               char *buf)
+{
+       struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev);
+       struct solos_card *card = atmdev->dev_data;
+       struct solos_param prm;
+       struct sk_buff *skb;
+       struct pkt_hdr *header;
+       int buflen;
+
+       buflen = strlen(attr->attr.name) + 10;
+
+       skb = alloc_skb(sizeof(*header) + buflen, GFP_KERNEL);
+       if (!skb) {
+               dev_warn(&card->dev->dev, "Failed to allocate sk_buff in solos_param_show()\n");
+               return -ENOMEM;
+       }
+
+       header = (void *)skb_put(skb, sizeof(*header));
+
+       buflen = snprintf((void *)&header[1], buflen - 1,
+                         "L%05d\n%s\n", current->pid, attr->attr.name);
+       skb_put(skb, buflen);
+
+       header->size = cpu_to_le16(buflen);
+       header->vpi = cpu_to_le16(0);
+       header->vci = cpu_to_le16(0);
+       header->type = cpu_to_le16(PKT_COMMAND);
+
+       prm.pid = current->pid;
+       prm.response = NULL;
+       prm.port = SOLOS_CHAN(atmdev);
+
+       spin_lock_irq(&card->param_queue_lock);
+       list_add(&prm.list, &card->param_queue);
+       spin_unlock_irq(&card->param_queue_lock);
+
+       fpga_queue(card, prm.port, skb, NULL);
+
+       wait_event_timeout(card->param_wq, prm.response, 5 * HZ);
+
+       spin_lock_irq(&card->param_queue_lock);
+       list_del(&prm.list);
+       spin_unlock_irq(&card->param_queue_lock);
+
+       if (!prm.response)
+               return -EIO;
+
+       buflen = prm.response->len;
+       memcpy(buf, prm.response->data, buflen);
+       kfree_skb(prm.response);
+
+       return buflen;
+}
+
+static ssize_t solos_param_store(struct device *dev, struct device_attribute *attr,
+                                const char *buf, size_t count)
+{
+       struct atm_dev *atmdev = container_of(dev, struct atm_dev, class_dev);
+       struct solos_card *card = atmdev->dev_data;
+       struct solos_param prm;
+       struct sk_buff *skb;
+       struct pkt_hdr *header;
+       int buflen;
+       ssize_t ret;
+
+       buflen = strlen(attr->attr.name) + 11 + count;
+
+       skb = alloc_skb(sizeof(*header) + buflen, GFP_KERNEL);
+       if (!skb) {
+               dev_warn(&card->dev->dev, "Failed to allocate sk_buff in solos_param_store()\n");
+               return -ENOMEM;
+       }
+
+       header = (void *)skb_put(skb, sizeof(*header));
+
+       buflen = snprintf((void *)&header[1], buflen - 1,
+                         "L%05d\n%s\n%s\n", current->pid, attr->attr.name, buf);
+
+       skb_put(skb, buflen);
+       header->size = cpu_to_le16(buflen);
+       header->vpi = cpu_to_le16(0);
+       header->vci = cpu_to_le16(0);
+       header->type = cpu_to_le16(PKT_COMMAND);
+
+       prm.pid = current->pid;
+       prm.response = NULL;
+       prm.port = SOLOS_CHAN(atmdev);
+
+       spin_lock_irq(&card->param_queue_lock);
+       list_add(&prm.list, &card->param_queue);
+       spin_unlock_irq(&card->param_queue_lock);
+
+       fpga_queue(card, prm.port, skb, NULL);
+
+       wait_event_timeout(card->param_wq, prm.response, 5 * HZ);
+
+       spin_lock_irq(&card->param_queue_lock);
+       list_del(&prm.list);
+       spin_unlock_irq(&card->param_queue_lock);
+
+       skb = prm.response;
+
+       if (!skb)
+               return -EIO;
+
+       buflen = skb->len;
+
+       /* Sometimes it has a newline, sometimes it doesn't. */
+       if (skb->data[buflen - 1] == '\n')
+               buflen--;
+
+       if (buflen == 2 && !strncmp(skb->data, "OK", 2))
+               ret = count;
+       else if (buflen == 5 && !strncmp(skb->data, "ERROR", 5))
+               ret = -EIO;
+       else {
+               /* We know we have enough space allocated for this; we allocated 
+                  it ourselves */
+               skb->data[buflen] = 0;
+       
+               dev_warn(&card->dev->dev, "Unexpected parameter response: '%s'\n",
+                        skb->data);
+               ret = -EIO;
+       }
+       kfree_skb(skb);
+
+       return ret;
+}
+
+static char *next_string(struct sk_buff *skb)
+{
+       int i = 0;
+       char *this = skb->data;
+       
+       for (i = 0; i < skb->len; i++) {
+               if (this[i] == '\n') {
+                       this[i] = 0;
+                       skb_pull(skb, i + 1);
+                       return this;
+               }
+               if (!isprint(this[i]))
+                       return NULL;
+       }
+       return NULL;
+}
+
+/*
+ * Status packet has fields separated by \n, starting with a version number
+ * for the information therein. Fields are....
+ *
+ *     packet version
+ *     RxBitRate       (version >= 1)
+ *     TxBitRate       (version >= 1)
+ *     State           (version >= 1)
+ *     LocalSNRMargin  (version >= 1)
+ *     LocalLineAttn   (version >= 1)
+ */       
+static int process_status(struct solos_card *card, int port, struct sk_buff *skb)
+{
+       char *str, *end, *state_str, *snr, *attn;
+       int ver, rate_up, rate_down;
+
+       if (!card->atmdev[port])
+               return -ENODEV;
+
+       str = next_string(skb);
+       if (!str)
+               return -EIO;
+
+       ver = simple_strtol(str, NULL, 10);
+       if (ver < 1) {
+               dev_warn(&card->dev->dev, "Unexpected status interrupt version %d\n",
+                        ver);
+               return -EIO;
+       }
+
+       str = next_string(skb);
+       if (!str)
+               return -EIO;
+       if (!strcmp(str, "ERROR")) {
+               dev_dbg(&card->dev->dev, "Status packet indicated Solos error on port %d (starting up?)\n",
+                        port);
+               return 0;
+       }
+
+       rate_down = simple_strtol(str, &end, 10);
+       if (*end)
+               return -EIO;
+
+       str = next_string(skb);
+       if (!str)
+               return -EIO;
+       rate_up = simple_strtol(str, &end, 10);
+       if (*end)
+               return -EIO;
+
+       state_str = next_string(skb);
+       if (!state_str)
+               return -EIO;
+
+       /* Anything but 'Showtime' is down */
+       if (strcmp(state_str, "Showtime")) {
+               card->atmdev[port]->signal = ATM_PHY_SIG_LOST;
+               release_vccs(card->atmdev[port]);
+               dev_info(&card->dev->dev, "Port %d: %s\n", port, state_str);
+               return 0;
+       }
+
+       snr = next_string(skb);
+       if (!str)
+               return -EIO;
+       attn = next_string(skb);
+       if (!attn)
+               return -EIO;
+
+       dev_info(&card->dev->dev, "Port %d: %s @%d/%d kb/s%s%s%s%s\n",
+                port, state_str, rate_down/1000, rate_up/1000,
+                snr[0]?", SNR ":"", snr, attn[0]?", Attn ":"", attn);
+       
+       card->atmdev[port]->link_rate = rate_down / 424;
+       card->atmdev[port]->signal = ATM_PHY_SIG_FOUND;
+
+       return 0;
+}
+
+static int process_command(struct solos_card *card, int port, struct sk_buff *skb)
+{
+       struct solos_param *prm;
+       unsigned long flags;
+       int cmdpid;
+       int found = 0;
+
+       if (skb->len < 7)
+               return 0;
+
+       if (skb->data[0] != 'L'    || !isdigit(skb->data[1]) ||
+           !isdigit(skb->data[2]) || !isdigit(skb->data[3]) ||
+           !isdigit(skb->data[4]) || !isdigit(skb->data[5]) ||
+           skb->data[6] != '\n')
+               return 0;
+
+       cmdpid = simple_strtol(&skb->data[1], NULL, 10);
+
+       spin_lock_irqsave(&card->param_queue_lock, flags);
+       list_for_each_entry(prm, &card->param_queue, list) {
+               if (prm->port == port && prm->pid == cmdpid) {
+                       prm->response = skb;
+                       skb_pull(skb, 7);
+                       wake_up(&card->param_wq);
+                       found = 1;
+                       break;
+               }
+       }
+       spin_unlock_irqrestore(&card->param_queue_lock, flags);
+       return found;
+}
+
 static ssize_t console_show(struct device *dev, struct device_attribute *attr,
                            char *buf)
 {
@@ -140,8 +445,6 @@ static int send_command(struct solos_card *card, int dev, const char *buf, size_
        struct sk_buff *skb;
        struct pkt_hdr *header;
 
-//     dev_dbg(&card->dev->dev, "size: %d\n", size);
-
        if (size > (BUF_SIZE - sizeof(*header))) {
                dev_dbg(&card->dev->dev, "Command is too big.  Dropping request\n");
                return 0;
@@ -180,82 +483,181 @@ static ssize_t console_store(struct device *dev, struct device_attribute *attr,
 
 static DEVICE_ATTR(console, 0644, console_show, console_store);
 
+
+#define SOLOS_ATTR_RO(x) static DEVICE_ATTR(x, 0444, solos_param_show, NULL);
+#define SOLOS_ATTR_RW(x) static DEVICE_ATTR(x, 0644, solos_param_show, solos_param_store);
+
+#include "solos-attrlist.c"
+
+#undef SOLOS_ATTR_RO
+#undef SOLOS_ATTR_RW
+
+#define SOLOS_ATTR_RO(x) &dev_attr_##x.attr,
+#define SOLOS_ATTR_RW(x) &dev_attr_##x.attr,
+
+static struct attribute *solos_attrs[] = {
+#include "solos-attrlist.c"
+       NULL
+};
+
+static struct attribute_group solos_attr_group = {
+       .attrs = solos_attrs,
+       .name = "parameters",
+};
+
+static int flash_upgrade(struct solos_card *card, int chip)
+{
+       const struct firmware *fw;
+       const char *fw_name;
+       uint32_t data32 = 0;
+       int blocksize = 0;
+       int numblocks = 0;
+       int offset;
+
+       if (chip == 0) {
+               fw_name = "solos-FPGA.bin";
+               blocksize = FPGA_BLOCK;
+       } else {
+               fw_name = "solos-Firmware.bin";
+               blocksize = SOLOS_BLOCK;
+       }
+
+       if (request_firmware(&fw, fw_name, &card->dev->dev))
+               return -ENOENT;
+
+       dev_info(&card->dev->dev, "Flash upgrade starting\n");
+
+       numblocks = fw->size / blocksize;
+       dev_info(&card->dev->dev, "Firmware size: %zd\n", fw->size);
+       dev_info(&card->dev->dev, "Number of blocks: %d\n", numblocks);
+       
+       dev_info(&card->dev->dev, "Changing FPGA to Update mode\n");
+       iowrite32(1, card->config_regs + FPGA_MODE);
+       data32 = ioread32(card->config_regs + FPGA_MODE); 
+
+       /* Set mode to Chip Erase */
+       dev_info(&card->dev->dev, "Set FPGA Flash mode to %s Chip Erase\n",
+                chip?"Solos":"FPGA");
+       iowrite32((chip * 2), card->config_regs + FLASH_MODE);
+
+
+       iowrite32(1, card->config_regs + WRITE_FLASH);
+       wait_event(card->fw_wq, !ioread32(card->config_regs + FLASH_BUSY));
+
+       for (offset = 0; offset < fw->size; offset += blocksize) {
+               int i;
+
+               /* Clear write flag */
+               iowrite32(0, card->config_regs + WRITE_FLASH);
+
+               /* Set mode to Block Write */
+               /* dev_info(&card->dev->dev, "Set FPGA Flash mode to Block Write\n"); */
+               iowrite32(((chip * 2) + 1), card->config_regs + FLASH_MODE);
+
+               /* Copy block to buffer, swapping each 16 bits */
+               for(i = 0; i < blocksize; i += 4) {
+                       uint32_t word = swahb32p((uint32_t *)(fw->data + offset + i));
+                       iowrite32(word, RX_BUF(card, 3) + i);
+               }
+
+               /* Specify block number and then trigger flash write */
+               iowrite32(offset / blocksize, card->config_regs + FLASH_BLOCK);
+               iowrite32(1, card->config_regs + WRITE_FLASH);
+               wait_event(card->fw_wq, !ioread32(card->config_regs + FLASH_BUSY));
+       }
+
+       release_firmware(fw);
+       iowrite32(0, card->config_regs + WRITE_FLASH);
+       iowrite32(0, card->config_regs + FPGA_MODE);
+       iowrite32(0, card->config_regs + FLASH_MODE);
+       dev_info(&card->dev->dev, "Returning FPGA to Data mode\n");
+       return 0;
+}
+
 static irqreturn_t solos_irq(int irq, void *dev_id)
 {
        struct solos_card *card = dev_id;
        int handled = 1;
 
-       //ACK IRQ
        iowrite32(0, card->config_regs + IRQ_CLEAR);
-       //Disable IRQs from FPGA
-       iowrite32(0, card->config_regs + IRQ_EN_ADDR);
 
-       /* If we only do it when the device is open, we lose console
-          messages */
-       if (1 || opens)
+       /* If we're up and running, just kick the tasklet to process TX/RX */
+       if (card->atmdev[0])
                tasklet_schedule(&card->tlet);
+       else
+               wake_up(&card->fw_wq);
 
-       //Enable IRQs from FPGA
-       iowrite32(1, card->config_regs + IRQ_EN_ADDR);
        return IRQ_RETVAL(handled);
 }
 
 void solos_bh(unsigned long card_arg)
 {
        struct solos_card *card = (void *)card_arg;
-       int port;
        uint32_t card_flags;
-       uint32_t tx_mask;
        uint32_t rx_done = 0;
+       int port;
 
-       card_flags = ioread32(card->config_regs + FLAGS_ADDR);
-
-       /* The TX bits are set if the channel is busy; clear if not. We want to
-          invoke fpga_tx() unless _all_ the bits for active channels are set */
-       tx_mask = (1 << card->nr_ports) - 1;
-       if ((card_flags & tx_mask) != tx_mask)
-               fpga_tx(card);
+       /*
+        * Since fpga_tx() is going to need to read the flags under its lock,
+        * it can return them to us so that we don't have to hit PCI MMIO
+        * again for the same information
+        */
+       card_flags = fpga_tx(card);
 
        for (port = 0; port < card->nr_ports; port++) {
                if (card_flags & (0x10 << port)) {
-                       struct pkt_hdr header;
+                       struct pkt_hdr _hdr, *header;
                        struct sk_buff *skb;
                        struct atm_vcc *vcc;
                        int size;
 
-                       rx_done |= 0x10 << port;
+                       if (card->using_dma) {
+                               skb = card->rx_skb[port];
+                               card->rx_skb[port] = NULL;
 
-                       memcpy_fromio(&header, RX_BUF(card, port), sizeof(header));
+                               pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr,
+                                                RX_DMA_SIZE, PCI_DMA_FROMDEVICE);
 
-                       size = le16_to_cpu(header.size);
+                               header = (void *)skb->data;
+                               size = le16_to_cpu(header->size);
+                               skb_put(skb, size + sizeof(*header));
+                               skb_pull(skb, sizeof(*header));
+                       } else {
+                               header = &_hdr;
 
-                       skb = alloc_skb(size, GFP_ATOMIC);
-                       if (!skb) {
-                               if (net_ratelimit())
-                                       dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n");
-                               continue;
-                       }
+                               rx_done |= 0x10 << port;
+
+                               memcpy_fromio(header, RX_BUF(card, port), sizeof(*header));
 
-                       memcpy_fromio(skb_put(skb, size),
-                                     RX_BUF(card, port) + sizeof(header),
-                                     size);
+                               size = le16_to_cpu(header->size);
 
+                               skb = alloc_skb(size + 1, GFP_ATOMIC);
+                               if (!skb) {
+                                       if (net_ratelimit())
+                                               dev_warn(&card->dev->dev, "Failed to allocate sk_buff for RX\n");
+                                       continue;
+                               }
+
+                               memcpy_fromio(skb_put(skb, size),
+                                             RX_BUF(card, port) + sizeof(*header),
+                                             size);
+                       }
                        if (atmdebug) {
                                dev_info(&card->dev->dev, "Received: device %d\n", port);
                                dev_info(&card->dev->dev, "size: %d VPI: %d VCI: %d\n",
-                                        size, le16_to_cpu(header.vpi),
-                                        le16_to_cpu(header.vci));
+                                        size, le16_to_cpu(header->vpi),
+                                        le16_to_cpu(header->vci));
                                print_buffer(skb);
                        }
 
-                       switch (le16_to_cpu(header.type)) {
+                       switch (le16_to_cpu(header->type)) {
                        case PKT_DATA:
-                               vcc = find_vcc(card->atmdev[port], le16_to_cpu(header.vpi),
-                                              le16_to_cpu(header.vci));
+                               vcc = find_vcc(card->atmdev[port], le16_to_cpu(header->vpi),
+                                              le16_to_cpu(header->vci));
                                if (!vcc) {
                                        if (net_ratelimit())
                                                dev_warn(&card->dev->dev, "Received packet for unknown VCI.VPI %d.%d on port %d\n",
-                                                        le16_to_cpu(header.vci), le16_to_cpu(header.vpi),
+                                                        le16_to_cpu(header->vci), le16_to_cpu(header->vpi),
                                                         port);
                                        continue;
                                }
@@ -264,19 +666,50 @@ void solos_bh(unsigned long card_arg)
                                atomic_inc(&vcc->stats->rx);
                                break;
 
+                       case PKT_STATUS:
+                               if (process_status(card, port, skb) &&
+                                   net_ratelimit()) {
+                                       dev_warn(&card->dev->dev, "Bad status packet of %d bytes on port %d:\n", skb->len, port);
+                                       print_buffer(skb);
+                               }
+                               dev_kfree_skb_any(skb);
+                               break;
+
                        case PKT_COMMAND:
                        default: /* FIXME: Not really, surely? */
+                               if (process_command(card, port, skb))
+                                       break;
                                spin_lock(&card->cli_queue_lock);
                                if (skb_queue_len(&card->cli_queue[port]) > 10) {
                                        if (net_ratelimit())
                                                dev_warn(&card->dev->dev, "Dropping console response on port %d\n",
                                                         port);
+                                       dev_kfree_skb_any(skb);
                                } else
                                        skb_queue_tail(&card->cli_queue[port], skb);
                                spin_unlock(&card->cli_queue_lock);
                                break;
                        }
                }
+               /* Allocate RX skbs for any ports which need them */
+               if (card->using_dma && card->atmdev[port] &&
+                   !card->rx_skb[port]) {
+                       struct sk_buff *skb = alloc_skb(RX_DMA_SIZE, GFP_ATOMIC);
+                       if (skb) {
+                               SKB_CB(skb)->dma_addr =
+                                       pci_map_single(card->dev, skb->data,
+                                                      RX_DMA_SIZE, PCI_DMA_FROMDEVICE);
+                               iowrite32(SKB_CB(skb)->dma_addr,
+                                         card->config_regs + RX_DMA_ADDR(port));
+                               card->rx_skb[port] = skb;
+                       } else {
+                               if (net_ratelimit())
+                                       dev_warn(&card->dev->dev, "Failed to allocate RX skb");
+
+                               /* We'll have to try again later */
+                               tasklet_schedule(&card->tlet);
+                       }
+               }
        }
        if (rx_done)
                iowrite32(rx_done, card->config_regs + FLAGS_ADDR);
@@ -326,7 +759,7 @@ static int list_vccs(int vci)
                               vcc->vci);
                }
        } else {
-               for(i=0; i<32; i++){
+               for(i = 0; i < VCC_HTABLE_SIZE; i++){
                        head = &vcc_hash[i];
                        sk_for_each(s, node, head) {
                                num_found ++;
@@ -342,6 +775,28 @@ static int list_vccs(int vci)
        return num_found;
 }
 
+static void release_vccs(struct atm_dev *dev)
+{
+        int i;
+
+        write_lock_irq(&vcc_sklist_lock);
+        for (i = 0; i < VCC_HTABLE_SIZE; i++) {
+                struct hlist_head *head = &vcc_hash[i];
+                struct hlist_node *node, *tmp;
+                struct sock *s;
+                struct atm_vcc *vcc;
+
+                sk_for_each_safe(s, node, tmp, head) {
+                        vcc = atm_sk(s);
+                        if (vcc->dev == dev) {
+                                vcc_release_async(vcc, -EPIPE);
+                                sk_del_node_init(s);
+                        }
+                }
+        }
+        write_unlock_irq(&vcc_sklist_lock);
+}
+
 
 static int popen(struct atm_vcc *vcc)
 {
@@ -349,6 +804,12 @@ static int popen(struct atm_vcc *vcc)
        struct sk_buff *skb;
        struct pkt_hdr *header;
 
+       if (vcc->qos.aal != ATM_AAL5) {
+               dev_warn(&card->dev->dev, "Unsupported ATM type %d\n",
+                        vcc->qos.aal);
+               return -EINVAL;
+       }
+
        skb = alloc_skb(sizeof(*header), GFP_ATOMIC);
        if (!skb && net_ratelimit()) {
                dev_warn(&card->dev->dev, "Failed to allocate sk_buff in popen()\n");
@@ -356,22 +817,17 @@ static int popen(struct atm_vcc *vcc)
        }
        header = (void *)skb_put(skb, sizeof(*header));
 
-       header->size = cpu_to_le16(sizeof(*header));
+       header->size = cpu_to_le16(0);
        header->vpi = cpu_to_le16(vcc->vpi);
        header->vci = cpu_to_le16(vcc->vci);
        header->type = cpu_to_le16(PKT_POPEN);
 
        fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL);
 
-//     dev_dbg(&card->dev->dev, "Open for vpi %d and vci %d on interface %d\n", vcc->vpi, vcc->vci, SOLOS_CHAN(vcc->dev));
-       set_bit(ATM_VF_ADDR, &vcc->flags); // accept the vpi / vci
+       set_bit(ATM_VF_ADDR, &vcc->flags);
        set_bit(ATM_VF_READY, &vcc->flags);
        list_vccs(0);
 
-       if (!opens)
-               iowrite32(1, card->config_regs + IRQ_EN_ADDR);
-
-       opens++; //count open PVCs
 
        return 0;
 }
@@ -389,17 +845,13 @@ static void pclose(struct atm_vcc *vcc)
        }
        header = (void *)skb_put(skb, sizeof(*header));
 
-       header->size = cpu_to_le16(sizeof(*header));
+       header->size = cpu_to_le16(0);
        header->vpi = cpu_to_le16(vcc->vpi);
        header->vci = cpu_to_le16(vcc->vci);
        header->type = cpu_to_le16(PKT_PCLOSE);
 
        fpga_queue(card, SOLOS_CHAN(vcc->dev), skb, NULL);
 
-//     dev_dbg(&card->dev->dev, "Close for vpi %d and vci %d on interface %d\n", vcc->vpi, vcc->vci, SOLOS_CHAN(vcc->dev));
-       if (!--opens)
-               iowrite32(0, card->config_regs + IRQ_EN_ADDR);
-
        clear_bit(ATM_VF_ADDR, &vcc->flags);
        clear_bit(ATM_VF_READY, &vcc->flags);
 
@@ -439,22 +891,26 @@ static void fpga_queue(struct solos_card *card, int port, struct sk_buff *skb,
                       struct atm_vcc *vcc)
 {
        int old_len;
+       unsigned long flags;
 
-       *(void **)skb->cb = vcc;
+       SKB_CB(skb)->vcc = vcc;
 
-       spin_lock(&card->tx_queue_lock);
+       spin_lock_irqsave(&card->tx_queue_lock, flags);
        old_len = skb_queue_len(&card->tx_queue[port]);
        skb_queue_tail(&card->tx_queue[port], skb);
-       spin_unlock(&card->tx_queue_lock);
+       if (!old_len)
+               card->tx_mask |= (1 << port);
+       spin_unlock_irqrestore(&card->tx_queue_lock, flags);
 
-       /* If TX might need to be started, do so */
+       /* Theoretically we could just schedule the tasklet here, but
+          that introduces latency we don't want -- it's noticeable */
        if (!old_len)
                fpga_tx(card);
 }
 
-static int fpga_tx(struct solos_card *card)
+static uint32_t fpga_tx(struct solos_card *card)
 {
-       uint32_t tx_pending;
+       uint32_t tx_pending, card_flags;
        uint32_t tx_started = 0;
        struct sk_buff *skb;
        struct atm_vcc *vcc;
@@ -462,69 +918,77 @@ static int fpga_tx(struct solos_card *card)
        unsigned long flags;
 
        spin_lock_irqsave(&card->tx_lock, flags);
-
-       tx_pending = ioread32(card->config_regs + FLAGS_ADDR);
-
-       dev_vdbg(&card->dev->dev, "TX Flags are %X\n", tx_pending);
-
-       for (port = 0; port < card->nr_ports; port++) {
-               if (!(tx_pending & (1 << port))) {
+       
+       card_flags = ioread32(card->config_regs + FLAGS_ADDR);
+       /*
+        * The queue lock is required for _writing_ to tx_mask, but we're
+        * OK to read it here without locking. The only potential update
+        * that we could race with is in fpga_queue() where it sets a bit
+        * for a new port... but it's going to call this function again if
+        * it's doing that, anyway.
+        */
+       tx_pending = card->tx_mask & ~card_flags;
+
+       for (port = 0; tx_pending; tx_pending >>= 1, port++) {
+               if (tx_pending & 1) {
+                       struct sk_buff *oldskb = card->tx_skb[port];
+                       if (oldskb)
+                               pci_unmap_single(card->dev, SKB_CB(oldskb)->dma_addr,
+                                                oldskb->len, PCI_DMA_TODEVICE);
 
                        spin_lock(&card->tx_queue_lock);
                        skb = skb_dequeue(&card->tx_queue[port]);
+                       if (!skb)
+                               card->tx_mask &= ~(1 << port);
                        spin_unlock(&card->tx_queue_lock);
 
-                       if (!skb)
+                       if (skb && !card->using_dma) {
+                               memcpy_toio(TX_BUF(card, port), skb->data, skb->len);
+                               tx_started |= 1 << port;
+                               oldskb = skb; /* We're done with this skb already */
+                       } else if (skb && card->using_dma) {
+                               SKB_CB(skb)->dma_addr = pci_map_single(card->dev, skb->data,
+                                                                      skb->len, PCI_DMA_TODEVICE);
+                               iowrite32(SKB_CB(skb)->dma_addr,
+                                         card->config_regs + TX_DMA_ADDR(port));
+                       }
+
+                       if (!oldskb)
                                continue;
 
+                       /* Clean up and free oldskb now it's gone */
                        if (atmdebug) {
                                dev_info(&card->dev->dev, "Transmitted: port %d\n",
                                         port);
-                               print_buffer(skb);
+                               print_buffer(oldskb);
                        }
-                       memcpy_toio(TX_BUF(card, port), skb->data, skb->len);
 
-                       vcc = *(void **)skb->cb;
+                       vcc = SKB_CB(oldskb)->vcc;
 
                        if (vcc) {
                                atomic_inc(&vcc->stats->tx);
-                               solos_pop(vcc, skb);
+                               solos_pop(vcc, oldskb);
                        } else
-                               dev_kfree_skb_irq(skb);
+                               dev_kfree_skb_irq(oldskb);
 
-                       tx_started |= 1 << port; //Set TX full flag
                }
        }
+       /* For non-DMA TX, write the 'TX start' bit for all four ports simultaneously */
        if (tx_started)
                iowrite32(tx_started, card->config_regs + FLAGS_ADDR);
 
        spin_unlock_irqrestore(&card->tx_lock, flags);
-       return 0;
+       return card_flags;
 }
 
 static int psend(struct atm_vcc *vcc, struct sk_buff *skb)
 {
        struct solos_card *card = vcc->dev->dev_data;
-       struct sk_buff *skb2 = NULL;
        struct pkt_hdr *header;
+       int pktlen;
 
-       //dev_dbg(&card->dev->dev, "psend called.\n");
-       //dev_dbg(&card->dev->dev, "dev,vpi,vci = %d,%d,%d\n",SOLOS_CHAN(vcc->dev),vcc->vpi,vcc->vci);
-
-       if (debug) {
-               skb2 = atm_alloc_charge(vcc, skb->len, GFP_ATOMIC);
-               if (skb2) {
-                       memcpy(skb2->data, skb->data, skb->len);
-                       skb_put(skb2, skb->len);
-                       vcc->push(vcc, skb2);
-                       atomic_inc(&vcc->stats->rx);
-               }
-               atomic_inc(&vcc->stats->tx);
-               solos_pop(vcc, skb);
-               return 0;
-       }
-
-       if (skb->len > (BUF_SIZE - sizeof(*header))) {
+       pktlen = skb->len;
+       if (pktlen > (BUF_SIZE - sizeof(*header))) {
                dev_warn(&card->dev->dev, "Length of PDU is too large. Dropping PDU.\n");
                solos_pop(vcc, skb);
                return 0;
@@ -539,6 +1003,7 @@ static int psend(struct atm_vcc *vcc, struct sk_buff *skb)
 
                ret = pskb_expand_head(skb, expand_by, 0, GFP_ATOMIC);
                if (ret) {
+                       dev_warn(&card->dev->dev, "pskb_expand_head failed.\n");
                        solos_pop(vcc, skb);
                        return ret;
                }
@@ -546,7 +1011,8 @@ static int psend(struct atm_vcc *vcc, struct sk_buff *skb)
 
        header = (void *)skb_push(skb, sizeof(*header));
 
-       header->size = cpu_to_le16(skb->len);
+       /* This does _not_ include the size of the header */
+       header->size = cpu_to_le16(pktlen);
        header->vpi = cpu_to_le16(vcc->vpi);
        header->vci = cpu_to_le16(vcc->vci);
        header->type = cpu_to_le16(PKT_DATA);
@@ -573,20 +1039,19 @@ static struct atmdev_ops fpga_ops = {
 
 static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
 {
-       int err, i;
+       int err;
        uint16_t fpga_ver;
        uint8_t major_ver, minor_ver;
        uint32_t data32;
        struct solos_card *card;
 
-       if (debug)
-               return 0;
-
        card = kzalloc(sizeof(*card), GFP_KERNEL);
        if (!card)
                return -ENOMEM;
 
        card->dev = dev;
+       init_waitqueue_head(&card->fw_wq);
+       init_waitqueue_head(&card->param_wq);
 
        err = pci_enable_device(dev);
        if (err) {
@@ -594,6 +1059,12 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
                goto out;
        }
 
+       err = pci_set_dma_mask(dev, DMA_32BIT_MASK);
+       if (err) {
+               dev_warn(&dev->dev, "Failed to set 32-bit DMA mask\n");
+               goto out;
+       }
+
        err = pci_request_regions(dev, "solos");
        if (err) {
                dev_warn(&dev->dev, "Failed to request regions\n");
@@ -611,17 +1082,13 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
                goto out_unmap_config;
        }
 
-//     for(i=0;i<64 ;i+=4){
-//             data32=ioread32(card->buffers + i);
-//             dev_dbg(&card->dev->dev, "%08lX\n",(unsigned long)data32);
-//     }
-
-       //Fill Config Mem with zeros
-       for(i = 0; i < 128; i += 4)
-               iowrite32(0, card->config_regs + i);
+       if (reset) {
+               iowrite32(1, card->config_regs + FPGA_MODE);
+               data32 = ioread32(card->config_regs + FPGA_MODE); 
 
-       //Set RX empty flags
-       iowrite32(0xF0, card->config_regs + FLAGS_ADDR);
+               iowrite32(0, card->config_regs + FPGA_MODE);
+               data32 = ioread32(card->config_regs + FPGA_MODE); 
+       }
 
        data32 = ioread32(card->config_regs + FPGA_VER);
        fpga_ver = (data32 & 0x0000FFFF);
@@ -630,55 +1097,53 @@ static int fpga_probe(struct pci_dev *dev, const struct pci_device_id *id)
        dev_info(&dev->dev, "Solos FPGA Version %d.%02d svn-%d\n",
                 major_ver, minor_ver, fpga_ver);
 
-       card->nr_ports = 2; /* FIXME: Detect daughterboard */
+       if (0 && fpga_ver > 27)
+               card->using_dma = 1;
+       else {
+               /* Set RX empty flag for all ports */
+               iowrite32(0xF0, card->config_regs + FLAGS_ADDR);
+       }
 
-       err = atm_init(card);
-       if (err)
-               goto out_unmap_both;
+       data32 = ioread32(card->config_regs + PORTS);
+       card->nr_ports = (data32 & 0x000000FF);
 
        pci_set_drvdata(dev, card);
+
        tasklet_init(&card->tlet, solos_bh, (unsigned long)card);
        spin_lock_init(&card->tx_lock);
        spin_lock_init(&card->tx_queue_lock);
        spin_lock_init(&card->cli_queue_lock);
-/*
-       // Set Loopback mode
-       data32 = 0x00010000;
-       iowrite32(data32,card->config_regs + FLAGS_ADDR);
-*/
-/*
-       // Fill Buffers with zeros
-       for (i = 0; i < BUF_SIZE * 8; i += 4)
-               iowrite32(0, card->buffers + i);
-*/
-/*
-       for(i = 0; i < (BUF_SIZE * 1); i += 4)
-               iowrite32(0x12345678, card->buffers + i + (0*BUF_SIZE));
-       for(i = 0; i < (BUF_SIZE * 1); i += 4)
-               iowrite32(0xabcdef98, card->buffers + i + (1*BUF_SIZE));
-
-       // Read Config Memory
-       printk(KERN_DEBUG "Reading Config MEM\n");
-       i = 0;
-       for(i = 0; i < 16; i++) {
-               data32=ioread32(card->buffers + i*(BUF_SIZE/2));
-               printk(KERN_ALERT "Addr: %lX Data: %08lX\n",
-                      (unsigned long)(addr_start + i*(BUF_SIZE/2)),
-                      (unsigned long)data32);
-       }
-*/
-       //dev_dbg(&card->dev->dev, "Requesting IRQ: %d\n",dev->irq);
-       err = request_irq(dev->irq, solos_irq, IRQF_DISABLED|IRQF_SHARED,
+       spin_lock_init(&card->param_queue_lock);
+       INIT_LIST_HEAD(&card->param_queue);
+
+       err = request_irq(dev->irq, solos_irq, IRQF_SHARED,
                          "solos-pci", card);
-       if (err)
+       if (err) {
                dev_dbg(&card->dev->dev, "Failed to request interrupt IRQ: %d\n", dev->irq);
+               goto out_unmap_both;
+       }
 
-       // Enable IRQs
        iowrite32(1, card->config_regs + IRQ_EN_ADDR);
 
+       if (fpga_upgrade)
+               flash_upgrade(card, 0);
+
+       if (firmware_upgrade)
+               flash_upgrade(card, 1);
+
+       err = atm_init(card);
+       if (err)
+               goto out_free_irq;
+
        return 0;
 
+ out_free_irq:
+       iowrite32(0, card->config_regs + IRQ_EN_ADDR);
+       free_irq(dev->irq, card);
+       tasklet_kill(&card->tlet);
+       
  out_unmap_both:
+       pci_set_drvdata(dev, NULL);
        pci_iounmap(dev, card->config_regs);
  out_unmap_config:
        pci_iounmap(dev, card->buffers);
@@ -693,9 +1158,10 @@ static int atm_init(struct solos_card *card)
 {
        int i;
 
-       opens = 0;
-
        for (i = 0; i < card->nr_ports; i++) {
+               struct sk_buff *skb;
+               struct pkt_hdr *header;
+
                skb_queue_head_init(&card->tx_queue[i]);
                skb_queue_head_init(&card->cli_queue[i]);
 
@@ -707,6 +1173,8 @@ static int atm_init(struct solos_card *card)
                }
                if (device_create_file(&card->atmdev[i]->class_dev, &dev_attr_console))
                        dev_err(&card->dev->dev, "Could not register console for ATM device %d\n", i);
+               if (sysfs_create_group(&card->atmdev[i]->class_dev.kobj, &solos_attr_group))
+                       dev_err(&card->dev->dev, "Could not register parameter group for ATM device %d\n", i);
 
                dev_info(&card->dev->dev, "Registered ATM device %d\n", card->atmdev[i]->number);
 
@@ -714,6 +1182,22 @@ static int atm_init(struct solos_card *card)
                card->atmdev[i]->ci_range.vci_bits = 16;
                card->atmdev[i]->dev_data = card;
                card->atmdev[i]->phy_data = (void *)(unsigned long)i;
+               card->atmdev[i]->signal = ATM_PHY_SIG_UNKNOWN;
+
+               skb = alloc_skb(sizeof(*header), GFP_ATOMIC);
+               if (!skb) {
+                       dev_warn(&card->dev->dev, "Failed to allocate sk_buff in atm_init()\n");
+                       continue;
+               }
+
+               header = (void *)skb_put(skb, sizeof(*header));
+
+               header->size = cpu_to_le16(0);
+               header->vpi = cpu_to_le16(0);
+               header->vci = cpu_to_le16(0);
+               header->type = cpu_to_le16(PKT_STATUS);
+
+               fpga_queue(card, i, skb, NULL);
        }
        return 0;
 }
@@ -724,8 +1208,28 @@ static void atm_remove(struct solos_card *card)
 
        for (i = 0; i < card->nr_ports; i++) {
                if (card->atmdev[i]) {
+                       struct sk_buff *skb;
+
                        dev_info(&card->dev->dev, "Unregistering ATM device %d\n", card->atmdev[i]->number);
+
+                       sysfs_remove_group(&card->atmdev[i]->class_dev.kobj, &solos_attr_group);
                        atm_dev_deregister(card->atmdev[i]);
+
+                       skb = card->rx_skb[i];
+                       if (skb) {
+                               pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr,
+                                                RX_DMA_SIZE, PCI_DMA_FROMDEVICE);
+                               dev_kfree_skb(skb);
+                       }
+                       skb = card->tx_skb[i];
+                       if (skb) {
+                               pci_unmap_single(card->dev, SKB_CB(skb)->dma_addr,
+                                                skb->len, PCI_DMA_TODEVICE);
+                               dev_kfree_skb(skb);
+                       }
+                       while ((skb = skb_dequeue(&card->tx_queue[i])))
+                               dev_kfree_skb(skb);
                }
        }
 }
@@ -733,31 +1237,31 @@ static void atm_remove(struct solos_card *card)
 static void fpga_remove(struct pci_dev *dev)
 {
        struct solos_card *card = pci_get_drvdata(dev);
+       
+       /* Disable IRQs */
+       iowrite32(0, card->config_regs + IRQ_EN_ADDR);
 
-       if (debug)
-               return;
+       /* Reset FPGA */
+       iowrite32(1, card->config_regs + FPGA_MODE);
+       (void)ioread32(card->config_regs + FPGA_MODE); 
 
        atm_remove(card);
 
-       dev_vdbg(&dev->dev, "Freeing IRQ\n");
-       // Disable IRQs from FPGA
-       iowrite32(0, card->config_regs + IRQ_EN_ADDR);
        free_irq(dev->irq, card);
        tasklet_kill(&card->tlet);
 
-       //      iowrite32(0x01,pciregs);
-       dev_vdbg(&dev->dev, "Unmapping PCI resource\n");
+       /* Release device from reset */
+       iowrite32(0, card->config_regs + FPGA_MODE);
+       (void)ioread32(card->config_regs + FPGA_MODE); 
+
        pci_iounmap(dev, card->buffers);
        pci_iounmap(dev, card->config_regs);
 
-       dev_vdbg(&dev->dev, "Releasing PCI Region\n");
        pci_release_regions(dev);
        pci_disable_device(dev);
 
        pci_set_drvdata(dev, NULL);
        kfree(card);
-//     dev_dbg(&card->dev->dev, "fpga_remove\n");
-       return;
 }
 
 static struct pci_device_id fpga_pci_tbl[] __devinitdata = {
index 0a5f055dffbaa389fd8f4b2f0bfe81fe5a352241..9f50f1b545dc49de323135663628da1566797175 100644 (file)
@@ -88,8 +88,6 @@ extern void driver_detach(struct device_driver *drv);
 extern int driver_probe_device(struct device_driver *drv, struct device *dev);
 
 extern void sysdev_shutdown(void);
-extern int sysdev_suspend(pm_message_t state);
-extern int sysdev_resume(void);
 
 extern char *make_class_name(const char *name, struct kobject *kobj);
 
index 315bed8d5e7fc5e33d1ea10e9f4c084e03428036..1352312391032fcda76f672c5b43a76e5c6df6f0 100644 (file)
  */
 
 #include <linux/device.h>
+#include <linux/delay.h>
 #include <linux/module.h>
 #include <linux/kthread.h>
 #include <linux/wait.h>
+#include <linux/async.h>
 
 #include "base.h"
 #include "power/power.h"
@@ -167,6 +169,21 @@ int driver_probe_done(void)
        return 0;
 }
 
+/**
+ * wait_for_device_probe
+ * Wait for device probing to be completed.
+ *
+ * Note: this function polls at 100 msec intervals.
+ */
+int wait_for_device_probe(void)
+{
+       /* wait for the known devices to complete their probing */
+       while (driver_probe_done() != 0)
+               msleep(100);
+       async_synchronize_full();
+       return 0;
+}
+
 /**
  * driver_probe_device - attempt to bind device & driver together
  * @drv: driver to bind a device to
index 670c9d6c140743a7fac01bcfada07254d4da5016..2d14f4ae6c01da28be636629db5e50b9205b5699 100644 (file)
@@ -333,7 +333,6 @@ static void dpm_power_up(pm_message_t state)
  */
 void device_power_up(pm_message_t state)
 {
-       sysdev_resume();
        dpm_power_up(state);
 }
 EXPORT_SYMBOL_GPL(device_power_up);
@@ -577,8 +576,6 @@ int device_power_down(pm_message_t state)
                }
                dev->power.status = DPM_OFF_IRQ;
        }
-       if (!error)
-               error = sysdev_suspend(state);
        if (error)
                dpm_power_up(resume_event(state));
        return error;
index c98c31ec2f752189e2481a278ed8e7f02cf01985..b428c8c4bc6464177ea32524341e85992346ce3b 100644 (file)
@@ -303,7 +303,6 @@ void sysdev_unregister(struct sys_device * sysdev)
  *     is guaranteed by virtue of the fact that child devices are registered
  *     after their parents.
  */
-
 void sysdev_shutdown(void)
 {
        struct sysdev_class * cls;
@@ -363,7 +362,6 @@ static void __sysdev_resume(struct sys_device *dev)
  *     This is only called by the device PM core, so we let them handle
  *     all synchronization.
  */
-
 int sysdev_suspend(pm_message_t state)
 {
        struct sysdev_class * cls;
@@ -432,7 +430,7 @@ aux_driver:
        }
        return ret;
 }
-
+EXPORT_SYMBOL_GPL(sysdev_suspend);
 
 /**
  *     sysdev_resume - Bring system devices back to life.
@@ -442,7 +440,6 @@ aux_driver:
  *
  *     Note: Interrupts are disabled when called.
  */
-
 int sysdev_resume(void)
 {
        struct sysdev_class * cls;
@@ -463,7 +460,7 @@ int sysdev_resume(void)
        }
        return 0;
 }
-
+EXPORT_SYMBOL_GPL(sysdev_resume);
 
 int __init system_bus_init(void)
 {
index c237527b1aa59880b272a13bc8d0a17d6206ca2a..5e41e6dd657b9a7326ba1347346c8147c428f3c2 100644 (file)
@@ -18,6 +18,7 @@
 enum {
        AOECMD_ATA,
        AOECMD_CFG,
+       AOECMD_VEND_MIN = 0xf0,
 
        AOEFL_RSP = (1<<3),
        AOEFL_ERR = (1<<2),
index cc250577d405e6d061054b268ddc54b96ddd0cdc..eeea477d96016596ccd729a6f75d37d5e3d30a0e 100644 (file)
@@ -173,7 +173,7 @@ skbfree(struct sk_buff *skb)
                return;
        while (atomic_read(&skb_shinfo(skb)->dataref) != 1 && i-- > 0)
                msleep(Sms);
-       if (i <= 0) {
+       if (i < 0) {
                printk(KERN_ERR
                        "aoe: %s holds ref: %s\n",
                        skb->dev ? skb->dev->name : "netif",
index 30de5b1c647e80b05007a22f1a4e0b79a38dcad4..ce0d62cd71b265de46e12447b3a665b10c479131 100644 (file)
@@ -142,6 +142,8 @@ aoenet_rcv(struct sk_buff *skb, struct net_device *ifp, struct packet_type *pt,
                aoecmd_cfg_rsp(skb);
                break;
        default:
+               if (h->cmd >= AOECMD_VEND_MIN)
+                       break;  /* don't complain about vendor commands */
                printk(KERN_INFO "aoe: unknown cmd %d\n", h->cmd);
        }
 exit:
@@ -149,7 +151,7 @@ exit:
        return 0;
 }
 
-static struct packet_type aoe_pt = {
+static struct packet_type aoe_pt __read_mostly = {
        .type = __constant_htons(ETH_P_AOE),
        .func = aoenet_rcv,
 };
index 69e1df7dfa14a4447c6797a0b6f1f6d8c18993fb..4234c11c1e4cfe34592c9830eca7d2a68400b052 100644 (file)
@@ -1730,7 +1730,7 @@ static int __init fd_test_drive_present( int drive )
 
        timeout = jiffies + 2*HZ+HZ/2;
        while (time_before(jiffies, timeout))
-               if (!(mfp.par_dt_reg & 0x20))
+               if (!(st_mfp.par_dt_reg & 0x20))
                        break;
 
        status = FDC_READ( FDCREG_STATUS );
@@ -1747,7 +1747,7 @@ static int __init fd_test_drive_present( int drive )
                /* dummy seek command to make WP bit accessible */
                FDC_WRITE( FDCREG_DATA, 0 );
                FDC_WRITE( FDCREG_CMD, FDCCMD_SEEK );
-               while( mfp.par_dt_reg & 0x20 )
+               while( st_mfp.par_dt_reg & 0x20 )
                        ;
                status = FDC_READ( FDCREG_STATUS );
        }
index 01e69383d9c07ece3df6e56d23b4d3b2bf687475..b5a06111463018b5d93f3d2b944caf9c60654281 100644 (file)
@@ -3390,6 +3390,203 @@ static void free_hba(int i)
        kfree(p);
 }
 
+/* Send a message CDB to the firmware. */
+static __devinit int cciss_message(struct pci_dev *pdev, unsigned char opcode, unsigned char type)
+{
+       typedef struct {
+               CommandListHeader_struct CommandHeader;
+               RequestBlock_struct Request;
+               ErrDescriptor_struct ErrorDescriptor;
+       } Command;
+       static const size_t cmd_sz = sizeof(Command) + sizeof(ErrorInfo_struct);
+       Command *cmd;
+       dma_addr_t paddr64;
+       uint32_t paddr32, tag;
+       void __iomem *vaddr;
+       int i, err;
+
+       vaddr = ioremap_nocache(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+       if (vaddr == NULL)
+               return -ENOMEM;
+
+       /* The Inbound Post Queue only accepts 32-bit physical addresses for the
+          CCISS commands, so they must be allocated from the lower 4GiB of
+          memory. */
+       err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
+       if (err) {
+               iounmap(vaddr);
+               return -ENOMEM;
+       }
+
+       cmd = pci_alloc_consistent(pdev, cmd_sz, &paddr64);
+       if (cmd == NULL) {
+               iounmap(vaddr);
+               return -ENOMEM;
+       }
+
+       /* This must fit, because of the 32-bit consistent DMA mask.  Also,
+          although there's no guarantee, we assume that the address is at
+          least 4-byte aligned (most likely, it's page-aligned). */
+       paddr32 = paddr64;
+
+       cmd->CommandHeader.ReplyQueue = 0;
+       cmd->CommandHeader.SGList = 0;
+       cmd->CommandHeader.SGTotal = 0;
+       cmd->CommandHeader.Tag.lower = paddr32;
+       cmd->CommandHeader.Tag.upper = 0;
+       memset(&cmd->CommandHeader.LUN.LunAddrBytes, 0, 8);
+
+       cmd->Request.CDBLen = 16;
+       cmd->Request.Type.Type = TYPE_MSG;
+       cmd->Request.Type.Attribute = ATTR_HEADOFQUEUE;
+       cmd->Request.Type.Direction = XFER_NONE;
+       cmd->Request.Timeout = 0; /* Don't time out */
+       cmd->Request.CDB[0] = opcode;
+       cmd->Request.CDB[1] = type;
+       memset(&cmd->Request.CDB[2], 0, 14); /* the rest of the CDB is reserved */
+
+       cmd->ErrorDescriptor.Addr.lower = paddr32 + sizeof(Command);
+       cmd->ErrorDescriptor.Addr.upper = 0;
+       cmd->ErrorDescriptor.Len = sizeof(ErrorInfo_struct);
+
+       writel(paddr32, vaddr + SA5_REQUEST_PORT_OFFSET);
+
+       for (i = 0; i < 10; i++) {
+               tag = readl(vaddr + SA5_REPLY_PORT_OFFSET);
+               if ((tag & ~3) == paddr32)
+                       break;
+               schedule_timeout_uninterruptible(HZ);
+       }
+
+       iounmap(vaddr);
+
+       /* we leak the DMA buffer here ... no choice since the controller could
+          still complete the command. */
+       if (i == 10) {
+               printk(KERN_ERR "cciss: controller message %02x:%02x timed out\n",
+                       opcode, type);
+               return -ETIMEDOUT;
+       }
+
+       pci_free_consistent(pdev, cmd_sz, cmd, paddr64);
+
+       if (tag & 2) {
+               printk(KERN_ERR "cciss: controller message %02x:%02x failed\n",
+                       opcode, type);
+               return -EIO;
+       }
+
+       printk(KERN_INFO "cciss: controller message %02x:%02x succeeded\n",
+               opcode, type);
+       return 0;
+}
+
+#define cciss_soft_reset_controller(p) cciss_message(p, 1, 0)
+#define cciss_noop(p) cciss_message(p, 3, 0)
+
+static __devinit int cciss_reset_msi(struct pci_dev *pdev)
+{
+/* the #defines are stolen from drivers/pci/msi.h. */
+#define msi_control_reg(base)          (base + PCI_MSI_FLAGS)
+#define PCI_MSIX_FLAGS_ENABLE          (1 << 15)
+
+       int pos;
+       u16 control = 0;
+
+       pos = pci_find_capability(pdev, PCI_CAP_ID_MSI);
+       if (pos) {
+               pci_read_config_word(pdev, msi_control_reg(pos), &control);
+               if (control & PCI_MSI_FLAGS_ENABLE) {
+                       printk(KERN_INFO "cciss: resetting MSI\n");
+                       pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSI_FLAGS_ENABLE);
+               }
+       }
+
+       pos = pci_find_capability(pdev, PCI_CAP_ID_MSIX);
+       if (pos) {
+               pci_read_config_word(pdev, msi_control_reg(pos), &control);
+               if (control & PCI_MSIX_FLAGS_ENABLE) {
+                       printk(KERN_INFO "cciss: resetting MSI-X\n");
+                       pci_write_config_word(pdev, msi_control_reg(pos), control & ~PCI_MSIX_FLAGS_ENABLE);
+               }
+       }
+
+       return 0;
+}
+
+/* This does a hard reset of the controller using PCI power management
+ * states. */
+static __devinit int cciss_hard_reset_controller(struct pci_dev *pdev)
+{
+       u16 pmcsr, saved_config_space[32];
+       int i, pos;
+
+       printk(KERN_INFO "cciss: using PCI PM to reset controller\n");
+
+       /* This is very nearly the same thing as
+
+          pci_save_state(pci_dev);
+          pci_set_power_state(pci_dev, PCI_D3hot);
+          pci_set_power_state(pci_dev, PCI_D0);
+          pci_restore_state(pci_dev);
+
+          but we can't use these nice canned kernel routines on
+          kexec, because they also check the MSI/MSI-X state in PCI
+          configuration space and do the wrong thing when it is
+          set/cleared.  Also, the pci_save/restore_state functions
+          violate the ordering requirements for restoring the
+          configuration space from the CCISS document (see the
+          comment below).  So we roll our own .... */
+
+       for (i = 0; i < 32; i++)
+               pci_read_config_word(pdev, 2*i, &saved_config_space[i]);
+
+       pos = pci_find_capability(pdev, PCI_CAP_ID_PM);
+       if (pos == 0) {
+               printk(KERN_ERR "cciss_reset_controller: PCI PM not supported\n");
+               return -ENODEV;
+       }
+
+       /* Quoting from the Open CISS Specification: "The Power
+        * Management Control/Status Register (CSR) controls the power
+        * state of the device.  The normal operating state is D0,
+        * CSR=00h.  The software off state is D3, CSR=03h.  To reset
+        * the controller, place the interface device in D3 then to
+        * D0, this causes a secondary PCI reset which will reset the
+        * controller." */
+
+       /* enter the D3hot power management state */
+       pci_read_config_word(pdev, pos + PCI_PM_CTRL, &pmcsr);
+       pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+       pmcsr |= PCI_D3hot;
+       pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+
+       schedule_timeout_uninterruptible(HZ >> 1);
+
+       /* enter the D0 power management state */
+       pmcsr &= ~PCI_PM_CTRL_STATE_MASK;
+       pmcsr |= PCI_D0;
+       pci_write_config_word(pdev, pos + PCI_PM_CTRL, pmcsr);
+
+       schedule_timeout_uninterruptible(HZ >> 1);
+
+       /* Restore the PCI configuration space.  The Open CISS
+        * Specification says, "Restore the PCI Configuration
+        * Registers, offsets 00h through 60h. It is important to
+        * restore the command register, 16-bits at offset 04h,
+        * last. Do not restore the configuration status register,
+        * 16-bits at offset 06h."  Note that the offset is 2*i. */
+       for (i = 0; i < 32; i++) {
+               if (i == 2 || i == 3)
+                       continue;
+               pci_write_config_word(pdev, 2*i, saved_config_space[i]);
+       }
+       wmb();
+       pci_write_config_word(pdev, 4, saved_config_space[2]);
+
+       return 0;
+}
+
 /*
  *  This is it.  Find all the controllers and register them.  I really hate
  *  stealing all these major device numbers.
@@ -3404,6 +3601,28 @@ static int __devinit cciss_init_one(struct pci_dev *pdev,
        int dac, return_code;
        InquiryData_struct *inq_buff = NULL;
 
+       if (reset_devices) {
+               /* Reset the controller with a PCI power-cycle */
+               if (cciss_hard_reset_controller(pdev) || cciss_reset_msi(pdev))
+                       return -ENODEV;
+
+               /* Some devices (notably the HP Smart Array 5i Controller)
+                  need a little pause here */
+               schedule_timeout_uninterruptible(30*HZ);
+
+               /* Now try to get the controller to respond to a no-op */
+               for (i=0; i<30; i++) {
+                       if (cciss_noop(pdev) == 0)
+                               break;
+
+                       schedule_timeout_uninterruptible(HZ);
+               }
+               if (i == 30) {
+                       printk(KERN_ERR "cciss: controller seems dead\n");
+                       return -EBUSY;
+               }
+       }
+
        i = alloc_cciss_hba();
        if (i < 0)
                return -1;
index cf29cc4e6ab73d2d95e6d4778f576aae9c98b327..83d8ed39433d058f70896057e52fc4d1e4dc99f3 100644 (file)
@@ -558,6 +558,8 @@ static void process_fd_request(void);
 static void recalibrate_floppy(void);
 static void floppy_shutdown(unsigned long);
 
+static int floppy_request_regions(int);
+static void floppy_release_regions(int);
 static int floppy_grab_irq_and_dma(void);
 static void floppy_release_irq_and_dma(void);
 
@@ -4274,8 +4276,7 @@ static int __init floppy_init(void)
                FDCS->rawcmd = 2;
                if (user_reset_fdc(-1, FD_RESET_ALWAYS, 0)) {
                        /* free ioports reserved by floppy_grab_irq_and_dma() */
-                       release_region(FDCS->address + 2, 4);
-                       release_region(FDCS->address + 7, 1);
+                       floppy_release_regions(fdc);
                        FDCS->address = -1;
                        FDCS->version = FDC_NONE;
                        continue;
@@ -4284,8 +4285,7 @@ static int __init floppy_init(void)
                FDCS->version = get_fdc_version();
                if (FDCS->version == FDC_NONE) {
                        /* free ioports reserved by floppy_grab_irq_and_dma() */
-                       release_region(FDCS->address + 2, 4);
-                       release_region(FDCS->address + 7, 1);
+                       floppy_release_regions(fdc);
                        FDCS->address = -1;
                        continue;
                }
@@ -4358,6 +4358,47 @@ out_put_disk:
 
 static DEFINE_SPINLOCK(floppy_usage_lock);
 
+static const struct io_region {
+       int offset;
+       int size;
+} io_regions[] = {
+       { 2, 1 },
+       /* address + 3 is sometimes reserved by pnp bios for motherboard */
+       { 4, 2 },
+       /* address + 6 is reserved, and may be taken by IDE.
+        * Unfortunately, Adaptec doesn't know this :-(, */
+       { 7, 1 },
+};
+
+static void floppy_release_allocated_regions(int fdc, const struct io_region *p)
+{
+       while (p != io_regions) {
+               p--;
+               release_region(FDCS->address + p->offset, p->size);
+       }
+}
+
+#define ARRAY_END(X) (&((X)[ARRAY_SIZE(X)]))
+
+static int floppy_request_regions(int fdc)
+{
+       const struct io_region *p;
+
+       for (p = io_regions; p < ARRAY_END(io_regions); p++) {
+               if (!request_region(FDCS->address + p->offset, p->size, "floppy")) {
+                       DPRINT("Floppy io-port 0x%04lx in use\n", FDCS->address + p->offset);
+                       floppy_release_allocated_regions(fdc, p);
+                       return -EBUSY;
+               }
+       }
+       return 0;
+}
+
+static void floppy_release_regions(int fdc)
+{
+       floppy_release_allocated_regions(fdc, ARRAY_END(io_regions));
+}
+
 static int floppy_grab_irq_and_dma(void)
 {
        unsigned long flags;
@@ -4399,18 +4440,8 @@ static int floppy_grab_irq_and_dma(void)
 
        for (fdc = 0; fdc < N_FDC; fdc++) {
                if (FDCS->address != -1) {
-                       if (!request_region(FDCS->address + 2, 4, "floppy")) {
-                               DPRINT("Floppy io-port 0x%04lx in use\n",
-                                      FDCS->address + 2);
-                               goto cleanup1;
-                       }
-                       if (!request_region(FDCS->address + 7, 1, "floppy DIR")) {
-                               DPRINT("Floppy io-port 0x%04lx in use\n",
-                                      FDCS->address + 7);
-                               goto cleanup2;
-                       }
-                       /* address + 6 is reserved, and may be taken by IDE.
-                        * Unfortunately, Adaptec doesn't know this :-(, */
+                       if (floppy_request_regions(fdc))
+                               goto cleanup;
                }
        }
        for (fdc = 0; fdc < N_FDC; fdc++) {
@@ -4432,15 +4463,11 @@ static int floppy_grab_irq_and_dma(void)
        fdc = 0;
        irqdma_allocated = 1;
        return 0;
-cleanup2:
-       release_region(FDCS->address + 2, 4);
-cleanup1:
+cleanup:
        fd_free_irq();
        fd_free_dma();
-       while (--fdc >= 0) {
-               release_region(FDCS->address + 2, 4);
-               release_region(FDCS->address + 7, 1);
-       }
+       while (--fdc >= 0)
+               floppy_release_regions(fdc);
        spin_lock_irqsave(&floppy_usage_lock, flags);
        usage_count--;
        spin_unlock_irqrestore(&floppy_usage_lock, flags);
@@ -4501,10 +4528,8 @@ static void floppy_release_irq_and_dma(void)
 #endif
        old_fdc = fdc;
        for (fdc = 0; fdc < N_FDC; fdc++)
-               if (FDCS->address != -1) {
-                       release_region(FDCS->address + 2, 4);
-                       release_region(FDCS->address + 7, 1);
-               }
+               if (FDCS->address != -1)
+                       floppy_release_regions(fdc);
        fdc = old_fdc;
 }
 
index 9dfa27163001e9d31de36f5196be7db0f2334a2d..c397b3ddba9b8676293bf773edfa90b29cf3101d 100644 (file)
@@ -422,7 +422,7 @@ static void xs(char *buf, char *targ, int len)
 
        for (k = 0; k < len; k++) {
                char c = *buf++;
-               if (c != ' ' || c != l)
+               if (c != ' ' && c != l)
                        l = *targ++ = c;
        }
        if (l == ' ')
index 918ef725de41c849f3f78b7e30f80d7709e01a39..b6c8ce25435994558885e9e4b9c4ac6aafaa9357 100644 (file)
@@ -40,6 +40,7 @@
 #include <linux/hdreg.h>
 #include <linux/cdrom.h>
 #include <linux/module.h>
+#include <linux/scatterlist.h>
 
 #include <xen/xenbus.h>
 #include <xen/grant_table.h>
@@ -82,6 +83,7 @@ struct blkfront_info
        enum blkif_state connected;
        int ring_ref;
        struct blkif_front_ring ring;
+       struct scatterlist sg[BLKIF_MAX_SEGMENTS_PER_REQUEST];
        unsigned int evtchn, irq;
        struct request_queue *rq;
        struct work_struct work;
@@ -204,12 +206,11 @@ static int blkif_queue_request(struct request *req)
        struct blkfront_info *info = req->rq_disk->private_data;
        unsigned long buffer_mfn;
        struct blkif_request *ring_req;
-       struct req_iterator iter;
-       struct bio_vec *bvec;
        unsigned long id;
        unsigned int fsect, lsect;
-       int ref;
+       int i, ref;
        grant_ref_t gref_head;
+       struct scatterlist *sg;
 
        if (unlikely(info->connected != BLKIF_STATE_CONNECTED))
                return 1;
@@ -238,12 +239,13 @@ static int blkif_queue_request(struct request *req)
        if (blk_barrier_rq(req))
                ring_req->operation = BLKIF_OP_WRITE_BARRIER;
 
-       ring_req->nr_segments = 0;
-       rq_for_each_segment(bvec, req, iter) {
-               BUG_ON(ring_req->nr_segments == BLKIF_MAX_SEGMENTS_PER_REQUEST);
-               buffer_mfn = pfn_to_mfn(page_to_pfn(bvec->bv_page));
-               fsect = bvec->bv_offset >> 9;
-               lsect = fsect + (bvec->bv_len >> 9) - 1;
+       ring_req->nr_segments = blk_rq_map_sg(req->q, req, info->sg);
+       BUG_ON(ring_req->nr_segments > BLKIF_MAX_SEGMENTS_PER_REQUEST);
+
+       for_each_sg(info->sg, sg, ring_req->nr_segments, i) {
+               buffer_mfn = pfn_to_mfn(page_to_pfn(sg_page(sg)));
+               fsect = sg->offset >> 9;
+               lsect = fsect + (sg->length >> 9) - 1;
                /* install a grant reference. */
                ref = gnttab_claim_grant_reference(&gref_head);
                BUG_ON(ref == -ENOSPC);
@@ -254,16 +256,12 @@ static int blkif_queue_request(struct request *req)
                                buffer_mfn,
                                rq_data_dir(req) );
 
-               info->shadow[id].frame[ring_req->nr_segments] =
-                               mfn_to_pfn(buffer_mfn);
-
-               ring_req->seg[ring_req->nr_segments] =
+               info->shadow[id].frame[i] = mfn_to_pfn(buffer_mfn);
+               ring_req->seg[i] =
                                (struct blkif_request_segment) {
                                        .gref       = ref,
                                        .first_sect = fsect,
                                        .last_sect  = lsect };
-
-               ring_req->nr_segments++;
        }
 
        info->ring.req_prod_pvt++;
@@ -622,6 +620,8 @@ static int setup_blkring(struct xenbus_device *dev,
        SHARED_RING_INIT(sring);
        FRONT_RING_INIT(&info->ring, sring, PAGE_SIZE);
 
+       sg_init_table(info->sg, BLKIF_MAX_SEGMENTS_PER_REQUEST);
+
        err = xenbus_grant_ring(dev, virt_to_mfn(info->ring.sring));
        if (err < 0) {
                free_page((unsigned long)sring);
index d3f14bee0f1939fcb1ff0261e6018b0f99e1689e..2a00707aba3bb697493f7fabaeba939a388d092e 100644 (file)
@@ -257,8 +257,7 @@ static inline int bfusb_recv_block(struct bfusb_data *data, int hdr, unsigned ch
 
        if (hdr & 0x10) {
                BT_ERR("%s error in block", data->hdev->name);
-               if (data->reassembly)
-                       kfree_skb(data->reassembly);
+               kfree_skb(data->reassembly);
                data->reassembly = NULL;
                return -EIO;
        }
index ff195c23082587e03a957043cb48dd009984d745..d58e22b9f06a46b2b6a082703f822519f0b815b7 100644 (file)
@@ -359,9 +359,9 @@ static irqreturn_t bt3c_interrupt(int irq, void *dev_inst)
                        BT_ERR("Very strange (stat=0x%04x)", stat);
                } else if ((stat & 0xff) != 0xff) {
                        if (stat & 0x0020) {
-                               int stat = bt3c_read(iobase, 0x7002) & 0x10;
+                               int status = bt3c_read(iobase, 0x7002) & 0x10;
                                BT_INFO("%s: Antenna %s", info->hdev->name,
-                                                       stat ? "out" : "in");
+                                                       status ? "out" : "in");
                        }
                        if (stat & 0x0001)
                                bt3c_receive(info);
index b5fbda6d490a4a142e5a11936b3e14260a09d3de..e70c57ee42211e655499031db8db9eefaf0319e1 100644 (file)
@@ -35,7 +35,7 @@
 #include <net/bluetooth/bluetooth.h>
 #include <net/bluetooth/hci_core.h>
 
-#define VERSION "0.4"
+#define VERSION "0.5"
 
 static int ignore_dga;
 static int ignore_csr;
@@ -171,6 +171,7 @@ struct btusb_data {
 
        __u8 cmdreq_type;
 
+       unsigned int sco_num;
        int isoc_altsetting;
        int suspend_count;
 };
@@ -496,11 +497,23 @@ static int btusb_open(struct hci_dev *hdev)
                return 0;
 
        err = btusb_submit_intr_urb(hdev, GFP_KERNEL);
+       if (err < 0)
+               goto failed;
+
+       err = btusb_submit_bulk_urb(hdev, GFP_KERNEL);
        if (err < 0) {
-               clear_bit(BTUSB_INTR_RUNNING, &data->flags);
-               clear_bit(HCI_RUNNING, &hdev->flags);
+               usb_kill_anchored_urbs(&data->intr_anchor);
+               goto failed;
        }
 
+       set_bit(BTUSB_BULK_RUNNING, &data->flags);
+       btusb_submit_bulk_urb(hdev, GFP_KERNEL);
+
+       return 0;
+
+failed:
+       clear_bit(BTUSB_INTR_RUNNING, &data->flags);
+       clear_bit(HCI_RUNNING, &hdev->flags);
        return err;
 }
 
@@ -655,19 +668,10 @@ static void btusb_notify(struct hci_dev *hdev, unsigned int evt)
 
        BT_DBG("%s evt %d", hdev->name, evt);
 
-       if (hdev->conn_hash.acl_num > 0) {
-               if (!test_and_set_bit(BTUSB_BULK_RUNNING, &data->flags)) {
-                       if (btusb_submit_bulk_urb(hdev, GFP_ATOMIC) < 0)
-                               clear_bit(BTUSB_BULK_RUNNING, &data->flags);
-                       else
-                               btusb_submit_bulk_urb(hdev, GFP_ATOMIC);
-               }
-       } else {
-               clear_bit(BTUSB_BULK_RUNNING, &data->flags);
-               usb_unlink_anchored_urbs(&data->bulk_anchor);
+       if (hdev->conn_hash.sco_num != data->sco_num) {
+               data->sco_num = hdev->conn_hash.sco_num;
+               schedule_work(&data->work);
        }
-
-       schedule_work(&data->work);
 }
 
 static int inline __set_isoc_interface(struct hci_dev *hdev, int altsetting)
@@ -982,9 +986,11 @@ static int btusb_resume(struct usb_interface *intf)
        }
 
        if (test_bit(BTUSB_BULK_RUNNING, &data->flags)) {
-               if (btusb_submit_bulk_urb(hdev, GFP_NOIO) < 0)
+               err = btusb_submit_bulk_urb(hdev, GFP_NOIO);
+               if (err < 0) {
                        clear_bit(BTUSB_BULK_RUNNING, &data->flags);
-               else
+                       return err;
+               } else
                        btusb_submit_bulk_urb(hdev, GFP_NOIO);
        }
 
index b0fafb0559964762ee7db79a32dd336d34e2017b..c0ce8134814e161e5da0b9f59635b9ce26e21983 100644 (file)
@@ -102,8 +102,7 @@ static int h4_close(struct hci_uart *hu)
 
        skb_queue_purge(&h4->txq);
 
-       if (h4->rx_skb)
-               kfree_skb(h4->rx_skb);
+       kfree_skb(h4->rx_skb);
 
        hu->priv = NULL;
        kfree(h4);
index b91d45a41b2f6b7e88716626b392a33124b789d8..5c65014635bee18b493870f3a70b94b03b652df2 100644 (file)
@@ -163,8 +163,7 @@ static int ll_close(struct hci_uart *hu)
        skb_queue_purge(&ll->tx_wait_q);
        skb_queue_purge(&ll->txq);
 
-       if (ll->rx_skb)
-               kfree_skb(ll->rx_skb);
+       kfree_skb(ll->rx_skb);
 
        hu->priv = NULL;
 
index 93998f5baff576d9a68dcbd4077aa1ad37be1c95..341b1142bea864228d0b42a00fb64824d2afc6ca 100644 (file)
@@ -387,7 +387,7 @@ struct scc_port {
 /* The SCC needs 3.5 PCLK cycles recovery time between to register
  * accesses. PCLK runs with 8 MHz on an Atari, so this delay is 3.5 *
  * 125 ns = 437.5 ns. This is too short for udelay().
- * 10/16/95: A tstb mfp.par_dt_reg takes 600ns (sure?) and thus should be
+ * 10/16/95: A tstb st_mfp.par_dt_reg takes 600ns (sure?) and thus should be
  * quite right
  */
 
index f146e90404fa984586513966ed3a87033e01a0b3..518f2a25d91ec6b1a208c6fe233c505a7395aa47 100644 (file)
@@ -1746,9 +1746,10 @@ static long sx_fw_ioctl(struct file *filp, unsigned int cmd,
                sx_dprintk(SX_DEBUG_FIRMWARE, "returning type= %ld\n", rc);
                break;
        case SXIO_DO_RAMTEST:
-               if (sx_initialized)     /* Already initialized: better not ramtest the board.  */
+               if (sx_initialized) {   /* Already initialized: better not ramtest the board.  */
                        rc = -EPERM;
                        break;
+               }
                if (IS_SX_BOARD(board)) {
                        rc = do_memtest(board, 0, 0x7000);
                        if (!rc)
@@ -1788,7 +1789,7 @@ static long sx_fw_ioctl(struct file *filp, unsigned int cmd,
                                                nbytes - i : SX_CHUNK_SIZE)) {
                                        kfree(tmp);
                                        rc = -EFAULT;
-                                       break;
+                                       goto out;
                                }
                                memcpy_toio(board->base2 + offset + i, tmp,
                                                (i + SX_CHUNK_SIZE > nbytes) ?
index 2d637e0fbc038df28dbfbff2d342b89edf6db4a4..d9e751be8c5fb120e5f0d06ef27684c8f33fa549 100644 (file)
@@ -457,10 +457,12 @@ static int init_ixp_crypto(void)
        if (!ctx_pool) {
                goto err;
        }
-       ret = qmgr_request_queue(SEND_QID, NPE_QLEN_TOTAL, 0, 0);
+       ret = qmgr_request_queue(SEND_QID, NPE_QLEN_TOTAL, 0, 0,
+                                "ixp_crypto:out", NULL);
        if (ret)
                goto err;
-       ret = qmgr_request_queue(RECV_QID, NPE_QLEN, 0, 0);
+       ret = qmgr_request_queue(RECV_QID, NPE_QLEN, 0, 0,
+                                "ixp_crypto:in", NULL);
        if (ret) {
                qmgr_release_queue(SEND_QID);
                goto err;
index 856b3cc2558387b7b239923c37c54f9d47b250ff..3f0fdd18255db9febb61836d44b3d7382385140d 100644 (file)
@@ -489,4 +489,4 @@ MODULE_DESCRIPTION("VIA PadLock AES algorithm support");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Michal Ludvig");
 
-MODULE_ALIAS("aes");
+MODULE_ALIAS("aes-all");
index a7fbadebf62330864734e5302be660d2f39ab51a..a2c8e8514b6340ac85915f158d7780491ce8b4a8 100644 (file)
@@ -304,7 +304,7 @@ MODULE_DESCRIPTION("VIA PadLock SHA1/SHA256 algorithms support.");
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR("Michal Ludvig");
 
-MODULE_ALIAS("sha1");
-MODULE_ALIAS("sha256");
+MODULE_ALIAS("sha1-all");
+MODULE_ALIAS("sha256-all");
 MODULE_ALIAS("sha1-padlock");
 MODULE_ALIAS("sha256-padlock");
index bb538b9690e08186ae6c7d73240901b95b6b9ee3..ee916c9857eed0896460e6efb65451082ddbe593 100644 (file)
@@ -1,3 +1,24 @@
+/*
+ * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
+
 #include <linux/kernel.h>
 #include <linux/spinlock.h>
 #include <linux/device.h>
index a58993011edb4bc369a39b6caed0a93f62dc44a8..280a9d263eb3c4271d1cff6e55448cae0a93b387 100644 (file)
@@ -518,6 +518,7 @@ struct dma_chan *__dma_request_channel(dma_cap_mask_t *mask, dma_filter_fn fn, v
                                       dma_chan_name(chan), err);
                        else
                                break;
+                       chan->private = NULL;
                        chan = NULL;
                }
        }
@@ -536,6 +537,7 @@ void dma_release_channel(struct dma_chan *chan)
        WARN_ONCE(chan->client_count != 1,
                  "chan reference count %d != 1\n", chan->client_count);
        dma_chan_put(chan);
+       chan->private = NULL;
        mutex_unlock(&dma_list_mutex);
 }
 EXPORT_SYMBOL_GPL(dma_release_channel);
index 6b702cc46b3d1c36d4a7bdd19228f7c253f35ca8..a97c07eef7ec92468c24150669e690033f310a4f 100644 (file)
@@ -560,7 +560,7 @@ dwc_prep_slave_sg(struct dma_chan *chan, struct scatterlist *sgl,
                unsigned long flags)
 {
        struct dw_dma_chan      *dwc = to_dw_dma_chan(chan);
-       struct dw_dma_slave     *dws = dwc->dws;
+       struct dw_dma_slave     *dws = chan->private;
        struct dw_desc          *prev;
        struct dw_desc          *first;
        u32                     ctllo;
@@ -790,7 +790,7 @@ static int dwc_alloc_chan_resources(struct dma_chan *chan)
        cfghi = DWC_CFGH_FIFO_MODE;
        cfglo = 0;
 
-       dws = dwc->dws;
+       dws = chan->private;
        if (dws) {
                /*
                 * We need controller-specific data to set up slave
@@ -866,7 +866,6 @@ static void dwc_free_chan_resources(struct dma_chan *chan)
        spin_lock_bh(&dwc->lock);
        list_splice_init(&dwc->free_list, &list);
        dwc->descs_allocated = 0;
-       dwc->dws = NULL;
 
        /* Disable interrupts */
        channel_clear_bit(dw, MASK.XFER, dwc->mask);
index 00fdd187bb0cf7ddbb5188cc33097f9739ee4ea7..b252b202c5cf1888f65149d3e22deee3d9cfeef0 100644 (file)
@@ -139,8 +139,6 @@ struct dw_dma_chan {
        struct list_head        queue;
        struct list_head        free_list;
 
-       struct dw_dma_slave     *dws;
-
        unsigned int            descs_allocated;
 };
 
index ea5440dd10dc1ffb56dda5393d51f388e02ca87b..647374acba94a7c526d04236af5a855f81b7258c 100644 (file)
@@ -1401,7 +1401,7 @@ MODULE_ALIAS("platform:iop-adma");
 
 static struct platform_driver iop_adma_driver = {
        .probe          = iop_adma_probe,
-       .remove         = iop_adma_remove,
+       .remove         = __devexit_p(iop_adma_remove),
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = "iop-adma",
index d35cbd1ff0b31e6635dd803eeae708cf75d68772..5d5d5b31867fc9e28dd70696e52ad00fa68c997c 100644 (file)
@@ -1287,7 +1287,7 @@ mv_xor_conf_mbus_windows(struct mv_xor_shared_private *msp,
 
 static struct platform_driver mv_xor_driver = {
        .probe          = mv_xor_probe,
-       .remove         = mv_xor_remove,
+       .remove         = __devexit_p(mv_xor_remove),
        .driver         = {
                .owner  = THIS_MODULE,
                .name   = MV_XOR_NAME,
index 261b9aa3f248e6c2df0c67d5492b35586cf1bb96..05aa2d406ac64769ecfbb3f6827d5e7fb53915e3 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * linux/drivers/firmware/memmap.c
  *  Copyright (C) 2008 SUSE LINUX Products GmbH
- *  by Bernhard Walle <bwalle@suse.de>
+ *  by Bernhard Walle <bernhard.walle@gmx.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License v2.0 as published by
index 4be3acbaaf9a429ff3208d2be7622babe0ac6245..3a22eb9be3783ac890514980e4ea7939c0a38e31 100644 (file)
@@ -80,18 +80,17 @@ config DRM_I915
          XFree86 4.4 and above. If unsure, build this and i830 as modules and
          the X server will load the correct one.
 
-endchoice
-
 config DRM_I915_KMS
        bool "Enable modesetting on intel by default"
        depends on DRM_I915
        help
-       Choose this option if you want kernel modesetting enabled by default,
-       and you have a new enough userspace to support this. Running old
-       userspaces with this enabled will cause pain.  Note that this causes
-       the driver to bind to PCI devices, which precludes loading things
-       like intelfb.
+         Choose this option if you want kernel modesetting enabled by default,
+         and you have a new enough userspace to support this. Running old
+         userspaces with this enabled will cause pain.  Note that this causes
+         the driver to bind to PCI devices, which precludes loading things
+         like intelfb.
 
+endchoice
 
 config DRM_MGA
        tristate "Matrox g200/g400"
index 72c667f9bee1aadbc4067687d05aca0849be751b..12715d3c078d6e9d111c265fe96b5ccc63961d3e 100644 (file)
@@ -420,7 +420,7 @@ int drm_rmmap_locked(struct drm_device *dev, drm_local_map_t *map)
                                dev->sigdata.lock = NULL;
                        master->lock.hw_lock = NULL;   /* SHM removed */
                        master->lock.file_priv = NULL;
-                       wake_up_interruptible(&master->lock.lock_queue);
+                       wake_up_interruptible_all(&master->lock.lock_queue);
                }
                break;
        case _DRM_AGP:
index bfce0992fefbcaa3c3b6848f3e440f88577b2af7..94a76887173444f0e8390014a0ff586eefbea8f8 100644 (file)
@@ -1741,9 +1741,8 @@ out:
  * RETURNS:
  * Zero on success, errno on failure.
  */
-void drm_fb_release(struct file *filp)
+void drm_fb_release(struct drm_file *priv)
 {
-       struct drm_file *priv = filp->private_data;
        struct drm_device *dev = priv->minor->dev;
        struct drm_framebuffer *fb, *tfb;
 
index 964c5eb1fada4266795056abbad038ac23463dd7..1c3a8c5571408a6f0a698a53b58f93f6f471a9a9 100644 (file)
@@ -452,6 +452,59 @@ static void drm_setup_crtcs(struct drm_device *dev)
        kfree(modes);
        kfree(enabled);
 }
+
+/**
+ * drm_encoder_crtc_ok - can a given crtc drive a given encoder?
+ * @encoder: encoder to test
+ * @crtc: crtc to test
+ *
+ * Return false if @encoder can't be driven by @crtc, true otherwise.
+ */
+static bool drm_encoder_crtc_ok(struct drm_encoder *encoder,
+                               struct drm_crtc *crtc)
+{
+       struct drm_device *dev;
+       struct drm_crtc *tmp;
+       int crtc_mask = 1;
+
+       WARN(!crtc, "checking null crtc?");
+
+       dev = crtc->dev;
+
+       list_for_each_entry(tmp, &dev->mode_config.crtc_list, head) {
+               if (tmp == crtc)
+                       break;
+               crtc_mask <<= 1;
+       }
+
+       if (encoder->possible_crtcs & crtc_mask)
+               return true;
+       return false;
+}
+
+/*
+ * Check the CRTC we're going to map each output to vs. its current
+ * CRTC.  If they don't match, we have to disable the output and the CRTC
+ * since the driver will have to re-route things.
+ */
+static void
+drm_crtc_prepare_encoders(struct drm_device *dev)
+{
+       struct drm_encoder_helper_funcs *encoder_funcs;
+       struct drm_encoder *encoder;
+
+       list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
+               encoder_funcs = encoder->helper_private;
+               /* Disable unused encoders */
+               if (encoder->crtc == NULL)
+                       (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
+               /* Disable encoders whose CRTC is about to change */
+               if (encoder_funcs->get_crtc &&
+                   encoder->crtc != (*encoder_funcs->get_crtc)(encoder))
+                       (*encoder_funcs->dpms)(encoder, DRM_MODE_DPMS_OFF);
+       }
+}
+
 /**
  * drm_crtc_set_mode - set a mode
  * @crtc: CRTC to program
@@ -512,8 +565,8 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
        if (drm_mode_equal(&saved_mode, &crtc->mode)) {
                if (saved_x != crtc->x || saved_y != crtc->y ||
                    depth_changed || bpp_changed) {
-                       crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y,
-                                                 old_fb);
+                       ret = !crtc_funcs->mode_set_base(crtc, crtc->x, crtc->y,
+                                                        old_fb);
                        goto done;
                }
        }
@@ -547,12 +600,16 @@ bool drm_crtc_helper_set_mode(struct drm_crtc *crtc,
                encoder_funcs->prepare(encoder);
        }
 
+       drm_crtc_prepare_encoders(dev);
+
        crtc_funcs->prepare(crtc);
 
        /* Set up the DPLL and any encoders state that needs to adjust or depend
         * on the DPLL.
         */
-       crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb);
+       ret = !crtc_funcs->mode_set(crtc, mode, adjusted_mode, x, y, old_fb);
+       if (!ret)
+           goto done;
 
        list_for_each_entry(encoder, &dev->mode_config.encoder_list, head) {
 
@@ -615,7 +672,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
        struct drm_device *dev;
        struct drm_crtc **save_crtcs, *new_crtc;
        struct drm_encoder **save_encoders, *new_encoder;
-       struct drm_framebuffer *old_fb;
+       struct drm_framebuffer *old_fb = NULL;
        bool save_enabled;
        bool mode_changed = false;
        bool fb_changed = false;
@@ -666,9 +723,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
         * and then just flip_or_move it */
        if (set->crtc->fb != set->fb) {
                /* If we have no fb then treat it as a full mode set */
-               if (set->crtc->fb == NULL)
+               if (set->crtc->fb == NULL) {
+                       DRM_DEBUG("crtc has no fb, full mode set\n");
                        mode_changed = true;
-               else if ((set->fb->bits_per_pixel !=
+               else if ((set->fb->bits_per_pixel !=
                         set->crtc->fb->bits_per_pixel) ||
                         set->fb->depth != set->crtc->fb->depth)
                        fb_changed = true;
@@ -680,7 +738,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                fb_changed = true;
 
        if (set->mode && !drm_mode_equal(set->mode, &set->crtc->mode)) {
-               DRM_DEBUG("modes are different\n");
+               DRM_DEBUG("modes are different, full mode set\n");
                drm_mode_debug_printmodeline(&set->crtc->mode);
                drm_mode_debug_printmodeline(set->mode);
                mode_changed = true;
@@ -706,6 +764,7 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                }
 
                if (new_encoder != connector->encoder) {
+                       DRM_DEBUG("encoder changed, full mode switch\n");
                        mode_changed = true;
                        connector->encoder = new_encoder;
                }
@@ -732,10 +791,20 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                        if (set->connectors[ro] == connector)
                                new_crtc = set->crtc;
                }
+
+               /* Make sure the new CRTC will work with the encoder */
+               if (new_crtc &&
+                   !drm_encoder_crtc_ok(connector->encoder, new_crtc)) {
+                       ret = -EINVAL;
+                       goto fail_set_mode;
+               }
                if (new_crtc != connector->encoder->crtc) {
+                       DRM_DEBUG("crtc changed, full mode switch\n");
                        mode_changed = true;
                        connector->encoder->crtc = new_crtc;
                }
+               DRM_DEBUG("setting connector %d crtc to %p\n",
+                         connector->base.id, new_crtc);
        }
 
        /* mode_set_base is not a required function */
@@ -752,6 +821,8 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                        if (!drm_crtc_helper_set_mode(set->crtc, set->mode,
                                                      set->x, set->y,
                                                      old_fb)) {
+                               DRM_ERROR("failed to set mode on crtc %p\n",
+                                         set->crtc);
                                ret = -EINVAL;
                                goto fail_set_mode;
                        }
@@ -765,7 +836,10 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
                old_fb = set->crtc->fb;
                if (set->crtc->fb != set->fb)
                        set->crtc->fb = set->fb;
-               crtc_funcs->mode_set_base(set->crtc, set->x, set->y, old_fb);
+               ret = crtc_funcs->mode_set_base(set->crtc,
+                                               set->x, set->y, old_fb);
+               if (ret != 0)
+                   goto fail_set_mode;
        }
 
        kfree(save_encoders);
@@ -774,9 +848,14 @@ int drm_crtc_helper_set_config(struct drm_mode_set *set)
 
 fail_set_mode:
        set->crtc->enabled = save_enabled;
+       set->crtc->fb = old_fb;
        count = 0;
-       list_for_each_entry(connector, &dev->mode_config.connector_list, head)
+       list_for_each_entry(connector, &dev->mode_config.connector_list, head) {
+               if (!connector->encoder)
+                       continue;
+
                connector->encoder->crtc = save_crtcs[count++];
+       }
 fail_no_encoder:
        kfree(save_crtcs);
        count = 0;
index 5a4d3244758a102ec7cea6ed87342619dd47c85e..a839a28d8ee606763ad213d9dc785bc4dde0dd6c 100644 (file)
@@ -125,7 +125,7 @@ static bool edid_is_valid(struct edid *edid)
                DRM_ERROR("EDID has major version %d, instead of 1\n", edid->version);
                goto bad;
        }
-       if (edid->revision <= 0 || edid->revision > 3) {
+       if (edid->revision > 3) {
                DRM_ERROR("EDID has minor version %d, which is not between 0-3\n", edid->revision);
                goto bad;
        }
@@ -320,10 +320,10 @@ static struct drm_display_mode *drm_mode_detailed(struct drm_device *dev,
        mode->htotal = mode->hdisplay + ((pt->hblank_hi << 8) | pt->hblank_lo);
 
        mode->vdisplay = (pt->vactive_hi << 8) | pt->vactive_lo;
-       mode->vsync_start = mode->vdisplay + ((pt->vsync_offset_hi << 8) |
+       mode->vsync_start = mode->vdisplay + ((pt->vsync_offset_hi << 4) |
                                              pt->vsync_offset_lo);
        mode->vsync_end = mode->vsync_start +
-               ((pt->vsync_pulse_width_hi << 8) |
+               ((pt->vsync_pulse_width_hi << 4) |
                 pt->vsync_pulse_width_lo);
        mode->vtotal = mode->vdisplay + ((pt->vblank_hi << 8) | pt->vblank_lo);
 
index b06a53715853af03df4717108106a72c1effdba5..f52663ebe016f5ea194b5aa2a403881ebb2e0448 100644 (file)
@@ -457,6 +457,9 @@ int drm_release(struct inode *inode, struct file *filp)
        if (dev->driver->driver_features & DRIVER_GEM)
                drm_gem_release(dev, file_priv);
 
+       if (dev->driver->driver_features & DRIVER_MODESET)
+               drm_fb_release(file_priv);
+
        mutex_lock(&dev->ctxlist_mutex);
        if (!list_empty(&dev->ctxlist)) {
                struct drm_ctx_list *pos, *n;
@@ -481,6 +484,7 @@ int drm_release(struct inode *inode, struct file *filp)
        mutex_lock(&dev->struct_mutex);
 
        if (file_priv->is_master) {
+               struct drm_master *master = file_priv->master;
                struct drm_file *temp;
                list_for_each_entry(temp, &dev->filelist, lhead) {
                        if ((temp->master == file_priv->master) &&
@@ -488,6 +492,19 @@ int drm_release(struct inode *inode, struct file *filp)
                                temp->authenticated = 0;
                }
 
+               /**
+                * Since the master is disappearing, so is the
+                * possibility to lock.
+                */
+
+               if (master->lock.hw_lock) {
+                       if (dev->sigdata.lock == master->lock.hw_lock)
+                               dev->sigdata.lock = NULL;
+                       master->lock.hw_lock = NULL;
+                       master->lock.file_priv = NULL;
+                       wake_up_interruptible_all(&master->lock.lock_queue);
+               }
+
                if (file_priv->minor->master == file_priv->master) {
                        /* drop the reference held my the minor */
                        drm_master_put(&file_priv->minor->master);
index 6915fb82d0b0ea6aaa4a5c82b1ac5cf61b572e74..88d3368ffddd946974ba9a42ac273810f9c68c21 100644 (file)
@@ -104,8 +104,8 @@ drm_gem_init(struct drm_device *dev)
 
        if (drm_mm_init(&mm->offset_manager, DRM_FILE_PAGE_OFFSET_START,
                        DRM_FILE_PAGE_OFFSET_SIZE)) {
-               drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM);
                drm_ht_remove(&mm->offset_hash);
+               drm_free(mm, sizeof(struct drm_gem_mm), DRM_MEM_MM);
                return -ENOMEM;
        }
 
@@ -295,35 +295,37 @@ drm_gem_flink_ioctl(struct drm_device *dev, void *data,
                return -EBADF;
 
 again:
-       if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0)
-               return -ENOMEM;
+       if (idr_pre_get(&dev->object_name_idr, GFP_KERNEL) == 0) {
+               ret = -ENOMEM;
+               goto err;
+       }
 
        spin_lock(&dev->object_name_lock);
-       if (obj->name) {
-               args->name = obj->name;
+       if (!obj->name) {
+               ret = idr_get_new_above(&dev->object_name_idr, obj, 1,
+                                       &obj->name);
+               args->name = (uint64_t) obj->name;
                spin_unlock(&dev->object_name_lock);
-               return 0;
-       }
-       ret = idr_get_new_above(&dev->object_name_idr, obj, 1,
-                                &obj->name);
-       spin_unlock(&dev->object_name_lock);
-       if (ret == -EAGAIN)
-               goto again;
 
-       if (ret != 0) {
-               mutex_lock(&dev->struct_mutex);
-               drm_gem_object_unreference(obj);
-               mutex_unlock(&dev->struct_mutex);
-               return ret;
-       }
+               if (ret == -EAGAIN)
+                       goto again;
 
-       /*
-        * Leave the reference from the lookup around as the
-        * name table now holds one
-        */
-       args->name = (uint64_t) obj->name;
+               if (ret != 0)
+                       goto err;
 
-       return 0;
+               /* Allocate a reference for the name table.  */
+               drm_gem_object_reference(obj);
+       } else {
+               args->name = (uint64_t) obj->name;
+               spin_unlock(&dev->object_name_lock);
+               ret = 0;
+       }
+
+err:
+       mutex_lock(&dev->struct_mutex);
+       drm_gem_object_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
+       return ret;
 }
 
 /**
@@ -448,6 +450,7 @@ drm_gem_object_handle_free(struct kref *kref)
        spin_lock(&dev->object_name_lock);
        if (obj->name) {
                idr_remove(&dev->object_name_idr, obj->name);
+               obj->name = 0;
                spin_unlock(&dev->object_name_lock);
                /*
                 * The object name held a reference to this object, drop
@@ -460,6 +463,26 @@ drm_gem_object_handle_free(struct kref *kref)
 }
 EXPORT_SYMBOL(drm_gem_object_handle_free);
 
+void drm_gem_vm_open(struct vm_area_struct *vma)
+{
+       struct drm_gem_object *obj = vma->vm_private_data;
+
+       drm_gem_object_reference(obj);
+}
+EXPORT_SYMBOL(drm_gem_vm_open);
+
+void drm_gem_vm_close(struct vm_area_struct *vma)
+{
+       struct drm_gem_object *obj = vma->vm_private_data;
+       struct drm_device *dev = obj->dev;
+
+       mutex_lock(&dev->struct_mutex);
+       drm_gem_object_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
+}
+EXPORT_SYMBOL(drm_gem_vm_close);
+
+
 /**
  * drm_gem_mmap - memory map routine for GEM objects
  * @filp: DRM file pointer
@@ -521,6 +544,14 @@ int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma)
 #endif
        vma->vm_page_prot = __pgprot(prot);
 
+       /* Take a ref for this mapping of the object, so that the fault
+        * handler can dereference the mmap offset's pointer to the object.
+        * This reference is cleaned up by the corresponding vm_close
+        * (which should happen whether the vma was created by this call, or
+        * by a vm_open due to mremap or partial unmap or whatever).
+        */
+       drm_gem_object_reference(obj);
+
        vma->vm_file = filp;    /* Needed for drm_vm_open() */
        drm_vm_open_locked(vma);
 
index 3795dbc0f50cff99b167fc0659f0d0862c8d57d5..93e677a481f5388f380bc86547297e8f87bddbb0 100644 (file)
@@ -435,6 +435,8 @@ EXPORT_SYMBOL(drm_vblank_get);
  */
 void drm_vblank_put(struct drm_device *dev, int crtc)
 {
+       BUG_ON (atomic_read (&dev->vblank_refcount[crtc]) == 0);
+
        /* Last user schedules interrupt disable */
        if (atomic_dec_and_test(&dev->vblank_refcount[crtc]))
                mod_timer(&dev->vblank_disable_timer, jiffies + 5*DRM_HZ);
@@ -460,8 +462,9 @@ void drm_vblank_pre_modeset(struct drm_device *dev, int crtc)
         * so that interrupts remain enabled in the interim.
         */
        if (!dev->vblank_inmodeset[crtc]) {
-               dev->vblank_inmodeset[crtc] = 1;
-               drm_vblank_get(dev, crtc);
+               dev->vblank_inmodeset[crtc] = 0x1;
+               if (drm_vblank_get(dev, crtc) == 0)
+                       dev->vblank_inmodeset[crtc] |= 0x2;
        }
 }
 EXPORT_SYMBOL(drm_vblank_pre_modeset);
@@ -473,9 +476,12 @@ void drm_vblank_post_modeset(struct drm_device *dev, int crtc)
        if (dev->vblank_inmodeset[crtc]) {
                spin_lock_irqsave(&dev->vbl_lock, irqflags);
                dev->vblank_disable_allowed = 1;
-               dev->vblank_inmodeset[crtc] = 0;
                spin_unlock_irqrestore(&dev->vbl_lock, irqflags);
-               drm_vblank_put(dev, crtc);
+
+               if (dev->vblank_inmodeset[crtc] & 0x2)
+                       drm_vblank_put(dev, crtc);
+
+               dev->vblank_inmodeset[crtc] = 0;
        }
 }
 EXPORT_SYMBOL(drm_vblank_post_modeset);
index 46e7b28f0707397d545948dc21bbcc272f16eb6f..e2f70a516c34412112078131203309c3656622d7 100644 (file)
@@ -80,6 +80,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
                __set_current_state(TASK_INTERRUPTIBLE);
                if (!master->lock.hw_lock) {
                        /* Device has been unregistered */
+                       send_sig(SIGTERM, current, 0);
                        ret = -EINTR;
                        break;
                }
@@ -93,7 +94,7 @@ int drm_lock(struct drm_device *dev, void *data, struct drm_file *file_priv)
                /* Contention */
                schedule();
                if (signal_pending(current)) {
-                       ret = -ERESTARTSYS;
+                       ret = -EINTR;
                        break;
                }
        }
index 46bb923b097c39ad6fef2c37f29e59ae0c648f42..7c8b15b22bf2e089fd9356debc9f967031723cbe 100644 (file)
@@ -146,14 +146,6 @@ static void drm_master_destroy(struct kref *kref)
 
        drm_ht_remove(&master->magiclist);
 
-       if (master->lock.hw_lock) {
-               if (dev->sigdata.lock == master->lock.hw_lock)
-                       dev->sigdata.lock = NULL;
-               master->lock.hw_lock = NULL;
-               master->lock.file_priv = NULL;
-               wake_up_interruptible(&master->lock.lock_queue);
-       }
-
        drm_free(master, sizeof(*master), DRM_MEM_DRIVER);
 }
 
@@ -176,7 +168,7 @@ int drm_setmaster_ioctl(struct drm_device *dev, void *data,
            file_priv->minor->master != file_priv->master) {
                mutex_lock(&dev->struct_mutex);
                file_priv->minor->master = drm_master_get(file_priv->master);
-               mutex_lock(&dev->struct_mutex);
+               mutex_unlock(&dev->struct_mutex);
        }
 
        return 0;
index 81f1cff56fd5e2ff02313849a2d9f4d412d22237..6dab63bdc4c10e3182447bb61fbd5930d8366d6f 100644 (file)
@@ -202,7 +202,7 @@ static int i915_initialize(struct drm_device * dev, drm_i915_init_t * init)
                dev_priv->ring.map.flags = 0;
                dev_priv->ring.map.mtrr = 0;
 
-               drm_core_ioremap(&dev_priv->ring.map, dev);
+               drm_core_ioremap_wc(&dev_priv->ring.map, dev);
 
                if (dev_priv->ring.map.handle == NULL) {
                        i915_dma_cleanup(dev);
@@ -811,7 +811,7 @@ static int i915_set_status_page(struct drm_device *dev, void *data,
        dev_priv->hws_map.flags = 0;
        dev_priv->hws_map.mtrr = 0;
 
-       drm_core_ioremap(&dev_priv->hws_map, dev);
+       drm_core_ioremap_wc(&dev_priv->hws_map, dev);
        if (dev_priv->hws_map.handle == NULL) {
                i915_dma_cleanup(dev);
                dev_priv->status_gfx_addr = 0;
@@ -1090,6 +1090,11 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
         dev_priv->mm.gtt_mapping =
                io_mapping_create_wc(dev->agp->base,
                                     dev->agp->agp_info.aper_size * 1024*1024);
+       if (dev_priv->mm.gtt_mapping == NULL) {
+               ret = -EIO;
+               goto out_rmmap;
+       }
+
        /* Set up a WC MTRR for non-PAT systems.  This is more common than
         * one would think, because the kernel disables PAT on first
         * generation Core chips because WC PAT gets overridden by a UC
@@ -1122,7 +1127,7 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
        if (!I915_NEED_GFX_HWS(dev)) {
                ret = i915_init_phys_hws(dev);
                if (ret != 0)
-                       goto out_rmmap;
+                       goto out_iomapfree;
        }
 
        /* On the 945G/GM, the chipset reports the MSI capability on the
@@ -1161,6 +1166,8 @@ int i915_driver_load(struct drm_device *dev, unsigned long flags)
 
        return 0;
 
+out_iomapfree:
+       io_mapping_free(dev_priv->mm.gtt_mapping);
 out_rmmap:
        iounmap(dev_priv->regs);
 free_priv:
index aac12ee31a46e86540e7e2cba43d8cef273e27c2..b293ef0bae7153805d587201c8ce6c84f3703f4c 100644 (file)
@@ -27,6 +27,7 @@
  *
  */
 
+#include <linux/device.h>
 #include "drmP.h"
 #include "drm.h"
 #include "i915_drm.h"
@@ -66,6 +67,14 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
 
        i915_save_state(dev);
 
+       /* If KMS is active, we do the leavevt stuff here */
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               if (i915_gem_idle(dev))
+                       dev_err(&dev->pdev->dev,
+                               "GEM idle failed, resume may fail\n");
+               drm_irq_uninstall(dev);
+       }
+
        intel_opregion_free(dev);
 
        if (state.event == PM_EVENT_SUSPEND) {
@@ -79,6 +88,9 @@ static int i915_suspend(struct drm_device *dev, pm_message_t state)
 
 static int i915_resume(struct drm_device *dev)
 {
+       struct drm_i915_private *dev_priv = dev->dev_private;
+       int ret = 0;
+
        pci_set_power_state(dev->pdev, PCI_D0);
        pci_restore_state(dev->pdev);
        if (pci_enable_device(dev->pdev))
@@ -89,11 +101,26 @@ static int i915_resume(struct drm_device *dev)
 
        intel_opregion_init(dev);
 
-       return 0;
+       /* KMS EnterVT equivalent */
+       if (drm_core_check_feature(dev, DRIVER_MODESET)) {
+               mutex_lock(&dev->struct_mutex);
+               dev_priv->mm.suspended = 0;
+
+               ret = i915_gem_init_ringbuffer(dev);
+               if (ret != 0)
+                       ret = -1;
+               mutex_unlock(&dev->struct_mutex);
+
+               drm_irq_install(dev);
+       }
+
+       return ret;
 }
 
 static struct vm_operations_struct i915_gem_vm_ops = {
        .fault = i915_gem_fault,
+       .open = drm_gem_vm_open,
+       .close = drm_gem_vm_close,
 };
 
 static struct drm_driver driver = {
index 7325363164f84cf26a2f39bc3312753d1c31f28b..17fa40858d26147b5ae6ca041adb5984c05ac06a 100644 (file)
@@ -184,6 +184,8 @@ typedef struct drm_i915_private {
        unsigned int lvds_dither:1;
        unsigned int lvds_vbt:1;
        unsigned int int_crt_support:1;
+       unsigned int lvds_use_ssc:1;
+       int lvds_ssc_freq;
 
        struct drm_i915_fence_reg fence_regs[16]; /* assume 965 */
        int fence_reg_start; /* 4 if userland hasn't ioctl'd us yet */
@@ -616,6 +618,7 @@ int i915_gem_init_ringbuffer(struct drm_device *dev);
 void i915_gem_cleanup_ringbuffer(struct drm_device *dev);
 int i915_gem_do_init(struct drm_device *dev, unsigned long start,
                     unsigned long end);
+int i915_gem_idle(struct drm_device *dev);
 int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf);
 int i915_gem_object_set_to_gtt_domain(struct drm_gem_object *obj,
                                      int write);
index 818576654092b341746ebb40a846e15ebfb4d5fc..85685bfd12daf02fb26bea88a90e521d6e3237c2 100644 (file)
 
 #define I915_GEM_GPU_DOMAINS   (~(I915_GEM_DOMAIN_CPU | I915_GEM_DOMAIN_GTT))
 
-static void
-i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
-                                 uint32_t read_domains,
-                                 uint32_t write_domain);
 static void i915_gem_object_flush_gpu_write_domain(struct drm_gem_object *obj);
 static void i915_gem_object_flush_gtt_write_domain(struct drm_gem_object *obj);
 static void i915_gem_object_flush_cpu_write_domain(struct drm_gem_object *obj);
@@ -607,8 +603,6 @@ int i915_gem_fault(struct vm_area_struct *vma, struct vm_fault *vmf)
        case -EAGAIN:
                return VM_FAULT_OOM;
        case -EFAULT:
-       case -EBUSY:
-               DRM_ERROR("can't insert pfn??  fault or busy...\n");
                return VM_FAULT_SIGBUS;
        default:
                return VM_FAULT_NOPAGE;
@@ -684,6 +678,30 @@ out_free_list:
        return ret;
 }
 
+static void
+i915_gem_free_mmap_offset(struct drm_gem_object *obj)
+{
+       struct drm_device *dev = obj->dev;
+       struct drm_i915_gem_object *obj_priv = obj->driver_private;
+       struct drm_gem_mm *mm = dev->mm_private;
+       struct drm_map_list *list;
+
+       list = &obj->map_list;
+       drm_ht_remove_item(&mm->offset_hash, &list->hash);
+
+       if (list->file_offset_node) {
+               drm_mm_put_block(list->file_offset_node);
+               list->file_offset_node = NULL;
+       }
+
+       if (list->map) {
+               drm_free(list->map, sizeof(struct drm_map), DRM_MEM_DRIVER);
+               list->map = NULL;
+       }
+
+       obj_priv->mmap_offset = 0;
+}
+
 /**
  * i915_gem_get_gtt_alignment - return required GTT alignment for an object
  * @obj: object to check
@@ -758,8 +776,11 @@ i915_gem_mmap_gtt_ioctl(struct drm_device *dev, void *data,
 
        if (!obj_priv->mmap_offset) {
                ret = i915_gem_create_mmap_offset(obj);
-               if (ret)
+               if (ret) {
+                       drm_gem_object_unreference(obj);
+                       mutex_unlock(&dev->struct_mutex);
                        return ret;
+               }
        }
 
        args->offset = obj_priv->mmap_offset;
@@ -1030,6 +1051,9 @@ i915_gem_retire_requests(struct drm_device *dev)
        drm_i915_private_t *dev_priv = dev->dev_private;
        uint32_t seqno;
 
+       if (!dev_priv->hw_status_page)
+               return;
+
        seqno = i915_get_gem_seqno(dev);
 
        while (!list_empty(&dev_priv->mm.request_list)) {
@@ -1996,30 +2020,28 @@ i915_gem_object_set_to_cpu_domain(struct drm_gem_object *obj, int write)
  *             drm_agp_chipset_flush
  */
 static void
-i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
-                                 uint32_t read_domains,
-                                 uint32_t write_domain)
+i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj)
 {
        struct drm_device               *dev = obj->dev;
        struct drm_i915_gem_object      *obj_priv = obj->driver_private;
        uint32_t                        invalidate_domains = 0;
        uint32_t                        flush_domains = 0;
 
-       BUG_ON(read_domains & I915_GEM_DOMAIN_CPU);
-       BUG_ON(write_domain == I915_GEM_DOMAIN_CPU);
+       BUG_ON(obj->pending_read_domains & I915_GEM_DOMAIN_CPU);
+       BUG_ON(obj->pending_write_domain == I915_GEM_DOMAIN_CPU);
 
 #if WATCH_BUF
        DRM_INFO("%s: object %p read %08x -> %08x write %08x -> %08x\n",
                 __func__, obj,
-                obj->read_domains, read_domains,
-                obj->write_domain, write_domain);
+                obj->read_domains, obj->pending_read_domains,
+                obj->write_domain, obj->pending_write_domain);
 #endif
        /*
         * If the object isn't moving to a new write domain,
         * let the object stay in multiple read domains
         */
-       if (write_domain == 0)
-               read_domains |= obj->read_domains;
+       if (obj->pending_write_domain == 0)
+               obj->pending_read_domains |= obj->read_domains;
        else
                obj_priv->dirty = 1;
 
@@ -2029,15 +2051,17 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
         * any read domains which differ from the old
         * write domain
         */
-       if (obj->write_domain && obj->write_domain != read_domains) {
+       if (obj->write_domain &&
+           obj->write_domain != obj->pending_read_domains) {
                flush_domains |= obj->write_domain;
-               invalidate_domains |= read_domains & ~obj->write_domain;
+               invalidate_domains |=
+                       obj->pending_read_domains & ~obj->write_domain;
        }
        /*
         * Invalidate any read caches which may have
         * stale data. That is, any new read domains.
         */
-       invalidate_domains |= read_domains & ~obj->read_domains;
+       invalidate_domains |= obj->pending_read_domains & ~obj->read_domains;
        if ((flush_domains | invalidate_domains) & I915_GEM_DOMAIN_CPU) {
 #if WATCH_BUF
                DRM_INFO("%s: CPU domain flush %08x invalidate %08x\n",
@@ -2046,9 +2070,15 @@ i915_gem_object_set_to_gpu_domain(struct drm_gem_object *obj,
                i915_gem_clflush_object(obj);
        }
 
-       if ((write_domain | flush_domains) != 0)
-               obj->write_domain = write_domain;
-       obj->read_domains = read_domains;
+       /* The actual obj->write_domain will be updated with
+        * pending_write_domain after we emit the accumulated flush for all
+        * of our domain changes in execbuffers (which clears objects'
+        * write_domains).  So if we have a current write domain that we
+        * aren't changing, set pending_write_domain to that.
+        */
+       if (flush_domains == 0 && obj->pending_write_domain == 0)
+               obj->pending_write_domain = obj->write_domain;
+       obj->read_domains = obj->pending_read_domains;
 
        dev->invalidate_domains |= invalidate_domains;
        dev->flush_domains |= flush_domains;
@@ -2251,6 +2281,8 @@ i915_gem_object_pin_and_relocate(struct drm_gem_object *obj,
                                  (int) reloc.offset,
                                  reloc.read_domains,
                                  reloc.write_domain);
+                       drm_gem_object_unreference(target_obj);
+                       i915_gem_object_unpin(obj);
                        return -EINVAL;
                }
 
@@ -2480,13 +2512,15 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
        if (dev_priv->mm.wedged) {
                DRM_ERROR("Execbuf while wedged\n");
                mutex_unlock(&dev->struct_mutex);
-               return -EIO;
+               ret = -EIO;
+               goto pre_mutex_err;
        }
 
        if (dev_priv->mm.suspended) {
                DRM_ERROR("Execbuf while VT-switched.\n");
                mutex_unlock(&dev->struct_mutex);
-               return -EBUSY;
+               ret = -EBUSY;
+               goto pre_mutex_err;
        }
 
        /* Look up object handles */
@@ -2554,9 +2588,7 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
                struct drm_gem_object *obj = object_list[i];
 
                /* Compute new gpu domains and update invalidate/flush */
-               i915_gem_object_set_to_gpu_domain(obj,
-                                                 obj->pending_read_domains,
-                                                 obj->pending_write_domain);
+               i915_gem_object_set_to_gpu_domain(obj);
        }
 
        i915_verify_inactive(dev, __FILE__, __LINE__);
@@ -2575,6 +2607,12 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
                        (void)i915_add_request(dev, dev->flush_domains);
        }
 
+       for (i = 0; i < args->buffer_count; i++) {
+               struct drm_gem_object *obj = object_list[i];
+
+               obj->write_domain = obj->pending_write_domain;
+       }
+
        i915_verify_inactive(dev, __FILE__, __LINE__);
 
 #if WATCH_COHERENCY
@@ -2632,15 +2670,6 @@ i915_gem_execbuffer(struct drm_device *dev, void *data,
 
        i915_verify_inactive(dev, __FILE__, __LINE__);
 
-       /* Copy the new buffer offsets back to the user's exec list. */
-       ret = copy_to_user((struct drm_i915_relocation_entry __user *)
-                          (uintptr_t) args->buffers_ptr,
-                          exec_list,
-                          sizeof(*exec_list) * args->buffer_count);
-       if (ret)
-               DRM_ERROR("failed to copy %d exec entries "
-                         "back to user (%d)\n",
-                          args->buffer_count, ret);
 err:
        for (i = 0; i < pinned; i++)
                i915_gem_object_unpin(object_list[i]);
@@ -2650,6 +2679,18 @@ err:
 
        mutex_unlock(&dev->struct_mutex);
 
+       if (!ret) {
+               /* Copy the new buffer offsets back to the user's exec list. */
+               ret = copy_to_user((struct drm_i915_relocation_entry __user *)
+                                  (uintptr_t) args->buffers_ptr,
+                                  exec_list,
+                                  sizeof(*exec_list) * args->buffer_count);
+               if (ret)
+                       DRM_ERROR("failed to copy %d exec entries "
+                                 "back to user (%d)\n",
+                                 args->buffer_count, ret);
+       }
+
 pre_mutex_err:
        drm_free(object_list, sizeof(*object_list) * args->buffer_count,
                 DRM_MEM_DRIVER);
@@ -2753,6 +2794,7 @@ i915_gem_pin_ioctl(struct drm_device *dev, void *data,
        if (obj_priv->pin_filp != NULL && obj_priv->pin_filp != file_priv) {
                DRM_ERROR("Already pinned in i915_gem_pin_ioctl(): %d\n",
                          args->handle);
+               drm_gem_object_unreference(obj);
                mutex_unlock(&dev->struct_mutex);
                return -EINVAL;
        }
@@ -2833,6 +2875,13 @@ i915_gem_busy_ioctl(struct drm_device *dev, void *data,
                return -EBADF;
        }
 
+       /* Update the active list for the hardware's current position.
+        * Otherwise this only updates on a delayed timer or when irqs are
+        * actually unmasked, and our working set ends up being larger than
+        * required.
+        */
+       i915_gem_retire_requests(dev);
+
        obj_priv = obj->driver_private;
        /* Don't count being on the flushing list against the object being
         * done.  Otherwise, a buffer left on the flushing list but not getting
@@ -2885,9 +2934,6 @@ int i915_gem_init_object(struct drm_gem_object *obj)
 void i915_gem_free_object(struct drm_gem_object *obj)
 {
        struct drm_device *dev = obj->dev;
-       struct drm_gem_mm *mm = dev->mm_private;
-       struct drm_map_list *list;
-       struct drm_map *map;
        struct drm_i915_gem_object *obj_priv = obj->driver_private;
 
        while (obj_priv->pin_count > 0)
@@ -2898,19 +2944,7 @@ void i915_gem_free_object(struct drm_gem_object *obj)
 
        i915_gem_object_unbind(obj);
 
-       list = &obj->map_list;
-       drm_ht_remove_item(&mm->offset_hash, &list->hash);
-
-       if (list->file_offset_node) {
-               drm_mm_put_block(list->file_offset_node);
-               list->file_offset_node = NULL;
-       }
-
-       map = list->map;
-       if (map) {
-               drm_free(map, sizeof(*map), DRM_MEM_DRIVER);
-               list->map = NULL;
-       }
+       i915_gem_free_mmap_offset(obj);
 
        drm_free(obj_priv->page_cpu_valid, 1, DRM_MEM_DRIVER);
        drm_free(obj->driver_private, 1, DRM_MEM_DRIVER);
@@ -2949,7 +2983,7 @@ i915_gem_evict_from_list(struct drm_device *dev, struct list_head *head)
        return 0;
 }
 
-static int
+int
 i915_gem_idle(struct drm_device *dev)
 {
        drm_i915_private_t *dev_priv = dev->dev_private;
@@ -3095,6 +3129,7 @@ i915_gem_init_hws(struct drm_device *dev)
        if (dev_priv->hw_status_page == NULL) {
                DRM_ERROR("Failed to map status page.\n");
                memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
+               i915_gem_object_unpin(obj);
                drm_gem_object_unreference(obj);
                return -EINVAL;
        }
@@ -3107,6 +3142,31 @@ i915_gem_init_hws(struct drm_device *dev)
        return 0;
 }
 
+static void
+i915_gem_cleanup_hws(struct drm_device *dev)
+{
+       drm_i915_private_t *dev_priv = dev->dev_private;
+       struct drm_gem_object *obj;
+       struct drm_i915_gem_object *obj_priv;
+
+       if (dev_priv->hws_obj == NULL)
+               return;
+
+       obj = dev_priv->hws_obj;
+       obj_priv = obj->driver_private;
+
+       kunmap(obj_priv->page_list[0]);
+       i915_gem_object_unpin(obj);
+       drm_gem_object_unreference(obj);
+       dev_priv->hws_obj = NULL;
+
+       memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
+       dev_priv->hw_status_page = NULL;
+
+       /* Write high address into HWS_PGA when disabling. */
+       I915_WRITE(HWS_PGA, 0x1ffff000);
+}
+
 int
 i915_gem_init_ringbuffer(struct drm_device *dev)
 {
@@ -3124,6 +3184,7 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
        obj = drm_gem_object_alloc(dev, 128 * 1024);
        if (obj == NULL) {
                DRM_ERROR("Failed to allocate ringbuffer\n");
+               i915_gem_cleanup_hws(dev);
                return -ENOMEM;
        }
        obj_priv = obj->driver_private;
@@ -3131,6 +3192,7 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
        ret = i915_gem_object_pin(obj, 4096);
        if (ret != 0) {
                drm_gem_object_unreference(obj);
+               i915_gem_cleanup_hws(dev);
                return ret;
        }
 
@@ -3148,7 +3210,9 @@ i915_gem_init_ringbuffer(struct drm_device *dev)
        if (ring->map.handle == NULL) {
                DRM_ERROR("Failed to map ringbuffer.\n");
                memset(&dev_priv->ring, 0, sizeof(dev_priv->ring));
+               i915_gem_object_unpin(obj);
                drm_gem_object_unreference(obj);
+               i915_gem_cleanup_hws(dev);
                return -EINVAL;
        }
        ring->ring_obj = obj;
@@ -3228,20 +3292,7 @@ i915_gem_cleanup_ringbuffer(struct drm_device *dev)
        dev_priv->ring.ring_obj = NULL;
        memset(&dev_priv->ring, 0, sizeof(dev_priv->ring));
 
-       if (dev_priv->hws_obj != NULL) {
-               struct drm_gem_object *obj = dev_priv->hws_obj;
-               struct drm_i915_gem_object *obj_priv = obj->driver_private;
-
-               kunmap(obj_priv->page_list[0]);
-               i915_gem_object_unpin(obj);
-               drm_gem_object_unreference(obj);
-               dev_priv->hws_obj = NULL;
-               memset(&dev_priv->hws_map, 0, sizeof(dev_priv->hws_map));
-               dev_priv->hw_status_page = NULL;
-
-               /* Write high address into HWS_PGA when disabling. */
-               I915_WRITE(HWS_PGA, 0x1ffff000);
-       }
+       i915_gem_cleanup_hws(dev);
 }
 
 int
@@ -3497,7 +3548,7 @@ i915_gem_phys_pwrite(struct drm_device *dev, struct drm_gem_object *obj,
        user_data = (char __user *) (uintptr_t) args->data_ptr;
        obj_addr = obj_priv->phys_obj->handle->vaddr + args->offset;
 
-       DRM_ERROR("obj_addr %p, %lld\n", obj_addr, args->size);
+       DRM_DEBUG("obj_addr %p, %lld\n", obj_addr, args->size);
        ret = copy_from_user(obj_addr, user_data, args->size);
        if (ret)
                return -EFAULT;
index fa1685cba8402fdbd456be37f627bd21c170cca4..7fb4191ef934c2b9a9549a36737e075d6ee3fca7 100644 (file)
@@ -299,9 +299,8 @@ i915_gem_set_tiling(struct drm_device *dev, void *data,
        }
        obj_priv->stride = args->stride;
 
-       mutex_unlock(&dev->struct_mutex);
-
        drm_gem_object_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
 
        return 0;
 }
@@ -340,9 +339,8 @@ i915_gem_get_tiling(struct drm_device *dev, void *data,
                DRM_ERROR("unknown tiling mode\n");
        }
 
-       mutex_unlock(&dev->struct_mutex);
-
        drm_gem_object_unreference(obj);
+       mutex_unlock(&dev->struct_mutex);
 
        return 0;
 }
index 548ff2c66431ee93a205b15d84362084da7486ce..87b6b603469ea278780af278fb9b7dc92d013ed0 100644 (file)
@@ -383,12 +383,13 @@ int i915_irq_emit(struct drm_device *dev, void *data,
        drm_i915_irq_emit_t *emit = data;
        int result;
 
-       RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
-
        if (!dev_priv) {
                DRM_ERROR("called with no initialization\n");
                return -EINVAL;
        }
+
+       RING_LOCK_TEST_WITH_RETURN(dev, file_priv);
+
        mutex_lock(&dev->struct_mutex);
        result = i915_emit_irq(dev);
        mutex_unlock(&dev->struct_mutex);
index 4ca82a0255255e09f82426bc23b2bc25da555f08..fc28e2bbd5427e6030869724dfb9bd20b5797451 100644 (file)
@@ -111,6 +111,12 @@ parse_panel_data(struct drm_i915_private *dev_priv, struct bdb_header *bdb)
        panel_fixed_mode->clock = dvo_timing->clock * 10;
        panel_fixed_mode->type = DRM_MODE_TYPE_PREFERRED;
 
+       /* Some VBTs have bogus h/vtotal values */
+       if (panel_fixed_mode->hsync_end > panel_fixed_mode->htotal)
+               panel_fixed_mode->htotal = panel_fixed_mode->hsync_end + 1;
+       if (panel_fixed_mode->vsync_end > panel_fixed_mode->vtotal)
+               panel_fixed_mode->vtotal = panel_fixed_mode->vsync_end + 1;
+
        drm_mode_set_name(panel_fixed_mode);
 
        dev_priv->vbt_mode = panel_fixed_mode;
@@ -135,6 +141,14 @@ parse_general_features(struct drm_i915_private *dev_priv,
        if (general) {
                dev_priv->int_tv_support = general->int_tv_support;
                dev_priv->int_crt_support = general->int_crt_support;
+               dev_priv->lvds_use_ssc = general->enable_ssc;
+
+               if (dev_priv->lvds_use_ssc) {
+                 if (IS_I855(dev_priv->dev))
+                   dev_priv->lvds_ssc_freq = general->ssc_freq ? 66 : 48;
+                 else
+                   dev_priv->lvds_ssc_freq = general->ssc_freq ? 100 : 96;
+               }
        }
 }
 
index bbdd72909a113db3cf70411de682121d57ebba0a..a2834276cb38637949648dad2ae2b59de8995fbf 100644 (file)
@@ -90,12 +90,12 @@ typedef struct {
 #define I9XX_DOT_MAX            400000
 #define I9XX_VCO_MIN           1400000
 #define I9XX_VCO_MAX           2800000
-#define I9XX_N_MIN                   3
-#define I9XX_N_MAX                   8
+#define I9XX_N_MIN                   1
+#define I9XX_N_MAX                   6
 #define I9XX_M_MIN                  70
 #define I9XX_M_MAX                 120
 #define I9XX_M1_MIN                 10
-#define I9XX_M1_MAX                 20
+#define I9XX_M1_MAX                 22
 #define I9XX_M2_MIN                  5
 #define I9XX_M2_MAX                  9
 #define I9XX_P_SDVO_DAC_MIN          5
@@ -189,9 +189,7 @@ static const intel_limit_t *intel_limit(struct drm_crtc *crtc)
        return limit;
 }
 
-/** Derive the pixel clock for the given refclk and divisors for 8xx chips. */
-
-static void i8xx_clock(int refclk, intel_clock_t *clock)
+static void intel_clock(int refclk, intel_clock_t *clock)
 {
        clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
        clock->p = clock->p1 * clock->p2;
@@ -199,25 +197,6 @@ static void i8xx_clock(int refclk, intel_clock_t *clock)
        clock->dot = clock->vco / clock->p;
 }
 
-/** Derive the pixel clock for the given refclk and divisors for 9xx chips. */
-
-static void i9xx_clock(int refclk, intel_clock_t *clock)
-{
-       clock->m = 5 * (clock->m1 + 2) + (clock->m2 + 2);
-       clock->p = clock->p1 * clock->p2;
-       clock->vco = refclk * clock->m / (clock->n + 2);
-       clock->dot = clock->vco / clock->p;
-}
-
-static void intel_clock(struct drm_device *dev, int refclk,
-                       intel_clock_t *clock)
-{
-       if (IS_I9XX(dev))
-               i9xx_clock (refclk, clock);
-       else
-               i8xx_clock (refclk, clock);
-}
-
 /**
  * Returns whether any output on the specified pipe is of the specified type
  */
@@ -238,7 +217,7 @@ bool intel_pipe_has_type (struct drm_crtc *crtc, int type)
     return false;
 }
 
-#define INTELPllInvalid(s)   { /* ErrorF (s) */; return false; }
+#define INTELPllInvalid(s)   do { /* DRM_DEBUG(s); */ return false; } while (0)
 /**
  * Returns whether the given set of divisors are valid for a given refclk with
  * the given connectors.
@@ -318,7 +297,7 @@ static bool intel_find_best_PLL(struct drm_crtc *crtc, int target,
                                     clock.p1 <= limit->p1.max; clock.p1++) {
                                        int this_err;
 
-                                       intel_clock(dev, refclk, &clock);
+                                       intel_clock(refclk, &clock);
 
                                        if (!intel_PLL_is_valid(crtc, &clock))
                                                continue;
@@ -343,7 +322,7 @@ intel_wait_for_vblank(struct drm_device *dev)
        udelay(20000);
 }
 
-static void
+static int
 intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                    struct drm_framebuffer *old_fb)
 {
@@ -361,11 +340,21 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
        int dspstride = (pipe == 0) ? DSPASTRIDE : DSPBSTRIDE;
        int dspcntr_reg = (pipe == 0) ? DSPACNTR : DSPBCNTR;
        u32 dspcntr, alignment;
+       int ret;
 
        /* no fb bound */
        if (!crtc->fb) {
                DRM_DEBUG("No FB bound\n");
-               return;
+               return 0;
+       }
+
+       switch (pipe) {
+       case 0:
+       case 1:
+               break;
+       default:
+               DRM_ERROR("Can't update pipe %d in SAREA\n", pipe);
+               return -EINVAL;
        }
 
        intel_fb = to_intel_framebuffer(crtc->fb);
@@ -377,28 +366,30 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                alignment = 64 * 1024;
                break;
        case I915_TILING_X:
-               if (IS_I9XX(dev))
-                       alignment = 1024 * 1024;
-               else
-                       alignment = 512 * 1024;
+               /* pin() will align the object as required by fence */
+               alignment = 0;
                break;
        case I915_TILING_Y:
                /* FIXME: Is this true? */
                DRM_ERROR("Y tiled not allowed for scan out buffers\n");
-               return;
+               return -EINVAL;
        default:
                BUG();
        }
 
-       if (i915_gem_object_pin(intel_fb->obj, alignment))
-               return;
-
-       i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1);
-
-       Start = obj_priv->gtt_offset;
-       Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8);
+       mutex_lock(&dev->struct_mutex);
+       ret = i915_gem_object_pin(intel_fb->obj, alignment);
+       if (ret != 0) {
+               mutex_unlock(&dev->struct_mutex);
+               return ret;
+       }
 
-       I915_WRITE(dspstride, crtc->fb->pitch);
+       ret = i915_gem_object_set_to_gtt_domain(intel_fb->obj, 1);
+       if (ret != 0) {
+               i915_gem_object_unpin(intel_fb->obj);
+               mutex_unlock(&dev->struct_mutex);
+               return ret;
+       }
 
        dspcntr = I915_READ(dspcntr_reg);
        /* Mask out pixel format bits in case we change it */
@@ -419,11 +410,17 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                break;
        default:
                DRM_ERROR("Unknown color depth\n");
-               return;
+               i915_gem_object_unpin(intel_fb->obj);
+               mutex_unlock(&dev->struct_mutex);
+               return -EINVAL;
        }
        I915_WRITE(dspcntr_reg, dspcntr);
 
+       Start = obj_priv->gtt_offset;
+       Offset = y * crtc->fb->pitch + x * (crtc->fb->bits_per_pixel / 8);
+
        DRM_DEBUG("Writing base %08lX %08lX %d %d\n", Start, Offset, x, y);
+       I915_WRITE(dspstride, crtc->fb->pitch);
        if (IS_I965G(dev)) {
                I915_WRITE(dspbase, Offset);
                I915_READ(dspbase);
@@ -440,27 +437,24 @@ intel_pipe_set_base(struct drm_crtc *crtc, int x, int y,
                intel_fb = to_intel_framebuffer(old_fb);
                i915_gem_object_unpin(intel_fb->obj);
        }
+       mutex_unlock(&dev->struct_mutex);
 
        if (!dev->primary->master)
-               return;
+               return 0;
 
        master_priv = dev->primary->master->driver_priv;
        if (!master_priv->sarea_priv)
-               return;
+               return 0;
 
-       switch (pipe) {
-       case 0:
-               master_priv->sarea_priv->pipeA_x = x;
-               master_priv->sarea_priv->pipeA_y = y;
-               break;
-       case 1:
+       if (pipe) {
                master_priv->sarea_priv->pipeB_x = x;
                master_priv->sarea_priv->pipeB_y = y;
-               break;
-       default:
-               DRM_ERROR("Can't update pipe %d in SAREA\n", pipe);
-               break;
+       } else {
+               master_priv->sarea_priv->pipeA_x = x;
+               master_priv->sarea_priv->pipeA_y = y;
        }
+
+       return 0;
 }
 
 
@@ -708,11 +702,11 @@ static int intel_panel_fitter_pipe (struct drm_device *dev)
        return 1;
 }
 
-static void intel_crtc_mode_set(struct drm_crtc *crtc,
-                               struct drm_display_mode *mode,
-                               struct drm_display_mode *adjusted_mode,
-                               int x, int y,
-                               struct drm_framebuffer *old_fb)
+static int intel_crtc_mode_set(struct drm_crtc *crtc,
+                              struct drm_display_mode *mode,
+                              struct drm_display_mode *adjusted_mode,
+                              int x, int y,
+                              struct drm_framebuffer *old_fb)
 {
        struct drm_device *dev = crtc->dev;
        struct drm_i915_private *dev_priv = dev->dev_private;
@@ -732,13 +726,14 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
        int dspsize_reg = (pipe == 0) ? DSPASIZE : DSPBSIZE;
        int dsppos_reg = (pipe == 0) ? DSPAPOS : DSPBPOS;
        int pipesrc_reg = (pipe == 0) ? PIPEASRC : PIPEBSRC;
-       int refclk;
+       int refclk, num_outputs = 0;
        intel_clock_t clock;
        u32 dpll = 0, fp = 0, dspcntr, pipeconf;
        bool ok, is_sdvo = false, is_dvo = false;
        bool is_crt = false, is_lvds = false, is_tv = false;
        struct drm_mode_config *mode_config = &dev->mode_config;
        struct drm_connector *connector;
+       int ret;
 
        drm_vblank_pre_modeset(dev, pipe);
 
@@ -768,9 +763,14 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
                        is_crt = true;
                        break;
                }
+
+               num_outputs++;
        }
 
-       if (IS_I9XX(dev)) {
+       if (is_lvds && dev_priv->lvds_use_ssc && num_outputs < 2) {
+               refclk = dev_priv->lvds_ssc_freq * 1000;
+               DRM_DEBUG("using SSC reference clock of %d MHz\n", refclk / 1000);
+       } else if (IS_I9XX(dev)) {
                refclk = 96000;
        } else {
                refclk = 48000;
@@ -779,7 +779,7 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
        ok = intel_find_best_PLL(crtc, adjusted_mode->clock, refclk, &clock);
        if (!ok) {
                DRM_ERROR("Couldn't find PLL settings for mode!\n");
-               return;
+               return -EINVAL;
        }
 
        fp = clock.n << 16 | clock.m1 << 8 | clock.m2;
@@ -829,11 +829,14 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
                }
        }
 
-       if (is_tv) {
+       if (is_sdvo && is_tv)
+               dpll |= PLL_REF_INPUT_TVCLKINBC;
+       else if (is_tv)
                /* XXX: just matching BIOS for now */
-/*     dpll |= PLL_REF_INPUT_TVCLKINBC; */
+               /*      dpll |= PLL_REF_INPUT_TVCLKINBC; */
                dpll |= 3;
-       }
+       else if (is_lvds && dev_priv->lvds_use_ssc && num_outputs < 2)
+               dpll |= PLLB_REF_INPUT_SPREADSPECTRUMIN;
        else
                dpll |= PLL_REF_INPUT_DREFCLK;
 
@@ -950,9 +953,13 @@ static void intel_crtc_mode_set(struct drm_crtc *crtc,
        I915_WRITE(dspcntr_reg, dspcntr);
 
        /* Flush the plane changes */
-       intel_pipe_set_base(crtc, x, y, old_fb);
+       ret = intel_pipe_set_base(crtc, x, y, old_fb);
+       if (ret != 0)
+           return ret;
 
        drm_vblank_post_modeset(dev, pipe);
+
+       return 0;
 }
 
 /** Loads the palette/gamma unit for the CRTC with the prepared values */
@@ -1001,6 +1008,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
                temp = CURSOR_MODE_DISABLE;
                addr = 0;
                bo = NULL;
+               mutex_lock(&dev->struct_mutex);
                goto finish;
        }
 
@@ -1023,18 +1031,19 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
        }
 
        /* we only need to pin inside GTT if cursor is non-phy */
+       mutex_lock(&dev->struct_mutex);
        if (!dev_priv->cursor_needs_physical) {
                ret = i915_gem_object_pin(bo, PAGE_SIZE);
                if (ret) {
                        DRM_ERROR("failed to pin cursor bo\n");
-                       goto fail;
+                       goto fail_locked;
                }
                addr = obj_priv->gtt_offset;
        } else {
                ret = i915_gem_attach_phys_object(dev, bo, (pipe == 0) ? I915_GEM_PHYS_CURSOR_0 : I915_GEM_PHYS_CURSOR_1);
                if (ret) {
                        DRM_ERROR("failed to attach phys object\n");
-                       goto fail;
+                       goto fail_locked;
                }
                addr = obj_priv->phys_obj->handle->busaddr;
        }
@@ -1054,10 +1063,9 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
                                i915_gem_detach_phys_object(dev, intel_crtc->cursor_bo);
                } else
                        i915_gem_object_unpin(intel_crtc->cursor_bo);
-               mutex_lock(&dev->struct_mutex);
                drm_gem_object_unreference(intel_crtc->cursor_bo);
-               mutex_unlock(&dev->struct_mutex);
        }
+       mutex_unlock(&dev->struct_mutex);
 
        intel_crtc->cursor_addr = addr;
        intel_crtc->cursor_bo = bo;
@@ -1065,6 +1073,7 @@ static int intel_crtc_cursor_set(struct drm_crtc *crtc,
        return 0;
 fail:
        mutex_lock(&dev->struct_mutex);
+fail_locked:
        drm_gem_object_unreference(bo);
        mutex_unlock(&dev->struct_mutex);
        return ret;
@@ -1292,7 +1301,7 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
                }
 
                /* XXX: Handle the 100Mhz refclk */
-               i9xx_clock(96000, &clock);
+               intel_clock(96000, &clock);
        } else {
                bool is_lvds = (pipe == 1) && (I915_READ(LVDS) & LVDS_PORT_EN);
 
@@ -1304,9 +1313,9 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
                        if ((dpll & PLL_REF_INPUT_MASK) ==
                            PLLB_REF_INPUT_SPREADSPECTRUMIN) {
                                /* XXX: might not be 66MHz */
-                               i8xx_clock(66000, &clock);
+                               intel_clock(66000, &clock);
                        } else
-                               i8xx_clock(48000, &clock);
+                               intel_clock(48000, &clock);
                } else {
                        if (dpll & PLL_P1_DIVIDE_BY_TWO)
                                clock.p1 = 2;
@@ -1319,7 +1328,7 @@ static int intel_crtc_clock_get(struct drm_device *dev, struct drm_crtc *crtc)
                        else
                                clock.p2 = 2;
 
-                       i8xx_clock(48000, &clock);
+                       intel_clock(48000, &clock);
                }
        }
 
@@ -1598,7 +1607,9 @@ intel_user_framebuffer_create(struct drm_device *dev,
 
        ret = intel_framebuffer_create(dev, mode_cmd, &fb, obj);
        if (ret) {
+               mutex_lock(&dev->struct_mutex);
                drm_gem_object_unreference(obj);
+               mutex_unlock(&dev->struct_mutex);
                return NULL;
        }
 
index afd1217b8a02cb4bfff4b7371baf2f842a4599fb..b7f0ebe9f810105b1d68a2446a5bab9921fa795c 100644 (file)
@@ -473,7 +473,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
        ret = intel_framebuffer_create(dev, &mode_cmd, &fb, fbo);
        if (ret) {
                DRM_ERROR("failed to allocate fb.\n");
-               goto out_unref;
+               goto out_unpin;
        }
 
        list_add(&fb->filp_head, &dev->mode_config.fb_kernel_list);
@@ -484,7 +484,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
        info = framebuffer_alloc(sizeof(struct intelfb_par), device);
        if (!info) {
                ret = -ENOMEM;
-               goto out_unref;
+               goto out_unpin;
        }
 
        par = info->par;
@@ -513,7 +513,7 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
                                       size);
        if (!info->screen_base) {
                ret = -ENOSPC;
-               goto out_unref;
+               goto out_unpin;
        }
        info->screen_size = size;
 
@@ -608,6 +608,8 @@ static int intelfb_create(struct drm_device *dev, uint32_t fb_width,
        mutex_unlock(&dev->struct_mutex);
        return 0;
 
+out_unpin:
+       i915_gem_object_unpin(fbo);
 out_unref:
        drm_gem_object_unreference(fbo);
        mutex_unlock(&dev->struct_mutex);
index 6d4f9126535443366debd7b0f769bcc9c2dceb31..0d211af98854c18debd6af4f1ea6a246af16871d 100644 (file)
@@ -481,8 +481,6 @@ void intel_lvds_init(struct drm_device *dev)
                if (dev_priv->panel_fixed_mode) {
                        dev_priv->panel_fixed_mode->type |=
                                DRM_MODE_TYPE_PREFERRED;
-                       drm_mode_probed_add(connector,
-                                           dev_priv->panel_fixed_mode);
                        goto out;
                }
        }
index a30508b639ba3ffa04d4a0812ddc9f2a4e880092..fbe6f3931b1b116cb022daa2238ee78d2e7c359c 100644 (file)
@@ -193,7 +193,7 @@ static bool intel_sdvo_write_byte(struct intel_output *intel_output, int addr,
 
 #define SDVO_CMD_NAME_ENTRY(cmd) {cmd, #cmd}
 /** Mapping of command numbers to names, for debug output */
-const static struct _sdvo_cmd_name {
+static const struct _sdvo_cmd_name {
        u8 cmd;
        char *name;
 } sdvo_cmd_names[] = {
index fbb35dc56f5c15ee917a892b1ab2df9f45398d9b..56485d67369b8dcf913b28b17afa9bb3bd3b3de8 100644 (file)
@@ -411,7 +411,7 @@ struct tv_mode {
  * These values account for -1s required.
  */
 
-const static struct tv_mode tv_modes[] = {
+static const struct tv_mode tv_modes[] = {
        {
                .name           = "NTSC-M",
                .clock          = 107520,
index df4cf97e5d976cb1c5d445dc487b15d2c3333029..92965dbb3c147a7b46c3cf248466765f2d08f5e8 100644 (file)
@@ -557,8 +557,10 @@ static int radeon_do_engine_reset(struct drm_device * dev)
 }
 
 static void radeon_cp_init_ring_buffer(struct drm_device * dev,
-                                      drm_radeon_private_t * dev_priv)
+                                      drm_radeon_private_t *dev_priv,
+                                      struct drm_file *file_priv)
 {
+       struct drm_radeon_master_private *master_priv;
        u32 ring_start, cur_read_ptr;
        u32 tmp;
 
@@ -677,6 +679,14 @@ static void radeon_cp_init_ring_buffer(struct drm_device * dev,
        dev_priv->scratch[2] = 0;
        RADEON_WRITE(RADEON_LAST_CLEAR_REG, 0);
 
+       /* reset sarea copies of these */
+       master_priv = file_priv->master->driver_priv;
+       if (master_priv->sarea_priv) {
+               master_priv->sarea_priv->last_frame = 0;
+               master_priv->sarea_priv->last_dispatch = 0;
+               master_priv->sarea_priv->last_clear = 0;
+       }
+
        radeon_do_wait_for_idle(dev_priv);
 
        /* Sync everything up */
@@ -1215,7 +1225,7 @@ static int radeon_do_init_cp(struct drm_device *dev, drm_radeon_init_t *init,
        }
 
        radeon_cp_load_microcode(dev_priv);
-       radeon_cp_init_ring_buffer(dev, dev_priv);
+       radeon_cp_init_ring_buffer(dev, dev_priv, file_priv);
 
        dev_priv->last_buf = 0;
 
@@ -1281,7 +1291,7 @@ static int radeon_do_cleanup_cp(struct drm_device * dev)
  *
  * Charl P. Botha <http://cpbotha.net>
  */
-static int radeon_do_resume_cp(struct drm_device * dev)
+static int radeon_do_resume_cp(struct drm_device *dev, struct drm_file *file_priv)
 {
        drm_radeon_private_t *dev_priv = dev->dev_private;
 
@@ -1304,7 +1314,7 @@ static int radeon_do_resume_cp(struct drm_device * dev)
        }
 
        radeon_cp_load_microcode(dev_priv);
-       radeon_cp_init_ring_buffer(dev, dev_priv);
+       radeon_cp_init_ring_buffer(dev, dev_priv, file_priv);
 
        radeon_do_engine_reset(dev);
        radeon_irq_set_state(dev, RADEON_SW_INT_ENABLE, 1);
@@ -1479,8 +1489,7 @@ int radeon_cp_idle(struct drm_device *dev, void *data, struct drm_file *file_pri
  */
 int radeon_cp_resume(struct drm_device *dev, void *data, struct drm_file *file_priv)
 {
-
-       return radeon_do_resume_cp(dev);
+       return radeon_do_resume_cp(dev, file_priv);
 }
 
 int radeon_engine_reset(struct drm_device *dev, void *data, struct drm_file *file_priv)
index 6cad69ed21c558c908b68fb9751a381a92cf0eae..1cc967448f4d5c760a8d75329c4e76bb82f4000f 100644 (file)
@@ -1300,7 +1300,13 @@ static const struct hid_device_id hid_blacklist[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_PS3_CONTROLLER) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SONY, USB_DEVICE_ID_SONY_VAIO_VGX_MOUSE) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SUNPLUS, USB_DEVICE_ID_SUNPLUS_WDESKTOP) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TOPSEED, USB_DEVICE_ID_TOPSEED_CYBERLINK) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
 
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_APPLE, 0x030c) },
        { HID_BLUETOOTH_DEVICE(USB_VENDOR_ID_MICROSOFT, USB_DEVICE_ID_MS_PRESENTER_8K_BT) },
@@ -1605,6 +1611,7 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0002) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0003) },
        { HID_USB_DEVICE(USB_VENDOR_ID_PANJIT, 0x0004) },
+       { HID_USB_DEVICE(USB_VENDOR_ID_POWERCOM, USB_DEVICE_ID_POWERCOM_UPS) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD2) },
        { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD3) },
@@ -1612,10 +1619,6 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_SOUNDGRAPH, USB_DEVICE_ID_SOUNDGRAPH_IMON_LCD5) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY1) },
        { HID_USB_DEVICE(USB_VENDOR_ID_TENX, USB_DEVICE_ID_TENX_IBUDDY2) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb300) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb304) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb651) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_THRUSTMASTER, 0xb654) },
        { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_LABPRO) },
        { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_GOTEMP) },
        { HID_USB_DEVICE(USB_VENDOR_ID_VERNIER, USB_DEVICE_ID_VERNIER_SKIP) },
@@ -1626,8 +1629,6 @@ static const struct hid_device_id hid_ignore_list[] = {
        { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_1_PHIDGETSERVO_20) },
        { HID_USB_DEVICE(USB_VENDOR_ID_WISEGROUP, USB_DEVICE_ID_8_8_4_IF_KIT) },
        { HID_USB_DEVICE(USB_VENDOR_ID_YEALINK, USB_DEVICE_ID_YEALINK_P1K_P4K_B2K) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0005) },
-       { HID_USB_DEVICE(USB_VENDOR_ID_ZEROPLUS, 0x0030) },
        { }
 };
 
index e899f510ebeb5c474c1e682f874559ea9f690e79..88511970508d71b8ceae437ae78726ca35563cc8 100644 (file)
 #define USB_VENDOR_ID_PLAYDOTCOM       0x0b43
 #define USB_DEVICE_ID_PLAYDOTCOM_EMS_USBII     0x0003
 
+#define USB_VENDOR_ID_POWERCOM         0x0d9f
+#define USB_DEVICE_ID_POWERCOM_UPS     0x0002
+
 #define USB_VENDOR_ID_SAITEK           0x06a3
 #define USB_DEVICE_ID_SAITEK_RUMBLEPAD 0xff17
 
index 732449628971185d7603728aaa4c764266342274..02b19db5442ebd1d1fce7c0716bb2a071f528e12 100644 (file)
@@ -267,8 +267,10 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
                default:
                        {
                                struct hid_device *hid = dev->hid;
-                               if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ)
-                                       return -EINVAL;
+                               if (_IOC_TYPE(cmd) != 'H' || _IOC_DIR(cmd) != _IOC_READ) {
+                                       ret = -EINVAL;
+                                       break;
+                               }
 
                                if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWNAME(0))) {
                                        int len;
@@ -277,8 +279,9 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
                                        len = strlen(hid->name) + 1;
                                        if (len > _IOC_SIZE(cmd))
                                                len = _IOC_SIZE(cmd);
-                                       return copy_to_user(user_arg, hid->name, len) ?
+                                       ret = copy_to_user(user_arg, hid->name, len) ?
                                                -EFAULT : len;
+                                       break;
                                }
 
                                if (_IOC_NR(cmd) == _IOC_NR(HIDIOCGRAWPHYS(0))) {
@@ -288,12 +291,13 @@ static long hidraw_ioctl(struct file *file, unsigned int cmd,
                                        len = strlen(hid->phys) + 1;
                                        if (len > _IOC_SIZE(cmd))
                                                len = _IOC_SIZE(cmd);
-                                       return copy_to_user(user_arg, hid->phys, len) ?
+                                       ret = copy_to_user(user_arg, hid->phys, len) ?
                                                -EFAULT : len;
+                                       break;
                                }
                 }
 
-                       ret = -ENOTTY;
+               ret = -ENOTTY;
        }
        unlock_kernel();
        return ret;
index 609cafff86bc2ce23c364831f959c2dbcd310baf..5f81ddf7150871e67c7fe3ff1647df7e01c6c2c5 100644 (file)
@@ -1872,7 +1872,7 @@ static int __init f71882fg_find(int sioaddr, unsigned short *address,
 
        devid = superio_inw(sioaddr, SIO_REG_MANID);
        if (devid != SIO_FINTEK_ID) {
-               printk(KERN_INFO DRVNAME ": Not a Fintek device\n");
+               pr_debug(DRVNAME ": Not a Fintek device\n");
                goto exit;
        }
 
@@ -1932,7 +1932,7 @@ static int __init f71882fg_device_add(unsigned short address,
        res.name = f71882fg_pdev->name;
        err = acpi_check_resource_conflict(&res);
        if (err)
-               return err;
+               goto exit_device_put;
 
        err = platform_device_add_resources(f71882fg_pdev, &res, 1);
        if (err) {
index abf4dfc8ec229c874b286acb4942278c50a138c1..29c83b5b96974bb88cbeb67d896ba46ee71469f2 100644 (file)
@@ -166,6 +166,18 @@ static struct axis_conversion lis3lv02d_axis_xy_swap_yz_inverted = {2, -1, -3};
        },                                              \
        .driver_data = &lis3lv02d_axis_##_axis          \
 }
+
+#define AXIS_DMI_MATCH2(_ident, _class1, _name1,       \
+                               _class2, _name2,        \
+                               _axis) {                \
+       .ident = _ident,                                \
+       .callback = lis3lv02d_dmi_matched,              \
+       .matches = {                                    \
+               DMI_MATCH(DMI_##_class1, _name1),       \
+               DMI_MATCH(DMI_##_class2, _name2),       \
+       },                                              \
+       .driver_data = &lis3lv02d_axis_##_axis          \
+}
 static struct dmi_system_id lis3lv02d_dmi_ids[] = {
        /* product names are truncated to match all kinds of a same model */
        AXIS_DMI_MATCH("NC64x0", "HP Compaq nc64", x_inverted),
@@ -179,6 +191,16 @@ static struct dmi_system_id lis3lv02d_dmi_ids[] = {
        AXIS_DMI_MATCH("NC673x", "HP Compaq 673", xy_rotated_left_usd),
        AXIS_DMI_MATCH("NC651xx", "HP Compaq 651", xy_rotated_right),
        AXIS_DMI_MATCH("NC671xx", "HP Compaq 671", xy_swap_yz_inverted),
+       /* Intel-based HP Pavilion dv5 */
+       AXIS_DMI_MATCH2("HPDV5_I",
+                       PRODUCT_NAME, "HP Pavilion dv5",
+                       BOARD_NAME, "3603",
+                       x_inverted),
+       /* AMD-based HP Pavilion dv5 */
+       AXIS_DMI_MATCH2("HPDV5_A",
+                       PRODUCT_NAME, "HP Pavilion dv5",
+                       BOARD_NAME, "3600",
+                       y_inverted),
        { NULL, }
 /* Laptop models without axis info (yet):
  * "NC6910" "HP Compaq 6910"
@@ -213,9 +235,49 @@ static struct delayed_led_classdev hpled_led = {
        .set_brightness = hpled_set,
 };
 
+static acpi_status
+lis3lv02d_get_resource(struct acpi_resource *resource, void *context)
+{
+       if (resource->type == ACPI_RESOURCE_TYPE_EXTENDED_IRQ) {
+               struct acpi_resource_extended_irq *irq;
+               u32 *device_irq = context;
+
+               irq = &resource->data.extended_irq;
+               *device_irq = irq->interrupts[0];
+       }
+
+       return AE_OK;
+}
+
+static void lis3lv02d_enum_resources(struct acpi_device *device)
+{
+       acpi_status status;
+
+       status = acpi_walk_resources(device->handle, METHOD_NAME__CRS,
+                                       lis3lv02d_get_resource, &adev.irq);
+       if (ACPI_FAILURE(status))
+               printk(KERN_DEBUG DRIVER_NAME ": Error getting resources\n");
+}
+
+static s16 lis3lv02d_read_16(acpi_handle handle, int reg)
+{
+       u8 lo, hi;
+
+       adev.read(handle, reg - 1, &lo);
+       adev.read(handle, reg, &hi);
+       /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */
+       return (s16)((hi << 8) | lo);
+}
+
+static s16 lis3lv02d_read_8(acpi_handle handle, int reg)
+{
+       s8 lo;
+       adev.read(handle, reg, &lo);
+       return lo;
+}
+
 static int lis3lv02d_add(struct acpi_device *device)
 {
-       u8 val;
        int ret;
 
        if (!device)
@@ -229,10 +291,22 @@ static int lis3lv02d_add(struct acpi_device *device)
        strcpy(acpi_device_class(device), ACPI_MDPS_CLASS);
        device->driver_data = &adev;
 
-       lis3lv02d_acpi_read(device->handle, WHO_AM_I, &val);
-       if ((val != LIS3LV02DL_ID) && (val != LIS302DL_ID)) {
+       lis3lv02d_acpi_read(device->handle, WHO_AM_I, &adev.whoami);
+       switch (adev.whoami) {
+       case LIS_DOUBLE_ID:
+               printk(KERN_INFO DRIVER_NAME ": 2-byte sensor found\n");
+               adev.read_data = lis3lv02d_read_16;
+               adev.mdps_max_val = 2048;
+               break;
+       case LIS_SINGLE_ID:
+               printk(KERN_INFO DRIVER_NAME ": 1-byte sensor found\n");
+               adev.read_data = lis3lv02d_read_8;
+               adev.mdps_max_val = 128;
+               break;
+       default:
                printk(KERN_ERR DRIVER_NAME
-                               ": Accelerometer chip not LIS3LV02D{L,Q}\n");
+                       ": unknown sensor type 0x%X\n", adev.whoami);
+               return -EINVAL;
        }
 
        /* If possible use a "standard" axes order */
@@ -247,6 +321,9 @@ static int lis3lv02d_add(struct acpi_device *device)
        if (ret)
                return ret;
 
+       /* obtain IRQ number of our device from ACPI */
+       lis3lv02d_enum_resources(adev.device);
+
        ret = lis3lv02d_init_device(&adev);
        if (ret) {
                flush_work(&hpled_led.work);
index 219d2d0d5a626713377ada0f311d190dca9048c6..8bb2158f0453c01f3c089ffaa88d8eea2927fd9d 100644 (file)
@@ -3,7 +3,7 @@
  *
  *  Copyright (C) 2007-2008 Yan Burman
  *  Copyright (C) 2008 Eric Piel
- *  Copyright (C) 2008 Pavel Machek
+ *  Copyright (C) 2008-2009 Pavel Machek
  *
  *  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
@@ -35,6 +35,7 @@
 #include <linux/poll.h>
 #include <linux/freezer.h>
 #include <linux/uaccess.h>
+#include <linux/miscdevice.h>
 #include <acpi/acpi_drivers.h>
 #include <asm/atomic.h>
 #include "lis3lv02d.h"
  * joystick.
  */
 
-/* Maximum value our axis may get for the input device (signed 12 bits) */
-#define MDPS_MAX_VAL 2048
+struct acpi_lis3lv02d adev = {
+       .misc_wait   = __WAIT_QUEUE_HEAD_INITIALIZER(adev.misc_wait),
+};
 
-struct acpi_lis3lv02d adev;
 EXPORT_SYMBOL_GPL(adev);
 
 static int lis3lv02d_add_fs(struct acpi_device *device);
 
-static s16 lis3lv02d_read_16(acpi_handle handle, int reg)
-{
-       u8 lo, hi;
-
-       adev.read(handle, reg, &lo);
-       adev.read(handle, reg + 1, &hi);
-       /* In "12 bit right justified" mode, bit 6, bit 7, bit 8 = bit 5 */
-       return (s16)((hi << 8) | lo);
-}
-
 /**
  * lis3lv02d_get_axis - For the given axis, give the value converted
  * @axis:      1,2,3 - can also be negative
@@ -98,9 +89,9 @@ static void lis3lv02d_get_xyz(acpi_handle handle, int *x, int *y, int *z)
 {
        int position[3];
 
-       position[0] = lis3lv02d_read_16(handle, OUTX_L);
-       position[1] = lis3lv02d_read_16(handle, OUTY_L);
-       position[2] = lis3lv02d_read_16(handle, OUTZ_L);
+       position[0] = adev.read_data(handle, OUTX);
+       position[1] = adev.read_data(handle, OUTY);
+       position[2] = adev.read_data(handle, OUTZ);
 
        *x = lis3lv02d_get_axis(adev.ac.x, position);
        *y = lis3lv02d_get_axis(adev.ac.y, position);
@@ -110,26 +101,13 @@ static void lis3lv02d_get_xyz(acpi_handle handle, int *x, int *y, int *z)
 void lis3lv02d_poweroff(acpi_handle handle)
 {
        adev.is_on = 0;
-       /* disable X,Y,Z axis and power down */
-       adev.write(handle, CTRL_REG1, 0x00);
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_poweroff);
 
 void lis3lv02d_poweron(acpi_handle handle)
 {
-       u8 val;
-
        adev.is_on = 1;
        adev.init(handle);
-       adev.write(handle, FF_WU_CFG, 0);
-       /*
-        * BDU: LSB and MSB values are not updated until both have been read.
-        *      So the value read will always be correct.
-        * IEN: Interrupt for free-fall and DD, not for data-ready.
-        */
-       adev.read(handle, CTRL_REG2, &val);
-       val |= CTRL2_BDU | CTRL2_IEN;
-       adev.write(handle, CTRL_REG2, val);
 }
 EXPORT_SYMBOL_GPL(lis3lv02d_poweron);
 
@@ -162,6 +140,140 @@ static void lis3lv02d_decrease_use(struct acpi_lis3lv02d *dev)
        mutex_unlock(&dev->lock);
 }
 
+static irqreturn_t lis302dl_interrupt(int irq, void *dummy)
+{
+       /*
+        * Be careful: on some HP laptops the bios force DD when on battery and
+        * the lid is closed. This leads to interrupts as soon as a little move
+        * is done.
+        */
+       atomic_inc(&adev.count);
+
+       wake_up_interruptible(&adev.misc_wait);
+       kill_fasync(&adev.async_queue, SIGIO, POLL_IN);
+       return IRQ_HANDLED;
+}
+
+static int lis3lv02d_misc_open(struct inode *inode, struct file *file)
+{
+       int ret;
+
+       if (test_and_set_bit(0, &adev.misc_opened))
+               return -EBUSY; /* already open */
+
+       atomic_set(&adev.count, 0);
+
+       /*
+        * The sensor can generate interrupts for free-fall and direction
+        * detection (distinguishable with FF_WU_SRC and DD_SRC) but to keep
+        * the things simple and _fast_ we activate it only for free-fall, so
+        * no need to read register (very slow with ACPI). For the same reason,
+        * we forbid shared interrupts.
+        *
+        * IRQF_TRIGGER_RISING seems pointless on HP laptops because the
+        * io-apic is not configurable (and generates a warning) but I keep it
+        * in case of support for other hardware.
+        */
+       ret = request_irq(adev.irq, lis302dl_interrupt, IRQF_TRIGGER_RISING,
+                         DRIVER_NAME, &adev);
+
+       if (ret) {
+               clear_bit(0, &adev.misc_opened);
+               printk(KERN_ERR DRIVER_NAME ": IRQ%d allocation failed\n", adev.irq);
+               return -EBUSY;
+       }
+       lis3lv02d_increase_use(&adev);
+       printk("lis3: registered interrupt %d\n", adev.irq);
+       return 0;
+}
+
+static int lis3lv02d_misc_release(struct inode *inode, struct file *file)
+{
+       fasync_helper(-1, file, 0, &adev.async_queue);
+       lis3lv02d_decrease_use(&adev);
+       free_irq(adev.irq, &adev);
+       clear_bit(0, &adev.misc_opened); /* release the device */
+       return 0;
+}
+
+static ssize_t lis3lv02d_misc_read(struct file *file, char __user *buf,
+                               size_t count, loff_t *pos)
+{
+       DECLARE_WAITQUEUE(wait, current);
+       u32 data;
+       unsigned char byte_data;
+       ssize_t retval = 1;
+
+       if (count < 1)
+               return -EINVAL;
+
+       add_wait_queue(&adev.misc_wait, &wait);
+       while (true) {
+               set_current_state(TASK_INTERRUPTIBLE);
+               data = atomic_xchg(&adev.count, 0);
+               if (data)
+                       break;
+
+               if (file->f_flags & O_NONBLOCK) {
+                       retval = -EAGAIN;
+                       goto out;
+               }
+
+               if (signal_pending(current)) {
+                       retval = -ERESTARTSYS;
+                       goto out;
+               }
+
+               schedule();
+       }
+
+       if (data < 255)
+               byte_data = data;
+       else
+               byte_data = 255;
+
+       /* make sure we are not going into copy_to_user() with
+        * TASK_INTERRUPTIBLE state */
+       set_current_state(TASK_RUNNING);
+       if (copy_to_user(buf, &byte_data, sizeof(byte_data)))
+               retval = -EFAULT;
+
+out:
+       __set_current_state(TASK_RUNNING);
+       remove_wait_queue(&adev.misc_wait, &wait);
+
+       return retval;
+}
+
+static unsigned int lis3lv02d_misc_poll(struct file *file, poll_table *wait)
+{
+       poll_wait(file, &adev.misc_wait, wait);
+       if (atomic_read(&adev.count))
+               return POLLIN | POLLRDNORM;
+       return 0;
+}
+
+static int lis3lv02d_misc_fasync(int fd, struct file *file, int on)
+{
+       return fasync_helper(fd, file, on, &adev.async_queue);
+}
+
+static const struct file_operations lis3lv02d_misc_fops = {
+       .owner   = THIS_MODULE,
+       .llseek  = no_llseek,
+       .read    = lis3lv02d_misc_read,
+       .open    = lis3lv02d_misc_open,
+       .release = lis3lv02d_misc_release,
+       .poll    = lis3lv02d_misc_poll,
+       .fasync  = lis3lv02d_misc_fasync,
+};
+
+static struct miscdevice lis3lv02d_misc_device = {
+       .minor   = MISC_DYNAMIC_MINOR,
+       .name    = "freefall",
+       .fops    = &lis3lv02d_misc_fops,
+};
+
 /**
  * lis3lv02d_joystick_kthread - Kthread polling function
  * @data: unused - here to conform to threadfn prototype
@@ -203,7 +315,6 @@ static void lis3lv02d_joystick_close(struct input_dev *input)
        lis3lv02d_decrease_use(&adev);
 }
 
-
 static inline void lis3lv02d_calibrate_joystick(void)
 {
        lis3lv02d_get_xyz(adev.device->handle, &adev.xcalib, &adev.ycalib, &adev.zcalib);
@@ -231,9 +342,9 @@ int lis3lv02d_joystick_enable(void)
        adev.idev->close      = lis3lv02d_joystick_close;
 
        set_bit(EV_ABS, adev.idev->evbit);
-       input_set_abs_params(adev.idev, ABS_X, -MDPS_MAX_VAL, MDPS_MAX_VAL, 3, 3);
-       input_set_abs_params(adev.idev, ABS_Y, -MDPS_MAX_VAL, MDPS_MAX_VAL, 3, 3);
-       input_set_abs_params(adev.idev, ABS_Z, -MDPS_MAX_VAL, MDPS_MAX_VAL, 3, 3);
+       input_set_abs_params(adev.idev, ABS_X, -adev.mdps_max_val, adev.mdps_max_val, 3, 3);
+       input_set_abs_params(adev.idev, ABS_Y, -adev.mdps_max_val, adev.mdps_max_val, 3, 3);
+       input_set_abs_params(adev.idev, ABS_Z, -adev.mdps_max_val, adev.mdps_max_val, 3, 3);
 
        err = input_register_device(adev.idev);
        if (err) {
@@ -250,6 +361,7 @@ void lis3lv02d_joystick_disable(void)
        if (!adev.idev)
                return;
 
+       misc_deregister(&lis3lv02d_misc_device);
        input_unregister_device(adev.idev);
        adev.idev = NULL;
 }
@@ -268,6 +380,19 @@ int lis3lv02d_init_device(struct acpi_lis3lv02d *dev)
        if (lis3lv02d_joystick_enable())
                printk(KERN_ERR DRIVER_NAME ": joystick initialization failed\n");
 
+       printk("lis3_init_device: irq %d\n", dev->irq);
+
+       /* if we did not get an IRQ from ACPI - we have nothing more to do */
+       if (!dev->irq) {
+               printk(KERN_ERR DRIVER_NAME
+                       ": No IRQ in ACPI. Disabling /dev/freefall\n");
+               goto out;
+       }
+
+       printk("lis3: registering device\n");
+       if (misc_register(&lis3lv02d_misc_device))
+               printk(KERN_ERR DRIVER_NAME ": misc_register failed\n");
+out:
        lis3lv02d_decrease_use(dev);
        return 0;
 }
@@ -351,6 +476,6 @@ int lis3lv02d_remove_fs(void)
 EXPORT_SYMBOL_GPL(lis3lv02d_remove_fs);
 
 MODULE_DESCRIPTION("ST LIS3LV02Dx three-axis digital accelerometer driver");
-MODULE_AUTHOR("Yan Burman and Eric Piel");
+MODULE_AUTHOR("Yan Burman, Eric Piel, Pavel Machek");
 MODULE_LICENSE("GPL");
 
index 223f1c0763bba4decc69c85e74c990ba4472ba9d..75972bf372ff474a2fd1a43cdaf85db9ddddebd4 100644 (file)
 /*
  * The actual chip is STMicroelectronics LIS3LV02DL or LIS3LV02DQ that seems to
  * be connected via SPI. There exists also several similar chips (such as LIS302DL or
- * LIS3L02DQ) but not in the HP laptops and they have slightly different registers.
+ * LIS3L02DQ) and they have slightly different registers, but we can provide a
+ * common interface for all of them.
  * They can also be connected via I²C.
  */
 
-#define LIS3LV02DL_ID  0x3A /* Also the LIS3LV02DQ */
-#define LIS302DL_ID    0x3B /* Also the LIS202DL! */
+/* 2-byte registers */
+#define LIS_DOUBLE_ID  0x3A /* LIS3LV02D[LQ] */
+/* 1-byte registers */
+#define LIS_SINGLE_ID  0x3B /* LIS[32]02DL and others */
 
 enum lis3lv02d_reg {
        WHO_AM_I        = 0x0F,
@@ -44,10 +47,13 @@ enum lis3lv02d_reg {
        STATUS_REG      = 0x27,
        OUTX_L          = 0x28,
        OUTX_H          = 0x29,
+       OUTX            = 0x29,
        OUTY_L          = 0x2A,
        OUTY_H          = 0x2B,
+       OUTY            = 0x2B,
        OUTZ_L          = 0x2C,
        OUTZ_H          = 0x2D,
+       OUTZ            = 0x2D,
        FF_WU_CFG       = 0x30,
        FF_WU_SRC       = 0x31,
        FF_WU_ACK       = 0x32,
@@ -159,6 +165,10 @@ struct acpi_lis3lv02d {
        acpi_status (*write) (acpi_handle handle, int reg, u8 val);
        acpi_status (*read) (acpi_handle handle, int reg, u8 *ret);
 
+       u8                      whoami;    /* 3Ah: 2-byte registries, 3Bh: 1-byte registries */
+       s16 (*read_data) (acpi_handle handle, int reg);
+       int                     mdps_max_val;
+
        struct input_dev        *idev;     /* input device */
        struct task_struct      *kthread;  /* kthread for input */
        struct mutex            lock;
@@ -170,6 +180,11 @@ struct acpi_lis3lv02d {
        unsigned char           is_on;     /* whether the device is on or off */
        unsigned char           usage;     /* usage counter */
        struct axis_conversion  ac;        /* hw -> logical axis */
+
+       u32                     irq;       /* IRQ number */
+       struct fasync_struct    *async_queue; /* queue for the misc device */
+       wait_queue_head_t       misc_wait; /* Wait queue for the misc device */
+       unsigned long           misc_opened; /* bit0: whether the device is open */
 };
 
 int lis3lv02d_init_device(struct acpi_lis3lv02d *dev);
index b0ce3785228101f6cf8ff388497e57e5b0f44f98..73f77a9b8b188fb15840beea34d5f2f07a8d8a4f 100644 (file)
@@ -1262,7 +1262,7 @@ static int __init vt1211_device_add(unsigned short address)
        res.name = pdev->name;
        err = acpi_check_resource_conflict(&res);
        if (err)
-               goto EXIT;
+               goto EXIT_DEV_PUT;
 
        err = platform_device_add_resources(pdev, &res, 1);
        if (err) {
index cb808d0153619838378bd70f1ea5bfc3ca1c5ad2..feae743ba99163c2475b0f51663c89fc7e7f1375 100644 (file)
@@ -1548,7 +1548,7 @@ static int __init sensors_w83627ehf_init(void)
 
        err = acpi_check_resource_conflict(&res);
        if (err)
-               goto exit;
+               goto exit_device_put;
 
        err = platform_device_add_resources(pdev, &res, 1);
        if (err) {
index 9fee3ca17344b9ab6adf895b4869a82e7d8bac6b..9aefb5e5864df92b9f5d6226db680c55e8bdf274 100644 (file)
@@ -79,10 +79,11 @@ static struct i2c_algo_bit_data ioc_data = {
        .getsda         = ioc_getsda,
        .getscl         = ioc_getscl,
        .udelay         = 80,
-       .timeout        = 100
+       .timeout        = HZ,
 };
 
 static struct i2c_adapter ioc_ops = {
+       .nr                     = 0,
        .algo_data              = &ioc_data,
 };
 
@@ -90,7 +91,7 @@ static int __init i2c_ioc_init(void)
 {
        force_ones = FORCE_ONES | SCL | SDA;
 
-       return i2c_bit_add_bus(&ioc_ops);
+       return i2c_bit_add_numbered_bus(&ioc_ops);
 }
 
 module_init(i2c_ioc_init);
index edab51973bf5501c303fc56a23b1f90f722b1e6a..a7c59908c457cbeb23937904dc6d6a76a05e060c 100644 (file)
@@ -72,7 +72,7 @@ static unsigned int amd_ec_wait_write(struct amd_smbus *smbus)
 {
        int timeout = 500;
 
-       while (timeout-- && (inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_IBF))
+       while ((inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_IBF) && --timeout)
                udelay(1);
 
        if (!timeout) {
@@ -88,7 +88,7 @@ static unsigned int amd_ec_wait_read(struct amd_smbus *smbus)
 {
        int timeout = 500;
 
-       while (timeout-- && (~inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_OBF))
+       while ((~inb(smbus->base + AMD_EC_SC) & AMD_EC_SC_OBF) && --timeout)
                udelay(1);
 
        if (!timeout) {
index 8e8467970481bb86972eadcb16bdb2dce7cf6a3d..c016f7a2c5fc2712433dbd83ec7d1c6dd1d48f3b 100644 (file)
@@ -114,7 +114,7 @@ static int ixp2000_i2c_probe(struct platform_device *plat_dev)
        drv_data->algo_data.getsda = ixp2000_bit_getsda;
        drv_data->algo_data.getscl = ixp2000_bit_getscl;
        drv_data->algo_data.udelay = 6;
-       drv_data->algo_data.timeout = 100;
+       drv_data->algo_data.timeout = HZ;
 
        strlcpy(drv_data->adapter.name, plat_dev->dev.driver->name,
                sizeof(drv_data->adapter.name));
index eeda276f8f164021a9f59c12e1c7612ac60d94b4..7f186bbcb99d965bc69cdc8df5bd1cd83b8e89da 100644 (file)
@@ -482,7 +482,7 @@ mv64xxx_i2c_map_regs(struct platform_device *pd,
        return 0;
 }
 
-static void __devexit
+static void
 mv64xxx_i2c_unmap_regs(struct mv64xxx_i2c_data *drv_data)
 {
        if (drv_data->reg_base) {
@@ -577,7 +577,7 @@ mv64xxx_i2c_remove(struct platform_device *dev)
 
 static struct platform_driver mv64xxx_i2c_driver = {
        .probe  = mv64xxx_i2c_probe,
-       .remove = mv64xxx_i2c_remove,
+       .remove = __devexit_p(mv64xxx_i2c_remove),
        .driver = {
                .owner  = THIS_MODULE,
                .name   = MV64XXX_I2C_CTLR_NAME,
index 6af68146c34248507c0d8df07691992c31d54991..bdb1f7510e91555209bdf5dedfd20a48f50e1aba 100644 (file)
@@ -644,7 +644,7 @@ static int i2c_pxa_do_pio_xfer(struct pxa_i2c *i2c,
 
        i2c_pxa_start_message(i2c);
 
-       while (timeout-- && i2c->msg_num > 0) {
+       while (i2c->msg_num > 0 && --timeout) {
                i2c_pxa_handler(0, i2c);
                udelay(10);
        }
index 162b74a04886c5497296579c6bbabda7015f2948..42df0eca43d5229b1fd88624e3fee4c369f0f462 100644 (file)
@@ -76,7 +76,7 @@ static struct i2c_algo_bit_data scx200_i2c_data = {
        .getsda         = scx200_i2c_getsda,
        .getscl         = scx200_i2c_getscl,
        .udelay         = 10,
-       .timeout        = 100,
+       .timeout        = HZ,
 };
 
 static struct i2c_adapter scx200_i2c_ops = {
index b1c9abe24c7b2a84f143c264d82a3ee74cdc0639..e7d984866de0465f5846225c6b59a0072fec7fd1 100644 (file)
@@ -1831,7 +1831,8 @@ static s32 i2c_smbus_xfer_emulated(struct i2c_adapter * adapter, u16 addr,
        case I2C_SMBUS_QUICK:
                msg[0].len = 0;
                /* Special case: The read/write field is used as data */
-               msg[0].flags = flags | (read_write==I2C_SMBUS_READ)?I2C_M_RD:0;
+               msg[0].flags = flags | (read_write == I2C_SMBUS_READ ?
+                                       I2C_M_RD : 0);
                num = 1;
                break;
        case I2C_SMBUS_BYTE:
index c171988a9f517d7009319674265c47a10859a8c3..7e13d2df9af384f0b048faa36c427171dab30fa0 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c-dev.h>
 #include <linux/smp_lock.h>
+#include <linux/jiffies.h>
 #include <asm/uaccess.h>
 
 static struct i2c_driver i2cdev_driver;
@@ -422,7 +423,10 @@ static long i2cdev_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
                client->adapter->retries = arg;
                break;
        case I2C_TIMEOUT:
-               client->adapter->timeout = arg;
+               /* For historical reasons, user-space sets the timeout
+                * value in units of 10 ms.
+                */
+               client->adapter->timeout = msecs_to_jiffies(arg * 10);
                break;
        default:
                /* NOTE:  returning a fault code here could cause trouble
index 3dad2299d9c57e9b22ec420bb180c93d975b1e77..e072903b12f016aab1aa0d72e0939907253ff033 100644 (file)
@@ -46,7 +46,7 @@ menuconfig IDE
          SMART parameters from disk drives.
 
          To compile this driver as a module, choose M here: the
-         module will be called ide.
+         module will be called ide-core.ko.
 
          For further information, please read <file:Documentation/ide/ide.txt>.
 
index 69660a431cd9890f707c87d7e7a38f3429e643de..77267c85996578a47adb19d7104db6992e128e38 100644 (file)
@@ -166,7 +166,7 @@ static unsigned int init_chipset_amd74xx(struct pci_dev *dev)
         * Check for broken FIFO support.
         */
        if (dev->vendor == PCI_VENDOR_ID_AMD &&
-           dev->vendor == PCI_DEVICE_ID_AMD_VIPER_7411)
+           dev->device == PCI_DEVICE_ID_AMD_VIPER_7411)
                t &= 0x0f;
        else
                t |= 0xf0;
index b2735d28f5cc22019b88c8f159da1af91dccbb7e..ecd1e62ca91a86b0373bf7156e8326e67ffbfa25 100644 (file)
@@ -52,7 +52,7 @@ static void atiixp_set_pio_mode(ide_drive_t *drive, const u8 pio)
 {
        struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
        unsigned long flags;
-       int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
+       int timing_shift = (drive->dn ^ 1) * 8;
        u32 pio_timing_data;
        u16 pio_mode_data;
 
@@ -85,7 +85,7 @@ static void atiixp_set_dma_mode(ide_drive_t *drive, const u8 speed)
 {
        struct pci_dev *dev = to_pci_dev(drive->hwif->dev);
        unsigned long flags;
-       int timing_shift = (drive->dn & 2) ? 16 : 0 + (drive->dn & 1) ? 0 : 8;
+       int timing_shift = (drive->dn ^ 1) * 8;
        u32 tmp32;
        u16 tmp16;
        u16 udma_ctl = 0;
index 0bfeb0c79d6e8e172cdbb5fd3af9a9df084351c5..ddfbea41d296a738a1efb5ace07b22b9a7dff2ad 100644 (file)
@@ -55,7 +55,7 @@
 
 static DEFINE_MUTEX(idecd_ref_mutex);
 
-static void ide_cd_release(struct kref *);
+static void ide_cd_release(struct device *);
 
 static struct cdrom_info *ide_cd_get(struct gendisk *disk)
 {
@@ -67,7 +67,7 @@ static struct cdrom_info *ide_cd_get(struct gendisk *disk)
                if (ide_device_get(cd->drive))
                        cd = NULL;
                else
-                       kref_get(&cd->kref);
+                       get_device(&cd->dev);
 
        }
        mutex_unlock(&idecd_ref_mutex);
@@ -79,7 +79,7 @@ static void ide_cd_put(struct cdrom_info *cd)
        ide_drive_t *drive = cd->drive;
 
        mutex_lock(&idecd_ref_mutex);
-       kref_put(&cd->kref, ide_cd_release);
+       put_device(&cd->dev);
        ide_device_put(drive);
        mutex_unlock(&idecd_ref_mutex);
 }
@@ -194,6 +194,14 @@ static void cdrom_analyze_sense_data(ide_drive_t *drive,
                        bio_sectors = max(bio_sectors(failed_command->bio), 4U);
                        sector &= ~(bio_sectors - 1);
 
+                       /*
+                        * The SCSI specification allows for the value
+                        * returned by READ CAPACITY to be up to 75 2K
+                        * sectors past the last readable block.
+                        * Therefore, if we hit a medium error within the
+                        * last 75 2K sectors, we decrease the saved size
+                        * value.
+                        */
                        if (sector < get_capacity(info->disk) &&
                            drive->probed_capacity - sector < 4 * 75)
                                set_capacity(info->disk, sector);
@@ -1790,15 +1798,17 @@ static void ide_cd_remove(ide_drive_t *drive)
        ide_debug_log(IDE_DBG_FUNC, "Call %s\n", __func__);
 
        ide_proc_unregister_driver(drive, info->driver);
-
+       device_del(&info->dev);
        del_gendisk(info->disk);
 
-       ide_cd_put(info);
+       mutex_lock(&idecd_ref_mutex);
+       put_device(&info->dev);
+       mutex_unlock(&idecd_ref_mutex);
 }
 
-static void ide_cd_release(struct kref *kref)
+static void ide_cd_release(struct device *dev)
 {
-       struct cdrom_info *info = to_ide_drv(kref, cdrom_info);
+       struct cdrom_info *info = to_ide_drv(dev, cdrom_info);
        struct cdrom_device_info *devinfo = &info->devinfo;
        ide_drive_t *drive = info->drive;
        struct gendisk *g = info->disk;
@@ -1997,7 +2007,12 @@ static int ide_cd_probe(ide_drive_t *drive)
 
        ide_init_disk(g, drive);
 
-       kref_init(&info->kref);
+       info->dev.parent = &drive->gendev;
+       info->dev.release = ide_cd_release;
+       dev_set_name(&info->dev, dev_name(&drive->gendev));
+
+       if (device_register(&info->dev))
+               goto out_free_disk;
 
        info->drive = drive;
        info->driver = &ide_cdrom_driver;
@@ -2011,7 +2026,7 @@ static int ide_cd_probe(ide_drive_t *drive)
        g->driverfs_dev = &drive->gendev;
        g->flags = GENHD_FL_CD | GENHD_FL_REMOVABLE;
        if (ide_cdrom_setup(drive)) {
-               ide_cd_release(&info->kref);
+               put_device(&info->dev);
                goto failed;
        }
 
@@ -2021,6 +2036,8 @@ static int ide_cd_probe(ide_drive_t *drive)
        add_disk(g);
        return 0;
 
+out_free_disk:
+       put_disk(g);
 out_free_cd:
        kfree(info);
 failed:
index ac40d6cb90a240725ae40d661e428e27ebc36aef..c878bfcf111698430e8f870c0ccbc4e12b6e71ca 100644 (file)
@@ -80,7 +80,7 @@ struct cdrom_info {
        ide_drive_t             *drive;
        struct ide_driver       *driver;
        struct gendisk          *disk;
-       struct kref             kref;
+       struct device           dev;
 
        /* Buffer for table of contents.  NULL if we haven't allocated
           a TOC buffer for this device yet. */
index 7857b209c6df7616397e9a1e20a621807729f83e..047109419902c0ad6b3f741e68fdaab0e05a1069 100644 (file)
@@ -25,7 +25,7 @@ module_param(debug_mask, ulong, 0644);
 
 static DEFINE_MUTEX(ide_disk_ref_mutex);
 
-static void ide_disk_release(struct kref *);
+static void ide_disk_release(struct device *);
 
 static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
 {
@@ -37,7 +37,7 @@ static struct ide_disk_obj *ide_disk_get(struct gendisk *disk)
                if (ide_device_get(idkp->drive))
                        idkp = NULL;
                else
-                       kref_get(&idkp->kref);
+                       get_device(&idkp->dev);
        }
        mutex_unlock(&ide_disk_ref_mutex);
        return idkp;
@@ -48,7 +48,7 @@ static void ide_disk_put(struct ide_disk_obj *idkp)
        ide_drive_t *drive = idkp->drive;
 
        mutex_lock(&ide_disk_ref_mutex);
-       kref_put(&idkp->kref, ide_disk_release);
+       put_device(&idkp->dev);
        ide_device_put(drive);
        mutex_unlock(&ide_disk_ref_mutex);
 }
@@ -66,17 +66,18 @@ static void ide_gd_remove(ide_drive_t *drive)
        struct gendisk *g = idkp->disk;
 
        ide_proc_unregister_driver(drive, idkp->driver);
-
+       device_del(&idkp->dev);
        del_gendisk(g);
-
        drive->disk_ops->flush(drive);
 
-       ide_disk_put(idkp);
+       mutex_lock(&ide_disk_ref_mutex);
+       put_device(&idkp->dev);
+       mutex_unlock(&ide_disk_ref_mutex);
 }
 
-static void ide_disk_release(struct kref *kref)
+static void ide_disk_release(struct device *dev)
 {
-       struct ide_disk_obj *idkp = to_ide_drv(kref, ide_disk_obj);
+       struct ide_disk_obj *idkp = to_ide_drv(dev, ide_disk_obj);
        ide_drive_t *drive = idkp->drive;
        struct gendisk *g = idkp->disk;
 
@@ -348,7 +349,12 @@ static int ide_gd_probe(ide_drive_t *drive)
 
        ide_init_disk(g, drive);
 
-       kref_init(&idkp->kref);
+       idkp->dev.parent = &drive->gendev;
+       idkp->dev.release = ide_disk_release;
+       dev_set_name(&idkp->dev, dev_name(&drive->gendev));
+
+       if (device_register(&idkp->dev))
+               goto out_free_disk;
 
        idkp->drive = drive;
        idkp->driver = &ide_gd_driver;
@@ -373,6 +379,8 @@ static int ide_gd_probe(ide_drive_t *drive)
        add_disk(g);
        return 0;
 
+out_free_disk:
+       put_disk(g);
 out_free_idkp:
        kfree(idkp);
 failed:
index a86779f0756b7c117ece8a93c3acaa649c6dd9d9..b604bdd318a1294a6e7cb8c9d2addcca68f8759d 100644 (file)
@@ -17,7 +17,7 @@ struct ide_disk_obj {
        ide_drive_t             *drive;
        struct ide_driver       *driver;
        struct gendisk          *disk;
-       struct kref             kref;
+       struct device           dev;
        unsigned int            openers;        /* protected by BKL for now */
 
        /* Last failed packet command */
index d7ecd3c79757f036e0f9f5d083a63f31b64059b1..bb450a7608c2fe9a8ef08f19b03d86ba980f3fde 100644 (file)
@@ -169,7 +169,7 @@ typedef struct ide_tape_obj {
        ide_drive_t             *drive;
        struct ide_driver       *driver;
        struct gendisk          *disk;
-       struct kref             kref;
+       struct device           dev;
 
        /*
         *      failed_pc points to the last failed packet command, or contains
@@ -267,7 +267,7 @@ static DEFINE_MUTEX(idetape_ref_mutex);
 
 static struct class *idetape_sysfs_class;
 
-static void ide_tape_release(struct kref *);
+static void ide_tape_release(struct device *);
 
 static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
 {
@@ -279,7 +279,7 @@ static struct ide_tape_obj *ide_tape_get(struct gendisk *disk)
                if (ide_device_get(tape->drive))
                        tape = NULL;
                else
-                       kref_get(&tape->kref);
+                       get_device(&tape->dev);
        }
        mutex_unlock(&idetape_ref_mutex);
        return tape;
@@ -290,7 +290,7 @@ static void ide_tape_put(struct ide_tape_obj *tape)
        ide_drive_t *drive = tape->drive;
 
        mutex_lock(&idetape_ref_mutex);
-       kref_put(&tape->kref, ide_tape_release);
+       put_device(&tape->dev);
        ide_device_put(drive);
        mutex_unlock(&idetape_ref_mutex);
 }
@@ -308,7 +308,7 @@ static struct ide_tape_obj *ide_tape_chrdev_get(unsigned int i)
        mutex_lock(&idetape_ref_mutex);
        tape = idetape_devs[i];
        if (tape)
-               kref_get(&tape->kref);
+               get_device(&tape->dev);
        mutex_unlock(&idetape_ref_mutex);
        return tape;
 }
@@ -2256,15 +2256,17 @@ static void ide_tape_remove(ide_drive_t *drive)
        idetape_tape_t *tape = drive->driver_data;
 
        ide_proc_unregister_driver(drive, tape->driver);
-
+       device_del(&tape->dev);
        ide_unregister_region(tape->disk);
 
-       ide_tape_put(tape);
+       mutex_lock(&idetape_ref_mutex);
+       put_device(&tape->dev);
+       mutex_unlock(&idetape_ref_mutex);
 }
 
-static void ide_tape_release(struct kref *kref)
+static void ide_tape_release(struct device *dev)
 {
-       struct ide_tape_obj *tape = to_ide_drv(kref, ide_tape_obj);
+       struct ide_tape_obj *tape = to_ide_drv(dev, ide_tape_obj);
        ide_drive_t *drive = tape->drive;
        struct gendisk *g = tape->disk;
 
@@ -2407,7 +2409,12 @@ static int ide_tape_probe(ide_drive_t *drive)
 
        ide_init_disk(g, drive);
 
-       kref_init(&tape->kref);
+       tape->dev.parent = &drive->gendev;
+       tape->dev.release = ide_tape_release;
+       dev_set_name(&tape->dev, dev_name(&drive->gendev));
+
+       if (device_register(&tape->dev))
+               goto out_free_disk;
 
        tape->drive = drive;
        tape->driver = &idetape_driver;
@@ -2436,6 +2443,8 @@ static int ide_tape_probe(ide_drive_t *drive)
 
        return 0;
 
+out_free_disk:
+       put_disk(g);
 out_free_tape:
        kfree(tape);
 failed:
index 258805da15c33f596079fd1a804b25d24d10c2cb..0920e3b0c962451d6e98cff91bf87e5e150b0afb 100644 (file)
@@ -337,6 +337,7 @@ static int ide_set_dev_param_mask(const char *s, struct kernel_param *kp)
        int a, b, i, j = 1;
        unsigned int *dev_param_mask = (unsigned int *)kp->arg;
 
+       /* controller . device (0 or 1) [ : 1 (set) | 0 (clear) ] */
        if (sscanf(s, "%d.%d:%d", &a, &b, &j) != 3 &&
            sscanf(s, "%d.%d", &a, &b) != 2)
                return -EINVAL;
@@ -349,7 +350,7 @@ static int ide_set_dev_param_mask(const char *s, struct kernel_param *kp)
        if (j)
                *dev_param_mask |= (1 << i);
        else
-               *dev_param_mask &= (1 << i);
+               *dev_param_mask &= ~(1 << i);
 
        return 0;
 }
@@ -392,6 +393,8 @@ static int ide_set_disk_chs(const char *str, struct kernel_param *kp)
 {
        int a, b, c = 0, h = 0, s = 0, i, j = 1;
 
+       /* controller . device (0 or 1) : Cylinders , Heads , Sectors */
+       /* controller . device (0 or 1) : 1 (use CHS) | 0 (ignore CHS) */
        if (sscanf(str, "%d.%d:%d,%d,%d", &a, &b, &c, &h, &s) != 5 &&
            sscanf(str, "%d.%d:%d", &a, &b, &j) != 3)
                return -EINVAL;
@@ -407,7 +410,7 @@ static int ide_set_disk_chs(const char *str, struct kernel_param *kp)
        if (j)
                ide_disks |= (1 << i);
        else
-               ide_disks &= (1 << i);
+               ide_disks &= ~(1 << i);
 
        ide_disks_chs[i].cyl  = c;
        ide_disks_chs[i].head = h;
@@ -469,6 +472,8 @@ static int ide_set_ignore_cable(const char *s, struct kernel_param *kp)
 {
        int i, j = 1;
 
+       /* controller (ignore) */
+       /* controller : 1 (ignore) | 0 (use) */
        if (sscanf(s, "%d:%d", &i, &j) != 2 && sscanf(s, "%d", &i) != 1)
                return -EINVAL;
 
@@ -478,7 +483,7 @@ static int ide_set_ignore_cable(const char *s, struct kernel_param *kp)
        if (j)
                ide_ignore_cable |= (1 << i);
        else
-               ide_ignore_cable &= (1 << i);
+               ide_ignore_cable &= ~(1 << i);
 
        return 0;
 }
index e1c4f5437396b076bf09f55f32eed07e9ef6b9f4..13b8153112edf3394235f3009aaefd18e1197bc4 100644 (file)
@@ -5,9 +5,8 @@
  *  May be copied or modified under the terms of the GNU General Public License
  *  Based in part on the ITE vendor provided SCSI driver.
  *
- *  Documentation available from
- *     http://www.ite.com.tw/pc/IT8212F_V04.pdf
- *  Some other documents are NDA.
+ *  Documentation:
+ *     Datasheet is freely available, some other documents under NDA.
  *
  *  The ITE8212 isn't exactly a standard IDE controller. It has two
  *  modes. In pass through mode then it is an IDE controller. In its smart
index 2727bcd24194c6e36651fadbc9439721708e93a8..467373cab8e5a1fc7ed1ffcea2e14560b8898db3 100644 (file)
@@ -12,6 +12,7 @@
 
 #include <asm/types.h>
 
+struct file;
 struct pci_dev;
 struct scatterlist;
 struct vm_area_struct;
index 2beb8d94f7bd3b7584c2c30003c98892b97d3e43..87233800372182916a51caaebbc3b06f89472963 100644 (file)
@@ -1275,7 +1275,7 @@ static void __exit ieee1394_cleanup(void)
        unregister_chrdev_region(IEEE1394_CORE_DEV, 256);
 }
 
-module_init(ieee1394_init);
+fs_initcall(ieee1394_init);
 module_exit(ieee1394_cleanup);
 
 /* Exported symbols */
@@ -1314,6 +1314,7 @@ EXPORT_SYMBOL(hpsb_make_lock64packet);
 EXPORT_SYMBOL(hpsb_make_phypacket);
 EXPORT_SYMBOL(hpsb_read);
 EXPORT_SYMBOL(hpsb_write);
+EXPORT_SYMBOL(hpsb_lock);
 EXPORT_SYMBOL(hpsb_packet_success);
 
 /** highlevel.c **/
index 10c3d9f8c038ea944750bff2e913ef8b3c12d8b0..675b3135d5f19a78816976b0835deb54468c94af 100644 (file)
@@ -501,8 +501,6 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
        if (length == 0)
                return -EINVAL;
 
-       BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
-
        packet = hpsb_make_readpacket(host, node, addr, length);
 
        if (!packet) {
@@ -550,8 +548,6 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
        if (length == 0)
                return -EINVAL;
 
-       BUG_ON(in_interrupt()); // We can't be called in an interrupt, yet
-
        packet = hpsb_make_writepacket(host, node, addr, buffer, length);
 
        if (!packet)
@@ -570,3 +566,30 @@ int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
 
        return retval;
 }
+
+int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+             u64 addr, int extcode, quadlet_t *data, quadlet_t arg)
+{
+       struct hpsb_packet *packet;
+       int retval = 0;
+
+       packet = hpsb_make_lockpacket(host, node, addr, extcode, data, arg);
+       if (!packet)
+               return -ENOMEM;
+
+       packet->generation = generation;
+       retval = hpsb_send_packet_and_wait(packet);
+       if (retval < 0)
+               goto hpsb_lock_fail;
+
+       retval = hpsb_packet_success(packet);
+
+       if (retval == 0)
+               *data = packet->data[0];
+
+hpsb_lock_fail:
+       hpsb_free_tlabel(packet);
+       hpsb_free_packet(packet);
+
+       return retval;
+}
index d2d5bc3546d74093b2fe0ce56ef913b63ef6648e..20b693be14b22f558491285e895e7cad5bf20828 100644 (file)
@@ -30,6 +30,8 @@ int hpsb_read(struct hpsb_host *host, nodeid_t node, unsigned int generation,
              u64 addr, quadlet_t *buffer, size_t length);
 int hpsb_write(struct hpsb_host *host, nodeid_t node, unsigned int generation,
               u64 addr, quadlet_t *buffer, size_t length);
+int hpsb_lock(struct hpsb_host *host, nodeid_t node, unsigned int generation,
+             u64 addr, int extcode, quadlet_t *data, quadlet_t arg);
 
 #ifdef HPSB_DEBUG_TLABELS
 extern spinlock_t hpsb_tlabel_lock;
index b5de5f21ef78a57e45032500867fdb24538de00e..c2089c093aa76eaf1165391a3ea2d8d5b023b960 100644 (file)
@@ -13,6 +13,7 @@
 #define IEEE1394_ISO_H
 
 #include <linux/spinlock_types.h>
+#include <linux/wait.h>
 #include <asm/atomic.h>
 #include <asm/types.h>
 
index 906c5a98d8142585a1ad86ef2c1d55f9b16cc3eb..53aada5bbe1ebad918803836b8752a21cecbb37e 100644 (file)
@@ -971,6 +971,9 @@ static struct unit_directory *nodemgr_process_unit_directory
        ud->ud_kv = ud_kv;
        ud->id = (*id)++;
 
+       /* inherit vendor_id from root directory if none exists in unit dir */
+       ud->vendor_id = ne->vendor_id;
+
        csr1212_for_each_dir_entry(ne->csr, kv, ud_kv, dentry) {
                switch (kv->key.id) {
                case CSR1212_KV_ID_VENDOR:
@@ -1265,7 +1268,8 @@ static void nodemgr_update_node(struct node_entry *ne, struct csr1212_csr *csr,
                csr1212_destroy_csr(csr);
        }
 
-       /* Mark the node current */
+       /* Finally, mark the node current */
+       smp_wmb();
        ne->generation = generation;
 
        if (ne->in_limbo) {
@@ -1798,7 +1802,7 @@ void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet)
 {
        packet->host = ne->host;
        packet->generation = ne->generation;
-       barrier();
+       smp_rmb();
        packet->node_id = ne->nodeid;
 }
 
@@ -1807,7 +1811,7 @@ int hpsb_node_write(struct node_entry *ne, u64 addr,
 {
        unsigned int generation = ne->generation;
 
-       barrier();
+       smp_rmb();
        return hpsb_write(ne->host, ne->nodeid, generation,
                          addr, buffer, length);
 }
index 15ea09733e84fbc1ee4588f730ed77b049aa1e5c..ee5acdbd114aed18c942fd11c6a38bbc3193be10 100644 (file)
 #define _IEEE1394_NODEMGR_H
 
 #include <linux/device.h>
+#include <asm/system.h>
 #include <asm/types.h>
 
 #include "ieee1394_core.h"
+#include "ieee1394_transactions.h"
 #include "ieee1394_types.h"
 
 struct csr1212_csr;
@@ -154,6 +156,22 @@ static inline int hpsb_node_entry_valid(struct node_entry *ne)
 void hpsb_node_fill_packet(struct node_entry *ne, struct hpsb_packet *packet);
 int hpsb_node_write(struct node_entry *ne, u64 addr,
                    quadlet_t *buffer, size_t length);
+static inline int hpsb_node_read(struct node_entry *ne, u64 addr,
+                                quadlet_t *buffer, size_t length)
+{
+       unsigned int g = ne->generation;
+
+       smp_rmb();
+       return hpsb_read(ne->host, ne->nodeid, g, addr, buffer, length);
+}
+static inline int hpsb_node_lock(struct node_entry *ne, u64 addr, int extcode,
+                                quadlet_t *buffer, quadlet_t arg)
+{
+       unsigned int g = ne->generation;
+
+       smp_rmb();
+       return hpsb_lock(ne->host, ne->nodeid, g, addr, extcode, buffer, arg);
+}
 int nodemgr_for_each_host(void *data, int (*cb)(struct hpsb_host *, void *));
 
 int init_ieee1394_nodemgr(void);
index 113f3c03c5b5bc8391260dcaf14976537a94d30f..7d79aa361e26c84677f87bcf665a288f2b4b6182 100644 (file)
@@ -76,7 +76,6 @@ static irqreturn_t c2_interrupt(int irq, void *dev_id);
 static void c2_tx_timeout(struct net_device *netdev);
 static int c2_change_mtu(struct net_device *netdev, int new_mtu);
 static void c2_reset(struct c2_port *c2_port);
-static struct net_device_stats *c2_get_stats(struct net_device *netdev);
 
 static struct pci_device_id c2_pci_table[] = {
        { PCI_DEVICE(0x18b8, 0xb001) },
@@ -349,7 +348,7 @@ static void c2_tx_clean(struct c2_port *c2_port)
                                             elem->hw_desc + C2_TXP_ADDR);
                                __raw_writew((__force u16) cpu_to_be16(TXP_HTXD_DONE),
                                             elem->hw_desc + C2_TXP_FLAGS);
-                               c2_port->netstats.tx_dropped++;
+                               c2_port->netdev->stats.tx_dropped++;
                                break;
                        } else {
                                __raw_writew(0,
@@ -457,7 +456,7 @@ static void c2_rx_error(struct c2_port *c2_port, struct c2_element *elem)
                     elem->hw_desc + C2_RXP_FLAGS);
 
        pr_debug("packet dropped\n");
-       c2_port->netstats.rx_dropped++;
+       c2_port->netdev->stats.rx_dropped++;
 }
 
 static void c2_rx_interrupt(struct net_device *netdev)
@@ -532,8 +531,8 @@ static void c2_rx_interrupt(struct net_device *netdev)
                netif_rx(skb);
 
                netdev->last_rx = jiffies;
-               c2_port->netstats.rx_packets++;
-               c2_port->netstats.rx_bytes += buflen;
+               netdev->stats.rx_packets++;
+               netdev->stats.rx_bytes += buflen;
        }
 
        /* Save where we left off */
@@ -797,8 +796,8 @@ static int c2_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        __raw_writew((__force u16) cpu_to_be16(TXP_HTXD_READY),
                     elem->hw_desc + C2_TXP_FLAGS);
 
-       c2_port->netstats.tx_packets++;
-       c2_port->netstats.tx_bytes += maplen;
+       netdev->stats.tx_packets++;
+       netdev->stats.tx_bytes += maplen;
 
        /* Loop thru additional data fragments and queue them */
        if (skb_shinfo(skb)->nr_frags) {
@@ -823,8 +822,8 @@ static int c2_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                        __raw_writew((__force u16) cpu_to_be16(TXP_HTXD_READY),
                                     elem->hw_desc + C2_TXP_FLAGS);
 
-                       c2_port->netstats.tx_packets++;
-                       c2_port->netstats.tx_bytes += maplen;
+                       netdev->stats.tx_packets++;
+                       netdev->stats.tx_bytes += maplen;
                }
        }
 
@@ -845,13 +844,6 @@ static int c2_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        return NETDEV_TX_OK;
 }
 
-static struct net_device_stats *c2_get_stats(struct net_device *netdev)
-{
-       struct c2_port *c2_port = netdev_priv(netdev);
-
-       return &c2_port->netstats;
-}
-
 static void c2_tx_timeout(struct net_device *netdev)
 {
        struct c2_port *c2_port = netdev_priv(netdev);
@@ -880,6 +872,16 @@ static int c2_change_mtu(struct net_device *netdev, int new_mtu)
        return ret;
 }
 
+static const struct net_device_ops c2_netdev = {
+       .ndo_open               = c2_up,
+       .ndo_stop               = c2_down,
+       .ndo_start_xmit         = c2_xmit_frame,
+       .ndo_tx_timeout         = c2_tx_timeout,
+       .ndo_change_mtu         = c2_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 /* Initialize network device */
 static struct net_device *c2_devinit(struct c2_dev *c2dev,
                                     void __iomem * mmio_addr)
@@ -894,12 +896,7 @@ static struct net_device *c2_devinit(struct c2_dev *c2dev,
 
        SET_NETDEV_DEV(netdev, &c2dev->pcidev->dev);
 
-       netdev->open = c2_up;
-       netdev->stop = c2_down;
-       netdev->hard_start_xmit = c2_xmit_frame;
-       netdev->get_stats = c2_get_stats;
-       netdev->tx_timeout = c2_tx_timeout;
-       netdev->change_mtu = c2_change_mtu;
+       netdev->netdev_ops = &c2_netdev;
        netdev->watchdog_timeo = C2_TX_TIMEOUT;
        netdev->irq = c2dev->pcidev->irq;
 
index d12a24a84fd960838441413178486f1e4636ce24..f7ff66f9836166fe30a8dce543d1d1fc55df8923 100644 (file)
@@ -369,8 +369,6 @@ struct c2_port {
        unsigned long mem_size;
 
        u32 rx_buf_size;
-
-       struct net_device_stats netstats;
 };
 
 /*
index 5119d6508181633bf2ace7886bc0034afd74bcf8..f1948fad85d7cd1586c009bd7e89d53f2c30375b 100644 (file)
@@ -708,26 +708,27 @@ static int c2_pseudo_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
 static int c2_pseudo_change_mtu(struct net_device *netdev, int new_mtu)
 {
-       int ret = 0;
-
        if (new_mtu < ETH_ZLEN || new_mtu > ETH_JUMBO_MTU)
                return -EINVAL;
 
        netdev->mtu = new_mtu;
 
        /* TODO: Tell rnic about new rmda interface mtu */
-       return ret;
+       return 0;
 }
 
+static const struct net_device_ops c2_pseudo_netdev_ops = {
+       .ndo_open               = c2_pseudo_up,
+       .ndo_stop               = c2_pseudo_down,
+       .ndo_start_xmit         = c2_pseudo_xmit_frame,
+       .ndo_change_mtu         = c2_pseudo_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 static void setup(struct net_device *netdev)
 {
-       netdev->open = c2_pseudo_up;
-       netdev->stop = c2_pseudo_down;
-       netdev->hard_start_xmit = c2_pseudo_xmit_frame;
-       netdev->get_stats = NULL;
-       netdev->tx_timeout = NULL;
-       netdev->set_mac_address = NULL;
-       netdev->change_mtu = c2_pseudo_change_mtu;
+       netdev->netdev_ops = &c2_pseudo_netdev_ops;
+
        netdev->watchdog_timeo = 0;
        netdev->type = ARPHRD_ETHER;
        netdev->mtu = 1500;
@@ -735,7 +736,6 @@ static void setup(struct net_device *netdev)
        netdev->addr_len = ETH_ALEN;
        netdev->tx_queue_len = 0;
        netdev->flags |= IFF_NOARP;
-       return;
 }
 
 static struct net_device *c2_pseudo_netdev_init(struct c2_dev *c2dev)
index f5484ad1279bd2110a253870b482b7de5fc8b537..ae8c6888b533a8e244265c154b9b3f47b1f5c6d6 100644 (file)
@@ -1568,6 +1568,19 @@ static void nes_netdev_vlan_rx_register(struct net_device *netdev, struct vlan_g
        spin_unlock_irqrestore(&nesadapter->phy_lock, flags);
 }
 
+static const struct net_device_ops nes_netdev_ops = {
+       .ndo_open               = nes_netdev_open,
+       .ndo_stop               = nes_netdev_stop,
+       .ndo_start_xmit         = nes_netdev_start_xmit,
+       .ndo_get_stats          = nes_netdev_get_stats,
+       .ndo_tx_timeout         = nes_netdev_tx_timeout,
+       .ndo_set_mac_address    = nes_netdev_set_mac_address,
+       .ndo_set_multicast_list = nes_netdev_set_multicast_list,
+       .ndo_change_mtu         = nes_netdev_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_vlan_rx_register   = nes_netdev_vlan_rx_register,
+};
 
 /**
  * nes_netdev_init - initialize network device
@@ -1593,17 +1606,6 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
 
        SET_NETDEV_DEV(netdev, &nesdev->pcidev->dev);
 
-       nesvnic = netdev_priv(netdev);
-       memset(nesvnic, 0, sizeof(*nesvnic));
-
-       netdev->open = nes_netdev_open;
-       netdev->stop = nes_netdev_stop;
-       netdev->hard_start_xmit = nes_netdev_start_xmit;
-       netdev->get_stats = nes_netdev_get_stats;
-       netdev->tx_timeout = nes_netdev_tx_timeout;
-       netdev->set_mac_address = nes_netdev_set_mac_address;
-       netdev->set_multicast_list = nes_netdev_set_multicast_list;
-       netdev->change_mtu = nes_netdev_change_mtu;
        netdev->watchdog_timeo = NES_TX_TIMEOUT;
        netdev->irq = nesdev->pcidev->irq;
        netdev->mtu = ETH_DATA_LEN;
@@ -1611,14 +1613,15 @@ struct net_device *nes_netdev_init(struct nes_device *nesdev,
        netdev->addr_len = ETH_ALEN;
        netdev->type = ARPHRD_ETHER;
        netdev->features = NETIF_F_HIGHDMA;
+       netdev->netdev_ops = &nes_netdev_ops;
        netdev->ethtool_ops = &nes_ethtool_ops;
        netif_napi_add(netdev, &nesvnic->napi, nes_netdev_poll, 128);
        nes_debug(NES_DBG_INIT, "Enabling VLAN Insert/Delete.\n");
        netdev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-       netdev->vlan_rx_register = nes_netdev_vlan_rx_register;
        netdev->features |= NETIF_F_LLTX;
 
        /* Fill in the port structure */
+       nesvnic = netdev_priv(netdev);
        nesvnic->netdev = netdev;
        nesvnic->nesdev = nesdev;
        nesvnic->msg_enable = netif_msg_init(debug, default_msg);
index 0bd2a4ff08428dfae19de45d8f808a91f8ca384e..ca837b0a889ba9ef031d094e0c3375f6cb82d9e4 100644 (file)
@@ -1016,18 +1016,22 @@ static void ipoib_lro_setup(struct ipoib_dev_priv *priv)
        priv->lro.lro_mgr.ip_summed_aggr = CHECKSUM_UNNECESSARY;
 }
 
+static const struct net_device_ops ipoib_netdev_ops = {
+       .ndo_open                = ipoib_open,
+       .ndo_stop                = ipoib_stop,
+       .ndo_change_mtu          = ipoib_change_mtu,
+       .ndo_start_xmit          = ipoib_start_xmit,
+       .ndo_tx_timeout          = ipoib_timeout,
+       .ndo_set_multicast_list  = ipoib_set_mcast_list,
+       .ndo_neigh_setup         = ipoib_neigh_setup_dev,
+};
+
 static void ipoib_setup(struct net_device *dev)
 {
        struct ipoib_dev_priv *priv = netdev_priv(dev);
 
-       dev->open                = ipoib_open;
-       dev->stop                = ipoib_stop;
-       dev->change_mtu          = ipoib_change_mtu;
-       dev->hard_start_xmit     = ipoib_start_xmit;
-       dev->tx_timeout          = ipoib_timeout;
+       dev->netdev_ops          = &ipoib_netdev_ops;
        dev->header_ops          = &ipoib_header_ops;
-       dev->set_multicast_list  = ipoib_set_mcast_list;
-       dev->neigh_setup         = ipoib_neigh_setup_dev;
 
        ipoib_set_ethtool_ops(dev);
 
index c3c8b9bc40ae6220f46a8dba295f8a87c7e1e6e3..45470f18d7e9ea7c252a1a2c4e671490483da36b 100644 (file)
@@ -839,7 +839,7 @@ static void atkbd_disconnect(struct serio *serio)
  */
 static void atkbd_dell_laptop_keymap_fixup(struct atkbd *atkbd)
 {
-       const unsigned int forced_release_keys[] = {
+       static const unsigned int forced_release_keys[] = {
                0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8f, 0x93,
        };
        int i;
@@ -856,7 +856,7 @@ static void atkbd_dell_laptop_keymap_fixup(struct atkbd *atkbd)
  */
 static void atkbd_hp_keymap_fixup(struct atkbd *atkbd)
 {
-       const unsigned int forced_release_keys[] = {
+       static const unsigned int forced_release_keys[] = {
                0x94,
        };
        int i;
index 19284016e0f4d1c2ce47e3f86f4a5f59e04445fc..ee855c5202e827b8545978f023204937b13dccc2 100644 (file)
@@ -209,8 +209,8 @@ static int __devinit bfin_kpad_probe(struct platform_device *pdev)
                goto out;
        }
 
-       if (!pdata->debounce_time || !pdata->debounce_time > MAX_MULT ||
-           !pdata->coldrive_time || !pdata->coldrive_time > MAX_MULT) {
+       if (!pdata->debounce_time || pdata->debounce_time > MAX_MULT ||
+           !pdata->coldrive_time || pdata->coldrive_time > MAX_MULT) {
                printk(KERN_ERR DRV_NAME
                        ": Invalid Debounce/Columdrive Time from pdata\n");
                bfin_write_KPAD_MSEL(0xFF0);    /* Default MSEL */
index c8ed065ea0cbd9f2d360331c101b2052bc8d2ebb..abb04c82c622edd638228054f1d6dc8a9066accd 100644 (file)
@@ -288,7 +288,7 @@ static int corgikbd_resume(struct platform_device *dev)
 #define corgikbd_resume                NULL
 #endif
 
-static int __init corgikbd_probe(struct platform_device *pdev)
+static int __devinit corgikbd_probe(struct platform_device *pdev)
 {
        struct corgikbd *corgikbd;
        struct input_dev *input_dev;
@@ -368,7 +368,7 @@ static int __init corgikbd_probe(struct platform_device *pdev)
        return err;
 }
 
-static int corgikbd_remove(struct platform_device *pdev)
+static int __devexit corgikbd_remove(struct platform_device *pdev)
 {
        int i;
        struct corgikbd *corgikbd = platform_get_drvdata(pdev);
@@ -388,7 +388,7 @@ static int corgikbd_remove(struct platform_device *pdev)
 
 static struct platform_driver corgikbd_driver = {
        .probe          = corgikbd_probe,
-       .remove         = corgikbd_remove,
+       .remove         = __devexit_p(corgikbd_remove),
        .suspend        = corgikbd_suspend,
        .resume         = corgikbd_resume,
        .driver         = {
@@ -397,7 +397,7 @@ static struct platform_driver corgikbd_driver = {
        },
 };
 
-static int __devinit corgikbd_init(void)
+static int __init corgikbd_init(void)
 {
        return platform_driver_register(&corgikbd_driver);
 }
index 3f3d1198cdb10dd76fb4973766ab9d6e1908d246..058fa8b02c21ee1b939085c024c23884e2f6ca1d 100644 (file)
@@ -279,7 +279,7 @@ static int omap_kp_resume(struct platform_device *dev)
 #define omap_kp_resume NULL
 #endif
 
-static int __init omap_kp_probe(struct platform_device *pdev)
+static int __devinit omap_kp_probe(struct platform_device *pdev)
 {
        struct omap_kp *omap_kp;
        struct input_dev *input_dev;
@@ -422,7 +422,7 @@ err1:
        return -EINVAL;
 }
 
-static int omap_kp_remove(struct platform_device *pdev)
+static int __devexit omap_kp_remove(struct platform_device *pdev)
 {
        struct omap_kp *omap_kp = platform_get_drvdata(pdev);
 
@@ -454,7 +454,7 @@ static int omap_kp_remove(struct platform_device *pdev)
 
 static struct platform_driver omap_kp_driver = {
        .probe          = omap_kp_probe,
-       .remove         = omap_kp_remove,
+       .remove         = __devexit_p(omap_kp_remove),
        .suspend        = omap_kp_suspend,
        .resume         = omap_kp_resume,
        .driver         = {
@@ -463,7 +463,7 @@ static struct platform_driver omap_kp_driver = {
        },
 };
 
-static int __devinit omap_kp_init(void)
+static int __init omap_kp_init(void)
 {
        printk(KERN_INFO "OMAP Keypad Driver\n");
        return platform_driver_register(&omap_kp_driver);
index c48b76a46a58ef5adf68601171007db16cae1abb..9d1781a618e99466f0855f480cbb8974e6a3fbd8 100644 (file)
@@ -343,7 +343,7 @@ static int spitzkbd_resume(struct platform_device *dev)
 #define spitzkbd_resume                NULL
 #endif
 
-static int __init spitzkbd_probe(struct platform_device *dev)
+static int __devinit spitzkbd_probe(struct platform_device *dev)
 {
        struct spitzkbd *spitzkbd;
        struct input_dev *input_dev;
@@ -444,7 +444,7 @@ static int __init spitzkbd_probe(struct platform_device *dev)
        return err;
 }
 
-static int spitzkbd_remove(struct platform_device *dev)
+static int __devexit spitzkbd_remove(struct platform_device *dev)
 {
        int i;
        struct spitzkbd *spitzkbd = platform_get_drvdata(dev);
@@ -470,7 +470,7 @@ static int spitzkbd_remove(struct platform_device *dev)
 
 static struct platform_driver spitzkbd_driver = {
        .probe          = spitzkbd_probe,
-       .remove         = spitzkbd_remove,
+       .remove         = __devexit_p(spitzkbd_remove),
        .suspend        = spitzkbd_suspend,
        .resume         = spitzkbd_resume,
        .driver         = {
@@ -479,7 +479,7 @@ static struct platform_driver spitzkbd_driver = {
        },
 };
 
-static int __devinit spitzkbd_init(void)
+static int __init spitzkbd_init(void)
 {
        return platform_driver_register(&spitzkbd_driver);
 }
index 093c8c1bca746b651a4c18ab260931a02dac5dae..9705f3a00a3d944a5e3883e3cdf2fce4de20a2e8 100644 (file)
@@ -70,7 +70,7 @@ config MOUSE_PS2_SYNAPTICS
 config MOUSE_PS2_LIFEBOOK
        bool "Fujitsu Lifebook PS/2 mouse protocol extension" if EMBEDDED
        default y
-       depends on MOUSE_PS2
+       depends on MOUSE_PS2 && X86
        help
          Say Y here if you have a Fujitsu B-series Lifebook PS/2
          TouchScreen connected to your system.
index b9a25d57bc5ea085222597430fd8bb242ba2adee..6ab0eb1ada1c6e94c5c4f3e14d846e24f6b3339d 100644 (file)
@@ -542,7 +542,7 @@ int elantech_detect(struct psmouse *psmouse, int set_properties)
            ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE11) ||
            ps2_command(ps2dev,  NULL, PSMOUSE_CMD_SETSCALE11) ||
            ps2_command(ps2dev, param, PSMOUSE_CMD_GETINFO)) {
-               pr_err("elantech.c: sending Elantech magic knock failed.\n");
+               pr_debug("elantech.c: sending Elantech magic knock failed.\n");
                return -1;
        }
 
@@ -551,8 +551,27 @@ int elantech_detect(struct psmouse *psmouse, int set_properties)
         * set of magic numbers
         */
        if (param[0] != 0x3c || param[1] != 0x03 || param[2] != 0xc8) {
-               pr_info("elantech.c: unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n",
-                       param[0], param[1], param[2]);
+               pr_debug("elantech.c: "
+                        "unexpected magic knock result 0x%02x, 0x%02x, 0x%02x.\n",
+                        param[0], param[1], param[2]);
+               return -1;
+       }
+
+       /*
+        * Query touchpad's firmware version and see if it reports known
+        * value to avoid mis-detection. Logitech mice are known to respond
+        * to Elantech magic knock and there might be more.
+        */
+       if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) {
+               pr_debug("elantech.c: failed to query firmware version.\n");
+               return -1;
+       }
+
+       pr_debug("elantech.c: Elantech version query result 0x%02x, 0x%02x, 0x%02x.\n",
+                param[0], param[1], param[2]);
+
+       if (param[0] == 0 || param[1] != 0) {
+               pr_debug("elantech.c: Probably not a real Elantech touchpad. Aborting.\n");
                return -1;
        }
 
@@ -600,8 +619,7 @@ int elantech_init(struct psmouse *psmouse)
        int i, error;
        unsigned char param[3];
 
-       etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL);
-       psmouse->private = etd;
+       psmouse->private = etd = kzalloc(sizeof(struct elantech_data), GFP_KERNEL);
        if (!etd)
                return -1;
 
@@ -610,14 +628,12 @@ int elantech_init(struct psmouse *psmouse)
                etd->parity[i] = etd->parity[i & (i - 1)] ^ 1;
 
        /*
-        * Find out what version hardware this is
+        * Do the version query again so we can store the result
         */
        if (synaptics_send_cmd(psmouse, ETP_FW_VERSION_QUERY, param)) {
                pr_err("elantech.c: failed to query firmware version.\n");
                goto init_fail;
        }
-       pr_info("elantech.c: Elantech version query result 0x%02x, 0x%02x, 0x%02x.\n",
-               param[0], param[1], param[2]);
        etd->fw_version_maj = param[0];
        etd->fw_version_min = param[2];
 
index d297accf9a7feeb8077737c187d39d64c3f89c0b..1e827ad0afbedd58a36438cb1fe23e4a0ad3adf8 100644 (file)
@@ -83,7 +83,7 @@ static int write_tbcr(struct pxa930_trkball *trkball, int v)
 
        __raw_writel(v, trkball->mmio_base + TBCR);
 
-       while (i--) {
+       while (--i) {
                if (__raw_readl(trkball->mmio_base + TBCR) == v)
                        break;
                msleep(1);
index 865fc69e9bc39e8ef81b213722e572c95917fb0e..f3e4f7b0240d04d40521f3ff1b79302293c0ea32 100644 (file)
@@ -182,11 +182,6 @@ static int synaptics_identify(struct psmouse *psmouse)
 
 static int synaptics_query_hardware(struct psmouse *psmouse)
 {
-       int retries = 0;
-
-       while ((retries++ < 3) && psmouse_reset(psmouse))
-               /* empty */;
-
        if (synaptics_identify(psmouse))
                return -1;
        if (synaptics_model_id(psmouse))
@@ -582,6 +577,8 @@ static int synaptics_reconnect(struct psmouse *psmouse)
        struct synaptics_data *priv = psmouse->private;
        struct synaptics_data old_priv = *priv;
 
+       psmouse_reset(psmouse);
+
        if (synaptics_detect(psmouse, 0))
                return -1;
 
@@ -640,6 +637,8 @@ int synaptics_init(struct psmouse *psmouse)
        if (!priv)
                return -1;
 
+       psmouse_reset(psmouse);
+
        if (synaptics_query_hardware(psmouse)) {
                printk(KERN_ERR "Unable to query Synaptics hardware.\n");
                goto init_fail;
index b10ffae7c39b341319f89142e01b0845fe5001c3..e29cdc13a199c007ab8ac6c6337086fe3685c5c4 100644 (file)
@@ -57,7 +57,7 @@ static int amba_kmi_write(struct serio *io, unsigned char val)
        struct amba_kmi_port *kmi = io->port_data;
        unsigned int timeleft = 10000; /* timeout in 100ms */
 
-       while ((readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && timeleft--)
+       while ((readb(KMISTAT) & KMISTAT_TXEMPTY) == 0 && --timeleft)
                udelay(10);
 
        if (timeleft)
@@ -129,8 +129,8 @@ static int amba_kmi_probe(struct amba_device *dev, void *id)
        io->write       = amba_kmi_write;
        io->open        = amba_kmi_open;
        io->close       = amba_kmi_close;
-       strlcpy(io->name, dev->dev.bus_id, sizeof(io->name));
-       strlcpy(io->phys, dev->dev.bus_id, sizeof(io->phys));
+       strlcpy(io->name, dev_name(&dev->dev), sizeof(io->name));
+       strlcpy(io->phys, dev_name(&dev->dev), sizeof(io->phys));
        io->port_data   = kmi;
        io->dev.parent  = &dev->dev;
 
index adc3bd6e7f7bbc9a0d038d748dd3f95794a46f8f..bd0f92d9f40f991c479d9237b851e381887f47e8 100644 (file)
@@ -359,7 +359,7 @@ static int __init gscps2_probe(struct parisc_device *dev)
 
        snprintf(serio->name, sizeof(serio->name), "GSC PS/2 %s",
                 (ps2port->id == GSC_ID_KEYBOARD) ? "keyboard" : "mouse");
-       strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys));
+       strlcpy(serio->phys, dev_name(&dev->dev), sizeof(serio->phys));
        serio->id.type          = SERIO_8042;
        serio->write            = gscps2_write;
        serio->open             = gscps2_open;
index 2ad88780a170aec1a61bc118c6013ae09dbbfacd..57953c0eb82fa8302b23eb84edf9e6507e5915b3 100644 (file)
@@ -246,8 +246,8 @@ static int __devinit ps2_probe(struct sa1111_dev *dev)
        serio->write            = ps2_write;
        serio->open             = ps2_open;
        serio->close            = ps2_close;
-       strlcpy(serio->name, dev->dev.bus_id, sizeof(serio->name));
-       strlcpy(serio->phys, dev->dev.bus_id, sizeof(serio->phys));
+       strlcpy(serio->name, dev_name(&dev->dev), sizeof(serio->name));
+       strlcpy(serio->phys, dev_name(&dev->dev), sizeof(serio->phys));
        serio->port_data        = ps2if;
        serio->dev.parent       = &dev->dev;
        ps2if->io               = serio;
index a89a6a8f05e6c9631f7368fb2488e080490b6fe0..055969e8be132de9a3954c85384b9801b4bcb667 100644 (file)
@@ -236,7 +236,7 @@ static int __devinit atmel_tsadcc_probe(struct platform_device *pdev)
        ts_dev->bufferedmeasure = 0;
 
        snprintf(ts_dev->phys, sizeof(ts_dev->phys),
-                "%s/input0", pdev->dev.bus_id);
+                "%s/input0", dev_name(&pdev->dev));
 
        input_dev->name = "atmel touch screen controller";
        input_dev->phys = ts_dev->phys;
index 65202c9f63ffbe4f7838654d59514ea34048ed7d..3fb51b54fe61e22a9960ae0cb58d19721a5d1932 100644 (file)
@@ -268,7 +268,7 @@ static int corgits_resume(struct platform_device *dev)
 #define corgits_resume         NULL
 #endif
 
-static int __init corgits_probe(struct platform_device *pdev)
+static int __devinit corgits_probe(struct platform_device *pdev)
 {
        struct corgi_ts *corgi_ts;
        struct input_dev *input_dev;
@@ -343,7 +343,7 @@ static int __init corgits_probe(struct platform_device *pdev)
        return err;
 }
 
-static int corgits_remove(struct platform_device *pdev)
+static int __devexit corgits_remove(struct platform_device *pdev)
 {
        struct corgi_ts *corgi_ts = platform_get_drvdata(pdev);
 
@@ -352,12 +352,13 @@ static int corgits_remove(struct platform_device *pdev)
        corgi_ts->machinfo->put_hsync();
        input_unregister_device(corgi_ts->input);
        kfree(corgi_ts);
+
        return 0;
 }
 
 static struct platform_driver corgits_driver = {
        .probe          = corgits_probe,
-       .remove         = corgits_remove,
+       .remove         = __devexit_p(corgits_remove),
        .suspend        = corgits_suspend,
        .resume         = corgits_resume,
        .driver         = {
@@ -366,7 +367,7 @@ static struct platform_driver corgits_driver = {
        },
 };
 
-static int __devinit corgits_init(void)
+static int __init corgits_init(void)
 {
        return platform_driver_register(&corgits_driver);
 }
index b75dc2990574e9549d483846d30f77e6f0eb08c1..4ab070246892c5935d8482af73f0499b98b199b6 100644 (file)
@@ -289,7 +289,8 @@ static int tsc2007_probe(struct i2c_client *client,
 
        pdata->init_platform_hw();
 
-       snprintf(ts->phys, sizeof(ts->phys), "%s/input0", client->dev.bus_id);
+       snprintf(ts->phys, sizeof(ts->phys),
+                "%s/input0", dev_name(&client->dev));
 
        input_dev->name = "TSC2007 Touchscreen";
        input_dev->phys = ts->phys;
index 5080b26ba1608ba2c54e1abe4de83d72d2ed62cf..fb7cb9bdfbd5c4971cedeb064b8839ae3d09365a 100644 (file)
@@ -60,6 +60,10 @@ static int swap_xy;
 module_param(swap_xy, bool, 0644);
 MODULE_PARM_DESC(swap_xy, "If set X and Y axes are swapped.");
 
+static int hwcalib_xy;
+module_param(hwcalib_xy, bool, 0644);
+MODULE_PARM_DESC(hwcalib_xy, "If set hw-calibrated X/Y are used if available");
+
 /* device specifc data/functions */
 struct usbtouch_usb;
 struct usbtouch_device_info {
@@ -118,6 +122,7 @@ enum {
 
 #define USB_DEVICE_HID_CLASS(vend, prod) \
        .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS \
+               | USB_DEVICE_ID_MATCH_INT_PROTOCOL \
                | USB_DEVICE_ID_MATCH_DEVICE, \
        .idVendor = (vend), \
        .idProduct = (prod), \
@@ -260,8 +265,13 @@ static int panjit_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 
 static int mtouch_read_data(struct usbtouch_usb *dev, unsigned char *pkt)
 {
-       dev->x = (pkt[8] << 8) | pkt[7];
-       dev->y = (pkt[10] << 8) | pkt[9];
+       if (hwcalib_xy) {
+               dev->x = (pkt[4] << 8) | pkt[3];
+               dev->y = 0xffff - ((pkt[6] << 8) | pkt[5]);
+       } else {
+               dev->x = (pkt[8] << 8) | pkt[7];
+               dev->y = (pkt[10] << 8) | pkt[9];
+       }
        dev->touch = (pkt[2] & 0x40) ? 1 : 0;
 
        return 1;
@@ -294,6 +304,12 @@ static int mtouch_init(struct usbtouch_usb *usbtouch)
                        return ret;
        }
 
+       /* Default min/max xy are the raw values, override if using hw-calib */
+       if (hwcalib_xy) {
+               input_set_abs_params(usbtouch->input, ABS_X, 0, 0xffff, 0, 0);
+               input_set_abs_params(usbtouch->input, ABS_Y, 0, 0xffff, 0, 0);
+       }
+
        return 0;
 }
 #endif
index 1bd8960ead3398654970dd627f516f3f8a7a1f3c..fea5b783335d5ba8ead97d03e93dfc0cfdc112a7 100644 (file)
@@ -257,9 +257,9 @@ act2000_isa_receive(act2000_card *card)
                                        printk(KERN_WARNING
                                               "act2000_isa_receive: Invalid CAPI msg\n");
                                        {
-                                               int i; __u8 *p; __u8 *c; __u8 tmp[30];
-                                               for (i = 0, p = (__u8 *)&card->idat.isa.rcvhdr, c = tmp; i < 8; i++)
-                                                       c += sprintf(c, "%02x ", *(p++));
+                                               int i; __u8 *p; __u8 *t; __u8 tmp[30];
+                                               for (i = 0, p = (__u8 *)&card->idat.isa.rcvhdr, t = tmp; i < 8; i++)
+                                                       t += sprintf(t, "%02x ", *(p++));
                                                printk(KERN_WARNING "act2000_isa_receive: %s\n", tmp);
                                        }
                                }
index 1b5bf87c4cf4719cd66e75575d3b97250e368e06..3e468d2cf730b0467c44de5403b4c7efaab58933 100644 (file)
@@ -277,7 +277,7 @@ static void capiminor_free(struct capiminor *mp)
        list_del(&mp->list);
        write_unlock_irqrestore(&capiminor_list_lock, flags);
 
-       if (mp->ttyskb) kfree_skb(mp->ttyskb);
+       kfree_skb(mp->ttyskb);
        mp->ttyskb = NULL;
        skb_queue_purge(&mp->inqueue);
        skb_queue_purge(&mp->outqueue);
index c29208bd752131e9d8406c193a48f2a5982df272..50ed778f63fc84cd3c31da19a15b1f6bd60f5754 100644 (file)
@@ -239,6 +239,7 @@ static const struct file_operations proc_applstats_ops = {
 // ---------------------------------------------------------------------------
 
 static void *capi_driver_start(struct seq_file *seq, loff_t *pos)
+       __acquires(&capi_drivers_list_lock)
 {
        read_lock(&capi_drivers_list_lock);
        return seq_list_start(&capi_drivers, *pos);
@@ -250,6 +251,7 @@ static void *capi_driver_next(struct seq_file *seq, void *v, loff_t *pos)
 }
 
 static void capi_driver_stop(struct seq_file *seq, void *v)
+       __releases(&capi_drivers_list_lock)
 {
        read_unlock(&capi_drivers_list_lock);
 }
index 0017e50c6948d853438dc7fe1d80353693d6bf2f..9ca889adf120123010b343bf59f63dacfad17bdc 100644 (file)
@@ -1,5 +1,5 @@
 menuconfig ISDN_DRV_GIGASET
-       tristate "Siemens Gigaset support (isdn)"
+       tristate "Siemens Gigaset support"
        select CRC_CCITT
        select BITREVERSE
        help
@@ -11,11 +11,11 @@ menuconfig ISDN_DRV_GIGASET
          one of the connection specific parts that follow.
          This will build a module called "gigaset".
 
-if ISDN_DRV_GIGASET!=n
+if ISDN_DRV_GIGASET
 
 config GIGASET_BASE
        tristate "Gigaset base station support"
-       depends on ISDN_DRV_GIGASET && USB
+       depends on USB
        help
          Say M here if you want to use the USB interface of the Gigaset
          base for connection to your system.
@@ -23,7 +23,7 @@ config GIGASET_BASE
 
 config GIGASET_M105
        tristate "Gigaset M105 support"
-       depends on ISDN_DRV_GIGASET && USB
+       depends on USB
        help
          Say M here if you want to connect to the Gigaset base via DECT
          using a Gigaset M105 (Sinus 45 Data 2) USB DECT device.
@@ -31,7 +31,6 @@ config GIGASET_M105
 
 config GIGASET_M101
        tristate "Gigaset M101 support"
-       depends on ISDN_DRV_GIGASET
        help
          Say M here if you want to connect to the Gigaset base via DECT
          using a Gigaset M101 (Sinus 45 Data 1) RS232 DECT device.
@@ -48,7 +47,6 @@ config GIGASET_UNDOCREQ
        help
          This enables support for USB requests we only know from
          reverse engineering (currently M105 only). If you need
-         features like configuration mode of M105, say yes. If you
-         care about your device, say no.
+         features like configuration mode of M105, say yes.
 
-endif # ISDN_DRV_GIGASET != n
+endif # ISDN_DRV_GIGASET
index 18dd8aacbe8d4157bee715943ab0612873c2b75c..831ddce1467bd162c1e875b7c019e6cf2f3c420d 100644 (file)
@@ -46,6 +46,9 @@ MODULE_PARM_DESC(cidmode, "Call-ID mode");
 /* length limit according to Siemens 3070usb-protokoll.doc ch. 2.1 */
 #define IF_WRITEBUF 264
 
+/* interrupt pipe message size according to ibid. ch. 2.2 */
+#define IP_MSGSIZE 3
+
 /* Values for the Gigaset 307x */
 #define USB_GIGA_VENDOR_ID      0x0681
 #define USB_3070_PRODUCT_ID     0x0001
@@ -110,7 +113,7 @@ struct bas_cardstate {
        unsigned char           *rcvbuf;        /* AT reply receive buffer */
 
        struct urb              *urb_int_in;    /* URB for interrupt pipe */
-       unsigned char           int_in_buf[3];
+       unsigned char           *int_in_buf;
 
        spinlock_t              lock;           /* locks all following */
        int                     basstate;       /* bitmap (BS_*) */
@@ -657,7 +660,7 @@ static void read_int_callback(struct urb *urb)
        }
 
        /* drop incomplete packets even if the missing bytes wouldn't matter */
-       if (unlikely(urb->actual_length < 3)) {
+       if (unlikely(urb->actual_length < IP_MSGSIZE)) {
                dev_warn(cs->dev, "incomplete interrupt packet (%d bytes)\n",
                         urb->actual_length);
                goto resubmit;
@@ -2127,6 +2130,7 @@ static void gigaset_reinitbcshw(struct bc_state *bcs)
 static void gigaset_freecshw(struct cardstate *cs)
 {
        /* timers, URBs and rcvbuf are disposed of in disconnect */
+       kfree(cs->hw.bas->int_in_buf);
        kfree(cs->hw.bas);
        cs->hw.bas = NULL;
 }
@@ -2140,6 +2144,12 @@ static int gigaset_initcshw(struct cardstate *cs)
                pr_err("out of memory\n");
                return 0;
        }
+       ucs->int_in_buf = kmalloc(IP_MSGSIZE, GFP_KERNEL);
+       if (!ucs->int_in_buf) {
+               kfree(ucs);
+               pr_err("out of memory\n");
+               return 0;
+       }
 
        ucs->urb_cmd_in = NULL;
        ucs->urb_cmd_out = NULL;
@@ -2292,7 +2302,7 @@ static int gigaset_probe(struct usb_interface *interface,
        usb_fill_int_urb(ucs->urb_int_in, udev,
                         usb_rcvintpipe(udev,
                                        (endpoint->bEndpointAddress) & 0x0f),
-                        ucs->int_in_buf, 3, read_int_callback, cs,
+                        ucs->int_in_buf, IP_MSGSIZE, read_int_callback, cs,
                         endpoint->bInterval);
        if ((rc = usb_submit_urb(ucs->urb_int_in, GFP_KERNEL)) != 0) {
                dev_err(cs->dev, "could not submit interrupt URB: %s\n",
index fba61f6705278250139bc2ac94e51f2409b025f5..d7838516609997b67b41610f3a6d8fca8f2df221 100644 (file)
@@ -278,17 +278,17 @@ static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
 static int gigaset_set_modem_ctrl(struct cardstate *cs, unsigned old_state,
                                  unsigned new_state)
 {
-       return -EINVAL;
+       return -ENOTTY;
 }
 
 static int gigaset_set_line_ctrl(struct cardstate *cs, unsigned cflag)
 {
-       return -EINVAL;
+       return -ENOTTY;
 }
 
 static int gigaset_baud_rate(struct cardstate *cs, unsigned cflag)
 {
-       return -EINVAL;
+       return -ENOTTY;
 }
 #endif
 
@@ -577,7 +577,7 @@ static int gigaset_brkchars(struct cardstate *cs, const unsigned char buf[6])
        return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x19, 0x41,
                               0, 0, &buf, 6, 2000);
 #else
-       return -EINVAL;
+       return -ENOTTY;
 #endif
 }
 
index 84318ec8d13eefc65d23e7b99764da500b395d88..33ce89eed65bde2715ad1abab81c4ba7d6592673 100644 (file)
@@ -1198,7 +1198,7 @@ int SuperTraceASSIGN (void* AdapterHandle, byte* data) {
         pC->xbuffer[5] = (byte)(rx_dma_magic >>  8);
         pC->xbuffer[6] = (byte)(rx_dma_magic >> 16);
         pC->xbuffer[7] = (byte)(rx_dma_magic >> 24);
-        pC->xbuffer[8] = (byte)DIVA_MAX_MANAGEMENT_TRANSFER_SIZE;
+       pC->xbuffer[8] = (byte)(DIVA_MAX_MANAGEMENT_TRANSFER_SIZE & 0xFF);
         pC->xbuffer[9] = (byte)(DIVA_MAX_MANAGEMENT_TRANSFER_SIZE >> 8);
         pC->xbuffer[10] = 0;
 
index 4cc94f200b724a2843333bb29a87c2bc4c5f0934..31f91c18c69871061606ee3fd30ea09a0e0ea452 100644 (file)
@@ -1194,7 +1194,8 @@ static char hex_digit_table[0x10] =
 /* translation function for each message                            */
 /*------------------------------------------------------------------*/
 
-byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+static byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                       PLCI *plci, APPL *appl, API_PARSE *parms)
 {
   word ch;
   word i;
@@ -1411,7 +1412,8 @@ byte connect_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci,
   return 2;
 }
 
-byte connect_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+static byte connect_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                       PLCI *plci, APPL *appl, API_PARSE *parms)
 {
   word i, Info;
   word Reject;
@@ -1567,13 +1569,15 @@ byte connect_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci,
   return 1;
 }
 
-byte connect_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+static byte connect_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                         PLCI *plci, APPL *appl, API_PARSE *msg)
 {
   dbug(1,dprintf("connect_a_res"));
   return false;
 }
 
-byte disconnect_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+static byte disconnect_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                          PLCI *plci, APPL *appl, API_PARSE *msg)
 {
   word Info;
   word i;
@@ -1628,7 +1632,8 @@ byte disconnect_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plc
   return false;
 }
 
-byte disconnect_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+static byte disconnect_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                          PLCI *plci, APPL *appl, API_PARSE *msg)
 {
   dbug(1,dprintf("disconnect_res"));
   if(plci)
@@ -1655,7 +1660,8 @@ byte disconnect_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plc
   return 0;
 }
 
-byte listen_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+static byte listen_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                      PLCI *plci, APPL *appl, API_PARSE *parms)
 {
   word Info;
   byte i;
@@ -1704,7 +1710,8 @@ byte listen_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, A
   return false;
 }
 
-byte info_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+static byte info_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                    PLCI *plci, APPL *appl, API_PARSE *msg)
 {
   word i;
   API_PARSE * ai;
@@ -1813,13 +1820,15 @@ byte info_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APP
   return false;
 }
 
-byte info_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+static byte info_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                    PLCI *plci, APPL *appl, API_PARSE *msg)
 {
   dbug(1,dprintf("info_res"));
   return false;
 }
 
-byte alert_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+static byte alert_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                     PLCI *plci, APPL *appl, API_PARSE *msg)
 {
   word Info;
   byte ret;
@@ -1849,7 +1858,8 @@ byte alert_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, AP
   return ret;
 }
 
-byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+static byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                        PLCI *plci, APPL *appl, API_PARSE *msg)
 {
   word Info = 0;
   word i    = 0;
@@ -2599,13 +2609,15 @@ byte facility_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci,
   return false;
 }
 
-byte facility_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+static byte facility_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                        PLCI *plci, APPL *appl, API_PARSE *msg)
 {
   dbug(1,dprintf("facility_res"));
   return false;
 }
 
-byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+static byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                          PLCI *plci, APPL *appl, API_PARSE *parms)
 {
   word Info = 0;
   byte req;
@@ -2839,7 +2851,8 @@ byte connect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plc
   return false;
 }
 
-byte connect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+static byte connect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                          PLCI *plci, APPL *appl, API_PARSE *parms)
 {
   word ncci;
   API_PARSE * ncpi;
@@ -2954,7 +2967,8 @@ byte connect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plc
   return false;
 }
 
-byte connect_b3_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+static byte connect_b3_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                            PLCI *plci, APPL *appl, API_PARSE *parms)
 {
   word ncci;
 
@@ -2974,7 +2988,8 @@ byte connect_b3_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * p
   return false;
 }
 
-byte disconnect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+static byte disconnect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                             PLCI *plci, APPL *appl, API_PARSE *parms)
 {
   word Info;
   word ncci;
@@ -3030,7 +3045,8 @@ byte disconnect_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   *
   return false;
 }
 
-byte disconnect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+static byte disconnect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                             PLCI *plci, APPL *appl, API_PARSE *parms)
 {
   word ncci;
   word i;
@@ -3086,7 +3102,8 @@ byte disconnect_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   *
   return false;
 }
 
-byte data_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+static byte data_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                       PLCI *plci, APPL *appl, API_PARSE *parms)
 {
   NCCI   *ncci_ptr;
   DATA_B3_DESC   *data;
@@ -3163,7 +3180,8 @@ byte data_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci,
   return false;
 }
 
-byte data_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+static byte data_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                       PLCI *plci, APPL *appl, API_PARSE *parms)
 {
   word n;
   word ncci;
@@ -3196,7 +3214,8 @@ byte data_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci,
   return false;
 }
 
-byte reset_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+static byte reset_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                        PLCI *plci, APPL *appl, API_PARSE *parms)
 {
   word Info;
   word ncci;
@@ -3237,7 +3256,8 @@ byte reset_b3_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci,
   return false;
 }
 
-byte reset_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+static byte reset_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                        PLCI *plci, APPL *appl, API_PARSE *parms)
 {
   word ncci;
 
@@ -3261,7 +3281,8 @@ byte reset_b3_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci,
   return false;
 }
 
-byte connect_b3_t90_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * parms)
+static byte connect_b3_t90_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                                PLCI *plci, APPL *appl, API_PARSE *parms)
 {
   word ncci;
   API_PARSE * ncpi;
@@ -3295,7 +3316,8 @@ byte connect_b3_t90_a_res(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI
 }
 
 
-byte select_b_req(dword Id, word Number, DIVA_CAPI_ADAPTER   * a, PLCI   * plci, APPL   * appl, API_PARSE * msg)
+static byte select_b_req(dword Id, word Number, DIVA_CAPI_ADAPTER *a,
+                        PLCI *plci, APPL *appl, API_PARSE *msg)
 {
   word Info=0;
   word i;
@@ -8689,7 +8711,7 @@ static word add_modem_b23 (PLCI  * plci, API_PARSE* bp_parms)
 /* send a request for the signaling entity                          */
 /*------------------------------------------------------------------*/
 
-void sig_req(PLCI   * plci, byte req, byte Id)
+static void sig_req(PLCI *plci, byte req, byte Id)
 {
   if(!plci) return;
   if(plci->adapter->adapter_disabled) return;
@@ -8789,7 +8811,7 @@ static void send_req(PLCI *plci)
   dbug(1,dprintf("send_ok"));
 }
 
-void send_data(PLCI   * plci)
+static void send_data(PLCI *plci)
 {
   DIVA_CAPI_ADAPTER   * a;
   DATA_B3_DESC   * data;
index 7c56c44f0fd16955be1e7c488bfc862e709f24a1..025a20d487c5df71a8f42d7babc6fc696d308737 100644 (file)
@@ -24,7 +24,6 @@
 const char *lli_revision = "$Revision: 2.59.2.4 $";
 
 extern struct IsdnCard cards[];
-extern int nrcards;
 
 static int init_b_st(struct Channel *chanp, int incoming);
 static void release_b_st(struct Channel *chanp);
index ded9d0baf607b0daa8450c1b0e7bad775285e048..4fab18d4d02fecf84e42d7da99c4ef1d318a877f 100644 (file)
@@ -361,12 +361,6 @@ module_param_array(io1, int, NULL, 0);
 
 int nrcards;
 
-extern const char *l1_revision;
-extern const char *l2_revision;
-extern const char *l3_revision;
-extern const char *lli_revision;
-extern const char *tei_revision;
-
 char *HiSax_getrev(const char *revision)
 {
        char *rev;
index cf082665cc8bb36022cc671c2c57b22234f2aa8e..20d7688b397baee6d9c6b3056f1c142bb4a548a2 100644 (file)
@@ -16,8 +16,6 @@
 #include "hfc_2bds0.h"
 #include "isdnl1.h"
 
-extern const char *CardType[];
-
 static const char *hfcs_revision = "$Revision: 1.10.2.4 $";
 
 static irqreturn_t
index e8d429fda846847fd4a6e0063e9a8efd1742615c..f8527046f1973a879a8a07d8111972ea3a0422ea 100644 (file)
 
 #ifdef __KERNEL__
 
+extern const char *CardType[];
+extern int nrcards;
+
+extern const char *l1_revision;
+extern const char *l2_revision;
+extern const char *l3_revision;
+extern const char *lli_revision;
+extern const char *tei_revision;
+
 /* include l3dss1 & ni1 specific process structures, but no other defines */
 #ifdef CONFIG_HISAX_EURO
   #define l3dss1_process
index a14204ec88eec7990aeadbe332b7406840a2bbd3..317f16f516f242b6468ba5cd59c47862e6c36a0a 100644 (file)
  *
  */
 
-const char *l1_revision = "$Revision: 2.46.2.5 $";
-
 #include <linux/init.h>
 #include "hisax.h"
 #include "isdnl1.h"
 
+const char *l1_revision = "$Revision: 2.46.2.5 $";
+
 #define TIMER3_VALUE 7000
 
 static struct Fsm l1fsm_b;
index a10dfa82c734d815f7018ab3cf9932fabdee03fd..5569a522e2a13c998f305c730c361d0809a0d8f4 100644 (file)
@@ -48,8 +48,6 @@
 #include <linux/pci.h>
 #include <linux/isapnp.h>
 
-extern const char *CardType[];
-
 static const char *Sedlbauer_revision = "$Revision: 1.34.2.6 $";
 
 static const char *Sedlbauer_Types[] =
index 48581335f43c991fab4f415e5c7942cc0105022a..3ca0bed1b88cab005b8a899b109ec03632038248 100644 (file)
@@ -21,8 +21,6 @@
 #include "isac.h"
 #include "hscx.h"
 
-extern const char *CardType[];
-
 static const char *teles0_revision = "$Revision: 2.15.2.4 $";
 
 #define TELES_IOMEM_SIZE       0x400
index 5dc9f1a436291e8c3ddacb42127da72dd4cc3fff..e9f5bb4cdffaabe64f2adf7cc76519d9088e4a78 100644 (file)
@@ -20,7 +20,6 @@
 #include "hscx.h"
 #include "isdnl1.h"
 
-extern const char *CardType[];
 static const char *teles3_revision = "$Revision: 2.19.2.4 $";
 
 #define byteout(addr,val) outb(val,addr)
index f2b32186d4a19f2fbec632b5a7cf7c915a94134a..bbd99d3282c0cf32299086fe8575450ca042b75f 100644 (file)
@@ -152,8 +152,7 @@ dev_expire_timer(unsigned long data)
        u_long                  flags;
 
        spin_lock_irqsave(&timer->dev->lock, flags);
-       list_del(&timer->list);
-       list_add_tail(&timer->list, &timer->dev->expired);
+       list_move_tail(&timer->list, &timer->dev->expired);
        spin_unlock_irqrestore(&timer->dev->lock, flags);
        wake_up_interruptible(&timer->dev->wait);
 }
index 5ba2a879df1447e42bcead890600ba9c51ed9800..e075e8d2fce044a445720e39f97c61b71870d5f7 100644 (file)
@@ -347,8 +347,7 @@ pcbit_receive(struct pcbit_dev *dev)
                if (dev->read_frame) {
                        printk(KERN_DEBUG "pcbit_receive: Type 0 frame and read_frame != NULL\n");
                        /* discard previous queued frame */
-                       if (dev->read_frame->skb)
-                               kfree_skb(dev->read_frame->skb);
+                       kfree_skb(dev->read_frame->skb);
                        kfree(dev->read_frame);
                        dev->read_frame = NULL;
                }
@@ -601,8 +600,7 @@ pcbit_l2_err_recover(unsigned long data)
        dev->w_busy = dev->r_busy = 1;
 
        if (dev->read_frame) {
-               if (dev->read_frame->skb)
-                       kfree_skb(dev->read_frame->skb);
+               kfree_skb(dev->read_frame->skb);
                kfree(dev->read_frame);
                dev->read_frame = NULL;
        }
index 712220cef139469f93bd82ad5c97239c932d4841..7f16d75d2d89fa1137cad8651e765eb9b4a512e2 100644 (file)
@@ -54,7 +54,7 @@ void memcpy_toshmem(int card, void *dest, const void *src, size_t n)
        spin_unlock_irqrestore(&sc_adapter[card]->lock, flags);
        pr_debug("%s: set page to %#x\n",sc_adapter[card]->devicename,
                ((sc_adapter[card]->shmem_magic + ch * SRAM_PAGESIZE)>>14)|0x80);
-       pr_debug("%s: copying %d bytes from %#lx to %#lx\n",
+       pr_debug("%s: copying %zu bytes from %#lx to %#lx\n",
                sc_adapter[card]->devicename, n,
                (unsigned long) src,
                sc_adapter[card]->rambase + ((unsigned long) dest %0x4000));
index a34338567a2a601c3cdbda72441d54299301f89a..f14813be4eff88ccdc082b62336690e20b0342cb 100644 (file)
@@ -328,7 +328,7 @@ static void dispatch_io(int rw, unsigned int num_regions,
        struct dpages old_pages = *dp;
 
        if (sync)
-               rw |= (1 << BIO_RW_SYNC);
+               rw |= (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG);
 
        /*
         * For multiple regions we need to be careful to rewind
index 3073618269ea3030e468541ea2af6f05dd2aac65..0a225da21272543c33b4992a9bf1c83b923b8bbf 100644 (file)
@@ -344,7 +344,7 @@ static int run_io_job(struct kcopyd_job *job)
 {
        int r;
        struct dm_io_request io_req = {
-               .bi_rw = job->rw | (1 << BIO_RW_SYNC),
+               .bi_rw = job->rw | (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG),
                .mem.type = DM_IO_PAGE_LIST,
                .mem.ptr.pl = job->pages,
                .mem.offset = job->offset,
index 4495104f6c9f33297727891510e667db46ac29ac..03b4cd0a6344cf2e458a035325eb2ec7ffc8805a 100644 (file)
@@ -474,7 +474,7 @@ void md_super_write(mddev_t *mddev, mdk_rdev_t *rdev,
         * causes ENOTSUPP, we allocate a spare bio...
         */
        struct bio *bio = bio_alloc(GFP_NOIO, 1);
-       int rw = (1<<BIO_RW) | (1<<BIO_RW_SYNC);
+       int rw = (1<<BIO_RW) | (1<<BIO_RW_SYNCIO) | (1<<BIO_RW_UNPLUG);
 
        bio->bi_bdev = rdev->bdev;
        bio->bi_sector = sector;
@@ -531,7 +531,7 @@ int sync_page_io(struct block_device *bdev, sector_t sector, int size,
        struct completion event;
        int ret;
 
-       rw |= (1 << BIO_RW_SYNC);
+       rw |= (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG);
 
        bio->bi_bdev = bdev;
        bio->bi_sector = sector;
index 01e3cffd03b8fd28dae613614f3efd10c04f2416..e2466425d9cad798edf40858183404408b319e3d 100644 (file)
@@ -1237,8 +1237,9 @@ static void end_sync_write(struct bio *bio, int error)
        update_head_pos(mirror, r1_bio);
 
        if (atomic_dec_and_test(&r1_bio->remaining)) {
-               md_done_sync(mddev, r1_bio->sectors, uptodate);
+               sector_t s = r1_bio->sectors;
                put_buf(r1_bio);
+               md_done_sync(mddev, s, uptodate);
        }
 }
 
index 6736d6dff981c8a1a5c12e773c3d788410a0f191..7301631abe0453a4791dec55ba0eff84912876c3 100644 (file)
@@ -1236,6 +1236,7 @@ static void end_sync_read(struct bio *bio, int error)
        /* for reconstruct, we always reschedule after a read.
         * for resync, only after all reads
         */
+       rdev_dec_pending(conf->mirrors[d].rdev, conf->mddev);
        if (test_bit(R10BIO_IsRecover, &r10_bio->state) ||
            atomic_dec_and_test(&r10_bio->remaining)) {
                /* we have read all the blocks,
@@ -1243,7 +1244,6 @@ static void end_sync_read(struct bio *bio, int error)
                 */
                reschedule_retry(r10_bio);
        }
-       rdev_dec_pending(conf->mirrors[d].rdev, conf->mddev);
 }
 
 static void end_sync_write(struct bio *bio, int error)
@@ -1264,11 +1264,13 @@ static void end_sync_write(struct bio *bio, int error)
 
        update_head_pos(i, r10_bio);
 
+       rdev_dec_pending(conf->mirrors[d].rdev, mddev);
        while (atomic_dec_and_test(&r10_bio->remaining)) {
                if (r10_bio->master_bio == NULL) {
                        /* the primary of several recovery bios */
-                       md_done_sync(mddev, r10_bio->sectors, 1);
+                       sector_t s = r10_bio->sectors;
                        put_buf(r10_bio);
+                       md_done_sync(mddev, s, 1);
                        break;
                } else {
                        r10bio_t *r10_bio2 = (r10bio_t *)r10_bio->master_bio;
@@ -1276,7 +1278,6 @@ static void end_sync_write(struct bio *bio, int error)
                        r10_bio = r10_bio2;
                }
        }
-       rdev_dec_pending(conf->mirrors[d].rdev, mddev);
 }
 
 /*
@@ -1749,8 +1750,6 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
        if (!go_faster && conf->nr_waiting)
                msleep_interruptible(1000);
 
-       bitmap_cond_end_sync(mddev->bitmap, sector_nr);
-
        /* Again, very different code for resync and recovery.
         * Both must result in an r10bio with a list of bios that
         * have bi_end_io, bi_sector, bi_bdev set,
@@ -1886,6 +1885,8 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
                /* resync. Schedule a read for every block at this virt offset */
                int count = 0;
 
+               bitmap_cond_end_sync(mddev->bitmap, sector_nr);
+
                if (!bitmap_start_sync(mddev->bitmap, sector_nr,
                                       &sync_blocks, mddev->degraded) &&
                    !conf->fullsync && !test_bit(MD_RECOVERY_REQUESTED, &mddev->recovery)) {
@@ -2010,13 +2011,13 @@ static sector_t sync_request(mddev_t *mddev, sector_t sector_nr, int *skipped, i
        /* There is nowhere to write, so all non-sync
         * drives must be failed, so try the next chunk...
         */
-       {
-       sector_t sec = max_sector - sector_nr;
-       sectors_skipped += sec;
+       if (sector_nr + max_sync < max_sector)
+               max_sector = sector_nr + max_sync;
+
+       sectors_skipped += (max_sector - sector_nr);
        chunks_skipped ++;
        sector_nr = max_sector;
        goto skipped;
-       }
 }
 
 static int run(mddev_t *mddev)
index de7adaf5fa5b1d186c8c05b8c46925bea1c52d65..78412c9c424a13e492a59ad467368716755be6b2 100644 (file)
@@ -318,7 +318,6 @@ static int simple_std_setup(struct dvb_frontend *fe,
                            u8 *config, u8 *cb)
 {
        struct tuner_simple_priv *priv = fe->tuner_priv;
-       u8 tuneraddr;
        int rc;
 
        /* tv norm specific stuff for multi-norm tuners */
@@ -387,6 +386,7 @@ static int simple_std_setup(struct dvb_frontend *fe,
 
        case TUNER_PHILIPS_TUV1236D:
        {
+               struct tuner_i2c_props i2c = priv->i2c_props;
                /* 0x40 -> ATSC antenna input 1 */
                /* 0x48 -> ATSC antenna input 2 */
                /* 0x00 -> NTSC antenna input 1 */
@@ -398,17 +398,15 @@ static int simple_std_setup(struct dvb_frontend *fe,
                        buffer[1] = 0x04;
                }
                /* set to the correct mode (analog or digital) */
-               tuneraddr = priv->i2c_props.addr;
-               priv->i2c_props.addr = 0x0a;
-               rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[0], 2);
+               i2c.addr = 0x0a;
+               rc = tuner_i2c_xfer_send(&i2c, &buffer[0], 2);
                if (2 != rc)
                        tuner_warn("i2c i/o error: rc == %d "
                                   "(should be 2)\n", rc);
-               rc = tuner_i2c_xfer_send(&priv->i2c_props, &buffer[2], 2);
+               rc = tuner_i2c_xfer_send(&i2c, &buffer[2], 2);
                if (2 != rc)
                        tuner_warn("i2c i/o error: rc == %d "
                                   "(should be 2)\n", rc);
-               priv->i2c_props.addr = tuneraddr;
                break;
        }
        }
index 40ebde53b3ce22443a60be62357c5722f64f256d..b0198691892a4a4ecab85d7febccf554c5dfe381 100644 (file)
@@ -51,6 +51,10 @@ comment "Supported SDMC DM1105 Adapters"
        depends on DVB_CORE && PCI && I2C
 source "drivers/media/dvb/dm1105/Kconfig"
 
+comment "Supported FireWire (IEEE 1394) Adapters"
+       depends on DVB_CORE && IEEE1394
+source "drivers/media/dvb/firewire/Kconfig"
+
 comment "Supported DVB Frontends"
        depends on DVB_CORE
 source "drivers/media/dvb/frontends/Kconfig"
index f91e9eb15e52effa8e9f15d1e0e2e4573beeae59..6092a5bb5a7d8901562e4efee7868cb003819d4f 100644 (file)
@@ -3,3 +3,5 @@
 #
 
 obj-y        := dvb-core/ frontends/ ttpci/ ttusb-dec/ ttusb-budget/ b2c2/ bt8xx/ dvb-usb/ pluto2/ siano/ dm1105/
+
+obj-$(CONFIG_DVB_FIREDTV)      += firewire/
index b386cc66c6b31e3b89a2b982e5ad8efede9fdead..451974ba32f37adb656356291146716c8358d819 100644 (file)
@@ -192,6 +192,7 @@ int flexcop_pid_feed_control(struct flexcop_device *fc, struct dvb_demux_feed *d
 
        return 0;
 }
+EXPORT_SYMBOL(flexcop_pid_feed_control);
 
 void flexcop_hw_filter_init(struct flexcop_device *fc)
 {
index 5b30dfc7846b2fbbe870efb38901e311c3bc2375..76e37fd96bb6a3995e1ec301b36d166f507e54d3 100644 (file)
@@ -13,9 +13,9 @@ static int enable_pid_filtering = 1;
 module_param(enable_pid_filtering, int, 0444);
 MODULE_PARM_DESC(enable_pid_filtering, "enable hardware pid filtering: supported values: 0 (fullts), 1");
 
-static int irq_chk_intv;
+static int irq_chk_intv = 100;
 module_param(irq_chk_intv, int, 0644);
-MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently just debugging).");
+MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ streaming watchdog.");
 
 #ifdef CONFIG_DVB_B2C2_FLEXCOP_DEBUG
 #define dprintk(level,args...) \
@@ -34,7 +34,9 @@ MODULE_PARM_DESC(irq_chk_intv, "set the interval for IRQ watchdog (currently jus
 
 static int debug;
 module_param(debug, int, 0644);
-MODULE_PARM_DESC(debug, "set debug level (1=info,2=regs,4=TS,8=irqdma (|-able))." DEBSTATUS);
+MODULE_PARM_DESC(debug,
+       "set debug level (1=info,2=regs,4=TS,8=irqdma,16=check (|-able))."
+        DEBSTATUS);
 
 #define DRIVER_VERSION "0.1"
 #define DRIVER_NAME "Technisat/B2C2 FlexCop II/IIb/III Digital TV PCI Driver"
@@ -58,6 +60,8 @@ struct flexcop_pci {
        int active_dma1_addr; /* 0 = addr0 of dma1; 1 = addr1 of dma1 */
        u32 last_dma1_cur_pos; /* position of the pointer last time the timer/packet irq occured */
        int count;
+       int count_prev;
+       int stream_problem;
 
        spinlock_t irq_lock;
 
@@ -103,18 +107,32 @@ static void flexcop_pci_irq_check_work(struct work_struct *work)
                container_of(work, struct flexcop_pci, irq_check_work.work);
        struct flexcop_device *fc = fc_pci->fc_dev;
 
-       flexcop_ibi_value v = fc->read_ibi_reg(fc,sram_dest_reg_714);
-
-       flexcop_dump_reg(fc_pci->fc_dev,dma1_000,4);
-
-       if (v.sram_dest_reg_714.net_ovflow_error)
-               deb_chk("sram net_ovflow_error\n");
-       if (v.sram_dest_reg_714.media_ovflow_error)
-               deb_chk("sram media_ovflow_error\n");
-       if (v.sram_dest_reg_714.cai_ovflow_error)
-               deb_chk("sram cai_ovflow_error\n");
-       if (v.sram_dest_reg_714.cai_ovflow_error)
-               deb_chk("sram cai_ovflow_error\n");
+       if (fc->feedcount) {
+
+               if (fc_pci->count == fc_pci->count_prev) {
+                       deb_chk("no IRQ since the last check\n");
+                       if (fc_pci->stream_problem++ == 3) {
+                               struct dvb_demux_feed *feed;
+
+                               spin_lock_irq(&fc->demux.lock);
+                               list_for_each_entry(feed, &fc->demux.feed_list,
+                                       list_head) {
+                                       flexcop_pid_feed_control(fc, feed, 0);
+                               }
+
+                               list_for_each_entry(feed, &fc->demux.feed_list,
+                                       list_head) {
+                                       flexcop_pid_feed_control(fc, feed, 1);
+                               }
+                               spin_unlock_irq(&fc->demux.lock);
+
+                               fc_pci->stream_problem = 0;
+                       }
+               } else {
+                       fc_pci->stream_problem = 0;
+                       fc_pci->count_prev = fc_pci->count;
+               }
+       }
 
        schedule_delayed_work(&fc_pci->irq_check_work,
                        msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
@@ -216,16 +234,12 @@ static int flexcop_pci_stream_control(struct flexcop_device *fc, int onoff)
                flexcop_dma_control_timer_irq(fc,FC_DMA_1,1);
                deb_irq("IRQ enabled\n");
 
+               fc_pci->count_prev = fc_pci->count;
+
 //             fc_pci->active_dma1_addr = 0;
 //             flexcop_dma_control_size_irq(fc,FC_DMA_1,1);
 
-               if (irq_chk_intv > 0)
-                       schedule_delayed_work(&fc_pci->irq_check_work,
-                                       msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
        } else {
-               if (irq_chk_intv > 0)
-                       cancel_delayed_work(&fc_pci->irq_check_work);
-
                flexcop_dma_control_timer_irq(fc,FC_DMA_1,0);
                deb_irq("IRQ disabled\n");
 
@@ -299,8 +313,6 @@ static int flexcop_pci_init(struct flexcop_pci *fc_pci)
                                        IRQF_SHARED, DRIVER_NAME, fc_pci)) != 0)
                goto err_pci_iounmap;
 
-
-
        fc_pci->init_state |= FC_PCI_INIT;
        return ret;
 
@@ -375,6 +387,10 @@ static int flexcop_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
 
        INIT_DELAYED_WORK(&fc_pci->irq_check_work, flexcop_pci_irq_check_work);
 
+               if (irq_chk_intv > 0)
+                       schedule_delayed_work(&fc_pci->irq_check_work,
+               msecs_to_jiffies(irq_chk_intv < 100 ? 100 : irq_chk_intv));
+
        return ret;
 
 err_fc_exit:
@@ -393,6 +409,9 @@ static void flexcop_pci_remove(struct pci_dev *pdev)
 {
        struct flexcop_pci *fc_pci = pci_get_drvdata(pdev);
 
+       if (irq_chk_intv > 0)
+               cancel_delayed_work(&fc_pci->irq_check_work);
+
        flexcop_pci_dma_exit(fc_pci);
        flexcop_device_exit(fc_pci->fc_dev);
        flexcop_pci_exit(fc_pci);
index 676413a915b45c3302995dfe82d49d283843c625..91068952b502b753a349467c78927ae75ce8a670 100644 (file)
@@ -212,8 +212,7 @@ void flexcop_reset_block_300(struct flexcop_device *fc)
        v210.sw_reset_210.Block_reset_enable = 0xb2;
 
        fc->write_ibi_reg(fc,sw_reset_210,v210);
-       msleep(1);
-
+       udelay(1000);
        fc->write_ibi_reg(fc,ctrl_208,v208_save);
 }
 
index 0c733c66a44150d7abd6afdea0acbbd760fe385b..069d847ba887c39e2f1f83eafdf7c06a07b838a7 100644 (file)
@@ -364,16 +364,15 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
                                       enum dmx_success success)
 {
        struct dmxdev_filter *dmxdevfilter = filter->priv;
-       unsigned long flags;
        int ret;
 
        if (dmxdevfilter->buffer.error) {
                wake_up(&dmxdevfilter->buffer.queue);
                return 0;
        }
-       spin_lock_irqsave(&dmxdevfilter->dev->lock, flags);
+       spin_lock(&dmxdevfilter->dev->lock);
        if (dmxdevfilter->state != DMXDEV_STATE_GO) {
-               spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
+               spin_unlock(&dmxdevfilter->dev->lock);
                return 0;
        }
        del_timer(&dmxdevfilter->timer);
@@ -392,7 +391,7 @@ static int dvb_dmxdev_section_callback(const u8 *buffer1, size_t buffer1_len,
        }
        if (dmxdevfilter->params.sec.flags & DMX_ONESHOT)
                dmxdevfilter->state = DMXDEV_STATE_DONE;
-       spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
+       spin_unlock(&dmxdevfilter->dev->lock);
        wake_up(&dmxdevfilter->buffer.queue);
        return 0;
 }
@@ -404,12 +403,11 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
 {
        struct dmxdev_filter *dmxdevfilter = feed->priv;
        struct dvb_ringbuffer *buffer;
-       unsigned long flags;
        int ret;
 
-       spin_lock_irqsave(&dmxdevfilter->dev->lock, flags);
+       spin_lock(&dmxdevfilter->dev->lock);
        if (dmxdevfilter->params.pes.output == DMX_OUT_DECODER) {
-               spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
+               spin_unlock(&dmxdevfilter->dev->lock);
                return 0;
        }
 
@@ -419,7 +417,7 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
        else
                buffer = &dmxdevfilter->dev->dvr_buffer;
        if (buffer->error) {
-               spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
+               spin_unlock(&dmxdevfilter->dev->lock);
                wake_up(&buffer->queue);
                return 0;
        }
@@ -430,7 +428,7 @@ static int dvb_dmxdev_ts_callback(const u8 *buffer1, size_t buffer1_len,
                dvb_ringbuffer_flush(buffer);
                buffer->error = ret;
        }
-       spin_unlock_irqrestore(&dmxdevfilter->dev->lock, flags);
+       spin_unlock(&dmxdevfilter->dev->lock);
        wake_up(&buffer->queue);
        return 0;
 }
index a2c1fd5d2f67b05b5b25da04cf6a8dc0d7e8da49..e2eca0b1fe7cfad6dc1215aa6d2bd1247497b93e 100644 (file)
@@ -399,9 +399,7 @@ static void dvb_dmx_swfilter_packet(struct dvb_demux *demux, const u8 *buf)
 void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
                              size_t count)
 {
-       unsigned long flags;
-
-       spin_lock_irqsave(&demux->lock, flags);
+       spin_lock(&demux->lock);
 
        while (count--) {
                if (buf[0] == 0x47)
@@ -409,17 +407,16 @@ void dvb_dmx_swfilter_packets(struct dvb_demux *demux, const u8 *buf,
                buf += 188;
        }
 
-       spin_unlock_irqrestore(&demux->lock, flags);
+       spin_unlock(&demux->lock);
 }
 
 EXPORT_SYMBOL(dvb_dmx_swfilter_packets);
 
 void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
 {
-       unsigned long flags;
        int p = 0, i, j;
 
-       spin_lock_irqsave(&demux->lock, flags);
+       spin_lock(&demux->lock);
 
        if (demux->tsbufp) {
                i = demux->tsbufp;
@@ -452,18 +449,17 @@ void dvb_dmx_swfilter(struct dvb_demux *demux, const u8 *buf, size_t count)
        }
 
 bailout:
-       spin_unlock_irqrestore(&demux->lock, flags);
+       spin_unlock(&demux->lock);
 }
 
 EXPORT_SYMBOL(dvb_dmx_swfilter);
 
 void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
 {
-       unsigned long flags;
        int p = 0, i, j;
        u8 tmppack[188];
 
-       spin_lock_irqsave(&demux->lock, flags);
+       spin_lock(&demux->lock);
 
        if (demux->tsbufp) {
                i = demux->tsbufp;
@@ -504,7 +500,7 @@ void dvb_dmx_swfilter_204(struct dvb_demux *demux, const u8 *buf, size_t count)
        }
 
 bailout:
-       spin_unlock_irqrestore(&demux->lock, flags);
+       spin_unlock(&demux->lock);
 }
 
 EXPORT_SYMBOL(dvb_dmx_swfilter_204);
diff --git a/drivers/media/dvb/firewire/Kconfig b/drivers/media/dvb/firewire/Kconfig
new file mode 100644 (file)
index 0000000..6902825
--- /dev/null
@@ -0,0 +1,22 @@
+config DVB_FIREDTV
+       tristate "FireDTV and FloppyDTV"
+       depends on DVB_CORE && IEEE1394
+       help
+         Support for DVB receivers from Digital Everywhere
+         which are connected via IEEE 1394 (FireWire).
+
+         These devices don't have an MPEG decoder built in,
+         so you need an external software decoder to watch TV.
+
+         To compile this driver as a module, say M here:
+         the module will be called firedtv.
+
+if DVB_FIREDTV
+
+config DVB_FIREDTV_IEEE1394
+       def_bool IEEE1394
+
+config DVB_FIREDTV_INPUT
+       def_bool INPUT = y || (INPUT = m && DVB_FIREDTV = m)
+
+endif # DVB_FIREDTV
diff --git a/drivers/media/dvb/firewire/Makefile b/drivers/media/dvb/firewire/Makefile
new file mode 100644 (file)
index 0000000..2034695
--- /dev/null
@@ -0,0 +1,8 @@
+obj-$(CONFIG_DVB_FIREDTV) += firedtv.o
+
+firedtv-y := firedtv-avc.o firedtv-ci.o firedtv-dvb.o firedtv-fe.o
+firedtv-$(CONFIG_DVB_FIREDTV_IEEE1394) += firedtv-1394.o
+firedtv-$(CONFIG_DVB_FIREDTV_INPUT)    += firedtv-rc.o
+
+ccflags-y += -Idrivers/media/dvb/dvb-core
+ccflags-$(CONFIG_DVB_FIREDTV_IEEE1394) += -Idrivers/ieee1394
diff --git a/drivers/media/dvb/firewire/firedtv-1394.c b/drivers/media/dvb/firewire/firedtv-1394.c
new file mode 100644 (file)
index 0000000..4e20765
--- /dev/null
@@ -0,0 +1,285 @@
+/*
+ * FireDTV driver (formerly known as FireSAT)
+ *
+ * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
+ * Copyright (C) 2007-2008 Ben Backx <ben@bbackx.com>
+ * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <linux/spinlock.h>
+#include <linux/types.h>
+
+#include <dma.h>
+#include <csr1212.h>
+#include <highlevel.h>
+#include <hosts.h>
+#include <ieee1394.h>
+#include <iso.h>
+#include <nodemgr.h>
+
+#include "firedtv.h"
+
+static LIST_HEAD(node_list);
+static DEFINE_SPINLOCK(node_list_lock);
+
+#define FIREWIRE_HEADER_SIZE   4
+#define CIP_HEADER_SIZE                8
+
+static void rawiso_activity_cb(struct hpsb_iso *iso)
+{
+       struct firedtv *f, *fdtv = NULL;
+       unsigned int i, num, packet;
+       unsigned char *buf;
+       unsigned long flags;
+       int count;
+
+       spin_lock_irqsave(&node_list_lock, flags);
+       list_for_each_entry(f, &node_list, list)
+               if (f->backend_data == iso) {
+                       fdtv = f;
+                       break;
+               }
+       spin_unlock_irqrestore(&node_list_lock, flags);
+
+       packet = iso->first_packet;
+       num = hpsb_iso_n_ready(iso);
+
+       if (!fdtv) {
+               dev_err(fdtv->device, "received at unknown iso channel\n");
+               goto out;
+       }
+
+       for (i = 0; i < num; i++, packet = (packet + 1) % iso->buf_packets) {
+               buf = dma_region_i(&iso->data_buf, unsigned char,
+                       iso->infos[packet].offset + CIP_HEADER_SIZE);
+               count = (iso->infos[packet].len - CIP_HEADER_SIZE) /
+                       (188 + FIREWIRE_HEADER_SIZE);
+
+               /* ignore empty packet */
+               if (iso->infos[packet].len <= CIP_HEADER_SIZE)
+                       continue;
+
+               while (count--) {
+                       if (buf[FIREWIRE_HEADER_SIZE] == 0x47)
+                               dvb_dmx_swfilter_packets(&fdtv->demux,
+                                               &buf[FIREWIRE_HEADER_SIZE], 1);
+                       else
+                               dev_err(fdtv->device,
+                                       "skipping invalid packet\n");
+                       buf += 188 + FIREWIRE_HEADER_SIZE;
+               }
+       }
+out:
+       hpsb_iso_recv_release_packets(iso, num);
+}
+
+static inline struct node_entry *node_of(struct firedtv *fdtv)
+{
+       return container_of(fdtv->device, struct unit_directory, device)->ne;
+}
+
+static int node_lock(struct firedtv *fdtv, u64 addr, void *data, __be32 arg)
+{
+       return hpsb_node_lock(node_of(fdtv), addr, EXTCODE_COMPARE_SWAP, data,
+                             (__force quadlet_t)arg);
+}
+
+static int node_read(struct firedtv *fdtv, u64 addr, void *data, size_t len)
+{
+       return hpsb_node_read(node_of(fdtv), addr, data, len);
+}
+
+static int node_write(struct firedtv *fdtv, u64 addr, void *data, size_t len)
+{
+       return hpsb_node_write(node_of(fdtv), addr, data, len);
+}
+
+#define FDTV_ISO_BUFFER_PACKETS 256
+#define FDTV_ISO_BUFFER_SIZE (FDTV_ISO_BUFFER_PACKETS * 200)
+
+static int start_iso(struct firedtv *fdtv)
+{
+       struct hpsb_iso *iso_handle;
+       int ret;
+
+       iso_handle = hpsb_iso_recv_init(node_of(fdtv)->host,
+                               FDTV_ISO_BUFFER_SIZE, FDTV_ISO_BUFFER_PACKETS,
+                               fdtv->isochannel, HPSB_ISO_DMA_DEFAULT,
+                               -1, /* stat.config.irq_interval */
+                               rawiso_activity_cb);
+       if (iso_handle == NULL) {
+               dev_err(fdtv->device, "cannot initialize iso receive\n");
+               return -ENOMEM;
+       }
+       fdtv->backend_data = iso_handle;
+
+       ret = hpsb_iso_recv_start(iso_handle, -1, -1, 0);
+       if (ret != 0) {
+               dev_err(fdtv->device, "cannot start iso receive\n");
+               hpsb_iso_shutdown(iso_handle);
+               fdtv->backend_data = NULL;
+       }
+       return ret;
+}
+
+static void stop_iso(struct firedtv *fdtv)
+{
+       struct hpsb_iso *iso_handle = fdtv->backend_data;
+
+       if (iso_handle != NULL) {
+               hpsb_iso_stop(iso_handle);
+               hpsb_iso_shutdown(iso_handle);
+       }
+       fdtv->backend_data = NULL;
+}
+
+static const struct firedtv_backend fdtv_1394_backend = {
+       .lock           = node_lock,
+       .read           = node_read,
+       .write          = node_write,
+       .start_iso      = start_iso,
+       .stop_iso       = stop_iso,
+};
+
+static void fcp_request(struct hpsb_host *host, int nodeid, int direction,
+                       int cts, u8 *data, size_t length)
+{
+       struct firedtv *f, *fdtv = NULL;
+       unsigned long flags;
+       int su;
+
+       if (length == 0 || (data[0] & 0xf0) != 0)
+               return;
+
+       su = data[1] & 0x7;
+
+       spin_lock_irqsave(&node_list_lock, flags);
+       list_for_each_entry(f, &node_list, list)
+               if (node_of(f)->host == host &&
+                   node_of(f)->nodeid == nodeid &&
+                   (f->subunit == su || (f->subunit == 0 && su == 0x7))) {
+                       fdtv = f;
+                       break;
+               }
+       spin_unlock_irqrestore(&node_list_lock, flags);
+
+       if (fdtv)
+               avc_recv(fdtv, data, length);
+}
+
+static int node_probe(struct device *dev)
+{
+       struct unit_directory *ud =
+                       container_of(dev, struct unit_directory, device);
+       struct firedtv *fdtv;
+       int kv_len, err;
+       void *kv_str;
+
+       kv_len = (ud->model_name_kv->value.leaf.len - 2) * sizeof(quadlet_t);
+       kv_str = CSR1212_TEXTUAL_DESCRIPTOR_LEAF_DATA(ud->model_name_kv);
+
+       fdtv = fdtv_alloc(dev, &fdtv_1394_backend, kv_str, kv_len);
+       if (!fdtv)
+               return -ENOMEM;
+
+       /*
+        * Work around a bug in udev's path_id script:  Use the fw-host's dev
+        * instead of the unit directory's dev as parent of the input device.
+        */
+       err = fdtv_register_rc(fdtv, dev->parent->parent);
+       if (err)
+               goto fail_free;
+
+       spin_lock_irq(&node_list_lock);
+       list_add_tail(&fdtv->list, &node_list);
+       spin_unlock_irq(&node_list_lock);
+
+       err = avc_identify_subunit(fdtv);
+       if (err)
+               goto fail;
+
+       err = fdtv_dvb_register(fdtv);
+       if (err)
+               goto fail;
+
+       avc_register_remote_control(fdtv);
+       return 0;
+fail:
+       spin_lock_irq(&node_list_lock);
+       list_del(&fdtv->list);
+       spin_unlock_irq(&node_list_lock);
+       fdtv_unregister_rc(fdtv);
+fail_free:
+       kfree(fdtv);
+       return err;
+}
+
+static int node_remove(struct device *dev)
+{
+       struct firedtv *fdtv = dev->driver_data;
+
+       fdtv_dvb_unregister(fdtv);
+
+       spin_lock_irq(&node_list_lock);
+       list_del(&fdtv->list);
+       spin_unlock_irq(&node_list_lock);
+
+       cancel_work_sync(&fdtv->remote_ctrl_work);
+       fdtv_unregister_rc(fdtv);
+
+       kfree(fdtv);
+       return 0;
+}
+
+static int node_update(struct unit_directory *ud)
+{
+       struct firedtv *fdtv = ud->device.driver_data;
+
+       if (fdtv->isochannel >= 0)
+               cmp_establish_pp_connection(fdtv, fdtv->subunit,
+                                           fdtv->isochannel);
+       return 0;
+}
+
+static struct hpsb_protocol_driver fdtv_driver = {
+       .name           = "firedtv",
+       .update         = node_update,
+       .driver         = {
+               .probe  = node_probe,
+               .remove = node_remove,
+       },
+};
+
+static struct hpsb_highlevel fdtv_highlevel = {
+       .name           = "firedtv",
+       .fcp_request    = fcp_request,
+};
+
+int __init fdtv_1394_init(struct ieee1394_device_id id_table[])
+{
+       int ret;
+
+       hpsb_register_highlevel(&fdtv_highlevel);
+       fdtv_driver.id_table = id_table;
+       ret = hpsb_register_protocol(&fdtv_driver);
+       if (ret) {
+               printk(KERN_ERR "firedtv: failed to register protocol\n");
+               hpsb_unregister_highlevel(&fdtv_highlevel);
+       }
+       return ret;
+}
+
+void __exit fdtv_1394_exit(void)
+{
+       hpsb_unregister_protocol(&fdtv_driver);
+       hpsb_unregister_highlevel(&fdtv_highlevel);
+}
diff --git a/drivers/media/dvb/firewire/firedtv-avc.c b/drivers/media/dvb/firewire/firedtv-avc.c
new file mode 100644 (file)
index 0000000..b55d9cc
--- /dev/null
@@ -0,0 +1,1315 @@
+/*
+ * FireDTV driver (formerly known as FireSAT)
+ *
+ * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
+ * Copyright (C) 2008 Ben Backx <ben@bbackx.com>
+ * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ */
+
+#include <linux/bug.h>
+#include <linux/crc32.h>
+#include <linux/delay.h>
+#include <linux/device.h>
+#include <linux/jiffies.h>
+#include <linux/kernel.h>
+#include <linux/moduleparam.h>
+#include <linux/mutex.h>
+#include <linux/string.h>
+#include <linux/stringify.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+#include "firedtv.h"
+
+#define FCP_COMMAND_REGISTER           0xfffff0000b00ULL
+
+#define AVC_CTYPE_CONTROL              0x0
+#define AVC_CTYPE_STATUS               0x1
+#define AVC_CTYPE_NOTIFY               0x3
+
+#define AVC_RESPONSE_ACCEPTED          0x9
+#define AVC_RESPONSE_STABLE            0xc
+#define AVC_RESPONSE_CHANGED           0xd
+#define AVC_RESPONSE_INTERIM           0xf
+
+#define AVC_SUBUNIT_TYPE_TUNER         (0x05 << 3)
+#define AVC_SUBUNIT_TYPE_UNIT          (0x1f << 3)
+
+#define AVC_OPCODE_VENDOR              0x00
+#define AVC_OPCODE_READ_DESCRIPTOR     0x09
+#define AVC_OPCODE_DSIT                        0xc8
+#define AVC_OPCODE_DSD                 0xcb
+
+#define DESCRIPTOR_TUNER_STATUS        0x80
+#define DESCRIPTOR_SUBUNIT_IDENTIFIER  0x00
+
+#define SFE_VENDOR_DE_COMPANYID_0      0x00 /* OUI of Digital Everywhere */
+#define SFE_VENDOR_DE_COMPANYID_1      0x12
+#define SFE_VENDOR_DE_COMPANYID_2      0x87
+
+#define SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL 0x0a
+#define SFE_VENDOR_OPCODE_LNB_CONTROL          0x52
+#define SFE_VENDOR_OPCODE_TUNE_QPSK            0x58 /* for DVB-S */
+
+#define SFE_VENDOR_OPCODE_GET_FIRMWARE_VERSION 0x00
+#define SFE_VENDOR_OPCODE_HOST2CA              0x56
+#define SFE_VENDOR_OPCODE_CA2HOST              0x57
+#define SFE_VENDOR_OPCODE_CISTATUS             0x59
+#define SFE_VENDOR_OPCODE_TUNE_QPSK2           0x60 /* for DVB-S2 */
+
+#define SFE_VENDOR_TAG_CA_RESET                        0x00
+#define SFE_VENDOR_TAG_CA_APPLICATION_INFO     0x01
+#define SFE_VENDOR_TAG_CA_PMT                  0x02
+#define SFE_VENDOR_TAG_CA_DATE_TIME            0x04
+#define SFE_VENDOR_TAG_CA_MMI                  0x05
+#define SFE_VENDOR_TAG_CA_ENTER_MENU           0x07
+
+#define EN50221_LIST_MANAGEMENT_ONLY   0x03
+#define EN50221_TAG_APP_INFO           0x9f8021
+#define EN50221_TAG_CA_INFO            0x9f8031
+
+struct avc_command_frame {
+       int length;
+       u8 ctype;
+       u8 subunit;
+       u8 opcode;
+       u8 operand[509];
+};
+
+struct avc_response_frame {
+       int length;
+       u8 response;
+       u8 subunit;
+       u8 opcode;
+       u8 operand[509];
+};
+
+#define AVC_DEBUG_FCP_SUBACTIONS       1
+#define AVC_DEBUG_FCP_PAYLOADS         2
+
+static int avc_debug;
+module_param_named(debug, avc_debug, int, 0644);
+MODULE_PARM_DESC(debug, "Verbose logging (default = 0"
+       ", FCP subactions = "   __stringify(AVC_DEBUG_FCP_SUBACTIONS)
+       ", FCP payloads = "     __stringify(AVC_DEBUG_FCP_PAYLOADS)
+       ", or all = -1)");
+
+static const char *debug_fcp_ctype(unsigned int ctype)
+{
+       static const char *ctypes[] = {
+               [0x0] = "CONTROL",              [0x1] = "STATUS",
+               [0x2] = "SPECIFIC INQUIRY",     [0x3] = "NOTIFY",
+               [0x4] = "GENERAL INQUIRY",      [0x8] = "NOT IMPLEMENTED",
+               [0x9] = "ACCEPTED",             [0xa] = "REJECTED",
+               [0xb] = "IN TRANSITION",        [0xc] = "IMPLEMENTED/STABLE",
+               [0xd] = "CHANGED",              [0xf] = "INTERIM",
+       };
+       const char *ret = ctype < ARRAY_SIZE(ctypes) ? ctypes[ctype] : NULL;
+
+       return ret ? ret : "?";
+}
+
+static const char *debug_fcp_opcode(unsigned int opcode,
+                                   const u8 *data, size_t length)
+{
+       switch (opcode) {
+       case AVC_OPCODE_VENDOR:                 break;
+       case AVC_OPCODE_READ_DESCRIPTOR:        return "ReadDescriptor";
+       case AVC_OPCODE_DSIT:                   return "DirectSelectInfo.Type";
+       case AVC_OPCODE_DSD:                    return "DirectSelectData";
+       default:                                return "?";
+       }
+
+       if (length < 7 ||
+           data[3] != SFE_VENDOR_DE_COMPANYID_0 ||
+           data[4] != SFE_VENDOR_DE_COMPANYID_1 ||
+           data[5] != SFE_VENDOR_DE_COMPANYID_2)
+               return "Vendor";
+
+       switch (data[6]) {
+       case SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL: return "RegisterRC";
+       case SFE_VENDOR_OPCODE_LNB_CONTROL:             return "LNBControl";
+       case SFE_VENDOR_OPCODE_TUNE_QPSK:               return "TuneQPSK";
+       case SFE_VENDOR_OPCODE_HOST2CA:                 return "Host2CA";
+       case SFE_VENDOR_OPCODE_CA2HOST:                 return "CA2Host";
+       }
+       return "Vendor";
+}
+
+static void debug_fcp(const u8 *data, size_t length)
+{
+       unsigned int subunit_type, subunit_id, op;
+       const char *prefix = data[0] > 7 ? "FCP <- " : "FCP -> ";
+
+       if (avc_debug & AVC_DEBUG_FCP_SUBACTIONS) {
+               subunit_type = data[1] >> 3;
+               subunit_id = data[1] & 7;
+               op = subunit_type == 0x1e || subunit_id == 5 ? ~0 : data[2];
+               printk(KERN_INFO "%ssu=%x.%x l=%d: %-8s - %s\n",
+                      prefix, subunit_type, subunit_id, length,
+                      debug_fcp_ctype(data[0]),
+                      debug_fcp_opcode(op, data, length));
+       }
+
+       if (avc_debug & AVC_DEBUG_FCP_PAYLOADS)
+               print_hex_dump(KERN_INFO, prefix, DUMP_PREFIX_NONE, 16, 1,
+                              data, length, false);
+}
+
+static int __avc_write(struct firedtv *fdtv,
+               const struct avc_command_frame *c, struct avc_response_frame *r)
+{
+       int err, retry;
+
+       if (r)
+               fdtv->avc_reply_received = false;
+
+       for (retry = 0; retry < 6; retry++) {
+               if (unlikely(avc_debug))
+                       debug_fcp(&c->ctype, c->length);
+
+               err = fdtv->backend->write(fdtv, FCP_COMMAND_REGISTER,
+                                          (void *)&c->ctype, c->length);
+               if (err) {
+                       fdtv->avc_reply_received = true;
+                       dev_err(fdtv->device, "FCP command write failed\n");
+                       return err;
+               }
+
+               if (!r)
+                       return 0;
+
+               /*
+                * AV/C specs say that answers should be sent within 150 ms.
+                * Time out after 200 ms.
+                */
+               if (wait_event_timeout(fdtv->avc_wait,
+                                      fdtv->avc_reply_received,
+                                      msecs_to_jiffies(200)) != 0) {
+                       r->length = fdtv->response_length;
+                       memcpy(&r->response, fdtv->response, r->length);
+
+                       return 0;
+               }
+       }
+       dev_err(fdtv->device, "FCP response timed out\n");
+       return -ETIMEDOUT;
+}
+
+static int avc_write(struct firedtv *fdtv,
+               const struct avc_command_frame *c, struct avc_response_frame *r)
+{
+       int ret;
+
+       if (mutex_lock_interruptible(&fdtv->avc_mutex))
+               return -EINTR;
+
+       ret = __avc_write(fdtv, c, r);
+
+       mutex_unlock(&fdtv->avc_mutex);
+       return ret;
+}
+
+int avc_recv(struct firedtv *fdtv, void *data, size_t length)
+{
+       struct avc_response_frame *r =
+                       data - offsetof(struct avc_response_frame, response);
+
+       if (unlikely(avc_debug))
+               debug_fcp(data, length);
+
+       if (length >= 8 &&
+           r->operand[0] == SFE_VENDOR_DE_COMPANYID_0 &&
+           r->operand[1] == SFE_VENDOR_DE_COMPANYID_1 &&
+           r->operand[2] == SFE_VENDOR_DE_COMPANYID_2 &&
+           r->operand[3] == SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL) {
+               if (r->response == AVC_RESPONSE_CHANGED) {
+                       fdtv_handle_rc(fdtv,
+                           r->operand[4] << 8 | r->operand[5]);
+                       schedule_work(&fdtv->remote_ctrl_work);
+               } else if (r->response != AVC_RESPONSE_INTERIM) {
+                       dev_info(fdtv->device,
+                                "remote control result = %d\n", r->response);
+               }
+               return 0;
+       }
+
+       if (fdtv->avc_reply_received) {
+               dev_err(fdtv->device, "out-of-order AVC response, ignored\n");
+               return -EIO;
+       }
+
+       memcpy(fdtv->response, data, length);
+       fdtv->response_length = length;
+
+       fdtv->avc_reply_received = true;
+       wake_up(&fdtv->avc_wait);
+
+       return 0;
+}
+
+/*
+ * tuning command for setting the relative LNB frequency
+ * (not supported by the AVC standard)
+ */
+static void avc_tuner_tuneqpsk(struct firedtv *fdtv,
+                              struct dvb_frontend_parameters *params,
+                              struct avc_command_frame *c)
+{
+       c->opcode = AVC_OPCODE_VENDOR;
+
+       c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+       c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+       c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+       c->operand[3] = SFE_VENDOR_OPCODE_TUNE_QPSK;
+
+       c->operand[4] = (params->frequency >> 24) & 0xff;
+       c->operand[5] = (params->frequency >> 16) & 0xff;
+       c->operand[6] = (params->frequency >> 8) & 0xff;
+       c->operand[7] = params->frequency & 0xff;
+
+       c->operand[8] = ((params->u.qpsk.symbol_rate / 1000) >> 8) & 0xff;
+       c->operand[9] = (params->u.qpsk.symbol_rate / 1000) & 0xff;
+
+       switch (params->u.qpsk.fec_inner) {
+       case FEC_1_2:   c->operand[10] = 0x1; break;
+       case FEC_2_3:   c->operand[10] = 0x2; break;
+       case FEC_3_4:   c->operand[10] = 0x3; break;
+       case FEC_5_6:   c->operand[10] = 0x4; break;
+       case FEC_7_8:   c->operand[10] = 0x5; break;
+       case FEC_4_5:
+       case FEC_8_9:
+       case FEC_AUTO:
+       default:        c->operand[10] = 0x0;
+       }
+
+       if (fdtv->voltage == 0xff)
+               c->operand[11] = 0xff;
+       else if (fdtv->voltage == SEC_VOLTAGE_18) /* polarisation */
+               c->operand[11] = 0;
+       else
+               c->operand[11] = 1;
+
+       if (fdtv->tone == 0xff)
+               c->operand[12] = 0xff;
+       else if (fdtv->tone == SEC_TONE_ON) /* band */
+               c->operand[12] = 1;
+       else
+               c->operand[12] = 0;
+
+       if (fdtv->type == FIREDTV_DVB_S2) {
+               c->operand[13] = 0x1;
+               c->operand[14] = 0xff;
+               c->operand[15] = 0xff;
+               c->length = 20;
+       } else {
+               c->length = 16;
+       }
+}
+
+static void avc_tuner_dsd_dvb_c(struct dvb_frontend_parameters *params,
+                               struct avc_command_frame *c)
+{
+       c->opcode = AVC_OPCODE_DSD;
+
+       c->operand[0] = 0;    /* source plug */
+       c->operand[1] = 0xd2; /* subfunction replace */
+       c->operand[2] = 0x20; /* system id = DVB */
+       c->operand[3] = 0x00; /* antenna number */
+       c->operand[4] = 0x11; /* system_specific_multiplex selection_length */
+
+       /* multiplex_valid_flags, high byte */
+       c->operand[5] =   0 << 7 /* reserved */
+                       | 0 << 6 /* Polarisation */
+                       | 0 << 5 /* Orbital_Pos */
+                       | 1 << 4 /* Frequency */
+                       | 1 << 3 /* Symbol_Rate */
+                       | 0 << 2 /* FEC_outer */
+                       | (params->u.qam.fec_inner  != FEC_AUTO ? 1 << 1 : 0)
+                       | (params->u.qam.modulation != QAM_AUTO ? 1 << 0 : 0);
+
+       /* multiplex_valid_flags, low byte */
+       c->operand[6] =   0 << 7 /* NetworkID */
+                       | 0 << 0 /* reserved */ ;
+
+       c->operand[7]  = 0x00;
+       c->operand[8]  = 0x00;
+       c->operand[9]  = 0x00;
+       c->operand[10] = 0x00;
+
+       c->operand[11] = (((params->frequency / 4000) >> 16) & 0xff) | (2 << 6);
+       c->operand[12] = ((params->frequency / 4000) >> 8) & 0xff;
+       c->operand[13] = (params->frequency / 4000) & 0xff;
+       c->operand[14] = ((params->u.qpsk.symbol_rate / 1000) >> 12) & 0xff;
+       c->operand[15] = ((params->u.qpsk.symbol_rate / 1000) >> 4) & 0xff;
+       c->operand[16] = ((params->u.qpsk.symbol_rate / 1000) << 4) & 0xf0;
+       c->operand[17] = 0x00;
+
+       switch (params->u.qpsk.fec_inner) {
+       case FEC_1_2:   c->operand[18] = 0x1; break;
+       case FEC_2_3:   c->operand[18] = 0x2; break;
+       case FEC_3_4:   c->operand[18] = 0x3; break;
+       case FEC_5_6:   c->operand[18] = 0x4; break;
+       case FEC_7_8:   c->operand[18] = 0x5; break;
+       case FEC_8_9:   c->operand[18] = 0x6; break;
+       case FEC_4_5:   c->operand[18] = 0x8; break;
+       case FEC_AUTO:
+       default:        c->operand[18] = 0x0;
+       }
+
+       switch (params->u.qam.modulation) {
+       case QAM_16:    c->operand[19] = 0x08; break;
+       case QAM_32:    c->operand[19] = 0x10; break;
+       case QAM_64:    c->operand[19] = 0x18; break;
+       case QAM_128:   c->operand[19] = 0x20; break;
+       case QAM_256:   c->operand[19] = 0x28; break;
+       case QAM_AUTO:
+       default:        c->operand[19] = 0x00;
+       }
+
+       c->operand[20] = 0x00;
+       c->operand[21] = 0x00;
+       /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */
+       c->operand[22] = 0x00;
+
+       c->length = 28;
+}
+
+static void avc_tuner_dsd_dvb_t(struct dvb_frontend_parameters *params,
+                               struct avc_command_frame *c)
+{
+       struct dvb_ofdm_parameters *ofdm = &params->u.ofdm;
+
+       c->opcode = AVC_OPCODE_DSD;
+
+       c->operand[0] = 0;    /* source plug */
+       c->operand[1] = 0xd2; /* subfunction replace */
+       c->operand[2] = 0x20; /* system id = DVB */
+       c->operand[3] = 0x00; /* antenna number */
+       c->operand[4] = 0x0c; /* system_specific_multiplex selection_length */
+
+       /* multiplex_valid_flags, high byte */
+       c->operand[5] =
+             0 << 7 /* reserved */
+           | 1 << 6 /* CenterFrequency */
+           | (ofdm->bandwidth      != BANDWIDTH_AUTO        ? 1 << 5 : 0)
+           | (ofdm->constellation  != QAM_AUTO              ? 1 << 4 : 0)
+           | (ofdm->hierarchy_information != HIERARCHY_AUTO ? 1 << 3 : 0)
+           | (ofdm->code_rate_HP   != FEC_AUTO              ? 1 << 2 : 0)
+           | (ofdm->code_rate_LP   != FEC_AUTO              ? 1 << 1 : 0)
+           | (ofdm->guard_interval != GUARD_INTERVAL_AUTO   ? 1 << 0 : 0);
+
+       /* multiplex_valid_flags, low byte */
+       c->operand[6] =
+             0 << 7 /* NetworkID */
+           | (ofdm->transmission_mode != TRANSMISSION_MODE_AUTO ? 1 << 6 : 0)
+           | 0 << 5 /* OtherFrequencyFlag */
+           | 0 << 0 /* reserved */ ;
+
+       c->operand[7]  = 0x0;
+       c->operand[8]  = (params->frequency / 10) >> 24;
+       c->operand[9]  = ((params->frequency / 10) >> 16) & 0xff;
+       c->operand[10] = ((params->frequency / 10) >>  8) & 0xff;
+       c->operand[11] = (params->frequency / 10) & 0xff;
+
+       switch (ofdm->bandwidth) {
+       case BANDWIDTH_7_MHZ:   c->operand[12] = 0x20; break;
+       case BANDWIDTH_8_MHZ:
+       case BANDWIDTH_6_MHZ:   /* not defined by AVC spec */
+       case BANDWIDTH_AUTO:
+       default:                c->operand[12] = 0x00;
+       }
+
+       switch (ofdm->constellation) {
+       case QAM_16:    c->operand[13] = 1 << 6; break;
+       case QAM_64:    c->operand[13] = 2 << 6; break;
+       case QPSK:
+       default:        c->operand[13] = 0x00;
+       }
+
+       switch (ofdm->hierarchy_information) {
+       case HIERARCHY_1:       c->operand[13] |= 1 << 3; break;
+       case HIERARCHY_2:       c->operand[13] |= 2 << 3; break;
+       case HIERARCHY_4:       c->operand[13] |= 3 << 3; break;
+       case HIERARCHY_AUTO:
+       case HIERARCHY_NONE:
+       default:                break;
+       }
+
+       switch (ofdm->code_rate_HP) {
+       case FEC_2_3:   c->operand[13] |= 1; break;
+       case FEC_3_4:   c->operand[13] |= 2; break;
+       case FEC_5_6:   c->operand[13] |= 3; break;
+       case FEC_7_8:   c->operand[13] |= 4; break;
+       case FEC_1_2:
+       default:        break;
+       }
+
+       switch (ofdm->code_rate_LP) {
+       case FEC_2_3:   c->operand[14] = 1 << 5; break;
+       case FEC_3_4:   c->operand[14] = 2 << 5; break;
+       case FEC_5_6:   c->operand[14] = 3 << 5; break;
+       case FEC_7_8:   c->operand[14] = 4 << 5; break;
+       case FEC_1_2:
+       default:        c->operand[14] = 0x00; break;
+       }
+
+       switch (ofdm->guard_interval) {
+       case GUARD_INTERVAL_1_16:       c->operand[14] |= 1 << 3; break;
+       case GUARD_INTERVAL_1_8:        c->operand[14] |= 2 << 3; break;
+       case GUARD_INTERVAL_1_4:        c->operand[14] |= 3 << 3; break;
+       case GUARD_INTERVAL_1_32:
+       case GUARD_INTERVAL_AUTO:
+       default:                        break;
+       }
+
+       switch (ofdm->transmission_mode) {
+       case TRANSMISSION_MODE_8K:      c->operand[14] |= 1 << 1; break;
+       case TRANSMISSION_MODE_2K:
+       case TRANSMISSION_MODE_AUTO:
+       default:                        break;
+       }
+
+       c->operand[15] = 0x00; /* network_ID[0] */
+       c->operand[16] = 0x00; /* network_ID[1] */
+       /* Nr_of_dsd_sel_specs = 0 -> no PIDs are transmitted */
+       c->operand[17] = 0x00;
+
+       c->length = 24;
+}
+
+int avc_tuner_dsd(struct firedtv *fdtv,
+                 struct dvb_frontend_parameters *params)
+{
+       char buffer[sizeof(struct avc_command_frame)];
+       struct avc_command_frame *c = (void *)buffer;
+       struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+
+       memset(c, 0, sizeof(*c));
+
+       c->ctype   = AVC_CTYPE_CONTROL;
+       c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+
+       switch (fdtv->type) {
+       case FIREDTV_DVB_S:
+       case FIREDTV_DVB_S2: avc_tuner_tuneqpsk(fdtv, params, c); break;
+       case FIREDTV_DVB_C: avc_tuner_dsd_dvb_c(params, c); break;
+       case FIREDTV_DVB_T: avc_tuner_dsd_dvb_t(params, c); break;
+       default:
+               BUG();
+       }
+
+       if (avc_write(fdtv, c, r) < 0)
+               return -EIO;
+
+       msleep(500);
+#if 0
+       /* FIXME: */
+       /* u8 *status was an out-parameter of avc_tuner_dsd, unused by caller */
+       if (status)
+               *status = r->operand[2];
+#endif
+       return 0;
+}
+
+int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[])
+{
+       char buffer[sizeof(struct avc_command_frame)];
+       struct avc_command_frame *c = (void *)buffer;
+       struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+       int pos, k;
+
+       if (pidc > 16 && pidc != 0xff)
+               return -EINVAL;
+
+       memset(c, 0, sizeof(*c));
+
+       c->ctype   = AVC_CTYPE_CONTROL;
+       c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+       c->opcode  = AVC_OPCODE_DSD;
+
+       c->operand[0] = 0;      /* source plug */
+       c->operand[1] = 0xd2;   /* subfunction replace */
+       c->operand[2] = 0x20;   /* system id = DVB */
+       c->operand[3] = 0x00;   /* antenna number */
+       c->operand[4] = 0x00;   /* system_specific_multiplex selection_length */
+       c->operand[5] = pidc;   /* Nr_of_dsd_sel_specs */
+
+       pos = 6;
+       if (pidc != 0xff)
+               for (k = 0; k < pidc; k++) {
+                       c->operand[pos++] = 0x13; /* flowfunction relay */
+                       c->operand[pos++] = 0x80; /* dsd_sel_spec_valid_flags -> PID */
+                       c->operand[pos++] = (pid[k] >> 8) & 0x1f;
+                       c->operand[pos++] = pid[k] & 0xff;
+                       c->operand[pos++] = 0x00; /* tableID */
+                       c->operand[pos++] = 0x00; /* filter_length */
+               }
+
+       c->length = ALIGN(3 + pos, 4);
+
+       if (avc_write(fdtv, c, r) < 0)
+               return -EIO;
+
+       msleep(50);
+       return 0;
+}
+
+int avc_tuner_get_ts(struct firedtv *fdtv)
+{
+       char buffer[sizeof(struct avc_command_frame)];
+       struct avc_command_frame *c = (void *)buffer;
+       struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+       int sl;
+
+       memset(c, 0, sizeof(*c));
+
+       c->ctype   = AVC_CTYPE_CONTROL;
+       c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+       c->opcode  = AVC_OPCODE_DSIT;
+
+       sl = fdtv->type == FIREDTV_DVB_T ? 0x0c : 0x11;
+
+       c->operand[0] = 0;      /* source plug */
+       c->operand[1] = 0xd2;   /* subfunction replace */
+       c->operand[2] = 0xff;   /* status */
+       c->operand[3] = 0x20;   /* system id = DVB */
+       c->operand[4] = 0x00;   /* antenna number */
+       c->operand[5] = 0x0;    /* system_specific_search_flags */
+       c->operand[6] = sl;     /* system_specific_multiplex selection_length */
+       c->operand[7] = 0x00;   /* valid_flags [0] */
+       c->operand[8] = 0x00;   /* valid_flags [1] */
+       c->operand[7 + sl] = 0x00; /* nr_of_dsit_sel_specs (always 0) */
+
+       c->length = fdtv->type == FIREDTV_DVB_T ? 24 : 28;
+
+       if (avc_write(fdtv, c, r) < 0)
+               return -EIO;
+
+       msleep(250);
+       return 0;
+}
+
+int avc_identify_subunit(struct firedtv *fdtv)
+{
+       char buffer[sizeof(struct avc_command_frame)];
+       struct avc_command_frame *c = (void *)buffer;
+       struct avc_response_frame *r = (void *)buffer;
+
+       memset(c, 0, sizeof(*c));
+
+       c->ctype   = AVC_CTYPE_CONTROL;
+       c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+       c->opcode  = AVC_OPCODE_READ_DESCRIPTOR;
+
+       c->operand[0] = DESCRIPTOR_SUBUNIT_IDENTIFIER;
+       c->operand[1] = 0xff;
+       c->operand[2] = 0x00;
+       c->operand[3] = 0x00; /* length highbyte */
+       c->operand[4] = 0x08; /* length lowbyte  */
+       c->operand[5] = 0x00; /* offset highbyte */
+       c->operand[6] = 0x0d; /* offset lowbyte  */
+
+       c->length = 12;
+
+       if (avc_write(fdtv, c, r) < 0)
+               return -EIO;
+
+       if ((r->response != AVC_RESPONSE_STABLE &&
+            r->response != AVC_RESPONSE_ACCEPTED) ||
+           (r->operand[3] << 8) + r->operand[4] != 8) {
+               dev_err(fdtv->device, "cannot read subunit identifier\n");
+               return -EINVAL;
+       }
+       return 0;
+}
+
+#define SIZEOF_ANTENNA_INPUT_INFO 22
+
+int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat)
+{
+       char buffer[sizeof(struct avc_command_frame)];
+       struct avc_command_frame *c = (void *)buffer;
+       struct avc_response_frame *r = (void *)buffer;
+       int length;
+
+       memset(c, 0, sizeof(*c));
+
+       c->ctype   = AVC_CTYPE_CONTROL;
+       c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+       c->opcode  = AVC_OPCODE_READ_DESCRIPTOR;
+
+       c->operand[0] = DESCRIPTOR_TUNER_STATUS;
+       c->operand[1] = 0xff;   /* read_result_status */
+       c->operand[2] = 0x00;   /* reserved */
+       c->operand[3] = 0;      /* SIZEOF_ANTENNA_INPUT_INFO >> 8; */
+       c->operand[4] = 0;      /* SIZEOF_ANTENNA_INPUT_INFO & 0xff; */
+       c->operand[5] = 0x00;
+       c->operand[6] = 0x00;
+
+       c->length = 12;
+
+       if (avc_write(fdtv, c, r) < 0)
+               return -EIO;
+
+       if (r->response != AVC_RESPONSE_STABLE &&
+           r->response != AVC_RESPONSE_ACCEPTED) {
+               dev_err(fdtv->device, "cannot read tuner status\n");
+               return -EINVAL;
+       }
+
+       length = r->operand[9];
+       if (r->operand[1] != 0x10 || length != SIZEOF_ANTENNA_INPUT_INFO) {
+               dev_err(fdtv->device, "got invalid tuner status\n");
+               return -EINVAL;
+       }
+
+       stat->active_system             = r->operand[10];
+       stat->searching                 = r->operand[11] >> 7 & 1;
+       stat->moving                    = r->operand[11] >> 6 & 1;
+       stat->no_rf                     = r->operand[11] >> 5 & 1;
+       stat->input                     = r->operand[12] >> 7 & 1;
+       stat->selected_antenna          = r->operand[12] & 0x7f;
+       stat->ber                       = r->operand[13] << 24 |
+                                         r->operand[14] << 16 |
+                                         r->operand[15] << 8 |
+                                         r->operand[16];
+       stat->signal_strength           = r->operand[17];
+       stat->raster_frequency          = r->operand[18] >> 6 & 2;
+       stat->rf_frequency              = (r->operand[18] & 0x3f) << 16 |
+                                         r->operand[19] << 8 |
+                                         r->operand[20];
+       stat->man_dep_info_length       = r->operand[21];
+       stat->front_end_error           = r->operand[22] >> 4 & 1;
+       stat->antenna_error             = r->operand[22] >> 3 & 1;
+       stat->front_end_power_status    = r->operand[22] >> 1 & 1;
+       stat->power_supply              = r->operand[22] & 1;
+       stat->carrier_noise_ratio       = r->operand[23] << 8 |
+                                         r->operand[24];
+       stat->power_supply_voltage      = r->operand[27];
+       stat->antenna_voltage           = r->operand[28];
+       stat->firewire_bus_voltage      = r->operand[29];
+       stat->ca_mmi                    = r->operand[30] & 1;
+       stat->ca_pmt_reply              = r->operand[31] >> 7 & 1;
+       stat->ca_date_time_request      = r->operand[31] >> 6 & 1;
+       stat->ca_application_info       = r->operand[31] >> 5 & 1;
+       stat->ca_module_present_status  = r->operand[31] >> 4 & 1;
+       stat->ca_dvb_flag               = r->operand[31] >> 3 & 1;
+       stat->ca_error_flag             = r->operand[31] >> 2 & 1;
+       stat->ca_initialization_status  = r->operand[31] >> 1 & 1;
+
+       return 0;
+}
+
+int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
+                   char conttone, char nrdiseq,
+                   struct dvb_diseqc_master_cmd *diseqcmd)
+{
+       char buffer[sizeof(struct avc_command_frame)];
+       struct avc_command_frame *c = (void *)buffer;
+       struct avc_response_frame *r = (void *)buffer;
+       int i, j, k;
+
+       memset(c, 0, sizeof(*c));
+
+       c->ctype   = AVC_CTYPE_CONTROL;
+       c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+       c->opcode  = AVC_OPCODE_VENDOR;
+
+       c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+       c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+       c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+       c->operand[3] = SFE_VENDOR_OPCODE_LNB_CONTROL;
+
+       c->operand[4] = voltage;
+       c->operand[5] = nrdiseq;
+
+       i = 6;
+
+       for (j = 0; j < nrdiseq; j++) {
+               c->operand[i++] = diseqcmd[j].msg_len;
+
+               for (k = 0; k < diseqcmd[j].msg_len; k++)
+                       c->operand[i++] = diseqcmd[j].msg[k];
+       }
+
+       c->operand[i++] = burst;
+       c->operand[i++] = conttone;
+
+       c->length = ALIGN(3 + i, 4);
+
+       if (avc_write(fdtv, c, r) < 0)
+               return -EIO;
+
+       if (r->response != AVC_RESPONSE_ACCEPTED) {
+               dev_err(fdtv->device, "LNB control failed\n");
+               return -EINVAL;
+       }
+
+       return 0;
+}
+
+int avc_register_remote_control(struct firedtv *fdtv)
+{
+       char buffer[sizeof(struct avc_command_frame)];
+       struct avc_command_frame *c = (void *)buffer;
+
+       memset(c, 0, sizeof(*c));
+
+       c->ctype   = AVC_CTYPE_NOTIFY;
+       c->subunit = AVC_SUBUNIT_TYPE_UNIT | 7;
+       c->opcode  = AVC_OPCODE_VENDOR;
+
+       c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+       c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+       c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+       c->operand[3] = SFE_VENDOR_OPCODE_REGISTER_REMOTE_CONTROL;
+
+       c->length = 8;
+
+       return avc_write(fdtv, c, NULL);
+}
+
+void avc_remote_ctrl_work(struct work_struct *work)
+{
+       struct firedtv *fdtv =
+                       container_of(work, struct firedtv, remote_ctrl_work);
+
+       /* Should it be rescheduled in failure cases? */
+       avc_register_remote_control(fdtv);
+}
+
+#if 0 /* FIXME: unused */
+int avc_tuner_host2ca(struct firedtv *fdtv)
+{
+       char buffer[sizeof(struct avc_command_frame)];
+       struct avc_command_frame *c = (void *)buffer;
+       struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+
+       memset(c, 0, sizeof(*c));
+
+       c->ctype   = AVC_CTYPE_CONTROL;
+       c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+       c->opcode  = AVC_OPCODE_VENDOR;
+
+       c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+       c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+       c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+       c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
+       c->operand[4] = 0; /* slot */
+       c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
+       c->operand[6] = 0; /* more/last */
+       c->operand[7] = 0; /* length */
+
+       c->length = 12;
+
+       if (avc_write(fdtv, c, r) < 0)
+               return -EIO;
+
+       return 0;
+}
+#endif
+
+static int get_ca_object_pos(struct avc_response_frame *r)
+{
+       int length = 1;
+
+       /* Check length of length field */
+       if (r->operand[7] & 0x80)
+               length = (r->operand[7] & 0x7f) + 1;
+       return length + 7;
+}
+
+static int get_ca_object_length(struct avc_response_frame *r)
+{
+#if 0 /* FIXME: unused */
+       int size = 0;
+       int i;
+
+       if (r->operand[7] & 0x80)
+               for (i = 0; i < (r->operand[7] & 0x7f); i++) {
+                       size <<= 8;
+                       size += r->operand[8 + i];
+               }
+#endif
+       return r->operand[7];
+}
+
+int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
+{
+       char buffer[sizeof(struct avc_command_frame)];
+       struct avc_command_frame *c = (void *)buffer;
+       struct avc_response_frame *r = (void *)buffer;
+       int pos;
+
+       memset(c, 0, sizeof(*c));
+
+       c->ctype   = AVC_CTYPE_STATUS;
+       c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+       c->opcode  = AVC_OPCODE_VENDOR;
+
+       c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+       c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+       c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+       c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
+       c->operand[4] = 0; /* slot */
+       c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
+
+       c->length = 12;
+
+       if (avc_write(fdtv, c, r) < 0)
+               return -EIO;
+
+       /* FIXME: check response code and validate response data */
+
+       pos = get_ca_object_pos(r);
+       app_info[0] = (EN50221_TAG_APP_INFO >> 16) & 0xff;
+       app_info[1] = (EN50221_TAG_APP_INFO >>  8) & 0xff;
+       app_info[2] = (EN50221_TAG_APP_INFO >>  0) & 0xff;
+       app_info[3] = 6 + r->operand[pos + 4];
+       app_info[4] = 0x01;
+       memcpy(&app_info[5], &r->operand[pos], 5 + r->operand[pos + 4]);
+       *len = app_info[3] + 4;
+
+       return 0;
+}
+
+int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len)
+{
+       char buffer[sizeof(struct avc_command_frame)];
+       struct avc_command_frame *c = (void *)buffer;
+       struct avc_response_frame *r = (void *)buffer;
+       int pos;
+
+       memset(c, 0, sizeof(*c));
+
+       c->ctype   = AVC_CTYPE_STATUS;
+       c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+       c->opcode  = AVC_OPCODE_VENDOR;
+
+       c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+       c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+       c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+       c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
+       c->operand[4] = 0; /* slot */
+       c->operand[5] = SFE_VENDOR_TAG_CA_APPLICATION_INFO; /* ca tag */
+
+       c->length = 12;
+
+       if (avc_write(fdtv, c, r) < 0)
+               return -EIO;
+
+       pos = get_ca_object_pos(r);
+       app_info[0] = (EN50221_TAG_CA_INFO >> 16) & 0xff;
+       app_info[1] = (EN50221_TAG_CA_INFO >>  8) & 0xff;
+       app_info[2] = (EN50221_TAG_CA_INFO >>  0) & 0xff;
+       app_info[3] = 2;
+       app_info[4] = r->operand[pos + 0];
+       app_info[5] = r->operand[pos + 1];
+       *len = app_info[3] + 4;
+
+       return 0;
+}
+
+int avc_ca_reset(struct firedtv *fdtv)
+{
+       char buffer[sizeof(struct avc_command_frame)];
+       struct avc_command_frame *c = (void *)buffer;
+       struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+
+       memset(c, 0, sizeof(*c));
+
+       c->ctype   = AVC_CTYPE_CONTROL;
+       c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+       c->opcode  = AVC_OPCODE_VENDOR;
+
+       c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+       c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+       c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+       c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
+       c->operand[4] = 0; /* slot */
+       c->operand[5] = SFE_VENDOR_TAG_CA_RESET; /* ca tag */
+       c->operand[6] = 0; /* more/last */
+       c->operand[7] = 1; /* length */
+       c->operand[8] = 0; /* force hardware reset */
+
+       c->length = 12;
+
+       if (avc_write(fdtv, c, r) < 0)
+               return -EIO;
+
+       return 0;
+}
+
+int avc_ca_pmt(struct firedtv *fdtv, char *msg, int length)
+{
+       char buffer[sizeof(struct avc_command_frame)];
+       struct avc_command_frame *c = (void *)buffer;
+       struct avc_response_frame *r = (void *)buffer;
+       int list_management;
+       int program_info_length;
+       int pmt_cmd_id;
+       int read_pos;
+       int write_pos;
+       int es_info_length;
+       int crc32_csum;
+
+       memset(c, 0, sizeof(*c));
+
+       c->ctype   = AVC_CTYPE_CONTROL;
+       c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+       c->opcode  = AVC_OPCODE_VENDOR;
+
+       if (msg[0] != EN50221_LIST_MANAGEMENT_ONLY) {
+               dev_info(fdtv->device, "forcing list_management to ONLY\n");
+               msg[0] = EN50221_LIST_MANAGEMENT_ONLY;
+       }
+       /* We take the cmd_id from the programme level only! */
+       list_management = msg[0];
+       program_info_length = ((msg[4] & 0x0f) << 8) + msg[5];
+       if (program_info_length > 0)
+               program_info_length--; /* Remove pmt_cmd_id */
+       pmt_cmd_id = msg[6];
+
+       c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+       c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+       c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+       c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
+       c->operand[4] = 0; /* slot */
+       c->operand[5] = SFE_VENDOR_TAG_CA_PMT; /* ca tag */
+       c->operand[6] = 0; /* more/last */
+       /* c->operand[7] = XXXprogram_info_length + 17; */ /* length */
+       c->operand[8] = list_management;
+       c->operand[9] = 0x01; /* pmt_cmd=OK_descramble */
+
+       /* TS program map table */
+
+       c->operand[10] = 0x02; /* Table id=2 */
+       c->operand[11] = 0x80; /* Section syntax + length */
+       /* c->operand[12] = XXXprogram_info_length + 12; */
+       c->operand[13] = msg[1]; /* Program number */
+       c->operand[14] = msg[2];
+       c->operand[15] = 0x01; /* Version number=0 + current/next=1 */
+       c->operand[16] = 0x00; /* Section number=0 */
+       c->operand[17] = 0x00; /* Last section number=0 */
+       c->operand[18] = 0x1f; /* PCR_PID=1FFF */
+       c->operand[19] = 0xff;
+       c->operand[20] = (program_info_length >> 8); /* Program info length */
+       c->operand[21] = (program_info_length & 0xff);
+
+       /* CA descriptors at programme level */
+       read_pos = 6;
+       write_pos = 22;
+       if (program_info_length > 0) {
+               pmt_cmd_id = msg[read_pos++];
+               if (pmt_cmd_id != 1 && pmt_cmd_id != 4)
+                       dev_err(fdtv->device,
+                               "invalid pmt_cmd_id %d\n", pmt_cmd_id);
+
+               memcpy(&c->operand[write_pos], &msg[read_pos],
+                      program_info_length);
+               read_pos += program_info_length;
+               write_pos += program_info_length;
+       }
+       while (read_pos < length) {
+               c->operand[write_pos++] = msg[read_pos++];
+               c->operand[write_pos++] = msg[read_pos++];
+               c->operand[write_pos++] = msg[read_pos++];
+               es_info_length =
+                       ((msg[read_pos] & 0x0f) << 8) + msg[read_pos + 1];
+               read_pos += 2;
+               if (es_info_length > 0)
+                       es_info_length--; /* Remove pmt_cmd_id */
+               c->operand[write_pos++] = es_info_length >> 8;
+               c->operand[write_pos++] = es_info_length & 0xff;
+               if (es_info_length > 0) {
+                       pmt_cmd_id = msg[read_pos++];
+                       if (pmt_cmd_id != 1 && pmt_cmd_id != 4)
+                               dev_err(fdtv->device, "invalid pmt_cmd_id %d "
+                                       "at stream level\n", pmt_cmd_id);
+
+                       memcpy(&c->operand[write_pos], &msg[read_pos],
+                              es_info_length);
+                       read_pos += es_info_length;
+                       write_pos += es_info_length;
+               }
+       }
+
+       /* CRC */
+       c->operand[write_pos++] = 0x00;
+       c->operand[write_pos++] = 0x00;
+       c->operand[write_pos++] = 0x00;
+       c->operand[write_pos++] = 0x00;
+
+       c->operand[7] = write_pos - 8;
+       c->operand[12] = write_pos - 13;
+
+       crc32_csum = crc32_be(0, &c->operand[10], c->operand[12] - 1);
+       c->operand[write_pos - 4] = (crc32_csum >> 24) & 0xff;
+       c->operand[write_pos - 3] = (crc32_csum >> 16) & 0xff;
+       c->operand[write_pos - 2] = (crc32_csum >>  8) & 0xff;
+       c->operand[write_pos - 1] = (crc32_csum >>  0) & 0xff;
+
+       c->length = ALIGN(3 + write_pos, 4);
+
+       if (avc_write(fdtv, c, r) < 0)
+               return -EIO;
+
+       if (r->response != AVC_RESPONSE_ACCEPTED) {
+               dev_err(fdtv->device,
+                       "CA PMT failed with response 0x%x\n", r->response);
+               return -EFAULT;
+       }
+
+       return 0;
+}
+
+int avc_ca_get_time_date(struct firedtv *fdtv, int *interval)
+{
+       char buffer[sizeof(struct avc_command_frame)];
+       struct avc_command_frame *c = (void *)buffer;
+       struct avc_response_frame *r = (void *)buffer;
+
+       memset(c, 0, sizeof(*c));
+
+       c->ctype   = AVC_CTYPE_STATUS;
+       c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+       c->opcode  = AVC_OPCODE_VENDOR;
+
+       c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+       c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+       c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+       c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
+       c->operand[4] = 0; /* slot */
+       c->operand[5] = SFE_VENDOR_TAG_CA_DATE_TIME; /* ca tag */
+       c->operand[6] = 0; /* more/last */
+       c->operand[7] = 0; /* length */
+
+       c->length = 12;
+
+       if (avc_write(fdtv, c, r) < 0)
+               return -EIO;
+
+       /* FIXME: check response code and validate response data */
+
+       *interval = r->operand[get_ca_object_pos(r)];
+
+       return 0;
+}
+
+int avc_ca_enter_menu(struct firedtv *fdtv)
+{
+       char buffer[sizeof(struct avc_command_frame)];
+       struct avc_command_frame *c = (void *)buffer;
+       struct avc_response_frame *r = (void *)buffer; /* FIXME: unused */
+
+       memset(c, 0, sizeof(*c));
+
+       c->ctype   = AVC_CTYPE_STATUS;
+       c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+       c->opcode  = AVC_OPCODE_VENDOR;
+
+       c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+       c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+       c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+       c->operand[3] = SFE_VENDOR_OPCODE_HOST2CA;
+       c->operand[4] = 0; /* slot */
+       c->operand[5] = SFE_VENDOR_TAG_CA_ENTER_MENU;
+       c->operand[6] = 0; /* more/last */
+       c->operand[7] = 0; /* length */
+
+       c->length = 12;
+
+       if (avc_write(fdtv, c, r) < 0)
+               return -EIO;
+
+       return 0;
+}
+
+int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len)
+{
+       char buffer[sizeof(struct avc_command_frame)];
+       struct avc_command_frame *c = (void *)buffer;
+       struct avc_response_frame *r = (void *)buffer;
+
+       memset(c, 0, sizeof(*c));
+
+       c->ctype   = AVC_CTYPE_STATUS;
+       c->subunit = AVC_SUBUNIT_TYPE_TUNER | fdtv->subunit;
+       c->opcode  = AVC_OPCODE_VENDOR;
+
+       c->operand[0] = SFE_VENDOR_DE_COMPANYID_0;
+       c->operand[1] = SFE_VENDOR_DE_COMPANYID_1;
+       c->operand[2] = SFE_VENDOR_DE_COMPANYID_2;
+       c->operand[3] = SFE_VENDOR_OPCODE_CA2HOST;
+       c->operand[4] = 0; /* slot */
+       c->operand[5] = SFE_VENDOR_TAG_CA_MMI;
+       c->operand[6] = 0; /* more/last */
+       c->operand[7] = 0; /* length */
+
+       c->length = 12;
+
+       if (avc_write(fdtv, c, r) < 0)
+               return -EIO;
+
+       /* FIXME: check response code and validate response data */
+
+       *len = get_ca_object_length(r);
+       memcpy(mmi_object, &r->operand[get_ca_object_pos(r)], *len);
+
+       return 0;
+}
+
+#define CMP_OUTPUT_PLUG_CONTROL_REG_0  0xfffff0000904ULL
+
+static int cmp_read(struct firedtv *fdtv, void *buf, u64 addr, size_t len)
+{
+       int ret;
+
+       if (mutex_lock_interruptible(&fdtv->avc_mutex))
+               return -EINTR;
+
+       ret = fdtv->backend->read(fdtv, addr, buf, len);
+       if (ret < 0)
+               dev_err(fdtv->device, "CMP: read I/O error\n");
+
+       mutex_unlock(&fdtv->avc_mutex);
+       return ret;
+}
+
+static int cmp_lock(struct firedtv *fdtv, void *data, u64 addr, __be32 arg)
+{
+       int ret;
+
+       if (mutex_lock_interruptible(&fdtv->avc_mutex))
+               return -EINTR;
+
+       ret = fdtv->backend->lock(fdtv, addr, data, arg);
+       if (ret < 0)
+               dev_err(fdtv->device, "CMP: lock I/O error\n");
+
+       mutex_unlock(&fdtv->avc_mutex);
+       return ret;
+}
+
+static inline u32 get_opcr(__be32 opcr, u32 mask, u32 shift)
+{
+       return (be32_to_cpu(opcr) >> shift) & mask;
+}
+
+static inline void set_opcr(__be32 *opcr, u32 value, u32 mask, u32 shift)
+{
+       *opcr &= ~cpu_to_be32(mask << shift);
+       *opcr |= cpu_to_be32((value & mask) << shift);
+}
+
+#define get_opcr_online(v)             get_opcr((v), 0x1, 31)
+#define get_opcr_p2p_connections(v)    get_opcr((v), 0x3f, 24)
+#define get_opcr_channel(v)            get_opcr((v), 0x3f, 16)
+
+#define set_opcr_p2p_connections(p, v) set_opcr((p), (v), 0x3f, 24)
+#define set_opcr_channel(p, v)         set_opcr((p), (v), 0x3f, 16)
+#define set_opcr_data_rate(p, v)       set_opcr((p), (v), 0x3, 14)
+#define set_opcr_overhead_id(p, v)     set_opcr((p), (v), 0xf, 10)
+
+int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel)
+{
+       __be32 old_opcr, opcr;
+       u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
+       int attempts = 0;
+       int ret;
+
+       ret = cmp_read(fdtv, &opcr, opcr_address, 4);
+       if (ret < 0)
+               return ret;
+
+repeat:
+       if (!get_opcr_online(opcr)) {
+               dev_err(fdtv->device, "CMP: output offline\n");
+               return -EBUSY;
+       }
+
+       old_opcr = opcr;
+
+       if (get_opcr_p2p_connections(opcr)) {
+               if (get_opcr_channel(opcr) != channel) {
+                       dev_err(fdtv->device, "CMP: cannot change channel\n");
+                       return -EBUSY;
+               }
+               dev_info(fdtv->device, "CMP: overlaying connection\n");
+
+               /* We don't allocate isochronous resources. */
+       } else {
+               set_opcr_channel(&opcr, channel);
+               set_opcr_data_rate(&opcr, 2); /* S400 */
+
+               /* FIXME: this is for the worst case - optimize */
+               set_opcr_overhead_id(&opcr, 0);
+
+               /*
+                * FIXME: allocate isochronous channel and bandwidth at IRM
+                * fdtv->backend->alloc_resources(fdtv, channels_mask, bw);
+                */
+       }
+
+       set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) + 1);
+
+       ret = cmp_lock(fdtv, &opcr, opcr_address, old_opcr);
+       if (ret < 0)
+               return ret;
+
+       if (old_opcr != opcr) {
+               /*
+                * FIXME: if old_opcr.P2P_Connections > 0,
+                * deallocate isochronous channel and bandwidth at IRM
+                * if (...)
+                *      fdtv->backend->dealloc_resources(fdtv, channel, bw);
+                */
+
+               if (++attempts < 6) /* arbitrary limit */
+                       goto repeat;
+               return -EBUSY;
+       }
+
+       return 0;
+}
+
+void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel)
+{
+       __be32 old_opcr, opcr;
+       u64 opcr_address = CMP_OUTPUT_PLUG_CONTROL_REG_0 + (plug << 2);
+       int attempts = 0;
+
+       if (cmp_read(fdtv, &opcr, opcr_address, 4) < 0)
+               return;
+
+repeat:
+       if (!get_opcr_online(opcr) || !get_opcr_p2p_connections(opcr) ||
+           get_opcr_channel(opcr) != channel) {
+               dev_err(fdtv->device, "CMP: no connection to break\n");
+               return;
+       }
+
+       old_opcr = opcr;
+       set_opcr_p2p_connections(&opcr, get_opcr_p2p_connections(opcr) - 1);
+
+       if (cmp_lock(fdtv, &opcr, opcr_address, old_opcr) < 0)
+               return;
+
+       if (old_opcr != opcr) {
+               /*
+                * FIXME: if old_opcr.P2P_Connections == 1, i.e. we were last
+                * owner, deallocate isochronous channel and bandwidth at IRM
+                * if (...)
+                *      fdtv->backend->dealloc_resources(fdtv, channel, bw);
+                */
+
+               if (++attempts < 6) /* arbitrary limit */
+                       goto repeat;
+       }
+}
diff --git a/drivers/media/dvb/firewire/firedtv-ci.c b/drivers/media/dvb/firewire/firedtv-ci.c
new file mode 100644 (file)
index 0000000..eeb80d0
--- /dev/null
@@ -0,0 +1,260 @@
+/*
+ * FireDTV driver (formerly known as FireSAT)
+ *
+ * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
+ * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/dvb/ca.h>
+#include <linux/fs.h>
+#include <linux/module.h>
+
+#include <dvbdev.h>
+
+#include "firedtv.h"
+
+#define EN50221_TAG_APP_INFO_ENQUIRY   0x9f8020
+#define EN50221_TAG_CA_INFO_ENQUIRY    0x9f8030
+#define EN50221_TAG_CA_PMT             0x9f8032
+#define EN50221_TAG_ENTER_MENU         0x9f8022
+
+static int fdtv_ca_ready(struct firedtv_tuner_status *stat)
+{
+       return stat->ca_initialization_status   == 1 &&
+              stat->ca_error_flag              == 0 &&
+              stat->ca_dvb_flag                == 1 &&
+              stat->ca_module_present_status   == 1;
+}
+
+static int fdtv_get_ca_flags(struct firedtv_tuner_status *stat)
+{
+       int flags = 0;
+
+       if (stat->ca_module_present_status == 1)
+               flags |= CA_CI_MODULE_PRESENT;
+       if (stat->ca_initialization_status == 1 &&
+           stat->ca_error_flag            == 0 &&
+           stat->ca_dvb_flag              == 1)
+               flags |= CA_CI_MODULE_READY;
+       return flags;
+}
+
+static int fdtv_ca_reset(struct firedtv *fdtv)
+{
+       return avc_ca_reset(fdtv) ? -EFAULT : 0;
+}
+
+static int fdtv_ca_get_caps(void *arg)
+{
+       struct ca_caps *cap = arg;
+
+       cap->slot_num = 1;
+       cap->slot_type = CA_CI;
+       cap->descr_num = 1;
+       cap->descr_type = CA_ECD;
+       return 0;
+}
+
+static int fdtv_ca_get_slot_info(struct firedtv *fdtv, void *arg)
+{
+       struct firedtv_tuner_status stat;
+       struct ca_slot_info *slot = arg;
+
+       if (avc_tuner_status(fdtv, &stat))
+               return -EFAULT;
+
+       if (slot->num != 0)
+               return -EFAULT;
+
+       slot->type = CA_CI;
+       slot->flags = fdtv_get_ca_flags(&stat);
+       return 0;
+}
+
+static int fdtv_ca_app_info(struct firedtv *fdtv, void *arg)
+{
+       struct ca_msg *reply = arg;
+
+       return avc_ca_app_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0;
+}
+
+static int fdtv_ca_info(struct firedtv *fdtv, void *arg)
+{
+       struct ca_msg *reply = arg;
+
+       return avc_ca_info(fdtv, reply->msg, &reply->length) ? -EFAULT : 0;
+}
+
+static int fdtv_ca_get_mmi(struct firedtv *fdtv, void *arg)
+{
+       struct ca_msg *reply = arg;
+
+       return avc_ca_get_mmi(fdtv, reply->msg, &reply->length) ? -EFAULT : 0;
+}
+
+static int fdtv_ca_get_msg(struct firedtv *fdtv, void *arg)
+{
+       struct firedtv_tuner_status stat;
+       int err;
+
+       switch (fdtv->ca_last_command) {
+       case EN50221_TAG_APP_INFO_ENQUIRY:
+               err = fdtv_ca_app_info(fdtv, arg);
+               break;
+       case EN50221_TAG_CA_INFO_ENQUIRY:
+               err = fdtv_ca_info(fdtv, arg);
+               break;
+       default:
+               if (avc_tuner_status(fdtv, &stat))
+                       err = -EFAULT;
+               else if (stat.ca_mmi == 1)
+                       err = fdtv_ca_get_mmi(fdtv, arg);
+               else {
+                       dev_info(fdtv->device, "unhandled CA message 0x%08x\n",
+                                fdtv->ca_last_command);
+                       err = -EFAULT;
+               }
+       }
+       fdtv->ca_last_command = 0;
+       return err;
+}
+
+static int fdtv_ca_pmt(struct firedtv *fdtv, void *arg)
+{
+       struct ca_msg *msg = arg;
+       int data_pos;
+       int data_length;
+       int i;
+
+       data_pos = 4;
+       if (msg->msg[3] & 0x80) {
+               data_length = 0;
+               for (i = 0; i < (msg->msg[3] & 0x7f); i++)
+                       data_length = (data_length << 8) + msg->msg[data_pos++];
+       } else {
+               data_length = msg->msg[3];
+       }
+
+       return avc_ca_pmt(fdtv, &msg->msg[data_pos], data_length) ? -EFAULT : 0;
+}
+
+static int fdtv_ca_send_msg(struct firedtv *fdtv, void *arg)
+{
+       struct ca_msg *msg = arg;
+       int err;
+
+       /* Do we need a semaphore for this? */
+       fdtv->ca_last_command =
+               (msg->msg[0] << 16) + (msg->msg[1] << 8) + msg->msg[2];
+       switch (fdtv->ca_last_command) {
+       case EN50221_TAG_CA_PMT:
+               err = fdtv_ca_pmt(fdtv, arg);
+               break;
+       case EN50221_TAG_APP_INFO_ENQUIRY:
+               /* handled in ca_get_msg */
+               err = 0;
+               break;
+       case EN50221_TAG_CA_INFO_ENQUIRY:
+               /* handled in ca_get_msg */
+               err = 0;
+               break;
+       case EN50221_TAG_ENTER_MENU:
+               err = avc_ca_enter_menu(fdtv);
+               break;
+       default:
+               dev_err(fdtv->device, "unhandled CA message 0x%08x\n",
+                       fdtv->ca_last_command);
+               err = -EFAULT;
+       }
+       return err;
+}
+
+static int fdtv_ca_ioctl(struct inode *inode, struct file *file,
+                           unsigned int cmd, void *arg)
+{
+       struct dvb_device *dvbdev = file->private_data;
+       struct firedtv *fdtv = dvbdev->priv;
+       struct firedtv_tuner_status stat;
+       int err;
+
+       switch (cmd) {
+       case CA_RESET:
+               err = fdtv_ca_reset(fdtv);
+               break;
+       case CA_GET_CAP:
+               err = fdtv_ca_get_caps(arg);
+               break;
+       case CA_GET_SLOT_INFO:
+               err = fdtv_ca_get_slot_info(fdtv, arg);
+               break;
+       case CA_GET_MSG:
+               err = fdtv_ca_get_msg(fdtv, arg);
+               break;
+       case CA_SEND_MSG:
+               err = fdtv_ca_send_msg(fdtv, arg);
+               break;
+       default:
+               dev_info(fdtv->device, "unhandled CA ioctl %u\n", cmd);
+               err = -EOPNOTSUPP;
+       }
+
+       /* FIXME Is this necessary? */
+       avc_tuner_status(fdtv, &stat);
+
+       return err;
+}
+
+static unsigned int fdtv_ca_io_poll(struct file *file, poll_table *wait)
+{
+       return POLLIN;
+}
+
+static struct file_operations fdtv_ca_fops = {
+       .owner          = THIS_MODULE,
+       .ioctl          = dvb_generic_ioctl,
+       .open           = dvb_generic_open,
+       .release        = dvb_generic_release,
+       .poll           = fdtv_ca_io_poll,
+};
+
+static struct dvb_device fdtv_ca = {
+       .users          = 1,
+       .readers        = 1,
+       .writers        = 1,
+       .fops           = &fdtv_ca_fops,
+       .kernel_ioctl   = fdtv_ca_ioctl,
+};
+
+int fdtv_ca_register(struct firedtv *fdtv)
+{
+       struct firedtv_tuner_status stat;
+       int err;
+
+       if (avc_tuner_status(fdtv, &stat))
+               return -EINVAL;
+
+       if (!fdtv_ca_ready(&stat))
+               return -EFAULT;
+
+       err = dvb_register_device(&fdtv->adapter, &fdtv->cadev,
+                                 &fdtv_ca, fdtv, DVB_DEVICE_CA);
+
+       if (stat.ca_application_info == 0)
+               dev_err(fdtv->device, "CaApplicationInfo is not set\n");
+       if (stat.ca_date_time_request == 1)
+               avc_ca_get_time_date(fdtv, &fdtv->ca_time_interval);
+
+       return err;
+}
+
+void fdtv_ca_release(struct firedtv *fdtv)
+{
+       if (fdtv->cadev)
+               dvb_unregister_device(fdtv->cadev);
+}
diff --git a/drivers/media/dvb/firewire/firedtv-dvb.c b/drivers/media/dvb/firewire/firedtv-dvb.c
new file mode 100644 (file)
index 0000000..9d308dd
--- /dev/null
@@ -0,0 +1,364 @@
+/*
+ * FireDTV driver (formerly known as FireSAT)
+ *
+ * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
+ * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ */
+
+#include <linux/bitops.h>
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/mod_devicetable.h>
+#include <linux/module.h>
+#include <linux/mutex.h>
+#include <linux/slab.h>
+#include <linux/string.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+#include <dmxdev.h>
+#include <dvb_demux.h>
+#include <dvbdev.h>
+#include <dvb_frontend.h>
+
+#include "firedtv.h"
+
+static int alloc_channel(struct firedtv *fdtv)
+{
+       int i;
+
+       for (i = 0; i < 16; i++)
+               if (!__test_and_set_bit(i, &fdtv->channel_active))
+                       break;
+       return i;
+}
+
+static void collect_channels(struct firedtv *fdtv, int *pidc, u16 pid[])
+{
+       int i, n;
+
+       for (i = 0, n = 0; i < 16; i++)
+               if (test_bit(i, &fdtv->channel_active))
+                       pid[n++] = fdtv->channel_pid[i];
+       *pidc = n;
+}
+
+static inline void dealloc_channel(struct firedtv *fdtv, int i)
+{
+       __clear_bit(i, &fdtv->channel_active);
+}
+
+int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       struct firedtv *fdtv = dvbdmxfeed->demux->priv;
+       int pidc, c, ret;
+       u16 pids[16];
+
+       switch (dvbdmxfeed->type) {
+       case DMX_TYPE_TS:
+       case DMX_TYPE_SEC:
+               break;
+       default:
+               dev_err(fdtv->device, "can't start dmx feed: invalid type %u\n",
+                       dvbdmxfeed->type);
+               return -EINVAL;
+       }
+
+       if (mutex_lock_interruptible(&fdtv->demux_mutex))
+               return -EINTR;
+
+       if (dvbdmxfeed->type == DMX_TYPE_TS) {
+               switch (dvbdmxfeed->pes_type) {
+               case DMX_TS_PES_VIDEO:
+               case DMX_TS_PES_AUDIO:
+               case DMX_TS_PES_TELETEXT:
+               case DMX_TS_PES_PCR:
+               case DMX_TS_PES_OTHER:
+                       c = alloc_channel(fdtv);
+                       break;
+               default:
+                       dev_err(fdtv->device,
+                               "can't start dmx feed: invalid pes type %u\n",
+                               dvbdmxfeed->pes_type);
+                       ret = -EINVAL;
+                       goto out;
+               }
+       } else {
+               c = alloc_channel(fdtv);
+       }
+
+       if (c > 15) {
+               dev_err(fdtv->device, "can't start dmx feed: busy\n");
+               ret = -EBUSY;
+               goto out;
+       }
+
+       dvbdmxfeed->priv = (typeof(dvbdmxfeed->priv))(unsigned long)c;
+       fdtv->channel_pid[c] = dvbdmxfeed->pid;
+       collect_channels(fdtv, &pidc, pids);
+
+       if (dvbdmxfeed->pid == 8192) {
+               ret = avc_tuner_get_ts(fdtv);
+               if (ret) {
+                       dealloc_channel(fdtv, c);
+                       dev_err(fdtv->device, "can't get TS\n");
+                       goto out;
+               }
+       } else {
+               ret = avc_tuner_set_pids(fdtv, pidc, pids);
+               if (ret) {
+                       dealloc_channel(fdtv, c);
+                       dev_err(fdtv->device, "can't set PIDs\n");
+                       goto out;
+               }
+       }
+out:
+       mutex_unlock(&fdtv->demux_mutex);
+
+       return ret;
+}
+
+int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed)
+{
+       struct dvb_demux *demux = dvbdmxfeed->demux;
+       struct firedtv *fdtv = demux->priv;
+       int pidc, c, ret;
+       u16 pids[16];
+
+       if (dvbdmxfeed->type == DMX_TYPE_TS &&
+           !((dvbdmxfeed->ts_type & TS_PACKET) &&
+             (demux->dmx.frontend->source != DMX_MEMORY_FE))) {
+
+               if (dvbdmxfeed->ts_type & TS_DECODER) {
+                       if (dvbdmxfeed->pes_type >= DMX_TS_PES_OTHER ||
+                           !demux->pesfilter[dvbdmxfeed->pes_type])
+                               return -EINVAL;
+
+                       demux->pids[dvbdmxfeed->pes_type] |= 0x8000;
+                       demux->pesfilter[dvbdmxfeed->pes_type] = NULL;
+               }
+
+               if (!(dvbdmxfeed->ts_type & TS_DECODER &&
+                     dvbdmxfeed->pes_type < DMX_TS_PES_OTHER))
+                       return 0;
+       }
+
+       if (mutex_lock_interruptible(&fdtv->demux_mutex))
+               return -EINTR;
+
+       c = (unsigned long)dvbdmxfeed->priv;
+       dealloc_channel(fdtv, c);
+       collect_channels(fdtv, &pidc, pids);
+
+       ret = avc_tuner_set_pids(fdtv, pidc, pids);
+
+       mutex_unlock(&fdtv->demux_mutex);
+
+       return ret;
+}
+
+DVB_DEFINE_MOD_OPT_ADAPTER_NR(adapter_nr);
+
+int fdtv_dvb_register(struct firedtv *fdtv)
+{
+       int err;
+
+       err = dvb_register_adapter(&fdtv->adapter, fdtv_model_names[fdtv->type],
+                                  THIS_MODULE, fdtv->device, adapter_nr);
+       if (err < 0)
+               goto fail_log;
+
+       /*DMX_TS_FILTERING | DMX_SECTION_FILTERING*/
+       fdtv->demux.dmx.capabilities = 0;
+
+       fdtv->demux.priv        = fdtv;
+       fdtv->demux.filternum   = 16;
+       fdtv->demux.feednum     = 16;
+       fdtv->demux.start_feed  = fdtv_start_feed;
+       fdtv->demux.stop_feed   = fdtv_stop_feed;
+       fdtv->demux.write_to_decoder = NULL;
+
+       err = dvb_dmx_init(&fdtv->demux);
+       if (err)
+               goto fail_unreg_adapter;
+
+       fdtv->dmxdev.filternum    = 16;
+       fdtv->dmxdev.demux        = &fdtv->demux.dmx;
+       fdtv->dmxdev.capabilities = 0;
+
+       err = dvb_dmxdev_init(&fdtv->dmxdev, &fdtv->adapter);
+       if (err)
+               goto fail_dmx_release;
+
+       fdtv->frontend.source = DMX_FRONTEND_0;
+
+       err = fdtv->demux.dmx.add_frontend(&fdtv->demux.dmx, &fdtv->frontend);
+       if (err)
+               goto fail_dmxdev_release;
+
+       err = fdtv->demux.dmx.connect_frontend(&fdtv->demux.dmx,
+                                              &fdtv->frontend);
+       if (err)
+               goto fail_rem_frontend;
+
+       dvb_net_init(&fdtv->adapter, &fdtv->dvbnet, &fdtv->demux.dmx);
+
+       fdtv_frontend_init(fdtv);
+       err = dvb_register_frontend(&fdtv->adapter, &fdtv->fe);
+       if (err)
+               goto fail_net_release;
+
+       err = fdtv_ca_register(fdtv);
+       if (err)
+               dev_info(fdtv->device,
+                        "Conditional Access Module not enabled\n");
+       return 0;
+
+fail_net_release:
+       dvb_net_release(&fdtv->dvbnet);
+       fdtv->demux.dmx.close(&fdtv->demux.dmx);
+fail_rem_frontend:
+       fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
+fail_dmxdev_release:
+       dvb_dmxdev_release(&fdtv->dmxdev);
+fail_dmx_release:
+       dvb_dmx_release(&fdtv->demux);
+fail_unreg_adapter:
+       dvb_unregister_adapter(&fdtv->adapter);
+fail_log:
+       dev_err(fdtv->device, "DVB initialization failed\n");
+       return err;
+}
+
+void fdtv_dvb_unregister(struct firedtv *fdtv)
+{
+       fdtv_ca_release(fdtv);
+       dvb_unregister_frontend(&fdtv->fe);
+       dvb_net_release(&fdtv->dvbnet);
+       fdtv->demux.dmx.close(&fdtv->demux.dmx);
+       fdtv->demux.dmx.remove_frontend(&fdtv->demux.dmx, &fdtv->frontend);
+       dvb_dmxdev_release(&fdtv->dmxdev);
+       dvb_dmx_release(&fdtv->demux);
+       dvb_unregister_adapter(&fdtv->adapter);
+}
+
+const char *fdtv_model_names[] = {
+       [FIREDTV_UNKNOWN] = "unknown type",
+       [FIREDTV_DVB_S]   = "FireDTV S/CI",
+       [FIREDTV_DVB_C]   = "FireDTV C/CI",
+       [FIREDTV_DVB_T]   = "FireDTV T/CI",
+       [FIREDTV_DVB_S2]  = "FireDTV S2  ",
+};
+
+struct firedtv *fdtv_alloc(struct device *dev,
+                          const struct firedtv_backend *backend,
+                          const char *name, size_t name_len)
+{
+       struct firedtv *fdtv;
+       int i;
+
+       fdtv = kzalloc(sizeof(*fdtv), GFP_KERNEL);
+       if (!fdtv)
+               return NULL;
+
+       dev->driver_data        = fdtv;
+       fdtv->device            = dev;
+       fdtv->isochannel        = -1;
+       fdtv->voltage           = 0xff;
+       fdtv->tone              = 0xff;
+       fdtv->backend           = backend;
+
+       mutex_init(&fdtv->avc_mutex);
+       init_waitqueue_head(&fdtv->avc_wait);
+       fdtv->avc_reply_received = true;
+       mutex_init(&fdtv->demux_mutex);
+       INIT_WORK(&fdtv->remote_ctrl_work, avc_remote_ctrl_work);
+
+       for (i = ARRAY_SIZE(fdtv_model_names); --i; )
+               if (strlen(fdtv_model_names[i]) <= name_len &&
+                   strncmp(name, fdtv_model_names[i], name_len) == 0)
+                       break;
+       fdtv->type = i;
+
+       return fdtv;
+}
+
+#define MATCH_FLAGS (IEEE1394_MATCH_VENDOR_ID | IEEE1394_MATCH_MODEL_ID | \
+                    IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION)
+
+#define DIGITAL_EVERYWHERE_OUI 0x001287
+#define AVC_UNIT_SPEC_ID_ENTRY 0x00a02d
+#define AVC_SW_VERSION_ENTRY   0x010001
+
+static struct ieee1394_device_id fdtv_id_table[] = {
+       {
+               /* FloppyDTV S/CI and FloppyDTV S2 */
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000024,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
+       }, {
+               /* FloppyDTV T/CI */
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000025,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
+       }, {
+               /* FloppyDTV C/CI */
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000026,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
+       }, {
+               /* FireDTV S/CI and FloppyDTV S2 */
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000034,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
+       }, {
+               /* FireDTV T/CI */
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000035,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
+       }, {
+               /* FireDTV C/CI */
+               .match_flags    = MATCH_FLAGS,
+               .vendor_id      = DIGITAL_EVERYWHERE_OUI,
+               .model_id       = 0x000036,
+               .specifier_id   = AVC_UNIT_SPEC_ID_ENTRY,
+               .version        = AVC_SW_VERSION_ENTRY,
+       }, {}
+};
+MODULE_DEVICE_TABLE(ieee1394, fdtv_id_table);
+
+static int __init fdtv_init(void)
+{
+       return fdtv_1394_init(fdtv_id_table);
+}
+
+static void __exit fdtv_exit(void)
+{
+       fdtv_1394_exit();
+}
+
+module_init(fdtv_init);
+module_exit(fdtv_exit);
+
+MODULE_AUTHOR("Andreas Monitzer <andy@monitzer.com>");
+MODULE_AUTHOR("Ben Backx <ben@bbackx.com>");
+MODULE_DESCRIPTION("FireDTV DVB Driver");
+MODULE_LICENSE("GPL");
+MODULE_SUPPORTED_DEVICE("FireDTV DVB");
diff --git a/drivers/media/dvb/firewire/firedtv-fe.c b/drivers/media/dvb/firewire/firedtv-fe.c
new file mode 100644 (file)
index 0000000..7ba4363
--- /dev/null
@@ -0,0 +1,247 @@
+/*
+ * FireDTV driver (formerly known as FireSAT)
+ *
+ * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
+ * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ */
+
+#include <linux/device.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include <dvb_frontend.h>
+
+#include "firedtv.h"
+
+static int fdtv_dvb_init(struct dvb_frontend *fe)
+{
+       struct firedtv *fdtv = fe->sec_priv;
+       int err;
+
+       /* FIXME - allocate free channel at IRM */
+       fdtv->isochannel = fdtv->adapter.num;
+
+       err = cmp_establish_pp_connection(fdtv, fdtv->subunit,
+                                         fdtv->isochannel);
+       if (err) {
+               dev_err(fdtv->device,
+                       "could not establish point to point connection\n");
+               return err;
+       }
+
+       return fdtv->backend->start_iso(fdtv);
+}
+
+static int fdtv_sleep(struct dvb_frontend *fe)
+{
+       struct firedtv *fdtv = fe->sec_priv;
+
+       fdtv->backend->stop_iso(fdtv);
+       cmp_break_pp_connection(fdtv, fdtv->subunit, fdtv->isochannel);
+       fdtv->isochannel = -1;
+       return 0;
+}
+
+#define LNBCONTROL_DONTCARE 0xff
+
+static int fdtv_diseqc_send_master_cmd(struct dvb_frontend *fe,
+                                      struct dvb_diseqc_master_cmd *cmd)
+{
+       struct firedtv *fdtv = fe->sec_priv;
+
+       return avc_lnb_control(fdtv, LNBCONTROL_DONTCARE, LNBCONTROL_DONTCARE,
+                              LNBCONTROL_DONTCARE, 1, cmd);
+}
+
+static int fdtv_diseqc_send_burst(struct dvb_frontend *fe,
+                                 fe_sec_mini_cmd_t minicmd)
+{
+       return 0;
+}
+
+static int fdtv_set_tone(struct dvb_frontend *fe, fe_sec_tone_mode_t tone)
+{
+       struct firedtv *fdtv = fe->sec_priv;
+
+       fdtv->tone = tone;
+       return 0;
+}
+
+static int fdtv_set_voltage(struct dvb_frontend *fe,
+                           fe_sec_voltage_t voltage)
+{
+       struct firedtv *fdtv = fe->sec_priv;
+
+       fdtv->voltage = voltage;
+       return 0;
+}
+
+static int fdtv_read_status(struct dvb_frontend *fe, fe_status_t *status)
+{
+       struct firedtv *fdtv = fe->sec_priv;
+       struct firedtv_tuner_status stat;
+
+       if (avc_tuner_status(fdtv, &stat))
+               return -EINVAL;
+
+       if (stat.no_rf)
+               *status = 0;
+       else
+               *status = FE_HAS_SIGNAL | FE_HAS_VITERBI | FE_HAS_SYNC |
+                         FE_HAS_CARRIER | FE_HAS_LOCK;
+       return 0;
+}
+
+static int fdtv_read_ber(struct dvb_frontend *fe, u32 *ber)
+{
+       struct firedtv *fdtv = fe->sec_priv;
+       struct firedtv_tuner_status stat;
+
+       if (avc_tuner_status(fdtv, &stat))
+               return -EINVAL;
+
+       *ber = stat.ber;
+       return 0;
+}
+
+static int fdtv_read_signal_strength(struct dvb_frontend *fe, u16 *strength)
+{
+       struct firedtv *fdtv = fe->sec_priv;
+       struct firedtv_tuner_status stat;
+
+       if (avc_tuner_status(fdtv, &stat))
+               return -EINVAL;
+
+       *strength = stat.signal_strength << 8;
+       return 0;
+}
+
+static int fdtv_read_snr(struct dvb_frontend *fe, u16 *snr)
+{
+       struct firedtv *fdtv = fe->sec_priv;
+       struct firedtv_tuner_status stat;
+
+       if (avc_tuner_status(fdtv, &stat))
+               return -EINVAL;
+
+       /* C/N[dB] = -10 * log10(snr / 65535) */
+       *snr = stat.carrier_noise_ratio * 257;
+       return 0;
+}
+
+static int fdtv_read_uncorrected_blocks(struct dvb_frontend *fe, u32 *ucblocks)
+{
+       return -EOPNOTSUPP;
+}
+
+#define ACCEPTED 0x9
+
+static int fdtv_set_frontend(struct dvb_frontend *fe,
+                            struct dvb_frontend_parameters *params)
+{
+       struct firedtv *fdtv = fe->sec_priv;
+
+       /* FIXME: avc_tuner_dsd never returns ACCEPTED. Check status? */
+       if (avc_tuner_dsd(fdtv, params) != ACCEPTED)
+               return -EINVAL;
+       else
+               return 0; /* not sure of this... */
+}
+
+static int fdtv_get_frontend(struct dvb_frontend *fe,
+                            struct dvb_frontend_parameters *params)
+{
+       return -EOPNOTSUPP;
+}
+
+void fdtv_frontend_init(struct firedtv *fdtv)
+{
+       struct dvb_frontend_ops *ops = &fdtv->fe.ops;
+       struct dvb_frontend_info *fi = &ops->info;
+
+       ops->init                       = fdtv_dvb_init;
+       ops->sleep                      = fdtv_sleep;
+
+       ops->set_frontend               = fdtv_set_frontend;
+       ops->get_frontend               = fdtv_get_frontend;
+
+       ops->read_status                = fdtv_read_status;
+       ops->read_ber                   = fdtv_read_ber;
+       ops->read_signal_strength       = fdtv_read_signal_strength;
+       ops->read_snr                   = fdtv_read_snr;
+       ops->read_ucblocks              = fdtv_read_uncorrected_blocks;
+
+       ops->diseqc_send_master_cmd     = fdtv_diseqc_send_master_cmd;
+       ops->diseqc_send_burst          = fdtv_diseqc_send_burst;
+       ops->set_tone                   = fdtv_set_tone;
+       ops->set_voltage                = fdtv_set_voltage;
+
+       switch (fdtv->type) {
+       case FIREDTV_DVB_S:
+       case FIREDTV_DVB_S2:
+               fi->type                = FE_QPSK;
+
+               fi->frequency_min       = 950000;
+               fi->frequency_max       = 2150000;
+               fi->frequency_stepsize  = 125;
+               fi->symbol_rate_min     = 1000000;
+               fi->symbol_rate_max     = 40000000;
+
+               fi->caps                = FE_CAN_INVERSION_AUTO |
+                                         FE_CAN_FEC_1_2        |
+                                         FE_CAN_FEC_2_3        |
+                                         FE_CAN_FEC_3_4        |
+                                         FE_CAN_FEC_5_6        |
+                                         FE_CAN_FEC_7_8        |
+                                         FE_CAN_FEC_AUTO       |
+                                         FE_CAN_QPSK;
+               break;
+
+       case FIREDTV_DVB_C:
+               fi->type                = FE_QAM;
+
+               fi->frequency_min       = 47000000;
+               fi->frequency_max       = 866000000;
+               fi->frequency_stepsize  = 62500;
+               fi->symbol_rate_min     = 870000;
+               fi->symbol_rate_max     = 6900000;
+
+               fi->caps                = FE_CAN_INVERSION_AUTO |
+                                         FE_CAN_QAM_16         |
+                                         FE_CAN_QAM_32         |
+                                         FE_CAN_QAM_64         |
+                                         FE_CAN_QAM_128        |
+                                         FE_CAN_QAM_256        |
+                                         FE_CAN_QAM_AUTO;
+               break;
+
+       case FIREDTV_DVB_T:
+               fi->type                = FE_OFDM;
+
+               fi->frequency_min       = 49000000;
+               fi->frequency_max       = 861000000;
+               fi->frequency_stepsize  = 62500;
+
+               fi->caps                = FE_CAN_INVERSION_AUTO         |
+                                         FE_CAN_FEC_2_3                |
+                                         FE_CAN_TRANSMISSION_MODE_AUTO |
+                                         FE_CAN_GUARD_INTERVAL_AUTO    |
+                                         FE_CAN_HIERARCHY_AUTO;
+               break;
+
+       default:
+               dev_err(fdtv->device, "no frontend for model type %d\n",
+                       fdtv->type);
+       }
+       strcpy(fi->name, fdtv_model_names[fdtv->type]);
+
+       fdtv->fe.dvb = &fdtv->adapter;
+       fdtv->fe.sec_priv = fdtv;
+}
diff --git a/drivers/media/dvb/firewire/firedtv-rc.c b/drivers/media/dvb/firewire/firedtv-rc.c
new file mode 100644 (file)
index 0000000..46a6324
--- /dev/null
@@ -0,0 +1,190 @@
+/*
+ * FireDTV driver (formerly known as FireSAT)
+ *
+ * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
+ *
+ *     This program is free software; you can redistribute it and/or
+ *     modify it under the terms of the GNU General Public License as
+ *     published by the Free Software Foundation; either version 2 of
+ *     the License, or (at your option) any later version.
+ */
+
+#include <linux/bitops.h>
+#include <linux/input.h>
+#include <linux/kernel.h>
+#include <linux/string.h>
+#include <linux/types.h>
+
+#include "firedtv.h"
+
+/* fixed table with older keycodes, geared towards MythTV */
+const static u16 oldtable[] = {
+
+       /* code from device: 0x4501...0x451f */
+
+       KEY_ESC,
+       KEY_F9,
+       KEY_1,
+       KEY_2,
+       KEY_3,
+       KEY_4,
+       KEY_5,
+       KEY_6,
+       KEY_7,
+       KEY_8,
+       KEY_9,
+       KEY_I,
+       KEY_0,
+       KEY_ENTER,
+       KEY_RED,
+       KEY_UP,
+       KEY_GREEN,
+       KEY_F10,
+       KEY_SPACE,
+       KEY_F11,
+       KEY_YELLOW,
+       KEY_DOWN,
+       KEY_BLUE,
+       KEY_Z,
+       KEY_P,
+       KEY_PAGEDOWN,
+       KEY_LEFT,
+       KEY_W,
+       KEY_RIGHT,
+       KEY_P,
+       KEY_M,
+
+       /* code from device: 0x4540...0x4542 */
+
+       KEY_R,
+       KEY_V,
+       KEY_C,
+};
+
+/* user-modifiable table for a remote as sold in 2008 */
+const static u16 keytable[] = {
+
+       /* code from device: 0x0300...0x031f */
+
+       [0x00] = KEY_POWER,
+       [0x01] = KEY_SLEEP,
+       [0x02] = KEY_STOP,
+       [0x03] = KEY_OK,
+       [0x04] = KEY_RIGHT,
+       [0x05] = KEY_1,
+       [0x06] = KEY_2,
+       [0x07] = KEY_3,
+       [0x08] = KEY_LEFT,
+       [0x09] = KEY_4,
+       [0x0a] = KEY_5,
+       [0x0b] = KEY_6,
+       [0x0c] = KEY_UP,
+       [0x0d] = KEY_7,
+       [0x0e] = KEY_8,
+       [0x0f] = KEY_9,
+       [0x10] = KEY_DOWN,
+       [0x11] = KEY_TITLE,     /* "OSD" - fixme */
+       [0x12] = KEY_0,
+       [0x13] = KEY_F20,       /* "16:9" - fixme */
+       [0x14] = KEY_SCREEN,    /* "FULL" - fixme */
+       [0x15] = KEY_MUTE,
+       [0x16] = KEY_SUBTITLE,
+       [0x17] = KEY_RECORD,
+       [0x18] = KEY_TEXT,
+       [0x19] = KEY_AUDIO,
+       [0x1a] = KEY_RED,
+       [0x1b] = KEY_PREVIOUS,
+       [0x1c] = KEY_REWIND,
+       [0x1d] = KEY_PLAYPAUSE,
+       [0x1e] = KEY_NEXT,
+       [0x1f] = KEY_VOLUMEUP,
+
+       /* code from device: 0x0340...0x0354 */
+
+       [0x20] = KEY_CHANNELUP,
+       [0x21] = KEY_F21,       /* "4:3" - fixme */
+       [0x22] = KEY_TV,
+       [0x23] = KEY_DVD,
+       [0x24] = KEY_VCR,
+       [0x25] = KEY_AUX,
+       [0x26] = KEY_GREEN,
+       [0x27] = KEY_YELLOW,
+       [0x28] = KEY_BLUE,
+       [0x29] = KEY_CHANNEL,   /* "CH.LIST" */
+       [0x2a] = KEY_VENDOR,    /* "CI" - fixme */
+       [0x2b] = KEY_VOLUMEDOWN,
+       [0x2c] = KEY_CHANNELDOWN,
+       [0x2d] = KEY_LAST,
+       [0x2e] = KEY_INFO,
+       [0x2f] = KEY_FORWARD,
+       [0x30] = KEY_LIST,
+       [0x31] = KEY_FAVORITES,
+       [0x32] = KEY_MENU,
+       [0x33] = KEY_EPG,
+       [0x34] = KEY_EXIT,
+};
+
+int fdtv_register_rc(struct firedtv *fdtv, struct device *dev)
+{
+       struct input_dev *idev;
+       int i, err;
+
+       idev = input_allocate_device();
+       if (!idev)
+               return -ENOMEM;
+
+       fdtv->remote_ctrl_dev = idev;
+       idev->name = "FireDTV remote control";
+       idev->dev.parent = dev;
+       idev->evbit[0] = BIT_MASK(EV_KEY);
+       idev->keycode = kmemdup(keytable, sizeof(keytable), GFP_KERNEL);
+       if (!idev->keycode) {
+               err = -ENOMEM;
+               goto fail;
+       }
+       idev->keycodesize = sizeof(keytable[0]);
+       idev->keycodemax = ARRAY_SIZE(keytable);
+
+       for (i = 0; i < ARRAY_SIZE(keytable); i++)
+               set_bit(keytable[i], idev->keybit);
+
+       err = input_register_device(idev);
+       if (err)
+               goto fail_free_keymap;
+
+       return 0;
+
+fail_free_keymap:
+       kfree(idev->keycode);
+fail:
+       input_free_device(idev);
+       return err;
+}
+
+void fdtv_unregister_rc(struct firedtv *fdtv)
+{
+       kfree(fdtv->remote_ctrl_dev->keycode);
+       input_unregister_device(fdtv->remote_ctrl_dev);
+}
+
+void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code)
+{
+       u16 *keycode = fdtv->remote_ctrl_dev->keycode;
+
+       if (code >= 0x0300 && code <= 0x031f)
+               code = keycode[code - 0x0300];
+       else if (code >= 0x0340 && code <= 0x0354)
+               code = keycode[code - 0x0320];
+       else if (code >= 0x4501 && code <= 0x451f)
+               code = oldtable[code - 0x4501];
+       else if (code >= 0x4540 && code <= 0x4542)
+               code = oldtable[code - 0x4521];
+       else {
+               printk(KERN_DEBUG "firedtv: invalid key code 0x%04x "
+                      "from remote control\n", code);
+               return;
+       }
+
+       input_report_key(fdtv->remote_ctrl_dev, code, 1);
+       input_report_key(fdtv->remote_ctrl_dev, code, 0);
+}
diff --git a/drivers/media/dvb/firewire/firedtv.h b/drivers/media/dvb/firewire/firedtv.h
new file mode 100644 (file)
index 0000000..d48530b
--- /dev/null
@@ -0,0 +1,182 @@
+/*
+ * FireDTV driver (formerly known as FireSAT)
+ *
+ * Copyright (C) 2004 Andreas Monitzer <andy@monitzer.com>
+ * Copyright (C) 2008 Henrik Kurelid <henrik@kurelid.se>
+ *
+ *     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.
+ */
+
+#ifndef _FIREDTV_H
+#define _FIREDTV_H
+
+#include <linux/dvb/dmx.h>
+#include <linux/dvb/frontend.h>
+#include <linux/list.h>
+#include <linux/mutex.h>
+#include <linux/spinlock_types.h>
+#include <linux/types.h>
+#include <linux/wait.h>
+#include <linux/workqueue.h>
+
+#include <demux.h>
+#include <dmxdev.h>
+#include <dvb_demux.h>
+#include <dvb_frontend.h>
+#include <dvb_net.h>
+#include <dvbdev.h>
+
+struct firedtv_tuner_status {
+       unsigned active_system:8;
+       unsigned searching:1;
+       unsigned moving:1;
+       unsigned no_rf:1;
+       unsigned input:1;
+       unsigned selected_antenna:7;
+       unsigned ber:32;
+       unsigned signal_strength:8;
+       unsigned raster_frequency:2;
+       unsigned rf_frequency:22;
+       unsigned man_dep_info_length:8;
+       unsigned front_end_error:1;
+       unsigned antenna_error:1;
+       unsigned front_end_power_status:1;
+       unsigned power_supply:1;
+       unsigned carrier_noise_ratio:16;
+       unsigned power_supply_voltage:8;
+       unsigned antenna_voltage:8;
+       unsigned firewire_bus_voltage:8;
+       unsigned ca_mmi:1;
+       unsigned ca_pmt_reply:1;
+       unsigned ca_date_time_request:1;
+       unsigned ca_application_info:1;
+       unsigned ca_module_present_status:1;
+       unsigned ca_dvb_flag:1;
+       unsigned ca_error_flag:1;
+       unsigned ca_initialization_status:1;
+};
+
+enum model_type {
+       FIREDTV_UNKNOWN = 0,
+       FIREDTV_DVB_S   = 1,
+       FIREDTV_DVB_C   = 2,
+       FIREDTV_DVB_T   = 3,
+       FIREDTV_DVB_S2  = 4,
+};
+
+struct device;
+struct input_dev;
+struct firedtv;
+
+struct firedtv_backend {
+       int (*lock)(struct firedtv *fdtv, u64 addr, void *data, __be32 arg);
+       int (*read)(struct firedtv *fdtv, u64 addr, void *data, size_t len);
+       int (*write)(struct firedtv *fdtv, u64 addr, void *data, size_t len);
+       int (*start_iso)(struct firedtv *fdtv);
+       void (*stop_iso)(struct firedtv *fdtv);
+};
+
+struct firedtv {
+       struct device *device;
+       struct list_head list;
+
+       struct dvb_adapter      adapter;
+       struct dmxdev           dmxdev;
+       struct dvb_demux        demux;
+       struct dmx_frontend     frontend;
+       struct dvb_net          dvbnet;
+       struct dvb_frontend     fe;
+
+       struct dvb_device       *cadev;
+       int                     ca_last_command;
+       int                     ca_time_interval;
+
+       struct mutex            avc_mutex;
+       wait_queue_head_t       avc_wait;
+       bool                    avc_reply_received;
+       struct work_struct      remote_ctrl_work;
+       struct input_dev        *remote_ctrl_dev;
+
+       enum model_type         type;
+       char                    subunit;
+       char                    isochannel;
+       fe_sec_voltage_t        voltage;
+       fe_sec_tone_mode_t      tone;
+
+       const struct firedtv_backend *backend;
+       void                    *backend_data;
+
+       struct mutex            demux_mutex;
+       unsigned long           channel_active;
+       u16                     channel_pid[16];
+
+       size_t                  response_length;
+       u8                      response[512];
+};
+
+/* firedtv-1394.c */
+#ifdef CONFIG_DVB_FIREDTV_IEEE1394
+int fdtv_1394_init(struct ieee1394_device_id id_table[]);
+void fdtv_1394_exit(void);
+#else
+static inline int fdtv_1394_init(struct ieee1394_device_id it[]) { return 0; }
+static inline void fdtv_1394_exit(void) {}
+#endif
+
+/* firedtv-avc.c */
+int avc_recv(struct firedtv *fdtv, void *data, size_t length);
+int avc_tuner_status(struct firedtv *fdtv, struct firedtv_tuner_status *stat);
+struct dvb_frontend_parameters;
+int avc_tuner_dsd(struct firedtv *fdtv, struct dvb_frontend_parameters *params);
+int avc_tuner_set_pids(struct firedtv *fdtv, unsigned char pidc, u16 pid[]);
+int avc_tuner_get_ts(struct firedtv *fdtv);
+int avc_identify_subunit(struct firedtv *fdtv);
+struct dvb_diseqc_master_cmd;
+int avc_lnb_control(struct firedtv *fdtv, char voltage, char burst,
+                   char conttone, char nrdiseq,
+                   struct dvb_diseqc_master_cmd *diseqcmd);
+void avc_remote_ctrl_work(struct work_struct *work);
+int avc_register_remote_control(struct firedtv *fdtv);
+int avc_ca_app_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
+int avc_ca_info(struct firedtv *fdtv, char *app_info, unsigned int *len);
+int avc_ca_reset(struct firedtv *fdtv);
+int avc_ca_pmt(struct firedtv *fdtv, char *app_info, int length);
+int avc_ca_get_time_date(struct firedtv *fdtv, int *interval);
+int avc_ca_enter_menu(struct firedtv *fdtv);
+int avc_ca_get_mmi(struct firedtv *fdtv, char *mmi_object, unsigned int *len);
+int cmp_establish_pp_connection(struct firedtv *fdtv, int plug, int channel);
+void cmp_break_pp_connection(struct firedtv *fdtv, int plug, int channel);
+
+/* firedtv-ci.c */
+int fdtv_ca_register(struct firedtv *fdtv);
+void fdtv_ca_release(struct firedtv *fdtv);
+
+/* firedtv-dvb.c */
+int fdtv_start_feed(struct dvb_demux_feed *dvbdmxfeed);
+int fdtv_stop_feed(struct dvb_demux_feed *dvbdmxfeed);
+int fdtv_dvb_register(struct firedtv *fdtv);
+void fdtv_dvb_unregister(struct firedtv *fdtv);
+struct firedtv *fdtv_alloc(struct device *dev,
+                          const struct firedtv_backend *backend,
+                          const char *name, size_t name_len);
+extern const char *fdtv_model_names[];
+
+/* firedtv-fe.c */
+void fdtv_frontend_init(struct firedtv *fdtv);
+
+/* firedtv-rc.c */
+#ifdef CONFIG_DVB_FIREDTV_INPUT
+int fdtv_register_rc(struct firedtv *fdtv, struct device *dev);
+void fdtv_unregister_rc(struct firedtv *fdtv);
+void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code);
+#else
+static inline int fdtv_register_rc(struct firedtv *fdtv,
+                                  struct device *dev) { return 0; }
+static inline void fdtv_unregister_rc(struct firedtv *fdtv) {}
+static inline void fdtv_handle_rc(struct firedtv *fdtv, unsigned int code) {}
+#endif
+
+#endif /* _FIREDTV_H */
index 67cbce82cb913a0619f3a72fb8a4e519076cbf96..4dfed6aa2dbc54921e175a591f8a40668553b294 100644 (file)
  *             - blacklisted KWorld radio in hid-core.c and hid-ids.h
  * 2008-12-03  Mark Lord <mlord@pobox.com>
  *             - add support for DealExtreme USB Radio
+ * 2009-01-31  Bob Ross <pigiron@gmx.com>
+ *             - correction of stereo detection/setting
+ *             - correction of signal strength indicator scaling
+ * 2009-01-31  Rick Bronson <rick@efn.org>
+ *             Tobias Lorenz <tobias.lorenz@gmx.net>
+ *             - add LED status output
  *
  * ToDo:
  * - add firmware download/update support
  * - RDS support: interrupt mode, instead of polling
- * - add LED status output (check if that's not already done in firmware)
  */
 
 
@@ -881,6 +886,30 @@ static int si470x_rds_on(struct si470x_device *radio)
 
 
 
+/**************************************************************************
+ * General Driver Functions - LED_REPORT
+ **************************************************************************/
+
+/*
+ * si470x_set_led_state - sets the led state
+ */
+static int si470x_set_led_state(struct si470x_device *radio,
+               unsigned char led_state)
+{
+       unsigned char buf[LED_REPORT_SIZE];
+       int retval;
+
+       buf[0] = LED_REPORT;
+       buf[1] = LED_COMMAND;
+       buf[2] = led_state;
+
+       retval = si470x_set_report(radio, (void *) &buf, sizeof(buf));
+
+       return (retval < 0) ? -EINVAL : 0;
+}
+
+
+
 /**************************************************************************
  * RDS Driver Functions
  **************************************************************************/
@@ -1385,20 +1414,22 @@ static int si470x_vidioc_g_tuner(struct file *file, void *priv,
        };
 
        /* stereo indicator == stereo (instead of mono) */
-       if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 1)
-               tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
-       else
+       if ((radio->registers[STATUSRSSI] & STATUSRSSI_ST) == 0)
                tuner->rxsubchans = V4L2_TUNER_SUB_MONO;
+       else
+               tuner->rxsubchans = V4L2_TUNER_SUB_MONO | V4L2_TUNER_SUB_STEREO;
 
        /* mono/stereo selector */
-       if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 1)
-               tuner->audmode = V4L2_TUNER_MODE_MONO;
-       else
+       if ((radio->registers[POWERCFG] & POWERCFG_MONO) == 0)
                tuner->audmode = V4L2_TUNER_MODE_STEREO;
+       else
+               tuner->audmode = V4L2_TUNER_MODE_MONO;
 
        /* min is worst, max is best; signal:0..0xffff; rssi: 0..0xff */
-       tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI)
-                               * 0x0101;
+       /* measured in units of dbµV in 1 db increments (max at ~75 dbµV) */
+       tuner->signal = (radio->registers[STATUSRSSI] & STATUSRSSI_RSSI);
+       /* the ideal factor is 0xffff/75 = 873,8 */
+       tuner->signal = (tuner->signal * 873) + (8 * tuner->signal / 10);
 
        /* automatic frequency control: -1: freq to low, 1 freq to high */
        /* AFCRL does only indicate that freq. differs, not if too low/high */
@@ -1632,6 +1663,9 @@ static int si470x_usb_driver_probe(struct usb_interface *intf,
        /* set initial frequency */
        si470x_set_freq(radio, 87.5 * FREQ_MUL); /* available in all regions */
 
+       /* set led to connect state */
+       si470x_set_led_state(radio, BLINK_GREEN_LED);
+
        /* rds buffer allocation */
        radio->buf_size = rds_buf * 3;
        radio->buffer = kmalloc(radio->buf_size, GFP_KERNEL);
@@ -1715,6 +1749,9 @@ static void si470x_usb_driver_disconnect(struct usb_interface *intf)
        cancel_delayed_work_sync(&radio->work);
        usb_set_intfdata(intf, NULL);
        if (radio->users == 0) {
+               /* set led to disconnect state */
+               si470x_set_led_state(radio, BLINK_ORANGE_LED);
+
                video_unregister_device(radio->videodev);
                kfree(radio->buffer);
                kfree(radio);
index 5d882a44e3eee5444c00062f3e5edf70b118cc4e..2ac738fa6a07e0cd66fac559fd3c9688060dff39 100644 (file)
@@ -463,6 +463,8 @@ static int em28xx_audio_init(struct em28xx *dev)
        pcm->info_flags = 0;
        pcm->private_data = dev;
        strcpy(pcm->name, "Empia 28xx Capture");
+
+       snd_card_set_dev(card, &dev->udev->dev);
        strcpy(card->driver, "Empia Em28xx Audio");
        strcpy(card->shortname, "Em28xx Audio");
        strcpy(card->longname, "Empia Em28xx Audio");
index 2ed24527ecd61cea70287dd668725445799ee4fa..65e4901f4db70a713a4b1d60c0400c4ec9f9250a 100644 (file)
@@ -422,6 +422,7 @@ static void destroy_urbs(struct gspca_dev *gspca_dev)
                if (urb == NULL)
                        break;
 
+               BUG_ON(!gspca_dev->dev);
                gspca_dev->urb[i] = NULL;
                if (!gspca_dev->present)
                        usb_kill_urb(urb);
@@ -1950,8 +1951,12 @@ void gspca_disconnect(struct usb_interface *intf)
 {
        struct gspca_dev *gspca_dev = usb_get_intfdata(intf);
 
+       mutex_lock(&gspca_dev->usb_lock);
        gspca_dev->present = 0;
+       mutex_unlock(&gspca_dev->usb_lock);
 
+       destroy_urbs(gspca_dev);
+       gspca_dev->dev = NULL;
        usb_set_intfdata(intf, NULL);
 
        /* release the device */
index f6b3ef6e691be8465ab82b397b7c796bd27b0cf4..c13bd2aa0bea6180a98fe078be7449e6ea2e25ca 100644 (file)
@@ -393,7 +393,7 @@ static int ivtv_g_fmt_sliced_vbi_cap(struct file *file, void *fh, struct v4l2_fo
                return 0;
        }
 
-       v4l2_subdev_call(itv->sd_video, video, s_fmt, fmt);
+       v4l2_subdev_call(itv->sd_video, video, g_fmt, fmt);
        vbifmt->service_set = ivtv_get_service_set(vbifmt);
        return 0;
 }
@@ -1748,6 +1748,18 @@ static long ivtv_default(struct file *file, void *fh, int cmd, void *arg)
                break;
        }
 
+       case IVTV_IOC_DMA_FRAME:
+       case VIDEO_GET_PTS:
+       case VIDEO_GET_FRAME_COUNT:
+       case VIDEO_GET_EVENT:
+       case VIDEO_PLAY:
+       case VIDEO_STOP:
+       case VIDEO_FREEZE:
+       case VIDEO_CONTINUE:
+       case VIDEO_COMMAND:
+       case VIDEO_TRY_COMMAND:
+               return ivtv_decoder_ioctls(file, cmd, (void *)arg);
+
        default:
                return -EINVAL;
        }
@@ -1790,18 +1802,6 @@ static long ivtv_serialized_ioctl(struct ivtv *itv, struct file *filp,
                ivtv_vapi(itv, CX2341X_DEC_SET_AUDIO_MODE, 2, itv->audio_bilingual_mode, itv->audio_stereo_mode);
                return 0;
 
-       case IVTV_IOC_DMA_FRAME:
-       case VIDEO_GET_PTS:
-       case VIDEO_GET_FRAME_COUNT:
-       case VIDEO_GET_EVENT:
-       case VIDEO_PLAY:
-       case VIDEO_STOP:
-       case VIDEO_FREEZE:
-       case VIDEO_CONTINUE:
-       case VIDEO_COMMAND:
-       case VIDEO_TRY_COMMAND:
-               return ivtv_decoder_ioctls(filp, cmd, (void *)arg);
-
        default:
                break;
        }
index a1d6008efcbb5c5a2f22164dc6ab55e9b9b8e366..07c334f25aae69bf257a2a0cff91465bd5e784b9 100644 (file)
@@ -1155,23 +1155,23 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
 {
        struct soc_camera_host *ici = to_soc_camera_host(icd->dev.parent);
        struct pxa_camera_dev *pcdev = ici->priv;
-       const struct soc_camera_data_format *host_fmt, *cam_fmt = NULL;
-       const struct soc_camera_format_xlate *xlate;
+       const struct soc_camera_data_format *cam_fmt = NULL;
+       const struct soc_camera_format_xlate *xlate = NULL;
        struct soc_camera_sense sense = {
                .master_clock = pcdev->mclk,
                .pixel_clock_max = pcdev->ciclk / 4,
        };
-       int ret, buswidth;
+       int ret;
 
-       xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
-       if (!xlate) {
-               dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
-               return -EINVAL;
-       }
+       if (pixfmt) {
+               xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
+               if (!xlate) {
+                       dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
+                       return -EINVAL;
+               }
 
-       buswidth = xlate->buswidth;
-       host_fmt = xlate->host_fmt;
-       cam_fmt = xlate->cam_fmt;
+               cam_fmt = xlate->cam_fmt;
+       }
 
        /* If PCLK is used to latch data from the sensor, check sense */
        if (pcdev->platform_flags & PXA_CAMERA_PCLK_EN)
@@ -1201,8 +1201,8 @@ static int pxa_camera_set_fmt(struct soc_camera_device *icd,
        }
 
        if (pixfmt && !ret) {
-               icd->buswidth = buswidth;
-               icd->current_fmt = host_fmt;
+               icd->buswidth = xlate->buswidth;
+               icd->current_fmt = xlate->host_fmt;
        }
 
        return ret;
index 9a2586b07a05c610728de368efe637baddd2778a..ddcb81d0b81a36df1ebebe0b6663c0eed1887040 100644 (file)
@@ -603,21 +603,18 @@ static int sh_mobile_ceu_set_fmt(struct soc_camera_device *icd,
        const struct soc_camera_format_xlate *xlate;
        int ret;
 
+       if (!pixfmt)
+               return icd->ops->set_fmt(icd, pixfmt, rect);
+
        xlate = soc_camera_xlate_by_fourcc(icd, pixfmt);
        if (!xlate) {
                dev_warn(&ici->dev, "Format %x not found\n", pixfmt);
                return -EINVAL;
        }
 
-       switch (pixfmt) {
-       case 0:                         /* Only geometry change */
-               ret = icd->ops->set_fmt(icd, pixfmt, rect);
-               break;
-       default:
-               ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect);
-       }
+       ret = icd->ops->set_fmt(icd, xlate->cam_fmt->fourcc, rect);
 
-       if (pixfmt && !ret) {
+       if (!ret) {
                icd->buswidth = xlate->buswidth;
                icd->current_fmt = xlate->host_fmt;
                pcdev->camera_fmt = xlate->cam_fmt;
index c1e4ae27c61388f9c70c529badef2dfc9dd0808d..c705f248da8856d72c384d5b69b67df0c86a7567 100644 (file)
@@ -46,8 +46,8 @@ static int uvc_input_init(struct uvc_device *dev)
        usb_to_input_id(udev, &input->id);
        input->dev.parent = &dev->intf->dev;
 
-       set_bit(EV_KEY, input->evbit);
-       set_bit(BTN_0, input->keybit);
+       __set_bit(EV_KEY, input->evbit);
+       __set_bit(KEY_CAMERA, input->keybit);
 
        if ((ret = input_register_device(input)) < 0)
                goto error;
@@ -70,8 +70,10 @@ static void uvc_input_cleanup(struct uvc_device *dev)
 static void uvc_input_report_key(struct uvc_device *dev, unsigned int code,
        int value)
 {
-       if (dev->input)
+       if (dev->input) {
                input_report_key(dev->input, code, value);
+               input_sync(dev->input);
+       }
 }
 
 #else
@@ -96,7 +98,7 @@ static void uvc_event_streaming(struct uvc_device *dev, __u8 *data, int len)
                        return;
                uvc_trace(UVC_TRACE_STATUS, "Button (intf %u) %s len %d\n",
                        data[1], data[3] ? "pressed" : "released", len);
-               uvc_input_report_key(dev, BTN_0, data[3]);
+               uvc_input_report_key(dev, KEY_CAMERA, data[3]);
        } else {
                uvc_trace(UVC_TRACE_STATUS, "Stream %u error event %02x %02x "
                        "len %d.\n", data[1], data[2], data[3], len);
index 96ac88317b8ecbadd702a3934c883b579e50aa49..ea3aafbbda449696b6653edc9ebf02094490e067 100644 (file)
@@ -91,9 +91,9 @@ MODULE_PARM_DESC(mpt_msi_enable_fc, " Enable MSI Support for FC \
                controllers (default=0)");
 
 static int mpt_msi_enable_sas;
-module_param(mpt_msi_enable_sas, int, 1);
+module_param(mpt_msi_enable_sas, int, 0);
 MODULE_PARM_DESC(mpt_msi_enable_sas, " Enable MSI Support for SAS \
-               controllers (default=1)");
+               controllers (default=0)");
 
 
 static int mpt_channel_mapping;
index 1a4d04664d6dca96426c965b0ad80062f3042a95..aa266e1f69b255875ee5b98e67988b31019fcf18 100644 (file)
@@ -286,7 +286,7 @@ static int __init egpio_probe(struct platform_device *pdev)
        res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
        if (!res)
                goto fail;
-       ei->base_addr = ioremap_nocache(res->start, res->end - res->start);
+       ei->base_addr = ioremap_nocache(res->start, resource_size(res));
        if (!ei->base_addr)
                goto fail;
        pr_debug("EGPIO phys=%08x virt=%p\n", (u32)res->start, ei->base_addr);
@@ -307,7 +307,7 @@ static int __init egpio_probe(struct platform_device *pdev)
 
        ei->nchips = pdata->num_chips;
        ei->chip = kzalloc(sizeof(struct egpio_chip) * ei->nchips, GFP_KERNEL);
-       if (!ei) {
+       if (!ei->chip) {
                ret = -ENOMEM;
                goto fail;
        }
index ea9488e7ad6d60a7d8b80d90083d2cbe83d7beef..2e36057659e12acedd5d2be43268d692aaefe8e3 100644 (file)
@@ -678,6 +678,7 @@ static int __devexit pcf50633_remove(struct i2c_client *client)
 
 static struct i2c_device_id pcf50633_id_table[] = {
        {"pcf50633", 0x73},
+       {/* end of list */}
 };
 
 static struct i2c_driver pcf50633_driver = {
index 0e5761f12634c02c493e4b346b29ec8722eb3f21..4c7b7962f6b8002b18ef57c0a6d4015bcf7c2fc1 100644 (file)
@@ -1050,7 +1050,7 @@ static int __devinit sm501_gpio_register_chip(struct sm501_devdata *sm,
        return gpiochip_add(gchip);
 }
 
-static int sm501_register_gpio(struct sm501_devdata *sm)
+static int __devinit sm501_register_gpio(struct sm501_devdata *sm)
 {
        struct sm501_gpio *gpio = &sm->gpio;
        resource_size_t iobase = sm->io_res->start + SM501_GPIO;
@@ -1321,7 +1321,7 @@ static unsigned int sm501_mem_local[] = {
  * Common init code for an SM501
 */
 
-static int sm501_init_dev(struct sm501_devdata *sm)
+static int __devinit sm501_init_dev(struct sm501_devdata *sm)
 {
        struct sm501_initdata *idata;
        struct sm501_platdata *pdata;
@@ -1397,7 +1397,7 @@ static int sm501_init_dev(struct sm501_devdata *sm)
        return 0;
 }
 
-static int sm501_plat_probe(struct platform_device *dev)
+static int __devinit sm501_plat_probe(struct platform_device *dev)
 {
        struct sm501_devdata *sm;
        int ret;
@@ -1586,8 +1586,8 @@ static struct sm501_platdata sm501_pci_platdata = {
        .gpio_base      = -1,
 };
 
-static int sm501_pci_probe(struct pci_dev *dev,
-                          const struct pci_device_id *id)
+static int __devinit sm501_pci_probe(struct pci_dev *dev,
+                                    const struct pci_device_id *id)
 {
        struct sm501_devdata *sm;
        int err;
@@ -1693,7 +1693,7 @@ static void sm501_dev_remove(struct sm501_devdata *sm)
        sm501_gpio_remove(sm);
 }
 
-static void sm501_pci_remove(struct pci_dev *dev)
+static void __devexit sm501_pci_remove(struct pci_dev *dev)
 {
        struct sm501_devdata *sm = pci_get_drvdata(dev);
 
@@ -1727,16 +1727,16 @@ static struct pci_device_id sm501_pci_tbl[] = {
 
 MODULE_DEVICE_TABLE(pci, sm501_pci_tbl);
 
-static struct pci_driver sm501_pci_drv = {
+static struct pci_driver sm501_pci_driver = {
        .name           = "sm501",
        .id_table       = sm501_pci_tbl,
        .probe          = sm501_pci_probe,
-       .remove         = sm501_pci_remove,
+       .remove         = __devexit_p(sm501_pci_remove),
 };
 
 MODULE_ALIAS("platform:sm501");
 
-static struct platform_driver sm501_plat_drv = {
+static struct platform_driver sm501_plat_driver = {
        .driver         = {
                .name   = "sm501",
                .owner  = THIS_MODULE,
@@ -1749,14 +1749,14 @@ static struct platform_driver sm501_plat_drv = {
 
 static int __init sm501_base_init(void)
 {
-       platform_driver_register(&sm501_plat_drv);
-       return pci_register_driver(&sm501_pci_drv);
+       platform_driver_register(&sm501_plat_driver);
+       return pci_register_driver(&sm501_pci_driver);
 }
 
 static void __exit sm501_base_exit(void)
 {
-       platform_driver_unregister(&sm501_plat_drv);
-       pci_unregister_driver(&sm501_pci_drv);
+       platform_driver_unregister(&sm501_plat_driver);
+       pci_unregister_driver(&sm501_pci_driver);
 }
 
 module_init(sm501_base_init);
index e7ab0035d3054fdfd159b48c9e548150758b986b..68826f1e36bccd057f938919083e6877731025c3 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/i2c.h>
 #include <linux/i2c/twl4030.h>
 
-#ifdef CONFIG_ARM
+#if defined(CONFIG_ARCH_OMAP2) || defined(CONFIG_ARCH_OMAP3)
 #include <mach/cpu.h>
 #endif
 
index f92595c8f165b7223d66958f648ba183dbb5519e..84d5ea1ec17120e9c4d8d94b6a2c9376ac241449 100644 (file)
@@ -1111,7 +1111,7 @@ int wm8350_read_auxadc(struct wm8350 *wm8350, int channel, int scale, int vref)
        do {
                schedule_timeout_interruptible(1);
                reg = wm8350_reg_read(wm8350, WM8350_DIGITISER_CONTROL_1);
-       } while (tries-- && (reg & WM8350_AUXADC_POLL));
+       } while (--tries && (reg & WM8350_AUXADC_POLL));
 
        if (!tries)
                dev_err(wm8350->dev, "adc chn %d read timeout\n", channel);
@@ -1297,14 +1297,29 @@ static void wm8350_client_dev_register(struct wm8350 *wm8350,
 int wm8350_device_init(struct wm8350 *wm8350, int irq,
                       struct wm8350_platform_data *pdata)
 {
-       int ret = -EINVAL;
+       int ret;
        u16 id1, id2, mask_rev;
        u16 cust_id, mode, chip_rev;
 
        /* get WM8350 revision and config mode */
-       wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1);
-       wm8350->read_dev(wm8350, WM8350_ID, sizeof(id2), &id2);
-       wm8350->read_dev(wm8350, WM8350_REVISION, sizeof(mask_rev), &mask_rev);
+       ret = wm8350->read_dev(wm8350, WM8350_RESET_ID, sizeof(id1), &id1);
+       if (ret != 0) {
+               dev_err(wm8350->dev, "Failed to read ID: %d\n", ret);
+               goto err;
+       }
+
+       ret = wm8350->read_dev(wm8350, WM8350_ID, sizeof(id2), &id2);
+       if (ret != 0) {
+               dev_err(wm8350->dev, "Failed to read ID: %d\n", ret);
+               goto err;
+       }
+
+       ret = wm8350->read_dev(wm8350, WM8350_REVISION, sizeof(mask_rev),
+                              &mask_rev);
+       if (ret != 0) {
+               dev_err(wm8350->dev, "Failed to read revision: %d\n", ret);
+               goto err;
+       }
 
        id1 = be16_to_cpu(id1);
        id2 = be16_to_cpu(id2);
@@ -1404,14 +1419,12 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
                return ret;
        }
 
-       if (pdata && pdata->init) {
-               ret = pdata->init(wm8350);
-               if (ret != 0) {
-                       dev_err(wm8350->dev, "Platform init() failed: %d\n",
-                               ret);
-                       goto err;
-               }
-       }
+       wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0xFFFF);
+       wm8350_reg_write(wm8350, WM8350_INT_STATUS_1_MASK, 0xFFFF);
+       wm8350_reg_write(wm8350, WM8350_INT_STATUS_2_MASK, 0xFFFF);
+       wm8350_reg_write(wm8350, WM8350_UNDER_VOLTAGE_INT_STATUS_MASK, 0xFFFF);
+       wm8350_reg_write(wm8350, WM8350_GPIO_INT_STATUS_MASK, 0xFFFF);
+       wm8350_reg_write(wm8350, WM8350_COMPARATOR_INT_STATUS_MASK, 0xFFFF);
 
        mutex_init(&wm8350->auxadc_mutex);
        mutex_init(&wm8350->irq_mutex);
@@ -1430,6 +1443,15 @@ int wm8350_device_init(struct wm8350 *wm8350, int irq,
        }
        wm8350->chip_irq = irq;
 
+       if (pdata && pdata->init) {
+               ret = pdata->init(wm8350);
+               if (ret != 0) {
+                       dev_err(wm8350->dev, "Platform init() failed: %d\n",
+                               ret);
+                       goto err;
+               }
+       }
+
        wm8350_reg_write(wm8350, WM8350_SYSTEM_INTERRUPTS_MASK, 0x0);
 
        wm8350_client_dev_register(wm8350, "wm8350-codec",
index 68887b817d17e071a834fbbd71c4a86c44fc2796..9a4cc954cb7c72fcbfd4ef18e363e05795dab287 100644 (file)
@@ -3188,7 +3188,7 @@ const struct wm8350_reg_access wm8350_reg_io_map[] = {
        { 0x7CFF, 0x0C00, 0x7FFF }, /* R1   - ID */
        { 0x0000, 0x0000, 0x0000 }, /* R2 */
        { 0xBE3B, 0xBE3B, 0x8000 }, /* R3   - System Control 1 */
-       { 0xFCF7, 0xFCF7, 0xF800 }, /* R4   - System Control 2 */
+       { 0xFEF7, 0xFEF7, 0xF800 }, /* R4   - System Control 2 */
        { 0x80FF, 0x80FF, 0x8000 }, /* R5   - System Hibernate */
        { 0xFB0E, 0xFB0E, 0x0000 }, /* R6   - Interface Control */
        { 0x0000, 0x0000, 0x0000 }, /* R7 */
index f26667a7abf7c6ce0e7a3a911d7bb193f2489859..cf991850f01ba04b23ad40b1ded35747735b0bf4 100644 (file)
@@ -710,6 +710,7 @@ out:
 
 static struct pci_device_id ilo_devices[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_COMPAQ, 0xB204) },
+       { PCI_DEVICE(PCI_VENDOR_ID_HP, 0x3307) },
        { }
 };
 MODULE_DEVICE_TABLE(pci, ilo_devices);
@@ -758,7 +759,7 @@ static void __exit ilo_exit(void)
        class_destroy(ilo_class);
 }
 
-MODULE_VERSION("0.06");
+MODULE_VERSION("1.0");
 MODULE_ALIAS(ILO_NAME);
 MODULE_DESCRIPTION(ILO_NAME);
 MODULE_AUTHOR("David Altobelli <david.altobelli@hp.com>");
index 45b1f430685fca915aa12c7f28913fa4ed6a0733..513eb09a638f305d93f28aa2bdbfe967f70c32fc 100644 (file)
@@ -584,7 +584,7 @@ static int mmc_blk_probe(struct mmc_card *card)
        if (err)
                goto out;
 
-       string_get_size(get_capacity(md->disk) << 9, STRING_UNITS_2,
+       string_get_size((u64)get_capacity(md->disk) << 9, STRING_UNITS_2,
                        cap_str, sizeof(cap_str));
        printk(KERN_INFO "%s: %s %s %s %s\n",
                md->disk->disk_name, mmc_card_id(card), mmc_card_name(card),
index b92b172074ee5a6f2b698a0292951b900dbd3008..b9f1e84897cc14fc2cbfa1e12adff95b4b93bb2e 100644 (file)
@@ -494,7 +494,7 @@ static int mmc_test_basic_read(struct mmc_test_card *test)
 
        sg_init_one(&sg, test->buffer, 512);
 
-       ret = mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 1);
+       ret = mmc_test_simple_transfer(test, &sg, 1, 0, 1, 512, 0);
        if (ret)
                return ret;
 
index 76bfe16c09b1e3e159a8016b479408a906c5bebd..2b1196e6142c1b951e47655d36ea185ac9466019 100644 (file)
@@ -1548,9 +1548,10 @@ static bool filter(struct dma_chan *chan, void *slave)
 {
        struct dw_dma_slave *dws = slave;
 
-       if (dws->dma_dev == chan->device->dev)
+       if (dws->dma_dev == chan->device->dev) {
+               chan->private = dws;
                return true;
-       else
+       else
                return false;
 }
 #endif
index db37490f67ec724d68732cd56054735d684a223e..a631c81dce1243bcb9bacefd26dcd3f0e439073d 100644 (file)
@@ -55,6 +55,7 @@
 #define VS30                   (1 << 25)
 #define SDVS18                 (0x5 << 9)
 #define SDVS30                 (0x6 << 9)
+#define SDVS33                 (0x7 << 9)
 #define SDVSCLR                        0xFFFFF1FF
 #define SDVSDET                        0x00000400
 #define AUTOIDLE               0x1
@@ -375,6 +376,32 @@ static void mmc_omap_report_irq(struct mmc_omap_host *host, u32 status)
 }
 #endif  /* CONFIG_MMC_DEBUG */
 
+/*
+ * MMC controller internal state machines reset
+ *
+ * Used to reset command or data internal state machines, using respectively
+ *  SRC or SRD bit of SYSCTL register
+ * Can be called from interrupt context
+ */
+static inline void mmc_omap_reset_controller_fsm(struct mmc_omap_host *host,
+               unsigned long bit)
+{
+       unsigned long i = 0;
+       unsigned long limit = (loops_per_jiffy *
+                               msecs_to_jiffies(MMC_TIMEOUT_MS));
+
+       OMAP_HSMMC_WRITE(host->base, SYSCTL,
+                        OMAP_HSMMC_READ(host->base, SYSCTL) | bit);
+
+       while ((OMAP_HSMMC_READ(host->base, SYSCTL) & bit) &&
+               (i++ < limit))
+               cpu_relax();
+
+       if (OMAP_HSMMC_READ(host->base, SYSCTL) & bit)
+               dev_err(mmc_dev(host->mmc),
+                       "Timeout waiting on controller reset in %s\n",
+                       __func__);
+}
 
 /*
  * MMC controller IRQ handler
@@ -403,21 +430,17 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
                        (status & CMD_CRC)) {
                        if (host->cmd) {
                                if (status & CMD_TIMEOUT) {
-                                       OMAP_HSMMC_WRITE(host->base, SYSCTL,
-                                               OMAP_HSMMC_READ(host->base,
-                                                               SYSCTL) | SRC);
-                                       while (OMAP_HSMMC_READ(host->base,
-                                                       SYSCTL) & SRC)
-                                               ;
-
+                                       mmc_omap_reset_controller_fsm(host, SRC);
                                        host->cmd->error = -ETIMEDOUT;
                                } else {
                                        host->cmd->error = -EILSEQ;
                                }
                                end_cmd = 1;
                        }
-                       if (host->data)
+                       if (host->data) {
                                mmc_dma_cleanup(host);
+                               mmc_omap_reset_controller_fsm(host, SRD);
+                       }
                }
                if ((status & DATA_TIMEOUT) ||
                        (status & DATA_CRC)) {
@@ -426,12 +449,7 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
                                        mmc_dma_cleanup(host);
                                else
                                        host->data->error = -EILSEQ;
-                               OMAP_HSMMC_WRITE(host->base, SYSCTL,
-                                       OMAP_HSMMC_READ(host->base,
-                                                       SYSCTL) | SRD);
-                               while (OMAP_HSMMC_READ(host->base,
-                                               SYSCTL) & SRD)
-                                       ;
+                               mmc_omap_reset_controller_fsm(host, SRD);
                                end_trans = 1;
                        }
                }
@@ -456,13 +474,20 @@ static irqreturn_t mmc_omap_irq(int irq, void *dev_id)
 }
 
 /*
- * Switch MMC operating voltage
+ * Switch MMC interface voltage ... only relevant for MMC1.
+ *
+ * MMC2 and MMC3 use fixed 1.8V levels, and maybe a transceiver.
+ * The MMC2 transceiver controls are used instead of DAT4..DAT7.
+ * Some chips, like eMMC ones, use internal transceivers.
  */
 static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd)
 {
        u32 reg_val = 0;
        int ret;
 
+       if (host->id != OMAP_MMC1_DEVID)
+               return 0;
+
        /* Disable the clocks */
        clk_disable(host->fclk);
        clk_disable(host->iclk);
@@ -485,19 +510,26 @@ static int omap_mmc_switch_opcond(struct mmc_omap_host *host, int vdd)
        OMAP_HSMMC_WRITE(host->base, HCTL,
                OMAP_HSMMC_READ(host->base, HCTL) & SDVSCLR);
        reg_val = OMAP_HSMMC_READ(host->base, HCTL);
+
        /*
         * If a MMC dual voltage card is detected, the set_ios fn calls
         * this fn with VDD bit set for 1.8V. Upon card removal from the
         * slot, omap_mmc_set_ios sets the VDD back to 3V on MMC_POWER_OFF.
         *
-        * Only MMC1 supports 3.0V.  MMC2 will not function if SDVS30 is
-        * set in HCTL.
+        * Cope with a bit of slop in the range ... per data sheets:
+        *  - "1.8V" for vdds_mmc1/vdds_mmc1a can be up to 2.45V max,
+        *    but recommended values are 1.71V to 1.89V
+        *  - "3.0V" for vdds_mmc1/vdds_mmc1a can be up to 3.5V max,
+        *    but recommended values are 2.7V to 3.3V
+        *
+        * Board setup code shouldn't permit anything very out-of-range.
+        * TWL4030-family VMMC1 and VSIM regulators are fine (avoiding the
+        * middle range) but VSIM can't power DAT4..DAT7 at more than 3V.
         */
-       if (host->id == OMAP_MMC1_DEVID && (((1 << vdd) == MMC_VDD_32_33) ||
-                               ((1 << vdd) == MMC_VDD_33_34)))
-               reg_val |= SDVS30;
-       if ((1 << vdd) == MMC_VDD_165_195)
+       if ((1 << vdd) <= MMC_VDD_23_24)
                reg_val |= SDVS18;
+       else
+               reg_val |= SDVS30;
 
        OMAP_HSMMC_WRITE(host->base, HCTL, reg_val);
 
@@ -517,16 +549,15 @@ static void mmc_omap_detect(struct work_struct *work)
 {
        struct mmc_omap_host *host = container_of(work, struct mmc_omap_host,
                                                mmc_carddetect_work);
+       struct omap_mmc_slot_data *slot = &mmc_slot(host);
+
+       host->carddetect = slot->card_detect(slot->card_detect_irq);
 
        sysfs_notify(&host->mmc->class_dev.kobj, NULL, "cover_switch");
        if (host->carddetect) {
                mmc_detect_change(host->mmc, (HZ * 200) / 1000);
        } else {
-               OMAP_HSMMC_WRITE(host->base, SYSCTL,
-                       OMAP_HSMMC_READ(host->base, SYSCTL) | SRD);
-               while (OMAP_HSMMC_READ(host->base, SYSCTL) & SRD)
-                       ;
-
+               mmc_omap_reset_controller_fsm(host, SRD);
                mmc_detect_change(host->mmc, (HZ * 50) / 1000);
        }
 }
@@ -538,7 +569,6 @@ static irqreturn_t omap_mmc_cd_handler(int irq, void *dev_id)
 {
        struct mmc_omap_host *host = (struct mmc_omap_host *)dev_id;
 
-       host->carddetect = mmc_slot(host).card_detect(irq);
        schedule_work(&host->mmc_carddetect_work);
 
        return IRQ_HANDLED;
@@ -757,10 +787,14 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        case MMC_POWER_OFF:
                mmc_slot(host).set_power(host->dev, host->slot_id, 0, 0);
                /*
-                * Reset bus voltage to 3V if it got set to 1.8V earlier.
+                * Reset interface voltage to 3V if it's 1.8V now;
+                * only relevant on MMC-1, the others always use 1.8V.
+                *
                 * REVISIT: If we are able to detect cards after unplugging
                 * a 1.8V card, this code should not be needed.
                 */
+               if (host->id != OMAP_MMC1_DEVID)
+                       break;
                if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
                        int vdd = fls(host->mmc->ocr_avail) - 1;
                        if (omap_mmc_switch_opcond(host, vdd) != 0)
@@ -784,7 +818,9 @@ static void omap_mmc_set_ios(struct mmc_host *mmc, struct mmc_ios *ios)
        }
 
        if (host->id == OMAP_MMC1_DEVID) {
-               /* Only MMC1 can operate at 3V/1.8V */
+               /* Only MMC1 can interface at 3V without some flavor
+                * of external transceiver; but they all handle 1.8V.
+                */
                if ((OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET) &&
                        (ios->vdd == DUAL_VOLT_OCR_BIT)) {
                                /*
@@ -1137,7 +1173,9 @@ static int omap_mmc_suspend(struct platform_device *pdev, pm_message_t state)
                                                " level suspend\n");
                        }
 
-                       if (!(OMAP_HSMMC_READ(host->base, HCTL) & SDVSDET)) {
+                       if (host->id == OMAP_MMC1_DEVID
+                                       && !(OMAP_HSMMC_READ(host->base, HCTL)
+                                                       & SDVSDET)) {
                                OMAP_HSMMC_WRITE(host->base, HCTL,
                                        OMAP_HSMMC_READ(host->base, HCTL)
                                        & SDVSCLR);
index 35a98eec74149a916c1baf735bff1b6ceff0baa4..f4a67c65d301b4d5aacc52ac85c8e452d6c63fd7 100644 (file)
@@ -329,7 +329,7 @@ static void do_pio_write(struct s3cmci_host *host)
 
        to_ptr = host->base + host->sdidata;
 
-       while ((fifo = fifo_free(host))) {
+       while ((fifo = fifo_free(host)) > 3) {
                if (!host->pio_bytes) {
                        res = get_data_buffer(host, &host->pio_bytes,
                                                        &host->pio_ptr);
index f07255cb17ee7a9d50dd3beacecd9157f523f1f0..406da9a8d453718b7d057e174199a139cab332e1 100644 (file)
@@ -107,6 +107,7 @@ static const struct sdhci_pci_fixes sdhci_ene_714 = {
 
 static const struct sdhci_pci_fixes sdhci_cafe = {
        .quirks         = SDHCI_QUIRK_NO_SIMULT_VDD_AND_POWER |
+                         SDHCI_QUIRK_NO_BUSY_IRQ |
                          SDHCI_QUIRK_BROKEN_TIMEOUT_VAL,
 };
 
@@ -144,8 +145,7 @@ static int jmicron_probe(struct sdhci_pci_chip *chip)
                          SDHCI_QUIRK_32BIT_DMA_SIZE |
                          SDHCI_QUIRK_32BIT_ADMA_SIZE |
                          SDHCI_QUIRK_RESET_AFTER_REQUEST |
-                         SDHCI_QUIRK_BROKEN_SMALL_PIO |
-                         SDHCI_QUIRK_FORCE_HIGHSPEED;
+                         SDHCI_QUIRK_BROKEN_SMALL_PIO;
        }
 
        /*
index 6b2d1f99af6728d9cd12d42ebe2c71e0adaf08fe..accb592764edb4522a24160eced3db7afca13f4a 100644 (file)
@@ -1291,8 +1291,11 @@ static void sdhci_cmd_irq(struct sdhci_host *host, u32 intmask)
                if (host->cmd->data)
                        DBG("Cannot wait for busy signal when also "
                                "doing a data transfer");
-               else
+               else if (!(host->quirks & SDHCI_QUIRK_NO_BUSY_IRQ))
                        return;
+
+               /* The controller does not support the end-of-busy IRQ,
+                * fall through and take the SDHCI_INT_RESPONSE */
        }
 
        if (intmask & SDHCI_INT_RESPONSE)
@@ -1636,8 +1639,7 @@ int sdhci_add_host(struct sdhci_host *host)
        mmc->f_max = host->max_clk;
        mmc->caps = MMC_CAP_4_BIT_DATA | MMC_CAP_SDIO_IRQ;
 
-       if ((caps & SDHCI_CAN_DO_HISPD) ||
-               (host->quirks & SDHCI_QUIRK_FORCE_HIGHSPEED))
+       if (caps & SDHCI_CAN_DO_HISPD)
                mmc->caps |= MMC_CAP_SD_HIGHSPEED;
 
        mmc->ocr_avail = 0;
@@ -1723,7 +1725,9 @@ int sdhci_add_host(struct sdhci_host *host)
 #endif
 
 #ifdef SDHCI_USE_LEDS_CLASS
-       host->led.name = mmc_hostname(mmc);
+       snprintf(host->led_name, sizeof(host->led_name),
+               "%s::", mmc_hostname(mmc));
+       host->led.name = host->led_name;
        host->led.brightness = LED_OFF;
        host->led.default_trigger = mmc_hostname(mmc);
        host->led.brightness_set = sdhci_led_control;
index 3efba236394164b195674905d4e978856494b477..43c37c68d07af44c15ab89bb372730b13517be5a 100644 (file)
@@ -208,8 +208,8 @@ struct sdhci_host {
 #define SDHCI_QUIRK_BROKEN_TIMEOUT_VAL                 (1<<12)
 /* Controller has an issue with buffer bits for small transfers */
 #define SDHCI_QUIRK_BROKEN_SMALL_PIO                   (1<<13)
-/* Controller supports high speed but doesn't have the caps bit set */
-#define SDHCI_QUIRK_FORCE_HIGHSPEED                    (1<<14)
+/* Controller does not provide transfer-complete interrupt when not busy */
+#define SDHCI_QUIRK_NO_BUSY_IRQ                                (1<<14)
 
        int                     irq;            /* Device IRQ */
        void __iomem *          ioaddr;         /* Mapped address */
@@ -222,6 +222,7 @@ struct sdhci_host {
 
 #if defined(CONFIG_LEDS_CLASS) || defined(CONFIG_LEDS_CLASS_MODULE)
        struct led_classdev     led;            /* LED control */
+       char   led_name[32];
 #endif
 
        spinlock_t              lock;           /* Mutex */
index 821d0ed6bae3970453a38d2e40bb0bb802930b1d..c76d6e5f47ee305868da2bc6b382c205107b2247 100644 (file)
@@ -19,6 +19,7 @@ static int maprom_read (struct mtd_info *, loff_t, size_t, size_t *, u_char *);
 static int maprom_write (struct mtd_info *, loff_t, size_t, size_t *, const u_char *);
 static void maprom_nop (struct mtd_info *);
 static struct mtd_info *map_rom_probe(struct map_info *map);
+static int maprom_erase (struct mtd_info *mtd, struct erase_info *info);
 
 static struct mtd_chip_driver maprom_chipdrv = {
        .probe  = map_rom_probe,
@@ -42,6 +43,7 @@ static struct mtd_info *map_rom_probe(struct map_info *map)
        mtd->read = maprom_read;
        mtd->write = maprom_write;
        mtd->sync = maprom_nop;
+       mtd->erase = maprom_erase;
        mtd->flags = MTD_CAP_ROM;
        mtd->erasesize = map->size;
        mtd->writesize = 1;
@@ -71,6 +73,12 @@ static int maprom_write (struct mtd_info *mtd, loff_t to, size_t len, size_t *re
        return -EIO;
 }
 
+static int maprom_erase (struct mtd_info *mtd, struct erase_info *info)
+{
+       /* We do our best 8) */
+       return -EROFS;
+}
+
 static int __init map_rom_init(void)
 {
        register_mtd_chip_driver(&maprom_chipdrv);
index a425d09f35a02fd9f3fbd2f0ff9df68019ba11e3..00248e81ecd5b3350a71a3c5e5e79c03be7af088 100644 (file)
@@ -267,22 +267,28 @@ static int parse_cmdline(char *devname, char *szstart, char *szlength)
        if (*(szlength) != '+') {
                devlength = simple_strtoul(szlength, &buffer, 0);
                devlength = handle_unit(devlength, buffer) - devstart;
+               if (devlength < devstart)
+                       goto err_out;
+
+               devlength -= devstart;
        } else {
                devlength = simple_strtoul(szlength + 1, &buffer, 0);
                devlength = handle_unit(devlength, buffer);
        }
        T("slram: devname=%s, devstart=0x%lx, devlength=0x%lx\n",
                        devname, devstart, devlength);
-       if ((devstart < 0) || (devlength < 0) || (devlength % SLRAM_BLK_SZ != 0)) {
-               E("slram: Illegal start / length parameter.\n");
-               return(-EINVAL);
-       }
+       if (devlength % SLRAM_BLK_SZ != 0)
+               goto err_out;
 
        if ((devstart = register_device(devname, devstart, devlength))){
                unregister_devices();
                return((int)devstart);
        }
        return(0);
+
+err_out:
+       E("slram: Illegal length parameter.\n");
+       return(-EINVAL);
 }
 
 #ifndef MODULE
index acd4ea9b22781f841e4737d748e53122b8f020a7..5a401d8047ab52bfcdd690041272e80dfafda9cb 100644 (file)
@@ -12,6 +12,7 @@ config MTD_LPDDR
          DDR memories, intended for battery-operated systems.
 
 config MTD_QINFO_PROBE
+       depends on MTD_LPDDR
        tristate "Detect flash chips by QINFO probe"
        help
            Device Information for LPDDR chips is offered through the Overlay
index 0225cbbf22de3ceb21b14a6bb8cf05cb3987817a..043d50fb6ef65abd085a98cc42fe8ca6942dc85c 100644 (file)
@@ -491,7 +491,7 @@ config MTD_PCMCIA_ANONYMOUS
 
 config MTD_BFIN_ASYNC
        tristate "Blackfin BF533-STAMP Flash Chip Support"
-       depends on BFIN533_STAMP && MTD_CFI
+       depends on BFIN533_STAMP && MTD_CFI && MTD_COMPLEX_MAPPINGS
        select MTD_PARTITIONS
        default y
        help
index 6fec86aaed7ebd0100e9d921e4e01bc37806a047..576611f605db1df5063775a677d3cc499cb010e7 100644 (file)
@@ -152,14 +152,18 @@ static int __devinit bfin_flash_probe(struct platform_device *pdev)
 
        if (gpio_request(state->enet_flash_pin, DRIVER_NAME)) {
                pr_devinit(KERN_ERR DRIVER_NAME ": Failed to request gpio %d\n", state->enet_flash_pin);
+               kfree(state);
                return -EBUSY;
        }
        gpio_direction_output(state->enet_flash_pin, 1);
 
        pr_devinit(KERN_NOTICE DRIVER_NAME ": probing %d-bit flash bus\n", state->map.bankwidth * 8);
        state->mtd = do_map_probe(memory->name, &state->map);
-       if (!state->mtd)
+       if (!state->mtd) {
+               gpio_free(state->enet_flash_pin);
+               kfree(state);
                return -ENXIO;
+       }
 
 #ifdef CONFIG_MTD_PARTITIONS
        ret = parse_mtd_partitions(state->mtd, part_probe_types, &pdata->parts, 0);
index 5f7a245ed13294b5038aaed76e4a1383debc49a6..424f17d6ffd1270bfae71befae6975781814f168 100644 (file)
@@ -342,9 +342,9 @@ static struct pci_device_id ck804xrom_pci_tbl[] = {
        { 0, }
 };
 
+#if 0
 MODULE_DEVICE_TABLE(pci, ck804xrom_pci_tbl);
 
-#if 0
 static struct pci_driver ck804xrom_driver = {
        .name =         MOD_NAME,
        .id_table =     ck804xrom_pci_tbl,
index 87743661d48ebfc4e43f317f5ceddee6e9397fe8..4b122e7ab4b3a5efb36071359137e0a2637c80df 100644 (file)
@@ -29,6 +29,7 @@ struct physmap_flash_info {
        struct map_info         map[MAX_RESOURCES];
 #ifdef CONFIG_MTD_PARTITIONS
        int                     nr_parts;
+       struct mtd_partition    *parts;
 #endif
 };
 
@@ -45,25 +46,26 @@ static int physmap_flash_remove(struct platform_device *dev)
 
        physmap_data = dev->dev.platform_data;
 
-#ifdef CONFIG_MTD_CONCAT
-       if (info->cmtd != info->mtd[0]) {
+#ifdef CONFIG_MTD_PARTITIONS
+       if (info->nr_parts) {
+               del_mtd_partitions(info->cmtd);
+               kfree(info->parts);
+       } else if (physmap_data->nr_parts)
+               del_mtd_partitions(info->cmtd);
+       else
                del_mtd_device(info->cmtd);
+#else
+       del_mtd_device(info->cmtd);
+#endif
+
+#ifdef CONFIG_MTD_CONCAT
+       if (info->cmtd != info->mtd[0])
                mtd_concat_destroy(info->cmtd);
-       }
 #endif
 
        for (i = 0; i < MAX_RESOURCES; i++) {
-               if (info->mtd[i] != NULL) {
-#ifdef CONFIG_MTD_PARTITIONS
-                       if (info->nr_parts || physmap_data->nr_parts)
-                               del_mtd_partitions(info->mtd[i]);
-                       else
-                               del_mtd_device(info->mtd[i]);
-#else
-                       del_mtd_device(info->mtd[i]);
-#endif
+               if (info->mtd[i] != NULL)
                        map_destroy(info->mtd[i]);
-               }
        }
        return 0;
 }
@@ -86,9 +88,6 @@ static int physmap_flash_probe(struct platform_device *dev)
        int err = 0;
        int i;
        int devices_found = 0;
-#ifdef CONFIG_MTD_PARTITIONS
-       struct mtd_partition *parts;
-#endif
 
        physmap_data = dev->dev.platform_data;
        if (physmap_data == NULL)
@@ -167,10 +166,11 @@ static int physmap_flash_probe(struct platform_device *dev)
                goto err_out;
 
 #ifdef CONFIG_MTD_PARTITIONS
-       err = parse_mtd_partitions(info->cmtd, part_probe_types, &parts, 0);
+       err = parse_mtd_partitions(info->cmtd, part_probe_types,
+                               &info->parts, 0);
        if (err > 0) {
-               add_mtd_partitions(info->cmtd, parts, err);
-               kfree(parts);
+               add_mtd_partitions(info->cmtd, info->parts, err);
+               info->nr_parts = err;
                return 0;
        }
 
index c98c1570a40b1ef5f3f3931ab4e0512be0341406..47a33cec3793d4b3f1a8b512e3fcf95d5ca83aba 100644 (file)
@@ -139,7 +139,8 @@ static int atmel_nand_device_ready(struct mtd_info *mtd)
        struct nand_chip *nand_chip = mtd->priv;
        struct atmel_nand_host *host = nand_chip->priv;
 
-       return gpio_get_value(host->board->rdy_pin);
+       return gpio_get_value(host->board->rdy_pin) ^
+                !!host->board->rdy_pin_active_low;
 }
 
 /*
index 917cf8d3ae9561c5e4e1559758b46efb89d466d2..c2dfd3ea353d61315a8ed4bfc8c056201c30f67e 100644 (file)
@@ -149,7 +149,7 @@ static int __devexit orion_nand_remove(struct platform_device *pdev)
 
 static struct platform_driver orion_nand_driver = {
        .probe          = orion_nand_probe,
-       .remove         = orion_nand_remove,
+       .remove         = __devexit_p(orion_nand_remove),
        .driver         = {
                .name   = "orion_nand",
                .owner  = THIS_MODULE,
index b2563d384cf2998a8b763cf9767146716b718b86..c56698402420ab5493c83fed72dc3f2b44089f47 100644 (file)
@@ -102,8 +102,8 @@ static int vortex_debug = 1;
 #include <linux/delay.h>
 
 
-static char version[] __devinitdata =
-DRV_NAME ": Donald Becker and others.\n";
+static const char version[] __devinitconst =
+       DRV_NAME ": Donald Becker and others.\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("3Com 3c59x/3c9xx ethernet driver ");
@@ -2908,7 +2908,7 @@ static void vortex_get_drvinfo(struct net_device *dev,
                strcpy(info->bus_info, pci_name(VORTEX_PCI(vp)));
        } else {
                if (VORTEX_EISA(vp))
-                       sprintf(info->bus_info, dev_name(vp->gendev));
+                       strcpy(info->bus_info, dev_name(vp->gendev));
                else
                        sprintf(info->bus_info, "EISA 0x%lx %d",
                                        dev->base_addr, dev->irq);
index 35517b06ec3ff39901f8eeba255146e84ea8e7b0..a09e3a7cac4f7c834c6e65d9a462ea6158d9dd4c 100644 (file)
@@ -1602,6 +1602,28 @@ static int cp_ioctl (struct net_device *dev, struct ifreq *rq, int cmd)
        return rc;
 }
 
+static int cp_set_mac_address(struct net_device *dev, void *p)
+{
+       struct cp_private *cp = netdev_priv(dev);
+       struct sockaddr *addr = p;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+       spin_lock_irq(&cp->lock);
+
+       cpw8_f(Cfg9346, Cfg9346_Unlock);
+       cpw32_f(MAC0 + 0, le32_to_cpu (*(__le32 *) (dev->dev_addr + 0)));
+       cpw32_f(MAC0 + 4, le32_to_cpu (*(__le32 *) (dev->dev_addr + 4)));
+       cpw8_f(Cfg9346, Cfg9346_Lock);
+
+       spin_unlock_irq(&cp->lock);
+
+       return 0;
+}
+
 /* Serial EEPROM section. */
 
 /*  EEPROM_Ctrl bits. */
@@ -1821,7 +1843,7 @@ static const struct net_device_ops cp_netdev_ops = {
        .ndo_open               = cp_open,
        .ndo_stop               = cp_close,
        .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_mac_address    = cp_set_mac_address,
        .ndo_set_multicast_list = cp_set_rx_mode,
        .ndo_get_stats          = cp_get_stats,
        .ndo_do_ioctl           = cp_ioctl,
index 5341da604e8465df4aafedf5ebba6404db627ee6..29df398b7727436361d502aa46ca7476b92b1454 100644 (file)
@@ -640,6 +640,7 @@ static int rtl8139_start_xmit (struct sk_buff *skb,
 #ifdef CONFIG_NET_POLL_CONTROLLER
 static void rtl8139_poll_controller(struct net_device *dev);
 #endif
+static int rtl8139_set_mac_address(struct net_device *dev, void *p);
 static int rtl8139_poll(struct napi_struct *napi, int budget);
 static irqreturn_t rtl8139_interrupt (int irq, void *dev_instance);
 static int rtl8139_close (struct net_device *dev);
@@ -917,7 +918,7 @@ static const struct net_device_ops rtl8139_netdev_ops = {
        .ndo_stop               = rtl8139_close,
        .ndo_get_stats          = rtl8139_get_stats,
        .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_mac_address    = rtl8139_set_mac_address,
        .ndo_start_xmit         = rtl8139_start_xmit,
        .ndo_set_multicast_list = rtl8139_set_rx_mode,
        .ndo_do_ioctl           = netdev_ioctl,
@@ -2215,6 +2216,29 @@ static void rtl8139_poll_controller(struct net_device *dev)
 }
 #endif
 
+static int rtl8139_set_mac_address(struct net_device *dev, void *p)
+{
+       struct rtl8139_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->mmio_addr;
+       struct sockaddr *addr = p;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
+
+       spin_lock_irq(&tp->lock);
+
+       RTL_W8_F(Cfg9346, Cfg9346_Unlock);
+       RTL_W32_F(MAC0 + 0, cpu_to_le32 (*(u32 *) (dev->dev_addr + 0)));
+       RTL_W32_F(MAC0 + 4, cpu_to_le32 (*(u32 *) (dev->dev_addr + 4)));
+       RTL_W8_F(Cfg9346, Cfg9346_Lock);
+
+       spin_unlock_irq(&tp->lock);
+
+       return 0;
+}
+
 static int rtl8139_close (struct net_device *dev)
 {
        struct rtl8139_private *tp = netdev_priv(dev);
index 3fed3347f4b358097c3e6daa31418c01d0a897a4..e5ffc1c606c19691f8fe200389747550555cece3 100644 (file)
@@ -26,6 +26,15 @@ menuconfig NETDEVICES
 # that for each of the symbols.
 if NETDEVICES
 
+config COMPAT_NET_DEV_OPS
+       default y
+       bool "Enable older network device API compatiablity"
+       ---help---
+          This option enables kernel compatiability with older network devices
+          that do not use net_device_ops interface.
+
+         If unsure, say Y.
+
 config IFB
        tristate "Intermediate Functional Block support"
        depends on NET_CLS_ACT
@@ -1040,6 +1049,17 @@ config NI65
          To compile this driver as a module, choose M here. The module
          will be called ni65.
 
+config DNET
+       tristate "Dave ethernet support (DNET)"
+       depends on NET_ETHERNET && HAS_IOMEM
+       select PHYLIB
+       help
+         The Dave ethernet interface (DNET) is found on Qong Board FPGA.
+         Say Y to include support for the DNET chip.
+
+         To compile this driver as a module, choose M here: the module
+         will be called dnet.
+
 source "drivers/net/tulip/Kconfig"
 
 config AT1700
@@ -2019,14 +2039,6 @@ config IGB
          To compile this driver as a module, choose M here. The module
          will be called igb.
 
-config IGB_LRO 
-       bool "Use software LRO"
-       depends on IGB && INET
-       ---help---
-         Say Y here if you want to use large receive offload. 
-
-         If in doubt, say N.
-
 config IGB_DCA
        bool "Direct Cache Access (DCA) Support"
        default y
@@ -2309,6 +2321,7 @@ config UGETH_TX_ON_DEMAND
 config MV643XX_ETH
        tristate "Marvell Discovery (643XX) and Orion ethernet support"
        depends on MV64360 || MV64X60 || (PPC_MULTIPLATFORM && PPC32) || PLAT_ORION
+       select INET_LRO
        select PHYLIB
        help
          This driver supports the gigabit ethernet MACs in the
@@ -2318,16 +2331,6 @@ config MV643XX_ETH
          Some boards that use the Discovery chipset are the Momenco
          Ocelot C and Jaguar ATX and Pegasos II.
 
-config MV643XX_ETH_LRO
-       tristate "Marvell 643XX ethernet driver LRO support"
-       depends on MV643XX_ETH
-       select INET_LRO
-       help
-         Say y here if you want to use Large Receive Offload for the
-         mv643xx_eth driver.
-
-         If in doubt, say N.
-
 config QLA3XXX
        tristate "QLogic QLA3XXX Network Driver Support"
        depends on PCI
@@ -2360,6 +2363,17 @@ config ATL1E
          To compile this driver as a module, choose M here.  The module
          will be called atl1e.
 
+config ATL1C
+       tristate "Atheros L1C Gigabit Ethernet support (EXPERIMENTAL)"
+       depends on PCI && EXPERIMENTAL
+       select CRC32
+       select MII
+       help
+         This driver supports the Atheros L1C gigabit ethernet adapter.
+
+         To compile this driver as a module, choose M here.  The module
+         will be called atl1c.
+
 config JME
        tristate "JMicron(R) PCI-Express Gigabit Ethernet support"
        depends on PCI
@@ -2624,6 +2638,8 @@ config QLGE
 
 source "drivers/net/sfc/Kconfig"
 
+source "drivers/net/benet/Kconfig"
+
 endif # NETDEV_10000
 
 source "drivers/net/tokenring/Kconfig"
index ad87ba72cf1fc5f6014c0890e2863f4b325ad494..758ecdf4c8202d492f9ec683d696a6834e09262a 100644 (file)
@@ -17,10 +17,12 @@ obj-$(CONFIG_BONDING) += bonding/
 obj-$(CONFIG_ATL1) += atlx/
 obj-$(CONFIG_ATL2) += atlx/
 obj-$(CONFIG_ATL1E) += atl1e/
+obj-$(CONFIG_ATL1C) += atl1c/
 obj-$(CONFIG_GIANFAR) += gianfar_driver.o
 obj-$(CONFIG_TEHUTI) += tehuti.o
 obj-$(CONFIG_ENIC) += enic/
 obj-$(CONFIG_JME) += jme.o
+obj-$(CONFIG_BE2NET) += benet/
 
 gianfar_driver-objs := gianfar.o \
                gianfar_ethtool.o \
@@ -231,6 +233,7 @@ obj-$(CONFIG_ENC28J60) += enc28j60.o
 
 obj-$(CONFIG_XTENSA_XT2000_SONIC) += xtsonic.o
 
+obj-$(CONFIG_DNET) += dnet.o
 obj-$(CONFIG_MACB) += macb.o
 
 obj-$(CONFIG_ARM) += arm/
index 7a60bdd9a242f27320b23249455b794bb90bf4c8..d0d0c2fee054c28d0236d5b35e34fd5f44097b56 100644 (file)
@@ -552,18 +552,13 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
        struct lance_private *lp = netdev_priv(dev);
        volatile struct lance_regs *ll = lp->ll;
        volatile struct lance_init_block *ib = lp->init_block;
-       int entry, skblen, len;
+       int entry, skblen;
        int status = 0;
        unsigned long flags;
 
-       skblen = skb->len;
-       len = skblen;
-
-       if (len < ETH_ZLEN) {
-               len = ETH_ZLEN;
-               if (skb_padto(skb, ETH_ZLEN))
-                       return 0;
-       }
+       if (skb_padto(skb, ETH_ZLEN))
+               return 0;
+       skblen = max_t(unsigned, skb->len, ETH_ZLEN);
 
        local_irq_save(flags);
 
@@ -586,15 +581,11 @@ static int lance_start_xmit (struct sk_buff *skb, struct net_device *dev)
        }
 #endif
        entry = lp->tx_new & lp->tx_ring_mod_mask;
-       ib->btx_ring [entry].length = (-len) | 0xf000;
+       ib->btx_ring [entry].length = (-skblen) | 0xf000;
        ib->btx_ring [entry].misc = 0;
 
        skb_copy_from_linear_data(skb, (void *)&ib->tx_buf [entry][0], skblen);
 
-       /* Clear the slack of the packet, do I need this? */
-       if (len != skblen)
-               memset ((void *) &ib->tx_buf [entry][skblen], 0, len - skblen);
-
        /* Now, give the packet to the lance */
        ib->btx_ring [entry].tmd1_bits = (LE_T1_POK|LE_T1_OWN);
        lp->tx_new = (lp->tx_new+1) & lp->tx_ring_mod_mask;
index 9589d620639d7ee6a7e04000d617873ffb0d1c45..06a9f11669f31c9176fce319fb579419db020ee0 100644 (file)
@@ -437,7 +437,7 @@ MODULE_PARM_DESC(max_rx_desc, "AceNIC/3C985/GA620 max number of receive descript
 MODULE_PARM_DESC(tx_ratio, "AceNIC/3C985/GA620 ratio of NIC memory used for TX/RX descriptors (range 0-63)");
 
 
-static char version[] __devinitdata =
+static const char version[] __devinitconst =
   "acenic.c: v0.92 08/05/2002  Jes Sorensen, linux-acenic@SunSITE.dk\n"
   "                            http://home.cern.ch/~jes/gige/acenic.html\n";
 
index c69c0cdba4a26b1cc254f1ac112cce46171c5f04..811a3ccd14c107c56136af8884022f7cd9f4498f 100644 (file)
@@ -4,7 +4,7 @@
 #
 
 obj-$(CONFIG_ARM_AM79C961A)    += am79c961a.o
-obj-$(CONFIG_ARM_ETHERH)       += etherh.o ../8390.o
+obj-$(CONFIG_ARM_ETHERH)       += etherh.o
 obj-$(CONFIG_ARM_ETHER3)       += ether3.o
 obj-$(CONFIG_ARM_ETHER1)       += ether1.o
 obj-$(CONFIG_ARM_AT91_ETHER)   += at91_ether.o
index 54b52e5b1821bbcd196b3f2f70cea19c51a5ec37..f52f668c49bfae5fcf526d299f9368661dd0d32c 100644 (file)
@@ -641,15 +641,15 @@ static const struct net_device_ops etherh_netdev_ops = {
        .ndo_open               = etherh_open,
        .ndo_stop               = etherh_close,
        .ndo_set_config         = etherh_set_config,
-       .ndo_start_xmit         = ei_start_xmit,
-       .ndo_tx_timeout         = ei_tx_timeout,
-       .ndo_get_stats          = ei_get_stats,
-       .ndo_set_multicast_list = ei_set_multicast_list,
+       .ndo_start_xmit         = __ei_start_xmit,
+       .ndo_tx_timeout         = __ei_tx_timeout,
+       .ndo_get_stats          = __ei_get_stats,
+       .ndo_set_multicast_list = __ei_set_multicast_list,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = eth_mac_addr,
        .ndo_change_mtu         = eth_change_mtu,
 #ifdef CONFIG_NET_POLL_CONTROLLER
-       .ndo_poll_controller    = ei_poll,
+       .ndo_poll_controller    = __ei_poll,
 #endif
 };
 
index b39210cf4fb39fd3f16e6831ad8cf7e095f58e11..35cd264abae70e6436e9e0e2a1288a7aa5484c89 100644 (file)
@@ -560,7 +560,7 @@ ks8695_reset(struct ks8695_priv *ksp)
                msleep(1);
        }
 
-       if (reset_timeout == 0) {
+       if (reset_timeout < 0) {
                dev_crit(ksp->dev,
                         "Timeout waiting for DMA engines to reset\n");
                /* And blithely carry on */
diff --git a/drivers/net/atl1c/Makefile b/drivers/net/atl1c/Makefile
new file mode 100644 (file)
index 0000000..c37d966
--- /dev/null
@@ -0,0 +1,2 @@
+obj-$(CONFIG_ATL1C) += atl1c.o
+atl1c-objs := atl1c_main.o atl1c_hw.o atl1c_ethtool.o
diff --git a/drivers/net/atl1c/atl1c.h b/drivers/net/atl1c/atl1c.h
new file mode 100644 (file)
index 0000000..e1658ef
--- /dev/null
@@ -0,0 +1,605 @@
+/*
+ * Copyright(c) 2008 - 2009 Atheros Corporation. All rights reserved.
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _ATL1C_H_
+#define _ATL1C_H_
+
+#include <linux/version.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/errno.h>
+#include <linux/module.h>
+#include <linux/pci.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/skbuff.h>
+#include <linux/ioport.h>
+#include <linux/slab.h>
+#include <linux/list.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+#include <linux/in.h>
+#include <linux/ip.h>
+#include <linux/ipv6.h>
+#include <linux/udp.h>
+#include <linux/mii.h>
+#include <linux/io.h>
+#include <linux/vmalloc.h>
+#include <linux/pagemap.h>
+#include <linux/tcp.h>
+#include <linux/ethtool.h>
+#include <linux/if_vlan.h>
+#include <linux/workqueue.h>
+#include <net/checksum.h>
+#include <net/ip6_checksum.h>
+
+#include "atl1c_hw.h"
+
+/* Wake Up Filter Control */
+#define AT_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define AT_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
+#define AT_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
+#define AT_WUFC_MC   0x00000008 /* Multicast Wakeup Enable */
+#define AT_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
+
+#define AT_VLAN_TO_TAG(_vlan, _tag)       \
+       _tag =  ((((_vlan) >> 8) & 0xFF)  |\
+                (((_vlan) & 0xFF) << 8))
+
+#define AT_TAG_TO_VLAN(_tag, _vlan)     \
+       _vlan = ((((_tag) >> 8) & 0xFF) |\
+               (((_tag) & 0xFF) << 8))
+
+#define SPEED_0                   0xffff
+#define HALF_DUPLEX        1
+#define FULL_DUPLEX        2
+
+#define AT_RX_BUF_SIZE         (ETH_FRAME_LEN + VLAN_HLEN + ETH_FCS_LEN)
+#define MAX_JUMBO_FRAME_SIZE   (9*1024)
+#define MAX_TX_OFFLOAD_THRESH  (9*1024)
+
+#define AT_MAX_RECEIVE_QUEUE    4
+#define AT_DEF_RECEIVE_QUEUE   1
+#define AT_MAX_TRANSMIT_QUEUE  2
+
+#define AT_DMA_HI_ADDR_MASK     0xffffffff00000000ULL
+#define AT_DMA_LO_ADDR_MASK     0x00000000ffffffffULL
+
+#define AT_TX_WATCHDOG  (5 * HZ)
+#define AT_MAX_INT_WORK                5
+#define AT_TWSI_EEPROM_TIMEOUT         100
+#define AT_HW_MAX_IDLE_DELAY   10
+#define AT_SUSPEND_LINK_TIMEOUT 28
+
+#define AT_ASPM_L0S_TIMER      6
+#define AT_ASPM_L1_TIMER       12
+
+#define ATL1C_PCIE_L0S_L1_DISABLE      0x01
+#define ATL1C_PCIE_PHY_RESET           0x02
+
+#define ATL1C_ASPM_L0s_ENABLE          0x0001
+#define ATL1C_ASPM_L1_ENABLE           0x0002
+
+#define AT_REGS_LEN    (75 * sizeof(u32))
+#define AT_EEPROM_LEN  512
+
+#define ATL1C_GET_DESC(R, i, type)     (&(((type *)((R)->desc))[i]))
+#define ATL1C_RFD_DESC(R, i)   ATL1C_GET_DESC(R, i, struct atl1c_rx_free_desc)
+#define ATL1C_TPD_DESC(R, i)   ATL1C_GET_DESC(R, i, struct atl1c_tpd_desc)
+#define ATL1C_RRD_DESC(R, i)   ATL1C_GET_DESC(R, i, struct atl1c_recv_ret_status)
+
+/* tpd word 1 bit 0:7 General Checksum task offload */
+#define TPD_L4HDR_OFFSET_MASK  0x00FF
+#define TPD_L4HDR_OFFSET_SHIFT 0
+
+/* tpd word 1 bit 0:7 Large Send task offload (IPv4/IPV6) */
+#define TPD_TCPHDR_OFFSET_MASK 0x00FF
+#define TPD_TCPHDR_OFFSET_SHIFT        0
+
+/* tpd word 1 bit 0:7 Custom Checksum task offload */
+#define TPD_PLOADOFFSET_MASK   0x00FF
+#define TPD_PLOADOFFSET_SHIFT  0
+
+/* tpd word 1 bit 8:17 */
+#define TPD_CCSUM_EN_MASK      0x0001
+#define TPD_CCSUM_EN_SHIFT     8
+#define TPD_IP_CSUM_MASK       0x0001
+#define TPD_IP_CSUM_SHIFT      9
+#define TPD_TCP_CSUM_MASK      0x0001
+#define TPD_TCP_CSUM_SHIFT     10
+#define TPD_UDP_CSUM_MASK      0x0001
+#define TPD_UDP_CSUM_SHIFT     11
+#define TPD_LSO_EN_MASK                0x0001  /* TCP Large Send Offload */
+#define TPD_LSO_EN_SHIFT       12
+#define TPD_LSO_VER_MASK       0x0001
+#define TPD_LSO_VER_SHIFT      13      /* 0 : ipv4; 1 : ipv4/ipv6 */
+#define TPD_CON_VTAG_MASK      0x0001
+#define TPD_CON_VTAG_SHIFT     14
+#define TPD_INS_VTAG_MASK      0x0001
+#define TPD_INS_VTAG_SHIFT     15
+#define TPD_IPV4_PACKET_MASK   0x0001  /* valid when LSO VER  is 1 */
+#define TPD_IPV4_PACKET_SHIFT  16
+#define TPD_ETH_TYPE_MASK      0x0001
+#define TPD_ETH_TYPE_SHIFT     17      /* 0 : 802.3 frame; 1 : Ethernet */
+
+/* tpd word 18:25 Custom Checksum task offload */
+#define TPD_CCSUM_OFFSET_MASK  0x00FF
+#define TPD_CCSUM_OFFSET_SHIFT 18
+#define TPD_CCSUM_EPAD_MASK    0x0001
+#define TPD_CCSUM_EPAD_SHIFT   30
+
+/* tpd word 18:30 Large Send task offload (IPv4/IPV6) */
+#define TPD_MSS_MASK            0x1FFF
+#define TPD_MSS_SHIFT          18
+
+#define TPD_EOP_MASK           0x0001
+#define TPD_EOP_SHIFT          31
+
+struct atl1c_tpd_desc {
+       __le16  buffer_len; /* include 4-byte CRC */
+       __le16  vlan_tag;
+       __le32  word1;
+       __le64  buffer_addr;
+};
+
+struct atl1c_tpd_ext_desc {
+       u32 reservd_0;
+       __le32 word1;
+       __le32 pkt_len;
+       u32 reservd_1;
+};
+/* rrs word 0 bit 0:31 */
+#define RRS_RX_CSUM_MASK       0xFFFF
+#define RRS_RX_CSUM_SHIFT      0
+#define RRS_RX_RFD_CNT_MASK    0x000F
+#define RRS_RX_RFD_CNT_SHIFT   16
+#define RRS_RX_RFD_INDEX_MASK  0x0FFF
+#define RRS_RX_RFD_INDEX_SHIFT 20
+
+/* rrs flag bit 0:16 */
+#define RRS_HEAD_LEN_MASK      0x00FF
+#define RRS_HEAD_LEN_SHIFT     0
+#define RRS_HDS_TYPE_MASK      0x0003
+#define RRS_HDS_TYPE_SHIFT     8
+#define RRS_CPU_NUM_MASK       0x0003
+#define        RRS_CPU_NUM_SHIFT       10
+#define RRS_HASH_FLG_MASK      0x000F
+#define RRS_HASH_FLG_SHIFT     12
+
+#define RRS_HDS_TYPE_HEAD      1
+#define RRS_HDS_TYPE_DATA      2
+
+#define RRS_IS_NO_HDS_TYPE(flag) \
+       (((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == 0)
+
+#define RRS_IS_HDS_HEAD(flag) \
+       (((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == \
+                       RRS_HDS_TYPE_HEAD)
+
+#define RRS_IS_HDS_DATA(flag) \
+       (((flag) >> (RRS_HDS_TYPE_SHIFT)) & RRS_HDS_TYPE_MASK == \
+                       RRS_HDS_TYPE_DATA)
+
+/* rrs word 3 bit 0:31 */
+#define RRS_PKT_SIZE_MASK      0x3FFF
+#define RRS_PKT_SIZE_SHIFT     0
+#define RRS_ERR_L4_CSUM_MASK   0x0001
+#define RRS_ERR_L4_CSUM_SHIFT  14
+#define RRS_ERR_IP_CSUM_MASK   0x0001
+#define RRS_ERR_IP_CSUM_SHIFT  15
+#define RRS_VLAN_INS_MASK      0x0001
+#define RRS_VLAN_INS_SHIFT     16
+#define RRS_PROT_ID_MASK       0x0007
+#define RRS_PROT_ID_SHIFT      17
+#define RRS_RX_ERR_SUM_MASK    0x0001
+#define RRS_RX_ERR_SUM_SHIFT   20
+#define RRS_RX_ERR_CRC_MASK    0x0001
+#define RRS_RX_ERR_CRC_SHIFT   21
+#define RRS_RX_ERR_FAE_MASK    0x0001
+#define RRS_RX_ERR_FAE_SHIFT   22
+#define RRS_RX_ERR_TRUNC_MASK  0x0001
+#define RRS_RX_ERR_TRUNC_SHIFT 23
+#define RRS_RX_ERR_RUNC_MASK   0x0001
+#define RRS_RX_ERR_RUNC_SHIFT  24
+#define RRS_RX_ERR_ICMP_MASK   0x0001
+#define RRS_RX_ERR_ICMP_SHIFT  25
+#define RRS_PACKET_BCAST_MASK  0x0001
+#define RRS_PACKET_BCAST_SHIFT 26
+#define RRS_PACKET_MCAST_MASK  0x0001
+#define RRS_PACKET_MCAST_SHIFT 27
+#define RRS_PACKET_TYPE_MASK   0x0001
+#define RRS_PACKET_TYPE_SHIFT  28
+#define RRS_FIFO_FULL_MASK     0x0001
+#define RRS_FIFO_FULL_SHIFT    29
+#define RRS_802_3_LEN_ERR_MASK         0x0001
+#define RRS_802_3_LEN_ERR_SHIFT 30
+#define RRS_RXD_UPDATED_MASK   0x0001
+#define RRS_RXD_UPDATED_SHIFT  31
+
+#define RRS_ERR_L4_CSUM         0x00004000
+#define RRS_ERR_IP_CSUM         0x00008000
+#define RRS_VLAN_INS            0x00010000
+#define RRS_RX_ERR_SUM          0x00100000
+#define RRS_RX_ERR_CRC          0x00200000
+#define RRS_802_3_LEN_ERR      0x40000000
+#define RRS_RXD_UPDATED                0x80000000
+
+#define RRS_PACKET_TYPE_802_3          1
+#define RRS_PACKET_TYPE_ETH    0
+#define RRS_PACKET_IS_ETH(word) \
+       (((word) >> RRS_PACKET_TYPE_SHIFT) & RRS_PACKET_TYPE_MASK == \
+                       RRS_PACKET_TYPE_ETH)
+#define RRS_RXD_IS_VALID(word) \
+       ((((word) >> RRS_RXD_UPDATED_SHIFT) & RRS_RXD_UPDATED_MASK) == 1)
+
+#define RRS_PACKET_PROT_IS_IPV4_ONLY(word) \
+       ((((word) >> RRS_PROT_ID_SHIFT) & RRS_PROT_ID_MASK) == 1)
+#define RRS_PACKET_PROT_IS_IPV6_ONLY(word) \
+       ((((word) >> RRS_PROT_ID_SHIFT) & RRS_PROT_ID_MASK) == 6)
+
+struct atl1c_recv_ret_status {
+       __le32  word0;
+       __le32  rss_hash;
+       __le16  vlan_tag;
+       __le16  flag;
+       __le32  word3;
+};
+
+/* RFD desciptor */
+struct atl1c_rx_free_desc {
+       __le64  buffer_addr;
+};
+
+/* DMA Order Settings */
+enum atl1c_dma_order {
+       atl1c_dma_ord_in = 1,
+       atl1c_dma_ord_enh = 2,
+       atl1c_dma_ord_out = 4
+};
+
+enum atl1c_dma_rcb {
+       atl1c_rcb_64 = 0,
+       atl1c_rcb_128 = 1
+};
+
+enum atl1c_mac_speed {
+       atl1c_mac_speed_0 = 0,
+       atl1c_mac_speed_10_100 = 1,
+       atl1c_mac_speed_1000 = 2
+};
+
+enum atl1c_dma_req_block {
+       atl1c_dma_req_128 = 0,
+       atl1c_dma_req_256 = 1,
+       atl1c_dma_req_512 = 2,
+       atl1c_dma_req_1024 = 3,
+       atl1c_dma_req_2048 = 4,
+       atl1c_dma_req_4096 = 5
+};
+
+enum atl1c_rss_mode {
+       atl1c_rss_mode_disable = 0,
+       atl1c_rss_sig_que = 1,
+       atl1c_rss_mul_que_sig_int = 2,
+       atl1c_rss_mul_que_mul_int = 4,
+};
+
+enum atl1c_rss_type {
+       atl1c_rss_disable = 0,
+       atl1c_rss_ipv4 = 1,
+       atl1c_rss_ipv4_tcp = 2,
+       atl1c_rss_ipv6 = 4,
+       atl1c_rss_ipv6_tcp = 8
+};
+
+enum atl1c_nic_type {
+       athr_l1c = 0,
+       athr_l2c = 1,
+};
+
+enum atl1c_trans_queue {
+       atl1c_trans_normal = 0,
+       atl1c_trans_high = 1
+};
+
+struct atl1c_hw_stats {
+       /* rx */
+       unsigned long rx_ok;            /* The number of good packet received. */
+       unsigned long rx_bcast;         /* The number of good broadcast packet received. */
+       unsigned long rx_mcast;         /* The number of good multicast packet received. */
+       unsigned long rx_pause;         /* The number of Pause packet received. */
+       unsigned long rx_ctrl;          /* The number of Control packet received other than Pause frame. */
+       unsigned long rx_fcs_err;       /* The number of packets with bad FCS. */
+       unsigned long rx_len_err;       /* The number of packets with mismatch of length field and actual size. */
+       unsigned long rx_byte_cnt;      /* The number of bytes of good packet received. FCS is NOT included. */
+       unsigned long rx_runt;          /* The number of packets received that are less than 64 byte long and with good FCS. */
+       unsigned long rx_frag;          /* The number of packets received that are less than 64 byte long and with bad FCS. */
+       unsigned long rx_sz_64;         /* The number of good and bad packets received that are 64 byte long. */
+       unsigned long rx_sz_65_127;     /* The number of good and bad packets received that are between 65 and 127-byte long. */
+       unsigned long rx_sz_128_255;    /* The number of good and bad packets received that are between 128 and 255-byte long. */
+       unsigned long rx_sz_256_511;    /* The number of good and bad packets received that are between 256 and 511-byte long. */
+       unsigned long rx_sz_512_1023;   /* The number of good and bad packets received that are between 512 and 1023-byte long. */
+       unsigned long rx_sz_1024_1518;  /* The number of good and bad packets received that are between 1024 and 1518-byte long. */
+       unsigned long rx_sz_1519_max;   /* The number of good and bad packets received that are between 1519-byte and MTU. */
+       unsigned long rx_sz_ov;         /* The number of good and bad packets received that are more than MTU size truncated by Selene. */
+       unsigned long rx_rxf_ov;        /* The number of frame dropped due to occurrence of RX FIFO overflow. */
+       unsigned long rx_rrd_ov;        /* The number of frame dropped due to occurrence of RRD overflow. */
+       unsigned long rx_align_err;     /* Alignment Error */
+       unsigned long rx_bcast_byte_cnt; /* The byte count of broadcast packet received, excluding FCS. */
+       unsigned long rx_mcast_byte_cnt; /* The byte count of multicast packet received, excluding FCS. */
+       unsigned long rx_err_addr;      /* The number of packets dropped due to address filtering. */
+
+       /* tx */
+       unsigned long tx_ok;            /* The number of good packet transmitted. */
+       unsigned long tx_bcast;         /* The number of good broadcast packet transmitted. */
+       unsigned long tx_mcast;         /* The number of good multicast packet transmitted. */
+       unsigned long tx_pause;         /* The number of Pause packet transmitted. */
+       unsigned long tx_exc_defer;     /* The number of packets transmitted with excessive deferral. */
+       unsigned long tx_ctrl;          /* The number of packets transmitted is a control frame, excluding Pause frame. */
+       unsigned long tx_defer;         /* The number of packets transmitted that is deferred. */
+       unsigned long tx_byte_cnt;      /* The number of bytes of data transmitted. FCS is NOT included. */
+       unsigned long tx_sz_64;         /* The number of good and bad packets transmitted that are 64 byte long. */
+       unsigned long tx_sz_65_127;     /* The number of good and bad packets transmitted that are between 65 and 127-byte long. */
+       unsigned long tx_sz_128_255;    /* The number of good and bad packets transmitted that are between 128 and 255-byte long. */
+       unsigned long tx_sz_256_511;    /* The number of good and bad packets transmitted that are between 256 and 511-byte long. */
+       unsigned long tx_sz_512_1023;   /* The number of good and bad packets transmitted that are between 512 and 1023-byte long. */
+       unsigned long tx_sz_1024_1518;  /* The number of good and bad packets transmitted that are between 1024 and 1518-byte long. */
+       unsigned long tx_sz_1519_max;   /* The number of good and bad packets transmitted that are between 1519-byte and MTU. */
+       unsigned long tx_1_col;         /* The number of packets subsequently transmitted successfully with a single prior collision. */
+       unsigned long tx_2_col;         /* The number of packets subsequently transmitted successfully with multiple prior collisions. */
+       unsigned long tx_late_col;      /* The number of packets transmitted with late collisions. */
+       unsigned long tx_abort_col;     /* The number of transmit packets aborted due to excessive collisions. */
+       unsigned long tx_underrun;      /* The number of transmit packets aborted due to transmit FIFO underrun, or TRD FIFO underrun */
+       unsigned long tx_rd_eop;        /* The number of times that read beyond the EOP into the next frame area when TRD was not written timely */
+       unsigned long tx_len_err;       /* The number of transmit packets with length field does NOT match the actual frame size. */
+       unsigned long tx_trunc;         /* The number of transmit packets truncated due to size exceeding MTU. */
+       unsigned long tx_bcast_byte;    /* The byte count of broadcast packet transmitted, excluding FCS. */
+       unsigned long tx_mcast_byte;    /* The byte count of multicast packet transmitted, excluding FCS. */
+};
+
+struct atl1c_hw {
+       u8 __iomem      *hw_addr;            /* inner register address */
+       struct atl1c_adapter *adapter;
+       enum atl1c_nic_type  nic_type;
+       enum atl1c_dma_order dma_order;
+       enum atl1c_dma_rcb   rcb_value;
+       enum atl1c_dma_req_block dmar_block;
+       enum atl1c_dma_req_block dmaw_block;
+
+       u16 device_id;
+       u16 vendor_id;
+       u16 subsystem_id;
+       u16 subsystem_vendor_id;
+       u8 revision_id;
+
+       u32 intr_mask;
+       u8 dmaw_dly_cnt;
+       u8 dmar_dly_cnt;
+
+       u8 preamble_len;
+       u16 max_frame_size;
+       u16 min_frame_size;
+
+       enum atl1c_mac_speed mac_speed;
+       bool mac_duplex;
+       bool hibernate;
+       u16 media_type;
+#define MEDIA_TYPE_AUTO_SENSOR  0
+#define MEDIA_TYPE_100M_FULL    1
+#define MEDIA_TYPE_100M_HALF    2
+#define MEDIA_TYPE_10M_FULL     3
+#define MEDIA_TYPE_10M_HALF     4
+
+       u16 autoneg_advertised;
+       u16 mii_autoneg_adv_reg;
+       u16 mii_1000t_ctrl_reg;
+
+       u16 tx_imt;     /* TX Interrupt Moderator timer ( 2us resolution) */
+       u16 rx_imt;     /* RX Interrupt Moderator timer ( 2us resolution) */
+       u16 ict;        /* Interrupt Clear timer (2us resolution) */
+       u16 ctrl_flags;
+#define ATL1C_INTR_CLEAR_ON_READ       0x0001
+#define ATL1C_INTR_MODRT_ENABLE                0x0002
+#define ATL1C_CMB_ENABLE               0x0004
+#define ATL1C_SMB_ENABLE               0x0010
+#define ATL1C_TXQ_MODE_ENHANCE         0x0020
+#define ATL1C_RX_IPV6_CHKSUM           0x0040
+#define ATL1C_ASPM_L0S_SUPPORT         0x0080
+#define ATL1C_ASPM_L1_SUPPORT          0x0100
+#define ATL1C_ASPM_CTRL_MON            0x0200
+#define ATL1C_HIB_DISABLE              0x0400
+#define ATL1C_LINK_CAP_1000M           0x0800
+#define ATL1C_FPGA_VERSION             0x8000
+       u16 cmb_tpd;
+       u16 cmb_rrd;
+       u16 cmb_rx_timer; /* 2us resolution */
+       u16 cmb_tx_timer;
+       u32 smb_timer;
+
+       u16 rrd_thresh; /* Threshold of number of RRD produced to trigger
+                         interrupt request */
+       u16 tpd_thresh;
+       u8 tpd_burst;   /* Number of TPD to prefetch in cache-aligned burst. */
+       u8 rfd_burst;
+       enum atl1c_rss_type rss_type;
+       enum atl1c_rss_mode rss_mode;
+       u8 rss_hash_bits;
+       u32 base_cpu;
+       u32 indirect_tab;
+       u8 mac_addr[ETH_ALEN];
+       u8 perm_mac_addr[ETH_ALEN];
+
+       bool phy_configured;
+       bool re_autoneg;
+       bool emi_ca;
+};
+
+/*
+ * atl1c_ring_header represents a single, contiguous block of DMA space
+ * mapped for the three descriptor rings (tpd, rfd, rrd) and the two
+ * message blocks (cmb, smb) described below
+ */
+struct atl1c_ring_header {
+       void *desc;             /* virtual address */
+       dma_addr_t dma;         /* physical address*/
+       unsigned int size;      /* length in bytes */
+};
+
+/*
+ * atl1c_buffer is wrapper around a pointer to a socket buffer
+ * so a DMA handle can be stored along with the skb
+ */
+struct atl1c_buffer {
+       struct sk_buff *skb;    /* socket buffer */
+       u16 length;             /* rx buffer length */
+       u16 state;              /* state of buffer */
+#define ATL1_BUFFER_FREE       0
+#define ATL1_BUFFER_BUSY       1
+       dma_addr_t dma;
+};
+
+/* transimit packet descriptor (tpd) ring */
+struct atl1c_tpd_ring {
+       void *desc;             /* descriptor ring virtual address */
+       dma_addr_t dma;         /* descriptor ring physical address */
+       u16 size;               /* descriptor ring length in bytes */
+       u16 count;              /* number of descriptors in the ring */
+       u16 next_to_use;        /* this is protectd by adapter->tx_lock */
+       atomic_t next_to_clean;
+       struct atl1c_buffer *buffer_info;
+};
+
+/* receive free descriptor (rfd) ring */
+struct atl1c_rfd_ring {
+       void *desc;             /* descriptor ring virtual address */
+       dma_addr_t dma;         /* descriptor ring physical address */
+       u16 size;               /* descriptor ring length in bytes */
+       u16 count;              /* number of descriptors in the ring */
+       u16 next_to_use;
+       u16 next_to_clean;
+       struct atl1c_buffer *buffer_info;
+};
+
+/* receive return desciptor (rrd) ring */
+struct atl1c_rrd_ring {
+       void *desc;             /* descriptor ring virtual address */
+       dma_addr_t dma;         /* descriptor ring physical address */
+       u16 size;               /* descriptor ring length in bytes */
+       u16 count;              /* number of descriptors in the ring */
+       u16 next_to_use;
+       u16 next_to_clean;
+};
+
+struct atl1c_cmb {
+       void *cmb;
+       dma_addr_t dma;
+};
+
+struct atl1c_smb {
+       void *smb;
+       dma_addr_t dma;
+};
+
+/* board specific private data structure */
+struct atl1c_adapter {
+       struct net_device   *netdev;
+       struct pci_dev      *pdev;
+       struct vlan_group   *vlgrp;
+       struct napi_struct  napi;
+       struct atl1c_hw        hw;
+       struct atl1c_hw_stats  hw_stats;
+       struct net_device_stats net_stats;
+       struct mii_if_info  mii;    /* MII interface info */
+       u16 rx_buffer_len;
+
+       unsigned long flags;
+#define __AT_TESTING        0x0001
+#define __AT_RESETTING      0x0002
+#define __AT_DOWN           0x0003
+       u32 msg_enable;
+
+       bool have_msi;
+       u32 wol;
+       u16 link_speed;
+       u16 link_duplex;
+
+       spinlock_t mdio_lock;
+       spinlock_t tx_lock;
+       atomic_t irq_sem;
+
+       struct work_struct reset_task;
+       struct work_struct link_chg_task;
+       struct timer_list watchdog_timer;
+       struct timer_list phy_config_timer;
+
+       /* All Descriptor memory */
+       struct atl1c_ring_header ring_header;
+       struct atl1c_tpd_ring tpd_ring[AT_MAX_TRANSMIT_QUEUE];
+       struct atl1c_rfd_ring rfd_ring[AT_MAX_RECEIVE_QUEUE];
+       struct atl1c_rrd_ring rrd_ring[AT_MAX_RECEIVE_QUEUE];
+       struct atl1c_cmb cmb;
+       struct atl1c_smb smb;
+       int num_rx_queues;
+       u32 bd_number;     /* board number;*/
+};
+
+#define AT_WRITE_REG(a, reg, value) ( \
+               writel((value), ((a)->hw_addr + reg)))
+
+#define AT_WRITE_FLUSH(a) (\
+               readl((a)->hw_addr))
+
+#define AT_READ_REG(a, reg, pdata) do {                                        \
+               if (unlikely((a)->hibernate)) {                         \
+                       readl((a)->hw_addr + reg);                      \
+                       *(u32 *)pdata = readl((a)->hw_addr + reg);      \
+               } else {                                                \
+                       *(u32 *)pdata = readl((a)->hw_addr + reg);      \
+               }                                                       \
+       } while (0)
+
+#define AT_WRITE_REGB(a, reg, value) (\
+               writeb((value), ((a)->hw_addr + reg)))
+
+#define AT_READ_REGB(a, reg) (\
+               readb((a)->hw_addr + reg))
+
+#define AT_WRITE_REGW(a, reg, value) (\
+               writew((value), ((a)->hw_addr + reg)))
+
+#define AT_READ_REGW(a, reg) (\
+               readw((a)->hw_addr + reg))
+
+#define AT_WRITE_REG_ARRAY(a, reg, offset, value) ( \
+               writel((value), (((a)->hw_addr + reg) + ((offset) << 2))))
+
+#define AT_READ_REG_ARRAY(a, reg, offset) ( \
+               readl(((a)->hw_addr + reg) + ((offset) << 2)))
+
+extern char atl1c_driver_name[];
+extern char atl1c_driver_version[];
+
+extern int atl1c_up(struct atl1c_adapter *adapter);
+extern void atl1c_down(struct atl1c_adapter *adapter);
+extern void atl1c_reinit_locked(struct atl1c_adapter *adapter);
+extern s32 atl1c_reset_hw(struct atl1c_hw *hw);
+extern void atl1c_set_ethtool_ops(struct net_device *netdev);
+#endif /* _ATL1C_H_ */
diff --git a/drivers/net/atl1c/atl1c_ethtool.c b/drivers/net/atl1c/atl1c_ethtool.c
new file mode 100644 (file)
index 0000000..45c5b73
--- /dev/null
@@ -0,0 +1,317 @@
+/*
+ * Copyright(c) 2009 - 2009 Atheros Corporation. All rights reserved.
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ */
+
+#include <linux/netdevice.h>
+#include <linux/ethtool.h>
+
+#include "atl1c.h"
+
+static int atl1c_get_settings(struct net_device *netdev,
+                             struct ethtool_cmd *ecmd)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       struct atl1c_hw *hw = &adapter->hw;
+
+       ecmd->supported = (SUPPORTED_10baseT_Half  |
+                          SUPPORTED_10baseT_Full  |
+                          SUPPORTED_100baseT_Half |
+                          SUPPORTED_100baseT_Full |
+                          SUPPORTED_Autoneg       |
+                          SUPPORTED_TP);
+       if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M)
+               ecmd->supported |= SUPPORTED_1000baseT_Full;
+
+       ecmd->advertising = ADVERTISED_TP;
+
+       ecmd->advertising |= hw->autoneg_advertised;
+
+       ecmd->port = PORT_TP;
+       ecmd->phy_address = 0;
+       ecmd->transceiver = XCVR_INTERNAL;
+
+       if (adapter->link_speed != SPEED_0) {
+               ecmd->speed = adapter->link_speed;
+               if (adapter->link_duplex == FULL_DUPLEX)
+                       ecmd->duplex = DUPLEX_FULL;
+               else
+                       ecmd->duplex = DUPLEX_HALF;
+       } else {
+               ecmd->speed = -1;
+               ecmd->duplex = -1;
+       }
+
+       ecmd->autoneg = AUTONEG_ENABLE;
+       return 0;
+}
+
+static int atl1c_set_settings(struct net_device *netdev,
+                             struct ethtool_cmd *ecmd)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       struct atl1c_hw *hw = &adapter->hw;
+       u16  autoneg_advertised;
+
+       while (test_and_set_bit(__AT_RESETTING, &adapter->flags))
+               msleep(1);
+
+       if (ecmd->autoneg == AUTONEG_ENABLE) {
+               autoneg_advertised = ADVERTISED_Autoneg;
+       } else {
+               if (ecmd->speed == SPEED_1000) {
+                       if (ecmd->duplex != DUPLEX_FULL) {
+                               if (netif_msg_link(adapter))
+                                       dev_warn(&adapter->pdev->dev,
+                                               "1000M half is invalid\n");
+                               clear_bit(__AT_RESETTING, &adapter->flags);
+                               return -EINVAL;
+                       }
+                       autoneg_advertised = ADVERTISED_1000baseT_Full;
+               } else if (ecmd->speed == SPEED_100) {
+                       if (ecmd->duplex == DUPLEX_FULL)
+                               autoneg_advertised = ADVERTISED_100baseT_Full;
+                       else
+                               autoneg_advertised = ADVERTISED_100baseT_Half;
+               } else {
+                       if (ecmd->duplex == DUPLEX_FULL)
+                               autoneg_advertised = ADVERTISED_10baseT_Full;
+                       else
+                               autoneg_advertised = ADVERTISED_10baseT_Half;
+               }
+       }
+
+       if (hw->autoneg_advertised != autoneg_advertised) {
+               hw->autoneg_advertised = autoneg_advertised;
+               if (atl1c_restart_autoneg(hw) != 0) {
+                       if (netif_msg_link(adapter))
+                               dev_warn(&adapter->pdev->dev,
+                                       "ethtool speed/duplex setting failed\n");
+                       clear_bit(__AT_RESETTING, &adapter->flags);
+                       return -EINVAL;
+               }
+       }
+       clear_bit(__AT_RESETTING, &adapter->flags);
+       return 0;
+}
+
+static u32 atl1c_get_tx_csum(struct net_device *netdev)
+{
+       return (netdev->features & NETIF_F_HW_CSUM) != 0;
+}
+
+static u32 atl1c_get_msglevel(struct net_device *netdev)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       return adapter->msg_enable;
+}
+
+static void atl1c_set_msglevel(struct net_device *netdev, u32 data)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       adapter->msg_enable = data;
+}
+
+static int atl1c_get_regs_len(struct net_device *netdev)
+{
+       return AT_REGS_LEN;
+}
+
+static void atl1c_get_regs(struct net_device *netdev,
+                          struct ethtool_regs *regs, void *p)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       struct atl1c_hw *hw = &adapter->hw;
+       u32 *regs_buff = p;
+       u16 phy_data;
+
+       memset(p, 0, AT_REGS_LEN);
+
+       regs->version = 0;
+       AT_READ_REG(hw, REG_VPD_CAP,              p++);
+       AT_READ_REG(hw, REG_PM_CTRL,              p++);
+       AT_READ_REG(hw, REG_MAC_HALF_DUPLX_CTRL,  p++);
+       AT_READ_REG(hw, REG_TWSI_CTRL,            p++);
+       AT_READ_REG(hw, REG_PCIE_DEV_MISC_CTRL,   p++);
+       AT_READ_REG(hw, REG_MASTER_CTRL,          p++);
+       AT_READ_REG(hw, REG_MANUAL_TIMER_INIT,    p++);
+       AT_READ_REG(hw, REG_IRQ_MODRT_TIMER_INIT, p++);
+       AT_READ_REG(hw, REG_GPHY_CTRL,            p++);
+       AT_READ_REG(hw, REG_LINK_CTRL,            p++);
+       AT_READ_REG(hw, REG_IDLE_STATUS,          p++);
+       AT_READ_REG(hw, REG_MDIO_CTRL,            p++);
+       AT_READ_REG(hw, REG_SERDES_LOCK,          p++);
+       AT_READ_REG(hw, REG_MAC_CTRL,             p++);
+       AT_READ_REG(hw, REG_MAC_IPG_IFG,          p++);
+       AT_READ_REG(hw, REG_MAC_STA_ADDR,         p++);
+       AT_READ_REG(hw, REG_MAC_STA_ADDR+4,       p++);
+       AT_READ_REG(hw, REG_RX_HASH_TABLE,        p++);
+       AT_READ_REG(hw, REG_RX_HASH_TABLE+4,      p++);
+       AT_READ_REG(hw, REG_RXQ_CTRL,             p++);
+       AT_READ_REG(hw, REG_TXQ_CTRL,             p++);
+       AT_READ_REG(hw, REG_MTU,                  p++);
+       AT_READ_REG(hw, REG_WOL_CTRL,             p++);
+
+       atl1c_read_phy_reg(hw, MII_BMCR, &phy_data);
+       regs_buff[73] = (u32) phy_data;
+       atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+       regs_buff[74] = (u32) phy_data;
+}
+
+static int atl1c_get_eeprom_len(struct net_device *netdev)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+       if (atl1c_check_eeprom_exist(&adapter->hw))
+               return AT_EEPROM_LEN;
+       else
+               return 0;
+}
+
+static int atl1c_get_eeprom(struct net_device *netdev,
+               struct ethtool_eeprom *eeprom, u8 *bytes)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       struct atl1c_hw *hw = &adapter->hw;
+       u32 *eeprom_buff;
+       int first_dword, last_dword;
+       int ret_val = 0;
+       int i;
+
+       if (eeprom->len == 0)
+               return -EINVAL;
+
+       if (!atl1c_check_eeprom_exist(hw)) /* not exist */
+               return -EINVAL;
+
+       eeprom->magic = adapter->pdev->vendor |
+                       (adapter->pdev->device << 16);
+
+       first_dword = eeprom->offset >> 2;
+       last_dword = (eeprom->offset + eeprom->len - 1) >> 2;
+
+       eeprom_buff = kmalloc(sizeof(u32) *
+                       (last_dword - first_dword + 1), GFP_KERNEL);
+       if (eeprom_buff == NULL)
+               return -ENOMEM;
+
+       for (i = first_dword; i < last_dword; i++) {
+               if (!atl1c_read_eeprom(hw, i * 4, &(eeprom_buff[i-first_dword]))) {
+                       kfree(eeprom_buff);
+                       return -EIO;
+               }
+       }
+
+       memcpy(bytes, (u8 *)eeprom_buff + (eeprom->offset & 3),
+                       eeprom->len);
+       kfree(eeprom_buff);
+
+       return ret_val;
+       return 0;
+}
+
+static void atl1c_get_drvinfo(struct net_device *netdev,
+               struct ethtool_drvinfo *drvinfo)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+       strncpy(drvinfo->driver,  atl1c_driver_name, sizeof(drvinfo->driver));
+       strncpy(drvinfo->version, atl1c_driver_version,
+               sizeof(drvinfo->version));
+       strncpy(drvinfo->fw_version, "N/A", sizeof(drvinfo->fw_version));
+       strncpy(drvinfo->bus_info, pci_name(adapter->pdev),
+               sizeof(drvinfo->bus_info));
+       drvinfo->n_stats = 0;
+       drvinfo->testinfo_len = 0;
+       drvinfo->regdump_len = atl1c_get_regs_len(netdev);
+       drvinfo->eedump_len = atl1c_get_eeprom_len(netdev);
+}
+
+static void atl1c_get_wol(struct net_device *netdev,
+                         struct ethtool_wolinfo *wol)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+       wol->supported = WAKE_MAGIC | WAKE_PHY;
+       wol->wolopts = 0;
+
+       if (adapter->wol & AT_WUFC_EX)
+               wol->wolopts |= WAKE_UCAST;
+       if (adapter->wol & AT_WUFC_MC)
+               wol->wolopts |= WAKE_MCAST;
+       if (adapter->wol & AT_WUFC_BC)
+               wol->wolopts |= WAKE_BCAST;
+       if (adapter->wol & AT_WUFC_MAG)
+               wol->wolopts |= WAKE_MAGIC;
+       if (adapter->wol & AT_WUFC_LNKC)
+               wol->wolopts |= WAKE_PHY;
+
+       return;
+}
+
+static int atl1c_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+       if (wol->wolopts & (WAKE_ARP | WAKE_MAGICSECURE |
+                           WAKE_MCAST | WAKE_BCAST | WAKE_MCAST))
+               return -EOPNOTSUPP;
+       /* these settings will always override what we currently have */
+       adapter->wol = 0;
+
+       if (wol->wolopts & WAKE_MAGIC)
+               adapter->wol |= AT_WUFC_MAG;
+       if (wol->wolopts & WAKE_PHY)
+               adapter->wol |= AT_WUFC_LNKC;
+
+       return 0;
+}
+
+static int atl1c_nway_reset(struct net_device *netdev)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       if (netif_running(netdev))
+               atl1c_reinit_locked(adapter);
+       return 0;
+}
+
+static struct ethtool_ops atl1c_ethtool_ops = {
+       .get_settings           = atl1c_get_settings,
+       .set_settings           = atl1c_set_settings,
+       .get_drvinfo            = atl1c_get_drvinfo,
+       .get_regs_len           = atl1c_get_regs_len,
+       .get_regs               = atl1c_get_regs,
+       .get_wol                = atl1c_get_wol,
+       .set_wol                = atl1c_set_wol,
+       .get_msglevel           = atl1c_get_msglevel,
+       .set_msglevel           = atl1c_set_msglevel,
+       .nway_reset             = atl1c_nway_reset,
+       .get_link               = ethtool_op_get_link,
+       .get_eeprom_len         = atl1c_get_eeprom_len,
+       .get_eeprom             = atl1c_get_eeprom,
+       .get_tx_csum            = atl1c_get_tx_csum,
+       .get_sg                 = ethtool_op_get_sg,
+       .set_sg                 = ethtool_op_set_sg,
+};
+
+void atl1c_set_ethtool_ops(struct net_device *netdev)
+{
+       SET_ETHTOOL_OPS(netdev, &atl1c_ethtool_ops);
+}
diff --git a/drivers/net/atl1c/atl1c_hw.c b/drivers/net/atl1c/atl1c_hw.c
new file mode 100644 (file)
index 0000000..3e69b94
--- /dev/null
@@ -0,0 +1,527 @@
+/*
+ * Copyright(c) 2007 Atheros Corporation. All rights reserved.
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/mii.h>
+#include <linux/crc32.h>
+
+#include "atl1c.h"
+
+/*
+ * check_eeprom_exist
+ * return 1 if eeprom exist
+ */
+int atl1c_check_eeprom_exist(struct atl1c_hw *hw)
+{
+       u32 data;
+
+       AT_READ_REG(hw, REG_TWSI_DEBUG, &data);
+       if (data & TWSI_DEBUG_DEV_EXIST)
+               return 1;
+
+       return 0;
+}
+
+void atl1c_hw_set_mac_addr(struct atl1c_hw *hw)
+{
+       u32 value;
+       /*
+        * 00-0B-6A-F6-00-DC
+        * 0:  6AF600DC 1: 000B
+        * low dword
+        */
+       value = (((u32)hw->mac_addr[2]) << 24) |
+               (((u32)hw->mac_addr[3]) << 16) |
+               (((u32)hw->mac_addr[4]) << 8)  |
+               (((u32)hw->mac_addr[5])) ;
+       AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 0, value);
+       /* hight dword */
+       value = (((u32)hw->mac_addr[0]) << 8) |
+               (((u32)hw->mac_addr[1])) ;
+       AT_WRITE_REG_ARRAY(hw, REG_MAC_STA_ADDR, 1, value);
+}
+
+/*
+ * atl1c_get_permanent_address
+ * return 0 if get valid mac address,
+ */
+static int atl1c_get_permanent_address(struct atl1c_hw *hw)
+{
+       u32 addr[2];
+       u32 i;
+       u32 otp_ctrl_data;
+       u32 twsi_ctrl_data;
+       u8  eth_addr[ETH_ALEN];
+
+       /* init */
+       addr[0] = addr[1] = 0;
+       AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
+       if (atl1c_check_eeprom_exist(hw)) {
+               /* Enable OTP CLK */
+               if (!(otp_ctrl_data & OTP_CTRL_CLK_EN)) {
+                       otp_ctrl_data |= OTP_CTRL_CLK_EN;
+                       AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
+                       AT_WRITE_FLUSH(hw);
+                       msleep(1);
+               }
+
+               AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
+               twsi_ctrl_data |= TWSI_CTRL_SW_LDSTART;
+               AT_WRITE_REG(hw, REG_TWSI_CTRL, twsi_ctrl_data);
+               for (i = 0; i < AT_TWSI_EEPROM_TIMEOUT; i++) {
+                       msleep(10);
+                       AT_READ_REG(hw, REG_TWSI_CTRL, &twsi_ctrl_data);
+                       if ((twsi_ctrl_data & TWSI_CTRL_SW_LDSTART) == 0)
+                               break;
+               }
+               if (i >= AT_TWSI_EEPROM_TIMEOUT)
+                       return -1;
+       }
+       /* Disable OTP_CLK */
+       if (otp_ctrl_data & OTP_CTRL_CLK_EN) {
+               otp_ctrl_data &= ~OTP_CTRL_CLK_EN;
+               AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
+               AT_WRITE_FLUSH(hw);
+               msleep(1);
+       }
+
+       /* maybe MAC-address is from BIOS */
+       AT_READ_REG(hw, REG_MAC_STA_ADDR, &addr[0]);
+       AT_READ_REG(hw, REG_MAC_STA_ADDR + 4, &addr[1]);
+       *(u32 *) &eth_addr[2] = swab32(addr[0]);
+       *(u16 *) &eth_addr[0] = swab16(*(u16 *)&addr[1]);
+
+       if (is_valid_ether_addr(eth_addr)) {
+               memcpy(hw->perm_mac_addr, eth_addr, ETH_ALEN);
+               return 0;
+       }
+
+       return -1;
+}
+
+bool atl1c_read_eeprom(struct atl1c_hw *hw, u32 offset, u32 *p_value)
+{
+       int i;
+       int ret = false;
+       u32 otp_ctrl_data;
+       u32 control;
+       u32 data;
+
+       if (offset & 3)
+               return ret; /* address do not align */
+
+       AT_READ_REG(hw, REG_OTP_CTRL, &otp_ctrl_data);
+       if (!(otp_ctrl_data & OTP_CTRL_CLK_EN))
+               AT_WRITE_REG(hw, REG_OTP_CTRL,
+                               (otp_ctrl_data | OTP_CTRL_CLK_EN));
+
+       AT_WRITE_REG(hw, REG_EEPROM_DATA_LO, 0);
+       control = (offset & EEPROM_CTRL_ADDR_MASK) << EEPROM_CTRL_ADDR_SHIFT;
+       AT_WRITE_REG(hw, REG_EEPROM_CTRL, control);
+
+       for (i = 0; i < 10; i++) {
+               udelay(100);
+               AT_READ_REG(hw, REG_EEPROM_CTRL, &control);
+               if (control & EEPROM_CTRL_RW)
+                       break;
+       }
+       if (control & EEPROM_CTRL_RW) {
+               AT_READ_REG(hw, REG_EEPROM_CTRL, &data);
+               AT_READ_REG(hw, REG_EEPROM_DATA_LO, p_value);
+               data = data & 0xFFFF;
+               *p_value = swab32((data << 16) | (*p_value >> 16));
+               ret = true;
+       }
+       if (!(otp_ctrl_data & OTP_CTRL_CLK_EN))
+               AT_WRITE_REG(hw, REG_OTP_CTRL, otp_ctrl_data);
+
+       return ret;
+}
+/*
+ * Reads the adapter's MAC address from the EEPROM
+ *
+ * hw - Struct containing variables accessed by shared code
+ */
+int atl1c_read_mac_addr(struct atl1c_hw *hw)
+{
+       int err = 0;
+
+       err = atl1c_get_permanent_address(hw);
+       if (err)
+               random_ether_addr(hw->perm_mac_addr);
+
+       memcpy(hw->mac_addr, hw->perm_mac_addr, sizeof(hw->perm_mac_addr));
+       return 0;
+}
+
+/*
+ * atl1c_hash_mc_addr
+ *  purpose
+ *      set hash value for a multicast address
+ *      hash calcu processing :
+ *          1. calcu 32bit CRC for multicast address
+ *          2. reverse crc with MSB to LSB
+ */
+u32 atl1c_hash_mc_addr(struct atl1c_hw *hw, u8 *mc_addr)
+{
+       u32 crc32;
+       u32 value = 0;
+       int i;
+
+       crc32 = ether_crc_le(6, mc_addr);
+       for (i = 0; i < 32; i++)
+               value |= (((crc32 >> i) & 1) << (31 - i));
+
+       return value;
+}
+
+/*
+ * Sets the bit in the multicast table corresponding to the hash value.
+ * hw - Struct containing variables accessed by shared code
+ * hash_value - Multicast address hash value
+ */
+void atl1c_hash_set(struct atl1c_hw *hw, u32 hash_value)
+{
+       u32 hash_bit, hash_reg;
+       u32 mta;
+
+       /*
+        * The HASH Table  is a register array of 2 32-bit registers.
+        * It is treated like an array of 64 bits.  We want to set
+        * bit BitArray[hash_value]. So we figure out what register
+        * the bit is in, read it, OR in the new bit, then write
+        * back the new value.  The register is determined by the
+        * upper bit of the hash value and the bit within that
+        * register are determined by the lower 5 bits of the value.
+        */
+       hash_reg = (hash_value >> 31) & 0x1;
+       hash_bit = (hash_value >> 26) & 0x1F;
+
+       mta = AT_READ_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg);
+
+       mta |= (1 << hash_bit);
+
+       AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, hash_reg, mta);
+}
+
+/*
+ * Reads the value from a PHY register
+ * hw - Struct containing variables accessed by shared code
+ * reg_addr - address of the PHY register to read
+ */
+int atl1c_read_phy_reg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data)
+{
+       u32 val;
+       int i;
+
+       val = ((u32)(reg_addr & MDIO_REG_ADDR_MASK)) << MDIO_REG_ADDR_SHIFT |
+               MDIO_START | MDIO_SUP_PREAMBLE | MDIO_RW |
+               MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT;
+
+       AT_WRITE_REG(hw, REG_MDIO_CTRL, val);
+
+       for (i = 0; i < MDIO_WAIT_TIMES; i++) {
+               udelay(2);
+               AT_READ_REG(hw, REG_MDIO_CTRL, &val);
+               if (!(val & (MDIO_START | MDIO_BUSY)))
+                       break;
+       }
+       if (!(val & (MDIO_START | MDIO_BUSY))) {
+               *phy_data = (u16)val;
+               return 0;
+       }
+
+       return -1;
+}
+
+/*
+ * Writes a value to a PHY register
+ * hw - Struct containing variables accessed by shared code
+ * reg_addr - address of the PHY register to write
+ * data - data to write to the PHY
+ */
+int atl1c_write_phy_reg(struct atl1c_hw *hw, u32 reg_addr, u16 phy_data)
+{
+       int i;
+       u32 val;
+
+       val = ((u32)(phy_data & MDIO_DATA_MASK)) << MDIO_DATA_SHIFT   |
+              (reg_addr & MDIO_REG_ADDR_MASK) << MDIO_REG_ADDR_SHIFT |
+              MDIO_SUP_PREAMBLE | MDIO_START |
+              MDIO_CLK_25_4 << MDIO_CLK_SEL_SHIFT;
+
+       AT_WRITE_REG(hw, REG_MDIO_CTRL, val);
+
+       for (i = 0; i < MDIO_WAIT_TIMES; i++) {
+               udelay(2);
+               AT_READ_REG(hw, REG_MDIO_CTRL, &val);
+               if (!(val & (MDIO_START | MDIO_BUSY)))
+                       break;
+       }
+
+       if (!(val & (MDIO_START | MDIO_BUSY)))
+               return 0;
+
+       return -1;
+}
+
+/*
+ * Configures PHY autoneg and flow control advertisement settings
+ *
+ * hw - Struct containing variables accessed by shared code
+ */
+static int atl1c_phy_setup_adv(struct atl1c_hw *hw)
+{
+       u16 mii_adv_data = ADVERTISE_DEFAULT_CAP & ~ADVERTISE_SPEED_MASK;
+       u16 mii_giga_ctrl_data = GIGA_CR_1000T_DEFAULT_CAP &
+                               ~GIGA_CR_1000T_SPEED_MASK;
+
+       if (hw->autoneg_advertised & ADVERTISED_10baseT_Half)
+               mii_adv_data |= ADVERTISE_10HALF;
+       if (hw->autoneg_advertised & ADVERTISED_10baseT_Full)
+               mii_adv_data |= ADVERTISE_10FULL;
+       if (hw->autoneg_advertised & ADVERTISED_100baseT_Half)
+               mii_adv_data |= ADVERTISE_100HALF;
+       if (hw->autoneg_advertised & ADVERTISED_100baseT_Full)
+               mii_adv_data |= ADVERTISE_100FULL;
+
+       if (hw->autoneg_advertised & ADVERTISED_Autoneg)
+               mii_adv_data |= ADVERTISE_10HALF  | ADVERTISE_10FULL |
+                               ADVERTISE_100HALF | ADVERTISE_100FULL;
+
+       if (hw->ctrl_flags & ATL1C_LINK_CAP_1000M) {
+               if (hw->autoneg_advertised & ADVERTISED_1000baseT_Half)
+                       mii_giga_ctrl_data |= ADVERTISE_1000HALF;
+               if (hw->autoneg_advertised & ADVERTISED_1000baseT_Full)
+                       mii_giga_ctrl_data |= ADVERTISE_1000FULL;
+               if (hw->autoneg_advertised & ADVERTISED_Autoneg)
+                       mii_giga_ctrl_data |= ADVERTISE_1000HALF |
+                                       ADVERTISE_1000FULL;
+       }
+
+       if (atl1c_write_phy_reg(hw, MII_ADVERTISE, mii_adv_data) != 0 ||
+           atl1c_write_phy_reg(hw, MII_GIGA_CR, mii_giga_ctrl_data) != 0)
+               return -1;
+       return 0;
+}
+
+void atl1c_phy_disable(struct atl1c_hw *hw)
+{
+       AT_WRITE_REGW(hw, REG_GPHY_CTRL,
+                       GPHY_CTRL_PW_WOL_DIS | GPHY_CTRL_EXT_RESET);
+}
+
+static void atl1c_phy_magic_data(struct atl1c_hw *hw)
+{
+       u16 data;
+
+       data = ANA_LOOP_SEL_10BT | ANA_EN_MASK_TB | ANA_EN_10BT_IDLE |
+               ((1 & ANA_INTERVAL_SEL_TIMER_MASK) <<
+               ANA_INTERVAL_SEL_TIMER_SHIFT);
+
+       atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_18);
+       atl1c_write_phy_reg(hw, MII_DBG_DATA, data);
+
+       data = (2 & ANA_SERDES_CDR_BW_MASK) | ANA_MS_PAD_DBG |
+               ANA_SERDES_EN_DEEM | ANA_SERDES_SEL_HSP | ANA_SERDES_EN_PLL |
+               ANA_SERDES_EN_LCKDT;
+
+       atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_5);
+       atl1c_write_phy_reg(hw, MII_DBG_DATA, data);
+
+       data = (44 & ANA_LONG_CABLE_TH_100_MASK) |
+               ((33 & ANA_SHORT_CABLE_TH_100_MASK) <<
+               ANA_SHORT_CABLE_TH_100_SHIFT) | ANA_BP_BAD_LINK_ACCUM |
+               ANA_BP_SMALL_BW;
+
+       atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_54);
+       atl1c_write_phy_reg(hw, MII_DBG_DATA, data);
+
+       data = (11 & ANA_IECHO_ADJ_MASK) | ((11 & ANA_IECHO_ADJ_MASK) <<
+               ANA_IECHO_ADJ_2_SHIFT) | ((8 & ANA_IECHO_ADJ_MASK) <<
+               ANA_IECHO_ADJ_1_SHIFT) | ((8 & ANA_IECHO_ADJ_MASK) <<
+               ANA_IECHO_ADJ_0_SHIFT);
+
+       atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_4);
+       atl1c_write_phy_reg(hw, MII_DBG_DATA, data);
+
+       data = ANA_RESTART_CAL | ((7 & ANA_MANUL_SWICH_ON_MASK) <<
+               ANA_MANUL_SWICH_ON_SHIFT) | ANA_MAN_ENABLE |
+               ANA_SEL_HSP | ANA_EN_HB | ANA_OEN_125M;
+
+       atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_0);
+       atl1c_write_phy_reg(hw, MII_DBG_DATA, data);
+
+       if (hw->ctrl_flags & ATL1C_HIB_DISABLE) {
+               atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_41);
+               if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &data) != 0)
+                       return;
+               data &= ~ANA_TOP_PS_EN;
+               atl1c_write_phy_reg(hw, MII_DBG_DATA, data);
+
+               atl1c_write_phy_reg(hw, MII_DBG_ADDR, MII_ANA_CTRL_11);
+               if (atl1c_read_phy_reg(hw, MII_DBG_DATA, &data) != 0)
+                       return;
+               data &= ~ANA_PS_HIB_EN;
+               atl1c_write_phy_reg(hw, MII_DBG_DATA, data);
+       }
+}
+
+int atl1c_phy_reset(struct atl1c_hw *hw)
+{
+       struct atl1c_adapter *adapter = hw->adapter;
+       struct pci_dev *pdev = adapter->pdev;
+       u32 phy_ctrl_data = GPHY_CTRL_DEFAULT;
+       u32 mii_ier_data = IER_LINK_UP | IER_LINK_DOWN;
+       int err;
+
+       if (hw->ctrl_flags & ATL1C_HIB_DISABLE)
+               phy_ctrl_data &= ~GPHY_CTRL_HIB_EN;
+
+       AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl_data);
+       AT_WRITE_FLUSH(hw);
+       msleep(40);
+       phy_ctrl_data |= GPHY_CTRL_EXT_RESET;
+       AT_WRITE_REG(hw, REG_GPHY_CTRL, phy_ctrl_data);
+       AT_WRITE_FLUSH(hw);
+       msleep(10);
+
+       /*Enable PHY LinkChange Interrupt */
+       err = atl1c_write_phy_reg(hw, MII_IER, mii_ier_data);
+       if (err) {
+               if (netif_msg_hw(adapter))
+                       dev_err(&pdev->dev,
+                               "Error enable PHY linkChange Interrupt\n");
+               return err;
+       }
+       if (!(hw->ctrl_flags & ATL1C_FPGA_VERSION))
+               atl1c_phy_magic_data(hw);
+       return 0;
+}
+
+int atl1c_phy_init(struct atl1c_hw *hw)
+{
+       struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
+       struct pci_dev *pdev = adapter->pdev;
+       int ret_val;
+       u16 mii_bmcr_data = BMCR_RESET;
+       u16 phy_id1, phy_id2;
+
+       if ((atl1c_read_phy_reg(hw, MII_PHYSID1, &phy_id1) != 0) ||
+               (atl1c_read_phy_reg(hw, MII_PHYSID2, &phy_id2) != 0)) {
+                       if (netif_msg_link(adapter))
+                               dev_err(&pdev->dev, "Error get phy ID\n");
+               return -1;
+       }
+       switch (hw->media_type) {
+       case MEDIA_TYPE_AUTO_SENSOR:
+               ret_val = atl1c_phy_setup_adv(hw);
+               if (ret_val) {
+                       if (netif_msg_link(adapter))
+                               dev_err(&pdev->dev,
+                                       "Error Setting up Auto-Negotiation\n");
+                       return ret_val;
+               }
+               mii_bmcr_data |= BMCR_AUTO_NEG_EN | BMCR_RESTART_AUTO_NEG;
+               break;
+       case MEDIA_TYPE_100M_FULL:
+               mii_bmcr_data |= BMCR_SPEED_100 | BMCR_FULL_DUPLEX;
+               break;
+       case MEDIA_TYPE_100M_HALF:
+               mii_bmcr_data |= BMCR_SPEED_100;
+               break;
+       case MEDIA_TYPE_10M_FULL:
+               mii_bmcr_data |= BMCR_SPEED_10 | BMCR_FULL_DUPLEX;
+               break;
+       case MEDIA_TYPE_10M_HALF:
+               mii_bmcr_data |= BMCR_SPEED_10;
+               break;
+       default:
+               if (netif_msg_link(adapter))
+                       dev_err(&pdev->dev, "Wrong Media type %d\n",
+                               hw->media_type);
+               return -1;
+               break;
+       }
+
+       ret_val = atl1c_write_phy_reg(hw, MII_BMCR, mii_bmcr_data);
+       if (ret_val)
+               return ret_val;
+       hw->phy_configured = true;
+
+       return 0;
+}
+
+/*
+ * Detects the current speed and duplex settings of the hardware.
+ *
+ * hw - Struct containing variables accessed by shared code
+ * speed - Speed of the connection
+ * duplex - Duplex setting of the connection
+ */
+int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex)
+{
+       int err;
+       u16 phy_data;
+
+       /* Read   PHY Specific Status Register (17) */
+       err = atl1c_read_phy_reg(hw, MII_GIGA_PSSR, &phy_data);
+       if (err)
+               return err;
+
+       if (!(phy_data & GIGA_PSSR_SPD_DPLX_RESOLVED))
+               return -1;
+
+       switch (phy_data & GIGA_PSSR_SPEED) {
+       case GIGA_PSSR_1000MBS:
+               *speed = SPEED_1000;
+               break;
+       case GIGA_PSSR_100MBS:
+               *speed = SPEED_100;
+               break;
+       case  GIGA_PSSR_10MBS:
+               *speed = SPEED_10;
+               break;
+       default:
+               return -1;
+               break;
+       }
+
+       if (phy_data & GIGA_PSSR_DPLX)
+               *duplex = FULL_DUPLEX;
+       else
+               *duplex = HALF_DUPLEX;
+
+       return 0;
+}
+
+int atl1c_restart_autoneg(struct atl1c_hw *hw)
+{
+       int err = 0;
+       u16 mii_bmcr_data = BMCR_RESET;
+
+       err = atl1c_phy_setup_adv(hw);
+       if (err)
+               return err;
+       mii_bmcr_data |= BMCR_AUTO_NEG_EN | BMCR_RESTART_AUTO_NEG;
+
+       return atl1c_write_phy_reg(hw, MII_BMCR, mii_bmcr_data);
+}
diff --git a/drivers/net/atl1c/atl1c_hw.h b/drivers/net/atl1c/atl1c_hw.h
new file mode 100644 (file)
index 0000000..c2c738d
--- /dev/null
@@ -0,0 +1,859 @@
+/*
+ * Copyright(c) 2008 - 2009 Atheros Corporation. All rights reserved.
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#ifndef _ATL1C_HW_H_
+#define _ATL1C_HW_H_
+
+#include <linux/types.h>
+#include <linux/mii.h>
+
+struct atl1c_adapter;
+struct atl1c_hw;
+
+/* function prototype */
+void atl1c_phy_disable(struct atl1c_hw *hw);
+void atl1c_hw_set_mac_addr(struct atl1c_hw *hw);
+int atl1c_phy_reset(struct atl1c_hw *hw);
+int atl1c_read_mac_addr(struct atl1c_hw *hw);
+int atl1c_get_speed_and_duplex(struct atl1c_hw *hw, u16 *speed, u16 *duplex);
+u32 atl1c_hash_mc_addr(struct atl1c_hw *hw, u8 *mc_addr);
+void atl1c_hash_set(struct atl1c_hw *hw, u32 hash_value);
+int atl1c_read_phy_reg(struct atl1c_hw *hw, u16 reg_addr, u16 *phy_data);
+int atl1c_write_phy_reg(struct atl1c_hw *hw, u32 reg_addr, u16 phy_data);
+bool atl1c_read_eeprom(struct atl1c_hw *hw, u32 offset, u32 *p_value);
+int atl1c_phy_init(struct atl1c_hw *hw);
+int atl1c_check_eeprom_exist(struct atl1c_hw *hw);
+int atl1c_restart_autoneg(struct atl1c_hw *hw);
+
+/* register definition */
+#define REG_DEVICE_CAP                 0x5C
+#define DEVICE_CAP_MAX_PAYLOAD_MASK     0x7
+#define DEVICE_CAP_MAX_PAYLOAD_SHIFT    0
+
+#define REG_DEVICE_CTRL                        0x60
+#define DEVICE_CTRL_MAX_PAYLOAD_MASK    0x7
+#define DEVICE_CTRL_MAX_PAYLOAD_SHIFT   5
+#define DEVICE_CTRL_MAX_RREQ_SZ_MASK    0x7
+#define DEVICE_CTRL_MAX_RREQ_SZ_SHIFT   12
+
+#define REG_LINK_CTRL                  0x68
+#define LINK_CTRL_L0S_EN               0x01
+#define LINK_CTRL_L1_EN                        0x02
+
+#define REG_VPD_CAP                    0x6C
+#define VPD_CAP_ID_MASK                 0xff
+#define VPD_CAP_ID_SHIFT                0
+#define VPD_CAP_NEXT_PTR_MASK           0xFF
+#define VPD_CAP_NEXT_PTR_SHIFT          8
+#define VPD_CAP_VPD_ADDR_MASK           0x7FFF
+#define VPD_CAP_VPD_ADDR_SHIFT          16
+#define VPD_CAP_VPD_FLAG                0x80000000
+
+#define REG_VPD_DATA                   0x70
+
+#define REG_PCIE_UC_SEVERITY           0x10C
+#define PCIE_UC_SERVRITY_TRN           0x00000001
+#define PCIE_UC_SERVRITY_DLP           0x00000010
+#define PCIE_UC_SERVRITY_PSN_TLP       0x00001000
+#define PCIE_UC_SERVRITY_FCP           0x00002000
+#define PCIE_UC_SERVRITY_CPL_TO                0x00004000
+#define PCIE_UC_SERVRITY_CA            0x00008000
+#define PCIE_UC_SERVRITY_UC            0x00010000
+#define PCIE_UC_SERVRITY_ROV           0x00020000
+#define PCIE_UC_SERVRITY_MLFP          0x00040000
+#define PCIE_UC_SERVRITY_ECRC          0x00080000
+#define PCIE_UC_SERVRITY_UR            0x00100000
+
+#define REG_DEV_SERIALNUM_CTRL         0x200
+#define REG_DEV_MAC_SEL_MASK           0x0 /* 0:EUI; 1:MAC */
+#define REG_DEV_MAC_SEL_SHIFT          0
+#define REG_DEV_SERIAL_NUM_EN_MASK     0x1
+#define REG_DEV_SERIAL_NUM_EN_SHIFT    1
+
+#define REG_TWSI_CTRL                  0x218
+#define TWSI_CTRL_LD_OFFSET_MASK        0xFF
+#define TWSI_CTRL_LD_OFFSET_SHIFT       0
+#define TWSI_CTRL_LD_SLV_ADDR_MASK      0x7
+#define TWSI_CTRL_LD_SLV_ADDR_SHIFT     8
+#define TWSI_CTRL_SW_LDSTART            0x800
+#define TWSI_CTRL_HW_LDSTART            0x1000
+#define TWSI_CTRL_SMB_SLV_ADDR_MASK     0x7F
+#define TWSI_CTRL_SMB_SLV_ADDR_SHIFT    15
+#define TWSI_CTRL_LD_EXIST              0x400000
+#define TWSI_CTRL_READ_FREQ_SEL_MASK    0x3
+#define TWSI_CTRL_READ_FREQ_SEL_SHIFT   23
+#define TWSI_CTRL_FREQ_SEL_100K         0
+#define TWSI_CTRL_FREQ_SEL_200K         1
+#define TWSI_CTRL_FREQ_SEL_300K         2
+#define TWSI_CTRL_FREQ_SEL_400K         3
+#define TWSI_CTRL_SMB_SLV_ADDR
+#define TWSI_CTRL_WRITE_FREQ_SEL_MASK   0x3
+#define TWSI_CTRL_WRITE_FREQ_SEL_SHIFT  24
+
+
+#define REG_PCIE_DEV_MISC_CTRL         0x21C
+#define PCIE_DEV_MISC_EXT_PIPE         0x2
+#define PCIE_DEV_MISC_RETRY_BUFDIS     0x1
+#define PCIE_DEV_MISC_SPIROM_EXIST     0x4
+#define PCIE_DEV_MISC_SERDES_ENDIAN            0x8
+#define PCIE_DEV_MISC_SERDES_SEL_DIN           0x10
+
+#define REG_PCIE_PHYMISC               0x1000
+#define PCIE_PHYMISC_FORCE_RCV_DET     0x4
+
+#define REG_TWSI_DEBUG                 0x1108
+#define TWSI_DEBUG_DEV_EXIST           0x20000000
+
+#define REG_EEPROM_CTRL                        0x12C0
+#define EEPROM_CTRL_DATA_HI_MASK       0xFFFF
+#define EEPROM_CTRL_DATA_HI_SHIFT      0
+#define EEPROM_CTRL_ADDR_MASK          0x3FF
+#define EEPROM_CTRL_ADDR_SHIFT         16
+#define EEPROM_CTRL_ACK                        0x40000000
+#define EEPROM_CTRL_RW                 0x80000000
+
+#define REG_EEPROM_DATA_LO             0x12C4
+
+#define REG_OTP_CTRL                   0x12F0
+#define OTP_CTRL_CLK_EN                        0x0002
+
+#define REG_PM_CTRL                    0x12F8
+#define PM_CTRL_SDES_EN                        0x00000001
+#define PM_CTRL_RBER_EN                        0x00000002
+#define PM_CTRL_CLK_REQ_EN             0x00000004
+#define PM_CTRL_ASPM_L1_EN             0x00000008
+#define PM_CTRL_SERDES_L1_EN           0x00000010
+#define PM_CTRL_SERDES_PLL_L1_EN       0x00000020
+#define PM_CTRL_SERDES_PD_EX_L1                0x00000040
+#define PM_CTRL_SERDES_BUDS_RX_L1_EN   0x00000080
+#define PM_CTRL_L0S_ENTRY_TIMER_MASK   0xF
+#define PM_CTRL_L0S_ENTRY_TIMER_SHIFT  8
+#define PM_CTRL_ASPM_L0S_EN            0x00001000
+#define PM_CTRL_CLK_SWH_L1             0x00002000
+#define PM_CTRL_CLK_PWM_VER1_1         0x00004000
+#define PM_CTRL_PCIE_RECV              0x00008000
+#define PM_CTRL_L1_ENTRY_TIMER_MASK    0xF
+#define PM_CTRL_L1_ENTRY_TIMER_SHIFT   16
+#define PM_CTRL_PM_REQ_TIMER_MASK      0xF
+#define PM_CTRL_PM_REQ_TIMER_SHIFT     20
+#define PM_CTRL_LCKDET_TIMER_MASK      0x3F
+#define PM_CTRL_LCKDET_TIMER_SHIFT     24
+#define PM_CTRL_MAC_ASPM_CHK           0x40000000
+#define PM_CTRL_HOTRST                 0x80000000
+
+/* Selene Master Control Register */
+#define REG_MASTER_CTRL                        0x1400
+#define MASTER_CTRL_SOFT_RST            0x1
+#define MASTER_CTRL_TEST_MODE_MASK     0x3
+#define MASTER_CTRL_TEST_MODE_SHIFT    2
+#define MASTER_CTRL_BERT_START         0x10
+#define MASTER_CTRL_MTIMER_EN           0x100
+#define MASTER_CTRL_MANUAL_INT          0x200
+#define MASTER_CTRL_TX_ITIMER_EN       0x400
+#define MASTER_CTRL_RX_ITIMER_EN       0x800
+#define MASTER_CTRL_CLK_SEL_DIS                0x1000
+#define MASTER_CTRL_CLK_SWH_MODE       0x2000
+#define MASTER_CTRL_INT_RDCLR          0x4000
+#define MASTER_CTRL_REV_NUM_SHIFT      16
+#define MASTER_CTRL_REV_NUM_MASK       0xff
+#define MASTER_CTRL_DEV_ID_SHIFT       24
+#define MASTER_CTRL_DEV_ID_MASK                0x7f
+#define MASTER_CTRL_OTP_SEL            0x80000000
+
+/* Timer Initial Value Register */
+#define REG_MANUAL_TIMER_INIT          0x1404
+
+/* IRQ ModeratorTimer Initial Value Register */
+#define REG_IRQ_MODRT_TIMER_INIT       0x1408
+#define IRQ_MODRT_TIMER_MASK           0xffff
+#define IRQ_MODRT_TX_TIMER_SHIFT       0
+#define IRQ_MODRT_RX_TIMER_SHIFT       16
+
+#define REG_GPHY_CTRL                  0x140C
+#define GPHY_CTRL_EXT_RESET            0x1
+#define GPHY_CTRL_RTL_MODE             0x2
+#define GPHY_CTRL_LED_MODE             0x4
+#define GPHY_CTRL_ANEG_NOW             0x8
+#define GPHY_CTRL_REV_ANEG             0x10
+#define GPHY_CTRL_GATE_25M_EN          0x20
+#define GPHY_CTRL_LPW_EXIT             0x40
+#define GPHY_CTRL_PHY_IDDQ             0x80
+#define GPHY_CTRL_PHY_IDDQ_DIS         0x100
+#define GPHY_CTRL_GIGA_DIS             0x200
+#define GPHY_CTRL_HIB_EN               0x400
+#define GPHY_CTRL_HIB_PULSE            0x800
+#define GPHY_CTRL_SEL_ANA_RST          0x1000
+#define GPHY_CTRL_PHY_PLL_ON           0x2000
+#define GPHY_CTRL_PWDOWN_HW            0x4000
+#define GPHY_CTRL_PHY_PLL_BYPASS       0x8000
+
+#define GPHY_CTRL_DEFAULT (             \
+               GPHY_CTRL_SEL_ANA_RST   |\
+               GPHY_CTRL_HIB_PULSE     |\
+               GPHY_CTRL_HIB_EN)
+
+#define GPHY_CTRL_PW_WOL_DIS (          \
+               GPHY_CTRL_SEL_ANA_RST   |\
+               GPHY_CTRL_HIB_PULSE     |\
+               GPHY_CTRL_HIB_EN        |\
+               GPHY_CTRL_PWDOWN_HW     |\
+               GPHY_CTRL_PHY_IDDQ)
+
+/* Block IDLE Status Register */
+#define REG_IDLE_STATUS                0x1410
+#define IDLE_STATUS_MASK               0x00FF
+#define IDLE_STATUS_RXMAC_NO_IDLE              0x1
+#define IDLE_STATUS_TXMAC_NO_IDLE              0x2
+#define IDLE_STATUS_RXQ_NO_IDLE                0x4
+#define IDLE_STATUS_TXQ_NO_IDLE                0x8
+#define IDLE_STATUS_DMAR_NO_IDLE               0x10
+#define IDLE_STATUS_DMAW_NO_IDLE               0x20
+#define IDLE_STATUS_SMB_NO_IDLE                0x40
+#define IDLE_STATUS_CMB_NO_IDLE                0x80
+
+/* MDIO Control Register */
+#define REG_MDIO_CTRL                  0x1414
+#define MDIO_DATA_MASK                 0xffff  /* On MDIO write, the 16-bit
+                                                * control data to write to PHY
+                                                * MII management register */
+#define MDIO_DATA_SHIFT                0       /* On MDIO read, the 16-bit
+                                                * status data that was read
+                                                * from the PHY MII management register */
+#define MDIO_REG_ADDR_MASK             0x1f    /* MDIO register address */
+#define MDIO_REG_ADDR_SHIFT            16
+#define MDIO_RW                        0x200000  /* 1: read, 0: write */
+#define MDIO_SUP_PREAMBLE              0x400000  /* Suppress preamble */
+#define MDIO_START                     0x800000  /* Write 1 to initiate the MDIO
+                                                  * master. And this bit is self
+                                                  * cleared after one cycle */
+#define MDIO_CLK_SEL_SHIFT             24
+#define MDIO_CLK_25_4                  0
+#define MDIO_CLK_25_6                  2
+#define MDIO_CLK_25_8                  3
+#define MDIO_CLK_25_10                 4
+#define MDIO_CLK_25_14                 5
+#define MDIO_CLK_25_20                 6
+#define MDIO_CLK_25_28                 7
+#define MDIO_BUSY                      0x8000000
+#define MDIO_AP_EN                     0x10000000
+#define MDIO_WAIT_TIMES                10
+
+/* MII PHY Status Register */
+#define REG_PHY_STATUS                 0x1418
+#define PHY_GENERAL_STATUS_MASK                0xFFFF
+#define PHY_STATUS_RECV_ENABLE         0x0001
+#define PHY_OE_PWSP_STATUS_MASK                0x07FF
+#define PHY_OE_PWSP_STATUS_SHIFT       16
+#define PHY_STATUS_LPW_STATE           0x80000000
+/* BIST Control and Status Register0 (for the Packet Memory) */
+#define REG_BIST0_CTRL                 0x141c
+#define BIST0_NOW                      0x1
+#define BIST0_SRAM_FAIL                0x2 /* 1: The SRAM failure is
+                                            * un-repairable  because
+                                            * it has address decoder
+                                            * failure or more than 1 cell
+                                            * stuck-to-x failure */
+#define BIST0_FUSE_FLAG                0x4
+
+/* BIST Control and Status Register1(for the retry buffer of PCI Express) */
+#define REG_BIST1_CTRL                 0x1420
+#define BIST1_NOW                      0x1
+#define BIST1_SRAM_FAIL                0x2
+#define BIST1_FUSE_FLAG                0x4
+
+/* SerDes Lock Detect Control and Status Register */
+#define REG_SERDES_LOCK                0x1424
+#define SERDES_LOCK_DETECT             0x1  /* SerDes lock detected. This signal
+                                             * comes from Analog SerDes */
+#define SERDES_LOCK_DETECT_EN          0x2  /* 1: Enable SerDes Lock detect function */
+
+/* MAC Control Register  */
+#define REG_MAC_CTRL                   0x1480
+#define MAC_CTRL_TX_EN                 0x1
+#define MAC_CTRL_RX_EN                 0x2
+#define MAC_CTRL_TX_FLOW               0x4
+#define MAC_CTRL_RX_FLOW               0x8
+#define MAC_CTRL_LOOPBACK              0x10
+#define MAC_CTRL_DUPLX                 0x20
+#define MAC_CTRL_ADD_CRC               0x40
+#define MAC_CTRL_PAD                   0x80
+#define MAC_CTRL_LENCHK                0x100
+#define MAC_CTRL_HUGE_EN               0x200
+#define MAC_CTRL_PRMLEN_SHIFT          10
+#define MAC_CTRL_PRMLEN_MASK           0xf
+#define MAC_CTRL_RMV_VLAN              0x4000
+#define MAC_CTRL_PROMIS_EN             0x8000
+#define MAC_CTRL_TX_PAUSE              0x10000
+#define MAC_CTRL_SCNT                  0x20000
+#define MAC_CTRL_SRST_TX               0x40000
+#define MAC_CTRL_TX_SIMURST            0x80000
+#define MAC_CTRL_SPEED_SHIFT           20
+#define MAC_CTRL_SPEED_MASK            0x3
+#define MAC_CTRL_DBG_TX_BKPRESURE      0x400000
+#define MAC_CTRL_TX_HUGE               0x800000
+#define MAC_CTRL_RX_CHKSUM_EN          0x1000000
+#define MAC_CTRL_MC_ALL_EN             0x2000000
+#define MAC_CTRL_BC_EN                 0x4000000
+#define MAC_CTRL_DBG                   0x8000000
+#define MAC_CTRL_SINGLE_PAUSE_EN       0x10000000
+
+/* MAC IPG/IFG Control Register  */
+#define REG_MAC_IPG_IFG                0x1484
+#define MAC_IPG_IFG_IPGT_SHIFT         0       /* Desired back to back
+                                                * inter-packet gap. The
+                                                * default is 96-bit time */
+#define MAC_IPG_IFG_IPGT_MASK          0x7f
+#define MAC_IPG_IFG_MIFG_SHIFT         8       /* Minimum number of IFG to
+                                                * enforce in between RX frames */
+#define MAC_IPG_IFG_MIFG_MASK          0xff    /* Frame gap below such IFP is dropped */
+#define MAC_IPG_IFG_IPGR1_SHIFT        16      /* 64bit Carrier-Sense window */
+#define MAC_IPG_IFG_IPGR1_MASK         0x7f
+#define MAC_IPG_IFG_IPGR2_SHIFT        24      /* 96-bit IPG window */
+#define MAC_IPG_IFG_IPGR2_MASK         0x7f
+
+/* MAC STATION ADDRESS  */
+#define REG_MAC_STA_ADDR               0x1488
+
+/* Hash table for multicast address */
+#define REG_RX_HASH_TABLE              0x1490
+
+/* MAC Half-Duplex Control Register */
+#define REG_MAC_HALF_DUPLX_CTRL        0x1498
+#define MAC_HALF_DUPLX_CTRL_LCOL_SHIFT  0      /* Collision Window */
+#define MAC_HALF_DUPLX_CTRL_LCOL_MASK   0x3ff
+#define MAC_HALF_DUPLX_CTRL_RETRY_SHIFT 12
+#define MAC_HALF_DUPLX_CTRL_RETRY_MASK  0xf
+#define MAC_HALF_DUPLX_CTRL_EXC_DEF_EN  0x10000
+#define MAC_HALF_DUPLX_CTRL_NO_BACK_C   0x20000
+#define MAC_HALF_DUPLX_CTRL_NO_BACK_P   0x40000 /* No back-off on backpressure,
+                                                * immediately start the
+                                                * transmission after back pressure */
+#define MAC_HALF_DUPLX_CTRL_ABEBE        0x80000 /* 1: Alternative Binary Exponential Back-off Enabled */
+#define MAC_HALF_DUPLX_CTRL_ABEBT_SHIFT  20      /* Maximum binary exponential number */
+#define MAC_HALF_DUPLX_CTRL_ABEBT_MASK   0xf
+#define MAC_HALF_DUPLX_CTRL_JAMIPG_SHIFT 24      /* IPG to start JAM for collision based flow control in half-duplex */
+#define MAC_HALF_DUPLX_CTRL_JAMIPG_MASK  0xf     /* mode. In unit of 8-bit time */
+
+/* Maximum Frame Length Control Register   */
+#define REG_MTU                        0x149c
+
+/* Wake-On-Lan control register */
+#define REG_WOL_CTRL                   0x14a0
+#define WOL_PATTERN_EN                 0x00000001
+#define WOL_PATTERN_PME_EN              0x00000002
+#define WOL_MAGIC_EN                    0x00000004
+#define WOL_MAGIC_PME_EN                0x00000008
+#define WOL_LINK_CHG_EN                 0x00000010
+#define WOL_LINK_CHG_PME_EN             0x00000020
+#define WOL_PATTERN_ST                  0x00000100
+#define WOL_MAGIC_ST                    0x00000200
+#define WOL_LINKCHG_ST                  0x00000400
+#define WOL_CLK_SWITCH_EN               0x00008000
+#define WOL_PT0_EN                      0x00010000
+#define WOL_PT1_EN                      0x00020000
+#define WOL_PT2_EN                      0x00040000
+#define WOL_PT3_EN                      0x00080000
+#define WOL_PT4_EN                      0x00100000
+#define WOL_PT5_EN                      0x00200000
+#define WOL_PT6_EN                      0x00400000
+
+/* WOL Length ( 2 DWORD ) */
+#define REG_WOL_PATTERN_LEN            0x14a4
+#define WOL_PT_LEN_MASK                 0x7f
+#define WOL_PT0_LEN_SHIFT               0
+#define WOL_PT1_LEN_SHIFT               8
+#define WOL_PT2_LEN_SHIFT               16
+#define WOL_PT3_LEN_SHIFT               24
+#define WOL_PT4_LEN_SHIFT               0
+#define WOL_PT5_LEN_SHIFT               8
+#define WOL_PT6_LEN_SHIFT               16
+
+/* Internal SRAM Partition Register */
+#define RFDX_HEAD_ADDR_MASK            0x03FF
+#define RFDX_HARD_ADDR_SHIFT           0
+#define RFDX_TAIL_ADDR_MASK            0x03FF
+#define RFDX_TAIL_ADDR_SHIFT            16
+
+#define REG_SRAM_RFD0_INFO             0x1500
+#define REG_SRAM_RFD1_INFO             0x1504
+#define REG_SRAM_RFD2_INFO             0x1508
+#define        REG_SRAM_RFD3_INFO              0x150C
+
+#define REG_RFD_NIC_LEN                        0x1510 /* In 8-bytes */
+#define RFD_NIC_LEN_MASK               0x03FF
+
+#define REG_SRAM_TRD_ADDR              0x1518
+#define TPD_HEAD_ADDR_MASK             0x03FF
+#define TPD_HEAD_ADDR_SHIFT            0
+#define TPD_TAIL_ADDR_MASK             0x03FF
+#define TPD_TAIL_ADDR_SHIFT            16
+
+#define REG_SRAM_TRD_LEN               0x151C /* In 8-bytes */
+#define TPD_NIC_LEN_MASK               0x03FF
+
+#define REG_SRAM_RXF_ADDR              0x1520
+#define REG_SRAM_RXF_LEN               0x1524
+#define REG_SRAM_TXF_ADDR              0x1528
+#define REG_SRAM_TXF_LEN               0x152C
+#define REG_SRAM_TCPH_ADDR             0x1530
+#define REG_SRAM_PKTH_ADDR             0x1532
+
+/*
+ * Load Ptr Register
+ * Software sets this bit after the initialization of the head and tail */
+#define REG_LOAD_PTR                   0x1534
+
+/*
+ * addresses of all descriptors, as well as the following descriptor
+ * control register, which triggers each function block to load the head
+ * pointer to prepare for the operation. This bit is then self-cleared
+ * after one cycle.
+ */
+#define REG_RX_BASE_ADDR_HI            0x1540
+#define REG_TX_BASE_ADDR_HI            0x1544
+#define REG_SMB_BASE_ADDR_HI           0x1548
+#define REG_SMB_BASE_ADDR_LO           0x154C
+#define REG_RFD0_HEAD_ADDR_LO          0x1550
+#define REG_RFD1_HEAD_ADDR_LO          0x1554
+#define REG_RFD2_HEAD_ADDR_LO          0x1558
+#define REG_RFD3_HEAD_ADDR_LO          0x155C
+#define REG_RFD_RING_SIZE              0x1560
+#define RFD_RING_SIZE_MASK             0x0FFF
+#define REG_RX_BUF_SIZE                        0x1564
+#define RX_BUF_SIZE_MASK               0xFFFF
+#define REG_RRD0_HEAD_ADDR_LO          0x1568
+#define REG_RRD1_HEAD_ADDR_LO          0x156C
+#define REG_RRD2_HEAD_ADDR_LO          0x1570
+#define REG_RRD3_HEAD_ADDR_LO          0x1574
+#define REG_RRD_RING_SIZE              0x1578
+#define RRD_RING_SIZE_MASK             0x0FFF
+#define REG_HTPD_HEAD_ADDR_LO          0x157C
+#define REG_NTPD_HEAD_ADDR_LO          0x1580
+#define REG_TPD_RING_SIZE              0x1584
+#define TPD_RING_SIZE_MASK             0xFFFF
+#define REG_CMB_BASE_ADDR_LO           0x1588
+
+/* RSS about */
+#define REG_RSS_KEY0                    0x14B0
+#define REG_RSS_KEY1                    0x14B4
+#define REG_RSS_KEY2                    0x14B8
+#define REG_RSS_KEY3                    0x14BC
+#define REG_RSS_KEY4                    0x14C0
+#define REG_RSS_KEY5                    0x14C4
+#define REG_RSS_KEY6                    0x14C8
+#define REG_RSS_KEY7                    0x14CC
+#define REG_RSS_KEY8                    0x14D0
+#define REG_RSS_KEY9                    0x14D4
+#define REG_IDT_TABLE0                 0x14E0
+#define REG_IDT_TABLE1                  0x14E4
+#define REG_IDT_TABLE2                  0x14E8
+#define REG_IDT_TABLE3                  0x14EC
+#define REG_IDT_TABLE4                  0x14F0
+#define REG_IDT_TABLE5                  0x14F4
+#define REG_IDT_TABLE6                  0x14F8
+#define REG_IDT_TABLE7                  0x14FC
+#define REG_IDT_TABLE                   REG_IDT_TABLE0
+#define REG_RSS_HASH_VALUE              0x15B0
+#define REG_RSS_HASH_FLAG               0x15B4
+#define REG_BASE_CPU_NUMBER             0x15B8
+
+/* TXQ Control Register */
+#define REG_TXQ_CTRL                   0x1590
+#define        TXQ_NUM_TPD_BURST_MASK          0xF
+#define TXQ_NUM_TPD_BURST_SHIFT        0
+#define TXQ_CTRL_IP_OPTION_EN          0x10
+#define TXQ_CTRL_EN                     0x20
+#define TXQ_CTRL_ENH_MODE               0x40
+#define TXQ_CTRL_LS_8023_EN            0x80
+#define TXQ_TXF_BURST_NUM_SHIFT        16
+#define TXQ_TXF_BURST_NUM_MASK         0xFFFF
+
+/* Jumbo packet Threshold for task offload */
+#define REG_TX_TSO_OFFLOAD_THRESH      0x1594 /* In 8-bytes */
+#define TX_TSO_OFFLOAD_THRESH_MASK     0x07FF
+
+#define        REG_TXF_WATER_MARK              0x1598 /* In 8-bytes */
+#define TXF_WATER_MARK_MASK            0x0FFF
+#define TXF_LOW_WATER_MARK_SHIFT       0
+#define TXF_HIGH_WATER_MARK_SHIFT      16
+#define TXQ_CTRL_BURST_MODE_EN         0x80000000
+
+#define REG_THRUPUT_MON_CTRL           0x159C
+#define THRUPUT_MON_RATE_MASK          0x3
+#define THRUPUT_MON_RATE_SHIFT         0
+#define THRUPUT_MON_EN                 0x80
+
+/* RXQ Control Register */
+#define REG_RXQ_CTRL                   0x15A0
+#define ASPM_THRUPUT_LIMIT_MASK                0x3
+#define ASPM_THRUPUT_LIMIT_SHIFT       0
+#define ASPM_THRUPUT_LIMIT_NO          0x00
+#define ASPM_THRUPUT_LIMIT_1M          0x01
+#define ASPM_THRUPUT_LIMIT_10M         0x02
+#define ASPM_THRUPUT_LIMIT_100M                0x04
+#define RXQ1_CTRL_EN                   0x10
+#define RXQ2_CTRL_EN                   0x20
+#define RXQ3_CTRL_EN                   0x40
+#define IPV6_CHKSUM_CTRL_EN            0x80
+#define RSS_HASH_BITS_MASK             0x00FF
+#define RSS_HASH_BITS_SHIFT            8
+#define RSS_HASH_IPV4                  0x10000
+#define RSS_HASH_IPV4_TCP              0x20000
+#define RSS_HASH_IPV6                  0x40000
+#define RSS_HASH_IPV6_TCP              0x80000
+#define RXQ_RFD_BURST_NUM_MASK         0x003F
+#define RXQ_RFD_BURST_NUM_SHIFT                20
+#define RSS_MODE_MASK                  0x0003
+#define RSS_MODE_SHIFT                 26
+#define RSS_NIP_QUEUE_SEL_MASK         0x1
+#define RSS_NIP_QUEUE_SEL_SHIFT                28
+#define RRS_HASH_CTRL_EN               0x20000000
+#define RX_CUT_THRU_EN                 0x40000000
+#define RXQ_CTRL_EN                    0x80000000
+
+#define REG_RFD_FREE_THRESH            0x15A4
+#define RFD_FREE_THRESH_MASK           0x003F
+#define RFD_FREE_HI_THRESH_SHIFT       0
+#define RFD_FREE_LO_THRESH_SHIFT       6
+
+/* RXF flow control register */
+#define REG_RXQ_RXF_PAUSE_THRESH       0x15A8
+#define RXQ_RXF_PAUSE_TH_HI_SHIFT       0
+#define RXQ_RXF_PAUSE_TH_HI_MASK        0x0FFF
+#define RXQ_RXF_PAUSE_TH_LO_SHIFT       16
+#define RXQ_RXF_PAUSE_TH_LO_MASK        0x0FFF
+
+#define REG_RXD_DMA_CTRL               0x15AC
+#define RXD_DMA_THRESH_MASK            0x0FFF  /* In 8-bytes */
+#define RXD_DMA_THRESH_SHIFT           0
+#define RXD_DMA_DOWN_TIMER_MASK                0xFFFF
+#define RXD_DMA_DOWN_TIMER_SHIFT       16
+
+/* DMA Engine Control Register */
+#define REG_DMA_CTRL                   0x15C0
+#define DMA_CTRL_DMAR_IN_ORDER          0x1
+#define DMA_CTRL_DMAR_ENH_ORDER         0x2
+#define DMA_CTRL_DMAR_OUT_ORDER         0x4
+#define DMA_CTRL_RCB_VALUE              0x8
+#define DMA_CTRL_DMAR_BURST_LEN_MASK    0x0007
+#define DMA_CTRL_DMAR_BURST_LEN_SHIFT   4
+#define DMA_CTRL_DMAW_BURST_LEN_MASK    0x0007
+#define DMA_CTRL_DMAW_BURST_LEN_SHIFT   7
+#define DMA_CTRL_DMAR_REQ_PRI           0x400
+#define DMA_CTRL_DMAR_DLY_CNT_MASK      0x001F
+#define DMA_CTRL_DMAR_DLY_CNT_SHIFT     11
+#define DMA_CTRL_DMAW_DLY_CNT_MASK      0x000F
+#define DMA_CTRL_DMAW_DLY_CNT_SHIFT     16
+#define DMA_CTRL_CMB_EN                0x100000
+#define DMA_CTRL_SMB_EN                        0x200000
+#define DMA_CTRL_CMB_NOW               0x400000
+#define MAC_CTRL_SMB_DIS               0x1000000
+#define DMA_CTRL_SMB_NOW               0x80000000
+
+/* CMB/SMB Control Register */
+#define REG_SMB_STAT_TIMER             0x15C4  /* 2us resolution */
+#define SMB_STAT_TIMER_MASK            0xFFFFFF
+#define REG_CMB_TPD_THRESH             0x15C8
+#define CMB_TPD_THRESH_MASK            0xFFFF
+#define REG_CMB_TX_TIMER               0x15CC  /* 2us resolution */
+#define CMB_TX_TIMER_MASK              0xFFFF
+
+/* Mail box */
+#define MB_RFDX_PROD_IDX_MASK          0xFFFF
+#define REG_MB_RFD0_PROD_IDX           0x15E0
+#define REG_MB_RFD1_PROD_IDX           0x15E4
+#define REG_MB_RFD2_PROD_IDX           0x15E8
+#define REG_MB_RFD3_PROD_IDX           0x15EC
+
+#define MB_PRIO_PROD_IDX_MASK          0xFFFF
+#define REG_MB_PRIO_PROD_IDX           0x15F0
+#define MB_HTPD_PROD_IDX_SHIFT         0
+#define MB_NTPD_PROD_IDX_SHIFT         16
+
+#define MB_PRIO_CONS_IDX_MASK          0xFFFF
+#define REG_MB_PRIO_CONS_IDX           0x15F4
+#define MB_HTPD_CONS_IDX_SHIFT         0
+#define MB_NTPD_CONS_IDX_SHIFT         16
+
+#define REG_MB_RFD01_CONS_IDX          0x15F8
+#define MB_RFD0_CONS_IDX_MASK          0x0000FFFF
+#define MB_RFD1_CONS_IDX_MASK          0xFFFF0000
+#define REG_MB_RFD23_CONS_IDX          0x15FC
+#define MB_RFD2_CONS_IDX_MASK          0x0000FFFF
+#define MB_RFD3_CONS_IDX_MASK          0xFFFF0000
+
+/* Interrupt Status Register */
+#define REG_ISR                        0x1600
+#define ISR_SMB                                0x00000001
+#define ISR_TIMER                      0x00000002
+/*
+ * Software manual interrupt, for debug. Set when SW_MAN_INT_EN is set
+ * in Table 51 Selene Master Control Register (Offset 0x1400).
+ */
+#define ISR_MANUAL                     0x00000004
+#define ISR_HW_RXF_OV                          0x00000008 /* RXF overflow interrupt */
+#define ISR_RFD0_UR                    0x00000010 /* RFD0 under run */
+#define ISR_RFD1_UR                    0x00000020
+#define ISR_RFD2_UR                    0x00000040
+#define ISR_RFD3_UR                    0x00000080
+#define ISR_TXF_UR                     0x00000100
+#define ISR_DMAR_TO_RST                        0x00000200
+#define ISR_DMAW_TO_RST                        0x00000400
+#define ISR_TX_CREDIT                  0x00000800
+#define ISR_GPHY                       0x00001000
+/* GPHY low power state interrupt */
+#define ISR_GPHY_LPW                           0x00002000
+#define ISR_TXQ_TO_RST                 0x00004000
+#define ISR_TX_PKT                     0x00008000
+#define ISR_RX_PKT_0                   0x00010000
+#define ISR_RX_PKT_1                   0x00020000
+#define ISR_RX_PKT_2                   0x00040000
+#define ISR_RX_PKT_3                   0x00080000
+#define ISR_MAC_RX                     0x00100000
+#define ISR_MAC_TX                     0x00200000
+#define ISR_UR_DETECTED                        0x00400000
+#define ISR_FERR_DETECTED              0x00800000
+#define ISR_NFERR_DETECTED             0x01000000
+#define ISR_CERR_DETECTED              0x02000000
+#define ISR_PHY_LINKDOWN               0x04000000
+#define ISR_DIS_INT                    0x80000000
+
+/* Interrupt Mask Register */
+#define REG_IMR                                0x1604
+
+#define IMR_NORMAL_MASK                (\
+               ISR_MANUAL      |\
+               ISR_HW_RXF_OV   |\
+               ISR_RFD0_UR     |\
+               ISR_TXF_UR      |\
+               ISR_DMAR_TO_RST |\
+               ISR_TXQ_TO_RST  |\
+               ISR_DMAW_TO_RST |\
+               ISR_GPHY        |\
+               ISR_TX_PKT      |\
+               ISR_RX_PKT_0    |\
+               ISR_GPHY_LPW    |\
+               ISR_PHY_LINKDOWN)
+
+#define ISR_RX_PKT     (\
+       ISR_RX_PKT_0    |\
+       ISR_RX_PKT_1    |\
+       ISR_RX_PKT_2    |\
+       ISR_RX_PKT_3)
+
+#define ISR_OVER       (\
+       ISR_RFD0_UR     |\
+       ISR_RFD1_UR     |\
+       ISR_RFD2_UR     |\
+       ISR_RFD3_UR     |\
+       ISR_HW_RXF_OV   |\
+       ISR_TXF_UR)
+
+#define ISR_ERROR      (\
+       ISR_DMAR_TO_RST |\
+       ISR_TXQ_TO_RST  |\
+       ISR_DMAW_TO_RST |\
+       ISR_PHY_LINKDOWN)
+
+#define REG_INT_RETRIG_TIMER           0x1608
+#define INT_RETRIG_TIMER_MASK          0xFFFF
+
+#define REG_HDS_CTRL                   0x160C
+#define HDS_CTRL_EN                    0x0001
+#define HDS_CTRL_BACKFILLSIZE_SHIFT    8
+#define HDS_CTRL_BACKFILLSIZE_MASK     0x0FFF
+#define HDS_CTRL_MAX_HDRSIZE_SHIFT     20
+#define HDS_CTRL_MAC_HDRSIZE_MASK      0x0FFF
+
+#define REG_MAC_RX_STATUS_BIN          0x1700
+#define REG_MAC_RX_STATUS_END          0x175c
+#define REG_MAC_TX_STATUS_BIN          0x1760
+#define REG_MAC_TX_STATUS_END          0x17c0
+
+/* DEBUG ADDR */
+#define REG_DEBUG_DATA0                0x1900
+#define REG_DEBUG_DATA1                0x1904
+
+/* PHY Control Register */
+#define MII_BMCR                       0x00
+#define BMCR_SPEED_SELECT_MSB          0x0040  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define BMCR_COLL_TEST_ENABLE          0x0080  /* Collision test enable */
+#define BMCR_FULL_DUPLEX               0x0100  /* FDX =1, half duplex =0 */
+#define BMCR_RESTART_AUTO_NEG          0x0200  /* Restart auto negotiation */
+#define BMCR_ISOLATE                   0x0400  /* Isolate PHY from MII */
+#define BMCR_POWER_DOWN                        0x0800  /* Power down */
+#define BMCR_AUTO_NEG_EN               0x1000  /* Auto Neg Enable */
+#define BMCR_SPEED_SELECT_LSB          0x2000  /* bits 6,13: 10=1000, 01=100, 00=10 */
+#define BMCR_LOOPBACK                  0x4000  /* 0 = normal, 1 = loopback */
+#define BMCR_RESET                     0x8000  /* 0 = normal, 1 = PHY reset */
+#define BMCR_SPEED_MASK                        0x2040
+#define BMCR_SPEED_1000                        0x0040
+#define BMCR_SPEED_100                 0x2000
+#define BMCR_SPEED_10                  0x0000
+
+/* PHY Status Register */
+#define MII_BMSR                       0x01
+#define BMMSR_EXTENDED_CAPS            0x0001  /* Extended register capabilities */
+#define BMSR_JABBER_DETECT             0x0002  /* Jabber Detected */
+#define BMSR_LINK_STATUS               0x0004  /* Link Status 1 = link */
+#define BMSR_AUTONEG_CAPS              0x0008  /* Auto Neg Capable */
+#define BMSR_REMOTE_FAULT              0x0010  /* Remote Fault Detect */
+#define BMSR_AUTONEG_COMPLETE          0x0020  /* Auto Neg Complete */
+#define BMSR_PREAMBLE_SUPPRESS         0x0040  /* Preamble may be suppressed */
+#define BMSR_EXTENDED_STATUS           0x0100  /* Ext. status info in Reg 0x0F */
+#define BMSR_100T2_HD_CAPS             0x0200  /* 100T2 Half Duplex Capable */
+#define BMSR_100T2_FD_CAPS             0x0400  /* 100T2 Full Duplex Capable */
+#define BMSR_10T_HD_CAPS               0x0800  /* 10T   Half Duplex Capable */
+#define BMSR_10T_FD_CAPS               0x1000  /* 10T   Full Duplex Capable */
+#define BMSR_100X_HD_CAPS              0x2000  /* 100X  Half Duplex Capable */
+#define BMMII_SR_100X_FD_CAPS          0x4000  /* 100X  Full Duplex Capable */
+#define BMMII_SR_100T4_CAPS            0x8000  /* 100T4 Capable */
+
+#define MII_PHYSID1                    0x02
+#define MII_PHYSID2                    0x03
+
+/* Autoneg Advertisement Register */
+#define MII_ADVERTISE                  0x04
+#define ADVERTISE_SPEED_MASK           0x01E0
+#define ADVERTISE_DEFAULT_CAP          0x0DE0
+
+/* 1000BASE-T Control Register */
+#define MII_GIGA_CR                    0x09
+#define GIGA_CR_1000T_REPEATER_DTE     0x0400  /* 1=Repeater/switch device port 0=DTE device */
+
+#define GIGA_CR_1000T_MS_VALUE         0x0800  /* 1=Configure PHY as Master 0=Configure PHY as Slave */
+#define GIGA_CR_1000T_MS_ENABLE                0x1000  /* 1=Master/Slave manual config value 0=Automatic Master/Slave config */
+#define GIGA_CR_1000T_TEST_MODE_NORMAL 0x0000  /* Normal Operation */
+#define GIGA_CR_1000T_TEST_MODE_1      0x2000  /* Transmit Waveform test */
+#define GIGA_CR_1000T_TEST_MODE_2      0x4000  /* Master Transmit Jitter test */
+#define GIGA_CR_1000T_TEST_MODE_3      0x6000  /* Slave Transmit Jitter test */
+#define GIGA_CR_1000T_TEST_MODE_4      0x8000  /* Transmitter Distortion test */
+#define GIGA_CR_1000T_SPEED_MASK       0x0300
+#define GIGA_CR_1000T_DEFAULT_CAP      0x0300
+
+/* PHY Specific Status Register */
+#define MII_GIGA_PSSR                  0x11
+#define GIGA_PSSR_SPD_DPLX_RESOLVED    0x0800  /* 1=Speed & Duplex resolved */
+#define GIGA_PSSR_DPLX                 0x2000  /* 1=Duplex 0=Half Duplex */
+#define GIGA_PSSR_SPEED                        0xC000  /* Speed, bits 14:15 */
+#define GIGA_PSSR_10MBS                        0x0000  /* 00=10Mbs */
+#define GIGA_PSSR_100MBS               0x4000  /* 01=100Mbs */
+#define GIGA_PSSR_1000MBS              0x8000  /* 10=1000Mbs */
+
+/* PHY Interrupt Enable Register */
+#define MII_IER                                0x12
+#define IER_LINK_UP                    0x0400
+#define IER_LINK_DOWN                  0x0800
+
+/* PHY Interrupt Status Register */
+#define MII_ISR                                0x13
+#define ISR_LINK_UP                    0x0400
+#define ISR_LINK_DOWN                  0x0800
+
+/* Cable-Detect-Test Control Register */
+#define MII_CDTC                       0x16
+#define CDTC_EN_OFF                    0   /* sc */
+#define CDTC_EN_BITS                   1
+#define CDTC_PAIR_OFF                  8
+#define CDTC_PAIR_BIT                  2
+
+/* Cable-Detect-Test Status Register */
+#define MII_CDTS                       0x1C
+#define CDTS_STATUS_OFF                        8
+#define CDTS_STATUS_BITS               2
+#define CDTS_STATUS_NORMAL             0
+#define CDTS_STATUS_SHORT              1
+#define CDTS_STATUS_OPEN               2
+#define CDTS_STATUS_INVALID            3
+
+#define MII_DBG_ADDR                   0x1D
+#define MII_DBG_DATA                   0x1E
+
+#define MII_ANA_CTRL_0                 0x0
+#define ANA_RESTART_CAL                        0x0001
+#define ANA_MANUL_SWICH_ON_SHIFT       0x1
+#define ANA_MANUL_SWICH_ON_MASK                0xF
+#define ANA_MAN_ENABLE                 0x0020
+#define ANA_SEL_HSP                    0x0040
+#define ANA_EN_HB                      0x0080
+#define ANA_EN_HBIAS                   0x0100
+#define ANA_OEN_125M                   0x0200
+#define ANA_EN_LCKDT                   0x0400
+#define ANA_LCKDT_PHY                  0x0800
+#define ANA_AFE_MODE                   0x1000
+#define ANA_VCO_SLOW                   0x2000
+#define ANA_VCO_FAST                   0x4000
+#define ANA_SEL_CLK125M_DSP            0x8000
+
+#define MII_ANA_CTRL_4                 0x4
+#define ANA_IECHO_ADJ_MASK             0xF
+#define ANA_IECHO_ADJ_3_SHIFT          0
+#define ANA_IECHO_ADJ_2_SHIFT          4
+#define ANA_IECHO_ADJ_1_SHIFT          8
+#define ANA_IECHO_ADJ_0_SHIFT          12
+
+#define MII_ANA_CTRL_5                 0x5
+#define ANA_SERDES_CDR_BW_SHIFT                0
+#define ANA_SERDES_CDR_BW_MASK         0x3
+#define ANA_MS_PAD_DBG                 0x0004
+#define ANA_SPEEDUP_DBG                        0x0008
+#define ANA_SERDES_TH_LOS_SHIFT                4
+#define ANA_SERDES_TH_LOS_MASK         0x3
+#define ANA_SERDES_EN_DEEM             0x0040
+#define ANA_SERDES_TXELECIDLE          0x0080
+#define ANA_SERDES_BEACON              0x0100
+#define ANA_SERDES_HALFTXDR            0x0200
+#define ANA_SERDES_SEL_HSP             0x0400
+#define ANA_SERDES_EN_PLL              0x0800
+#define ANA_SERDES_EN                  0x1000
+#define ANA_SERDES_EN_LCKDT            0x2000
+
+#define MII_ANA_CTRL_11                        0xB
+#define ANA_PS_HIB_EN                  0x8000
+
+#define MII_ANA_CTRL_18                        0x12
+#define ANA_TEST_MODE_10BT_01SHIFT     0
+#define ANA_TEST_MODE_10BT_01MASK      0x3
+#define ANA_LOOP_SEL_10BT              0x0004
+#define ANA_RGMII_MODE_SW              0x0008
+#define ANA_EN_LONGECABLE              0x0010
+#define ANA_TEST_MODE_10BT_2           0x0020
+#define ANA_EN_10BT_IDLE               0x0400
+#define ANA_EN_MASK_TB                 0x0800
+#define ANA_TRIGGER_SEL_TIMER_SHIFT    12
+#define ANA_TRIGGER_SEL_TIMER_MASK     0x3
+#define ANA_INTERVAL_SEL_TIMER_SHIFT   14
+#define ANA_INTERVAL_SEL_TIMER_MASK    0x3
+
+#define MII_ANA_CTRL_41                        0x29
+#define ANA_TOP_PS_EN                  0x8000
+
+#define MII_ANA_CTRL_54                        0x36
+#define ANA_LONG_CABLE_TH_100_SHIFT    0
+#define ANA_LONG_CABLE_TH_100_MASK     0x3F
+#define ANA_DESERVED                   0x0040
+#define ANA_EN_LIT_CH                  0x0080
+#define ANA_SHORT_CABLE_TH_100_SHIFT   8
+#define ANA_SHORT_CABLE_TH_100_MASK    0x3F
+#define ANA_BP_BAD_LINK_ACCUM          0x4000
+#define ANA_BP_SMALL_BW                        0x8000
+
+#endif /*_ATL1C_HW_H_*/
diff --git a/drivers/net/atl1c/atl1c_main.c b/drivers/net/atl1c/atl1c_main.c
new file mode 100644 (file)
index 0000000..deb7b53
--- /dev/null
@@ -0,0 +1,2797 @@
+/*
+ * Copyright(c) 2008 - 2009 Atheros Corporation. All rights reserved.
+ *
+ * Derived from Intel e1000 driver
+ * Copyright(c) 1999 - 2005 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ */
+
+#include "atl1c.h"
+
+#define ATL1C_DRV_VERSION "1.0.0.1-NAPI"
+char atl1c_driver_name[] = "atl1c";
+char atl1c_driver_version[] = ATL1C_DRV_VERSION;
+#define PCI_DEVICE_ID_ATTANSIC_L2C      0x1062
+#define PCI_DEVICE_ID_ATTANSIC_L1C      0x1063
+/*
+ * atl1c_pci_tbl - PCI Device ID Table
+ *
+ * Wildcard entries (PCI_ANY_ID) should come last
+ * Last entry must be all 0s
+ *
+ * { Vendor ID, Device ID, SubVendor ID, SubDevice ID,
+ *   Class, Class Mask, private data (not used) }
+ */
+static struct pci_device_id atl1c_pci_tbl[] = {
+       {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L1C)},
+       {PCI_DEVICE(PCI_VENDOR_ID_ATTANSIC, PCI_DEVICE_ID_ATTANSIC_L2C)},
+       /* required last entry */
+       { 0 }
+};
+MODULE_DEVICE_TABLE(pci, atl1c_pci_tbl);
+
+MODULE_AUTHOR("Jie Yang <jie.yang@atheros.com>");
+MODULE_DESCRIPTION("Atheros 1000M Ethernet Network Driver");
+MODULE_LICENSE("GPL");
+MODULE_VERSION(ATL1C_DRV_VERSION);
+
+static int atl1c_stop_mac(struct atl1c_hw *hw);
+static void atl1c_enable_rx_ctrl(struct atl1c_hw *hw);
+static void atl1c_enable_tx_ctrl(struct atl1c_hw *hw);
+static void atl1c_disable_l0s_l1(struct atl1c_hw *hw);
+static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup);
+static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter);
+static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, u8 que,
+                  int *work_done, int work_to_do);
+
+static const u16 atl1c_pay_load_size[] = {
+       128, 256, 512, 1024, 2048, 4096,
+};
+
+static const u16 atl1c_rfd_prod_idx_regs[AT_MAX_RECEIVE_QUEUE] =
+{
+       REG_MB_RFD0_PROD_IDX,
+       REG_MB_RFD1_PROD_IDX,
+       REG_MB_RFD2_PROD_IDX,
+       REG_MB_RFD3_PROD_IDX
+};
+
+static const u16 atl1c_rfd_addr_lo_regs[AT_MAX_RECEIVE_QUEUE] =
+{
+       REG_RFD0_HEAD_ADDR_LO,
+       REG_RFD1_HEAD_ADDR_LO,
+       REG_RFD2_HEAD_ADDR_LO,
+       REG_RFD3_HEAD_ADDR_LO
+};
+
+static const u16 atl1c_rrd_addr_lo_regs[AT_MAX_RECEIVE_QUEUE] =
+{
+       REG_RRD0_HEAD_ADDR_LO,
+       REG_RRD1_HEAD_ADDR_LO,
+       REG_RRD2_HEAD_ADDR_LO,
+       REG_RRD3_HEAD_ADDR_LO
+};
+
+static const u32 atl1c_default_msg = NETIF_MSG_DRV | NETIF_MSG_PROBE |
+       NETIF_MSG_LINK | NETIF_MSG_TIMER | NETIF_MSG_IFDOWN | NETIF_MSG_IFUP;
+
+/*
+ * atl1c_init_pcie - init PCIE module
+ */
+static void atl1c_reset_pcie(struct atl1c_hw *hw, u32 flag)
+{
+       u32 data;
+       u32 pci_cmd;
+       struct pci_dev *pdev = hw->adapter->pdev;
+
+       AT_READ_REG(hw, PCI_COMMAND, &pci_cmd);
+       pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
+       pci_cmd |= (PCI_COMMAND_MEMORY | PCI_COMMAND_MASTER |
+               PCI_COMMAND_IO);
+       AT_WRITE_REG(hw, PCI_COMMAND, pci_cmd);
+
+       /*
+        * Clear any PowerSaveing Settings
+        */
+       pci_enable_wake(pdev, PCI_D3hot, 0);
+       pci_enable_wake(pdev, PCI_D3cold, 0);
+
+       /*
+        * Mask some pcie error bits
+        */
+       AT_READ_REG(hw, REG_PCIE_UC_SEVERITY, &data);
+       data &= ~PCIE_UC_SERVRITY_DLP;
+       data &= ~PCIE_UC_SERVRITY_FCP;
+       AT_WRITE_REG(hw, REG_PCIE_UC_SEVERITY, data);
+
+       if (flag & ATL1C_PCIE_L0S_L1_DISABLE)
+               atl1c_disable_l0s_l1(hw);
+       if (flag & ATL1C_PCIE_PHY_RESET)
+               AT_WRITE_REG(hw, REG_GPHY_CTRL, GPHY_CTRL_DEFAULT);
+       else
+               AT_WRITE_REG(hw, REG_GPHY_CTRL,
+                       GPHY_CTRL_DEFAULT | GPHY_CTRL_EXT_RESET);
+
+       msleep(1);
+}
+
+/*
+ * atl1c_irq_enable - Enable default interrupt generation settings
+ * @adapter: board private structure
+ */
+static inline void atl1c_irq_enable(struct atl1c_adapter *adapter)
+{
+       if (likely(atomic_dec_and_test(&adapter->irq_sem))) {
+               AT_WRITE_REG(&adapter->hw, REG_ISR, 0x7FFFFFFF);
+               AT_WRITE_REG(&adapter->hw, REG_IMR, adapter->hw.intr_mask);
+               AT_WRITE_FLUSH(&adapter->hw);
+       }
+}
+
+/*
+ * atl1c_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ */
+static inline void atl1c_irq_disable(struct atl1c_adapter *adapter)
+{
+       atomic_inc(&adapter->irq_sem);
+       AT_WRITE_REG(&adapter->hw, REG_IMR, 0);
+       AT_WRITE_FLUSH(&adapter->hw);
+       synchronize_irq(adapter->pdev->irq);
+}
+
+/*
+ * atl1c_irq_reset - reset interrupt confiure on the NIC
+ * @adapter: board private structure
+ */
+static inline void atl1c_irq_reset(struct atl1c_adapter *adapter)
+{
+       atomic_set(&adapter->irq_sem, 1);
+       atl1c_irq_enable(adapter);
+}
+
+/*
+ * atl1c_phy_config - Timer Call-back
+ * @data: pointer to netdev cast into an unsigned long
+ */
+static void atl1c_phy_config(unsigned long data)
+{
+       struct atl1c_adapter *adapter = (struct atl1c_adapter *) data;
+       struct atl1c_hw *hw = &adapter->hw;
+       unsigned long flags;
+
+       spin_lock_irqsave(&adapter->mdio_lock, flags);
+       atl1c_restart_autoneg(hw);
+       spin_unlock_irqrestore(&adapter->mdio_lock, flags);
+}
+
+void atl1c_reinit_locked(struct atl1c_adapter *adapter)
+{
+
+       WARN_ON(in_interrupt());
+       atl1c_down(adapter);
+       atl1c_up(adapter);
+       clear_bit(__AT_RESETTING, &adapter->flags);
+}
+
+static void atl1c_reset_task(struct work_struct *work)
+{
+       struct atl1c_adapter *adapter;
+       struct net_device *netdev;
+
+       adapter = container_of(work, struct atl1c_adapter, reset_task);
+       netdev = adapter->netdev;
+
+       netif_device_detach(netdev);
+       atl1c_down(adapter);
+       atl1c_up(adapter);
+       netif_device_attach(netdev);
+}
+
+static void atl1c_check_link_status(struct atl1c_adapter *adapter)
+{
+       struct atl1c_hw *hw = &adapter->hw;
+       struct net_device *netdev = adapter->netdev;
+       struct pci_dev    *pdev   = adapter->pdev;
+       int err;
+       unsigned long flags;
+       u16 speed, duplex, phy_data;
+
+       spin_lock_irqsave(&adapter->mdio_lock, flags);
+       /* MII_BMSR must read twise */
+       atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+       atl1c_read_phy_reg(hw, MII_BMSR, &phy_data);
+       spin_unlock_irqrestore(&adapter->mdio_lock, flags);
+
+       if ((phy_data & BMSR_LSTATUS) == 0) {
+               /* link down */
+               if (netif_carrier_ok(netdev)) {
+                       hw->hibernate = true;
+                       atl1c_set_aspm(hw, false);
+                       if (atl1c_stop_mac(hw) != 0)
+                               if (netif_msg_hw(adapter))
+                                       dev_warn(&pdev->dev,
+                                               "stop mac failed\n");
+               }
+               netif_carrier_off(netdev);
+       } else {
+               /* Link Up */
+               hw->hibernate = false;
+               spin_lock_irqsave(&adapter->mdio_lock, flags);
+               err = atl1c_get_speed_and_duplex(hw, &speed, &duplex);
+               spin_unlock_irqrestore(&adapter->mdio_lock, flags);
+               if (unlikely(err))
+                       return;
+               /* link result is our setting */
+               if (adapter->link_speed != speed ||
+                   adapter->link_duplex != duplex) {
+                       adapter->link_speed  = speed;
+                       adapter->link_duplex = duplex;
+                       atl1c_enable_tx_ctrl(hw);
+                       atl1c_enable_rx_ctrl(hw);
+                       atl1c_setup_mac_ctrl(adapter);
+                       atl1c_set_aspm(hw, true);
+                       if (netif_msg_link(adapter))
+                               dev_info(&pdev->dev,
+                                       "%s: %s NIC Link is Up<%d Mbps %s>\n",
+                                       atl1c_driver_name, netdev->name,
+                                       adapter->link_speed,
+                                       adapter->link_duplex == FULL_DUPLEX ?
+                                       "Full Duplex" : "Half Duplex");
+               }
+               if (!netif_carrier_ok(netdev))
+                       netif_carrier_on(netdev);
+       }
+}
+
+/*
+ * atl1c_link_chg_task - deal with link change event Out of interrupt context
+ * @netdev: network interface device structure
+ */
+static void atl1c_link_chg_task(struct work_struct *work)
+{
+       struct atl1c_adapter *adapter;
+
+       adapter = container_of(work, struct atl1c_adapter, link_chg_task);
+       atl1c_check_link_status(adapter);
+}
+
+static void atl1c_link_chg_event(struct atl1c_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct pci_dev    *pdev   = adapter->pdev;
+       u16 phy_data;
+       u16 link_up;
+
+       spin_lock(&adapter->mdio_lock);
+       atl1c_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+       atl1c_read_phy_reg(&adapter->hw, MII_BMSR, &phy_data);
+       spin_unlock(&adapter->mdio_lock);
+       link_up = phy_data & BMSR_LSTATUS;
+       /* notify upper layer link down ASAP */
+       if (!link_up) {
+               if (netif_carrier_ok(netdev)) {
+                       /* old link state: Up */
+                       netif_carrier_off(netdev);
+                       if (netif_msg_link(adapter))
+                               dev_info(&pdev->dev,
+                                       "%s: %s NIC Link is Down\n",
+                                       atl1c_driver_name, netdev->name);
+                       adapter->link_speed = SPEED_0;
+               }
+       }
+       schedule_work(&adapter->link_chg_task);
+}
+
+static void atl1c_del_timer(struct atl1c_adapter *adapter)
+{
+       del_timer_sync(&adapter->phy_config_timer);
+}
+
+static void atl1c_cancel_work(struct atl1c_adapter *adapter)
+{
+       cancel_work_sync(&adapter->reset_task);
+       cancel_work_sync(&adapter->link_chg_task);
+}
+
+/*
+ * atl1c_tx_timeout - Respond to a Tx Hang
+ * @netdev: network interface device structure
+ */
+static void atl1c_tx_timeout(struct net_device *netdev)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+       /* Do the reset outside of interrupt context */
+       schedule_work(&adapter->reset_task);
+}
+
+/*
+ * atl1c_set_multi - Multicast and Promiscuous mode set
+ * @netdev: network interface device structure
+ *
+ * The set_multi entry point is called whenever the multicast address
+ * list or the network interface flags are updated.  This routine is
+ * responsible for configuring the hardware for proper multicast,
+ * promiscuous mode, and all-multi behavior.
+ */
+static void atl1c_set_multi(struct net_device *netdev)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       struct atl1c_hw *hw = &adapter->hw;
+       struct dev_mc_list *mc_ptr;
+       u32 mac_ctrl_data;
+       u32 hash_value;
+
+       /* Check for Promiscuous and All Multicast modes */
+       AT_READ_REG(hw, REG_MAC_CTRL, &mac_ctrl_data);
+
+       if (netdev->flags & IFF_PROMISC) {
+               mac_ctrl_data |= MAC_CTRL_PROMIS_EN;
+       } else if (netdev->flags & IFF_ALLMULTI) {
+               mac_ctrl_data |= MAC_CTRL_MC_ALL_EN;
+               mac_ctrl_data &= ~MAC_CTRL_PROMIS_EN;
+       } else {
+               mac_ctrl_data &= ~(MAC_CTRL_PROMIS_EN | MAC_CTRL_MC_ALL_EN);
+       }
+
+       AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
+
+       /* clear the old settings from the multicast hash table */
+       AT_WRITE_REG(hw, REG_RX_HASH_TABLE, 0);
+       AT_WRITE_REG_ARRAY(hw, REG_RX_HASH_TABLE, 1, 0);
+
+       /* comoute mc addresses' hash value ,and put it into hash table */
+       for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
+               hash_value = atl1c_hash_mc_addr(hw, mc_ptr->dmi_addr);
+               atl1c_hash_set(hw, hash_value);
+       }
+}
+
+static void atl1c_vlan_rx_register(struct net_device *netdev,
+                                  struct vlan_group *grp)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       struct pci_dev *pdev = adapter->pdev;
+       u32 mac_ctrl_data = 0;
+
+       if (netif_msg_pktdata(adapter))
+               dev_dbg(&pdev->dev, "atl1c_vlan_rx_register\n");
+
+       atl1c_irq_disable(adapter);
+
+       adapter->vlgrp = grp;
+       AT_READ_REG(&adapter->hw, REG_MAC_CTRL, &mac_ctrl_data);
+
+       if (grp) {
+               /* enable VLAN tag insert/strip */
+               mac_ctrl_data |= MAC_CTRL_RMV_VLAN;
+       } else {
+               /* disable VLAN tag insert/strip */
+               mac_ctrl_data &= ~MAC_CTRL_RMV_VLAN;
+       }
+
+       AT_WRITE_REG(&adapter->hw, REG_MAC_CTRL, mac_ctrl_data);
+       atl1c_irq_enable(adapter);
+}
+
+static void atl1c_restore_vlan(struct atl1c_adapter *adapter)
+{
+       struct pci_dev *pdev = adapter->pdev;
+
+       if (netif_msg_pktdata(adapter))
+               dev_dbg(&pdev->dev, "atl1c_restore_vlan !");
+       atl1c_vlan_rx_register(adapter->netdev, adapter->vlgrp);
+}
+/*
+ * atl1c_set_mac - Change the Ethernet Address of the NIC
+ * @netdev: network interface device structure
+ * @p: pointer to an address structure
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int atl1c_set_mac_addr(struct net_device *netdev, void *p)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       struct sockaddr *addr = p;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       if (netif_running(netdev))
+               return -EBUSY;
+
+       memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+       memcpy(adapter->hw.mac_addr, addr->sa_data, netdev->addr_len);
+
+       atl1c_hw_set_mac_addr(&adapter->hw);
+
+       return 0;
+}
+
+static void atl1c_set_rxbufsize(struct atl1c_adapter *adapter,
+                               struct net_device *dev)
+{
+       int mtu = dev->mtu;
+
+       adapter->rx_buffer_len = mtu > AT_RX_BUF_SIZE ?
+               roundup(mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN, 8) : AT_RX_BUF_SIZE;
+}
+/*
+ * atl1c_change_mtu - Change the Maximum Transfer Unit
+ * @netdev: network interface device structure
+ * @new_mtu: new value for maximum frame size
+ *
+ * Returns 0 on success, negative on failure
+ */
+static int atl1c_change_mtu(struct net_device *netdev, int new_mtu)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       int old_mtu   = netdev->mtu;
+       int max_frame = new_mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN;
+
+       if ((max_frame < ETH_ZLEN + ETH_FCS_LEN) ||
+                       (max_frame > MAX_JUMBO_FRAME_SIZE)) {
+               if (netif_msg_link(adapter))
+                       dev_warn(&adapter->pdev->dev, "invalid MTU setting\n");
+               return -EINVAL;
+       }
+       /* set MTU */
+       if (old_mtu != new_mtu && netif_running(netdev)) {
+               while (test_and_set_bit(__AT_RESETTING, &adapter->flags))
+                       msleep(1);
+               netdev->mtu = new_mtu;
+               adapter->hw.max_frame_size = new_mtu;
+               atl1c_set_rxbufsize(adapter, netdev);
+               atl1c_down(adapter);
+               atl1c_up(adapter);
+               clear_bit(__AT_RESETTING, &adapter->flags);
+               if (adapter->hw.ctrl_flags & ATL1C_FPGA_VERSION) {
+                       u32 phy_data;
+
+                       AT_READ_REG(&adapter->hw, 0x1414, &phy_data);
+                       phy_data |= 0x10000000;
+                       AT_WRITE_REG(&adapter->hw, 0x1414, phy_data);
+               }
+
+       }
+       return 0;
+}
+
+/*
+ *  caller should hold mdio_lock
+ */
+static int atl1c_mdio_read(struct net_device *netdev, int phy_id, int reg_num)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       u16 result;
+
+       atl1c_read_phy_reg(&adapter->hw, reg_num & MDIO_REG_ADDR_MASK, &result);
+       return result;
+}
+
+static void atl1c_mdio_write(struct net_device *netdev, int phy_id,
+                            int reg_num, int val)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+       atl1c_write_phy_reg(&adapter->hw, reg_num & MDIO_REG_ADDR_MASK, val);
+}
+
+/*
+ * atl1c_mii_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ */
+static int atl1c_mii_ioctl(struct net_device *netdev,
+                          struct ifreq *ifr, int cmd)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       struct pci_dev *pdev = adapter->pdev;
+       struct mii_ioctl_data *data = if_mii(ifr);
+       unsigned long flags;
+       int retval = 0;
+
+       if (!netif_running(netdev))
+               return -EINVAL;
+
+       spin_lock_irqsave(&adapter->mdio_lock, flags);
+       switch (cmd) {
+       case SIOCGMIIPHY:
+               data->phy_id = 0;
+               break;
+
+       case SIOCGMIIREG:
+               if (!capable(CAP_NET_ADMIN)) {
+                       retval = -EPERM;
+                       goto out;
+               }
+               if (atl1c_read_phy_reg(&adapter->hw, data->reg_num & 0x1F,
+                                   &data->val_out)) {
+                       retval = -EIO;
+                       goto out;
+               }
+               break;
+
+       case SIOCSMIIREG:
+               if (!capable(CAP_NET_ADMIN)) {
+                       retval = -EPERM;
+                       goto out;
+               }
+               if (data->reg_num & ~(0x1F)) {
+                       retval = -EFAULT;
+                       goto out;
+               }
+
+               dev_dbg(&pdev->dev, "<atl1c_mii_ioctl> write %x %x",
+                               data->reg_num, data->val_in);
+               if (atl1c_write_phy_reg(&adapter->hw,
+                                    data->reg_num, data->val_in)) {
+                       retval = -EIO;
+                       goto out;
+               }
+               break;
+
+       default:
+               retval = -EOPNOTSUPP;
+               break;
+       }
+out:
+       spin_unlock_irqrestore(&adapter->mdio_lock, flags);
+       return retval;
+}
+
+/*
+ * atl1c_ioctl -
+ * @netdev:
+ * @ifreq:
+ * @cmd:
+ */
+static int atl1c_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
+{
+       switch (cmd) {
+       case SIOCGMIIPHY:
+       case SIOCGMIIREG:
+       case SIOCSMIIREG:
+               return atl1c_mii_ioctl(netdev, ifr, cmd);
+       default:
+               return -EOPNOTSUPP;
+       }
+}
+
+/*
+ * atl1c_alloc_queues - Allocate memory for all rings
+ * @adapter: board private structure to initialize
+ *
+ */
+static int __devinit atl1c_alloc_queues(struct atl1c_adapter *adapter)
+{
+       return 0;
+}
+
+static void atl1c_set_mac_type(struct atl1c_hw *hw)
+{
+       switch (hw->device_id) {
+       case PCI_DEVICE_ID_ATTANSIC_L2C:
+               hw->nic_type = athr_l2c;
+               break;
+
+       case PCI_DEVICE_ID_ATTANSIC_L1C:
+               hw->nic_type = athr_l1c;
+               break;
+
+       default:
+               break;
+       }
+}
+
+static int atl1c_setup_mac_funcs(struct atl1c_hw *hw)
+{
+       u32 phy_status_data;
+       u32 link_ctrl_data;
+
+       atl1c_set_mac_type(hw);
+       AT_READ_REG(hw, REG_PHY_STATUS, &phy_status_data);
+       AT_READ_REG(hw, REG_LINK_CTRL, &link_ctrl_data);
+
+       hw->ctrl_flags = ATL1C_INTR_CLEAR_ON_READ |
+                        ATL1C_INTR_MODRT_ENABLE  |
+                        ATL1C_RX_IPV6_CHKSUM     |
+                        ATL1C_TXQ_MODE_ENHANCE;
+       if (link_ctrl_data & LINK_CTRL_L0S_EN)
+               hw->ctrl_flags |= ATL1C_ASPM_L0S_SUPPORT;
+       if (link_ctrl_data & LINK_CTRL_L1_EN)
+               hw->ctrl_flags |= ATL1C_ASPM_L1_SUPPORT;
+
+       if (hw->nic_type == athr_l1c) {
+               hw->ctrl_flags |= ATL1C_ASPM_CTRL_MON;
+               hw->ctrl_flags |= ATL1C_LINK_CAP_1000M;
+       }
+       return 0;
+}
+/*
+ * atl1c_sw_init - Initialize general software structures (struct atl1c_adapter)
+ * @adapter: board private structure to initialize
+ *
+ * atl1c_sw_init initializes the Adapter private data structure.
+ * Fields are initialized based on PCI device information and
+ * OS network device settings (MTU size).
+ */
+static int __devinit atl1c_sw_init(struct atl1c_adapter *adapter)
+{
+       struct atl1c_hw *hw   = &adapter->hw;
+       struct pci_dev  *pdev = adapter->pdev;
+
+       adapter->wol = 0;
+       adapter->link_speed = SPEED_0;
+       adapter->link_duplex = FULL_DUPLEX;
+       adapter->num_rx_queues = AT_DEF_RECEIVE_QUEUE;
+       adapter->tpd_ring[0].count = 1024;
+       adapter->rfd_ring[0].count = 512;
+
+       hw->vendor_id = pdev->vendor;
+       hw->device_id = pdev->device;
+       hw->subsystem_vendor_id = pdev->subsystem_vendor;
+       hw->subsystem_id = pdev->subsystem_device;
+
+       /* before link up, we assume hibernate is true */
+       hw->hibernate = true;
+       hw->media_type = MEDIA_TYPE_AUTO_SENSOR;
+       if (atl1c_setup_mac_funcs(hw) != 0) {
+               dev_err(&pdev->dev, "set mac function pointers failed\n");
+               return -1;
+       }
+       hw->intr_mask = IMR_NORMAL_MASK;
+       hw->phy_configured = false;
+       hw->preamble_len = 7;
+       hw->max_frame_size = adapter->netdev->mtu;
+       if (adapter->num_rx_queues < 2) {
+               hw->rss_type = atl1c_rss_disable;
+               hw->rss_mode = atl1c_rss_mode_disable;
+       } else {
+               hw->rss_type = atl1c_rss_ipv4;
+               hw->rss_mode = atl1c_rss_mul_que_mul_int;
+               hw->rss_hash_bits = 16;
+       }
+       hw->autoneg_advertised = ADVERTISED_Autoneg;
+       hw->indirect_tab = 0xE4E4E4E4;
+       hw->base_cpu = 0;
+
+       hw->ict = 50000;                /* 100ms */
+       hw->smb_timer = 200000;         /* 400ms */
+       hw->cmb_tpd = 4;
+       hw->cmb_tx_timer = 1;           /* 2 us  */
+       hw->rx_imt = 200;
+       hw->tx_imt = 1000;
+
+       hw->tpd_burst = 5;
+       hw->rfd_burst = 8;
+       hw->dma_order = atl1c_dma_ord_out;
+       hw->dmar_block = atl1c_dma_req_1024;
+       hw->dmaw_block = atl1c_dma_req_1024;
+       hw->dmar_dly_cnt = 15;
+       hw->dmaw_dly_cnt = 4;
+
+       if (atl1c_alloc_queues(adapter)) {
+               dev_err(&pdev->dev, "Unable to allocate memory for queues\n");
+               return -ENOMEM;
+       }
+       /* TODO */
+       atl1c_set_rxbufsize(adapter, adapter->netdev);
+       atomic_set(&adapter->irq_sem, 1);
+       spin_lock_init(&adapter->mdio_lock);
+       spin_lock_init(&adapter->tx_lock);
+       set_bit(__AT_DOWN, &adapter->flags);
+
+       return 0;
+}
+
+/*
+ * atl1c_clean_tx_ring - Free Tx-skb
+ * @adapter: board private structure
+ */
+static void atl1c_clean_tx_ring(struct atl1c_adapter *adapter,
+                               enum atl1c_trans_queue type)
+{
+       struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type];
+       struct atl1c_buffer *buffer_info;
+       struct pci_dev *pdev = adapter->pdev;
+       u16 index, ring_count;
+
+       ring_count = tpd_ring->count;
+       for (index = 0; index < ring_count; index++) {
+               buffer_info = &tpd_ring->buffer_info[index];
+               if (buffer_info->state == ATL1_BUFFER_FREE)
+                       continue;
+               if (buffer_info->dma)
+                       pci_unmap_single(pdev, buffer_info->dma,
+                                       buffer_info->length,
+                                       PCI_DMA_TODEVICE);
+               if (buffer_info->skb)
+                       dev_kfree_skb(buffer_info->skb);
+               buffer_info->dma = 0;
+               buffer_info->skb = NULL;
+               buffer_info->state = ATL1_BUFFER_FREE;
+       }
+
+       /* Zero out Tx-buffers */
+       memset(tpd_ring->desc, 0, sizeof(struct atl1c_tpd_desc) *
+                               ring_count);
+       atomic_set(&tpd_ring->next_to_clean, 0);
+       tpd_ring->next_to_use = 0;
+}
+
+/*
+ * atl1c_clean_rx_ring - Free rx-reservation skbs
+ * @adapter: board private structure
+ */
+static void atl1c_clean_rx_ring(struct atl1c_adapter *adapter)
+{
+       struct atl1c_rfd_ring *rfd_ring = adapter->rfd_ring;
+       struct atl1c_rrd_ring *rrd_ring = adapter->rrd_ring;
+       struct atl1c_buffer *buffer_info;
+       struct pci_dev *pdev = adapter->pdev;
+       int i, j;
+
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               for (j = 0; j < rfd_ring[i].count; j++) {
+                       buffer_info = &rfd_ring[i].buffer_info[j];
+                       if (buffer_info->state == ATL1_BUFFER_FREE)
+                               continue;
+                       if (buffer_info->dma)
+                               pci_unmap_single(pdev, buffer_info->dma,
+                                               buffer_info->length,
+                                               PCI_DMA_FROMDEVICE);
+                       if (buffer_info->skb)
+                               dev_kfree_skb(buffer_info->skb);
+                       buffer_info->state = ATL1_BUFFER_FREE;
+                       buffer_info->skb = NULL;
+               }
+               /* zero out the descriptor ring */
+               memset(rfd_ring[i].desc, 0, rfd_ring[i].size);
+               rfd_ring[i].next_to_clean = 0;
+               rfd_ring[i].next_to_use = 0;
+               rrd_ring[i].next_to_use = 0;
+               rrd_ring[i].next_to_clean = 0;
+       }
+}
+
+/*
+ * Read / Write Ptr Initialize:
+ */
+static void atl1c_init_ring_ptrs(struct atl1c_adapter *adapter)
+{
+       struct atl1c_tpd_ring *tpd_ring = adapter->tpd_ring;
+       struct atl1c_rfd_ring *rfd_ring = adapter->rfd_ring;
+       struct atl1c_rrd_ring *rrd_ring = adapter->rrd_ring;
+       struct atl1c_buffer *buffer_info;
+       int i, j;
+
+       for (i = 0; i < AT_MAX_TRANSMIT_QUEUE; i++) {
+               tpd_ring[i].next_to_use = 0;
+               atomic_set(&tpd_ring[i].next_to_clean, 0);
+               buffer_info = tpd_ring[i].buffer_info;
+               for (j = 0; j < tpd_ring->count; j++)
+                       buffer_info[i].state = ATL1_BUFFER_FREE;
+       }
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               rfd_ring[i].next_to_use = 0;
+               rfd_ring[i].next_to_clean = 0;
+               rrd_ring[i].next_to_use = 0;
+               rrd_ring[i].next_to_clean = 0;
+               for (j = 0; j < rfd_ring[i].count; j++) {
+                       buffer_info = &rfd_ring[i].buffer_info[j];
+                       buffer_info->state = ATL1_BUFFER_FREE;
+               }
+       }
+}
+
+/*
+ * atl1c_free_ring_resources - Free Tx / RX descriptor Resources
+ * @adapter: board private structure
+ *
+ * Free all transmit software resources
+ */
+static void atl1c_free_ring_resources(struct atl1c_adapter *adapter)
+{
+       struct pci_dev *pdev = adapter->pdev;
+
+       pci_free_consistent(pdev, adapter->ring_header.size,
+                                       adapter->ring_header.desc,
+                                       adapter->ring_header.dma);
+       adapter->ring_header.desc = NULL;
+
+       /* Note: just free tdp_ring.buffer_info,
+       *  it contain rfd_ring.buffer_info, do not double free */
+       if (adapter->tpd_ring[0].buffer_info) {
+               kfree(adapter->tpd_ring[0].buffer_info);
+               adapter->tpd_ring[0].buffer_info = NULL;
+       }
+}
+
+/*
+ * atl1c_setup_mem_resources - allocate Tx / RX descriptor resources
+ * @adapter: board private structure
+ *
+ * Return 0 on success, negative on failure
+ */
+static int atl1c_setup_ring_resources(struct atl1c_adapter *adapter)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       struct atl1c_tpd_ring *tpd_ring = adapter->tpd_ring;
+       struct atl1c_rfd_ring *rfd_ring = adapter->rfd_ring;
+       struct atl1c_rrd_ring *rrd_ring = adapter->rrd_ring;
+       struct atl1c_ring_header *ring_header = &adapter->ring_header;
+       int num_rx_queues = adapter->num_rx_queues;
+       int size;
+       int i;
+       int count = 0;
+       int rx_desc_count = 0;
+       u32 offset = 0;
+
+       rrd_ring[0].count = rfd_ring[0].count;
+       for (i = 1; i < AT_MAX_TRANSMIT_QUEUE; i++)
+               tpd_ring[i].count = tpd_ring[0].count;
+
+       for (i = 1; i < adapter->num_rx_queues; i++)
+               rfd_ring[i].count = rrd_ring[i].count = rfd_ring[0].count;
+
+       /* 2 tpd queue, one high priority queue,
+        * another normal priority queue */
+       size = sizeof(struct atl1c_buffer) * (tpd_ring->count * 2 +
+               rfd_ring->count * num_rx_queues);
+       tpd_ring->buffer_info = kzalloc(size, GFP_KERNEL);
+       if (unlikely(!tpd_ring->buffer_info)) {
+               dev_err(&pdev->dev, "kzalloc failed, size = %d\n",
+                       size);
+               goto err_nomem;
+       }
+       for (i = 0; i < AT_MAX_TRANSMIT_QUEUE; i++) {
+               tpd_ring[i].buffer_info =
+                       (struct atl1c_buffer *) (tpd_ring->buffer_info + count);
+               count += tpd_ring[i].count;
+       }
+
+       for (i = 0; i < num_rx_queues; i++) {
+               rfd_ring[i].buffer_info =
+                       (struct atl1c_buffer *) (tpd_ring->buffer_info + count);
+               count += rfd_ring[i].count;
+               rx_desc_count += rfd_ring[i].count;
+       }
+       /*
+        * real ring DMA buffer
+        * each ring/block may need up to 8 bytes for alignment, hence the
+        * additional bytes tacked onto the end.
+        */
+       ring_header->size = size =
+               sizeof(struct atl1c_tpd_desc) * tpd_ring->count * 2 +
+               sizeof(struct atl1c_rx_free_desc) * rx_desc_count +
+               sizeof(struct atl1c_recv_ret_status) * rx_desc_count +
+               sizeof(struct atl1c_hw_stats) +
+               8 * 4 + 8 * 2 * num_rx_queues;
+
+       ring_header->desc = pci_alloc_consistent(pdev, ring_header->size,
+                               &ring_header->dma);
+       if (unlikely(!ring_header->desc)) {
+               dev_err(&pdev->dev, "pci_alloc_consistend failed\n");
+               goto err_nomem;
+       }
+       memset(ring_header->desc, 0, ring_header->size);
+       /* init TPD ring */
+
+       tpd_ring[0].dma = roundup(ring_header->dma, 8);
+       offset = tpd_ring[0].dma - ring_header->dma;
+       for (i = 0; i < AT_MAX_TRANSMIT_QUEUE; i++) {
+               tpd_ring[i].dma = ring_header->dma + offset;
+               tpd_ring[i].desc = (u8 *) ring_header->desc + offset;
+               tpd_ring[i].size =
+                       sizeof(struct atl1c_tpd_desc) * tpd_ring[i].count;
+               offset += roundup(tpd_ring[i].size, 8);
+       }
+       /* init RFD ring */
+       for (i = 0; i < num_rx_queues; i++) {
+               rfd_ring[i].dma = ring_header->dma + offset;
+               rfd_ring[i].desc = (u8 *) ring_header->desc + offset;
+               rfd_ring[i].size = sizeof(struct atl1c_rx_free_desc) *
+                               rfd_ring[i].count;
+               offset += roundup(rfd_ring[i].size, 8);
+       }
+
+       /* init RRD ring */
+       for (i = 0; i < num_rx_queues; i++) {
+               rrd_ring[i].dma = ring_header->dma + offset;
+               rrd_ring[i].desc = (u8 *) ring_header->desc + offset;
+               rrd_ring[i].size = sizeof(struct atl1c_recv_ret_status) *
+                               rrd_ring[i].count;
+               offset += roundup(rrd_ring[i].size, 8);
+       }
+
+       adapter->smb.dma = ring_header->dma + offset;
+       adapter->smb.smb = (u8 *)ring_header->desc + offset;
+       return 0;
+
+err_nomem:
+       kfree(tpd_ring->buffer_info);
+       return -ENOMEM;
+}
+
+static void atl1c_configure_des_ring(struct atl1c_adapter *adapter)
+{
+       struct atl1c_hw *hw = &adapter->hw;
+       struct atl1c_rfd_ring *rfd_ring = (struct atl1c_rfd_ring *)
+                               adapter->rfd_ring;
+       struct atl1c_rrd_ring *rrd_ring = (struct atl1c_rrd_ring *)
+                               adapter->rrd_ring;
+       struct atl1c_tpd_ring *tpd_ring = (struct atl1c_tpd_ring *)
+                               adapter->tpd_ring;
+       struct atl1c_cmb *cmb = (struct atl1c_cmb *) &adapter->cmb;
+       struct atl1c_smb *smb = (struct atl1c_smb *) &adapter->smb;
+       int i;
+
+       /* TPD */
+       AT_WRITE_REG(hw, REG_TX_BASE_ADDR_HI,
+                       (u32)((tpd_ring[atl1c_trans_normal].dma &
+                               AT_DMA_HI_ADDR_MASK) >> 32));
+       /* just enable normal priority TX queue */
+       AT_WRITE_REG(hw, REG_NTPD_HEAD_ADDR_LO,
+                       (u32)(tpd_ring[atl1c_trans_normal].dma &
+                               AT_DMA_LO_ADDR_MASK));
+       AT_WRITE_REG(hw, REG_HTPD_HEAD_ADDR_LO,
+                       (u32)(tpd_ring[atl1c_trans_high].dma &
+                               AT_DMA_LO_ADDR_MASK));
+       AT_WRITE_REG(hw, REG_TPD_RING_SIZE,
+                       (u32)(tpd_ring[0].count & TPD_RING_SIZE_MASK));
+
+
+       /* RFD */
+       AT_WRITE_REG(hw, REG_RX_BASE_ADDR_HI,
+                       (u32)((rfd_ring[0].dma & AT_DMA_HI_ADDR_MASK) >> 32));
+       for (i = 0; i < adapter->num_rx_queues; i++)
+               AT_WRITE_REG(hw, atl1c_rfd_addr_lo_regs[i],
+                       (u32)(rfd_ring[i].dma & AT_DMA_LO_ADDR_MASK));
+
+       AT_WRITE_REG(hw, REG_RFD_RING_SIZE,
+                       rfd_ring[0].count & RFD_RING_SIZE_MASK);
+       AT_WRITE_REG(hw, REG_RX_BUF_SIZE,
+                       adapter->rx_buffer_len & RX_BUF_SIZE_MASK);
+
+       /* RRD */
+       for (i = 0; i < adapter->num_rx_queues; i++)
+               AT_WRITE_REG(hw, atl1c_rrd_addr_lo_regs[i],
+                       (u32)(rrd_ring[i].dma & AT_DMA_LO_ADDR_MASK));
+       AT_WRITE_REG(hw, REG_RRD_RING_SIZE,
+                       (rrd_ring[0].count & RRD_RING_SIZE_MASK));
+
+       /* CMB */
+       AT_WRITE_REG(hw, REG_CMB_BASE_ADDR_LO, cmb->dma & AT_DMA_LO_ADDR_MASK);
+
+       /* SMB */
+       AT_WRITE_REG(hw, REG_SMB_BASE_ADDR_HI,
+                       (u32)((smb->dma & AT_DMA_HI_ADDR_MASK) >> 32));
+       AT_WRITE_REG(hw, REG_SMB_BASE_ADDR_LO,
+                       (u32)(smb->dma & AT_DMA_LO_ADDR_MASK));
+       /* Load all of base address above */
+       AT_WRITE_REG(hw, REG_LOAD_PTR, 1);
+}
+
+static void atl1c_configure_tx(struct atl1c_adapter *adapter)
+{
+       struct atl1c_hw *hw = &adapter->hw;
+       u32 dev_ctrl_data;
+       u32 max_pay_load;
+       u16 tx_offload_thresh;
+       u32 txq_ctrl_data;
+       u32 extra_size = 0;     /* Jumbo frame threshold in QWORD unit */
+
+       extra_size = ETH_HLEN + VLAN_HLEN + ETH_FCS_LEN;
+       tx_offload_thresh = MAX_TX_OFFLOAD_THRESH;
+       AT_WRITE_REG(hw, REG_TX_TSO_OFFLOAD_THRESH,
+               (tx_offload_thresh >> 3) & TX_TSO_OFFLOAD_THRESH_MASK);
+       AT_READ_REG(hw, REG_DEVICE_CTRL, &dev_ctrl_data);
+       max_pay_load  = (dev_ctrl_data >> DEVICE_CTRL_MAX_PAYLOAD_SHIFT) &
+                       DEVICE_CTRL_MAX_PAYLOAD_MASK;
+       hw->dmaw_block = min(max_pay_load, hw->dmaw_block);
+       max_pay_load  = (dev_ctrl_data >> DEVICE_CTRL_MAX_RREQ_SZ_SHIFT) &
+                       DEVICE_CTRL_MAX_RREQ_SZ_MASK;
+       hw->dmar_block = min(max_pay_load, hw->dmar_block);
+
+       txq_ctrl_data = (hw->tpd_burst & TXQ_NUM_TPD_BURST_MASK) <<
+                       TXQ_NUM_TPD_BURST_SHIFT;
+       if (hw->ctrl_flags & ATL1C_TXQ_MODE_ENHANCE)
+               txq_ctrl_data |= TXQ_CTRL_ENH_MODE;
+       txq_ctrl_data |= (atl1c_pay_load_size[hw->dmar_block] &
+                       TXQ_TXF_BURST_NUM_MASK) << TXQ_TXF_BURST_NUM_SHIFT;
+
+       AT_WRITE_REG(hw, REG_TXQ_CTRL, txq_ctrl_data);
+}
+
+static void atl1c_configure_rx(struct atl1c_adapter *adapter)
+{
+       struct atl1c_hw *hw = &adapter->hw;
+       u32 rxq_ctrl_data;
+
+       rxq_ctrl_data = (hw->rfd_burst & RXQ_RFD_BURST_NUM_MASK) <<
+                       RXQ_RFD_BURST_NUM_SHIFT;
+
+       if (hw->ctrl_flags & ATL1C_RX_IPV6_CHKSUM)
+               rxq_ctrl_data |= IPV6_CHKSUM_CTRL_EN;
+       if (hw->rss_type == atl1c_rss_ipv4)
+               rxq_ctrl_data |= RSS_HASH_IPV4;
+       if (hw->rss_type == atl1c_rss_ipv4_tcp)
+               rxq_ctrl_data |= RSS_HASH_IPV4_TCP;
+       if (hw->rss_type == atl1c_rss_ipv6)
+               rxq_ctrl_data |= RSS_HASH_IPV6;
+       if (hw->rss_type == atl1c_rss_ipv6_tcp)
+               rxq_ctrl_data |= RSS_HASH_IPV6_TCP;
+       if (hw->rss_type != atl1c_rss_disable)
+               rxq_ctrl_data |= RRS_HASH_CTRL_EN;
+
+       rxq_ctrl_data |= (hw->rss_mode & RSS_MODE_MASK) <<
+                       RSS_MODE_SHIFT;
+       rxq_ctrl_data |= (hw->rss_hash_bits & RSS_HASH_BITS_MASK) <<
+                       RSS_HASH_BITS_SHIFT;
+       if (hw->ctrl_flags & ATL1C_ASPM_CTRL_MON)
+               rxq_ctrl_data |= (ASPM_THRUPUT_LIMIT_100M &
+                       ASPM_THRUPUT_LIMIT_MASK) << ASPM_THRUPUT_LIMIT_SHIFT;
+
+       AT_WRITE_REG(hw, REG_RXQ_CTRL, rxq_ctrl_data);
+}
+
+static void atl1c_configure_rss(struct atl1c_adapter *adapter)
+{
+       struct atl1c_hw *hw = &adapter->hw;
+
+       AT_WRITE_REG(hw, REG_IDT_TABLE, hw->indirect_tab);
+       AT_WRITE_REG(hw, REG_BASE_CPU_NUMBER, hw->base_cpu);
+}
+
+static void atl1c_configure_dma(struct atl1c_adapter *adapter)
+{
+       struct atl1c_hw *hw = &adapter->hw;
+       u32 dma_ctrl_data;
+
+       dma_ctrl_data = DMA_CTRL_DMAR_REQ_PRI;
+       if (hw->ctrl_flags & ATL1C_CMB_ENABLE)
+               dma_ctrl_data |= DMA_CTRL_CMB_EN;
+       if (hw->ctrl_flags & ATL1C_SMB_ENABLE)
+               dma_ctrl_data |= DMA_CTRL_SMB_EN;
+       else
+               dma_ctrl_data |= MAC_CTRL_SMB_DIS;
+
+       switch (hw->dma_order) {
+       case atl1c_dma_ord_in:
+               dma_ctrl_data |= DMA_CTRL_DMAR_IN_ORDER;
+               break;
+       case atl1c_dma_ord_enh:
+               dma_ctrl_data |= DMA_CTRL_DMAR_ENH_ORDER;
+               break;
+       case atl1c_dma_ord_out:
+               dma_ctrl_data |= DMA_CTRL_DMAR_OUT_ORDER;
+               break;
+       default:
+               break;
+       }
+
+       dma_ctrl_data |= (((u32)hw->dmar_block) & DMA_CTRL_DMAR_BURST_LEN_MASK)
+               << DMA_CTRL_DMAR_BURST_LEN_SHIFT;
+       dma_ctrl_data |= (((u32)hw->dmaw_block) & DMA_CTRL_DMAW_BURST_LEN_MASK)
+               << DMA_CTRL_DMAW_BURST_LEN_SHIFT;
+       dma_ctrl_data |= (((u32)hw->dmar_dly_cnt) & DMA_CTRL_DMAR_DLY_CNT_MASK)
+               << DMA_CTRL_DMAR_DLY_CNT_SHIFT;
+       dma_ctrl_data |= (((u32)hw->dmaw_dly_cnt) & DMA_CTRL_DMAW_DLY_CNT_MASK)
+               << DMA_CTRL_DMAW_DLY_CNT_SHIFT;
+
+       AT_WRITE_REG(hw, REG_DMA_CTRL, dma_ctrl_data);
+}
+
+/*
+ * Stop the mac, transmit and receive units
+ * hw - Struct containing variables accessed by shared code
+ * return : 0  or  idle status (if error)
+ */
+static int atl1c_stop_mac(struct atl1c_hw *hw)
+{
+       u32 data;
+       int timeout;
+
+       AT_READ_REG(hw, REG_RXQ_CTRL, &data);
+       data &= ~(RXQ1_CTRL_EN | RXQ2_CTRL_EN |
+                 RXQ3_CTRL_EN | RXQ_CTRL_EN);
+       AT_WRITE_REG(hw, REG_RXQ_CTRL, data);
+
+       AT_READ_REG(hw, REG_TXQ_CTRL, &data);
+       data &= ~TXQ_CTRL_EN;
+       AT_WRITE_REG(hw, REG_TWSI_CTRL, data);
+
+       for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
+               AT_READ_REG(hw, REG_IDLE_STATUS, &data);
+               if ((data & (IDLE_STATUS_RXQ_NO_IDLE |
+                       IDLE_STATUS_TXQ_NO_IDLE)) == 0)
+                       break;
+               msleep(1);
+       }
+
+       AT_READ_REG(hw, REG_MAC_CTRL, &data);
+       data &= ~(MAC_CTRL_TX_EN | MAC_CTRL_RX_EN);
+       AT_WRITE_REG(hw, REG_MAC_CTRL, data);
+
+       for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
+               AT_READ_REG(hw, REG_IDLE_STATUS, &data);
+               if ((data & IDLE_STATUS_MASK) == 0)
+                       return 0;
+               msleep(1);
+       }
+       return data;
+}
+
+static void atl1c_enable_rx_ctrl(struct atl1c_hw *hw)
+{
+       u32 data;
+
+       AT_READ_REG(hw, REG_RXQ_CTRL, &data);
+       switch (hw->adapter->num_rx_queues) {
+       case 4:
+               data |= (RXQ3_CTRL_EN | RXQ2_CTRL_EN | RXQ1_CTRL_EN);
+               break;
+       case 3:
+               data |= (RXQ2_CTRL_EN | RXQ1_CTRL_EN);
+               break;
+       case 2:
+               data |= RXQ1_CTRL_EN;
+               break;
+       default:
+               break;
+       }
+       data |= RXQ_CTRL_EN;
+       AT_WRITE_REG(hw, REG_RXQ_CTRL, data);
+}
+
+static void atl1c_enable_tx_ctrl(struct atl1c_hw *hw)
+{
+       u32 data;
+
+       AT_READ_REG(hw, REG_TXQ_CTRL, &data);
+       data |= TXQ_CTRL_EN;
+       AT_WRITE_REG(hw, REG_TXQ_CTRL, data);
+}
+
+/*
+ * Reset the transmit and receive units; mask and clear all interrupts.
+ * hw - Struct containing variables accessed by shared code
+ * return : 0  or  idle status (if error)
+ */
+static int atl1c_reset_mac(struct atl1c_hw *hw)
+{
+       struct atl1c_adapter *adapter = (struct atl1c_adapter *)hw->adapter;
+       struct pci_dev *pdev = adapter->pdev;
+       u32 idle_status_data = 0;
+       int timeout = 0;
+       int ret;
+
+       AT_WRITE_REG(hw, REG_IMR, 0);
+       AT_WRITE_REG(hw, REG_ISR, ISR_DIS_INT);
+
+       ret = atl1c_stop_mac(hw);
+       if (ret)
+               return ret;
+       /*
+        * Issue Soft Reset to the MAC.  This will reset the chip's
+        * transmit, receive, DMA.  It will not effect
+        * the current PCI configuration.  The global reset bit is self-
+        * clearing, and should clear within a microsecond.
+        */
+       AT_WRITE_REGW(hw, REG_MASTER_CTRL, MASTER_CTRL_SOFT_RST);
+       AT_WRITE_FLUSH(hw);
+       msleep(10);
+       /* Wait at least 10ms for All module to be Idle */
+       for (timeout = 0; timeout < AT_HW_MAX_IDLE_DELAY; timeout++) {
+               AT_READ_REG(hw, REG_IDLE_STATUS, &idle_status_data);
+               if ((idle_status_data & IDLE_STATUS_MASK) == 0)
+                       break;
+               msleep(1);
+       }
+       if (timeout >= AT_HW_MAX_IDLE_DELAY) {
+               dev_err(&pdev->dev,
+                       "MAC state machine cann't be idle since"
+                       " disabled for 10ms second\n");
+               return -1;
+       }
+       return 0;
+}
+
+static void atl1c_disable_l0s_l1(struct atl1c_hw *hw)
+{
+       u32 pm_ctrl_data;
+
+       AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data);
+       pm_ctrl_data &= ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
+                       PM_CTRL_L1_ENTRY_TIMER_SHIFT);
+       pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1;
+       pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
+       pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+       pm_ctrl_data &= ~PM_CTRL_MAC_ASPM_CHK;
+       pm_ctrl_data &= ~PM_CTRL_SERDES_PD_EX_L1;
+
+       pm_ctrl_data |= PM_CTRL_SERDES_BUDS_RX_L1_EN;
+       pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN;
+       pm_ctrl_data |= PM_CTRL_SERDES_L1_EN;
+       AT_WRITE_REG(hw, REG_PM_CTRL, pm_ctrl_data);
+}
+
+/*
+ * Set ASPM state.
+ * Enable/disable L0s/L1 depend on link state.
+ */
+static void atl1c_set_aspm(struct atl1c_hw *hw, bool linkup)
+{
+       u32 pm_ctrl_data;
+
+       AT_READ_REG(hw, REG_PM_CTRL, &pm_ctrl_data);
+
+       pm_ctrl_data &= PM_CTRL_SERDES_PD_EX_L1;
+       pm_ctrl_data |= ~PM_CTRL_SERDES_BUDS_RX_L1_EN;
+       pm_ctrl_data |= ~PM_CTRL_SERDES_L1_EN;
+       pm_ctrl_data &=  ~(PM_CTRL_L1_ENTRY_TIMER_MASK <<
+                       PM_CTRL_L1_ENTRY_TIMER_SHIFT);
+
+       pm_ctrl_data |= PM_CTRL_MAC_ASPM_CHK;
+
+       if (linkup) {
+               pm_ctrl_data |= PM_CTRL_SERDES_PLL_L1_EN;
+               pm_ctrl_data &= ~PM_CTRL_CLK_SWH_L1;
+
+               if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT) {
+                       pm_ctrl_data |= AT_ASPM_L1_TIMER <<
+                               PM_CTRL_L1_ENTRY_TIMER_SHIFT;
+                       pm_ctrl_data |= PM_CTRL_ASPM_L1_EN;
+               } else
+                       pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+
+               if (hw->ctrl_flags & ATL1C_ASPM_L0S_SUPPORT)
+                       pm_ctrl_data |= PM_CTRL_ASPM_L0S_EN;
+               else
+                       pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
+
+       } else {
+               pm_ctrl_data &= ~PM_CTRL_ASPM_L0S_EN;
+               pm_ctrl_data &= ~PM_CTRL_SERDES_PLL_L1_EN;
+
+               pm_ctrl_data |= PM_CTRL_CLK_SWH_L1;
+
+               if (hw->ctrl_flags & ATL1C_ASPM_L1_SUPPORT)
+                       pm_ctrl_data |= PM_CTRL_ASPM_L1_EN;
+               else
+                       pm_ctrl_data &= ~PM_CTRL_ASPM_L1_EN;
+       }
+
+       AT_WRITE_REG(hw, REG_PM_CTRL, pm_ctrl_data);
+}
+
+static void atl1c_setup_mac_ctrl(struct atl1c_adapter *adapter)
+{
+       struct atl1c_hw *hw = &adapter->hw;
+       struct net_device *netdev = adapter->netdev;
+       u32 mac_ctrl_data;
+
+       mac_ctrl_data = MAC_CTRL_TX_EN | MAC_CTRL_RX_EN;
+       mac_ctrl_data |= (MAC_CTRL_TX_FLOW | MAC_CTRL_RX_FLOW);
+
+       if (adapter->link_duplex == FULL_DUPLEX) {
+               hw->mac_duplex = true;
+               mac_ctrl_data |= MAC_CTRL_DUPLX;
+       }
+
+       if (adapter->link_speed == SPEED_1000)
+               hw->mac_speed = atl1c_mac_speed_1000;
+       else
+               hw->mac_speed = atl1c_mac_speed_10_100;
+
+       mac_ctrl_data |= (hw->mac_speed & MAC_CTRL_SPEED_MASK) <<
+                       MAC_CTRL_SPEED_SHIFT;
+
+       mac_ctrl_data |= (MAC_CTRL_ADD_CRC | MAC_CTRL_PAD);
+       mac_ctrl_data |= ((hw->preamble_len & MAC_CTRL_PRMLEN_MASK) <<
+                       MAC_CTRL_PRMLEN_SHIFT);
+
+       if (adapter->vlgrp)
+               mac_ctrl_data |= MAC_CTRL_RMV_VLAN;
+
+       mac_ctrl_data |= MAC_CTRL_BC_EN;
+       if (netdev->flags & IFF_PROMISC)
+               mac_ctrl_data |= MAC_CTRL_PROMIS_EN;
+       if (netdev->flags & IFF_ALLMULTI)
+               mac_ctrl_data |= MAC_CTRL_MC_ALL_EN;
+
+       mac_ctrl_data |= MAC_CTRL_SINGLE_PAUSE_EN;
+       AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
+}
+
+/*
+ * atl1c_configure - Configure Transmit&Receive Unit after Reset
+ * @adapter: board private structure
+ *
+ * Configure the Tx /Rx unit of the MAC after a reset.
+ */
+static int atl1c_configure(struct atl1c_adapter *adapter)
+{
+       struct atl1c_hw *hw = &adapter->hw;
+       u32 master_ctrl_data = 0;
+       u32 intr_modrt_data;
+
+       /* clear interrupt status */
+       AT_WRITE_REG(hw, REG_ISR, 0xFFFFFFFF);
+       /*  Clear any WOL status */
+       AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
+       /* set Interrupt Clear Timer
+        * HW will enable self to assert interrupt event to system after
+        * waiting x-time for software to notify it accept interrupt.
+        */
+       AT_WRITE_REG(hw, REG_INT_RETRIG_TIMER,
+               hw->ict & INT_RETRIG_TIMER_MASK);
+
+       atl1c_configure_des_ring(adapter);
+
+       if (hw->ctrl_flags & ATL1C_INTR_MODRT_ENABLE) {
+               intr_modrt_data = (hw->tx_imt & IRQ_MODRT_TIMER_MASK) <<
+                                       IRQ_MODRT_TX_TIMER_SHIFT;
+               intr_modrt_data |= (hw->rx_imt & IRQ_MODRT_TIMER_MASK) <<
+                                       IRQ_MODRT_RX_TIMER_SHIFT;
+               AT_WRITE_REG(hw, REG_IRQ_MODRT_TIMER_INIT, intr_modrt_data);
+               master_ctrl_data |=
+                       MASTER_CTRL_TX_ITIMER_EN | MASTER_CTRL_RX_ITIMER_EN;
+       }
+
+       if (hw->ctrl_flags & ATL1C_INTR_CLEAR_ON_READ)
+               master_ctrl_data |= MASTER_CTRL_INT_RDCLR;
+
+       AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data);
+
+       if (hw->ctrl_flags & ATL1C_CMB_ENABLE) {
+               AT_WRITE_REG(hw, REG_CMB_TPD_THRESH,
+                       hw->cmb_tpd & CMB_TPD_THRESH_MASK);
+               AT_WRITE_REG(hw, REG_CMB_TX_TIMER,
+                       hw->cmb_tx_timer & CMB_TX_TIMER_MASK);
+       }
+
+       if (hw->ctrl_flags & ATL1C_SMB_ENABLE)
+               AT_WRITE_REG(hw, REG_SMB_STAT_TIMER,
+                       hw->smb_timer & SMB_STAT_TIMER_MASK);
+       /* set MTU */
+       AT_WRITE_REG(hw, REG_MTU, hw->max_frame_size + ETH_HLEN +
+                       VLAN_HLEN + ETH_FCS_LEN);
+       /* HDS, disable */
+       AT_WRITE_REG(hw, REG_HDS_CTRL, 0);
+
+       atl1c_configure_tx(adapter);
+       atl1c_configure_rx(adapter);
+       atl1c_configure_rss(adapter);
+       atl1c_configure_dma(adapter);
+
+       return 0;
+}
+
+static void atl1c_update_hw_stats(struct atl1c_adapter *adapter)
+{
+       u16 hw_reg_addr = 0;
+       unsigned long *stats_item = NULL;
+       u32 data;
+
+       /* update rx status */
+       hw_reg_addr = REG_MAC_RX_STATUS_BIN;
+       stats_item  = &adapter->hw_stats.rx_ok;
+       while (hw_reg_addr <= REG_MAC_RX_STATUS_END) {
+               AT_READ_REG(&adapter->hw, hw_reg_addr, &data);
+               *stats_item += data;
+               stats_item++;
+               hw_reg_addr += 4;
+       }
+/* update tx status */
+       hw_reg_addr = REG_MAC_TX_STATUS_BIN;
+       stats_item  = &adapter->hw_stats.tx_ok;
+       while (hw_reg_addr <= REG_MAC_TX_STATUS_END) {
+               AT_READ_REG(&adapter->hw, hw_reg_addr, &data);
+               *stats_item += data;
+               stats_item++;
+               hw_reg_addr += 4;
+       }
+}
+
+/*
+ * atl1c_get_stats - Get System Network Statistics
+ * @netdev: network interface device structure
+ *
+ * Returns the address of the device statistics structure.
+ * The statistics are actually updated from the timer callback.
+ */
+static struct net_device_stats *atl1c_get_stats(struct net_device *netdev)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       struct atl1c_hw_stats  *hw_stats = &adapter->hw_stats;
+       struct net_device_stats *net_stats = &adapter->net_stats;
+
+       atl1c_update_hw_stats(adapter);
+       net_stats->rx_packets = hw_stats->rx_ok;
+       net_stats->tx_packets = hw_stats->tx_ok;
+       net_stats->rx_bytes   = hw_stats->rx_byte_cnt;
+       net_stats->tx_bytes   = hw_stats->tx_byte_cnt;
+       net_stats->multicast  = hw_stats->rx_mcast;
+       net_stats->collisions = hw_stats->tx_1_col +
+                               hw_stats->tx_2_col * 2 +
+                               hw_stats->tx_late_col + hw_stats->tx_abort_col;
+       net_stats->rx_errors  = hw_stats->rx_frag + hw_stats->rx_fcs_err +
+                               hw_stats->rx_len_err + hw_stats->rx_sz_ov +
+                               hw_stats->rx_rrd_ov + hw_stats->rx_align_err;
+       net_stats->rx_fifo_errors   = hw_stats->rx_rxf_ov;
+       net_stats->rx_length_errors = hw_stats->rx_len_err;
+       net_stats->rx_crc_errors    = hw_stats->rx_fcs_err;
+       net_stats->rx_frame_errors  = hw_stats->rx_align_err;
+       net_stats->rx_over_errors   = hw_stats->rx_rrd_ov + hw_stats->rx_rxf_ov;
+
+       net_stats->rx_missed_errors = hw_stats->rx_rrd_ov + hw_stats->rx_rxf_ov;
+
+       net_stats->tx_errors = hw_stats->tx_late_col + hw_stats->tx_abort_col +
+                               hw_stats->tx_underrun + hw_stats->tx_trunc;
+       net_stats->tx_fifo_errors    = hw_stats->tx_underrun;
+       net_stats->tx_aborted_errors = hw_stats->tx_abort_col;
+       net_stats->tx_window_errors  = hw_stats->tx_late_col;
+
+       return &adapter->net_stats;
+}
+
+static inline void atl1c_clear_phy_int(struct atl1c_adapter *adapter)
+{
+       u16 phy_data;
+
+       spin_lock(&adapter->mdio_lock);
+       atl1c_read_phy_reg(&adapter->hw, MII_ISR, &phy_data);
+       spin_unlock(&adapter->mdio_lock);
+}
+
+static bool atl1c_clean_tx_irq(struct atl1c_adapter *adapter,
+                               enum atl1c_trans_queue type)
+{
+       struct atl1c_tpd_ring *tpd_ring = (struct atl1c_tpd_ring *)
+                               &adapter->tpd_ring[type];
+       struct atl1c_buffer *buffer_info;
+       u16 next_to_clean = atomic_read(&tpd_ring->next_to_clean);
+       u16 hw_next_to_clean;
+       u16 shift;
+       u32 data;
+
+       if (type == atl1c_trans_high)
+               shift = MB_HTPD_CONS_IDX_SHIFT;
+       else
+               shift = MB_NTPD_CONS_IDX_SHIFT;
+
+       AT_READ_REG(&adapter->hw, REG_MB_PRIO_CONS_IDX, &data);
+       hw_next_to_clean = (data >> shift) & MB_PRIO_PROD_IDX_MASK;
+
+       while (next_to_clean != hw_next_to_clean) {
+               buffer_info = &tpd_ring->buffer_info[next_to_clean];
+               if (buffer_info->state == ATL1_BUFFER_BUSY) {
+                       pci_unmap_page(adapter->pdev, buffer_info->dma,
+                                       buffer_info->length, PCI_DMA_TODEVICE);
+                       buffer_info->dma = 0;
+                       if (buffer_info->skb) {
+                               dev_kfree_skb_irq(buffer_info->skb);
+                               buffer_info->skb = NULL;
+                       }
+                       buffer_info->state = ATL1_BUFFER_FREE;
+               }
+               if (++next_to_clean == tpd_ring->count)
+                       next_to_clean = 0;
+               atomic_set(&tpd_ring->next_to_clean, next_to_clean);
+       }
+
+       if (netif_queue_stopped(adapter->netdev) &&
+                       netif_carrier_ok(adapter->netdev)) {
+               netif_wake_queue(adapter->netdev);
+       }
+
+       return true;
+}
+
+/*
+ * atl1c_intr - Interrupt Handler
+ * @irq: interrupt number
+ * @data: pointer to a network interface device structure
+ * @pt_regs: CPU registers structure
+ */
+static irqreturn_t atl1c_intr(int irq, void *data)
+{
+       struct net_device *netdev  = data;
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       struct pci_dev *pdev = adapter->pdev;
+       struct atl1c_hw *hw = &adapter->hw;
+       int max_ints = AT_MAX_INT_WORK;
+       int handled = IRQ_NONE;
+       u32 status;
+       u32 reg_data;
+
+       do {
+               AT_READ_REG(hw, REG_ISR, &reg_data);
+               status = reg_data & hw->intr_mask;
+
+               if (status == 0 || (status & ISR_DIS_INT) != 0) {
+                       if (max_ints != AT_MAX_INT_WORK)
+                               handled = IRQ_HANDLED;
+                       break;
+               }
+               /* link event */
+               if (status & ISR_GPHY)
+                       atl1c_clear_phy_int(adapter);
+               /* Ack ISR */
+               AT_WRITE_REG(hw, REG_ISR, status | ISR_DIS_INT);
+               if (status & ISR_RX_PKT) {
+                       if (likely(napi_schedule_prep(&adapter->napi))) {
+                               hw->intr_mask &= ~ISR_RX_PKT;
+                               AT_WRITE_REG(hw, REG_IMR, hw->intr_mask);
+                               __napi_schedule(&adapter->napi);
+                       }
+               }
+               if (status & ISR_TX_PKT)
+                       atl1c_clean_tx_irq(adapter, atl1c_trans_normal);
+
+               handled = IRQ_HANDLED;
+               /* check if PCIE PHY Link down */
+               if (status & ISR_ERROR) {
+                       if (netif_msg_hw(adapter))
+                               dev_err(&pdev->dev,
+                                       "atl1c hardware error (status = 0x%x)\n",
+                                       status & ISR_ERROR);
+                       /* reset MAC */
+                       hw->intr_mask &= ~ISR_ERROR;
+                       AT_WRITE_REG(hw, REG_IMR, hw->intr_mask);
+                       schedule_work(&adapter->reset_task);
+                       break;
+               }
+
+               if (status & ISR_OVER)
+                       if (netif_msg_intr(adapter))
+                               dev_warn(&pdev->dev,
+                                       "TX/RX over flow (status = 0x%x)\n",
+                                       status & ISR_OVER);
+
+               /* link event */
+               if (status & (ISR_GPHY | ISR_MANUAL)) {
+                       adapter->net_stats.tx_carrier_errors++;
+                       atl1c_link_chg_event(adapter);
+                       break;
+               }
+
+       } while (--max_ints > 0);
+       /* re-enable Interrupt*/
+       AT_WRITE_REG(&adapter->hw, REG_ISR, 0);
+       return handled;
+}
+
+static inline void atl1c_rx_checksum(struct atl1c_adapter *adapter,
+                 struct sk_buff *skb, struct atl1c_recv_ret_status *prrs)
+{
+       /*
+        * The pid field in RRS in not correct sometimes, so we
+        * cannot figure out if the packet is fragmented or not,
+        * so we tell the KERNEL CHECKSUM_NONE
+        */
+       skb->ip_summed = CHECKSUM_NONE;
+}
+
+static int atl1c_alloc_rx_buffer(struct atl1c_adapter *adapter, const int ringid)
+{
+       struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring[ringid];
+       struct pci_dev *pdev = adapter->pdev;
+       struct atl1c_buffer *buffer_info, *next_info;
+       struct sk_buff *skb;
+       void *vir_addr = NULL;
+       u16 num_alloc = 0;
+       u16 rfd_next_to_use, next_next;
+       struct atl1c_rx_free_desc *rfd_desc;
+
+       next_next = rfd_next_to_use = rfd_ring->next_to_use;
+       if (++next_next == rfd_ring->count)
+               next_next = 0;
+       buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
+       next_info = &rfd_ring->buffer_info[next_next];
+
+       while (next_info->state == ATL1_BUFFER_FREE) {
+               rfd_desc = ATL1C_RFD_DESC(rfd_ring, rfd_next_to_use);
+
+               skb = dev_alloc_skb(adapter->rx_buffer_len);
+               if (unlikely(!skb)) {
+                       if (netif_msg_rx_err(adapter))
+                               dev_warn(&pdev->dev, "alloc rx buffer failed\n");
+                       break;
+               }
+
+               /*
+                * Make buffer alignment 2 beyond a 16 byte boundary
+                * this will result in a 16 byte aligned IP header after
+                * the 14 byte MAC header is removed
+                */
+               vir_addr = skb->data;
+               buffer_info->state = ATL1_BUFFER_BUSY;
+               buffer_info->skb = skb;
+               buffer_info->length = adapter->rx_buffer_len;
+               buffer_info->dma = pci_map_single(pdev, vir_addr,
+                                               buffer_info->length,
+                                               PCI_DMA_FROMDEVICE);
+               rfd_desc->buffer_addr = cpu_to_le64(buffer_info->dma);
+               rfd_next_to_use = next_next;
+               if (++next_next == rfd_ring->count)
+                       next_next = 0;
+               buffer_info = &rfd_ring->buffer_info[rfd_next_to_use];
+               next_info = &rfd_ring->buffer_info[next_next];
+               num_alloc++;
+       }
+
+       if (num_alloc) {
+               /* TODO: update mailbox here */
+               wmb();
+               rfd_ring->next_to_use = rfd_next_to_use;
+               AT_WRITE_REG(&adapter->hw, atl1c_rfd_prod_idx_regs[ringid],
+                       rfd_ring->next_to_use & MB_RFDX_PROD_IDX_MASK);
+       }
+
+       return num_alloc;
+}
+
+static void atl1c_clean_rrd(struct atl1c_rrd_ring *rrd_ring,
+                       struct  atl1c_recv_ret_status *rrs, u16 num)
+{
+       u16 i;
+       /* the relationship between rrd and rfd is one map one */
+       for (i = 0; i < num; i++, rrs = ATL1C_RRD_DESC(rrd_ring,
+                                       rrd_ring->next_to_clean)) {
+               rrs->word3 &= ~RRS_RXD_UPDATED;
+               if (++rrd_ring->next_to_clean == rrd_ring->count)
+                       rrd_ring->next_to_clean = 0;
+       }
+}
+
+static void atl1c_clean_rfd(struct atl1c_rfd_ring *rfd_ring,
+       struct atl1c_recv_ret_status *rrs, u16 num)
+{
+       u16 i;
+       u16 rfd_index;
+       struct atl1c_buffer *buffer_info = rfd_ring->buffer_info;
+
+       rfd_index = (rrs->word0 >> RRS_RX_RFD_INDEX_SHIFT) &
+                       RRS_RX_RFD_INDEX_MASK;
+       for (i = 0; i < num; i++) {
+               buffer_info[rfd_index].skb = NULL;
+               buffer_info[rfd_index].state = ATL1_BUFFER_FREE;
+               if (++rfd_index == rfd_ring->count)
+                       rfd_index = 0;
+       }
+       rfd_ring->next_to_clean = rfd_index;
+}
+
+static void atl1c_clean_rx_irq(struct atl1c_adapter *adapter, u8 que,
+                  int *work_done, int work_to_do)
+{
+       u16 rfd_num, rfd_index;
+       u16 count = 0;
+       u16 length;
+       struct pci_dev *pdev = adapter->pdev;
+       struct net_device *netdev  = adapter->netdev;
+       struct atl1c_rfd_ring *rfd_ring = &adapter->rfd_ring[que];
+       struct atl1c_rrd_ring *rrd_ring = &adapter->rrd_ring[que];
+       struct sk_buff *skb;
+       struct atl1c_recv_ret_status *rrs;
+       struct atl1c_buffer *buffer_info;
+
+       while (1) {
+               if (*work_done >= work_to_do)
+                       break;
+               rrs = ATL1C_RRD_DESC(rrd_ring, rrd_ring->next_to_clean);
+               if (likely(RRS_RXD_IS_VALID(rrs->word3))) {
+                       rfd_num = (rrs->word0 >> RRS_RX_RFD_CNT_SHIFT) &
+                               RRS_RX_RFD_CNT_MASK;
+                       if (unlikely(rfd_num) != 1)
+                               /* TODO support mul rfd*/
+                               if (netif_msg_rx_err(adapter))
+                                       dev_warn(&pdev->dev,
+                                               "Multi rfd not support yet!\n");
+                       goto rrs_checked;
+               } else {
+                       break;
+               }
+rrs_checked:
+               atl1c_clean_rrd(rrd_ring, rrs, rfd_num);
+               if (rrs->word3 & (RRS_RX_ERR_SUM | RRS_802_3_LEN_ERR)) {
+                       atl1c_clean_rfd(rfd_ring, rrs, rfd_num);
+                               if (netif_msg_rx_err(adapter))
+                                       dev_warn(&pdev->dev,
+                                               "wrong packet! rrs word3 is %x\n",
+                                               rrs->word3);
+                       continue;
+               }
+
+               length = le16_to_cpu((rrs->word3 >> RRS_PKT_SIZE_SHIFT) &
+                               RRS_PKT_SIZE_MASK);
+               /* Good Receive */
+               if (likely(rfd_num == 1)) {
+                       rfd_index = (rrs->word0 >> RRS_RX_RFD_INDEX_SHIFT) &
+                                       RRS_RX_RFD_INDEX_MASK;
+                       buffer_info = &rfd_ring->buffer_info[rfd_index];
+                       pci_unmap_single(pdev, buffer_info->dma,
+                               buffer_info->length, PCI_DMA_FROMDEVICE);
+                       skb = buffer_info->skb;
+               } else {
+                       /* TODO */
+                       if (netif_msg_rx_err(adapter))
+                               dev_warn(&pdev->dev,
+                                       "Multi rfd not support yet!\n");
+                       break;
+               }
+               atl1c_clean_rfd(rfd_ring, rrs, rfd_num);
+               skb_put(skb, length - ETH_FCS_LEN);
+               skb->protocol = eth_type_trans(skb, netdev);
+               skb->dev = netdev;
+               atl1c_rx_checksum(adapter, skb, rrs);
+               if (unlikely(adapter->vlgrp) && rrs->word3 & RRS_VLAN_INS) {
+                       u16 vlan;
+
+                       AT_TAG_TO_VLAN(rrs->vlan_tag, vlan);
+                       vlan = le16_to_cpu(vlan);
+                       vlan_hwaccel_receive_skb(skb, adapter->vlgrp, vlan);
+               } else
+                       netif_receive_skb(skb);
+
+               netdev->last_rx = jiffies;
+               (*work_done)++;
+               count++;
+       }
+       if (count)
+               atl1c_alloc_rx_buffer(adapter, que);
+}
+
+/*
+ * atl1c_clean - NAPI Rx polling callback
+ * @adapter: board private structure
+ */
+static int atl1c_clean(struct napi_struct *napi, int budget)
+{
+       struct atl1c_adapter *adapter =
+                       container_of(napi, struct atl1c_adapter, napi);
+       int work_done = 0;
+
+       /* Keep link state information with original netdev */
+       if (!netif_carrier_ok(adapter->netdev))
+               goto quit_polling;
+       /* just enable one RXQ */
+       atl1c_clean_rx_irq(adapter, 0, &work_done, budget);
+
+       if (work_done < budget) {
+quit_polling:
+               napi_complete(napi);
+               adapter->hw.intr_mask |= ISR_RX_PKT;
+               AT_WRITE_REG(&adapter->hw, REG_IMR, adapter->hw.intr_mask);
+       }
+       return work_done;
+}
+
+#ifdef CONFIG_NET_POLL_CONTROLLER
+
+/*
+ * Polling 'interrupt' - used by things like netconsole to send skbs
+ * without having to re-enable interrupts. It's not called while
+ * the interrupt routine is executing.
+ */
+static void atl1c_netpoll(struct net_device *netdev)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+       disable_irq(adapter->pdev->irq);
+       atl1c_intr(adapter->pdev->irq, netdev);
+       enable_irq(adapter->pdev->irq);
+}
+#endif
+
+static inline u16 atl1c_tpd_avail(struct atl1c_adapter *adapter, enum atl1c_trans_queue type)
+{
+       struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type];
+       u16 next_to_use = 0;
+       u16 next_to_clean = 0;
+
+       next_to_clean = atomic_read(&tpd_ring->next_to_clean);
+       next_to_use   = tpd_ring->next_to_use;
+
+       return (u16)(next_to_clean > next_to_use) ?
+               (next_to_clean - next_to_use - 1) :
+               (tpd_ring->count + next_to_clean - next_to_use - 1);
+}
+
+/*
+ * get next usable tpd
+ * Note: should call atl1c_tdp_avail to make sure
+ * there is enough tpd to use
+ */
+static struct atl1c_tpd_desc *atl1c_get_tpd(struct atl1c_adapter *adapter,
+       enum atl1c_trans_queue type)
+{
+       struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type];
+       struct atl1c_tpd_desc *tpd_desc;
+       u16 next_to_use = 0;
+
+       next_to_use = tpd_ring->next_to_use;
+       if (++tpd_ring->next_to_use == tpd_ring->count)
+               tpd_ring->next_to_use = 0;
+       tpd_desc = ATL1C_TPD_DESC(tpd_ring, next_to_use);
+       memset(tpd_desc, 0, sizeof(struct atl1c_tpd_desc));
+       return  tpd_desc;
+}
+
+static struct atl1c_buffer *
+atl1c_get_tx_buffer(struct atl1c_adapter *adapter, struct atl1c_tpd_desc *tpd)
+{
+       struct atl1c_tpd_ring *tpd_ring = adapter->tpd_ring;
+
+       return &tpd_ring->buffer_info[tpd -
+                       (struct atl1c_tpd_desc *)tpd_ring->desc];
+}
+
+/* Calculate the transmit packet descript needed*/
+static u16 atl1c_cal_tpd_req(const struct sk_buff *skb)
+{
+       u16 tpd_req;
+       u16 proto_hdr_len = 0;
+
+       tpd_req = skb_shinfo(skb)->nr_frags + 1;
+
+       if (skb_is_gso(skb)) {
+               proto_hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               if (proto_hdr_len < skb_headlen(skb))
+                       tpd_req++;
+               if (skb_shinfo(skb)->gso_type & SKB_GSO_TCPV6)
+                       tpd_req++;
+       }
+       return tpd_req;
+}
+
+static int atl1c_tso_csum(struct atl1c_adapter *adapter,
+                         struct sk_buff *skb,
+                         struct atl1c_tpd_desc **tpd,
+                         enum atl1c_trans_queue type)
+{
+       struct pci_dev *pdev = adapter->pdev;
+       u8 hdr_len;
+       u32 real_len;
+       unsigned short offload_type;
+       int err;
+
+       if (skb_is_gso(skb)) {
+               if (skb_header_cloned(skb)) {
+                       err = pskb_expand_head(skb, 0, 0, GFP_ATOMIC);
+                       if (unlikely(err))
+                               return -1;
+               }
+               offload_type = skb_shinfo(skb)->gso_type;
+
+               if (offload_type & SKB_GSO_TCPV4) {
+                       real_len = (((unsigned char *)ip_hdr(skb) - skb->data)
+                                       + ntohs(ip_hdr(skb)->tot_len));
+
+                       if (real_len < skb->len)
+                               pskb_trim(skb, real_len);
+
+                       hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb));
+                       if (unlikely(skb->len == hdr_len)) {
+                               /* only xsum need */
+                               if (netif_msg_tx_queued(adapter))
+                                       dev_warn(&pdev->dev,
+                                               "IPV4 tso with zero data??\n");
+                               goto check_sum;
+                       } else {
+                               ip_hdr(skb)->check = 0;
+                               tcp_hdr(skb)->check = ~csum_tcpudp_magic(
+                                                       ip_hdr(skb)->saddr,
+                                                       ip_hdr(skb)->daddr,
+                                                       0, IPPROTO_TCP, 0);
+                               (*tpd)->word1 |= 1 << TPD_IPV4_PACKET_SHIFT;
+                       }
+               }
+
+               if (offload_type & SKB_GSO_TCPV6) {
+                       struct atl1c_tpd_ext_desc *etpd =
+                               *(struct atl1c_tpd_ext_desc **)(tpd);
+
+                       memset(etpd, 0, sizeof(struct atl1c_tpd_ext_desc));
+                       *tpd = atl1c_get_tpd(adapter, type);
+                       ipv6_hdr(skb)->payload_len = 0;
+                       /* check payload == 0 byte ? */
+                       hdr_len = (skb_transport_offset(skb) + tcp_hdrlen(skb));
+                       if (unlikely(skb->len == hdr_len)) {
+                               /* only xsum need */
+                               if (netif_msg_tx_queued(adapter))
+                                       dev_warn(&pdev->dev,
+                                               "IPV6 tso with zero data??\n");
+                               goto check_sum;
+                       } else
+                               tcp_hdr(skb)->check = ~csum_ipv6_magic(
+                                               &ipv6_hdr(skb)->saddr,
+                                               &ipv6_hdr(skb)->daddr,
+                                               0, IPPROTO_TCP, 0);
+                       etpd->word1 |= 1 << TPD_LSO_EN_SHIFT;
+                       etpd->word1 |= 1 << TPD_LSO_VER_SHIFT;
+                       etpd->pkt_len = cpu_to_le32(skb->len);
+                       (*tpd)->word1 |= 1 << TPD_LSO_VER_SHIFT;
+               }
+
+               (*tpd)->word1 |= 1 << TPD_LSO_EN_SHIFT;
+               (*tpd)->word1 |= (skb_transport_offset(skb) & TPD_TCPHDR_OFFSET_MASK) <<
+                               TPD_TCPHDR_OFFSET_SHIFT;
+               (*tpd)->word1 |= (skb_shinfo(skb)->gso_size & TPD_MSS_MASK) <<
+                               TPD_MSS_SHIFT;
+               return 0;
+       }
+
+check_sum:
+       if (likely(skb->ip_summed == CHECKSUM_PARTIAL)) {
+               u8 css, cso;
+               cso = skb_transport_offset(skb);
+
+               if (unlikely(cso & 0x1)) {
+                       if (netif_msg_tx_err(adapter))
+                               dev_err(&adapter->pdev->dev,
+                                       "payload offset should not an event number\n");
+                       return -1;
+               } else {
+                       css = cso + skb->csum_offset;
+
+                       (*tpd)->word1 |= ((cso >> 1) & TPD_PLOADOFFSET_MASK) <<
+                                       TPD_PLOADOFFSET_SHIFT;
+                       (*tpd)->word1 |= ((css >> 1) & TPD_CCSUM_OFFSET_MASK) <<
+                                       TPD_CCSUM_OFFSET_SHIFT;
+                       (*tpd)->word1 |= 1 << TPD_CCSUM_EN_SHIFT;
+               }
+       }
+       return 0;
+}
+
+static void atl1c_tx_map(struct atl1c_adapter *adapter,
+                     struct sk_buff *skb, struct atl1c_tpd_desc *tpd,
+                       enum atl1c_trans_queue type)
+{
+       struct atl1c_tpd_desc *use_tpd = NULL;
+       struct atl1c_buffer *buffer_info = NULL;
+       u16 buf_len = skb_headlen(skb);
+       u16 map_len = 0;
+       u16 mapped_len = 0;
+       u16 hdr_len = 0;
+       u16 nr_frags;
+       u16 f;
+       int tso;
+
+       nr_frags = skb_shinfo(skb)->nr_frags;
+       tso = (tpd->word1 >> TPD_LSO_EN_SHIFT) & TPD_LSO_EN_MASK;
+       if (tso) {
+               /* TSO */
+               map_len = hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+               use_tpd = tpd;
+
+               buffer_info = atl1c_get_tx_buffer(adapter, use_tpd);
+               buffer_info->length = map_len;
+               buffer_info->dma = pci_map_single(adapter->pdev,
+                                       skb->data, hdr_len, PCI_DMA_TODEVICE);
+               buffer_info->state = ATL1_BUFFER_BUSY;
+               mapped_len += map_len;
+               use_tpd->buffer_addr = cpu_to_le64(buffer_info->dma);
+               use_tpd->buffer_len = cpu_to_le16(buffer_info->length);
+       }
+
+       if (mapped_len < buf_len) {
+               /* mapped_len == 0, means we should use the first tpd,
+                  which is given by caller  */
+               if (mapped_len == 0)
+                       use_tpd = tpd;
+               else {
+                       use_tpd = atl1c_get_tpd(adapter, type);
+                       memcpy(use_tpd, tpd, sizeof(struct atl1c_tpd_desc));
+                       use_tpd = atl1c_get_tpd(adapter, type);
+                       memcpy(use_tpd, tpd, sizeof(struct atl1c_tpd_desc));
+               }
+               buffer_info = atl1c_get_tx_buffer(adapter, use_tpd);
+               buffer_info->length = buf_len - mapped_len;
+               buffer_info->dma =
+                       pci_map_single(adapter->pdev, skb->data + mapped_len,
+                                       buffer_info->length, PCI_DMA_TODEVICE);
+               buffer_info->state = ATL1_BUFFER_BUSY;
+
+               use_tpd->buffer_addr = cpu_to_le64(buffer_info->dma);
+               use_tpd->buffer_len  = cpu_to_le16(buffer_info->length);
+       }
+
+       for (f = 0; f < nr_frags; f++) {
+               struct skb_frag_struct *frag;
+
+               frag = &skb_shinfo(skb)->frags[f];
+
+               use_tpd = atl1c_get_tpd(adapter, type);
+               memcpy(use_tpd, tpd, sizeof(struct atl1c_tpd_desc));
+
+               buffer_info = atl1c_get_tx_buffer(adapter, use_tpd);
+               buffer_info->length = frag->size;
+               buffer_info->dma =
+                       pci_map_page(adapter->pdev, frag->page,
+                                       frag->page_offset,
+                                       buffer_info->length,
+                                       PCI_DMA_TODEVICE);
+               buffer_info->state = ATL1_BUFFER_BUSY;
+
+               use_tpd->buffer_addr = cpu_to_le64(buffer_info->dma);
+               use_tpd->buffer_len  = cpu_to_le16(buffer_info->length);
+       }
+
+       /* The last tpd */
+       use_tpd->word1 |= 1 << TPD_EOP_SHIFT;
+       /* The last buffer info contain the skb address,
+          so it will be free after unmap */
+       buffer_info->skb = skb;
+}
+
+static void atl1c_tx_queue(struct atl1c_adapter *adapter, struct sk_buff *skb,
+                          struct atl1c_tpd_desc *tpd, enum atl1c_trans_queue type)
+{
+       struct atl1c_tpd_ring *tpd_ring = &adapter->tpd_ring[type];
+       u32 prod_data;
+
+       AT_READ_REG(&adapter->hw, REG_MB_PRIO_PROD_IDX, &prod_data);
+       switch (type) {
+       case atl1c_trans_high:
+               prod_data &= 0xFFFF0000;
+               prod_data |= tpd_ring->next_to_use & 0xFFFF;
+               break;
+       case atl1c_trans_normal:
+               prod_data &= 0x0000FFFF;
+               prod_data |= (tpd_ring->next_to_use & 0xFFFF) << 16;
+               break;
+       default:
+               break;
+       }
+       wmb();
+       AT_WRITE_REG(&adapter->hw, REG_MB_PRIO_PROD_IDX, prod_data);
+}
+
+static int atl1c_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       unsigned long flags;
+       u16 tpd_req = 1;
+       struct atl1c_tpd_desc *tpd;
+       enum atl1c_trans_queue type = atl1c_trans_normal;
+
+       if (test_bit(__AT_DOWN, &adapter->flags)) {
+               dev_kfree_skb_any(skb);
+               return NETDEV_TX_OK;
+       }
+
+       tpd_req = atl1c_cal_tpd_req(skb);
+       if (!spin_trylock_irqsave(&adapter->tx_lock, flags)) {
+               if (netif_msg_pktdata(adapter))
+                       dev_info(&adapter->pdev->dev, "tx locked\n");
+               return NETDEV_TX_LOCKED;
+       }
+       if (skb->mark == 0x01)
+               type = atl1c_trans_high;
+       else
+               type = atl1c_trans_normal;
+
+       if (atl1c_tpd_avail(adapter, type) < tpd_req) {
+               /* no enough descriptor, just stop queue */
+               netif_stop_queue(netdev);
+               spin_unlock_irqrestore(&adapter->tx_lock, flags);
+               return NETDEV_TX_BUSY;
+       }
+
+       tpd = atl1c_get_tpd(adapter, type);
+
+       /* do TSO and check sum */
+       if (atl1c_tso_csum(adapter, skb, &tpd, type) != 0) {
+               spin_unlock_irqrestore(&adapter->tx_lock, flags);
+               dev_kfree_skb_any(skb);
+               return NETDEV_TX_OK;
+       }
+
+       if (unlikely(adapter->vlgrp && vlan_tx_tag_present(skb))) {
+               u16 vlan = vlan_tx_tag_get(skb);
+               __le16 tag;
+
+               vlan = cpu_to_le16(vlan);
+               AT_VLAN_TO_TAG(vlan, tag);
+               tpd->word1 |= 1 << TPD_INS_VTAG_SHIFT;
+               tpd->vlan_tag = tag;
+       }
+
+       if (skb_network_offset(skb) != ETH_HLEN)
+               tpd->word1 |= 1 << TPD_ETH_TYPE_SHIFT; /* Ethernet frame */
+
+       atl1c_tx_map(adapter, skb, tpd, type);
+       atl1c_tx_queue(adapter, skb, tpd, type);
+
+       netdev->trans_start = jiffies;
+       spin_unlock_irqrestore(&adapter->tx_lock, flags);
+       return NETDEV_TX_OK;
+}
+
+static void atl1c_free_irq(struct atl1c_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+
+       free_irq(adapter->pdev->irq, netdev);
+
+       if (adapter->have_msi)
+               pci_disable_msi(adapter->pdev);
+}
+
+static int atl1c_request_irq(struct atl1c_adapter *adapter)
+{
+       struct pci_dev    *pdev   = adapter->pdev;
+       struct net_device *netdev = adapter->netdev;
+       int flags = 0;
+       int err = 0;
+
+       adapter->have_msi = true;
+       err = pci_enable_msi(adapter->pdev);
+       if (err) {
+               if (netif_msg_ifup(adapter))
+                       dev_err(&pdev->dev,
+                               "Unable to allocate MSI interrupt Error: %d\n",
+                               err);
+               adapter->have_msi = false;
+       } else
+               netdev->irq = pdev->irq;
+
+       if (!adapter->have_msi)
+               flags |= IRQF_SHARED;
+       err = request_irq(adapter->pdev->irq, &atl1c_intr, flags,
+                       netdev->name, netdev);
+       if (err) {
+               if (netif_msg_ifup(adapter))
+                       dev_err(&pdev->dev,
+                               "Unable to allocate interrupt Error: %d\n",
+                               err);
+               if (adapter->have_msi)
+                       pci_disable_msi(adapter->pdev);
+               return err;
+       }
+       if (netif_msg_ifup(adapter))
+               dev_dbg(&pdev->dev, "atl1c_request_irq OK\n");
+       return err;
+}
+
+int atl1c_up(struct atl1c_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       int num;
+       int err;
+       int i;
+
+       netif_carrier_off(netdev);
+       atl1c_init_ring_ptrs(adapter);
+       atl1c_set_multi(netdev);
+       atl1c_restore_vlan(adapter);
+
+       for (i = 0; i < adapter->num_rx_queues; i++) {
+               num = atl1c_alloc_rx_buffer(adapter, i);
+               if (unlikely(num == 0)) {
+                       err = -ENOMEM;
+                       goto err_alloc_rx;
+               }
+       }
+
+       if (atl1c_configure(adapter)) {
+               err = -EIO;
+               goto err_up;
+       }
+
+       err = atl1c_request_irq(adapter);
+       if (unlikely(err))
+               goto err_up;
+
+       clear_bit(__AT_DOWN, &adapter->flags);
+       napi_enable(&adapter->napi);
+       atl1c_irq_enable(adapter);
+       atl1c_check_link_status(adapter);
+       netif_start_queue(netdev);
+       return err;
+
+err_up:
+err_alloc_rx:
+       atl1c_clean_rx_ring(adapter);
+       return err;
+}
+
+void atl1c_down(struct atl1c_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+
+       atl1c_del_timer(adapter);
+       atl1c_cancel_work(adapter);
+
+       /* signal that we're down so the interrupt handler does not
+        * reschedule our watchdog timer */
+       set_bit(__AT_DOWN, &adapter->flags);
+       netif_carrier_off(netdev);
+       napi_disable(&adapter->napi);
+       atl1c_irq_disable(adapter);
+       atl1c_free_irq(adapter);
+       AT_WRITE_REG(&adapter->hw, REG_ISR, ISR_DIS_INT);
+       /* reset MAC to disable all RX/TX */
+       atl1c_reset_mac(&adapter->hw);
+       msleep(1);
+
+       adapter->link_speed = SPEED_0;
+       adapter->link_duplex = -1;
+       atl1c_clean_tx_ring(adapter, atl1c_trans_normal);
+       atl1c_clean_tx_ring(adapter, atl1c_trans_high);
+       atl1c_clean_rx_ring(adapter);
+}
+
+/*
+ * atl1c_open - Called when a network interface is made active
+ * @netdev: network interface device structure
+ *
+ * Returns 0 on success, negative value on failure
+ *
+ * The open entry point is called when a network interface is made
+ * active by the system (IFF_UP).  At this point all resources needed
+ * for transmit and receive operations are allocated, the interrupt
+ * handler is registered with the OS, the watchdog timer is started,
+ * and the stack is notified that the interface is ready.
+ */
+static int atl1c_open(struct net_device *netdev)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       int err;
+
+       /* disallow open during test */
+       if (test_bit(__AT_TESTING, &adapter->flags))
+               return -EBUSY;
+
+       /* allocate rx/tx dma buffer & descriptors */
+       err = atl1c_setup_ring_resources(adapter);
+       if (unlikely(err))
+               return err;
+
+       err = atl1c_up(adapter);
+       if (unlikely(err))
+               goto err_up;
+
+       if (adapter->hw.ctrl_flags & ATL1C_FPGA_VERSION) {
+               u32 phy_data;
+
+               AT_READ_REG(&adapter->hw, REG_MDIO_CTRL, &phy_data);
+               phy_data |= MDIO_AP_EN;
+               AT_WRITE_REG(&adapter->hw, REG_MDIO_CTRL, phy_data);
+       }
+       return 0;
+
+err_up:
+       atl1c_free_irq(adapter);
+       atl1c_free_ring_resources(adapter);
+       atl1c_reset_mac(&adapter->hw);
+       return err;
+}
+
+/*
+ * atl1c_close - Disables a network interface
+ * @netdev: network interface device structure
+ *
+ * Returns 0, this is not allowed to fail
+ *
+ * The close entry point is called when an interface is de-activated
+ * by the OS.  The hardware is still under the drivers control, but
+ * needs to be disabled.  A global MAC reset is issued to stop the
+ * hardware, and all transmit and receive resources are freed.
+ */
+static int atl1c_close(struct net_device *netdev)
+{
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+       WARN_ON(test_bit(__AT_RESETTING, &adapter->flags));
+       atl1c_down(adapter);
+       atl1c_free_ring_resources(adapter);
+       return 0;
+}
+
+static int atl1c_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+       struct atl1c_hw *hw = &adapter->hw;
+       u32 ctrl;
+       u32 mac_ctrl_data;
+       u32 master_ctrl_data;
+       u32 wol_ctrl_data;
+       u16 mii_bmsr_data;
+       u16 save_autoneg_advertised;
+       u16 mii_intr_status_data;
+       u32 wufc = adapter->wol;
+       u32 i;
+       int retval = 0;
+
+       if (netif_running(netdev)) {
+               WARN_ON(test_bit(__AT_RESETTING, &adapter->flags));
+               atl1c_down(adapter);
+       }
+       netif_device_detach(netdev);
+       atl1c_disable_l0s_l1(hw);
+       retval = pci_save_state(pdev);
+       if (retval)
+               return retval;
+       if (wufc) {
+               AT_READ_REG(hw, REG_MASTER_CTRL, &master_ctrl_data);
+               master_ctrl_data &= ~MASTER_CTRL_CLK_SEL_DIS;
+
+               /* get link status */
+               atl1c_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
+               atl1c_read_phy_reg(hw, MII_BMSR, (u16 *)&mii_bmsr_data);
+               save_autoneg_advertised = hw->autoneg_advertised;
+               hw->autoneg_advertised = ADVERTISED_10baseT_Half;
+               if (atl1c_restart_autoneg(hw) != 0)
+                       if (netif_msg_link(adapter))
+                               dev_warn(&pdev->dev, "phy autoneg failed\n");
+               hw->phy_configured = false; /* re-init PHY when resume */
+               hw->autoneg_advertised = save_autoneg_advertised;
+               /* turn on magic packet wol */
+               if (wufc & AT_WUFC_MAG)
+                       wol_ctrl_data = WOL_MAGIC_EN | WOL_MAGIC_PME_EN;
+
+               if (wufc & AT_WUFC_LNKC) {
+                       for (i = 0; i < AT_SUSPEND_LINK_TIMEOUT; i++) {
+                               msleep(100);
+                               atl1c_read_phy_reg(hw, MII_BMSR,
+                                       (u16 *)&mii_bmsr_data);
+                               if (mii_bmsr_data & BMSR_LSTATUS)
+                                       break;
+                       }
+                       if ((mii_bmsr_data & BMSR_LSTATUS) == 0)
+                               if (netif_msg_link(adapter))
+                                       dev_warn(&pdev->dev,
+                                               "%s: Link may change"
+                                               "when suspend\n",
+                                               atl1c_driver_name);
+                       wol_ctrl_data |=  WOL_LINK_CHG_EN | WOL_LINK_CHG_PME_EN;
+                       /* only link up can wake up */
+                       if (atl1c_write_phy_reg(hw, MII_IER, IER_LINK_UP) != 0) {
+                               if (netif_msg_link(adapter))
+                                       dev_err(&pdev->dev,
+                                               "%s: read write phy "
+                                               "register failed.\n",
+                                               atl1c_driver_name);
+                               goto wol_dis;
+                       }
+               }
+               /* clear phy interrupt */
+               atl1c_read_phy_reg(hw, MII_ISR, &mii_intr_status_data);
+               /* Config MAC Ctrl register */
+               mac_ctrl_data = MAC_CTRL_RX_EN;
+               /* set to 10/100M halt duplex */
+               mac_ctrl_data |= atl1c_mac_speed_10_100 << MAC_CTRL_SPEED_SHIFT;
+               mac_ctrl_data |= (((u32)adapter->hw.preamble_len &
+                                MAC_CTRL_PRMLEN_MASK) <<
+                                MAC_CTRL_PRMLEN_SHIFT);
+
+               if (adapter->vlgrp)
+                       mac_ctrl_data |= MAC_CTRL_RMV_VLAN;
+
+               /* magic packet maybe Broadcast&multicast&Unicast frame */
+               if (wufc & AT_WUFC_MAG)
+                       mac_ctrl_data |= MAC_CTRL_BC_EN;
+
+               if (netif_msg_hw(adapter))
+                       dev_dbg(&pdev->dev,
+                               "%s: suspend MAC=0x%x\n",
+                               atl1c_driver_name, mac_ctrl_data);
+               AT_WRITE_REG(hw, REG_MASTER_CTRL, master_ctrl_data);
+               AT_WRITE_REG(hw, REG_WOL_CTRL, wol_ctrl_data);
+               AT_WRITE_REG(hw, REG_MAC_CTRL, mac_ctrl_data);
+
+               /* pcie patch */
+               AT_READ_REG(hw, REG_PCIE_PHYMISC, &ctrl);
+               ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
+               AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
+
+               pci_enable_wake(pdev, pci_choose_state(pdev, state), 1);
+               goto suspend_exit;
+       }
+wol_dis:
+
+       /* WOL disabled */
+       AT_WRITE_REG(hw, REG_WOL_CTRL, 0);
+
+       /* pcie patch */
+       AT_READ_REG(hw, REG_PCIE_PHYMISC, &ctrl);
+       ctrl |= PCIE_PHYMISC_FORCE_RCV_DET;
+       AT_WRITE_REG(hw, REG_PCIE_PHYMISC, ctrl);
+
+       atl1c_phy_disable(hw);
+       hw->phy_configured = false; /* re-init PHY when resume */
+
+       pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
+suspend_exit:
+
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+
+       return 0;
+}
+
+static int atl1c_resume(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
+       pci_enable_wake(pdev, PCI_D3hot, 0);
+       pci_enable_wake(pdev, PCI_D3cold, 0);
+
+       AT_WRITE_REG(&adapter->hw, REG_WOL_CTRL, 0);
+
+       atl1c_phy_reset(&adapter->hw);
+       atl1c_reset_mac(&adapter->hw);
+       netif_device_attach(netdev);
+       if (netif_running(netdev))
+               atl1c_up(adapter);
+
+       return 0;
+}
+
+static void atl1c_shutdown(struct pci_dev *pdev)
+{
+       atl1c_suspend(pdev, PMSG_SUSPEND);
+}
+
+static const struct net_device_ops atl1c_netdev_ops = {
+       .ndo_open               = atl1c_open,
+       .ndo_stop               = atl1c_close,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_start_xmit         = atl1c_xmit_frame,
+       .ndo_set_mac_address    = atl1c_set_mac_addr,
+       .ndo_set_multicast_list = atl1c_set_multi,
+       .ndo_change_mtu         = atl1c_change_mtu,
+       .ndo_do_ioctl           = atl1c_ioctl,
+       .ndo_tx_timeout         = atl1c_tx_timeout,
+       .ndo_get_stats          = atl1c_get_stats,
+       .ndo_vlan_rx_register   = atl1c_vlan_rx_register,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = atl1c_netpoll,
+#endif
+};
+
+static int atl1c_init_netdev(struct net_device *netdev, struct pci_dev *pdev)
+{
+       SET_NETDEV_DEV(netdev, &pdev->dev);
+       pci_set_drvdata(pdev, netdev);
+
+       netdev->irq  = pdev->irq;
+       netdev->netdev_ops = &atl1c_netdev_ops;
+       netdev->watchdog_timeo = AT_TX_WATCHDOG;
+       atl1c_set_ethtool_ops(netdev);
+
+       /* TODO: add when ready */
+       netdev->features =      NETIF_F_SG         |
+                               NETIF_F_HW_CSUM    |
+                               NETIF_F_HW_VLAN_TX |
+                               NETIF_F_HW_VLAN_RX |
+                               NETIF_F_TSO        |
+                               NETIF_F_TSO6;
+       return 0;
+}
+
+/*
+ * atl1c_probe - Device Initialization Routine
+ * @pdev: PCI device information struct
+ * @ent: entry in atl1c_pci_tbl
+ *
+ * Returns 0 on success, negative on failure
+ *
+ * atl1c_probe initializes an adapter identified by a pci_dev structure.
+ * The OS initialization, configuring of the adapter private structure,
+ * and a hardware reset occur.
+ */
+static int __devinit atl1c_probe(struct pci_dev *pdev,
+                                const struct pci_device_id *ent)
+{
+       struct net_device *netdev;
+       struct atl1c_adapter *adapter;
+       static int cards_found;
+
+       int err = 0;
+
+       /* enable device (incl. PCI PM wakeup and hotplug setup) */
+       err = pci_enable_device_mem(pdev);
+       if (err) {
+               dev_err(&pdev->dev, "cannot enable PCI device\n");
+               return err;
+       }
+
+       /*
+        * The atl1c chip can DMA to 64-bit addresses, but it uses a single
+        * shared register for the high 32 bits, so only a single, aligned,
+        * 4 GB physical address range can be used at a time.
+        *
+        * Supporting 64-bit DMA on this hardware is more trouble than it's
+        * worth.  It is far easier to limit to 32-bit DMA than update
+        * various kernel subsystems to support the mechanics required by a
+        * fixed-high-32-bit system.
+        */
+       if ((pci_set_dma_mask(pdev, DMA_32BIT_MASK) != 0) ||
+           (pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK) != 0)) {
+               dev_err(&pdev->dev, "No usable DMA configuration,aborting\n");
+               goto err_dma;
+       }
+
+       err = pci_request_regions(pdev, atl1c_driver_name);
+       if (err) {
+               dev_err(&pdev->dev, "cannot obtain PCI resources\n");
+               goto err_pci_reg;
+       }
+
+       pci_set_master(pdev);
+
+       netdev = alloc_etherdev(sizeof(struct atl1c_adapter));
+       if (netdev == NULL) {
+               err = -ENOMEM;
+               dev_err(&pdev->dev, "etherdev alloc failed\n");
+               goto err_alloc_etherdev;
+       }
+
+       err = atl1c_init_netdev(netdev, pdev);
+       if (err) {
+               dev_err(&pdev->dev, "init netdevice failed\n");
+               goto err_init_netdev;
+       }
+       adapter = netdev_priv(netdev);
+       adapter->bd_number = cards_found;
+       adapter->netdev = netdev;
+       adapter->pdev = pdev;
+       adapter->hw.adapter = adapter;
+       adapter->msg_enable = netif_msg_init(-1, atl1c_default_msg);
+       adapter->hw.hw_addr = ioremap(pci_resource_start(pdev, 0), pci_resource_len(pdev, 0));
+       if (!adapter->hw.hw_addr) {
+               err = -EIO;
+               dev_err(&pdev->dev, "cannot map device registers\n");
+               goto err_ioremap;
+       }
+       netdev->base_addr = (unsigned long)adapter->hw.hw_addr;
+
+       /* init mii data */
+       adapter->mii.dev = netdev;
+       adapter->mii.mdio_read  = atl1c_mdio_read;
+       adapter->mii.mdio_write = atl1c_mdio_write;
+       adapter->mii.phy_id_mask = 0x1f;
+       adapter->mii.reg_num_mask = MDIO_REG_ADDR_MASK;
+       netif_napi_add(netdev, &adapter->napi, atl1c_clean, 64);
+       setup_timer(&adapter->phy_config_timer, atl1c_phy_config,
+                       (unsigned long)adapter);
+       /* setup the private structure */
+       err = atl1c_sw_init(adapter);
+       if (err) {
+               dev_err(&pdev->dev, "net device private data init failed\n");
+               goto err_sw_init;
+       }
+       atl1c_reset_pcie(&adapter->hw, ATL1C_PCIE_L0S_L1_DISABLE |
+                       ATL1C_PCIE_PHY_RESET);
+
+       /* Init GPHY as early as possible due to power saving issue  */
+       atl1c_phy_reset(&adapter->hw);
+
+       err = atl1c_reset_mac(&adapter->hw);
+       if (err) {
+               err = -EIO;
+               goto err_reset;
+       }
+
+       device_init_wakeup(&pdev->dev, 1);
+       /* reset the controller to
+        * put the device in a known good starting state */
+       err = atl1c_phy_init(&adapter->hw);
+       if (err) {
+               err = -EIO;
+               goto err_reset;
+       }
+       if (atl1c_read_mac_addr(&adapter->hw) != 0) {
+               err = -EIO;
+               dev_err(&pdev->dev, "get mac address failed\n");
+               goto err_eeprom;
+       }
+       memcpy(netdev->dev_addr, adapter->hw.mac_addr, netdev->addr_len);
+       memcpy(netdev->perm_addr, adapter->hw.mac_addr, netdev->addr_len);
+       if (netif_msg_probe(adapter))
+               dev_dbg(&pdev->dev,
+                       "mac address : %02x-%02x-%02x-%02x-%02x-%02x\n",
+                       adapter->hw.mac_addr[0], adapter->hw.mac_addr[1],
+                       adapter->hw.mac_addr[2], adapter->hw.mac_addr[3],
+                       adapter->hw.mac_addr[4], adapter->hw.mac_addr[5]);
+
+       atl1c_hw_set_mac_addr(&adapter->hw);
+       INIT_WORK(&adapter->reset_task, atl1c_reset_task);
+       INIT_WORK(&adapter->link_chg_task, atl1c_link_chg_task);
+       err = register_netdev(netdev);
+       if (err) {
+               dev_err(&pdev->dev, "register netdevice failed\n");
+               goto err_register;
+       }
+
+       if (netif_msg_probe(adapter))
+               dev_info(&pdev->dev, "version %s\n", ATL1C_DRV_VERSION);
+       cards_found++;
+       return 0;
+
+err_reset:
+err_register:
+err_sw_init:
+err_eeprom:
+       iounmap(adapter->hw.hw_addr);
+err_init_netdev:
+err_ioremap:
+       free_netdev(netdev);
+err_alloc_etherdev:
+       pci_release_regions(pdev);
+err_pci_reg:
+err_dma:
+       pci_disable_device(pdev);
+       return err;
+}
+
+/*
+ * atl1c_remove - Device Removal Routine
+ * @pdev: PCI device information struct
+ *
+ * atl1c_remove is called by the PCI subsystem to alert the driver
+ * that it should release a PCI device.  The could be caused by a
+ * Hot-Plug event, or because the driver is going to be removed from
+ * memory.
+ */
+static void __devexit atl1c_remove(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+       unregister_netdev(netdev);
+       atl1c_phy_disable(&adapter->hw);
+
+       iounmap(adapter->hw.hw_addr);
+
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+       free_netdev(netdev);
+}
+
+/*
+ * atl1c_io_error_detected - called when PCI error is detected
+ * @pdev: Pointer to PCI device
+ * @state: The current pci connection state
+ *
+ * This function is called after a PCI bus error affecting
+ * this device has been detected.
+ */
+static pci_ers_result_t atl1c_io_error_detected(struct pci_dev *pdev,
+                                               pci_channel_state_t state)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+       netif_device_detach(netdev);
+
+       if (netif_running(netdev))
+               atl1c_down(adapter);
+
+       pci_disable_device(pdev);
+
+       /* Request a slot slot reset. */
+       return PCI_ERS_RESULT_NEED_RESET;
+}
+
+/*
+ * atl1c_io_slot_reset - called after the pci bus has been reset.
+ * @pdev: Pointer to PCI device
+ *
+ * Restart the card from scratch, as if from a cold-boot. Implementation
+ * resembles the first-half of the e1000_resume routine.
+ */
+static pci_ers_result_t atl1c_io_slot_reset(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+       if (pci_enable_device(pdev)) {
+               if (netif_msg_hw(adapter))
+                       dev_err(&pdev->dev,
+                               "Cannot re-enable PCI device after reset\n");
+               return PCI_ERS_RESULT_DISCONNECT;
+       }
+       pci_set_master(pdev);
+
+       pci_enable_wake(pdev, PCI_D3hot, 0);
+       pci_enable_wake(pdev, PCI_D3cold, 0);
+
+       atl1c_reset_mac(&adapter->hw);
+
+       return PCI_ERS_RESULT_RECOVERED;
+}
+
+/*
+ * atl1c_io_resume - called when traffic can start flowing again.
+ * @pdev: Pointer to PCI device
+ *
+ * This callback is called when the error recovery driver tells us that
+ * its OK to resume normal operation. Implementation resembles the
+ * second-half of the atl1c_resume routine.
+ */
+static void atl1c_io_resume(struct pci_dev *pdev)
+{
+       struct net_device *netdev = pci_get_drvdata(pdev);
+       struct atl1c_adapter *adapter = netdev_priv(netdev);
+
+       if (netif_running(netdev)) {
+               if (atl1c_up(adapter)) {
+                       if (netif_msg_hw(adapter))
+                               dev_err(&pdev->dev,
+                                       "Cannot bring device back up after reset\n");
+                       return;
+               }
+       }
+
+       netif_device_attach(netdev);
+}
+
+static struct pci_error_handlers atl1c_err_handler = {
+       .error_detected = atl1c_io_error_detected,
+       .slot_reset = atl1c_io_slot_reset,
+       .resume = atl1c_io_resume,
+};
+
+static struct pci_driver atl1c_driver = {
+       .name     = atl1c_driver_name,
+       .id_table = atl1c_pci_tbl,
+       .probe    = atl1c_probe,
+       .remove   = __devexit_p(atl1c_remove),
+       /* Power Managment Hooks */
+       .suspend  = atl1c_suspend,
+       .resume   = atl1c_resume,
+       .shutdown = atl1c_shutdown,
+       .err_handler = &atl1c_err_handler
+};
+
+/*
+ * atl1c_init_module - Driver Registration Routine
+ *
+ * atl1c_init_module is the first routine called when the driver is
+ * loaded. All it does is register with the PCI subsystem.
+ */
+static int __init atl1c_init_module(void)
+{
+       return pci_register_driver(&atl1c_driver);
+}
+
+/*
+ * atl1c_exit_module - Driver Exit Cleanup Routine
+ *
+ * atl1c_exit_module is called just before the driver is removed
+ * from memory.
+ */
+static void __exit atl1c_exit_module(void)
+{
+       pci_unregister_driver(&atl1c_driver);
+}
+
+module_init(atl1c_init_module);
+module_exit(atl1c_exit_module);
index 2a51c757997688849f07be96d5e125e16031efb9..5c84541e07377ac80eb2a9da592b7645e6eb82c2 100644 (file)
@@ -1264,8 +1264,14 @@ static void b44_clear_stats(struct b44 *bp)
 static void b44_chip_reset(struct b44 *bp, int reset_kind)
 {
        struct ssb_device *sdev = bp->sdev;
+       bool was_enabled;
 
-       if (ssb_device_is_enabled(bp->sdev)) {
+       was_enabled = ssb_device_is_enabled(bp->sdev);
+
+       ssb_device_enable(bp->sdev, 0);
+       ssb_pcicore_dev_irqvecs_enable(&sdev->bus->pcicore, sdev);
+
+       if (was_enabled) {
                bw32(bp, B44_RCV_LAZY, 0);
                bw32(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE);
                b44_wait_bit(bp, B44_ENET_CTRL, ENET_CTRL_DISABLE, 200, 1);
@@ -1277,10 +1283,8 @@ static void b44_chip_reset(struct b44 *bp, int reset_kind)
                }
                bw32(bp, B44_DMARX_CTRL, 0);
                bp->rx_prod = bp->rx_cons = 0;
-       } else
-               ssb_pcicore_dev_irqvecs_enable(&sdev->bus->pcicore, sdev);
+       }
 
-       ssb_device_enable(bp->sdev, 0);
        b44_clear_stats(bp);
 
        /*
@@ -2236,6 +2240,7 @@ static void __devexit b44_remove_one(struct ssb_device *sdev)
        struct net_device *dev = ssb_get_drvdata(sdev);
 
        unregister_netdev(dev);
+       ssb_device_disable(sdev, 0);
        ssb_bus_may_powerdown(sdev->bus);
        free_netdev(dev);
        ssb_pcihost_set_power_state(sdev, PCI_D3hot);
diff --git a/drivers/net/benet/Kconfig b/drivers/net/benet/Kconfig
new file mode 100644 (file)
index 0000000..c6934f1
--- /dev/null
@@ -0,0 +1,7 @@
+config BE2NET
+       tristate "ServerEngines' 10Gbps NIC - BladeEngine 2"
+       depends on PCI && INET
+       select INET_LRO
+       help
+       This driver implements the NIC functionality for ServerEngines'
+       10Gbps network adapter - BladeEngine 2.
diff --git a/drivers/net/benet/Makefile b/drivers/net/benet/Makefile
new file mode 100644 (file)
index 0000000..a60cd80
--- /dev/null
@@ -0,0 +1,7 @@
+#
+# Makefile to build the network driver for ServerEngine's BladeEngine.
+#
+
+obj-$(CONFIG_BE2NET) += be2net.o
+
+be2net-y :=  be_main.o be_cmds.o be_ethtool.o
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h
new file mode 100644 (file)
index 0000000..f327be5
--- /dev/null
@@ -0,0 +1,328 @@
+/*
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.  The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+
+#ifndef BE_H
+#define BE_H
+
+#include <linux/pci.h>
+#include <linux/etherdevice.h>
+#include <linux/version.h>
+#include <linux/delay.h>
+#include <net/tcp.h>
+#include <net/ip.h>
+#include <net/ipv6.h>
+#include <linux/if_vlan.h>
+#include <linux/workqueue.h>
+#include <linux/interrupt.h>
+#include <linux/inet_lro.h>
+
+#include "be_hw.h"
+
+#define DRV_VER                        "2.0.348"
+#define DRV_NAME               "be2net"
+#define BE_NAME                        "ServerEngines BladeEngine2 10Gbps NIC"
+#define DRV_DESC               BE_NAME "Driver"
+
+/* Number of bytes of an RX frame that are copied to skb->data */
+#define BE_HDR_LEN             64
+#define BE_MAX_JUMBO_FRAME_SIZE        9018
+#define BE_MIN_MTU             256
+
+#define BE_NUM_VLANS_SUPPORTED 64
+#define BE_MAX_EQD             96
+#define        BE_MAX_TX_FRAG_COUNT    30
+
+#define EVNT_Q_LEN             1024
+#define TX_Q_LEN               2048
+#define TX_CQ_LEN              1024
+#define RX_Q_LEN               1024    /* Does not support any other value */
+#define RX_CQ_LEN              1024
+#define MCC_Q_LEN              64      /* total size not to exceed 8 pages */
+#define MCC_CQ_LEN             256
+
+#define BE_NAPI_WEIGHT         64
+#define MAX_RX_POST            BE_NAPI_WEIGHT /* Frags posted at a time */
+#define RX_FRAGS_REFILL_WM     (RX_Q_LEN - MAX_RX_POST)
+
+#define BE_MAX_LRO_DESCRIPTORS  16
+#define BE_MAX_FRAGS_PER_FRAME  16
+
+struct be_dma_mem {
+       void *va;
+       dma_addr_t dma;
+       u32 size;
+};
+
+struct be_queue_info {
+       struct be_dma_mem dma_mem;
+       u16 len;
+       u16 entry_size; /* Size of an element in the queue */
+       u16 id;
+       u16 tail, head;
+       bool created;
+       atomic_t used;  /* Number of valid elements in the queue */
+};
+
+struct be_ctrl_info {
+       u8 __iomem *csr;
+       u8 __iomem *db;         /* Door Bell */
+       u8 __iomem *pcicfg;     /* PCI config space */
+       int pci_func;
+
+       /* Mbox used for cmd request/response */
+       spinlock_t cmd_lock;    /* For serializing cmds to BE card */
+       struct be_dma_mem mbox_mem;
+       /* Mbox mem is adjusted to align to 16 bytes. The allocated addr
+        * is stored for freeing purpose */
+       struct be_dma_mem mbox_mem_alloced;
+};
+
+#include "be_cmds.h"
+
+struct be_drvr_stats {
+       u32 be_tx_reqs;         /* number of TX requests initiated */
+       u32 be_tx_stops;        /* number of times TX Q was stopped */
+       u32 be_fwd_reqs;        /* number of send reqs through forwarding i/f */
+       u32 be_tx_wrbs;         /* number of tx WRBs used */
+       u32 be_tx_events;       /* number of tx completion events  */
+       u32 be_tx_compl;        /* number of tx completion entries processed */
+       u64 be_tx_jiffies;
+       ulong be_tx_bytes;
+       ulong be_tx_bytes_prev;
+       u32 be_tx_rate;
+
+       u32 cache_barrier[16];
+
+       u32 be_ethrx_post_fail;/* number of ethrx buffer alloc failures */
+       u32 be_polls;           /* number of times NAPI called poll function */
+       u32 be_rx_events;       /* number of ucast rx completion events  */
+       u32 be_rx_compl;        /* number of rx completion entries processed */
+       u32 be_lro_hgram_data[8];       /* histogram of LRO data packets */
+       u32 be_lro_hgram_ack[8];        /* histogram of LRO ACKs */
+       u64 be_rx_jiffies;
+       ulong be_rx_bytes;
+       ulong be_rx_bytes_prev;
+       u32 be_rx_rate;
+       /* number of non ether type II frames dropped where
+        * frame len > length field of Mac Hdr */
+       u32 be_802_3_dropped_frames;
+       /* number of non ether type II frames malformed where
+        * in frame len < length field of Mac Hdr */
+       u32 be_802_3_malformed_frames;
+       u32 be_rxcp_err;        /* Num rx completion entries w/ err set. */
+       ulong rx_fps_jiffies;   /* jiffies at last FPS calc */
+       u32 be_rx_frags;
+       u32 be_prev_rx_frags;
+       u32 be_rx_fps;          /* Rx frags per second */
+};
+
+struct be_stats_obj {
+       struct be_drvr_stats drvr_stats;
+       struct net_device_stats net_stats;
+       struct be_dma_mem cmd;
+};
+
+struct be_eq_obj {
+       struct be_queue_info q;
+       char desc[32];
+
+       /* Adaptive interrupt coalescing (AIC) info */
+       bool enable_aic;
+       u16 min_eqd;            /* in usecs */
+       u16 max_eqd;            /* in usecs */
+       u16 cur_eqd;            /* in usecs */
+
+       struct napi_struct napi;
+};
+
+struct be_tx_obj {
+       struct be_queue_info q;
+       struct be_queue_info cq;
+       /* Remember the skbs that were transmitted */
+       struct sk_buff *sent_skb_list[TX_Q_LEN];
+};
+
+/* Struct to remember the pages posted for rx frags */
+struct be_rx_page_info {
+       struct page *page;
+       dma_addr_t bus;
+       u16 page_offset;
+       bool last_page_user;
+};
+
+struct be_rx_obj {
+       struct be_queue_info q;
+       struct be_queue_info cq;
+       struct be_rx_page_info page_info_tbl[RX_Q_LEN];
+       struct net_lro_mgr lro_mgr;
+       struct net_lro_desc lro_desc[BE_MAX_LRO_DESCRIPTORS];
+};
+
+#define BE_NUM_MSIX_VECTORS            2       /* 1 each for Tx and Rx */
+struct be_adapter {
+       struct pci_dev *pdev;
+       struct net_device *netdev;
+
+       /* Mbox, pci config, csr address information */
+       struct be_ctrl_info ctrl;
+
+       struct msix_entry msix_entries[BE_NUM_MSIX_VECTORS];
+       bool msix_enabled;
+       bool isr_registered;
+
+       /* TX Rings */
+       struct be_eq_obj tx_eq;
+       struct be_tx_obj tx_obj;
+
+       u32 cache_line_break[8];
+
+       /* Rx rings */
+       struct be_eq_obj rx_eq;
+       struct be_rx_obj rx_obj;
+       u32 big_page_size;      /* Compounded page size shared by rx wrbs */
+       bool rx_post_starved;   /* Zero rx frags have been posted to BE */
+
+       struct vlan_group *vlan_grp;
+       u16 num_vlans;
+       u8 vlan_tag[VLAN_GROUP_ARRAY_LEN];
+
+       struct be_stats_obj stats;
+       /* Work queue used to perform periodic tasks like getting statistics */
+       struct delayed_work work;
+
+       /* Ethtool knobs and info */
+       bool rx_csum;           /* BE card must perform rx-checksumming */
+       u32 max_rx_coal;
+       char fw_ver[FW_VER_LEN];
+       u32 if_handle;          /* Used to configure filtering */
+       u32 pmac_id;            /* MAC addr handle used by BE card */
+
+       struct be_link_info link;
+       u32 port_num;
+};
+
+extern struct ethtool_ops be_ethtool_ops;
+
+#define drvr_stats(adapter)            (&adapter->stats.drvr_stats)
+
+#define BE_SET_NETDEV_OPS(netdev, ops) (netdev->netdev_ops = ops)
+
+static inline u32 MODULO(u16 val, u16 limit)
+{
+       BUG_ON(limit & (limit - 1));
+       return val & (limit - 1);
+}
+
+static inline void index_adv(u16 *index, u16 val, u16 limit)
+{
+       *index = MODULO((*index + val), limit);
+}
+
+static inline void index_inc(u16 *index, u16 limit)
+{
+       *index = MODULO((*index + 1), limit);
+}
+
+#define PAGE_SHIFT_4K          12
+#define PAGE_SIZE_4K           (1 << PAGE_SHIFT_4K)
+
+/* Returns number of pages spanned by the data starting at the given addr */
+#define PAGES_4K_SPANNED(_address, size)                               \
+               ((u32)((((size_t)(_address) & (PAGE_SIZE_4K - 1)) +     \
+                       (size) + (PAGE_SIZE_4K - 1)) >> PAGE_SHIFT_4K))
+
+/* Byte offset into the page corresponding to given address */
+#define OFFSET_IN_PAGE(addr)                                           \
+                ((size_t)(addr) & (PAGE_SIZE_4K-1))
+
+/* Returns bit offset within a DWORD of a bitfield */
+#define AMAP_BIT_OFFSET(_struct, field)                                \
+               (((size_t)&(((_struct *)0)->field))%32)
+
+/* Returns the bit mask of the field that is NOT shifted into location. */
+static inline u32 amap_mask(u32 bitsize)
+{
+       return (bitsize == 32 ? 0xFFFFFFFF : (1 << bitsize) - 1);
+}
+
+static inline void
+amap_set(void *ptr, u32 dw_offset, u32 mask, u32 offset, u32 value)
+{
+       u32 *dw = (u32 *) ptr + dw_offset;
+       *dw &= ~(mask << offset);
+       *dw |= (mask & value) << offset;
+}
+
+#define AMAP_SET_BITS(_struct, field, ptr, val)                                \
+               amap_set(ptr,                                           \
+                       offsetof(_struct, field)/32,                    \
+                       amap_mask(sizeof(((_struct *)0)->field)),       \
+                       AMAP_BIT_OFFSET(_struct, field),                \
+                       val)
+
+static inline u32 amap_get(void *ptr, u32 dw_offset, u32 mask, u32 offset)
+{
+       u32 *dw = (u32 *) ptr;
+       return mask & (*(dw + dw_offset) >> offset);
+}
+
+#define AMAP_GET_BITS(_struct, field, ptr)                             \
+               amap_get(ptr,                                           \
+                       offsetof(_struct, field)/32,                    \
+                       amap_mask(sizeof(((_struct *)0)->field)),       \
+                       AMAP_BIT_OFFSET(_struct, field))
+
+#define be_dws_cpu_to_le(wrb, len)     swap_dws(wrb, len)
+#define be_dws_le_to_cpu(wrb, len)     swap_dws(wrb, len)
+static inline void swap_dws(void *wrb, int len)
+{
+#ifdef __BIG_ENDIAN
+       u32 *dw = wrb;
+       BUG_ON(len % 4);
+       do {
+               *dw = cpu_to_le32(*dw);
+               dw++;
+               len -= 4;
+       } while (len);
+#endif                         /* __BIG_ENDIAN */
+}
+
+static inline u8 is_tcp_pkt(struct sk_buff *skb)
+{
+       u8 val = 0;
+
+       if (ip_hdr(skb)->version == 4)
+               val = (ip_hdr(skb)->protocol == IPPROTO_TCP);
+       else if (ip_hdr(skb)->version == 6)
+               val = (ipv6_hdr(skb)->nexthdr == NEXTHDR_TCP);
+
+       return val;
+}
+
+static inline u8 is_udp_pkt(struct sk_buff *skb)
+{
+       u8 val = 0;
+
+       if (ip_hdr(skb)->version == 4)
+               val = (ip_hdr(skb)->protocol == IPPROTO_UDP);
+       else if (ip_hdr(skb)->version == 6)
+               val = (ipv6_hdr(skb)->nexthdr == NEXTHDR_UDP);
+
+       return val;
+}
+
+#endif                         /* BE_H */
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c
new file mode 100644 (file)
index 0000000..d444aed
--- /dev/null
@@ -0,0 +1,861 @@
+/*
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.  The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+
+#include "be.h"
+
+static int be_mbox_db_ready_wait(void __iomem *db)
+{
+       int cnt = 0, wait = 5;
+       u32 ready;
+
+       do {
+               ready = ioread32(db) & MPU_MAILBOX_DB_RDY_MASK;
+               if (ready)
+                       break;
+
+               if (cnt > 200000) {
+                       printk(KERN_WARNING DRV_NAME
+                               ": mbox_db poll timed out\n");
+                       return -1;
+               }
+
+               if (cnt > 50)
+                       wait = 200;
+               cnt += wait;
+               udelay(wait);
+       } while (true);
+
+       return 0;
+}
+
+/*
+ * Insert the mailbox address into the doorbell in two steps
+ */
+static int be_mbox_db_ring(struct be_ctrl_info *ctrl)
+{
+       int status;
+       u16 compl_status, extd_status;
+       u32 val = 0;
+       void __iomem *db = ctrl->db + MPU_MAILBOX_DB_OFFSET;
+       struct be_dma_mem *mbox_mem = &ctrl->mbox_mem;
+       struct be_mcc_mailbox *mbox = mbox_mem->va;
+       struct be_mcc_cq_entry *cqe = &mbox->cqe;
+
+       memset(cqe, 0, sizeof(*cqe));
+
+       val &= ~MPU_MAILBOX_DB_RDY_MASK;
+       val |= MPU_MAILBOX_DB_HI_MASK;
+       /* at bits 2 - 31 place mbox dma addr msb bits 34 - 63 */
+       val |= (upper_32_bits(mbox_mem->dma) >> 2) << 2;
+       iowrite32(val, db);
+
+       /* wait for ready to be set */
+       status = be_mbox_db_ready_wait(db);
+       if (status != 0)
+               return status;
+
+       val = 0;
+       val &= ~MPU_MAILBOX_DB_RDY_MASK;
+       val &= ~MPU_MAILBOX_DB_HI_MASK;
+       /* at bits 2 - 31 place mbox dma addr lsb bits 4 - 33 */
+       val |= (u32)(mbox_mem->dma >> 4) << 2;
+       iowrite32(val, db);
+
+       status = be_mbox_db_ready_wait(db);
+       if (status != 0)
+               return status;
+
+       /* compl entry has been made now */
+       be_dws_le_to_cpu(cqe, sizeof(*cqe));
+       if (!(cqe->flags & CQE_FLAGS_VALID_MASK)) {
+               printk(KERN_WARNING DRV_NAME ": ERROR invalid mbox compl\n");
+               return -1;
+       }
+
+       compl_status = (cqe->status >> CQE_STATUS_COMPL_SHIFT) &
+                               CQE_STATUS_COMPL_MASK;
+       if (compl_status != MCC_STATUS_SUCCESS) {
+               extd_status = (cqe->status >> CQE_STATUS_EXTD_SHIFT) &
+                               CQE_STATUS_EXTD_MASK;
+               printk(KERN_WARNING DRV_NAME
+                       ": ERROR in cmd compl. status(compl/extd)=%d/%d\n",
+                       compl_status, extd_status);
+       }
+
+       return compl_status;
+}
+
+static int be_POST_stage_get(struct be_ctrl_info *ctrl, u16 *stage)
+{
+       u32 sem = ioread32(ctrl->csr + MPU_EP_SEMAPHORE_OFFSET);
+
+       *stage = sem & EP_SEMAPHORE_POST_STAGE_MASK;
+       if ((sem >> EP_SEMAPHORE_POST_ERR_SHIFT) & EP_SEMAPHORE_POST_ERR_MASK)
+               return -1;
+       else
+               return 0;
+}
+
+static int be_POST_stage_poll(struct be_ctrl_info *ctrl, u16 poll_stage)
+{
+       u16 stage, cnt, error;
+       for (cnt = 0; cnt < 5000; cnt++) {
+               error = be_POST_stage_get(ctrl, &stage);
+               if (error)
+                       return -1;
+
+               if (stage == poll_stage)
+                       break;
+               udelay(1000);
+       }
+       if (stage != poll_stage)
+               return -1;
+       return 0;
+}
+
+
+int be_cmd_POST(struct be_ctrl_info *ctrl)
+{
+       u16 stage, error;
+
+       error = be_POST_stage_get(ctrl, &stage);
+       if (error)
+               goto err;
+
+       if (stage == POST_STAGE_ARMFW_RDY)
+               return 0;
+
+       if (stage != POST_STAGE_AWAITING_HOST_RDY)
+               goto err;
+
+       /* On awaiting host rdy, reset and again poll on awaiting host rdy */
+       iowrite32(POST_STAGE_BE_RESET, ctrl->csr + MPU_EP_SEMAPHORE_OFFSET);
+       error = be_POST_stage_poll(ctrl, POST_STAGE_AWAITING_HOST_RDY);
+       if (error)
+               goto err;
+
+       /* Now kickoff POST and poll on armfw ready */
+       iowrite32(POST_STAGE_HOST_RDY, ctrl->csr + MPU_EP_SEMAPHORE_OFFSET);
+       error = be_POST_stage_poll(ctrl, POST_STAGE_ARMFW_RDY);
+       if (error)
+               goto err;
+
+       return 0;
+err:
+       printk(KERN_WARNING DRV_NAME ": ERROR, stage=%d\n", stage);
+       return -1;
+}
+
+static inline void *embedded_payload(struct be_mcc_wrb *wrb)
+{
+       return wrb->payload.embedded_payload;
+}
+
+static inline struct be_sge *nonembedded_sgl(struct be_mcc_wrb *wrb)
+{
+       return &wrb->payload.sgl[0];
+}
+
+/* Don't touch the hdr after it's prepared */
+static void be_wrb_hdr_prepare(struct be_mcc_wrb *wrb, int payload_len,
+                               bool embedded, u8 sge_cnt)
+{
+       if (embedded)
+               wrb->embedded |= MCC_WRB_EMBEDDED_MASK;
+       else
+               wrb->embedded |= (sge_cnt & MCC_WRB_SGE_CNT_MASK) <<
+                               MCC_WRB_SGE_CNT_SHIFT;
+       wrb->payload_length = payload_len;
+       be_dws_cpu_to_le(wrb, 20);
+}
+
+/* Don't touch the hdr after it's prepared */
+static void be_cmd_hdr_prepare(struct be_cmd_req_hdr *req_hdr,
+                               u8 subsystem, u8 opcode, int cmd_len)
+{
+       req_hdr->opcode = opcode;
+       req_hdr->subsystem = subsystem;
+       req_hdr->request_length = cpu_to_le32(cmd_len - sizeof(*req_hdr));
+}
+
+static void be_cmd_page_addrs_prepare(struct phys_addr *pages, u32 max_pages,
+                       struct be_dma_mem *mem)
+{
+       int i, buf_pages = min(PAGES_4K_SPANNED(mem->va, mem->size), max_pages);
+       u64 dma = (u64)mem->dma;
+
+       for (i = 0; i < buf_pages; i++) {
+               pages[i].lo = cpu_to_le32(dma & 0xFFFFFFFF);
+               pages[i].hi = cpu_to_le32(upper_32_bits(dma));
+               dma += PAGE_SIZE_4K;
+       }
+}
+
+/* Converts interrupt delay in microseconds to multiplier value */
+static u32 eq_delay_to_mult(u32 usec_delay)
+{
+#define MAX_INTR_RATE                  651042
+       const u32 round = 10;
+       u32 multiplier;
+
+       if (usec_delay == 0)
+               multiplier = 0;
+       else {
+               u32 interrupt_rate = 1000000 / usec_delay;
+               /* Max delay, corresponding to the lowest interrupt rate */
+               if (interrupt_rate == 0)
+                       multiplier = 1023;
+               else {
+                       multiplier = (MAX_INTR_RATE - interrupt_rate) * round;
+                       multiplier /= interrupt_rate;
+                       /* Round the multiplier to the closest value.*/
+                       multiplier = (multiplier + round/2) / round;
+                       multiplier = min(multiplier, (u32)1023);
+               }
+       }
+       return multiplier;
+}
+
+static inline struct be_mcc_wrb *wrb_from_mbox(struct be_dma_mem *mbox_mem)
+{
+       return &((struct be_mcc_mailbox *)(mbox_mem->va))->wrb;
+}
+
+int be_cmd_eq_create(struct be_ctrl_info *ctrl,
+               struct be_queue_info *eq, int eq_delay)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_eq_create *req = embedded_payload(wrb);
+       struct be_cmd_resp_eq_create *resp = embedded_payload(wrb);
+       struct be_dma_mem *q_mem = &eq->dma_mem;
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_EQ_CREATE, sizeof(*req));
+
+       req->num_pages =  cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
+
+       AMAP_SET_BITS(struct amap_eq_context, func, req->context,
+                       ctrl->pci_func);
+       AMAP_SET_BITS(struct amap_eq_context, valid, req->context, 1);
+       /* 4byte eqe*/
+       AMAP_SET_BITS(struct amap_eq_context, size, req->context, 0);
+       AMAP_SET_BITS(struct amap_eq_context, count, req->context,
+                       __ilog2_u32(eq->len/256));
+       AMAP_SET_BITS(struct amap_eq_context, delaymult, req->context,
+                       eq_delay_to_mult(eq_delay));
+       be_dws_cpu_to_le(req->context, sizeof(req->context));
+
+       be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
+
+       status = be_mbox_db_ring(ctrl);
+       if (!status) {
+               eq->id = le16_to_cpu(resp->eq_id);
+               eq->created = true;
+       }
+       spin_unlock(&ctrl->cmd_lock);
+       return status;
+}
+
+int be_cmd_mac_addr_query(struct be_ctrl_info *ctrl, u8 *mac_addr,
+                       u8 type, bool permanent, u32 if_handle)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_mac_query *req = embedded_payload(wrb);
+       struct be_cmd_resp_mac_query *resp = embedded_payload(wrb);
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_NTWK_MAC_QUERY, sizeof(*req));
+
+       req->type = type;
+       if (permanent) {
+               req->permanent = 1;
+       } else {
+               req->if_id = cpu_to_le16((u16)if_handle);
+               req->permanent = 0;
+       }
+
+       status = be_mbox_db_ring(ctrl);
+       if (!status)
+               memcpy(mac_addr, resp->mac.addr, ETH_ALEN);
+
+       spin_unlock(&ctrl->cmd_lock);
+       return status;
+}
+
+int be_cmd_pmac_add(struct be_ctrl_info *ctrl, u8 *mac_addr,
+               u32 if_id, u32 *pmac_id)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_pmac_add *req = embedded_payload(wrb);
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_NTWK_PMAC_ADD, sizeof(*req));
+
+       req->if_id = cpu_to_le32(if_id);
+       memcpy(req->mac_address, mac_addr, ETH_ALEN);
+
+       status = be_mbox_db_ring(ctrl);
+       if (!status) {
+               struct be_cmd_resp_pmac_add *resp = embedded_payload(wrb);
+               *pmac_id = le32_to_cpu(resp->pmac_id);
+       }
+
+       spin_unlock(&ctrl->cmd_lock);
+       return status;
+}
+
+int be_cmd_pmac_del(struct be_ctrl_info *ctrl, u32 if_id, u32 pmac_id)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_pmac_del *req = embedded_payload(wrb);
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_NTWK_PMAC_DEL, sizeof(*req));
+
+       req->if_id = cpu_to_le32(if_id);
+       req->pmac_id = cpu_to_le32(pmac_id);
+
+       status = be_mbox_db_ring(ctrl);
+       spin_unlock(&ctrl->cmd_lock);
+
+       return status;
+}
+
+int be_cmd_cq_create(struct be_ctrl_info *ctrl,
+               struct be_queue_info *cq, struct be_queue_info *eq,
+               bool sol_evts, bool no_delay, int coalesce_wm)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_cq_create *req = embedded_payload(wrb);
+       struct be_cmd_resp_cq_create *resp = embedded_payload(wrb);
+       struct be_dma_mem *q_mem = &cq->dma_mem;
+       void *ctxt = &req->context;
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_CQ_CREATE, sizeof(*req));
+
+       req->num_pages =  cpu_to_le16(PAGES_4K_SPANNED(q_mem->va, q_mem->size));
+
+       AMAP_SET_BITS(struct amap_cq_context, coalescwm, ctxt, coalesce_wm);
+       AMAP_SET_BITS(struct amap_cq_context, nodelay, ctxt, no_delay);
+       AMAP_SET_BITS(struct amap_cq_context, count, ctxt,
+                       __ilog2_u32(cq->len/256));
+       AMAP_SET_BITS(struct amap_cq_context, valid, ctxt, 1);
+       AMAP_SET_BITS(struct amap_cq_context, solevent, ctxt, sol_evts);
+       AMAP_SET_BITS(struct amap_cq_context, eventable, ctxt, 1);
+       AMAP_SET_BITS(struct amap_cq_context, eqid, ctxt, eq->id);
+       AMAP_SET_BITS(struct amap_cq_context, armed, ctxt, 0);
+       AMAP_SET_BITS(struct amap_cq_context, func, ctxt, ctrl->pci_func);
+       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_db_ring(ctrl);
+       if (!status) {
+               cq->id = le16_to_cpu(resp->cq_id);
+               cq->created = true;
+       }
+       spin_unlock(&ctrl->cmd_lock);
+
+       return status;
+}
+
+int be_cmd_txq_create(struct be_ctrl_info *ctrl,
+                       struct be_queue_info *txq,
+                       struct be_queue_info *cq)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_eth_tx_create *req = embedded_payload(wrb);
+       struct be_dma_mem *q_mem = &txq->dma_mem;
+       void *ctxt = &req->context;
+       int status;
+       u32 len_encoded;
+
+       spin_lock(&ctrl->cmd_lock);
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_TX_CREATE,
+               sizeof(*req));
+
+       req->num_pages = PAGES_4K_SPANNED(q_mem->va, q_mem->size);
+       req->ulp_num = BE_ULP1_NUM;
+       req->type = BE_ETH_TX_RING_TYPE_STANDARD;
+
+       len_encoded = fls(txq->len); /* log2(len) + 1 */
+       if (len_encoded == 16)
+               len_encoded = 0;
+       AMAP_SET_BITS(struct amap_tx_context, tx_ring_size, ctxt, len_encoded);
+       AMAP_SET_BITS(struct amap_tx_context, pci_func_id, ctxt,
+                       ctrl->pci_func);
+       AMAP_SET_BITS(struct amap_tx_context, ctx_valid, ctxt, 1);
+       AMAP_SET_BITS(struct amap_tx_context, cq_id_send, 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_db_ring(ctrl);
+       if (!status) {
+               struct be_cmd_resp_eth_tx_create *resp = embedded_payload(wrb);
+               txq->id = le16_to_cpu(resp->cid);
+               txq->created = true;
+       }
+       spin_unlock(&ctrl->cmd_lock);
+
+       return status;
+}
+
+int be_cmd_rxq_create(struct be_ctrl_info *ctrl,
+               struct be_queue_info *rxq, u16 cq_id, u16 frag_size,
+               u16 max_frame_size, u32 if_id, u32 rss)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_eth_rx_create *req = embedded_payload(wrb);
+       struct be_dma_mem *q_mem = &rxq->dma_mem;
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH, OPCODE_ETH_RX_CREATE,
+               sizeof(*req));
+
+       req->cq_id = cpu_to_le16(cq_id);
+       req->frag_size = fls(frag_size) - 1;
+       req->num_pages = 2;
+       be_cmd_page_addrs_prepare(req->pages, ARRAY_SIZE(req->pages), q_mem);
+       req->interface_id = cpu_to_le32(if_id);
+       req->max_frame_size = cpu_to_le16(max_frame_size);
+       req->rss_queue = cpu_to_le32(rss);
+
+       status = be_mbox_db_ring(ctrl);
+       if (!status) {
+               struct be_cmd_resp_eth_rx_create *resp = embedded_payload(wrb);
+               rxq->id = le16_to_cpu(resp->id);
+               rxq->created = true;
+       }
+       spin_unlock(&ctrl->cmd_lock);
+
+       return status;
+}
+
+/* Generic destroyer function for all types of queues */
+int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
+               int queue_type)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_q_destroy *req = embedded_payload(wrb);
+       u8 subsys = 0, opcode = 0;
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+
+       memset(wrb, 0, sizeof(*wrb));
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       switch (queue_type) {
+       case QTYPE_EQ:
+               subsys = CMD_SUBSYSTEM_COMMON;
+               opcode = OPCODE_COMMON_EQ_DESTROY;
+               break;
+       case QTYPE_CQ:
+               subsys = CMD_SUBSYSTEM_COMMON;
+               opcode = OPCODE_COMMON_CQ_DESTROY;
+               break;
+       case QTYPE_TXQ:
+               subsys = CMD_SUBSYSTEM_ETH;
+               opcode = OPCODE_ETH_TX_DESTROY;
+               break;
+       case QTYPE_RXQ:
+               subsys = CMD_SUBSYSTEM_ETH;
+               opcode = OPCODE_ETH_RX_DESTROY;
+               break;
+       default:
+               printk(KERN_WARNING DRV_NAME ":bad Q type in Q destroy cmd\n");
+               status = -1;
+               goto err;
+       }
+       be_cmd_hdr_prepare(&req->hdr, subsys, opcode, sizeof(*req));
+       req->id = cpu_to_le16(q->id);
+
+       status = be_mbox_db_ring(ctrl);
+err:
+       spin_unlock(&ctrl->cmd_lock);
+
+       return status;
+}
+
+/* Create an rx filtering policy configuration on an i/f */
+int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 flags, u8 *mac,
+               bool pmac_invalid, u32 *if_handle, u32 *pmac_id)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_if_create *req = embedded_payload(wrb);
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_NTWK_INTERFACE_CREATE, sizeof(*req));
+
+       req->capability_flags = cpu_to_le32(flags);
+       req->enable_flags = cpu_to_le32(flags);
+       if (!pmac_invalid)
+               memcpy(req->mac_addr, mac, ETH_ALEN);
+
+       status = be_mbox_db_ring(ctrl);
+       if (!status) {
+               struct be_cmd_resp_if_create *resp = embedded_payload(wrb);
+               *if_handle = le32_to_cpu(resp->interface_id);
+               if (!pmac_invalid)
+                       *pmac_id = le32_to_cpu(resp->pmac_id);
+       }
+
+       spin_unlock(&ctrl->cmd_lock);
+       return status;
+}
+
+int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 interface_id)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_if_destroy *req = embedded_payload(wrb);
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_NTWK_INTERFACE_DESTROY, sizeof(*req));
+
+       req->interface_id = cpu_to_le32(interface_id);
+       status = be_mbox_db_ring(ctrl);
+
+       spin_unlock(&ctrl->cmd_lock);
+
+       return status;
+}
+
+/* Get stats is a non embedded command: the request is not embedded inside
+ * WRB but is a separate dma memory block
+ */
+int be_cmd_get_stats(struct be_ctrl_info *ctrl, struct be_dma_mem *nonemb_cmd)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_get_stats *req = nonemb_cmd->va;
+       struct be_sge *sge = nonembedded_sgl(wrb);
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+       memset(wrb, 0, sizeof(*wrb));
+
+       memset(req, 0, sizeof(*req));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), false, 1);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
+               OPCODE_ETH_GET_STATISTICS, sizeof(*req));
+       sge->pa_hi = cpu_to_le32(upper_32_bits(nonemb_cmd->dma));
+       sge->pa_lo = cpu_to_le32(nonemb_cmd->dma & 0xFFFFFFFF);
+       sge->len = cpu_to_le32(nonemb_cmd->size);
+
+       status = be_mbox_db_ring(ctrl);
+       if (!status) {
+               struct be_cmd_resp_get_stats *resp = nonemb_cmd->va;
+               be_dws_le_to_cpu(&resp->hw_stats, sizeof(resp->hw_stats));
+       }
+
+       spin_unlock(&ctrl->cmd_lock);
+       return status;
+}
+
+int be_cmd_link_status_query(struct be_ctrl_info *ctrl,
+                       struct be_link_info *link)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_link_status *req = embedded_payload(wrb);
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_NTWK_LINK_STATUS_QUERY, sizeof(*req));
+
+       status = be_mbox_db_ring(ctrl);
+       if (!status) {
+               struct be_cmd_resp_link_status *resp = embedded_payload(wrb);
+               link->speed = resp->mac_speed;
+               link->duplex = resp->mac_duplex;
+               link->fault = resp->mac_fault;
+       } else {
+               link->speed = PHY_LINK_SPEED_ZERO;
+       }
+
+       spin_unlock(&ctrl->cmd_lock);
+       return status;
+}
+
+int be_cmd_get_fw_ver(struct be_ctrl_info *ctrl, char *fw_ver)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_get_fw_version *req = embedded_payload(wrb);
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_GET_FW_VERSION, sizeof(*req));
+
+       status = be_mbox_db_ring(ctrl);
+       if (!status) {
+               struct be_cmd_resp_get_fw_version *resp = embedded_payload(wrb);
+               strncpy(fw_ver, resp->firmware_version_string, FW_VER_LEN);
+       }
+
+       spin_unlock(&ctrl->cmd_lock);
+       return status;
+}
+
+/* set the EQ delay interval of an EQ to specified value */
+int be_cmd_modify_eqd(struct be_ctrl_info *ctrl, u32 eq_id, u32 eqd)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_modify_eq_delay *req = embedded_payload(wrb);
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_MODIFY_EQ_DELAY, sizeof(*req));
+
+       req->num_eq = cpu_to_le32(1);
+       req->delay[0].eq_id = cpu_to_le32(eq_id);
+       req->delay[0].phase = 0;
+       req->delay[0].delay_multiplier = cpu_to_le32(eqd);
+
+       status = be_mbox_db_ring(ctrl);
+
+       spin_unlock(&ctrl->cmd_lock);
+       return status;
+}
+
+int be_cmd_vlan_config(struct be_ctrl_info *ctrl, u32 if_id, u16 *vtag_array,
+                       u32 num, bool untagged, bool promiscuous)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_vlan_config *req = embedded_payload(wrb);
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_NTWK_VLAN_CONFIG, sizeof(*req));
+
+       req->interface_id = if_id;
+       req->promiscuous = promiscuous;
+       req->untagged = untagged;
+       req->num_vlan = num;
+       if (!promiscuous) {
+               memcpy(req->normal_vlan, vtag_array,
+                       req->num_vlan * sizeof(vtag_array[0]));
+       }
+
+       status = be_mbox_db_ring(ctrl);
+
+       spin_unlock(&ctrl->cmd_lock);
+       return status;
+}
+
+int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl, u8 port_num, bool en)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_promiscuous_config *req = embedded_payload(wrb);
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_ETH,
+               OPCODE_ETH_PROMISCUOUS, sizeof(*req));
+
+       if (port_num)
+               req->port1_promiscuous = en;
+       else
+               req->port0_promiscuous = en;
+
+       status = be_mbox_db_ring(ctrl);
+
+       spin_unlock(&ctrl->cmd_lock);
+       return status;
+}
+
+int be_cmd_mcast_mac_set(struct be_ctrl_info *ctrl, u32 if_id, u8 *mac_table,
+                       u32 num, bool promiscuous)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_mcast_mac_config *req = embedded_payload(wrb);
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_NTWK_MULTICAST_SET, sizeof(*req));
+
+       req->interface_id = if_id;
+       req->promiscuous = promiscuous;
+       if (!promiscuous) {
+               req->num_mac = cpu_to_le16(num);
+               if (num)
+                       memcpy(req->mac, mac_table, ETH_ALEN * num);
+       }
+
+       status = be_mbox_db_ring(ctrl);
+
+       spin_unlock(&ctrl->cmd_lock);
+       return status;
+}
+
+int be_cmd_set_flow_control(struct be_ctrl_info *ctrl, u32 tx_fc, u32 rx_fc)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_set_flow_control *req = embedded_payload(wrb);
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_SET_FLOW_CONTROL, sizeof(*req));
+
+       req->tx_flow_control = cpu_to_le16((u16)tx_fc);
+       req->rx_flow_control = cpu_to_le16((u16)rx_fc);
+
+       status = be_mbox_db_ring(ctrl);
+
+       spin_unlock(&ctrl->cmd_lock);
+       return status;
+}
+
+int be_cmd_get_flow_control(struct be_ctrl_info *ctrl, u32 *tx_fc, u32 *rx_fc)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_get_flow_control *req = embedded_payload(wrb);
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_GET_FLOW_CONTROL, sizeof(*req));
+
+       status = be_mbox_db_ring(ctrl);
+       if (!status) {
+               struct be_cmd_resp_get_flow_control *resp =
+                                               embedded_payload(wrb);
+               *tx_fc = le16_to_cpu(resp->tx_flow_control);
+               *rx_fc = le16_to_cpu(resp->rx_flow_control);
+       }
+
+       spin_unlock(&ctrl->cmd_lock);
+       return status;
+}
+
+int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num)
+{
+       struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem);
+       struct be_cmd_req_query_fw_cfg *req = embedded_payload(wrb);
+       int status;
+
+       spin_lock(&ctrl->cmd_lock);
+
+       memset(wrb, 0, sizeof(*wrb));
+
+       be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0);
+
+       be_cmd_hdr_prepare(&req->hdr, CMD_SUBSYSTEM_COMMON,
+               OPCODE_COMMON_QUERY_FIRMWARE_CONFIG, sizeof(*req));
+
+       status = be_mbox_db_ring(ctrl);
+       if (!status) {
+               struct be_cmd_resp_query_fw_cfg *resp = embedded_payload(wrb);
+               *port_num = le32_to_cpu(resp->phys_port);
+       }
+
+       spin_unlock(&ctrl->cmd_lock);
+       return status;
+}
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h
new file mode 100644 (file)
index 0000000..e499e2d
--- /dev/null
@@ -0,0 +1,688 @@
+/*
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.  The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+
+/*
+ * The driver sends configuration and managements command requests to the
+ * firmware in the BE. These requests are communicated to the processor
+ * using Work Request Blocks (WRBs) submitted to the MCC-WRB ring or via one
+ * WRB inside a MAILBOX.
+ * The commands are serviced by the ARM processor in the BladeEngine's MPU.
+ */
+
+struct be_sge {
+       u32 pa_lo;
+       u32 pa_hi;
+       u32 len;
+};
+
+#define MCC_WRB_EMBEDDED_MASK  1       /* bit 0 of dword 0*/
+#define MCC_WRB_SGE_CNT_SHIFT  3       /* bits 3 - 7 of dword 0 */
+#define MCC_WRB_SGE_CNT_MASK   0x1F    /* bits 3 - 7 of dword 0 */
+struct be_mcc_wrb {
+       u32 embedded;           /* dword 0 */
+       u32 payload_length;     /* dword 1 */
+       u32 tag0;               /* dword 2 */
+       u32 tag1;               /* dword 3 */
+       u32 rsvd;               /* dword 4 */
+       union {
+               u8 embedded_payload[236]; /* used by embedded cmds */
+               struct be_sge sgl[19];    /* used by non-embedded cmds */
+       } payload;
+};
+
+#define CQE_FLAGS_VALID_MASK           (1 << 31)
+#define CQE_FLAGS_ASYNC_MASK           (1 << 30)
+#define CQE_FLAGS_COMPLETED_MASK       (1 << 28)
+#define CQE_FLAGS_CONSUMED_MASK        (1 << 27)
+
+/* Completion Status */
+enum {
+       MCC_STATUS_SUCCESS = 0x0,
+/* The client does not have sufficient privileges to execute the command */
+       MCC_STATUS_INSUFFICIENT_PRIVILEGES = 0x1,
+/* A parameter in the command was invalid. */
+       MCC_STATUS_INVALID_PARAMETER = 0x2,
+/* There are insufficient chip resources to execute the command */
+       MCC_STATUS_INSUFFICIENT_RESOURCES = 0x3,
+/* The command is completing because the queue was getting flushed */
+       MCC_STATUS_QUEUE_FLUSHING = 0x4,
+/* The command is completing with a DMA error */
+       MCC_STATUS_DMA_FAILED = 0x5
+};
+
+#define CQE_STATUS_COMPL_MASK          0xFFFF
+#define CQE_STATUS_COMPL_SHIFT         0       /* bits 0 - 15 */
+#define CQE_STATUS_EXTD_MASK           0xFFFF
+#define CQE_STATUS_EXTD_SHIFT          0       /* bits 0 - 15 */
+
+struct be_mcc_cq_entry {
+       u32 status;             /* dword 0 */
+       u32 tag0;               /* dword 1 */
+       u32 tag1;               /* dword 2 */
+       u32 flags;              /* dword 3 */
+};
+
+struct be_mcc_mailbox {
+       struct be_mcc_wrb wrb;
+       struct be_mcc_cq_entry cqe;
+};
+
+#define CMD_SUBSYSTEM_COMMON   0x1
+#define CMD_SUBSYSTEM_ETH      0x3
+
+#define OPCODE_COMMON_NTWK_MAC_QUERY                   1
+#define OPCODE_COMMON_NTWK_MAC_SET                     2
+#define OPCODE_COMMON_NTWK_MULTICAST_SET               3
+#define OPCODE_COMMON_NTWK_VLAN_CONFIG                 4
+#define OPCODE_COMMON_NTWK_LINK_STATUS_QUERY           5
+#define OPCODE_COMMON_CQ_CREATE                                12
+#define OPCODE_COMMON_EQ_CREATE                                13
+#define OPCODE_COMMON_MCC_CREATE                       21
+#define OPCODE_COMMON_NTWK_RX_FILTER                   34
+#define OPCODE_COMMON_GET_FW_VERSION                   35
+#define OPCODE_COMMON_SET_FLOW_CONTROL                 36
+#define OPCODE_COMMON_GET_FLOW_CONTROL                 37
+#define OPCODE_COMMON_SET_FRAME_SIZE                   39
+#define OPCODE_COMMON_MODIFY_EQ_DELAY                  41
+#define OPCODE_COMMON_FIRMWARE_CONFIG                  42
+#define OPCODE_COMMON_NTWK_INTERFACE_CREATE            50
+#define OPCODE_COMMON_NTWK_INTERFACE_DESTROY           51
+#define OPCODE_COMMON_CQ_DESTROY                       54
+#define OPCODE_COMMON_EQ_DESTROY                       55
+#define OPCODE_COMMON_QUERY_FIRMWARE_CONFIG            58
+#define OPCODE_COMMON_NTWK_PMAC_ADD                    59
+#define OPCODE_COMMON_NTWK_PMAC_DEL                    60
+
+#define OPCODE_ETH_ACPI_CONFIG                         2
+#define OPCODE_ETH_PROMISCUOUS                         3
+#define OPCODE_ETH_GET_STATISTICS                      4
+#define OPCODE_ETH_TX_CREATE                           7
+#define OPCODE_ETH_RX_CREATE                           8
+#define OPCODE_ETH_TX_DESTROY                          9
+#define OPCODE_ETH_RX_DESTROY                          10
+
+struct be_cmd_req_hdr {
+       u8 opcode;              /* dword 0 */
+       u8 subsystem;           /* dword 0 */
+       u8 port_number;         /* dword 0 */
+       u8 domain;              /* dword 0 */
+       u32 timeout;            /* dword 1 */
+       u32 request_length;     /* dword 2 */
+       u32 rsvd;               /* dword 3 */
+};
+
+#define RESP_HDR_INFO_OPCODE_SHIFT     0       /* bits 0 - 7 */
+#define RESP_HDR_INFO_SUBSYS_SHIFT     8       /* bits 8 - 15 */
+struct be_cmd_resp_hdr {
+       u32 info;               /* dword 0 */
+       u32 status;             /* dword 1 */
+       u32 response_length;    /* dword 2 */
+       u32 actual_resp_len;    /* dword 3 */
+};
+
+struct phys_addr {
+       u32 lo;
+       u32 hi;
+};
+
+/**************************
+ * BE Command definitions *
+ **************************/
+
+/* Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field */
+struct amap_eq_context {
+       u8 cidx[13];            /* dword 0*/
+       u8 rsvd0[3];            /* dword 0*/
+       u8 epidx[13];           /* dword 0*/
+       u8 valid;               /* dword 0*/
+       u8 rsvd1;               /* dword 0*/
+       u8 size;                /* dword 0*/
+       u8 pidx[13];            /* dword 1*/
+       u8 rsvd2[3];            /* dword 1*/
+       u8 pd[10];              /* dword 1*/
+       u8 count[3];            /* dword 1*/
+       u8 solevent;            /* dword 1*/
+       u8 stalled;             /* dword 1*/
+       u8 armed;               /* dword 1*/
+       u8 rsvd3[4];            /* dword 2*/
+       u8 func[8];             /* dword 2*/
+       u8 rsvd4;               /* dword 2*/
+       u8 delaymult[10];       /* dword 2*/
+       u8 rsvd5[2];            /* dword 2*/
+       u8 phase[2];            /* dword 2*/
+       u8 nodelay;             /* dword 2*/
+       u8 rsvd6[4];            /* dword 2*/
+       u8 rsvd7[32];           /* dword 3*/
+} __packed;
+
+struct be_cmd_req_eq_create {
+       struct be_cmd_req_hdr hdr;
+       u16 num_pages;          /* sword */
+       u16 rsvd0;              /* sword */
+       u8 context[sizeof(struct amap_eq_context) / 8];
+       struct phys_addr pages[8];
+} __packed;
+
+struct be_cmd_resp_eq_create {
+       struct be_cmd_resp_hdr resp_hdr;
+       u16 eq_id;              /* sword */
+       u16 rsvd0;              /* sword */
+} __packed;
+
+/******************** Mac query ***************************/
+enum {
+       MAC_ADDRESS_TYPE_STORAGE = 0x0,
+       MAC_ADDRESS_TYPE_NETWORK = 0x1,
+       MAC_ADDRESS_TYPE_PD = 0x2,
+       MAC_ADDRESS_TYPE_MANAGEMENT = 0x3
+};
+
+struct mac_addr {
+       u16 size_of_struct;
+       u8 addr[ETH_ALEN];
+} __packed;
+
+struct be_cmd_req_mac_query {
+       struct be_cmd_req_hdr hdr;
+       u8 type;
+       u8 permanent;
+       u16 if_id;
+} __packed;
+
+struct be_cmd_resp_mac_query {
+       struct be_cmd_resp_hdr hdr;
+       struct mac_addr mac;
+};
+
+/******************** PMac Add ***************************/
+struct be_cmd_req_pmac_add {
+       struct be_cmd_req_hdr hdr;
+       u32 if_id;
+       u8 mac_address[ETH_ALEN];
+       u8 rsvd0[2];
+} __packed;
+
+struct be_cmd_resp_pmac_add {
+       struct be_cmd_resp_hdr hdr;
+       u32 pmac_id;
+};
+
+/******************** PMac Del ***************************/
+struct be_cmd_req_pmac_del {
+       struct be_cmd_req_hdr hdr;
+       u32 if_id;
+       u32 pmac_id;
+};
+
+/******************** Create CQ ***************************/
+/* Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field */
+struct amap_cq_context {
+       u8 cidx[11];            /* dword 0*/
+       u8 rsvd0;               /* dword 0*/
+       u8 coalescwm[2];        /* dword 0*/
+       u8 nodelay;             /* dword 0*/
+       u8 epidx[11];           /* dword 0*/
+       u8 rsvd1;               /* dword 0*/
+       u8 count[2];            /* dword 0*/
+       u8 valid;               /* dword 0*/
+       u8 solevent;            /* dword 0*/
+       u8 eventable;           /* dword 0*/
+       u8 pidx[11];            /* dword 1*/
+       u8 rsvd2;               /* dword 1*/
+       u8 pd[10];              /* dword 1*/
+       u8 eqid[8];             /* dword 1*/
+       u8 stalled;             /* dword 1*/
+       u8 armed;               /* dword 1*/
+       u8 rsvd3[4];            /* dword 2*/
+       u8 func[8];             /* dword 2*/
+       u8 rsvd4[20];           /* dword 2*/
+       u8 rsvd5[32];           /* dword 3*/
+} __packed;
+
+struct be_cmd_req_cq_create {
+       struct be_cmd_req_hdr hdr;
+       u16 num_pages;
+       u16 rsvd0;
+       u8 context[sizeof(struct amap_cq_context) / 8];
+       struct phys_addr pages[8];
+} __packed;
+
+struct be_cmd_resp_cq_create {
+       struct be_cmd_resp_hdr hdr;
+       u16 cq_id;
+       u16 rsvd0;
+} __packed;
+
+/******************** Create TxQ ***************************/
+#define BE_ETH_TX_RING_TYPE_STANDARD           2
+#define BE_ULP1_NUM                            1
+
+/* Pseudo amap definition in which each bit of the actual structure is defined
+ * as a byte: used to calculate offset/shift/mask of each field */
+struct amap_tx_context {
+       u8 rsvd0[16];           /* dword 0 */
+       u8 tx_ring_size[4];     /* dword 0 */
+       u8 rsvd1[26];           /* dword 0 */
+       u8 pci_func_id[8];      /* dword 1 */
+       u8 rsvd2[9];            /* dword 1 */
+       u8 ctx_valid;           /* dword 1 */
+       u8 cq_id_send[16];      /* dword 2 */
+       u8 rsvd3[16];           /* dword 2 */
+       u8 rsvd4[32];           /* dword 3 */
+       u8 rsvd5[32];           /* dword 4 */
+       u8 rsvd6[32];           /* dword 5 */
+       u8 rsvd7[32];           /* dword 6 */
+       u8 rsvd8[32];           /* dword 7 */
+       u8 rsvd9[32];           /* dword 8 */
+       u8 rsvd10[32];          /* dword 9 */
+       u8 rsvd11[32];          /* dword 10 */
+       u8 rsvd12[32];          /* dword 11 */
+       u8 rsvd13[32];          /* dword 12 */
+       u8 rsvd14[32];          /* dword 13 */
+       u8 rsvd15[32];          /* dword 14 */
+       u8 rsvd16[32];          /* dword 15 */
+} __packed;
+
+struct be_cmd_req_eth_tx_create {
+       struct be_cmd_req_hdr hdr;
+       u8 num_pages;
+       u8 ulp_num;
+       u8 type;
+       u8 bound_port;
+       u8 context[sizeof(struct amap_tx_context) / 8];
+       struct phys_addr pages[8];
+} __packed;
+
+struct be_cmd_resp_eth_tx_create {
+       struct be_cmd_resp_hdr hdr;
+       u16 cid;
+       u16 rsvd0;
+} __packed;
+
+/******************** Create RxQ ***************************/
+struct be_cmd_req_eth_rx_create {
+       struct be_cmd_req_hdr hdr;
+       u16 cq_id;
+       u8 frag_size;
+       u8 num_pages;
+       struct phys_addr pages[2];
+       u32 interface_id;
+       u16 max_frame_size;
+       u16 rsvd0;
+       u32 rss_queue;
+} __packed;
+
+struct be_cmd_resp_eth_rx_create {
+       struct be_cmd_resp_hdr hdr;
+       u16 id;
+       u8 cpu_id;
+       u8 rsvd0;
+} __packed;
+
+/******************** Q Destroy  ***************************/
+/* Type of Queue to be destroyed */
+enum {
+       QTYPE_EQ = 1,
+       QTYPE_CQ,
+       QTYPE_TXQ,
+       QTYPE_RXQ
+};
+
+struct be_cmd_req_q_destroy {
+       struct be_cmd_req_hdr hdr;
+       u16 id;
+       u16 bypass_flush;       /* valid only for rx q destroy */
+} __packed;
+
+/************ I/f Create (it's actually I/f Config Create)**********/
+
+/* Capability flags for the i/f */
+enum be_if_flags {
+       BE_IF_FLAGS_RSS = 0x4,
+       BE_IF_FLAGS_PROMISCUOUS = 0x8,
+       BE_IF_FLAGS_BROADCAST = 0x10,
+       BE_IF_FLAGS_UNTAGGED = 0x20,
+       BE_IF_FLAGS_ULP = 0x40,
+       BE_IF_FLAGS_VLAN_PROMISCUOUS = 0x80,
+       BE_IF_FLAGS_VLAN = 0x100,
+       BE_IF_FLAGS_MCAST_PROMISCUOUS = 0x200,
+       BE_IF_FLAGS_PASS_L2_ERRORS = 0x400,
+       BE_IF_FLAGS_PASS_L3L4_ERRORS = 0x800
+};
+
+/* An RX interface is an object with one or more MAC addresses and
+ * filtering capabilities. */
+struct be_cmd_req_if_create {
+       struct be_cmd_req_hdr hdr;
+       u32 version;            /* ignore currntly */
+       u32 capability_flags;
+       u32 enable_flags;
+       u8 mac_addr[ETH_ALEN];
+       u8 rsvd0;
+       u8 pmac_invalid; /* if set, don't attach the mac addr to the i/f */
+       u32 vlan_tag;    /* not used currently */
+} __packed;
+
+struct be_cmd_resp_if_create {
+       struct be_cmd_resp_hdr hdr;
+       u32 interface_id;
+       u32 pmac_id;
+};
+
+/****** I/f Destroy(it's actually I/f Config Destroy )**********/
+struct be_cmd_req_if_destroy {
+       struct be_cmd_req_hdr hdr;
+       u32 interface_id;
+};
+
+/*************** HW Stats Get **********************************/
+struct be_port_rxf_stats {
+       u32 rx_bytes_lsd;       /* dword 0*/
+       u32 rx_bytes_msd;       /* dword 1*/
+       u32 rx_total_frames;    /* dword 2*/
+       u32 rx_unicast_frames;  /* dword 3*/
+       u32 rx_multicast_frames;        /* dword 4*/
+       u32 rx_broadcast_frames;        /* dword 5*/
+       u32 rx_crc_errors;      /* dword 6*/
+       u32 rx_alignment_symbol_errors; /* dword 7*/
+       u32 rx_pause_frames;    /* dword 8*/
+       u32 rx_control_frames;  /* dword 9*/
+       u32 rx_in_range_errors; /* dword 10*/
+       u32 rx_out_range_errors;        /* dword 11*/
+       u32 rx_frame_too_long;  /* dword 12*/
+       u32 rx_address_match_errors;    /* dword 13*/
+       u32 rx_vlan_mismatch;   /* dword 14*/
+       u32 rx_dropped_too_small;       /* dword 15*/
+       u32 rx_dropped_too_short;       /* dword 16*/
+       u32 rx_dropped_header_too_small;        /* dword 17*/
+       u32 rx_dropped_tcp_length;      /* dword 18*/
+       u32 rx_dropped_runt;    /* dword 19*/
+       u32 rx_64_byte_packets; /* dword 20*/
+       u32 rx_65_127_byte_packets;     /* dword 21*/
+       u32 rx_128_256_byte_packets;    /* dword 22*/
+       u32 rx_256_511_byte_packets;    /* dword 23*/
+       u32 rx_512_1023_byte_packets;   /* dword 24*/
+       u32 rx_1024_1518_byte_packets;  /* dword 25*/
+       u32 rx_1519_2047_byte_packets;  /* dword 26*/
+       u32 rx_2048_4095_byte_packets;  /* dword 27*/
+       u32 rx_4096_8191_byte_packets;  /* dword 28*/
+       u32 rx_8192_9216_byte_packets;  /* dword 29*/
+       u32 rx_ip_checksum_errs;        /* dword 30*/
+       u32 rx_tcp_checksum_errs;       /* dword 31*/
+       u32 rx_udp_checksum_errs;       /* dword 32*/
+       u32 rx_non_rss_packets; /* dword 33*/
+       u32 rx_ipv4_packets;    /* dword 34*/
+       u32 rx_ipv6_packets;    /* dword 35*/
+       u32 rx_ipv4_bytes_lsd;  /* dword 36*/
+       u32 rx_ipv4_bytes_msd;  /* dword 37*/
+       u32 rx_ipv6_bytes_lsd;  /* dword 38*/
+       u32 rx_ipv6_bytes_msd;  /* dword 39*/
+       u32 rx_chute1_packets;  /* dword 40*/
+       u32 rx_chute2_packets;  /* dword 41*/
+       u32 rx_chute3_packets;  /* dword 42*/
+       u32 rx_management_packets;      /* dword 43*/
+       u32 rx_switched_unicast_packets;        /* dword 44*/
+       u32 rx_switched_multicast_packets;      /* dword 45*/
+       u32 rx_switched_broadcast_packets;      /* dword 46*/
+       u32 tx_bytes_lsd;       /* dword 47*/
+       u32 tx_bytes_msd;       /* dword 48*/
+       u32 tx_unicastframes;   /* dword 49*/
+       u32 tx_multicastframes; /* dword 50*/
+       u32 tx_broadcastframes; /* dword 51*/
+       u32 tx_pauseframes;     /* dword 52*/
+       u32 tx_controlframes;   /* dword 53*/
+       u32 tx_64_byte_packets; /* dword 54*/
+       u32 tx_65_127_byte_packets;     /* dword 55*/
+       u32 tx_128_256_byte_packets;    /* dword 56*/
+       u32 tx_256_511_byte_packets;    /* dword 57*/
+       u32 tx_512_1023_byte_packets;   /* dword 58*/
+       u32 tx_1024_1518_byte_packets;  /* dword 59*/
+       u32 tx_1519_2047_byte_packets;  /* dword 60*/
+       u32 tx_2048_4095_byte_packets;  /* dword 61*/
+       u32 tx_4096_8191_byte_packets;  /* dword 62*/
+       u32 tx_8192_9216_byte_packets;  /* dword 63*/
+       u32 rx_fifo_overflow;   /* dword 64*/
+       u32 rx_input_fifo_overflow;     /* dword 65*/
+};
+
+struct be_rxf_stats {
+       struct be_port_rxf_stats port[2];
+       u32 rx_drops_no_pbuf;   /* dword 132*/
+       u32 rx_drops_no_txpb;   /* dword 133*/
+       u32 rx_drops_no_erx_descr;      /* dword 134*/
+       u32 rx_drops_no_tpre_descr;     /* dword 135*/
+       u32 management_rx_port_packets; /* dword 136*/
+       u32 management_rx_port_bytes;   /* dword 137*/
+       u32 management_rx_port_pause_frames;    /* dword 138*/
+       u32 management_rx_port_errors;  /* dword 139*/
+       u32 management_tx_port_packets; /* dword 140*/
+       u32 management_tx_port_bytes;   /* dword 141*/
+       u32 management_tx_port_pause;   /* dword 142*/
+       u32 management_rx_port_rxfifo_overflow; /* dword 143*/
+       u32 rx_drops_too_many_frags;    /* dword 144*/
+       u32 rx_drops_invalid_ring;      /* dword 145*/
+       u32 forwarded_packets;  /* dword 146*/
+       u32 rx_drops_mtu;       /* dword 147*/
+       u32 rsvd0[15];
+};
+
+struct be_erx_stats {
+       u32 rx_drops_no_fragments[44];     /* dwordS 0 to 43*/
+       u32 debug_wdma_sent_hold;          /* dword 44*/
+       u32 debug_wdma_pbfree_sent_hold;   /* dword 45*/
+       u32 debug_wdma_zerobyte_pbfree_sent_hold; /* dword 46*/
+       u32 debug_pmem_pbuf_dealloc;       /* dword 47*/
+};
+
+struct be_hw_stats {
+       struct be_rxf_stats rxf;
+       u32 rsvd[48];
+       struct be_erx_stats erx;
+};
+
+struct be_cmd_req_get_stats {
+       struct be_cmd_req_hdr hdr;
+       u8 rsvd[sizeof(struct be_hw_stats)];
+};
+
+struct be_cmd_resp_get_stats {
+       struct be_cmd_resp_hdr hdr;
+       struct be_hw_stats hw_stats;
+};
+
+struct be_cmd_req_vlan_config {
+       struct be_cmd_req_hdr hdr;
+       u8 interface_id;
+       u8 promiscuous;
+       u8 untagged;
+       u8 num_vlan;
+       u16 normal_vlan[64];
+} __packed;
+
+struct be_cmd_req_promiscuous_config {
+       struct be_cmd_req_hdr hdr;
+       u8 port0_promiscuous;
+       u8 port1_promiscuous;
+       u16 rsvd0;
+} __packed;
+
+struct macaddr {
+       u8 byte[ETH_ALEN];
+};
+
+struct be_cmd_req_mcast_mac_config {
+       struct be_cmd_req_hdr hdr;
+       u16 num_mac;
+       u8 promiscuous;
+       u8 interface_id;
+       struct macaddr mac[32];
+} __packed;
+
+static inline struct be_hw_stats *
+hw_stats_from_cmd(struct be_cmd_resp_get_stats *cmd)
+{
+       return &cmd->hw_stats;
+}
+
+/******************** Link Status Query *******************/
+struct be_cmd_req_link_status {
+       struct be_cmd_req_hdr hdr;
+       u32 rsvd;
+};
+
+struct be_link_info {
+       u8 duplex;
+       u8 speed;
+       u8 fault;
+};
+
+enum {
+       PHY_LINK_DUPLEX_NONE = 0x0,
+       PHY_LINK_DUPLEX_HALF = 0x1,
+       PHY_LINK_DUPLEX_FULL = 0x2
+};
+
+enum {
+       PHY_LINK_SPEED_ZERO = 0x0,      /* => No link */
+       PHY_LINK_SPEED_10MBPS = 0x1,
+       PHY_LINK_SPEED_100MBPS = 0x2,
+       PHY_LINK_SPEED_1GBPS = 0x3,
+       PHY_LINK_SPEED_10GBPS = 0x4
+};
+
+struct be_cmd_resp_link_status {
+       struct be_cmd_resp_hdr hdr;
+       u8 physical_port;
+       u8 mac_duplex;
+       u8 mac_speed;
+       u8 mac_fault;
+       u8 mgmt_mac_duplex;
+       u8 mgmt_mac_speed;
+       u16 rsvd0;
+} __packed;
+
+/******************** Get FW Version *******************/
+#define FW_VER_LEN                     32
+struct be_cmd_req_get_fw_version {
+       struct be_cmd_req_hdr hdr;
+       u8 rsvd0[FW_VER_LEN];
+       u8 rsvd1[FW_VER_LEN];
+} __packed;
+
+struct be_cmd_resp_get_fw_version {
+       struct be_cmd_resp_hdr hdr;
+       u8 firmware_version_string[FW_VER_LEN];
+       u8 fw_on_flash_version_string[FW_VER_LEN];
+} __packed;
+
+/******************** Set Flow Contrl *******************/
+struct be_cmd_req_set_flow_control {
+       struct be_cmd_req_hdr hdr;
+       u16 tx_flow_control;
+       u16 rx_flow_control;
+} __packed;
+
+/******************** Get Flow Contrl *******************/
+struct be_cmd_req_get_flow_control {
+       struct be_cmd_req_hdr hdr;
+       u32 rsvd;
+};
+
+struct be_cmd_resp_get_flow_control {
+       struct be_cmd_resp_hdr hdr;
+       u16 tx_flow_control;
+       u16 rx_flow_control;
+} __packed;
+
+/******************** Modify EQ Delay *******************/
+struct be_cmd_req_modify_eq_delay {
+       struct be_cmd_req_hdr hdr;
+       u32 num_eq;
+       struct {
+               u32 eq_id;
+               u32 phase;
+               u32 delay_multiplier;
+       } delay[8];
+} __packed;
+
+struct be_cmd_resp_modify_eq_delay {
+       struct be_cmd_resp_hdr hdr;
+       u32 rsvd0;
+} __packed;
+
+/******************** Get FW Config *******************/
+struct be_cmd_req_query_fw_cfg {
+       struct be_cmd_req_hdr hdr;
+       u32 rsvd[30];
+};
+
+struct be_cmd_resp_query_fw_cfg {
+       struct be_cmd_resp_hdr hdr;
+       u32 be_config_number;
+       u32 asic_revision;
+       u32 phys_port;
+       u32 function_mode;
+       u32 rsvd[26];
+};
+
+extern int be_pci_fnum_get(struct be_ctrl_info *ctrl);
+extern int be_cmd_POST(struct be_ctrl_info *ctrl);
+extern int be_cmd_mac_addr_query(struct be_ctrl_info *ctrl, u8 *mac_addr,
+                       u8 type, bool permanent, u32 if_handle);
+extern int be_cmd_pmac_add(struct be_ctrl_info *ctrl, u8 *mac_addr,
+                       u32 if_id, u32 *pmac_id);
+extern int be_cmd_pmac_del(struct be_ctrl_info *ctrl, u32 if_id, u32 pmac_id);
+extern int be_cmd_if_create(struct be_ctrl_info *ctrl, u32 if_flags, u8 *mac,
+                       bool pmac_invalid, u32 *if_handle, u32 *pmac_id);
+extern int be_cmd_if_destroy(struct be_ctrl_info *ctrl, u32 if_handle);
+extern int be_cmd_eq_create(struct be_ctrl_info *ctrl,
+                       struct be_queue_info *eq, int eq_delay);
+extern int be_cmd_cq_create(struct be_ctrl_info *ctrl,
+                       struct be_queue_info *cq, struct be_queue_info *eq,
+                       bool sol_evts, bool no_delay,
+                       int num_cqe_dma_coalesce);
+extern int be_cmd_txq_create(struct be_ctrl_info *ctrl,
+                       struct be_queue_info *txq,
+                       struct be_queue_info *cq);
+extern int be_cmd_rxq_create(struct be_ctrl_info *ctrl,
+                       struct be_queue_info *rxq, u16 cq_id,
+                       u16 frag_size, u16 max_frame_size, u32 if_id,
+                       u32 rss);
+extern int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q,
+                       int type);
+extern int be_cmd_link_status_query(struct be_ctrl_info *ctrl,
+                       struct be_link_info *link);
+extern int be_cmd_reset(struct be_ctrl_info *ctrl);
+extern int be_cmd_get_stats(struct be_ctrl_info *ctrl,
+                       struct be_dma_mem *nonemb_cmd);
+extern int be_cmd_get_fw_ver(struct be_ctrl_info *ctrl, char *fw_ver);
+
+extern int be_cmd_modify_eqd(struct be_ctrl_info *ctrl, u32 eq_id, u32 eqd);
+extern int be_cmd_vlan_config(struct be_ctrl_info *ctrl, u32 if_id,
+                       u16 *vtag_array, u32 num, bool untagged,
+                       bool promiscuous);
+extern int be_cmd_promiscuous_config(struct be_ctrl_info *ctrl,
+                       u8 port_num, bool en);
+extern int be_cmd_mcast_mac_set(struct be_ctrl_info *ctrl, u32 if_id,
+                       u8 *mac_table, u32 num, bool promiscuous);
+extern int be_cmd_set_flow_control(struct be_ctrl_info *ctrl,
+                       u32 tx_fc, u32 rx_fc);
+extern int be_cmd_get_flow_control(struct be_ctrl_info *ctrl,
+                       u32 *tx_fc, u32 *rx_fc);
+extern int be_cmd_query_fw_cfg(struct be_ctrl_info *ctrl, u32 *port_num);
diff --git a/drivers/net/benet/be_ethtool.c b/drivers/net/benet/be_ethtool.c
new file mode 100644 (file)
index 0000000..04f4b73
--- /dev/null
@@ -0,0 +1,362 @@
+/*
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.  The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+
+#include "be.h"
+#include <linux/ethtool.h>
+
+struct be_ethtool_stat {
+       char desc[ETH_GSTRING_LEN];
+       int type;
+       int size;
+       int offset;
+};
+
+enum {NETSTAT, PORTSTAT, MISCSTAT, DRVSTAT, ERXSTAT};
+#define FIELDINFO(_struct, field) FIELD_SIZEOF(_struct, field), \
+                                       offsetof(_struct, field)
+#define NETSTAT_INFO(field)    #field, NETSTAT,\
+                                       FIELDINFO(struct net_device_stats,\
+                                               field)
+#define DRVSTAT_INFO(field)    #field, DRVSTAT,\
+                                       FIELDINFO(struct be_drvr_stats, field)
+#define MISCSTAT_INFO(field)   #field, MISCSTAT,\
+                                       FIELDINFO(struct be_rxf_stats, field)
+#define PORTSTAT_INFO(field)   #field, PORTSTAT,\
+                                       FIELDINFO(struct be_port_rxf_stats, \
+                                               field)
+#define ERXSTAT_INFO(field)    #field, ERXSTAT,\
+                                       FIELDINFO(struct be_erx_stats, field)
+
+static const struct be_ethtool_stat et_stats[] = {
+       {NETSTAT_INFO(rx_packets)},
+       {NETSTAT_INFO(tx_packets)},
+       {NETSTAT_INFO(rx_bytes)},
+       {NETSTAT_INFO(tx_bytes)},
+       {NETSTAT_INFO(rx_errors)},
+       {NETSTAT_INFO(tx_errors)},
+       {NETSTAT_INFO(rx_dropped)},
+       {NETSTAT_INFO(tx_dropped)},
+       {DRVSTAT_INFO(be_tx_reqs)},
+       {DRVSTAT_INFO(be_tx_stops)},
+       {DRVSTAT_INFO(be_fwd_reqs)},
+       {DRVSTAT_INFO(be_tx_wrbs)},
+       {DRVSTAT_INFO(be_polls)},
+       {DRVSTAT_INFO(be_tx_events)},
+       {DRVSTAT_INFO(be_rx_events)},
+       {DRVSTAT_INFO(be_tx_compl)},
+       {DRVSTAT_INFO(be_rx_compl)},
+       {DRVSTAT_INFO(be_ethrx_post_fail)},
+       {DRVSTAT_INFO(be_802_3_dropped_frames)},
+       {DRVSTAT_INFO(be_802_3_malformed_frames)},
+       {DRVSTAT_INFO(be_tx_rate)},
+       {DRVSTAT_INFO(be_rx_rate)},
+       {PORTSTAT_INFO(rx_unicast_frames)},
+       {PORTSTAT_INFO(rx_multicast_frames)},
+       {PORTSTAT_INFO(rx_broadcast_frames)},
+       {PORTSTAT_INFO(rx_crc_errors)},
+       {PORTSTAT_INFO(rx_alignment_symbol_errors)},
+       {PORTSTAT_INFO(rx_pause_frames)},
+       {PORTSTAT_INFO(rx_control_frames)},
+       {PORTSTAT_INFO(rx_in_range_errors)},
+       {PORTSTAT_INFO(rx_out_range_errors)},
+       {PORTSTAT_INFO(rx_frame_too_long)},
+       {PORTSTAT_INFO(rx_address_match_errors)},
+       {PORTSTAT_INFO(rx_vlan_mismatch)},
+       {PORTSTAT_INFO(rx_dropped_too_small)},
+       {PORTSTAT_INFO(rx_dropped_too_short)},
+       {PORTSTAT_INFO(rx_dropped_header_too_small)},
+       {PORTSTAT_INFO(rx_dropped_tcp_length)},
+       {PORTSTAT_INFO(rx_dropped_runt)},
+       {PORTSTAT_INFO(rx_fifo_overflow)},
+       {PORTSTAT_INFO(rx_input_fifo_overflow)},
+       {PORTSTAT_INFO(rx_ip_checksum_errs)},
+       {PORTSTAT_INFO(rx_tcp_checksum_errs)},
+       {PORTSTAT_INFO(rx_udp_checksum_errs)},
+       {PORTSTAT_INFO(rx_non_rss_packets)},
+       {PORTSTAT_INFO(rx_ipv4_packets)},
+       {PORTSTAT_INFO(rx_ipv6_packets)},
+       {PORTSTAT_INFO(tx_unicastframes)},
+       {PORTSTAT_INFO(tx_multicastframes)},
+       {PORTSTAT_INFO(tx_broadcastframes)},
+       {PORTSTAT_INFO(tx_pauseframes)},
+       {PORTSTAT_INFO(tx_controlframes)},
+       {MISCSTAT_INFO(rx_drops_no_pbuf)},
+       {MISCSTAT_INFO(rx_drops_no_txpb)},
+       {MISCSTAT_INFO(rx_drops_no_erx_descr)},
+       {MISCSTAT_INFO(rx_drops_no_tpre_descr)},
+       {MISCSTAT_INFO(rx_drops_too_many_frags)},
+       {MISCSTAT_INFO(rx_drops_invalid_ring)},
+       {MISCSTAT_INFO(forwarded_packets)},
+       {MISCSTAT_INFO(rx_drops_mtu)},
+       {ERXSTAT_INFO(rx_drops_no_fragments)},
+};
+#define ETHTOOL_STATS_NUM ARRAY_SIZE(et_stats)
+
+static void
+be_get_drvinfo(struct net_device *netdev, struct ethtool_drvinfo *drvinfo)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+
+       strcpy(drvinfo->driver, DRV_NAME);
+       strcpy(drvinfo->version, DRV_VER);
+       strncpy(drvinfo->fw_version, adapter->fw_ver, FW_VER_LEN);
+       strcpy(drvinfo->bus_info, pci_name(adapter->pdev));
+       drvinfo->testinfo_len = 0;
+       drvinfo->regdump_len = 0;
+       drvinfo->eedump_len = 0;
+}
+
+static int
+be_get_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       struct be_eq_obj *rx_eq = &adapter->rx_eq;
+       struct be_eq_obj *tx_eq = &adapter->tx_eq;
+
+       coalesce->rx_max_coalesced_frames = adapter->max_rx_coal;
+
+       coalesce->rx_coalesce_usecs = rx_eq->cur_eqd;
+       coalesce->rx_coalesce_usecs_high = rx_eq->max_eqd;
+       coalesce->rx_coalesce_usecs_low = rx_eq->min_eqd;
+
+       coalesce->tx_coalesce_usecs = tx_eq->cur_eqd;
+       coalesce->tx_coalesce_usecs_high = tx_eq->max_eqd;
+       coalesce->tx_coalesce_usecs_low = tx_eq->min_eqd;
+
+       coalesce->use_adaptive_rx_coalesce = rx_eq->enable_aic;
+       coalesce->use_adaptive_tx_coalesce = tx_eq->enable_aic;
+
+       return 0;
+}
+
+/*
+ * This routine is used to set interrup coalescing delay *as well as*
+ * the number of pkts to coalesce for LRO.
+ */
+static int
+be_set_coalesce(struct net_device *netdev, struct ethtool_coalesce *coalesce)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       struct be_ctrl_info *ctrl = &adapter->ctrl;
+       struct be_eq_obj *rx_eq = &adapter->rx_eq;
+       struct be_eq_obj *tx_eq = &adapter->tx_eq;
+       u32 tx_max, tx_min, tx_cur;
+       u32 rx_max, rx_min, rx_cur;
+       int status = 0;
+
+       if (coalesce->use_adaptive_tx_coalesce == 1)
+               return -EINVAL;
+
+       adapter->max_rx_coal = coalesce->rx_max_coalesced_frames;
+       if (adapter->max_rx_coal > MAX_SKB_FRAGS)
+               adapter->max_rx_coal = MAX_SKB_FRAGS - 1;
+
+       /* if AIC is being turned on now, start with an EQD of 0 */
+       if (rx_eq->enable_aic == 0 &&
+               coalesce->use_adaptive_rx_coalesce == 1) {
+               rx_eq->cur_eqd = 0;
+       }
+       rx_eq->enable_aic = coalesce->use_adaptive_rx_coalesce;
+
+       rx_max = coalesce->rx_coalesce_usecs_high;
+       rx_min = coalesce->rx_coalesce_usecs_low;
+       rx_cur = coalesce->rx_coalesce_usecs;
+
+       tx_max = coalesce->tx_coalesce_usecs_high;
+       tx_min = coalesce->tx_coalesce_usecs_low;
+       tx_cur = coalesce->tx_coalesce_usecs;
+
+       if (tx_cur > BE_MAX_EQD)
+               tx_cur = BE_MAX_EQD;
+       if (tx_eq->cur_eqd != tx_cur) {
+               status = be_cmd_modify_eqd(ctrl, tx_eq->q.id, tx_cur);
+               if (!status)
+                       tx_eq->cur_eqd = tx_cur;
+       }
+
+       if (rx_eq->enable_aic) {
+               if (rx_max > BE_MAX_EQD)
+                       rx_max = BE_MAX_EQD;
+               if (rx_min > rx_max)
+                       rx_min = rx_max;
+               rx_eq->max_eqd = rx_max;
+               rx_eq->min_eqd = rx_min;
+               if (rx_eq->cur_eqd > rx_max)
+                       rx_eq->cur_eqd = rx_max;
+               if (rx_eq->cur_eqd < rx_min)
+                       rx_eq->cur_eqd = rx_min;
+       } else {
+               if (rx_cur > BE_MAX_EQD)
+                       rx_cur = BE_MAX_EQD;
+               if (rx_eq->cur_eqd != rx_cur) {
+                       status = be_cmd_modify_eqd(ctrl, rx_eq->q.id, rx_cur);
+                       if (!status)
+                               rx_eq->cur_eqd = rx_cur;
+               }
+       }
+       return 0;
+}
+
+static u32 be_get_rx_csum(struct net_device *netdev)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+
+       return adapter->rx_csum;
+}
+
+static int be_set_rx_csum(struct net_device *netdev, uint32_t data)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+
+       if (data)
+               adapter->rx_csum = true;
+       else
+               adapter->rx_csum = false;
+
+       return 0;
+}
+
+static void
+be_get_ethtool_stats(struct net_device *netdev,
+               struct ethtool_stats *stats, uint64_t *data)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       struct be_drvr_stats *drvr_stats = &adapter->stats.drvr_stats;
+       struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats.cmd.va);
+       struct be_rxf_stats *rxf_stats = &hw_stats->rxf;
+       struct be_port_rxf_stats *port_stats =
+                       &rxf_stats->port[adapter->port_num];
+       struct net_device_stats *net_stats = &adapter->stats.net_stats;
+       struct be_erx_stats *erx_stats = &hw_stats->erx;
+       void *p = NULL;
+       int i;
+
+       for (i = 0; i < ETHTOOL_STATS_NUM; i++) {
+               switch (et_stats[i].type) {
+               case NETSTAT:
+                       p = net_stats;
+                       break;
+               case DRVSTAT:
+                       p = drvr_stats;
+                       break;
+               case PORTSTAT:
+                       p = port_stats;
+                       break;
+               case MISCSTAT:
+                       p = rxf_stats;
+                       break;
+               case ERXSTAT: /* Currently only one ERX stat is provided */
+                       p = (u32 *)erx_stats + adapter->rx_obj.q.id;
+                       break;
+               }
+
+               p = (u8 *)p + et_stats[i].offset;
+               data[i] = (et_stats[i].size == sizeof(u64)) ?
+                               *(u64 *)p: *(u32 *)p;
+       }
+
+       return;
+}
+
+static void
+be_get_stat_strings(struct net_device *netdev, uint32_t stringset,
+               uint8_t *data)
+{
+       int i;
+       switch (stringset) {
+       case ETH_SS_STATS:
+               for (i = 0; i < ETHTOOL_STATS_NUM; i++) {
+                       memcpy(data, et_stats[i].desc, ETH_GSTRING_LEN);
+                       data += ETH_GSTRING_LEN;
+               }
+               break;
+       }
+}
+
+static int be_get_stats_count(struct net_device *netdev)
+{
+       return ETHTOOL_STATS_NUM;
+}
+
+static int be_get_settings(struct net_device *netdev, struct ethtool_cmd *ecmd)
+{
+       ecmd->speed = SPEED_10000;
+       ecmd->duplex = DUPLEX_FULL;
+       ecmd->autoneg = AUTONEG_DISABLE;
+       return 0;
+}
+
+static void
+be_get_ringparam(struct net_device *netdev, struct ethtool_ringparam *ring)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+
+       ring->rx_max_pending = adapter->rx_obj.q.len;
+       ring->tx_max_pending = adapter->tx_obj.q.len;
+
+       ring->rx_pending = atomic_read(&adapter->rx_obj.q.used);
+       ring->tx_pending = atomic_read(&adapter->tx_obj.q.used);
+}
+
+static void
+be_get_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+
+       be_cmd_get_flow_control(&adapter->ctrl, &ecmd->tx_pause,
+               &ecmd->rx_pause);
+       ecmd->autoneg = AUTONEG_ENABLE;
+}
+
+static int
+be_set_pauseparam(struct net_device *netdev, struct ethtool_pauseparam *ecmd)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       int status;
+
+       if (ecmd->autoneg != AUTONEG_ENABLE)
+               return -EINVAL;
+
+       status = be_cmd_set_flow_control(&adapter->ctrl, ecmd->tx_pause,
+                       ecmd->rx_pause);
+       if (!status)
+               dev_warn(&adapter->pdev->dev, "Pause param set failed.\n");
+
+       return status;
+}
+
+struct ethtool_ops be_ethtool_ops = {
+       .get_settings = be_get_settings,
+       .get_drvinfo = be_get_drvinfo,
+       .get_link = ethtool_op_get_link,
+       .get_coalesce = be_get_coalesce,
+       .set_coalesce = be_set_coalesce,
+       .get_ringparam = be_get_ringparam,
+       .get_pauseparam = be_get_pauseparam,
+       .set_pauseparam = be_set_pauseparam,
+       .get_rx_csum = be_get_rx_csum,
+       .set_rx_csum = be_set_rx_csum,
+       .get_tx_csum = ethtool_op_get_tx_csum,
+       .set_tx_csum = ethtool_op_set_tx_csum,
+       .get_sg = ethtool_op_get_sg,
+       .set_sg = ethtool_op_set_sg,
+       .get_tso = ethtool_op_get_tso,
+       .set_tso = ethtool_op_set_tso,
+       .get_strings = be_get_stat_strings,
+       .get_stats_count = be_get_stats_count,
+       .get_ethtool_stats = be_get_ethtool_stats,
+};
diff --git a/drivers/net/benet/be_hw.h b/drivers/net/benet/be_hw.h
new file mode 100644 (file)
index 0000000..b132aa4
--- /dev/null
@@ -0,0 +1,211 @@
+/*
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.  The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+
+/********* Mailbox door bell *************/
+/* Used for driver communication with the FW.
+ * The software must write this register twice to post any command. First,
+ * it writes the register with hi=1 and the upper bits of the physical address
+ * for the MAILBOX structure. Software must poll the ready bit until this
+ * is acknowledged. Then, sotware writes the register with hi=0 with the lower
+ * bits in the address. It must poll the ready bit until the command is
+ * complete. Upon completion, the MAILBOX will contain a valid completion
+ * queue entry.
+ */
+#define MPU_MAILBOX_DB_OFFSET  0x160
+#define MPU_MAILBOX_DB_RDY_MASK        0x1     /* bit 0 */
+#define MPU_MAILBOX_DB_HI_MASK 0x2     /* bit 1 */
+
+#define MPU_EP_CONTROL                 0
+
+/********** MPU semphore ******************/
+#define MPU_EP_SEMAPHORE_OFFSET        0xac
+#define EP_SEMAPHORE_POST_STAGE_MASK   0x0000FFFF
+#define EP_SEMAPHORE_POST_ERR_MASK     0x1
+#define EP_SEMAPHORE_POST_ERR_SHIFT    31
+/* MPU semphore POST stage values */
+#define POST_STAGE_AWAITING_HOST_RDY   0x1 /* FW awaiting goahead from host */
+#define POST_STAGE_HOST_RDY            0x2 /* Host has given go-ahed to FW */
+#define POST_STAGE_BE_RESET            0x3 /* Host wants to reset chip */
+#define POST_STAGE_ARMFW_RDY           0xc000  /* FW is done with POST */
+
+/********* Memory BAR register ************/
+#define PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET     0xfc
+/* Host Interrupt Enable, if set interrupts are enabled although "PCI Interrupt
+ * Disable" may still globally block interrupts in addition to individual
+ * interrupt masks; a mechanism for the device driver to block all interrupts
+ * atomically without having to arbitrate for the PCI Interrupt Disable bit
+ * with the OS.
+ */
+#define MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK     (1 << 29) /* bit 29 */
+/* PCI physical function number */
+#define MEMBAR_CTRL_INT_CTRL_PFUNC_MASK        0x7     /* bits 26 - 28 */
+#define MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT       26
+
+/********* Event Q door bell *************/
+#define DB_EQ_OFFSET                   DB_CQ_OFFSET
+#define DB_EQ_RING_ID_MASK             0x1FF   /* bits 0 - 8 */
+/* Clear the interrupt for this eq */
+#define DB_EQ_CLR_SHIFT                        (9)     /* bit 9 */
+/* Must be 1 */
+#define DB_EQ_EVNT_SHIFT                       (10)    /* bit 10 */
+/* Number of event entries processed */
+#define DB_EQ_NUM_POPPED_SHIFT         (16)    /* bits 16 - 28 */
+/* Rearm bit */
+#define DB_EQ_REARM_SHIFT              (29)    /* bit 29 */
+
+/********* Compl Q door bell *************/
+#define DB_CQ_OFFSET                   0x120
+#define DB_CQ_RING_ID_MASK             0x3FF   /* bits 0 - 9 */
+/* Number of event entries processed */
+#define DB_CQ_NUM_POPPED_SHIFT         (16)    /* bits 16 - 28 */
+/* Rearm bit */
+#define DB_CQ_REARM_SHIFT              (29)    /* bit 29 */
+
+/********** TX ULP door bell *************/
+#define DB_TXULP1_OFFSET               0x60
+#define DB_TXULP_RING_ID_MASK          0x7FF   /* bits 0 - 10 */
+/* Number of tx entries posted */
+#define DB_TXULP_NUM_POSTED_SHIFT      (16)    /* bits 16 - 29 */
+#define DB_TXULP_NUM_POSTED_MASK       0x3FFF  /* bits 16 - 29 */
+
+/********** RQ(erx) door bell ************/
+#define DB_RQ_OFFSET                   0x100
+#define DB_RQ_RING_ID_MASK             0x3FF   /* bits 0 - 9 */
+/* Number of rx frags posted */
+#define DB_RQ_NUM_POSTED_SHIFT         (24)    /* bits 24 - 31 */
+
+/*
+ * BE descriptors: host memory data structures whose formats
+ * are hardwired in BE silicon.
+ */
+/* Event Queue Descriptor */
+#define EQ_ENTRY_VALID_MASK            0x1     /* bit 0 */
+#define EQ_ENTRY_RES_ID_MASK           0xFFFF  /* bits 16 - 31 */
+#define EQ_ENTRY_RES_ID_SHIFT          16
+struct be_eq_entry {
+       u32 evt;
+};
+
+/* TX Queue Descriptor */
+#define ETH_WRB_FRAG_LEN_MASK          0xFFFF
+struct be_eth_wrb {
+       u32 frag_pa_hi;         /* dword 0 */
+       u32 frag_pa_lo;         /* dword 1 */
+       u32 rsvd0;              /* dword 2 */
+       u32 frag_len;           /* dword 3: bits 0 - 15 */
+} __packed;
+
+/* Pseudo amap definition for eth_hdr_wrb in which each bit of the
+ * actual structure is defined as a byte : used to calculate
+ * offset/shift/mask of each field */
+struct amap_eth_hdr_wrb {
+       u8 rsvd0[32];           /* dword 0 */
+       u8 rsvd1[32];           /* dword 1 */
+       u8 complete;            /* dword 2 */
+       u8 event;
+       u8 crc;
+       u8 forward;
+       u8 ipsec;
+       u8 mgmt;
+       u8 ipcs;
+       u8 udpcs;
+       u8 tcpcs;
+       u8 lso;
+       u8 vlan;
+       u8 gso[2];
+       u8 num_wrb[5];
+       u8 lso_mss[14];
+       u8 len[16];             /* dword 3 */
+       u8 vlan_tag[16];
+} __packed;
+
+struct be_eth_hdr_wrb {
+       u32 dw[4];
+};
+
+/* TX Compl Queue Descriptor */
+
+/* Pseudo amap definition for eth_tx_compl in which each bit of the
+ * actual structure is defined as a byte: used to calculate
+ * offset/shift/mask of each field */
+struct amap_eth_tx_compl {
+       u8 wrb_index[16];       /* dword 0 */
+       u8 ct[2];               /* dword 0 */
+       u8 port[2];             /* dword 0 */
+       u8 rsvd0[8];            /* dword 0 */
+       u8 status[4];           /* dword 0 */
+       u8 user_bytes[16];      /* dword 1 */
+       u8 nwh_bytes[8];        /* dword 1 */
+       u8 lso;                 /* dword 1 */
+       u8 cast_enc[2];         /* dword 1 */
+       u8 rsvd1[5];            /* dword 1 */
+       u8 rsvd2[32];           /* dword 2 */
+       u8 pkts[16];            /* dword 3 */
+       u8 ringid[11];          /* dword 3 */
+       u8 hash_val[4];         /* dword 3 */
+       u8 valid;               /* dword 3 */
+} __packed;
+
+struct be_eth_tx_compl {
+       u32 dw[4];
+};
+
+/* RX Queue Descriptor */
+struct be_eth_rx_d {
+       u32 fragpa_hi;
+       u32 fragpa_lo;
+};
+
+/* RX Compl Queue Descriptor */
+
+/* Pseudo amap definition for eth_rx_compl in which each bit of the
+ * actual structure is defined as a byte: used to calculate
+ * offset/shift/mask of each field */
+struct amap_eth_rx_compl {
+       u8 vlan_tag[16];        /* dword 0 */
+       u8 pktsize[14];         /* dword 0 */
+       u8 port;                /* dword 0 */
+       u8 ip_opt;              /* dword 0 */
+       u8 err;                 /* dword 1 */
+       u8 rsshp;               /* dword 1 */
+       u8 ipf;                 /* dword 1 */
+       u8 tcpf;                /* dword 1 */
+       u8 udpf;                /* dword 1 */
+       u8 ipcksm;              /* dword 1 */
+       u8 l4_cksm;             /* dword 1 */
+       u8 ip_version;          /* dword 1 */
+       u8 macdst[6];           /* dword 1 */
+       u8 vtp;                 /* dword 1 */
+       u8 rsvd0;               /* dword 1 */
+       u8 fragndx[10];         /* dword 1 */
+       u8 ct[2];               /* dword 1 */
+       u8 sw;                  /* dword 1 */
+       u8 numfrags[3];         /* dword 1 */
+       u8 rss_flush;           /* dword 2 */
+       u8 cast_enc[2];         /* dword 2 */
+       u8 qnq;                 /* dword 2 */
+       u8 rss_bank;            /* dword 2 */
+       u8 rsvd1[23];           /* dword 2 */
+       u8 lro_pkt;             /* dword 2 */
+       u8 rsvd2[2];            /* dword 2 */
+       u8 valid;               /* dword 2 */
+       u8 rsshash[32];         /* dword 3 */
+} __packed;
+
+struct be_eth_rx_compl {
+       u32 dw[4];
+};
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c
new file mode 100644 (file)
index 0000000..0ecaffb
--- /dev/null
@@ -0,0 +1,1911 @@
+/*
+ * Copyright (C) 2005 - 2009 ServerEngines
+ * All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License version 2
+ * as published by the Free Software Foundation.  The full GNU General
+ * Public License is included in this distribution in the file called COPYING.
+ *
+ * Contact Information:
+ * linux-drivers@serverengines.com
+ *
+ * ServerEngines
+ * 209 N. Fair Oaks Ave
+ * Sunnyvale, CA 94085
+ */
+
+#include "be.h"
+
+MODULE_VERSION(DRV_VER);
+MODULE_DEVICE_TABLE(pci, be_dev_ids);
+MODULE_DESCRIPTION(DRV_DESC " " DRV_VER);
+MODULE_AUTHOR("ServerEngines Corporation");
+MODULE_LICENSE("GPL");
+
+static unsigned int rx_frag_size = 2048;
+module_param(rx_frag_size, uint, S_IRUGO);
+MODULE_PARM_DESC(rx_frag_size, "Size of a fragment that holds rcvd data.");
+
+#define BE_VENDOR_ID           0x19a2
+#define BE2_DEVICE_ID_1        0x0211
+static DEFINE_PCI_DEVICE_TABLE(be_dev_ids) = {
+       { PCI_DEVICE(BE_VENDOR_ID, BE2_DEVICE_ID_1) },
+       { 0 }
+};
+MODULE_DEVICE_TABLE(pci, be_dev_ids);
+
+static void be_queue_free(struct be_adapter *adapter, struct be_queue_info *q)
+{
+       struct be_dma_mem *mem = &q->dma_mem;
+       if (mem->va)
+               pci_free_consistent(adapter->pdev, mem->size,
+                       mem->va, mem->dma);
+}
+
+static int be_queue_alloc(struct be_adapter *adapter, struct be_queue_info *q,
+               u16 len, u16 entry_size)
+{
+       struct be_dma_mem *mem = &q->dma_mem;
+
+       memset(q, 0, sizeof(*q));
+       q->len = len;
+       q->entry_size = entry_size;
+       mem->size = len * entry_size;
+       mem->va = pci_alloc_consistent(adapter->pdev, mem->size, &mem->dma);
+       if (!mem->va)
+               return -1;
+       memset(mem->va, 0, mem->size);
+       return 0;
+}
+
+static inline void *queue_head_node(struct be_queue_info *q)
+{
+       return q->dma_mem.va + q->head * q->entry_size;
+}
+
+static inline void *queue_tail_node(struct be_queue_info *q)
+{
+       return q->dma_mem.va + q->tail * q->entry_size;
+}
+
+static inline void queue_head_inc(struct be_queue_info *q)
+{
+       index_inc(&q->head, q->len);
+}
+
+static inline void queue_tail_inc(struct be_queue_info *q)
+{
+       index_inc(&q->tail, q->len);
+}
+
+static void be_intr_set(struct be_ctrl_info *ctrl, bool enable)
+{
+       u8 __iomem *addr = ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET;
+       u32 reg = ioread32(addr);
+       u32 enabled = reg & MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
+       if (!enabled && enable) {
+               reg |= MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
+       } else if (enabled && !enable) {
+               reg &= ~MEMBAR_CTRL_INT_CTRL_HOSTINTR_MASK;
+       } else {
+               printk(KERN_WARNING DRV_NAME
+                       ": bad value in membar_int_ctrl reg=0x%x\n", reg);
+               return;
+       }
+       iowrite32(reg, addr);
+}
+
+static void be_rxq_notify(struct be_ctrl_info *ctrl, u16 qid, u16 posted)
+{
+       u32 val = 0;
+       val |= qid & DB_RQ_RING_ID_MASK;
+       val |= posted << DB_RQ_NUM_POSTED_SHIFT;
+       iowrite32(val, ctrl->db + DB_RQ_OFFSET);
+}
+
+static void be_txq_notify(struct be_ctrl_info *ctrl, u16 qid, u16 posted)
+{
+       u32 val = 0;
+       val |= qid & DB_TXULP_RING_ID_MASK;
+       val |= (posted & DB_TXULP_NUM_POSTED_MASK) << DB_TXULP_NUM_POSTED_SHIFT;
+       iowrite32(val, ctrl->db + DB_TXULP1_OFFSET);
+}
+
+static void be_eq_notify(struct be_ctrl_info *ctrl, u16 qid,
+               bool arm, bool clear_int, u16 num_popped)
+{
+       u32 val = 0;
+       val |= qid & DB_EQ_RING_ID_MASK;
+       if (arm)
+               val |= 1 << DB_EQ_REARM_SHIFT;
+       if (clear_int)
+               val |= 1 << DB_EQ_CLR_SHIFT;
+       val |= 1 << DB_EQ_EVNT_SHIFT;
+       val |= num_popped << DB_EQ_NUM_POPPED_SHIFT;
+       iowrite32(val, ctrl->db + DB_EQ_OFFSET);
+}
+
+static void be_cq_notify(struct be_ctrl_info *ctrl, u16 qid,
+               bool arm, u16 num_popped)
+{
+       u32 val = 0;
+       val |= qid & DB_CQ_RING_ID_MASK;
+       if (arm)
+               val |= 1 << DB_CQ_REARM_SHIFT;
+       val |= num_popped << DB_CQ_NUM_POPPED_SHIFT;
+       iowrite32(val, ctrl->db + DB_CQ_OFFSET);
+}
+
+
+static int be_mac_addr_set(struct net_device *netdev, void *p)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       struct sockaddr *addr = p;
+       int status = 0;
+
+       if (netif_running(netdev)) {
+               status = be_cmd_pmac_del(&adapter->ctrl, adapter->if_handle,
+                               adapter->pmac_id);
+               if (status)
+                       return status;
+
+               status = be_cmd_pmac_add(&adapter->ctrl, (u8 *)addr->sa_data,
+                               adapter->if_handle, &adapter->pmac_id);
+       }
+
+       if (!status)
+               memcpy(netdev->dev_addr, addr->sa_data, netdev->addr_len);
+
+       return status;
+}
+
+static void netdev_stats_update(struct be_adapter *adapter)
+{
+       struct be_hw_stats *hw_stats = hw_stats_from_cmd(adapter->stats.cmd.va);
+       struct be_rxf_stats *rxf_stats = &hw_stats->rxf;
+       struct be_port_rxf_stats *port_stats =
+                       &rxf_stats->port[adapter->port_num];
+       struct net_device_stats *dev_stats = &adapter->stats.net_stats;
+
+       dev_stats->rx_packets = port_stats->rx_total_frames;
+       dev_stats->tx_packets = port_stats->tx_unicastframes +
+               port_stats->tx_multicastframes + port_stats->tx_broadcastframes;
+       dev_stats->rx_bytes = (u64) port_stats->rx_bytes_msd << 32 |
+                               (u64) port_stats->rx_bytes_lsd;
+       dev_stats->tx_bytes = (u64) port_stats->tx_bytes_msd << 32 |
+                               (u64) port_stats->tx_bytes_lsd;
+
+       /* bad pkts received */
+       dev_stats->rx_errors = port_stats->rx_crc_errors +
+               port_stats->rx_alignment_symbol_errors +
+               port_stats->rx_in_range_errors +
+               port_stats->rx_out_range_errors + port_stats->rx_frame_too_long;
+
+       /*  packet transmit problems */
+       dev_stats->tx_errors = 0;
+
+       /*  no space in linux buffers */
+       dev_stats->rx_dropped = 0;
+
+       /* no space available in linux */
+       dev_stats->tx_dropped = 0;
+
+       dev_stats->multicast = port_stats->tx_multicastframes;
+       dev_stats->collisions = 0;
+
+       /* detailed rx errors */
+       dev_stats->rx_length_errors = port_stats->rx_in_range_errors +
+               port_stats->rx_out_range_errors + port_stats->rx_frame_too_long;
+       /* receive ring buffer overflow */
+       dev_stats->rx_over_errors = 0;
+       dev_stats->rx_crc_errors = port_stats->rx_crc_errors;
+
+       /* frame alignment errors */
+       dev_stats->rx_frame_errors = port_stats->rx_alignment_symbol_errors;
+       /* receiver fifo overrun */
+       /* drops_no_pbuf is no per i/f, it's per BE card */
+       dev_stats->rx_fifo_errors = port_stats->rx_fifo_overflow +
+                                       port_stats->rx_input_fifo_overflow +
+                                       rxf_stats->rx_drops_no_pbuf;
+       /* receiver missed packetd */
+       dev_stats->rx_missed_errors = 0;
+       /* detailed tx_errors */
+       dev_stats->tx_aborted_errors = 0;
+       dev_stats->tx_carrier_errors = 0;
+       dev_stats->tx_fifo_errors = 0;
+       dev_stats->tx_heartbeat_errors = 0;
+       dev_stats->tx_window_errors = 0;
+}
+
+static void be_link_status_update(struct be_adapter *adapter)
+{
+       struct be_link_info *prev = &adapter->link;
+       struct be_link_info now = { 0 };
+       struct net_device *netdev = adapter->netdev;
+
+       be_cmd_link_status_query(&adapter->ctrl, &now);
+
+       /* If link came up or went down */
+       if (now.speed != prev->speed && (now.speed == PHY_LINK_SPEED_ZERO ||
+                       prev->speed == PHY_LINK_SPEED_ZERO)) {
+               if (now.speed == PHY_LINK_SPEED_ZERO) {
+                       netif_stop_queue(netdev);
+                       netif_carrier_off(netdev);
+                       printk(KERN_INFO "%s: Link down\n", netdev->name);
+               } else {
+                       netif_start_queue(netdev);
+                       netif_carrier_on(netdev);
+                       printk(KERN_INFO "%s: Link up\n", netdev->name);
+               }
+       }
+       *prev = now;
+}
+
+/* Update the EQ delay n BE based on the RX frags consumed / sec */
+static void be_rx_eqd_update(struct be_adapter *adapter)
+{
+       u32 eqd;
+       struct be_ctrl_info *ctrl = &adapter->ctrl;
+       struct be_eq_obj *rx_eq = &adapter->rx_eq;
+       struct be_drvr_stats *stats = &adapter->stats.drvr_stats;
+
+       /* Update once a second */
+       if (((jiffies - stats->rx_fps_jiffies) < HZ) || rx_eq->enable_aic == 0)
+               return;
+
+       stats->be_rx_fps = (stats->be_rx_frags - stats->be_prev_rx_frags) /
+                       ((jiffies - stats->rx_fps_jiffies) / HZ);
+
+       stats->rx_fps_jiffies = jiffies;
+       stats->be_prev_rx_frags = stats->be_rx_frags;
+       eqd = stats->be_rx_fps / 110000;
+       eqd = eqd << 3;
+       if (eqd > rx_eq->max_eqd)
+               eqd = rx_eq->max_eqd;
+       if (eqd < rx_eq->min_eqd)
+               eqd = rx_eq->min_eqd;
+       if (eqd < 10)
+               eqd = 0;
+       if (eqd != rx_eq->cur_eqd)
+               be_cmd_modify_eqd(ctrl, rx_eq->q.id, eqd);
+
+       rx_eq->cur_eqd = eqd;
+}
+
+static struct net_device_stats *be_get_stats(struct net_device *dev)
+{
+       struct be_adapter *adapter = netdev_priv(dev);
+
+       return &adapter->stats.net_stats;
+}
+
+static void be_tx_stats_update(struct be_adapter *adapter,
+                       u32 wrb_cnt, u32 copied, bool stopped)
+{
+       struct be_drvr_stats *stats = &adapter->stats.drvr_stats;
+       stats->be_tx_reqs++;
+       stats->be_tx_wrbs += wrb_cnt;
+       stats->be_tx_bytes += copied;
+       if (stopped)
+               stats->be_tx_stops++;
+
+       /* Update tx rate once in two seconds */
+       if ((jiffies - stats->be_tx_jiffies) > 2 * HZ) {
+               u32 r;
+               r = (stats->be_tx_bytes - stats->be_tx_bytes_prev) /
+                       ((u32) (jiffies - stats->be_tx_jiffies) / HZ);
+               r = (r / 1000000);                      /* M bytes/s */
+               stats->be_tx_rate = (r * 8);    /* M bits/s */
+               stats->be_tx_jiffies = jiffies;
+               stats->be_tx_bytes_prev = stats->be_tx_bytes;
+       }
+}
+
+/* Determine number of WRB entries needed to xmit data in an skb */
+static u32 wrb_cnt_for_skb(struct sk_buff *skb, bool *dummy)
+{
+       int cnt = 0;
+       while (skb) {
+               if (skb->len > skb->data_len)
+                       cnt++;
+               cnt += skb_shinfo(skb)->nr_frags;
+               skb = skb_shinfo(skb)->frag_list;
+       }
+       /* to account for hdr wrb */
+       cnt++;
+       if (cnt & 1) {
+               /* add a dummy to make it an even num */
+               cnt++;
+               *dummy = true;
+       } else
+               *dummy = false;
+       BUG_ON(cnt > BE_MAX_TX_FRAG_COUNT);
+       return cnt;
+}
+
+static inline void wrb_fill(struct be_eth_wrb *wrb, u64 addr, int len)
+{
+       wrb->frag_pa_hi = upper_32_bits(addr);
+       wrb->frag_pa_lo = addr & 0xFFFFFFFF;
+       wrb->frag_len = len & ETH_WRB_FRAG_LEN_MASK;
+}
+
+static void wrb_fill_hdr(struct be_eth_hdr_wrb *hdr, struct sk_buff *skb,
+               bool vlan, u32 wrb_cnt, u32 len)
+{
+       memset(hdr, 0, sizeof(*hdr));
+
+       AMAP_SET_BITS(struct amap_eth_hdr_wrb, crc, hdr, 1);
+
+       if (skb_shinfo(skb)->gso_segs > 1 && skb_shinfo(skb)->gso_size) {
+               AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso, hdr, 1);
+               AMAP_SET_BITS(struct amap_eth_hdr_wrb, lso_mss,
+                       hdr, skb_shinfo(skb)->gso_size);
+       } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+               if (is_tcp_pkt(skb))
+                       AMAP_SET_BITS(struct amap_eth_hdr_wrb, tcpcs, hdr, 1);
+               else if (is_udp_pkt(skb))
+                       AMAP_SET_BITS(struct amap_eth_hdr_wrb, udpcs, hdr, 1);
+       }
+
+       if (vlan && vlan_tx_tag_present(skb)) {
+               AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan, hdr, 1);
+               AMAP_SET_BITS(struct amap_eth_hdr_wrb, vlan_tag,
+                       hdr, vlan_tx_tag_get(skb));
+       }
+
+       AMAP_SET_BITS(struct amap_eth_hdr_wrb, event, hdr, 1);
+       AMAP_SET_BITS(struct amap_eth_hdr_wrb, complete, hdr, 1);
+       AMAP_SET_BITS(struct amap_eth_hdr_wrb, num_wrb, hdr, wrb_cnt);
+       AMAP_SET_BITS(struct amap_eth_hdr_wrb, len, hdr, len);
+}
+
+
+static int make_tx_wrbs(struct be_adapter *adapter,
+               struct sk_buff *skb, u32 wrb_cnt, bool dummy_wrb)
+{
+       u64 busaddr;
+       u32 i, copied = 0;
+       struct pci_dev *pdev = adapter->pdev;
+       struct sk_buff *first_skb = skb;
+       struct be_queue_info *txq = &adapter->tx_obj.q;
+       struct be_eth_wrb *wrb;
+       struct be_eth_hdr_wrb *hdr;
+
+       atomic_add(wrb_cnt, &txq->used);
+       hdr = queue_head_node(txq);
+       queue_head_inc(txq);
+
+       while (skb) {
+               if (skb->len > skb->data_len) {
+                       int len = skb->len - skb->data_len;
+                       busaddr = pci_map_single(pdev, skb->data, len,
+                                       PCI_DMA_TODEVICE);
+                       wrb = queue_head_node(txq);
+                       wrb_fill(wrb, busaddr, len);
+                       be_dws_cpu_to_le(wrb, sizeof(*wrb));
+                       queue_head_inc(txq);
+                       copied += len;
+               }
+
+               for (i = 0; i < skb_shinfo(skb)->nr_frags; i++) {
+                       struct skb_frag_struct *frag =
+                               &skb_shinfo(skb)->frags[i];
+                       busaddr = pci_map_page(pdev, frag->page,
+                                       frag->page_offset,
+                                       frag->size, PCI_DMA_TODEVICE);
+                       wrb = queue_head_node(txq);
+                       wrb_fill(wrb, busaddr, frag->size);
+                       be_dws_cpu_to_le(wrb, sizeof(*wrb));
+                       queue_head_inc(txq);
+                       copied += frag->size;
+               }
+               skb = skb_shinfo(skb)->frag_list;
+       }
+
+       if (dummy_wrb) {
+               wrb = queue_head_node(txq);
+               wrb_fill(wrb, 0, 0);
+               be_dws_cpu_to_le(wrb, sizeof(*wrb));
+               queue_head_inc(txq);
+       }
+
+       wrb_fill_hdr(hdr, first_skb, adapter->vlan_grp ? true : false,
+               wrb_cnt, copied);
+       be_dws_cpu_to_le(hdr, sizeof(*hdr));
+
+       return copied;
+}
+
+static int be_xmit(struct sk_buff *skb, struct net_device *netdev)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       struct be_tx_obj *tx_obj = &adapter->tx_obj;
+       struct be_queue_info *txq = &tx_obj->q;
+       u32 wrb_cnt = 0, copied = 0;
+       u32 start = txq->head;
+       bool dummy_wrb, stopped = false;
+
+       wrb_cnt = wrb_cnt_for_skb(skb, &dummy_wrb);
+
+       copied = make_tx_wrbs(adapter, skb, wrb_cnt, dummy_wrb);
+
+       /* record the sent skb in the sent_skb table */
+       BUG_ON(tx_obj->sent_skb_list[start]);
+       tx_obj->sent_skb_list[start] = skb;
+
+       /* Ensure that txq has space for the next skb; Else stop the queue
+        * *BEFORE* ringing the tx doorbell, so that we serialze the
+        * tx compls of the current transmit which'll wake up the queue
+        */
+       if ((BE_MAX_TX_FRAG_COUNT + atomic_read(&txq->used)) >= txq->len) {
+               netif_stop_queue(netdev);
+               stopped = true;
+       }
+
+       be_txq_notify(&adapter->ctrl, txq->id, wrb_cnt);
+
+       netdev->trans_start = jiffies;
+
+       be_tx_stats_update(adapter, wrb_cnt, copied, stopped);
+       return NETDEV_TX_OK;
+}
+
+static int be_change_mtu(struct net_device *netdev, int new_mtu)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       if (new_mtu < BE_MIN_MTU ||
+                       new_mtu > BE_MAX_JUMBO_FRAME_SIZE) {
+               dev_info(&adapter->pdev->dev,
+                       "MTU must be between %d and %d bytes\n",
+                       BE_MIN_MTU, BE_MAX_JUMBO_FRAME_SIZE);
+               return -EINVAL;
+       }
+       dev_info(&adapter->pdev->dev, "MTU changed from %d to %d bytes\n",
+                       netdev->mtu, new_mtu);
+       netdev->mtu = new_mtu;
+       return 0;
+}
+
+/*
+ * if there are BE_NUM_VLANS_SUPPORTED or lesser number of VLANS configured,
+ * program them in BE.  If more than BE_NUM_VLANS_SUPPORTED are configured,
+ * set the BE in promiscuous VLAN mode.
+ */
+static void be_vid_config(struct net_device *netdev)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       u16 vtag[BE_NUM_VLANS_SUPPORTED];
+       u16 ntags = 0, i;
+
+       if (adapter->num_vlans <= BE_NUM_VLANS_SUPPORTED)  {
+               /* Construct VLAN Table to give to HW */
+               for (i = 0; i < VLAN_GROUP_ARRAY_LEN; i++) {
+                       if (adapter->vlan_tag[i]) {
+                               vtag[ntags] = cpu_to_le16(i);
+                               ntags++;
+                       }
+               }
+               be_cmd_vlan_config(&adapter->ctrl, adapter->if_handle,
+                       vtag, ntags, 1, 0);
+       } else {
+               be_cmd_vlan_config(&adapter->ctrl, adapter->if_handle,
+                       NULL, 0, 1, 1);
+       }
+}
+
+static void be_vlan_register(struct net_device *netdev, struct vlan_group *grp)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       struct be_eq_obj *rx_eq = &adapter->rx_eq;
+       struct be_eq_obj *tx_eq = &adapter->tx_eq;
+       struct be_ctrl_info *ctrl = &adapter->ctrl;
+
+       be_eq_notify(ctrl, rx_eq->q.id, false, false, 0);
+       be_eq_notify(ctrl, tx_eq->q.id, false, false, 0);
+       adapter->vlan_grp = grp;
+       be_eq_notify(ctrl, rx_eq->q.id, true, false, 0);
+       be_eq_notify(ctrl, tx_eq->q.id, true, false, 0);
+}
+
+static void be_vlan_add_vid(struct net_device *netdev, u16 vid)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+
+       adapter->num_vlans++;
+       adapter->vlan_tag[vid] = 1;
+
+       be_vid_config(netdev);
+}
+
+static void be_vlan_rem_vid(struct net_device *netdev, u16 vid)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+
+       adapter->num_vlans--;
+       adapter->vlan_tag[vid] = 0;
+
+       vlan_group_set_device(adapter->vlan_grp, vid, NULL);
+       be_vid_config(netdev);
+}
+
+static void be_set_multicast_filter(struct net_device *netdev)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       struct dev_mc_list *mc_ptr;
+       u8 mac_addr[32][ETH_ALEN];
+       int i = 0;
+
+       if (netdev->flags & IFF_ALLMULTI) {
+               /* set BE in Multicast promiscuous */
+               be_cmd_mcast_mac_set(&adapter->ctrl,
+                                       adapter->if_handle, NULL, 0, true);
+               return;
+       }
+
+       for (mc_ptr = netdev->mc_list; mc_ptr; mc_ptr = mc_ptr->next) {
+               memcpy(&mac_addr[i][0], mc_ptr->dmi_addr, ETH_ALEN);
+               if (++i >= 32) {
+                       be_cmd_mcast_mac_set(&adapter->ctrl,
+                               adapter->if_handle, &mac_addr[0][0], i, false);
+                       i = 0;
+               }
+
+       }
+
+       if (i) {
+               /* reset the promiscuous mode also. */
+               be_cmd_mcast_mac_set(&adapter->ctrl,
+                       adapter->if_handle, &mac_addr[0][0], i, false);
+       }
+}
+
+static void be_set_multicast_list(struct net_device *netdev)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+
+       if (netdev->flags & IFF_PROMISC) {
+               be_cmd_promiscuous_config(&adapter->ctrl, adapter->port_num, 1);
+       } else {
+               be_cmd_promiscuous_config(&adapter->ctrl, adapter->port_num, 0);
+               be_set_multicast_filter(netdev);
+       }
+}
+
+static void be_rx_rate_update(struct be_adapter *adapter, u32 pktsize,
+                       u16 numfrags)
+{
+       struct be_drvr_stats *stats = &adapter->stats.drvr_stats;
+       u32 rate;
+
+       stats->be_rx_compl++;
+       stats->be_rx_frags += numfrags;
+       stats->be_rx_bytes += pktsize;
+
+       /* Update the rate once in two seconds */
+       if ((jiffies - stats->be_rx_jiffies) < 2 * HZ)
+               return;
+
+       rate = (stats->be_rx_bytes - stats->be_rx_bytes_prev) /
+               ((u32) (jiffies - stats->be_rx_jiffies) / HZ);
+       rate = (rate / 1000000);        /* MB/Sec */
+       stats->be_rx_rate = (rate * 8);         /* Mega Bits/Sec */
+       stats->be_rx_jiffies = jiffies;
+       stats->be_rx_bytes_prev = stats->be_rx_bytes;
+}
+
+static struct be_rx_page_info *
+get_rx_page_info(struct be_adapter *adapter, u16 frag_idx)
+{
+       struct be_rx_page_info *rx_page_info;
+       struct be_queue_info *rxq = &adapter->rx_obj.q;
+
+       rx_page_info = &adapter->rx_obj.page_info_tbl[frag_idx];
+       BUG_ON(!rx_page_info->page);
+
+       if (rx_page_info->last_page_user)
+               pci_unmap_page(adapter->pdev, pci_unmap_addr(rx_page_info, bus),
+                       adapter->big_page_size, PCI_DMA_FROMDEVICE);
+
+       atomic_dec(&rxq->used);
+       return rx_page_info;
+}
+
+/* Throwaway the data in the Rx completion */
+static void be_rx_compl_discard(struct be_adapter *adapter,
+                       struct be_eth_rx_compl *rxcp)
+{
+       struct be_queue_info *rxq = &adapter->rx_obj.q;
+       struct be_rx_page_info *page_info;
+       u16 rxq_idx, i, num_rcvd;
+
+       rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
+       num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
+
+       for (i = 0; i < num_rcvd; i++) {
+               page_info = get_rx_page_info(adapter, rxq_idx);
+               put_page(page_info->page);
+               memset(page_info, 0, sizeof(*page_info));
+               index_inc(&rxq_idx, rxq->len);
+       }
+}
+
+/*
+ * skb_fill_rx_data forms a complete skb for an ether frame
+ * indicated by rxcp.
+ */
+static void skb_fill_rx_data(struct be_adapter *adapter,
+                       struct sk_buff *skb, struct be_eth_rx_compl *rxcp)
+{
+       struct be_queue_info *rxq = &adapter->rx_obj.q;
+       struct be_rx_page_info *page_info;
+       u16 rxq_idx, i, num_rcvd;
+       u32 pktsize, hdr_len, curr_frag_len;
+       u8 *start;
+
+       rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
+       pktsize = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp);
+       num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
+
+       page_info = get_rx_page_info(adapter, rxq_idx);
+
+       start = page_address(page_info->page) + page_info->page_offset;
+       prefetch(start);
+
+       /* Copy data in the first descriptor of this completion */
+       curr_frag_len = min(pktsize, rx_frag_size);
+
+       /* Copy the header portion into skb_data */
+       hdr_len = min((u32)BE_HDR_LEN, curr_frag_len);
+       memcpy(skb->data, start, hdr_len);
+       skb->len = curr_frag_len;
+       if (curr_frag_len <= BE_HDR_LEN) { /* tiny packet */
+               /* Complete packet has now been moved to data */
+               put_page(page_info->page);
+               skb->data_len = 0;
+               skb->tail += curr_frag_len;
+       } else {
+               skb_shinfo(skb)->nr_frags = 1;
+               skb_shinfo(skb)->frags[0].page = page_info->page;
+               skb_shinfo(skb)->frags[0].page_offset =
+                                       page_info->page_offset + hdr_len;
+               skb_shinfo(skb)->frags[0].size = curr_frag_len - hdr_len;
+               skb->data_len = curr_frag_len - hdr_len;
+               skb->tail += hdr_len;
+       }
+       memset(page_info, 0, sizeof(*page_info));
+
+       if (pktsize <= rx_frag_size) {
+               BUG_ON(num_rcvd != 1);
+               return;
+       }
+
+       /* More frags present for this completion */
+       pktsize -= curr_frag_len; /* account for above copied frag */
+       for (i = 1; i < num_rcvd; i++) {
+               index_inc(&rxq_idx, rxq->len);
+               page_info = get_rx_page_info(adapter, rxq_idx);
+
+               curr_frag_len = min(pktsize, rx_frag_size);
+
+               skb_shinfo(skb)->frags[i].page = page_info->page;
+               skb_shinfo(skb)->frags[i].page_offset = page_info->page_offset;
+               skb_shinfo(skb)->frags[i].size = curr_frag_len;
+               skb->len += curr_frag_len;
+               skb->data_len += curr_frag_len;
+               skb_shinfo(skb)->nr_frags++;
+               pktsize -= curr_frag_len;
+
+               memset(page_info, 0, sizeof(*page_info));
+       }
+
+       be_rx_rate_update(adapter, pktsize, num_rcvd);
+       return;
+}
+
+/* Process the RX completion indicated by rxcp when LRO is disabled */
+static void be_rx_compl_process(struct be_adapter *adapter,
+                       struct be_eth_rx_compl *rxcp)
+{
+       struct sk_buff *skb;
+       u32 vtp, vid;
+       int l4_cksm;
+
+       l4_cksm = AMAP_GET_BITS(struct amap_eth_rx_compl, l4_cksm, rxcp);
+       vtp = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
+
+       skb = netdev_alloc_skb(adapter->netdev, BE_HDR_LEN + NET_IP_ALIGN);
+       if (!skb) {
+               if (net_ratelimit())
+                       dev_warn(&adapter->pdev->dev, "skb alloc failed\n");
+               be_rx_compl_discard(adapter, rxcp);
+               return;
+       }
+
+       skb_reserve(skb, NET_IP_ALIGN);
+
+       skb_fill_rx_data(adapter, skb, rxcp);
+
+       if (l4_cksm && adapter->rx_csum)
+               skb->ip_summed = CHECKSUM_UNNECESSARY;
+       else
+               skb->ip_summed = CHECKSUM_NONE;
+
+       skb->truesize = skb->len + sizeof(struct sk_buff);
+       skb->protocol = eth_type_trans(skb, adapter->netdev);
+       skb->dev = adapter->netdev;
+
+       if (vtp) {
+               if (!adapter->vlan_grp || adapter->num_vlans == 0) {
+                       kfree_skb(skb);
+                       return;
+               }
+               vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
+               vid = be16_to_cpu(vid);
+               vlan_hwaccel_receive_skb(skb, adapter->vlan_grp, vid);
+       } else {
+               netif_receive_skb(skb);
+       }
+
+       adapter->netdev->last_rx = jiffies;
+
+       return;
+}
+
+/* Process the RX completion indicated by rxcp when LRO is enabled */
+static void be_rx_compl_process_lro(struct be_adapter *adapter,
+                       struct be_eth_rx_compl *rxcp)
+{
+       struct be_rx_page_info *page_info;
+       struct skb_frag_struct rx_frags[BE_MAX_FRAGS_PER_FRAME];
+       struct be_queue_info *rxq = &adapter->rx_obj.q;
+       u32 num_rcvd, pkt_size, remaining, vlanf, curr_frag_len;
+       u16 i, rxq_idx = 0, vid;
+
+       num_rcvd = AMAP_GET_BITS(struct amap_eth_rx_compl, numfrags, rxcp);
+       pkt_size = AMAP_GET_BITS(struct amap_eth_rx_compl, pktsize, rxcp);
+       vlanf = AMAP_GET_BITS(struct amap_eth_rx_compl, vtp, rxcp);
+       rxq_idx = AMAP_GET_BITS(struct amap_eth_rx_compl, fragndx, rxcp);
+
+       remaining = pkt_size;
+       for (i = 0; i < num_rcvd; i++) {
+               page_info = get_rx_page_info(adapter, rxq_idx);
+
+               curr_frag_len = min(remaining, rx_frag_size);
+
+               rx_frags[i].page = page_info->page;
+               rx_frags[i].page_offset = page_info->page_offset;
+               rx_frags[i].size = curr_frag_len;
+               remaining -= curr_frag_len;
+
+               index_inc(&rxq_idx, rxq->len);
+
+               memset(page_info, 0, sizeof(*page_info));
+       }
+
+       if (likely(!vlanf)) {
+               lro_receive_frags(&adapter->rx_obj.lro_mgr, rx_frags, pkt_size,
+                               pkt_size, NULL, 0);
+       } else {
+               vid = AMAP_GET_BITS(struct amap_eth_rx_compl, vlan_tag, rxcp);
+               vid = be16_to_cpu(vid);
+
+               if (!adapter->vlan_grp || adapter->num_vlans == 0)
+                       return;
+
+               lro_vlan_hwaccel_receive_frags(&adapter->rx_obj.lro_mgr,
+                       rx_frags, pkt_size, pkt_size, adapter->vlan_grp,
+                       vid, NULL, 0);
+       }
+
+       be_rx_rate_update(adapter, pkt_size, num_rcvd);
+       return;
+}
+
+static struct be_eth_rx_compl *be_rx_compl_get(struct be_adapter *adapter)
+{
+       struct be_eth_rx_compl *rxcp = queue_tail_node(&adapter->rx_obj.cq);
+
+       if (rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] == 0)
+               return NULL;
+
+       be_dws_le_to_cpu(rxcp, sizeof(*rxcp));
+
+       rxcp->dw[offsetof(struct amap_eth_rx_compl, valid) / 32] = 0;
+
+       queue_tail_inc(&adapter->rx_obj.cq);
+       return rxcp;
+}
+
+static inline struct page *be_alloc_pages(u32 size)
+{
+       gfp_t alloc_flags = GFP_ATOMIC;
+       u32 order = get_order(size);
+       if (order > 0)
+               alloc_flags |= __GFP_COMP;
+       return  alloc_pages(alloc_flags, order);
+}
+
+/*
+ * Allocate a page, split it to fragments of size rx_frag_size and post as
+ * receive buffers to BE
+ */
+static void be_post_rx_frags(struct be_adapter *adapter)
+{
+       struct be_rx_page_info *page_info_tbl = adapter->rx_obj.page_info_tbl;
+       struct be_rx_page_info *page_info = NULL;
+       struct be_queue_info *rxq = &adapter->rx_obj.q;
+       struct page *pagep = NULL;
+       struct be_eth_rx_d *rxd;
+       u64 page_dmaaddr = 0, frag_dmaaddr;
+       u32 posted, page_offset = 0;
+
+
+       page_info = &page_info_tbl[rxq->head];
+       for (posted = 0; posted < MAX_RX_POST && !page_info->page; posted++) {
+               if (!pagep) {
+                       pagep = be_alloc_pages(adapter->big_page_size);
+                       if (unlikely(!pagep)) {
+                               drvr_stats(adapter)->be_ethrx_post_fail++;
+                               break;
+                       }
+                       page_dmaaddr = pci_map_page(adapter->pdev, pagep, 0,
+                                               adapter->big_page_size,
+                                               PCI_DMA_FROMDEVICE);
+                       page_info->page_offset = 0;
+               } else {
+                       get_page(pagep);
+                       page_info->page_offset = page_offset + rx_frag_size;
+               }
+               page_offset = page_info->page_offset;
+               page_info->page = pagep;
+               pci_unmap_addr_set(page_info, bus, page_dmaaddr);
+               frag_dmaaddr = page_dmaaddr + page_info->page_offset;
+
+               rxd = queue_head_node(rxq);
+               rxd->fragpa_lo = cpu_to_le32(frag_dmaaddr & 0xFFFFFFFF);
+               rxd->fragpa_hi = cpu_to_le32(upper_32_bits(frag_dmaaddr));
+               queue_head_inc(rxq);
+
+               /* Any space left in the current big page for another frag? */
+               if ((page_offset + rx_frag_size + rx_frag_size) >
+                                       adapter->big_page_size) {
+                       pagep = NULL;
+                       page_info->last_page_user = true;
+               }
+               page_info = &page_info_tbl[rxq->head];
+       }
+       if (pagep)
+               page_info->last_page_user = true;
+
+       if (posted) {
+               atomic_add(posted, &rxq->used);
+               be_rxq_notify(&adapter->ctrl, rxq->id, posted);
+       } else if (atomic_read(&rxq->used) == 0) {
+               /* Let be_worker replenish when memory is available */
+               adapter->rx_post_starved = true;
+       }
+
+       return;
+}
+
+static struct be_eth_tx_compl *
+be_tx_compl_get(struct be_adapter *adapter)
+{
+       struct be_queue_info *tx_cq = &adapter->tx_obj.cq;
+       struct be_eth_tx_compl *txcp = queue_tail_node(tx_cq);
+
+       if (txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] == 0)
+               return NULL;
+
+       be_dws_le_to_cpu(txcp, sizeof(*txcp));
+
+       txcp->dw[offsetof(struct amap_eth_tx_compl, valid) / 32] = 0;
+
+       queue_tail_inc(tx_cq);
+       return txcp;
+}
+
+static void be_tx_compl_process(struct be_adapter *adapter, u16 last_index)
+{
+       struct be_queue_info *txq = &adapter->tx_obj.q;
+       struct be_eth_wrb *wrb;
+       struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list;
+       struct sk_buff *sent_skb;
+       u64 busaddr;
+       u16 cur_index, num_wrbs = 0;
+
+       cur_index = txq->tail;
+       sent_skb = sent_skbs[cur_index];
+       BUG_ON(!sent_skb);
+       sent_skbs[cur_index] = NULL;
+
+       do {
+               cur_index = txq->tail;
+               wrb = queue_tail_node(txq);
+               be_dws_le_to_cpu(wrb, sizeof(*wrb));
+               busaddr = ((u64)wrb->frag_pa_hi << 32) | (u64)wrb->frag_pa_lo;
+               if (busaddr != 0) {
+                       pci_unmap_single(adapter->pdev, busaddr,
+                               wrb->frag_len, PCI_DMA_TODEVICE);
+               }
+               num_wrbs++;
+               queue_tail_inc(txq);
+       } while (cur_index != last_index);
+
+       atomic_sub(num_wrbs, &txq->used);
+
+       kfree_skb(sent_skb);
+}
+
+static void be_rx_q_clean(struct be_adapter *adapter)
+{
+       struct be_rx_page_info *page_info;
+       struct be_queue_info *rxq = &adapter->rx_obj.q;
+       struct be_queue_info *rx_cq = &adapter->rx_obj.cq;
+       struct be_eth_rx_compl *rxcp;
+       u16 tail;
+
+       /* First cleanup pending rx completions */
+       while ((rxcp = be_rx_compl_get(adapter)) != NULL) {
+               be_rx_compl_discard(adapter, rxcp);
+               be_cq_notify(&adapter->ctrl, rx_cq->id, true, 1);
+       }
+
+       /* Then free posted rx buffer that were not used */
+       tail = (rxq->head + rxq->len - atomic_read(&rxq->used)) % rxq->len;
+       for (; tail != rxq->head; index_inc(&tail, rxq->len)) {
+               page_info = get_rx_page_info(adapter, tail);
+               put_page(page_info->page);
+               memset(page_info, 0, sizeof(*page_info));
+       }
+       BUG_ON(atomic_read(&rxq->used));
+}
+
+static void be_tx_q_clean(struct be_adapter *adapter)
+{
+       struct sk_buff **sent_skbs = adapter->tx_obj.sent_skb_list;
+       struct sk_buff *sent_skb;
+       struct be_queue_info *txq = &adapter->tx_obj.q;
+       u16 last_index;
+       bool dummy_wrb;
+
+       while (atomic_read(&txq->used)) {
+               sent_skb = sent_skbs[txq->tail];
+               last_index = txq->tail;
+               index_adv(&last_index,
+                       wrb_cnt_for_skb(sent_skb, &dummy_wrb) - 1, txq->len);
+               be_tx_compl_process(adapter, last_index);
+       }
+}
+
+static void be_tx_queues_destroy(struct be_adapter *adapter)
+{
+       struct be_queue_info *q;
+
+       q = &adapter->tx_obj.q;
+       if (q->created)
+               be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_TXQ);
+       be_queue_free(adapter, q);
+
+       q = &adapter->tx_obj.cq;
+       if (q->created)
+               be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_CQ);
+       be_queue_free(adapter, q);
+
+       /* No more tx completions can be rcvd now; clean up if there are
+        * any pending completions or pending tx requests */
+       be_tx_q_clean(adapter);
+
+       q = &adapter->tx_eq.q;
+       if (q->created)
+               be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_EQ);
+       be_queue_free(adapter, q);
+}
+
+static int be_tx_queues_create(struct be_adapter *adapter)
+{
+       struct be_queue_info *eq, *q, *cq;
+
+       adapter->tx_eq.max_eqd = 0;
+       adapter->tx_eq.min_eqd = 0;
+       adapter->tx_eq.cur_eqd = 96;
+       adapter->tx_eq.enable_aic = false;
+       /* Alloc Tx Event queue */
+       eq = &adapter->tx_eq.q;
+       if (be_queue_alloc(adapter, eq, EVNT_Q_LEN, sizeof(struct be_eq_entry)))
+               return -1;
+
+       /* Ask BE to create Tx Event queue */
+       if (be_cmd_eq_create(&adapter->ctrl, eq, adapter->tx_eq.cur_eqd))
+               goto tx_eq_free;
+       /* Alloc TX eth compl queue */
+       cq = &adapter->tx_obj.cq;
+       if (be_queue_alloc(adapter, cq, TX_CQ_LEN,
+                       sizeof(struct be_eth_tx_compl)))
+               goto tx_eq_destroy;
+
+       /* Ask BE to create Tx eth compl queue */
+       if (be_cmd_cq_create(&adapter->ctrl, cq, eq, false, false, 3))
+               goto tx_cq_free;
+
+       /* Alloc TX eth queue */
+       q = &adapter->tx_obj.q;
+       if (be_queue_alloc(adapter, q, TX_Q_LEN, sizeof(struct be_eth_wrb)))
+               goto tx_cq_destroy;
+
+       /* Ask BE to create Tx eth queue */
+       if (be_cmd_txq_create(&adapter->ctrl, q, cq))
+               goto tx_q_free;
+       return 0;
+
+tx_q_free:
+       be_queue_free(adapter, q);
+tx_cq_destroy:
+       be_cmd_q_destroy(&adapter->ctrl, cq, QTYPE_CQ);
+tx_cq_free:
+       be_queue_free(adapter, cq);
+tx_eq_destroy:
+       be_cmd_q_destroy(&adapter->ctrl, eq, QTYPE_EQ);
+tx_eq_free:
+       be_queue_free(adapter, eq);
+       return -1;
+}
+
+static void be_rx_queues_destroy(struct be_adapter *adapter)
+{
+       struct be_queue_info *q;
+
+       q = &adapter->rx_obj.q;
+       if (q->created) {
+               be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_RXQ);
+               be_rx_q_clean(adapter);
+       }
+       be_queue_free(adapter, q);
+
+       q = &adapter->rx_obj.cq;
+       if (q->created)
+               be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_CQ);
+       be_queue_free(adapter, q);
+
+       q = &adapter->rx_eq.q;
+       if (q->created)
+               be_cmd_q_destroy(&adapter->ctrl, q, QTYPE_EQ);
+       be_queue_free(adapter, q);
+}
+
+static int be_rx_queues_create(struct be_adapter *adapter)
+{
+       struct be_queue_info *eq, *q, *cq;
+       int rc;
+
+       adapter->max_rx_coal = BE_MAX_FRAGS_PER_FRAME;
+       adapter->big_page_size = (1 << get_order(rx_frag_size)) * PAGE_SIZE;
+       adapter->rx_eq.max_eqd = BE_MAX_EQD;
+       adapter->rx_eq.min_eqd = 0;
+       adapter->rx_eq.cur_eqd = 0;
+       adapter->rx_eq.enable_aic = true;
+
+       /* Alloc Rx Event queue */
+       eq = &adapter->rx_eq.q;
+       rc = be_queue_alloc(adapter, eq, EVNT_Q_LEN,
+                               sizeof(struct be_eq_entry));
+       if (rc)
+               return rc;
+
+       /* Ask BE to create Rx Event queue */
+       rc = be_cmd_eq_create(&adapter->ctrl, eq, adapter->rx_eq.cur_eqd);
+       if (rc)
+               goto rx_eq_free;
+
+       /* Alloc RX eth compl queue */
+       cq = &adapter->rx_obj.cq;
+       rc = be_queue_alloc(adapter, cq, RX_CQ_LEN,
+                       sizeof(struct be_eth_rx_compl));
+       if (rc)
+               goto rx_eq_destroy;
+
+       /* Ask BE to create Rx eth compl queue */
+       rc = be_cmd_cq_create(&adapter->ctrl, cq, eq, false, false, 3);
+       if (rc)
+               goto rx_cq_free;
+
+       /* Alloc RX eth queue */
+       q = &adapter->rx_obj.q;
+       rc = be_queue_alloc(adapter, q, RX_Q_LEN, sizeof(struct be_eth_rx_d));
+       if (rc)
+               goto rx_cq_destroy;
+
+       /* Ask BE to create Rx eth queue */
+       rc = be_cmd_rxq_create(&adapter->ctrl, q, cq->id, rx_frag_size,
+               BE_MAX_JUMBO_FRAME_SIZE, adapter->if_handle, false);
+       if (rc)
+               goto rx_q_free;
+
+       return 0;
+rx_q_free:
+       be_queue_free(adapter, q);
+rx_cq_destroy:
+       be_cmd_q_destroy(&adapter->ctrl, cq, QTYPE_CQ);
+rx_cq_free:
+       be_queue_free(adapter, cq);
+rx_eq_destroy:
+       be_cmd_q_destroy(&adapter->ctrl, eq, QTYPE_EQ);
+rx_eq_free:
+       be_queue_free(adapter, eq);
+       return rc;
+}
+static bool event_get(struct be_eq_obj *eq_obj, u16 *rid)
+{
+       struct be_eq_entry *entry = queue_tail_node(&eq_obj->q);
+       u32 evt = entry->evt;
+
+       if (!evt)
+               return false;
+
+       evt = le32_to_cpu(evt);
+       *rid = (evt >> EQ_ENTRY_RES_ID_SHIFT) & EQ_ENTRY_RES_ID_MASK;
+       entry->evt = 0;
+       queue_tail_inc(&eq_obj->q);
+       return true;
+}
+
+static int event_handle(struct be_ctrl_info *ctrl,
+                       struct be_eq_obj *eq_obj)
+{
+       u16 rid = 0, num = 0;
+
+       while (event_get(eq_obj, &rid))
+               num++;
+
+       /* We can see an interrupt and no event */
+       be_eq_notify(ctrl, eq_obj->q.id, true, true, num);
+       if (num)
+               napi_schedule(&eq_obj->napi);
+
+       return num;
+}
+
+static irqreturn_t be_intx(int irq, void *dev)
+{
+       struct be_adapter *adapter = dev;
+       struct be_ctrl_info *ctrl = &adapter->ctrl;
+       int rx, tx;
+
+       tx = event_handle(ctrl, &adapter->tx_eq);
+       rx = event_handle(ctrl, &adapter->rx_eq);
+
+       if (rx || tx)
+               return IRQ_HANDLED;
+       else
+               return IRQ_NONE;
+}
+
+static irqreturn_t be_msix_rx(int irq, void *dev)
+{
+       struct be_adapter *adapter = dev;
+
+       event_handle(&adapter->ctrl, &adapter->rx_eq);
+
+       return IRQ_HANDLED;
+}
+
+static irqreturn_t be_msix_tx(int irq, void *dev)
+{
+       struct be_adapter *adapter = dev;
+
+       event_handle(&adapter->ctrl, &adapter->tx_eq);
+
+       return IRQ_HANDLED;
+}
+
+static inline bool do_lro(struct be_adapter *adapter,
+                       struct be_eth_rx_compl *rxcp)
+{
+       int err = AMAP_GET_BITS(struct amap_eth_rx_compl, err, rxcp);
+       int tcp_frame = AMAP_GET_BITS(struct amap_eth_rx_compl, tcpf, rxcp);
+
+       if (err)
+               drvr_stats(adapter)->be_rxcp_err++;
+
+       return (!tcp_frame || err || (adapter->max_rx_coal <= 1)) ?
+               false : true;
+}
+
+int be_poll_rx(struct napi_struct *napi, int budget)
+{
+       struct be_eq_obj *rx_eq = container_of(napi, struct be_eq_obj, napi);
+       struct be_adapter *adapter =
+               container_of(rx_eq, struct be_adapter, rx_eq);
+       struct be_queue_info *rx_cq = &adapter->rx_obj.cq;
+       struct be_eth_rx_compl *rxcp;
+       u32 work_done;
+
+       for (work_done = 0; work_done < budget; work_done++) {
+               rxcp = be_rx_compl_get(adapter);
+               if (!rxcp)
+                       break;
+
+               if (do_lro(adapter, rxcp))
+                       be_rx_compl_process_lro(adapter, rxcp);
+               else
+                       be_rx_compl_process(adapter, rxcp);
+       }
+
+       lro_flush_all(&adapter->rx_obj.lro_mgr);
+
+       /* Refill the queue */
+       if (atomic_read(&adapter->rx_obj.q.used) < RX_FRAGS_REFILL_WM)
+               be_post_rx_frags(adapter);
+
+       /* All consumed */
+       if (work_done < budget) {
+               napi_complete(napi);
+               be_cq_notify(&adapter->ctrl, rx_cq->id, true, work_done);
+       } else {
+               /* More to be consumed; continue with interrupts disabled */
+               be_cq_notify(&adapter->ctrl, rx_cq->id, false, work_done);
+       }
+       return work_done;
+}
+
+/* For TX we don't honour budget; consume everything */
+int be_poll_tx(struct napi_struct *napi, int budget)
+{
+       struct be_eq_obj *tx_eq = container_of(napi, struct be_eq_obj, napi);
+       struct be_adapter *adapter =
+               container_of(tx_eq, struct be_adapter, tx_eq);
+       struct be_tx_obj *tx_obj = &adapter->tx_obj;
+       struct be_queue_info *tx_cq = &tx_obj->cq;
+       struct be_queue_info *txq = &tx_obj->q;
+       struct be_eth_tx_compl *txcp;
+       u32 num_cmpl = 0;
+       u16 end_idx;
+
+       while ((txcp = be_tx_compl_get(adapter))) {
+               end_idx = AMAP_GET_BITS(struct amap_eth_tx_compl,
+                                       wrb_index, txcp);
+               be_tx_compl_process(adapter, end_idx);
+               num_cmpl++;
+       }
+
+       /* As Tx wrbs have been freed up, wake up netdev queue if
+        * it was stopped due to lack of tx wrbs.
+        */
+       if (netif_queue_stopped(adapter->netdev) &&
+                       atomic_read(&txq->used) < txq->len / 2) {
+               netif_wake_queue(adapter->netdev);
+       }
+
+       napi_complete(napi);
+
+       be_cq_notify(&adapter->ctrl, tx_cq->id, true, num_cmpl);
+
+       drvr_stats(adapter)->be_tx_events++;
+       drvr_stats(adapter)->be_tx_compl += num_cmpl;
+
+       return 1;
+}
+
+static void be_worker(struct work_struct *work)
+{
+       struct be_adapter *adapter =
+               container_of(work, struct be_adapter, work.work);
+       int status;
+
+       /* Check link */
+       be_link_status_update(adapter);
+
+       /* Get Stats */
+       status = be_cmd_get_stats(&adapter->ctrl, &adapter->stats.cmd);
+       if (!status)
+               netdev_stats_update(adapter);
+
+       /* Set EQ delay */
+       be_rx_eqd_update(adapter);
+
+       if (adapter->rx_post_starved) {
+               adapter->rx_post_starved = false;
+               be_post_rx_frags(adapter);
+       }
+
+       schedule_delayed_work(&adapter->work, msecs_to_jiffies(1000));
+}
+
+static void be_msix_enable(struct be_adapter *adapter)
+{
+       int i, status;
+
+       for (i = 0; i < BE_NUM_MSIX_VECTORS; i++)
+               adapter->msix_entries[i].entry = i;
+
+       status = pci_enable_msix(adapter->pdev, adapter->msix_entries,
+               BE_NUM_MSIX_VECTORS);
+       if (status == 0)
+               adapter->msix_enabled = true;
+       return;
+}
+
+static inline int be_msix_vec_get(struct be_adapter *adapter, u32 eq_id)
+{
+       return adapter->msix_entries[eq_id -
+                       8 * adapter->ctrl.pci_func].vector;
+}
+
+static int be_msix_register(struct be_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct be_eq_obj *tx_eq = &adapter->tx_eq;
+       struct be_eq_obj *rx_eq = &adapter->rx_eq;
+       int status, vec;
+
+       sprintf(tx_eq->desc, "%s-tx", netdev->name);
+       vec = be_msix_vec_get(adapter, tx_eq->q.id);
+       status = request_irq(vec, be_msix_tx, 0, tx_eq->desc, adapter);
+       if (status)
+               goto err;
+
+       sprintf(rx_eq->desc, "%s-rx", netdev->name);
+       vec = be_msix_vec_get(adapter, rx_eq->q.id);
+       status = request_irq(vec, be_msix_rx, 0, rx_eq->desc, adapter);
+       if (status) { /* Free TX IRQ */
+               vec = be_msix_vec_get(adapter, tx_eq->q.id);
+               free_irq(vec, adapter);
+               goto err;
+       }
+       return 0;
+err:
+       dev_warn(&adapter->pdev->dev,
+               "MSIX Request IRQ failed - err %d\n", status);
+       pci_disable_msix(adapter->pdev);
+       adapter->msix_enabled = false;
+       return status;
+}
+
+static int be_irq_register(struct be_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       int status;
+
+       if (adapter->msix_enabled) {
+               status = be_msix_register(adapter);
+               if (status == 0)
+                       goto done;
+       }
+
+       /* INTx */
+       netdev->irq = adapter->pdev->irq;
+       status = request_irq(netdev->irq, be_intx, IRQF_SHARED, netdev->name,
+                       adapter);
+       if (status) {
+               dev_err(&adapter->pdev->dev,
+                       "INTx request IRQ failed - err %d\n", status);
+               return status;
+       }
+done:
+       adapter->isr_registered = true;
+       return 0;
+}
+
+static void be_irq_unregister(struct be_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       int vec;
+
+       if (!adapter->isr_registered)
+               return;
+
+       /* INTx */
+       if (!adapter->msix_enabled) {
+               free_irq(netdev->irq, adapter);
+               goto done;
+       }
+
+       /* MSIx */
+       vec = be_msix_vec_get(adapter, adapter->tx_eq.q.id);
+       free_irq(vec, adapter);
+       vec = be_msix_vec_get(adapter, adapter->rx_eq.q.id);
+       free_irq(vec, adapter);
+done:
+       adapter->isr_registered = false;
+       return;
+}
+
+static int be_open(struct net_device *netdev)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       struct be_ctrl_info *ctrl = &adapter->ctrl;
+       struct be_eq_obj *rx_eq = &adapter->rx_eq;
+       struct be_eq_obj *tx_eq = &adapter->tx_eq;
+       u32 if_flags;
+       int status;
+
+       if_flags = BE_IF_FLAGS_BROADCAST | BE_IF_FLAGS_PROMISCUOUS |
+               BE_IF_FLAGS_MCAST_PROMISCUOUS | BE_IF_FLAGS_UNTAGGED |
+               BE_IF_FLAGS_PASS_L3L4_ERRORS;
+       status = be_cmd_if_create(ctrl, if_flags, netdev->dev_addr,
+                       false/* pmac_invalid */, &adapter->if_handle,
+                       &adapter->pmac_id);
+       if (status != 0)
+               goto do_none;
+
+       be_vid_config(netdev);
+
+       status = be_cmd_set_flow_control(ctrl, true, true);
+       if (status != 0)
+               goto if_destroy;
+
+       status = be_tx_queues_create(adapter);
+       if (status != 0)
+               goto if_destroy;
+
+       status = be_rx_queues_create(adapter);
+       if (status != 0)
+               goto tx_qs_destroy;
+
+       /* First time posting */
+       be_post_rx_frags(adapter);
+
+       napi_enable(&rx_eq->napi);
+       napi_enable(&tx_eq->napi);
+
+       be_irq_register(adapter);
+
+       be_intr_set(ctrl, true);
+
+       /* The evt queues are created in the unarmed state; arm them */
+       be_eq_notify(ctrl, rx_eq->q.id, true, false, 0);
+       be_eq_notify(ctrl, tx_eq->q.id, true, false, 0);
+
+       /* The compl queues are created in the unarmed state; arm them */
+       be_cq_notify(ctrl, adapter->rx_obj.cq.id, true, 0);
+       be_cq_notify(ctrl, adapter->tx_obj.cq.id, true, 0);
+
+       be_link_status_update(adapter);
+
+       schedule_delayed_work(&adapter->work, msecs_to_jiffies(100));
+       return 0;
+
+tx_qs_destroy:
+       be_tx_queues_destroy(adapter);
+if_destroy:
+       be_cmd_if_destroy(ctrl, adapter->if_handle);
+do_none:
+       return status;
+}
+
+static int be_close(struct net_device *netdev)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+       struct be_ctrl_info *ctrl = &adapter->ctrl;
+       struct be_eq_obj *rx_eq = &adapter->rx_eq;
+       struct be_eq_obj *tx_eq = &adapter->tx_eq;
+       int vec;
+
+       cancel_delayed_work(&adapter->work);
+
+       netif_stop_queue(netdev);
+       netif_carrier_off(netdev);
+       adapter->link.speed = PHY_LINK_SPEED_ZERO;
+
+       be_intr_set(ctrl, false);
+
+       if (adapter->msix_enabled) {
+               vec = be_msix_vec_get(adapter, tx_eq->q.id);
+               synchronize_irq(vec);
+               vec = be_msix_vec_get(adapter, rx_eq->q.id);
+               synchronize_irq(vec);
+       } else {
+               synchronize_irq(netdev->irq);
+       }
+       be_irq_unregister(adapter);
+
+       napi_disable(&rx_eq->napi);
+       napi_disable(&tx_eq->napi);
+
+       be_rx_queues_destroy(adapter);
+       be_tx_queues_destroy(adapter);
+
+       be_cmd_if_destroy(ctrl, adapter->if_handle);
+       return 0;
+}
+
+static int be_get_frag_header(struct skb_frag_struct *frag, void **mac_hdr,
+                               void **ip_hdr, void **tcpudp_hdr,
+                               u64 *hdr_flags, void *priv)
+{
+       struct ethhdr *eh;
+       struct vlan_ethhdr *veh;
+       struct iphdr *iph;
+       u8 *va = page_address(frag->page) + frag->page_offset;
+       unsigned long ll_hlen;
+
+       prefetch(va);
+       eh = (struct ethhdr *)va;
+       *mac_hdr = eh;
+       ll_hlen = ETH_HLEN;
+       if (eh->h_proto != htons(ETH_P_IP)) {
+               if (eh->h_proto == htons(ETH_P_8021Q)) {
+                       veh = (struct vlan_ethhdr *)va;
+                       if (veh->h_vlan_encapsulated_proto != htons(ETH_P_IP))
+                               return -1;
+
+                       ll_hlen += VLAN_HLEN;
+               } else {
+                       return -1;
+               }
+       }
+       *hdr_flags = LRO_IPV4;
+       iph = (struct iphdr *)(va + ll_hlen);
+       *ip_hdr = iph;
+       if (iph->protocol != IPPROTO_TCP)
+               return -1;
+       *hdr_flags |= LRO_TCP;
+       *tcpudp_hdr = (u8 *) (*ip_hdr) + (iph->ihl << 2);
+
+       return 0;
+}
+
+static void be_lro_init(struct be_adapter *adapter, struct net_device *netdev)
+{
+       struct net_lro_mgr *lro_mgr;
+
+       lro_mgr = &adapter->rx_obj.lro_mgr;
+       lro_mgr->dev = netdev;
+       lro_mgr->features = LRO_F_NAPI;
+       lro_mgr->ip_summed = CHECKSUM_UNNECESSARY;
+       lro_mgr->ip_summed_aggr = CHECKSUM_UNNECESSARY;
+       lro_mgr->max_desc = BE_MAX_LRO_DESCRIPTORS;
+       lro_mgr->lro_arr = adapter->rx_obj.lro_desc;
+       lro_mgr->get_frag_header = be_get_frag_header;
+       lro_mgr->max_aggr = BE_MAX_FRAGS_PER_FRAME;
+}
+
+static struct net_device_ops be_netdev_ops = {
+       .ndo_open               = be_open,
+       .ndo_stop               = be_close,
+       .ndo_start_xmit         = be_xmit,
+       .ndo_get_stats          = be_get_stats,
+       .ndo_set_rx_mode        = be_set_multicast_list,
+       .ndo_set_mac_address    = be_mac_addr_set,
+       .ndo_change_mtu         = be_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_vlan_rx_register   = be_vlan_register,
+       .ndo_vlan_rx_add_vid    = be_vlan_add_vid,
+       .ndo_vlan_rx_kill_vid   = be_vlan_rem_vid,
+};
+
+static void be_netdev_init(struct net_device *netdev)
+{
+       struct be_adapter *adapter = netdev_priv(netdev);
+
+       netdev->features |= NETIF_F_SG | NETIF_F_HW_VLAN_RX | NETIF_F_TSO |
+               NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_FILTER | NETIF_F_IP_CSUM |
+               NETIF_F_IPV6_CSUM | NETIF_F_TSO6;
+
+       netdev->flags |= IFF_MULTICAST;
+
+       BE_SET_NETDEV_OPS(netdev, &be_netdev_ops);
+
+       SET_ETHTOOL_OPS(netdev, &be_ethtool_ops);
+
+       be_lro_init(adapter, netdev);
+
+       netif_napi_add(netdev, &adapter->rx_eq.napi, be_poll_rx,
+               BE_NAPI_WEIGHT);
+       netif_napi_add(netdev, &adapter->tx_eq.napi, be_poll_tx,
+               BE_NAPI_WEIGHT);
+
+       netif_carrier_off(netdev);
+       netif_stop_queue(netdev);
+}
+
+static void be_unmap_pci_bars(struct be_adapter *adapter)
+{
+       struct be_ctrl_info *ctrl = &adapter->ctrl;
+       if (ctrl->csr)
+               iounmap(ctrl->csr);
+       if (ctrl->db)
+               iounmap(ctrl->db);
+       if (ctrl->pcicfg)
+               iounmap(ctrl->pcicfg);
+}
+
+static int be_map_pci_bars(struct be_adapter *adapter)
+{
+       u8 __iomem *addr;
+
+       addr = ioremap_nocache(pci_resource_start(adapter->pdev, 2),
+                       pci_resource_len(adapter->pdev, 2));
+       if (addr == NULL)
+               return -ENOMEM;
+       adapter->ctrl.csr = addr;
+
+       addr = ioremap_nocache(pci_resource_start(adapter->pdev, 4),
+                       128 * 1024);
+       if (addr == NULL)
+               goto pci_map_err;
+       adapter->ctrl.db = addr;
+
+       addr = ioremap_nocache(pci_resource_start(adapter->pdev, 1),
+                       pci_resource_len(adapter->pdev, 1));
+       if (addr == NULL)
+               goto pci_map_err;
+       adapter->ctrl.pcicfg = addr;
+
+       return 0;
+pci_map_err:
+       be_unmap_pci_bars(adapter);
+       return -ENOMEM;
+}
+
+
+static void be_ctrl_cleanup(struct be_adapter *adapter)
+{
+       struct be_dma_mem *mem = &adapter->ctrl.mbox_mem_alloced;
+
+       be_unmap_pci_bars(adapter);
+
+       if (mem->va)
+               pci_free_consistent(adapter->pdev, mem->size,
+                       mem->va, mem->dma);
+}
+
+/* Initialize the mbox required to send cmds to BE */
+static int be_ctrl_init(struct be_adapter *adapter)
+{
+       struct be_ctrl_info *ctrl = &adapter->ctrl;
+       struct be_dma_mem *mbox_mem_alloc = &ctrl->mbox_mem_alloced;
+       struct be_dma_mem *mbox_mem_align = &ctrl->mbox_mem;
+       int status;
+       u32 val;
+
+       status = be_map_pci_bars(adapter);
+       if (status)
+               return status;
+
+       mbox_mem_alloc->size = sizeof(struct be_mcc_mailbox) + 16;
+       mbox_mem_alloc->va = pci_alloc_consistent(adapter->pdev,
+                               mbox_mem_alloc->size, &mbox_mem_alloc->dma);
+       if (!mbox_mem_alloc->va) {
+               be_unmap_pci_bars(adapter);
+               return -1;
+       }
+       mbox_mem_align->size = sizeof(struct be_mcc_mailbox);
+       mbox_mem_align->va = PTR_ALIGN(mbox_mem_alloc->va, 16);
+       mbox_mem_align->dma = PTR_ALIGN(mbox_mem_alloc->dma, 16);
+       memset(mbox_mem_align->va, 0, sizeof(struct be_mcc_mailbox));
+       spin_lock_init(&ctrl->cmd_lock);
+
+       val = ioread32(ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET);
+       ctrl->pci_func = (val >> MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT) &
+                                       MEMBAR_CTRL_INT_CTRL_PFUNC_MASK;
+       return 0;
+}
+
+static void be_stats_cleanup(struct be_adapter *adapter)
+{
+       struct be_stats_obj *stats = &adapter->stats;
+       struct be_dma_mem *cmd = &stats->cmd;
+
+       if (cmd->va)
+               pci_free_consistent(adapter->pdev, cmd->size,
+                       cmd->va, cmd->dma);
+}
+
+static int be_stats_init(struct be_adapter *adapter)
+{
+       struct be_stats_obj *stats = &adapter->stats;
+       struct be_dma_mem *cmd = &stats->cmd;
+
+       cmd->size = sizeof(struct be_cmd_req_get_stats);
+       cmd->va = pci_alloc_consistent(adapter->pdev, cmd->size, &cmd->dma);
+       if (cmd->va == NULL)
+               return -1;
+       return 0;
+}
+
+static void __devexit be_remove(struct pci_dev *pdev)
+{
+       struct be_adapter *adapter = pci_get_drvdata(pdev);
+       if (!adapter)
+               return;
+
+       unregister_netdev(adapter->netdev);
+
+       be_stats_cleanup(adapter);
+
+       be_ctrl_cleanup(adapter);
+
+       if (adapter->msix_enabled) {
+               pci_disable_msix(adapter->pdev);
+               adapter->msix_enabled = false;
+       }
+
+       pci_set_drvdata(pdev, NULL);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+
+       free_netdev(adapter->netdev);
+}
+
+static int be_hw_up(struct be_adapter *adapter)
+{
+       struct be_ctrl_info *ctrl = &adapter->ctrl;
+       int status;
+
+       status = be_cmd_POST(ctrl);
+       if (status)
+               return status;
+
+       status = be_cmd_get_fw_ver(ctrl, adapter->fw_ver);
+       if (status)
+               return status;
+
+       status = be_cmd_query_fw_cfg(ctrl, &adapter->port_num);
+       return status;
+}
+
+static int __devinit be_probe(struct pci_dev *pdev,
+                       const struct pci_device_id *pdev_id)
+{
+       int status = 0;
+       struct be_adapter *adapter;
+       struct net_device *netdev;
+       struct be_ctrl_info *ctrl;
+       u8 mac[ETH_ALEN];
+
+       status = pci_enable_device(pdev);
+       if (status)
+               goto do_none;
+
+       status = pci_request_regions(pdev, DRV_NAME);
+       if (status)
+               goto disable_dev;
+       pci_set_master(pdev);
+
+       netdev = alloc_etherdev(sizeof(struct be_adapter));
+       if (netdev == NULL) {
+               status = -ENOMEM;
+               goto rel_reg;
+       }
+       adapter = netdev_priv(netdev);
+       adapter->pdev = pdev;
+       pci_set_drvdata(pdev, adapter);
+       adapter->netdev = netdev;
+
+       be_msix_enable(adapter);
+
+       status = pci_set_dma_mask(pdev, DMA_64BIT_MASK);
+       if (!status) {
+               netdev->features |= NETIF_F_HIGHDMA;
+       } else {
+               status = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
+               if (status) {
+                       dev_err(&pdev->dev, "Could not set PCI DMA Mask\n");
+                       goto free_netdev;
+               }
+       }
+
+       ctrl = &adapter->ctrl;
+       status = be_ctrl_init(adapter);
+       if (status)
+               goto free_netdev;
+
+       status = be_stats_init(adapter);
+       if (status)
+               goto ctrl_clean;
+
+       status = be_hw_up(adapter);
+       if (status)
+               goto stats_clean;
+
+       status = be_cmd_mac_addr_query(ctrl, mac, MAC_ADDRESS_TYPE_NETWORK,
+                       true /* permanent */, 0);
+       if (status)
+               goto stats_clean;
+       memcpy(netdev->dev_addr, mac, ETH_ALEN);
+
+       INIT_DELAYED_WORK(&adapter->work, be_worker);
+       be_netdev_init(netdev);
+       SET_NETDEV_DEV(netdev, &adapter->pdev->dev);
+
+       status = register_netdev(netdev);
+       if (status != 0)
+               goto stats_clean;
+
+       dev_info(&pdev->dev, BE_NAME " port %d\n", adapter->port_num);
+       return 0;
+
+stats_clean:
+       be_stats_cleanup(adapter);
+ctrl_clean:
+       be_ctrl_cleanup(adapter);
+free_netdev:
+       free_netdev(adapter->netdev);
+rel_reg:
+       pci_release_regions(pdev);
+disable_dev:
+       pci_disable_device(pdev);
+do_none:
+       dev_warn(&pdev->dev, BE_NAME " initialization failed\n");
+       return status;
+}
+
+static int be_suspend(struct pci_dev *pdev, pm_message_t state)
+{
+       struct be_adapter *adapter = pci_get_drvdata(pdev);
+       struct net_device *netdev =  adapter->netdev;
+
+       netif_device_detach(netdev);
+       if (netif_running(netdev)) {
+               rtnl_lock();
+               be_close(netdev);
+               rtnl_unlock();
+       }
+
+       pci_save_state(pdev);
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
+       return 0;
+}
+
+static int be_resume(struct pci_dev *pdev)
+{
+       int status = 0;
+       struct be_adapter *adapter = pci_get_drvdata(pdev);
+       struct net_device *netdev =  adapter->netdev;
+
+       netif_device_detach(netdev);
+
+       status = pci_enable_device(pdev);
+       if (status)
+               return status;
+
+       pci_set_power_state(pdev, 0);
+       pci_restore_state(pdev);
+
+       if (netif_running(netdev)) {
+               rtnl_lock();
+               be_open(netdev);
+               rtnl_unlock();
+       }
+       netif_device_attach(netdev);
+       return 0;
+}
+
+static struct pci_driver be_driver = {
+       .name = DRV_NAME,
+       .id_table = be_dev_ids,
+       .probe = be_probe,
+       .remove = be_remove,
+       .suspend = be_suspend,
+       .resume = be_resume
+};
+
+static int __init be_init_module(void)
+{
+       if (rx_frag_size != 8192 && rx_frag_size != 4096
+               && rx_frag_size != 2048) {
+               printk(KERN_WARNING DRV_NAME
+                       " : Module param rx_frag_size must be 2048/4096/8192."
+                       " Using 2048\n");
+               rx_frag_size = 2048;
+       }
+       /* Ensure rx_frag_size is aligned to chache line */
+       if (SKB_DATA_ALIGN(rx_frag_size) != rx_frag_size) {
+               printk(KERN_WARNING DRV_NAME
+                       " : Bad module param rx_frag_size. Using 2048\n");
+               rx_frag_size = 2048;
+       }
+
+       return pci_register_driver(&be_driver);
+}
+module_init(be_init_module);
+
+static void __exit be_exit_module(void)
+{
+       pci_unregister_driver(&be_driver);
+}
+module_exit(be_exit_module);
index 1ab58375d0617039cfdf658d7ee8c56f0f6bbf09..44d015f70d1c8ff92b30dfb81d17efa118fb9ba4 100644 (file)
@@ -1062,7 +1062,6 @@ static int miscintcount;
 static irqreturn_t bmac_misc_intr(int irq, void *dev_id)
 {
        struct net_device *dev = (struct net_device *) dev_id;
-       struct bmac_data *bp = netdev_priv(dev);
        unsigned int status = bmread(dev, STATUS);
        if (miscintcount++ < 10) {
                XXDEBUG(("bmac_misc_intr\n"));
index 8466d351a70375b7e733d4498862086302cca349..ad446db8e1861bb5a5c2813ba14856cd490b8510 100644 (file)
@@ -57,8 +57,8 @@
 
 #define DRV_MODULE_NAME                "bnx2"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "1.9.2"
-#define DRV_MODULE_RELDATE     "Feb 11, 2009"
+#define DRV_MODULE_VERSION     "1.9.3"
+#define DRV_MODULE_RELDATE     "March 17, 2009"
 
 #define RUN_AT(x) (jiffies + (x))
 
@@ -5855,9 +5855,6 @@ bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
        for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
                msix_ent[i].entry = i;
                msix_ent[i].vector = 0;
-
-               snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i);
-               bp->irq_tbl[i].handler = bnx2_msi_1shot;
        }
 
        rc = pci_enable_msix(bp->pdev, msix_ent, BNX2_MAX_MSIX_VEC);
@@ -5866,8 +5863,11 @@ bnx2_enable_msix(struct bnx2 *bp, int msix_vecs)
 
        bp->irq_nvecs = msix_vecs;
        bp->flags |= BNX2_FLAG_USING_MSIX | BNX2_FLAG_ONE_SHOT_MSI;
-       for (i = 0; i < BNX2_MAX_MSIX_VEC; i++)
+       for (i = 0; i < BNX2_MAX_MSIX_VEC; i++) {
                bp->irq_tbl[i].vector = msix_ent[i].vector;
+               snprintf(bp->irq_tbl[i].name, len, "%s-%d", dev->name, i);
+               bp->irq_tbl[i].handler = bnx2_msi_1shot;
+       }
 }
 
 static void
index 408eae7d6cc613b8ce059c49f75d2db0b2486140..a329bee25550ded2b08b6903b889d702037464d6 100644 (file)
@@ -160,7 +160,7 @@ struct sw_rx_page {
 #define PAGES_PER_SGE                  (1 << PAGES_PER_SGE_SHIFT)
 #define SGE_PAGE_SIZE                  PAGE_SIZE
 #define SGE_PAGE_SHIFT                 PAGE_SHIFT
-#define SGE_PAGE_ALIGN(addr)           PAGE_ALIGN(addr)
+#define SGE_PAGE_ALIGN(addr)           PAGE_ALIGN((typeof(PAGE_SIZE))addr)
 
 /* SGE ring related macros */
 #define NUM_RX_SGE_PAGES               2
diff --git a/drivers/net/bnx2x_dump.h b/drivers/net/bnx2x_dump.h
new file mode 100644 (file)
index 0000000..78c6b03
--- /dev/null
@@ -0,0 +1,526 @@
+/* bnx2x_dump.h: Broadcom Everest network driver.
+ *
+ * Copyright (c) 2009 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation.
+ */
+
+
+/* This struct holds a signature to ensure the dump returned from the driver
+ * match the meta data file inserted to grc_dump.tcl
+ * The signature is time stamp, diag version and grc_dump version
+ */
+
+struct dump_sign {
+       u32 time_stamp;
+       u32 diag_ver;
+       u32 grc_dump_ver;
+};
+
+#define TSTORM_WAITP_ADDR      0x1b8a80
+#define CSTORM_WAITP_ADDR      0x238a80
+#define XSTORM_WAITP_ADDR      0x2b8a80
+#define USTORM_WAITP_ADDR      0x338a80
+#define TSTORM_CAM_MODE                0x1b1440
+
+#define RI_E1                  0x1
+#define RI_E1H                 0x2
+#define RI_ONLINE              0x100
+
+#define RI_E1_OFFLINE          (RI_E1)
+#define RI_E1_ONLINE           (RI_E1 | RI_ONLINE)
+#define RI_E1H_OFFLINE         (RI_E1H)
+#define RI_E1H_ONLINE          (RI_E1H | RI_ONLINE)
+#define RI_ALL_OFFLINE         (RI_E1 | RI_E1H)
+#define RI_ALL_ONLINE          (RI_E1 | RI_E1H | RI_ONLINE)
+
+#define MAX_TIMER_PENDING      200
+#define TIMER_SCAN_DONT_CARE   0xFF
+
+
+struct dump_hdr {
+       u32              hdr_size;      /* in dwords, excluding this field */
+       struct dump_sign dump_sign;
+       u32              xstorm_waitp;
+       u32              tstorm_waitp;
+       u32              ustorm_waitp;
+       u32              cstorm_waitp;
+       u16              info;
+       u8               idle_chk;
+       u8               reserved;
+};
+
+struct reg_addr {
+       u32 addr;
+       u32 size;
+       u16 info;
+};
+
+struct wreg_addr {
+       u32 addr;
+       u32 size;
+       u32 read_regs_count;
+       const u32 *read_regs;
+       u16 info;
+};
+
+
+#define REGS_COUNT             558
+static const struct reg_addr reg_addrs[REGS_COUNT] = {
+       { 0x2000, 341, RI_ALL_ONLINE}, { 0x2800, 103, RI_ALL_ONLINE},
+       { 0x3000, 287, RI_ALL_ONLINE}, { 0x3800, 331, RI_ALL_ONLINE},
+       { 0x8800, 6, RI_E1_ONLINE}, { 0xa000, 223, RI_ALL_ONLINE},
+       { 0xa388, 1, RI_ALL_ONLINE}, { 0xa398, 1, RI_ALL_ONLINE},
+       { 0xa39c, 7, RI_E1H_ONLINE}, { 0xa3c0, 3, RI_E1H_ONLINE},
+       { 0xa3d0, 1, RI_E1H_ONLINE}, { 0xa3d8, 1, RI_E1H_ONLINE},
+       { 0xa3e0, 1, RI_E1H_ONLINE}, { 0xa3e8, 1, RI_E1H_ONLINE},
+       { 0xa3f0, 1, RI_E1H_ONLINE}, { 0xa3f8, 1, RI_E1H_ONLINE},
+       { 0xa400, 69, RI_ALL_ONLINE}, { 0xa518, 1, RI_ALL_ONLINE},
+       { 0xa520, 1, RI_ALL_ONLINE}, { 0xa528, 1, RI_ALL_ONLINE},
+       { 0xa530, 1, RI_ALL_ONLINE}, { 0xa538, 1, RI_ALL_ONLINE},
+       { 0xa540, 1, RI_ALL_ONLINE}, { 0xa548, 1, RI_ALL_ONLINE},
+       { 0xa550, 1, RI_ALL_ONLINE}, { 0xa558, 1, RI_ALL_ONLINE},
+       { 0xa560, 1, RI_ALL_ONLINE}, { 0xa568, 1, RI_ALL_ONLINE},
+       { 0xa570, 1, RI_ALL_ONLINE}, { 0xa580, 1, RI_ALL_ONLINE},
+       { 0xa590, 1, RI_ALL_ONLINE}, { 0xa5a0, 1, RI_ALL_ONLINE},
+       { 0xa5c0, 1, RI_ALL_ONLINE}, { 0xa5e0, 1, RI_E1H_ONLINE},
+       { 0xa5e8, 1, RI_E1H_ONLINE}, { 0xa5f0, 1, RI_E1H_ONLINE},
+       { 0xa5f8, 10, RI_E1H_ONLINE}, { 0x10000, 236, RI_ALL_ONLINE},
+       { 0x103bc, 1, RI_ALL_ONLINE}, { 0x103cc, 1, RI_ALL_ONLINE},
+       { 0x103dc, 1, RI_ALL_ONLINE}, { 0x10400, 57, RI_ALL_ONLINE},
+       { 0x104e8, 2, RI_ALL_ONLINE}, { 0x104f4, 2, RI_ALL_ONLINE},
+       { 0x10500, 146, RI_ALL_ONLINE}, { 0x10750, 2, RI_ALL_ONLINE},
+       { 0x10760, 2, RI_ALL_ONLINE}, { 0x10770, 2, RI_ALL_ONLINE},
+       { 0x10780, 2, RI_ALL_ONLINE}, { 0x10790, 2, RI_ALL_ONLINE},
+       { 0x107a0, 2, RI_ALL_ONLINE}, { 0x107b0, 2, RI_ALL_ONLINE},
+       { 0x107c0, 2, RI_ALL_ONLINE}, { 0x107d0, 2, RI_ALL_ONLINE},
+       { 0x107e0, 2, RI_ALL_ONLINE}, { 0x10880, 2, RI_ALL_ONLINE},
+       { 0x10900, 2, RI_ALL_ONLINE}, { 0x12000, 1, RI_ALL_ONLINE},
+       { 0x14000, 1, RI_ALL_ONLINE}, { 0x16000, 26, RI_E1H_ONLINE},
+       { 0x16070, 18, RI_E1H_ONLINE}, { 0x160c0, 27, RI_E1H_ONLINE},
+       { 0x16140, 1, RI_E1H_ONLINE}, { 0x16160, 1, RI_E1H_ONLINE},
+       { 0x16180, 2, RI_E1H_ONLINE}, { 0x161c0, 2, RI_E1H_ONLINE},
+       { 0x16204, 5, RI_E1H_ONLINE}, { 0x18000, 1, RI_E1H_ONLINE},
+       { 0x18008, 1, RI_E1H_ONLINE}, { 0x20000, 24, RI_ALL_ONLINE},
+       { 0x20060, 8, RI_ALL_ONLINE}, { 0x20080, 138, RI_ALL_ONLINE},
+       { 0x202b4, 1, RI_ALL_ONLINE}, { 0x202c4, 1, RI_ALL_ONLINE},
+       { 0x20400, 2, RI_ALL_ONLINE}, { 0x2040c, 8, RI_ALL_ONLINE},
+       { 0x2042c, 18, RI_E1H_ONLINE}, { 0x20480, 1, RI_ALL_ONLINE},
+       { 0x20500, 1, RI_ALL_ONLINE}, { 0x20600, 1, RI_ALL_ONLINE},
+       { 0x28000, 1, RI_ALL_ONLINE}, { 0x28004, 8191, RI_ALL_OFFLINE},
+       { 0x30000, 1, RI_ALL_ONLINE}, { 0x30004, 16383, RI_ALL_OFFLINE},
+       { 0x40000, 98, RI_ALL_ONLINE}, { 0x40194, 1, RI_ALL_ONLINE},
+       { 0x401a4, 1, RI_ALL_ONLINE}, { 0x401a8, 11, RI_E1H_ONLINE},
+       { 0x40200, 4, RI_ALL_ONLINE}, { 0x40400, 43, RI_ALL_ONLINE},
+       { 0x404b8, 1, RI_ALL_ONLINE}, { 0x404c8, 1, RI_ALL_ONLINE},
+       { 0x404cc, 3, RI_E1H_ONLINE}, { 0x40500, 2, RI_ALL_ONLINE},
+       { 0x40510, 2, RI_ALL_ONLINE}, { 0x40520, 2, RI_ALL_ONLINE},
+       { 0x40530, 2, RI_ALL_ONLINE}, { 0x40540, 2, RI_ALL_ONLINE},
+       { 0x42000, 164, RI_ALL_ONLINE}, { 0x4229c, 1, RI_ALL_ONLINE},
+       { 0x422ac, 1, RI_ALL_ONLINE}, { 0x422bc, 1, RI_ALL_ONLINE},
+       { 0x422d4, 5, RI_E1H_ONLINE}, { 0x42400, 49, RI_ALL_ONLINE},
+       { 0x424c8, 38, RI_ALL_ONLINE}, { 0x42568, 2, RI_ALL_ONLINE},
+       { 0x42800, 1, RI_ALL_ONLINE}, { 0x50000, 20, RI_ALL_ONLINE},
+       { 0x50050, 8, RI_ALL_ONLINE}, { 0x50070, 88, RI_ALL_ONLINE},
+       { 0x501dc, 1, RI_ALL_ONLINE}, { 0x501ec, 1, RI_ALL_ONLINE},
+       { 0x501f0, 4, RI_E1H_ONLINE}, { 0x50200, 2, RI_ALL_ONLINE},
+       { 0x5020c, 7, RI_ALL_ONLINE}, { 0x50228, 6, RI_E1H_ONLINE},
+       { 0x50240, 1, RI_ALL_ONLINE}, { 0x50280, 1, RI_ALL_ONLINE},
+       { 0x52000, 1, RI_ALL_ONLINE}, { 0x54000, 1, RI_ALL_ONLINE},
+       { 0x54004, 3327, RI_ALL_OFFLINE}, { 0x58000, 1, RI_ALL_ONLINE},
+       { 0x58004, 8191, RI_ALL_OFFLINE}, { 0x60000, 71, RI_ALL_ONLINE},
+       { 0x60128, 1, RI_ALL_ONLINE}, { 0x60138, 1, RI_ALL_ONLINE},
+       { 0x6013c, 24, RI_E1H_ONLINE}, { 0x60200, 1, RI_ALL_ONLINE},
+       { 0x61000, 1, RI_ALL_ONLINE}, { 0x61004, 511, RI_ALL_OFFLINE},
+       { 0x70000, 8, RI_ALL_ONLINE}, { 0x70020, 21496, RI_ALL_OFFLINE},
+       { 0x85000, 3, RI_ALL_ONLINE}, { 0x8500c, 4, RI_ALL_OFFLINE},
+       { 0x8501c, 7, RI_ALL_ONLINE}, { 0x85038, 4, RI_ALL_OFFLINE},
+       { 0x85048, 1, RI_ALL_ONLINE}, { 0x8504c, 109, RI_ALL_OFFLINE},
+       { 0x85200, 32, RI_ALL_ONLINE}, { 0x85280, 11104, RI_ALL_OFFLINE},
+       { 0xa0000, 16384, RI_ALL_ONLINE}, { 0xb0000, 16384, RI_E1H_ONLINE},
+       { 0xc1000, 7, RI_ALL_ONLINE}, { 0xc1028, 1, RI_ALL_ONLINE},
+       { 0xc1038, 1, RI_ALL_ONLINE}, { 0xc1800, 2, RI_ALL_ONLINE},
+       { 0xc2000, 164, RI_ALL_ONLINE}, { 0xc229c, 1, RI_ALL_ONLINE},
+       { 0xc22ac, 1, RI_ALL_ONLINE}, { 0xc22bc, 1, RI_ALL_ONLINE},
+       { 0xc2400, 49, RI_ALL_ONLINE}, { 0xc24c8, 38, RI_ALL_ONLINE},
+       { 0xc2568, 2, RI_ALL_ONLINE}, { 0xc2600, 1, RI_ALL_ONLINE},
+       { 0xc4000, 165, RI_ALL_ONLINE}, { 0xc42a0, 1, RI_ALL_ONLINE},
+       { 0xc42b0, 1, RI_ALL_ONLINE}, { 0xc42c0, 1, RI_ALL_ONLINE},
+       { 0xc42e0, 7, RI_E1H_ONLINE}, { 0xc4400, 51, RI_ALL_ONLINE},
+       { 0xc44d0, 38, RI_ALL_ONLINE}, { 0xc4570, 2, RI_ALL_ONLINE},
+       { 0xc4600, 1, RI_ALL_ONLINE}, { 0xd0000, 19, RI_ALL_ONLINE},
+       { 0xd004c, 8, RI_ALL_ONLINE}, { 0xd006c, 91, RI_ALL_ONLINE},
+       { 0xd01e4, 1, RI_ALL_ONLINE}, { 0xd01f4, 1, RI_ALL_ONLINE},
+       { 0xd0200, 2, RI_ALL_ONLINE}, { 0xd020c, 7, RI_ALL_ONLINE},
+       { 0xd0228, 18, RI_E1H_ONLINE}, { 0xd0280, 1, RI_ALL_ONLINE},
+       { 0xd0300, 1, RI_ALL_ONLINE}, { 0xd0400, 1, RI_ALL_ONLINE},
+       { 0xd4000, 1, RI_ALL_ONLINE}, { 0xd4004, 2559, RI_ALL_OFFLINE},
+       { 0xd8000, 1, RI_ALL_ONLINE}, { 0xd8004, 8191, RI_ALL_OFFLINE},
+       { 0xe0000, 21, RI_ALL_ONLINE}, { 0xe0054, 8, RI_ALL_ONLINE},
+       { 0xe0074, 85, RI_ALL_ONLINE}, { 0xe01d4, 1, RI_ALL_ONLINE},
+       { 0xe01e4, 1, RI_ALL_ONLINE}, { 0xe0200, 2, RI_ALL_ONLINE},
+       { 0xe020c, 8, RI_ALL_ONLINE}, { 0xe022c, 18, RI_E1H_ONLINE},
+       { 0xe0280, 1, RI_ALL_ONLINE}, { 0xe0300, 1, RI_ALL_ONLINE},
+       { 0xe1000, 1, RI_ALL_ONLINE}, { 0xe2000, 1, RI_ALL_ONLINE},
+       { 0xe2004, 2047, RI_ALL_OFFLINE}, { 0xf0000, 1, RI_ALL_ONLINE},
+       { 0xf0004, 16383, RI_ALL_OFFLINE}, { 0x101000, 12, RI_ALL_ONLINE},
+       { 0x10103c, 1, RI_ALL_ONLINE}, { 0x10104c, 1, RI_ALL_ONLINE},
+       { 0x101050, 1, RI_E1H_ONLINE}, { 0x101100, 1, RI_ALL_ONLINE},
+       { 0x101800, 8, RI_ALL_ONLINE}, { 0x102000, 18, RI_ALL_ONLINE},
+       { 0x102054, 1, RI_ALL_ONLINE}, { 0x102064, 1, RI_ALL_ONLINE},
+       { 0x102080, 17, RI_ALL_ONLINE}, { 0x1020c8, 8, RI_E1H_ONLINE},
+       { 0x102400, 1, RI_ALL_ONLINE}, { 0x103000, 26, RI_ALL_ONLINE},
+       { 0x103074, 1, RI_ALL_ONLINE}, { 0x103084, 1, RI_ALL_ONLINE},
+       { 0x103094, 1, RI_ALL_ONLINE}, { 0x103098, 5, RI_E1H_ONLINE},
+       { 0x103800, 8, RI_ALL_ONLINE}, { 0x104000, 63, RI_ALL_ONLINE},
+       { 0x104108, 1, RI_ALL_ONLINE}, { 0x104118, 1, RI_ALL_ONLINE},
+       { 0x104200, 17, RI_ALL_ONLINE}, { 0x104400, 64, RI_ALL_ONLINE},
+       { 0x104500, 192, RI_ALL_OFFLINE}, { 0x104800, 64, RI_ALL_ONLINE},
+       { 0x104900, 192, RI_ALL_OFFLINE}, { 0x105000, 7, RI_ALL_ONLINE},
+       { 0x10501c, 1, RI_ALL_OFFLINE}, { 0x105020, 3, RI_ALL_ONLINE},
+       { 0x10502c, 1, RI_ALL_OFFLINE}, { 0x105030, 3, RI_ALL_ONLINE},
+       { 0x10503c, 1, RI_ALL_OFFLINE}, { 0x105040, 3, RI_ALL_ONLINE},
+       { 0x10504c, 1, RI_ALL_OFFLINE}, { 0x105050, 3, RI_ALL_ONLINE},
+       { 0x10505c, 1, RI_ALL_OFFLINE}, { 0x105060, 3, RI_ALL_ONLINE},
+       { 0x10506c, 1, RI_ALL_OFFLINE}, { 0x105070, 3, RI_ALL_ONLINE},
+       { 0x10507c, 1, RI_ALL_OFFLINE}, { 0x105080, 3, RI_ALL_ONLINE},
+       { 0x10508c, 1, RI_ALL_OFFLINE}, { 0x105090, 3, RI_ALL_ONLINE},
+       { 0x10509c, 1, RI_ALL_OFFLINE}, { 0x1050a0, 3, RI_ALL_ONLINE},
+       { 0x1050ac, 1, RI_ALL_OFFLINE}, { 0x1050b0, 3, RI_ALL_ONLINE},
+       { 0x1050bc, 1, RI_ALL_OFFLINE}, { 0x1050c0, 3, RI_ALL_ONLINE},
+       { 0x1050cc, 1, RI_ALL_OFFLINE}, { 0x1050d0, 3, RI_ALL_ONLINE},
+       { 0x1050dc, 1, RI_ALL_OFFLINE}, { 0x1050e0, 3, RI_ALL_ONLINE},
+       { 0x1050ec, 1, RI_ALL_OFFLINE}, { 0x1050f0, 3, RI_ALL_ONLINE},
+       { 0x1050fc, 1, RI_ALL_OFFLINE}, { 0x105100, 3, RI_ALL_ONLINE},
+       { 0x10510c, 1, RI_ALL_OFFLINE}, { 0x105110, 3, RI_ALL_ONLINE},
+       { 0x10511c, 1, RI_ALL_OFFLINE}, { 0x105120, 3, RI_ALL_ONLINE},
+       { 0x10512c, 1, RI_ALL_OFFLINE}, { 0x105130, 3, RI_ALL_ONLINE},
+       { 0x10513c, 1, RI_ALL_OFFLINE}, { 0x105140, 3, RI_ALL_ONLINE},
+       { 0x10514c, 1, RI_ALL_OFFLINE}, { 0x105150, 3, RI_ALL_ONLINE},
+       { 0x10515c, 1, RI_ALL_OFFLINE}, { 0x105160, 3, RI_ALL_ONLINE},
+       { 0x10516c, 1, RI_ALL_OFFLINE}, { 0x105170, 3, RI_ALL_ONLINE},
+       { 0x10517c, 1, RI_ALL_OFFLINE}, { 0x105180, 3, RI_ALL_ONLINE},
+       { 0x10518c, 1, RI_ALL_OFFLINE}, { 0x105190, 3, RI_ALL_ONLINE},
+       { 0x10519c, 1, RI_ALL_OFFLINE}, { 0x1051a0, 3, RI_ALL_ONLINE},
+       { 0x1051ac, 1, RI_ALL_OFFLINE}, { 0x1051b0, 3, RI_ALL_ONLINE},
+       { 0x1051bc, 1, RI_ALL_OFFLINE}, { 0x1051c0, 3, RI_ALL_ONLINE},
+       { 0x1051cc, 1, RI_ALL_OFFLINE}, { 0x1051d0, 3, RI_ALL_ONLINE},
+       { 0x1051dc, 1, RI_ALL_OFFLINE}, { 0x1051e0, 3, RI_ALL_ONLINE},
+       { 0x1051ec, 1, RI_ALL_OFFLINE}, { 0x1051f0, 3, RI_ALL_ONLINE},
+       { 0x1051fc, 1, RI_ALL_OFFLINE}, { 0x105200, 3, RI_ALL_ONLINE},
+       { 0x10520c, 1, RI_ALL_OFFLINE}, { 0x105210, 3, RI_ALL_ONLINE},
+       { 0x10521c, 1, RI_ALL_OFFLINE}, { 0x105220, 3, RI_ALL_ONLINE},
+       { 0x10522c, 1, RI_ALL_OFFLINE}, { 0x105230, 3, RI_ALL_ONLINE},
+       { 0x10523c, 1, RI_ALL_OFFLINE}, { 0x105240, 3, RI_ALL_ONLINE},
+       { 0x10524c, 1, RI_ALL_OFFLINE}, { 0x105250, 3, RI_ALL_ONLINE},
+       { 0x10525c, 1, RI_ALL_OFFLINE}, { 0x105260, 3, RI_ALL_ONLINE},
+       { 0x10526c, 1, RI_ALL_OFFLINE}, { 0x105270, 3, RI_ALL_ONLINE},
+       { 0x10527c, 1, RI_ALL_OFFLINE}, { 0x105280, 3, RI_ALL_ONLINE},
+       { 0x10528c, 1, RI_ALL_OFFLINE}, { 0x105290, 3, RI_ALL_ONLINE},
+       { 0x10529c, 1, RI_ALL_OFFLINE}, { 0x1052a0, 3, RI_ALL_ONLINE},
+       { 0x1052ac, 1, RI_ALL_OFFLINE}, { 0x1052b0, 3, RI_ALL_ONLINE},
+       { 0x1052bc, 1, RI_ALL_OFFLINE}, { 0x1052c0, 3, RI_ALL_ONLINE},
+       { 0x1052cc, 1, RI_ALL_OFFLINE}, { 0x1052d0, 3, RI_ALL_ONLINE},
+       { 0x1052dc, 1, RI_ALL_OFFLINE}, { 0x1052e0, 3, RI_ALL_ONLINE},
+       { 0x1052ec, 1, RI_ALL_OFFLINE}, { 0x1052f0, 3, RI_ALL_ONLINE},
+       { 0x1052fc, 1, RI_ALL_OFFLINE}, { 0x105300, 3, RI_ALL_ONLINE},
+       { 0x10530c, 1, RI_ALL_OFFLINE}, { 0x105310, 3, RI_ALL_ONLINE},
+       { 0x10531c, 1, RI_ALL_OFFLINE}, { 0x105320, 3, RI_ALL_ONLINE},
+       { 0x10532c, 1, RI_ALL_OFFLINE}, { 0x105330, 3, RI_ALL_ONLINE},
+       { 0x10533c, 1, RI_ALL_OFFLINE}, { 0x105340, 3, RI_ALL_ONLINE},
+       { 0x10534c, 1, RI_ALL_OFFLINE}, { 0x105350, 3, RI_ALL_ONLINE},
+       { 0x10535c, 1, RI_ALL_OFFLINE}, { 0x105360, 3, RI_ALL_ONLINE},
+       { 0x10536c, 1, RI_ALL_OFFLINE}, { 0x105370, 3, RI_ALL_ONLINE},
+       { 0x10537c, 1, RI_ALL_OFFLINE}, { 0x105380, 3, RI_ALL_ONLINE},
+       { 0x10538c, 1, RI_ALL_OFFLINE}, { 0x105390, 3, RI_ALL_ONLINE},
+       { 0x10539c, 1, RI_ALL_OFFLINE}, { 0x1053a0, 3, RI_ALL_ONLINE},
+       { 0x1053ac, 1, RI_ALL_OFFLINE}, { 0x1053b0, 3, RI_ALL_ONLINE},
+       { 0x1053bc, 1, RI_ALL_OFFLINE}, { 0x1053c0, 3, RI_ALL_ONLINE},
+       { 0x1053cc, 1, RI_ALL_OFFLINE}, { 0x1053d0, 3, RI_ALL_ONLINE},
+       { 0x1053dc, 1, RI_ALL_OFFLINE}, { 0x1053e0, 3, RI_ALL_ONLINE},
+       { 0x1053ec, 1, RI_ALL_OFFLINE}, { 0x1053f0, 3, RI_ALL_ONLINE},
+       { 0x1053fc, 769, RI_ALL_OFFLINE}, { 0x108000, 33, RI_ALL_ONLINE},
+       { 0x108090, 1, RI_ALL_ONLINE}, { 0x1080a0, 1, RI_ALL_ONLINE},
+       { 0x1080ac, 5, RI_E1H_ONLINE}, { 0x108100, 5, RI_ALL_ONLINE},
+       { 0x108120, 5, RI_ALL_ONLINE}, { 0x108200, 74, RI_ALL_ONLINE},
+       { 0x108400, 74, RI_ALL_ONLINE}, { 0x108800, 152, RI_ALL_ONLINE},
+       { 0x109000, 1, RI_ALL_ONLINE}, { 0x120000, 347, RI_ALL_ONLINE},
+       { 0x120578, 1, RI_ALL_ONLINE}, { 0x120588, 1, RI_ALL_ONLINE},
+       { 0x120598, 1, RI_ALL_ONLINE}, { 0x12059c, 23, RI_E1H_ONLINE},
+       { 0x120614, 1, RI_E1H_ONLINE}, { 0x12061c, 30, RI_E1H_ONLINE},
+       { 0x12080c, 65, RI_ALL_ONLINE}, { 0x120a00, 2, RI_ALL_ONLINE},
+       { 0x122000, 2, RI_ALL_ONLINE}, { 0x128000, 2, RI_E1H_ONLINE},
+       { 0x140000, 114, RI_ALL_ONLINE}, { 0x1401d4, 1, RI_ALL_ONLINE},
+       { 0x1401e4, 1, RI_ALL_ONLINE}, { 0x140200, 6, RI_ALL_ONLINE},
+       { 0x144000, 4, RI_ALL_ONLINE}, { 0x148000, 4, RI_ALL_ONLINE},
+       { 0x14c000, 4, RI_ALL_ONLINE}, { 0x150000, 4, RI_ALL_ONLINE},
+       { 0x154000, 4, RI_ALL_ONLINE}, { 0x158000, 4, RI_ALL_ONLINE},
+       { 0x15c000, 7, RI_E1H_ONLINE}, { 0x161000, 7, RI_ALL_ONLINE},
+       { 0x161028, 1, RI_ALL_ONLINE}, { 0x161038, 1, RI_ALL_ONLINE},
+       { 0x161800, 2, RI_ALL_ONLINE}, { 0x164000, 60, RI_ALL_ONLINE},
+       { 0x1640fc, 1, RI_ALL_ONLINE}, { 0x16410c, 1, RI_ALL_ONLINE},
+       { 0x164110, 2, RI_E1H_ONLINE}, { 0x164200, 1, RI_ALL_ONLINE},
+       { 0x164208, 1, RI_ALL_ONLINE}, { 0x164210, 1, RI_ALL_ONLINE},
+       { 0x164218, 1, RI_ALL_ONLINE}, { 0x164220, 1, RI_ALL_ONLINE},
+       { 0x164228, 1, RI_ALL_ONLINE}, { 0x164230, 1, RI_ALL_ONLINE},
+       { 0x164238, 1, RI_ALL_ONLINE}, { 0x164240, 1, RI_ALL_ONLINE},
+       { 0x164248, 1, RI_ALL_ONLINE}, { 0x164250, 1, RI_ALL_ONLINE},
+       { 0x164258, 1, RI_ALL_ONLINE}, { 0x164260, 1, RI_ALL_ONLINE},
+       { 0x164270, 2, RI_ALL_ONLINE}, { 0x164280, 2, RI_ALL_ONLINE},
+       { 0x164800, 2, RI_ALL_ONLINE}, { 0x165000, 2, RI_ALL_ONLINE},
+       { 0x166000, 164, RI_ALL_ONLINE}, { 0x16629c, 1, RI_ALL_ONLINE},
+       { 0x1662ac, 1, RI_ALL_ONLINE}, { 0x1662bc, 1, RI_ALL_ONLINE},
+       { 0x166400, 49, RI_ALL_ONLINE}, { 0x1664c8, 38, RI_ALL_ONLINE},
+       { 0x166568, 2, RI_ALL_ONLINE}, { 0x166800, 1, RI_ALL_ONLINE},
+       { 0x168000, 270, RI_ALL_ONLINE}, { 0x168444, 1, RI_ALL_ONLINE},
+       { 0x168454, 1, RI_ALL_ONLINE}, { 0x168800, 19, RI_ALL_ONLINE},
+       { 0x168900, 1, RI_ALL_ONLINE}, { 0x168a00, 128, RI_ALL_ONLINE},
+       { 0x16a000, 1, RI_ALL_ONLINE}, { 0x16a004, 1535, RI_ALL_OFFLINE},
+       { 0x16c000, 1, RI_ALL_ONLINE}, { 0x16c004, 1535, RI_ALL_OFFLINE},
+       { 0x16e000, 16, RI_E1H_ONLINE}, { 0x16e100, 1, RI_E1H_ONLINE},
+       { 0x16e200, 2, RI_E1H_ONLINE}, { 0x16e400, 183, RI_E1H_ONLINE},
+       { 0x170000, 93, RI_ALL_ONLINE}, { 0x170180, 1, RI_ALL_ONLINE},
+       { 0x170190, 1, RI_ALL_ONLINE}, { 0x170200, 4, RI_ALL_ONLINE},
+       { 0x170214, 1, RI_ALL_ONLINE}, { 0x178000, 1, RI_ALL_ONLINE},
+       { 0x180000, 61, RI_ALL_ONLINE}, { 0x180100, 1, RI_ALL_ONLINE},
+       { 0x180110, 1, RI_ALL_ONLINE}, { 0x180120, 1, RI_ALL_ONLINE},
+       { 0x180130, 1, RI_ALL_ONLINE}, { 0x18013c, 2, RI_E1H_ONLINE},
+       { 0x180200, 58, RI_ALL_ONLINE}, { 0x180340, 4, RI_ALL_ONLINE},
+       { 0x180400, 1, RI_ALL_ONLINE}, { 0x180404, 255, RI_ALL_OFFLINE},
+       { 0x181000, 4, RI_ALL_ONLINE}, { 0x181010, 1020, RI_ALL_OFFLINE},
+       { 0x1a0000, 1, RI_ALL_ONLINE}, { 0x1a0004, 1023, RI_ALL_OFFLINE},
+       { 0x1a1000, 1, RI_ALL_ONLINE}, { 0x1a1004, 4607, RI_ALL_OFFLINE},
+       { 0x1a5800, 2560, RI_E1H_OFFLINE}, { 0x1a8000, 64, RI_ALL_OFFLINE},
+       { 0x1a8100, 1984, RI_E1H_OFFLINE}, { 0x1aa000, 1, RI_E1H_ONLINE},
+       { 0x1aa004, 6655, RI_E1H_OFFLINE}, { 0x1b1800, 128, RI_ALL_OFFLINE},
+       { 0x1b1c00, 128, RI_ALL_OFFLINE}, { 0x1b2000, 1, RI_ALL_OFFLINE},
+       { 0x1b2400, 64, RI_E1H_OFFLINE}, { 0x1b8200, 1, RI_ALL_ONLINE},
+       { 0x1b8240, 1, RI_ALL_ONLINE}, { 0x1b8280, 1, RI_ALL_ONLINE},
+       { 0x1b82c0, 1, RI_ALL_ONLINE}, { 0x1b8a00, 1, RI_ALL_ONLINE},
+       { 0x1b8a80, 1, RI_ALL_ONLINE}, { 0x1c0000, 2, RI_ALL_ONLINE},
+       { 0x200000, 65, RI_ALL_ONLINE}, { 0x200110, 1, RI_ALL_ONLINE},
+       { 0x200120, 1, RI_ALL_ONLINE}, { 0x200130, 1, RI_ALL_ONLINE},
+       { 0x200140, 1, RI_ALL_ONLINE}, { 0x20014c, 2, RI_E1H_ONLINE},
+       { 0x200200, 58, RI_ALL_ONLINE}, { 0x200340, 4, RI_ALL_ONLINE},
+       { 0x200400, 1, RI_ALL_ONLINE}, { 0x200404, 255, RI_ALL_OFFLINE},
+       { 0x202000, 4, RI_ALL_ONLINE}, { 0x202010, 2044, RI_ALL_OFFLINE},
+       { 0x220000, 1, RI_ALL_ONLINE}, { 0x220004, 1023, RI_ALL_OFFLINE},
+       { 0x221000, 1, RI_ALL_ONLINE}, { 0x221004, 4607, RI_ALL_OFFLINE},
+       { 0x225800, 1536, RI_E1H_OFFLINE}, { 0x227000, 1, RI_E1H_ONLINE},
+       { 0x227004, 1023, RI_E1H_OFFLINE}, { 0x228000, 64, RI_ALL_OFFLINE},
+       { 0x228100, 8640, RI_E1H_OFFLINE}, { 0x231800, 128, RI_ALL_OFFLINE},
+       { 0x231c00, 128, RI_ALL_OFFLINE}, { 0x232000, 1, RI_ALL_OFFLINE},
+       { 0x232400, 64, RI_E1H_OFFLINE}, { 0x238200, 1, RI_ALL_ONLINE},
+       { 0x238240, 1, RI_ALL_ONLINE}, { 0x238280, 1, RI_ALL_ONLINE},
+       { 0x2382c0, 1, RI_ALL_ONLINE}, { 0x238a00, 1, RI_ALL_ONLINE},
+       { 0x238a80, 1, RI_ALL_ONLINE}, { 0x240000, 2, RI_ALL_ONLINE},
+       { 0x280000, 65, RI_ALL_ONLINE}, { 0x280110, 1, RI_ALL_ONLINE},
+       { 0x280120, 1, RI_ALL_ONLINE}, { 0x280130, 1, RI_ALL_ONLINE},
+       { 0x280140, 1, RI_ALL_ONLINE}, { 0x28014c, 2, RI_E1H_ONLINE},
+       { 0x280200, 58, RI_ALL_ONLINE}, { 0x280340, 4, RI_ALL_ONLINE},
+       { 0x280400, 1, RI_ALL_ONLINE}, { 0x280404, 255, RI_ALL_OFFLINE},
+       { 0x282000, 4, RI_ALL_ONLINE}, { 0x282010, 2044, RI_ALL_OFFLINE},
+       { 0x2a0000, 1, RI_ALL_ONLINE}, { 0x2a0004, 1023, RI_ALL_OFFLINE},
+       { 0x2a1000, 1, RI_ALL_ONLINE}, { 0x2a1004, 4607, RI_ALL_OFFLINE},
+       { 0x2a5800, 2560, RI_E1H_OFFLINE}, { 0x2a8000, 64, RI_ALL_OFFLINE},
+       { 0x2a8100, 960, RI_E1H_OFFLINE}, { 0x2a9000, 1, RI_E1H_ONLINE},
+       { 0x2a9004, 7679, RI_E1H_OFFLINE}, { 0x2b1800, 128, RI_ALL_OFFLINE},
+       { 0x2b1c00, 128, RI_ALL_OFFLINE}, { 0x2b2000, 1, RI_ALL_OFFLINE},
+       { 0x2b2400, 64, RI_E1H_OFFLINE}, { 0x2b8200, 1, RI_ALL_ONLINE},
+       { 0x2b8240, 1, RI_ALL_ONLINE}, { 0x2b8280, 1, RI_ALL_ONLINE},
+       { 0x2b82c0, 1, RI_ALL_ONLINE}, { 0x2b8a00, 1, RI_ALL_ONLINE},
+       { 0x2b8a80, 1, RI_ALL_ONLINE}, { 0x2c0000, 2, RI_ALL_ONLINE},
+       { 0x300000, 65, RI_ALL_ONLINE}, { 0x300110, 1, RI_ALL_ONLINE},
+       { 0x300120, 1, RI_ALL_ONLINE}, { 0x300130, 1, RI_ALL_ONLINE},
+       { 0x300140, 1, RI_ALL_ONLINE}, { 0x30014c, 2, RI_E1H_ONLINE},
+       { 0x300200, 58, RI_ALL_ONLINE}, { 0x300340, 4, RI_ALL_ONLINE},
+       { 0x300400, 1, RI_ALL_ONLINE}, { 0x300404, 255, RI_ALL_OFFLINE},
+       { 0x302000, 4, RI_ALL_ONLINE}, { 0x302010, 2044, RI_ALL_OFFLINE},
+       { 0x320000, 1, RI_ALL_ONLINE}, { 0x320004, 1023, RI_ALL_OFFLINE},
+       { 0x321000, 1, RI_ALL_ONLINE}, { 0x321004, 4607, RI_ALL_OFFLINE},
+       { 0x325800, 2560, RI_E1H_OFFLINE}, { 0x328000, 64, RI_ALL_OFFLINE},
+       { 0x328100, 536, RI_E1H_OFFLINE}, { 0x328960, 1, RI_E1H_ONLINE},
+       { 0x328964, 8103, RI_E1H_OFFLINE}, { 0x331800, 128, RI_ALL_OFFLINE},
+       { 0x331c00, 128, RI_ALL_OFFLINE}, { 0x332000, 1, RI_ALL_OFFLINE},
+       { 0x332400, 64, RI_E1H_OFFLINE}, { 0x338200, 1, RI_ALL_ONLINE},
+       { 0x338240, 1, RI_ALL_ONLINE}, { 0x338280, 1, RI_ALL_ONLINE},
+       { 0x3382c0, 1, RI_ALL_ONLINE}, { 0x338a00, 1, RI_ALL_ONLINE},
+       { 0x338a80, 1, RI_ALL_ONLINE}, { 0x340000, 2, RI_ALL_ONLINE}
+};
+
+
+#define IDLEREGS_COUNT         277
+static const struct reg_addr idle_addrs[IDLEREGS_COUNT] = {
+       { 0x2114, 1, RI_ALL_ONLINE}, { 0x2120, 1, RI_ALL_ONLINE},
+       { 0x212c, 4, RI_ALL_ONLINE}, { 0x2814, 1, RI_ALL_ONLINE},
+       { 0x281c, 2, RI_ALL_ONLINE}, { 0xa38c, 1, RI_ALL_ONLINE},
+       { 0xa408, 1, RI_ALL_ONLINE}, { 0xa42c, 12, RI_ALL_ONLINE},
+       { 0xa600, 5, RI_E1H_ONLINE}, { 0xa618, 1, RI_E1H_ONLINE},
+       { 0xc09c, 1, RI_ALL_ONLINE}, { 0x103b0, 1, RI_ALL_ONLINE},
+       { 0x103c0, 1, RI_ALL_ONLINE}, { 0x103d0, 1, RI_E1H_ONLINE},
+       { 0x2021c, 11, RI_ALL_ONLINE}, { 0x202a8, 1, RI_ALL_ONLINE},
+       { 0x202b8, 1, RI_ALL_ONLINE}, { 0x20404, 1, RI_ALL_ONLINE},
+       { 0x2040c, 2, RI_ALL_ONLINE}, { 0x2041c, 2, RI_ALL_ONLINE},
+       { 0x40154, 14, RI_ALL_ONLINE}, { 0x40198, 1, RI_ALL_ONLINE},
+       { 0x404ac, 1, RI_ALL_ONLINE}, { 0x404bc, 1, RI_ALL_ONLINE},
+       { 0x42290, 1, RI_ALL_ONLINE}, { 0x422a0, 1, RI_ALL_ONLINE},
+       { 0x422b0, 1, RI_ALL_ONLINE}, { 0x42548, 1, RI_ALL_ONLINE},
+       { 0x42550, 1, RI_ALL_ONLINE}, { 0x42558, 1, RI_ALL_ONLINE},
+       { 0x50160, 8, RI_ALL_ONLINE}, { 0x501d0, 1, RI_ALL_ONLINE},
+       { 0x501e0, 1, RI_ALL_ONLINE}, { 0x50204, 1, RI_ALL_ONLINE},
+       { 0x5020c, 2, RI_ALL_ONLINE}, { 0x5021c, 1, RI_ALL_ONLINE},
+       { 0x60090, 1, RI_ALL_ONLINE}, { 0x6011c, 1, RI_ALL_ONLINE},
+       { 0x6012c, 1, RI_ALL_ONLINE}, { 0xc101c, 1, RI_ALL_ONLINE},
+       { 0xc102c, 1, RI_ALL_ONLINE}, { 0xc2290, 1, RI_ALL_ONLINE},
+       { 0xc22a0, 1, RI_ALL_ONLINE}, { 0xc22b0, 1, RI_ALL_ONLINE},
+       { 0xc2548, 1, RI_ALL_ONLINE}, { 0xc2550, 1, RI_ALL_ONLINE},
+       { 0xc2558, 1, RI_ALL_ONLINE}, { 0xc4294, 1, RI_ALL_ONLINE},
+       { 0xc42a4, 1, RI_ALL_ONLINE}, { 0xc42b4, 1, RI_ALL_ONLINE},
+       { 0xc4550, 1, RI_ALL_ONLINE}, { 0xc4558, 1, RI_ALL_ONLINE},
+       { 0xc4560, 1, RI_ALL_ONLINE}, { 0xd016c, 8, RI_ALL_ONLINE},
+       { 0xd01d8, 1, RI_ALL_ONLINE}, { 0xd01e8, 1, RI_ALL_ONLINE},
+       { 0xd0204, 1, RI_ALL_ONLINE}, { 0xd020c, 3, RI_ALL_ONLINE},
+       { 0xe0154, 8, RI_ALL_ONLINE}, { 0xe01c8, 1, RI_ALL_ONLINE},
+       { 0xe01d8, 1, RI_ALL_ONLINE}, { 0xe0204, 1, RI_ALL_ONLINE},
+       { 0xe020c, 2, RI_ALL_ONLINE}, { 0xe021c, 2, RI_ALL_ONLINE},
+       { 0x101014, 1, RI_ALL_ONLINE}, { 0x101030, 1, RI_ALL_ONLINE},
+       { 0x101040, 1, RI_ALL_ONLINE}, { 0x102058, 1, RI_ALL_ONLINE},
+       { 0x102080, 16, RI_ALL_ONLINE}, { 0x103004, 2, RI_ALL_ONLINE},
+       { 0x103068, 1, RI_ALL_ONLINE}, { 0x103078, 1, RI_ALL_ONLINE},
+       { 0x103088, 1, RI_ALL_ONLINE}, { 0x10309c, 2, RI_E1H_ONLINE},
+       { 0x104004, 1, RI_ALL_ONLINE}, { 0x104018, 1, RI_ALL_ONLINE},
+       { 0x104020, 1, RI_ALL_ONLINE}, { 0x10403c, 1, RI_ALL_ONLINE},
+       { 0x1040fc, 1, RI_ALL_ONLINE}, { 0x10410c, 1, RI_ALL_ONLINE},
+       { 0x104400, 64, RI_ALL_ONLINE}, { 0x104800, 64, RI_ALL_ONLINE},
+       { 0x105000, 3, RI_ALL_ONLINE}, { 0x105010, 3, RI_ALL_ONLINE},
+       { 0x105020, 3, RI_ALL_ONLINE}, { 0x105030, 3, RI_ALL_ONLINE},
+       { 0x105040, 3, RI_ALL_ONLINE}, { 0x105050, 3, RI_ALL_ONLINE},
+       { 0x105060, 3, RI_ALL_ONLINE}, { 0x105070, 3, RI_ALL_ONLINE},
+       { 0x105080, 3, RI_ALL_ONLINE}, { 0x105090, 3, RI_ALL_ONLINE},
+       { 0x1050a0, 3, RI_ALL_ONLINE}, { 0x1050b0, 3, RI_ALL_ONLINE},
+       { 0x1050c0, 3, RI_ALL_ONLINE}, { 0x1050d0, 3, RI_ALL_ONLINE},
+       { 0x1050e0, 3, RI_ALL_ONLINE}, { 0x1050f0, 3, RI_ALL_ONLINE},
+       { 0x105100, 3, RI_ALL_ONLINE}, { 0x105110, 3, RI_ALL_ONLINE},
+       { 0x105120, 3, RI_ALL_ONLINE}, { 0x105130, 3, RI_ALL_ONLINE},
+       { 0x105140, 3, RI_ALL_ONLINE}, { 0x105150, 3, RI_ALL_ONLINE},
+       { 0x105160, 3, RI_ALL_ONLINE}, { 0x105170, 3, RI_ALL_ONLINE},
+       { 0x105180, 3, RI_ALL_ONLINE}, { 0x105190, 3, RI_ALL_ONLINE},
+       { 0x1051a0, 3, RI_ALL_ONLINE}, { 0x1051b0, 3, RI_ALL_ONLINE},
+       { 0x1051c0, 3, RI_ALL_ONLINE}, { 0x1051d0, 3, RI_ALL_ONLINE},
+       { 0x1051e0, 3, RI_ALL_ONLINE}, { 0x1051f0, 3, RI_ALL_ONLINE},
+       { 0x105200, 3, RI_ALL_ONLINE}, { 0x105210, 3, RI_ALL_ONLINE},
+       { 0x105220, 3, RI_ALL_ONLINE}, { 0x105230, 3, RI_ALL_ONLINE},
+       { 0x105240, 3, RI_ALL_ONLINE}, { 0x105250, 3, RI_ALL_ONLINE},
+       { 0x105260, 3, RI_ALL_ONLINE}, { 0x105270, 3, RI_ALL_ONLINE},
+       { 0x105280, 3, RI_ALL_ONLINE}, { 0x105290, 3, RI_ALL_ONLINE},
+       { 0x1052a0, 3, RI_ALL_ONLINE}, { 0x1052b0, 3, RI_ALL_ONLINE},
+       { 0x1052c0, 3, RI_ALL_ONLINE}, { 0x1052d0, 3, RI_ALL_ONLINE},
+       { 0x1052e0, 3, RI_ALL_ONLINE}, { 0x1052f0, 3, RI_ALL_ONLINE},
+       { 0x105300, 3, RI_ALL_ONLINE}, { 0x105310, 3, RI_ALL_ONLINE},
+       { 0x105320, 3, RI_ALL_ONLINE}, { 0x105330, 3, RI_ALL_ONLINE},
+       { 0x105340, 3, RI_ALL_ONLINE}, { 0x105350, 3, RI_ALL_ONLINE},
+       { 0x105360, 3, RI_ALL_ONLINE}, { 0x105370, 3, RI_ALL_ONLINE},
+       { 0x105380, 3, RI_ALL_ONLINE}, { 0x105390, 3, RI_ALL_ONLINE},
+       { 0x1053a0, 3, RI_ALL_ONLINE}, { 0x1053b0, 3, RI_ALL_ONLINE},
+       { 0x1053c0, 3, RI_ALL_ONLINE}, { 0x1053d0, 3, RI_ALL_ONLINE},
+       { 0x1053e0, 3, RI_ALL_ONLINE}, { 0x1053f0, 3, RI_ALL_ONLINE},
+       { 0x108094, 1, RI_ALL_ONLINE}, { 0x1201b0, 2, RI_ALL_ONLINE},
+       { 0x12032c, 1, RI_ALL_ONLINE}, { 0x12036c, 3, RI_ALL_ONLINE},
+       { 0x120408, 2, RI_ALL_ONLINE}, { 0x120414, 15, RI_ALL_ONLINE},
+       { 0x120478, 2, RI_ALL_ONLINE}, { 0x12052c, 1, RI_ALL_ONLINE},
+       { 0x120564, 3, RI_ALL_ONLINE}, { 0x12057c, 1, RI_ALL_ONLINE},
+       { 0x12058c, 1, RI_ALL_ONLINE}, { 0x120608, 1, RI_E1H_ONLINE},
+       { 0x120808, 1, RI_E1_ONLINE}, { 0x12080c, 2, RI_ALL_ONLINE},
+       { 0x120818, 1, RI_ALL_ONLINE}, { 0x120820, 1, RI_ALL_ONLINE},
+       { 0x120828, 1, RI_ALL_ONLINE}, { 0x120830, 1, RI_ALL_ONLINE},
+       { 0x120838, 1, RI_ALL_ONLINE}, { 0x120840, 1, RI_ALL_ONLINE},
+       { 0x120848, 1, RI_ALL_ONLINE}, { 0x120850, 1, RI_ALL_ONLINE},
+       { 0x120858, 1, RI_ALL_ONLINE}, { 0x120860, 1, RI_ALL_ONLINE},
+       { 0x120868, 1, RI_ALL_ONLINE}, { 0x120870, 1, RI_ALL_ONLINE},
+       { 0x120878, 1, RI_ALL_ONLINE}, { 0x120880, 1, RI_ALL_ONLINE},
+       { 0x120888, 1, RI_ALL_ONLINE}, { 0x120890, 1, RI_ALL_ONLINE},
+       { 0x120898, 1, RI_ALL_ONLINE}, { 0x1208a0, 1, RI_ALL_ONLINE},
+       { 0x1208a8, 1, RI_ALL_ONLINE}, { 0x1208b0, 1, RI_ALL_ONLINE},
+       { 0x1208b8, 1, RI_ALL_ONLINE}, { 0x1208c0, 1, RI_ALL_ONLINE},
+       { 0x1208c8, 1, RI_ALL_ONLINE}, { 0x1208d0, 1, RI_ALL_ONLINE},
+       { 0x1208d8, 1, RI_ALL_ONLINE}, { 0x1208e0, 1, RI_ALL_ONLINE},
+       { 0x1208e8, 1, RI_ALL_ONLINE}, { 0x1208f0, 1, RI_ALL_ONLINE},
+       { 0x1208f8, 1, RI_ALL_ONLINE}, { 0x120900, 1, RI_ALL_ONLINE},
+       { 0x120908, 1, RI_ALL_ONLINE}, { 0x14005c, 2, RI_ALL_ONLINE},
+       { 0x1400d0, 2, RI_ALL_ONLINE}, { 0x1400e0, 1, RI_ALL_ONLINE},
+       { 0x1401c8, 1, RI_ALL_ONLINE}, { 0x140200, 6, RI_ALL_ONLINE},
+       { 0x16101c, 1, RI_ALL_ONLINE}, { 0x16102c, 1, RI_ALL_ONLINE},
+       { 0x164014, 2, RI_ALL_ONLINE}, { 0x1640f0, 1, RI_ALL_ONLINE},
+       { 0x166290, 1, RI_ALL_ONLINE}, { 0x1662a0, 1, RI_ALL_ONLINE},
+       { 0x1662b0, 1, RI_ALL_ONLINE}, { 0x166548, 1, RI_ALL_ONLINE},
+       { 0x166550, 1, RI_ALL_ONLINE}, { 0x166558, 1, RI_ALL_ONLINE},
+       { 0x168000, 1, RI_ALL_ONLINE}, { 0x168008, 1, RI_ALL_ONLINE},
+       { 0x168010, 1, RI_ALL_ONLINE}, { 0x168018, 1, RI_ALL_ONLINE},
+       { 0x168028, 2, RI_ALL_ONLINE}, { 0x168058, 4, RI_ALL_ONLINE},
+       { 0x168070, 1, RI_ALL_ONLINE}, { 0x168238, 1, RI_ALL_ONLINE},
+       { 0x1682d0, 2, RI_ALL_ONLINE}, { 0x1682e0, 1, RI_ALL_ONLINE},
+       { 0x168300, 67, RI_ALL_ONLINE}, { 0x168410, 2, RI_ALL_ONLINE},
+       { 0x168438, 1, RI_ALL_ONLINE}, { 0x168448, 1, RI_ALL_ONLINE},
+       { 0x168a00, 128, RI_ALL_ONLINE}, { 0x16e200, 128, RI_E1H_ONLINE},
+       { 0x16e404, 2, RI_E1H_ONLINE}, { 0x16e584, 70, RI_E1H_ONLINE},
+       { 0x1700a4, 1, RI_ALL_ONLINE}, { 0x1700ac, 2, RI_ALL_ONLINE},
+       { 0x1700c0, 1, RI_ALL_ONLINE}, { 0x170174, 1, RI_ALL_ONLINE},
+       { 0x170184, 1, RI_ALL_ONLINE}, { 0x1800f4, 1, RI_ALL_ONLINE},
+       { 0x180104, 1, RI_ALL_ONLINE}, { 0x180114, 1, RI_ALL_ONLINE},
+       { 0x180124, 1, RI_ALL_ONLINE}, { 0x18026c, 1, RI_ALL_ONLINE},
+       { 0x1802a0, 1, RI_ALL_ONLINE}, { 0x1a1000, 1, RI_ALL_ONLINE},
+       { 0x1aa000, 1, RI_E1H_ONLINE}, { 0x1b8000, 1, RI_ALL_ONLINE},
+       { 0x1b8040, 1, RI_ALL_ONLINE}, { 0x1b8080, 1, RI_ALL_ONLINE},
+       { 0x1b80c0, 1, RI_ALL_ONLINE}, { 0x200104, 1, RI_ALL_ONLINE},
+       { 0x200114, 1, RI_ALL_ONLINE}, { 0x200124, 1, RI_ALL_ONLINE},
+       { 0x200134, 1, RI_ALL_ONLINE}, { 0x20026c, 1, RI_ALL_ONLINE},
+       { 0x2002a0, 1, RI_ALL_ONLINE}, { 0x221000, 1, RI_ALL_ONLINE},
+       { 0x227000, 1, RI_E1H_ONLINE}, { 0x238000, 1, RI_ALL_ONLINE},
+       { 0x238040, 1, RI_ALL_ONLINE}, { 0x238080, 1, RI_ALL_ONLINE},
+       { 0x2380c0, 1, RI_ALL_ONLINE}, { 0x280104, 1, RI_ALL_ONLINE},
+       { 0x280114, 1, RI_ALL_ONLINE}, { 0x280124, 1, RI_ALL_ONLINE},
+       { 0x280134, 1, RI_ALL_ONLINE}, { 0x28026c, 1, RI_ALL_ONLINE},
+       { 0x2802a0, 1, RI_ALL_ONLINE}, { 0x2a1000, 1, RI_ALL_ONLINE},
+       { 0x2a9000, 1, RI_E1H_ONLINE}, { 0x2b8000, 1, RI_ALL_ONLINE},
+       { 0x2b8040, 1, RI_ALL_ONLINE}, { 0x2b8080, 1, RI_ALL_ONLINE},
+       { 0x2b80c0, 1, RI_ALL_ONLINE}, { 0x300104, 1, RI_ALL_ONLINE},
+       { 0x300114, 1, RI_ALL_ONLINE}, { 0x300124, 1, RI_ALL_ONLINE},
+       { 0x300134, 1, RI_ALL_ONLINE}, { 0x30026c, 1, RI_ALL_ONLINE},
+       { 0x3002a0, 1, RI_ALL_ONLINE}, { 0x321000, 1, RI_ALL_ONLINE},
+       { 0x328960, 1, RI_E1H_ONLINE}, { 0x338000, 1, RI_ALL_ONLINE},
+       { 0x338040, 1, RI_ALL_ONLINE}, { 0x338080, 1, RI_ALL_ONLINE},
+       { 0x3380c0, 1, RI_ALL_ONLINE}
+};
+
+static const u32 read_reg_e1_0[] = { 0x1b1000 };
+
+#define WREGS_COUNT_E1         1
+static const struct wreg_addr wreg_addrs_e1[WREGS_COUNT_E1] = {
+       { 0x1b0c00, 192, 1, read_reg_e1_0, RI_E1_OFFLINE }
+};
+
+static const u32 read_reg_e1h_0[] = { 0x1b1040, 0x1b1000 };
+
+#define WREGS_COUNT_E1H                1
+static const struct wreg_addr wreg_addrs_e1h[WREGS_COUNT_E1H] = {
+       { 0x1b0c00, 256, 2, read_reg_e1h_0, RI_E1H_OFFLINE }
+};
+
+
+static const struct dump_sign dump_sign_all = { 0x49aa93ee, 0x40835, 0x22 };
+
+
+#define TIMER_REGS_COUNT_E1    2
+static const u32 timer_status_regs_e1[TIMER_REGS_COUNT_E1] =
+       { 0x164014, 0x164018 };
+static const u32 timer_scan_regs_e1[TIMER_REGS_COUNT_E1] =
+       { 0x1640d0, 0x1640d4 };
+
+#define TIMER_REGS_COUNT_E1H   2
+static const u32 timer_status_regs_e1h[TIMER_REGS_COUNT_E1H] =
+       { 0x164014, 0x164018 };
+static const u32 timer_scan_regs_e1h[TIMER_REGS_COUNT_E1H] =
+       { 0x1640d0, 0x1640d4 };
+
index 8af27573afe804495a8f34bfd6fee958f1072f2c..39ba2936c0c2c93d16a9229597c35a79f6066e34 100644 (file)
 #define INIT_ASIC                      0x4
 #define INIT_HARDWARE                  0x7
 
-#define STORM_INTMEM_SIZE_E1           (0x5800 / 4)
-#define STORM_INTMEM_SIZE_E1H          (0x10000 / 4)
-#define TSTORM_INTMEM_ADDR             0x1a0000
-#define CSTORM_INTMEM_ADDR             0x220000
-#define XSTORM_INTMEM_ADDR             0x2a0000
-#define USTORM_INTMEM_ADDR             0x320000
+#define TSTORM_INTMEM_ADDR             TSEM_REG_FAST_MEMORY
+#define CSTORM_INTMEM_ADDR             CSEM_REG_FAST_MEMORY
+#define XSTORM_INTMEM_ADDR             XSEM_REG_FAST_MEMORY
+#define USTORM_INTMEM_ADDR             USEM_REG_FAST_MEMORY
+/* RAM0 size in bytes */
+#define STORM_INTMEM_SIZE_E1           0x5800
+#define STORM_INTMEM_SIZE_E1H          0x10000
+#define STORM_INTMEM_SIZE(bp)  ((CHIP_IS_E1H(bp) ? STORM_INTMEM_SIZE_E1H : \
+                                                   STORM_INTMEM_SIZE_E1) / 4)
 
 
 /* Init operation types and structures */
@@ -150,7 +153,6 @@ static void bnx2x_init_ind_wr(struct bnx2x *bp, u32 addr, const u32 *data,
 
 static void bnx2x_write_big_buf(struct bnx2x *bp, u32 addr, u32 len)
 {
-#ifdef USE_DMAE
        int offset = 0;
 
        if (bp->dmae_ready) {
@@ -164,28 +166,28 @@ static void bnx2x_write_big_buf(struct bnx2x *bp, u32 addr, u32 len)
                                 addr + offset, len);
        } else
                bnx2x_init_str_wr(bp, addr, bp->gunzip_buf, len);
-#else
-       bnx2x_init_str_wr(bp, addr, bp->gunzip_buf, len);
-#endif
 }
 
 static void bnx2x_init_fill(struct bnx2x *bp, u32 addr, int fill, u32 len)
 {
-       if ((len * 4) > FW_BUF_SIZE) {
-               BNX2X_ERR("LARGE DMAE OPERATION ! addr 0x%x  len 0x%x\n",
-                         addr, len*4);
-               return;
-       }
-       memset(bp->gunzip_buf, fill, len * 4);
+       u32 buf_len = (((len * 4) > FW_BUF_SIZE) ? FW_BUF_SIZE : (len * 4));
+       u32 buf_len32 = buf_len / 4;
+       int i;
 
-       bnx2x_write_big_buf(bp, addr, len);
+       memset(bp->gunzip_buf, fill, buf_len);
+
+       for (i = 0; i < len; i += buf_len32) {
+               u32 cur_len = min(buf_len32, len - i);
+
+               bnx2x_write_big_buf(bp, addr + i * 4, cur_len);
+       }
 }
 
 static void bnx2x_init_wr_64(struct bnx2x *bp, u32 addr, const u32 *data,
                             u32 len64)
 {
-       u32 buf_len32 = FW_BUF_SIZE/4;
-       u32 len = len64*2;
+       u32 buf_len32 = FW_BUF_SIZE / 4;
+       u32 len = len64 * 2;
        u64 data64 = 0;
        int i;
 
index 6e18a556fb5e7d02676b6ebbdb607518e702f458..1f22c9ab66d407accb797e532ab194b043970a85 100644 (file)
@@ -1,7 +1,23 @@
 #ifndef __BNX2X_INIT_VALUES_H__
 #define __BNX2X_INIT_VALUES_H__
 
-/* This array contains the list of operations needed to initialize the chip.
+/* bnx2x_init_values.h: Broadcom NX2 10G network driver.
+ *
+ * Copyright (c) 2007-2009 Broadcom Corporation
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation, except as noted below.
+ *
+ * This file contains firmware data derived from proprietary unpublished
+ * source code, Copyright (c) 2007-2009 Broadcom Corporation.
+ *
+ * Permission is hereby granted for the distribution of this firmware data
+ * in hexadecimal or equivalent format, provided this copyright notice is
+ * accompanying it.
+ *
+ *
+ * This array contains the list of operations needed to initialize the chip.
  *
  * For each block in the chip there are three init stages:
  * common - HW used by both ports,
index 73b52f17ea848d6de2a650afa583052088a79f76..ed648acef7cffef16ee31923562b0a8b9c9ed731 100644 (file)
@@ -2258,6 +2258,11 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
                       MDIO_PMA_REG_GEN_CTRL,
                       MDIO_PMA_REG_GEN_CTRL_ROM_MICRO_RESET);
 
+       bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
+                      MDIO_PMA_DEVAD,
+                      MDIO_PMA_REG_GEN_CTRL2,
+                      0x73A0);
+
        /* Clear soft reset.
        Will automatically reset micro-controller re-boot */
        bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
@@ -2265,8 +2270,8 @@ static void bnx2x_bcm8726_external_rom_boot(struct link_params *params)
                       MDIO_PMA_REG_GEN_CTRL,
                       MDIO_PMA_REG_GEN_CTRL_ROM_RESET_INTERNAL_MP);
 
-       /* wait for 100ms for microcode load */
-       msleep(100);
+       /* wait for 150ms for microcode load */
+       msleep(150);
 
        /* Disable serial boot control, tristates pins SS_N, SCK, MOSI, MISO */
        bnx2x_cl45_write(bp, port, ext_phy_type, ext_phy_addr,
@@ -2524,7 +2529,7 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
        u8 ext_phy_addr = ((params->ext_phy_config &
                            PORT_HW_CFG_XGXS_EXT_PHY_ADDR_MASK) >>
                           PORT_HW_CFG_XGXS_EXT_PHY_ADDR_SHIFT);
-
+       u16 cur_limiting_mode;
        if (bnx2x_read_sfp_module_eeprom(params,
                                       SFP_EEPROM_OPTIONS_ADDR,
                                       SFP_EEPROM_OPTIONS_SIZE,
@@ -2535,6 +2540,16 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
        }
        limiting_mode = !(options[0] &
                          SFP_EEPROM_OPTIONS_LINEAR_RX_OUT_MASK);
+
+       bnx2x_cl45_read(bp, port,
+                     PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
+                     ext_phy_addr,
+                     MDIO_PMA_DEVAD,
+                     MDIO_PMA_REG_ROM_VER2,
+                     &cur_limiting_mode);
+       DP(NETIF_MSG_LINK, "Current Limiting mode is 0x%x\n",
+                cur_limiting_mode);
+
        if (limiting_mode &&
            (module_type != SFP_MODULE_TYPE_PASSIVE_COPPER_CABLE)) {
                DP(NETIF_MSG_LINK,
@@ -2547,17 +2562,10 @@ static u8 bnx2x_bcm8726_set_limiting_mode(struct link_params *params,
                               MDIO_PMA_REG_ROM_VER2,
                               SFP_LIMITING_MODE_VALUE);
        } else { /* LRM mode ( default )*/
-               u16 cur_limiting_mode;
+
                DP(NETIF_MSG_LINK, "Module options = 0x%x.Setting LRM MODE\n",
                         options[0]);
 
-               bnx2x_cl45_read(bp, port,
-                              PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726,
-                              ext_phy_addr,
-                              MDIO_PMA_DEVAD,
-                              MDIO_PMA_REG_ROM_VER2,
-                              &cur_limiting_mode);
-
                /* Changing to LRM mode takes quite few seconds.
                So do it only if current mode is limiting
                ( default is LRM )*/
@@ -2660,11 +2668,7 @@ static u8 bnx2x_sfp_module_detection(struct link_params *params)
                          params->port);
 
        /* Check and set limiting mode / LRM mode */
-       if (bnx2x_bcm8726_set_limiting_mode(params, module_type)
-            != 0) {
-               DP(NETIF_MSG_LINK, "Setting limiting mode failed!!\n");
-               return -EINVAL;
-       }
+       bnx2x_bcm8726_set_limiting_mode(params, module_type);
 
        /* Enable transmit for this module */
        bnx2x_bcm8726_set_transmitter(bp, params->port,
@@ -3029,10 +3033,9 @@ static u8 bnx2x_ext_phy_init(struct link_params *params, struct link_vars *vars)
                                       MDIO_WIS_DEVAD,
                                       MDIO_WIS_REG_LASI_CNTL, 0x1);
 
-                       bnx2x_save_bcm_spirom_ver(bp, params->port,
-                                               ext_phy_type,
-                                               ext_phy_addr,
-                                               params->shmem_base);
+                       /* BCM8705 doesn't have microcode, hence the 0 */
+                       bnx2x_save_spirom_version(bp, params->port,
+                                               params->shmem_base, 0);
                        break;
 
                case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
@@ -4241,6 +4244,7 @@ u8 bnx2x_get_ext_phy_fw_version(struct link_params *params, u8 driver_loaded,
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705:
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8706:
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726:
+       case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481:
                status = bnx2x_format_ver(spirom_ver, version, len);
                break;
        case PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT:
@@ -4620,13 +4624,13 @@ static u8 bnx2x_link_initialize(struct link_params *params,
 
        /* init ext phy and enable link state int */
        non_ext_phy = ((ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_DIRECT) ||
-                      (params->loopback_mode == LOOPBACK_XGXS_10) ||
-                      (params->loopback_mode == LOOPBACK_EXT_PHY));
+                      (params->loopback_mode == LOOPBACK_XGXS_10));
 
        if (non_ext_phy ||
            (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8705) ||
            (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8726) ||
-           (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481)) {
+           (ext_phy_type == PORT_HW_CFG_XGXS_EXT_PHY_TYPE_BCM8481) ||
+           (params->loopback_mode == LOOPBACK_EXT_PHY)) {
                if (params->req_line_speed == SPEED_AUTO_NEG)
                        bnx2x_set_parallel_detection(params, vars->phy_flags);
                bnx2x_init_internal_phy(params, vars);
index 942717526d6a942dd1576560f18da5a9a13fbf65..00a78e8677b01431a30bff2690884ca005e43bdb 100644 (file)
 
 #include "bnx2x.h"
 #include "bnx2x_init.h"
+#include "bnx2x_dump.h"
 
-#define DRV_MODULE_VERSION     "1.48.102"
-#define DRV_MODULE_RELDATE     "2009/02/12"
+#define DRV_MODULE_VERSION     "1.48.105"
+#define DRV_MODULE_RELDATE     "2009/03/02"
 #define BNX2X_BC_VER           0x040200
 
 /* Time in jiffies before concluding the transmitter is hung */
@@ -72,6 +73,7 @@ MODULE_VERSION(DRV_MODULE_VERSION);
 
 static int multi_mode = 1;
 module_param(multi_mode, int, 0);
+MODULE_PARM_DESC(multi_mode, " Use per-CPU queues");
 
 static int disable_tpa;
 module_param(disable_tpa, int, 0);
@@ -215,7 +217,7 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
        dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
        dmae->comp_val = DMAE_COMP_VAL;
 
-       DP(BNX2X_MSG_OFF, "dmae: opcode 0x%08x\n"
+       DP(BNX2X_MSG_OFF, "DMAE: opcode 0x%08x\n"
           DP_LEVEL "src_addr  [%x:%08x]  len [%d *4]  "
                    "dst_addr [%x:%08x (%08x)]\n"
           DP_LEVEL "comp_addr [%x:%08x]  comp_val 0x%08x\n",
@@ -236,7 +238,7 @@ void bnx2x_write_dmae(struct bnx2x *bp, dma_addr_t dma_addr, u32 dst_addr,
                DP(BNX2X_MSG_OFF, "wb_comp 0x%08x\n", *wb_comp);
 
                if (!cnt) {
-                       BNX2X_ERR("dmae timeout!\n");
+                       BNX2X_ERR("DMAE timeout!\n");
                        break;
                }
                cnt--;
@@ -291,7 +293,7 @@ void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
        dmae->comp_addr_hi = U64_HI(bnx2x_sp_mapping(bp, wb_comp));
        dmae->comp_val = DMAE_COMP_VAL;
 
-       DP(BNX2X_MSG_OFF, "dmae: opcode 0x%08x\n"
+       DP(BNX2X_MSG_OFF, "DMAE: opcode 0x%08x\n"
           DP_LEVEL "src_addr  [%x:%08x]  len [%d *4]  "
                    "dst_addr [%x:%08x (%08x)]\n"
           DP_LEVEL "comp_addr [%x:%08x]  comp_val 0x%08x\n",
@@ -308,7 +310,7 @@ void bnx2x_read_dmae(struct bnx2x *bp, u32 src_addr, u32 len32)
        while (*wb_comp != DMAE_COMP_VAL) {
 
                if (!cnt) {
-                       BNX2X_ERR("dmae timeout!\n");
+                       BNX2X_ERR("DMAE timeout!\n");
                        break;
                }
                cnt--;
@@ -516,13 +518,13 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
        for_each_rx_queue(bp, i) {
                struct bnx2x_fastpath *fp = &bp->fp[i];
 
-               BNX2X_ERR("queue[%d]: rx_bd_prod(%x)  rx_bd_cons(%x)"
+               BNX2X_ERR("fp%d: rx_bd_prod(%x)  rx_bd_cons(%x)"
                          "  *rx_bd_cons_sb(%x)  rx_comp_prod(%x)"
                          "  rx_comp_cons(%x)  *rx_cons_sb(%x)\n",
                          i, fp->rx_bd_prod, fp->rx_bd_cons,
                          le16_to_cpu(*fp->rx_bd_cons_sb), fp->rx_comp_prod,
                          fp->rx_comp_cons, le16_to_cpu(*fp->rx_cons_sb));
-               BNX2X_ERR("          rx_sge_prod(%x)  last_max_sge(%x)"
+               BNX2X_ERR("      rx_sge_prod(%x)  last_max_sge(%x)"
                          "  fp_u_idx(%x) *sb_u_idx(%x)\n",
                          fp->rx_sge_prod, fp->last_max_sge,
                          le16_to_cpu(fp->fp_u_idx),
@@ -534,11 +536,11 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
                struct bnx2x_fastpath *fp = &bp->fp[i];
                struct eth_tx_db_data *hw_prods = fp->hw_tx_prods;
 
-               BNX2X_ERR("queue[%d]: tx_pkt_prod(%x)  tx_pkt_cons(%x)"
+               BNX2X_ERR("fp%d: tx_pkt_prod(%x)  tx_pkt_cons(%x)"
                          "  tx_bd_prod(%x)  tx_bd_cons(%x)  *tx_cons_sb(%x)\n",
                          i, fp->tx_pkt_prod, fp->tx_pkt_cons, fp->tx_bd_prod,
                          fp->tx_bd_cons, le16_to_cpu(*fp->tx_cons_sb));
-               BNX2X_ERR("          fp_c_idx(%x)  *sb_c_idx(%x)"
+               BNX2X_ERR("      fp_c_idx(%x)  *sb_c_idx(%x)"
                          "  bd data(%x,%x)\n", le16_to_cpu(fp->fp_c_idx),
                          fp->status_blk->c_status_block.status_block_index,
                          hw_prods->packets_prod, hw_prods->bds_prod);
@@ -555,8 +557,8 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
                        u32 *rx_bd = (u32 *)&fp->rx_desc_ring[j];
                        struct sw_rx_bd *sw_bd = &fp->rx_buf_ring[j];
 
-                       BNX2X_ERR("rx_bd[%x]=[%x:%x]  sw_bd=[%p]\n",
-                                 j, rx_bd[1], rx_bd[0], sw_bd->skb);
+                       BNX2X_ERR("fp%d: rx_bd[%x]=[%x:%x]  sw_bd=[%p]\n",
+                                 i, j, rx_bd[1], rx_bd[0], sw_bd->skb);
                }
 
                start = RX_SGE(fp->rx_sge_prod);
@@ -565,8 +567,8 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
                        u32 *rx_sge = (u32 *)&fp->rx_sge_ring[j];
                        struct sw_rx_page *sw_page = &fp->rx_page_ring[j];
 
-                       BNX2X_ERR("rx_sge[%x]=[%x:%x]  sw_page=[%p]\n",
-                                 j, rx_sge[1], rx_sge[0], sw_page->page);
+                       BNX2X_ERR("fp%d: rx_sge[%x]=[%x:%x]  sw_page=[%p]\n",
+                                 i, j, rx_sge[1], rx_sge[0], sw_page->page);
                }
 
                start = RCQ_BD(fp->rx_comp_cons - 10);
@@ -574,8 +576,8 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
                for (j = start; j != end; j = RCQ_BD(j + 1)) {
                        u32 *cqe = (u32 *)&fp->rx_comp_ring[j];
 
-                       BNX2X_ERR("cqe[%x]=[%x:%x:%x:%x]\n",
-                                 j, cqe[0], cqe[1], cqe[2], cqe[3]);
+                       BNX2X_ERR("fp%d: cqe[%x]=[%x:%x:%x:%x]\n",
+                                 i, j, cqe[0], cqe[1], cqe[2], cqe[3]);
                }
        }
 
@@ -588,8 +590,8 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
                for (j = start; j != end; j = TX_BD(j + 1)) {
                        struct sw_tx_bd *sw_bd = &fp->tx_buf_ring[j];
 
-                       BNX2X_ERR("packet[%x]=[%p,%x]\n", j,
-                                 sw_bd->skb, sw_bd->first_bd);
+                       BNX2X_ERR("fp%d: packet[%x]=[%p,%x]\n",
+                                 i, j, sw_bd->skb, sw_bd->first_bd);
                }
 
                start = TX_BD(fp->tx_bd_cons - 10);
@@ -597,8 +599,8 @@ static void bnx2x_panic_dump(struct bnx2x *bp)
                for (j = start; j != end; j = TX_BD(j + 1)) {
                        u32 *tx_bd = (u32 *)&fp->tx_desc_ring[j];
 
-                       BNX2X_ERR("tx_bd[%x]=[%x:%x:%x:%x]\n",
-                                 j, tx_bd[0], tx_bd[1], tx_bd[2], tx_bd[3]);
+                       BNX2X_ERR("fp%d: tx_bd[%x]=[%x:%x:%x:%x]\n",
+                                 i, j, tx_bd[0], tx_bd[1], tx_bd[2], tx_bd[3]);
                }
        }
 
@@ -874,7 +876,7 @@ static inline u16 bnx2x_tx_avail(struct bnx2x_fastpath *fp)
        return (s16)(fp->bp->tx_ring_size) - used;
 }
 
-static void bnx2x_tx_int(struct bnx2x_fastpath *fp, int work)
+static void bnx2x_tx_int(struct bnx2x_fastpath *fp)
 {
        struct bnx2x *bp = fp->bp;
        struct netdev_queue *txq;
@@ -908,26 +910,24 @@ static void bnx2x_tx_int(struct bnx2x_fastpath *fp, int work)
                bd_cons = bnx2x_free_tx_pkt(bp, fp, pkt_cons);
                sw_cons++;
                done++;
-
-               if (done == work)
-                       break;
        }
 
        fp->tx_pkt_cons = sw_cons;
        fp->tx_bd_cons = bd_cons;
 
-       /* Need to make the tx_bd_cons update visible to start_xmit()
-        * before checking for netif_tx_queue_stopped().  Without the
-        * memory barrier, there is a small possibility that start_xmit()
-        * will miss it and cause the queue to be stopped forever.
-        */
-       smp_mb();
-
        /* TBD need a thresh? */
        if (unlikely(netif_tx_queue_stopped(txq))) {
 
                __netif_tx_lock(txq, smp_processor_id());
 
+               /* Need to make the tx_bd_cons update visible to start_xmit()
+                * before checking for netif_tx_queue_stopped().  Without the
+                * memory barrier, there is a small possibility that
+                * start_xmit() will miss it and cause the queue to be stopped
+                * forever.
+                */
+               smp_mb();
+
                if ((netif_tx_queue_stopped(txq)) &&
                    (bp->state == BNX2X_STATE_OPEN) &&
                    (bnx2x_tx_avail(fp) >= MAX_SKB_FRAGS + 3))
@@ -3668,7 +3668,7 @@ static int bnx2x_hw_stats_update(struct bnx2x *bp)
                bnx2x_emac_stats_update(bp);
 
        else { /* unreached */
-               BNX2X_ERR("stats updated by dmae but no MAC active\n");
+               BNX2X_ERR("stats updated by DMAE but no MAC active\n");
                return -1;
        }
 
@@ -4176,7 +4176,7 @@ static void bnx2x_timer(unsigned long data)
                struct bnx2x_fastpath *fp = &bp->fp[0];
                int rc;
 
-               bnx2x_tx_int(fp, 1000);
+               bnx2x_tx_int(fp);
                rc = bnx2x_rx_int(fp, 1000);
        }
 
@@ -4224,10 +4224,10 @@ static void bnx2x_zero_sb(struct bnx2x *bp, int sb_id)
 {
        int port = BP_PORT(bp);
 
-       bnx2x_init_fill(bp, BAR_USTRORM_INTMEM +
+       bnx2x_init_fill(bp, USTORM_INTMEM_ADDR +
                        USTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), 0,
                        sizeof(struct ustorm_status_block)/4);
-       bnx2x_init_fill(bp, BAR_CSTRORM_INTMEM +
+       bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR +
                        CSTORM_SB_HOST_STATUS_BLOCK_OFFSET(port, sb_id), 0,
                        sizeof(struct cstorm_status_block)/4);
 }
@@ -4281,18 +4281,18 @@ static void bnx2x_zero_def_sb(struct bnx2x *bp)
 {
        int func = BP_FUNC(bp);
 
-       bnx2x_init_fill(bp, BAR_USTRORM_INTMEM +
+       bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR +
+                       TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0,
+                       sizeof(struct tstorm_def_status_block)/4);
+       bnx2x_init_fill(bp, USTORM_INTMEM_ADDR +
                        USTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0,
                        sizeof(struct ustorm_def_status_block)/4);
-       bnx2x_init_fill(bp, BAR_CSTRORM_INTMEM +
+       bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR +
                        CSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0,
                        sizeof(struct cstorm_def_status_block)/4);
-       bnx2x_init_fill(bp, BAR_XSTRORM_INTMEM +
+       bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR +
                        XSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0,
                        sizeof(struct xstorm_def_status_block)/4);
-       bnx2x_init_fill(bp, BAR_TSTRORM_INTMEM +
-                       TSTORM_DEF_SB_HOST_STATUS_BLOCK_OFFSET(func), 0,
-                       sizeof(struct tstorm_def_status_block)/4);
 }
 
 static void bnx2x_init_def_sb(struct bnx2x *bp,
@@ -5153,6 +5153,10 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
                bnx2x_update_fpsb_idx(fp);
        }
 
+       /* ensure status block indices were read */
+       rmb();
+
+
        bnx2x_init_def_sb(bp, bp->def_status_blk, bp->def_status_blk_mapping,
                          DEF_SB_ID);
        bnx2x_update_dsb_idx(bp);
@@ -5612,37 +5616,10 @@ static int bnx2x_init_common(struct bnx2x *bp)
        bnx2x_init_block(bp, USDM_COMMON_START, USDM_COMMON_END);
        bnx2x_init_block(bp, XSDM_COMMON_START, XSDM_COMMON_END);
 
-       if (CHIP_IS_E1H(bp)) {
-               bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR, 0,
-                               STORM_INTMEM_SIZE_E1H/2);
-               bnx2x_init_fill(bp,
-                               TSTORM_INTMEM_ADDR + STORM_INTMEM_SIZE_E1H/2,
-                               0, STORM_INTMEM_SIZE_E1H/2);
-               bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR, 0,
-                               STORM_INTMEM_SIZE_E1H/2);
-               bnx2x_init_fill(bp,
-                               CSTORM_INTMEM_ADDR + STORM_INTMEM_SIZE_E1H/2,
-                               0, STORM_INTMEM_SIZE_E1H/2);
-               bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR, 0,
-                               STORM_INTMEM_SIZE_E1H/2);
-               bnx2x_init_fill(bp,
-                               XSTORM_INTMEM_ADDR + STORM_INTMEM_SIZE_E1H/2,
-                               0, STORM_INTMEM_SIZE_E1H/2);
-               bnx2x_init_fill(bp, USTORM_INTMEM_ADDR, 0,
-                               STORM_INTMEM_SIZE_E1H/2);
-               bnx2x_init_fill(bp,
-                               USTORM_INTMEM_ADDR + STORM_INTMEM_SIZE_E1H/2,
-                               0, STORM_INTMEM_SIZE_E1H/2);
-       } else { /* E1 */
-               bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR, 0,
-                               STORM_INTMEM_SIZE_E1);
-               bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR, 0,
-                               STORM_INTMEM_SIZE_E1);
-               bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR, 0,
-                               STORM_INTMEM_SIZE_E1);
-               bnx2x_init_fill(bp, USTORM_INTMEM_ADDR, 0,
-                               STORM_INTMEM_SIZE_E1);
-       }
+       bnx2x_init_fill(bp, TSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp));
+       bnx2x_init_fill(bp, USTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp));
+       bnx2x_init_fill(bp, CSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp));
+       bnx2x_init_fill(bp, XSTORM_INTMEM_ADDR, 0, STORM_INTMEM_SIZE(bp));
 
        bnx2x_init_block(bp, TSEM_COMMON_START, TSEM_COMMON_END);
        bnx2x_init_block(bp, USEM_COMMON_START, USEM_COMMON_END);
@@ -6597,10 +6574,8 @@ static void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
 {
        bnx2x_int_disable_sync(bp, disable_hw);
        bnx2x_napi_disable(bp);
-       if (netif_running(bp->dev)) {
-               netif_tx_disable(bp->dev);
-               bp->dev->trans_start = jiffies; /* prevent tx timeout */
-       }
+       netif_tx_disable(bp->dev);
+       bp->dev->trans_start = jiffies; /* prevent tx timeout */
 }
 
 /*
@@ -7210,10 +7185,9 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
                struct bnx2x_fastpath *fp = &bp->fp[i];
 
                cnt = 1000;
-               smp_mb();
                while (bnx2x_has_tx_work_unload(fp)) {
 
-                       bnx2x_tx_int(fp, 1000);
+                       bnx2x_tx_int(fp);
                        if (!cnt) {
                                BNX2X_ERR("timeout waiting for queue[%d]\n",
                                          i);
@@ -7226,7 +7200,6 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
                        }
                        cnt--;
                        msleep(1);
-                       smp_mb();
                }
        }
        /* Give HW time to discard old tx messages */
@@ -8499,6 +8472,84 @@ static void bnx2x_get_drvinfo(struct net_device *dev,
        info->regdump_len = 0;
 }
 
+#define IS_E1_ONLINE(info)     (((info) & RI_E1_ONLINE) == RI_E1_ONLINE)
+#define IS_E1H_ONLINE(info)    (((info) & RI_E1H_ONLINE) == RI_E1H_ONLINE)
+
+static int bnx2x_get_regs_len(struct net_device *dev)
+{
+       static u32 regdump_len;
+       struct bnx2x *bp = netdev_priv(dev);
+       int i;
+
+       if (regdump_len)
+               return regdump_len;
+
+       if (CHIP_IS_E1(bp)) {
+               for (i = 0; i < REGS_COUNT; i++)
+                       if (IS_E1_ONLINE(reg_addrs[i].info))
+                               regdump_len += reg_addrs[i].size;
+
+               for (i = 0; i < WREGS_COUNT_E1; i++)
+                       if (IS_E1_ONLINE(wreg_addrs_e1[i].info))
+                               regdump_len += wreg_addrs_e1[i].size *
+                                       (1 + wreg_addrs_e1[i].read_regs_count);
+
+       } else { /* E1H */
+               for (i = 0; i < REGS_COUNT; i++)
+                       if (IS_E1H_ONLINE(reg_addrs[i].info))
+                               regdump_len += reg_addrs[i].size;
+
+               for (i = 0; i < WREGS_COUNT_E1H; i++)
+                       if (IS_E1H_ONLINE(wreg_addrs_e1h[i].info))
+                               regdump_len += wreg_addrs_e1h[i].size *
+                                       (1 + wreg_addrs_e1h[i].read_regs_count);
+       }
+       regdump_len *= 4;
+       regdump_len += sizeof(struct dump_hdr);
+
+       return regdump_len;
+}
+
+static void bnx2x_get_regs(struct net_device *dev,
+                          struct ethtool_regs *regs, void *_p)
+{
+       u32 *p = _p, i, j;
+       struct bnx2x *bp = netdev_priv(dev);
+       struct dump_hdr dump_hdr = {0};
+
+       regs->version = 0;
+       memset(p, 0, regs->len);
+
+       if (!netif_running(bp->dev))
+               return;
+
+       dump_hdr.hdr_size = (sizeof(struct dump_hdr) / 4) - 1;
+       dump_hdr.dump_sign = dump_sign_all;
+       dump_hdr.xstorm_waitp = REG_RD(bp, XSTORM_WAITP_ADDR);
+       dump_hdr.tstorm_waitp = REG_RD(bp, TSTORM_WAITP_ADDR);
+       dump_hdr.ustorm_waitp = REG_RD(bp, USTORM_WAITP_ADDR);
+       dump_hdr.cstorm_waitp = REG_RD(bp, CSTORM_WAITP_ADDR);
+       dump_hdr.info = CHIP_IS_E1(bp) ? RI_E1_ONLINE : RI_E1H_ONLINE;
+
+       memcpy(p, &dump_hdr, sizeof(struct dump_hdr));
+       p += dump_hdr.hdr_size + 1;
+
+       if (CHIP_IS_E1(bp)) {
+               for (i = 0; i < REGS_COUNT; i++)
+                       if (IS_E1_ONLINE(reg_addrs[i].info))
+                               for (j = 0; j < reg_addrs[i].size; j++)
+                                       *p++ = REG_RD(bp,
+                                                     reg_addrs[i].addr + j*4);
+
+       } else { /* E1H */
+               for (i = 0; i < REGS_COUNT; i++)
+                       if (IS_E1H_ONLINE(reg_addrs[i].info))
+                               for (j = 0; j < reg_addrs[i].size; j++)
+                                       *p++ = REG_RD(bp,
+                                                     reg_addrs[i].addr + j*4);
+       }
+}
+
 static void bnx2x_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
 {
        struct bnx2x *bp = netdev_priv(dev);
@@ -9954,6 +10005,8 @@ static struct ethtool_ops bnx2x_ethtool_ops = {
        .get_settings           = bnx2x_get_settings,
        .set_settings           = bnx2x_set_settings,
        .get_drvinfo            = bnx2x_get_drvinfo,
+       .get_regs_len           = bnx2x_get_regs_len,
+       .get_regs               = bnx2x_get_regs,
        .get_wol                = bnx2x_get_wol,
        .set_wol                = bnx2x_set_wol,
        .get_msglevel           = bnx2x_get_msglevel,
@@ -10066,16 +10119,29 @@ static int bnx2x_poll(struct napi_struct *napi, int budget)
        bnx2x_update_fpsb_idx(fp);
 
        if (bnx2x_has_tx_work(fp))
-               bnx2x_tx_int(fp, budget);
+               bnx2x_tx_int(fp);
 
-       if (bnx2x_has_rx_work(fp))
+       if (bnx2x_has_rx_work(fp)) {
                work_done = bnx2x_rx_int(fp, budget);
 
-       rmb(); /* BNX2X_HAS_WORK() reads the status block */
+               /* must not complete if we consumed full budget */
+               if (work_done >= budget)
+                       goto poll_again;
+       }
 
-       /* must not complete if we consumed full budget */
-       if ((work_done < budget) && !BNX2X_HAS_WORK(fp)) {
+       /* BNX2X_HAS_WORK() reads the status block, thus we need to
+        * ensure that status block indices have been actually read
+        * (bnx2x_update_fpsb_idx) prior to this check (BNX2X_HAS_WORK)
+        * so that we won't write the "newer" value of the status block to IGU
+        * (if there was a DMA right after BNX2X_HAS_WORK and
+        * if there is no rmb, the memory reading (bnx2x_update_fpsb_idx)
+        * may be postponed to right before bnx2x_ack_sb). In this case
+        * there will never be another interrupt until there is another update
+        * of the status block, while there is still unhandled work.
+        */
+       rmb();
 
+       if (!BNX2X_HAS_WORK(fp)) {
 #ifdef BNX2X_STOP_ON_ERROR
 poll_panic:
 #endif
@@ -10087,6 +10153,7 @@ poll_panic:
                             le16_to_cpu(fp->fp_c_idx), IGU_INT_ENABLE, 1);
        }
 
+poll_again:
        return work_done;
 }
 
@@ -11062,6 +11129,7 @@ static int __devinit bnx2x_init_one(struct pci_dev *pdev,
               (bnx2x_get_pcie_speed(bp) == 2) ? "5GHz (Gen2)" : "2.5GHz",
               dev->base_addr, bp->pdev->irq);
        printk(KERN_CONT "node addr %pM\n", dev->dev_addr);
+
        return 0;
 
 init_one_exit:
index 360a2564aa986918540b26f6d8824071408851ee..b8ce6fc927a06631d113df0e0da5cd328647c78c 100644 (file)
 #define PCICFG_COMMAND_INT_DISABLE             (1<<10)
 #define PCICFG_COMMAND_RESERVED                (0x1f<<11)
 #define PCICFG_STATUS_OFFSET                           0x06
-#define PCICFG_REVESION_ID                             0x08
+#define PCICFG_REVESION_ID_OFFSET                      0x08
 #define PCICFG_CACHE_LINE_SIZE                         0x0c
 #define PCICFG_LATENCY_TIMER                           0x0d
 #define PCICFG_BAR_1_LOW                               0x10
 #define PCICFG_PM_CSR_STATE                    (0x3<<0)
 #define PCICFG_PM_CSR_PME_ENABLE               (1<<8)
 #define PCICFG_PM_CSR_PME_STATUS               (1<<15)
-#define PCICFG_MSI_CAP_ID                              0x58
+#define PCICFG_MSI_CAP_ID_OFFSET                       0x58
 #define PCICFG_MSI_CONTROL_ENABLE              (0x1<<16)
 #define PCICFG_MSI_CONTROL_MCAP                (0x7<<17)
 #define PCICFG_MSI_CONTROL_MENA                (0x7<<20)
 #define PCICFG_MSI_CONTROL_MSI_PVMASK_CAPABLE  (0x1<<24)
 #define PCICFG_GRC_ADDRESS                             0x78
 #define PCICFG_GRC_DATA                                0x80
-#define PCICFG_MSIX_CAP_ID                             0xa0
+#define PCICFG_MSIX_CAP_ID_OFFSET                      0xa0
 #define PCICFG_MSIX_CONTROL_TABLE_SIZE         (0x7ff<<16)
 #define PCICFG_MSIX_CONTROL_RESERVED           (0x7<<27)
 #define PCICFG_MSIX_CONTROL_FUNC_MASK          (0x1<<30)
@@ -5843,6 +5843,7 @@ Theotherbitsarereservedandshouldbezero*/
 #define MDIO_PMA_REG_ROM_VER2          0xca1a
 #define MDIO_PMA_REG_EDC_FFE_MAIN      0xca1b
 #define MDIO_PMA_REG_PLL_BANDWIDTH     0xca1d
+#define MDIO_PMA_REG_GEN_CTRL2         0xca1e
 #define MDIO_PMA_REG_MISC_CTRL0        0xca23
 #define MDIO_PMA_REG_LRM_MODE          0xca3f
 #define MDIO_PMA_REG_CDR_BANDWIDTH     0xca46
index 2c96b93b12a5780209bf0c5a894c30903d1175c3..dce3cf92c61370ffec9d16b48c6fbafd7d6b0513 100644 (file)
@@ -3545,11 +3545,26 @@ static int bond_slave_netdev_event(unsigned long event, struct net_device *slave
                }
                break;
        case NETDEV_CHANGE:
-               /*
-                * TODO: is this what we get if somebody
-                * sets up a hierarchical bond, then rmmod's
-                * one of the slave bonding devices?
-                */
+               if (bond->params.mode == BOND_MODE_8023AD || bond_is_lb(bond)) {
+                       struct slave *slave;
+
+                       slave = bond_get_slave_by_dev(bond, slave_dev);
+                       if (slave) {
+                               u16 old_speed = slave->speed;
+                               u16 old_duplex = slave->duplex;
+
+                               bond_update_speed_duplex(slave);
+
+                               if (bond_is_lb(bond))
+                                       break;
+
+                               if (old_speed != slave->speed)
+                                       bond_3ad_adapter_speed_changed(slave);
+                               if (old_duplex != slave->duplex)
+                                       bond_3ad_adapter_duplex_changed(slave);
+                       }
+               }
+
                break;
        case NETDEV_DOWN:
                /*
@@ -4121,7 +4136,7 @@ static int bond_neigh_setup(struct net_device *dev, struct neigh_parms *parms)
                const struct net_device_ops *slave_ops
                        = slave->dev->netdev_ops;
                if (slave_ops->ndo_neigh_setup)
-                       return slave_ops->ndo_neigh_setup(dev, parms);
+                       return slave_ops->ndo_neigh_setup(slave->dev, parms);
        }
        return 0;
 }
index 840da83fb3cf46669515ba8b6d849aa942d14374..58f6fc055f6a55cd1e9e3bc52af92b96cd31c9a4 100644 (file)
@@ -1967,8 +1967,7 @@ void t1_sge_stop(struct sge *sge)
                tx_sched_stop(sge);
 
        for (i = 0; i < MAX_NPORTS; i++)
-               if (sge->espibug_skb[i])
-                       kfree_skb(sge->espibug_skb[i]);
+               kfree_skb(sge->espibug_skb[i]);
 }
 
 /*
index fbe15699584e537d6715a17d849acdb639296d7f..71eaa431371dc39c15fd3abee7723a087982bf0f 100644 (file)
@@ -68,6 +68,8 @@ struct port_info {
        struct net_device_stats netstats;
        int activity;
        __be32 iscsi_ipv4addr;
+
+       int link_fault; /* link fault was detected */
 };
 
 enum {                         /* adapter flags */
@@ -91,6 +93,7 @@ struct rx_sw_desc;
 struct sge_fl {                     /* SGE per free-buffer list state */
        unsigned int buf_size;      /* size of each Rx buffer */
        unsigned int credits;       /* # of available Rx buffers */
+       unsigned int pend_cred;     /* new buffers since last FL DB ring */
        unsigned int size;          /* capacity of free list */
        unsigned int cidx;          /* consumer index */
        unsigned int pidx;          /* producer index */
@@ -196,6 +199,7 @@ struct sge_qset {           /* an SGE queue set */
        struct netdev_queue *tx_q;      /* associated netdev TX queue */
        unsigned long txq_stopped;      /* which Tx queues are stopped */
        struct timer_list tx_reclaim_timer;     /* reclaims TX buffers */
+       struct timer_list rx_reclaim_timer;     /* reclaims RX buffers */
        unsigned long port_stats[SGE_PSTAT_MAX];
 } ____cacheline_aligned;
 
@@ -239,6 +243,7 @@ struct adapter {
        struct delayed_work adap_check_task;
        struct work_struct ext_intr_handler_task;
        struct work_struct fatal_error_handler_task;
+       struct work_struct link_fault_handler_task;
 
        struct dentry *debugfs_root;
 
@@ -281,6 +286,8 @@ void t3_os_ext_intr_handler(struct adapter *adapter);
 void t3_os_link_changed(struct adapter *adapter, int port_id, int link_status,
                        int speed, int duplex, int fc);
 void t3_os_phymod_changed(struct adapter *adap, int port_id);
+void t3_os_link_fault(struct adapter *adapter, int port_id, int state);
+void t3_os_link_fault_handler(struct adapter *adapter, int port_id);
 
 void t3_sge_start(struct adapter *adap);
 void t3_sge_stop(struct adapter *adap);
index db4f4f575b6a1e153a8be1e4056ddf3e97da4870..9ee021e750c8165264720eac31e925ced07ef0db 100644 (file)
@@ -280,6 +280,7 @@ struct mac_stats {
        unsigned long num_toggled; /* # times toggled TxEn due to stuck TX */
        unsigned long num_resets;  /* # times reset due to stuck TX */
 
+       unsigned long link_faults;  /* # detected link faults */
 };
 
 struct tp_mib_stats {
@@ -701,6 +702,8 @@ int t3_phy_lasi_intr_handler(struct cphy *phy);
 void t3_intr_enable(struct adapter *adapter);
 void t3_intr_disable(struct adapter *adapter);
 void t3_intr_clear(struct adapter *adapter);
+void t3_xgm_intr_enable(struct adapter *adapter, int idx);
+void t3_xgm_intr_disable(struct adapter *adapter, int idx);
 void t3_port_intr_enable(struct adapter *adapter, int idx);
 void t3_port_intr_disable(struct adapter *adapter, int idx);
 void t3_port_intr_clear(struct adapter *adapter, int idx);
@@ -708,6 +711,7 @@ int t3_slow_intr_handler(struct adapter *adapter);
 int t3_phy_intr_handler(struct adapter *adapter);
 
 void t3_link_changed(struct adapter *adapter, int port_id);
+void t3_link_fault(struct adapter *adapter, int port_id);
 int t3_link_start(struct cphy *phy, struct cmac *mac, struct link_config *lc);
 const struct adapter_info *t3_get_adapter_info(unsigned int board_id);
 int t3_seeprom_read(struct adapter *adapter, u32 addr, __le32 *data);
@@ -744,6 +748,8 @@ int t3_mc7_bd_read(struct mc7 *mc7, unsigned int start, unsigned int n,
 
 int t3_mac_reset(struct cmac *mac);
 void t3b_pcs_reset(struct cmac *mac);
+void t3_mac_disable_exact_filters(struct cmac *mac);
+void t3_mac_enable_exact_filters(struct cmac *mac);
 int t3_mac_enable(struct cmac *mac, int which);
 int t3_mac_disable(struct cmac *mac, int which);
 int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu);
index 0f6062aaa2c6ab15aa0accf27f2f94d59abd6915..d8be89621bf746779d2b9961201f5a6d8c504bdb 100644 (file)
@@ -90,6 +90,7 @@ static const struct pci_device_id cxgb3_pci_tbl[] = {
        CH_DEVICE(0x30, 2),     /* T3B10 */
        CH_DEVICE(0x31, 3),     /* T3B20 */
        CH_DEVICE(0x32, 1),     /* T3B02 */
+       CH_DEVICE(0x35, 6),     /* T3C20-derived T3C10 */
        {0,}
 };
 
@@ -169,6 +170,40 @@ static void link_report(struct net_device *dev)
        }
 }
 
+void t3_os_link_fault(struct adapter *adap, int port_id, int state)
+{
+       struct net_device *dev = adap->port[port_id];
+       struct port_info *pi = netdev_priv(dev);
+
+       if (state == netif_carrier_ok(dev))
+               return;
+
+       if (state) {
+               struct cmac *mac = &pi->mac;
+
+               netif_carrier_on(dev);
+
+               /* Clear local faults */
+               t3_xgm_intr_disable(adap, pi->port_id);
+               t3_read_reg(adap, A_XGM_INT_STATUS +
+                                   pi->mac.offset);
+               t3_write_reg(adap,
+                            A_XGM_INT_CAUSE + pi->mac.offset,
+                            F_XGM_INT);
+
+               t3_set_reg_field(adap,
+                                A_XGM_INT_ENABLE +
+                                pi->mac.offset,
+                                F_XGM_INT, F_XGM_INT);
+               t3_xgm_intr_enable(adap, pi->port_id);
+
+               t3_mac_enable(mac, MAC_DIRECTION_TX);
+       } else
+               netif_carrier_off(dev);
+
+       link_report(dev);
+}
+
 /**
  *     t3_os_link_changed - handle link status changes
  *     @adapter: the adapter associated with the link change
@@ -196,10 +231,34 @@ void t3_os_link_changed(struct adapter *adapter, int port_id, int link_stat,
        if (link_stat != netif_carrier_ok(dev)) {
                if (link_stat) {
                        t3_mac_enable(mac, MAC_DIRECTION_RX);
+
+                       /* Clear local faults */
+                       t3_xgm_intr_disable(adapter, pi->port_id);
+                       t3_read_reg(adapter, A_XGM_INT_STATUS +
+                                   pi->mac.offset);
+                       t3_write_reg(adapter,
+                                    A_XGM_INT_CAUSE + pi->mac.offset,
+                                    F_XGM_INT);
+
+                       t3_set_reg_field(adapter,
+                                        A_XGM_INT_ENABLE + pi->mac.offset,
+                                        F_XGM_INT, F_XGM_INT);
+                       t3_xgm_intr_enable(adapter, pi->port_id);
+
                        netif_carrier_on(dev);
                } else {
                        netif_carrier_off(dev);
-                       pi->phy.ops->power_down(&pi->phy, 1);
+
+                       t3_xgm_intr_disable(adapter, pi->port_id);
+                       t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
+                       t3_set_reg_field(adapter,
+                                        A_XGM_INT_ENABLE + pi->mac.offset,
+                                        F_XGM_INT, 0);
+
+                       if (is_10G(adapter))
+                               pi->phy.ops->power_down(&pi->phy, 1);
+
+                       t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
                        t3_mac_disable(mac, MAC_DIRECTION_RX);
                        t3_link_start(&pi->phy, mac, &pi->link_config);
                }
@@ -1172,6 +1231,10 @@ static int cxgb_close(struct net_device *dev)
        struct port_info *pi = netdev_priv(dev);
        struct adapter *adapter = pi->adapter;
 
+       /* Stop link fault interrupts */
+       t3_xgm_intr_disable(adapter, pi->port_id);
+       t3_read_reg(adapter, A_XGM_INT_STATUS + pi->mac.offset);
+
        t3_port_intr_disable(adapter, pi->port_id);
        netif_tx_stop_all_queues(dev);
        pi->phy.ops->power_down(&pi->phy, 1);
@@ -1298,6 +1361,7 @@ static char stats_strings[][ETH_GSTRING_LEN] = {
        "CheckTXEnToggled   ",
        "CheckResets        ",
 
+       "LinkFaults         ",
 };
 
 static int get_sset_count(struct net_device *dev, int sset)
@@ -1430,6 +1494,8 @@ static void get_stats(struct net_device *dev, struct ethtool_stats *stats,
 
        *data++ = s->num_toggled;
        *data++ = s->num_resets;
+
+       *data++ = s->link_faults;
 }
 
 static inline void reg_block_dump(struct adapter *ap, void *buf,
@@ -2424,8 +2490,20 @@ static void check_link_status(struct adapter *adapter)
                struct net_device *dev = adapter->port[i];
                struct port_info *p = netdev_priv(dev);
 
-               if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev))
+               spin_lock_irq(&adapter->work_lock);
+               if (p->link_fault) {
+                       spin_unlock_irq(&adapter->work_lock);
+                       continue;
+               }
+               spin_unlock_irq(&adapter->work_lock);
+
+               if (!(p->phy.caps & SUPPORTED_IRQ) && netif_running(dev)) {
+                       t3_xgm_intr_disable(adapter, i);
+                       t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset);
+
                        t3_link_changed(adapter, i);
+                       t3_xgm_intr_enable(adapter, i);
+               }
        }
 }
 
@@ -2470,6 +2548,8 @@ static void t3_adap_check_task(struct work_struct *work)
        struct adapter *adapter = container_of(work, struct adapter,
                                               adap_check_task.work);
        const struct adapter_params *p = &adapter->params;
+       int port;
+       unsigned int v, status, reset;
 
        adapter->check_task_cnt++;
 
@@ -2488,6 +2568,54 @@ static void t3_adap_check_task(struct work_struct *work)
        if (p->rev == T3_REV_B2)
                check_t3b2_mac(adapter);
 
+       /*
+        * Scan the XGMAC's to check for various conditions which we want to
+        * monitor in a periodic polling manner rather than via an interrupt
+        * condition.  This is used for conditions which would otherwise flood
+        * the system with interrupts and we only really need to know that the
+        * conditions are "happening" ...  For each condition we count the
+        * detection of the condition and reset it for the next polling loop.
+        */
+       for_each_port(adapter, port) {
+               struct cmac *mac =  &adap2pinfo(adapter, port)->mac;
+               u32 cause;
+
+               cause = t3_read_reg(adapter, A_XGM_INT_CAUSE + mac->offset);
+               reset = 0;
+               if (cause & F_RXFIFO_OVERFLOW) {
+                       mac->stats.rx_fifo_ovfl++;
+                       reset |= F_RXFIFO_OVERFLOW;
+               }
+
+               t3_write_reg(adapter, A_XGM_INT_CAUSE + mac->offset, reset);
+       }
+
+       /*
+        * We do the same as above for FL_EMPTY interrupts.
+        */
+       status = t3_read_reg(adapter, A_SG_INT_CAUSE);
+       reset = 0;
+
+       if (status & F_FLEMPTY) {
+               struct sge_qset *qs = &adapter->sge.qs[0];
+               int i = 0;
+
+               reset |= F_FLEMPTY;
+
+               v = (t3_read_reg(adapter, A_SG_RSPQ_FL_STATUS) >> S_FL0EMPTY) &
+                   0xffff;
+
+               while (v) {
+                       qs->fl[i].empty += (v & 1);
+                       if (i)
+                               qs++;
+                       i ^= 1;
+                       v >>= 1;
+               }
+       }
+
+       t3_write_reg(adapter, A_SG_INT_CAUSE, reset);
+
        /* Schedule the next check update if any port is active. */
        spin_lock_irq(&adapter->work_lock);
        if (adapter->open_device_map & PORT_MASK)
@@ -2502,9 +2630,23 @@ static void ext_intr_task(struct work_struct *work)
 {
        struct adapter *adapter = container_of(work, struct adapter,
                                               ext_intr_handler_task);
+       int i;
 
+       /* Disable link fault interrupts */
+       for_each_port(adapter, i) {
+               struct net_device *dev = adapter->port[i];
+               struct port_info *p = netdev_priv(dev);
+
+               t3_xgm_intr_disable(adapter, i);
+               t3_read_reg(adapter, A_XGM_INT_STATUS + p->mac.offset);
+       }
+
+       /* Re-enable link fault interrupts */
        t3_phy_intr_handler(adapter);
 
+       for_each_port(adapter, i)
+               t3_xgm_intr_enable(adapter, i);
+
        /* Now reenable external interrupts */
        spin_lock_irq(&adapter->work_lock);
        if (adapter->slow_intr_mask) {
@@ -2537,6 +2679,32 @@ void t3_os_ext_intr_handler(struct adapter *adapter)
        spin_unlock(&adapter->work_lock);
 }
 
+static void link_fault_task(struct work_struct *work)
+{
+       struct adapter *adapter = container_of(work, struct adapter,
+                                              link_fault_handler_task);
+       int i;
+
+       for_each_port(adapter, i) {
+               struct net_device *netdev = adapter->port[i];
+               struct port_info *pi = netdev_priv(netdev);
+
+               if (pi->link_fault)
+                       t3_link_fault(adapter, i);
+       }
+}
+
+void t3_os_link_fault_handler(struct adapter *adapter, int port_id)
+{
+       struct net_device *netdev = adapter->port[port_id];
+       struct port_info *pi = netdev_priv(netdev);
+
+       spin_lock(&adapter->work_lock);
+       pi->link_fault = 1;
+       queue_work(cxgb3_wq, &adapter->link_fault_handler_task);
+       spin_unlock(&adapter->work_lock);
+}
+
 static int t3_adapter_error(struct adapter *adapter, int reset)
 {
        int i, ret = 0;
@@ -2653,7 +2821,6 @@ void t3_fatal_err(struct adapter *adapter)
                CH_ALERT(adapter, "FW status: 0x%x, 0x%x, 0x%x, 0x%x\n",
                         fw_status[0], fw_status[1],
                         fw_status[2], fw_status[3]);
-
 }
 
 /**
@@ -2911,6 +3078,7 @@ static int __devinit init_one(struct pci_dev *pdev,
 
        INIT_LIST_HEAD(&adapter->adapter_list);
        INIT_WORK(&adapter->ext_intr_handler_task, ext_intr_task);
+       INIT_WORK(&adapter->link_fault_handler_task, link_fault_task);
        INIT_WORK(&adapter->fatal_error_handler_task, fatal_error_task);
        INIT_DELAYED_WORK(&adapter->adap_check_task, t3_adap_check_task);
 
index a035d5c24442cf5e80dcf6d887586973618d6f2f..1b5327b5a965d14848b2afee5b30c4411c7ab056 100644 (file)
 
 #define S_RSPQ0DISABLED    8
 
+#define S_FL0EMPTY    16
+#define V_FL0EMPTY(x) ((x) << S_FL0EMPTY)
+#define F_FL0EMPTY    V_FL0EMPTY(1U)
+
 #define A_SG_EGR_RCQ_DRB_THRSH 0x54
 
 #define S_HIRCQDRBTHRSH    16
 #define V_RSPQCREDITOVERFOW(x) ((x) << S_RSPQCREDITOVERFOW)
 #define F_RSPQCREDITOVERFOW    V_RSPQCREDITOVERFOW(1U)
 
+#define S_FLEMPTY    1
+#define V_FLEMPTY(x) ((x) << S_FLEMPTY)
+#define F_FLEMPTY    V_FLEMPTY(1U)
+
 #define A_SG_INT_ENABLE 0x60
 
 #define A_SG_CMDQ_CREDIT_TH 0x64
 
 #define A_XGM_RX_EXACT_MATCH_LOW_8 0x854
 
+#define A_XGM_INT_STATUS 0x86c
+
+#define S_LINKFAULTCHANGE    9
+#define V_LINKFAULTCHANGE(x) ((x) << S_LINKFAULTCHANGE)
+#define F_LINKFAULTCHANGE    V_LINKFAULTCHANGE(1U)
+
+#define A_XGM_XGM_INT_ENABLE 0x874
+#define A_XGM_XGM_INT_DISABLE 0x878
+
 #define A_XGM_STAT_CTRL 0x880
 
 #define S_CLRSTATS    2
 #define V_XAUIPCSALIGNCHANGE(x) ((x) << S_XAUIPCSALIGNCHANGE)
 #define F_XAUIPCSALIGNCHANGE    V_XAUIPCSALIGNCHANGE(1U)
 
+#define S_XGM_INT    0
+#define V_XGM_INT(x) ((x) << S_XGM_INT)
+#define F_XGM_INT    V_XGM_INT(1U)
+
 #define A_XGM_INT_CAUSE 0x8d8
 
 #define A_XGM_XAUI_ACT_CTRL 0x8dc
index 8205aa4ae945bee947e8613b5dd18f1208142f4e..a7555cb3fa4a2aec944dc8ebf064d5b0fc1ee688 100644 (file)
 #define FL1_PG_ORDER (PAGE_SIZE > 8192 ? 0 : 1)
 
 #define SGE_RX_DROP_THRES 16
+#define RX_RECLAIM_PERIOD (HZ/4)
 
+/*
+ * Max number of Rx buffers we replenish at a time.
+ */
+#define MAX_RX_REFILL 16U
 /*
  * Period of the Tx buffer reclaim timer.  This timer does not need to run
  * frequently as Tx buffers are usually reclaimed by new Tx packets.
  */
 #define TX_RECLAIM_PERIOD (HZ / 4)
+#define TX_RECLAIM_TIMER_CHUNK 64U
+#define TX_RECLAIM_CHUNK 16U
 
 /* WR size in bytes */
 #define WR_LEN (WR_FLITS * 8)
@@ -304,21 +311,25 @@ static void free_tx_desc(struct adapter *adapter, struct sge_txq *q,
  *     reclaim_completed_tx - reclaims completed Tx descriptors
  *     @adapter: the adapter
  *     @q: the Tx queue to reclaim completed descriptors from
+ *     @chunk: maximum number of descriptors to reclaim
  *
  *     Reclaims Tx descriptors that the SGE has indicated it has processed,
  *     and frees the associated buffers if possible.  Called with the Tx
  *     queue's lock held.
  */
-static inline void reclaim_completed_tx(struct adapter *adapter,
-                                       struct sge_txq *q)
+static inline unsigned int reclaim_completed_tx(struct adapter *adapter,
+                                               struct sge_txq *q,
+                                               unsigned int chunk)
 {
        unsigned int reclaim = q->processed - q->cleaned;
 
+       reclaim = min(chunk, reclaim);
        if (reclaim) {
                free_tx_desc(adapter, q, reclaim);
                q->cleaned += reclaim;
                q->in_use -= reclaim;
        }
+       return q->processed - q->cleaned;
 }
 
 /**
@@ -334,6 +345,18 @@ static inline int should_restart_tx(const struct sge_txq *q)
        return q->in_use - r < (q->size >> 1);
 }
 
+static void clear_rx_desc(const struct sge_fl *q, struct rx_sw_desc *d)
+{
+       if (q->use_pages) {
+               if (d->pg_chunk.page)
+                       put_page(d->pg_chunk.page);
+               d->pg_chunk.page = NULL;
+       } else {
+               kfree_skb(d->skb);
+               d->skb = NULL;
+       }
+}
+
 /**
  *     free_rx_bufs - free the Rx buffers on an SGE free list
  *     @pdev: the PCI device associated with the adapter
@@ -351,14 +374,7 @@ static void free_rx_bufs(struct pci_dev *pdev, struct sge_fl *q)
 
                pci_unmap_single(pdev, pci_unmap_addr(d, dma_addr),
                                 q->buf_size, PCI_DMA_FROMDEVICE);
-               if (q->use_pages) {
-                       if (d->pg_chunk.page)
-                               put_page(d->pg_chunk.page);
-                       d->pg_chunk.page = NULL;
-               } else {
-                       kfree_skb(d->skb);
-                       d->skb = NULL;
-               }
+               clear_rx_desc(q, d);
                if (++cidx == q->size)
                        cidx = 0;
        }
@@ -423,6 +439,14 @@ static int alloc_pg_chunk(struct sge_fl *q, struct rx_sw_desc *sd, gfp_t gfp,
        return 0;
 }
 
+static inline void ring_fl_db(struct adapter *adap, struct sge_fl *q)
+{
+       if (q->pend_cred >= q->credits / 4) {
+               q->pend_cred = 0;
+               t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
+       }
+}
+
 /**
  *     refill_fl - refill an SGE free-buffer list
  *     @adapter: the adapter
@@ -463,10 +487,7 @@ nomem:                             q->alloc_failed++;
                err = add_one_rx_buf(buf_start, q->buf_size, d, sd, q->gen,
                                     adap->pdev);
                if (unlikely(err)) {
-                       if (!q->use_pages) {
-                               kfree_skb(sd->skb);
-                               sd->skb = NULL;
-                       }
+                       clear_rx_desc(q, sd);
                        break;
                }
 
@@ -478,19 +499,19 @@ nomem:                            q->alloc_failed++;
                        sd = q->sdesc;
                        d = q->desc;
                }
-               q->credits++;
                count++;
        }
-       wmb();
-       if (likely(count))
-               t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
+
+       q->credits += count;
+       q->pend_cred += count;
+       ring_fl_db(adap, q);
 
        return count;
 }
 
 static inline void __refill_fl(struct adapter *adap, struct sge_fl *fl)
 {
-       refill_fl(adap, fl, min(16U, fl->size - fl->credits),
+       refill_fl(adap, fl, min(MAX_RX_REFILL, fl->size - fl->credits),
                  GFP_ATOMIC | __GFP_COMP);
 }
 
@@ -515,13 +536,15 @@ static void recycle_rx_buf(struct adapter *adap, struct sge_fl *q,
        wmb();
        to->len_gen = cpu_to_be32(V_FLD_GEN1(q->gen));
        to->gen2 = cpu_to_be32(V_FLD_GEN2(q->gen));
-       q->credits++;
 
        if (++q->pidx == q->size) {
                q->pidx = 0;
                q->gen ^= 1;
        }
-       t3_write_reg(adap, A_SG_KDOORBELL, V_EGRCNTX(q->cntxt_id));
+
+       q->credits++;
+       q->pend_cred++;
+       ring_fl_db(adap, q);
 }
 
 /**
@@ -585,6 +608,7 @@ static void t3_reset_qset(struct sge_qset *q)
        memset(q->txq, 0, sizeof(struct sge_txq) * SGE_TXQ_PER_SET);
        q->txq_stopped = 0;
        q->tx_reclaim_timer.function = NULL; /* for t3_stop_sge_timers() */
+       q->rx_reclaim_timer.function = NULL;
        q->lro_frag_tbl.nr_frags = q->lro_frag_tbl.len = 0;
 }
 
@@ -732,7 +756,9 @@ recycle:
                return skb;
        }
 
-       if (unlikely(fl->credits < drop_thres))
+       if (unlikely(fl->credits < drop_thres) &&
+           refill_fl(adap, fl, min(MAX_RX_REFILL, fl->size - fl->credits - 1),
+                     GFP_ATOMIC | __GFP_COMP) == 0)
                goto recycle;
 
 use_orig_buf:
@@ -812,14 +838,15 @@ recycle:
                                   len - SGE_RX_PULL_LEN);
                newskb->len = len;
                newskb->data_len = len - SGE_RX_PULL_LEN;
+               newskb->truesize += newskb->data_len;
        } else {
                skb_fill_page_desc(newskb, skb_shinfo(newskb)->nr_frags,
                                   sd->pg_chunk.page,
                                   sd->pg_chunk.offset, len);
                newskb->len += len;
                newskb->data_len += len;
+               newskb->truesize += len;
        }
-       newskb->truesize += newskb->data_len;
 
        fl->credits--;
        /*
@@ -1160,7 +1187,7 @@ int t3_eth_xmit(struct sk_buff *skb, struct net_device *dev)
        txq = netdev_get_tx_queue(dev, qidx);
 
        spin_lock(&q->lock);
-       reclaim_completed_tx(adap, q);
+       reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
 
        credits = q->size - q->in_use;
        ndesc = calc_tx_descs(skb);
@@ -1569,7 +1596,7 @@ static int ofld_xmit(struct adapter *adap, struct sge_txq *q,
        unsigned int ndesc = calc_tx_descs_ofld(skb), pidx, gen;
 
        spin_lock(&q->lock);
-      again:reclaim_completed_tx(adap, q);
+again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
 
        ret = check_desc_avail(adap, q, skb, ndesc, TXQ_OFLD);
        if (unlikely(ret)) {
@@ -1611,7 +1638,7 @@ static void restart_offloadq(unsigned long data)
        struct adapter *adap = pi->adapter;
 
        spin_lock(&q->lock);
-      again:reclaim_completed_tx(adap, q);
+again: reclaim_completed_tx(adap, q, TX_RECLAIM_CHUNK);
 
        while ((skb = skb_peek(&q->sendq)) != NULL) {
                unsigned int gen, pidx;
@@ -2010,6 +2037,8 @@ static void lro_add_page(struct adapter *adap, struct sge_qset *qs,
        pci_unmap_single(adap->pdev, pci_unmap_addr(sd, dma_addr),
                         fl->buf_size, PCI_DMA_FROMDEVICE);
 
+       prefetch(&qs->lro_frag_tbl);
+
        rx_frag += nr_frags;
        rx_frag->page = sd->pg_chunk.page;
        rx_frag->page_offset = sd->pg_chunk.offset + offset;
@@ -2696,7 +2725,8 @@ irq_handler_t t3_intr_handler(struct adapter *adap, int polling)
  */
 void t3_sge_err_intr_handler(struct adapter *adapter)
 {
-       unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE);
+       unsigned int v, status = t3_read_reg(adapter, A_SG_INT_CAUSE) &
+                                ~F_FLEMPTY;
 
        if (status & SGE_PARERR)
                CH_ALERT(adapter, "SGE parity error (0x%x)\n",
@@ -2726,13 +2756,13 @@ void t3_sge_err_intr_handler(struct adapter *adapter)
 }
 
 /**
- *     sge_timer_cb - perform periodic maintenance of an SGE qset
+ *     sge_timer_tx - perform periodic maintenance of an SGE qset
  *     @data: the SGE queue set to maintain
  *
  *     Runs periodically from a timer to perform maintenance of an SGE queue
  *     set.  It performs two tasks:
  *
- *     a) Cleans up any completed Tx descriptors that may still be pending.
+ *     Cleans up any completed Tx descriptors that may still be pending.
  *     Normal descriptor cleanup happens when new packets are added to a Tx
  *     queue so this timer is relatively infrequent and does any cleanup only
  *     if the Tx queue has not seen any new packets in a while.  We make a
@@ -2742,51 +2772,87 @@ void t3_sge_err_intr_handler(struct adapter *adapter)
  *     up).  Since control queues use immediate data exclusively we don't
  *     bother cleaning them up here.
  *
- *     b) Replenishes Rx queues that have run out due to memory shortage.
- *     Normally new Rx buffers are added when existing ones are consumed but
- *     when out of memory a queue can become empty.  We try to add only a few
- *     buffers here, the queue will be replenished fully as these new buffers
- *     are used up if memory shortage has subsided.
  */
-static void sge_timer_cb(unsigned long data)
+static void sge_timer_tx(unsigned long data)
 {
-       spinlock_t *lock;
        struct sge_qset *qs = (struct sge_qset *)data;
-       struct adapter *adap = qs->adap;
+       struct port_info *pi = netdev_priv(qs->netdev);
+       struct adapter *adap = pi->adapter;
+       unsigned int tbd[SGE_TXQ_PER_SET] = {0, 0};
+       unsigned long next_period;
 
        if (spin_trylock(&qs->txq[TXQ_ETH].lock)) {
-               reclaim_completed_tx(adap, &qs->txq[TXQ_ETH]);
+               tbd[TXQ_ETH] = reclaim_completed_tx(adap, &qs->txq[TXQ_ETH],
+                                                   TX_RECLAIM_TIMER_CHUNK);
                spin_unlock(&qs->txq[TXQ_ETH].lock);
        }
        if (spin_trylock(&qs->txq[TXQ_OFLD].lock)) {
-               reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD]);
+               tbd[TXQ_OFLD] = reclaim_completed_tx(adap, &qs->txq[TXQ_OFLD],
+                                                    TX_RECLAIM_TIMER_CHUNK);
                spin_unlock(&qs->txq[TXQ_OFLD].lock);
        }
-       lock = (adap->flags & USING_MSIX) ? &qs->rspq.lock :
-                                           &adap->sge.qs[0].rspq.lock;
-       if (spin_trylock_irq(lock)) {
-               if (!napi_is_scheduled(&qs->napi)) {
-                       u32 status = t3_read_reg(adap, A_SG_RSPQ_FL_STATUS);
-
-                       if (qs->fl[0].credits < qs->fl[0].size)
-                               __refill_fl(adap, &qs->fl[0]);
-                       if (qs->fl[1].credits < qs->fl[1].size)
-                               __refill_fl(adap, &qs->fl[1]);
-
-                       if (status & (1 << qs->rspq.cntxt_id)) {
-                               qs->rspq.starved++;
-                               if (qs->rspq.credits) {
-                                       refill_rspq(adap, &qs->rspq, 1);
-                                       qs->rspq.credits--;
-                                       qs->rspq.restarted++;
-                                       t3_write_reg(adap, A_SG_RSPQ_FL_STATUS,
-                                                    1 << qs->rspq.cntxt_id);
-                               }
+
+       next_period = TX_RECLAIM_PERIOD >>
+                     (max(tbd[TXQ_ETH], tbd[TXQ_OFLD]) /
+                      TX_RECLAIM_TIMER_CHUNK);
+       mod_timer(&qs->tx_reclaim_timer, jiffies + next_period);
+}
+
+/*
+ *     sge_timer_rx - perform periodic maintenance of an SGE qset
+ *     @data: the SGE queue set to maintain
+ *
+ *     a) Replenishes Rx queues that have run out due to memory shortage.
+ *     Normally new Rx buffers are added when existing ones are consumed but
+ *     when out of memory a queue can become empty.  We try to add only a few
+ *     buffers here, the queue will be replenished fully as these new buffers
+ *     are used up if memory shortage has subsided.
+ *
+ *     b) Return coalesced response queue credits in case a response queue is
+ *     starved.
+ *
+ */
+static void sge_timer_rx(unsigned long data)
+{
+       spinlock_t *lock;
+       struct sge_qset *qs = (struct sge_qset *)data;
+       struct port_info *pi = netdev_priv(qs->netdev);
+       struct adapter *adap = pi->adapter;
+       u32 status;
+
+       lock = adap->params.rev > 0 ?
+              &qs->rspq.lock : &adap->sge.qs[0].rspq.lock;
+
+       if (!spin_trylock_irq(lock))
+               goto out;
+
+       if (napi_is_scheduled(&qs->napi))
+               goto unlock;
+
+       if (adap->params.rev < 4) {
+               status = t3_read_reg(adap, A_SG_RSPQ_FL_STATUS);
+
+               if (status & (1 << qs->rspq.cntxt_id)) {
+                       qs->rspq.starved++;
+                       if (qs->rspq.credits) {
+                               qs->rspq.credits--;
+                               refill_rspq(adap, &qs->rspq, 1);
+                               qs->rspq.restarted++;
+                               t3_write_reg(adap, A_SG_RSPQ_FL_STATUS,
+                                            1 << qs->rspq.cntxt_id);
                        }
                }
-               spin_unlock_irq(lock);
        }
-       mod_timer(&qs->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
+
+       if (qs->fl[0].credits < qs->fl[0].size)
+               __refill_fl(adap, &qs->fl[0]);
+       if (qs->fl[1].credits < qs->fl[1].size)
+               __refill_fl(adap, &qs->fl[1]);
+
+unlock:
+       spin_unlock_irq(lock);
+out:
+       mod_timer(&qs->rx_reclaim_timer, jiffies + RX_RECLAIM_PERIOD);
 }
 
 /**
@@ -2829,7 +2895,8 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
        struct sge_qset *q = &adapter->sge.qs[id];
 
        init_qset_cntxt(q, id);
-       setup_timer(&q->tx_reclaim_timer, sge_timer_cb, (unsigned long)q);
+       setup_timer(&q->tx_reclaim_timer, sge_timer_tx, (unsigned long)q);
+       setup_timer(&q->rx_reclaim_timer, sge_timer_rx, (unsigned long)q);
 
        q->fl[0].desc = alloc_ring(adapter->pdev, p->fl_size,
                                   sizeof(struct rx_desc),
@@ -2978,6 +3045,8 @@ int t3_sge_alloc_qset(struct adapter *adapter, unsigned int id, int nports,
                     V_NEWTIMER(q->rspq.holdoff_tmr));
 
        mod_timer(&q->tx_reclaim_timer, jiffies + TX_RECLAIM_PERIOD);
+       mod_timer(&q->rx_reclaim_timer, jiffies + RX_RECLAIM_PERIOD);
+
        return 0;
 
 err_unlock:
@@ -3002,6 +3071,8 @@ void t3_stop_sge_timers(struct adapter *adap)
 
                if (q->tx_reclaim_timer.function)
                        del_timer_sync(&q->tx_reclaim_timer);
+               if (q->rx_reclaim_timer.function)
+                       del_timer_sync(&q->rx_reclaim_timer);
        }
 }
 
index 2d1433077a8ee992a71ed1e89210ebf8749de816..ff262a04ded060ad227393b207a6454b80dce0bc 100644 (file)
@@ -512,6 +512,13 @@ static const struct adapter_info t3_adap_info[] = {
         F_GPIO5_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
         { S_GPIO9, S_GPIO3 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
         &mi1_mdio_ext_ops, "Chelsio T320"},
+       {},
+       {},
+       {1, 0,
+        F_GPIO1_OEN | F_GPIO2_OEN | F_GPIO4_OEN | F_GPIO6_OEN | F_GPIO7_OEN |
+        F_GPIO10_OEN | F_GPIO1_OUT_VAL | F_GPIO6_OUT_VAL | F_GPIO10_OUT_VAL,
+        { S_GPIO9 }, SUPPORTED_10000baseT_Full | SUPPORTED_AUI,
+        &mi1_mdio_ext_ops, "Chelsio T310" },
 };
 
 /*
@@ -1146,6 +1153,38 @@ int t3_cim_ctl_blk_read(struct adapter *adap, unsigned int addr,
        return ret;
 }
 
+static void t3_gate_rx_traffic(struct cmac *mac, u32 *rx_cfg,
+                              u32 *rx_hash_high, u32 *rx_hash_low)
+{
+       /* stop Rx unicast traffic */
+       t3_mac_disable_exact_filters(mac);
+
+       /* stop broadcast, multicast, promiscuous mode traffic */
+       *rx_cfg = t3_read_reg(mac->adapter, A_XGM_RX_CFG);
+       t3_set_reg_field(mac->adapter, A_XGM_RX_CFG,
+                        F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES,
+                        F_DISBCAST);
+
+       *rx_hash_high = t3_read_reg(mac->adapter, A_XGM_RX_HASH_HIGH);
+       t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH, 0);
+
+       *rx_hash_low = t3_read_reg(mac->adapter, A_XGM_RX_HASH_LOW);
+       t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW, 0);
+
+       /* Leave time to drain max RX fifo */
+       msleep(1);
+}
+
+static void t3_open_rx_traffic(struct cmac *mac, u32 rx_cfg,
+                              u32 rx_hash_high, u32 rx_hash_low)
+{
+       t3_mac_enable_exact_filters(mac);
+       t3_set_reg_field(mac->adapter, A_XGM_RX_CFG,
+                        F_ENHASHMCAST | F_DISBCAST | F_COPYALLFRAMES,
+                        rx_cfg);
+       t3_write_reg(mac->adapter, A_XGM_RX_HASH_HIGH, rx_hash_high);
+       t3_write_reg(mac->adapter, A_XGM_RX_HASH_LOW, rx_hash_low);
+}
 
 /**
  *     t3_link_changed - handle interface link changes
@@ -1163,9 +1202,32 @@ void t3_link_changed(struct adapter *adapter, int port_id)
        struct cphy *phy = &pi->phy;
        struct cmac *mac = &pi->mac;
        struct link_config *lc = &pi->link_config;
+       int force_link_down = 0;
 
        phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
 
+       if (!lc->link_ok && link_ok) {
+               u32 rx_cfg, rx_hash_high, rx_hash_low;
+               u32 status;
+
+               t3_xgm_intr_enable(adapter, port_id);
+               t3_gate_rx_traffic(mac, &rx_cfg, &rx_hash_high, &rx_hash_low);
+               t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0);
+               t3_mac_enable(mac, MAC_DIRECTION_RX);
+
+               status = t3_read_reg(adapter, A_XGM_INT_STATUS + mac->offset);
+               if (status & F_LINKFAULTCHANGE) {
+                       mac->stats.link_faults++;
+                       force_link_down = 1;
+               }
+               t3_open_rx_traffic(mac, rx_cfg, rx_hash_high, rx_hash_low);
+
+               if (force_link_down) {
+                       t3_os_link_fault_handler(adapter, port_id);
+                       return;
+               }
+       }
+
        if (lc->requested_fc & PAUSE_AUTONEG)
                fc &= lc->requested_fc;
        else
@@ -1195,6 +1257,57 @@ void t3_link_changed(struct adapter *adapter, int port_id)
        t3_os_link_changed(adapter, port_id, link_ok, speed, duplex, fc);
 }
 
+void t3_link_fault(struct adapter *adapter, int port_id)
+{
+       struct port_info *pi = adap2pinfo(adapter, port_id);
+       struct cmac *mac = &pi->mac;
+       struct cphy *phy = &pi->phy;
+       struct link_config *lc = &pi->link_config;
+       int link_ok, speed, duplex, fc, link_fault;
+       u32 rx_cfg, rx_hash_high, rx_hash_low;
+
+       t3_gate_rx_traffic(mac, &rx_cfg, &rx_hash_high, &rx_hash_low);
+
+       if (adapter->params.rev > 0 && uses_xaui(adapter))
+               t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset, 0);
+
+       t3_write_reg(adapter, A_XGM_RX_CTRL + mac->offset, 0);
+       t3_mac_enable(mac, MAC_DIRECTION_RX);
+
+       t3_open_rx_traffic(mac, rx_cfg, rx_hash_high, rx_hash_low);
+
+       link_fault = t3_read_reg(adapter,
+                                A_XGM_INT_STATUS + mac->offset);
+       link_fault &= F_LINKFAULTCHANGE;
+
+       phy->ops->get_link_status(phy, &link_ok, &speed, &duplex, &fc);
+
+       if (link_fault) {
+               lc->link_ok = 0;
+               lc->speed = SPEED_INVALID;
+               lc->duplex = DUPLEX_INVALID;
+
+               t3_os_link_fault(adapter, port_id, 0);
+
+               /* Account link faults only when the phy reports a link up */
+               if (link_ok)
+                       mac->stats.link_faults++;
+
+               msleep(1000);
+               t3_os_link_fault_handler(adapter, port_id);
+       } else {
+               if (link_ok)
+                       t3_write_reg(adapter, A_XGM_XAUI_ACT_CTRL + mac->offset,
+                                    F_TXACTENABLE | F_RXEN);
+
+               pi->link_fault = 0;
+               lc->link_ok = (unsigned char)link_ok;
+               lc->speed = speed < 0 ? SPEED_INVALID : speed;
+               lc->duplex = duplex < 0 ? DUPLEX_INVALID : duplex;
+               t3_os_link_fault(adapter, port_id, link_ok);
+       }
+}
+
 /**
  *     t3_link_start - apply link configuration to MAC/PHY
  *     @phy: the PHY to setup
@@ -1316,7 +1429,7 @@ static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
 #define MC7_INTR_MASK (F_AE | F_UE | F_CE | V_PE(M_PE))
 #define XGM_INTR_MASK (V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR) | \
                       V_RXFIFO_PRTY_ERR(M_RXFIFO_PRTY_ERR) | \
-                      F_TXFIFO_UNDERRUN | F_RXFIFO_OVERFLOW)
+                      F_TXFIFO_UNDERRUN)
 #define PCIX_INTR_MASK (F_MSTDETPARERR | F_SIGTARABT | F_RCVTARABT | \
                        F_RCVMSTABT | F_SIGSYSERR | F_DETPARERR | \
                        F_SPLCMPDIS | F_UNXSPLCMP | F_RCVSPLCMPERR | \
@@ -1353,11 +1466,11 @@ static int t3_handle_intr_status(struct adapter *adapter, unsigned int reg,
                       V_TX1TPPARERRENB(M_TX1TPPARERRENB) | \
                       V_RXTPPARERRENB(M_RXTPPARERRENB) | \
                       V_MCAPARERRENB(M_MCAPARERRENB))
+#define XGM_EXTRA_INTR_MASK (F_LINKFAULTCHANGE)
 #define PL_INTR_MASK (F_T3DBG | F_XGMAC0_0 | F_XGMAC0_1 | F_MC5A | F_PM1_TX | \
                      F_PM1_RX | F_ULP2_TX | F_ULP2_RX | F_TP1 | F_CIM | \
                      F_MC7_CM | F_MC7_PMTX | F_MC7_PMRX | F_SGE3 | F_PCIM0 | \
                      F_MPS0 | F_CPL_SWITCH)
-
 /*
  * Interrupt handler for the PCIX1 module.
  */
@@ -1688,7 +1801,14 @@ static void mc7_intr_handler(struct mc7 *mc7)
 static int mac_intr_handler(struct adapter *adap, unsigned int idx)
 {
        struct cmac *mac = &adap2pinfo(adap, idx)->mac;
-       u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset);
+       /*
+        * We mask out interrupt causes for which we're not taking interrupts.
+        * This allows us to use polling logic to monitor some of the other
+        * conditions when taking interrupts would impose too much load on the
+        * system.
+        */
+       u32 cause = t3_read_reg(adap, A_XGM_INT_CAUSE + mac->offset) &
+                   ~F_RXFIFO_OVERFLOW;
 
        if (cause & V_TXFIFO_PRTY_ERR(M_TXFIFO_PRTY_ERR)) {
                mac->stats.tx_fifo_parity_err++;
@@ -1708,10 +1828,20 @@ static int mac_intr_handler(struct adapter *adap, unsigned int idx)
                mac->stats.xaui_pcs_ctc_err++;
        if (cause & F_XAUIPCSALIGNCHANGE)
                mac->stats.xaui_pcs_align_change++;
+       if (cause & F_XGM_INT) {
+               t3_set_reg_field(adap,
+                                A_XGM_INT_ENABLE + mac->offset,
+                                F_XGM_INT, 0);
+               mac->stats.link_faults++;
+
+               t3_os_link_fault_handler(adap, idx);
+       }
 
        t3_write_reg(adap, A_XGM_INT_CAUSE + mac->offset, cause);
+
        if (cause & XGM_INTR_FATAL)
                t3_fatal_err(adap);
+
        return cause != 0;
 }
 
@@ -1917,6 +2047,22 @@ void t3_intr_clear(struct adapter *adapter)
        t3_read_reg(adapter, A_PL_INT_CAUSE0);  /* flush */
 }
 
+void t3_xgm_intr_enable(struct adapter *adapter, int idx)
+{
+       struct port_info *pi = adap2pinfo(adapter, idx);
+
+       t3_write_reg(adapter, A_XGM_XGM_INT_ENABLE + pi->mac.offset,
+                    XGM_EXTRA_INTR_MASK);
+}
+
+void t3_xgm_intr_disable(struct adapter *adapter, int idx)
+{
+       struct port_info *pi = adap2pinfo(adapter, idx);
+
+       t3_write_reg(adapter, A_XGM_XGM_INT_DISABLE + pi->mac.offset,
+                    0x7ff);
+}
+
 /**
  *     t3_port_intr_enable - enable port-specific interrupts
  *     @adapter: associated adapter
@@ -3610,7 +3756,15 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
        adapter->params.info = ai;
        adapter->params.nports = ai->nports;
        adapter->params.rev = t3_read_reg(adapter, A_PL_REV);
-       adapter->params.linkpoll_period = 0;
+       /*
+        * We used to only run the "adapter check task" once a second if
+        * we had PHYs which didn't support interrupts (we would check
+        * their link status once a second).  Now we check other conditions
+        * in that routine which could potentially impose a very high
+        * interrupt load on the system.  As such, we now always scan the
+        * adapter state once a second ...
+        */
+       adapter->params.linkpoll_period = 10;
        adapter->params.stats_update_period = is_10G(adapter) ?
            MAC_STATS_ACCUM_SECS : (MAC_STATS_ACCUM_SECS * 10);
        adapter->params.pci.vpd_cap_addr =
@@ -3700,7 +3854,14 @@ int t3_prep_adapter(struct adapter *adapter, const struct adapter_info *ai,
                       ETH_ALEN);
                init_link_config(&p->link_config, p->phy.caps);
                p->phy.ops->power_down(&p->phy, 1);
-               if (!(p->phy.caps & SUPPORTED_IRQ))
+
+               /*
+                * If the PHY doesn't support interrupts for link status
+                * changes, schedule a scan of the adapter links at least
+                * once a second.
+                */
+               if (!(p->phy.caps & SUPPORTED_IRQ) &&
+                   adapter->params.linkpoll_period > 10)
                        adapter->params.linkpoll_period = 10;
        }
 
index b1b25c37aa1062099cbb38dbeafc0a6ce2d476de..7bf963ec55483792e3ac4edfdd042870d14afeed 100644 (file)
 #define DRV_DESC "Chelsio T3 Network Driver"
 #define DRV_NAME "cxgb3"
 /* Driver version */
-#define DRV_VERSION "1.1.1-ko"
+#define DRV_VERSION "1.1.2-ko"
 
 /* Firmware version */
 #define FW_VERSION_MAJOR 7
-#define FW_VERSION_MINOR 0
+#define FW_VERSION_MINOR 1
 #define FW_VERSION_MICRO 0
 #endif                         /* __CHELSIO_VERSION_H */
index 9d7786937aadf4c7e806d3bec7c6c58e8dd46d04..f87f9435049f312c77629f581f915aa3a3ba4bd1 100644 (file)
@@ -150,7 +150,8 @@ int t3_mac_reset(struct cmac *mac)
 static int t3b2_mac_reset(struct cmac *mac)
 {
        struct adapter *adap = mac->adapter;
-       unsigned int oft = mac->offset;
+       unsigned int oft = mac->offset, store;
+       int idx = macidx(mac);
        u32 val;
 
        if (!macidx(mac))
@@ -158,14 +159,28 @@ static int t3b2_mac_reset(struct cmac *mac)
        else
                t3_set_reg_field(adap, A_MPS_CFG, F_PORT1ACTIVE, 0);
 
+       /* Stop NIC traffic to reduce the number of TXTOGGLES */
+       t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 0);
+       /* Ensure TX drains */
+       t3_set_reg_field(adap, A_XGM_TX_CFG + oft, F_TXPAUSEEN, 0);
+
        t3_write_reg(adap, A_XGM_RESET_CTRL + oft, F_MAC_RESET_);
        t3_read_reg(adap, A_XGM_RESET_CTRL + oft);    /* flush */
 
+       /* Store A_TP_TX_DROP_CFG_CH0 */
+       t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
+       store = t3_read_reg(adap, A_TP_TX_DROP_CFG_CH0 + idx);
+
        msleep(10);
 
+       /* Change DROP_CFG to 0xc0000011 */
+       t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
+       t3_write_reg(adap, A_TP_PIO_DATA, 0xc0000011);
+
        /* Check for xgm Rx fifo empty */
+       /* Increased loop count to 1000 from 5 cover 1G and 100Mbps case */
        if (t3_wait_op_done(adap, A_XGM_RX_MAX_PKT_SIZE_ERR_CNT + oft,
-                           0x80000000, 1, 5, 2)) {
+                           0x80000000, 1, 1000, 2)) {
                CH_ERR(adap, "MAC %d Rx fifo drain failed\n",
                       macidx(mac));
                return -1;
@@ -191,11 +206,21 @@ static int t3b2_mac_reset(struct cmac *mac)
                     F_DISPAUSEFRAMES | F_EN1536BFRAMES |
                     F_RMFCS | F_ENJUMBO | F_ENHASHMCAST);
 
-       if (!macidx(mac))
+       /* Restore the DROP_CFG */
+       t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
+       t3_write_reg(adap, A_TP_PIO_DATA, store);
+
+       if (!idx)
                t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT0ACTIVE);
        else
                t3_set_reg_field(adap, A_MPS_CFG, 0, F_PORT1ACTIVE);
 
+       /* re-enable nic traffic */
+       t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1);
+
+       /*  Set: re-enable NIC traffic */
+       t3_set_reg_field(adap, A_MPS_CFG, F_ENFORCEPKT, 1);
+
        return 0;
 }
 
@@ -236,7 +261,7 @@ int t3_mac_set_num_ucast(struct cmac *mac, int n)
        return 0;
 }
 
-static void disable_exact_filters(struct cmac *mac)
+void t3_mac_disable_exact_filters(struct cmac *mac)
 {
        unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_LOW_1;
 
@@ -247,7 +272,7 @@ static void disable_exact_filters(struct cmac *mac)
        t3_read_reg(mac->adapter, A_XGM_RX_EXACT_MATCH_LOW_1);  /* flush */
 }
 
-static void enable_exact_filters(struct cmac *mac)
+void t3_mac_enable_exact_filters(struct cmac *mac)
 {
        unsigned int i, reg = mac->offset + A_XGM_RX_EXACT_MATCH_HIGH_1;
 
@@ -332,18 +357,9 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
                return -EINVAL;
        t3_write_reg(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset, mtu);
 
-       /*
-        * Adjust the PAUSE frame watermarks.  We always set the LWM, and the
-        * HWM only if flow-control is enabled.
-        */
-       hwm = max_t(unsigned int, MAC_RXFIFO_SIZE - 3 * mtu,
-                   MAC_RXFIFO_SIZE * 38 / 100);
-       hwm = min(hwm, MAC_RXFIFO_SIZE - 8192);
-       lwm = min(3 * (int)mtu, MAC_RXFIFO_SIZE / 4);
-
        if (adap->params.rev >= T3_REV_B2 &&
            (t3_read_reg(adap, A_XGM_RX_CTRL + mac->offset) & F_RXEN)) {
-               disable_exact_filters(mac);
+               t3_mac_disable_exact_filters(mac);
                v = t3_read_reg(adap, A_XGM_RX_CFG + mac->offset);
                t3_set_reg_field(adap, A_XGM_RX_CFG + mac->offset,
                                 F_ENHASHMCAST | F_COPYALLFRAMES, F_DISBCAST);
@@ -355,14 +371,14 @@ int t3_mac_set_mtu(struct cmac *mac, unsigned int mtu)
                if (t3_wait_op_done(adap, reg + mac->offset,
                                    F_RXFIFO_EMPTY, 1, 20, 5)) {
                        t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
-                       enable_exact_filters(mac);
+                       t3_mac_enable_exact_filters(mac);
                        return -EIO;
                }
                t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
                                 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
                                 V_RXMAXPKTSIZE(mtu));
                t3_write_reg(adap, A_XGM_RX_CFG + mac->offset, v);
-               enable_exact_filters(mac);
+               t3_mac_enable_exact_filters(mac);
        } else
                t3_set_reg_field(adap, A_XGM_RX_MAX_PKT_SIZE + mac->offset,
                                 V_RXMAXPKTSIZE(M_RXMAXPKTSIZE),
@@ -452,9 +468,12 @@ int t3_mac_enable(struct cmac *mac, int which)
 
        if (which & MAC_DIRECTION_TX) {
                t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_CFG_CH0 + idx);
-               t3_write_reg(adap, A_TP_PIO_DATA, 0xc0ede401);
+               t3_write_reg(adap, A_TP_PIO_DATA,
+                            adap->params.rev == T3_REV_C ?
+                            0xc4ffff01 : 0xc0ede401);
                t3_write_reg(adap, A_TP_PIO_ADDR, A_TP_TX_DROP_MODE);
-               t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx, 1 << idx);
+               t3_set_reg_field(adap, A_TP_PIO_DATA, 1 << idx,
+                                adap->params.rev == T3_REV_C ? 0 : 1 << idx);
 
                t3_write_reg(adap, A_XGM_TX_CTRL + oft, F_TXEN);
 
@@ -510,15 +529,12 @@ int t3b2_mac_watchdog_task(struct cmac *mac)
        struct adapter *adap = mac->adapter;
        struct mac_stats *s = &mac->stats;
        unsigned int tx_tcnt, tx_xcnt;
-       unsigned int tx_mcnt = s->tx_frames;
-       unsigned int rx_mcnt = s->rx_frames;
-       unsigned int rx_xcnt;
+       u64 tx_mcnt = s->tx_frames;
        int status;
 
        status = 0;
        tx_xcnt = 1;            /* By default tx_xcnt is making progress */
        tx_tcnt = mac->tx_tcnt; /* If tx_mcnt is progressing ignore tx_tcnt */
-       rx_xcnt = 1;            /* By default rx_xcnt is making progress */
        if (tx_mcnt == mac->tx_mcnt && mac->rx_pause == s->rx_pause) {
                tx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
                                                A_XGM_TX_SPI4_SOP_EOP_CNT +
@@ -529,11 +545,11 @@ int t3b2_mac_watchdog_task(struct cmac *mac)
                        tx_tcnt = (G_TXDROPCNTCH0RCVD(t3_read_reg(adap,
                                                      A_TP_PIO_DATA)));
                } else {
-                       goto rxcheck;
+                       goto out;
                }
        } else {
                mac->toggle_cnt = 0;
-               goto rxcheck;
+               goto out;
        }
 
        if ((tx_tcnt != mac->tx_tcnt) && (mac->tx_xcnt == 0)) {
@@ -546,23 +562,6 @@ int t3b2_mac_watchdog_task(struct cmac *mac)
                }
        } else {
                mac->toggle_cnt = 0;
-               goto rxcheck;
-       }
-
-rxcheck:
-       if (rx_mcnt != mac->rx_mcnt) {
-               rx_xcnt = (G_TXSPI4SOPCNT(t3_read_reg(adap,
-                                               A_XGM_RX_SPI4_SOP_EOP_CNT +
-                                               mac->offset))) +
-                                               (s->rx_fifo_ovfl -
-                                                mac->rx_ocnt);
-               mac->rx_ocnt = s->rx_fifo_ovfl;
-       } else
-               goto out;
-
-       if (mac->rx_mcnt != s->rx_frames && rx_xcnt == 0 &&
-           mac->rx_xcnt == 0) {
-               status = 2;
                goto out;
        }
 
@@ -570,8 +569,6 @@ out:
        mac->tx_tcnt = tx_tcnt;
        mac->tx_xcnt = tx_xcnt;
        mac->tx_mcnt = s->tx_frames;
-       mac->rx_xcnt = rx_xcnt;
-       mac->rx_mcnt = s->rx_frames;
        mac->rx_pause = s->rx_pause;
        if (status == 1) {
                t3_write_reg(adap, A_XGM_TX_CTRL + mac->offset, 0);
index bcf92917bbf3192504bd90e48e4165716615208d..254ec62b5f58d4e13f3848040362e7660108b6d3 100644 (file)
@@ -930,13 +930,15 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
        struct net_device *dev = dev_id;
        board_info_t *db = netdev_priv(dev);
        int int_status;
+       unsigned long flags;
        u8 reg_save;
 
        dm9000_dbg(db, 3, "entering %s\n", __func__);
 
        /* A real interrupt coming */
 
-       spin_lock(&db->lock);
+       /* holders of db->lock must always block IRQs */
+       spin_lock_irqsave(&db->lock, flags);
 
        /* Save previous register address */
        reg_save = readb(db->io_addr);
@@ -972,7 +974,7 @@ static irqreturn_t dm9000_interrupt(int irq, void *dev_id)
        /* Restore previous register address */
        writeb(reg_save, db->io_addr);
 
-       spin_unlock(&db->lock);
+       spin_unlock_irqrestore(&db->lock, flags);
 
        return IRQ_HANDLED;
 }
diff --git a/drivers/net/dnet.c b/drivers/net/dnet.c
new file mode 100644 (file)
index 0000000..c05c2d6
--- /dev/null
@@ -0,0 +1,993 @@
+/*
+ * Dave DNET Ethernet Controller driver
+ *
+ * Copyright (C) 2008 Dave S.r.l. <www.dave.eu>
+ * Copyright (C) 2009 Ilya Yanok, Emcraft Systems Ltd, <yanok@emcraft.com>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+#include <linux/version.h>
+#include <linux/module.h>
+#include <linux/moduleparam.h>
+#include <linux/kernel.h>
+#include <linux/types.h>
+#include <linux/slab.h>
+#include <linux/delay.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/dma-mapping.h>
+#include <linux/platform_device.h>
+#include <linux/phy.h>
+
+#include "dnet.h"
+
+#undef DEBUG
+
+/* function for reading internal MAC register */
+u16 dnet_readw_mac(struct dnet *bp, u16 reg)
+{
+       u16 data_read;
+
+       /* issue a read */
+       dnet_writel(bp, reg, MACREG_ADDR);
+
+       /* since a read/write op to the MAC is very slow,
+        * we must wait before reading the data */
+       ndelay(500);
+
+       /* read data read from the MAC register */
+       data_read = dnet_readl(bp, MACREG_DATA);
+
+       /* all done */
+       return data_read;
+}
+
+/* function for writing internal MAC register */
+void dnet_writew_mac(struct dnet *bp, u16 reg, u16 val)
+{
+       /* load data to write */
+       dnet_writel(bp, val, MACREG_DATA);
+
+       /* issue a write */
+       dnet_writel(bp, reg | DNET_INTERNAL_WRITE, MACREG_ADDR);
+
+       /* since a read/write op to the MAC is very slow,
+        * we must wait before exiting */
+       ndelay(500);
+}
+
+static void __dnet_set_hwaddr(struct dnet *bp)
+{
+       u16 tmp;
+
+       tmp = cpu_to_be16(*((u16 *) bp->dev->dev_addr));
+       dnet_writew_mac(bp, DNET_INTERNAL_MAC_ADDR_0_REG, tmp);
+       tmp = cpu_to_be16(*((u16 *) (bp->dev->dev_addr + 2)));
+       dnet_writew_mac(bp, DNET_INTERNAL_MAC_ADDR_1_REG, tmp);
+       tmp = cpu_to_be16(*((u16 *) (bp->dev->dev_addr + 4)));
+       dnet_writew_mac(bp, DNET_INTERNAL_MAC_ADDR_2_REG, tmp);
+}
+
+static void __devinit dnet_get_hwaddr(struct dnet *bp)
+{
+       u16 tmp;
+       u8 addr[6];
+
+       /*
+        * from MAC docs:
+        * "Note that the MAC address is stored in the registers in Hexadecimal
+        * form. For example, to set the MAC Address to: AC-DE-48-00-00-80
+        * would require writing 0xAC (octet 0) to address 0x0B (high byte of
+        * Mac_addr[15:0]), 0xDE (octet 1) to address 0x0A (Low byte of
+        * Mac_addr[15:0]), 0x48 (octet 2) to address 0x0D (high byte of
+        * Mac_addr[15:0]), 0x00 (octet 3) to address 0x0C (Low byte of
+        * Mac_addr[15:0]), 0x00 (octet 4) to address 0x0F (high byte of
+        * Mac_addr[15:0]), and 0x80 (octet 5) to address * 0x0E (Low byte of
+        * Mac_addr[15:0]).
+        */
+       tmp = dnet_readw_mac(bp, DNET_INTERNAL_MAC_ADDR_0_REG);
+       *((u16 *) addr) = be16_to_cpu(tmp);
+       tmp = dnet_readw_mac(bp, DNET_INTERNAL_MAC_ADDR_1_REG);
+       *((u16 *) (addr + 2)) = be16_to_cpu(tmp);
+       tmp = dnet_readw_mac(bp, DNET_INTERNAL_MAC_ADDR_2_REG);
+       *((u16 *) (addr + 4)) = be16_to_cpu(tmp);
+
+       if (is_valid_ether_addr(addr))
+               memcpy(bp->dev->dev_addr, addr, sizeof(addr));
+}
+
+static int dnet_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
+{
+       struct dnet *bp = bus->priv;
+       u16 value;
+
+       while (!(dnet_readw_mac(bp, DNET_INTERNAL_GMII_MNG_CTL_REG)
+                               & DNET_INTERNAL_GMII_MNG_CMD_FIN))
+               cpu_relax();
+
+       /* only 5 bits allowed for phy-addr and reg_offset */
+       mii_id &= 0x1f;
+       regnum &= 0x1f;
+
+       /* prepare reg_value for a read */
+       value = (mii_id << 8);
+       value |= regnum;
+
+       /* write control word */
+       dnet_writew_mac(bp, DNET_INTERNAL_GMII_MNG_CTL_REG, value);
+
+       /* wait for end of transfer */
+       while (!(dnet_readw_mac(bp, DNET_INTERNAL_GMII_MNG_CTL_REG)
+                               & DNET_INTERNAL_GMII_MNG_CMD_FIN))
+               cpu_relax();
+
+       value = dnet_readw_mac(bp, DNET_INTERNAL_GMII_MNG_DAT_REG);
+
+       pr_debug("mdio_read %02x:%02x <- %04x\n", mii_id, regnum, value);
+
+       return value;
+}
+
+static int dnet_mdio_write(struct mii_bus *bus, int mii_id, int regnum,
+                          u16 value)
+{
+       struct dnet *bp = bus->priv;
+       u16 tmp;
+
+       pr_debug("mdio_write %02x:%02x <- %04x\n", mii_id, regnum, value);
+
+       while (!(dnet_readw_mac(bp, DNET_INTERNAL_GMII_MNG_CTL_REG)
+                               & DNET_INTERNAL_GMII_MNG_CMD_FIN))
+               cpu_relax();
+
+       /* prepare for a write operation */
+       tmp = (1 << 13);
+
+       /* only 5 bits allowed for phy-addr and reg_offset */
+       mii_id &= 0x1f;
+       regnum &= 0x1f;
+
+       /* only 16 bits on data */
+       value &= 0xffff;
+
+       /* prepare reg_value for a write */
+       tmp |= (mii_id << 8);
+       tmp |= regnum;
+
+       /* write data to write first */
+       dnet_writew_mac(bp, DNET_INTERNAL_GMII_MNG_DAT_REG, value);
+
+       /* write control word */
+       dnet_writew_mac(bp, DNET_INTERNAL_GMII_MNG_CTL_REG, tmp);
+
+       while (!(dnet_readw_mac(bp, DNET_INTERNAL_GMII_MNG_CTL_REG)
+                               & DNET_INTERNAL_GMII_MNG_CMD_FIN))
+               cpu_relax();
+
+       return 0;
+}
+
+static int dnet_mdio_reset(struct mii_bus *bus)
+{
+       return 0;
+}
+
+static void dnet_handle_link_change(struct net_device *dev)
+{
+       struct dnet *bp = netdev_priv(dev);
+       struct phy_device *phydev = bp->phy_dev;
+       unsigned long flags;
+       u32 mode_reg, ctl_reg;
+
+       int status_change = 0;
+
+       spin_lock_irqsave(&bp->lock, flags);
+
+       mode_reg = dnet_readw_mac(bp, DNET_INTERNAL_MODE_REG);
+       ctl_reg = dnet_readw_mac(bp, DNET_INTERNAL_RXTX_CONTROL_REG);
+
+       if (phydev->link) {
+               if (bp->duplex != phydev->duplex) {
+                       if (phydev->duplex)
+                               ctl_reg &=
+                                   ~(DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP);
+                       else
+                               ctl_reg |=
+                                   DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP;
+
+                       bp->duplex = phydev->duplex;
+                       status_change = 1;
+               }
+
+               if (bp->speed != phydev->speed) {
+                       status_change = 1;
+                       switch (phydev->speed) {
+                       case 1000:
+                               mode_reg |= DNET_INTERNAL_MODE_GBITEN;
+                               break;
+                       case 100:
+                       case 10:
+                               mode_reg &= ~DNET_INTERNAL_MODE_GBITEN;
+                               break;
+                       default:
+                               printk(KERN_WARNING
+                                      "%s: Ack!  Speed (%d) is not "
+                                      "10/100/1000!\n", dev->name,
+                                      phydev->speed);
+                               break;
+                       }
+                       bp->speed = phydev->speed;
+               }
+       }
+
+       if (phydev->link != bp->link) {
+               if (phydev->link) {
+                       mode_reg |=
+                           (DNET_INTERNAL_MODE_RXEN | DNET_INTERNAL_MODE_TXEN);
+               } else {
+                       mode_reg &=
+                           ~(DNET_INTERNAL_MODE_RXEN |
+                             DNET_INTERNAL_MODE_TXEN);
+                       bp->speed = 0;
+                       bp->duplex = -1;
+               }
+               bp->link = phydev->link;
+
+               status_change = 1;
+       }
+
+       if (status_change) {
+               dnet_writew_mac(bp, DNET_INTERNAL_RXTX_CONTROL_REG, ctl_reg);
+               dnet_writew_mac(bp, DNET_INTERNAL_MODE_REG, mode_reg);
+       }
+
+       spin_unlock_irqrestore(&bp->lock, flags);
+
+       if (status_change) {
+               if (phydev->link)
+                       printk(KERN_INFO "%s: link up (%d/%s)\n",
+                              dev->name, phydev->speed,
+                              DUPLEX_FULL == phydev->duplex ? "Full" : "Half");
+               else
+                       printk(KERN_INFO "%s: link down\n", dev->name);
+       }
+}
+
+static int dnet_mii_probe(struct net_device *dev)
+{
+       struct dnet *bp = netdev_priv(dev);
+       struct phy_device *phydev = NULL;
+       int phy_addr;
+
+       /* find the first phy */
+       for (phy_addr = 0; phy_addr < PHY_MAX_ADDR; phy_addr++) {
+               if (bp->mii_bus->phy_map[phy_addr]) {
+                       phydev = bp->mii_bus->phy_map[phy_addr];
+                       break;
+               }
+       }
+
+       if (!phydev) {
+               printk(KERN_ERR "%s: no PHY found\n", dev->name);
+               return -ENODEV;
+       }
+
+       /* TODO : add pin_irq */
+
+       /* attach the mac to the phy */
+       if (bp->capabilities & DNET_HAS_RMII) {
+               phydev = phy_connect(dev, dev_name(&phydev->dev),
+                                    &dnet_handle_link_change, 0,
+                                    PHY_INTERFACE_MODE_RMII);
+       } else {
+               phydev = phy_connect(dev, dev_name(&phydev->dev),
+                                    &dnet_handle_link_change, 0,
+                                    PHY_INTERFACE_MODE_MII);
+       }
+
+       if (IS_ERR(phydev)) {
+               printk(KERN_ERR "%s: Could not attach to PHY\n", dev->name);
+               return PTR_ERR(phydev);
+       }
+
+       /* mask with MAC supported features */
+       if (bp->capabilities & DNET_HAS_GIGABIT)
+               phydev->supported &= PHY_GBIT_FEATURES;
+       else
+               phydev->supported &= PHY_BASIC_FEATURES;
+
+       phydev->supported |= SUPPORTED_Asym_Pause | SUPPORTED_Pause;
+
+       phydev->advertising = phydev->supported;
+
+       bp->link = 0;
+       bp->speed = 0;
+       bp->duplex = -1;
+       bp->phy_dev = phydev;
+
+       return 0;
+}
+
+static int dnet_mii_init(struct dnet *bp)
+{
+       int err, i;
+
+       bp->mii_bus = mdiobus_alloc();
+       if (bp->mii_bus == NULL)
+               return -ENOMEM;
+
+       bp->mii_bus->name = "dnet_mii_bus";
+       bp->mii_bus->read = &dnet_mdio_read;
+       bp->mii_bus->write = &dnet_mdio_write;
+       bp->mii_bus->reset = &dnet_mdio_reset;
+
+       snprintf(bp->mii_bus->id, MII_BUS_ID_SIZE, "%x", 0);
+
+       bp->mii_bus->priv = bp;
+
+       bp->mii_bus->irq = kmalloc(sizeof(int) * PHY_MAX_ADDR, GFP_KERNEL);
+       if (!bp->mii_bus->irq) {
+               err = -ENOMEM;
+               goto err_out;
+       }
+
+       for (i = 0; i < PHY_MAX_ADDR; i++)
+               bp->mii_bus->irq[i] = PHY_POLL;
+
+       platform_set_drvdata(bp->dev, bp->mii_bus);
+
+       if (mdiobus_register(bp->mii_bus)) {
+               err = -ENXIO;
+               goto err_out_free_mdio_irq;
+       }
+
+       if (dnet_mii_probe(bp->dev) != 0) {
+               err = -ENXIO;
+               goto err_out_unregister_bus;
+       }
+
+       return 0;
+
+err_out_unregister_bus:
+       mdiobus_unregister(bp->mii_bus);
+err_out_free_mdio_irq:
+       kfree(bp->mii_bus->irq);
+err_out:
+       mdiobus_free(bp->mii_bus);
+       return err;
+}
+
+/* For Neptune board: LINK1000 as Link LED and TX as activity LED */
+int dnet_phy_marvell_fixup(struct phy_device *phydev)
+{
+       return phy_write(phydev, 0x18, 0x4148);
+}
+
+static void dnet_update_stats(struct dnet *bp)
+{
+       u32 __iomem *reg = bp->regs + DNET_RX_PKT_IGNR_CNT;
+       u32 *p = &bp->hw_stats.rx_pkt_ignr;
+       u32 *end = &bp->hw_stats.rx_byte + 1;
+
+       WARN_ON((unsigned long)(end - p - 1) !=
+               (DNET_RX_BYTE_CNT - DNET_RX_PKT_IGNR_CNT) / 4);
+
+       for (; p < end; p++, reg++)
+               *p += readl(reg);
+
+       reg = bp->regs + DNET_TX_UNICAST_CNT;
+       p = &bp->hw_stats.tx_unicast;
+       end = &bp->hw_stats.tx_byte + 1;
+
+       WARN_ON((unsigned long)(end - p - 1) !=
+               (DNET_TX_BYTE_CNT - DNET_TX_UNICAST_CNT) / 4);
+
+       for (; p < end; p++, reg++)
+               *p += readl(reg);
+}
+
+static int dnet_poll(struct napi_struct *napi, int budget)
+{
+       struct dnet *bp = container_of(napi, struct dnet, napi);
+       struct net_device *dev = bp->dev;
+       int npackets = 0;
+       unsigned int pkt_len;
+       struct sk_buff *skb;
+       unsigned int *data_ptr;
+       u32 int_enable;
+       u32 cmd_word;
+       int i;
+
+       while (npackets < budget) {
+               /*
+                * break out of while loop if there are no more
+                * packets waiting
+                */
+               if (!(dnet_readl(bp, RX_FIFO_WCNT) >> 16)) {
+                       napi_complete(napi);
+                       int_enable = dnet_readl(bp, INTR_ENB);
+                       int_enable |= DNET_INTR_SRC_RX_CMDFIFOAF;
+                       dnet_writel(bp, int_enable, INTR_ENB);
+                       return 0;
+               }
+
+               cmd_word = dnet_readl(bp, RX_LEN_FIFO);
+               pkt_len = cmd_word & 0xFFFF;
+
+               if (cmd_word & 0xDF180000)
+                       printk(KERN_ERR "%s packet receive error %x\n",
+                              __func__, cmd_word);
+
+               skb = dev_alloc_skb(pkt_len + 5);
+               if (skb != NULL) {
+                       /* Align IP on 16 byte boundaries */
+                       skb_reserve(skb, 2);
+                       /*
+                        * 'skb_put()' points to the start of sk_buff
+                        * data area.
+                        */
+                       data_ptr = (unsigned int *)skb_put(skb, pkt_len);
+                       for (i = 0; i < (pkt_len + 3) >> 2; i++)
+                               *data_ptr++ = dnet_readl(bp, RX_DATA_FIFO);
+                       skb->protocol = eth_type_trans(skb, dev);
+                       netif_receive_skb(skb);
+                       npackets++;
+               } else
+                       printk(KERN_NOTICE
+                              "%s: No memory to allocate a sk_buff of "
+                              "size %u.\n", dev->name, pkt_len);
+       }
+
+       budget -= npackets;
+
+       if (npackets < budget) {
+               /* We processed all packets available.  Tell NAPI it can
+                * stop polling then re-enable rx interrupts */
+               napi_complete(napi);
+               int_enable = dnet_readl(bp, INTR_ENB);
+               int_enable |= DNET_INTR_SRC_RX_CMDFIFOAF;
+               dnet_writel(bp, int_enable, INTR_ENB);
+               return 0;
+       }
+
+       /* There are still packets waiting */
+       return 1;
+}
+
+static irqreturn_t dnet_interrupt(int irq, void *dev_id)
+{
+       struct net_device *dev = dev_id;
+       struct dnet *bp = netdev_priv(dev);
+       u32 int_src, int_enable, int_current;
+       unsigned long flags;
+       unsigned int handled = 0;
+
+       spin_lock_irqsave(&bp->lock, flags);
+
+       /* read and clear the DNET irq (clear on read) */
+       int_src = dnet_readl(bp, INTR_SRC);
+       int_enable = dnet_readl(bp, INTR_ENB);
+       int_current = int_src & int_enable;
+
+       /* restart the queue if we had stopped it for TX fifo almost full */
+       if (int_current & DNET_INTR_SRC_TX_FIFOAE) {
+               int_enable = dnet_readl(bp, INTR_ENB);
+               int_enable &= ~DNET_INTR_ENB_TX_FIFOAE;
+               dnet_writel(bp, int_enable, INTR_ENB);
+               netif_wake_queue(dev);
+               handled = 1;
+       }
+
+       /* RX FIFO error checking */
+       if (int_current &
+           (DNET_INTR_SRC_RX_CMDFIFOFF | DNET_INTR_SRC_RX_DATAFIFOFF)) {
+               printk(KERN_ERR "%s: RX fifo error %x, irq %x\n", __func__,
+                      dnet_readl(bp, RX_STATUS), int_current);
+               /* we can only flush the RX FIFOs */
+               dnet_writel(bp, DNET_SYS_CTL_RXFIFOFLUSH, SYS_CTL);
+               ndelay(500);
+               dnet_writel(bp, 0, SYS_CTL);
+               handled = 1;
+       }
+
+       /* TX FIFO error checking */
+       if (int_current &
+           (DNET_INTR_SRC_TX_FIFOFULL | DNET_INTR_SRC_TX_DISCFRM)) {
+               printk(KERN_ERR "%s: TX fifo error %x, irq %x\n", __func__,
+                      dnet_readl(bp, TX_STATUS), int_current);
+               /* we can only flush the TX FIFOs */
+               dnet_writel(bp, DNET_SYS_CTL_TXFIFOFLUSH, SYS_CTL);
+               ndelay(500);
+               dnet_writel(bp, 0, SYS_CTL);
+               handled = 1;
+       }
+
+       if (int_current & DNET_INTR_SRC_RX_CMDFIFOAF) {
+               if (napi_schedule_prep(&bp->napi)) {
+                       /*
+                        * There's no point taking any more interrupts
+                        * until we have processed the buffers
+                        */
+                       /* Disable Rx interrupts and schedule NAPI poll */
+                       int_enable = dnet_readl(bp, INTR_ENB);
+                       int_enable &= ~DNET_INTR_SRC_RX_CMDFIFOAF;
+                       dnet_writel(bp, int_enable, INTR_ENB);
+                       __napi_schedule(&bp->napi);
+               }
+               handled = 1;
+       }
+
+       if (!handled)
+               pr_debug("%s: irq %x remains\n", __func__, int_current);
+
+       spin_unlock_irqrestore(&bp->lock, flags);
+
+       return IRQ_RETVAL(handled);
+}
+
+#ifdef DEBUG
+static inline void dnet_print_skb(struct sk_buff *skb)
+{
+       int k;
+       printk(KERN_DEBUG PFX "data:");
+       for (k = 0; k < skb->len; k++)
+               printk(" %02x", (unsigned int)skb->data[k]);
+       printk("\n");
+}
+#else
+#define dnet_print_skb(skb)    do {} while (0)
+#endif
+
+static int dnet_start_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+
+       struct dnet *bp = netdev_priv(dev);
+       u32 tx_status, irq_enable;
+       unsigned int len, i, tx_cmd, wrsz;
+       unsigned long flags;
+       unsigned int *bufp;
+
+       tx_status = dnet_readl(bp, TX_STATUS);
+
+       pr_debug("start_xmit: len %u head %p data %p\n",
+              skb->len, skb->head, skb->data);
+       dnet_print_skb(skb);
+
+       /* frame size (words) */
+       len = (skb->len + 3) >> 2;
+
+       spin_lock_irqsave(&bp->lock, flags);
+
+       tx_status = dnet_readl(bp, TX_STATUS);
+
+       bufp = (unsigned int *)(((unsigned long) skb->data) & ~0x3UL);
+       wrsz = (u32) skb->len + 3;
+       wrsz += ((unsigned long) skb->data) & 0x3;
+       wrsz >>= 2;
+       tx_cmd = ((((unsigned long)(skb->data)) & 0x03) << 16) | (u32) skb->len;
+
+       /* check if there is enough room for the current frame */
+       if (wrsz < (DNET_FIFO_SIZE - dnet_readl(bp, TX_FIFO_WCNT))) {
+               for (i = 0; i < wrsz; i++)
+                       dnet_writel(bp, *bufp++, TX_DATA_FIFO);
+
+               /*
+                * inform MAC that a packet's written and ready to be
+                * shipped out
+                */
+               dnet_writel(bp, tx_cmd, TX_LEN_FIFO);
+       }
+
+       if (dnet_readl(bp, TX_FIFO_WCNT) > DNET_FIFO_TX_DATA_AF_TH) {
+               netif_stop_queue(dev);
+               tx_status = dnet_readl(bp, INTR_SRC);
+               irq_enable = dnet_readl(bp, INTR_ENB);
+               irq_enable |= DNET_INTR_ENB_TX_FIFOAE;
+               dnet_writel(bp, irq_enable, INTR_ENB);
+       }
+
+       /* free the buffer */
+       dev_kfree_skb(skb);
+
+       spin_unlock_irqrestore(&bp->lock, flags);
+
+       dev->trans_start = jiffies;
+
+       return 0;
+}
+
+static void dnet_reset_hw(struct dnet *bp)
+{
+       /* put ts_mac in IDLE state i.e. disable rx/tx */
+       dnet_writew_mac(bp, DNET_INTERNAL_MODE_REG, DNET_INTERNAL_MODE_FCEN);
+
+       /*
+        * RX FIFO almost full threshold: only cmd FIFO almost full is
+        * implemented for RX side
+        */
+       dnet_writel(bp, DNET_FIFO_RX_CMD_AF_TH, RX_FIFO_TH);
+       /*
+        * TX FIFO almost empty threshold: only data FIFO almost empty
+        * is implemented for TX side
+        */
+       dnet_writel(bp, DNET_FIFO_TX_DATA_AE_TH, TX_FIFO_TH);
+
+       /* flush rx/tx fifos */
+       dnet_writel(bp, DNET_SYS_CTL_RXFIFOFLUSH | DNET_SYS_CTL_TXFIFOFLUSH,
+                       SYS_CTL);
+       msleep(1);
+       dnet_writel(bp, 0, SYS_CTL);
+}
+
+static void dnet_init_hw(struct dnet *bp)
+{
+       u32 config;
+
+       dnet_reset_hw(bp);
+       __dnet_set_hwaddr(bp);
+
+       config = dnet_readw_mac(bp, DNET_INTERNAL_RXTX_CONTROL_REG);
+
+       if (bp->dev->flags & IFF_PROMISC)
+               /* Copy All Frames */
+               config |= DNET_INTERNAL_RXTX_CONTROL_ENPROMISC;
+       if (!(bp->dev->flags & IFF_BROADCAST))
+               /* No BroadCast */
+               config |= DNET_INTERNAL_RXTX_CONTROL_RXMULTICAST;
+
+       config |= DNET_INTERNAL_RXTX_CONTROL_RXPAUSE |
+           DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST |
+           DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL |
+           DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS;
+
+       dnet_writew_mac(bp, DNET_INTERNAL_RXTX_CONTROL_REG, config);
+
+       /* clear irq before enabling them */
+       config = dnet_readl(bp, INTR_SRC);
+
+       /* enable RX/TX interrupt, recv packet ready interrupt */
+       dnet_writel(bp, DNET_INTR_ENB_GLOBAL_ENABLE | DNET_INTR_ENB_RX_SUMMARY |
+                       DNET_INTR_ENB_TX_SUMMARY | DNET_INTR_ENB_RX_FIFOERR |
+                       DNET_INTR_ENB_RX_ERROR | DNET_INTR_ENB_RX_FIFOFULL |
+                       DNET_INTR_ENB_TX_FIFOFULL | DNET_INTR_ENB_TX_DISCFRM |
+                       DNET_INTR_ENB_RX_PKTRDY, INTR_ENB);
+}
+
+static int dnet_open(struct net_device *dev)
+{
+       struct dnet *bp = netdev_priv(dev);
+
+       /* if the phy is not yet register, retry later */
+       if (!bp->phy_dev)
+               return -EAGAIN;
+
+       if (!is_valid_ether_addr(dev->dev_addr))
+               return -EADDRNOTAVAIL;
+
+       napi_enable(&bp->napi);
+       dnet_init_hw(bp);
+
+       phy_start_aneg(bp->phy_dev);
+
+       /* schedule a link state check */
+       phy_start(bp->phy_dev);
+
+       netif_start_queue(dev);
+
+       return 0;
+}
+
+static int dnet_close(struct net_device *dev)
+{
+       struct dnet *bp = netdev_priv(dev);
+
+       netif_stop_queue(dev);
+       napi_disable(&bp->napi);
+
+       if (bp->phy_dev)
+               phy_stop(bp->phy_dev);
+
+       dnet_reset_hw(bp);
+       netif_carrier_off(dev);
+
+       return 0;
+}
+
+static inline void dnet_print_pretty_hwstats(struct dnet_stats *hwstat)
+{
+       pr_debug("%s\n", __func__);
+       pr_debug("----------------------------- RX statistics "
+                "-------------------------------\n");
+       pr_debug("RX_PKT_IGNR_CNT %-8x\n", hwstat->rx_pkt_ignr);
+       pr_debug("RX_LEN_CHK_ERR_CNT %-8x\n", hwstat->rx_len_chk_err);
+       pr_debug("RX_LNG_FRM_CNT %-8x\n", hwstat->rx_lng_frm);
+       pr_debug("RX_SHRT_FRM_CNT %-8x\n", hwstat->rx_shrt_frm);
+       pr_debug("RX_IPG_VIOL_CNT %-8x\n", hwstat->rx_ipg_viol);
+       pr_debug("RX_CRC_ERR_CNT %-8x\n", hwstat->rx_crc_err);
+       pr_debug("RX_OK_PKT_CNT %-8x\n", hwstat->rx_ok_pkt);
+       pr_debug("RX_CTL_FRM_CNT %-8x\n", hwstat->rx_ctl_frm);
+       pr_debug("RX_PAUSE_FRM_CNT %-8x\n", hwstat->rx_pause_frm);
+       pr_debug("RX_MULTICAST_CNT %-8x\n", hwstat->rx_multicast);
+       pr_debug("RX_BROADCAST_CNT %-8x\n", hwstat->rx_broadcast);
+       pr_debug("RX_VLAN_TAG_CNT %-8x\n", hwstat->rx_vlan_tag);
+       pr_debug("RX_PRE_SHRINK_CNT %-8x\n", hwstat->rx_pre_shrink);
+       pr_debug("RX_DRIB_NIB_CNT %-8x\n", hwstat->rx_drib_nib);
+       pr_debug("RX_UNSUP_OPCD_CNT %-8x\n", hwstat->rx_unsup_opcd);
+       pr_debug("RX_BYTE_CNT %-8x\n", hwstat->rx_byte);
+       pr_debug("----------------------------- TX statistics "
+                "-------------------------------\n");
+       pr_debug("TX_UNICAST_CNT %-8x\n", hwstat->tx_unicast);
+       pr_debug("TX_PAUSE_FRM_CNT %-8x\n", hwstat->tx_pause_frm);
+       pr_debug("TX_MULTICAST_CNT %-8x\n", hwstat->tx_multicast);
+       pr_debug("TX_BRDCAST_CNT %-8x\n", hwstat->tx_brdcast);
+       pr_debug("TX_VLAN_TAG_CNT %-8x\n", hwstat->tx_vlan_tag);
+       pr_debug("TX_BAD_FCS_CNT %-8x\n", hwstat->tx_bad_fcs);
+       pr_debug("TX_JUMBO_CNT %-8x\n", hwstat->tx_jumbo);
+       pr_debug("TX_BYTE_CNT %-8x\n", hwstat->tx_byte);
+}
+
+static struct net_device_stats *dnet_get_stats(struct net_device *dev)
+{
+
+       struct dnet *bp = netdev_priv(dev);
+       struct net_device_stats *nstat = &dev->stats;
+       struct dnet_stats *hwstat = &bp->hw_stats;
+
+       /* read stats from hardware */
+       dnet_update_stats(bp);
+
+       /* Convert HW stats into netdevice stats */
+       nstat->rx_errors = (hwstat->rx_len_chk_err +
+                           hwstat->rx_lng_frm + hwstat->rx_shrt_frm +
+                           /* ignore IGP violation error
+                           hwstat->rx_ipg_viol + */
+                           hwstat->rx_crc_err +
+                           hwstat->rx_pre_shrink +
+                           hwstat->rx_drib_nib + hwstat->rx_unsup_opcd);
+       nstat->tx_errors = hwstat->tx_bad_fcs;
+       nstat->rx_length_errors = (hwstat->rx_len_chk_err +
+                                  hwstat->rx_lng_frm +
+                                  hwstat->rx_shrt_frm + hwstat->rx_pre_shrink);
+       nstat->rx_crc_errors = hwstat->rx_crc_err;
+       nstat->rx_frame_errors = hwstat->rx_pre_shrink + hwstat->rx_drib_nib;
+       nstat->rx_packets = hwstat->rx_ok_pkt;
+       nstat->tx_packets = (hwstat->tx_unicast +
+                            hwstat->tx_multicast + hwstat->tx_brdcast);
+       nstat->rx_bytes = hwstat->rx_byte;
+       nstat->tx_bytes = hwstat->tx_byte;
+       nstat->multicast = hwstat->rx_multicast;
+       nstat->rx_missed_errors = hwstat->rx_pkt_ignr;
+
+       dnet_print_pretty_hwstats(hwstat);
+
+       return nstat;
+}
+
+static int dnet_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct dnet *bp = netdev_priv(dev);
+       struct phy_device *phydev = bp->phy_dev;
+
+       if (!phydev)
+               return -ENODEV;
+
+       return phy_ethtool_gset(phydev, cmd);
+}
+
+static int dnet_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
+{
+       struct dnet *bp = netdev_priv(dev);
+       struct phy_device *phydev = bp->phy_dev;
+
+       if (!phydev)
+               return -ENODEV;
+
+       return phy_ethtool_sset(phydev, cmd);
+}
+
+static int dnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
+{
+       struct dnet *bp = netdev_priv(dev);
+       struct phy_device *phydev = bp->phy_dev;
+
+       if (!netif_running(dev))
+               return -EINVAL;
+
+       if (!phydev)
+               return -ENODEV;
+
+       return phy_mii_ioctl(phydev, if_mii(rq), cmd);
+}
+
+static void dnet_get_drvinfo(struct net_device *dev,
+                            struct ethtool_drvinfo *info)
+{
+       strcpy(info->driver, DRV_NAME);
+       strcpy(info->version, DRV_VERSION);
+       strcpy(info->bus_info, "0");
+}
+
+static const struct ethtool_ops dnet_ethtool_ops = {
+       .get_settings           = dnet_get_settings,
+       .set_settings           = dnet_set_settings,
+       .get_drvinfo            = dnet_get_drvinfo,
+       .get_link               = ethtool_op_get_link,
+};
+
+static const struct net_device_ops dnet_netdev_ops = {
+       .ndo_open               = dnet_open,
+       .ndo_stop               = dnet_close,
+       .ndo_get_stats          = dnet_get_stats,
+       .ndo_start_xmit         = dnet_start_xmit,
+       .ndo_do_ioctl           = dnet_ioctl,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_change_mtu         = eth_change_mtu,
+};
+
+static int __devinit dnet_probe(struct platform_device *pdev)
+{
+       struct resource *res;
+       struct net_device *dev;
+       struct dnet *bp;
+       struct phy_device *phydev;
+       int err = -ENXIO;
+       unsigned int mem_base, mem_size, irq;
+
+       res = platform_get_resource(pdev, IORESOURCE_MEM, 0);
+       if (!res) {
+               dev_err(&pdev->dev, "no mmio resource defined\n");
+               goto err_out;
+       }
+       mem_base = res->start;
+       mem_size = resource_size(res);
+       irq = platform_get_irq(pdev, 0);
+
+       if (!request_mem_region(mem_base, mem_size, DRV_NAME)) {
+               dev_err(&pdev->dev, "no memory region available\n");
+               err = -EBUSY;
+               goto err_out;
+       }
+
+       err = -ENOMEM;
+       dev = alloc_etherdev(sizeof(*bp));
+       if (!dev) {
+               dev_err(&pdev->dev, "etherdev alloc failed, aborting.\n");
+               goto err_out;
+       }
+
+       /* TODO: Actually, we have some interesting features... */
+       dev->features |= 0;
+
+       bp = netdev_priv(dev);
+       bp->dev = dev;
+
+       SET_NETDEV_DEV(dev, &pdev->dev);
+
+       spin_lock_init(&bp->lock);
+
+       bp->regs = ioremap(mem_base, mem_size);
+       if (!bp->regs) {
+               dev_err(&pdev->dev, "failed to map registers, aborting.\n");
+               err = -ENOMEM;
+               goto err_out_free_dev;
+       }
+
+       dev->irq = irq;
+       err = request_irq(dev->irq, dnet_interrupt, 0, DRV_NAME, dev);
+       if (err) {
+               dev_err(&pdev->dev, "Unable to request IRQ %d (error %d)\n",
+                      irq, err);
+               goto err_out_iounmap;
+       }
+
+       dev->netdev_ops = &dnet_netdev_ops;
+       netif_napi_add(dev, &bp->napi, dnet_poll, 64);
+       dev->ethtool_ops = &dnet_ethtool_ops;
+
+       dev->base_addr = (unsigned long)bp->regs;
+
+       bp->capabilities = dnet_readl(bp, VERCAPS) & DNET_CAPS_MASK;
+
+       dnet_get_hwaddr(bp);
+
+       if (!is_valid_ether_addr(dev->dev_addr)) {
+               /* choose a random ethernet address */
+               random_ether_addr(dev->dev_addr);
+               __dnet_set_hwaddr(bp);
+       }
+
+       err = register_netdev(dev);
+       if (err) {
+               dev_err(&pdev->dev, "Cannot register net device, aborting.\n");
+               goto err_out_free_irq;
+       }
+
+       /* register the PHY board fixup (for Marvell 88E1111) */
+       err = phy_register_fixup_for_uid(0x01410cc0, 0xfffffff0,
+                                        dnet_phy_marvell_fixup);
+       /* we can live without it, so just issue a warning */
+       if (err)
+               dev_warn(&pdev->dev, "Cannot register PHY board fixup.\n");
+
+       if (dnet_mii_init(bp) != 0)
+               goto err_out_unregister_netdev;
+
+       dev_info(&pdev->dev, "Dave DNET at 0x%p (0x%08x) irq %d %pM\n",
+              bp->regs, mem_base, dev->irq, dev->dev_addr);
+       dev_info(&pdev->dev, "has %smdio, %sirq, %sgigabit, %sdma \n",
+              (bp->capabilities & DNET_HAS_MDIO) ? "" : "no ",
+              (bp->capabilities & DNET_HAS_IRQ) ? "" : "no ",
+              (bp->capabilities & DNET_HAS_GIGABIT) ? "" : "no ",
+              (bp->capabilities & DNET_HAS_DMA) ? "" : "no ");
+       phydev = bp->phy_dev;
+       dev_info(&pdev->dev, "attached PHY driver [%s] "
+              "(mii_bus:phy_addr=%s, irq=%d)\n",
+              phydev->drv->name, dev_name(&phydev->dev), phydev->irq);
+
+       return 0;
+
+err_out_unregister_netdev:
+       unregister_netdev(dev);
+err_out_free_irq:
+       free_irq(dev->irq, dev);
+err_out_iounmap:
+       iounmap(bp->regs);
+err_out_free_dev:
+       free_netdev(dev);
+err_out:
+       return err;
+}
+
+static int __devexit dnet_remove(struct platform_device *pdev)
+{
+
+       struct net_device *dev;
+       struct dnet *bp;
+
+       dev = platform_get_drvdata(pdev);
+
+       if (dev) {
+               bp = netdev_priv(dev);
+               if (bp->phy_dev)
+                       phy_disconnect(bp->phy_dev);
+               mdiobus_unregister(bp->mii_bus);
+               kfree(bp->mii_bus->irq);
+               mdiobus_free(bp->mii_bus);
+               unregister_netdev(dev);
+               free_irq(dev->irq, dev);
+               iounmap(bp->regs);
+               free_netdev(dev);
+       }
+
+       return 0;
+}
+
+static struct platform_driver dnet_driver = {
+       .probe          = dnet_probe,
+       .remove         = __devexit_p(dnet_remove),
+       .driver         = {
+               .name           = "dnet",
+       },
+};
+
+static int __init dnet_init(void)
+{
+       return platform_driver_register(&dnet_driver);
+}
+
+static void __exit dnet_exit(void)
+{
+       platform_driver_unregister(&dnet_driver);
+}
+
+module_init(dnet_init);
+module_exit(dnet_exit);
+
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Dave DNET Ethernet driver");
+MODULE_AUTHOR("Ilya Yanok <yanok@emcraft.com>, "
+             "Matteo Vit <matteo.vit@dave.eu>");
diff --git a/drivers/net/dnet.h b/drivers/net/dnet.h
new file mode 100644 (file)
index 0000000..37f5b30
--- /dev/null
@@ -0,0 +1,225 @@
+/*
+ * Dave DNET Ethernet Controller driver
+ *
+ * Copyright (C) 2008 Dave S.r.l. <www.dave.eu>
+ *
+ * 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 _DNET_H
+#define _DNET_H
+
+#define DRV_NAME               "dnet"
+#define DRV_VERSION            "0.9.1"
+#define PFX                            DRV_NAME ": "
+
+/* Register access macros */
+#define dnet_writel(port, value, reg)  \
+       writel((value), (port)->regs + DNET_##reg)
+#define dnet_readl(port, reg)  readl((port)->regs + DNET_##reg)
+
+/* ALL DNET FIFO REGISTERS */
+#define DNET_RX_LEN_FIFO               0x000   /* RX_LEN_FIFO */
+#define DNET_RX_DATA_FIFO              0x004   /* RX_DATA_FIFO */
+#define DNET_TX_LEN_FIFO               0x008   /* TX_LEN_FIFO */
+#define DNET_TX_DATA_FIFO              0x00C   /* TX_DATA_FIFO */
+
+/* ALL DNET CONTROL/STATUS REGISTERS OFFSETS */
+#define DNET_VERCAPS                   0x100   /* VERCAPS */
+#define DNET_INTR_SRC                  0x104   /* INTR_SRC */
+#define DNET_INTR_ENB                  0x108   /* INTR_ENB */
+#define DNET_RX_STATUS                 0x10C   /* RX_STATUS */
+#define DNET_TX_STATUS                 0x110   /* TX_STATUS */
+#define DNET_RX_FRAMES_CNT             0x114   /* RX_FRAMES_CNT */
+#define DNET_TX_FRAMES_CNT             0x118   /* TX_FRAMES_CNT */
+#define DNET_RX_FIFO_TH                        0x11C   /* RX_FIFO_TH */
+#define DNET_TX_FIFO_TH                        0x120   /* TX_FIFO_TH */
+#define DNET_SYS_CTL                   0x124   /* SYS_CTL */
+#define DNET_PAUSE_TMR                 0x128   /* PAUSE_TMR */
+#define DNET_RX_FIFO_WCNT              0x12C   /* RX_FIFO_WCNT */
+#define DNET_TX_FIFO_WCNT              0x130   /* TX_FIFO_WCNT */
+
+/* ALL DNET MAC REGISTERS */
+#define DNET_MACREG_DATA               0x200   /* Mac-Reg Data */
+#define DNET_MACREG_ADDR               0x204   /* Mac-Reg Addr  */
+
+/* ALL DNET RX STATISTICS COUNTERS  */
+#define DNET_RX_PKT_IGNR_CNT           0x300
+#define DNET_RX_LEN_CHK_ERR_CNT                0x304
+#define DNET_RX_LNG_FRM_CNT            0x308
+#define DNET_RX_SHRT_FRM_CNT           0x30C
+#define DNET_RX_IPG_VIOL_CNT           0x310
+#define DNET_RX_CRC_ERR_CNT            0x314
+#define DNET_RX_OK_PKT_CNT             0x318
+#define DNET_RX_CTL_FRM_CNT            0x31C
+#define DNET_RX_PAUSE_FRM_CNT          0x320
+#define DNET_RX_MULTICAST_CNT          0x324
+#define DNET_RX_BROADCAST_CNT          0x328
+#define DNET_RX_VLAN_TAG_CNT           0x32C
+#define DNET_RX_PRE_SHRINK_CNT         0x330
+#define DNET_RX_DRIB_NIB_CNT           0x334
+#define DNET_RX_UNSUP_OPCD_CNT         0x338
+#define DNET_RX_BYTE_CNT               0x33C
+
+/* DNET TX STATISTICS COUNTERS */
+#define DNET_TX_UNICAST_CNT            0x400
+#define DNET_TX_PAUSE_FRM_CNT          0x404
+#define DNET_TX_MULTICAST_CNT          0x408
+#define DNET_TX_BRDCAST_CNT            0x40C
+#define DNET_TX_VLAN_TAG_CNT           0x410
+#define DNET_TX_BAD_FCS_CNT            0x414
+#define DNET_TX_JUMBO_CNT              0x418
+#define DNET_TX_BYTE_CNT               0x41C
+
+/* SOME INTERNAL MAC-CORE REGISTER */
+#define DNET_INTERNAL_MODE_REG         0x0
+#define DNET_INTERNAL_RXTX_CONTROL_REG 0x2
+#define DNET_INTERNAL_MAX_PKT_SIZE_REG 0x4
+#define DNET_INTERNAL_IGP_REG          0x8
+#define DNET_INTERNAL_MAC_ADDR_0_REG   0xa
+#define DNET_INTERNAL_MAC_ADDR_1_REG   0xc
+#define DNET_INTERNAL_MAC_ADDR_2_REG   0xe
+#define DNET_INTERNAL_TX_RX_STS_REG    0x12
+#define DNET_INTERNAL_GMII_MNG_CTL_REG 0x14
+#define DNET_INTERNAL_GMII_MNG_DAT_REG 0x16
+
+#define DNET_INTERNAL_GMII_MNG_CMD_FIN (1 << 14)
+
+#define DNET_INTERNAL_WRITE            (1 << 31)
+
+/* MAC-CORE REGISTER FIELDS */
+
+/* MAC-CORE MODE REGISTER FIELDS */
+#define DNET_INTERNAL_MODE_GBITEN                      (1 << 0)
+#define DNET_INTERNAL_MODE_FCEN                                (1 << 1)
+#define DNET_INTERNAL_MODE_RXEN                                (1 << 2)
+#define DNET_INTERNAL_MODE_TXEN                                (1 << 3)
+
+/* MAC-CORE RXTX CONTROL REGISTER FIELDS */
+#define DNET_INTERNAL_RXTX_CONTROL_RXSHORTFRAME                (1 << 8)
+#define DNET_INTERNAL_RXTX_CONTROL_RXBROADCAST         (1 << 7)
+#define DNET_INTERNAL_RXTX_CONTROL_RXMULTICAST         (1 << 4)
+#define DNET_INTERNAL_RXTX_CONTROL_RXPAUSE             (1 << 3)
+#define DNET_INTERNAL_RXTX_CONTROL_DISTXFCS            (1 << 2)
+#define DNET_INTERNAL_RXTX_CONTROL_DISCFXFCS           (1 << 1)
+#define DNET_INTERNAL_RXTX_CONTROL_ENPROMISC           (1 << 0)
+#define DNET_INTERNAL_RXTX_CONTROL_DROPCONTROL         (1 << 6)
+#define DNET_INTERNAL_RXTX_CONTROL_ENABLEHALFDUP       (1 << 5)
+
+/* SYSTEM CONTROL REGISTER FIELDS */
+#define DNET_SYS_CTL_IGNORENEXTPKT                     (1 << 0)
+#define DNET_SYS_CTL_SENDPAUSE                         (1 << 2)
+#define DNET_SYS_CTL_RXFIFOFLUSH                       (1 << 3)
+#define DNET_SYS_CTL_TXFIFOFLUSH                       (1 << 4)
+
+/* TX STATUS REGISTER FIELDS */
+#define DNET_TX_STATUS_FIFO_ALMOST_EMPTY               (1 << 2)
+#define DNET_TX_STATUS_FIFO_ALMOST_FULL                        (1 << 1)
+
+/* INTERRUPT SOURCE REGISTER FIELDS */
+#define DNET_INTR_SRC_TX_PKTSENT                       (1 << 0)
+#define DNET_INTR_SRC_TX_FIFOAF                                (1 << 1)
+#define DNET_INTR_SRC_TX_FIFOAE                                (1 << 2)
+#define DNET_INTR_SRC_TX_DISCFRM                       (1 << 3)
+#define DNET_INTR_SRC_TX_FIFOFULL                      (1 << 4)
+#define DNET_INTR_SRC_RX_CMDFIFOAF                     (1 << 8)
+#define DNET_INTR_SRC_RX_CMDFIFOFF                     (1 << 9)
+#define DNET_INTR_SRC_RX_DATAFIFOFF                    (1 << 10)
+#define DNET_INTR_SRC_TX_SUMMARY                       (1 << 16)
+#define DNET_INTR_SRC_RX_SUMMARY                       (1 << 17)
+#define DNET_INTR_SRC_PHY                              (1 << 19)
+
+/* INTERRUPT ENABLE REGISTER FIELDS */
+#define DNET_INTR_ENB_TX_PKTSENT                       (1 << 0)
+#define DNET_INTR_ENB_TX_FIFOAF                                (1 << 1)
+#define DNET_INTR_ENB_TX_FIFOAE                                (1 << 2)
+#define DNET_INTR_ENB_TX_DISCFRM                       (1 << 3)
+#define DNET_INTR_ENB_TX_FIFOFULL                      (1 << 4)
+#define DNET_INTR_ENB_RX_PKTRDY                                (1 << 8)
+#define DNET_INTR_ENB_RX_FIFOAF                                (1 << 9)
+#define DNET_INTR_ENB_RX_FIFOERR                       (1 << 10)
+#define DNET_INTR_ENB_RX_ERROR                         (1 << 11)
+#define DNET_INTR_ENB_RX_FIFOFULL                      (1 << 12)
+#define DNET_INTR_ENB_RX_FIFOAE                                (1 << 13)
+#define DNET_INTR_ENB_TX_SUMMARY                       (1 << 16)
+#define DNET_INTR_ENB_RX_SUMMARY                       (1 << 17)
+#define DNET_INTR_ENB_GLOBAL_ENABLE                    (1 << 18)
+
+/* default values:
+ * almost empty = less than one full sized ethernet frame (no jumbo) inside
+ * the fifo almost full = can write less than one full sized ethernet frame
+ * (no jumbo) inside the fifo
+ */
+#define DNET_CFG_TX_FIFO_FULL_THRES    25
+#define DNET_CFG_RX_FIFO_FULL_THRES    20
+
+/*
+ * Capabilities. Used by the driver to know the capabilities that the ethernet
+ * controller inside the FPGA have.
+ */
+
+#define DNET_HAS_MDIO          (1 << 0)
+#define DNET_HAS_IRQ           (1 << 1)
+#define DNET_HAS_GIGABIT       (1 << 2)
+#define DNET_HAS_DMA           (1 << 3)
+
+#define DNET_HAS_MII           (1 << 4) /* or GMII */
+#define DNET_HAS_RMII          (1 << 5) /* or RGMII */
+
+#define DNET_CAPS_MASK         0xFFFF
+
+#define DNET_FIFO_SIZE         1024 /* 1K x 32 bit */
+#define DNET_FIFO_TX_DATA_AF_TH        (DNET_FIFO_SIZE - 384) /* 384 = 1536 / 4 */
+#define DNET_FIFO_TX_DATA_AE_TH        384
+
+#define DNET_FIFO_RX_CMD_AF_TH (1 << 16) /* just one frame inside the FIFO */
+
+/*
+ * Hardware-collected statistics.
+ */
+struct dnet_stats {
+       u32 rx_pkt_ignr;
+       u32 rx_len_chk_err;
+       u32 rx_lng_frm;
+       u32 rx_shrt_frm;
+       u32 rx_ipg_viol;
+       u32 rx_crc_err;
+       u32 rx_ok_pkt;
+       u32 rx_ctl_frm;
+       u32 rx_pause_frm;
+       u32 rx_multicast;
+       u32 rx_broadcast;
+       u32 rx_vlan_tag;
+       u32 rx_pre_shrink;
+       u32 rx_drib_nib;
+       u32 rx_unsup_opcd;
+       u32 rx_byte;
+       u32 tx_unicast;
+       u32 tx_pause_frm;
+       u32 tx_multicast;
+       u32 tx_brdcast;
+       u32 tx_vlan_tag;
+       u32 tx_bad_fcs;
+       u32 tx_jumbo;
+       u32 tx_byte;
+};
+
+struct dnet {
+       void __iomem                    *regs;
+       spinlock_t                      lock;
+       struct platform_device          *pdev;
+       struct net_device               *dev;
+       struct dnet_stats               hw_stats;
+       unsigned int                    capabilities; /* read from FPGA */
+       struct napi_struct              napi;
+
+       /* PHY stuff */
+       struct mii_bus                  *mii_bus;
+       struct phy_device               *phy_dev;
+       unsigned int                    link;
+       unsigned int                    speed;
+       unsigned int                    duplex;
+};
+
+#endif /* _DNET_H */
index 861d2eeaa43c1bd34deaeefc956d5d3f62a1788e..0504db9ad6434c50bf1e9585b5a00b2090f7db26 100644 (file)
 
 #define DRV_NAME               "e100"
 #define DRV_EXT                        "-NAPI"
-#define DRV_VERSION            "3.5.23-k6"DRV_EXT
+#define DRV_VERSION            "3.5.24-k2"DRV_EXT
 #define DRV_DESCRIPTION                "Intel(R) PRO/100 Network Driver"
 #define DRV_COPYRIGHT          "Copyright(c) 1999-2006 Intel Corporation"
 #define PFX                    DRV_NAME ": "
@@ -240,6 +240,7 @@ static struct pci_device_id e100_id_table[] = {
        INTEL_8255X_ETHERNET_DEVICE(0x1093, 7),
        INTEL_8255X_ETHERNET_DEVICE(0x1094, 7),
        INTEL_8255X_ETHERNET_DEVICE(0x1095, 7),
+       INTEL_8255X_ETHERNET_DEVICE(0x10fe, 7),
        INTEL_8255X_ETHERNET_DEVICE(0x1209, 0),
        INTEL_8255X_ETHERNET_DEVICE(0x1229, 0),
        INTEL_8255X_ETHERNET_DEVICE(0x2449, 2),
@@ -275,6 +276,7 @@ enum phy {
        phy_82562_em = 0x032002A8,
        phy_82562_ek = 0x031002A8,
        phy_82562_eh = 0x017002A8,
+       phy_82552_v  = 0xd061004d,
        phy_unknown  = 0xFFFFFFFF,
 };
 
@@ -943,6 +945,22 @@ static int mdio_read(struct net_device *netdev, int addr, int reg)
 
 static void mdio_write(struct net_device *netdev, int addr, int reg, int data)
 {
+       struct nic *nic = netdev_priv(netdev);
+
+       if  ((nic->phy == phy_82552_v) && (reg == MII_BMCR) &&
+            (data & (BMCR_ANRESTART | BMCR_ANENABLE))) {
+               u16 advert = mdio_read(netdev, nic->mii.phy_id, MII_ADVERTISE);
+
+               /*
+                * Workaround Si issue where sometimes the part will not
+                * autoneg to 100Mbps even when advertised.
+                */
+               if (advert & ADVERTISE_100FULL)
+                       data |= BMCR_SPEED100 | BMCR_FULLDPLX;
+               else if (advert & ADVERTISE_100HALF)
+                       data |= BMCR_SPEED100;
+       }
+
        mdio_ctrl(netdev_priv(netdev), addr, mdi_write, reg, data);
 }
 
@@ -1276,16 +1294,12 @@ static int e100_phy_init(struct nic *nic)
        if (addr == 32)
                return -EAGAIN;
 
-       /* Selected the phy and isolate the rest */
-       for (addr = 0; addr < 32; addr++) {
-               if (addr != nic->mii.phy_id) {
-                       mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE);
-               } else {
-                       bmcr = mdio_read(netdev, addr, MII_BMCR);
-                       mdio_write(netdev, addr, MII_BMCR,
-                               bmcr & ~BMCR_ISOLATE);
-               }
-       }
+       /* Isolate all the PHY ids */
+       for (addr = 0; addr < 32; addr++)
+               mdio_write(netdev, addr, MII_BMCR, BMCR_ISOLATE);
+       /* Select the discovered PHY */
+       bmcr &= ~BMCR_ISOLATE;
+       mdio_write(netdev, nic->mii.phy_id, MII_BMCR, bmcr);
 
        /* Get phy ID */
        id_lo = mdio_read(netdev, nic->mii.phy_id, MII_PHYSID1);
@@ -1303,7 +1317,18 @@ static int e100_phy_init(struct nic *nic)
                mdio_write(netdev, nic->mii.phy_id, MII_NSC_CONG, cong);
        }
 
-       if ((nic->mac >= mac_82550_D102) || ((nic->flags & ich) &&
+       if (nic->phy == phy_82552_v) {
+               u16 advert = mdio_read(netdev, nic->mii.phy_id, MII_ADVERTISE);
+
+               /* Workaround Si not advertising flow-control during autoneg */
+               advert |= ADVERTISE_PAUSE_CAP | ADVERTISE_PAUSE_ASYM;
+               mdio_write(netdev, nic->mii.phy_id, MII_ADVERTISE, advert);
+
+               /* Reset for the above changes to take effect */
+               bmcr = mdio_read(netdev, nic->mii.phy_id, MII_BMCR);
+               bmcr |= BMCR_RESET;
+               mdio_write(netdev, nic->mii.phy_id, MII_BMCR, bmcr);
+       } else if ((nic->mac >= mac_82550_D102) || ((nic->flags & ich) &&
           (mdio_read(netdev, nic->mii.phy_id, MII_TPISTATUS) & 0x8000) &&
                !(nic->eeprom[eeprom_cnfg_mdix] & eeprom_mdix_enabled))) {
                /* enable/disable MDI/MDI-X auto-switching. */
@@ -2134,6 +2159,9 @@ err_clean_rx:
 }
 
 #define MII_LED_CONTROL        0x1B
+#define E100_82552_LED_OVERRIDE 0x19
+#define E100_82552_LED_ON       0x000F /* LEDTX and LED_RX both on */
+#define E100_82552_LED_OFF      0x000A /* LEDTX and LED_RX both off */
 static void e100_blink_led(unsigned long data)
 {
        struct nic *nic = (struct nic *)data;
@@ -2143,10 +2171,19 @@ static void e100_blink_led(unsigned long data)
                led_on_559 = 0x05,
                led_on_557 = 0x07,
        };
+       u16 led_reg = MII_LED_CONTROL;
+
+       if (nic->phy == phy_82552_v) {
+               led_reg = E100_82552_LED_OVERRIDE;
 
-       nic->leds = (nic->leds & led_on) ? led_off :
-               (nic->mac < mac_82559_D101M) ? led_on_557 : led_on_559;
-       mdio_write(nic->netdev, nic->mii.phy_id, MII_LED_CONTROL, nic->leds);
+               nic->leds = (nic->leds == E100_82552_LED_ON) ?
+                           E100_82552_LED_OFF : E100_82552_LED_ON;
+       } else {
+               nic->leds = (nic->leds & led_on) ? led_off :
+                           (nic->mac < mac_82559_D101M) ? led_on_557 :
+                           led_on_559;
+       }
+       mdio_write(nic->netdev, nic->mii.phy_id, led_reg, nic->leds);
        mod_timer(&nic->blink_timer, jiffies + HZ / 4);
 }
 
@@ -2375,13 +2412,15 @@ static void e100_diag_test(struct net_device *netdev,
 static int e100_phys_id(struct net_device *netdev, u32 data)
 {
        struct nic *nic = netdev_priv(netdev);
+       u16 led_reg = (nic->phy == phy_82552_v) ? E100_82552_LED_OVERRIDE :
+                     MII_LED_CONTROL;
 
        if (!data || data > (u32)(MAX_SCHEDULE_TIMEOUT / HZ))
                data = (u32)(MAX_SCHEDULE_TIMEOUT / HZ);
        mod_timer(&nic->blink_timer, jiffies);
        msleep_interruptible(data * 1000);
        del_timer_sync(&nic->blink_timer);
-       mdio_write(netdev, nic->mii.phy_id, MII_LED_CONTROL, 0);
+       mdio_write(netdev, nic->mii.phy_id, led_reg, 0);
 
        return 0;
 }
@@ -2686,6 +2725,9 @@ static void __devexit e100_remove(struct pci_dev *pdev)
        }
 }
 
+#define E100_82552_SMARTSPEED   0x14   /* SmartSpeed Ctrl register */
+#define E100_82552_REV_ANEG     0x0200 /* Reverse auto-negotiation */
+#define E100_82552_ANEG_NOW     0x0400 /* Auto-negotiate now */
 static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
@@ -2698,6 +2740,15 @@ static int e100_suspend(struct pci_dev *pdev, pm_message_t state)
        pci_save_state(pdev);
 
        if ((nic->flags & wol_magic) | e100_asf(nic)) {
+               /* enable reverse auto-negotiation */
+               if (nic->phy == phy_82552_v) {
+                       u16 smartspeed = mdio_read(netdev, nic->mii.phy_id,
+                                                  E100_82552_SMARTSPEED);
+
+                       mdio_write(netdev, nic->mii.phy_id,
+                                  E100_82552_SMARTSPEED, smartspeed |
+                                  E100_82552_REV_ANEG | E100_82552_ANEG_NOW);
+               }
                if (pci_enable_wake(pdev, PCI_D3cold, true))
                        pci_enable_wake(pdev, PCI_D3hot, true);
        } else {
@@ -2721,6 +2772,16 @@ static int e100_resume(struct pci_dev *pdev)
        /* ack any pending wake events, disable PME */
        pci_enable_wake(pdev, 0, 0);
 
+       /* disbale reverse auto-negotiation */
+       if (nic->phy == phy_82552_v) {
+               u16 smartspeed = mdio_read(netdev, nic->mii.phy_id,
+                                          E100_82552_SMARTSPEED);
+
+               mdio_write(netdev, nic->mii.phy_id,
+                          E100_82552_SMARTSPEED,
+                          smartspeed & ~(E100_82552_REV_ANEG));
+       }
+
        netif_device_attach(netdev);
        if (netif_running(netdev))
                e100_up(nic);
index ca7cd7e2bf23c7ccb2ee6329a91638b451331b8e..1f390ceb486978a70be5ffa9f37fd03a6a0b4828 100644 (file)
@@ -1877,8 +1877,6 @@ int e1000_setup_all_rx_resources(struct e1000_adapter *adapter)
  * e1000_setup_rctl - configure the receive control registers
  * @adapter: Board private structure
  **/
-#define PAGE_USE_COUNT(S) (((S) >> PAGE_SHIFT) + \
-                       (((S) & (PAGE_SIZE - 1)) ? 1 : 0))
 static void e1000_setup_rctl(struct e1000_adapter *adapter)
 {
        struct e1000_hw *hw = &adapter->hw;
@@ -2051,14 +2049,10 @@ void e1000_free_all_tx_resources(struct e1000_adapter *adapter)
 static void e1000_unmap_and_free_tx_resource(struct e1000_adapter *adapter,
                                             struct e1000_buffer *buffer_info)
 {
-       if (buffer_info->dma) {
-               pci_unmap_page(adapter->pdev,
-                               buffer_info->dma,
-                               buffer_info->length,
-                               PCI_DMA_TODEVICE);
-               buffer_info->dma = 0;
-       }
+       buffer_info->dma = 0;
        if (buffer_info->skb) {
+               skb_dma_unmap(&adapter->pdev->dev, buffer_info->skb,
+                             DMA_TO_DEVICE);
                dev_kfree_skb_any(buffer_info->skb);
                buffer_info->skb = NULL;
        }
@@ -2909,16 +2903,24 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
                        unsigned int mss)
 {
        struct e1000_hw *hw = &adapter->hw;
-       struct e1000_buffer *buffer_info;
-       unsigned int len = skb->len;
-       unsigned int offset = 0, size, count = 0, i;
+       unsigned int len = skb_headlen(skb);
+       unsigned int offset, size, count = 0, i;
        unsigned int f;
-       len -= skb->data_len;
+       dma_addr_t map;
 
        i = tx_ring->next_to_use;
 
+       if (skb_dma_map(&adapter->pdev->dev, skb, DMA_TO_DEVICE)) {
+               dev_err(&adapter->pdev->dev, "TX DMA map failed\n");
+               dev_kfree_skb(skb);
+               return -2;
+       }
+
+       map = skb_shinfo(skb)->dma_maps[0];
+       offset = 0;
+
        while (len) {
-               buffer_info = &tx_ring->buffer_info[i];
+               struct e1000_buffer *buffer_info = &tx_ring->buffer_info[i];
                size = min(len, max_per_txd);
                /* Workaround for Controller erratum --
                 * descriptor for non-tso packet in a linear SKB that follows a
@@ -2951,11 +2953,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
                        size -= 4;
 
                buffer_info->length = size;
-               buffer_info->dma =
-                       pci_map_single(adapter->pdev,
-                               skb->data + offset,
-                               size,
-                               PCI_DMA_TODEVICE);
+               buffer_info->dma = map + offset;
                buffer_info->time_stamp = jiffies;
                buffer_info->next_to_watch = i;
 
@@ -2970,9 +2968,11 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
 
                frag = &skb_shinfo(skb)->frags[f];
                len = frag->size;
-               offset = frag->page_offset;
+               map = skb_shinfo(skb)->dma_maps[f + 1];
+               offset = 0;
 
                while (len) {
+                       struct e1000_buffer *buffer_info;
                        buffer_info = &tx_ring->buffer_info[i];
                        size = min(len, max_per_txd);
                        /* Workaround for premature desc write-backs
@@ -2988,12 +2988,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
                                size -= 4;
 
                        buffer_info->length = size;
-                       buffer_info->dma =
-                               pci_map_page(adapter->pdev,
-                                       frag->page,
-                                       offset,
-                                       size,
-                                       PCI_DMA_TODEVICE);
+                       buffer_info->dma = map + offset;
                        buffer_info->time_stamp = jiffies;
                        buffer_info->next_to_watch = i;
 
@@ -3007,6 +3002,7 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
        i = (i == 0) ? tx_ring->count - 1 : i - 1;
        tx_ring->buffer_info[i].skb = skb;
        tx_ring->buffer_info[first].next_to_watch = i;
+       smp_wmb();
 
        return count;
 }
@@ -3846,6 +3842,11 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter,
                /* Detect a transmit hang in hardware, this serializes the
                 * check with the clearing of time_stamp and movement of i */
                adapter->detect_tx_hung = false;
+               /*
+                * read barrier to make sure that the ->dma member and time
+                * stamp are updated fully
+                */
+               smp_rmb();
                if (tx_ring->buffer_info[eop].dma &&
                    time_after(jiffies, tx_ring->buffer_info[eop].time_stamp +
                               (adapter->tx_timeout_factor * HZ))
index 51f8e84bd4a348a51c999b2924350c74f83efb66..6c01a2072c8704d35f9697fffa1cd96e4a4f8253 100644 (file)
@@ -40,6 +40,7 @@
  * 82573E Gigabit Ethernet Controller (Copper)
  * 82573L Gigabit Ethernet Controller
  * 82574L Gigabit Network Connection
+ * 82583V Gigabit Network Connection
  */
 
 #include <linux/netdevice.h>
@@ -100,6 +101,7 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
                phy->type                = e1000_phy_m88;
                break;
        case e1000_82574:
+       case e1000_82583:
                phy->type                = e1000_phy_bm;
                break;
        default:
@@ -122,6 +124,7 @@ static s32 e1000_init_phy_params_82571(struct e1000_hw *hw)
                        return -E1000_ERR_PHY;
                break;
        case e1000_82574:
+       case e1000_82583:
                if (phy->id != BME1000_E_PHY_ID_R2)
                        return -E1000_ERR_PHY;
                break;
@@ -165,6 +168,7 @@ static s32 e1000_init_nvm_params_82571(struct e1000_hw *hw)
        switch (hw->mac.type) {
        case e1000_82573:
        case e1000_82574:
+       case e1000_82583:
                if (((eecd >> 15) & 0x3) == 0x3) {
                        nvm->type = e1000_nvm_flash_hw;
                        nvm->word_size = 2048;
@@ -262,6 +266,7 @@ static s32 e1000_init_mac_params_82571(struct e1000_adapter *adapter)
 
        switch (hw->mac.type) {
        case e1000_82574:
+       case e1000_82583:
                func->check_mng_mode = e1000_check_mng_mode_82574;
                func->led_on = e1000_led_on_82574;
                break;
@@ -375,6 +380,7 @@ static s32 e1000_get_phy_id_82571(struct e1000_hw *hw)
                return e1000e_get_phy_id(hw);
                break;
        case e1000_82574:
+       case e1000_82583:
                ret_val = e1e_rphy(hw, PHY_ID1, &phy_id);
                if (ret_val)
                        return ret_val;
@@ -464,8 +470,15 @@ static s32 e1000_acquire_nvm_82571(struct e1000_hw *hw)
        if (ret_val)
                return ret_val;
 
-       if (hw->mac.type != e1000_82573 && hw->mac.type != e1000_82574)
+       switch (hw->mac.type) {
+       case e1000_82573:
+       case e1000_82574:
+       case e1000_82583:
+               break;
+       default:
                ret_val = e1000e_acquire_nvm(hw);
+               break;
+       }
 
        if (ret_val)
                e1000_put_hw_semaphore_82571(hw);
@@ -505,6 +518,7 @@ static s32 e1000_write_nvm_82571(struct e1000_hw *hw, u16 offset, u16 words,
        switch (hw->mac.type) {
        case e1000_82573:
        case e1000_82574:
+       case e1000_82583:
                ret_val = e1000_write_nvm_eewr_82571(hw, offset, words, data);
                break;
        case e1000_82571:
@@ -779,7 +793,10 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
         * Must acquire the MDIO ownership before MAC reset.
         * Ownership defaults to firmware after a reset.
         */
-       if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
+       switch (hw->mac.type) {
+       case e1000_82573:
+       case e1000_82574:
+       case e1000_82583:
                extcnf_ctrl = er32(EXTCNF_CTRL);
                extcnf_ctrl |= E1000_EXTCNF_CTRL_MDIO_SW_OWNERSHIP;
 
@@ -795,6 +812,9 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
                        msleep(2);
                        i++;
                } while (i < MDIO_OWNERSHIP_TIMEOUT);
+               break;
+       default:
+               break;
        }
 
        ctrl = er32(CTRL);
@@ -820,8 +840,16 @@ static s32 e1000_reset_hw_82571(struct e1000_hw *hw)
         * Need to wait for Phy configuration completion before accessing
         * NVM and Phy.
         */
-       if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574)
+
+       switch (hw->mac.type) {
+       case e1000_82573:
+       case e1000_82574:
+       case e1000_82583:
                msleep(25);
+               break;
+       default:
+               break;
+       }
 
        /* Clear any pending interrupt events. */
        ew32(IMC, 0xffffffff);
@@ -891,17 +919,22 @@ static s32 e1000_init_hw_82571(struct e1000_hw *hw)
        ew32(TXDCTL(0), reg_data);
 
        /* ...for both queues. */
-       if (mac->type != e1000_82573 && mac->type != e1000_82574) {
+       switch (mac->type) {
+       case e1000_82573:
+       case e1000_82574:
+       case e1000_82583:
+               e1000e_enable_tx_pkt_filtering(hw);
+               reg_data = er32(GCR);
+               reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
+               ew32(GCR, reg_data);
+               break;
+       default:
                reg_data = er32(TXDCTL(1));
                reg_data = (reg_data & ~E1000_TXDCTL_WTHRESH) |
                           E1000_TXDCTL_FULL_TX_DESC_WB |
                           E1000_TXDCTL_COUNT_DESC;
                ew32(TXDCTL(1), reg_data);
-       } else {
-               e1000e_enable_tx_pkt_filtering(hw);
-               reg_data = er32(GCR);
-               reg_data |= E1000_GCR_L1_ACT_WITHOUT_L0S_RX;
-               ew32(GCR, reg_data);
+               break;
        }
 
        /*
@@ -966,18 +999,30 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
        }
 
        /* Device Control */
-       if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
+       switch (hw->mac.type) {
+       case e1000_82573:
+       case e1000_82574:
+       case e1000_82583:
                reg = er32(CTRL);
                reg &= ~(1 << 29);
                ew32(CTRL, reg);
+               break;
+       default:
+               break;
        }
 
        /* Extended Device Control */
-       if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
+       switch (hw->mac.type) {
+       case e1000_82573:
+       case e1000_82574:
+       case e1000_82583:
                reg = er32(CTRL_EXT);
                reg &= ~(1 << 23);
                reg |= (1 << 22);
                ew32(CTRL_EXT, reg);
+               break;
+       default:
+               break;
        }
 
        if (hw->mac.type == e1000_82571) {
@@ -999,7 +1044,9 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
 
 
        /* PCI-Ex Control Registers */
-       if (hw->mac.type == e1000_82574) {
+       switch (hw->mac.type) {
+       case e1000_82574:
+       case e1000_82583:
                reg = er32(GCR);
                reg |= (1 << 22);
                ew32(GCR, reg);
@@ -1007,6 +1054,9 @@ static void e1000_initialize_hw_bits_82571(struct e1000_hw *hw)
                reg = er32(GCR2);
                reg |= 1;
                ew32(GCR2, reg);
+               break;
+       default:
+               break;
        }
 
        return;
@@ -1026,7 +1076,10 @@ void e1000e_clear_vfta(struct e1000_hw *hw)
        u32 vfta_offset = 0;
        u32 vfta_bit_in_reg = 0;
 
-       if (hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) {
+       switch (hw->mac.type) {
+       case e1000_82573:
+       case e1000_82574:
+       case e1000_82583:
                if (hw->mng_cookie.vlan_id != 0) {
                        /*
                         * The VFTA is a 4096b bit-field, each identifying
@@ -1041,6 +1094,9 @@ void e1000e_clear_vfta(struct e1000_hw *hw)
                        vfta_bit_in_reg = 1 << (hw->mng_cookie.vlan_id &
                                               E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
                }
+               break;
+       default:
+               break;
        }
        for (offset = 0; offset < E1000_VLAN_FILTER_TBL_SIZE; offset++) {
                /*
@@ -1139,9 +1195,16 @@ static s32 e1000_setup_link_82571(struct e1000_hw *hw)
         * the default flow control setting, so we explicitly
         * set it to full.
         */
-       if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) &&
-           hw->fc.requested_mode == e1000_fc_default)
-               hw->fc.requested_mode = e1000_fc_full;
+       switch (hw->mac.type) {
+       case e1000_82573:
+       case e1000_82574:
+       case e1000_82583:
+               if (hw->fc.requested_mode == e1000_fc_default)
+                       hw->fc.requested_mode = e1000_fc_full;
+               break;
+       default:
+               break;
+       }
 
        return e1000e_setup_link(hw);
 }
@@ -1362,11 +1425,19 @@ static s32 e1000_valid_led_default_82571(struct e1000_hw *hw, u16 *data)
                return ret_val;
        }
 
-       if ((hw->mac.type == e1000_82573 || hw->mac.type == e1000_82574) &&
-           *data == ID_LED_RESERVED_F746)
-               *data = ID_LED_DEFAULT_82573;
-       else if (*data == ID_LED_RESERVED_0000 || *data == ID_LED_RESERVED_FFFF)
-               *data = ID_LED_DEFAULT;
+       switch (hw->mac.type) {
+       case e1000_82573:
+       case e1000_82574:
+       case e1000_82583:
+               if (*data == ID_LED_RESERVED_F746)
+                       *data = ID_LED_DEFAULT_82573;
+               break;
+       default:
+               if (*data == ID_LED_RESERVED_0000 ||
+                   *data == ID_LED_RESERVED_FFFF)
+                       *data = ID_LED_DEFAULT;
+               break;
+       }
 
        return 0;
 }
@@ -1659,3 +1730,19 @@ struct e1000_info e1000_82574_info = {
        .nvm_ops                = &e82571_nvm_ops,
 };
 
+struct e1000_info e1000_82583_info = {
+       .mac                    = e1000_82583,
+       .flags                  = FLAG_HAS_HW_VLAN_FILTER
+                                 | FLAG_HAS_WOL
+                                 | FLAG_APME_IN_CTRL3
+                                 | FLAG_RX_CSUM_ENABLED
+                                 | FLAG_HAS_SMART_POWER_DOWN
+                                 | FLAG_HAS_AMT
+                                 | FLAG_HAS_CTRLEXT_ON_LOAD,
+       .pba                    = 20,
+       .get_variants           = e1000_get_variants_82571,
+       .mac_ops                = &e82571_mac_ops,
+       .phy_ops                = &e82_phy_ops_bm,
+       .nvm_ops                = &e82571_nvm_ops,
+};
+
index 28bf9a51346f57511107680a0a2633d56c7ad243..f37360aa12a8d11d21d5e72b416a02250bbb1a62 100644 (file)
@@ -101,6 +101,7 @@ enum e1000_boards {
        board_82572,
        board_82573,
        board_82574,
+       board_82583,
        board_80003es2lan,
        board_ich8lan,
        board_ich9lan,
@@ -399,6 +400,7 @@ extern struct e1000_info e1000_82571_info;
 extern struct e1000_info e1000_82572_info;
 extern struct e1000_info e1000_82573_info;
 extern struct e1000_info e1000_82574_info;
+extern struct e1000_info e1000_82583_info;
 extern struct e1000_info e1000_ich8_info;
 extern struct e1000_info e1000_ich9_info;
 extern struct e1000_info e1000_ich10_info;
index 2557aeef65e6cedff2561e755d5e1c5b5558afb1..4d25ede88369ddefe384465c91a0a7111011cdff 100644 (file)
@@ -790,6 +790,7 @@ static int e1000_reg_test(struct e1000_adapter *adapter, u64 *data)
                break;
        case e1000_82573:
        case e1000_82574:
+       case e1000_82583:
        case e1000_ich8lan:
        case e1000_ich9lan:
        case e1000_ich10lan:
index 5cb428c2811d4a7483d7b29f4e50ee509e53cb5e..11a2f203a01ce21fc6d4f573888d173cc977d769 100644 (file)
@@ -339,6 +339,7 @@ enum e1e_registers {
 #define E1000_DEV_ID_82573E_IAMT               0x108C
 #define E1000_DEV_ID_82573L                    0x109A
 #define E1000_DEV_ID_82574L                    0x10D3
+#define E1000_DEV_ID_82583V                     0x150C
 
 #define E1000_DEV_ID_80003ES2LAN_COPPER_DPT    0x1096
 #define E1000_DEV_ID_80003ES2LAN_SERDES_DPT    0x1098
@@ -376,6 +377,7 @@ enum e1000_mac_type {
        e1000_82572,
        e1000_82573,
        e1000_82574,
+       e1000_82583,
        e1000_80003es2lan,
        e1000_ich8lan,
        e1000_ich9lan,
index 04e007dcf47473f89e4b56f47b4c85a4e29b95ed..f388a01793254231c49c3f3ea1624fb65c758f2d 100644 (file)
@@ -57,6 +57,7 @@ static const struct e1000_info *e1000_info_tbl[] = {
        [board_82572]           = &e1000_82572_info,
        [board_82573]           = &e1000_82573_info,
        [board_82574]           = &e1000_82574_info,
+       [board_82583]           = &e1000_82583_info,
        [board_80003es2lan]     = &e1000_es2_info,
        [board_ich8lan]         = &e1000_ich8_info,
        [board_ich9lan]         = &e1000_ich9_info,
@@ -566,15 +567,14 @@ next_desc:
 static void e1000_put_txbuf(struct e1000_adapter *adapter,
                             struct e1000_buffer *buffer_info)
 {
-       if (buffer_info->dma) {
-               pci_unmap_page(adapter->pdev, buffer_info->dma,
-                              buffer_info->length, PCI_DMA_TODEVICE);
-               buffer_info->dma = 0;
-       }
+       buffer_info->dma = 0;
        if (buffer_info->skb) {
+               skb_dma_unmap(&adapter->pdev->dev, buffer_info->skb,
+                             DMA_TO_DEVICE);
                dev_kfree_skb_any(buffer_info->skb);
                buffer_info->skb = NULL;
        }
+       buffer_info->time_stamp = 0;
 }
 
 static void e1000_print_tx_hang(struct e1000_adapter *adapter)
@@ -679,12 +679,10 @@ static bool e1000_clean_tx_irq(struct e1000_adapter *adapter)
        }
 
        if (adapter->detect_tx_hung) {
-               /*
-                * Detect a transmit hang in hardware, this serializes the
-                * check with the clearing of time_stamp and movement of i
-                */
+               /* Detect a transmit hang in hardware, this serializes the
+                * check with the clearing of time_stamp and movement of i */
                adapter->detect_tx_hung = 0;
-               if (tx_ring->buffer_info[eop].dma &&
+               if (tx_ring->buffer_info[eop].time_stamp &&
                    time_after(jiffies, tx_ring->buffer_info[eop].time_stamp
                               + (adapter->tx_timeout_factor * HZ))
                    && !(er32(STATUS) & E1000_STATUS_TXOFF)) {
@@ -3309,7 +3307,7 @@ void e1000e_update_stats(struct e1000_adapter *adapter)
 
        adapter->stats.algnerrc += er32(ALGNERRC);
        adapter->stats.rxerrc += er32(RXERRC);
-       if (hw->mac.type != e1000_82574)
+       if ((hw->mac.type != e1000_82574) && (hw->mac.type != e1000_82583))
                adapter->stats.tncrs += er32(TNCRS);
        adapter->stats.cexterr += er32(CEXTERR);
        adapter->stats.tsctc += er32(TSCTC);
@@ -3766,11 +3764,17 @@ static bool e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
        unsigned int i;
        u8 css;
        u32 cmd_len = E1000_TXD_CMD_DEXT;
+       __be16 protocol;
 
        if (skb->ip_summed != CHECKSUM_PARTIAL)
                return 0;
 
-       switch (skb->protocol) {
+       if (skb->protocol == cpu_to_be16(ETH_P_8021Q))
+               protocol = vlan_eth_hdr(skb)->h_vlan_encapsulated_proto;
+       else
+               protocol = skb->protocol;
+
+       switch (protocol) {
        case cpu_to_be16(ETH_P_IP):
                if (ip_hdr(skb)->protocol == IPPROTO_TCP)
                        cmd_len |= E1000_TXD_CMD_TCP;
@@ -3782,7 +3786,8 @@ static bool e1000_tx_csum(struct e1000_adapter *adapter, struct sk_buff *skb)
                break;
        default:
                if (unlikely(net_ratelimit()))
-                       e_warn("checksum_partial proto=%x!\n", skb->protocol);
+                       e_warn("checksum_partial proto=%x!\n",
+                              be16_to_cpu(protocol));
                break;
        }
 
@@ -3821,42 +3826,40 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
 {
        struct e1000_ring *tx_ring = adapter->tx_ring;
        struct e1000_buffer *buffer_info;
-       unsigned int len = skb->len - skb->data_len;
-       unsigned int offset = 0, size, count = 0, i;
+       unsigned int len = skb_headlen(skb);
+       unsigned int offset, size, count = 0, i;
        unsigned int f;
+       dma_addr_t *map;
 
        i = tx_ring->next_to_use;
 
+       if (skb_dma_map(&adapter->pdev->dev, skb, DMA_TO_DEVICE)) {
+               dev_err(&adapter->pdev->dev, "TX DMA map failed\n");
+               adapter->tx_dma_failed++;
+               return 0;
+       }
+
+       map = skb_shinfo(skb)->dma_maps;
+       offset = 0;
+
        while (len) {
                buffer_info = &tx_ring->buffer_info[i];
                size = min(len, max_per_txd);
 
-               /* Workaround for premature desc write-backs
-                * in TSO mode.  Append 4-byte sentinel desc */
-               if (mss && !nr_frags && size == len && size > 8)
-                       size -= 4;
-
                buffer_info->length = size;
-               /* set time_stamp *before* dma to help avoid a possible race */
                buffer_info->time_stamp = jiffies;
-               buffer_info->dma =
-                       pci_map_single(adapter->pdev,
-                               skb->data + offset,
-                               size,
-                               PCI_DMA_TODEVICE);
-               if (pci_dma_mapping_error(adapter->pdev, buffer_info->dma)) {
-                       dev_err(&adapter->pdev->dev, "TX DMA map failed\n");
-                       adapter->tx_dma_failed++;
-                       return -1;
-               }
                buffer_info->next_to_watch = i;
+               buffer_info->dma = map[0] + offset;
+               count++;
 
                len -= size;
                offset += size;
-               count++;
-               i++;
-               if (i == tx_ring->count)
-                       i = 0;
+
+               if (len) {
+                       i++;
+                       if (i == tx_ring->count)
+                               i = 0;
+               }
        }
 
        for (f = 0; f < nr_frags; f++) {
@@ -3864,49 +3867,27 @@ static int e1000_tx_map(struct e1000_adapter *adapter,
 
                frag = &skb_shinfo(skb)->frags[f];
                len = frag->size;
-               offset = frag->page_offset;
+               offset = 0;
 
                while (len) {
+                       i++;
+                       if (i == tx_ring->count)
+                               i = 0;
+
                        buffer_info = &tx_ring->buffer_info[i];
                        size = min(len, max_per_txd);
-                       /* Workaround for premature desc write-backs
-                        * in TSO mode.  Append 4-byte sentinel desc */
-                       if (mss && f == (nr_frags-1) && size == len && size > 8)
-                               size -= 4;
 
                        buffer_info->length = size;
                        buffer_info->time_stamp = jiffies;
-                       buffer_info->dma =
-                               pci_map_page(adapter->pdev,
-                                       frag->page,
-                                       offset,
-                                       size,
-                                       PCI_DMA_TODEVICE);
-                       if (pci_dma_mapping_error(adapter->pdev,
-                                                 buffer_info->dma)) {
-                               dev_err(&adapter->pdev->dev,
-                                       "TX DMA page map failed\n");
-                               adapter->tx_dma_failed++;
-                               return -1;
-                       }
-
                        buffer_info->next_to_watch = i;
+                       buffer_info->dma = map[f + 1] + offset;
 
                        len -= size;
                        offset += size;
                        count++;
-
-                       i++;
-                       if (i == tx_ring->count)
-                               i = 0;
                }
        }
 
-       if (i == 0)
-               i = tx_ring->count - 1;
-       else
-               i--;
-
        tx_ring->buffer_info[i].skb = skb;
        tx_ring->buffer_info[first].next_to_watch = i;
 
@@ -4159,20 +4140,20 @@ static int e1000_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        if (skb->protocol == htons(ETH_P_IP))
                tx_flags |= E1000_TX_FLAGS_IPV4;
 
+       /* if count is 0 then mapping error has occured */
        count = e1000_tx_map(adapter, skb, first, max_per_txd, nr_frags, mss);
-       if (count < 0) {
-               /* handle pci_map_single() error in e1000_tx_map */
+       if (count) {
+               e1000_tx_queue(adapter, tx_flags, count);
+               netdev->trans_start = jiffies;
+               /* Make sure there is space in the ring for the next send. */
+               e1000_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 2);
+
+       } else {
                dev_kfree_skb_any(skb);
-               return NETDEV_TX_OK;
+               tx_ring->buffer_info[first].time_stamp = 0;
+               tx_ring->next_to_use = first;
        }
 
-       e1000_tx_queue(adapter, tx_flags, count);
-
-       netdev->trans_start = jiffies;
-
-       /* Make sure there is space in the ring for the next send. */
-       e1000_maybe_stop_tx(netdev, MAX_SKB_FRAGS + 2);
-
        return NETDEV_TX_OK;
 }
 
@@ -5149,6 +5130,7 @@ static struct pci_device_id e1000_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82573L), board_82573 },
 
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82574L), board_82574 },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_82583V), board_82583 },
 
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_80003ES2LAN_COPPER_DPT),
          board_80003es2lan },
index 656cf1b8d32b57f3b7c32a552a9f17202a73560e..6e317caf429c98efc00b8e21acda3864946599d3 100644 (file)
@@ -40,7 +40,7 @@
 #include <asm/io.h>
 
 #define DRV_NAME       "ehea"
-#define DRV_VERSION    "EHEA_0098"
+#define DRV_VERSION    "EHEA_0100"
 
 /* eHEA capability flags */
 #define DLPAR_PORT_ADD_REM 1
index 958dacbb49741caffd8545c96248ec402eb69c59..ac0c5b438e0ab8a0427f217e2f03a030d033eea7 100644 (file)
@@ -155,6 +155,8 @@ static void ehea_update_firmware_handles(void)
        int num_fw_handles, k, l;
 
        /* Determine number of handles */
+       mutex_lock(&ehea_fw_handles.lock);
+
        list_for_each_entry(adapter, &adapter_list, list) {
                num_adapters++;
 
@@ -176,15 +178,19 @@ static void ehea_update_firmware_handles(void)
        if (num_fw_handles) {
                arr = kzalloc(num_fw_handles * sizeof(*arr), GFP_KERNEL);
                if (!arr)
-                       return;  /* Keep the existing array */
+                       goto out;  /* Keep the existing array */
        } else
                goto out_update;
 
        list_for_each_entry(adapter, &adapter_list, list) {
+               if (num_adapters == 0)
+                       break;
+
                for (k = 0; k < EHEA_MAX_PORTS; k++) {
                        struct ehea_port *port = adapter->port[k];
 
-                       if (!port || (port->state != EHEA_PORT_UP))
+                       if (!port || (port->state != EHEA_PORT_UP)
+                               || (num_ports == 0))
                                continue;
 
                        for (l = 0;
@@ -207,6 +213,7 @@ static void ehea_update_firmware_handles(void)
                        }
                        arr[i].adh = adapter->handle;
                        arr[i++].fwh = port->qp_eq->fw_handle;
+                       num_ports--;
                }
 
                arr[i].adh = adapter->handle;
@@ -216,16 +223,20 @@ static void ehea_update_firmware_handles(void)
                        arr[i].adh = adapter->handle;
                        arr[i++].fwh = adapter->mr.handle;
                }
+               num_adapters--;
        }
 
 out_update:
        kfree(ehea_fw_handles.arr);
        ehea_fw_handles.arr = arr;
        ehea_fw_handles.num_entries = i;
+out:
+       mutex_unlock(&ehea_fw_handles.lock);
 }
 
 static void ehea_update_bcmc_registrations(void)
 {
+       unsigned long flags;
        struct ehea_bcmc_reg_entry *arr = NULL;
        struct ehea_adapter *adapter;
        struct ehea_mc_list *mc_entry;
@@ -233,6 +244,8 @@ static void ehea_update_bcmc_registrations(void)
        int i = 0;
        int k;
 
+       spin_lock_irqsave(&ehea_bcmc_regs.lock, flags);
+
        /* Determine number of registrations */
        list_for_each_entry(adapter, &adapter_list, list)
                for (k = 0; k < EHEA_MAX_PORTS; k++) {
@@ -250,7 +263,7 @@ static void ehea_update_bcmc_registrations(void)
        if (num_registrations) {
                arr = kzalloc(num_registrations * sizeof(*arr), GFP_ATOMIC);
                if (!arr)
-                       return;  /* Keep the existing array */
+                       goto out;  /* Keep the existing array */
        } else
                goto out_update;
 
@@ -261,6 +274,9 @@ static void ehea_update_bcmc_registrations(void)
                        if (!port || (port->state != EHEA_PORT_UP))
                                continue;
 
+                       if (num_registrations == 0)
+                               goto out_update;
+
                        arr[i].adh = adapter->handle;
                        arr[i].port_id = port->logical_port_id;
                        arr[i].reg_type = EHEA_BCMC_BROADCAST |
@@ -272,9 +288,13 @@ static void ehea_update_bcmc_registrations(void)
                        arr[i].reg_type = EHEA_BCMC_BROADCAST |
                                          EHEA_BCMC_VLANID_ALL;
                        arr[i++].macaddr = port->mac_addr;
+                       num_registrations -= 2;
 
                        list_for_each_entry(mc_entry,
                                            &port->mc_list->list, list) {
+                               if (num_registrations == 0)
+                                       goto out_update;
+
                                arr[i].adh = adapter->handle;
                                arr[i].port_id = port->logical_port_id;
                                arr[i].reg_type = EHEA_BCMC_SCOPE_ALL |
@@ -288,6 +308,7 @@ static void ehea_update_bcmc_registrations(void)
                                                  EHEA_BCMC_MULTICAST |
                                                  EHEA_BCMC_VLANID_ALL;
                                arr[i++].macaddr = mc_entry->macaddr;
+                               num_registrations -= 2;
                        }
                }
        }
@@ -296,6 +317,8 @@ out_update:
        kfree(ehea_bcmc_regs.arr);
        ehea_bcmc_regs.arr = arr;
        ehea_bcmc_regs.num_entries = i;
+out:
+       spin_unlock_irqrestore(&ehea_bcmc_regs.lock, flags);
 }
 
 static struct net_device_stats *ehea_get_stats(struct net_device *dev)
@@ -1762,8 +1785,6 @@ static int ehea_set_mac_addr(struct net_device *dev, void *sa)
 
        memcpy(dev->dev_addr, mac_addr->sa_data, dev->addr_len);
 
-       spin_lock(&ehea_bcmc_regs.lock);
-
        /* Deregister old MAC in pHYP */
        if (port->state == EHEA_PORT_UP) {
                ret = ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
@@ -1784,7 +1805,6 @@ static int ehea_set_mac_addr(struct net_device *dev, void *sa)
 
 out_upregs:
        ehea_update_bcmc_registrations();
-       spin_unlock(&ehea_bcmc_regs.lock);
 out_free:
        free_page((unsigned long)cb0);
 out:
@@ -1946,8 +1966,6 @@ static void ehea_set_multicast_list(struct net_device *dev)
        }
        ehea_promiscuous(dev, 0);
 
-       spin_lock(&ehea_bcmc_regs.lock);
-
        if (dev->flags & IFF_ALLMULTI) {
                ehea_allmulti(dev, 1);
                goto out;
@@ -1977,7 +1995,6 @@ static void ehea_set_multicast_list(struct net_device *dev)
        }
 out:
        ehea_update_bcmc_registrations();
-       spin_unlock(&ehea_bcmc_regs.lock);
        return;
 }
 
@@ -2458,8 +2475,6 @@ static int ehea_up(struct net_device *dev)
        if (port->state == EHEA_PORT_UP)
                return 0;
 
-       mutex_lock(&ehea_fw_handles.lock);
-
        ret = ehea_port_res_setup(port, port->num_def_qps,
                                  port->num_add_tx_qps);
        if (ret) {
@@ -2496,8 +2511,6 @@ static int ehea_up(struct net_device *dev)
                }
        }
 
-       spin_lock(&ehea_bcmc_regs.lock);
-
        ret = ehea_broadcast_reg_helper(port, H_REG_BCMC);
        if (ret) {
                ret = -EIO;
@@ -2519,10 +2532,7 @@ out:
                ehea_info("Failed starting %s. ret=%i", dev->name, ret);
 
        ehea_update_bcmc_registrations();
-       spin_unlock(&ehea_bcmc_regs.lock);
-
        ehea_update_firmware_handles();
-       mutex_unlock(&ehea_fw_handles.lock);
 
        return ret;
 }
@@ -2572,9 +2582,6 @@ static int ehea_down(struct net_device *dev)
        if (port->state == EHEA_PORT_DOWN)
                return 0;
 
-       mutex_lock(&ehea_fw_handles.lock);
-
-       spin_lock(&ehea_bcmc_regs.lock);
        ehea_drop_multicast_list(dev);
        ehea_broadcast_reg_helper(port, H_DEREG_BCMC);
 
@@ -2583,7 +2590,6 @@ static int ehea_down(struct net_device *dev)
        port->state = EHEA_PORT_DOWN;
 
        ehea_update_bcmc_registrations();
-       spin_unlock(&ehea_bcmc_regs.lock);
 
        ret = ehea_clean_all_portres(port);
        if (ret)
@@ -2591,7 +2597,6 @@ static int ehea_down(struct net_device *dev)
                          dev->name, ret);
 
        ehea_update_firmware_handles();
-       mutex_unlock(&ehea_fw_handles.lock);
 
        return ret;
 }
@@ -3368,7 +3373,6 @@ static int __devinit ehea_probe_adapter(struct of_device *dev,
                ehea_error("Invalid ibmebus device probed");
                return -EINVAL;
        }
-       mutex_lock(&ehea_fw_handles.lock);
 
        adapter = kzalloc(sizeof(*adapter), GFP_KERNEL);
        if (!adapter) {
@@ -3453,7 +3457,7 @@ out_free_ad:
 
 out:
        ehea_update_firmware_handles();
-       mutex_unlock(&ehea_fw_handles.lock);
+
        return ret;
 }
 
@@ -3472,8 +3476,6 @@ static int __devexit ehea_remove(struct of_device *dev)
 
        flush_scheduled_work();
 
-       mutex_lock(&ehea_fw_handles.lock);
-
        ibmebus_free_irq(adapter->neq->attr.ist1, adapter);
        tasklet_kill(&adapter->neq_tasklet);
 
@@ -3483,7 +3485,6 @@ static int __devexit ehea_remove(struct of_device *dev)
        kfree(adapter);
 
        ehea_update_firmware_handles();
-       mutex_unlock(&ehea_fw_handles.lock);
 
        return 0;
 }
@@ -3517,12 +3518,14 @@ static int ehea_mem_notifier(struct notifier_block *nb,
                /* Readd canceled memory block */
        case MEM_ONLINE:
                ehea_info("memory is going online");
+               set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
                if (ehea_add_sect_bmap(arg->start_pfn, arg->nr_pages))
                        return NOTIFY_BAD;
                ehea_rereg_mrs(NULL);
                break;
        case MEM_GOING_OFFLINE:
                ehea_info("memory is going offline");
+               set_bit(__EHEA_STOP_XFER, &ehea_driver_flags);
                if (ehea_rem_sect_bmap(arg->start_pfn, arg->nr_pages))
                        return NOTIFY_BAD;
                ehea_rereg_mrs(NULL);
@@ -3530,6 +3533,9 @@ static int ehea_mem_notifier(struct notifier_block *nb,
        default:
                break;
        }
+
+       ehea_update_firmware_handles();
+
        return NOTIFY_OK;
 }
 
index 40125694bd9f641209eb03fb90a04e8ad4d99998..51ead7941f83ad249f6757eda2b50f6b6521d758 100644 (file)
@@ -159,7 +159,7 @@ static void eql_timer(unsigned long param)
        add_timer(&eql->timer);
 }
 
-static char version[] __initdata =
+static const char version[] __initconst =
        "Equalizer2002: Simon Janes (simon@ncm.com) and David S. Miller (davem@redhat.com)\n";
 
 static const struct net_device_ops eql_netdev_ops = {
index daf7272c335260c2b2ac6edffbb3929ef7322edf..891be28a7d4f43625ad5072c77b372e854564a01 100644 (file)
@@ -93,8 +93,8 @@ static int full_duplex[MAX_UNITS] = { -1, -1, -1, -1, -1, -1, -1, -1 };
 #include <asm/byteorder.h>
 
 /* These identify the driver base version and may not be removed. */
-static char version[] =
-KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "\n";
+static const char version[] __devinitconst =
+       KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "\n";
 
 
 /* This driver was written to use PCI memory space, however some x86 systems
index fe2650237e349a407b8bc22c5bf0af5c7dbddb11..a515acccc61f7f64a7b19ecda6773e5af26131c2 100644 (file)
 #define FEC_ALIGNMENT  0x3
 #endif
 
-#if defined CONFIG_M5272 || defined CONFIG_M527x || defined CONFIG_M523x \
-       || defined CONFIG_M528x || defined CONFIG_M532x || defined CONFIG_M520x
-#define FEC_LEGACY
 /*
  * Define the fixed address of the FEC hardware.
  */
 #if defined(CONFIG_M5272)
 #define HAVE_mii_link_interrupt
-#endif
-
-#if defined(CONFIG_FEC2)
-#define        FEC_MAX_PORTS   2
-#else
-#define        FEC_MAX_PORTS   1
-#endif
-
-static unsigned int fec_hw[] = {
-#if defined(CONFIG_M5272)
-       (MCF_MBAR + 0x840),
-#elif defined(CONFIG_M527x)
-       (MCF_MBAR + 0x1000),
-       (MCF_MBAR + 0x1800),
-#elif defined(CONFIG_M523x) || defined(CONFIG_M528x)
-       (MCF_MBAR + 0x1000),
-#elif defined(CONFIG_M520x)
-       (MCF_MBAR+0x30000),
-#elif defined(CONFIG_M532x)
-       (MCF_MBAR+0xfc030000),
-#endif
-};
 
 static unsigned char   fec_mac_default[] = {
        0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
@@ -109,8 +84,7 @@ static unsigned char fec_mac_default[] = {
 #else
 #define        FEC_FLASHMAC    0
 #endif
-
-#endif /* FEC_LEGACY */
+#endif /* CONFIG_M5272 */
 
 /* Forward declarations of some structures to support different PHYs
 */
@@ -1242,89 +1216,14 @@ static phy_info_t const * const phy_info[] = {
 #ifdef HAVE_mii_link_interrupt
 static irqreturn_t
 mii_link_interrupt(int irq, void * dev_id);
-#endif
 
-#if defined(CONFIG_M5272)
 /*
- *     Code specific to Coldfire 5272 setup.
+ *     This is specific to the MII interrupt setup of the M5272EVB.
  */
-static void __inline__ fec_request_intrs(struct net_device *dev)
+static void __inline__ fec_request_mii_intr(struct net_device *dev)
 {
-       volatile unsigned long *icrp;
-       static const struct idesc {
-               char *name;
-               unsigned short irq;
-               irq_handler_t handler;
-       } *idp, id[] = {
-               { "fec(RX)", 86, fec_enet_interrupt },
-               { "fec(TX)", 87, fec_enet_interrupt },
-               { "fec(OTHER)", 88, fec_enet_interrupt },
-               { "fec(MII)", 66, mii_link_interrupt },
-               { NULL },
-       };
-
-       /* Setup interrupt handlers. */
-       for (idp = id; idp->name; idp++) {
-               if (request_irq(idp->irq, idp->handler, IRQF_DISABLED, idp->name, dev) != 0)
-                       printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, idp->irq);
-       }
-
-       /* Unmask interrupt at ColdFire 5272 SIM */
-       icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR3);
-       *icrp = 0x00000ddd;
-       icrp = (volatile unsigned long *) (MCF_MBAR + MCFSIM_ICR1);
-       *icrp = 0x0d000000;
-}
-
-static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
-{
-       volatile fec_t *fecp;
-
-       fecp = fep->hwp;
-       fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
-       fecp->fec_x_cntrl = 0x00;
-
-       /*
-        * Set MII speed to 2.5 MHz
-        * See 5272 manual section 11.5.8: MSCR
-        */
-       fep->phy_speed = ((((MCF_CLK / 4) / (2500000 / 10)) + 5) / 10) * 2;
-       fecp->fec_mii_speed = fep->phy_speed;
-
-       fec_restart(dev, 0);
-}
-
-static void __inline__ fec_get_mac(struct net_device *dev)
-{
-       struct fec_enet_private *fep = netdev_priv(dev);
-       volatile fec_t *fecp;
-       unsigned char *iap, tmpaddr[ETH_ALEN];
-
-       fecp = fep->hwp;
-
-       if (FEC_FLASHMAC) {
-               /*
-                * Get MAC address from FLASH.
-                * If it is all 1's or 0's, use the default.
-                */
-               iap = (unsigned char *)FEC_FLASHMAC;
-               if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
-                   (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
-                       iap = fec_mac_default;
-               if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
-                   (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
-                       iap = fec_mac_default;
-       } else {
-               *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
-               *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
-               iap = &tmpaddr[0];
-       }
-
-       memcpy(dev->dev_addr, iap, ETH_ALEN);
-
-       /* Adjust MAC if using default MAC address */
-       if (iap == fec_mac_default)
-                dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
+       if (request_irq(66, mii_link_interrupt, IRQF_DISABLED, "fec(MII)", dev) != 0)
+               printk("FEC: Could not allocate fec(MII) IRQ(66)!\n");
 }
 
 static void __inline__ fec_disable_phy_intr(void)
@@ -1342,218 +1241,7 @@ static void __inline__ fec_phy_ack_intr(void)
        *icrp = 0x0d000000;
 }
 
-/* ------------------------------------------------------------------------- */
-
-#elif defined(CONFIG_M523x) || defined(CONFIG_M527x) || defined(CONFIG_M528x)
-
-/*
- *     Code specific to Coldfire 5230/5231/5232/5234/5235,
- *     the 5270/5271/5274/5275 and 5280/5282 setups.
- */
-static void __inline__ fec_request_intrs(struct net_device *dev)
-{
-       struct fec_enet_private *fep;
-       int b;
-       static const struct idesc {
-               char *name;
-               unsigned short irq;
-       } *idp, id[] = {
-               { "fec(TXF)", 23 },
-               { "fec(RXF)", 27 },
-               { "fec(MII)", 29 },
-               { NULL },
-       };
-
-       fep = netdev_priv(dev);
-       b = (fep->index) ? 128 : 64;
-
-       /* Setup interrupt handlers. */
-       for (idp = id; idp->name; idp++) {
-               if (request_irq(b+idp->irq, fec_enet_interrupt, IRQF_DISABLED, idp->name, dev) != 0)
-                       printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq);
-       }
-
-       /* Unmask interrupts at ColdFire 5280/5282 interrupt controller */
-       {
-               volatile unsigned char  *icrp;
-               volatile unsigned long  *imrp;
-               int i, ilip;
-
-               b = (fep->index) ? MCFICM_INTC1 : MCFICM_INTC0;
-               icrp = (volatile unsigned char *) (MCF_IPSBAR + b +
-                       MCFINTC_ICR0);
-               for (i = 23, ilip = 0x28; (i < 36); i++)
-                       icrp[i] = ilip--;
-
-               imrp = (volatile unsigned long *) (MCF_IPSBAR + b +
-                       MCFINTC_IMRH);
-               *imrp &= ~0x0000000f;
-               imrp = (volatile unsigned long *) (MCF_IPSBAR + b +
-                       MCFINTC_IMRL);
-               *imrp &= ~0xff800001;
-       }
-
-#if defined(CONFIG_M528x)
-       /* Set up gpio outputs for MII lines */
-       {
-               volatile u16 *gpio_paspar;
-               volatile u8 *gpio_pehlpar;
-
-               gpio_paspar = (volatile u16 *) (MCF_IPSBAR + 0x100056);
-               gpio_pehlpar = (volatile u16 *) (MCF_IPSBAR + 0x100058);
-               *gpio_paspar |= 0x0f00;
-               *gpio_pehlpar = 0xc0;
-       }
-#endif
-
-#if defined(CONFIG_M527x)
-       /* Set up gpio outputs for MII lines */
-       {
-               volatile u8 *gpio_par_fec;
-               volatile u16 *gpio_par_feci2c;
-
-               gpio_par_feci2c = (volatile u16 *)(MCF_IPSBAR + 0x100082);
-               /* Set up gpio outputs for FEC0 MII lines */
-               gpio_par_fec = (volatile u8 *)(MCF_IPSBAR + 0x100078);
-
-               *gpio_par_feci2c |= 0x0f00;
-               *gpio_par_fec |= 0xc0;
-
-#if defined(CONFIG_FEC2)
-               /* Set up gpio outputs for FEC1 MII lines */
-               gpio_par_fec = (volatile u8 *)(MCF_IPSBAR + 0x100079);
-
-               *gpio_par_feci2c |= 0x00a0;
-               *gpio_par_fec |= 0xc0;
-#endif /* CONFIG_FEC2 */
-       }
-#endif /* CONFIG_M527x */
-}
-
-static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
-{
-       volatile fec_t *fecp;
-
-       fecp = fep->hwp;
-       fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
-       fecp->fec_x_cntrl = 0x00;
-
-       /*
-        * Set MII speed to 2.5 MHz
-        * See 5282 manual section 17.5.4.7: MSCR
-        */
-       fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2;
-       fecp->fec_mii_speed = fep->phy_speed;
-
-       fec_restart(dev, 0);
-}
-
-static void __inline__ fec_get_mac(struct net_device *dev)
-{
-       struct fec_enet_private *fep = netdev_priv(dev);
-       volatile fec_t *fecp;
-       unsigned char *iap, tmpaddr[ETH_ALEN];
-
-       fecp = fep->hwp;
-
-       if (FEC_FLASHMAC) {
-               /*
-                * Get MAC address from FLASH.
-                * If it is all 1's or 0's, use the default.
-                */
-               iap = FEC_FLASHMAC;
-               if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
-                   (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
-                       iap = fec_mac_default;
-               if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
-                   (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
-                       iap = fec_mac_default;
-       } else {
-               *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
-               *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
-               iap = &tmpaddr[0];
-       }
-
-       memcpy(dev->dev_addr, iap, ETH_ALEN);
-
-       /* Adjust MAC if using default MAC address */
-       if (iap == fec_mac_default)
-               dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
-}
-
-static void __inline__ fec_disable_phy_intr(void)
-{
-}
-
-static void __inline__ fec_phy_ack_intr(void)
-{
-}
-
-/* ------------------------------------------------------------------------- */
-
-#elif defined(CONFIG_M520x)
-
-/*
- *     Code specific to Coldfire 520x
- */
-static void __inline__ fec_request_intrs(struct net_device *dev)
-{
-       struct fec_enet_private *fep;
-       int b;
-       static const struct idesc {
-               char *name;
-               unsigned short irq;
-       } *idp, id[] = {
-               { "fec(TXF)", 23 },
-               { "fec(RXF)", 27 },
-               { "fec(MII)", 29 },
-               { NULL },
-       };
-
-       fep = netdev_priv(dev);
-       b = 64 + 13;
-
-       /* Setup interrupt handlers. */
-       for (idp = id; idp->name; idp++) {
-               if (request_irq(b+idp->irq, fec_enet_interrupt, IRQF_DISABLED, idp->name,dev) != 0)
-                       printk("FEC: Could not allocate %s IRQ(%d)!\n", idp->name, b+idp->irq);
-       }
-
-       /* Unmask interrupts at ColdFire interrupt controller */
-       {
-               volatile unsigned char  *icrp;
-               volatile unsigned long  *imrp;
-
-               icrp = (volatile unsigned char *) (MCF_IPSBAR + MCFICM_INTC0 +
-                       MCFINTC_ICR0);
-               for (b = 36; (b < 49); b++)
-                       icrp[b] = 0x04;
-               imrp = (volatile unsigned long *) (MCF_IPSBAR + MCFICM_INTC0 +
-                       MCFINTC_IMRH);
-               *imrp &= ~0x0001FFF0;
-       }
-       *(volatile unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FEC) |= 0xf0;
-       *(volatile unsigned char *)(MCF_IPSBAR + MCF_GPIO_PAR_FECI2C) |= 0x0f;
-}
-
-static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
-{
-       volatile fec_t *fecp;
-
-       fecp = fep->hwp;
-       fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
-       fecp->fec_x_cntrl = 0x00;
-
-       /*
-        * Set MII speed to 2.5 MHz
-        * See 5282 manual section 17.5.4.7: MSCR
-        */
-       fep->phy_speed = ((((MCF_CLK / 2) / (2500000 / 10)) + 5) / 10) * 2;
-       fecp->fec_mii_speed = fep->phy_speed;
-
-       fec_restart(dev, 0);
-}
-
+#ifdef CONFIG_M5272
 static void __inline__ fec_get_mac(struct net_device *dev)
 {
        struct fec_enet_private *fep = netdev_priv(dev);
@@ -1567,134 +1255,7 @@ static void __inline__ fec_get_mac(struct net_device *dev)
                 * Get MAC address from FLASH.
                 * If it is all 1's or 0's, use the default.
                 */
-               iap = FEC_FLASHMAC;
-               if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
-                  (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
-                       iap = fec_mac_default;
-               if ((iap[0] == 0xff) && (iap[1] == 0xff) && (iap[2] == 0xff) &&
-                  (iap[3] == 0xff) && (iap[4] == 0xff) && (iap[5] == 0xff))
-                       iap = fec_mac_default;
-       } else {
-               *((unsigned long *) &tmpaddr[0]) = fecp->fec_addr_low;
-               *((unsigned short *) &tmpaddr[4]) = (fecp->fec_addr_high >> 16);
-               iap = &tmpaddr[0];
-       }
-
-       memcpy(dev->dev_addr, iap, ETH_ALEN);
-
-       /* Adjust MAC if using default MAC address */
-       if (iap == fec_mac_default)
-               dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
-}
-
-static void __inline__ fec_disable_phy_intr(void)
-{
-}
-
-static void __inline__ fec_phy_ack_intr(void)
-{
-}
-
-/* ------------------------------------------------------------------------- */
-
-#elif defined(CONFIG_M532x)
-/*
- * Code specific for M532x
- */
-static void __inline__ fec_request_intrs(struct net_device *dev)
-{
-       struct fec_enet_private *fep;
-       int b;
-       static const struct idesc {
-               char *name;
-               unsigned short irq;
-       } *idp, id[] = {
-           { "fec(TXF)", 36 },
-           { "fec(RXF)", 40 },
-           { "fec(MII)", 42 },
-           { NULL },
-       };
-
-       fep = netdev_priv(dev);
-       b = (fep->index) ? 128 : 64;
-
-       /* Setup interrupt handlers. */
-       for (idp = id; idp->name; idp++) {
-               if (request_irq(b+idp->irq, fec_enet_interrupt, IRQF_DISABLED, idp->name,dev) != 0)
-                       printk("FEC: Could not allocate %s IRQ(%d)!\n",
-                               idp->name, b+idp->irq);
-       }
-
-       /* Unmask interrupts */
-       MCF_INTC0_ICR36 = 0x2;
-       MCF_INTC0_ICR37 = 0x2;
-       MCF_INTC0_ICR38 = 0x2;
-       MCF_INTC0_ICR39 = 0x2;
-       MCF_INTC0_ICR40 = 0x2;
-       MCF_INTC0_ICR41 = 0x2;
-       MCF_INTC0_ICR42 = 0x2;
-       MCF_INTC0_ICR43 = 0x2;
-       MCF_INTC0_ICR44 = 0x2;
-       MCF_INTC0_ICR45 = 0x2;
-       MCF_INTC0_ICR46 = 0x2;
-       MCF_INTC0_ICR47 = 0x2;
-       MCF_INTC0_ICR48 = 0x2;
-
-       MCF_INTC0_IMRH &= ~(
-               MCF_INTC_IMRH_INT_MASK36 |
-               MCF_INTC_IMRH_INT_MASK37 |
-               MCF_INTC_IMRH_INT_MASK38 |
-               MCF_INTC_IMRH_INT_MASK39 |
-               MCF_INTC_IMRH_INT_MASK40 |
-               MCF_INTC_IMRH_INT_MASK41 |
-               MCF_INTC_IMRH_INT_MASK42 |
-               MCF_INTC_IMRH_INT_MASK43 |
-               MCF_INTC_IMRH_INT_MASK44 |
-               MCF_INTC_IMRH_INT_MASK45 |
-               MCF_INTC_IMRH_INT_MASK46 |
-               MCF_INTC_IMRH_INT_MASK47 |
-               MCF_INTC_IMRH_INT_MASK48 );
-
-       /* Set up gpio outputs for MII lines */
-       MCF_GPIO_PAR_FECI2C |= (0 |
-               MCF_GPIO_PAR_FECI2C_PAR_MDC_EMDC |
-               MCF_GPIO_PAR_FECI2C_PAR_MDIO_EMDIO);
-       MCF_GPIO_PAR_FEC = (0 |
-               MCF_GPIO_PAR_FEC_PAR_FEC_7W_FEC |
-               MCF_GPIO_PAR_FEC_PAR_FEC_MII_FEC);
-}
-
-static void __inline__ fec_set_mii(struct net_device *dev, struct fec_enet_private *fep)
-{
-       volatile fec_t *fecp;
-
-       fecp = fep->hwp;
-       fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
-       fecp->fec_x_cntrl = 0x00;
-
-       /*
-        * Set MII speed to 2.5 MHz
-        */
-       fep->phy_speed = (MCF_CLK / 3) / (2500000 * 2 ) * 2;
-       fecp->fec_mii_speed = fep->phy_speed;
-
-       fec_restart(dev, 0);
-}
-
-static void __inline__ fec_get_mac(struct net_device *dev)
-{
-       struct fec_enet_private *fep = netdev_priv(dev);
-       volatile fec_t *fecp;
-       unsigned char *iap, tmpaddr[ETH_ALEN];
-
-       fecp = fep->hwp;
-
-       if (FEC_FLASHMAC) {
-               /*
-                * Get MAC address from FLASH.
-                * If it is all 1's or 0's, use the default.
-                */
-               iap = FEC_FLASHMAC;
+               iap = (unsigned char *)FEC_FLASHMAC;
                if ((iap[0] == 0) && (iap[1] == 0) && (iap[2] == 0) &&
                    (iap[3] == 0) && (iap[4] == 0) && (iap[5] == 0))
                        iap = fec_mac_default;
@@ -1711,17 +1272,8 @@ static void __inline__ fec_get_mac(struct net_device *dev)
 
        /* Adjust MAC if using default MAC address */
        if (iap == fec_mac_default)
-               dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
-}
-
-static void __inline__ fec_disable_phy_intr(void)
-{
-}
-
-static void __inline__ fec_phy_ack_intr(void)
-{
+                dev->dev_addr[ETH_ALEN-1] = fec_mac_default[ETH_ALEN-1] + fep->index;
 }
-
 #endif
 
 /* ------------------------------------------------------------------------- */
@@ -1927,7 +1479,7 @@ mii_discover_phy(uint mii_reg, struct net_device *dev)
                printk("FEC: No PHY device found.\n");
                /* Disable external MII interface */
                fecp->fec_mii_speed = fep->phy_speed = 0;
-#ifdef FREC_LEGACY
+#ifdef HAVE_mii_link_interrupt
                fec_disable_phy_intr();
 #endif
        }
@@ -2151,7 +1703,7 @@ int __init fec_enet_init(struct net_device *dev, int index)
        udelay(10);
 
        /* Set the Ethernet address */
-#ifdef FEC_LEGACY
+#ifdef CONFIG_M5272
        fec_get_mac(dev);
 #else
        {
@@ -2235,11 +1787,8 @@ int __init fec_enet_init(struct net_device *dev, int index)
        fecp->fec_x_des_start = (unsigned long)fep->bd_dma + sizeof(cbd_t)
                                * RX_RING_SIZE;
 
-#ifdef FEC_LEGACY
-       /* Install our interrupt handlers. This varies depending on
-        * the architecture.
-       */
-       fec_request_intrs(dev);
+#ifdef HAVE_mii_link_interrupt
+       fec_request_mii_intr(dev);
 #endif
 
        fecp->fec_grp_hash_table_high = 0;
@@ -2265,9 +1814,6 @@ int __init fec_enet_init(struct net_device *dev, int index)
        mii_free = mii_cmds;
 
        /* setup MII interface */
-#ifdef FEC_LEGACY
-       fec_set_mii(dev, fep);
-#else
        fecp->fec_r_cntrl = OPT_FRAME_SIZE | 0x04;
        fecp->fec_x_cntrl = 0x00;
 
@@ -2278,7 +1824,6 @@ int __init fec_enet_init(struct net_device *dev, int index)
                                        / 2500000) / 2) & 0x3F) << 1;
        fecp->fec_mii_speed = fep->phy_speed;
        fec_restart(dev, 0);
-#endif
 
        /* Clear and enable interrupts */
        fecp->fec_ievent = 0xffc00000;
@@ -2442,36 +1987,6 @@ fec_stop(struct net_device *dev)
        fecp->fec_mii_speed = fep->phy_speed;
 }
 
-#ifdef FEC_LEGACY
-static int __init fec_enet_module_init(void)
-{
-       struct net_device *dev;
-       int i, err;
-
-       printk("FEC ENET Version 0.2\n");
-
-       for (i = 0; (i < FEC_MAX_PORTS); i++) {
-               dev = alloc_etherdev(sizeof(struct fec_enet_private));
-               if (!dev)
-                       return -ENOMEM;
-               dev->base_addr = (unsigned long)fec_hw[i];
-               err = fec_enet_init(dev, i);
-               if (err) {
-                       free_netdev(dev);
-                       continue;
-               }
-               if (register_netdev(dev) != 0) {
-                       /* XXX: missing cleanup here */
-                       free_netdev(dev);
-                       return -EIO;
-               }
-
-               printk("%s: ethernet %pM\n", dev->name, dev->dev_addr);
-       }
-       return 0;
-}
-#else
-
 static int __devinit
 fec_probe(struct platform_device *pdev)
 {
@@ -2632,9 +2147,6 @@ fec_enet_cleanup(void)
 }
 
 module_exit(fec_enet_cleanup);
-
-#endif /* FEC_LEGACY */
-
 module_init(fec_enet_module_init);
 
 MODULE_LICENSE("GPL");
index 021308f9f0c79b5bf62a928a104de2ffab5f6fd4..a858c6ff80ddd7517df1fac3ef90eafc64d81a28 100644 (file)
@@ -39,7 +39,7 @@
  * DEV_NEED_TIMERIRQ will not harm you on sane hardware, only generating a few
  * superfluous timer interrupts from the nic.
  */
-#define FORCEDETH_VERSION              "0.63"
+#define FORCEDETH_VERSION              "0.64"
 #define DRV_NAME                       "forcedeth"
 
 #include <linux/module.h>
@@ -87,8 +87,8 @@
 #define DEV_HAS_MSI_X              0x000080  /* device supports MSI-X */
 #define DEV_HAS_POWER_CNTRL        0x000100  /* device supports power savings */
 #define DEV_HAS_STATISTICS_V1      0x000200  /* device supports hw statistics version 1 */
-#define DEV_HAS_STATISTICS_V2      0x000400  /* device supports hw statistics version 2 */
-#define DEV_HAS_STATISTICS_V3      0x000800  /* device supports hw statistics version 3 */
+#define DEV_HAS_STATISTICS_V2      0x000600  /* device supports hw statistics version 2 */
+#define DEV_HAS_STATISTICS_V3      0x000e00  /* device supports hw statistics version 3 */
 #define DEV_HAS_TEST_EXTENDED      0x001000  /* device supports extended diagnostic test */
 #define DEV_HAS_MGMT_UNIT          0x002000  /* device supports management unit */
 #define DEV_HAS_CORRECT_MACADDR    0x004000  /* device supports correct mac address order */
@@ -120,10 +120,6 @@ enum {
 #define NVREG_IRQ_RX_ALL               (NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_RX_FORCED)
 #define NVREG_IRQ_OTHER                        (NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_RECOVER_ERROR)
 
-#define NVREG_IRQ_UNKNOWN      (~(NVREG_IRQ_RX_ERROR|NVREG_IRQ_RX|NVREG_IRQ_RX_NOBUF|NVREG_IRQ_TX_ERR| \
-                                       NVREG_IRQ_TX_OK|NVREG_IRQ_TIMER|NVREG_IRQ_LINK|NVREG_IRQ_RX_FORCED| \
-                                       NVREG_IRQ_TX_FORCED|NVREG_IRQ_RECOVER_ERROR))
-
        NvRegUnknownSetupReg6 = 0x008,
 #define NVREG_UNKSETUP6_VAL            3
 
@@ -132,7 +128,7 @@ enum {
  * NVREG_POLL_DEFAULT=97 would result in an interval length of 1 ms
  */
        NvRegPollingInterval = 0x00c,
-#define NVREG_POLL_DEFAULT_THROUGHPUT  970 /* backup tx cleanup if loop max reached */
+#define NVREG_POLL_DEFAULT_THROUGHPUT  65535 /* backup tx cleanup if loop max reached */
 #define NVREG_POLL_DEFAULT_CPU 13
        NvRegMSIMap0 = 0x020,
        NvRegMSIMap1 = 0x024,
@@ -467,7 +463,7 @@ union ring_type {
 /* General driver defaults */
 #define NV_WATCHDOG_TIMEO      (5*HZ)
 
-#define RX_RING_DEFAULT                128
+#define RX_RING_DEFAULT                512
 #define TX_RING_DEFAULT                256
 #define RX_RING_MIN            128
 #define TX_RING_MIN            64
@@ -597,6 +593,9 @@ union ring_type {
 
 #define NV_TX_LIMIT_COUNT     16
 
+#define NV_DYNAMIC_THRESHOLD        4
+#define NV_DYNAMIC_MAX_QUIET_COUNT  2048
+
 /* statistics */
 struct nv_ethtool_str {
        char name[ETH_GSTRING_LEN];
@@ -754,11 +753,13 @@ struct fe_priv {
        u16 gigabit;
        int intr_test;
        int recover_error;
+       int quiet_count;
 
        /* General data: RO fields */
        dma_addr_t ring_addr;
        struct pci_dev *pci_dev;
        u32 orig_mac[2];
+       u32 events;
        u32 irqmask;
        u32 desc_ver;
        u32 txrxctl_bits;
@@ -835,7 +836,7 @@ struct fe_priv {
  * Maximum number of loops until we assume that a bit in the irq mask
  * is stuck. Overridable with module param.
  */
-static int max_interrupt_work = 15;
+static int max_interrupt_work = 4;
 
 /*
  * Optimization can be either throuput mode or cpu mode
@@ -845,9 +846,10 @@ static int max_interrupt_work = 15;
  */
 enum {
        NV_OPTIMIZATION_MODE_THROUGHPUT,
-       NV_OPTIMIZATION_MODE_CPU
+       NV_OPTIMIZATION_MODE_CPU,
+       NV_OPTIMIZATION_MODE_DYNAMIC
 };
-static int optimization_mode = NV_OPTIMIZATION_MODE_THROUGHPUT;
+static int optimization_mode = NV_OPTIMIZATION_MODE_DYNAMIC;
 
 /*
  * Poll interval for timer irq
@@ -940,7 +942,7 @@ static int reg_delay(struct net_device *dev, int offset, u32 mask, u32 target,
                delaymax -= delay;
                if (delaymax < 0) {
                        if (msg)
-                               printk(msg);
+                               printk("%s", msg);
                        return 1;
                }
        } while ((readl(base + offset) & mask) != target);
@@ -1069,6 +1071,24 @@ static void nv_disable_hw_interrupts(struct net_device *dev, u32 mask)
        }
 }
 
+static void nv_napi_enable(struct net_device *dev)
+{
+#ifdef CONFIG_FORCEDETH_NAPI
+       struct fe_priv *np = get_nvpriv(dev);
+
+       napi_enable(&np->napi);
+#endif
+}
+
+static void nv_napi_disable(struct net_device *dev)
+{
+#ifdef CONFIG_FORCEDETH_NAPI
+       struct fe_priv *np = get_nvpriv(dev);
+
+       napi_disable(&np->napi);
+#endif
+}
+
 #define MII_READ       (-1)
 /* mii_rw: read/write a register on the PHY.
  *
@@ -2382,14 +2402,16 @@ static inline void nv_tx_flip_ownership(struct net_device *dev)
  *
  * Caller must own np->lock.
  */
-static void nv_tx_done(struct net_device *dev)
+static int nv_tx_done(struct net_device *dev, int limit)
 {
        struct fe_priv *np = netdev_priv(dev);
        u32 flags;
+       int tx_work = 0;
        struct ring_desc* orig_get_tx = np->get_tx.orig;
 
        while ((np->get_tx.orig != np->put_tx.orig) &&
-              !((flags = le32_to_cpu(np->get_tx.orig->flaglen)) & NV_TX_VALID)) {
+              !((flags = le32_to_cpu(np->get_tx.orig->flaglen)) & NV_TX_VALID) &&
+              (tx_work < limit)) {
 
                dprintk(KERN_DEBUG "%s: nv_tx_done: flags 0x%x.\n",
                                        dev->name, flags);
@@ -2415,6 +2437,7 @@ static void nv_tx_done(struct net_device *dev)
                                }
                                dev_kfree_skb_any(np->get_tx_ctx->skb);
                                np->get_tx_ctx->skb = NULL;
+                               tx_work++;
                        }
                } else {
                        if (flags & NV_TX2_LASTPACKET) {
@@ -2432,6 +2455,7 @@ static void nv_tx_done(struct net_device *dev)
                                }
                                dev_kfree_skb_any(np->get_tx_ctx->skb);
                                np->get_tx_ctx->skb = NULL;
+                               tx_work++;
                        }
                }
                if (unlikely(np->get_tx.orig++ == np->last_tx.orig))
@@ -2443,17 +2467,19 @@ static void nv_tx_done(struct net_device *dev)
                np->tx_stop = 0;
                netif_wake_queue(dev);
        }
+       return tx_work;
 }
 
-static void nv_tx_done_optimized(struct net_device *dev, int limit)
+static int nv_tx_done_optimized(struct net_device *dev, int limit)
 {
        struct fe_priv *np = netdev_priv(dev);
        u32 flags;
+       int tx_work = 0;
        struct ring_desc_ex* orig_get_tx = np->get_tx.ex;
 
        while ((np->get_tx.ex != np->put_tx.ex) &&
               !((flags = le32_to_cpu(np->get_tx.ex->flaglen)) & NV_TX_VALID) &&
-              (limit-- > 0)) {
+              (tx_work < limit)) {
 
                dprintk(KERN_DEBUG "%s: nv_tx_done_optimized: flags 0x%x.\n",
                                        dev->name, flags);
@@ -2477,6 +2503,7 @@ static void nv_tx_done_optimized(struct net_device *dev, int limit)
 
                        dev_kfree_skb_any(np->get_tx_ctx->skb);
                        np->get_tx_ctx->skb = NULL;
+                       tx_work++;
 
                        if (np->tx_limit) {
                                nv_tx_flip_ownership(dev);
@@ -2491,6 +2518,7 @@ static void nv_tx_done_optimized(struct net_device *dev, int limit)
                np->tx_stop = 0;
                netif_wake_queue(dev);
        }
+       return tx_work;
 }
 
 /*
@@ -2563,7 +2591,7 @@ static void nv_tx_timeout(struct net_device *dev)
 
        /* 2) check that the packets were not sent already: */
        if (!nv_optimized(np))
-               nv_tx_done(dev);
+               nv_tx_done(dev, np->tx_ring_size);
        else
                nv_tx_done_optimized(dev, np->tx_ring_size);
 
@@ -2924,6 +2952,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu)
                 * Changing the MTU is a rare event, it shouldn't matter.
                 */
                nv_disable_irq(dev);
+               nv_napi_disable(dev);
                netif_tx_lock_bh(dev);
                netif_addr_lock(dev);
                spin_lock(&np->lock);
@@ -2952,6 +2981,7 @@ static int nv_change_mtu(struct net_device *dev, int new_mtu)
                spin_unlock(&np->lock);
                netif_addr_unlock(dev);
                netif_tx_unlock_bh(dev);
+               nv_napi_enable(dev);
                nv_enable_irq(dev);
        }
        return 0;
@@ -3392,50 +3422,71 @@ static void nv_msi_workaround(struct fe_priv *np)
        }
 }
 
+static inline int nv_change_interrupt_mode(struct net_device *dev, int total_work)
+{
+       struct fe_priv *np = netdev_priv(dev);
+
+       if (optimization_mode == NV_OPTIMIZATION_MODE_DYNAMIC) {
+               if (total_work > NV_DYNAMIC_THRESHOLD) {
+                       /* transition to poll based interrupts */
+                       np->quiet_count = 0;
+                       if (np->irqmask != NVREG_IRQMASK_CPU) {
+                               np->irqmask = NVREG_IRQMASK_CPU;
+                               return 1;
+                       }
+               } else {
+                       if (np->quiet_count < NV_DYNAMIC_MAX_QUIET_COUNT) {
+                               np->quiet_count++;
+                       } else {
+                               /* reached a period of low activity, switch
+                                  to per tx/rx packet interrupts */
+                               if (np->irqmask != NVREG_IRQMASK_THROUGHPUT) {
+                                       np->irqmask = NVREG_IRQMASK_THROUGHPUT;
+                                       return 1;
+                               }
+                       }
+               }
+       }
+       return 0;
+}
+
 static irqreturn_t nv_nic_irq(int foo, void *data)
 {
        struct net_device *dev = (struct net_device *) data;
        struct fe_priv *np = netdev_priv(dev);
        u8 __iomem *base = get_hwbase(dev);
-       u32 events;
-       int i;
+#ifndef CONFIG_FORCEDETH_NAPI
+       int total_work = 0;
+       int loop_count = 0;
+#endif
 
        dprintk(KERN_DEBUG "%s: nv_nic_irq\n", dev->name);
 
-       for (i=0; ; i++) {
-               if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
-                       events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
-                       writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
-               } else {
-                       events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
-                       writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
-               }
-               dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
-               if (!(events & np->irqmask))
-                       break;
-
-               nv_msi_workaround(np);
+       if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
+               np->events = readl(base + NvRegIrqStatus);
+               writel(np->events, base + NvRegIrqStatus);
+       } else {
+               np->events = readl(base + NvRegMSIXIrqStatus);
+               writel(np->events, base + NvRegMSIXIrqStatus);
+       }
+       dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events);
+       if (!(np->events & np->irqmask))
+               return IRQ_NONE;
 
-               spin_lock(&np->lock);
-               nv_tx_done(dev);
-               spin_unlock(&np->lock);
+       nv_msi_workaround(np);
 
 #ifdef CONFIG_FORCEDETH_NAPI
-               if (events & NVREG_IRQ_RX_ALL) {
-                       spin_lock(&np->lock);
-                       napi_schedule(&np->napi);
+       napi_schedule(&np->napi);
 
-                       /* Disable furthur receive irq's */
-                       np->irqmask &= ~NVREG_IRQ_RX_ALL;
+       /* Disable furthur irq's
+          (msix not enabled with napi) */
+       writel(0, base + NvRegIrqMask);
 
-                       if (np->msi_flags & NV_MSI_X_ENABLED)
-                               writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
-                       else
-                               writel(np->irqmask, base + NvRegIrqMask);
-                       spin_unlock(&np->lock);
-               }
 #else
-               if (nv_rx_process(dev, RX_WORK_PER_LOOP)) {
+       do
+       {
+               int work = 0;
+               if ((work = nv_rx_process(dev, RX_WORK_PER_LOOP))) {
                        if (unlikely(nv_alloc_rx(dev))) {
                                spin_lock(&np->lock);
                                if (!np->in_shutdown)
@@ -3443,65 +3494,56 @@ static irqreturn_t nv_nic_irq(int foo, void *data)
                                spin_unlock(&np->lock);
                        }
                }
-#endif
-               if (unlikely(events & NVREG_IRQ_LINK)) {
-                       spin_lock(&np->lock);
-                       nv_link_irq(dev);
-                       spin_unlock(&np->lock);
-               }
-               if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
-                       spin_lock(&np->lock);
-                       nv_linkchange(dev);
-                       spin_unlock(&np->lock);
-                       np->link_timeout = jiffies + LINK_TIMEOUT;
-               }
-               if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
-                       dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
-                                               dev->name, events);
-               }
-               if (unlikely(events & (NVREG_IRQ_UNKNOWN))) {
-                       printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
-                                               dev->name, events);
-               }
-               if (unlikely(events & NVREG_IRQ_RECOVER_ERROR)) {
-                       spin_lock(&np->lock);
-                       /* disable interrupts on the nic */
-                       if (!(np->msi_flags & NV_MSI_X_ENABLED))
-                               writel(0, base + NvRegIrqMask);
-                       else
-                               writel(np->irqmask, base + NvRegIrqMask);
-                       pci_push(base);
 
-                       if (!np->in_shutdown) {
-                               np->nic_poll_irq = np->irqmask;
-                               np->recover_error = 1;
-                               mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
-                       }
-                       spin_unlock(&np->lock);
-                       break;
-               }
-               if (unlikely(i > max_interrupt_work)) {
-                       spin_lock(&np->lock);
-                       /* disable interrupts on the nic */
-                       if (!(np->msi_flags & NV_MSI_X_ENABLED))
-                               writel(0, base + NvRegIrqMask);
-                       else
-                               writel(np->irqmask, base + NvRegIrqMask);
-                       pci_push(base);
+               spin_lock(&np->lock);
+               work += nv_tx_done(dev, TX_WORK_PER_LOOP);
+               spin_unlock(&np->lock);
 
-                       if (!np->in_shutdown) {
-                               np->nic_poll_irq = np->irqmask;
-                               mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
-                       }
-                       spin_unlock(&np->lock);
-                       printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
+               if (!work)
                        break;
-               }
 
+               total_work += work;
+
+               loop_count++;
+       }
+       while (loop_count < max_interrupt_work);
+
+       if (nv_change_interrupt_mode(dev, total_work)) {
+               /* setup new irq mask */
+               writel(np->irqmask, base + NvRegIrqMask);
+       }
+
+       if (unlikely(np->events & NVREG_IRQ_LINK)) {
+               spin_lock(&np->lock);
+               nv_link_irq(dev);
+               spin_unlock(&np->lock);
+       }
+       if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
+               spin_lock(&np->lock);
+               nv_linkchange(dev);
+               spin_unlock(&np->lock);
+               np->link_timeout = jiffies + LINK_TIMEOUT;
+       }
+       if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) {
+               spin_lock(&np->lock);
+               /* disable interrupts on the nic */
+               if (!(np->msi_flags & NV_MSI_X_ENABLED))
+                       writel(0, base + NvRegIrqMask);
+               else
+                       writel(np->irqmask, base + NvRegIrqMask);
+               pci_push(base);
+
+               if (!np->in_shutdown) {
+                       np->nic_poll_irq = np->irqmask;
+                       np->recover_error = 1;
+                       mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+               }
+               spin_unlock(&np->lock);
        }
+#endif
        dprintk(KERN_DEBUG "%s: nv_nic_irq completed\n", dev->name);
 
-       return IRQ_RETVAL(i);
+       return IRQ_HANDLED;
 }
 
 /**
@@ -3514,45 +3556,38 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
        struct net_device *dev = (struct net_device *) data;
        struct fe_priv *np = netdev_priv(dev);
        u8 __iomem *base = get_hwbase(dev);
-       u32 events;
-       int i;
+#ifndef CONFIG_FORCEDETH_NAPI
+       int total_work = 0;
+       int loop_count = 0;
+#endif
 
        dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized\n", dev->name);
 
-       for (i=0; ; i++) {
-               if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
-                       events = readl(base + NvRegIrqStatus) & NVREG_IRQSTAT_MASK;
-                       writel(NVREG_IRQSTAT_MASK, base + NvRegIrqStatus);
-               } else {
-                       events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQSTAT_MASK;
-                       writel(NVREG_IRQSTAT_MASK, base + NvRegMSIXIrqStatus);
-               }
-               dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, events);
-               if (!(events & np->irqmask))
-                       break;
-
-               nv_msi_workaround(np);
+       if (!(np->msi_flags & NV_MSI_X_ENABLED)) {
+               np->events = readl(base + NvRegIrqStatus);
+               writel(np->events, base + NvRegIrqStatus);
+       } else {
+               np->events = readl(base + NvRegMSIXIrqStatus);
+               writel(np->events, base + NvRegMSIXIrqStatus);
+       }
+       dprintk(KERN_DEBUG "%s: irq: %08x\n", dev->name, np->events);
+       if (!(np->events & np->irqmask))
+               return IRQ_NONE;
 
-               spin_lock(&np->lock);
-               nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
-               spin_unlock(&np->lock);
+       nv_msi_workaround(np);
 
 #ifdef CONFIG_FORCEDETH_NAPI
-               if (events & NVREG_IRQ_RX_ALL) {
-                       spin_lock(&np->lock);
-                       napi_schedule(&np->napi);
+       napi_schedule(&np->napi);
 
-                       /* Disable furthur receive irq's */
-                       np->irqmask &= ~NVREG_IRQ_RX_ALL;
+       /* Disable furthur irq's
+          (msix not enabled with napi) */
+       writel(0, base + NvRegIrqMask);
 
-                       if (np->msi_flags & NV_MSI_X_ENABLED)
-                               writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
-                       else
-                               writel(np->irqmask, base + NvRegIrqMask);
-                       spin_unlock(&np->lock);
-               }
 #else
-               if (nv_rx_process_optimized(dev, RX_WORK_PER_LOOP)) {
+       do
+       {
+               int work = 0;
+               if ((work = nv_rx_process_optimized(dev, RX_WORK_PER_LOOP))) {
                        if (unlikely(nv_alloc_rx_optimized(dev))) {
                                spin_lock(&np->lock);
                                if (!np->in_shutdown)
@@ -3560,66 +3595,57 @@ static irqreturn_t nv_nic_irq_optimized(int foo, void *data)
                                spin_unlock(&np->lock);
                        }
                }
-#endif
-               if (unlikely(events & NVREG_IRQ_LINK)) {
-                       spin_lock(&np->lock);
-                       nv_link_irq(dev);
-                       spin_unlock(&np->lock);
-               }
-               if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
-                       spin_lock(&np->lock);
-                       nv_linkchange(dev);
-                       spin_unlock(&np->lock);
-                       np->link_timeout = jiffies + LINK_TIMEOUT;
-               }
-               if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
-                       dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
-                                               dev->name, events);
-               }
-               if (unlikely(events & (NVREG_IRQ_UNKNOWN))) {
-                       printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
-                                               dev->name, events);
-               }
-               if (unlikely(events & NVREG_IRQ_RECOVER_ERROR)) {
-                       spin_lock(&np->lock);
-                       /* disable interrupts on the nic */
-                       if (!(np->msi_flags & NV_MSI_X_ENABLED))
-                               writel(0, base + NvRegIrqMask);
-                       else
-                               writel(np->irqmask, base + NvRegIrqMask);
-                       pci_push(base);
 
-                       if (!np->in_shutdown) {
-                               np->nic_poll_irq = np->irqmask;
-                               np->recover_error = 1;
-                               mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
-                       }
-                       spin_unlock(&np->lock);
+               spin_lock(&np->lock);
+               work += nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
+               spin_unlock(&np->lock);
+
+               if (!work)
                        break;
-               }
 
-               if (unlikely(i > max_interrupt_work)) {
-                       spin_lock(&np->lock);
-                       /* disable interrupts on the nic */
-                       if (!(np->msi_flags & NV_MSI_X_ENABLED))
-                               writel(0, base + NvRegIrqMask);
-                       else
-                               writel(np->irqmask, base + NvRegIrqMask);
-                       pci_push(base);
+               total_work += work;
 
-                       if (!np->in_shutdown) {
-                               np->nic_poll_irq = np->irqmask;
-                               mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
-                       }
-                       spin_unlock(&np->lock);
-                       printk(KERN_DEBUG "%s: too many iterations (%d) in nv_nic_irq.\n", dev->name, i);
-                       break;
-               }
+               loop_count++;
+       }
+       while (loop_count < max_interrupt_work);
+
+       if (nv_change_interrupt_mode(dev, total_work)) {
+               /* setup new irq mask */
+               writel(np->irqmask, base + NvRegIrqMask);
+       }
+
+       if (unlikely(np->events & NVREG_IRQ_LINK)) {
+               spin_lock(&np->lock);
+               nv_link_irq(dev);
+               spin_unlock(&np->lock);
+       }
+       if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
+               spin_lock(&np->lock);
+               nv_linkchange(dev);
+               spin_unlock(&np->lock);
+               np->link_timeout = jiffies + LINK_TIMEOUT;
+       }
+       if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) {
+               spin_lock(&np->lock);
+               /* disable interrupts on the nic */
+               if (!(np->msi_flags & NV_MSI_X_ENABLED))
+                       writel(0, base + NvRegIrqMask);
+               else
+                       writel(np->irqmask, base + NvRegIrqMask);
+               pci_push(base);
 
+               if (!np->in_shutdown) {
+                       np->nic_poll_irq = np->irqmask;
+                       np->recover_error = 1;
+                       mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+               }
+               spin_unlock(&np->lock);
        }
+
+#endif
        dprintk(KERN_DEBUG "%s: nv_nic_irq_optimized completed\n", dev->name);
 
-       return IRQ_RETVAL(i);
+       return IRQ_HANDLED;
 }
 
 static irqreturn_t nv_nic_irq_tx(int foo, void *data)
@@ -3644,10 +3670,6 @@ static irqreturn_t nv_nic_irq_tx(int foo, void *data)
                nv_tx_done_optimized(dev, TX_WORK_PER_LOOP);
                spin_unlock_irqrestore(&np->lock, flags);
 
-               if (unlikely(events & (NVREG_IRQ_TX_ERR))) {
-                       dprintk(KERN_DEBUG "%s: received irq with events 0x%x. Probably TX fail.\n",
-                                               dev->name, events);
-               }
                if (unlikely(i > max_interrupt_work)) {
                        spin_lock_irqsave(&np->lock, flags);
                        /* disable interrupts on the nic */
@@ -3676,13 +3698,22 @@ static int nv_napi_poll(struct napi_struct *napi, int budget)
        struct net_device *dev = np->dev;
        u8 __iomem *base = get_hwbase(dev);
        unsigned long flags;
-       int pkts, retcode;
+       int retcode;
+       int tx_work, rx_work;
 
        if (!nv_optimized(np)) {
-               pkts = nv_rx_process(dev, budget);
+               spin_lock_irqsave(&np->lock, flags);
+               tx_work = nv_tx_done(dev, np->tx_ring_size);
+               spin_unlock_irqrestore(&np->lock, flags);
+
+               rx_work = nv_rx_process(dev, budget);
                retcode = nv_alloc_rx(dev);
        } else {
-               pkts = nv_rx_process_optimized(dev, budget);
+               spin_lock_irqsave(&np->lock, flags);
+               tx_work = nv_tx_done_optimized(dev, np->tx_ring_size);
+               spin_unlock_irqrestore(&np->lock, flags);
+
+               rx_work = nv_rx_process_optimized(dev, budget);
                retcode = nv_alloc_rx_optimized(dev);
        }
 
@@ -3693,44 +3724,42 @@ static int nv_napi_poll(struct napi_struct *napi, int budget)
                spin_unlock_irqrestore(&np->lock, flags);
        }
 
-       if (pkts < budget) {
-               /* re-enable receive interrupts */
-               spin_lock_irqsave(&np->lock, flags);
+       nv_change_interrupt_mode(dev, tx_work + rx_work);
 
+       if (unlikely(np->events & NVREG_IRQ_LINK)) {
+               spin_lock_irqsave(&np->lock, flags);
+               nv_link_irq(dev);
+               spin_unlock_irqrestore(&np->lock, flags);
+       }
+       if (unlikely(np->need_linktimer && time_after(jiffies, np->link_timeout))) {
+               spin_lock_irqsave(&np->lock, flags);
+               nv_linkchange(dev);
+               spin_unlock_irqrestore(&np->lock, flags);
+               np->link_timeout = jiffies + LINK_TIMEOUT;
+       }
+       if (unlikely(np->events & NVREG_IRQ_RECOVER_ERROR)) {
+               spin_lock_irqsave(&np->lock, flags);
+               if (!np->in_shutdown) {
+                       np->nic_poll_irq = np->irqmask;
+                       np->recover_error = 1;
+                       mod_timer(&np->nic_poll, jiffies + POLL_WAIT);
+               }
+               spin_unlock_irqrestore(&np->lock, flags);
                __napi_complete(napi);
+               return rx_work;
+       }
 
-               np->irqmask |= NVREG_IRQ_RX_ALL;
-               if (np->msi_flags & NV_MSI_X_ENABLED)
-                       writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
-               else
-                       writel(np->irqmask, base + NvRegIrqMask);
+       if (rx_work < budget) {
+               /* re-enable interrupts
+                  (msix not enabled in napi) */
+               __napi_complete(napi);
 
-               spin_unlock_irqrestore(&np->lock, flags);
+               writel(np->irqmask, base + NvRegIrqMask);
        }
-       return pkts;
+       return rx_work;
 }
 #endif
 
-#ifdef CONFIG_FORCEDETH_NAPI
-static irqreturn_t nv_nic_irq_rx(int foo, void *data)
-{
-       struct net_device *dev = (struct net_device *) data;
-       struct fe_priv *np = netdev_priv(dev);
-       u8 __iomem *base = get_hwbase(dev);
-       u32 events;
-
-       events = readl(base + NvRegMSIXIrqStatus) & NVREG_IRQ_RX_ALL;
-
-       if (events) {
-               /* disable receive interrupts on the nic */
-               writel(NVREG_IRQ_RX_ALL, base + NvRegIrqMask);
-               pci_push(base);
-               writel(NVREG_IRQ_RX_ALL, base + NvRegMSIXIrqStatus);
-               napi_schedule(&np->napi);
-       }
-       return IRQ_HANDLED;
-}
-#else
 static irqreturn_t nv_nic_irq_rx(int foo, void *data)
 {
        struct net_device *dev = (struct net_device *) data;
@@ -3777,7 +3806,6 @@ static irqreturn_t nv_nic_irq_rx(int foo, void *data)
 
        return IRQ_RETVAL(i);
 }
-#endif
 
 static irqreturn_t nv_nic_irq_other(int foo, void *data)
 {
@@ -3827,10 +3855,6 @@ static irqreturn_t nv_nic_irq_other(int foo, void *data)
                        spin_unlock_irq(&np->lock);
                        break;
                }
-               if (events & (NVREG_IRQ_UNKNOWN)) {
-                       printk(KERN_DEBUG "%s: received irq with unknown events 0x%x. Please report\n",
-                                               dev->name, events);
-               }
                if (unlikely(i > max_interrupt_work)) {
                        spin_lock_irqsave(&np->lock, flags);
                        /* disable interrupts on the nic */
@@ -4592,6 +4616,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
 
        if (netif_running(dev)) {
                nv_disable_irq(dev);
+               nv_napi_disable(dev);
                netif_tx_lock_bh(dev);
                netif_addr_lock(dev);
                spin_lock(&np->lock);
@@ -4644,6 +4669,7 @@ static int nv_set_ringparam(struct net_device *dev, struct ethtool_ringparam* ri
                spin_unlock(&np->lock);
                netif_addr_unlock(dev);
                netif_tx_unlock_bh(dev);
+               nv_napi_enable(dev);
                nv_enable_irq(dev);
        }
        return 0;
@@ -4796,12 +4822,12 @@ static int nv_get_sset_count(struct net_device *dev, int sset)
                else
                        return NV_TEST_COUNT_BASE;
        case ETH_SS_STATS:
-               if (np->driver_data & DEV_HAS_STATISTICS_V1)
-                       return NV_DEV_STATISTICS_V1_COUNT;
+               if (np->driver_data & DEV_HAS_STATISTICS_V3)
+                       return NV_DEV_STATISTICS_V3_COUNT;
                else if (np->driver_data & DEV_HAS_STATISTICS_V2)
                        return NV_DEV_STATISTICS_V2_COUNT;
-               else if (np->driver_data & DEV_HAS_STATISTICS_V3)
-                       return NV_DEV_STATISTICS_V3_COUNT;
+               else if (np->driver_data & DEV_HAS_STATISTICS_V1)
+                       return NV_DEV_STATISTICS_V1_COUNT;
                else
                        return 0;
        default:
@@ -5070,9 +5096,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
        if (test->flags & ETH_TEST_FL_OFFLINE) {
                if (netif_running(dev)) {
                        netif_stop_queue(dev);
-#ifdef CONFIG_FORCEDETH_NAPI
-                       napi_disable(&np->napi);
-#endif
+                       nv_napi_disable(dev);
                        netif_tx_lock_bh(dev);
                        netif_addr_lock(dev);
                        spin_lock_irq(&np->lock);
@@ -5130,9 +5154,7 @@ static void nv_self_test(struct net_device *dev, struct ethtool_test *test, u64
                        /* restart rx engine */
                        nv_start_rxtx(dev);
                        netif_start_queue(dev);
-#ifdef CONFIG_FORCEDETH_NAPI
-                       napi_enable(&np->napi);
-#endif
+                       nv_napi_enable(dev);
                        nv_enable_hw_interrupts(dev, np->irqmask);
                }
        }
@@ -5424,9 +5446,7 @@ static int nv_open(struct net_device *dev)
        ret = nv_update_linkspeed(dev);
        nv_start_rxtx(dev);
        netif_start_queue(dev);
-#ifdef CONFIG_FORCEDETH_NAPI
-       napi_enable(&np->napi);
-#endif
+       nv_napi_enable(dev);
 
        if (ret) {
                netif_carrier_on(dev);
@@ -5458,9 +5478,7 @@ static int nv_close(struct net_device *dev)
        spin_lock_irq(&np->lock);
        np->in_shutdown = 1;
        spin_unlock_irq(&np->lock);
-#ifdef CONFIG_FORCEDETH_NAPI
-       napi_disable(&np->napi);
-#endif
+       nv_napi_disable(dev);
        synchronize_irq(np->pci_dev->irq);
 
        del_timer_sync(&np->oom_kick);
@@ -5651,14 +5669,6 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
                dev->features |= NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_TX;
        }
 
-       np->msi_flags = 0;
-       if ((id->driver_data & DEV_HAS_MSI) && msi) {
-               np->msi_flags |= NV_MSI_CAPABLE;
-       }
-       if ((id->driver_data & DEV_HAS_MSI_X) && msix) {
-               np->msi_flags |= NV_MSI_X_CAPABLE;
-       }
-
        np->pause_flags = NV_PAUSEFRAME_RX_CAPABLE | NV_PAUSEFRAME_RX_REQ | NV_PAUSEFRAME_AUTONEG;
        if ((id->driver_data & DEV_HAS_PAUSEFRAME_TX_V1) ||
            (id->driver_data & DEV_HAS_PAUSEFRAME_TX_V2) ||
@@ -5803,14 +5813,35 @@ static int __devinit nv_probe(struct pci_dev *pci_dev, const struct pci_device_i
        } else {
                np->tx_flags = NV_TX2_VALID;
        }
-       if (optimization_mode == NV_OPTIMIZATION_MODE_THROUGHPUT) {
-               np->irqmask = NVREG_IRQMASK_THROUGHPUT;
-               if (np->msi_flags & NV_MSI_X_CAPABLE) /* set number of vectors */
-                       np->msi_flags |= 0x0003;
-       } else {
+
+       np->msi_flags = 0;
+       if ((id->driver_data & DEV_HAS_MSI) && msi) {
+               np->msi_flags |= NV_MSI_CAPABLE;
+       }
+       if ((id->driver_data & DEV_HAS_MSI_X) && msix) {
+               /* msix has had reported issues when modifying irqmask
+                  as in the case of napi, therefore, disable for now
+               */
+#ifndef CONFIG_FORCEDETH_NAPI
+               np->msi_flags |= NV_MSI_X_CAPABLE;
+#endif
+       }
+
+       if (optimization_mode == NV_OPTIMIZATION_MODE_CPU) {
                np->irqmask = NVREG_IRQMASK_CPU;
                if (np->msi_flags & NV_MSI_X_CAPABLE) /* set number of vectors */
                        np->msi_flags |= 0x0001;
+       } else if (optimization_mode == NV_OPTIMIZATION_MODE_DYNAMIC &&
+                  !(id->driver_data & DEV_NEED_TIMERIRQ)) {
+               /* start off in throughput mode */
+               np->irqmask = NVREG_IRQMASK_THROUGHPUT;
+               /* remove support for msix mode */
+               np->msi_flags &= ~NV_MSI_X_CAPABLE;
+       } else {
+               optimization_mode = NV_OPTIMIZATION_MODE_THROUGHPUT;
+               np->irqmask = NVREG_IRQMASK_THROUGHPUT;
+               if (np->msi_flags & NV_MSI_X_CAPABLE) /* set number of vectors */
+                       np->msi_flags |= 0x0003;
        }
 
        if (id->driver_data & DEV_NEED_TIMERIRQ)
@@ -6102,9 +6133,20 @@ static void nv_shutdown(struct pci_dev *pdev)
        if (netif_running(dev))
                nv_close(dev);
 
-       nv_restore_mac_addr(pdev);
+       /*
+        * Restore the MAC so a kernel started by kexec won't get confused.
+        * If we really go for poweroff, we must not restore the MAC,
+        * otherwise the MAC for WOL will be reversed at least on some boards.
+        */
+       if (system_state != SYSTEM_POWER_OFF) {
+               nv_restore_mac_addr(pdev);
+       }
 
        pci_disable_device(pdev);
+       /*
+        * Apparently it is not possible to reinitialise from D3 hot,
+        * only put the device into D3 if we really go for poweroff.
+        */
        if (system_state == SYSTEM_POWER_OFF) {
                if (pci_enable_wake(pdev, PCI_D3cold, np->wolenabled))
                        pci_enable_wake(pdev, PCI_D3hot, np->wolenabled);
@@ -6156,19 +6198,19 @@ static struct pci_device_id pci_tbl[] = {
        },
        {       /* MCP04 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_10),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT,
        },
        {       /* MCP04 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_11),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_STATISTICS_V1|DEV_NEED_TX_LIMIT,
        },
        {       /* MCP51 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_12),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
        },
        {       /* MCP51 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_13),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_STATISTICS_V1,
        },
        {       /* MCP55 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_14),
@@ -6180,83 +6222,83 @@ static struct pci_device_id pci_tbl[] = {
        },
        {       /* MCP61 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_16),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
        },
        {       /* MCP61 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_17),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
        },
        {       /* MCP61 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_18),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
        },
        {       /* MCP61 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_19),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR,
        },
        {       /* MCP65 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_20),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP65 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_21),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP65 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_22),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP65 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_23),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP67 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_24),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP67 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_25),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP67 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_26),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP67 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_27),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP73 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_28),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP73 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_29),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP73 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_30),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP73 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_31),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_HIGH_DMA|DEV_HAS_POWER_CNTRL|DEV_HAS_MSI|DEV_HAS_PAUSEFRAME_TX_V1|DEV_HAS_STATISTICS_V2|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP77 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_32),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP77 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_33),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP77 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_34),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP77 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_35),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V2|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_MGMT_UNIT|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP79 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_36),
@@ -6264,15 +6306,15 @@ static struct pci_device_id pci_tbl[] = {
        },
        {       /* MCP79 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_37),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP79 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_38),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {       /* MCP79 Ethernet Controller */
                PCI_DEVICE(PCI_VENDOR_ID_NVIDIA, PCI_DEVICE_ID_NVIDIA_NVENET_39),
-               .driver_data = DEV_NEED_TIMERIRQ|DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
+               .driver_data = DEV_NEED_LINKTIMER|DEV_HAS_LARGEDESC|DEV_HAS_CHECKSUM|DEV_HAS_HIGH_DMA|DEV_HAS_MSI|DEV_HAS_POWER_CNTRL|DEV_HAS_PAUSEFRAME_TX_V3|DEV_HAS_STATISTICS_V3|DEV_HAS_TEST_EXTENDED|DEV_HAS_CORRECT_MACADDR|DEV_HAS_COLLISION_FIX|DEV_NEED_TX_LIMIT|DEV_HAS_GEAR_MODE,
        },
        {0,},
 };
@@ -6300,7 +6342,7 @@ static void __exit exit_nic(void)
 module_param(max_interrupt_work, int, 0);
 MODULE_PARM_DESC(max_interrupt_work, "forcedeth maximum events handled per interrupt");
 module_param(optimization_mode, int, 0);
-MODULE_PARM_DESC(optimization_mode, "In throughput mode (0), every tx & rx packet will generate an interrupt. In CPU mode (1), interrupts are controlled by a timer.");
+MODULE_PARM_DESC(optimization_mode, "In throughput mode (0), every tx & rx packet will generate an interrupt. In CPU mode (1), interrupts are controlled by a timer. In dynamic mode (2), the mode toggles between throughput and CPU mode based on network load.");
 module_param(poll_interval, int, 0);
 MODULE_PARM_DESC(poll_interval, "Interval determines how frequent timer interrupt is generated by [(time_in_micro_secs * 100) / (2^10)]. Min is 0 and Max is 65535.");
 module_param(msi, int, 0);
index c434a156d7a95e03f8e3254ebca85f8627c9b8d6..b3079a5a7f2bda4929d4a68a56ac326a11b250c7 100644 (file)
@@ -129,7 +129,7 @@ int fsl_pq_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
 static int fsl_pq_mdio_reset(struct mii_bus *bus)
 {
        struct fsl_pq_mdio __iomem *regs = (void __iomem *)bus->priv;
-       unsigned int timeout = PHY_INIT_TIMEOUT;
+       int timeout = PHY_INIT_TIMEOUT;
 
        mutex_lock(&bus->mdio_lock);
 
@@ -145,7 +145,7 @@ static int fsl_pq_mdio_reset(struct mii_bus *bus)
 
        mutex_unlock(&bus->mdio_lock);
 
-       if(timeout == 0) {
+       if (timeout < 0) {
                printk(KERN_ERR "%s: The MII Bus is stuck!\n",
                                bus->name);
                return -EBUSY;
@@ -194,11 +194,15 @@ static int *create_irq_map(struct device_node *np)
 
 void fsl_pq_mdio_bus_name(char *name, struct device_node *np)
 {
-       const u32 *reg;
+       const u32 *addr;
+       u64 taddr = OF_BAD_ADDR;
 
-       reg = of_get_property(np, "reg", NULL);
+       addr = of_get_address(np, 0, NULL, NULL);
+       if (addr)
+               taddr = of_translate_address(np, addr);
 
-       snprintf(name, MII_BUS_ID_SIZE, "%s@%x", np->name, reg ? *reg : 0);
+       snprintf(name, MII_BUS_ID_SIZE, "%s@%llx", np->name,
+               (unsigned long long)taddr);
 }
 
 /* Scan the bus in reverse, looking for an empty spot */
@@ -321,6 +325,7 @@ static int fsl_pq_mdio_probe(struct of_device *ofdev,
        dev_set_drvdata(&ofdev->dev, new_bus);
 
        if (of_device_is_compatible(np, "fsl,gianfar-mdio") ||
+                       of_device_is_compatible(np, "fsl,gianfar-tbi") ||
                        of_device_is_compatible(np, "gianfar")) {
 #ifdef CONFIG_GIANFAR
                tbipa = get_gfar_tbipa(regs);
index a64a4385f5a5f992eae32be996f35f03143d18dc..8a51df045e84a3564548236028decdbdba31ea26 100644 (file)
@@ -140,11 +140,26 @@ static void gfar_halt_nodisable(struct net_device *dev);
 void gfar_start(struct net_device *dev);
 static void gfar_clear_exact_match(struct net_device *dev);
 static void gfar_set_mac_for_addr(struct net_device *dev, int num, u8 *addr);
+static int gfar_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
 
 MODULE_AUTHOR("Freescale Semiconductor, Inc");
 MODULE_DESCRIPTION("Gianfar Ethernet Driver");
 MODULE_LICENSE("GPL");
 
+static const struct net_device_ops gfar_netdev_ops = {
+       .ndo_open = gfar_enet_open,
+       .ndo_start_xmit = gfar_start_xmit,
+       .ndo_stop = gfar_close,
+       .ndo_change_mtu = gfar_change_mtu,
+       .ndo_set_multicast_list = gfar_set_multi,
+       .ndo_tx_timeout = gfar_timeout,
+       .ndo_do_ioctl = gfar_ioctl,
+       .ndo_vlan_rx_register = gfar_vlan_rx_register,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller = gfar_netpoll,
+#endif
+};
+
 /* Returns 1 if incoming frames use an FCB */
 static inline int gfar_uses_fcb(struct gfar_private *priv)
 {
@@ -350,8 +365,10 @@ static int gfar_probe(struct of_device *ofdev,
                return -ENOMEM;
 
        priv = netdev_priv(dev);
-       priv->dev = dev;
+       priv->ndev = dev;
+       priv->ofdev = ofdev;
        priv->node = ofdev->node;
+       SET_NETDEV_DEV(dev, &ofdev->dev);
 
        err = gfar_of_init(dev);
 
@@ -390,21 +407,12 @@ static int gfar_probe(struct of_device *ofdev,
        SET_NETDEV_DEV(dev, &ofdev->dev);
 
        /* Fill in the dev structure */
-       dev->open = gfar_enet_open;
-       dev->hard_start_xmit = gfar_start_xmit;
-       dev->tx_timeout = gfar_timeout;
        dev->watchdog_timeo = TX_TIMEOUT;
        netif_napi_add(dev, &priv->napi, gfar_poll, GFAR_DEV_WEIGHT);
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       dev->poll_controller = gfar_netpoll;
-#endif
-       dev->stop = gfar_close;
-       dev->change_mtu = gfar_change_mtu;
        dev->mtu = 1500;
-       dev->set_multicast_list = gfar_set_multi;
 
+       dev->netdev_ops = &gfar_netdev_ops;
        dev->ethtool_ops = &gfar_ethtool_ops;
-       dev->do_ioctl = gfar_ioctl;
 
        if (priv->device_flags & FSL_GIANFAR_DEV_HAS_CSUM) {
                priv->rx_csum_enable = 1;
@@ -414,11 +422,8 @@ static int gfar_probe(struct of_device *ofdev,
 
        priv->vlgrp = NULL;
 
-       if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN) {
-               dev->vlan_rx_register = gfar_vlan_rx_register;
-
+       if (priv->device_flags & FSL_GIANFAR_DEV_HAS_VLAN)
                dev->features |= NETIF_F_HW_VLAN_TX | NETIF_F_HW_VLAN_RX;
-       }
 
        if (priv->device_flags & FSL_GIANFAR_DEV_HAS_EXTENDED_HASH) {
                priv->extended_hash = 1;
@@ -535,7 +540,7 @@ static int gfar_remove(struct of_device *ofdev)
        dev_set_drvdata(&ofdev->dev, NULL);
 
        iounmap(priv->regs);
-       free_netdev(priv->dev);
+       free_netdev(priv->ndev);
 
        return 0;
 }
@@ -544,7 +549,7 @@ static int gfar_remove(struct of_device *ofdev)
 static int gfar_suspend(struct of_device *ofdev, pm_message_t state)
 {
        struct gfar_private *priv = dev_get_drvdata(&ofdev->dev);
-       struct net_device *dev = priv->dev;
+       struct net_device *dev = priv->ndev;
        unsigned long flags;
        u32 tempval;
 
@@ -593,7 +598,7 @@ static int gfar_suspend(struct of_device *ofdev, pm_message_t state)
 static int gfar_resume(struct of_device *ofdev)
 {
        struct gfar_private *priv = dev_get_drvdata(&ofdev->dev);
-       struct net_device *dev = priv->dev;
+       struct net_device *dev = priv->ndev;
        unsigned long flags;
        u32 tempval;
        int magic_packet = priv->wol_en &&
@@ -867,7 +872,7 @@ void stop_gfar(struct net_device *dev)
 
        free_skb_resources(priv);
 
-       dma_free_coherent(&dev->dev,
+       dma_free_coherent(&priv->ofdev->dev,
                        sizeof(struct txbd8)*priv->tx_ring_size
                        + sizeof(struct rxbd8)*priv->rx_ring_size,
                        priv->tx_bd_base,
@@ -889,12 +894,12 @@ static void free_skb_resources(struct gfar_private *priv)
                if (!priv->tx_skbuff[i])
                        continue;
 
-               dma_unmap_single(&priv->dev->dev, txbdp->bufPtr,
+               dma_unmap_single(&priv->ofdev->dev, txbdp->bufPtr,
                                txbdp->length, DMA_TO_DEVICE);
                txbdp->lstatus = 0;
                for (j = 0; j < skb_shinfo(priv->tx_skbuff[i])->nr_frags; j++) {
                        txbdp++;
-                       dma_unmap_page(&priv->dev->dev, txbdp->bufPtr,
+                       dma_unmap_page(&priv->ofdev->dev, txbdp->bufPtr,
                                        txbdp->length, DMA_TO_DEVICE);
                }
                txbdp++;
@@ -911,7 +916,7 @@ static void free_skb_resources(struct gfar_private *priv)
        if(priv->rx_skbuff != NULL) {
                for (i = 0; i < priv->rx_ring_size; i++) {
                        if (priv->rx_skbuff[i]) {
-                               dma_unmap_single(&priv->dev->dev, rxbdp->bufPtr,
+                               dma_unmap_single(&priv->ofdev->dev, rxbdp->bufPtr,
                                                priv->rx_buffer_size,
                                                DMA_FROM_DEVICE);
 
@@ -977,7 +982,7 @@ int startup_gfar(struct net_device *dev)
        gfar_write(&regs->imask, IMASK_INIT_CLEAR);
 
        /* Allocate memory for the buffer descriptors */
-       vaddr = (unsigned long) dma_alloc_coherent(&dev->dev,
+       vaddr = (unsigned long) dma_alloc_coherent(&priv->ofdev->dev,
                        sizeof (struct txbd8) * priv->tx_ring_size +
                        sizeof (struct rxbd8) * priv->rx_ring_size,
                        &addr, GFP_KERNEL);
@@ -1189,7 +1194,7 @@ err_rxalloc_fail:
 rx_skb_fail:
        free_skb_resources(priv);
 tx_skb_fail:
-       dma_free_coherent(&dev->dev,
+       dma_free_coherent(&priv->ofdev->dev,
                        sizeof(struct txbd8)*priv->tx_ring_size
                        + sizeof(struct rxbd8)*priv->rx_ring_size,
                        priv->tx_bd_base,
@@ -1312,7 +1317,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
        spin_lock_irqsave(&priv->txlock, flags);
 
        /* check if there is space to queue this packet */
-       if (nr_frags > priv->num_txbdfree) {
+       if ((nr_frags+1) > priv->num_txbdfree) {
                /* no space, stop the queue */
                netif_stop_queue(dev);
                dev->stats.tx_fifo_errors++;
@@ -1342,7 +1347,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
                        if (i == nr_frags - 1)
                                lstatus |= BD_LFLAG(TXBD_LAST | TXBD_INTERRUPT);
 
-                       bufaddr = dma_map_page(&dev->dev,
+                       bufaddr = dma_map_page(&priv->ofdev->dev,
                                        skb_shinfo(skb)->frags[i].page,
                                        skb_shinfo(skb)->frags[i].page_offset,
                                        length,
@@ -1374,7 +1379,7 @@ static int gfar_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        /* setup the TxBD length and buffer pointer for the first BD */
        priv->tx_skbuff[priv->skb_curtx] = skb;
-       txbdp_start->bufPtr = dma_map_single(&dev->dev, skb->data,
+       txbdp_start->bufPtr = dma_map_single(&priv->ofdev->dev, skb->data,
                        skb_headlen(skb), DMA_TO_DEVICE);
 
        lstatus |= BD_LFLAG(TXBD_CRC | TXBD_READY) | skb_headlen(skb);
@@ -1560,7 +1565,7 @@ static void gfar_reset_task(struct work_struct *work)
 {
        struct gfar_private *priv = container_of(work, struct gfar_private,
                        reset_task);
-       struct net_device *dev = priv->dev;
+       struct net_device *dev = priv->ndev;
 
        if (dev->flags & IFF_UP) {
                stop_gfar(dev);
@@ -1607,7 +1612,7 @@ static int gfar_clean_tx_ring(struct net_device *dev)
                                (lstatus & BD_LENGTH_MASK))
                        break;
 
-               dma_unmap_single(&dev->dev,
+               dma_unmap_single(&priv->ofdev->dev,
                                bdp->bufPtr,
                                bdp->length,
                                DMA_TO_DEVICE);
@@ -1616,7 +1621,7 @@ static int gfar_clean_tx_ring(struct net_device *dev)
                bdp = next_txbd(bdp, base, tx_ring_size);
 
                for (i = 0; i < frags; i++) {
-                       dma_unmap_page(&dev->dev,
+                       dma_unmap_page(&priv->ofdev->dev,
                                        bdp->bufPtr,
                                        bdp->length,
                                        DMA_TO_DEVICE);
@@ -1693,7 +1698,7 @@ static void gfar_new_rxbdp(struct net_device *dev, struct rxbd8 *bdp,
        struct gfar_private *priv = netdev_priv(dev);
        u32 lstatus;
 
-       bdp->bufPtr = dma_map_single(&dev->dev, skb->data,
+       bdp->bufPtr = dma_map_single(&priv->ofdev->dev, skb->data,
                        priv->rx_buffer_size, DMA_FROM_DEVICE);
 
        lstatus = BD_LFLAG(RXBD_EMPTY | RXBD_INTERRUPT);
@@ -1853,7 +1858,7 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
 
                skb = priv->rx_skbuff[priv->skb_currx];
 
-               dma_unmap_single(&priv->dev->dev, bdp->bufPtr,
+               dma_unmap_single(&priv->ofdev->dev, bdp->bufPtr,
                                priv->rx_buffer_size, DMA_FROM_DEVICE);
 
                /* We drop the frame if we failed to allocate a new buffer */
@@ -1913,7 +1918,7 @@ int gfar_clean_rx_ring(struct net_device *dev, int rx_work_limit)
 static int gfar_poll(struct napi_struct *napi, int budget)
 {
        struct gfar_private *priv = container_of(napi, struct gfar_private, napi);
-       struct net_device *dev = priv->dev;
+       struct net_device *dev = priv->ndev;
        int tx_cleaned = 0;
        int rx_cleaned = 0;
        unsigned long flags;
index 54332b0059df72d6e6dccbaf9168ca5c62715235..dd499d7cde2670c6b38fb59b4a39694c49660b1b 100644 (file)
@@ -738,7 +738,8 @@ struct gfar_private {
        spinlock_t rxlock;
 
        struct device_node *node;
-       struct net_device *dev;
+       struct net_device *ndev;
+       struct of_device *ofdev;
        struct napi_struct napi;
 
        /* skb array and index */
diff --git a/drivers/net/gianfar_mii.c b/drivers/net/gianfar_mii.c
deleted file mode 100644 (file)
index 64e4679..0000000
+++ /dev/null
@@ -1,379 +0,0 @@
-/*
- * drivers/net/gianfar_mii.c
- *
- * Gianfar Ethernet Driver -- MIIM bus implementation
- * Provides Bus interface for MIIM regs
- *
- * Author: Andy Fleming
- * Maintainer: Kumar Gala
- *
- * Copyright (c) 2002-2004 Freescale Semiconductor, Inc.
- *
- * This program is free software; you can redistribute  it and/or modify it
- * under  the terms of  the GNU General  Public License as published by the
- * Free Software Foundation;  either version 2 of the  License, or (at your
- * option) any later version.
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/string.h>
-#include <linux/errno.h>
-#include <linux/unistd.h>
-#include <linux/slab.h>
-#include <linux/interrupt.h>
-#include <linux/init.h>
-#include <linux/delay.h>
-#include <linux/netdevice.h>
-#include <linux/etherdevice.h>
-#include <linux/skbuff.h>
-#include <linux/spinlock.h>
-#include <linux/mm.h>
-#include <linux/module.h>
-#include <linux/platform_device.h>
-#include <linux/crc32.h>
-#include <linux/mii.h>
-#include <linux/phy.h>
-#include <linux/of.h>
-#include <linux/of_platform.h>
-
-#include <asm/io.h>
-#include <asm/irq.h>
-#include <asm/uaccess.h>
-
-#include "gianfar.h"
-#include "gianfar_mii.h"
-
-/*
- * Write value to the PHY at mii_id at register regnum,
- * on the bus attached to the local interface, which may be different from the
- * generic mdio bus (tied to a single interface), waiting until the write is
- * done before returning. This is helpful in programming interfaces like
- * the TBI which control interfaces like onchip SERDES and are always tied to
- * the local mdio pins, which may not be the same as system mdio bus, used for
- * controlling the external PHYs, for example.
- */
-int gfar_local_mdio_write(struct gfar_mii __iomem *regs, int mii_id,
-                         int regnum, u16 value)
-{
-       /* Set the PHY address and the register address we want to write */
-       gfar_write(&regs->miimadd, (mii_id << 8) | regnum);
-
-       /* Write out the value we want */
-       gfar_write(&regs->miimcon, value);
-
-       /* Wait for the transaction to finish */
-       while (gfar_read(&regs->miimind) & MIIMIND_BUSY)
-               cpu_relax();
-
-       return 0;
-}
-
-/*
- * Read the bus for PHY at addr mii_id, register regnum, and
- * return the value.  Clears miimcom first.  All PHY operation
- * done on the bus attached to the local interface,
- * which may be different from the generic mdio bus
- * This is helpful in programming interfaces like
- * the TBI which, inturn, control interfaces like onchip SERDES
- * and are always tied to the local mdio pins, which may not be the
- * same as system mdio bus, used for controlling the external PHYs, for eg.
- */
-int gfar_local_mdio_read(struct gfar_mii __iomem *regs, int mii_id, int regnum)
-{
-       u16 value;
-
-       /* Set the PHY address and the register address we want to read */
-       gfar_write(&regs->miimadd, (mii_id << 8) | regnum);
-
-       /* Clear miimcom, and then initiate a read */
-       gfar_write(&regs->miimcom, 0);
-       gfar_write(&regs->miimcom, MII_READ_COMMAND);
-
-       /* Wait for the transaction to finish */
-       while (gfar_read(&regs->miimind) & (MIIMIND_NOTVALID | MIIMIND_BUSY))
-               cpu_relax();
-
-       /* Grab the value of the register from miimstat */
-       value = gfar_read(&regs->miimstat);
-
-       return value;
-}
-
-/* Write value to the PHY at mii_id at register regnum,
- * on the bus, waiting until the write is done before returning.
- * All PHY configuration is done through the TSEC1 MIIM regs */
-int gfar_mdio_write(struct mii_bus *bus, int mii_id, int regnum, u16 value)
-{
-       struct gfar_mii __iomem *regs = (void __force __iomem *)bus->priv;
-
-       /* Write to the local MII regs */
-       return(gfar_local_mdio_write(regs, mii_id, regnum, value));
-}
-
-/* Read the bus for PHY at addr mii_id, register regnum, and
- * return the value.  Clears miimcom first.  All PHY
- * configuration has to be done through the TSEC1 MIIM regs */
-int gfar_mdio_read(struct mii_bus *bus, int mii_id, int regnum)
-{
-       struct gfar_mii __iomem *regs = (void __force __iomem *)bus->priv;
-
-       /* Read the local MII regs */
-       return(gfar_local_mdio_read(regs, mii_id, regnum));
-}
-
-/* Reset the MIIM registers, and wait for the bus to free */
-static int gfar_mdio_reset(struct mii_bus *bus)
-{
-       struct gfar_mii __iomem *regs = (void __force __iomem *)bus->priv;
-       unsigned int timeout = PHY_INIT_TIMEOUT;
-
-       mutex_lock(&bus->mdio_lock);
-
-       /* Reset the management interface */
-       gfar_write(&regs->miimcfg, MIIMCFG_RESET);
-
-       /* Setup the MII Mgmt clock speed */
-       gfar_write(&regs->miimcfg, MIIMCFG_INIT_VALUE);
-
-       /* Wait until the bus is free */
-       while ((gfar_read(&regs->miimind) & MIIMIND_BUSY) &&
-                       --timeout)
-               cpu_relax();
-
-       mutex_unlock(&bus->mdio_lock);
-
-       if(timeout == 0) {
-               printk(KERN_ERR "%s: The MII Bus is stuck!\n",
-                               bus->name);
-               return -EBUSY;
-       }
-
-       return 0;
-}
-
-/* Allocate an array which provides irq #s for each PHY on the given bus */
-static int *create_irq_map(struct device_node *np)
-{
-       int *irqs;
-       int i;
-       struct device_node *child = NULL;
-
-       irqs = kcalloc(PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
-
-       if (!irqs)
-               return NULL;
-
-       for (i = 0; i < PHY_MAX_ADDR; i++)
-               irqs[i] = PHY_POLL;
-
-       while ((child = of_get_next_child(np, child)) != NULL) {
-               int irq = irq_of_parse_and_map(child, 0);
-               const u32 *id;
-
-               if (irq == NO_IRQ)
-                       continue;
-
-               id = of_get_property(child, "reg", NULL);
-
-               if (!id)
-                       continue;
-
-               if (*id < PHY_MAX_ADDR && *id >= 0)
-                       irqs[*id] = irq;
-               else
-                       printk(KERN_WARNING "%s: "
-                                       "%d is not a valid PHY address\n",
-                                       np->full_name, *id);
-       }
-
-       return irqs;
-}
-
-
-void gfar_mdio_bus_name(char *name, struct device_node *np)
-{
-       const u32 *reg;
-
-       reg = of_get_property(np, "reg", NULL);
-
-       snprintf(name, MII_BUS_ID_SIZE, "%s@%x", np->name, reg ? *reg : 0);
-}
-
-/* Scan the bus in reverse, looking for an empty spot */
-static int gfar_mdio_find_free(struct mii_bus *new_bus)
-{
-       int i;
-
-       for (i = PHY_MAX_ADDR; i > 0; i--) {
-               u32 phy_id;
-
-               if (get_phy_id(new_bus, i, &phy_id))
-                       return -1;
-
-               if (phy_id == 0xffffffff)
-                       break;
-       }
-
-       return i;
-}
-
-static int gfar_mdio_probe(struct of_device *ofdev,
-               const struct of_device_id *match)
-{
-       struct gfar_mii __iomem *regs;
-       struct gfar __iomem *enet_regs;
-       struct mii_bus *new_bus;
-       int err = 0;
-       u64 addr, size;
-       struct device_node *np = ofdev->node;
-       struct device_node *tbi;
-       int tbiaddr = -1;
-
-       new_bus = mdiobus_alloc();
-       if (NULL == new_bus)
-               return -ENOMEM;
-
-       device_init_wakeup(&ofdev->dev, 1);
-
-       new_bus->name = "Gianfar MII Bus",
-       new_bus->read = &gfar_mdio_read,
-       new_bus->write = &gfar_mdio_write,
-       new_bus->reset = &gfar_mdio_reset,
-       gfar_mdio_bus_name(new_bus->id, np);
-
-       /* Set the PHY base address */
-       addr = of_translate_address(np, of_get_address(np, 0, &size, NULL));
-       regs = ioremap(addr, size);
-
-       if (NULL == regs) {
-               err = -ENOMEM;
-               goto err_free_bus;
-       }
-
-       new_bus->priv = (void __force *)regs;
-
-       new_bus->irq = create_irq_map(np);
-
-       if (new_bus->irq == NULL) {
-               err = -ENOMEM;
-               goto err_unmap_regs;
-       }
-
-       new_bus->parent = &ofdev->dev;
-       dev_set_drvdata(&ofdev->dev, new_bus);
-
-       /*
-        * This is mildly evil, but so is our hardware for doing this.
-        * Also, we have to cast back to struct gfar_mii because of
-        * definition weirdness done in gianfar.h.
-        */
-       enet_regs = (struct gfar __force __iomem *)
-               ((char __force *)regs - offsetof(struct gfar, gfar_mii_regs));
-
-       for_each_child_of_node(np, tbi) {
-               if (!strncmp(tbi->type, "tbi-phy", 8))
-                       break;
-       }
-
-       if (tbi) {
-               const u32 *prop = of_get_property(tbi, "reg", NULL);
-
-               if (prop)
-                       tbiaddr = *prop;
-       }
-
-       if (tbiaddr == -1) {
-               gfar_write(&enet_regs->tbipa, 0);
-
-               tbiaddr = gfar_mdio_find_free(new_bus);
-       }
-
-       /*
-        * We define TBIPA at 0 to be illegal, opting to fail for boards that
-        * have PHYs at 1-31, rather than change tbipa and rescan.
-        */
-       if (tbiaddr == 0) {
-               err = -EBUSY;
-
-               goto err_free_irqs;
-       }
-
-       gfar_write(&enet_regs->tbipa, tbiaddr);
-
-       /*
-        * The TBIPHY-only buses will find PHYs at every address,
-        * so we mask them all but the TBI
-        */
-       if (!of_device_is_compatible(np, "fsl,gianfar-mdio"))
-               new_bus->phy_mask = ~(1 << tbiaddr);
-
-       err = mdiobus_register(new_bus);
-
-       if (err != 0) {
-               printk (KERN_ERR "%s: Cannot register as MDIO bus\n",
-                               new_bus->name);
-               goto err_free_irqs;
-       }
-
-       return 0;
-
-err_free_irqs:
-       kfree(new_bus->irq);
-err_unmap_regs:
-       iounmap(regs);
-err_free_bus:
-       mdiobus_free(new_bus);
-
-       return err;
-}
-
-
-static int gfar_mdio_remove(struct of_device *ofdev)
-{
-       struct mii_bus *bus = dev_get_drvdata(&ofdev->dev);
-
-       mdiobus_unregister(bus);
-
-       dev_set_drvdata(&ofdev->dev, NULL);
-
-       iounmap((void __force __iomem *)bus->priv);
-       bus->priv = NULL;
-       kfree(bus->irq);
-       mdiobus_free(bus);
-
-       return 0;
-}
-
-static struct of_device_id gfar_mdio_match[] =
-{
-       {
-               .compatible = "fsl,gianfar-mdio",
-       },
-       {
-               .compatible = "fsl,gianfar-tbi",
-       },
-       {
-               .type = "mdio",
-               .compatible = "gianfar",
-       },
-       {},
-};
-
-static struct of_platform_driver gianfar_mdio_driver = {
-       .name = "fsl-gianfar_mdio",
-       .match_table = gfar_mdio_match,
-
-       .probe = gfar_mdio_probe,
-       .remove = gfar_mdio_remove,
-};
-
-int __init gfar_mdio_init(void)
-{
-       return of_register_platform_driver(&gianfar_mdio_driver);
-}
-
-void gfar_mdio_exit(void)
-{
-       of_unregister_platform_driver(&gianfar_mdio_driver);
-}
index 455641f8677e6be6e523b2f7b2230b34662d6d59..310ee035067c3ff54002bf322e230bcbe6540493 100644 (file)
@@ -171,7 +171,7 @@ static int tx_params[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 #include <asm/unaligned.h>
 #include <asm/cache.h>
 
-static char version[] __devinitdata =
+static const char version[] __devinitconst =
 KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "  Written by Donald Becker\n"
 KERN_INFO "   Some modifications by Eric kasten <kasten@nscl.msu.edu>\n"
 KERN_INFO "   Further modifications by Keith Underwood <keithu@parl.clemson.edu>\n";
index 44b183b58f50282dc226eb8641690dd649e72b5c..d509b371a562165bc22cfd086fae186b7130ef2b 100644 (file)
@@ -97,7 +97,7 @@ static char bpq_eth_addr[6];
 static int bpq_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
 static int bpq_device_event(struct notifier_block *, unsigned long, void *);
 
-static struct packet_type bpq_packet_type = {
+static struct packet_type bpq_packet_type __read_mostly = {
        .type   = cpu_to_be16(ETH_P_BPQ),
        .func   = bpq_rcv,
 };
index 5e070f44663504b7207e19caeb7fdd2a91621acb..0486cbe01adbc6195dcd8c4d186227f0cc4406d8 100644 (file)
@@ -467,7 +467,7 @@ init_module(void)
                        if (this_dev != 0) break; /* only autoprobe 1st one */
                        printk(KERN_NOTICE "hp-plus.c: Presently autoprobing (not recommended) for a single card.\n");
                }
-               dev = alloc_ei_netdev();
+               dev = alloc_eip_netdev();
                if (!dev)
                        break;
                dev->irq = irq[this_dev];
index 87a706694fb35f6519e4933944b06df429849d48..a815e17a0ab407a4dabd4a86af4beb47a679d853 100644 (file)
@@ -134,7 +134,7 @@ static inline void emac_report_timeout_error(struct emac_instance *dev,
                                  EMAC_FTR_440EP_PHY_CLK_FIX))
                DBG(dev, "%s" NL, error);
        else if (net_ratelimit())
-               printk(KERN_ERR "%s: %s\n", dev->ndev->name, error);
+               printk(KERN_ERR "%s: %s\n", dev->ofdev->node->full_name, error);
 }
 
 /* EMAC PHY clock workaround:
@@ -2594,6 +2594,9 @@ static int __devinit emac_init_config(struct emac_instance *dev)
                if (of_device_is_compatible(np, "ibm,emac-460ex") ||
                    of_device_is_compatible(np, "ibm,emac-460gt"))
                        dev->features |= EMAC_FTR_460EX_PHY_CLK_FIX;
+               if (of_device_is_compatible(np, "ibm,emac-405ex") ||
+                   of_device_is_compatible(np, "ibm,emac-405exr"))
+                       dev->features |= EMAC_FTR_440EP_PHY_CLK_FIX;
        } else if (of_device_is_compatible(np, "ibm,emac4")) {
                dev->features |= EMAC_FTR_EMAC4;
                if (of_device_is_compatible(np, "ibm,emac-440gx"))
index cda3ad51bafab1d8e0774d57d5a03ccb1ab35969..8372cb9a8c1acb4d8a76c63d2f7c4be4f06fd994 100644 (file)
@@ -33,5 +33,5 @@
 obj-$(CONFIG_IGB) += igb.o
 
 igb-objs := igb_main.o igb_ethtool.o e1000_82575.o \
-           e1000_mac.o e1000_nvm.o e1000_phy.o
+           e1000_mac.o e1000_nvm.o e1000_phy.o e1000_mbx.o
 
index 7f43e253c566a935f074fa5a9feebcdc93c0e563..efd9be214885cbc4c5c5282df7072aee901beff9 100644 (file)
@@ -80,8 +80,10 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
                mac->type = e1000_82575;
                break;
        case E1000_DEV_ID_82576:
+       case E1000_DEV_ID_82576_NS:
        case E1000_DEV_ID_82576_FIBER:
        case E1000_DEV_ID_82576_SERDES:
+       case E1000_DEV_ID_82576_QUAD_COPPER:
                mac->type = e1000_82576;
                break;
        default:
@@ -213,6 +215,10 @@ static s32 igb_get_invariants_82575(struct e1000_hw *hw)
                return -E1000_ERR_PHY;
        }
 
+       /* if 82576 then initialize mailbox parameters */
+       if (mac->type == e1000_82576)
+               igb_init_mbx_params_pf(hw);
+
        return 0;
 }
 
@@ -1413,6 +1419,44 @@ void igb_rx_fifo_flush_82575(struct e1000_hw *hw)
        rd32(E1000_MPC);
 }
 
+/**
+ *  igb_vmdq_set_loopback_pf - enable or disable vmdq loopback
+ *  @hw: pointer to the hardware struct
+ *  @enable: state to enter, either enabled or disabled
+ *
+ *  enables/disables L2 switch loopback functionality.
+ **/
+void igb_vmdq_set_loopback_pf(struct e1000_hw *hw, bool enable)
+{
+       u32 dtxswc = rd32(E1000_DTXSWC);
+
+       if (enable)
+               dtxswc |= E1000_DTXSWC_VMDQ_LOOPBACK_EN;
+       else
+               dtxswc &= ~E1000_DTXSWC_VMDQ_LOOPBACK_EN;
+
+       wr32(E1000_DTXSWC, dtxswc);
+}
+
+/**
+ *  igb_vmdq_set_replication_pf - enable or disable vmdq replication
+ *  @hw: pointer to the hardware struct
+ *  @enable: state to enter, either enabled or disabled
+ *
+ *  enables/disables replication of packets across multiple pools.
+ **/
+void igb_vmdq_set_replication_pf(struct e1000_hw *hw, bool enable)
+{
+       u32 vt_ctl = rd32(E1000_VT_CTL);
+
+       if (enable)
+               vt_ctl |= E1000_VT_CTL_VM_REPL_EN;
+       else
+               vt_ctl &= ~E1000_VT_CTL_VM_REPL_EN;
+
+       wr32(E1000_VT_CTL, vt_ctl);
+}
+
 static struct e1000_mac_operations e1000_mac_ops_82575 = {
        .reset_hw             = igb_reset_hw_82575,
        .init_hw              = igb_init_hw_82575,
index 49b41c92a8c8ecbece09f5ce7d846c609900cf7d..eaf9770503685126dc4b9b74f3d948aa61443019 100644 (file)
@@ -40,8 +40,11 @@ extern void igb_rx_fifo_flush_82575(struct e1000_hw *hw);
 #define E1000_SRRCTL_BSIZEHDRSIZE_SHIFT                 2  /* Shift _left_ */
 #define E1000_SRRCTL_DESCTYPE_ADV_ONEBUF                0x02000000
 #define E1000_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS          0x0A000000
+#define E1000_SRRCTL_DROP_EN                            0x80000000
 
 #define E1000_MRQC_ENABLE_RSS_4Q            0x00000002
+#define E1000_MRQC_ENABLE_VMDQ              0x00000003
+#define E1000_MRQC_ENABLE_VMDQ_RSS_2Q       0x00000005
 #define E1000_MRQC_RSS_FIELD_IPV4_UDP       0x00400000
 #define E1000_MRQC_RSS_FIELD_IPV6_UDP       0x00800000
 #define E1000_MRQC_RSS_FIELD_IPV6_UDP_EX    0x01000000
@@ -159,4 +162,44 @@ struct e1000_adv_tx_context_desc {
 #define E1000_DCA_TXCTRL_CPUID_SHIFT 24 /* Tx CPUID now in the last byte */
 #define E1000_DCA_RXCTRL_CPUID_SHIFT 24 /* Rx CPUID now in the last byte */
 
+#define MAX_NUM_VFS                   8
+
+#define E1000_DTXSWC_VMDQ_LOOPBACK_EN (1 << 31)  /* global VF LB enable */
+
+/* Easy defines for setting default pool, would normally be left a zero */
+#define E1000_VT_CTL_DEFAULT_POOL_SHIFT 7
+#define E1000_VT_CTL_DEFAULT_POOL_MASK  (0x7 << E1000_VT_CTL_DEFAULT_POOL_SHIFT)
+
+/* Other useful VMD_CTL register defines */
+#define E1000_VT_CTL_IGNORE_MAC         (1 << 28)
+#define E1000_VT_CTL_DISABLE_DEF_POOL   (1 << 29)
+#define E1000_VT_CTL_VM_REPL_EN         (1 << 30)
+
+/* Per VM Offload register setup */
+#define E1000_VMOLR_RLPML_MASK 0x00003FFF /* Long Packet Maximum Length mask */
+#define E1000_VMOLR_LPE        0x00010000 /* Accept Long packet */
+#define E1000_VMOLR_RSSE       0x00020000 /* Enable RSS */
+#define E1000_VMOLR_AUPE       0x01000000 /* Accept untagged packets */
+#define E1000_VMOLR_ROMPE      0x02000000 /* Accept overflow multicast */
+#define E1000_VMOLR_ROPE       0x04000000 /* Accept overflow unicast */
+#define E1000_VMOLR_BAM        0x08000000 /* Accept Broadcast packets */
+#define E1000_VMOLR_MPME       0x10000000 /* Multicast promiscuous mode */
+#define E1000_VMOLR_STRVLAN    0x40000000 /* Vlan stripping enable */
+#define E1000_VMOLR_STRCRC     0x80000000 /* CRC stripping enable */
+
+#define E1000_VLVF_ARRAY_SIZE     32
+#define E1000_VLVF_VLANID_MASK    0x00000FFF
+#define E1000_VLVF_POOLSEL_SHIFT  12
+#define E1000_VLVF_POOLSEL_MASK   (0xFF << E1000_VLVF_POOLSEL_SHIFT)
+#define E1000_VLVF_LVLAN          0x00100000
+#define E1000_VLVF_VLANID_ENABLE  0x80000000
+
+#define E1000_IOVCTL 0x05BBC
+#define E1000_IOVCTL_REUSE_VFQ 0x00000001
+
+#define ALL_QUEUES   0xFFFF
+
+void igb_vmdq_set_loopback_pf(struct e1000_hw *, bool);
+void igb_vmdq_set_replication_pf(struct e1000_hw *, bool);
+
 #endif
index 5a32a7004e0a83c07afae0c489ae5f6c480bb914..ad2d319d0f8be731579a435de45618beba376b92 100644 (file)
@@ -45,6 +45,8 @@
 
 /* Extended Device Control */
 #define E1000_CTRL_EXT_SDP7_DATA 0x00000080 /* Value of SW Defineable Pin 7 */
+/* Physical Func Reset Done Indication */
+#define E1000_CTRL_EXT_PFRSTD    0x00004000
 #define E1000_CTRL_EXT_LINK_MODE_MASK 0x00C00000
 #define E1000_CTRL_EXT_LINK_MODE_PCIE_SERDES  0x00C00000
 #define E1000_CTRL_EXT_LINK_MODE_SGMII   0x00800000
 #define E1000_ICR_RXSEQ         0x00000008 /* rx sequence error */
 #define E1000_ICR_RXDMT0        0x00000010 /* rx desc min. threshold (0) */
 #define E1000_ICR_RXT0          0x00000080 /* rx timer intr (ring 0) */
+#define E1000_ICR_VMMB          0x00000100 /* VM MB event */
 /* If this bit asserted, the driver should claim the interrupt */
 #define E1000_ICR_INT_ASSERTED  0x80000000
 /* LAN connected device generates an interrupt */
 /* Interrupt Mask Set */
 #define E1000_IMS_TXDW      E1000_ICR_TXDW      /* Transmit desc written back */
 #define E1000_IMS_LSC       E1000_ICR_LSC       /* Link Status Change */
+#define E1000_IMS_VMMB      E1000_ICR_VMMB      /* Mail box activity */
 #define E1000_IMS_RXSEQ     E1000_ICR_RXSEQ     /* rx sequence error */
 #define E1000_IMS_RXDMT0    E1000_ICR_RXDMT0    /* rx desc min. threshold */
 #define E1000_IMS_RXT0      E1000_ICR_RXT0      /* rx timer intr */
 #define E1000_RAH_AV  0x80000000        /* Receive descriptor valid */
 #define E1000_RAL_MAC_ADDR_LEN 4
 #define E1000_RAH_MAC_ADDR_LEN 2
+#define E1000_RAH_POOL_MASK 0x03FC0000
+#define E1000_RAH_POOL_1 0x00040000
 
 /* Error Codes */
 #define E1000_ERR_NVM      1
 #define E1000_BLK_PHY_RESET   12
 #define E1000_ERR_SWFW_SYNC 13
 #define E1000_NOT_IMPLEMENTED 14
+#define E1000_ERR_MBX      15
 
 /* Loop limit on how long we wait for auto-negotiation to complete */
 #define COPPER_LINK_UP_LIMIT              10
 #define NVM_ID_LED_SETTINGS        0x0004
 /* For SERDES output amplitude adjustment. */
 #define NVM_INIT_CONTROL2_REG      0x000F
+#define NVM_INIT_CONTROL3_PORT_B   0x0014
 #define NVM_INIT_CONTROL3_PORT_A   0x0024
 #define NVM_ALT_MAC_ADDR_PTR       0x0037
 #define NVM_CHECKSUM_REG           0x003F
 #define E1000_GEN_CTL_ADDRESS_SHIFT     8
 #define E1000_GEN_POLL_TIMEOUT          640
 
+#define E1000_VFTA_ENTRY_SHIFT               5
+#define E1000_VFTA_ENTRY_MASK                0x7F
+#define E1000_VFTA_ENTRY_BIT_SHIFT_MASK      0x1F
+
 #endif
index 10b872d3c9f47149bdebe0809444a6babecdddf1..68aac20c31cac92164acd0f787cc312672deab64 100644 (file)
@@ -32,7 +32,6 @@
 #include <linux/delay.h>
 #include <linux/io.h>
 
-#include "e1000_mac.h"
 #include "e1000_regs.h"
 #include "e1000_defines.h"
 
@@ -41,6 +40,8 @@ struct e1000_hw;
 #define E1000_DEV_ID_82576                    0x10C9
 #define E1000_DEV_ID_82576_FIBER              0x10E6
 #define E1000_DEV_ID_82576_SERDES             0x10E7
+#define E1000_DEV_ID_82576_QUAD_COPPER        0x10E8
+#define E1000_DEV_ID_82576_NS                 0x150A
 #define E1000_DEV_ID_82575EB_COPPER           0x10A7
 #define E1000_DEV_ID_82575EB_FIBER_SERDES     0x10A9
 #define E1000_DEV_ID_82575GB_QUAD_COPPER      0x10D6
@@ -272,6 +273,7 @@ struct e1000_host_mng_command_info {
 #include "e1000_mac.h"
 #include "e1000_phy.h"
 #include "e1000_nvm.h"
+#include "e1000_mbx.h"
 
 struct e1000_mac_operations {
        s32  (*check_for_link)(struct e1000_hw *);
@@ -427,6 +429,34 @@ struct e1000_fc_info {
        enum e1000_fc_type original_type;
 };
 
+struct e1000_mbx_operations {
+       s32 (*init_params)(struct e1000_hw *hw);
+       s32 (*read)(struct e1000_hw *, u32 *, u16,  u16);
+       s32 (*write)(struct e1000_hw *, u32 *, u16, u16);
+       s32 (*read_posted)(struct e1000_hw *, u32 *, u16,  u16);
+       s32 (*write_posted)(struct e1000_hw *, u32 *, u16, u16);
+       s32 (*check_for_msg)(struct e1000_hw *, u16);
+       s32 (*check_for_ack)(struct e1000_hw *, u16);
+       s32 (*check_for_rst)(struct e1000_hw *, u16);
+};
+
+struct e1000_mbx_stats {
+       u32 msgs_tx;
+       u32 msgs_rx;
+
+       u32 acks;
+       u32 reqs;
+       u32 rsts;
+};
+
+struct e1000_mbx_info {
+       struct e1000_mbx_operations ops;
+       struct e1000_mbx_stats stats;
+       u32 timeout;
+       u32 usec_delay;
+       u16 size;
+};
+
 struct e1000_dev_spec_82575 {
        bool sgmii_active;
 };
@@ -443,6 +473,7 @@ struct e1000_hw {
        struct e1000_phy_info  phy;
        struct e1000_nvm_info  nvm;
        struct e1000_bus_info  bus;
+       struct e1000_mbx_info mbx;
        struct e1000_host_mng_dhcp_cookie mng_cookie;
 
        union {
index 5c249e2ce93bf56d3a17ee959e3932cf13811f38..f4c315b5a900f315488d3f6d84e2dc4459946029 100644 (file)
@@ -117,6 +117,37 @@ void igb_write_vfta(struct e1000_hw *hw, u32 offset, u32 value)
        wrfl();
 }
 
+/**
+ *  igb_vfta_set - enable or disable vlan in VLAN filter table
+ *  @hw: pointer to the HW structure
+ *  @vid: VLAN id to add or remove
+ *  @add: if true add filter, if false remove
+ *
+ *  Sets or clears a bit in the VLAN filter table array based on VLAN id
+ *  and if we are adding or removing the filter
+ **/
+s32 igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add)
+{
+       u32 index = (vid >> E1000_VFTA_ENTRY_SHIFT) & E1000_VFTA_ENTRY_MASK;
+       u32 mask = 1 << (vid & E1000_VFTA_ENTRY_BIT_SHIFT_MASK);
+       u32 vfta = array_rd32(E1000_VFTA, index);
+       s32 ret_val = 0;
+
+       /* bit was set/cleared before we started */
+       if ((!!(vfta & mask)) == add) {
+               ret_val = -E1000_ERR_CONFIG;
+       } else {
+               if (add)
+                       vfta |= mask;
+               else
+                       vfta &= ~mask;
+       }
+
+       igb_write_vfta(hw, index, vfta);
+
+       return ret_val;
+}
+
 /**
  *  igb_check_alt_mac_addr - Check for alternate MAC addr
  *  @hw: pointer to the HW structure
index e5200def582f4025d4fff6988d530d4adf1e4a28..a34de52696377c292ea31a4b357ea3dd71de143b 100644 (file)
@@ -58,6 +58,7 @@ s32  igb_write_8bit_ctrl_reg(struct e1000_hw *hw, u32 reg,
 
 void igb_clear_hw_cntrs_base(struct e1000_hw *hw);
 void igb_clear_vfta(struct e1000_hw *hw);
+s32  igb_vfta_set(struct e1000_hw *hw, u32 vid, bool add);
 void igb_config_collision_dist(struct e1000_hw *hw);
 void igb_mta_set(struct e1000_hw *hw, u32 hash_value);
 void igb_put_hw_semaphore(struct e1000_hw *hw);
diff --git a/drivers/net/igb/e1000_mbx.c b/drivers/net/igb/e1000_mbx.c
new file mode 100644 (file)
index 0000000..fe71c7d
--- /dev/null
@@ -0,0 +1,447 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "e1000_mbx.h"
+
+/**
+ *  igb_read_mbx - Reads a message from the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to read
+ *
+ *  returns SUCCESS if it successfuly read message from buffer
+ **/
+s32 igb_read_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+{
+       struct e1000_mbx_info *mbx = &hw->mbx;
+       s32 ret_val = -E1000_ERR_MBX;
+
+       /* limit read to size of mailbox */
+       if (size > mbx->size)
+               size = mbx->size;
+
+       if (mbx->ops.read)
+               ret_val = mbx->ops.read(hw, msg, size, mbx_id);
+
+       return ret_val;
+}
+
+/**
+ *  igb_write_mbx - Write a message to the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully copied message into the buffer
+ **/
+s32 igb_write_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+{
+       struct e1000_mbx_info *mbx = &hw->mbx;
+       s32 ret_val = 0;
+
+       if (size > mbx->size)
+               ret_val = -E1000_ERR_MBX;
+
+       else if (mbx->ops.write)
+               ret_val = mbx->ops.write(hw, msg, size, mbx_id);
+
+       return ret_val;
+}
+
+/**
+ *  igb_check_for_msg - checks to see if someone sent us mail
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns SUCCESS if the Status bit was found or else ERR_MBX
+ **/
+s32 igb_check_for_msg(struct e1000_hw *hw, u16 mbx_id)
+{
+       struct e1000_mbx_info *mbx = &hw->mbx;
+       s32 ret_val = -E1000_ERR_MBX;
+
+       if (mbx->ops.check_for_msg)
+               ret_val = mbx->ops.check_for_msg(hw, mbx_id);
+
+       return ret_val;
+}
+
+/**
+ *  igb_check_for_ack - checks to see if someone sent us ACK
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns SUCCESS if the Status bit was found or else ERR_MBX
+ **/
+s32 igb_check_for_ack(struct e1000_hw *hw, u16 mbx_id)
+{
+       struct e1000_mbx_info *mbx = &hw->mbx;
+       s32 ret_val = -E1000_ERR_MBX;
+
+       if (mbx->ops.check_for_ack)
+               ret_val = mbx->ops.check_for_ack(hw, mbx_id);
+
+       return ret_val;
+}
+
+/**
+ *  igb_check_for_rst - checks to see if other side has reset
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to check
+ *
+ *  returns SUCCESS if the Status bit was found or else ERR_MBX
+ **/
+s32 igb_check_for_rst(struct e1000_hw *hw, u16 mbx_id)
+{
+       struct e1000_mbx_info *mbx = &hw->mbx;
+       s32 ret_val = -E1000_ERR_MBX;
+
+       if (mbx->ops.check_for_rst)
+               ret_val = mbx->ops.check_for_rst(hw, mbx_id);
+
+       return ret_val;
+}
+
+/**
+ *  igb_poll_for_msg - Wait for message notification
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully received a message notification
+ **/
+static s32 igb_poll_for_msg(struct e1000_hw *hw, u16 mbx_id)
+{
+       struct e1000_mbx_info *mbx = &hw->mbx;
+       int countdown = mbx->timeout;
+
+       if (!mbx->ops.check_for_msg)
+               goto out;
+
+       while (mbx->ops.check_for_msg(hw, mbx_id)) {
+               if (!countdown)
+                       break;
+               countdown--;
+               udelay(mbx->usec_delay);
+       }
+out:
+       return countdown ? 0 : -E1000_ERR_MBX;
+}
+
+/**
+ *  igb_poll_for_ack - Wait for message acknowledgement
+ *  @hw: pointer to the HW structure
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully received a message acknowledgement
+ **/
+static s32 igb_poll_for_ack(struct e1000_hw *hw, u16 mbx_id)
+{
+       struct e1000_mbx_info *mbx = &hw->mbx;
+       int countdown = mbx->timeout;
+
+       if (!mbx->ops.check_for_ack)
+               goto out;
+
+       while (mbx->ops.check_for_ack(hw, mbx_id)) {
+               if (!countdown)
+                       break;
+               countdown--;
+               udelay(mbx->usec_delay);
+       }
+out:
+       return countdown ? 0 : -E1000_ERR_MBX;
+}
+
+/**
+ *  igb_read_posted_mbx - Wait for message notification and receive message
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully received a message notification and
+ *  copied it into the receive buffer.
+ **/
+s32 igb_read_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+{
+       struct e1000_mbx_info *mbx = &hw->mbx;
+       s32 ret_val = -E1000_ERR_MBX;
+
+       if (!mbx->ops.read)
+               goto out;
+
+       ret_val = igb_poll_for_msg(hw, mbx_id);
+
+       if (!ret_val)
+               ret_val = mbx->ops.read(hw, msg, size, mbx_id);
+out:
+       return ret_val;
+}
+
+/**
+ *  igb_write_posted_mbx - Write a message to the mailbox, wait for ack
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @mbx_id: id of mailbox to write
+ *
+ *  returns SUCCESS if it successfully copied message into the buffer and
+ *  received an ack to that message within delay * timeout period
+ **/
+s32 igb_write_posted_mbx(struct e1000_hw *hw, u32 *msg, u16 size, u16 mbx_id)
+{
+       struct e1000_mbx_info *mbx = &hw->mbx;
+       s32 ret_val = 0;
+
+       if (!mbx->ops.write)
+               goto out;
+
+       /* send msg*/
+       ret_val = mbx->ops.write(hw, msg, size, mbx_id);
+
+       /* if msg sent wait until we receive an ack */
+       if (!ret_val)
+               ret_val = igb_poll_for_ack(hw, mbx_id);
+out:
+       return ret_val;
+}
+
+/**
+ *  e1000_init_mbx_ops_generic - Initialize NVM function pointers
+ *  @hw: pointer to the HW structure
+ *
+ *  Setups up the function pointers to no-op functions
+ **/
+void e1000_init_mbx_ops_generic(struct e1000_hw *hw)
+{
+       struct e1000_mbx_info *mbx = &hw->mbx;
+       mbx->ops.read_posted = igb_read_posted_mbx;
+       mbx->ops.write_posted = igb_write_posted_mbx;
+}
+
+static s32 igb_check_for_bit_pf(struct e1000_hw *hw, u32 mask)
+{
+       u32 mbvficr = rd32(E1000_MBVFICR);
+       s32 ret_val = -E1000_ERR_MBX;
+
+       if (mbvficr & mask) {
+               ret_val = 0;
+               wr32(E1000_MBVFICR, mask);
+       }
+
+       return ret_val;
+}
+
+/**
+ *  igb_check_for_msg_pf - checks to see if the VF has sent mail
+ *  @hw: pointer to the HW structure
+ *  @vf_number: the VF index
+ *
+ *  returns SUCCESS if the VF has set the Status bit or else ERR_MBX
+ **/
+static s32 igb_check_for_msg_pf(struct e1000_hw *hw, u16 vf_number)
+{
+       s32 ret_val = -E1000_ERR_MBX;
+
+       if (!igb_check_for_bit_pf(hw, E1000_MBVFICR_VFREQ_VF1 << vf_number)) {
+               ret_val = 0;
+               hw->mbx.stats.reqs++;
+       }
+
+       return ret_val;
+}
+
+/**
+ *  igb_check_for_ack_pf - checks to see if the VF has ACKed
+ *  @hw: pointer to the HW structure
+ *  @vf_number: the VF index
+ *
+ *  returns SUCCESS if the VF has set the Status bit or else ERR_MBX
+ **/
+static s32 igb_check_for_ack_pf(struct e1000_hw *hw, u16 vf_number)
+{
+       s32 ret_val = -E1000_ERR_MBX;
+
+       if (!igb_check_for_bit_pf(hw, E1000_MBVFICR_VFACK_VF1 << vf_number)) {
+               ret_val = 0;
+               hw->mbx.stats.acks++;
+       }
+
+       return ret_val;
+}
+
+/**
+ *  igb_check_for_rst_pf - checks to see if the VF has reset
+ *  @hw: pointer to the HW structure
+ *  @vf_number: the VF index
+ *
+ *  returns SUCCESS if the VF has set the Status bit or else ERR_MBX
+ **/
+static s32 igb_check_for_rst_pf(struct e1000_hw *hw, u16 vf_number)
+{
+       u32 vflre = rd32(E1000_VFLRE);
+       s32 ret_val = -E1000_ERR_MBX;
+
+       if (vflre & (1 << vf_number)) {
+               ret_val = 0;
+               wr32(E1000_VFLRE, (1 << vf_number));
+               hw->mbx.stats.rsts++;
+       }
+
+       return ret_val;
+}
+
+/**
+ *  igb_write_mbx_pf - Places a message in the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @vf_number: the VF index
+ *
+ *  returns SUCCESS if it successfully copied message into the buffer
+ **/
+static s32 igb_write_mbx_pf(struct e1000_hw *hw, u32 *msg, u16 size,
+                              u16 vf_number)
+{
+       u32 p2v_mailbox;
+       s32 ret_val = 0;
+       u16 i;
+
+       /* Take ownership of the buffer */
+       wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_PFU);
+
+       /* Make sure we have ownership now... */
+       p2v_mailbox = rd32(E1000_P2VMAILBOX(vf_number));
+       if (!(p2v_mailbox & E1000_P2VMAILBOX_PFU)) {
+               /* failed to grab ownership */
+               ret_val = -E1000_ERR_MBX;
+               goto out_no_write;
+       }
+
+       /*
+        * flush any ack or msg which may already be in the queue
+        * as they are likely the result of an error
+        */
+       igb_check_for_ack_pf(hw, vf_number);
+       igb_check_for_msg_pf(hw, vf_number);
+
+       /* copy the caller specified message to the mailbox memory buffer */
+       for (i = 0; i < size; i++)
+               array_wr32(E1000_VMBMEM(vf_number), i, msg[i]);
+
+       /* Interrupt VF to tell it a message has been sent and release buffer*/
+       wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_STS);
+
+       /* update stats */
+       hw->mbx.stats.msgs_tx++;
+
+out_no_write:
+       return ret_val;
+
+}
+
+/**
+ *  igb_read_mbx_pf - Read a message from the mailbox
+ *  @hw: pointer to the HW structure
+ *  @msg: The message buffer
+ *  @size: Length of buffer
+ *  @vf_number: the VF index
+ *
+ *  This function copies a message from the mailbox buffer to the caller's
+ *  memory buffer.  The presumption is that the caller knows that there was
+ *  a message due to a VF request so no polling for message is needed.
+ **/
+static s32 igb_read_mbx_pf(struct e1000_hw *hw, u32 *msg, u16 size,
+                             u16 vf_number)
+{
+       u32 p2v_mailbox;
+       s32 ret_val = 0;
+       u16 i;
+
+       /* Take ownership of the buffer */
+       wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_PFU);
+
+       /* Make sure we have ownership now... */
+       p2v_mailbox = rd32(E1000_P2VMAILBOX(vf_number));
+       if (!(p2v_mailbox & E1000_P2VMAILBOX_PFU)) {
+               /* failed to grab ownership */
+               ret_val = -E1000_ERR_MBX;
+               goto out_no_read;
+       }
+
+       /* copy the message to the mailbox memory buffer */
+       for (i = 0; i < size; i++)
+               msg[i] = array_rd32(E1000_VMBMEM(vf_number), i);
+
+       /* Acknowledge the message and release buffer */
+       wr32(E1000_P2VMAILBOX(vf_number), E1000_P2VMAILBOX_ACK);
+
+       /* update stats */
+       hw->mbx.stats.msgs_rx++;
+
+       ret_val = 0;
+
+out_no_read:
+       return ret_val;
+}
+
+/**
+ *  e1000_init_mbx_params_pf - set initial values for pf mailbox
+ *  @hw: pointer to the HW structure
+ *
+ *  Initializes the hw->mbx struct to correct values for pf mailbox
+ */
+s32 igb_init_mbx_params_pf(struct e1000_hw *hw)
+{
+       struct e1000_mbx_info *mbx = &hw->mbx;
+
+       if (hw->mac.type == e1000_82576) {
+               mbx->timeout = 0;
+               mbx->usec_delay = 0;
+
+               mbx->size = E1000_VFMAILBOX_SIZE;
+
+               mbx->ops.read = igb_read_mbx_pf;
+               mbx->ops.write = igb_write_mbx_pf;
+               mbx->ops.read_posted = igb_read_posted_mbx;
+               mbx->ops.write_posted = igb_write_posted_mbx;
+               mbx->ops.check_for_msg = igb_check_for_msg_pf;
+               mbx->ops.check_for_ack = igb_check_for_ack_pf;
+               mbx->ops.check_for_rst = igb_check_for_rst_pf;
+
+               mbx->stats.msgs_tx = 0;
+               mbx->stats.msgs_rx = 0;
+               mbx->stats.reqs = 0;
+               mbx->stats.acks = 0;
+               mbx->stats.rsts = 0;
+       }
+
+       return 0;
+}
+
diff --git a/drivers/net/igb/e1000_mbx.h b/drivers/net/igb/e1000_mbx.h
new file mode 100644 (file)
index 0000000..6ec9890
--- /dev/null
@@ -0,0 +1,77 @@
+/*******************************************************************************
+
+  Intel(R) Gigabit Ethernet Linux driver
+  Copyright(c) 2007-2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _E1000_MBX_H_
+#define _E1000_MBX_H_
+
+#include "e1000_hw.h"
+
+#define E1000_P2VMAILBOX_STS   0x00000001 /* Initiate message send to VF */
+#define E1000_P2VMAILBOX_ACK   0x00000002 /* Ack message recv'd from VF */
+#define E1000_P2VMAILBOX_VFU   0x00000004 /* VF owns the mailbox buffer */
+#define E1000_P2VMAILBOX_PFU   0x00000008 /* PF owns the mailbox buffer */
+#define E1000_P2VMAILBOX_RVFU  0x00000010 /* Reset VFU - used when VF stuck */
+
+#define E1000_MBVFICR_VFREQ_MASK 0x000000FF /* bits for VF messages */
+#define E1000_MBVFICR_VFREQ_VF1  0x00000001 /* bit for VF 1 message */
+#define E1000_MBVFICR_VFACK_MASK 0x00FF0000 /* bits for VF acks */
+#define E1000_MBVFICR_VFACK_VF1  0x00010000 /* bit for VF 1 ack */
+
+#define E1000_VFMAILBOX_SIZE   16 /* 16 32 bit words - 64 bytes */
+
+/* If it's a E1000_VF_* msg then it originates in the VF and is sent to the
+ * PF.  The reverse is true if it is E1000_PF_*.
+ * Message ACK's are the value or'd with 0xF0000000
+ */
+#define E1000_VT_MSGTYPE_ACK      0x80000000  /* Messages below or'd with
+                                               * this are the ACK */
+#define E1000_VT_MSGTYPE_NACK     0x40000000  /* Messages below or'd with
+                                               * this are the NACK */
+#define E1000_VT_MSGTYPE_CTS      0x20000000  /* Indicates that VF is still
+                                                 clear to send requests */
+#define E1000_VT_MSGINFO_SHIFT    16
+/* bits 23:16 are used for exra info for certain messages */
+#define E1000_VT_MSGINFO_MASK     (0xFF << E1000_VT_MSGINFO_SHIFT)
+
+#define E1000_VF_RESET            0x01 /* VF requests reset */
+#define E1000_VF_SET_MAC_ADDR     0x02 /* VF requests PF to set MAC addr */
+#define E1000_VF_SET_MULTICAST    0x03 /* VF requests PF to set MC addr */
+#define E1000_VF_SET_VLAN         0x04 /* VF requests PF to set VLAN */
+#define E1000_VF_SET_LPE          0x05 /* VF requests PF to set VMOLR.LPE */
+
+#define E1000_PF_CONTROL_MSG      0x0100 /* PF control message */
+
+s32 igb_read_mbx(struct e1000_hw *, u32 *, u16, u16);
+s32 igb_write_mbx(struct e1000_hw *, u32 *, u16, u16);
+s32 igb_read_posted_mbx(struct e1000_hw *, u32 *, u16, u16);
+s32 igb_write_posted_mbx(struct e1000_hw *, u32 *, u16, u16);
+s32 igb_check_for_msg(struct e1000_hw *, u16);
+s32 igb_check_for_ack(struct e1000_hw *, u16);
+s32 igb_check_for_rst(struct e1000_hw *, u16);
+s32 igb_init_mbx_params_pf(struct e1000_hw *);
+
+#endif /* _E1000_MBX_H_ */
index 95ed8ec157700604c5e90f08636b98d3402d7a48..0bd7728fe469bd58c40c91385f609c8a061d3925 100644 (file)
@@ -292,7 +292,7 @@ enum {
 #define E1000_RAH(_i)  (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
                                        (0x054E4 + ((_i - 16) * 8)))
 #define E1000_VFTA     0x05600  /* VLAN Filter Table Array - RW Array */
-#define E1000_VMD_CTL  0x0581C  /* VMDq Control - RW */
+#define E1000_VT_CTL   0x0581C  /* VMDq Control - RW */
 #define E1000_WUC      0x05800  /* Wakeup Control - RW */
 #define E1000_WUFC     0x05808  /* Wakeup Filter Control - RW */
 #define E1000_WUS      0x05810  /* Wakeup Status - RO */
@@ -320,6 +320,23 @@ enum {
 #define E1000_RETA(_i)  (0x05C00 + ((_i) * 4))
 #define E1000_RSSRK(_i) (0x05C80 + ((_i) * 4)) /* RSS Random Key - RW Array */
 
+/* VT Registers */
+#define E1000_MBVFICR   0x00C80 /* Mailbox VF Cause - RWC */
+#define E1000_MBVFIMR   0x00C84 /* Mailbox VF int Mask - RW */
+#define E1000_VFLRE     0x00C88 /* VF Register Events - RWC */
+#define E1000_VFRE      0x00C8C /* VF Receive Enables */
+#define E1000_VFTE      0x00C90 /* VF Transmit Enables */
+#define E1000_QDE       0x02408 /* Queue Drop Enable - RW */
+#define E1000_DTXSWC    0x03500 /* DMA Tx Switch Control - RW */
+#define E1000_RPLOLR    0x05AF0 /* Replication Offload - RW */
+#define E1000_IOVTCL    0x05BBC /* IOV Control Register */
+/* These act per VF so an array friendly macro is used */
+#define E1000_P2VMAILBOX(_n)   (0x00C00 + (4 * (_n)))
+#define E1000_VMBMEM(_n)       (0x00800 + (64 * (_n)))
+#define E1000_VMOLR(_n)        (0x05AD0 + (4 * (_n)))
+#define E1000_VLVF(_n)         (0x05D00 + (4 * (_n))) /* VLAN Virtual Machine
+                                                       * Filter - RW */
+
 #define wr32(reg, value) (writel(value, hw->hw_addr + reg))
 #define rd32(reg) (readl(hw->hw_addr + reg))
 #define wrfl() ((void)rd32(E1000_STATUS))
index 49fc0daf45af9568ffafdd19ea9e57de8bdd6662..4e8464b9df2e4af277b3d532c59e88612fb062a0 100644 (file)
@@ -57,8 +57,21 @@ struct igb_adapter;
 #define IGB_MIN_ITR_USECS                 10
 
 /* Transmit and receive queues */
-#define IGB_MAX_RX_QUEUES                  4
-#define IGB_MAX_TX_QUEUES                  4
+#define IGB_MAX_RX_QUEUES     (adapter->vfs_allocated_count ? \
+                               (adapter->vfs_allocated_count > 6 ? 1 : 2) : 4)
+#define IGB_MAX_TX_QUEUES     IGB_MAX_RX_QUEUES
+#define IGB_ABS_MAX_TX_QUEUES     4
+
+#define IGB_MAX_VF_MC_ENTRIES              30
+#define IGB_MAX_VF_FUNCTIONS               8
+#define IGB_MAX_VFTA_ENTRIES               128
+
+struct vf_data_storage {
+       unsigned char vf_mac_addresses[ETH_ALEN];
+       u16 vf_mc_hashes[IGB_MAX_VF_MC_ENTRIES];
+       u16 num_vf_mc_hashes;
+       bool clear_to_send;
+};
 
 /* RX descriptor control thresholds.
  * PTHRESH - MAC will consider prefetch if it has fewer than this number of
@@ -86,8 +99,7 @@ struct igb_adapter;
 #define IGB_RXBUFFER_2048  2048
 #define IGB_RXBUFFER_16384 16384
 
-/* Packet Buffer allocations */
-
+#define MAX_STD_JUMBO_FRAME_SIZE 9234
 
 /* How many Tx Descriptors do we need to call netif_wake_queue ? */
 #define IGB_TX_QUEUE_WAKE      16
@@ -170,10 +182,6 @@ struct igb_ring {
        char name[IFNAMSIZ + 5];
 };
 
-#define IGB_DESC_UNUSED(R) \
-       ((((R)->next_to_clean > (R)->next_to_use) ? 0 : (R)->count) + \
-       (R)->next_to_clean - (R)->next_to_use - 1)
-
 #define E1000_RX_DESC_ADV(R, i)            \
        (&(((union e1000_adv_rx_desc *)((R).desc))[i]))
 #define E1000_TX_DESC_ADV(R, i)            \
@@ -267,9 +275,11 @@ struct igb_adapter {
        unsigned int flags;
        u32 eeprom_wol;
 
-       struct igb_ring *multi_tx_table[IGB_MAX_TX_QUEUES];
+       struct igb_ring *multi_tx_table[IGB_ABS_MAX_TX_QUEUES];
        unsigned int tx_ring_count;
        unsigned int rx_ring_count;
+       unsigned int vfs_allocated_count;
+       struct vf_data_storage *vf_data;
 };
 
 #define IGB_FLAG_HAS_MSI           (1 << 0)
index 31f9a64773ff882191a491fa62c8f08659803b04..fb09c8ad9f0d2c80fc15ba28797fbea04acaa5be 100644 (file)
@@ -398,7 +398,7 @@ static void igb_get_regs(struct net_device *netdev,
        regs_buff[34] = rd32(E1000_RLPML);
        regs_buff[35] = rd32(E1000_RFCTL);
        regs_buff[36] = rd32(E1000_MRQC);
-       regs_buff[37] = rd32(E1000_VMD_CTL);
+       regs_buff[37] = rd32(E1000_VT_CTL);
 
        /* Transmit */
        regs_buff[38] = rd32(E1000_TCTL);
@@ -1779,6 +1779,15 @@ static int igb_wol_exclusion(struct igb_adapter *adapter,
                /* return success for non excluded adapter ports */
                retval = 0;
                break;
+       case E1000_DEV_ID_82576_QUAD_COPPER:
+               /* quad port adapters only support WoL on port A */
+               if (!(adapter->flags & IGB_FLAG_QUAD_PORT_A)) {
+                       wol->supported = 0;
+                       break;
+               }
+               /* return success for non excluded adapter ports */
+               retval = 0;
+               break;
        default:
                /* dual port cards only support WoL on port A from now on
                 * unless it was enabled in the eeprom for port B
index 43f489aba19169875fe62edc83e9a291dbbcbd83..ca842163dce4257abb61782b6d2dcdf2a5e30c39 100644 (file)
@@ -62,8 +62,10 @@ static const struct e1000_info *igb_info_tbl[] = {
 
 static struct pci_device_id igb_pci_tbl[] = {
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576), board_82575 },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_NS), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_FIBER), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_SERDES), board_82575 },
+       { PCI_VDEVICE(INTEL, E1000_DEV_ID_82576_QUAD_COPPER), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_COPPER), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575EB_FIBER_SERDES), board_82575 },
        { PCI_VDEVICE(INTEL, E1000_DEV_ID_82575GB_QUAD_COPPER), board_82575 },
@@ -106,7 +108,6 @@ static irqreturn_t igb_intr_msi(int irq, void *);
 static irqreturn_t igb_msix_other(int irq, void *);
 static irqreturn_t igb_msix_rx(int irq, void *);
 static irqreturn_t igb_msix_tx(int irq, void *);
-static int igb_clean_rx_ring_msix(struct napi_struct *, int);
 #ifdef CONFIG_IGB_DCA
 static void igb_update_rx_dca(struct igb_ring *);
 static void igb_update_tx_dca(struct igb_ring *);
@@ -123,6 +124,16 @@ static void igb_vlan_rx_register(struct net_device *, struct vlan_group *);
 static void igb_vlan_rx_add_vid(struct net_device *, u16);
 static void igb_vlan_rx_kill_vid(struct net_device *, u16);
 static void igb_restore_vlan(struct igb_adapter *);
+static void igb_ping_all_vfs(struct igb_adapter *);
+static void igb_msg_task(struct igb_adapter *);
+static int igb_rcv_msg_from_vf(struct igb_adapter *, u32);
+static inline void igb_set_rah_pool(struct e1000_hw *, int , int);
+static void igb_set_mc_list_pools(struct igb_adapter *, int, u16);
+static void igb_vmm_control(struct igb_adapter *);
+static inline void igb_set_vmolr(struct e1000_hw *, int);
+static inline int igb_set_vf_rlpml(struct igb_adapter *, int, int);
+static int igb_set_vf_mac(struct igb_adapter *adapter, int, unsigned char *);
+static void igb_restore_vf_multicasts(struct igb_adapter *adapter);
 
 static int igb_suspend(struct pci_dev *, pm_message_t);
 #ifdef CONFIG_PM
@@ -137,12 +148,18 @@ static struct notifier_block dca_notifier = {
        .priority       = 0
 };
 #endif
-
 #ifdef CONFIG_NET_POLL_CONTROLLER
 /* for netdump / net console */
 static void igb_netpoll(struct net_device *);
 #endif
 
+#ifdef CONFIG_PCI_IOV
+static ssize_t igb_set_num_vfs(struct device *, struct device_attribute *,
+                               const char *, size_t);
+static ssize_t igb_show_num_vfs(struct device *, struct device_attribute *,
+                               char *);
+DEVICE_ATTR(num_vfs, S_IRUGO | S_IWUSR, igb_show_num_vfs, igb_set_num_vfs);
+#endif
 static pci_ers_result_t igb_io_error_detected(struct pci_dev *,
                     pci_channel_state_t);
 static pci_ers_result_t igb_io_slot_reset(struct pci_dev *);
@@ -260,6 +277,17 @@ static char *igb_get_time_str(struct igb_adapter *adapter,
 }
 #endif
 
+/**
+ * igb_desc_unused - calculate if we have unused descriptors
+ **/
+static int igb_desc_unused(struct igb_ring *ring)
+{
+       if (ring->next_to_clean > ring->next_to_use)
+               return ring->next_to_clean - ring->next_to_use - 1;
+
+       return ring->count + ring->next_to_clean - ring->next_to_use - 1;
+}
+
 /**
  * igb_init_module - Driver Registration Routine
  *
@@ -313,6 +341,7 @@ module_exit(igb_exit_module);
 static void igb_cache_ring_register(struct igb_adapter *adapter)
 {
        int i;
+       unsigned int rbase_offset = adapter->vfs_allocated_count;
 
        switch (adapter->hw.mac.type) {
        case e1000_82576:
@@ -322,9 +351,11 @@ static void igb_cache_ring_register(struct igb_adapter *adapter)
                 * and continue consuming queues in the same sequence
                 */
                for (i = 0; i < adapter->num_rx_queues; i++)
-                       adapter->rx_ring[i].reg_idx = Q_IDX_82576(i);
+                       adapter->rx_ring[i].reg_idx = rbase_offset +
+                                                     Q_IDX_82576(i);
                for (i = 0; i < adapter->num_tx_queues; i++)
-                       adapter->tx_ring[i].reg_idx = Q_IDX_82576(i);
+                       adapter->tx_ring[i].reg_idx = rbase_offset +
+                                                     Q_IDX_82576(i);
                break;
        case e1000_82575:
        default:
@@ -424,7 +455,7 @@ static void igb_assign_vector(struct igb_adapter *adapter, int rx_queue,
                   a vector number along with a "valid" bit.  Sadly, the layout
                   of the table is somewhat counterintuitive. */
                if (rx_queue > IGB_N0_QUEUE) {
-                       index = (rx_queue >> 1);
+                       index = (rx_queue >> 1) + adapter->vfs_allocated_count;
                        ivar = array_rd32(E1000_IVAR0, index);
                        if (rx_queue & 0x1) {
                                /* vector goes into third byte of register */
@@ -439,7 +470,7 @@ static void igb_assign_vector(struct igb_adapter *adapter, int rx_queue,
                        array_wr32(E1000_IVAR0, index, ivar);
                }
                if (tx_queue > IGB_N0_QUEUE) {
-                       index = (tx_queue >> 1);
+                       index = (tx_queue >> 1) + adapter->vfs_allocated_count;
                        ivar = array_rd32(E1000_IVAR0, index);
                        if (tx_queue & 0x1) {
                                /* vector goes into high byte of register */
@@ -576,9 +607,6 @@ static int igb_request_msix(struct igb_adapter *adapter)
                        goto out;
                ring->itr_register = E1000_EITR(0) + (vector << 2);
                ring->itr_val = adapter->itr;
-               /* overwrite the poll routine for MSIX, we've already done
-                * netif_napi_add */
-               ring->napi.poll = &igb_clean_rx_ring_msix;
                vector++;
        }
 
@@ -762,7 +790,10 @@ static void igb_irq_enable(struct igb_adapter *adapter)
                wr32(E1000_EIAC, adapter->eims_enable_mask);
                wr32(E1000_EIAM, adapter->eims_enable_mask);
                wr32(E1000_EIMS, adapter->eims_enable_mask);
-               wr32(E1000_IMS, E1000_IMS_LSC | E1000_IMS_DOUTSYNC);
+               if (adapter->vfs_allocated_count)
+                       wr32(E1000_MBVFIMR, 0xFF);
+               wr32(E1000_IMS, (E1000_IMS_LSC | E1000_IMS_VMMB |
+                                E1000_IMS_DOUTSYNC));
        } else {
                wr32(E1000_IMS, IMS_ENABLE_MASK);
                wr32(E1000_IAM, IMS_ENABLE_MASK);
@@ -853,12 +884,12 @@ static void igb_configure(struct igb_adapter *adapter)
 
        igb_rx_fifo_flush_82575(&adapter->hw);
 
-       /* call IGB_DESC_UNUSED which always leaves
+       /* call igb_desc_unused which always leaves
         * at least 1 descriptor unused to make sure
         * next_to_use != next_to_clean */
        for (i = 0; i < adapter->num_rx_queues; i++) {
                struct igb_ring *ring = &adapter->rx_ring[i];
-               igb_alloc_rx_buffers_adv(ring, IGB_DESC_UNUSED(ring));
+               igb_alloc_rx_buffers_adv(ring, igb_desc_unused(ring));
        }
 
 
@@ -886,6 +917,10 @@ int igb_up(struct igb_adapter *adapter)
        if (adapter->msix_entries)
                igb_configure_msix(adapter);
 
+       igb_vmm_control(adapter);
+       igb_set_rah_pool(hw, adapter->vfs_allocated_count, 0);
+       igb_set_vmolr(hw, adapter->vfs_allocated_count);
+
        /* Clear any pending interrupts. */
        rd32(E1000_ICR);
        igb_irq_enable(adapter);
@@ -1038,6 +1073,20 @@ void igb_reset(struct igb_adapter *adapter)
        fc->send_xon = 1;
        fc->type = fc->original_type;
 
+       /* disable receive for all VFs and wait one second */
+       if (adapter->vfs_allocated_count) {
+               int i;
+               for (i = 0 ; i < adapter->vfs_allocated_count; i++)
+                       adapter->vf_data[i].clear_to_send = false;
+
+               /* ping all the active vfs to let them know we are going down */
+                       igb_ping_all_vfs(adapter);
+
+               /* disable transmits and receives */
+               wr32(E1000_VFRE, 0);
+               wr32(E1000_VFTE, 0);
+       }
+
        /* Allow time for pending master requests to run */
        adapter->hw.mac.ops.reset_hw(&adapter->hw);
        wr32(E1000_WUC, 0);
@@ -1090,11 +1139,10 @@ static int __devinit igb_probe(struct pci_dev *pdev,
        struct net_device *netdev;
        struct igb_adapter *adapter;
        struct e1000_hw *hw;
-       struct pci_dev *us_dev;
        const struct e1000_info *ei = igb_info_tbl[ent->driver_data];
        unsigned long mmio_start, mmio_len;
-       int err, pci_using_dac, pos;
-       u16 eeprom_data = 0, state = 0;
+       int err, pci_using_dac;
+       u16 eeprom_data = 0;
        u16 eeprom_apme_mask = IGB_EEPROM_APME;
        u32 part_num;
 
@@ -1120,27 +1168,6 @@ static int __devinit igb_probe(struct pci_dev *pdev,
                }
        }
 
-       /* 82575 requires that the pci-e link partner disable the L0s state */
-       switch (pdev->device) {
-       case E1000_DEV_ID_82575EB_COPPER:
-       case E1000_DEV_ID_82575EB_FIBER_SERDES:
-       case E1000_DEV_ID_82575GB_QUAD_COPPER:
-               us_dev = pdev->bus->self;
-               pos = pci_find_capability(us_dev, PCI_CAP_ID_EXP);
-               if (pos) {
-                       pci_read_config_word(us_dev, pos + PCI_EXP_LNKCTL,
-                                            &state);
-                       state &= ~PCIE_LINK_STATE_L0S;
-                       pci_write_config_word(us_dev, pos + PCI_EXP_LNKCTL,
-                                             state);
-                       dev_info(&pdev->dev,
-                                "Disabling ASPM L0s upstream switch port %s\n",
-                                pci_name(us_dev));
-               }
-       default:
-               break;
-       }
-
        err = pci_request_selected_regions(pdev, pci_select_bars(pdev,
                                           IORESOURCE_MEM),
                                           igb_driver_name);
@@ -1158,7 +1185,8 @@ static int __devinit igb_probe(struct pci_dev *pdev,
        pci_save_state(pdev);
 
        err = -ENOMEM;
-       netdev = alloc_etherdev_mq(sizeof(struct igb_adapter), IGB_MAX_TX_QUEUES);
+       netdev = alloc_etherdev_mq(sizeof(struct igb_adapter),
+                                  IGB_ABS_MAX_TX_QUEUES);
        if (!netdev)
                goto err_alloc_etherdev;
 
@@ -1248,9 +1276,7 @@ static int __devinit igb_probe(struct pci_dev *pdev,
        netdev->features |= NETIF_F_TSO;
        netdev->features |= NETIF_F_TSO6;
 
-#ifdef CONFIG_IGB_LRO
        netdev->features |= NETIF_F_GRO;
-#endif
 
        netdev->vlan_features |= NETIF_F_TSO;
        netdev->vlan_features |= NETIF_F_TSO6;
@@ -1286,13 +1312,10 @@ static int __devinit igb_probe(struct pci_dev *pdev,
                goto err_eeprom;
        }
 
-       init_timer(&adapter->watchdog_timer);
-       adapter->watchdog_timer.function = &igb_watchdog;
-       adapter->watchdog_timer.data = (unsigned long) adapter;
-
-       init_timer(&adapter->phy_info_timer);
-       adapter->phy_info_timer.function = &igb_update_phy_info;
-       adapter->phy_info_timer.data = (unsigned long) adapter;
+       setup_timer(&adapter->watchdog_timer, &igb_watchdog,
+                   (unsigned long) adapter);
+       setup_timer(&adapter->phy_info_timer, &igb_update_phy_info,
+                   (unsigned long) adapter);
 
        INIT_WORK(&adapter->reset_task, igb_reset_task);
        INIT_WORK(&adapter->watchdog_task, igb_watchdog_task);
@@ -1316,9 +1339,10 @@ static int __devinit igb_probe(struct pci_dev *pdev,
         * enable the ACPI Magic Packet filter
         */
 
-       if (hw->bus.func == 0 ||
-           hw->device_id == E1000_DEV_ID_82575EB_COPPER)
+       if (hw->bus.func == 0)
                hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_A, 1, &eeprom_data);
+       else if (hw->bus.func == 1)
+               hw->nvm.ops.read(hw, NVM_INIT_CONTROL3_PORT_B, 1, &eeprom_data);
 
        if (eeprom_data & eeprom_apme_mask)
                adapter->eeprom_wol |= E1000_WUFC_MAG;
@@ -1338,6 +1362,16 @@ static int __devinit igb_probe(struct pci_dev *pdev,
                if (rd32(E1000_STATUS) & E1000_STATUS_FUNC_1)
                        adapter->eeprom_wol = 0;
                break;
+       case E1000_DEV_ID_82576_QUAD_COPPER:
+               /* if quad port adapter, disable WoL on all but port A */
+               if (global_quad_port_a != 0)
+                       adapter->eeprom_wol = 0;
+               else
+                       adapter->flags |= IGB_FLAG_QUAD_PORT_A;
+               /* Reset for multiple quad port adapters */
+               if (++global_quad_port_a == 4)
+                       global_quad_port_a = 0;
+               break;
        }
 
        /* initialize the wol settings based on the eeprom settings */
@@ -1360,6 +1394,19 @@ static int __devinit igb_probe(struct pci_dev *pdev,
        if (err)
                goto err_register;
 
+#ifdef CONFIG_PCI_IOV
+       /* since iov functionality isn't critical to base device function we
+        * can accept failure.  If it fails we don't allow iov to be enabled */
+       if (hw->mac.type == e1000_82576) {
+               err = pci_enable_sriov(pdev, 0);
+               if (!err)
+                       err = device_create_file(&netdev->dev,
+                                                &dev_attr_num_vfs);
+               if (err)
+                       dev_err(&pdev->dev, "Failed to initialize IOV\n");
+       }
+
+#endif
 #ifdef CONFIG_IGB_DCA
        if (dca_add_requester(&pdev->dev) == 0) {
                adapter->flags |= IGB_FLAG_DCA_ENABLED;
@@ -1515,6 +1562,20 @@ static void __devexit igb_remove(struct pci_dev *pdev)
 
        igb_free_queues(adapter);
 
+#ifdef CONFIG_PCI_IOV
+       /* reclaim resources allocated to VFs */
+       if (adapter->vf_data) {
+               /* disable iov and allow time for transactions to clear */
+               pci_disable_sriov(pdev);
+               msleep(500);
+
+               kfree(adapter->vf_data);
+               adapter->vf_data = NULL;
+               wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
+               msleep(100);
+               dev_info(&pdev->dev, "IOV Disabled\n");
+       }
+#endif
        iounmap(hw->hw_addr);
        if (hw->flash_address)
                iounmap(hw->flash_address);
@@ -1616,6 +1677,10 @@ static int igb_open(struct net_device *netdev)
         * clean_rx handler before we do so.  */
        igb_configure(adapter);
 
+       igb_vmm_control(adapter);
+       igb_set_rah_pool(hw, adapter->vfs_allocated_count, 0);
+       igb_set_vmolr(hw, adapter->vfs_allocated_count);
+
        err = igb_request_irq(adapter);
        if (err)
                goto err_req_irq;
@@ -1796,10 +1861,11 @@ static void igb_configure_tx(struct igb_adapter *adapter)
                wr32(E1000_DCA_TXCTRL(j), txctrl);
        }
 
-       /* Use the default values for the Tx Inter Packet Gap (IPG) timer */
+       /* disable queue 0 to prevent tail bump w/o re-configuration */
+       if (adapter->vfs_allocated_count)
+               wr32(E1000_TXDCTL(0), 0);
 
        /* Program the Transmit Control Register */
-
        tctl = rd32(E1000_TCTL);
        tctl &= ~E1000_TCTL_CT;
        tctl |= E1000_TCTL_PSP | E1000_TCTL_RTLC |
@@ -1953,6 +2019,30 @@ static void igb_setup_rctl(struct igb_adapter *adapter)
                srrctl |= E1000_SRRCTL_DESCTYPE_ADV_ONEBUF;
        }
 
+       /* Attention!!!  For SR-IOV PF driver operations you must enable
+        * queue drop for all VF and PF queues to prevent head of line blocking
+        * if an un-trusted VF does not provide descriptors to hardware.
+        */
+       if (adapter->vfs_allocated_count) {
+               u32 vmolr;
+
+               j = adapter->rx_ring[0].reg_idx;
+
+               /* set all queue drop enable bits */
+               wr32(E1000_QDE, ALL_QUEUES);
+               srrctl |= E1000_SRRCTL_DROP_EN;
+
+               /* disable queue 0 to prevent tail write w/o re-config */
+               wr32(E1000_RXDCTL(0), 0);
+
+               vmolr = rd32(E1000_VMOLR(j));
+               if (rctl & E1000_RCTL_LPE)
+                       vmolr |= E1000_VMOLR_LPE;
+               if (adapter->num_rx_queues > 0)
+                       vmolr |= E1000_VMOLR_RSSE;
+               wr32(E1000_VMOLR(j), vmolr);
+       }
+
        for (i = 0; i < adapter->num_rx_queues; i++) {
                j = adapter->rx_ring[i].reg_idx;
                wr32(E1000_SRRCTL(j), srrctl);
@@ -1961,6 +2051,54 @@ static void igb_setup_rctl(struct igb_adapter *adapter)
        wr32(E1000_RCTL, rctl);
 }
 
+/**
+ * igb_rlpml_set - set maximum receive packet size
+ * @adapter: board private structure
+ *
+ * Configure maximum receivable packet size.
+ **/
+static void igb_rlpml_set(struct igb_adapter *adapter)
+{
+       u32 max_frame_size = adapter->max_frame_size;
+       struct e1000_hw *hw = &adapter->hw;
+       u16 pf_id = adapter->vfs_allocated_count;
+
+       if (adapter->vlgrp)
+               max_frame_size += VLAN_TAG_SIZE;
+
+       /* if vfs are enabled we set RLPML to the largest possible request
+        * size and set the VMOLR RLPML to the size we need */
+       if (pf_id) {
+               igb_set_vf_rlpml(adapter, max_frame_size, pf_id);
+               max_frame_size = MAX_STD_JUMBO_FRAME_SIZE + VLAN_TAG_SIZE;
+       }
+
+       wr32(E1000_RLPML, max_frame_size);
+}
+
+/**
+ * igb_configure_vt_default_pool - Configure VT default pool
+ * @adapter: board private structure
+ *
+ * Configure the default pool
+ **/
+static void igb_configure_vt_default_pool(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u16 pf_id = adapter->vfs_allocated_count;
+       u32 vtctl;
+
+       /* not in sr-iov mode - do nothing */
+       if (!pf_id)
+               return;
+
+       vtctl = rd32(E1000_VT_CTL);
+       vtctl &= ~(E1000_VT_CTL_DEFAULT_POOL_MASK |
+                  E1000_VT_CTL_DISABLE_DEF_POOL);
+       vtctl |= pf_id << E1000_VT_CTL_DEFAULT_POOL_SHIFT;
+       wr32(E1000_VT_CTL, vtctl);
+}
+
 /**
  * igb_configure_rx - Configure receive Unit after Reset
  * @adapter: board private structure
@@ -1973,7 +2111,7 @@ static void igb_configure_rx(struct igb_adapter *adapter)
        struct e1000_hw *hw = &adapter->hw;
        u32 rctl, rxcsum;
        u32 rxdctl;
-       int i, j;
+       int i;
 
        /* disable receives while setting up the descriptors */
        rctl = rd32(E1000_RCTL);
@@ -1988,7 +2126,7 @@ static void igb_configure_rx(struct igb_adapter *adapter)
         * the Base and Length of the Rx Descriptor Ring */
        for (i = 0; i < adapter->num_rx_queues; i++) {
                struct igb_ring *ring = &adapter->rx_ring[i];
-               j = ring->reg_idx;
+               int j = ring->reg_idx;
                rdba = ring->dma;
                wr32(E1000_RDBAL(j),
                     rdba & 0x00000000ffffffffULL);
@@ -2032,7 +2170,10 @@ static void igb_configure_rx(struct igb_adapter *adapter)
                                writel(reta.dword,
                                       hw->hw_addr + E1000_RETA(0) + (j & ~3));
                }
-               mrqc = E1000_MRQC_ENABLE_RSS_4Q;
+               if (adapter->vfs_allocated_count)
+                       mrqc = E1000_MRQC_ENABLE_VMDQ_RSS_2Q;
+               else
+                       mrqc = E1000_MRQC_ENABLE_RSS_4Q;
 
                /* Fill out hash function seeds */
                for (j = 0; j < 10; j++)
@@ -2057,6 +2198,9 @@ static void igb_configure_rx(struct igb_adapter *adapter)
                rxcsum |= E1000_RXCSUM_PCSD;
                wr32(E1000_RXCSUM, rxcsum);
        } else {
+               /* Enable multi-queue for sr-iov */
+               if (adapter->vfs_allocated_count)
+                       wr32(E1000_MRQC, E1000_MRQC_ENABLE_VMDQ);
                /* Enable Receive Checksum Offload for TCP and UDP */
                rxcsum = rd32(E1000_RXCSUM);
                if (adapter->rx_csum)
@@ -2067,11 +2211,10 @@ static void igb_configure_rx(struct igb_adapter *adapter)
                wr32(E1000_RXCSUM, rxcsum);
        }
 
-       if (adapter->vlgrp)
-               wr32(E1000_RLPML,
-                               adapter->max_frame_size + VLAN_TAG_SIZE);
-       else
-               wr32(E1000_RLPML, adapter->max_frame_size);
+       /* Set the default pool for the PF's first queue */
+       igb_configure_vt_default_pool(adapter);
+
+       igb_rlpml_set(adapter);
 
        /* Enable Receives */
        wr32(E1000_RCTL, rctl);
@@ -2114,19 +2257,14 @@ static void igb_free_all_tx_resources(struct igb_adapter *adapter)
 static void igb_unmap_and_free_tx_resource(struct igb_adapter *adapter,
                                           struct igb_buffer *buffer_info)
 {
-       if (buffer_info->dma) {
-               pci_unmap_page(adapter->pdev,
-                               buffer_info->dma,
-                               buffer_info->length,
-                               PCI_DMA_TODEVICE);
-               buffer_info->dma = 0;
-       }
+       buffer_info->dma = 0;
        if (buffer_info->skb) {
+               skb_dma_unmap(&adapter->pdev->dev, buffer_info->skb,
+                             DMA_TO_DEVICE);
                dev_kfree_skb_any(buffer_info->skb);
                buffer_info->skb = NULL;
        }
        buffer_info->time_stamp = 0;
-       buffer_info->next_to_watch = 0;
        /* buffer_info must be completely set up in the transmit path */
 }
 
@@ -2301,6 +2439,8 @@ static int igb_set_mac(struct net_device *netdev, void *p)
 
        hw->mac.ops.rar_set(hw, hw->mac.addr, 0);
 
+       igb_set_rah_pool(hw, adapter->vfs_allocated_count, 0);
+
        return 0;
 }
 
@@ -2319,7 +2459,7 @@ static void igb_set_multi(struct net_device *netdev)
        struct e1000_hw *hw = &adapter->hw;
        struct e1000_mac_info *mac = &hw->mac;
        struct dev_mc_list *mc_ptr;
-       u8  *mta_list;
+       u8  *mta_list = NULL;
        u32 rctl;
        int i;
 
@@ -2340,17 +2480,15 @@ static void igb_set_multi(struct net_device *netdev)
        }
        wr32(E1000_RCTL, rctl);
 
-       if (!netdev->mc_count) {
-               /* nothing to program, so clear mc list */
-               igb_update_mc_addr_list(hw, NULL, 0, 1,
-                                       mac->rar_entry_count);
-               return;
+       if (netdev->mc_count) {
+               mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC);
+               if (!mta_list) {
+                       dev_err(&adapter->pdev->dev,
+                               "failed to allocate multicast filter list\n");
+                       return;
+               }
        }
 
-       mta_list = kzalloc(netdev->mc_count * 6, GFP_ATOMIC);
-       if (!mta_list)
-               return;
-
        /* The shared function expects a packed array of only addresses. */
        mc_ptr = netdev->mc_list;
 
@@ -2360,7 +2498,13 @@ static void igb_set_multi(struct net_device *netdev)
                memcpy(mta_list + (i*ETH_ALEN), mc_ptr->dmi_addr, ETH_ALEN);
                mc_ptr = mc_ptr->next;
        }
-       igb_update_mc_addr_list(hw, mta_list, i, 1, mac->rar_entry_count);
+       igb_update_mc_addr_list(hw, mta_list, i,
+                               adapter->vfs_allocated_count + 1,
+                               mac->rar_entry_count);
+
+       igb_set_mc_list_pools(adapter, i, mac->rar_entry_count);
+       igb_restore_vf_multicasts(adapter);
+
        kfree(mta_list);
 }
 
@@ -2476,6 +2620,8 @@ static void igb_watchdog_task(struct work_struct *work)
                        netif_carrier_on(netdev);
                        netif_tx_wake_all_queues(netdev);
 
+                       igb_ping_all_vfs(adapter);
+
                        /* link state has changed, schedule phy info update */
                        if (!test_bit(__IGB_DOWN, &adapter->state))
                                mod_timer(&adapter->phy_info_timer,
@@ -2491,6 +2637,8 @@ static void igb_watchdog_task(struct work_struct *work)
                        netif_carrier_off(netdev);
                        netif_tx_stop_all_queues(netdev);
 
+                       igb_ping_all_vfs(adapter);
+
                        /* link state has changed, schedule phy info update */
                        if (!test_bit(__IGB_DOWN, &adapter->state))
                                mod_timer(&adapter->phy_info_timer,
@@ -2514,7 +2662,7 @@ link_up:
        igb_update_adaptive(&adapter->hw);
 
        if (!netif_carrier_ok(netdev)) {
-               if (IGB_DESC_UNUSED(tx_ring) + 1 < tx_ring->count) {
+               if (igb_desc_unused(tx_ring) + 1 < tx_ring->count) {
                        /* We've lost link, so the controller stops DMA,
                         * but we've got queued Tx work that's never going
                         * to get done, so reset controller to flush Tx.
@@ -2861,7 +3009,18 @@ static inline bool igb_tx_csum_adv(struct igb_adapter *adapter,
                tu_cmd |= (E1000_TXD_CMD_DEXT | E1000_ADVTXD_DTYP_CTXT);
 
                if (skb->ip_summed == CHECKSUM_PARTIAL) {
-                       switch (skb->protocol) {
+                       __be16 protocol;
+
+                       if (skb->protocol == cpu_to_be16(ETH_P_8021Q)) {
+                               const struct vlan_ethhdr *vhdr =
+                                         (const struct vlan_ethhdr*)skb->data;
+
+                               protocol = vhdr->h_vlan_encapsulated_proto;
+                       } else {
+                               protocol = skb->protocol;
+                       }
+
+                       switch (protocol) {
                        case cpu_to_be16(ETH_P_IP):
                                tu_cmd |= E1000_ADVTXD_TUCMD_IPV4;
                                if (ip_hdr(skb)->protocol == IPPROTO_TCP)
@@ -2914,25 +3073,33 @@ static inline int igb_tx_map_adv(struct igb_adapter *adapter,
        unsigned int len = skb_headlen(skb);
        unsigned int count = 0, i;
        unsigned int f;
+       dma_addr_t *map;
 
        i = tx_ring->next_to_use;
 
+       if (skb_dma_map(&adapter->pdev->dev, skb, DMA_TO_DEVICE)) {
+               dev_err(&adapter->pdev->dev, "TX DMA map failed\n");
+               return 0;
+       }
+
+       map = skb_shinfo(skb)->dma_maps;
+
        buffer_info = &tx_ring->buffer_info[i];
        BUG_ON(len >= IGB_MAX_DATA_PER_TXD);
        buffer_info->length = len;
        /* set time_stamp *before* dma to help avoid a possible race */
        buffer_info->time_stamp = jiffies;
        buffer_info->next_to_watch = i;
-       buffer_info->dma = pci_map_single(adapter->pdev, skb->data, len,
-                                         PCI_DMA_TODEVICE);
+       buffer_info->dma = map[count];
        count++;
-       i++;
-       if (i == tx_ring->count)
-               i = 0;
 
        for (f = 0; f < skb_shinfo(skb)->nr_frags; f++) {
                struct skb_frag_struct *frag;
 
+               i++;
+               if (i == tx_ring->count)
+                       i = 0;
+
                frag = &skb_shinfo(skb)->frags[f];
                len = frag->size;
 
@@ -2941,19 +3108,10 @@ static inline int igb_tx_map_adv(struct igb_adapter *adapter,
                buffer_info->length = len;
                buffer_info->time_stamp = jiffies;
                buffer_info->next_to_watch = i;
-               buffer_info->dma = pci_map_page(adapter->pdev,
-                                               frag->page,
-                                               frag->page_offset,
-                                               len,
-                                               PCI_DMA_TODEVICE);
-
+               buffer_info->dma = map[count];
                count++;
-               i++;
-               if (i == tx_ring->count)
-                       i = 0;
        }
 
-       i = ((i == 0) ? tx_ring->count - 1 : i - 1);
        tx_ring->buffer_info[i].skb = skb;
        tx_ring->buffer_info[first].next_to_watch = i;
 
@@ -3041,7 +3199,7 @@ static int __igb_maybe_stop_tx(struct net_device *netdev,
 
        /* We need to check again in a case another CPU has just
         * made room available. */
-       if (IGB_DESC_UNUSED(tx_ring) < size)
+       if (igb_desc_unused(tx_ring) < size)
                return -EBUSY;
 
        /* A reprieve! */
@@ -3053,7 +3211,7 @@ static int __igb_maybe_stop_tx(struct net_device *netdev,
 static int igb_maybe_stop_tx(struct net_device *netdev,
                             struct igb_ring *tx_ring, int size)
 {
-       if (IGB_DESC_UNUSED(tx_ring) >= size)
+       if (igb_desc_unused(tx_ring) >= size)
                return 0;
        return __igb_maybe_stop_tx(netdev, tx_ring, size);
 }
@@ -3066,6 +3224,7 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb,
        unsigned int first;
        unsigned int tx_flags = 0;
        u8 hdr_len = 0;
+       int count = 0;
        int tso = 0;
        union skb_shared_tx *shtx;
 
@@ -3102,14 +3261,6 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb,
        if (unlikely(shtx->hardware)) {
                shtx->in_progress = 1;
                tx_flags |= IGB_TX_FLAGS_TSTAMP;
-       } else if (likely(!shtx->software)) {
-               /*
-                * TODO: can this be solved in dev.c:dev_hard_start_xmit()?
-                * There are probably unmodified driver which do something
-                * like this and thus don't work in combination with
-                * SOF_TIMESTAMPING_TX_SOFTWARE.
-                */
-               skb_orphan(skb);
        }
 
        if (adapter->vlgrp && vlan_tx_tag_present(skb)) {
@@ -3135,14 +3286,23 @@ static int igb_xmit_frame_ring_adv(struct sk_buff *skb,
                 (skb->ip_summed == CHECKSUM_PARTIAL))
                tx_flags |= IGB_TX_FLAGS_CSUM;
 
-       igb_tx_queue_adv(adapter, tx_ring, tx_flags,
-                        igb_tx_map_adv(adapter, tx_ring, skb, first),
-                        skb->len, hdr_len);
-
-       netdev->trans_start = jiffies;
-
-       /* Make sure there is space in the ring for the next send. */
-       igb_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 4);
+       /*
+        * count reflects descriptors mapped, if 0 then mapping error
+        * has occured and we need to rewind the descriptor queue
+        */
+       count = igb_tx_map_adv(adapter, tx_ring, skb, first);
+
+       if (count) {
+               igb_tx_queue_adv(adapter, tx_ring, tx_flags, count,
+                                skb->len, hdr_len);
+               netdev->trans_start = jiffies;
+               /* Make sure there is space in the ring for the next send. */
+               igb_maybe_stop_tx(netdev, tx_ring, MAX_SKB_FRAGS + 4);
+       } else {
+               dev_kfree_skb_any(skb);
+               tx_ring->buffer_info[first].time_stamp = 0;
+               tx_ring->next_to_use = first;
+       }
 
        return NETDEV_TX_OK;
 }
@@ -3153,7 +3313,7 @@ static int igb_xmit_frame_adv(struct sk_buff *skb, struct net_device *netdev)
        struct igb_ring *tx_ring;
 
        int r_idx = 0;
-       r_idx = skb->queue_mapping & (IGB_MAX_TX_QUEUES - 1);
+       r_idx = skb->queue_mapping & (IGB_ABS_MAX_TX_QUEUES - 1);
        tx_ring = adapter->multi_tx_table[r_idx];
 
        /* This goes back to the question of how to logically map a tx queue
@@ -3220,7 +3380,6 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu)
                return -EINVAL;
        }
 
-#define MAX_STD_JUMBO_FRAME_SIZE 9234
        if (max_frame > MAX_STD_JUMBO_FRAME_SIZE) {
                dev_err(&adapter->pdev->dev, "MTU > 9216 not supported.\n");
                return -EINVAL;
@@ -3254,6 +3413,12 @@ static int igb_change_mtu(struct net_device *netdev, int new_mtu)
 #else
                adapter->rx_buffer_len = PAGE_SIZE / 2;
 #endif
+
+       /* if sr-iov is enabled we need to force buffer size to 1K or larger */
+       if (adapter->vfs_allocated_count &&
+           (adapter->rx_buffer_len < IGB_RXBUFFER_1024))
+               adapter->rx_buffer_len = IGB_RXBUFFER_1024;
+
        /* adjust allocation if LPE protects us, and we aren't using SBP */
        if ((max_frame == ETH_FRAME_LEN + ETH_FCS_LEN) ||
             (max_frame == MAXIMUM_ETHERNET_VLAN_SIZE))
@@ -3423,15 +3588,19 @@ static irqreturn_t igb_msix_other(int irq, void *data)
                /* HW is reporting DMA is out of sync */
                adapter->stats.doosync++;
        }
-       if (!(icr & E1000_ICR_LSC))
-               goto no_link_interrupt;
-       hw->mac.get_link_status = 1;
-       /* guard against interrupt when we're going down */
-       if (!test_bit(__IGB_DOWN, &adapter->state))
-               mod_timer(&adapter->watchdog_timer, jiffies + 1);
 
-no_link_interrupt:
-       wr32(E1000_IMS, E1000_IMS_LSC | E1000_IMS_DOUTSYNC);
+       /* Check for a mailbox event */
+       if (icr & E1000_ICR_VMMB)
+               igb_msg_task(adapter);
+
+       if (icr & E1000_ICR_LSC) {
+               hw->mac.get_link_status = 1;
+               /* guard against interrupt when we're going down */
+               if (!test_bit(__IGB_DOWN, &adapter->state))
+                       mod_timer(&adapter->watchdog_timer, jiffies + 1);
+       }
+
+       wr32(E1000_IMS, E1000_IMS_LSC | E1000_IMS_DOUTSYNC | E1000_IMS_VMMB);
        wr32(E1000_EIMS, adapter->eims_other);
 
        return IRQ_HANDLED;
@@ -3513,11 +3682,11 @@ static void igb_update_rx_dca(struct igb_ring *rx_ring)
                dca_rxctrl = rd32(E1000_DCA_RXCTRL(q));
                if (hw->mac.type == e1000_82576) {
                        dca_rxctrl &= ~E1000_DCA_RXCTRL_CPUID_MASK_82576;
-                       dca_rxctrl |= dca_get_tag(cpu) <<
+                       dca_rxctrl |= dca3_get_tag(&adapter->pdev->dev, cpu) <<
                                      E1000_DCA_RXCTRL_CPUID_SHIFT;
                } else {
                        dca_rxctrl &= ~E1000_DCA_RXCTRL_CPUID_MASK;
-                       dca_rxctrl |= dca_get_tag(cpu);
+                       dca_rxctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
                }
                dca_rxctrl |= E1000_DCA_RXCTRL_DESC_DCA_EN;
                dca_rxctrl |= E1000_DCA_RXCTRL_HEAD_DCA_EN;
@@ -3540,11 +3709,11 @@ static void igb_update_tx_dca(struct igb_ring *tx_ring)
                dca_txctrl = rd32(E1000_DCA_TXCTRL(q));
                if (hw->mac.type == e1000_82576) {
                        dca_txctrl &= ~E1000_DCA_TXCTRL_CPUID_MASK_82576;
-                       dca_txctrl |= dca_get_tag(cpu) <<
+                       dca_txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu) <<
                                      E1000_DCA_TXCTRL_CPUID_SHIFT;
                } else {
                        dca_txctrl &= ~E1000_DCA_TXCTRL_CPUID_MASK;
-                       dca_txctrl |= dca_get_tag(cpu);
+                       dca_txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
                }
                dca_txctrl |= E1000_DCA_TXCTRL_DESC_DCA_EN;
                wr32(E1000_DCA_TXCTRL(q), dca_txctrl);
@@ -3619,6 +3788,322 @@ static int igb_notify_dca(struct notifier_block *nb, unsigned long event,
 }
 #endif /* CONFIG_IGB_DCA */
 
+static void igb_ping_all_vfs(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 ping;
+       int i;
+
+       for (i = 0 ; i < adapter->vfs_allocated_count; i++) {
+               ping = E1000_PF_CONTROL_MSG;
+               if (adapter->vf_data[i].clear_to_send)
+                       ping |= E1000_VT_MSGTYPE_CTS;
+               igb_write_mbx(hw, &ping, 1, i);
+       }
+}
+
+static int igb_set_vf_multicasts(struct igb_adapter *adapter,
+                                 u32 *msgbuf, u32 vf)
+{
+       int n = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
+       u16 *hash_list = (u16 *)&msgbuf[1];
+       struct vf_data_storage *vf_data = &adapter->vf_data[vf];
+       int i;
+
+       /* only up to 30 hash values supported */
+       if (n > 30)
+               n = 30;
+
+       /* salt away the number of multi cast addresses assigned
+        * to this VF for later use to restore when the PF multi cast
+        * list changes
+        */
+       vf_data->num_vf_mc_hashes = n;
+
+       /* VFs are limited to using the MTA hash table for their multicast
+        * addresses */
+       for (i = 0; i < n; i++)
+               vf_data->vf_mc_hashes[i] = hash_list[i];;
+
+       /* Flush and reset the mta with the new values */
+       igb_set_multi(adapter->netdev);
+
+       return 0;
+}
+
+static void igb_restore_vf_multicasts(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       struct vf_data_storage *vf_data;
+       int i, j;
+
+       for (i = 0; i < adapter->vfs_allocated_count; i++) {
+               vf_data = &adapter->vf_data[i];
+               for (j = 0; j < vf_data->num_vf_mc_hashes; j++)
+                       igb_mta_set(hw, vf_data->vf_mc_hashes[j]);
+       }
+}
+
+static void igb_clear_vf_vfta(struct igb_adapter *adapter, u32 vf)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 pool_mask, reg, vid;
+       int i;
+
+       pool_mask = 1 << (E1000_VLVF_POOLSEL_SHIFT + vf);
+
+       /* Find the vlan filter for this id */
+       for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
+               reg = rd32(E1000_VLVF(i));
+
+               /* remove the vf from the pool */
+               reg &= ~pool_mask;
+
+               /* if pool is empty then remove entry from vfta */
+               if (!(reg & E1000_VLVF_POOLSEL_MASK) &&
+                   (reg & E1000_VLVF_VLANID_ENABLE)) {
+                       reg = 0;
+                       vid = reg & E1000_VLVF_VLANID_MASK;
+                       igb_vfta_set(hw, vid, false);
+               }
+
+               wr32(E1000_VLVF(i), reg);
+       }
+}
+
+static s32 igb_vlvf_set(struct igb_adapter *adapter, u32 vid, bool add, u32 vf)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 reg, i;
+
+       /* It is an error to call this function when VFs are not enabled */
+       if (!adapter->vfs_allocated_count)
+               return -1;
+
+       /* Find the vlan filter for this id */
+       for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
+               reg = rd32(E1000_VLVF(i));
+               if ((reg & E1000_VLVF_VLANID_ENABLE) &&
+                   vid == (reg & E1000_VLVF_VLANID_MASK))
+                       break;
+       }
+
+       if (add) {
+               if (i == E1000_VLVF_ARRAY_SIZE) {
+                       /* Did not find a matching VLAN ID entry that was
+                        * enabled.  Search for a free filter entry, i.e.
+                        * one without the enable bit set
+                        */
+                       for (i = 0; i < E1000_VLVF_ARRAY_SIZE; i++) {
+                               reg = rd32(E1000_VLVF(i));
+                               if (!(reg & E1000_VLVF_VLANID_ENABLE))
+                                       break;
+                       }
+               }
+               if (i < E1000_VLVF_ARRAY_SIZE) {
+                       /* Found an enabled/available entry */
+                       reg |= 1 << (E1000_VLVF_POOLSEL_SHIFT + vf);
+
+                       /* if !enabled we need to set this up in vfta */
+                       if (!(reg & E1000_VLVF_VLANID_ENABLE)) {
+                               /* add VID to filter table, if bit already set
+                                * PF must have added it outside of table */
+                               if (igb_vfta_set(hw, vid, true))
+                                       reg |= 1 << (E1000_VLVF_POOLSEL_SHIFT +
+                                               adapter->vfs_allocated_count);
+                               reg |= E1000_VLVF_VLANID_ENABLE;
+                       }
+                       reg &= ~E1000_VLVF_VLANID_MASK;
+                       reg |= vid;
+
+                       wr32(E1000_VLVF(i), reg);
+                       return 0;
+               }
+       } else {
+               if (i < E1000_VLVF_ARRAY_SIZE) {
+                       /* remove vf from the pool */
+                       reg &= ~(1 << (E1000_VLVF_POOLSEL_SHIFT + vf));
+                       /* if pool is empty then remove entry from vfta */
+                       if (!(reg & E1000_VLVF_POOLSEL_MASK)) {
+                               reg = 0;
+                               igb_vfta_set(hw, vid, false);
+                       }
+                       wr32(E1000_VLVF(i), reg);
+                       return 0;
+               }
+       }
+       return -1;
+}
+
+static int igb_set_vf_vlan(struct igb_adapter *adapter, u32 *msgbuf, u32 vf)
+{
+       int add = (msgbuf[0] & E1000_VT_MSGINFO_MASK) >> E1000_VT_MSGINFO_SHIFT;
+       int vid = (msgbuf[1] & E1000_VLVF_VLANID_MASK);
+
+       return igb_vlvf_set(adapter, vid, add, vf);
+}
+
+static inline void igb_vf_reset_event(struct igb_adapter *adapter, u32 vf)
+{
+       struct e1000_hw *hw = &adapter->hw;
+
+       /* disable mailbox functionality for vf */
+       adapter->vf_data[vf].clear_to_send = false;
+
+       /* reset offloads to defaults */
+       igb_set_vmolr(hw, vf);
+
+       /* reset vlans for device */
+       igb_clear_vf_vfta(adapter, vf);
+
+       /* reset multicast table array for vf */
+       adapter->vf_data[vf].num_vf_mc_hashes = 0;
+
+       /* Flush and reset the mta with the new values */
+       igb_set_multi(adapter->netdev);
+}
+
+static inline void igb_vf_reset_msg(struct igb_adapter *adapter, u32 vf)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       unsigned char *vf_mac = adapter->vf_data[vf].vf_mac_addresses;
+       u32 reg, msgbuf[3];
+       u8 *addr = (u8 *)(&msgbuf[1]);
+
+       /* process all the same items cleared in a function level reset */
+       igb_vf_reset_event(adapter, vf);
+
+       /* set vf mac address */
+       igb_rar_set(hw, vf_mac, vf + 1);
+       igb_set_rah_pool(hw, vf, vf + 1);
+
+       /* enable transmit and receive for vf */
+       reg = rd32(E1000_VFTE);
+       wr32(E1000_VFTE, reg | (1 << vf));
+       reg = rd32(E1000_VFRE);
+       wr32(E1000_VFRE, reg | (1 << vf));
+
+       /* enable mailbox functionality for vf */
+       adapter->vf_data[vf].clear_to_send = true;
+
+       /* reply to reset with ack and vf mac address */
+       msgbuf[0] = E1000_VF_RESET | E1000_VT_MSGTYPE_ACK;
+       memcpy(addr, vf_mac, 6);
+       igb_write_mbx(hw, msgbuf, 3, vf);
+}
+
+static int igb_set_vf_mac_addr(struct igb_adapter *adapter, u32 *msg, int vf)
+{
+               unsigned char *addr = (char *)&msg[1];
+               int err = -1;
+
+               if (is_valid_ether_addr(addr))
+                       err = igb_set_vf_mac(adapter, vf, addr);
+
+               return err;
+
+}
+
+static void igb_rcv_ack_from_vf(struct igb_adapter *adapter, u32 vf)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 msg = E1000_VT_MSGTYPE_NACK;
+
+       /* if device isn't clear to send it shouldn't be reading either */
+       if (!adapter->vf_data[vf].clear_to_send)
+               igb_write_mbx(hw, &msg, 1, vf);
+}
+
+
+static void igb_msg_task(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 vf;
+
+       for (vf = 0; vf < adapter->vfs_allocated_count; vf++) {
+               /* process any reset requests */
+               if (!igb_check_for_rst(hw, vf)) {
+                       adapter->vf_data[vf].clear_to_send = false;
+                       igb_vf_reset_event(adapter, vf);
+               }
+
+               /* process any messages pending */
+               if (!igb_check_for_msg(hw, vf))
+                       igb_rcv_msg_from_vf(adapter, vf);
+
+               /* process any acks */
+               if (!igb_check_for_ack(hw, vf))
+                       igb_rcv_ack_from_vf(adapter, vf);
+
+       }
+}
+
+static int igb_rcv_msg_from_vf(struct igb_adapter *adapter, u32 vf)
+{
+       u32 mbx_size = E1000_VFMAILBOX_SIZE;
+       u32 msgbuf[mbx_size];
+       struct e1000_hw *hw = &adapter->hw;
+       s32 retval;
+
+       retval = igb_read_mbx(hw, msgbuf, mbx_size, vf);
+
+       if (retval)
+               dev_err(&adapter->pdev->dev,
+                       "Error receiving message from VF\n");
+
+       /* this is a message we already processed, do nothing */
+       if (msgbuf[0] & (E1000_VT_MSGTYPE_ACK | E1000_VT_MSGTYPE_NACK))
+               return retval;
+
+       /*
+        * until the vf completes a reset it should not be
+        * allowed to start any configuration.
+        */
+
+       if (msgbuf[0] == E1000_VF_RESET) {
+               igb_vf_reset_msg(adapter, vf);
+
+               return retval;
+       }
+
+       if (!adapter->vf_data[vf].clear_to_send) {
+               msgbuf[0] |= E1000_VT_MSGTYPE_NACK;
+               igb_write_mbx(hw, msgbuf, 1, vf);
+               return retval;
+       }
+
+       switch ((msgbuf[0] & 0xFFFF)) {
+       case E1000_VF_SET_MAC_ADDR:
+               retval = igb_set_vf_mac_addr(adapter, msgbuf, vf);
+               break;
+       case E1000_VF_SET_MULTICAST:
+               retval = igb_set_vf_multicasts(adapter, msgbuf, vf);
+               break;
+       case E1000_VF_SET_LPE:
+               retval = igb_set_vf_rlpml(adapter, msgbuf[1], vf);
+               break;
+       case E1000_VF_SET_VLAN:
+               retval = igb_set_vf_vlan(adapter, msgbuf, vf);
+               break;
+       default:
+               dev_err(&adapter->pdev->dev, "Unhandled Msg %08x\n", msgbuf[0]);
+               retval = -1;
+               break;
+       }
+
+       /* notify the VF of the results of what it sent us */
+       if (retval)
+               msgbuf[0] |= E1000_VT_MSGTYPE_NACK;
+       else
+               msgbuf[0] |= E1000_VT_MSGTYPE_ACK;
+
+       msgbuf[0] |= E1000_VT_MSGTYPE_CTS;
+
+       igb_write_mbx(hw, msgbuf, 1, vf);
+
+       return retval;
+}
+
 /**
  * igb_intr_msi - Interrupt Handler
  * @irq: interrupt number
@@ -3690,76 +4175,58 @@ static irqreturn_t igb_intr(int irq, void *data)
        return IRQ_HANDLED;
 }
 
-/**
- * igb_poll - NAPI Rx polling callback
- * @napi: napi polling structure
- * @budget: count of how many packets we should handle
- **/
-static int igb_poll(struct napi_struct *napi, int budget)
+static inline void igb_rx_irq_enable(struct igb_ring *rx_ring)
 {
-       struct igb_ring *rx_ring = container_of(napi, struct igb_ring, napi);
        struct igb_adapter *adapter = rx_ring->adapter;
-       struct net_device *netdev = adapter->netdev;
-       int tx_clean_complete, work_done = 0;
-
-       /* this poll routine only supports one tx and one rx queue */
-#ifdef CONFIG_IGB_DCA
-       if (adapter->flags & IGB_FLAG_DCA_ENABLED)
-               igb_update_tx_dca(&adapter->tx_ring[0]);
-#endif
-       tx_clean_complete = igb_clean_tx_irq(&adapter->tx_ring[0]);
-
-#ifdef CONFIG_IGB_DCA
-       if (adapter->flags & IGB_FLAG_DCA_ENABLED)
-               igb_update_rx_dca(&adapter->rx_ring[0]);
-#endif
-       igb_clean_rx_irq_adv(&adapter->rx_ring[0], &work_done, budget);
+       struct e1000_hw *hw = &adapter->hw;
 
-       /* If no Tx and not enough Rx work done, exit the polling mode */
-       if ((tx_clean_complete && (work_done < budget)) ||
-           !netif_running(netdev)) {
-               if (adapter->itr_setting & 3)
+       if (adapter->itr_setting & 3) {
+               if (adapter->num_rx_queues == 1)
                        igb_set_itr(adapter);
-               napi_complete(napi);
-               if (!test_bit(__IGB_DOWN, &adapter->state))
-                       igb_irq_enable(adapter);
-               return 0;
+               else
+                       igb_update_ring_itr(rx_ring);
        }
 
-       return 1;
+       if (!test_bit(__IGB_DOWN, &adapter->state)) {
+               if (adapter->msix_entries)
+                       wr32(E1000_EIMS, rx_ring->eims_value);
+               else
+                       igb_irq_enable(adapter);
+       }
 }
 
-static int igb_clean_rx_ring_msix(struct napi_struct *napi, int budget)
+/**
+ * igb_poll - NAPI Rx polling callback
+ * @napi: napi polling structure
+ * @budget: count of how many packets we should handle
+ **/
+static int igb_poll(struct napi_struct *napi, int budget)
 {
        struct igb_ring *rx_ring = container_of(napi, struct igb_ring, napi);
-       struct igb_adapter *adapter = rx_ring->adapter;
-       struct e1000_hw *hw = &adapter->hw;
-       struct net_device *netdev = adapter->netdev;
        int work_done = 0;
 
 #ifdef CONFIG_IGB_DCA
-       if (adapter->flags & IGB_FLAG_DCA_ENABLED)
+       if (rx_ring->adapter->flags & IGB_FLAG_DCA_ENABLED)
                igb_update_rx_dca(rx_ring);
 #endif
        igb_clean_rx_irq_adv(rx_ring, &work_done, budget);
 
+       if (rx_ring->buddy) {
+#ifdef CONFIG_IGB_DCA
+               if (rx_ring->adapter->flags & IGB_FLAG_DCA_ENABLED)
+                       igb_update_tx_dca(rx_ring->buddy);
+#endif
+               if (!igb_clean_tx_irq(rx_ring->buddy))
+                       work_done = budget;
+       }
+
        /* If not enough Rx work done, exit the polling mode */
-       if ((work_done == 0) || !netif_running(netdev)) {
+       if (work_done < budget) {
                napi_complete(napi);
-
-               if (adapter->itr_setting & 3) {
-                       if (adapter->num_rx_queues == 1)
-                               igb_set_itr(adapter);
-                       else
-                               igb_update_ring_itr(rx_ring);
-               }
-               if (!test_bit(__IGB_DOWN, &adapter->state))
-                       wr32(E1000_EIMS, rx_ring->eims_value);
-
-               return 0;
+               igb_rx_irq_enable(rx_ring);
        }
 
-       return 1;
+       return work_done;
 }
 
 /**
@@ -3793,9 +4260,6 @@ static void igb_tx_hwtstamp(struct igb_adapter *adapter, struct sk_buff *skb)
                                timecompare_transform(&adapter->compare, ns);
                        skb_tstamp_tx(skb, &shhwtstamps);
                }
-
-               /* delayed orphaning: skb_tstamp_tx() needs the socket */
-               skb_orphan(skb);
        }
 }
 
@@ -3856,7 +4320,7 @@ static bool igb_clean_tx_irq(struct igb_ring *tx_ring)
 
        if (unlikely(count &&
                     netif_carrier_ok(netdev) &&
-                    IGB_DESC_UNUSED(tx_ring) >= IGB_TX_QUEUE_WAKE)) {
+                    igb_desc_unused(tx_ring) >= IGB_TX_QUEUE_WAKE)) {
                /* Make sure that anybody stopping the queue after this
                 * sees the new next_to_clean.
                 */
@@ -4133,7 +4597,7 @@ next_desc:
        }
 
        rx_ring->next_to_clean = i;
-       cleaned_count = IGB_DESC_UNUSED(rx_ring);
+       cleaned_count = igb_desc_unused(rx_ring);
 
        if (cleaned_count)
                igb_alloc_rx_buffers_adv(rx_ring, cleaned_count);
@@ -4476,8 +4940,6 @@ static void igb_vlan_rx_register(struct net_device *netdev,
                rctl &= ~E1000_RCTL_CFIEN;
                wr32(E1000_RCTL, rctl);
                igb_update_mng_vlan(adapter);
-               wr32(E1000_RLPML,
-                               adapter->max_frame_size + VLAN_TAG_SIZE);
        } else {
                /* disable VLAN tag insert/strip */
                ctrl = rd32(E1000_CTRL);
@@ -4488,10 +4950,10 @@ static void igb_vlan_rx_register(struct net_device *netdev,
                        igb_vlan_rx_kill_vid(netdev, adapter->mng_vlan_id);
                        adapter->mng_vlan_id = IGB_MNG_VLAN_NONE;
                }
-               wr32(E1000_RLPML,
-                               adapter->max_frame_size);
        }
 
+       igb_rlpml_set(adapter);
+
        if (!test_bit(__IGB_DOWN, &adapter->state))
                igb_irq_enable(adapter);
 }
@@ -4500,24 +4962,25 @@ static void igb_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
 {
        struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
-       u32 vfta, index;
+       int pf_id = adapter->vfs_allocated_count;
 
        if ((hw->mng_cookie.status &
             E1000_MNG_DHCP_COOKIE_STATUS_VLAN) &&
            (vid == adapter->mng_vlan_id))
                return;
-       /* add VID to filter table */
-       index = (vid >> 5) & 0x7F;
-       vfta = array_rd32(E1000_VFTA, index);
-       vfta |= (1 << (vid & 0x1F));
-       igb_write_vfta(&adapter->hw, index, vfta);
+
+       /* add vid to vlvf if sr-iov is enabled,
+        * if that fails add directly to filter table */
+       if (igb_vlvf_set(adapter, vid, true, pf_id))
+               igb_vfta_set(hw, vid, true);
+
 }
 
 static void igb_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
 {
        struct igb_adapter *adapter = netdev_priv(netdev);
        struct e1000_hw *hw = &adapter->hw;
-       u32 vfta, index;
+       int pf_id = adapter->vfs_allocated_count;
 
        igb_irq_disable(adapter);
        vlan_group_set_device(adapter->vlgrp, vid, NULL);
@@ -4533,11 +4996,10 @@ static void igb_vlan_rx_kill_vid(struct net_device *netdev, u16 vid)
                return;
        }
 
-       /* remove VID from filter table */
-       index = (vid >> 5) & 0x7F;
-       vfta = array_rd32(E1000_VFTA, index);
-       vfta &= ~(1 << (vid & 0x1F));
-       igb_write_vfta(&adapter->hw, index, vfta);
+       /* remove vid from vlvf if sr-iov is enabled,
+        * if not in vlvf remove from vfta */
+       if (igb_vlvf_set(adapter, vid, false, pf_id))
+               igb_vfta_set(hw, vid, false);
 }
 
 static void igb_restore_vlan(struct igb_adapter *adapter)
@@ -4855,4 +5317,172 @@ static void igb_io_resume(struct pci_dev *pdev)
        igb_get_hw_control(adapter);
 }
 
+static inline void igb_set_vmolr(struct e1000_hw *hw, int vfn)
+{
+       u32 reg_data;
+
+       reg_data = rd32(E1000_VMOLR(vfn));
+       reg_data |= E1000_VMOLR_BAM |    /* Accept broadcast */
+                   E1000_VMOLR_ROPE |   /* Accept packets matched in UTA */
+                   E1000_VMOLR_ROMPE |  /* Accept packets matched in MTA */
+                   E1000_VMOLR_AUPE |   /* Accept untagged packets */
+                   E1000_VMOLR_STRVLAN; /* Strip vlan tags */
+       wr32(E1000_VMOLR(vfn), reg_data);
+}
+
+static inline int igb_set_vf_rlpml(struct igb_adapter *adapter, int size,
+                                 int vfn)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 vmolr;
+
+       vmolr = rd32(E1000_VMOLR(vfn));
+       vmolr &= ~E1000_VMOLR_RLPML_MASK;
+       vmolr |= size | E1000_VMOLR_LPE;
+       wr32(E1000_VMOLR(vfn), vmolr);
+
+       return 0;
+}
+
+static inline void igb_set_rah_pool(struct e1000_hw *hw, int pool, int entry)
+{
+       u32 reg_data;
+
+       reg_data = rd32(E1000_RAH(entry));
+       reg_data &= ~E1000_RAH_POOL_MASK;
+       reg_data |= E1000_RAH_POOL_1 << pool;;
+       wr32(E1000_RAH(entry), reg_data);
+}
+
+static void igb_set_mc_list_pools(struct igb_adapter *adapter,
+                                 int entry_count, u16 total_rar_filters)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       int i = adapter->vfs_allocated_count + 1;
+
+       if ((i + entry_count) < total_rar_filters)
+               total_rar_filters = i + entry_count;
+
+       for (; i < total_rar_filters; i++)
+               igb_set_rah_pool(hw, adapter->vfs_allocated_count, i);
+}
+
+static int igb_set_vf_mac(struct igb_adapter *adapter,
+                          int vf, unsigned char *mac_addr)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       int rar_entry = vf + 1; /* VF MAC addresses start at entry 1 */
+
+       igb_rar_set(hw, mac_addr, rar_entry);
+
+       memcpy(adapter->vf_data[vf].vf_mac_addresses, mac_addr, ETH_ALEN);
+
+       igb_set_rah_pool(hw, vf, rar_entry);
+
+       return 0;
+}
+
+static void igb_vmm_control(struct igb_adapter *adapter)
+{
+       struct e1000_hw *hw = &adapter->hw;
+       u32 reg_data;
+
+       if (!adapter->vfs_allocated_count)
+               return;
+
+       /* VF's need PF reset indication before they
+        * can send/receive mail */
+       reg_data = rd32(E1000_CTRL_EXT);
+       reg_data |= E1000_CTRL_EXT_PFRSTD;
+       wr32(E1000_CTRL_EXT, reg_data);
+
+       igb_vmdq_set_loopback_pf(hw, true);
+       igb_vmdq_set_replication_pf(hw, true);
+}
+
+#ifdef CONFIG_PCI_IOV
+static ssize_t igb_show_num_vfs(struct device *dev,
+                                struct device_attribute *attr, char *buf)
+{
+       struct igb_adapter *adapter = netdev_priv(to_net_dev(dev));
+
+       return sprintf(buf, "%d\n", adapter->vfs_allocated_count);
+}
+
+static ssize_t igb_set_num_vfs(struct device *dev,
+                               struct device_attribute *attr,
+                               const char *buf, size_t count)
+{
+       struct net_device *netdev = to_net_dev(dev);
+       struct igb_adapter *adapter = netdev_priv(netdev);
+       struct e1000_hw *hw = &adapter->hw;
+       struct pci_dev *pdev = adapter->pdev;
+       unsigned int num_vfs, i;
+       unsigned char mac_addr[ETH_ALEN];
+       int err;
+
+       sscanf(buf, "%u", &num_vfs);
+
+       if (num_vfs > 7)
+               num_vfs = 7;
+
+       /* value unchanged do nothing */
+       if (num_vfs == adapter->vfs_allocated_count)
+               return count;
+
+       if (netdev->flags & IFF_UP)
+               igb_close(netdev);
+
+       igb_reset_interrupt_capability(adapter);
+       igb_free_queues(adapter);
+       adapter->tx_ring = NULL;
+       adapter->rx_ring = NULL;
+       adapter->vfs_allocated_count = 0;
+
+       /* reclaim resources allocated to VFs since we are changing count */
+       if (adapter->vf_data) {
+               /* disable iov and allow time for transactions to clear */
+               pci_disable_sriov(pdev);
+               msleep(500);
+
+               kfree(adapter->vf_data);
+               adapter->vf_data = NULL;
+               wr32(E1000_IOVCTL, E1000_IOVCTL_REUSE_VFQ);
+               msleep(100);
+               dev_info(&pdev->dev, "IOV Disabled\n");
+       }
+
+       if (num_vfs) {
+               adapter->vf_data = kcalloc(num_vfs,
+                                          sizeof(struct vf_data_storage),
+                                          GFP_KERNEL);
+               if (!adapter->vf_data) {
+                       dev_err(&pdev->dev, "Could not allocate VF private "
+                               "data - IOV enable failed\n");
+               } else {
+                       err = pci_enable_sriov(pdev, num_vfs);
+                       if (!err) {
+                               adapter->vfs_allocated_count = num_vfs;
+                               dev_info(&pdev->dev, "%d vfs allocated\n", num_vfs);
+                               for (i = 0; i < adapter->vfs_allocated_count; i++) {
+                                       random_ether_addr(mac_addr);
+                                       igb_set_vf_mac(adapter, i, mac_addr);
+                               }
+                       } else {
+                               kfree(adapter->vf_data);
+                               adapter->vf_data = NULL;
+                       }
+               }
+       }
+
+       igb_set_interrupt_capability(adapter);
+       igb_alloc_queues(adapter);
+       igb_reset(adapter);
+
+       if (netdev->flags & IFF_UP)
+               igb_open(netdev);
+
+       return count;
+}
+#endif /* CONFIG_PCI_IOV */
 /* igb_main.c */
index 17779f9bffc4544b5fea9c84e4c6982041575ad3..ad179558002803e2f7af704d8f9bef9ade4a9bfe 100644 (file)
@@ -259,6 +259,20 @@ static void __exit ali_ircc_cleanup(void)
        IRDA_DEBUG(2, "%s(), ----------------- End -----------------\n", __func__);
 }
 
+static const struct net_device_ops ali_ircc_sir_ops = {
+       .ndo_open       = ali_ircc_net_open,
+       .ndo_stop       = ali_ircc_net_close,
+       .ndo_start_xmit = ali_ircc_sir_hard_xmit,
+       .ndo_do_ioctl   = ali_ircc_net_ioctl,
+};
+
+static const struct net_device_ops ali_ircc_fir_ops = {
+       .ndo_open       = ali_ircc_net_open,
+       .ndo_stop       = ali_ircc_net_close,
+       .ndo_start_xmit = ali_ircc_fir_hard_xmit,
+       .ndo_do_ioctl   = ali_ircc_net_ioctl,
+};
+
 /*
  * Function ali_ircc_open (int i, chipio_t *inf)
  *
@@ -361,10 +375,7 @@ static int ali_ircc_open(int i, chipio_t *info)
        self->tx_fifo.tail = self->tx_buff.head;
 
        /* Override the network functions we need to use */
-       dev->hard_start_xmit = ali_ircc_sir_hard_xmit;
-       dev->open            = ali_ircc_net_open;
-       dev->stop            = ali_ircc_net_close;
-       dev->do_ioctl        = ali_ircc_net_ioctl;
+       dev->netdev_ops = &ali_ircc_sir_ops;
 
        err = register_netdev(dev);
        if (err) {
@@ -974,7 +985,7 @@ static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud)
                ali_ircc_fir_change_speed(self, baud);                  
                
                /* Install FIR xmit handler*/
-               dev->hard_start_xmit = ali_ircc_fir_hard_xmit;          
+               dev->netdev_ops = &ali_ircc_fir_ops;
                                
                /* Enable Interuupt */
                self->ier = IER_EOM; // benjamin 2000/11/20 07:24PM                                     
@@ -988,7 +999,7 @@ static void ali_ircc_change_speed(struct ali_ircc_cb *self, __u32 baud)
                ali_ircc_sir_change_speed(self, baud);
                                
                /* Install SIR xmit handler*/
-               dev->hard_start_xmit = ali_ircc_sir_hard_xmit;
+               dev->netdev_ops = &ali_ircc_sir_ops;
        }
        
                
index 3a22dc41b656f02ec97281e751dd1dc0a38786fb..006ba23110dbb0e9247c1f841dd9fc9c0bb502f9 100644 (file)
@@ -1401,6 +1401,14 @@ static inline void irda_usb_init_qos(struct irda_usb_cb *self)
 }
 
 /*------------------------------------------------------------------*/
+static const struct net_device_ops irda_usb_netdev_ops = {
+       .ndo_open       = irda_usb_net_open,
+       .ndo_stop       = irda_usb_net_close,
+       .ndo_do_ioctl   = irda_usb_net_ioctl,
+       .ndo_start_xmit = irda_usb_hard_xmit,
+       .ndo_tx_timeout = irda_usb_net_timeout,
+};
+
 /*
  * Initialise the network side of the irda-usb instance
  * Called when a new USB instance is registered in irda_usb_probe()
@@ -1411,15 +1419,9 @@ static inline int irda_usb_open(struct irda_usb_cb *self)
 
        IRDA_DEBUG(1, "%s()\n", __func__);
 
-       irda_usb_init_qos(self);
+       netdev->netdev_ops = &irda_usb_netdev_ops;
 
-       /* Override the network functions we need to use */
-       netdev->hard_start_xmit = irda_usb_hard_xmit;
-       netdev->tx_timeout      = irda_usb_net_timeout;
-       netdev->watchdog_timeo  = 250*HZ/1000;  /* 250 ms > USB timeout */
-       netdev->open            = irda_usb_net_open;
-       netdev->stop            = irda_usb_net_close;
-       netdev->do_ioctl        = irda_usb_net_ioctl;
+       irda_usb_init_qos(self);
 
        return register_netdev(netdev);
 }
index b4a61717254aca54553bb96d14135a7a1ae95c31..9d813bc4502e721890aa59e1fc632ad7a383fbfc 100644 (file)
@@ -418,6 +418,12 @@ static int kingsun_net_ioctl(struct net_device *netdev, struct ifreq *rq,
        return ret;
 }
 
+static const struct net_device_ops kingsun_ops = {
+       .ndo_start_xmit = kingsun_hard_xmit,
+       .ndo_open            = kingsun_net_open,
+       .ndo_stop            = kingsun_net_close,
+       .ndo_do_ioctl        = kingsun_net_ioctl,
+};
 
 /*
  * This routine is called by the USB subsystem for each new device
@@ -520,10 +526,7 @@ static int kingsun_probe(struct usb_interface *intf,
        irda_qos_bits_to_value(&kingsun->qos);
 
        /* Override the network functions we need to use */
-       net->hard_start_xmit = kingsun_hard_xmit;
-       net->open            = kingsun_net_open;
-       net->stop            = kingsun_net_close;
-       net->do_ioctl        = kingsun_net_ioctl;
+       net->netdev_ops = &kingsun_ops;
 
        ret = register_netdev(net);
        if (ret != 0)
index 55322fb92cf1c36508bb7f9a0ba68e5f7a234cbd..b6ffe9715b61d5ef974fb7cf20c402efb848b3ff 100644 (file)
@@ -668,6 +668,12 @@ static int ks959_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
        return ret;
 }
 
+static const struct net_device_ops ks959_ops = {
+       .ndo_start_xmit = ks959_hard_xmit,
+       .ndo_open       = ks959_net_open,
+       .ndo_stop       = ks959_net_close,
+       .ndo_do_ioctl   = ks959_net_ioctl,
+};
 /*
  * This routine is called by the USB subsystem for each new device
  * in the system. We need to check if the device is ours, and in
@@ -780,10 +786,7 @@ static int ks959_probe(struct usb_interface *intf,
        irda_qos_bits_to_value(&kingsun->qos);
 
        /* Override the network functions we need to use */
-       net->hard_start_xmit = ks959_hard_xmit;
-       net->open = ks959_net_open;
-       net->stop = ks959_net_close;
-       net->do_ioctl = ks959_net_ioctl;
+       net->netdev_ops = &ks959_ops;
 
        ret = register_netdev(net);
        if (ret != 0)
index 5b327b09acd83bc21cd4634c78be9cc9d916d13a..64df27f2bfd469cb2568312ddbd5e9ef028280e7 100644 (file)
@@ -562,6 +562,13 @@ static int ksdazzle_net_ioctl(struct net_device *netdev, struct ifreq *rq,
        return ret;
 }
 
+static const struct net_device_ops ksdazzle_ops = {
+       .ndo_start_xmit = ksdazzle_hard_xmit,
+       .ndo_open       = ksdazzle_net_open,
+       .ndo_stop       = ksdazzle_net_close,
+       .ndo_do_ioctl   = ksdazzle_net_ioctl,
+};
+
 /*
  * This routine is called by the USB subsystem for each new device
  * in the system. We need to check if the device is ours, and in
@@ -684,10 +691,7 @@ static int ksdazzle_probe(struct usb_interface *intf,
        irda_qos_bits_to_value(&kingsun->qos);
 
        /* Override the network functions we need to use */
-       net->hard_start_xmit = ksdazzle_hard_xmit;
-       net->open = ksdazzle_net_open;
-       net->stop = ksdazzle_net_close;
-       net->do_ioctl = ksdazzle_net_ioctl;
+       net->netdev_ops = &ksdazzle_ops;
 
        ret = register_netdev(net);
        if (ret != 0)
index 85e88daab21a1f326952c6486694771a3dcbe43f..fac504d0cfd86d46f84ad94a880bc689bf122676 100644 (file)
@@ -873,6 +873,13 @@ static int mcs_hard_xmit(struct sk_buff *skb, struct net_device *ndev)
        return ret;
 }
 
+static const struct net_device_ops mcs_netdev_ops = {
+       .ndo_open = mcs_net_open,
+       .ndo_stop = mcs_net_close,
+       .ndo_start_xmit = mcs_hard_xmit,
+       .ndo_do_ioctl = mcs_net_ioctl,
+};
+
 /*
  * This function is called by the USB subsystem for each new device in the
  * system.  Need to verify the device and if it is, then start handling it.
@@ -919,11 +926,7 @@ static int mcs_probe(struct usb_interface *intf,
        /* Speed change work initialisation*/
        INIT_WORK(&mcs->work, mcs_speed_work);
 
-       /* Override the network functions we need to use */
-       ndev->hard_start_xmit = mcs_hard_xmit;
-       ndev->open = mcs_net_open;
-       ndev->stop = mcs_net_close;
-       ndev->do_ioctl = mcs_net_ioctl;
+       ndev->netdev_ops = &mcs_netdev_ops;
 
        if (!intf->cur_altsetting)
                goto error2;
index 61e509cb712ab1a63b1e9655fb18a2c422c7d3f2..45fd9c1eb34333499e2a3ead01c334b196c1a535 100644 (file)
@@ -331,6 +331,20 @@ static void __exit nsc_ircc_cleanup(void)
        pnp_registered = 0;
 }
 
+static const struct net_device_ops nsc_ircc_sir_ops = {
+       .ndo_open       = nsc_ircc_net_open,
+       .ndo_stop       = nsc_ircc_net_close,
+       .ndo_start_xmit = nsc_ircc_hard_xmit_sir,
+       .ndo_do_ioctl   = nsc_ircc_net_ioctl,
+};
+
+static const struct net_device_ops nsc_ircc_fir_ops = {
+       .ndo_open       = nsc_ircc_net_open,
+       .ndo_stop       = nsc_ircc_net_close,
+       .ndo_start_xmit = nsc_ircc_hard_xmit_fir,
+       .ndo_do_ioctl   = nsc_ircc_net_ioctl,
+};
+
 /*
  * Function nsc_ircc_open (iobase, irq)
  *
@@ -441,10 +455,7 @@ static int __init nsc_ircc_open(chipio_t *info)
        self->tx_fifo.tail = self->tx_buff.head;
 
        /* Override the network functions we need to use */
-       dev->hard_start_xmit = nsc_ircc_hard_xmit_sir;
-       dev->open            = nsc_ircc_net_open;
-       dev->stop            = nsc_ircc_net_close;
-       dev->do_ioctl        = nsc_ircc_net_ioctl;
+       dev->netdev_ops = &nsc_ircc_sir_ops;
 
        err = register_netdev(dev);
        if (err) {
@@ -1320,12 +1331,12 @@ static __u8 nsc_ircc_change_speed(struct nsc_ircc_cb *self, __u32 speed)
        switch_bank(iobase, BANK0); 
        if (speed > 115200) {
                /* Install FIR xmit handler */
-               dev->hard_start_xmit = nsc_ircc_hard_xmit_fir;
+               dev->netdev_ops = &nsc_ircc_fir_ops;
                ier = IER_SFIF_IE;
                nsc_ircc_dma_receive(self);
        } else {
                /* Install SIR xmit handler */
-               dev->hard_start_xmit = nsc_ircc_hard_xmit_sir;
+               dev->netdev_ops = &nsc_ircc_sir_ops;
                ier = IER_RXHDL_IE;
        }
        /* Set our current interrupt mask */
index c23d211758ae9480ae34a3e2a72d96cffa337a62..d940809762eca2bafa6c2966e4fc1b717b863d20 100644 (file)
@@ -780,8 +780,7 @@ static int sirdev_alloc_buffers(struct sir_dev *dev)
 
 static void sirdev_free_buffers(struct sir_dev *dev)
 {
-       if (dev->rx_buff.skb)
-               kfree_skb(dev->rx_buff.skb);
+       kfree_skb(dev->rx_buff.skb);
        kfree(dev->tx_buff.head);
        dev->rx_buff.head = dev->tx_buff.head = NULL;
        dev->rx_buff.skb = NULL;
@@ -866,6 +865,12 @@ out:
        return 0;
 }
 
+static const struct net_device_ops sirdev_ops = {
+       .ndo_start_xmit = sirdev_hard_xmit,
+       .ndo_open       = sirdev_open,
+       .ndo_stop       = sirdev_close,
+       .ndo_do_ioctl   = sirdev_ioctl,
+};
 /* ----------------------------------------------------------------------------- */
 
 struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *name)
@@ -909,10 +914,7 @@ struct sir_dev * sirdev_get_instance(const struct sir_driver *drv, const char *n
        dev->netdev = ndev;
 
        /* Override the network functions we need to use */
-       ndev->hard_start_xmit = sirdev_hard_xmit;
-       ndev->open = sirdev_open;
-       ndev->stop = sirdev_close;
-       ndev->do_ioctl = sirdev_ioctl;
+       ndev->netdev_ops = &sirdev_ops;
 
        if (register_netdev(ndev)) {
                IRDA_ERROR("%s(), register_netdev() failed!\n", __func__);
index dd73cce10991b10f07058a9e68464cd827419f2e..59d79807b4d506e4bdca343b8cab1e6fa771d478 100644 (file)
@@ -486,6 +486,26 @@ static int __init smsc_ircc_init(void)
        return ret;
 }
 
+static int smsc_ircc_net_xmit(struct sk_buff *skb, struct net_device *dev)
+{
+       struct smsc_ircc_cb *self = netdev_priv(dev);
+
+       if (self->io.speed > 115200)
+               return  smsc_ircc_hard_xmit_fir(skb, dev);
+       else
+               return  smsc_ircc_hard_xmit_sir(skb, dev);
+}
+
+static const struct net_device_ops smsc_ircc_netdev_ops = {
+       .ndo_open       = smsc_ircc_net_open,
+       .ndo_stop       = smsc_ircc_net_close,
+       .ndo_do_ioctl   = smsc_ircc_net_ioctl,
+       .ndo_start_xmit = smsc_ircc_net_xmit,
+#if SMSC_IRCC2_C_NET_TIMEOUT
+       .ndo_tx_timeout = smsc_ircc_timeout,
+#endif
+};
+
 /*
  * Function smsc_ircc_open (firbase, sirbase, dma, irq)
  *
@@ -519,14 +539,10 @@ static int __init smsc_ircc_open(unsigned int fir_base, unsigned int sir_base, u
                goto err_out1;
        }
 
-       dev->hard_start_xmit = smsc_ircc_hard_xmit_sir;
 #if SMSC_IRCC2_C_NET_TIMEOUT
-       dev->tx_timeout      = smsc_ircc_timeout;
        dev->watchdog_timeo  = HZ * 2;  /* Allow enough time for speed change */
 #endif
-       dev->open            = smsc_ircc_net_open;
-       dev->stop            = smsc_ircc_net_close;
-       dev->do_ioctl        = smsc_ircc_net_ioctl;
+       dev->netdev_ops = &smsc_ircc_netdev_ops;
 
        self = netdev_priv(dev);
        self->netdev = dev;
@@ -995,9 +1011,6 @@ static void smsc_ircc_fir_start(struct smsc_ircc_cb *self)
 
        /* Reset everything */
 
-       /* Install FIR transmit handler */
-       dev->hard_start_xmit = smsc_ircc_hard_xmit_fir;
-
        /* Clear FIFO */
        outb(inb(fir_base + IRCC_LCR_A) | IRCC_LCR_A_FIFO_RESET, fir_base + IRCC_LCR_A);
 
@@ -1894,7 +1907,6 @@ static void smsc_ircc_sir_start(struct smsc_ircc_cb *self)
        IRDA_ASSERT(self != NULL, return;);
        dev = self->netdev;
        IRDA_ASSERT(dev != NULL, return;);
-       dev->hard_start_xmit = &smsc_ircc_hard_xmit_sir;
 
        fir_base = self->io.fir_base;
        sir_base = self->io.sir_base;
index 8b1658c6c925a61eaff005d44907446c9662256f..8e5e45caf2f10fb41d2aa152350f6ade03177ba2 100644 (file)
@@ -1007,6 +1007,13 @@ static int stir_net_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
        return ret;
 }
 
+static const struct net_device_ops stir_netdev_ops = {
+       .ndo_open       = stir_net_open,
+       .ndo_stop       = stir_net_close,
+       .ndo_start_xmit = stir_hard_xmit,
+       .ndo_do_ioctl   = stir_net_ioctl,
+};
+
 /*
  * This routine is called by the USB subsystem for each new device
  * in the system. We need to check if the device is ours, and in
@@ -1054,10 +1061,7 @@ static int stir_probe(struct usb_interface *intf,
        irda_qos_bits_to_value(&stir->qos);
 
        /* Override the network functions we need to use */
-       net->hard_start_xmit = stir_hard_xmit;
-       net->open            = stir_net_open;
-       net->stop            = stir_net_close;
-       net->do_ioctl        = stir_net_ioctl;
+       net->netdev_ops = &stir_netdev_ops;
 
        ret = register_netdev(net);
        if (ret != 0)
index 8b3e545924ccd696d7593a12531d7665301e2439..864798502ff9ea6d686cb128239673f2b1c4ef1b 100644 (file)
@@ -310,6 +310,19 @@ static void __exit via_ircc_cleanup(void)
        pci_unregister_driver (&via_driver); 
 }
 
+static const struct net_device_ops via_ircc_sir_ops = {
+       .ndo_start_xmit = via_ircc_hard_xmit_sir,
+       .ndo_open = via_ircc_net_open,
+       .ndo_stop = via_ircc_net_close,
+       .ndo_do_ioctl = via_ircc_net_ioctl,
+};
+static const struct net_device_ops via_ircc_fir_ops = {
+       .ndo_start_xmit = via_ircc_hard_xmit_fir,
+       .ndo_open = via_ircc_net_open,
+       .ndo_stop = via_ircc_net_close,
+       .ndo_do_ioctl = via_ircc_net_ioctl,
+};
+
 /*
  * Function via_ircc_open (iobase, irq)
  *
@@ -428,10 +441,7 @@ static __devinit int via_ircc_open(int i, chipio_t * info, unsigned int id)
        self->tx_fifo.tail = self->tx_buff.head;
 
        /* Override the network functions we need to use */
-       dev->hard_start_xmit = via_ircc_hard_xmit_sir;
-       dev->open = via_ircc_net_open;
-       dev->stop = via_ircc_net_close;
-       dev->do_ioctl = via_ircc_net_ioctl;
+       dev->netdev_ops = &via_ircc_sir_ops;
 
        err = register_netdev(dev);
        if (err)
@@ -798,11 +808,11 @@ static void via_ircc_change_speed(struct via_ircc_cb *self, __u32 speed)
 
        if (speed > 115200) {
                /* Install FIR xmit handler */
-               dev->hard_start_xmit = via_ircc_hard_xmit_fir;
+               dev->netdev_ops = &via_ircc_fir_ops;
                via_ircc_dma_receive(self);
        } else {
                /* Install SIR xmit handler */
-               dev->hard_start_xmit = via_ircc_hard_xmit_sir;
+               dev->netdev_ops = &via_ircc_sir_ops;
        }
        netif_wake_queue(dev);
 }
index 723c4588c803860d49b4dd807e021b4ab64c2dd0..1243bc8e0035877dd2edf703b96edfbacdaaa54b 100644 (file)
@@ -1573,6 +1573,14 @@ static int vlsi_close(struct net_device *ndev)
        return 0;
 }
 
+static const struct net_device_ops vlsi_netdev_ops = {
+       .ndo_open       = vlsi_open,
+       .ndo_stop       = vlsi_close,
+       .ndo_start_xmit = vlsi_hard_start_xmit,
+       .ndo_do_ioctl   = vlsi_ioctl,
+       .ndo_tx_timeout = vlsi_tx_timeout,
+};
+
 static int vlsi_irda_init(struct net_device *ndev)
 {
        vlsi_irda_dev_t *idev = netdev_priv(ndev);
@@ -1608,11 +1616,7 @@ static int vlsi_irda_init(struct net_device *ndev)
        ndev->flags |= IFF_PORTSEL | IFF_AUTOMEDIA;
        ndev->if_port = IF_PORT_UNKNOWN;
  
-       ndev->open            = vlsi_open;
-       ndev->stop            = vlsi_close;
-       ndev->hard_start_xmit = vlsi_hard_start_xmit;
-       ndev->do_ioctl        = vlsi_ioctl;
-       ndev->tx_timeout      = vlsi_tx_timeout;
+       ndev->netdev_ops = &vlsi_netdev_ops;
        ndev->watchdog_timeo  = 500*HZ/1000;    /* max. allowed turn time for IrLAP */
 
        SET_NETDEV_DEV(ndev, &pdev->dev);
index dc0a2e4d830f60c7f7b813785a5103b0e5d06bee..d0883835b0c6e0a179ac8107daaba9e6c204771f 100644 (file)
@@ -140,6 +140,13 @@ static void __exit w83977af_cleanup(void)
        }
 }
 
+static const struct net_device_ops w83977_netdev_ops = {
+       .ndo_open       = w83977af_net_open,
+       .ndo_stop       = w83977af_net_close,
+       .ndo_start_xmit = w83977af_hard_xmit,
+       .ndo_do_ioctl   = w83977af_net_ioctl,
+};
+
 /*
  * Function w83977af_open (iobase, irq)
  *
@@ -231,11 +238,7 @@ static int w83977af_open(int i, unsigned int iobase, unsigned int irq,
        self->rx_buff.data = self->rx_buff.head;
        self->netdev = dev;
 
-       /* Override the network functions we need to use */
-       dev->hard_start_xmit = w83977af_hard_xmit;
-       dev->open            = w83977af_net_open;
-       dev->stop            = w83977af_net_close;
-       dev->do_ioctl        = w83977af_net_ioctl;
+       dev->netdev_ops = &w83977_netdev_ops;
 
        err = register_netdev(dev);
        if (err) {
index e2ef16b29700ed0c0d81e258338c978f5f65f1b5..4b0ea66d7a445e4345db9575745778acf9ce67bf 100644 (file)
@@ -887,19 +887,13 @@ static void
 ixgb_unmap_and_free_tx_resource(struct ixgb_adapter *adapter,
                                 struct ixgb_buffer *buffer_info)
 {
-       struct pci_dev *pdev = adapter->pdev;
-
-       if (buffer_info->dma)
-               pci_unmap_page(pdev, buffer_info->dma, buffer_info->length,
-                              PCI_DMA_TODEVICE);
-
-       /* okay to call kfree_skb here instead of kfree_skb_any because
-        * this is never called in interrupt context */
-       if (buffer_info->skb)
-               dev_kfree_skb(buffer_info->skb);
-
-       buffer_info->skb = NULL;
        buffer_info->dma = 0;
+       if (buffer_info->skb) {
+               skb_dma_unmap(&adapter->pdev->dev, buffer_info->skb,
+                             DMA_TO_DEVICE);
+               dev_kfree_skb_any(buffer_info->skb);
+               buffer_info->skb = NULL;
+       }
        buffer_info->time_stamp = 0;
        /* these fields must always be initialized in tx
         * buffer_info->length = 0;
@@ -1275,17 +1269,23 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
 {
        struct ixgb_desc_ring *tx_ring = &adapter->tx_ring;
        struct ixgb_buffer *buffer_info;
-       int len = skb->len;
+       int len = skb_headlen(skb);
        unsigned int offset = 0, size, count = 0, i;
        unsigned int mss = skb_shinfo(skb)->gso_size;
 
        unsigned int nr_frags = skb_shinfo(skb)->nr_frags;
        unsigned int f;
-
-       len -= skb->data_len;
+       dma_addr_t *map;
 
        i = tx_ring->next_to_use;
 
+       if (skb_dma_map(&adapter->pdev->dev, skb, DMA_TO_DEVICE)) {
+               dev_err(&adapter->pdev->dev, "TX DMA map failed\n");
+               return 0;
+       }
+
+       map = skb_shinfo(skb)->dma_maps;
+
        while (len) {
                buffer_info = &tx_ring->buffer_info[i];
                size = min(len, IXGB_MAX_DATA_PER_TXD);
@@ -1297,7 +1297,7 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
                buffer_info->length = size;
                WARN_ON(buffer_info->dma != 0);
                buffer_info->time_stamp = jiffies;
-               buffer_info->dma =
+               buffer_info->dma = map[0] + offset;
                        pci_map_single(adapter->pdev,
                                skb->data + offset,
                                size,
@@ -1307,7 +1307,11 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
                len -= size;
                offset += size;
                count++;
-               if (++i == tx_ring->count) i = 0;
+               if (len) {
+                       i++;
+                       if (i == tx_ring->count)
+                               i = 0;
+               }
        }
 
        for (f = 0; f < nr_frags; f++) {
@@ -1318,6 +1322,10 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
                offset = 0;
 
                while (len) {
+                       i++;
+                       if (i == tx_ring->count)
+                               i = 0;
+
                        buffer_info = &tx_ring->buffer_info[i];
                        size = min(len, IXGB_MAX_DATA_PER_TXD);
 
@@ -1329,21 +1337,14 @@ ixgb_tx_map(struct ixgb_adapter *adapter, struct sk_buff *skb,
 
                        buffer_info->length = size;
                        buffer_info->time_stamp = jiffies;
-                       buffer_info->dma =
-                               pci_map_page(adapter->pdev,
-                                       frag->page,
-                                       frag->page_offset + offset,
-                                       size,
-                                       PCI_DMA_TODEVICE);
+                       buffer_info->dma = map[f + 1] + offset;
                        buffer_info->next_to_watch = 0;
 
                        len -= size;
                        offset += size;
                        count++;
-                       if (++i == tx_ring->count) i = 0;
                }
        }
-       i = (i == 0) ? tx_ring->count - 1 : i - 1;
        tx_ring->buffer_info[i].skb = skb;
        tx_ring->buffer_info[first].next_to_watch = i;
 
@@ -1445,6 +1446,7 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        unsigned int first;
        unsigned int tx_flags = 0;
        int vlan_id = 0;
+       int count = 0;
        int tso;
 
        if (test_bit(__IXGB_DOWN, &adapter->flags)) {
@@ -1479,13 +1481,19 @@ ixgb_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        else if (ixgb_tx_csum(adapter, skb))
                tx_flags |= IXGB_TX_FLAGS_CSUM;
 
-       ixgb_tx_queue(adapter, ixgb_tx_map(adapter, skb, first), vlan_id,
-                       tx_flags);
+       count = ixgb_tx_map(adapter, skb, first);
 
-       netdev->trans_start = jiffies;
+       if (count) {
+               ixgb_tx_queue(adapter, count, vlan_id, tx_flags);
+               netdev->trans_start = jiffies;
+               /* Make sure there is space in the ring for the next send. */
+               ixgb_maybe_stop_tx(netdev, &adapter->tx_ring, DESC_NEEDED);
 
-       /* Make sure there is space in the ring for the next send. */
-       ixgb_maybe_stop_tx(netdev, &adapter->tx_ring, DESC_NEEDED);
+       } else {
+               dev_kfree_skb_any(skb);
+               adapter->tx_ring.buffer_info[first].time_stamp = 0;
+               adapter->tx_ring.next_to_use = first;
+       }
 
        return NETDEV_TX_OK;
 }
@@ -1818,7 +1826,7 @@ ixgb_clean_tx_irq(struct ixgb_adapter *adapter)
                /* detect a transmit hang in hardware, this serializes the
                 * check with the clearing of time_stamp and movement of i */
                adapter->detect_tx_hung = false;
-               if (tx_ring->buffer_info[eop].dma &&
+               if (tx_ring->buffer_info[eop].time_stamp &&
                   time_after(jiffies, tx_ring->buffer_info[eop].time_stamp + HZ)
                   && !(IXGB_READ_REG(&adapter->hw, STATUS) &
                        IXGB_STATUS_TXOFF)) {
index f6061950f5d124b8fd4b128512f4b94a3129abd9..b3f8208ec7bec21288df1c5b548d895af6ec3b40 100644 (file)
@@ -33,6 +33,7 @@
 obj-$(CONFIG_IXGBE) += ixgbe.o
 
 ixgbe-objs := ixgbe_main.o ixgbe_common.o ixgbe_ethtool.o \
-              ixgbe_82598.o ixgbe_phy.o
+              ixgbe_82599.o ixgbe_82598.o ixgbe_phy.o
 
-ixgbe-$(CONFIG_IXGBE_DCB) +=  ixgbe_dcb.o ixgbe_dcb_82598.o ixgbe_dcb_nl.o
+ixgbe-$(CONFIG_IXGBE_DCB) +=  ixgbe_dcb.o ixgbe_dcb_82598.o \
+                              ixgbe_dcb_82599.o ixgbe_dcb_nl.o
index e98ace8c578dfa37c67ddc56c7585bf8cf80770b..c26433d14605d9fd74fafc996f69065cbca75524 100644 (file)
@@ -71,6 +71,7 @@
 #define IXGBE_RXBUFFER_128   128    /* Used for packet split */
 #define IXGBE_RXBUFFER_256   256    /* Used for packet split */
 #define IXGBE_RXBUFFER_2048  2048
+#define IXGBE_MAX_RXBUFFER   16384  /* largest size for a single descriptor */
 
 #define IXGBE_RX_HDR_SIZE IXGBE_RXBUFFER_256
 
@@ -139,18 +140,24 @@ struct ixgbe_ring {
        int cpu;
 #endif
        struct ixgbe_queue_stats stats;
-       u16 v_idx; /* maps directly to the index for this ring in the hardware
-                  * vector array, can also be used for finding the bit in EICR
-                  * and friends that represents the vector for this ring */
+       u64 v_idx; /* maps directly to the index for this ring in the hardware
+                   * vector array, can also be used for finding the bit in EICR
+                   * and friends that represents the vector for this ring */
 
 
        u16 work_limit;                /* max work per interrupt */
        u16 rx_buf_len;
 };
 
-#define RING_F_DCB  0
-#define RING_F_VMDQ 1
-#define RING_F_RSS  2
+enum ixgbe_ring_f_enum {
+       RING_F_NONE = 0,
+       RING_F_DCB,
+       RING_F_VMDQ,
+       RING_F_RSS,
+
+       RING_F_ARRAY_SIZE      /* must be last in enum set */
+};
+
 #define IXGBE_MAX_DCB_INDICES   8
 #define IXGBE_MAX_RSS_INDICES  16
 #define IXGBE_MAX_VMDQ_INDICES 16
@@ -159,8 +166,8 @@ struct ixgbe_ring_feature {
        int mask;
 };
 
-#define MAX_RX_QUEUES 64
-#define MAX_TX_QUEUES 32
+#define MAX_RX_QUEUES 128
+#define MAX_TX_QUEUES 128
 
 #define MAX_RX_PACKET_BUFFERS ((adapter->flags & IXGBE_FLAG_DCB_ENABLED) \
                               ? 8 : 1)
@@ -182,10 +189,11 @@ struct ixgbe_q_vector {
 };
 
 /* Helper macros to switch between ints/sec and what the register uses.
- * And yes, it's the same math going both ways.
+ * And yes, it's the same math going both ways.  The lowest value
+ * supported by all of the ixgbe hardware is 8.
  */
 #define EITR_INTS_PER_SEC_TO_REG(_eitr) \
-       ((_eitr) ? (1000000000 / ((_eitr) * 256)) : 0)
+       ((_eitr) ? (1000000000 / ((_eitr) * 256)) : 8)
 #define EITR_REG_TO_INTS_PER_SEC EITR_INTS_PER_SEC_TO_REG
 
 #define IXGBE_DESC_UNUSED(R) \
@@ -204,11 +212,13 @@ struct ixgbe_q_vector {
 #define OTHER_VECTOR 1
 #define NON_Q_VECTORS (OTHER_VECTOR)
 
+#define MAX_MSIX_VECTORS_82599 64
+#define MAX_MSIX_Q_VECTORS_82599 64
 #define MAX_MSIX_VECTORS_82598 18
 #define MAX_MSIX_Q_VECTORS_82598 16
 
-#define MAX_MSIX_Q_VECTORS MAX_MSIX_Q_VECTORS_82598
-#define MAX_MSIX_COUNT MAX_MSIX_VECTORS_82598
+#define MAX_MSIX_Q_VECTORS MAX_MSIX_Q_VECTORS_82599
+#define MAX_MSIX_COUNT MAX_MSIX_VECTORS_82599
 
 #define MIN_MSIX_Q_VECTORS 2
 #define MIN_MSIX_COUNT (MIN_MSIX_Q_VECTORS + NON_Q_VECTORS)
@@ -220,7 +230,7 @@ struct ixgbe_adapter {
        u16 bd_number;
        struct work_struct reset_task;
        struct ixgbe_q_vector q_vector[MAX_MSIX_Q_VECTORS];
-       char name[MAX_MSIX_COUNT][IFNAMSIZ + 5];
+       char name[MAX_MSIX_COUNT][IFNAMSIZ + 9];
        struct ixgbe_dcb_config dcb_cfg;
        struct ixgbe_dcb_config temp_dcb_cfg;
        u8 dcb_set_bitmap;
@@ -245,11 +255,12 @@ struct ixgbe_adapter {
        struct ixgbe_ring *rx_ring;     /* One per active queue */
        int num_rx_queues;
        u64 hw_csum_rx_error;
+       u64 hw_rx_no_dma_resources;
        u64 hw_csum_rx_good;
        u64 non_eop_descs;
        int num_msix_vectors;
        int max_msix_q_vectors;         /* true count of q_vectors for device */
-       struct ixgbe_ring_feature ring_feature[3];
+       struct ixgbe_ring_feature ring_feature[RING_F_ARRAY_SIZE];
        struct msix_entry *msix_entries;
 
        u64 rx_hdr_split;
@@ -273,6 +284,7 @@ struct ixgbe_adapter {
 #define IXGBE_FLAG_DCA_CAPABLE                  (u32)(1 << 11)
 #define IXGBE_FLAG_IMIR_ENABLED                 (u32)(1 << 12)
 #define IXGBE_FLAG_MQ_CAPABLE                   (u32)(1 << 13)
+#define IXGBE_FLAG_DCB_ENABLED                  (u32)(1 << 14)
 #define IXGBE_FLAG_RSS_ENABLED                  (u32)(1 << 16)
 #define IXGBE_FLAG_RSS_CAPABLE                  (u32)(1 << 17)
 #define IXGBE_FLAG_VMDQ_CAPABLE                 (u32)(1 << 18)
@@ -280,7 +292,8 @@ struct ixgbe_adapter {
 #define IXGBE_FLAG_FAN_FAIL_CAPABLE             (u32)(1 << 20)
 #define IXGBE_FLAG_NEED_LINK_UPDATE             (u32)(1 << 22)
 #define IXGBE_FLAG_IN_WATCHDOG_TASK             (u32)(1 << 23)
-#define IXGBE_FLAG_DCB_ENABLED                  (u32)(1 << 24)
+#define IXGBE_FLAG_IN_SFP_LINK_TASK             (u32)(1 << 24)
+#define IXGBE_FLAG_IN_SFP_MOD_TASK              (u32)(1 << 25)
 
 /* default to trying for four seconds */
 #define IXGBE_TRY_LINK_TIMEOUT (4 * HZ)
@@ -310,7 +323,9 @@ struct ixgbe_adapter {
        struct work_struct watchdog_task;
        struct work_struct sfp_task;
        struct timer_list sfp_timer;
-
+       struct work_struct multispeed_fiber_task;
+       struct work_struct sfp_config_module_task;
+       u32 wol;
        u16 eeprom_version;
 };
 
@@ -323,9 +338,11 @@ enum ixbge_state_t {
 
 enum ixgbe_boards {
        board_82598,
+       board_82599,
 };
 
 extern struct ixgbe_info ixgbe_82598_info;
+extern struct ixgbe_info ixgbe_82599_info;
 #ifdef CONFIG_IXGBE_DCB
 extern struct dcbnl_rtnl_ops dcbnl_ops;
 extern int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg,
@@ -350,5 +367,6 @@ extern void ixgbe_reset_interrupt_capability(struct ixgbe_adapter *adapter);
 extern int ixgbe_init_interrupt_scheme(struct ixgbe_adapter *adapter);
 void ixgbe_napi_add_all(struct ixgbe_adapter *adapter);
 void ixgbe_napi_del_all(struct ixgbe_adapter *adapter);
+extern void ixgbe_write_eitr(struct ixgbe_adapter *, int, u32);
 
 #endif /* _IXGBE_H_ */
index 51dba1c78e1e85cfc1eaca3597f050f193a927b8..ed265a7a898faea70408ae635c92328ae54003a7 100644 (file)
@@ -79,6 +79,9 @@ static s32 ixgbe_get_invariants_82598(struct ixgbe_hw *hw)
        s32 ret_val = 0;
        u16 list_offset, data_offset;
 
+       /* Set the bus information prior to PHY identification */
+       mac->ops.get_bus_info(hw);
+
        /* Call PHY identify routine to get the phy type */
        ixgbe_identify_phy_generic(hw);
 
@@ -1046,9 +1049,9 @@ out:
  *
  *  Determines physical layer capabilities of the current configuration.
  **/
-static s32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw)
+static u32 ixgbe_get_supported_physical_layer_82598(struct ixgbe_hw *hw)
 {
-       s32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN;
+       u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN;
 
        switch (hw->device_id) {
        case IXGBE_DEV_ID_82598:
@@ -1111,8 +1114,11 @@ static struct ixgbe_mac_operations mac_ops_82598 = {
        .clear_hw_cntrs         = &ixgbe_clear_hw_cntrs_generic,
        .get_media_type         = &ixgbe_get_media_type_82598,
        .get_supported_physical_layer = &ixgbe_get_supported_physical_layer_82598,
+       .enable_rx_dma          = &ixgbe_enable_rx_dma_generic,
        .get_mac_addr           = &ixgbe_get_mac_addr_generic,
        .stop_adapter           = &ixgbe_stop_adapter_generic,
+       .get_bus_info           = &ixgbe_get_bus_info_generic,
+       .set_lan_id             = &ixgbe_set_lan_id_multi_port_pcie,
        .read_analog_reg8       = &ixgbe_read_analog_reg8_82598,
        .write_analog_reg8      = &ixgbe_write_analog_reg8_82598,
        .setup_link             = &ixgbe_setup_mac_link_82598,
diff --git a/drivers/net/ixgbe/ixgbe_82599.c b/drivers/net/ixgbe/ixgbe_82599.c
new file mode 100644 (file)
index 0000000..beae7e0
--- /dev/null
@@ -0,0 +1,1292 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/sched.h>
+
+#include "ixgbe.h"
+#include "ixgbe_phy.h"
+
+#define IXGBE_82599_MAX_TX_QUEUES 128
+#define IXGBE_82599_MAX_RX_QUEUES 128
+#define IXGBE_82599_RAR_ENTRIES   128
+#define IXGBE_82599_MC_TBL_SIZE   128
+#define IXGBE_82599_VFT_TBL_SIZE  128
+
+s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
+                                      ixgbe_link_speed *speed,
+                                      bool *autoneg);
+enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw);
+s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw);
+s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw,
+                                     ixgbe_link_speed speed, bool autoneg,
+                                     bool autoneg_wait_to_complete);
+s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw);
+s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw,
+                               ixgbe_link_speed *speed,
+                               bool *link_up, bool link_up_wait_to_complete);
+s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw,
+                                     ixgbe_link_speed speed,
+                                     bool autoneg,
+                                     bool autoneg_wait_to_complete);
+static s32 ixgbe_get_copper_link_capabilities_82599(struct ixgbe_hw *hw,
+                                             ixgbe_link_speed *speed,
+                                             bool *autoneg);
+static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw);
+static s32 ixgbe_setup_copper_link_speed_82599(struct ixgbe_hw *hw,
+                                               ixgbe_link_speed speed,
+                                               bool autoneg,
+                                               bool autoneg_wait_to_complete);
+s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw);
+s32 ixgbe_set_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq);
+s32 ixgbe_clear_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq);
+s32 ixgbe_set_vfta_82599(struct ixgbe_hw *hw, u32 vlan,
+                         u32 vind, bool vlan_on);
+s32 ixgbe_clear_vfta_82599(struct ixgbe_hw *hw);
+s32 ixgbe_blink_led_stop_82599(struct ixgbe_hw *hw, u32 index);
+s32 ixgbe_blink_led_start_82599(struct ixgbe_hw *hw, u32 index);
+s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw);
+s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val);
+s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val);
+s32 ixgbe_start_hw_rev_0_82599(struct ixgbe_hw *hw);
+s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw);
+s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw);
+u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw);
+
+void ixgbe_init_mac_link_ops_82599(struct ixgbe_hw *hw)
+{
+       struct ixgbe_mac_info *mac = &hw->mac;
+       if (hw->phy.multispeed_fiber) {
+               /* Set up dual speed SFP+ support */
+               mac->ops.setup_link =
+                         &ixgbe_setup_mac_link_multispeed_fiber;
+               mac->ops.setup_link_speed =
+                         &ixgbe_setup_mac_link_speed_multispeed_fiber;
+       } else {
+               mac->ops.setup_link =
+                         &ixgbe_setup_mac_link_82599;
+               mac->ops.setup_link_speed =
+                         &ixgbe_setup_mac_link_speed_82599;
+       }
+}
+
+s32 ixgbe_setup_sfp_modules_82599(struct ixgbe_hw *hw)
+{
+       s32 ret_val = 0;
+       u16 list_offset, data_offset, data_value;
+
+       if (hw->phy.sfp_type != ixgbe_sfp_type_unknown) {
+               ixgbe_init_mac_link_ops_82599(hw);
+               ret_val = ixgbe_get_sfp_init_sequence_offsets(hw, &list_offset,
+                                                             &data_offset);
+
+               if (ret_val != 0)
+                       goto setup_sfp_out;
+
+               hw->eeprom.ops.read(hw, ++data_offset, &data_value);
+               while (data_value != 0xffff) {
+                       IXGBE_WRITE_REG(hw, IXGBE_CORECTL, data_value);
+                       IXGBE_WRITE_FLUSH(hw);
+                       hw->eeprom.ops.read(hw, ++data_offset, &data_value);
+               }
+               /* Now restart DSP */
+               IXGBE_WRITE_REG(hw, IXGBE_CORECTL, 0x00000102);
+               IXGBE_WRITE_REG(hw, IXGBE_CORECTL, 0x00000b1d);
+               IXGBE_WRITE_FLUSH(hw);
+       }
+
+setup_sfp_out:
+       return ret_val;
+}
+
+/**
+ *  ixgbe_get_pcie_msix_count_82599 - Gets MSI-X vector count
+ *  @hw: pointer to hardware structure
+ *
+ *  Read PCIe configuration space, and get the MSI-X vector count from
+ *  the capabilities table.
+ **/
+u32 ixgbe_get_pcie_msix_count_82599(struct ixgbe_hw *hw)
+{
+       struct ixgbe_adapter *adapter = hw->back;
+       u16 msix_count;
+       pci_read_config_word(adapter->pdev, IXGBE_PCIE_MSIX_82599_CAPS,
+                            &msix_count);
+       msix_count &= IXGBE_PCIE_MSIX_TBL_SZ_MASK;
+
+       /* MSI-X count is zero-based in HW, so increment to give proper value */
+       msix_count++;
+
+       return msix_count;
+}
+
+static s32 ixgbe_get_invariants_82599(struct ixgbe_hw *hw)
+{
+       struct ixgbe_mac_info *mac = &hw->mac;
+       struct ixgbe_phy_info *phy = &hw->phy;
+       s32 ret_val;
+
+       /* Set the bus information prior to PHY identification */
+       mac->ops.get_bus_info(hw);
+
+       /* Call PHY identify routine to get the Cu or SFI phy type */
+       ret_val = phy->ops.identify(hw);
+
+       if (ret_val == IXGBE_ERR_SFP_NOT_SUPPORTED)
+               goto get_invariants_out;
+
+       ixgbe_init_mac_link_ops_82599(hw);
+
+       /* Setup SFP module if there is one present. */
+       ret_val = mac->ops.setup_sfp(hw);
+
+       /* If copper media, overwrite with copper function pointers */
+       if (mac->ops.get_media_type(hw) == ixgbe_media_type_copper) {
+               mac->ops.setup_link = &ixgbe_setup_copper_link_82599;
+               mac->ops.setup_link_speed =
+                                 &ixgbe_setup_copper_link_speed_82599;
+               mac->ops.get_link_capabilities =
+                                 &ixgbe_get_copper_link_capabilities_82599;
+       }
+
+       /* PHY Init */
+       switch (hw->phy.type) {
+       case ixgbe_phy_tn:
+               phy->ops.check_link = &ixgbe_check_phy_link_tnx;
+               phy->ops.get_firmware_version =
+                                 &ixgbe_get_phy_firmware_version_tnx;
+               break;
+       default:
+               break;
+       }
+
+       mac->mcft_size = IXGBE_82599_MC_TBL_SIZE;
+       mac->vft_size = IXGBE_82599_VFT_TBL_SIZE;
+       mac->num_rar_entries = IXGBE_82599_RAR_ENTRIES;
+       mac->max_rx_queues = IXGBE_82599_MAX_RX_QUEUES;
+       mac->max_tx_queues = IXGBE_82599_MAX_TX_QUEUES;
+       mac->max_msix_vectors = ixgbe_get_pcie_msix_count_82599(hw);
+
+get_invariants_out:
+       return ret_val;
+}
+
+/**
+ *  ixgbe_get_link_capabilities_82599 - Determines link capabilities
+ *  @hw: pointer to hardware structure
+ *  @speed: pointer to link speed
+ *  @negotiation: true when autoneg or autotry is enabled
+ *
+ *  Determines the link capabilities by reading the AUTOC register.
+ **/
+s32 ixgbe_get_link_capabilities_82599(struct ixgbe_hw *hw,
+                                      ixgbe_link_speed *speed,
+                                      bool *negotiation)
+{
+       s32 status = 0;
+
+       switch (hw->mac.orig_autoc & IXGBE_AUTOC_LMS_MASK) {
+       case IXGBE_AUTOC_LMS_1G_LINK_NO_AN:
+               *speed = IXGBE_LINK_SPEED_1GB_FULL;
+               *negotiation = false;
+               break;
+
+       case IXGBE_AUTOC_LMS_10G_LINK_NO_AN:
+               *speed = IXGBE_LINK_SPEED_10GB_FULL;
+               *negotiation = false;
+               break;
+
+       case IXGBE_AUTOC_LMS_1G_AN:
+               *speed = IXGBE_LINK_SPEED_1GB_FULL;
+               *negotiation = true;
+               break;
+
+       case IXGBE_AUTOC_LMS_10G_SERIAL:
+               *speed = IXGBE_LINK_SPEED_10GB_FULL;
+               *negotiation = false;
+               break;
+
+       case IXGBE_AUTOC_LMS_KX4_KX_KR:
+       case IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN:
+               *speed = IXGBE_LINK_SPEED_UNKNOWN;
+               if (hw->mac.orig_autoc & IXGBE_AUTOC_KR_SUPP)
+                       *speed |= IXGBE_LINK_SPEED_10GB_FULL;
+               if (hw->mac.orig_autoc & IXGBE_AUTOC_KX4_SUPP)
+                       *speed |= IXGBE_LINK_SPEED_10GB_FULL;
+               if (hw->mac.orig_autoc & IXGBE_AUTOC_KX_SUPP)
+                       *speed |= IXGBE_LINK_SPEED_1GB_FULL;
+               *negotiation = true;
+               break;
+
+       case IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII:
+               *speed = IXGBE_LINK_SPEED_100_FULL;
+               if (hw->mac.orig_autoc & IXGBE_AUTOC_KR_SUPP)
+                       *speed |= IXGBE_LINK_SPEED_10GB_FULL;
+               if (hw->mac.orig_autoc & IXGBE_AUTOC_KX4_SUPP)
+                       *speed |= IXGBE_LINK_SPEED_10GB_FULL;
+               if (hw->mac.orig_autoc & IXGBE_AUTOC_KX_SUPP)
+                       *speed |= IXGBE_LINK_SPEED_1GB_FULL;
+               *negotiation = true;
+               break;
+
+       case IXGBE_AUTOC_LMS_SGMII_1G_100M:
+               *speed = IXGBE_LINK_SPEED_1GB_FULL | IXGBE_LINK_SPEED_100_FULL;
+               *negotiation = false;
+               break;
+
+       default:
+               status = IXGBE_ERR_LINK_SETUP;
+               goto out;
+               break;
+       }
+
+       if (hw->phy.multispeed_fiber) {
+               *speed |= IXGBE_LINK_SPEED_10GB_FULL |
+                         IXGBE_LINK_SPEED_1GB_FULL;
+               *negotiation = true;
+       }
+
+out:
+       return status;
+}
+
+/**
+ *  ixgbe_get_copper_link_capabilities_82599 - Determines link capabilities
+ *  @hw: pointer to hardware structure
+ *  @speed: pointer to link speed
+ *  @autoneg: boolean auto-negotiation value
+ *
+ *  Determines the link capabilities by reading the AUTOC register.
+ **/
+static s32 ixgbe_get_copper_link_capabilities_82599(struct ixgbe_hw *hw,
+                                                    ixgbe_link_speed *speed,
+                                                    bool *autoneg)
+{
+       s32 status = IXGBE_ERR_LINK_SETUP;
+       u16 speed_ability;
+
+       *speed = 0;
+       *autoneg = true;
+
+       status = hw->phy.ops.read_reg(hw, IXGBE_MDIO_PHY_SPEED_ABILITY,
+                                     IXGBE_MDIO_PMA_PMD_DEV_TYPE,
+                                     &speed_ability);
+
+       if (status == 0) {
+               if (speed_ability & IXGBE_MDIO_PHY_SPEED_10G)
+                   *speed |= IXGBE_LINK_SPEED_10GB_FULL;
+               if (speed_ability & IXGBE_MDIO_PHY_SPEED_1G)
+                   *speed |= IXGBE_LINK_SPEED_1GB_FULL;
+       }
+
+       return status;
+}
+
+/**
+ *  ixgbe_get_media_type_82599 - Get media type
+ *  @hw: pointer to hardware structure
+ *
+ *  Returns the media type (fiber, copper, backplane)
+ **/
+enum ixgbe_media_type ixgbe_get_media_type_82599(struct ixgbe_hw *hw)
+{
+       enum ixgbe_media_type media_type;
+
+       /* Detect if there is a copper PHY attached. */
+       if (hw->phy.type == ixgbe_phy_cu_unknown ||
+           hw->phy.type == ixgbe_phy_tn) {
+               media_type = ixgbe_media_type_copper;
+               goto out;
+       }
+
+       switch (hw->device_id) {
+       case IXGBE_DEV_ID_82599:
+       case IXGBE_DEV_ID_82599_KX4:
+               /* Default device ID is mezzanine card KX/KX4 */
+               media_type = ixgbe_media_type_backplane;
+               break;
+       case IXGBE_DEV_ID_82599_SFP:
+               media_type = ixgbe_media_type_fiber;
+               break;
+       default:
+               media_type = ixgbe_media_type_unknown;
+               break;
+       }
+out:
+       return media_type;
+}
+
+/**
+ *  ixgbe_setup_mac_link_82599 - Setup MAC link settings
+ *  @hw: pointer to hardware structure
+ *
+ *  Configures link settings based on values in the ixgbe_hw struct.
+ *  Restarts the link.  Performs autonegotiation if needed.
+ **/
+s32 ixgbe_setup_mac_link_82599(struct ixgbe_hw *hw)
+{
+       u32 autoc_reg;
+       u32 links_reg;
+       u32 i;
+       s32 status = 0;
+
+       /* Restart link */
+       autoc_reg = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+       autoc_reg |= IXGBE_AUTOC_AN_RESTART;
+       IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc_reg);
+
+       /* Only poll for autoneg to complete if specified to do so */
+       if (hw->phy.autoneg_wait_to_complete) {
+               if ((autoc_reg & IXGBE_AUTOC_LMS_MASK) ==
+                    IXGBE_AUTOC_LMS_KX4_KX_KR ||
+                   (autoc_reg & IXGBE_AUTOC_LMS_MASK) ==
+                    IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN ||
+                   (autoc_reg & IXGBE_AUTOC_LMS_MASK) ==
+                    IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) {
+                       links_reg = 0; /* Just in case Autoneg time = 0 */
+                       for (i = 0; i < IXGBE_AUTO_NEG_TIME; i++) {
+                               links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
+                               if (links_reg & IXGBE_LINKS_KX_AN_COMP)
+                                       break;
+                               msleep(100);
+                       }
+                       if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) {
+                               status = IXGBE_ERR_AUTONEG_NOT_COMPLETE;
+                               hw_dbg(hw, "Autoneg did not complete.\n");
+                       }
+               }
+       }
+
+       /* Set up flow control */
+       status = ixgbe_setup_fc_generic(hw, 0);
+
+       /* Add delay to filter out noises during initial link setup */
+       msleep(50);
+
+       return status;
+}
+
+/**
+ *  ixgbe_setup_mac_link_multispeed_fiber - Setup MAC link settings
+ *  @hw: pointer to hardware structure
+ *
+ *  Configures link settings based on values in the ixgbe_hw struct.
+ *  Restarts the link for multi-speed fiber at 1G speed, if link
+ *  fails at 10G.
+ *  Performs autonegotiation if needed.
+ **/
+s32 ixgbe_setup_mac_link_multispeed_fiber(struct ixgbe_hw *hw)
+{
+       s32 status = 0;
+       ixgbe_link_speed link_speed = IXGBE_LINK_SPEED_82599_AUTONEG;
+       status = ixgbe_setup_mac_link_speed_multispeed_fiber(hw, link_speed,
+                                                            true, true);
+       return status;
+}
+
+/**
+ *  ixgbe_setup_mac_link_speed_multispeed_fiber - Set MAC link speed
+ *  @hw: pointer to hardware structure
+ *  @speed: new link speed
+ *  @autoneg: true if autonegotiation enabled
+ *  @autoneg_wait_to_complete: true when waiting for completion is needed
+ *
+ *  Set the link speed in the AUTOC register and restarts link.
+ **/
+s32 ixgbe_setup_mac_link_speed_multispeed_fiber(struct ixgbe_hw *hw,
+                                                ixgbe_link_speed speed,
+                                                bool autoneg,
+                                                bool autoneg_wait_to_complete)
+{
+       s32 status = 0;
+       ixgbe_link_speed phy_link_speed;
+       ixgbe_link_speed highest_link_speed = IXGBE_LINK_SPEED_UNKNOWN;
+       u32 speedcnt = 0;
+       u32 esdp_reg = IXGBE_READ_REG(hw, IXGBE_ESDP);
+       bool link_up = false;
+       bool negotiation;
+
+       /* Mask off requested but non-supported speeds */
+       hw->mac.ops.get_link_capabilities(hw, &phy_link_speed, &negotiation);
+       speed &= phy_link_speed;
+
+       /*
+        * Try each speed one by one, highest priority first.  We do this in
+        * software because 10gb fiber doesn't support speed autonegotiation.
+        */
+       if (speed & IXGBE_LINK_SPEED_10GB_FULL) {
+               speedcnt++;
+               highest_link_speed = IXGBE_LINK_SPEED_10GB_FULL;
+
+               /* Set hardware SDP's */
+               esdp_reg |= (IXGBE_ESDP_SDP5_DIR | IXGBE_ESDP_SDP5);
+               IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
+
+               ixgbe_setup_mac_link_speed_82599(hw,
+                                                IXGBE_LINK_SPEED_10GB_FULL,
+                                                autoneg,
+                                                autoneg_wait_to_complete);
+
+               msleep(50);
+
+               /* If we have link, just jump out */
+               hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false);
+               if (link_up)
+                       goto out;
+       }
+
+       if (speed & IXGBE_LINK_SPEED_1GB_FULL) {
+               speedcnt++;
+               if (highest_link_speed == IXGBE_LINK_SPEED_UNKNOWN)
+                       highest_link_speed = IXGBE_LINK_SPEED_1GB_FULL;
+
+               /* Set hardware SDP's */
+               esdp_reg &= ~IXGBE_ESDP_SDP5;
+               esdp_reg |= IXGBE_ESDP_SDP5_DIR;
+               IXGBE_WRITE_REG(hw, IXGBE_ESDP, esdp_reg);
+
+               ixgbe_setup_mac_link_speed_82599(
+                       hw, IXGBE_LINK_SPEED_1GB_FULL, autoneg,
+                       autoneg_wait_to_complete);
+
+               msleep(50);
+
+               /* If we have link, just jump out */
+               hw->mac.ops.check_link(hw, &phy_link_speed, &link_up, false);
+               if (link_up)
+                       goto out;
+       }
+
+       /*
+        * We didn't get link.  Configure back to the highest speed we tried,
+        * (if there was more than one).  We call ourselves back with just the
+        * single highest speed that the user requested.
+        */
+       if (speedcnt > 1)
+               status = ixgbe_setup_mac_link_speed_multispeed_fiber(hw,
+                                                    highest_link_speed,
+                                                    autoneg,
+                                                    autoneg_wait_to_complete);
+
+out:
+       return status;
+}
+
+/**
+ *  ixgbe_check_mac_link_82599 - Determine link and speed status
+ *  @hw: pointer to hardware structure
+ *  @speed: pointer to link speed
+ *  @link_up: true when link is up
+ *  @link_up_wait_to_complete: bool used to wait for link up or not
+ *
+ *  Reads the links register to determine if link is up and the current speed
+ **/
+s32 ixgbe_check_mac_link_82599(struct ixgbe_hw *hw, ixgbe_link_speed *speed,
+                               bool *link_up, bool link_up_wait_to_complete)
+{
+       u32 links_reg;
+       u32 i;
+
+       links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
+       if (link_up_wait_to_complete) {
+               for (i = 0; i < IXGBE_LINK_UP_TIME; i++) {
+                       if (links_reg & IXGBE_LINKS_UP) {
+                               *link_up = true;
+                               break;
+                       } else {
+                               *link_up = false;
+                       }
+                       msleep(100);
+                       links_reg = IXGBE_READ_REG(hw, IXGBE_LINKS);
+               }
+       } else {
+               if (links_reg & IXGBE_LINKS_UP)
+                       *link_up = true;
+               else
+                       *link_up = false;
+       }
+
+       if ((links_reg & IXGBE_LINKS_SPEED_82599) ==
+           IXGBE_LINKS_SPEED_10G_82599)
+               *speed = IXGBE_LINK_SPEED_10GB_FULL;
+       else if ((links_reg & IXGBE_LINKS_SPEED_82599) ==
+                IXGBE_LINKS_SPEED_1G_82599)
+               *speed = IXGBE_LINK_SPEED_1GB_FULL;
+       else
+               *speed = IXGBE_LINK_SPEED_100_FULL;
+
+
+       return 0;
+}
+
+/**
+ *  ixgbe_setup_mac_link_speed_82599 - Set MAC link speed
+ *  @hw: pointer to hardware structure
+ *  @speed: new link speed
+ *  @autoneg: true if autonegotiation enabled
+ *  @autoneg_wait_to_complete: true when waiting for completion is needed
+ *
+ *  Set the link speed in the AUTOC register and restarts link.
+ **/
+s32 ixgbe_setup_mac_link_speed_82599(struct ixgbe_hw *hw,
+                                     ixgbe_link_speed speed, bool autoneg,
+                                     bool autoneg_wait_to_complete)
+{
+       s32 status = 0;
+       u32 autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+       u32 autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
+       u32 link_mode = autoc & IXGBE_AUTOC_LMS_MASK;
+       u32 pma_pmd_1g = autoc & IXGBE_AUTOC_1G_PMA_PMD_MASK;
+       u32 pma_pmd_10g_serial = autoc2 & IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK;
+       u32 links_reg;
+       u32 i;
+       ixgbe_link_speed link_capabilities = IXGBE_LINK_SPEED_UNKNOWN;
+
+       /* Check to see if speed passed in is supported. */
+       hw->mac.ops.get_link_capabilities(hw, &link_capabilities, &autoneg);
+       speed &= link_capabilities;
+
+       if (speed == IXGBE_LINK_SPEED_UNKNOWN) {
+               status = IXGBE_ERR_LINK_SETUP;
+       } else if (link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR ||
+                  link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN ||
+                  link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) {
+               /* Set KX4/KX/KR support according to speed requested */
+               autoc &= ~(IXGBE_AUTOC_KX4_KX_SUPP_MASK | IXGBE_AUTOC_KR_SUPP);
+               if (speed & IXGBE_LINK_SPEED_10GB_FULL)
+                       if (hw->mac.orig_autoc & IXGBE_AUTOC_KX4_SUPP)
+                               autoc |= IXGBE_AUTOC_KX4_SUPP;
+                       if (hw->mac.orig_autoc & IXGBE_AUTOC_KR_SUPP)
+                               autoc |= IXGBE_AUTOC_KR_SUPP;
+               if (speed & IXGBE_LINK_SPEED_1GB_FULL)
+                       autoc |= IXGBE_AUTOC_KX_SUPP;
+       } else if ((pma_pmd_1g == IXGBE_AUTOC_1G_SFI) &&
+                  (link_mode == IXGBE_AUTOC_LMS_1G_LINK_NO_AN ||
+                   link_mode == IXGBE_AUTOC_LMS_1G_AN)) {
+               /* Switch from 1G SFI to 10G SFI if requested */
+               if ((speed == IXGBE_LINK_SPEED_10GB_FULL) &&
+                   (pma_pmd_10g_serial == IXGBE_AUTOC2_10G_SFI)) {
+                       autoc &= ~IXGBE_AUTOC_LMS_MASK;
+                       autoc |= IXGBE_AUTOC_LMS_10G_SERIAL;
+               }
+       } else if ((pma_pmd_10g_serial == IXGBE_AUTOC2_10G_SFI) &&
+                  (link_mode == IXGBE_AUTOC_LMS_10G_SERIAL)) {
+               /* Switch from 10G SFI to 1G SFI if requested */
+               if ((speed == IXGBE_LINK_SPEED_1GB_FULL) &&
+                   (pma_pmd_1g == IXGBE_AUTOC_1G_SFI)) {
+                       autoc &= ~IXGBE_AUTOC_LMS_MASK;
+                       if (autoneg)
+                               autoc |= IXGBE_AUTOC_LMS_1G_AN;
+                       else
+                               autoc |= IXGBE_AUTOC_LMS_1G_LINK_NO_AN;
+               }
+       }
+
+       if (status == 0) {
+               /* Restart link */
+               autoc |= IXGBE_AUTOC_AN_RESTART;
+               IXGBE_WRITE_REG(hw, IXGBE_AUTOC, autoc);
+
+               /* Only poll for autoneg to complete if specified to do so */
+               if (autoneg_wait_to_complete) {
+                       if (link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR ||
+                           link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN ||
+                           link_mode == IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII) {
+                               links_reg = 0; /*Just in case Autoneg time=0*/
+                               for (i = 0; i < IXGBE_AUTO_NEG_TIME; i++) {
+                                       links_reg =
+                                              IXGBE_READ_REG(hw, IXGBE_LINKS);
+                                       if (links_reg & IXGBE_LINKS_KX_AN_COMP)
+                                               break;
+                                       msleep(100);
+                               }
+                               if (!(links_reg & IXGBE_LINKS_KX_AN_COMP)) {
+                                       status =
+                                               IXGBE_ERR_AUTONEG_NOT_COMPLETE;
+                                       hw_dbg(hw, "Autoneg did not "
+                                              "complete.\n");
+                               }
+                       }
+               }
+
+               /* Set up flow control */
+               status = ixgbe_setup_fc_generic(hw, 0);
+
+               /* Add delay to filter out noises during initial link setup */
+               msleep(50);
+       }
+
+       return status;
+}
+
+/**
+ *  ixgbe_setup_copper_link_82599 - Setup copper link settings
+ *  @hw: pointer to hardware structure
+ *
+ *  Restarts the link on PHY and then MAC. Performs autonegotiation if needed.
+ **/
+static s32 ixgbe_setup_copper_link_82599(struct ixgbe_hw *hw)
+{
+       s32 status;
+
+       /* Restart autonegotiation on PHY */
+       status = hw->phy.ops.setup_link(hw);
+
+       /* Set up MAC */
+       ixgbe_setup_mac_link_82599(hw);
+
+       return status;
+}
+
+/**
+ *  ixgbe_setup_copper_link_speed_82599 - Set the PHY autoneg advertised field
+ *  @hw: pointer to hardware structure
+ *  @speed: new link speed
+ *  @autoneg: true if autonegotiation enabled
+ *  @autoneg_wait_to_complete: true if waiting is needed to complete
+ *
+ *  Restarts link on PHY and MAC based on settings passed in.
+ **/
+static s32 ixgbe_setup_copper_link_speed_82599(struct ixgbe_hw *hw,
+                                               ixgbe_link_speed speed,
+                                               bool autoneg,
+                                               bool autoneg_wait_to_complete)
+{
+       s32 status;
+
+       /* Setup the PHY according to input speed */
+       status = hw->phy.ops.setup_link_speed(hw, speed, autoneg,
+                                             autoneg_wait_to_complete);
+       /* Set up MAC */
+       ixgbe_setup_mac_link_82599(hw);
+
+       return status;
+}
+
+/**
+ *  ixgbe_reset_hw_82599 - Perform hardware reset
+ *  @hw: pointer to hardware structure
+ *
+ *  Resets the hardware by resetting the transmit and receive units, masks
+ *  and clears all interrupts, perform a PHY reset, and perform a link (MAC)
+ *  reset.
+ **/
+s32 ixgbe_reset_hw_82599(struct ixgbe_hw *hw)
+{
+       s32 status = 0;
+       u32 ctrl, ctrl_ext;
+       u32 i;
+       u32 autoc;
+       u32 autoc2;
+
+       /* Call adapter stop to disable tx/rx and clear interrupts */
+       hw->mac.ops.stop_adapter(hw);
+
+       /* Reset PHY */
+       hw->phy.ops.reset(hw);
+
+       /*
+        * Prevent the PCI-E bus from from hanging by disabling PCI-E master
+        * access and verify no pending requests before reset
+        */
+       if (ixgbe_disable_pcie_master(hw) != 0) {
+               status = IXGBE_ERR_MASTER_REQUESTS_PENDING;
+               hw_dbg(hw, "PCI-E Master disable polling has failed.\n");
+       }
+
+       /*
+        * Issue global reset to the MAC.  This needs to be a SW reset.
+        * If link reset is used, it might reset the MAC when mng is using it
+        */
+       ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
+       IXGBE_WRITE_REG(hw, IXGBE_CTRL, (ctrl | IXGBE_CTRL_RST));
+       IXGBE_WRITE_FLUSH(hw);
+
+       /* Poll for reset bit to self-clear indicating reset is complete */
+       for (i = 0; i < 10; i++) {
+               udelay(1);
+               ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
+               if (!(ctrl & IXGBE_CTRL_RST))
+                       break;
+       }
+       if (ctrl & IXGBE_CTRL_RST) {
+               status = IXGBE_ERR_RESET_FAILED;
+               hw_dbg(hw, "Reset polling failed to complete.\n");
+       }
+       /* Clear PF Reset Done bit so PF/VF Mail Ops can work */
+       ctrl_ext = IXGBE_READ_REG(hw, IXGBE_CTRL_EXT);
+       ctrl_ext |= IXGBE_CTRL_EXT_PFRSTD;
+       IXGBE_WRITE_REG(hw, IXGBE_CTRL_EXT, ctrl_ext);
+
+       msleep(50);
+
+
+
+       /*
+        * Store the original AUTOC/AUTOC2 values if they have not been
+        * stored off yet.  Otherwise restore the stored original
+        * values since the reset operation sets back to defaults.
+        */
+       autoc = IXGBE_READ_REG(hw, IXGBE_AUTOC);
+       autoc2 = IXGBE_READ_REG(hw, IXGBE_AUTOC2);
+       if (hw->mac.orig_link_settings_stored == false) {
+               hw->mac.orig_autoc = autoc;
+               hw->mac.orig_autoc2 = autoc2;
+               hw->mac.orig_link_settings_stored = true;
+       } else {
+               if (autoc != hw->mac.orig_autoc)
+                       IXGBE_WRITE_REG(hw, IXGBE_AUTOC, (hw->mac.orig_autoc |
+                                       IXGBE_AUTOC_AN_RESTART));
+
+               if ((autoc2 & IXGBE_AUTOC2_UPPER_MASK) !=
+                   (hw->mac.orig_autoc2 & IXGBE_AUTOC2_UPPER_MASK)) {
+                       autoc2 &= ~IXGBE_AUTOC2_UPPER_MASK;
+                       autoc2 |= (hw->mac.orig_autoc2 &
+                                  IXGBE_AUTOC2_UPPER_MASK);
+                       IXGBE_WRITE_REG(hw, IXGBE_AUTOC2, autoc2);
+               }
+       }
+
+       /* Store the permanent mac address */
+       hw->mac.ops.get_mac_addr(hw, hw->mac.perm_addr);
+
+       return status;
+}
+
+/**
+ *  ixgbe_clear_vmdq_82599 - Disassociate a VMDq pool index from a rx address
+ *  @hw: pointer to hardware struct
+ *  @rar: receive address register index to disassociate
+ *  @vmdq: VMDq pool index to remove from the rar
+ **/
+s32 ixgbe_clear_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq)
+{
+       u32 mpsar_lo, mpsar_hi;
+       u32 rar_entries = hw->mac.num_rar_entries;
+
+       if (rar < rar_entries) {
+               mpsar_lo = IXGBE_READ_REG(hw, IXGBE_MPSAR_LO(rar));
+               mpsar_hi = IXGBE_READ_REG(hw, IXGBE_MPSAR_HI(rar));
+
+               if (!mpsar_lo && !mpsar_hi)
+                       goto done;
+
+               if (vmdq == IXGBE_CLEAR_VMDQ_ALL) {
+                       if (mpsar_lo) {
+                               IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(rar), 0);
+                               mpsar_lo = 0;
+                       }
+                       if (mpsar_hi) {
+                               IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(rar), 0);
+                               mpsar_hi = 0;
+                       }
+               } else if (vmdq < 32) {
+                       mpsar_lo &= ~(1 << vmdq);
+                       IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(rar), mpsar_lo);
+               } else {
+                       mpsar_hi &= ~(1 << (vmdq - 32));
+                       IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(rar), mpsar_hi);
+               }
+
+               /* was that the last pool using this rar? */
+               if (mpsar_lo == 0 && mpsar_hi == 0 && rar != 0)
+                       hw->mac.ops.clear_rar(hw, rar);
+       } else {
+               hw_dbg(hw, "RAR index %d is out of range.\n", rar);
+       }
+
+done:
+       return 0;
+}
+
+/**
+ *  ixgbe_set_vmdq_82599 - Associate a VMDq pool index with a rx address
+ *  @hw: pointer to hardware struct
+ *  @rar: receive address register index to associate with a VMDq index
+ *  @vmdq: VMDq pool index
+ **/
+s32 ixgbe_set_vmdq_82599(struct ixgbe_hw *hw, u32 rar, u32 vmdq)
+{
+       u32 mpsar;
+       u32 rar_entries = hw->mac.num_rar_entries;
+
+       if (rar < rar_entries) {
+               if (vmdq < 32) {
+                       mpsar = IXGBE_READ_REG(hw, IXGBE_MPSAR_LO(rar));
+                       mpsar |= 1 << vmdq;
+                       IXGBE_WRITE_REG(hw, IXGBE_MPSAR_LO(rar), mpsar);
+               } else {
+                       mpsar = IXGBE_READ_REG(hw, IXGBE_MPSAR_HI(rar));
+                       mpsar |= 1 << (vmdq - 32);
+                       IXGBE_WRITE_REG(hw, IXGBE_MPSAR_HI(rar), mpsar);
+               }
+       } else {
+               hw_dbg(hw, "RAR index %d is out of range.\n", rar);
+       }
+       return 0;
+}
+
+/**
+ *  ixgbe_set_vfta_82599 - Set VLAN filter table
+ *  @hw: pointer to hardware structure
+ *  @vlan: VLAN id to write to VLAN filter
+ *  @vind: VMDq output index that maps queue to VLAN id in VFVFB
+ *  @vlan_on: boolean flag to turn on/off VLAN in VFVF
+ *
+ *  Turn on/off specified VLAN in the VLAN filter table.
+ **/
+s32 ixgbe_set_vfta_82599(struct ixgbe_hw *hw, u32 vlan, u32 vind,
+                         bool vlan_on)
+{
+       u32 regindex;
+       u32 bitindex;
+       u32 bits;
+       u32 first_empty_slot;
+
+       if (vlan > 4095)
+               return IXGBE_ERR_PARAM;
+
+       /*
+        * this is a 2 part operation - first the VFTA, then the
+        * VLVF and VLVFB if vind is set
+        */
+
+       /* Part 1
+        * The VFTA is a bitstring made up of 128 32-bit registers
+        * that enable the particular VLAN id, much like the MTA:
+        *    bits[11-5]: which register
+        *    bits[4-0]:  which bit in the register
+        */
+       regindex = (vlan >> 5) & 0x7F;
+       bitindex = vlan & 0x1F;
+       bits = IXGBE_READ_REG(hw, IXGBE_VFTA(regindex));
+       if (vlan_on)
+               bits |= (1 << bitindex);
+       else
+               bits &= ~(1 << bitindex);
+       IXGBE_WRITE_REG(hw, IXGBE_VFTA(regindex), bits);
+
+
+       /* Part 2
+        * If the vind is set
+        *   Either vlan_on
+        *     make sure the vlan is in VLVF
+        *     set the vind bit in the matching VLVFB
+        *   Or !vlan_on
+        *     clear the pool bit and possibly the vind
+        */
+       if (vind) {
+               /* find the vlanid or the first empty slot */
+               first_empty_slot = 0;
+
+               for (regindex = 1; regindex < IXGBE_VLVF_ENTRIES; regindex++) {
+                       bits = IXGBE_READ_REG(hw, IXGBE_VLVF(regindex));
+                       if (!bits && !first_empty_slot)
+                               first_empty_slot = regindex;
+                       else if ((bits & 0x0FFF) == vlan)
+                               break;
+               }
+
+               if (regindex >= IXGBE_VLVF_ENTRIES) {
+                       if (first_empty_slot)
+                               regindex = first_empty_slot;
+                       else {
+                               hw_dbg(hw, "No space in VLVF.\n");
+                               goto out;
+                       }
+               }
+
+               if (vlan_on) {
+                       /* set the pool bit */
+                       if (vind < 32) {
+                               bits = IXGBE_READ_REG(hw,
+                                                   IXGBE_VLVFB(regindex * 2));
+                               bits |= (1 << vind);
+                               IXGBE_WRITE_REG(hw,
+                                             IXGBE_VLVFB(regindex * 2), bits);
+                       } else {
+                               bits = IXGBE_READ_REG(hw,
+                                             IXGBE_VLVFB((regindex * 2) + 1));
+                               bits |= (1 << vind);
+                               IXGBE_WRITE_REG(hw,
+                                       IXGBE_VLVFB((regindex * 2) + 1), bits);
+                       }
+               } else {
+                       /* clear the pool bit */
+                       if (vind < 32) {
+                               bits = IXGBE_READ_REG(hw,
+                                    IXGBE_VLVFB(regindex * 2));
+                       bits &= ~(1 << vind);
+                               IXGBE_WRITE_REG(hw,
+                                             IXGBE_VLVFB(regindex * 2), bits);
+                               bits |= IXGBE_READ_REG(hw,
+                                             IXGBE_VLVFB((regindex * 2) + 1));
+                       } else {
+                               bits = IXGBE_READ_REG(hw,
+                                             IXGBE_VLVFB((regindex * 2) + 1));
+                               bits &= ~(1 << vind);
+                               IXGBE_WRITE_REG(hw,
+                                       IXGBE_VLVFB((regindex * 2) + 1), bits);
+                               bits |= IXGBE_READ_REG(hw,
+                                                   IXGBE_VLVFB(regindex * 2));
+                       }
+               }
+
+               if (bits)
+                       IXGBE_WRITE_REG(hw, IXGBE_VLVF(regindex),
+                                       (IXGBE_VLVF_VIEN | vlan));
+               else
+                       IXGBE_WRITE_REG(hw, IXGBE_VLVF(regindex), 0);
+       }
+
+out:
+       return 0;
+}
+
+/**
+ *  ixgbe_clear_vfta_82599 - Clear VLAN filter table
+ *  @hw: pointer to hardware structure
+ *
+ *  Clears the VLAN filer table, and the VMDq index associated with the filter
+ **/
+s32 ixgbe_clear_vfta_82599(struct ixgbe_hw *hw)
+{
+       u32 offset;
+
+       for (offset = 0; offset < hw->mac.vft_size; offset++)
+               IXGBE_WRITE_REG(hw, IXGBE_VFTA(offset), 0);
+
+       for (offset = 0; offset < IXGBE_VLVF_ENTRIES; offset++) {
+               IXGBE_WRITE_REG(hw, IXGBE_VLVF(offset), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_VLVFB(offset * 2), 0);
+               IXGBE_WRITE_REG(hw, IXGBE_VLVFB((offset * 2) + 1), 0);
+       }
+
+       return 0;
+}
+
+/**
+ *  ixgbe_blink_led_start_82599 - Blink LED based on index.
+ *  @hw: pointer to hardware structure
+ *  @index: led number to blink
+ **/
+s32 ixgbe_blink_led_start_82599(struct ixgbe_hw *hw, u32 index)
+{
+       u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+
+       led_reg &= ~IXGBE_LED_MODE_MASK(index);
+       led_reg |= IXGBE_LED_BLINK(index);
+       IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg);
+       IXGBE_WRITE_FLUSH(hw);
+
+       return 0;
+}
+
+/**
+ *  ixgbe_blink_led_stop_82599 - Stop blinking LED based on index.
+ *  @hw: pointer to hardware structure
+ *  @index: led number to stop blinking
+ **/
+s32 ixgbe_blink_led_stop_82599(struct ixgbe_hw *hw, u32 index)
+{
+       u32 led_reg = IXGBE_READ_REG(hw, IXGBE_LEDCTL);
+
+       led_reg &= ~IXGBE_LED_MODE_MASK(index);
+       led_reg &= ~IXGBE_LED_BLINK(index);
+       IXGBE_WRITE_REG(hw, IXGBE_LEDCTL, led_reg);
+       IXGBE_WRITE_FLUSH(hw);
+
+       return 0;
+}
+
+/**
+ *  ixgbe_init_uta_tables_82599 - Initialize the Unicast Table Array
+ *  @hw: pointer to hardware structure
+ **/
+s32 ixgbe_init_uta_tables_82599(struct ixgbe_hw *hw)
+{
+       int i;
+       hw_dbg(hw, " Clearing UTA\n");
+
+       for (i = 0; i < 128; i++)
+               IXGBE_WRITE_REG(hw, IXGBE_UTA(i), 0);
+
+       return 0;
+}
+
+/**
+ *  ixgbe_read_analog_reg8_82599 - Reads 8 bit Omer analog register
+ *  @hw: pointer to hardware structure
+ *  @reg: analog register to read
+ *  @val: read value
+ *
+ *  Performs read operation to Omer analog register specified.
+ **/
+s32 ixgbe_read_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 *val)
+{
+       u32  core_ctl;
+
+       IXGBE_WRITE_REG(hw, IXGBE_CORECTL, IXGBE_CORECTL_WRITE_CMD |
+                       (reg << 8));
+       IXGBE_WRITE_FLUSH(hw);
+       udelay(10);
+       core_ctl = IXGBE_READ_REG(hw, IXGBE_CORECTL);
+       *val = (u8)core_ctl;
+
+       return 0;
+}
+
+/**
+ *  ixgbe_write_analog_reg8_82599 - Writes 8 bit Omer analog register
+ *  @hw: pointer to hardware structure
+ *  @reg: atlas register to write
+ *  @val: value to write
+ *
+ *  Performs write operation to Omer analog register specified.
+ **/
+s32 ixgbe_write_analog_reg8_82599(struct ixgbe_hw *hw, u32 reg, u8 val)
+{
+       u32  core_ctl;
+
+       core_ctl = (reg << 8) | val;
+       IXGBE_WRITE_REG(hw, IXGBE_CORECTL, core_ctl);
+       IXGBE_WRITE_FLUSH(hw);
+       udelay(10);
+
+       return 0;
+}
+
+/**
+ *  ixgbe_start_hw_82599 - Prepare hardware for Tx/Rx
+ *  @hw: pointer to hardware structure
+ *
+ *  Starts the hardware using the generic start_hw function.
+ *  Then performs device-specific:
+ *  Clears the rate limiter registers.
+ **/
+s32 ixgbe_start_hw_82599(struct ixgbe_hw *hw)
+{
+       u32 q_num;
+
+       ixgbe_start_hw_generic(hw);
+
+       /* Clear the rate limiters */
+       for (q_num = 0; q_num < hw->mac.max_tx_queues; q_num++) {
+               IXGBE_WRITE_REG(hw, IXGBE_RTTDQSEL, q_num);
+               IXGBE_WRITE_REG(hw, IXGBE_RTTBCNRC, 0);
+       }
+       IXGBE_WRITE_FLUSH(hw);
+
+       return 0;
+}
+
+/**
+ *  ixgbe_identify_phy_82599 - Get physical layer module
+ *  @hw: pointer to hardware structure
+ *
+ *  Determines the physical layer module found on the current adapter.
+ **/
+s32 ixgbe_identify_phy_82599(struct ixgbe_hw *hw)
+{
+       s32 status = IXGBE_ERR_PHY_ADDR_INVALID;
+       status = ixgbe_identify_phy_generic(hw);
+       if (status != 0)
+               status = ixgbe_identify_sfp_module_generic(hw);
+       return status;
+}
+
+/**
+ *  ixgbe_get_supported_physical_layer_82599 - Returns physical layer type
+ *  @hw: pointer to hardware structure
+ *
+ *  Determines physical layer capabilities of the current configuration.
+ **/
+u32 ixgbe_get_supported_physical_layer_82599(struct ixgbe_hw *hw)
+{
+       u32 physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN;
+       u8 comp_codes_10g = 0;
+
+       switch (hw->device_id) {
+       case IXGBE_DEV_ID_82599:
+       case IXGBE_DEV_ID_82599_KX4:
+               /* Default device ID is mezzanine card KX/KX4 */
+               physical_layer = (IXGBE_PHYSICAL_LAYER_10GBASE_KX4 |
+                                 IXGBE_PHYSICAL_LAYER_1000BASE_KX);
+               break;
+       case IXGBE_DEV_ID_82599_SFP:
+               hw->phy.ops.identify_sfp(hw);
+
+               switch (hw->phy.sfp_type) {
+               case ixgbe_sfp_type_da_cu:
+               case ixgbe_sfp_type_da_cu_core0:
+               case ixgbe_sfp_type_da_cu_core1:
+                       physical_layer = IXGBE_PHYSICAL_LAYER_SFP_PLUS_CU;
+                       break;
+               case ixgbe_sfp_type_sr:
+                       physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_SR;
+                       break;
+               case ixgbe_sfp_type_lr:
+                       physical_layer = IXGBE_PHYSICAL_LAYER_10GBASE_LR;
+                       break;
+               case ixgbe_sfp_type_srlr_core0:
+               case ixgbe_sfp_type_srlr_core1:
+                       hw->phy.ops.read_i2c_eeprom(hw,
+                                                   IXGBE_SFF_10GBE_COMP_CODES,
+                                                   &comp_codes_10g);
+                       if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
+                               physical_layer =
+                                               IXGBE_PHYSICAL_LAYER_10GBASE_SR;
+                       else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
+                               physical_layer =
+                                               IXGBE_PHYSICAL_LAYER_10GBASE_LR;
+                       else
+                               physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN;
+               default:
+                       physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN;
+                       break;
+               }
+               break;
+       default:
+               physical_layer = IXGBE_PHYSICAL_LAYER_UNKNOWN;
+               break;
+       }
+
+       return physical_layer;
+}
+
+/**
+ *  ixgbe_enable_rx_dma_82599 - Enable the Rx DMA unit on 82599
+ *  @hw: pointer to hardware structure
+ *  @regval: register value to write to RXCTRL
+ *
+ *  Enables the Rx DMA unit for 82599
+ **/
+s32 ixgbe_enable_rx_dma_82599(struct ixgbe_hw *hw, u32 regval)
+{
+#define IXGBE_MAX_SECRX_POLL 30
+       int i;
+       int secrxreg;
+
+       /*
+        * Workaround for 82599 silicon errata when enabling the Rx datapath.
+        * If traffic is incoming before we enable the Rx unit, it could hang
+        * the Rx DMA unit.  Therefore, make sure the security engine is
+        * completely disabled prior to enabling the Rx unit.
+        */
+       secrxreg = IXGBE_READ_REG(hw, IXGBE_SECRXCTRL);
+       secrxreg |= IXGBE_SECRXCTRL_RX_DIS;
+       IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, secrxreg);
+       for (i = 0; i < IXGBE_MAX_SECRX_POLL; i++) {
+               secrxreg = IXGBE_READ_REG(hw, IXGBE_SECRXSTAT);
+               if (secrxreg & IXGBE_SECRXSTAT_SECRX_RDY)
+                       break;
+               else
+                       udelay(10);
+       }
+
+       /* For informational purposes only */
+       if (i >= IXGBE_MAX_SECRX_POLL)
+               hw_dbg(hw, "Rx unit being enabled before security "
+                      "path fully disabled.  Continuing with init.\n");
+
+       IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, regval);
+       secrxreg = IXGBE_READ_REG(hw, IXGBE_SECRXCTRL);
+       secrxreg &= ~IXGBE_SECRXCTRL_RX_DIS;
+       IXGBE_WRITE_REG(hw, IXGBE_SECRXCTRL, secrxreg);
+       IXGBE_WRITE_FLUSH(hw);
+
+       return 0;
+}
+
+static struct ixgbe_mac_operations mac_ops_82599 = {
+       .init_hw                = &ixgbe_init_hw_generic,
+       .reset_hw               = &ixgbe_reset_hw_82599,
+       .start_hw               = &ixgbe_start_hw_82599,
+       .clear_hw_cntrs         = &ixgbe_clear_hw_cntrs_generic,
+       .get_media_type         = &ixgbe_get_media_type_82599,
+       .get_supported_physical_layer = &ixgbe_get_supported_physical_layer_82599,
+       .enable_rx_dma          = &ixgbe_enable_rx_dma_82599,
+       .get_mac_addr           = &ixgbe_get_mac_addr_generic,
+       .stop_adapter           = &ixgbe_stop_adapter_generic,
+       .get_bus_info           = &ixgbe_get_bus_info_generic,
+       .set_lan_id             = &ixgbe_set_lan_id_multi_port_pcie,
+       .read_analog_reg8       = &ixgbe_read_analog_reg8_82599,
+       .write_analog_reg8      = &ixgbe_write_analog_reg8_82599,
+       .setup_link             = &ixgbe_setup_mac_link_82599,
+       .setup_link_speed       = &ixgbe_setup_mac_link_speed_82599,
+       .check_link             = &ixgbe_check_mac_link_82599,
+       .get_link_capabilities  = &ixgbe_get_link_capabilities_82599,
+       .led_on                 = &ixgbe_led_on_generic,
+       .led_off                = &ixgbe_led_off_generic,
+       .blink_led_start        = &ixgbe_blink_led_start_82599,
+       .blink_led_stop         = &ixgbe_blink_led_stop_82599,
+       .set_rar                = &ixgbe_set_rar_generic,
+       .clear_rar              = &ixgbe_clear_rar_generic,
+       .set_vmdq               = &ixgbe_set_vmdq_82599,
+       .clear_vmdq             = &ixgbe_clear_vmdq_82599,
+       .init_rx_addrs          = &ixgbe_init_rx_addrs_generic,
+       .update_uc_addr_list    = &ixgbe_update_uc_addr_list_generic,
+       .update_mc_addr_list    = &ixgbe_update_mc_addr_list_generic,
+       .enable_mc              = &ixgbe_enable_mc_generic,
+       .disable_mc             = &ixgbe_disable_mc_generic,
+       .clear_vfta             = &ixgbe_clear_vfta_82599,
+       .set_vfta               = &ixgbe_set_vfta_82599,
+       .setup_fc               = &ixgbe_setup_fc_generic,
+       .init_uta_tables        = &ixgbe_init_uta_tables_82599,
+       .setup_sfp              = &ixgbe_setup_sfp_modules_82599,
+};
+
+static struct ixgbe_eeprom_operations eeprom_ops_82599 = {
+       .init_params            = &ixgbe_init_eeprom_params_generic,
+       .read                   = &ixgbe_read_eeprom_generic,
+       .write                  = &ixgbe_write_eeprom_generic,
+       .validate_checksum      = &ixgbe_validate_eeprom_checksum_generic,
+       .update_checksum        = &ixgbe_update_eeprom_checksum_generic,
+};
+
+static struct ixgbe_phy_operations phy_ops_82599 = {
+       .identify               = &ixgbe_identify_phy_82599,
+       .identify_sfp           = &ixgbe_identify_sfp_module_generic,
+       .reset                  = &ixgbe_reset_phy_generic,
+       .read_reg               = &ixgbe_read_phy_reg_generic,
+       .write_reg              = &ixgbe_write_phy_reg_generic,
+       .setup_link             = &ixgbe_setup_phy_link_generic,
+       .setup_link_speed       = &ixgbe_setup_phy_link_speed_generic,
+       .read_i2c_byte          = &ixgbe_read_i2c_byte_generic,
+       .write_i2c_byte         = &ixgbe_write_i2c_byte_generic,
+       .read_i2c_eeprom        = &ixgbe_read_i2c_eeprom_generic,
+       .write_i2c_eeprom       = &ixgbe_write_i2c_eeprom_generic,
+};
+
+struct ixgbe_info ixgbe_82599_info = {
+       .mac                    = ixgbe_mac_82599EB,
+       .get_invariants         = &ixgbe_get_invariants_82599,
+       .mac_ops                = &mac_ops_82599,
+       .eeprom_ops             = &eeprom_ops_82599,
+       .phy_ops                = &phy_ops_82599,
+};
index 5ae93989784f06f3e52993cfbbd0c696c11fcf91..245db0e712e7e91af2c59fe6e03d032891826408 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/delay.h>
 #include <linux/sched.h>
 
+#include "ixgbe.h"
 #include "ixgbe_common.h"
 #include "ixgbe_phy.h"
 
@@ -250,6 +251,81 @@ s32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr)
        return 0;
 }
 
+/**
+ *  ixgbe_get_bus_info_generic - Generic set PCI bus info
+ *  @hw: pointer to hardware structure
+ *
+ *  Sets the PCI bus info (speed, width, type) within the ixgbe_hw structure
+ **/
+s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw)
+{
+       struct ixgbe_adapter *adapter = hw->back;
+       struct ixgbe_mac_info *mac = &hw->mac;
+       u16 link_status;
+
+       hw->bus.type = ixgbe_bus_type_pci_express;
+
+       /* Get the negotiated link width and speed from PCI config space */
+       pci_read_config_word(adapter->pdev, IXGBE_PCI_LINK_STATUS,
+                            &link_status);
+
+       switch (link_status & IXGBE_PCI_LINK_WIDTH) {
+       case IXGBE_PCI_LINK_WIDTH_1:
+               hw->bus.width = ixgbe_bus_width_pcie_x1;
+               break;
+       case IXGBE_PCI_LINK_WIDTH_2:
+               hw->bus.width = ixgbe_bus_width_pcie_x2;
+               break;
+       case IXGBE_PCI_LINK_WIDTH_4:
+               hw->bus.width = ixgbe_bus_width_pcie_x4;
+               break;
+       case IXGBE_PCI_LINK_WIDTH_8:
+               hw->bus.width = ixgbe_bus_width_pcie_x8;
+               break;
+       default:
+               hw->bus.width = ixgbe_bus_width_unknown;
+               break;
+       }
+
+       switch (link_status & IXGBE_PCI_LINK_SPEED) {
+       case IXGBE_PCI_LINK_SPEED_2500:
+               hw->bus.speed = ixgbe_bus_speed_2500;
+               break;
+       case IXGBE_PCI_LINK_SPEED_5000:
+               hw->bus.speed = ixgbe_bus_speed_5000;
+               break;
+       default:
+               hw->bus.speed = ixgbe_bus_speed_unknown;
+               break;
+       }
+
+       mac->ops.set_lan_id(hw);
+
+       return 0;
+}
+
+/**
+ *  ixgbe_set_lan_id_multi_port_pcie - Set LAN id for PCIe multiple port devices
+ *  @hw: pointer to the HW structure
+ *
+ *  Determines the LAN function id by reading memory-mapped registers
+ *  and swaps the port value if requested.
+ **/
+void ixgbe_set_lan_id_multi_port_pcie(struct ixgbe_hw *hw)
+{
+       struct ixgbe_bus_info *bus = &hw->bus;
+       u32 reg;
+
+       reg = IXGBE_READ_REG(hw, IXGBE_STATUS);
+       bus->func = (reg & IXGBE_STATUS_LAN_ID) >> IXGBE_STATUS_LAN_ID_SHIFT;
+       bus->lan_id = bus->func;
+
+       /* check for a port swap */
+       reg = IXGBE_READ_REG(hw, IXGBE_FACTPS);
+       if (reg & IXGBE_FACTPS_LFS)
+               bus->func ^= 0x1;
+}
+
 /**
  *  ixgbe_stop_adapter_generic - Generic stop Tx/Rx units
  *  @hw: pointer to hardware structure
@@ -389,6 +465,73 @@ s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw)
        return 0;
 }
 
+/**
+ *  ixgbe_write_eeprom_generic - Writes 16 bit value to EEPROM
+ *  @hw: pointer to hardware structure
+ *  @offset: offset within the EEPROM to be written to
+ *  @data: 16 bit word to be written to the EEPROM
+ *
+ *  If ixgbe_eeprom_update_checksum is not called after this function, the
+ *  EEPROM will most likely contain an invalid checksum.
+ **/
+s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data)
+{
+       s32 status;
+       u8 write_opcode = IXGBE_EEPROM_WRITE_OPCODE_SPI;
+
+       hw->eeprom.ops.init_params(hw);
+
+       if (offset >= hw->eeprom.word_size) {
+               status = IXGBE_ERR_EEPROM;
+               goto out;
+       }
+
+       /* Prepare the EEPROM for writing  */
+       status = ixgbe_acquire_eeprom(hw);
+
+       if (status == 0) {
+               if (ixgbe_ready_eeprom(hw) != 0) {
+                       ixgbe_release_eeprom(hw);
+                       status = IXGBE_ERR_EEPROM;
+               }
+       }
+
+       if (status == 0) {
+               ixgbe_standby_eeprom(hw);
+
+               /*  Send the WRITE ENABLE command (8 bit opcode )  */
+               ixgbe_shift_out_eeprom_bits(hw, IXGBE_EEPROM_WREN_OPCODE_SPI,
+                                           IXGBE_EEPROM_OPCODE_BITS);
+
+               ixgbe_standby_eeprom(hw);
+
+               /*
+                * Some SPI eeproms use the 8th address bit embedded in the
+                * opcode
+                */
+               if ((hw->eeprom.address_bits == 8) && (offset >= 128))
+                       write_opcode |= IXGBE_EEPROM_A8_OPCODE_SPI;
+
+               /* Send the Write command (8-bit opcode + addr) */
+               ixgbe_shift_out_eeprom_bits(hw, write_opcode,
+                                           IXGBE_EEPROM_OPCODE_BITS);
+               ixgbe_shift_out_eeprom_bits(hw, (u16)(offset*2),
+                                           hw->eeprom.address_bits);
+
+               /* Send the data */
+               data = (data >> 8) | (data << 8);
+               ixgbe_shift_out_eeprom_bits(hw, data, 16);
+               ixgbe_standby_eeprom(hw);
+
+               msleep(hw->eeprom.semaphore_delay);
+               /* Done with writing - release the EEPROM */
+               ixgbe_release_eeprom(hw);
+       }
+
+out:
+       return status;
+}
+
 /**
  *  ixgbe_read_eeprom_bit_bang_generic - Read EEPROM word using bit-bang
  *  @hw: pointer to hardware structure
@@ -518,7 +661,7 @@ static s32 ixgbe_poll_eeprom_eerd_done(struct ixgbe_hw *hw)
 static s32 ixgbe_acquire_eeprom(struct ixgbe_hw *hw)
 {
        s32 status = 0;
-       u32 eec;
+       u32 eec = 0;
        u32 i;
 
        if (ixgbe_acquire_swfw_sync(hw, IXGBE_GSSR_EEP_SM) != 0)
@@ -1486,6 +1629,101 @@ s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw)
        return 0;
 }
 
+/**
+ *  ixgbe_fc_enable - Enable flow control
+ *  @hw: pointer to hardware structure
+ *  @packetbuf_num: packet buffer number (0-7)
+ *
+ *  Enable flow control according to the current settings.
+ **/
+s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packetbuf_num)
+{
+       s32 ret_val = 0;
+       u32 mflcn_reg;
+       u32 fccfg_reg;
+       u32 reg;
+
+       mflcn_reg = IXGBE_READ_REG(hw, IXGBE_MFLCN);
+       mflcn_reg &= ~(IXGBE_MFLCN_RFCE | IXGBE_MFLCN_RPFCE);
+
+       fccfg_reg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
+       fccfg_reg &= ~(IXGBE_FCCFG_TFCE_802_3X | IXGBE_FCCFG_TFCE_PRIORITY);
+
+       /*
+        * The possible values of fc.current_mode are:
+        * 0: Flow control is completely disabled
+        * 1: Rx flow control is enabled (we can receive pause frames,
+        *    but not send pause frames).
+        * 2:  Tx flow control is enabled (we can send pause frames but
+        *     we do not support receiving pause frames).
+        * 3: Both Rx and Tx flow control (symmetric) are enabled.
+        * other: Invalid.
+        */
+       switch (hw->fc.current_mode) {
+       case ixgbe_fc_none:
+               /* Flow control completely disabled by software override. */
+               break;
+       case ixgbe_fc_rx_pause:
+               /*
+                * Rx Flow control is enabled and Tx Flow control is
+                * disabled by software override. Since there really
+                * isn't a way to advertise that we are capable of RX
+                * Pause ONLY, we will advertise that we support both
+                * symmetric and asymmetric Rx PAUSE.  Later, we will
+                * disable the adapter's ability to send PAUSE frames.
+                */
+               mflcn_reg |= IXGBE_MFLCN_RFCE;
+               break;
+       case ixgbe_fc_tx_pause:
+               /*
+                * Tx Flow control is enabled, and Rx Flow control is
+                * disabled by software override.
+                */
+               fccfg_reg |= IXGBE_FCCFG_TFCE_802_3X;
+               break;
+       case ixgbe_fc_full:
+               /* Flow control (both Rx and Tx) is enabled by SW override. */
+               mflcn_reg |= IXGBE_MFLCN_RFCE;
+               fccfg_reg |= IXGBE_FCCFG_TFCE_802_3X;
+               break;
+       default:
+               hw_dbg(hw, "Flow control param set incorrectly\n");
+               ret_val = -IXGBE_ERR_CONFIG;
+               goto out;
+               break;
+       }
+
+       /* Enable 802.3x based flow control settings. */
+       IXGBE_WRITE_REG(hw, IXGBE_MFLCN, mflcn_reg);
+       IXGBE_WRITE_REG(hw, IXGBE_FCCFG, fccfg_reg);
+
+       /* Set up and enable Rx high/low water mark thresholds, enable XON. */
+       if (hw->fc.current_mode & ixgbe_fc_tx_pause) {
+               if (hw->fc.send_xon)
+                       IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num),
+                                       (hw->fc.low_water | IXGBE_FCRTL_XONE));
+               else
+                       IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(packetbuf_num),
+                                       hw->fc.low_water);
+
+               IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(packetbuf_num),
+                               (hw->fc.high_water | IXGBE_FCRTH_FCEN));
+       }
+
+       /* Configure pause time (2 TCs per register) */
+       reg = IXGBE_READ_REG(hw, IXGBE_FCTTV(packetbuf_num));
+       if ((packetbuf_num & 1) == 0)
+               reg = (reg & 0xFFFF0000) | hw->fc.pause_time;
+       else
+               reg = (reg & 0x0000FFFF) | (hw->fc.pause_time << 16);
+       IXGBE_WRITE_REG(hw, IXGBE_FCTTV(packetbuf_num / 2), reg);
+
+       IXGBE_WRITE_REG(hw, IXGBE_FCRTV, (hw->fc.pause_time >> 1));
+
+out:
+       return ret_val;
+}
+
 /**
  *  ixgbe_fc_autoneg - Configure flow control
  *  @hw: pointer to hardware structure
@@ -1624,6 +1862,74 @@ out:
        return ret_val;
 }
 
+/**
+ *  ixgbe_setup_fc_generic - Set up flow control
+ *  @hw: pointer to hardware structure
+ *
+ *  Sets up flow control.
+ **/
+s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num)
+{
+       s32 ret_val = 0;
+       ixgbe_link_speed speed;
+       bool link_up;
+
+       /* Validate the packetbuf configuration */
+       if (packetbuf_num < 0 || packetbuf_num > 7) {
+               hw_dbg(hw, "Invalid packet buffer number [%d], expected range "
+                      "is 0-7\n", packetbuf_num);
+               ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
+               goto out;
+       }
+
+       /*
+        * Validate the water mark configuration.  Zero water marks are invalid
+        * because it causes the controller to just blast out fc packets.
+        */
+       if (!hw->fc.low_water || !hw->fc.high_water || !hw->fc.pause_time) {
+               hw_dbg(hw, "Invalid water mark configuration\n");
+               ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
+               goto out;
+       }
+
+       /*
+        * Validate the requested mode.  Strict IEEE mode does not allow
+        * ixgbe_fc_rx_pause because it will cause testing anomalies.
+        */
+       if (hw->fc.strict_ieee && hw->fc.requested_mode == ixgbe_fc_rx_pause) {
+               hw_dbg(hw, "ixgbe_fc_rx_pause not valid in strict "
+                      "IEEE mode\n");
+               ret_val = IXGBE_ERR_INVALID_LINK_SETTINGS;
+               goto out;
+       }
+
+       /*
+        * 10gig parts do not have a word in the EEPROM to determine the
+        * default flow control setting, so we explicitly set it to full.
+        */
+       if (hw->fc.requested_mode == ixgbe_fc_default)
+               hw->fc.requested_mode = ixgbe_fc_full;
+
+       /*
+        * Save off the requested flow control mode for use later.  Depending
+        * on the link partner's capabilities, we may or may not use this mode.
+        */
+       hw->fc.current_mode = hw->fc.requested_mode;
+
+       /* Decide whether to use autoneg or not. */
+       hw->mac.ops.check_link(hw, &speed, &link_up, false);
+       if (hw->phy.multispeed_fiber && (speed == IXGBE_LINK_SPEED_1GB_FULL))
+               ret_val = ixgbe_fc_autoneg(hw);
+
+       if (ret_val)
+               goto out;
+
+       ret_val = ixgbe_fc_enable(hw, packetbuf_num);
+
+out:
+       return ret_val;
+}
+
 /**
  *  ixgbe_disable_pcie_master - Disable PCI-express master access
  *  @hw: pointer to hardware structure
@@ -1732,3 +2038,16 @@ void ixgbe_release_swfw_sync(struct ixgbe_hw *hw, u16 mask)
        ixgbe_release_eeprom_semaphore(hw);
 }
 
+/**
+ *  ixgbe_enable_rx_dma_generic - Enable the Rx DMA unit
+ *  @hw: pointer to hardware structure
+ *  @regval: register value to write to RXCTRL
+ *
+ *  Enables the Rx DMA unit
+ **/
+s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval)
+{
+       IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, regval);
+
+       return 0;
+}
index c63021261e56715fc4308bde459ce0188210ac2c..7e94d6d399abfc0b9ebe25c21cad39bcea12ff67 100644 (file)
@@ -37,12 +37,14 @@ s32 ixgbe_clear_hw_cntrs_generic(struct ixgbe_hw *hw);
 s32 ixgbe_read_pba_num_generic(struct ixgbe_hw *hw, u32 *pba_num);
 s32 ixgbe_get_mac_addr_generic(struct ixgbe_hw *hw, u8 *mac_addr);
 s32 ixgbe_get_bus_info_generic(struct ixgbe_hw *hw);
+void ixgbe_set_lan_id_multi_port_pcie(struct ixgbe_hw *hw);
 s32 ixgbe_stop_adapter_generic(struct ixgbe_hw *hw);
 
 s32 ixgbe_led_on_generic(struct ixgbe_hw *hw, u32 index);
 s32 ixgbe_led_off_generic(struct ixgbe_hw *hw, u32 index);
 
 s32 ixgbe_init_eeprom_params_generic(struct ixgbe_hw *hw);
+s32 ixgbe_write_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 data);
 s32 ixgbe_read_eeprom_generic(struct ixgbe_hw *hw, u16 offset, u16 *data);
 s32 ixgbe_read_eeprom_bit_bang_generic(struct ixgbe_hw *hw, u16 offset,
                                        u16 *data);
@@ -61,6 +63,7 @@ s32 ixgbe_update_uc_addr_list_generic(struct ixgbe_hw *hw, u8 *addr_list,
                                       u32 addr_count, ixgbe_mc_addr_itr func);
 s32 ixgbe_enable_mc_generic(struct ixgbe_hw *hw);
 s32 ixgbe_disable_mc_generic(struct ixgbe_hw *hw);
+s32 ixgbe_enable_rx_dma_generic(struct ixgbe_hw *hw, u32 regval);
 s32 ixgbe_setup_fc_generic(struct ixgbe_hw *hw, s32 packetbuf_num);
 s32 ixgbe_fc_enable(struct ixgbe_hw *hw, s32 packtetbuf_num);
 s32 ixgbe_fc_autoneg(struct ixgbe_hw *hw);
@@ -75,6 +78,13 @@ s32 ixgbe_write_analog_reg8_generic(struct ixgbe_hw *hw, u32 reg, u8 val);
 
 #define IXGBE_WRITE_REG(a, reg, value) writel((value), ((a)->hw_addr + (reg)))
 
+#ifndef writeq
+#define writeq(val, addr) writel((u32) (val), addr); \
+    writel((u32) (val >> 32), (addr + 4));
+#endif
+
+#define IXGBE_WRITE_REG64(a, reg, value) writeq((value), ((a)->hw_addr + (reg)))
+
 #define IXGBE_READ_REG(a, reg) readl((a)->hw_addr + (reg))
 
 #define IXGBE_WRITE_REG_ARRAY(a, reg, offset, value) (\
index 2a60c89ab3465e1aeec72be9c0ee89ddc94a760a..a1562287342fb13009deee7463c18c87f590574d 100644 (file)
@@ -31,6 +31,7 @@
 #include "ixgbe_type.h"
 #include "ixgbe_dcb.h"
 #include "ixgbe_dcb_82598.h"
+#include "ixgbe_dcb_82599.h"
 
 /**
  * ixgbe_dcb_config - Struct containing DCB settings.
@@ -215,6 +216,8 @@ s32 ixgbe_dcb_get_tc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats,
        s32 ret = 0;
        if (hw->mac.type == ixgbe_mac_82598EB)
                ret = ixgbe_dcb_get_tc_stats_82598(hw, stats, tc_count);
+       else if (hw->mac.type == ixgbe_mac_82599EB)
+               ret = ixgbe_dcb_get_tc_stats_82599(hw, stats, tc_count);
        return ret;
 }
 
@@ -232,6 +235,8 @@ s32 ixgbe_dcb_get_pfc_stats(struct ixgbe_hw *hw, struct ixgbe_hw_stats *stats,
        s32 ret = 0;
        if (hw->mac.type == ixgbe_mac_82598EB)
                ret = ixgbe_dcb_get_pfc_stats_82598(hw, stats, tc_count);
+       else if (hw->mac.type == ixgbe_mac_82599EB)
+               ret = ixgbe_dcb_get_pfc_stats_82599(hw, stats, tc_count);
        return ret;
 }
 
@@ -248,6 +253,8 @@ s32 ixgbe_dcb_config_rx_arbiter(struct ixgbe_hw *hw,
        s32 ret = 0;
        if (hw->mac.type == ixgbe_mac_82598EB)
                ret = ixgbe_dcb_config_rx_arbiter_82598(hw, dcb_config);
+       else if (hw->mac.type == ixgbe_mac_82599EB)
+               ret = ixgbe_dcb_config_rx_arbiter_82599(hw, dcb_config);
        return ret;
 }
 
@@ -264,6 +271,8 @@ s32 ixgbe_dcb_config_tx_desc_arbiter(struct ixgbe_hw *hw,
        s32 ret = 0;
        if (hw->mac.type == ixgbe_mac_82598EB)
                ret = ixgbe_dcb_config_tx_desc_arbiter_82598(hw, dcb_config);
+       else if (hw->mac.type == ixgbe_mac_82599EB)
+               ret = ixgbe_dcb_config_tx_desc_arbiter_82599(hw, dcb_config);
        return ret;
 }
 
@@ -280,6 +289,8 @@ s32 ixgbe_dcb_config_tx_data_arbiter(struct ixgbe_hw *hw,
        s32 ret = 0;
        if (hw->mac.type == ixgbe_mac_82598EB)
                ret = ixgbe_dcb_config_tx_data_arbiter_82598(hw, dcb_config);
+       else if (hw->mac.type == ixgbe_mac_82599EB)
+               ret = ixgbe_dcb_config_tx_data_arbiter_82599(hw, dcb_config);
        return ret;
 }
 
@@ -296,6 +307,8 @@ s32 ixgbe_dcb_config_pfc(struct ixgbe_hw *hw,
        s32 ret = 0;
        if (hw->mac.type == ixgbe_mac_82598EB)
                ret = ixgbe_dcb_config_pfc_82598(hw, dcb_config);
+       else if (hw->mac.type == ixgbe_mac_82599EB)
+               ret = ixgbe_dcb_config_pfc_82599(hw, dcb_config);
        return ret;
 }
 
@@ -311,6 +324,8 @@ s32 ixgbe_dcb_config_tc_stats(struct ixgbe_hw *hw)
        s32 ret = 0;
        if (hw->mac.type == ixgbe_mac_82598EB)
                ret = ixgbe_dcb_config_tc_stats_82598(hw);
+       else if (hw->mac.type == ixgbe_mac_82599EB)
+               ret = ixgbe_dcb_config_tc_stats_82599(hw);
        return ret;
 }
 
@@ -327,6 +342,8 @@ s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw,
        s32 ret = 0;
        if (hw->mac.type == ixgbe_mac_82598EB)
                ret = ixgbe_dcb_hw_config_82598(hw, dcb_config);
+       else if (hw->mac.type == ixgbe_mac_82599EB)
+               ret = ixgbe_dcb_hw_config_82599(hw, dcb_config);
        return ret;
 }
 
index 0da5c6d5bcafc3207dd8a3dc980a242cd1a610f9..64a9fa15c059643f79db6b35aed1dd93455e0553 100644 (file)
@@ -75,6 +75,26 @@ enum strict_prio_type {
        prio_link
 };
 
+/* DCB capability definitions */
+#define IXGBE_DCB_PG_SUPPORT        0x00000001
+#define IXGBE_DCB_PFC_SUPPORT       0x00000002
+#define IXGBE_DCB_BCN_SUPPORT       0x00000004
+#define IXGBE_DCB_UP2TC_SUPPORT     0x00000008
+#define IXGBE_DCB_GSP_SUPPORT       0x00000010
+
+#define IXGBE_DCB_8_TC_SUPPORT      0x80
+
+struct dcb_support {
+       /* DCB capabilities */
+       u32 capabilities;
+
+       /* Each bit represents a number of TCs configurable in the hw.
+        * If 8 traffic classes can be configured, the value is 0x80.
+        */
+       u8  traffic_classes;
+       u8  pfc_traffic_classes;
+};
+
 /* Traffic class bandwidth allocation per direction */
 struct tc_bw_alloc {
        u8 bwg_id;                /* Bandwidth Group (BWG) ID */
@@ -108,38 +128,18 @@ enum dcb_rx_pba_cfg {
        pba_80_48      /* PBA[0-3] each use 80KB, PBA[4-7] each use 48KB */
 };
 
-/*
- * This structure contains many values encoded as fixed-point
- * numbers, meaning that some of bits are dedicated to the
- * magnitude and others to the fraction part. In the comments
- * this is shown as f=n, where n is the number of fraction bits.
- * These fraction bits are always the low-order bits. The size
- * of the magnitude is not specified.
- */
-struct bcn_config {
-       u32 rp_admin_mode[MAX_TRAFFIC_CLASS]; /* BCN enabled, per TC */
-       u32 bcna_option[2]; /* BCNA Port + MAC Addr */
-       u32 rp_w;        /* Derivative Weight, f=3 */
-       u32 rp_gi;       /* Increase Gain, f=12 */
-       u32 rp_gd;       /* Decrease Gain, f=12 */
-       u32 rp_ru;       /* Rate Unit */
-       u32 rp_alpha;    /* Max Decrease Factor, f=12 */
-       u32 rp_beta;     /* Max Increase Factor, f=12 */
-       u32 rp_ri;       /* Initial Rate */
-       u32 rp_td;       /* Drift Interval Timer */
-       u32 rp_rd;       /* Drift Increase */
-       u32 rp_tmax;     /* Severe Congestion Backoff Timer Range */
-       u32 rp_rmin;     /* Severe Congestion Restart Rate */
-       u32 rp_wrtt;     /* RTT Moving Average Weight */
+struct dcb_num_tcs {
+       u8 pg_tcs;
+       u8 pfc_tcs;
 };
 
 struct ixgbe_dcb_config {
-       struct bcn_config bcn;
-
+       struct dcb_support support;
+       struct dcb_num_tcs num_tcs;
        struct tc_configuration tc_config[MAX_TRAFFIC_CLASS];
        u8     bw_percentage[2][MAX_BW_GROUP]; /* One each for Tx/Rx */
-
-       bool  round_robin_enable;
+       bool   pfc_mode_enable;
+       bool   round_robin_enable;
 
        enum dcb_rx_pba_cfg rx_pba_cfg;
 
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.c b/drivers/net/ixgbe/ixgbe_dcb_82599.c
new file mode 100644 (file)
index 0000000..adcbac4
--- /dev/null
@@ -0,0 +1,470 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#include "ixgbe.h"
+#include "ixgbe_type.h"
+#include "ixgbe_dcb.h"
+#include "ixgbe_dcb_82599.h"
+
+/**
+ * ixgbe_dcb_get_tc_stats_82599 - Returns status for each traffic class
+ * @hw: pointer to hardware structure
+ * @stats: pointer to statistics structure
+ * @tc_count:  Number of elements in bwg_array.
+ *
+ * This function returns the status data for each of the Traffic Classes in use.
+ */
+s32 ixgbe_dcb_get_tc_stats_82599(struct ixgbe_hw *hw,
+                                 struct ixgbe_hw_stats *stats,
+                                 u8 tc_count)
+{
+       int tc;
+
+       if (tc_count > MAX_TRAFFIC_CLASS)
+               return DCB_ERR_PARAM;
+       /* Statistics pertaining to each traffic class */
+       for (tc = 0; tc < tc_count; tc++) {
+               /* Transmitted Packets */
+               stats->qptc[tc] += IXGBE_READ_REG(hw, IXGBE_QPTC(tc));
+               /* Transmitted Bytes */
+               stats->qbtc[tc] += IXGBE_READ_REG(hw, IXGBE_QBTC(tc));
+               /* Received Packets */
+               stats->qprc[tc] += IXGBE_READ_REG(hw, IXGBE_QPRC(tc));
+               /* Received Bytes */
+               stats->qbrc[tc] += IXGBE_READ_REG(hw, IXGBE_QBRC(tc));
+       }
+
+       return 0;
+}
+
+/**
+ * ixgbe_dcb_get_pfc_stats_82599 - Return CBFC status data
+ * @hw: pointer to hardware structure
+ * @stats: pointer to statistics structure
+ * @tc_count:  Number of elements in bwg_array.
+ *
+ * This function returns the CBFC status data for each of the Traffic Classes.
+ */
+s32 ixgbe_dcb_get_pfc_stats_82599(struct ixgbe_hw *hw,
+                                  struct ixgbe_hw_stats *stats,
+                                  u8 tc_count)
+{
+       int tc;
+
+       if (tc_count > MAX_TRAFFIC_CLASS)
+               return DCB_ERR_PARAM;
+       for (tc = 0; tc < tc_count; tc++) {
+               /* Priority XOFF Transmitted */
+               stats->pxofftxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFTXC(tc));
+               /* Priority XOFF Received */
+               stats->pxoffrxc[tc] += IXGBE_READ_REG(hw, IXGBE_PXOFFRXCNT(tc));
+       }
+
+       return 0;
+}
+
+/**
+ * ixgbe_dcb_config_packet_buffers_82599 - Configure DCB packet buffers
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure packet buffers for DCB mode.
+ */
+s32 ixgbe_dcb_config_packet_buffers_82599(struct ixgbe_hw *hw,
+                                          struct ixgbe_dcb_config *dcb_config)
+{
+       s32 ret_val = 0;
+       u32 value = IXGBE_RXPBSIZE_64KB;
+       u8  i = 0;
+
+       /* Setup Rx packet buffer sizes */
+       switch (dcb_config->rx_pba_cfg) {
+       case pba_80_48:
+               /* Setup the first four at 80KB */
+               value = IXGBE_RXPBSIZE_80KB;
+               for (; i < 4; i++)
+                       IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value);
+               /* Setup the last four at 48KB...don't re-init i */
+               value = IXGBE_RXPBSIZE_48KB;
+               /* Fall Through */
+       case pba_equal:
+       default:
+               for (; i < IXGBE_MAX_PACKET_BUFFERS; i++)
+                       IXGBE_WRITE_REG(hw, IXGBE_RXPBSIZE(i), value);
+
+               /* Setup Tx packet buffer sizes */
+               for (i = 0; i < IXGBE_MAX_PACKET_BUFFERS; i++) {
+                       IXGBE_WRITE_REG(hw, IXGBE_TXPBSIZE(i),
+                                       IXGBE_TXPBSIZE_20KB);
+                       IXGBE_WRITE_REG(hw, IXGBE_TXPBTHRESH(i),
+                                       IXGBE_TXPBTHRESH_DCB);
+               }
+               break;
+       }
+
+       return ret_val;
+}
+
+/**
+ * ixgbe_dcb_config_rx_arbiter_82599 - Config Rx Data arbiter
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure Rx Packet Arbiter and credits for each traffic class.
+ */
+s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw,
+                                      struct ixgbe_dcb_config *dcb_config)
+{
+       struct tc_bw_alloc    *p;
+       u32    reg           = 0;
+       u32    credit_refill = 0;
+       u32    credit_max    = 0;
+       u8     i             = 0;
+
+       /* Disable the arbiter before changing parameters */
+       IXGBE_WRITE_REG(hw, IXGBE_RTRPCS, IXGBE_RTRPCS_ARBDIS);
+
+       /* Map all traffic classes to their UP, 1 to 1 */
+       reg = 0;
+       for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
+               reg |= (i << (i * IXGBE_RTRUP2TC_UP_SHIFT));
+       IXGBE_WRITE_REG(hw, IXGBE_RTRUP2TC, reg);
+
+       /* Configure traffic class credits and priority */
+       for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+               p = &dcb_config->tc_config[i].path[DCB_RX_CONFIG];
+
+               credit_refill = p->data_credits_refill;
+               credit_max    = p->data_credits_max;
+               reg = credit_refill | (credit_max << IXGBE_RTRPT4C_MCL_SHIFT);
+
+               reg |= (u32)(p->bwg_id) << IXGBE_RTRPT4C_BWG_SHIFT;
+
+               if (p->prio_type == prio_link)
+                       reg |= IXGBE_RTRPT4C_LSP;
+
+               IXGBE_WRITE_REG(hw, IXGBE_RTRPT4C(i), reg);
+       }
+
+       /*
+        * Configure Rx packet plane (recycle mode; WSP) and
+        * enable arbiter
+        */
+       reg = IXGBE_RTRPCS_RRM | IXGBE_RTRPCS_RAC;
+       IXGBE_WRITE_REG(hw, IXGBE_RTRPCS, reg);
+
+       return 0;
+}
+
+/**
+ * ixgbe_dcb_config_tx_desc_arbiter_82599 - Config Tx Desc. arbiter
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure Tx Descriptor Arbiter and credits for each traffic class.
+ */
+s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw,
+                                           struct ixgbe_dcb_config *dcb_config)
+{
+       struct tc_bw_alloc *p;
+       u32    reg, max_credits;
+       u8     i;
+
+       /* Disable the arbiter before changing parameters */
+       IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, IXGBE_RTTDCS_ARBDIS);
+
+       /* Clear the per-Tx queue credits; we use per-TC instead */
+       for (i = 0; i < 128; i++) {
+               IXGBE_WRITE_REG(hw, IXGBE_RTTDQSEL, i);
+               IXGBE_WRITE_REG(hw, IXGBE_RTTDT1C, 0);
+       }
+
+       /* Configure traffic class credits and priority */
+       for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+               p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG];
+               max_credits = dcb_config->tc_config[i].desc_credits_max;
+               reg = max_credits << IXGBE_RTTDT2C_MCL_SHIFT;
+               reg |= p->data_credits_refill;
+               reg |= (u32)(p->bwg_id) << IXGBE_RTTDT2C_BWG_SHIFT;
+
+               if (p->prio_type == prio_group)
+                       reg |= IXGBE_RTTDT2C_GSP;
+
+               if (p->prio_type == prio_link)
+                       reg |= IXGBE_RTTDT2C_LSP;
+
+               IXGBE_WRITE_REG(hw, IXGBE_RTTDT2C(i), reg);
+       }
+
+       /*
+        * Configure Tx descriptor plane (recycle mode; WSP) and
+        * enable arbiter
+        */
+       reg = IXGBE_RTTDCS_TDPAC | IXGBE_RTTDCS_TDRM;
+       IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, reg);
+
+       return 0;
+}
+
+/**
+ * ixgbe_dcb_config_tx_data_arbiter_82599 - Config Tx Data arbiter
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure Tx Packet Arbiter and credits for each traffic class.
+ */
+s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw,
+                                           struct ixgbe_dcb_config *dcb_config)
+{
+       struct tc_bw_alloc *p;
+       u32 reg;
+       u8 i;
+
+       /* Disable the arbiter before changing parameters */
+       IXGBE_WRITE_REG(hw, IXGBE_RTTPCS, IXGBE_RTTPCS_ARBDIS);
+
+       /* Map all traffic classes to their UP, 1 to 1 */
+       reg = 0;
+       for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
+               reg |= (i << (i * IXGBE_RTTUP2TC_UP_SHIFT));
+       IXGBE_WRITE_REG(hw, IXGBE_RTTUP2TC, reg);
+
+       /* Configure traffic class credits and priority */
+       for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+               p = &dcb_config->tc_config[i].path[DCB_TX_CONFIG];
+               reg = p->data_credits_refill;
+               reg |= (u32)(p->data_credits_max) << IXGBE_RTTPT2C_MCL_SHIFT;
+               reg |= (u32)(p->bwg_id) << IXGBE_RTTPT2C_BWG_SHIFT;
+
+               if (p->prio_type == prio_group)
+                       reg |= IXGBE_RTTPT2C_GSP;
+
+               if (p->prio_type == prio_link)
+                       reg |= IXGBE_RTTPT2C_LSP;
+
+               IXGBE_WRITE_REG(hw, IXGBE_RTTPT2C(i), reg);
+       }
+
+       /*
+        * Configure Tx packet plane (recycle mode; SP; arb delay) and
+        * enable arbiter
+        */
+       reg = IXGBE_RTTPCS_TPPAC | IXGBE_RTTPCS_TPRM |
+             (IXGBE_RTTPCS_ARBD_DCB << IXGBE_RTTPCS_ARBD_SHIFT);
+       IXGBE_WRITE_REG(hw, IXGBE_RTTPCS, reg);
+
+       return 0;
+}
+
+/**
+ * ixgbe_dcb_config_pfc_82599 - Configure priority flow control
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure Priority Flow Control (PFC) for each traffic class.
+ */
+s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw,
+                               struct ixgbe_dcb_config *dcb_config)
+{
+       u32 i, reg;
+
+       /* If PFC is disabled globally then fall back to LFC. */
+       if (!dcb_config->pfc_mode_enable) {
+               for (i = 0; i < MAX_TRAFFIC_CLASS; i++)
+                       hw->mac.ops.setup_fc(hw, i);
+               goto out;
+       }
+
+       /* PFC is mutually exclusive with link flow control */
+       hw->fc.current_mode = ixgbe_fc_none;
+
+       /* Configure PFC Tx thresholds per TC */
+       for (i = 0; i < MAX_TRAFFIC_CLASS; i++) {
+               /* Config and remember Tx */
+               if (dcb_config->tc_config[i].dcb_pfc == pfc_enabled_full ||
+                   dcb_config->tc_config[i].dcb_pfc == pfc_enabled_tx) {
+                       reg = hw->fc.high_water | IXGBE_FCRTH_FCEN;
+                       IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(i), reg);
+                       reg = hw->fc.low_water | IXGBE_FCRTL_XONE;
+                       IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), reg);
+               } else {
+                       IXGBE_WRITE_REG(hw, IXGBE_FCRTH_82599(i), 0);
+                       IXGBE_WRITE_REG(hw, IXGBE_FCRTL_82599(i), 0);
+               }
+       }
+
+       /* Configure pause time (2 TCs per register) */
+       reg = hw->fc.pause_time | (hw->fc.pause_time << 16);
+       for (i = 0; i < (MAX_TRAFFIC_CLASS / 2); i++)
+               IXGBE_WRITE_REG(hw, IXGBE_FCTTV(i), reg);
+
+       /* Configure flow control refresh threshold value */
+       IXGBE_WRITE_REG(hw, IXGBE_FCRTV, hw->fc.pause_time / 2);
+
+       /* Enable Transmit PFC */
+       reg = IXGBE_FCCFG_TFCE_PRIORITY;
+       IXGBE_WRITE_REG(hw, IXGBE_FCCFG, reg);
+
+       /*
+        * Enable Receive PFC
+        * We will always honor XOFF frames we receive when
+        * we are in PFC mode.
+        */
+       reg = IXGBE_READ_REG(hw, IXGBE_MFLCN);
+       reg &= ~IXGBE_MFLCN_RFCE;
+       reg |= IXGBE_MFLCN_RPFCE;
+       IXGBE_WRITE_REG(hw, IXGBE_MFLCN, reg);
+out:
+       return 0;
+}
+
+/**
+ * ixgbe_dcb_config_tc_stats_82599 - Config traffic class statistics
+ * @hw: pointer to hardware structure
+ *
+ * Configure queue statistics registers, all queues belonging to same traffic
+ * class uses a single set of queue statistics counters.
+ */
+s32 ixgbe_dcb_config_tc_stats_82599(struct ixgbe_hw *hw)
+{
+       u32 reg = 0;
+       u8  i   = 0;
+
+       /*
+        * Receive Queues stats setting
+        * 32 RQSMR registers, each configuring 4 queues.
+        * Set all 16 queues of each TC to the same stat
+        * with TC 'n' going to stat 'n'.
+        */
+       for (i = 0; i < 32; i++) {
+               reg = 0x01010101 * (i / 4);
+               IXGBE_WRITE_REG(hw, IXGBE_RQSMR(i), reg);
+       }
+       /*
+        * Transmit Queues stats setting
+        * 32 TQSM registers, each controlling 4 queues.
+        * Set all queues of each TC to the same stat
+        * with TC 'n' going to stat 'n'.
+        * Tx queues are allocated non-uniformly to TCs:
+        * 32, 32, 16, 16, 8, 8, 8, 8.
+        */
+       for (i = 0; i < 32; i++) {
+               if (i < 8)
+                       reg = 0x00000000;
+               else if (i < 16)
+                       reg = 0x01010101;
+               else if (i < 20)
+                       reg = 0x02020202;
+               else if (i < 24)
+                       reg = 0x03030303;
+               else if (i < 26)
+                       reg = 0x04040404;
+               else if (i < 28)
+                       reg = 0x05050505;
+               else if (i < 30)
+                       reg = 0x06060606;
+               else
+                       reg = 0x07070707;
+               IXGBE_WRITE_REG(hw, IXGBE_TQSM(i), reg);
+       }
+
+       return 0;
+}
+
+/**
+ * ixgbe_dcb_config_82599 - Configure general DCB parameters
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure general DCB parameters.
+ */
+s32 ixgbe_dcb_config_82599(struct ixgbe_hw *hw)
+{
+       u32 reg;
+       u32 q;
+
+       /* Disable the Tx desc arbiter so that MTQC can be changed */
+       reg = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
+       reg |= IXGBE_RTTDCS_ARBDIS;
+       IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, reg);
+
+       /* Enable DCB for Rx with 8 TCs */
+       reg = IXGBE_READ_REG(hw, IXGBE_MRQC);
+       switch (reg & IXGBE_MRQC_MRQE_MASK) {
+       case 0:
+       case IXGBE_MRQC_RT4TCEN:
+               /* RSS disabled cases */
+               reg = (reg & ~IXGBE_MRQC_MRQE_MASK) | IXGBE_MRQC_RT8TCEN;
+               break;
+       case IXGBE_MRQC_RSSEN:
+       case IXGBE_MRQC_RTRSS4TCEN:
+               /* RSS enabled cases */
+               reg = (reg & ~IXGBE_MRQC_MRQE_MASK) | IXGBE_MRQC_RTRSS8TCEN;
+               break;
+       default:
+               /* Unsupported value, assume stale data, overwrite no RSS */
+               reg = (reg & ~IXGBE_MRQC_MRQE_MASK) | IXGBE_MRQC_RT8TCEN;
+       }
+       IXGBE_WRITE_REG(hw, IXGBE_MRQC, reg);
+
+       /* Enable DCB for Tx with 8 TCs */
+       reg = IXGBE_MTQC_RT_ENA | IXGBE_MTQC_8TC_8TQ;
+       IXGBE_WRITE_REG(hw, IXGBE_MTQC, reg);
+
+       /* Disable drop for all queues */
+       for (q = 0; q < 128; q++)
+               IXGBE_WRITE_REG(hw, IXGBE_QDE, q << IXGBE_QDE_IDX_SHIFT);
+
+       /* Enable the Tx desc arbiter */
+       reg = IXGBE_READ_REG(hw, IXGBE_RTTDCS);
+       reg &= ~IXGBE_RTTDCS_ARBDIS;
+       IXGBE_WRITE_REG(hw, IXGBE_RTTDCS, reg);
+
+       return 0;
+}
+
+/**
+ * ixgbe_dcb_hw_config_82599 - Configure and enable DCB
+ * @hw: pointer to hardware structure
+ * @dcb_config: pointer to ixgbe_dcb_config structure
+ *
+ * Configure dcb settings and enable dcb mode.
+ */
+s32 ixgbe_dcb_hw_config_82599(struct ixgbe_hw *hw,
+                              struct ixgbe_dcb_config *dcb_config)
+{
+       ixgbe_dcb_config_packet_buffers_82599(hw, dcb_config);
+       ixgbe_dcb_config_82599(hw);
+       ixgbe_dcb_config_rx_arbiter_82599(hw, dcb_config);
+       ixgbe_dcb_config_tx_desc_arbiter_82599(hw, dcb_config);
+       ixgbe_dcb_config_tx_data_arbiter_82599(hw, dcb_config);
+       ixgbe_dcb_config_pfc_82599(hw, dcb_config);
+       ixgbe_dcb_config_tc_stats_82599(hw);
+
+       return 0;
+}
+
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82599.h b/drivers/net/ixgbe/ixgbe_dcb_82599.h
new file mode 100644 (file)
index 0000000..9e5e282
--- /dev/null
@@ -0,0 +1,127 @@
+/*******************************************************************************
+
+  Intel 10 Gigabit PCI Express Linux driver
+  Copyright(c) 1999 - 2009 Intel Corporation.
+
+  This program is free software; you can redistribute it and/or modify it
+  under the terms and conditions of the GNU General Public License,
+  version 2, as published by the Free Software Foundation.
+
+  This program is distributed in the hope it will be useful, but WITHOUT
+  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+  FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+  more details.
+
+  You should have received a copy of the GNU General Public License along with
+  this program; if not, write to the Free Software Foundation, Inc.,
+  51 Franklin St - Fifth Floor, Boston, MA 02110-1301 USA.
+
+  The full GNU General Public License is included in this distribution in
+  the file called "COPYING".
+
+  Contact Information:
+  e1000-devel Mailing List <e1000-devel@lists.sourceforge.net>
+  Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
+
+*******************************************************************************/
+
+#ifndef _DCB_82599_CONFIG_H_
+#define _DCB_82599_CONFIG_H_
+
+/* DCB register definitions */
+#define IXGBE_RTTDCS_TDPAC      0x00000001 /* 0 Round Robin,
+                                            * 1 WSP - Weighted Strict Priority
+                                            */
+#define IXGBE_RTTDCS_VMPAC      0x00000002 /* 0 Round Robin,
+                                            * 1 WRR - Weighted Round Robin
+                                            */
+#define IXGBE_RTTDCS_TDRM       0x00000010 /* Transmit Recycle Mode */
+#define IXGBE_RTTDCS_ARBDIS     0x00000040 /* DCB arbiter disable */
+#define IXGBE_RTTDCS_BDPM       0x00400000 /* Bypass Data Pipe - must clear! */
+#define IXGBE_RTTDCS_BPBFSM     0x00800000 /* Bypass PB Free Space - must
+                                             * clear!
+                                             */
+#define IXGBE_RTTDCS_SPEED_CHG  0x80000000 /* Link speed change */
+
+/* Receive UP2TC mapping */
+#define IXGBE_RTRUP2TC_UP_SHIFT 3
+/* Transmit UP2TC mapping */
+#define IXGBE_RTTUP2TC_UP_SHIFT 3
+
+#define IXGBE_RTRPT4C_MCL_SHIFT 12 /* Offset to Max Credit Limit setting */
+#define IXGBE_RTRPT4C_BWG_SHIFT 9  /* Offset to BWG index */
+#define IXGBE_RTRPT4C_GSP       0x40000000 /* GSP enable bit */
+#define IXGBE_RTRPT4C_LSP       0x80000000 /* LSP enable bit */
+
+#define IXGBE_RDRXCTL_MPBEN     0x00000010 /* DMA config for multiple packet
+                                            * buffers enable
+                                            */
+#define IXGBE_RDRXCTL_MCEN      0x00000040 /* DMA config for multiple cores
+                                            * (RSS) enable
+                                            */
+
+/* RTRPCS Bit Masks */
+#define IXGBE_RTRPCS_RRM        0x00000002 /* Receive Recycle Mode enable */
+/* Receive Arbitration Control: 0 Round Robin, 1 DFP */
+#define IXGBE_RTRPCS_RAC        0x00000004
+#define IXGBE_RTRPCS_ARBDIS     0x00000040 /* Arbitration disable bit */
+
+/* RTTDT2C Bit Masks */
+#define IXGBE_RTTDT2C_MCL_SHIFT 12
+#define IXGBE_RTTDT2C_BWG_SHIFT 9
+#define IXGBE_RTTDT2C_GSP       0x40000000
+#define IXGBE_RTTDT2C_LSP       0x80000000
+
+#define IXGBE_RTTPT2C_MCL_SHIFT 12
+#define IXGBE_RTTPT2C_BWG_SHIFT 9
+#define IXGBE_RTTPT2C_GSP       0x40000000
+#define IXGBE_RTTPT2C_LSP       0x80000000
+
+/* RTTPCS Bit Masks */
+#define IXGBE_RTTPCS_TPPAC      0x00000020 /* 0 Round Robin,
+                                            * 1 SP - Strict Priority
+                                            */
+#define IXGBE_RTTPCS_ARBDIS     0x00000040 /* Arbiter disable */
+#define IXGBE_RTTPCS_TPRM       0x00000100 /* Transmit Recycle Mode enable */
+#define IXGBE_RTTPCS_ARBD_SHIFT 22
+#define IXGBE_RTTPCS_ARBD_DCB   0x4        /* Arbitration delay in DCB mode */
+
+#define IXGBE_TXPBSIZE_20KB     0x00005000 /* 20KB Packet Buffer */
+#define IXGBE_TXPBSIZE_40KB     0x0000A000 /* 40KB Packet Buffer */
+#define IXGBE_RXPBSIZE_48KB     0x0000C000 /* 48KB Packet Buffer */
+#define IXGBE_RXPBSIZE_64KB     0x00010000 /* 64KB Packet Buffer */
+#define IXGBE_RXPBSIZE_80KB     0x00014000 /* 80KB Packet Buffer */
+#define IXGBE_RXPBSIZE_128KB    0x00020000 /* 128KB Packet Buffer */
+
+#define IXGBE_TXPBTHRESH_DCB    0xA        /* THRESH value for DCB mode */
+
+
+/* DCB hardware-specific driver APIs */
+
+/* DCB PFC functions */
+s32 ixgbe_dcb_config_pfc_82599(struct ixgbe_hw *hw,
+                               struct ixgbe_dcb_config *dcb_config);
+s32 ixgbe_dcb_get_pfc_stats_82599(struct ixgbe_hw *hw,
+                                  struct ixgbe_hw_stats *stats,
+                                  u8 tc_count);
+
+/* DCB traffic class stats */
+s32 ixgbe_dcb_config_tc_stats_82599(struct ixgbe_hw *hw);
+s32 ixgbe_dcb_get_tc_stats_82599(struct ixgbe_hw *hw,
+                                 struct ixgbe_hw_stats *stats,
+                                 u8 tc_count);
+
+/* DCB config arbiters */
+s32 ixgbe_dcb_config_tx_desc_arbiter_82599(struct ixgbe_hw *hw,
+                                           struct ixgbe_dcb_config *dcb_config);
+s32 ixgbe_dcb_config_tx_data_arbiter_82599(struct ixgbe_hw *hw,
+                                           struct ixgbe_dcb_config *dcb_config);
+s32 ixgbe_dcb_config_rx_arbiter_82599(struct ixgbe_hw *hw,
+                                      struct ixgbe_dcb_config *dcb_config);
+
+
+/* DCB hw initialization */
+s32 ixgbe_dcb_hw_config_82599(struct ixgbe_hw *hw,
+                              struct ixgbe_dcb_config *config);
+
+#endif /* _DCB_82599_CONFIG_H */
index dd9d1d63a59c0fb069cd3d6c5a5b086e8c06bbfe..8a9939ee2927893f2c594d71d246eb6a20c3ec51 100644 (file)
@@ -35,6 +35,7 @@
 #define BIT_PG_RX      0x04
 #define BIT_PG_TX      0x08
 #define BIT_BCN         0x10
+#define BIT_LINKSPEED   0x80
 
 int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg,
                        struct ixgbe_dcb_config *dst_dcb_cfg, int tc_max)
@@ -89,25 +90,6 @@ int ixgbe_copy_dcb_cfg(struct ixgbe_dcb_config *src_dcb_cfg,
                        src_dcb_cfg->tc_config[i - DCB_PFC_UP_ATTR_0].dcb_pfc;
        }
 
-       for (i = DCB_BCN_ATTR_RP_0; i < DCB_BCN_ATTR_RP_ALL; i++) {
-               dst_dcb_cfg->bcn.rp_admin_mode[i - DCB_BCN_ATTR_RP_0] =
-                       src_dcb_cfg->bcn.rp_admin_mode[i - DCB_BCN_ATTR_RP_0];
-       }
-       dst_dcb_cfg->bcn.bcna_option[0] = src_dcb_cfg->bcn.bcna_option[0];
-       dst_dcb_cfg->bcn.bcna_option[1] = src_dcb_cfg->bcn.bcna_option[1];
-       dst_dcb_cfg->bcn.rp_alpha = src_dcb_cfg->bcn.rp_alpha;
-       dst_dcb_cfg->bcn.rp_beta = src_dcb_cfg->bcn.rp_beta;
-       dst_dcb_cfg->bcn.rp_gd = src_dcb_cfg->bcn.rp_gd;
-       dst_dcb_cfg->bcn.rp_gi = src_dcb_cfg->bcn.rp_gi;
-       dst_dcb_cfg->bcn.rp_tmax = src_dcb_cfg->bcn.rp_tmax;
-       dst_dcb_cfg->bcn.rp_td = src_dcb_cfg->bcn.rp_td;
-       dst_dcb_cfg->bcn.rp_rmin = src_dcb_cfg->bcn.rp_rmin;
-       dst_dcb_cfg->bcn.rp_w = src_dcb_cfg->bcn.rp_w;
-       dst_dcb_cfg->bcn.rp_rd = src_dcb_cfg->bcn.rp_rd;
-       dst_dcb_cfg->bcn.rp_ru = src_dcb_cfg->bcn.rp_ru;
-       dst_dcb_cfg->bcn.rp_wrtt = src_dcb_cfg->bcn.rp_wrtt;
-       dst_dcb_cfg->bcn.rp_ri = src_dcb_cfg->bcn.rp_ri;
-
        return 0;
 }
 
@@ -120,12 +102,6 @@ static u8 ixgbe_dcbnl_get_state(struct net_device *netdev)
        return !!(adapter->flags & IXGBE_FLAG_DCB_ENABLED);
 }
 
-static u16 ixgbe_dcb_select_queue(struct net_device *dev, struct sk_buff *skb)
-{
-       /* All traffic should default to class 0 */
-       return 0;
-}
-
 static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state)
 {
        u8 err = 0;
@@ -153,7 +129,6 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state)
                kfree(adapter->rx_ring);
                adapter->tx_ring = NULL;
                adapter->rx_ring = NULL;
-               netdev->select_queue = &ixgbe_dcb_select_queue;
 
                adapter->flags &= ~IXGBE_FLAG_RSS_ENABLED;
                adapter->flags |= IXGBE_FLAG_DCB_ENABLED;
@@ -172,7 +147,6 @@ static u8 ixgbe_dcbnl_set_state(struct net_device *netdev, u8 state)
                        kfree(adapter->rx_ring);
                        adapter->tx_ring = NULL;
                        adapter->rx_ring = NULL;
-                       netdev->select_queue = NULL;
 
                        adapter->flags &= ~IXGBE_FLAG_DCB_ENABLED;
                        adapter->flags |= IXGBE_FLAG_RSS_ENABLED;
@@ -444,175 +418,6 @@ static void ixgbe_dcbnl_setpfcstate(struct net_device *netdev, u8 state)
        return;
 }
 
-static void ixgbe_dcbnl_getbcnrp(struct net_device *netdev, int priority,
-                                 u8 *setting)
-{
-       struct ixgbe_adapter *adapter = netdev_priv(netdev);
-
-       *setting = adapter->dcb_cfg.bcn.rp_admin_mode[priority];
-}
-
-
-static void ixgbe_dcbnl_getbcncfg(struct net_device *netdev, int enum_index,
-                                 u32 *setting)
-{
-       struct ixgbe_adapter *adapter = netdev_priv(netdev);
-
-       switch (enum_index) {
-       case DCB_BCN_ATTR_BCNA_0:
-               *setting = adapter->dcb_cfg.bcn.bcna_option[0];
-               break;
-       case DCB_BCN_ATTR_BCNA_1:
-               *setting = adapter->dcb_cfg.bcn.bcna_option[1];
-               break;
-       case DCB_BCN_ATTR_ALPHA:
-               *setting = adapter->dcb_cfg.bcn.rp_alpha;
-               break;
-       case DCB_BCN_ATTR_BETA:
-               *setting = adapter->dcb_cfg.bcn.rp_beta;
-               break;
-       case DCB_BCN_ATTR_GD:
-               *setting = adapter->dcb_cfg.bcn.rp_gd;
-               break;
-       case DCB_BCN_ATTR_GI:
-               *setting = adapter->dcb_cfg.bcn.rp_gi;
-               break;
-       case DCB_BCN_ATTR_TMAX:
-               *setting = adapter->dcb_cfg.bcn.rp_tmax;
-               break;
-       case DCB_BCN_ATTR_TD:
-               *setting = adapter->dcb_cfg.bcn.rp_td;
-               break;
-       case DCB_BCN_ATTR_RMIN:
-               *setting = adapter->dcb_cfg.bcn.rp_rmin;
-               break;
-       case DCB_BCN_ATTR_W:
-               *setting = adapter->dcb_cfg.bcn.rp_w;
-               break;
-       case DCB_BCN_ATTR_RD:
-               *setting = adapter->dcb_cfg.bcn.rp_rd;
-               break;
-       case DCB_BCN_ATTR_RU:
-               *setting = adapter->dcb_cfg.bcn.rp_ru;
-               break;
-       case DCB_BCN_ATTR_WRTT:
-               *setting = adapter->dcb_cfg.bcn.rp_wrtt;
-               break;
-       case DCB_BCN_ATTR_RI:
-               *setting = adapter->dcb_cfg.bcn.rp_ri;
-               break;
-       default:
-               *setting = -1;
-       }
-}
-
-static void ixgbe_dcbnl_setbcnrp(struct net_device *netdev, int priority,
-                                u8 setting)
-{
-       struct ixgbe_adapter *adapter = netdev_priv(netdev);
-
-       adapter->temp_dcb_cfg.bcn.rp_admin_mode[priority] = setting;
-
-       if (adapter->temp_dcb_cfg.bcn.rp_admin_mode[priority] !=
-           adapter->dcb_cfg.bcn.rp_admin_mode[priority])
-               adapter->dcb_set_bitmap |= BIT_BCN;
-}
-
-static void ixgbe_dcbnl_setbcncfg(struct net_device *netdev, int enum_index,
-                                u32 setting)
-{
-       struct ixgbe_adapter *adapter = netdev_priv(netdev);
-
-       switch (enum_index) {
-       case DCB_BCN_ATTR_BCNA_0:
-               adapter->temp_dcb_cfg.bcn.bcna_option[0] = setting;
-               if (adapter->temp_dcb_cfg.bcn.bcna_option[0] !=
-                       adapter->dcb_cfg.bcn.bcna_option[0])
-                       adapter->dcb_set_bitmap |= BIT_BCN;
-               break;
-       case DCB_BCN_ATTR_BCNA_1:
-               adapter->temp_dcb_cfg.bcn.bcna_option[1] = setting;
-               if (adapter->temp_dcb_cfg.bcn.bcna_option[1] !=
-                       adapter->dcb_cfg.bcn.bcna_option[1])
-                       adapter->dcb_set_bitmap |= BIT_BCN;
-               break;
-       case DCB_BCN_ATTR_ALPHA:
-               adapter->temp_dcb_cfg.bcn.rp_alpha = setting;
-               if (adapter->temp_dcb_cfg.bcn.rp_alpha !=
-                   adapter->dcb_cfg.bcn.rp_alpha)
-                       adapter->dcb_set_bitmap |= BIT_BCN;
-               break;
-       case DCB_BCN_ATTR_BETA:
-               adapter->temp_dcb_cfg.bcn.rp_beta = setting;
-               if (adapter->temp_dcb_cfg.bcn.rp_beta !=
-                   adapter->dcb_cfg.bcn.rp_beta)
-                       adapter->dcb_set_bitmap |= BIT_BCN;
-               break;
-       case DCB_BCN_ATTR_GD:
-               adapter->temp_dcb_cfg.bcn.rp_gd = setting;
-               if (adapter->temp_dcb_cfg.bcn.rp_gd !=
-                   adapter->dcb_cfg.bcn.rp_gd)
-                       adapter->dcb_set_bitmap |= BIT_BCN;
-               break;
-       case DCB_BCN_ATTR_GI:
-               adapter->temp_dcb_cfg.bcn.rp_gi = setting;
-               if (adapter->temp_dcb_cfg.bcn.rp_gi !=
-                   adapter->dcb_cfg.bcn.rp_gi)
-                       adapter->dcb_set_bitmap |= BIT_BCN;
-               break;
-       case DCB_BCN_ATTR_TMAX:
-               adapter->temp_dcb_cfg.bcn.rp_tmax = setting;
-               if (adapter->temp_dcb_cfg.bcn.rp_tmax !=
-                   adapter->dcb_cfg.bcn.rp_tmax)
-                       adapter->dcb_set_bitmap |= BIT_BCN;
-               break;
-       case DCB_BCN_ATTR_TD:
-               adapter->temp_dcb_cfg.bcn.rp_td = setting;
-               if (adapter->temp_dcb_cfg.bcn.rp_td !=
-                   adapter->dcb_cfg.bcn.rp_td)
-                       adapter->dcb_set_bitmap |= BIT_BCN;
-               break;
-       case DCB_BCN_ATTR_RMIN:
-               adapter->temp_dcb_cfg.bcn.rp_rmin = setting;
-               if (adapter->temp_dcb_cfg.bcn.rp_rmin !=
-                   adapter->dcb_cfg.bcn.rp_rmin)
-                       adapter->dcb_set_bitmap |= BIT_BCN;
-               break;
-       case DCB_BCN_ATTR_W:
-               adapter->temp_dcb_cfg.bcn.rp_w = setting;
-               if (adapter->temp_dcb_cfg.bcn.rp_w !=
-                   adapter->dcb_cfg.bcn.rp_w)
-                       adapter->dcb_set_bitmap |= BIT_BCN;
-               break;
-       case DCB_BCN_ATTR_RD:
-               adapter->temp_dcb_cfg.bcn.rp_rd = setting;
-               if (adapter->temp_dcb_cfg.bcn.rp_rd !=
-                   adapter->dcb_cfg.bcn.rp_rd)
-                       adapter->dcb_set_bitmap |= BIT_BCN;
-               break;
-       case DCB_BCN_ATTR_RU:
-               adapter->temp_dcb_cfg.bcn.rp_ru = setting;
-               if (adapter->temp_dcb_cfg.bcn.rp_ru !=
-                   adapter->dcb_cfg.bcn.rp_ru)
-                       adapter->dcb_set_bitmap |= BIT_BCN;
-               break;
-       case DCB_BCN_ATTR_WRTT:
-               adapter->temp_dcb_cfg.bcn.rp_wrtt = setting;
-               if (adapter->temp_dcb_cfg.bcn.rp_wrtt !=
-                   adapter->dcb_cfg.bcn.rp_wrtt)
-                       adapter->dcb_set_bitmap |= BIT_BCN;
-               break;
-       case DCB_BCN_ATTR_RI:
-               adapter->temp_dcb_cfg.bcn.rp_ri = setting;
-               if (adapter->temp_dcb_cfg.bcn.rp_ri !=
-                   adapter->dcb_cfg.bcn.rp_ri)
-                       adapter->dcb_set_bitmap |= BIT_BCN;
-               break;
-       default:
-               break;
-       }
-}
-
 struct dcbnl_rtnl_ops dcbnl_ops = {
        .getstate       = ixgbe_dcbnl_get_state,
        .setstate       = ixgbe_dcbnl_set_state,
@@ -633,9 +438,5 @@ struct dcbnl_rtnl_ops dcbnl_ops = {
        .setnumtcs      = ixgbe_dcbnl_setnumtcs,
        .getpfcstate    = ixgbe_dcbnl_getpfcstate,
        .setpfcstate    = ixgbe_dcbnl_setpfcstate,
-       .getbcncfg      = ixgbe_dcbnl_getbcncfg,
-       .getbcnrp       = ixgbe_dcbnl_getbcnrp,
-       .setbcncfg      = ixgbe_dcbnl_setbcncfg,
-       .setbcnrp       = ixgbe_dcbnl_setbcnrp
 };
 
index cec2f4e8c61eae107429dafe08b9466ee26a99ec..18ecba7f6ecb32951ebb82324da1637aaf5cb9c9 100644 (file)
@@ -89,6 +89,7 @@ static struct ixgbe_stats ixgbe_gstrings_stats[] = {
        {"rx_header_split", IXGBE_STAT(rx_hdr_split)},
        {"alloc_rx_page_failed", IXGBE_STAT(alloc_rx_page_failed)},
        {"alloc_rx_buff_failed", IXGBE_STAT(alloc_rx_buff_failed)},
+       {"rx_no_dma_resources", IXGBE_STAT(hw_rx_no_dma_resources)},
 };
 
 #define IXGBE_QUEUE_STATS_LEN \
@@ -469,7 +470,7 @@ static void ixgbe_get_regs(struct net_device *netdev,
        regs_buff[825] = IXGBE_READ_REG(hw, IXGBE_IP6AT);
        regs_buff[826] = IXGBE_READ_REG(hw, IXGBE_WUPL);
        regs_buff[827] = IXGBE_READ_REG(hw, IXGBE_WUPM);
-       regs_buff[828] = IXGBE_READ_REG(hw, IXGBE_FHFT);
+       regs_buff[828] = IXGBE_READ_REG(hw, IXGBE_FHFT(0));
 
        regs_buff[829] = IXGBE_READ_REG(hw, IXGBE_RMCS);
        regs_buff[830] = IXGBE_READ_REG(hw, IXGBE_DPMCS);
@@ -908,12 +909,50 @@ static void ixgbe_get_strings(struct net_device *netdev, u32 stringset,
 static void ixgbe_get_wol(struct net_device *netdev,
                           struct ethtool_wolinfo *wol)
 {
-       wol->supported = 0;
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+       wol->supported = WAKE_UCAST | WAKE_MCAST |
+                        WAKE_BCAST | WAKE_MAGIC;
        wol->wolopts = 0;
 
+       if (!device_can_wakeup(&adapter->pdev->dev))
+               return;
+
+       if (adapter->wol & IXGBE_WUFC_EX)
+               wol->wolopts |= WAKE_UCAST;
+       if (adapter->wol & IXGBE_WUFC_MC)
+               wol->wolopts |= WAKE_MCAST;
+       if (adapter->wol & IXGBE_WUFC_BC)
+               wol->wolopts |= WAKE_BCAST;
+       if (adapter->wol & IXGBE_WUFC_MAG)
+               wol->wolopts |= WAKE_MAGIC;
+
        return;
 }
 
+static int ixgbe_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(netdev);
+
+       if (wol->wolopts & (WAKE_PHY | WAKE_ARP | WAKE_MAGICSECURE))
+               return -EOPNOTSUPP;
+
+       adapter->wol = 0;
+
+       if (wol->wolopts & WAKE_UCAST)
+               adapter->wol |= IXGBE_WUFC_EX;
+       if (wol->wolopts & WAKE_MCAST)
+               adapter->wol |= IXGBE_WUFC_MC;
+       if (wol->wolopts & WAKE_BCAST)
+               adapter->wol |= IXGBE_WUFC_BC;
+       if (wol->wolopts & WAKE_MAGIC)
+               adapter->wol |= IXGBE_WUFC_MAG;
+
+       device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
+
+       return 0;
+}
+
 static int ixgbe_nway_reset(struct net_device *netdev)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -976,40 +1015,47 @@ static int ixgbe_set_coalesce(struct net_device *netdev,
                               struct ethtool_coalesce *ec)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
-       struct ixgbe_hw *hw = &adapter->hw;
        int i;
 
        if (ec->tx_max_coalesced_frames_irq)
                adapter->tx_ring[0].work_limit = ec->tx_max_coalesced_frames_irq;
 
        if (ec->rx_coalesce_usecs > 1) {
+               /* check the limits */
+               if ((1000000/ec->rx_coalesce_usecs > IXGBE_MAX_INT_RATE) ||
+                   (1000000/ec->rx_coalesce_usecs < IXGBE_MIN_INT_RATE))
+                       return -EINVAL;
+
                /* store the value in ints/second */
                adapter->eitr_param = 1000000/ec->rx_coalesce_usecs;
 
                /* static value of interrupt rate */
                adapter->itr_setting = adapter->eitr_param;
-               /* clear the lower bit */
+               /* clear the lower bit as its used for dynamic state */
                adapter->itr_setting &= ~1;
        } else if (ec->rx_coalesce_usecs == 1) {
                /* 1 means dynamic mode */
                adapter->eitr_param = 20000;
                adapter->itr_setting = 1;
        } else {
-               /* any other value means disable eitr, which is best
-                * served by setting the interrupt rate very high */
-               adapter->eitr_param = 3000000;
+               /*
+                * any other value means disable eitr, which is best
+                * served by setting the interrupt rate very high
+                */
+               adapter->eitr_param = IXGBE_MAX_INT_RATE;
                adapter->itr_setting = 0;
        }
 
        for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++) {
                struct ixgbe_q_vector *q_vector = &adapter->q_vector[i];
                if (q_vector->txr_count && !q_vector->rxr_count)
+                       /* tx vector gets half the rate */
                        q_vector->eitr = (adapter->eitr_param >> 1);
                else
                        /* rx only or mixed */
                        q_vector->eitr = adapter->eitr_param;
-               IXGBE_WRITE_REG(hw, IXGBE_EITR(i),
-                               EITR_INTS_PER_SEC_TO_REG(q_vector->eitr));
+               ixgbe_write_eitr(adapter, i,
+                                EITR_INTS_PER_SEC_TO_REG(q_vector->eitr));
        }
 
        return 0;
@@ -1023,6 +1069,7 @@ static const struct ethtool_ops ixgbe_ethtool_ops = {
        .get_regs_len           = ixgbe_get_regs_len,
        .get_regs               = ixgbe_get_regs,
        .get_wol                = ixgbe_get_wol,
+       .set_wol                = ixgbe_set_wol,
        .nway_reset             = ixgbe_nway_reset,
        .get_link               = ethtool_op_get_link,
        .get_eeprom_len         = ixgbe_get_eeprom_len,
index 8c32c18f569c8f17b07946e06955400cff73fd9a..79aa811c403c5c2d5dcd3bfff6939ae067ccc1e5 100644 (file)
@@ -47,12 +47,13 @@ char ixgbe_driver_name[] = "ixgbe";
 static const char ixgbe_driver_string[] =
                               "Intel(R) 10 Gigabit PCI Express Network Driver";
 
-#define DRV_VERSION "1.3.56-k2"
+#define DRV_VERSION "2.0.8-k2"
 const char ixgbe_driver_version[] = DRV_VERSION;
 static char ixgbe_copyright[] = "Copyright (c) 1999-2009 Intel Corporation.";
 
 static const struct ixgbe_info *ixgbe_info_tbl[] = {
        [board_82598] = &ixgbe_82598_info,
+       [board_82599] = &ixgbe_82599_info,
 };
 
 /* ixgbe_pci_tbl - PCI Device ID Table
@@ -86,6 +87,10 @@ static struct pci_device_id ixgbe_pci_tbl[] = {
         board_82598 },
        {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82598_BX),
         board_82598 },
+       {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_KX4),
+        board_82599 },
+       {PCI_VDEVICE(INTEL, IXGBE_DEV_ID_82599_SFP),
+        board_82599 },
 
        /* required last entry */
        {0, }
@@ -129,17 +134,53 @@ static void ixgbe_get_hw_control(struct ixgbe_adapter *adapter)
                        ctrl_ext | IXGBE_CTRL_EXT_DRV_LOAD);
 }
 
-static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, u16 int_alloc_entry,
-                           u8 msix_vector)
+/*
+ * ixgbe_set_ivar - set the IVAR registers, mapping interrupt causes to vectors
+ * @adapter: pointer to adapter struct
+ * @direction: 0 for Rx, 1 for Tx, -1 for other causes
+ * @queue: queue to map the corresponding interrupt to
+ * @msix_vector: the vector to map to the corresponding queue
+ *
+ */
+static void ixgbe_set_ivar(struct ixgbe_adapter *adapter, s8 direction,
+                          u8 queue, u8 msix_vector)
 {
        u32 ivar, index;
-
-       msix_vector |= IXGBE_IVAR_ALLOC_VAL;
-       index = (int_alloc_entry >> 2) & 0x1F;
-       ivar = IXGBE_READ_REG(&adapter->hw, IXGBE_IVAR(index));
-       ivar &= ~(0xFF << (8 * (int_alloc_entry & 0x3)));
-       ivar |= (msix_vector << (8 * (int_alloc_entry & 0x3)));
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR(index), ivar);
+       struct ixgbe_hw *hw = &adapter->hw;
+       switch (hw->mac.type) {
+       case ixgbe_mac_82598EB:
+               msix_vector |= IXGBE_IVAR_ALLOC_VAL;
+               if (direction == -1)
+                       direction = 0;
+               index = (((direction * 64) + queue) >> 2) & 0x1F;
+               ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(index));
+               ivar &= ~(0xFF << (8 * (queue & 0x3)));
+               ivar |= (msix_vector << (8 * (queue & 0x3)));
+               IXGBE_WRITE_REG(hw, IXGBE_IVAR(index), ivar);
+               break;
+       case ixgbe_mac_82599EB:
+               if (direction == -1) {
+                       /* other causes */
+                       msix_vector |= IXGBE_IVAR_ALLOC_VAL;
+                       index = ((queue & 1) * 8);
+                       ivar = IXGBE_READ_REG(&adapter->hw, IXGBE_IVAR_MISC);
+                       ivar &= ~(0xFF << index);
+                       ivar |= (msix_vector << index);
+                       IXGBE_WRITE_REG(&adapter->hw, IXGBE_IVAR_MISC, ivar);
+                       break;
+               } else {
+                       /* tx or rx causes */
+                       msix_vector |= IXGBE_IVAR_ALLOC_VAL;
+                       index = ((16 * (queue & 1)) + (8 * direction));
+                       ivar = IXGBE_READ_REG(hw, IXGBE_IVAR(queue >> 1));
+                       ivar &= ~(0xFF << index);
+                       ivar |= (msix_vector << index);
+                       IXGBE_WRITE_REG(hw, IXGBE_IVAR(queue >> 1), ivar);
+                       break;
+               }
+       default:
+               break;
+       }
 }
 
 static void ixgbe_unmap_and_free_tx_resource(struct ixgbe_adapter *adapter,
@@ -210,6 +251,8 @@ static void ixgbe_tx_timeout(struct net_device *netdev);
  * ixgbe_clean_tx_irq - Reclaim resources after transmit completes
  * @adapter: board private structure
  * @tx_ring: tx ring to clean
+ *
+ * returns true if transmit work is done
  **/
 static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
                                struct ixgbe_ring *tx_ring)
@@ -225,7 +268,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
        eop_desc = IXGBE_TX_DESC_ADV(*tx_ring, eop);
 
        while ((eop_desc->wb.status & cpu_to_le32(IXGBE_TXD_STAT_DD)) &&
-              (count < tx_ring->count)) {
+              (count < tx_ring->work_limit)) {
                bool cleaned = false;
                for ( ; !cleaned; count++) {
                        struct sk_buff *skb;
@@ -287,8 +330,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
        }
 
        /* re-arm the interrupt */
-       if ((total_packets >= tx_ring->work_limit) ||
-           (count == tx_ring->count))
+       if (count >= tx_ring->work_limit)
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EICS, tx_ring->v_idx);
 
        tx_ring->total_bytes += total_bytes;
@@ -297,7 +339,7 @@ static bool ixgbe_clean_tx_irq(struct ixgbe_adapter *adapter,
        tx_ring->stats.bytes += total_bytes;
        adapter->net_stats.tx_bytes += total_bytes;
        adapter->net_stats.tx_packets += total_packets;
-       return (total_packets ? true : false);
+       return (count < tx_ring->work_limit);
 }
 
 #ifdef CONFIG_IXGBE_DCA
@@ -310,13 +352,19 @@ static void ixgbe_update_rx_dca(struct ixgbe_adapter *adapter,
 
        if (rx_ring->cpu != cpu) {
                rxctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q));
-               rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK;
-               rxctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
+               if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
+                       rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK;
+                       rxctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
+               } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+                       rxctrl &= ~IXGBE_DCA_RXCTRL_CPUID_MASK_82599;
+                       rxctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) <<
+                                  IXGBE_DCA_RXCTRL_CPUID_SHIFT_82599);
+               }
                rxctrl |= IXGBE_DCA_RXCTRL_DESC_DCA_EN;
                rxctrl |= IXGBE_DCA_RXCTRL_HEAD_DCA_EN;
                rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_RRO_EN);
                rxctrl &= ~(IXGBE_DCA_RXCTRL_DESC_WRO_EN |
-                           IXGBE_DCA_RXCTRL_DESC_HSRO_EN);
+                           IXGBE_DCA_RXCTRL_DESC_HSRO_EN);
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_RXCTRL(q), rxctrl);
                rx_ring->cpu = cpu;
        }
@@ -332,8 +380,14 @@ static void ixgbe_update_tx_dca(struct ixgbe_adapter *adapter,
 
        if (tx_ring->cpu != cpu) {
                txctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_DCA_TXCTRL(q));
-               txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK;
-               txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
+               if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
+                       txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK;
+                       txctrl |= dca3_get_tag(&adapter->pdev->dev, cpu);
+               } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+                       txctrl &= ~IXGBE_DCA_TXCTRL_CPUID_MASK_82599;
+                       txctrl |= (dca3_get_tag(&adapter->pdev->dev, cpu) <<
+                                  IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599);
+               }
                txctrl |= IXGBE_DCA_TXCTRL_DESC_DCA_EN;
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_DCA_TXCTRL(q), txctrl);
                tx_ring->cpu = cpu;
@@ -464,6 +518,19 @@ static inline void ixgbe_rx_checksum(struct ixgbe_adapter *adapter,
        adapter->hw_csum_rx_good++;
 }
 
+static inline void ixgbe_release_rx_desc(struct ixgbe_hw *hw,
+                                         struct ixgbe_ring *rx_ring, u32 val)
+{
+       /*
+        * Force memory writes to complete before letting h/w
+        * know there are new descriptors to fetch.  (Only
+        * applicable for weak-ordered memory model archs,
+        * such as IA-64).
+        */
+       wmb();
+       IXGBE_WRITE_REG(hw, IXGBE_RDT(rx_ring->reg_idx), val);
+}
+
 /**
  * ixgbe_alloc_rx_buffers - Replace used receive buffers; packet split
  * @adapter: address of board private structure
@@ -476,6 +543,7 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
        union ixgbe_adv_rx_desc *rx_desc;
        struct ixgbe_rx_buffer *bi;
        unsigned int i;
+       unsigned int bufsz = rx_ring->rx_buf_len + NET_IP_ALIGN;
 
        i = rx_ring->next_to_use;
        bi = &rx_ring->rx_buffer_info[i];
@@ -505,9 +573,7 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
 
                if (!bi->skb) {
                        struct sk_buff *skb;
-                       skb = netdev_alloc_skb(adapter->netdev,
-                                              (rx_ring->rx_buf_len +
-                                               NET_IP_ALIGN));
+                       skb = netdev_alloc_skb(adapter->netdev, bufsz);
 
                        if (!skb) {
                                adapter->alloc_rx_buff_failed++;
@@ -522,8 +588,7 @@ static void ixgbe_alloc_rx_buffers(struct ixgbe_adapter *adapter,
                        skb_reserve(skb, NET_IP_ALIGN);
 
                        bi->skb = skb;
-                       bi->dma = pci_map_single(pdev, skb->data,
-                                                rx_ring->rx_buf_len,
+                       bi->dma = pci_map_single(pdev, skb->data, bufsz,
                                                 PCI_DMA_FROMDEVICE);
                }
                /* Refresh the desc even if buffer_addrs didn't change because
@@ -547,14 +612,7 @@ no_buffers:
                if (i-- == 0)
                        i = (rx_ring->count - 1);
 
-               /*
-                * Force memory writes to complete before letting h/w
-                * know there are new descriptors to fetch.  (Only
-                * applicable for weak-ordered memory model archs,
-                * such as IA-64).
-                */
-               wmb();
-               writel(i, adapter->hw.hw_addr + rx_ring->tail);
+               ixgbe_release_rx_desc(&adapter->hw, rx_ring, i);
        }
 }
 
@@ -721,7 +779,8 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
 
        q_vectors = adapter->num_msix_vectors - NON_Q_VECTORS;
 
-       /* Populate the IVAR table and set the ITR values to the
+       /*
+        * Populate the IVAR table and set the ITR values to the
         * corresponding register.
         */
        for (v_idx = 0; v_idx < q_vectors; v_idx++) {
@@ -732,7 +791,7 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
 
                for (i = 0; i < q_vector->rxr_count; i++) {
                        j = adapter->rx_ring[r_idx].reg_idx;
-                       ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(j), v_idx);
+                       ixgbe_set_ivar(adapter, 0, j, v_idx);
                        r_idx = find_next_bit(q_vector->rxr_idx,
                                              adapter->num_rx_queues,
                                              r_idx + 1);
@@ -742,7 +801,7 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
 
                for (i = 0; i < q_vector->txr_count; i++) {
                        j = adapter->tx_ring[r_idx].reg_idx;
-                       ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(j), v_idx);
+                       ixgbe_set_ivar(adapter, 1, j, v_idx);
                        r_idx = find_next_bit(q_vector->txr_idx,
                                              adapter->num_tx_queues,
                                              r_idx + 1);
@@ -751,15 +810,23 @@ static void ixgbe_configure_msix(struct ixgbe_adapter *adapter)
                /* if this is a tx only vector halve the interrupt rate */
                if (q_vector->txr_count && !q_vector->rxr_count)
                        q_vector->eitr = (adapter->eitr_param >> 1);
-               else
+               else if (q_vector->rxr_count)
                        /* rx only */
                        q_vector->eitr = adapter->eitr_param;
 
+               /*
+                * since this is initial set up don't need to call
+                * ixgbe_write_eitr helper
+                */
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx),
                                EITR_INTS_PER_SEC_TO_REG(q_vector->eitr));
        }
 
-       ixgbe_set_ivar(adapter, IXGBE_IVAR_OTHER_CAUSES_INDEX, v_idx);
+       if (adapter->hw.mac.type == ixgbe_mac_82598EB)
+               ixgbe_set_ivar(adapter, -1, IXGBE_IVAR_OTHER_CAUSES_INDEX,
+                              v_idx);
+       else if (adapter->hw.mac.type == ixgbe_mac_82599EB)
+               ixgbe_set_ivar(adapter, -1, 1, v_idx);
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EITR(v_idx), 1950);
 
        /* set up to autoclear timer, and the vectors */
@@ -835,10 +902,35 @@ update_itr_done:
        return retval;
 }
 
+/**
+ * ixgbe_write_eitr - write EITR register in hardware specific way
+ * @adapter: pointer to adapter struct
+ * @v_idx: vector index into q_vector array
+ * @itr_reg: new value to be written in *register* format, not ints/s
+ *
+ * This function is made to be called by ethtool and by the driver
+ * when it needs to update EITR registers at runtime.  Hardware
+ * specific quirks/differences are taken care of here.
+ */
+void ixgbe_write_eitr(struct ixgbe_adapter *adapter, int v_idx, u32 itr_reg)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+       if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
+               /* must write high and low 16 bits to reset counter */
+               itr_reg |= (itr_reg << 16);
+       } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+               /*
+                * set the WDIS bit to not clear the timer bits and cause an
+                * immediate assertion of the interrupt
+                */
+               itr_reg |= IXGBE_EITR_CNT_WDIS;
+       }
+       IXGBE_WRITE_REG(hw, IXGBE_EITR(v_idx), itr_reg);
+}
+
 static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
 {
        struct ixgbe_adapter *adapter = q_vector->adapter;
-       struct ixgbe_hw *hw = &adapter->hw;
        u32 new_itr;
        u8 current_itr, ret_itr;
        int i, r_idx, v_idx = ((void *)q_vector - (void *)(adapter->q_vector)) /
@@ -893,14 +985,13 @@ static void ixgbe_set_itr_msix(struct ixgbe_q_vector *q_vector)
 
        if (new_itr != q_vector->eitr) {
                u32 itr_reg;
+
+               /* save the algorithm value here, not the smoothed one */
+               q_vector->eitr = new_itr;
                /* do an exponential smoothing */
                new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100);
-               q_vector->eitr = new_itr;
                itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr);
-               /* must write high and low 16 bits to reset counter */
-               DPRINTK(TX_ERR, DEBUG, "writing eitr(%d): %08X\n", v_idx,
-                       itr_reg);
-               IXGBE_WRITE_REG(hw, IXGBE_EITR(v_idx), itr_reg | (itr_reg)<<16);
+               ixgbe_write_eitr(adapter, v_idx, itr_reg);
        }
 
        return;
@@ -918,6 +1009,24 @@ static void ixgbe_check_fan_failure(struct ixgbe_adapter *adapter, u32 eicr)
        }
 }
 
+static void ixgbe_check_sfp_event(struct ixgbe_adapter *adapter, u32 eicr)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+
+       if (eicr & IXGBE_EICR_GPI_SDP1) {
+               /* Clear the interrupt */
+               IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP1);
+               schedule_work(&adapter->multispeed_fiber_task);
+       } else if (eicr & IXGBE_EICR_GPI_SDP2) {
+               /* Clear the interrupt */
+               IXGBE_WRITE_REG(hw, IXGBE_EICR, IXGBE_EICR_GPI_SDP2);
+               schedule_work(&adapter->sfp_config_module_task);
+       } else {
+               /* Interrupt isn't for us... */
+               return;
+       }
+}
+
 static void ixgbe_check_lsc(struct ixgbe_adapter *adapter)
 {
        struct ixgbe_hw *hw = &adapter->hw;
@@ -936,13 +1045,25 @@ static irqreturn_t ixgbe_msix_lsc(int irq, void *data)
        struct net_device *netdev = data;
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        struct ixgbe_hw *hw = &adapter->hw;
-       u32 eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
+       u32 eicr;
+
+       /*
+        * Workaround for Silicon errata.  Use clear-by-write instead
+        * of clear-by-read.  Reading with EICS will return the
+        * interrupt causes without clearing, which later be done
+        * with the write to EICR.
+        */
+       eicr = IXGBE_READ_REG(hw, IXGBE_EICS);
+       IXGBE_WRITE_REG(hw, IXGBE_EICR, eicr);
 
        if (eicr & IXGBE_EICR_LSC)
                ixgbe_check_lsc(adapter);
 
-       ixgbe_check_fan_failure(adapter, eicr);
+       if (hw->mac.type == ixgbe_mac_82598EB)
+               ixgbe_check_fan_failure(adapter, eicr);
 
+       if (hw->mac.type == ixgbe_mac_82599EB)
+               ixgbe_check_sfp_event(adapter, eicr);
        if (!test_bit(__IXGBE_DOWN, &adapter->state))
                IXGBE_WRITE_REG(hw, IXGBE_EIMS, IXGBE_EIMS_OTHER);
 
@@ -1047,7 +1168,7 @@ static int ixgbe_clean_rxonly(struct napi_struct *napi, int budget)
        /* If all Rx work done, exit the polling mode */
        if (work_done < budget) {
                napi_complete(napi);
-               if (adapter->itr_setting & 3)
+               if (adapter->itr_setting & 1)
                        ixgbe_set_itr_msix(q_vector);
                if (!test_bit(__IXGBE_DOWN, &adapter->state))
                        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, rx_ring->v_idx);
@@ -1096,7 +1217,7 @@ static int ixgbe_clean_rxonly_many(struct napi_struct *napi, int budget)
        /* If all Rx work done, exit the polling mode */
        if (work_done < budget) {
                napi_complete(napi);
-               if (adapter->itr_setting & 3)
+               if (adapter->itr_setting & 1)
                        ixgbe_set_itr_msix(q_vector);
                if (!test_bit(__IXGBE_DOWN, &adapter->state))
                        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, enable_mask);
@@ -1266,7 +1387,6 @@ out:
 
 static void ixgbe_set_itr(struct ixgbe_adapter *adapter)
 {
-       struct ixgbe_hw *hw = &adapter->hw;
        struct ixgbe_q_vector *q_vector = adapter->q_vector;
        u8 current_itr;
        u32 new_itr = q_vector->eitr;
@@ -1301,34 +1421,18 @@ static void ixgbe_set_itr(struct ixgbe_adapter *adapter)
 
        if (new_itr != q_vector->eitr) {
                u32 itr_reg;
+
+               /* save the algorithm value here, not the smoothed one */
+               q_vector->eitr = new_itr;
                /* do an exponential smoothing */
                new_itr = ((q_vector->eitr * 90)/100) + ((new_itr * 10)/100);
-               q_vector->eitr = new_itr;
                itr_reg = EITR_INTS_PER_SEC_TO_REG(new_itr);
-               /* must write high and low 16 bits to reset counter */
-               IXGBE_WRITE_REG(hw, IXGBE_EITR(0), itr_reg | (itr_reg)<<16);
+               ixgbe_write_eitr(adapter, 0, itr_reg);
        }
 
        return;
 }
 
-/**
- * ixgbe_irq_disable - Mask off interrupt generation on the NIC
- * @adapter: board private structure
- **/
-static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
-{
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
-       IXGBE_WRITE_FLUSH(&adapter->hw);
-       if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
-               int i;
-               for (i = 0; i < adapter->num_msix_vectors; i++)
-                       synchronize_irq(adapter->msix_entries[i].vector);
-       } else {
-               synchronize_irq(adapter->pdev->irq);
-       }
-}
-
 /**
  * ixgbe_irq_enable - Enable default interrupt generation settings
  * @adapter: board private structure
@@ -1339,7 +1443,21 @@ static inline void ixgbe_irq_enable(struct ixgbe_adapter *adapter)
        mask = IXGBE_EIMS_ENABLE_MASK;
        if (adapter->flags & IXGBE_FLAG_FAN_FAIL_CAPABLE)
                mask |= IXGBE_EIMS_GPI_SDP1;
+       if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+               mask |= IXGBE_EIMS_ECC;
+               mask |= IXGBE_EIMS_GPI_SDP1;
+               mask |= IXGBE_EIMS_GPI_SDP2;
+       }
+
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
+       if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+               /* enable the rest of the queue vectors */
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(1),
+                               (IXGBE_EIMS_RTX_QUEUE << 16));
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(2),
+                               ((IXGBE_EIMS_RTX_QUEUE << 16) |
+                                 IXGBE_EIMS_RTX_QUEUE));
+       }
        IXGBE_WRITE_FLUSH(&adapter->hw);
 }
 
@@ -1355,6 +1473,12 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
        struct ixgbe_hw *hw = &adapter->hw;
        u32 eicr;
 
+       /*
+        * Workaround for silicon errata.  Mask the interrupts
+        * before the read of EICR.
+        */
+       IXGBE_WRITE_REG(hw, IXGBE_EIMC, IXGBE_IRQ_CLEAR_MASK);
+
        /* for NAPI, using EIAM to auto-mask tx/rx interrupt bits on read
         * therefore no explict interrupt disable is necessary */
        eicr = IXGBE_READ_REG(hw, IXGBE_EICR);
@@ -1369,6 +1493,9 @@ static irqreturn_t ixgbe_intr(int irq, void *data)
        if (eicr & IXGBE_EICR_LSC)
                ixgbe_check_lsc(adapter);
 
+       if (hw->mac.type == ixgbe_mac_82599EB)
+               ixgbe_check_sfp_event(adapter, eicr);
+
        ixgbe_check_fan_failure(adapter, eicr);
 
        if (napi_schedule_prep(&adapter->q_vector[0].napi)) {
@@ -1448,6 +1575,39 @@ static void ixgbe_free_irq(struct ixgbe_adapter *adapter)
        }
 }
 
+/**
+ * ixgbe_irq_disable - Mask off interrupt generation on the NIC
+ * @adapter: board private structure
+ **/
+static inline void ixgbe_irq_disable(struct ixgbe_adapter *adapter)
+{
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC, ~0);
+       if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(1), ~0);
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMC_EX(2), ~0);
+       }
+       IXGBE_WRITE_FLUSH(&adapter->hw);
+       if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+               int i;
+               for (i = 0; i < adapter->num_msix_vectors; i++)
+                       synchronize_irq(adapter->msix_entries[i].vector);
+       } else {
+               synchronize_irq(adapter->pdev->irq);
+       }
+}
+
+static inline void ixgbe_irq_enable_queues(struct ixgbe_adapter *adapter)
+{
+       u32 mask = IXGBE_EIMS_RTX_QUEUE;
+       IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS, mask);
+       if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(1), mask << 16);
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_EIMS_EX(2),
+                               (mask << 16 | mask));
+       }
+       /* skip the flush */
+}
+
 /**
  * ixgbe_configure_msi_and_legacy - Initialize PIN (INTA...) and MSI interrupts
  *
@@ -1459,8 +1619,8 @@ static void ixgbe_configure_msi_and_legacy(struct ixgbe_adapter *adapter)
        IXGBE_WRITE_REG(hw, IXGBE_EITR(0),
                        EITR_INTS_PER_SEC_TO_REG(adapter->eitr_param));
 
-       ixgbe_set_ivar(adapter, IXGBE_IVAR_RX_QUEUE(0), 0);
-       ixgbe_set_ivar(adapter, IXGBE_IVAR_TX_QUEUE(0), 0);
+       ixgbe_set_ivar(adapter, 0, 0, 0);
+       ixgbe_set_ivar(adapter, 1, 0, 0);
 
        map_vector_to_rxq(adapter, 0, 0);
        map_vector_to_txq(adapter, 0, 0);
@@ -1501,26 +1661,25 @@ static void ixgbe_configure_tx(struct ixgbe_adapter *adapter)
                txctrl &= ~IXGBE_DCA_TXCTRL_TX_WB_RO_EN;
                IXGBE_WRITE_REG(hw, IXGBE_DCA_TXCTRL(j), txctrl);
        }
+       if (hw->mac.type == ixgbe_mac_82599EB) {
+               /* We enable 8 traffic classes, DCB only */
+               if (adapter->flags & IXGBE_FLAG_DCB_ENABLED)
+                       IXGBE_WRITE_REG(hw, IXGBE_MTQC, (IXGBE_MTQC_RT_ENA |
+                                       IXGBE_MTQC_8TC_8TQ));
+       }
 }
 
-#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT        2
+#define IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT 2
 
 static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, int index)
 {
        struct ixgbe_ring *rx_ring;
        u32 srrctl;
-       int queue0;
+       int queue0 = 0;
        unsigned long mask;
 
-       /* program one srrctl register per VMDq index */
-       if (adapter->flags & IXGBE_FLAG_VMDQ_ENABLED) {
-               long shift, len;
-               mask = (unsigned long) adapter->ring_feature[RING_F_RSS].mask;
-               len = sizeof(adapter->ring_feature[RING_F_VMDQ].mask) * 8;
-               shift = find_first_bit(&mask, len);
-               queue0 = index & mask;
-               index = (index & mask) >> shift;
-       /* program one srrctl per RSS queue since RDRXCTL.MVMEN is enabled */
+       if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+               queue0 = index;
        } else {
                mask = (unsigned long) adapter->ring_feature[RING_F_RSS].mask;
                queue0 = index & mask;
@@ -1535,7 +1694,14 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, int index)
        srrctl &= ~IXGBE_SRRCTL_BSIZEPKT_MASK;
 
        if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
-               srrctl |= IXGBE_RXBUFFER_2048 >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
+               u16 bufsz = IXGBE_RXBUFFER_2048;
+               /* grow the amount we can receive on large page machines */
+               if (bufsz < (PAGE_SIZE / 2))
+                       bufsz = (PAGE_SIZE / 2);
+               /* cap the bufsz at our largest descriptor size */
+               bufsz = min((u16)IXGBE_MAX_RXBUFFER, bufsz);
+
+               srrctl |= bufsz >> IXGBE_SRRCTL_BSIZEPKT_SHIFT;
                srrctl |= IXGBE_SRRCTL_DESCTYPE_HDR_SPLIT_ALWAYS;
                srrctl |= ((IXGBE_RX_HDR_SIZE <<
                            IXGBE_SRRCTL_BSIZEHDRSIZE_SHIFT) &
@@ -1550,6 +1716,7 @@ static void ixgbe_configure_srrctl(struct ixgbe_adapter *adapter, int index)
                        srrctl |= rx_ring->rx_buf_len >>
                                  IXGBE_SRRCTL_BSIZEPKT_SHIFT;
        }
+
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_SRRCTL(index), srrctl);
 }
 
@@ -1571,7 +1738,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
                          0xA54F2BEC, 0xEA49AF7C, 0xE214AD3D, 0xB855AABE,
                          0x6A3E67EA, 0x14364D17, 0x3BED200D};
        u32 fctrl, hlreg0;
-       u32 reta = 0, mrqc;
+       u32 reta = 0, mrqc = 0;
        u32 rdrxctl;
        int rx_buf_len;
 
@@ -1581,6 +1748,14 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
        /* Set the RX buffer length according to the mode */
        if (adapter->flags & IXGBE_FLAG_RX_PS_ENABLED) {
                rx_buf_len = IXGBE_RX_HDR_SIZE;
+               if (hw->mac.type == ixgbe_mac_82599EB) {
+                       /* PSRTYPE must be initialized in 82599 */
+                       u32 psrtype = IXGBE_PSRTYPE_TCPHDR |
+                                     IXGBE_PSRTYPE_UDPHDR |
+                                     IXGBE_PSRTYPE_IPV4HDR |
+                                     IXGBE_PSRTYPE_IPV6HDR;
+                       IXGBE_WRITE_REG(hw, IXGBE_PSRTYPE(0), psrtype);
+               }
        } else {
                if (netdev->mtu <= ETH_DATA_LEN)
                        rx_buf_len = MAXIMUM_ETHERNET_VLAN_SIZE;
@@ -1591,6 +1766,7 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
        fctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_FCTRL);
        fctrl |= IXGBE_FCTRL_BAM;
        fctrl |= IXGBE_FCTRL_DPF; /* discard pause frames when FC enabled */
+       fctrl |= IXGBE_FCTRL_PMCF;
        IXGBE_WRITE_REG(&adapter->hw, IXGBE_FCTRL, fctrl);
 
        hlreg0 = IXGBE_READ_REG(hw, IXGBE_HLREG0);
@@ -1622,23 +1798,40 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
                ixgbe_configure_srrctl(adapter, j);
        }
 
-       /*
-        * For VMDq support of different descriptor types or
-        * buffer sizes through the use of multiple SRRCTL
-        * registers, RDRXCTL.MVMEN must be set to 1
-        *
-        * also, the manual doesn't mention it clearly but DCA hints
-        * will only use queue 0's tags unless this bit is set.  Side
-        * effects of setting this bit are only that SRRCTL must be
-        * fully programmed [0..15]
-        */
-       if (adapter->flags &
-           (IXGBE_FLAG_RSS_ENABLED | IXGBE_FLAG_VMDQ_ENABLED)) {
+       if (hw->mac.type == ixgbe_mac_82598EB) {
+               /*
+                * For VMDq support of different descriptor types or
+                * buffer sizes through the use of multiple SRRCTL
+                * registers, RDRXCTL.MVMEN must be set to 1
+                *
+                * also, the manual doesn't mention it clearly but DCA hints
+                * will only use queue 0's tags unless this bit is set.  Side
+                * effects of setting this bit are only that SRRCTL must be
+                * fully programmed [0..15]
+                */
                rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
                rdrxctl |= IXGBE_RDRXCTL_MVMEN;
                IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
        }
 
+       /* Program MRQC for the distribution of queues */
+       if (hw->mac.type == ixgbe_mac_82599EB) {
+               int mask = adapter->flags & (
+                               IXGBE_FLAG_RSS_ENABLED
+                               | IXGBE_FLAG_DCB_ENABLED
+                               );
+
+               switch (mask) {
+               case (IXGBE_FLAG_RSS_ENABLED):
+                       mrqc = IXGBE_MRQC_RSSEN;
+                       break;
+               case (IXGBE_FLAG_DCB_ENABLED):
+                       mrqc = IXGBE_MRQC_RT8TCEN;
+                       break;
+               default:
+                       break;
+               }
+       }
        if (adapter->flags & IXGBE_FLAG_RSS_ENABLED) {
                /* Fill out redirection table */
                for (i = 0, j = 0; i < 128; i++, j++) {
@@ -1655,19 +1848,17 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
                for (i = 0; i < 10; i++)
                        IXGBE_WRITE_REG(hw, IXGBE_RSSRK(i), seed[i]);
 
-               mrqc = IXGBE_MRQC_RSSEN
+               if (hw->mac.type == ixgbe_mac_82598EB)
+                       mrqc |= IXGBE_MRQC_RSSEN;
                    /* Perform hash on these packet types */
-                      | IXGBE_MRQC_RSS_FIELD_IPV4
-                      | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
-                      | IXGBE_MRQC_RSS_FIELD_IPV4_UDP
-                      | IXGBE_MRQC_RSS_FIELD_IPV6_EX_TCP
-                      | IXGBE_MRQC_RSS_FIELD_IPV6_EX
-                      | IXGBE_MRQC_RSS_FIELD_IPV6
-                      | IXGBE_MRQC_RSS_FIELD_IPV6_TCP
-                      | IXGBE_MRQC_RSS_FIELD_IPV6_UDP
-                      | IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP;
-               IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
+               mrqc |= IXGBE_MRQC_RSS_FIELD_IPV4
+                     | IXGBE_MRQC_RSS_FIELD_IPV4_TCP
+                     | IXGBE_MRQC_RSS_FIELD_IPV4_UDP
+                     | IXGBE_MRQC_RSS_FIELD_IPV6
+                     | IXGBE_MRQC_RSS_FIELD_IPV6_TCP
+                     | IXGBE_MRQC_RSS_FIELD_IPV6_UDP;
        }
+       IXGBE_WRITE_REG(hw, IXGBE_MRQC, mrqc);
 
        rxcsum = IXGBE_READ_REG(hw, IXGBE_RXCSUM);
 
@@ -1684,6 +1875,12 @@ static void ixgbe_configure_rx(struct ixgbe_adapter *adapter)
        }
 
        IXGBE_WRITE_REG(hw, IXGBE_RXCSUM, rxcsum);
+
+       if (hw->mac.type == ixgbe_mac_82599EB) {
+               rdrxctl = IXGBE_READ_REG(hw, IXGBE_RDRXCTL);
+               rdrxctl |= IXGBE_RDRXCTL_CRCSTRIP;
+               IXGBE_WRITE_REG(hw, IXGBE_RDRXCTL, rdrxctl);
+       }
 }
 
 static void ixgbe_vlan_rx_add_vid(struct net_device *netdev, u16 vid)
@@ -1717,6 +1914,7 @@ static void ixgbe_vlan_rx_register(struct net_device *netdev,
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
        u32 ctrl;
+       int i, j;
 
        if (!test_bit(__IXGBE_DOWN, &adapter->state))
                ixgbe_irq_disable(adapter);
@@ -1728,18 +1926,24 @@ static void ixgbe_vlan_rx_register(struct net_device *netdev,
         * not in DCB mode.
         */
        ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL);
-       ctrl |= IXGBE_VLNCTRL_VME;
-       ctrl &= ~IXGBE_VLNCTRL_CFIEN;
-       IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl);
-       ixgbe_vlan_rx_add_vid(netdev, 0);
-
-       if (grp) {
+       if (adapter->hw.mac.type == ixgbe_mac_82598EB) {
+               ctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE;
+               ctrl &= ~IXGBE_VLNCTRL_CFIEN;
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl);
+       } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+               ctrl |= IXGBE_VLNCTRL_VFE;
                /* enable VLAN tag insert/strip */
                ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_VLNCTRL);
-               ctrl |= IXGBE_VLNCTRL_VME;
                ctrl &= ~IXGBE_VLNCTRL_CFIEN;
                IXGBE_WRITE_REG(&adapter->hw, IXGBE_VLNCTRL, ctrl);
+               for (i = 0; i < adapter->num_rx_queues; i++) {
+                       j = adapter->rx_ring[i].reg_idx;
+                       ctrl = IXGBE_READ_REG(&adapter->hw, IXGBE_RXDCTL(j));
+                       ctrl |= IXGBE_RXDCTL_VME;
+                       IXGBE_WRITE_REG(&adapter->hw, IXGBE_RXDCTL(j), ctrl);
+               }
        }
+       ixgbe_vlan_rx_add_vid(netdev, 0);
 
        if (!test_bit(__IXGBE_DOWN, &adapter->state))
                ixgbe_irq_enable(adapter);
@@ -1902,9 +2106,21 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter)
        }
        /* Enable VLAN tag insert/strip */
        vlnctrl = IXGBE_READ_REG(hw, IXGBE_VLNCTRL);
-       vlnctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE;
-       vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
-       IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
+       if (hw->mac.type == ixgbe_mac_82598EB) {
+               vlnctrl |= IXGBE_VLNCTRL_VME | IXGBE_VLNCTRL_VFE;
+               vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
+               IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
+       } else if (hw->mac.type == ixgbe_mac_82599EB) {
+               vlnctrl |= IXGBE_VLNCTRL_VFE;
+               vlnctrl &= ~IXGBE_VLNCTRL_CFIEN;
+               IXGBE_WRITE_REG(hw, IXGBE_VLNCTRL, vlnctrl);
+               for (i = 0; i < adapter->num_rx_queues; i++) {
+                       j = adapter->rx_ring[i].reg_idx;
+                       vlnctrl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j));
+                       vlnctrl |= IXGBE_RXDCTL_VME;
+                       IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(j), vlnctrl);
+               }
+       }
        hw->mac.ops.set_vfta(&adapter->hw, 0, 0, true);
 }
 
@@ -1935,13 +2151,60 @@ static void ixgbe_configure(struct ixgbe_adapter *adapter)
                                       (adapter->rx_ring[i].count - 1));
 }
 
+static inline bool ixgbe_is_sfp(struct ixgbe_hw *hw)
+{
+       switch (hw->phy.type) {
+       case ixgbe_phy_sfp_avago:
+       case ixgbe_phy_sfp_ftl:
+       case ixgbe_phy_sfp_intel:
+       case ixgbe_phy_sfp_unknown:
+       case ixgbe_phy_tw_tyco:
+       case ixgbe_phy_tw_unknown:
+               return true;
+       default:
+               return false;
+       }
+}
+
 /**
- * ixgbe_link_config - set up initial link with default speed and duplex
+ * ixgbe_sfp_link_config - set up SFP+ link
+ * @adapter: pointer to private adapter struct
+ **/
+static void ixgbe_sfp_link_config(struct ixgbe_adapter *adapter)
+{
+       struct ixgbe_hw *hw = &adapter->hw;
+
+               if (hw->phy.multispeed_fiber) {
+                       /*
+                        * In multispeed fiber setups, the device may not have
+                        * had a physical connection when the driver loaded.
+                        * If that's the case, the initial link configuration
+                        * couldn't get the MAC into 10G or 1G mode, so we'll
+                        * never have a link status change interrupt fire.
+                        * We need to try and force an autonegotiation
+                        * session, then bring up link.
+                        */
+                       hw->mac.ops.setup_sfp(hw);
+                       if (!(adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK))
+                               schedule_work(&adapter->multispeed_fiber_task);
+               } else {
+                       /*
+                        * Direct Attach Cu and non-multispeed fiber modules
+                        * still need to be configured properly prior to
+                        * attempting link.
+                        */
+                       if (!(adapter->flags & IXGBE_FLAG_IN_SFP_MOD_TASK))
+                               schedule_work(&adapter->sfp_config_module_task);
+               }
+}
+
+/**
+ * ixgbe_non_sfp_link_config - set up non-SFP+ link
  * @hw: pointer to private hardware struct
  *
  * Returns 0 on success, negative on failure
  **/
-static int ixgbe_link_config(struct ixgbe_hw *hw)
+static int ixgbe_non_sfp_link_config(struct ixgbe_hw *hw)
 {
        u32 autoneg;
        bool link_up = false;
@@ -1961,19 +2224,42 @@ static int ixgbe_link_config(struct ixgbe_hw *hw)
 
        if (hw->mac.ops.setup_link_speed)
                ret = hw->mac.ops.setup_link_speed(hw, autoneg, true, link_up);
-
 link_cfg_out:
        return ret;
 }
 
+#define IXGBE_MAX_RX_DESC_POLL 10
+static inline void ixgbe_rx_desc_queue_enable(struct ixgbe_adapter *adapter,
+                                             int rxr)
+{
+       int j = adapter->rx_ring[rxr].reg_idx;
+       int k;
+
+       for (k = 0; k < IXGBE_MAX_RX_DESC_POLL; k++) {
+               if (IXGBE_READ_REG(&adapter->hw,
+                                  IXGBE_RXDCTL(j)) & IXGBE_RXDCTL_ENABLE)
+                       break;
+               else
+                       msleep(1);
+       }
+       if (k >= IXGBE_MAX_RX_DESC_POLL) {
+               DPRINTK(DRV, ERR, "RXDCTL.ENABLE on Rx queue %d "
+                       "not set within the polling period\n", rxr);
+       }
+       ixgbe_release_rx_desc(&adapter->hw, &adapter->rx_ring[rxr],
+                             (adapter->rx_ring[rxr].count - 1));
+}
+
 static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
 {
        struct net_device *netdev = adapter->netdev;
        struct ixgbe_hw *hw = &adapter->hw;
        int i, j = 0;
+       int num_rx_rings = adapter->num_rx_queues;
        int err;
        int max_frame = netdev->mtu + ETH_HLEN + ETH_FCS_LEN;
        u32 txdctl, rxdctl, mhadd;
+       u32 dmatxctl;
        u32 gpie;
 
        ixgbe_get_hw_control(adapter);
@@ -2005,6 +2291,13 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
                IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
        }
 
+       if (hw->mac.type == ixgbe_mac_82599EB) {
+               gpie = IXGBE_READ_REG(hw, IXGBE_GPIE);
+               gpie |= IXGBE_SDP1_GPIEN;
+               gpie |= IXGBE_SDP2_GPIEN;
+               IXGBE_WRITE_REG(hw, IXGBE_GPIE, gpie);
+       }
+
        mhadd = IXGBE_READ_REG(hw, IXGBE_MHADD);
        if (max_frame != (mhadd >> IXGBE_MHADD_MFS_SHIFT)) {
                mhadd &= ~IXGBE_MHADD_MFS_MASK;
@@ -2018,11 +2311,23 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
                txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
                /* enable WTHRESH=8 descriptors, to encourage burst writeback */
                txdctl |= (8 << 16);
+               IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
+       }
+
+       if (hw->mac.type == ixgbe_mac_82599EB) {
+               /* DMATXCTL.EN must be set after all Tx queue config is done */
+               dmatxctl = IXGBE_READ_REG(hw, IXGBE_DMATXCTL);
+               dmatxctl |= IXGBE_DMATXCTL_TE;
+               IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL, dmatxctl);
+       }
+       for (i = 0; i < adapter->num_tx_queues; i++) {
+               j = adapter->tx_ring[i].reg_idx;
+               txdctl = IXGBE_READ_REG(hw, IXGBE_TXDCTL(j));
                txdctl |= IXGBE_TXDCTL_ENABLE;
                IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j), txdctl);
        }
 
-       for (i = 0; i < adapter->num_rx_queues; i++) {
+       for (i = 0; i < num_rx_rings; i++) {
                j = adapter->rx_ring[i].reg_idx;
                rxdctl = IXGBE_READ_REG(hw, IXGBE_RXDCTL(j));
                /* enable PTHRESH=32 descriptors (half the internal cache)
@@ -2031,19 +2336,22 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
                rxdctl |= 0x0020;
                rxdctl |= IXGBE_RXDCTL_ENABLE;
                IXGBE_WRITE_REG(hw, IXGBE_RXDCTL(j), rxdctl);
+               if (hw->mac.type == ixgbe_mac_82599EB)
+                       ixgbe_rx_desc_queue_enable(adapter, i);
        }
        /* enable all receives */
        rxdctl = IXGBE_READ_REG(hw, IXGBE_RXCTRL);
-       rxdctl |= (IXGBE_RXCTRL_DMBYPS | IXGBE_RXCTRL_RXEN);
-       IXGBE_WRITE_REG(hw, IXGBE_RXCTRL, rxdctl);
+       if (hw->mac.type == ixgbe_mac_82598EB)
+               rxdctl |= (IXGBE_RXCTRL_DMBYPS | IXGBE_RXCTRL_RXEN);
+       else
+               rxdctl |= IXGBE_RXCTRL_RXEN;
+       hw->mac.ops.enable_rx_dma(hw, rxdctl);
 
        if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED)
                ixgbe_configure_msix(adapter);
        else
                ixgbe_configure_msi_and_legacy(adapter);
 
-       ixgbe_napi_add_all(adapter);
-
        clear_bit(__IXGBE_DOWN, &adapter->state);
        ixgbe_napi_enable_all(adapter);
 
@@ -2052,9 +2360,27 @@ static int ixgbe_up_complete(struct ixgbe_adapter *adapter)
 
        ixgbe_irq_enable(adapter);
 
-       err = ixgbe_link_config(hw);
-       if (err)
-               dev_err(&adapter->pdev->dev, "link_config FAILED %d\n", err);
+       /*
+        * For hot-pluggable SFP+ devices, a new SFP+ module may have
+        * arrived before interrupts were enabled.  We need to kick off
+        * the SFP+ module setup first, then try to bring up link.
+        * If we're not hot-pluggable SFP+, we just need to configure link
+        * and bring it up.
+        */
+       err = hw->phy.ops.identify(hw);
+       if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
+               DPRINTK(PROBE, ERR, "PHY not supported on this NIC %d\n", err);
+               ixgbe_down(adapter);
+               return err;
+       }
+
+       if (ixgbe_is_sfp(hw)) {
+               ixgbe_sfp_link_config(adapter);
+       } else {
+               err = ixgbe_non_sfp_link_config(hw);
+               if (err)
+                       DPRINTK(PROBE, ERR, "link_config FAILED %d\n", err);
+       }
 
        /* enable transmits */
        netif_tx_start_all_queues(netdev);
@@ -2082,6 +2408,8 @@ int ixgbe_up(struct ixgbe_adapter *adapter)
        /* hardware has been reset, we need to reload some things */
        ixgbe_configure(adapter);
 
+       ixgbe_napi_add_all(adapter);
+
        return ixgbe_up_complete(adapter);
 }
 
@@ -2143,8 +2471,10 @@ static void ixgbe_clean_rx_ring(struct ixgbe_adapter *adapter,
        rx_ring->next_to_clean = 0;
        rx_ring->next_to_use = 0;
 
-       writel(0, adapter->hw.hw_addr + rx_ring->head);
-       writel(0, adapter->hw.hw_addr + rx_ring->tail);
+       if (rx_ring->head)
+               writel(0, adapter->hw.hw_addr + rx_ring->head);
+       if (rx_ring->tail)
+               writel(0, adapter->hw.hw_addr + rx_ring->tail);
 }
 
 /**
@@ -2175,8 +2505,10 @@ static void ixgbe_clean_tx_ring(struct ixgbe_adapter *adapter,
        tx_ring->next_to_use = 0;
        tx_ring->next_to_clean = 0;
 
-       writel(0, adapter->hw.hw_addr + tx_ring->head);
-       writel(0, adapter->hw.hw_addr + tx_ring->tail);
+       if (tx_ring->head)
+               writel(0, adapter->hw.hw_addr + tx_ring->head);
+       if (tx_ring->tail)
+               writel(0, adapter->hw.hw_addr + tx_ring->tail);
 }
 
 /**
@@ -2239,6 +2571,11 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
                IXGBE_WRITE_REG(hw, IXGBE_TXDCTL(j),
                                (txdctl & ~IXGBE_TXDCTL_ENABLE));
        }
+       /* Disable the Tx DMA engine on 82599 */
+       if (hw->mac.type == ixgbe_mac_82599EB)
+               IXGBE_WRITE_REG(hw, IXGBE_DMATXCTL,
+                               (IXGBE_READ_REG(hw, IXGBE_DMATXCTL) &
+                                ~IXGBE_DMATXCTL_TE));
 
        netif_carrier_off(netdev);
 
@@ -2275,10 +2612,10 @@ void ixgbe_down(struct ixgbe_adapter *adapter)
  **/
 static int ixgbe_poll(struct napi_struct *napi, int budget)
 {
-       struct ixgbe_q_vector *q_vector = container_of(napi,
-                                                 struct ixgbe_q_vector, napi);
+       struct ixgbe_q_vector *q_vector =
+                               container_of(napi, struct ixgbe_q_vector, napi);
        struct ixgbe_adapter *adapter = q_vector->adapter;
-       int tx_cleaned, work_done = 0;
+       int tx_clean_complete, work_done = 0;
 
 #ifdef CONFIG_IXGBE_DCA
        if (adapter->flags & IXGBE_FLAG_DCA_ENABLED) {
@@ -2287,19 +2624,19 @@ static int ixgbe_poll(struct napi_struct *napi, int budget)
        }
 #endif
 
-       tx_cleaned = ixgbe_clean_tx_irq(adapter, adapter->tx_ring);
+       tx_clean_complete = ixgbe_clean_tx_irq(adapter, adapter->tx_ring);
        ixgbe_clean_rx_irq(q_vector, adapter->rx_ring, &work_done, budget);
 
-       if (tx_cleaned)
+       if (!tx_clean_complete)
                work_done = budget;
 
        /* If budget not fully consumed, exit the polling mode */
        if (work_done < budget) {
                napi_complete(napi);
-               if (adapter->itr_setting & 3)
+               if (adapter->itr_setting & 1)
                        ixgbe_set_itr(adapter);
                if (!test_bit(__IXGBE_DOWN, &adapter->state))
-                       ixgbe_irq_enable(adapter);
+                       ixgbe_irq_enable_queues(adapter);
        }
        return work_done;
 }
@@ -2351,6 +2688,14 @@ static inline bool ixgbe_set_dcb_queues(struct ixgbe_adapter *adapter)
 }
 #endif
 
+/**
+ * ixgbe_set_rss_queues: Allocate queues for RSS
+ * @adapter: board private structure to initialize
+ *
+ * This is our "base" multiqueue mode.  RSS (Receive Side Scaling) will try
+ * to allocate one Rx queue per CPU, and if available, one Tx queue per CPU.
+ *
+ **/
 static inline bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter)
 {
        bool ret = false;
@@ -2369,6 +2714,17 @@ static inline bool ixgbe_set_rss_queues(struct ixgbe_adapter *adapter)
        return ret;
 }
 
+/*
+ * ixgbe_set_num_queues: Allocate queues for device, feature dependant
+ * @adapter: board private structure to initialize
+ *
+ * This is the top level queue allocation routine.  The order here is very
+ * important, starting with the "most" number of features turned on at once,
+ * and ending with the smallest set of features.  This way large combinations
+ * can be allocated if they're turned on, and smaller combinations are the
+ * fallthrough conditions.
+ *
+ **/
 static void ixgbe_set_num_queues(struct ixgbe_adapter *adapter)
 {
        /* Start with base case */
@@ -2484,6 +2840,12 @@ static inline bool ixgbe_cache_ring_dcb(struct ixgbe_adapter *adapter)
                                adapter->tx_ring[i].reg_idx = i << 2;
                        }
                        ret = true;
+               } else if (adapter->hw.mac.type == ixgbe_mac_82599EB) {
+                       for (i = 0; i < dcb_i; i++) {
+                               adapter->rx_ring[i].reg_idx = i << 4;
+                               adapter->tx_ring[i].reg_idx = i << 4;
+                       }
+                       ret = true;
                } else {
                        ret = false;
                }
@@ -2526,7 +2888,8 @@ static void ixgbe_cache_ring_register(struct ixgbe_adapter *adapter)
  * @adapter: board private structure to initialize
  *
  * We allocate one ring per queue at run-time since we don't know the
- * number of queues at compile-time.
+ * number of queues at compile-time.  The polling_netdev array is
+ * intended for Multiqueue, but should work fine with a single queue.
  **/
 static int ixgbe_alloc_queues(struct ixgbe_adapter *adapter)
 {
@@ -2705,7 +3068,8 @@ static void ixgbe_sfp_timer(unsigned long data)
 {
        struct ixgbe_adapter *adapter = (struct ixgbe_adapter *)data;
 
-       /* Do the sfp_timer outside of interrupt context due to the
+       /*
+        * Do the sfp_timer outside of interrupt context due to the
         * delays that sfp+ detection requires
         */
        schedule_work(&adapter->sfp_task);
@@ -2779,7 +3143,10 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
        adapter->ring_feature[RING_F_RSS].indices = rss;
        adapter->flags |= IXGBE_FLAG_RSS_ENABLED;
        adapter->ring_feature[RING_F_DCB].indices = IXGBE_MAX_DCB_INDICES;
-       adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82598;
+       if (hw->mac.type == ixgbe_mac_82598EB)
+               adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82598;
+       else if (hw->mac.type == ixgbe_mac_82599EB)
+               adapter->max_msix_q_vectors = MAX_MSIX_Q_VECTORS_82599;
 
 #ifdef CONFIG_IXGBE_DCB
        /* Configure DCB traffic classes */
@@ -2800,9 +3167,6 @@ static int __devinit ixgbe_sw_init(struct ixgbe_adapter *adapter)
                           adapter->ring_feature[RING_F_DCB].indices);
 
 #endif
-       if (hw->mac.ops.get_media_type &&
-           (hw->mac.ops.get_media_type(hw) == ixgbe_media_type_copper))
-               adapter->flags |= IXGBE_FLAG_FAN_FAIL_CAPABLE;
 
        /* default flow control settings */
        hw->fc.requested_mode = ixgbe_fc_none;
@@ -3006,7 +3370,8 @@ static void ixgbe_free_all_tx_resources(struct ixgbe_adapter *adapter)
        int i;
 
        for (i = 0; i < adapter->num_tx_queues; i++)
-               ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]);
+               if (adapter->tx_ring[i].desc)
+                       ixgbe_free_tx_resources(adapter, &adapter->tx_ring[i]);
 }
 
 /**
@@ -3042,7 +3407,8 @@ static void ixgbe_free_all_rx_resources(struct ixgbe_adapter *adapter)
        int i;
 
        for (i = 0; i < adapter->num_rx_queues; i++)
-               ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]);
+               if (adapter->rx_ring[i].desc)
+                       ixgbe_free_rx_resources(adapter, &adapter->rx_ring[i]);
 }
 
 /**
@@ -3105,6 +3471,8 @@ static int ixgbe_open(struct net_device *netdev)
 
        ixgbe_configure(adapter);
 
+       ixgbe_napi_add_all(adapter);
+
        err = ixgbe_request_irq(adapter);
        if (err)
                goto err_req_irq;
@@ -3159,6 +3527,7 @@ static int ixgbe_close(struct net_device *netdev)
 /**
  * ixgbe_napi_add_all - prep napi structs for use
  * @adapter: private struct
+ *
  * helper function to napi_add each possible q_vector->napi
  */
 void ixgbe_napi_add_all(struct ixgbe_adapter *adapter)
@@ -3231,7 +3600,6 @@ static int ixgbe_resume(struct pci_dev *pdev)
                return err;
        }
 
-       ixgbe_napi_add_all(adapter);
        ixgbe_reset(adapter);
 
        if (netif_running(netdev)) {
@@ -3250,6 +3618,9 @@ static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *netdev = pci_get_drvdata(pdev);
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 ctrl, fctrl;
+       u32 wufc = adapter->wol;
 #ifdef CONFIG_PM
        int retval = 0;
 #endif
@@ -3272,10 +3643,35 @@ static int ixgbe_suspend(struct pci_dev *pdev, pm_message_t state)
        retval = pci_save_state(pdev);
        if (retval)
                return retval;
+
 #endif
+       if (wufc) {
+               ixgbe_set_rx_mode(netdev);
 
-       pci_enable_wake(pdev, PCI_D3hot, 0);
-       pci_enable_wake(pdev, PCI_D3cold, 0);
+               /* turn on all-multi mode if wake on multicast is enabled */
+               if (wufc & IXGBE_WUFC_MC) {
+                       fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+                       fctrl |= IXGBE_FCTRL_MPE;
+                       IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
+               }
+
+               ctrl = IXGBE_READ_REG(hw, IXGBE_CTRL);
+               ctrl |= IXGBE_CTRL_GIO_DIS;
+               IXGBE_WRITE_REG(hw, IXGBE_CTRL, ctrl);
+
+               IXGBE_WRITE_REG(hw, IXGBE_WUFC, wufc);
+       } else {
+               IXGBE_WRITE_REG(hw, IXGBE_WUC, 0);
+               IXGBE_WRITE_REG(hw, IXGBE_WUFC, 0);
+       }
+
+       if (wufc && hw->mac.type == ixgbe_mac_82599EB) {
+               pci_enable_wake(pdev, PCI_D3hot, 1);
+               pci_enable_wake(pdev, PCI_D3cold, 1);
+       } else {
+               pci_enable_wake(pdev, PCI_D3hot, 0);
+               pci_enable_wake(pdev, PCI_D3cold, 0);
+       }
 
        ixgbe_release_hw_control(adapter);
 
@@ -3301,6 +3697,12 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
        u64 total_mpc = 0;
        u32 i, missed_rx = 0, mpc, bprc, lxon, lxoff, xon_off_tot;
 
+       if (hw->mac.type == ixgbe_mac_82599EB) {
+               for (i = 0; i < 16; i++)
+                       adapter->hw_rx_no_dma_resources +=
+                                            IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
+       }
+
        adapter->stats.crcerrs += IXGBE_READ_REG(hw, IXGBE_CRCERRS);
        for (i = 0; i < 8; i++) {
                /* for packet buffers not used, the register should read 0 */
@@ -3308,32 +3710,55 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
                missed_rx += mpc;
                adapter->stats.mpc[i] += mpc;
                total_mpc += adapter->stats.mpc[i];
-               adapter->stats.rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i));
+               if (hw->mac.type == ixgbe_mac_82598EB)
+                       adapter->stats.rnbc[i] += IXGBE_READ_REG(hw, IXGBE_RNBC(i));
                adapter->stats.qptc[i] += IXGBE_READ_REG(hw, IXGBE_QPTC(i));
                adapter->stats.qbtc[i] += IXGBE_READ_REG(hw, IXGBE_QBTC(i));
                adapter->stats.qprc[i] += IXGBE_READ_REG(hw, IXGBE_QPRC(i));
                adapter->stats.qbrc[i] += IXGBE_READ_REG(hw, IXGBE_QBRC(i));
-               adapter->stats.pxonrxc[i] += IXGBE_READ_REG(hw,
-                                                           IXGBE_PXONRXC(i));
+               if (hw->mac.type == ixgbe_mac_82599EB) {
+                       adapter->stats.pxonrxc[i] += IXGBE_READ_REG(hw,
+                                                           IXGBE_PXONRXCNT(i));
+                       adapter->stats.pxoffrxc[i] += IXGBE_READ_REG(hw,
+                                                          IXGBE_PXOFFRXCNT(i));
+                       adapter->stats.qprdc[i] += IXGBE_READ_REG(hw, IXGBE_QPRDC(i));
+               } else {
+                       adapter->stats.pxonrxc[i] += IXGBE_READ_REG(hw,
+                                                             IXGBE_PXONRXC(i));
+                       adapter->stats.pxoffrxc[i] += IXGBE_READ_REG(hw,
+                                                            IXGBE_PXOFFRXC(i));
+               }
                adapter->stats.pxontxc[i] += IXGBE_READ_REG(hw,
                                                            IXGBE_PXONTXC(i));
-               adapter->stats.pxoffrxc[i] += IXGBE_READ_REG(hw,
-                                                           IXGBE_PXOFFRXC(i));
                adapter->stats.pxofftxc[i] += IXGBE_READ_REG(hw,
-                                                           IXGBE_PXOFFTXC(i));
+                                                            IXGBE_PXOFFTXC(i));
        }
        adapter->stats.gprc += IXGBE_READ_REG(hw, IXGBE_GPRC);
        /* work around hardware counting issue */
        adapter->stats.gprc -= missed_rx;
 
        /* 82598 hardware only has a 32 bit counter in the high register */
-       adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
-       adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
-       adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH);
+       if (hw->mac.type == ixgbe_mac_82599EB) {
+               adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCL);
+               IXGBE_READ_REG(hw, IXGBE_GORCH); /* to clear */
+               adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCL);
+               IXGBE_READ_REG(hw, IXGBE_GOTCH); /* to clear */
+               adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORL);
+               IXGBE_READ_REG(hw, IXGBE_TORH); /* to clear */
+               adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXCNT);
+               adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXCNT);
+       } else {
+               adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
+               adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
+               adapter->stats.gorc += IXGBE_READ_REG(hw, IXGBE_GORCH);
+               adapter->stats.gotc += IXGBE_READ_REG(hw, IXGBE_GOTCH);
+               adapter->stats.tor += IXGBE_READ_REG(hw, IXGBE_TORH);
+       }
        bprc = IXGBE_READ_REG(hw, IXGBE_BPRC);
        adapter->stats.bprc += bprc;
        adapter->stats.mprc += IXGBE_READ_REG(hw, IXGBE_MPRC);
-       adapter->stats.mprc -= bprc;
+       if (hw->mac.type == ixgbe_mac_82598EB)
+               adapter->stats.mprc -= bprc;
        adapter->stats.roc += IXGBE_READ_REG(hw, IXGBE_ROC);
        adapter->stats.prc64 += IXGBE_READ_REG(hw, IXGBE_PRC64);
        adapter->stats.prc127 += IXGBE_READ_REG(hw, IXGBE_PRC127);
@@ -3342,8 +3767,6 @@ void ixgbe_update_stats(struct ixgbe_adapter *adapter)
        adapter->stats.prc1023 += IXGBE_READ_REG(hw, IXGBE_PRC1023);
        adapter->stats.prc1522 += IXGBE_READ_REG(hw, IXGBE_PRC1522);
        adapter->stats.rlec += IXGBE_READ_REG(hw, IXGBE_RLEC);
-       adapter->stats.lxonrxc += IXGBE_READ_REG(hw, IXGBE_LXONRXC);
-       adapter->stats.lxoffrxc += IXGBE_READ_REG(hw, IXGBE_LXOFFRXC);
        lxon = IXGBE_READ_REG(hw, IXGBE_LXONTXC);
        adapter->stats.lxontxc += lxon;
        lxoff = IXGBE_READ_REG(hw, IXGBE_LXOFFTXC);
@@ -3395,17 +3818,54 @@ static void ixgbe_watchdog(unsigned long data)
        /* Do the watchdog outside of interrupt context due to the lovely
         * delays that some of the newer hardware requires */
        if (!test_bit(__IXGBE_DOWN, &adapter->state)) {
+               u64 eics = 0;
+               int i;
+
+               for (i = 0; i < adapter->num_msix_vectors - NON_Q_VECTORS; i++)
+                       eics |= (1 << i);
+
                /* Cause software interrupt to ensure rx rings are cleaned */
-               if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
-                       u32 eics =
-                        (1 << (adapter->num_msix_vectors - NON_Q_VECTORS)) - 1;
-                       IXGBE_WRITE_REG(hw, IXGBE_EICS, eics);
-               } else {
-                       /* For legacy and MSI interrupts don't set any bits that
-                        * are enabled for EIAM, because this operation would
-                        * set *both* EIMS and EICS for any bit in EIAM */
-                       IXGBE_WRITE_REG(hw, IXGBE_EICS,
-                                    (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER));
+               switch (hw->mac.type) {
+               case ixgbe_mac_82598EB:
+                       if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+                               IXGBE_WRITE_REG(hw, IXGBE_EICS, (u32)eics);
+                       } else {
+                               /*
+                                * for legacy and MSI interrupts don't set any
+                                * bits that are enabled for EIAM, because this
+                                * operation would set *both* EIMS and EICS for
+                                * any bit in EIAM
+                                */
+                               IXGBE_WRITE_REG(hw, IXGBE_EICS,
+                                    (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER));
+                       }
+                       break;
+               case ixgbe_mac_82599EB:
+                       if (adapter->flags & IXGBE_FLAG_MSIX_ENABLED) {
+                               /*
+                                * EICS(0..15) first 0-15 q vectors
+                                * EICS[1] (16..31) q vectors 16-31
+                                * EICS[2] (0..31) q vectors 32-63
+                                */
+                               IXGBE_WRITE_REG(hw, IXGBE_EICS,
+                                               (u32)(eics & 0xFFFF));
+                               IXGBE_WRITE_REG(hw, IXGBE_EICS_EX(1),
+                                               (u32)(eics & 0xFFFF0000));
+                               IXGBE_WRITE_REG(hw, IXGBE_EICS_EX(2),
+                                               (u32)(eics >> 32));
+                       } else {
+                               /*
+                                * for legacy and MSI interrupts don't set any
+                                * bits that are enabled for EIAM, because this
+                                * operation would set *both* EIMS and EICS for
+                                * any bit in EIAM
+                                */
+                               IXGBE_WRITE_REG(hw, IXGBE_EICS,
+                                    (IXGBE_EICS_TCP_TIMER | IXGBE_EICS_OTHER));
+                       }
+                       break;
+               default:
+                       break;
                }
                /* Reset the timer */
                mod_timer(&adapter->watchdog_timer,
@@ -3415,6 +3875,55 @@ static void ixgbe_watchdog(unsigned long data)
        schedule_work(&adapter->watchdog_task);
 }
 
+/**
+ * ixgbe_multispeed_fiber_task - worker thread to configure multispeed fiber
+ * @work: pointer to work_struct containing our data
+ **/
+static void ixgbe_multispeed_fiber_task(struct work_struct *work)
+{
+       struct ixgbe_adapter *adapter = container_of(work,
+                                                    struct ixgbe_adapter,
+                                                    multispeed_fiber_task);
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 autoneg;
+
+       adapter->flags |= IXGBE_FLAG_IN_SFP_LINK_TASK;
+       if (hw->mac.ops.get_link_capabilities)
+               hw->mac.ops.get_link_capabilities(hw, &autoneg,
+                                                 &hw->mac.autoneg);
+       if (hw->mac.ops.setup_link_speed)
+               hw->mac.ops.setup_link_speed(hw, autoneg, true, true);
+       adapter->flags |= IXGBE_FLAG_NEED_LINK_UPDATE;
+       adapter->flags &= ~IXGBE_FLAG_IN_SFP_LINK_TASK;
+}
+
+/**
+ * ixgbe_sfp_config_module_task - worker thread to configure a new SFP+ module
+ * @work: pointer to work_struct containing our data
+ **/
+static void ixgbe_sfp_config_module_task(struct work_struct *work)
+{
+       struct ixgbe_adapter *adapter = container_of(work,
+                                                    struct ixgbe_adapter,
+                                                    sfp_config_module_task);
+       struct ixgbe_hw *hw = &adapter->hw;
+       u32 err;
+
+       adapter->flags |= IXGBE_FLAG_IN_SFP_MOD_TASK;
+       err = hw->phy.ops.identify_sfp(hw);
+       if (err == IXGBE_ERR_SFP_NOT_SUPPORTED) {
+               DPRINTK(PROBE, ERR, "PHY not supported on this NIC %d\n", err);
+               ixgbe_down(adapter);
+               return;
+       }
+       hw->mac.ops.setup_sfp(hw);
+
+       if (!adapter->flags & IXGBE_FLAG_IN_SFP_LINK_TASK)
+               /* This will also work for DA Twinax connections */
+               schedule_work(&adapter->multispeed_fiber_task);
+       adapter->flags &= ~IXGBE_FLAG_IN_SFP_MOD_TASK;
+}
+
 /**
  * ixgbe_watchdog_task - worker thread to bring link up
  * @work: pointer to work_struct containing our data
@@ -3445,10 +3954,20 @@ static void ixgbe_watchdog_task(struct work_struct *work)
 
        if (link_up) {
                if (!netif_carrier_ok(netdev)) {
-                       u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
-                       u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS);
-#define FLOW_RX (frctl & IXGBE_FCTRL_RFCE)
-#define FLOW_TX (rmcs & IXGBE_RMCS_TFCE_802_3X)
+                       bool flow_rx, flow_tx;
+
+                       if (hw->mac.type == ixgbe_mac_82599EB) {
+                               u32 mflcn = IXGBE_READ_REG(hw, IXGBE_MFLCN);
+                               u32 fccfg = IXGBE_READ_REG(hw, IXGBE_FCCFG);
+                               flow_rx = (mflcn & IXGBE_MFLCN_RFCE);
+                               flow_tx = (fccfg & IXGBE_FCCFG_TFCE_802_3X);
+                       } else {
+                               u32 frctl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+                               u32 rmcs = IXGBE_READ_REG(hw, IXGBE_RMCS);
+                               flow_rx = (frctl & IXGBE_FCTRL_RFCE);
+                               flow_tx = (rmcs & IXGBE_RMCS_TFCE_802_3X);
+                       }
+
                        printk(KERN_INFO "ixgbe: %s NIC Link is Up %s, "
                               "Flow Control: %s\n",
                               netdev->name,
@@ -3456,9 +3975,9 @@ static void ixgbe_watchdog_task(struct work_struct *work)
                                "10 Gbps" :
                                (link_speed == IXGBE_LINK_SPEED_1GB_FULL ?
                                 "1 Gbps" : "unknown speed")),
-                              ((FLOW_RX && FLOW_TX) ? "RX/TX" :
-                               (FLOW_RX ? "RX" :
-                               (FLOW_TX ? "TX" : "None"))));
+                              ((flow_rx && flow_tx) ? "RX/TX" :
+                               (flow_rx ? "RX" :
+                               (flow_tx ? "TX" : "None"))));
 
                        netif_carrier_on(netdev);
                } else {
@@ -3802,6 +4321,16 @@ static int ixgbe_maybe_stop_tx(struct net_device *netdev,
        return __ixgbe_maybe_stop_tx(netdev, tx_ring, size);
 }
 
+static u16 ixgbe_select_queue(struct net_device *dev, struct sk_buff *skb)
+{
+       struct ixgbe_adapter *adapter = netdev_priv(dev);
+
+       if (adapter->flags & IXGBE_FLAG_DCB_ENABLED)
+               return 0;  /* All traffic should default to class 0 */
+
+       return skb_tx_hash(dev, skb);
+}
+
 static int ixgbe_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
        struct ixgbe_adapter *adapter = netdev_priv(netdev);
@@ -3931,7 +4460,9 @@ static const struct net_device_ops ixgbe_netdev_ops = {
        .ndo_open               = ixgbe_open,
        .ndo_stop               = ixgbe_close,
        .ndo_start_xmit         = ixgbe_xmit_frame,
+       .ndo_select_queue       = ixgbe_select_queue,
        .ndo_get_stats          = ixgbe_get_stats,
+       .ndo_set_rx_mode        = ixgbe_set_rx_mode,
        .ndo_set_multicast_list = ixgbe_set_rx_mode,
        .ndo_validate_addr      = eth_validate_addr,
        .ndo_set_mac_address    = ixgbe_set_mac,
@@ -3965,7 +4496,7 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        const struct ixgbe_info *ii = ixgbe_info_tbl[ent->driver_data];
        static int cards_found;
        int i, err, pci_using_dac;
-       u16 link_status, link_speed, link_width;
+       u16 pm_value = 0;
        u32 part_num, eec;
 
        err = pci_enable_device(pdev);
@@ -4064,6 +4595,13 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
 
        INIT_WORK(&adapter->sfp_task, ixgbe_sfp_task);
 
+       /* multispeed fiber has its own tasklet, called from GPI SDP1 context */
+       INIT_WORK(&adapter->multispeed_fiber_task, ixgbe_multispeed_fiber_task);
+
+       /* a new SFP+ module arrival, called from GPI SDP2 context */
+       INIT_WORK(&adapter->sfp_config_module_task,
+                 ixgbe_sfp_config_module_task);
+
        err = ii->get_invariants(hw);
        if (err == IXGBE_ERR_SFP_NOT_PRESENT) {
                /* start a kernel thread to watch for a module to arrive */
@@ -4144,26 +4682,41 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev,
        if (err)
                goto err_sw_init;
 
+       switch (pdev->device) {
+       case IXGBE_DEV_ID_82599_KX4:
+#define IXGBE_PCIE_PMCSR 0x44
+               adapter->wol = IXGBE_WUFC_MAG;
+               pci_read_config_word(pdev, IXGBE_PCIE_PMCSR, &pm_value);
+               pci_write_config_word(pdev, IXGBE_PCIE_PMCSR,
+                                     (pm_value | (1 << 8)));
+               break;
+       default:
+               adapter->wol = 0;
+               break;
+       }
+       device_init_wakeup(&adapter->pdev->dev, true);
+       device_set_wakeup_enable(&adapter->pdev->dev, adapter->wol);
+
        /* print bus type/speed/width info */
-       pci_read_config_word(pdev, IXGBE_PCI_LINK_STATUS, &link_status);
-       link_speed = link_status & IXGBE_PCI_LINK_SPEED;
-       link_width = link_status & IXGBE_PCI_LINK_WIDTH;
        dev_info(&pdev->dev, "(PCI Express:%s:%s) %pM\n",
-               ((link_speed == IXGBE_PCI_LINK_SPEED_5000) ? "5.0Gb/s" :
-                (link_speed == IXGBE_PCI_LINK_SPEED_2500) ? "2.5Gb/s" :
-                "Unknown"),
-               ((link_width == IXGBE_PCI_LINK_WIDTH_8) ? "Width x8" :
-                (link_width == IXGBE_PCI_LINK_WIDTH_4) ? "Width x4" :
-                (link_width == IXGBE_PCI_LINK_WIDTH_2) ? "Width x2" :
-                (link_width == IXGBE_PCI_LINK_WIDTH_1) ? "Width x1" :
+               ((hw->bus.speed == ixgbe_bus_speed_5000) ? "5.0Gb/s":
+                (hw->bus.speed == ixgbe_bus_speed_2500) ? "2.5Gb/s":"Unknown"),
+               ((hw->bus.width == ixgbe_bus_width_pcie_x8) ? "Width x8" :
+                (hw->bus.width == ixgbe_bus_width_pcie_x4) ? "Width x4" :
+                (hw->bus.width == ixgbe_bus_width_pcie_x1) ? "Width x1" :
                 "Unknown"),
                netdev->dev_addr);
        ixgbe_read_pba_num_generic(hw, &part_num);
-       dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
-                hw->mac.type, hw->phy.type,
-                (part_num >> 8), (part_num & 0xff));
+       if (ixgbe_is_sfp(hw) && hw->phy.sfp_type != ixgbe_sfp_type_not_present)
+               dev_info(&pdev->dev, "MAC: %d, PHY: %d, SFP+: %d, PBA No: %06x-%03x\n",
+                        hw->mac.type, hw->phy.type, hw->phy.sfp_type,
+                        (part_num >> 8), (part_num & 0xff));
+       else
+               dev_info(&pdev->dev, "MAC: %d, PHY: %d, PBA No: %06x-%03x\n",
+                        hw->mac.type, hw->phy.type,
+                        (part_num >> 8), (part_num & 0xff));
 
-       if (link_width <= IXGBE_PCI_LINK_WIDTH_4) {
+       if (hw->bus.width <= ixgbe_bus_width_pcie_x4) {
                dev_warn(&pdev->dev, "PCI-Express bandwidth available for "
                         "this card is not sufficient for optimal "
                         "performance.\n");
@@ -4207,6 +4760,8 @@ err_eeprom:
        clear_bit(__IXGBE_SFP_MODULE_NOT_FOUND, &adapter->state);
        del_timer_sync(&adapter->sfp_timer);
        cancel_work_sync(&adapter->sfp_task);
+       cancel_work_sync(&adapter->multispeed_fiber_task);
+       cancel_work_sync(&adapter->sfp_config_module_task);
        iounmap(hw->hw_addr);
 err_ioremap:
        free_netdev(netdev);
@@ -4243,6 +4798,8 @@ static void __devexit ixgbe_remove(struct pci_dev *pdev)
        del_timer_sync(&adapter->sfp_timer);
        cancel_work_sync(&adapter->watchdog_task);
        cancel_work_sync(&adapter->sfp_task);
+       cancel_work_sync(&adapter->multispeed_fiber_task);
+       cancel_work_sync(&adapter->sfp_config_module_task);
        flush_scheduled_work();
 
 #ifdef CONFIG_IXGBE_DCA
@@ -4326,7 +4883,7 @@ static pci_ers_result_t ixgbe_io_slot_reset(struct pci_dev *pdev)
                pci_enable_wake(pdev, PCI_D3cold, 0);
 
                ixgbe_reset(adapter);
-
+               IXGBE_WRITE_REG(&adapter->hw, IXGBE_WUS, ~0);
                result = PCI_ERS_RESULT_RECOVERED;
        }
 
index 77ec26f5650ae9808611127308fd72f0b09a9f96..14e9606aa3b30a42b734b5f5982cd0842a1370c1 100644 (file)
 #include "ixgbe_common.h"
 #include "ixgbe_phy.h"
 
+static void ixgbe_i2c_start(struct ixgbe_hw *hw);
+static void ixgbe_i2c_stop(struct ixgbe_hw *hw);
+static s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data);
+static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data);
+static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw);
+static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data);
+static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data);
+static s32 ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
+static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl);
+static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data);
+static bool ixgbe_get_i2c_data(u32 *i2cctl);
+static void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw);
 static bool ixgbe_validate_phy_addr(struct ixgbe_hw *hw, u32 phy_addr);
 static enum ixgbe_phy_type ixgbe_get_phy_type_from_id(u32 phy_id);
 static s32 ixgbe_get_phy_id(struct ixgbe_hw *hw);
@@ -543,8 +555,9 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
        u8 identifier = 0;
        u8 comp_codes_1g = 0;
        u8 comp_codes_10g = 0;
-       u8 oui_bytes[4] = {0, 0, 0, 0};
+       u8 oui_bytes[3] = {0, 0, 0};
        u8 transmission_media = 0;
+       u16 enforce_sfp = 0;
 
        status = hw->phy.ops.read_i2c_eeprom(hw, IXGBE_SFF_IDENTIFIER,
                                             &identifier);
@@ -564,18 +577,48 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
 
                /* ID Module
                 * =========
-                * 0    SFP_DA_CU
-                * 1    SFP_SR
-                * 2    SFP_LR
+                * 0    SFP_DA_CU
+                * 1    SFP_SR
+                * 2    SFP_LR
+                * 3    SFP_DA_CORE0 - 82599-specific
+                * 4    SFP_DA_CORE1 - 82599-specific
+                * 5    SFP_SR/LR_CORE0 - 82599-specific
+                * 6    SFP_SR/LR_CORE1 - 82599-specific
                 */
-               if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE)
-                       hw->phy.sfp_type = ixgbe_sfp_type_da_cu;
-               else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
-                       hw->phy.sfp_type = ixgbe_sfp_type_sr;
-               else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
-                       hw->phy.sfp_type = ixgbe_sfp_type_lr;
-               else
-                       hw->phy.sfp_type = ixgbe_sfp_type_unknown;
+               if (hw->mac.type == ixgbe_mac_82598EB) {
+                       if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE)
+                               hw->phy.sfp_type = ixgbe_sfp_type_da_cu;
+                       else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
+                               hw->phy.sfp_type = ixgbe_sfp_type_sr;
+                       else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
+                               hw->phy.sfp_type = ixgbe_sfp_type_lr;
+                       else
+                               hw->phy.sfp_type = ixgbe_sfp_type_unknown;
+               } else if (hw->mac.type == ixgbe_mac_82599EB) {
+                       if (transmission_media & IXGBE_SFF_TWIN_AX_CAPABLE)
+                               if (hw->bus.lan_id == 0)
+                                       hw->phy.sfp_type =
+                                                    ixgbe_sfp_type_da_cu_core0;
+                               else
+                                       hw->phy.sfp_type =
+                                                    ixgbe_sfp_type_da_cu_core1;
+                       else if (comp_codes_10g & IXGBE_SFF_10GBASESR_CAPABLE)
+                               if (hw->bus.lan_id == 0)
+                                       hw->phy.sfp_type =
+                                                     ixgbe_sfp_type_srlr_core0;
+                               else
+                                       hw->phy.sfp_type =
+                                                     ixgbe_sfp_type_srlr_core1;
+                       else if (comp_codes_10g & IXGBE_SFF_10GBASELR_CAPABLE)
+                               if (hw->bus.lan_id == 0)
+                                       hw->phy.sfp_type =
+                                                     ixgbe_sfp_type_srlr_core0;
+                               else
+                                       hw->phy.sfp_type =
+                                                     ixgbe_sfp_type_srlr_core1;
+                       else
+                               hw->phy.sfp_type = ixgbe_sfp_type_unknown;
+               }
 
                /* Determine PHY vendor */
                if (hw->phy.type == ixgbe_phy_unknown) {
@@ -607,6 +650,9 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
                        case IXGBE_SFF_VENDOR_OUI_AVAGO:
                                hw->phy.type = ixgbe_phy_sfp_avago;
                                break;
+                       case IXGBE_SFF_VENDOR_OUI_INTEL:
+                               hw->phy.type = ixgbe_phy_sfp_intel;
+                               break;
                        default:
                                if (transmission_media &
                                    IXGBE_SFF_TWIN_AX_CAPABLE)
@@ -616,7 +662,28 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
                                break;
                        }
                }
-               status = 0;
+               if (hw->mac.type == ixgbe_mac_82598EB ||
+                   (hw->phy.sfp_type != ixgbe_sfp_type_sr &&
+                    hw->phy.sfp_type != ixgbe_sfp_type_lr &&
+                    hw->phy.sfp_type != ixgbe_sfp_type_srlr_core0 &&
+                    hw->phy.sfp_type != ixgbe_sfp_type_srlr_core1)) {
+                       status = 0;
+                       goto out;
+               }
+
+               hw->eeprom.ops.read(hw, IXGBE_PHY_ENFORCE_INTEL_SFP_OFFSET,
+                                   &enforce_sfp);
+               if (!(enforce_sfp & IXGBE_PHY_ALLOW_ANY_SFP)) {
+                       /* Make sure we're a supported PHY type */
+                       if (hw->phy.type == ixgbe_phy_sfp_intel) {
+                               status = 0;
+                       } else {
+                               hw_dbg(hw, "SFP+ module not supported\n");
+                               status = IXGBE_ERR_SFP_NOT_SUPPORTED;
+                       }
+               } else {
+                       status = 0;
+               }
        }
 
 out:
@@ -651,7 +718,7 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
        hw->eeprom.ops.read(hw, IXGBE_PHY_INIT_OFFSET_NL, list_offset);
 
        if ((!*list_offset) || (*list_offset == 0xFFFF))
-               return IXGBE_ERR_PHY;
+               return IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT;
 
        /* Shift offset to first ID word */
        (*list_offset)++;
@@ -687,6 +754,501 @@ s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
        return 0;
 }
 
+/**
+ *  ixgbe_read_i2c_eeprom_generic - Reads 8 bit EEPROM word over I2C interface
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: EEPROM byte offset to read
+ *  @eeprom_data: value read
+ *
+ *  Performs byte read operation to SFP module's EEPROM over I2C interface.
+ **/
+s32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
+                                  u8 *eeprom_data)
+{
+       return hw->phy.ops.read_i2c_byte(hw, byte_offset,
+                                        IXGBE_I2C_EEPROM_DEV_ADDR,
+                                        eeprom_data);
+}
+
+/**
+ *  ixgbe_write_i2c_eeprom_generic - Writes 8 bit EEPROM word over I2C interface
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: EEPROM byte offset to write
+ *  @eeprom_data: value to write
+ *
+ *  Performs byte write operation to SFP module's EEPROM over I2C interface.
+ **/
+s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
+                                   u8 eeprom_data)
+{
+       return hw->phy.ops.write_i2c_byte(hw, byte_offset,
+                                         IXGBE_I2C_EEPROM_DEV_ADDR,
+                                         eeprom_data);
+}
+
+/**
+ *  ixgbe_read_i2c_byte_generic - Reads 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to read
+ *  @data: value read
+ *
+ *  Performs byte read operation to SFP module's EEPROM over I2C interface at
+ *  a specified deivce address.
+ **/
+s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
+                                u8 dev_addr, u8 *data)
+{
+       s32 status = 0;
+       u32 max_retry = 1;
+       u32 retry = 0;
+       bool nack = 1;
+
+       do {
+               ixgbe_i2c_start(hw);
+
+               /* Device Address and write indication */
+               status = ixgbe_clock_out_i2c_byte(hw, dev_addr);
+               if (status != 0)
+                       goto fail;
+
+               status = ixgbe_get_i2c_ack(hw);
+               if (status != 0)
+                       goto fail;
+
+               status = ixgbe_clock_out_i2c_byte(hw, byte_offset);
+               if (status != 0)
+                       goto fail;
+
+               status = ixgbe_get_i2c_ack(hw);
+               if (status != 0)
+                       goto fail;
+
+               ixgbe_i2c_start(hw);
+
+               /* Device Address and read indication */
+               status = ixgbe_clock_out_i2c_byte(hw, (dev_addr | 0x1));
+               if (status != 0)
+                       goto fail;
+
+               status = ixgbe_get_i2c_ack(hw);
+               if (status != 0)
+                       goto fail;
+
+               status = ixgbe_clock_in_i2c_byte(hw, data);
+               if (status != 0)
+                       goto fail;
+
+               status = ixgbe_clock_out_i2c_bit(hw, nack);
+               if (status != 0)
+                       goto fail;
+
+               ixgbe_i2c_stop(hw);
+               break;
+
+fail:
+               ixgbe_i2c_bus_clear(hw);
+               retry++;
+               if (retry < max_retry)
+                       hw_dbg(hw, "I2C byte read error - Retrying.\n");
+               else
+                       hw_dbg(hw, "I2C byte read error.\n");
+
+       } while (retry < max_retry);
+
+       return status;
+}
+
+/**
+ *  ixgbe_write_i2c_byte_generic - Writes 8 bit word over I2C
+ *  @hw: pointer to hardware structure
+ *  @byte_offset: byte offset to write
+ *  @data: value to write
+ *
+ *  Performs byte write operation to SFP module's EEPROM over I2C interface at
+ *  a specified device address.
+ **/
+s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
+                                 u8 dev_addr, u8 data)
+{
+       s32 status = 0;
+       u32 max_retry = 1;
+       u32 retry = 0;
+
+       do {
+               ixgbe_i2c_start(hw);
+
+               status = ixgbe_clock_out_i2c_byte(hw, dev_addr);
+               if (status != 0)
+                       goto fail;
+
+               status = ixgbe_get_i2c_ack(hw);
+               if (status != 0)
+                       goto fail;
+
+               status = ixgbe_clock_out_i2c_byte(hw, byte_offset);
+               if (status != 0)
+                       goto fail;
+
+               status = ixgbe_get_i2c_ack(hw);
+               if (status != 0)
+                       goto fail;
+
+               status = ixgbe_clock_out_i2c_byte(hw, data);
+               if (status != 0)
+                       goto fail;
+
+               status = ixgbe_get_i2c_ack(hw);
+               if (status != 0)
+                       goto fail;
+
+               ixgbe_i2c_stop(hw);
+               break;
+
+fail:
+               ixgbe_i2c_bus_clear(hw);
+               retry++;
+               if (retry < max_retry)
+                       hw_dbg(hw, "I2C byte write error - Retrying.\n");
+               else
+                       hw_dbg(hw, "I2C byte write error.\n");
+       } while (retry < max_retry);
+
+       return status;
+}
+
+/**
+ *  ixgbe_i2c_start - Sets I2C start condition
+ *  @hw: pointer to hardware structure
+ *
+ *  Sets I2C start condition (High -> Low on SDA while SCL is High)
+ **/
+static void ixgbe_i2c_start(struct ixgbe_hw *hw)
+{
+       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+
+       /* Start condition must begin with data and clock high */
+       ixgbe_set_i2c_data(hw, &i2cctl, 1);
+       ixgbe_raise_i2c_clk(hw, &i2cctl);
+
+       /* Setup time for start condition (4.7us) */
+       udelay(IXGBE_I2C_T_SU_STA);
+
+       ixgbe_set_i2c_data(hw, &i2cctl, 0);
+
+       /* Hold time for start condition (4us) */
+       udelay(IXGBE_I2C_T_HD_STA);
+
+       ixgbe_lower_i2c_clk(hw, &i2cctl);
+
+       /* Minimum low period of clock is 4.7 us */
+       udelay(IXGBE_I2C_T_LOW);
+
+}
+
+/**
+ *  ixgbe_i2c_stop - Sets I2C stop condition
+ *  @hw: pointer to hardware structure
+ *
+ *  Sets I2C stop condition (Low -> High on SDA while SCL is High)
+ **/
+static void ixgbe_i2c_stop(struct ixgbe_hw *hw)
+{
+       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+
+       /* Stop condition must begin with data low and clock high */
+       ixgbe_set_i2c_data(hw, &i2cctl, 0);
+       ixgbe_raise_i2c_clk(hw, &i2cctl);
+
+       /* Setup time for stop condition (4us) */
+       udelay(IXGBE_I2C_T_SU_STO);
+
+       ixgbe_set_i2c_data(hw, &i2cctl, 1);
+
+       /* bus free time between stop and start (4.7us)*/
+       udelay(IXGBE_I2C_T_BUF);
+}
+
+/**
+ *  ixgbe_clock_in_i2c_byte - Clocks in one byte via I2C
+ *  @hw: pointer to hardware structure
+ *  @data: data byte to clock in
+ *
+ *  Clocks in one byte data via I2C data/clock
+ **/
+static s32 ixgbe_clock_in_i2c_byte(struct ixgbe_hw *hw, u8 *data)
+{
+       s32 status = 0;
+       s32 i;
+       bool bit = 0;
+
+       for (i = 7; i >= 0; i--) {
+               status = ixgbe_clock_in_i2c_bit(hw, &bit);
+               *data |= bit << i;
+
+               if (status != 0)
+                       break;
+       }
+
+       return status;
+}
+
+/**
+ *  ixgbe_clock_out_i2c_byte - Clocks out one byte via I2C
+ *  @hw: pointer to hardware structure
+ *  @data: data byte clocked out
+ *
+ *  Clocks out one byte data via I2C data/clock
+ **/
+static s32 ixgbe_clock_out_i2c_byte(struct ixgbe_hw *hw, u8 data)
+{
+       s32 status = 0;
+       s32 i;
+       u32 i2cctl;
+       bool bit = 0;
+
+       for (i = 7; i >= 0; i--) {
+               bit = (data >> i) & 0x1;
+               status = ixgbe_clock_out_i2c_bit(hw, bit);
+
+               if (status != 0)
+                       break;
+       }
+
+       /* Release SDA line (set high) */
+       i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+       i2cctl |= IXGBE_I2C_DATA_OUT;
+       IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, i2cctl);
+
+       return status;
+}
+
+/**
+ *  ixgbe_get_i2c_ack - Polls for I2C ACK
+ *  @hw: pointer to hardware structure
+ *
+ *  Clocks in/out one bit via I2C data/clock
+ **/
+static s32 ixgbe_get_i2c_ack(struct ixgbe_hw *hw)
+{
+       s32 status;
+       u32 i = 0;
+       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+       u32 timeout = 10;
+       bool ack = 1;
+
+       status = ixgbe_raise_i2c_clk(hw, &i2cctl);
+
+       if (status != 0)
+               goto out;
+
+       /* Minimum high period of clock is 4us */
+       udelay(IXGBE_I2C_T_HIGH);
+
+       /* Poll for ACK.  Note that ACK in I2C spec is
+        * transition from 1 to 0 */
+       for (i = 0; i < timeout; i++) {
+               i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+               ack = ixgbe_get_i2c_data(&i2cctl);
+
+               udelay(1);
+               if (ack == 0)
+                       break;
+       }
+
+       if (ack == 1) {
+               hw_dbg(hw, "I2C ack was not received.\n");
+               status = IXGBE_ERR_I2C;
+       }
+
+       ixgbe_lower_i2c_clk(hw, &i2cctl);
+
+       /* Minimum low period of clock is 4.7 us */
+       udelay(IXGBE_I2C_T_LOW);
+
+out:
+       return status;
+}
+
+/**
+ *  ixgbe_clock_in_i2c_bit - Clocks in one bit via I2C data/clock
+ *  @hw: pointer to hardware structure
+ *  @data: read data value
+ *
+ *  Clocks in one bit via I2C data/clock
+ **/
+static s32 ixgbe_clock_in_i2c_bit(struct ixgbe_hw *hw, bool *data)
+{
+       s32 status;
+       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+
+       status = ixgbe_raise_i2c_clk(hw, &i2cctl);
+
+       /* Minimum high period of clock is 4us */
+       udelay(IXGBE_I2C_T_HIGH);
+
+       i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+       *data = ixgbe_get_i2c_data(&i2cctl);
+
+       ixgbe_lower_i2c_clk(hw, &i2cctl);
+
+       /* Minimum low period of clock is 4.7 us */
+       udelay(IXGBE_I2C_T_LOW);
+
+       return status;
+}
+
+/**
+ *  ixgbe_clock_out_i2c_bit - Clocks in/out one bit via I2C data/clock
+ *  @hw: pointer to hardware structure
+ *  @data: data value to write
+ *
+ *  Clocks out one bit via I2C data/clock
+ **/
+static s32 ixgbe_clock_out_i2c_bit(struct ixgbe_hw *hw, bool data)
+{
+       s32 status;
+       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+
+       status = ixgbe_set_i2c_data(hw, &i2cctl, data);
+       if (status == 0) {
+               status = ixgbe_raise_i2c_clk(hw, &i2cctl);
+
+               /* Minimum high period of clock is 4us */
+               udelay(IXGBE_I2C_T_HIGH);
+
+               ixgbe_lower_i2c_clk(hw, &i2cctl);
+
+               /* Minimum low period of clock is 4.7 us.
+                * This also takes care of the data hold time.
+                */
+               udelay(IXGBE_I2C_T_LOW);
+       } else {
+               status = IXGBE_ERR_I2C;
+               hw_dbg(hw, "I2C data was not set to %X\n", data);
+       }
+
+       return status;
+}
+/**
+ *  ixgbe_raise_i2c_clk - Raises the I2C SCL clock
+ *  @hw: pointer to hardware structure
+ *  @i2cctl: Current value of I2CCTL register
+ *
+ *  Raises the I2C clock line '0'->'1'
+ **/
+static s32 ixgbe_raise_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
+{
+       s32 status = 0;
+
+       *i2cctl |= IXGBE_I2C_CLK_OUT;
+
+       IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
+
+       /* SCL rise time (1000ns) */
+       udelay(IXGBE_I2C_T_RISE);
+
+       return status;
+}
+
+/**
+ *  ixgbe_lower_i2c_clk - Lowers the I2C SCL clock
+ *  @hw: pointer to hardware structure
+ *  @i2cctl: Current value of I2CCTL register
+ *
+ *  Lowers the I2C clock line '1'->'0'
+ **/
+static void ixgbe_lower_i2c_clk(struct ixgbe_hw *hw, u32 *i2cctl)
+{
+
+       *i2cctl &= ~IXGBE_I2C_CLK_OUT;
+
+       IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
+
+       /* SCL fall time (300ns) */
+       udelay(IXGBE_I2C_T_FALL);
+}
+
+/**
+ *  ixgbe_set_i2c_data - Sets the I2C data bit
+ *  @hw: pointer to hardware structure
+ *  @i2cctl: Current value of I2CCTL register
+ *  @data: I2C data value (0 or 1) to set
+ *
+ *  Sets the I2C data bit
+ **/
+static s32 ixgbe_set_i2c_data(struct ixgbe_hw *hw, u32 *i2cctl, bool data)
+{
+       s32 status = 0;
+
+       if (data)
+               *i2cctl |= IXGBE_I2C_DATA_OUT;
+       else
+               *i2cctl &= ~IXGBE_I2C_DATA_OUT;
+
+       IXGBE_WRITE_REG(hw, IXGBE_I2CCTL, *i2cctl);
+
+       /* Data rise/fall (1000ns/300ns) and set-up time (250ns) */
+       udelay(IXGBE_I2C_T_RISE + IXGBE_I2C_T_FALL + IXGBE_I2C_T_SU_DATA);
+
+       /* Verify data was set correctly */
+       *i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+       if (data != ixgbe_get_i2c_data(i2cctl)) {
+               status = IXGBE_ERR_I2C;
+               hw_dbg(hw, "Error - I2C data was not set to %X.\n", data);
+       }
+
+       return status;
+}
+
+/**
+ *  ixgbe_get_i2c_data - Reads the I2C SDA data bit
+ *  @hw: pointer to hardware structure
+ *  @i2cctl: Current value of I2CCTL register
+ *
+ *  Returns the I2C data bit value
+ **/
+static bool ixgbe_get_i2c_data(u32 *i2cctl)
+{
+       bool data;
+
+       if (*i2cctl & IXGBE_I2C_DATA_IN)
+               data = 1;
+       else
+               data = 0;
+
+       return data;
+}
+
+/**
+ *  ixgbe_i2c_bus_clear - Clears the I2C bus
+ *  @hw: pointer to hardware structure
+ *
+ *  Clears the I2C bus by sending nine clock pulses.
+ *  Used when data line is stuck low.
+ **/
+static void ixgbe_i2c_bus_clear(struct ixgbe_hw *hw)
+{
+       u32 i2cctl = IXGBE_READ_REG(hw, IXGBE_I2CCTL);
+       u32 i;
+
+       ixgbe_set_i2c_data(hw, &i2cctl, 1);
+
+       for (i = 0; i < 9; i++) {
+               ixgbe_raise_i2c_clk(hw, &i2cctl);
+
+               /* Min high period of clock is 4us */
+               udelay(IXGBE_I2C_T_HIGH);
+
+               ixgbe_lower_i2c_clk(hw, &i2cctl);
+
+               /* Min low period of clock is 4.7us*/
+               udelay(IXGBE_I2C_T_LOW);
+       }
+
+       /* Put the i2c bus back to default state */
+       ixgbe_i2c_stop(hw);
+}
+
 /**
  *  ixgbe_check_phy_link_tnx - Determine link and speed status
  *  @hw: pointer to hardware structure
index 539a3061eb29ac6a16553aedb41a4809cc1002b7..cc5f1b3287e18c4e8c28a058f2f1fe895e635f5f 100644 (file)
 #define IXGBE_I2C_EEPROM_STATUS_IN_PROGRESS  0x3
 
 /* Bit-shift macros */
-#define IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT    12
-#define IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT    8
-#define IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT    4
+#define IXGBE_SFF_VENDOR_OUI_BYTE0_SHIFT    24
+#define IXGBE_SFF_VENDOR_OUI_BYTE1_SHIFT    16
+#define IXGBE_SFF_VENDOR_OUI_BYTE2_SHIFT    8
 
 /* Vendor OUIs: format of OUI is 0x[byte0][byte1][byte2][00] */
 #define IXGBE_SFF_VENDOR_OUI_TYCO     0x00407600
 #define IXGBE_SFF_VENDOR_OUI_FTL      0x00906500
 #define IXGBE_SFF_VENDOR_OUI_AVAGO    0x00176A00
+#define IXGBE_SFF_VENDOR_OUI_INTEL    0x001B2100
 
 /* I2C SDA and SCL timing parameters for standard mode */
 #define IXGBE_I2C_T_HD_STA  4
@@ -101,5 +102,12 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw);
 s32 ixgbe_get_sfp_init_sequence_offsets(struct ixgbe_hw *hw,
                                         u16 *list_offset,
                                         u16 *data_offset);
-
+s32 ixgbe_read_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
+                                u8 dev_addr, u8 *data);
+s32 ixgbe_write_i2c_byte_generic(struct ixgbe_hw *hw, u8 byte_offset,
+                                 u8 dev_addr, u8 data);
+s32 ixgbe_read_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
+                                  u8 *eeprom_data);
+s32 ixgbe_write_i2c_eeprom_generic(struct ixgbe_hw *hw, u8 byte_offset,
+                                   u8 eeprom_data);
 #endif /* _IXGBE_PHY_H_ */
index 237c688f8b6e3196f2c202c96b297b3ecf0d93fc..95fc36cff261024e582d9a95e8986d6d494f1815 100644 (file)
@@ -45,6 +45,9 @@
 #define IXGBE_DEV_ID_82598_DA_DUAL_PORT  0x10F1
 #define IXGBE_DEV_ID_82598_SR_DUAL_PORT_EM      0x10E1
 #define IXGBE_DEV_ID_82598EB_XF_LR       0x10F4
+#define IXGBE_DEV_ID_82599               0x10D8
+#define IXGBE_DEV_ID_82599_KX4           0x10F7
+#define IXGBE_DEV_ID_82599_SFP           0x10FB
 
 /* General Registers */
 #define IXGBE_CTRL      0x00000
 #define IXGBE_CTRL_EXT  0x00018
 #define IXGBE_ESDP      0x00020
 #define IXGBE_EODSDP    0x00028
+#define IXGBE_I2CCTL    0x00028
 #define IXGBE_LEDCTL    0x00200
 #define IXGBE_FRTIMER   0x00048
 #define IXGBE_TCPTIMER  0x0004C
+#define IXGBE_CORESPARE 0x00600
+#define IXGBE_EXVET     0x05078
 
 /* NVM Registers */
 #define IXGBE_EEC       0x10010
 #define IXGBE_FLOP      0x1013C
 #define IXGBE_GRC       0x10200
 
+/* General Receive Control */
+#define IXGBE_GRC_MNG  0x00000001 /* Manageability Enable */
+#define IXGBE_GRC_APME 0x00000002 /* Advanced Power Management Enable */
+
+#define IXGBE_VPDDIAG0  0x10204
+#define IXGBE_VPDDIAG1  0x10208
+
+/* I2CCTL Bit Masks */
+#define IXGBE_I2C_CLK_IN    0x00000001
+#define IXGBE_I2C_CLK_OUT   0x00000002
+#define IXGBE_I2C_DATA_IN   0x00000004
+#define IXGBE_I2C_DATA_OUT  0x00000008
+
 /* Interrupt Registers */
 #define IXGBE_EICR      0x00800
 #define IXGBE_EICS      0x00808
 #define IXGBE_EIMC      0x00888
 #define IXGBE_EIAC      0x00810
 #define IXGBE_EIAM      0x00890
-#define IXGBE_EITR(_i)  (((_i) <= 23) ? (0x00820 + ((_i) * 4)) : (0x012300 + ((_i) * 4)))
+#define IXGBE_EICS_EX(_i)   (0x00A90 + (_i) * 4)
+#define IXGBE_EIMS_EX(_i)   (0x00AA0 + (_i) * 4)
+#define IXGBE_EIMC_EX(_i)   (0x00AB0 + (_i) * 4)
+#define IXGBE_EIAM_EX(_i)   (0x00AD0 + (_i) * 4)
+/*
+ * 82598 EITR is 16 bits but set the limits based on the max
+ * supported by all ixgbe hardware.  82599 EITR is only 12 bits,
+ * with the lower 3 always zero.
+ */
+#define IXGBE_MAX_INT_RATE 488281
+#define IXGBE_MIN_INT_RATE 956
+#define IXGBE_MAX_EITR     0x00000FF8
+#define IXGBE_MIN_EITR     8
+#define IXGBE_EITR(_i)  (((_i) <= 23) ? (0x00820 + ((_i) * 4)) : \
+                         (0x012300 + (((_i) - 24) * 4)))
+#define IXGBE_EITR_ITR_INT_MASK 0x00000FF8
+#define IXGBE_EITR_LLI_MOD      0x00008000
+#define IXGBE_EITR_CNT_WDIS     0x80000000
 #define IXGBE_IVAR(_i)  (0x00900 + ((_i) * 4)) /* 24 at 0x900-0x960 */
+#define IXGBE_IVAR_MISC 0x00A00 /* misc MSI-X interrupt causes */
+#define IXGBE_EITRSEL   0x00894
 #define IXGBE_MSIXT     0x00000 /* MSI-X Table. 0x0000 - 0x01C */
 #define IXGBE_MSIXPBA   0x02000 /* MSI-X Pending bit array */
 #define IXGBE_PBACL(_i) (((_i) == 0) ? (0x11068) : (0x110C0 + ((_i) * 4)))
 #define IXGBE_GPIE      0x00898
 
 /* Flow Control Registers */
+#define IXGBE_FCADBUL   0x03210
+#define IXGBE_FCADBUH   0x03214
+#define IXGBE_FCAMACL   0x04328
+#define IXGBE_FCAMACH   0x0432C
+#define IXGBE_FCRTH_82599(_i) (0x03260 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_FCRTL_82599(_i) (0x03220 + ((_i) * 4)) /* 8 of these (0-7) */
 #define IXGBE_PFCTOP    0x03008
 #define IXGBE_FCTTV(_i) (0x03200 + ((_i) * 4)) /* 4 of these (0-3) */
 #define IXGBE_FCRTL(_i) (0x03220 + ((_i) * 8)) /* 8 of these (0-7) */
 #define IXGBE_FCRTH(_i) (0x03260 + ((_i) * 8)) /* 8 of these (0-7) */
 #define IXGBE_FCRTV     0x032A0
+#define IXGBE_FCCFG     0x03D00
 #define IXGBE_TFCS      0x0CE00
 
 /* Receive DMA Registers */
-#define IXGBE_RDBAL(_i) (((_i) < 64) ? (0x01000 + ((_i) * 0x40)) : (0x0D000 + ((_i - 64) * 0x40)))
-#define IXGBE_RDBAH(_i) (((_i) < 64) ? (0x01004 + ((_i) * 0x40)) : (0x0D004 + ((_i - 64) * 0x40)))
-#define IXGBE_RDLEN(_i) (((_i) < 64) ? (0x01008 + ((_i) * 0x40)) : (0x0D008 + ((_i - 64) * 0x40)))
-#define IXGBE_RDH(_i)   (((_i) < 64) ? (0x01010 + ((_i) * 0x40)) : (0x0D010 + ((_i - 64) * 0x40)))
-#define IXGBE_RDT(_i)   (((_i) < 64) ? (0x01018 + ((_i) * 0x40)) : (0x0D018 + ((_i - 64) * 0x40)))
-#define IXGBE_RXDCTL(_i) (((_i) < 64) ? (0x01028 + ((_i) * 0x40)) : (0x0D028 + ((_i - 64) * 0x40)))
+#define IXGBE_RDBAL(_i) (((_i) < 64) ? (0x01000 + ((_i) * 0x40)) : \
+                         (0x0D000 + ((_i - 64) * 0x40)))
+#define IXGBE_RDBAH(_i) (((_i) < 64) ? (0x01004 + ((_i) * 0x40)) : \
+                         (0x0D004 + ((_i - 64) * 0x40)))
+#define IXGBE_RDLEN(_i) (((_i) < 64) ? (0x01008 + ((_i) * 0x40)) : \
+                         (0x0D008 + ((_i - 64) * 0x40)))
+#define IXGBE_RDH(_i)   (((_i) < 64) ? (0x01010 + ((_i) * 0x40)) : \
+                         (0x0D010 + ((_i - 64) * 0x40)))
+#define IXGBE_RDT(_i)   (((_i) < 64) ? (0x01018 + ((_i) * 0x40)) : \
+                         (0x0D018 + ((_i - 64) * 0x40)))
+#define IXGBE_RXDCTL(_i) (((_i) < 64) ? (0x01028 + ((_i) * 0x40)) : \
+                          (0x0D028 + ((_i - 64) * 0x40)))
+#define IXGBE_RDDCC      0x02F20
+#define IXGBE_RXMEMWRAP  0x03190
+#define IXGBE_STARCTRL   0x03024
 /*
  * Split and Replication Receive Control Registers
  * 00-15 : 0x02100 + n*4
 #define IXGBE_DRECCCTL_DISABLE 0
 /* Multicast Table Array - 128 entries */
 #define IXGBE_MTA(_i)   (0x05200 + ((_i) * 4))
-#define IXGBE_RAL(_i)   (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : (0x0A200 + ((_i) * 8)))
-#define IXGBE_RAH(_i)   (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : (0x0A204 + ((_i) * 8)))
+#define IXGBE_RAL(_i)   (((_i) <= 15) ? (0x05400 + ((_i) * 8)) : \
+                         (0x0A200 + ((_i) * 8)))
+#define IXGBE_RAH(_i)   (((_i) <= 15) ? (0x05404 + ((_i) * 8)) : \
+                         (0x0A204 + ((_i) * 8)))
+#define IXGBE_MPSAR_LO(_i) (0x0A600 + ((_i) * 8))
+#define IXGBE_MPSAR_HI(_i) (0x0A604 + ((_i) * 8))
 /* Packet split receive type */
-#define IXGBE_PSRTYPE(_i)    (((_i) <= 15) ? (0x05480 + ((_i) * 4)) : (0x0EA00 + ((_i) * 4)))
+#define IXGBE_PSRTYPE(_i)    (((_i) <= 15) ? (0x05480 + ((_i) * 4)) : \
+                              (0x0EA00 + ((_i) * 4)))
 /* array of 4096 1-bit vlan filters */
 #define IXGBE_VFTA(_i)  (0x0A000 + ((_i) * 4))
 /*array of 4096 4-bit vlan vmdq indices */
 #define IXGBE_VLNCTRL   0x05088
 #define IXGBE_MCSTCTRL  0x05090
 #define IXGBE_MRQC      0x05818
+#define IXGBE_SAQF(_i)  (0x0E000 + ((_i) * 4)) /* Source Address Queue Filter */
+#define IXGBE_DAQF(_i)  (0x0E200 + ((_i) * 4)) /* Dest. Address Queue Filter */
+#define IXGBE_SDPQF(_i) (0x0E400 + ((_i) * 4)) /* Src Dest. Addr Queue Filter */
+#define IXGBE_FTQF(_i)  (0x0E600 + ((_i) * 4)) /* Five Tuple Queue Filter */
+#define IXGBE_ETQF(_i)  (0x05128 + ((_i) * 4)) /* EType Queue Filter */
+#define IXGBE_ETQS(_i)  (0x0EC00 + ((_i) * 4)) /* EType Queue Select */
+#define IXGBE_SYNQF     0x0EC30 /* SYN Packet Queue Filter */
+#define IXGBE_RQTC      0x0EC70
+#define IXGBE_MTQC      0x08120
+#define IXGBE_VLVF(_i)  (0x0F100 + ((_i) * 4))  /* 64 of these (0-63) */
+#define IXGBE_VLVFB(_i) (0x0F200 + ((_i) * 4))  /* 128 of these (0-127) */
+#define IXGBE_VT_CTL    0x051B0
+#define IXGBE_VFRE(_i)  (0x051E0 + ((_i) * 4))
+#define IXGBE_VFTE(_i)  (0x08110 + ((_i) * 4))
+#define IXGBE_QDE       0x2F04
+#define IXGBE_VMOLR(_i) (0x0F000 + ((_i) * 4)) /* 64 total */
+#define IXGBE_UTA(_i)   (0x0F400 + ((_i) * 4))
+#define IXGBE_VMRCTL(_i)        (0x0F600 + ((_i) * 4))
+#define IXGBE_VMRVLAN(_i)       (0x0F610 + ((_i) * 4))
+#define IXGBE_VMRVM(_i)         (0x0F630 + ((_i) * 4))
+#define IXGBE_L34T_IMIR(_i)      (0x0E800 + ((_i) * 4)) /*128 of these (0-127)*/
+#define IXGBE_LLITHRESH 0x0EC90
 #define IXGBE_IMIR(_i)  (0x05A80 + ((_i) * 4))  /* 8 of these (0-7) */
 #define IXGBE_IMIREXT(_i)       (0x05AA0 + ((_i) * 4))  /* 8 of these (0-7) */
 #define IXGBE_IMIRVP    0x05AC0
 #define IXGBE_RETA(_i)  (0x05C00 + ((_i) * 4))  /* 32 of these (0-31) */
 #define IXGBE_RSSRK(_i) (0x05C80 + ((_i) * 4))  /* 10 of these (0-9) */
 
-
 /* Transmit DMA registers */
 #define IXGBE_TDBAL(_i) (0x06000 + ((_i) * 0x40)) /* 32 of these (0-31)*/
 #define IXGBE_TDBAH(_i) (0x06004 + ((_i) * 0x40))
 #define IXGBE_TDWBAH(_i) (0x0603C + ((_i) * 0x40))
 #define IXGBE_DTXCTL    0x07E00
 
+#define IXGBE_DMATXCTL  0x04A80
+#define IXGBE_DTXMXSZRQ     0x08100
+#define IXGBE_DTXTCPFLGL    0x04A88
+#define IXGBE_DTXTCPFLGH    0x04A8C
+#define IXGBE_LBDRPEN       0x0CA00
+#define IXGBE_TXPBTHRESH(_i) (0x04950 + ((_i) * 4)) /* 8 of these 0 - 7 */
+
+#define IXGBE_DMATXCTL_TE       0x1 /* Transmit Enable */
+#define IXGBE_DMATXCTL_NS       0x2 /* No Snoop LSO hdr buffer */
+#define IXGBE_DMATXCTL_GDV      0x8 /* Global Double VLAN */
+#define IXGBE_DMATXCTL_VT_SHIFT 16  /* VLAN EtherType */
 #define IXGBE_DCA_TXCTRL(_i)    (0x07200 + ((_i) * 4)) /* 16 of these (0-15) */
+/* Tx DCA Control register : 128 of these (0-127) */
+#define IXGBE_DCA_TXCTRL_82599(_i)  (0x0600C + ((_i) * 0x40))
 #define IXGBE_TIPG      0x0CB00
 #define IXGBE_TXPBSIZE(_i)      (0x0CC00 + ((_i) * 4)) /* 8 of these */
 #define IXGBE_MNGTXMAP  0x0CD10
 
 #define IXGBE_WUPL      0x05900
 #define IXGBE_WUPM      0x05A00 /* wake up pkt memory 0x5A00-0x5A7C */
-#define IXGBE_FHFT      0x09000 /* Flex host filter table 9000-93FC */
-
-/* Music registers */
+#define IXGBE_FHFT(_n)     (0x09000 + (_n * 0x100)) /* Flex host filter table */
+#define IXGBE_FHFT_EXT(_n) (0x09800 + (_n * 0x100)) /* Ext Flexible Host
+                                                     * Filter Table */
+
+#define IXGBE_FLEXIBLE_FILTER_COUNT_MAX         4
+#define IXGBE_EXT_FLEXIBLE_FILTER_COUNT_MAX     2
+
+/* Each Flexible Filter is at most 128 (0x80) bytes in length */
+#define IXGBE_FLEXIBLE_FILTER_SIZE_MAX  128
+#define IXGBE_FHFT_LENGTH_OFFSET        0xFC  /* Length byte in FHFT */
+#define IXGBE_FHFT_LENGTH_MASK          0x0FF /* Length in lower byte */
+
+/* Definitions for power management and wakeup registers */
+/* Wake Up Control */
+#define IXGBE_WUC_PME_EN     0x00000002 /* PME Enable */
+#define IXGBE_WUC_PME_STATUS 0x00000004 /* PME Status */
+#define IXGBE_WUC_ADVD3WUC   0x00000010 /* D3Cold wake up cap. enable*/
+
+/* Wake Up Filter Control */
+#define IXGBE_WUFC_LNKC 0x00000001 /* Link Status Change Wakeup Enable */
+#define IXGBE_WUFC_MAG  0x00000002 /* Magic Packet Wakeup Enable */
+#define IXGBE_WUFC_EX   0x00000004 /* Directed Exact Wakeup Enable */
+#define IXGBE_WUFC_MC   0x00000008 /* Directed Multicast Wakeup Enable */
+#define IXGBE_WUFC_BC   0x00000010 /* Broadcast Wakeup Enable */
+#define IXGBE_WUFC_ARP  0x00000020 /* ARP Request Packet Wakeup Enable */
+#define IXGBE_WUFC_IPV4 0x00000040 /* Directed IPv4 Packet Wakeup Enable */
+#define IXGBE_WUFC_IPV6 0x00000080 /* Directed IPv6 Packet Wakeup Enable */
+#define IXGBE_WUFC_MNG  0x00000100 /* Directed Mgmt Packet Wakeup Enable */
+
+#define IXGBE_WUFC_IGNORE_TCO   0x00008000 /* Ignore WakeOn TCO packets */
+#define IXGBE_WUFC_FLX0 0x00010000 /* Flexible Filter 0 Enable */
+#define IXGBE_WUFC_FLX1 0x00020000 /* Flexible Filter 1 Enable */
+#define IXGBE_WUFC_FLX2 0x00040000 /* Flexible Filter 2 Enable */
+#define IXGBE_WUFC_FLX3 0x00080000 /* Flexible Filter 3 Enable */
+#define IXGBE_WUFC_FLX4 0x00100000 /* Flexible Filter 4 Enable */
+#define IXGBE_WUFC_FLX5 0x00200000 /* Flexible Filter 5 Enable */
+#define IXGBE_WUFC_FLX_FILTERS     0x000F0000 /* Mask for 4 flex filters */
+#define IXGBE_WUFC_EXT_FLX_FILTERS 0x00300000 /* Mask for Ext. flex filters */
+#define IXGBE_WUFC_ALL_FILTERS     0x003F00FF /* Mask for all 6 wakeup filters*/
+#define IXGBE_WUFC_FLX_OFFSET      16 /* Offset to the Flexible Filters bits */
+
+/* Wake Up Status */
+#define IXGBE_WUS_LNKC  IXGBE_WUFC_LNKC
+#define IXGBE_WUS_MAG   IXGBE_WUFC_MAG
+#define IXGBE_WUS_EX    IXGBE_WUFC_EX
+#define IXGBE_WUS_MC    IXGBE_WUFC_MC
+#define IXGBE_WUS_BC    IXGBE_WUFC_BC
+#define IXGBE_WUS_ARP   IXGBE_WUFC_ARP
+#define IXGBE_WUS_IPV4  IXGBE_WUFC_IPV4
+#define IXGBE_WUS_IPV6  IXGBE_WUFC_IPV6
+#define IXGBE_WUS_MNG   IXGBE_WUFC_MNG
+#define IXGBE_WUS_FLX0  IXGBE_WUFC_FLX0
+#define IXGBE_WUS_FLX1  IXGBE_WUFC_FLX1
+#define IXGBE_WUS_FLX2  IXGBE_WUFC_FLX2
+#define IXGBE_WUS_FLX3  IXGBE_WUFC_FLX3
+#define IXGBE_WUS_FLX4  IXGBE_WUFC_FLX4
+#define IXGBE_WUS_FLX5  IXGBE_WUFC_FLX5
+#define IXGBE_WUS_FLX_FILTERS  IXGBE_WUFC_FLX_FILTERS
+
+/* Wake Up Packet Length */
+#define IXGBE_WUPL_LENGTH_MASK 0xFFFF
+
+/* DCB registers */
 #define IXGBE_RMCS      0x03D00
 #define IXGBE_DPMCS     0x07F40
 #define IXGBE_PDPMCS    0x0CD00
 #define IXGBE_TDPT2TCSR(_i)     (0x0CD40 + ((_i) * 4)) /* 8 of these (0-7) */
 
 
+/* Security Control Registers */
+#define IXGBE_SECTXCTRL         0x08800
+#define IXGBE_SECTXSTAT         0x08804
+#define IXGBE_SECTXBUFFAF       0x08808
+#define IXGBE_SECTXMINIFG       0x08810
+#define IXGBE_SECTXSTAT         0x08804
+#define IXGBE_SECRXCTRL         0x08D00
+#define IXGBE_SECRXSTAT         0x08D04
+
+/* Security Bit Fields and Masks */
+#define IXGBE_SECTXCTRL_SECTX_DIS       0x00000001
+#define IXGBE_SECTXCTRL_TX_DIS          0x00000002
+#define IXGBE_SECTXCTRL_STORE_FORWARD   0x00000004
+
+#define IXGBE_SECTXSTAT_SECTX_RDY       0x00000001
+#define IXGBE_SECTXSTAT_ECC_TXERR       0x00000002
+
+#define IXGBE_SECRXCTRL_SECRX_DIS       0x00000001
+#define IXGBE_SECRXCTRL_RX_DIS          0x00000002
+
+#define IXGBE_SECRXSTAT_SECRX_RDY       0x00000001
+#define IXGBE_SECRXSTAT_ECC_RXERR       0x00000002
+
+/* LinkSec (MacSec) Registers */
+#define IXGBE_LSECTXCAP         0x08A00
+#define IXGBE_LSECRXCAP         0x08F00
+#define IXGBE_LSECTXCTRL        0x08A04
+#define IXGBE_LSECTXSCL         0x08A08 /* SCI Low */
+#define IXGBE_LSECTXSCH         0x08A0C /* SCI High */
+#define IXGBE_LSECTXSA          0x08A10
+#define IXGBE_LSECTXPN0         0x08A14
+#define IXGBE_LSECTXPN1         0x08A18
+#define IXGBE_LSECTXKEY0(_n)    (0x08A1C + (4 * (_n))) /* 4 of these (0-3) */
+#define IXGBE_LSECTXKEY1(_n)    (0x08A2C + (4 * (_n))) /* 4 of these (0-3) */
+#define IXGBE_LSECRXCTRL        0x08F04
+#define IXGBE_LSECRXSCL         0x08F08
+#define IXGBE_LSECRXSCH         0x08F0C
+#define IXGBE_LSECRXSA(_i)      (0x08F10 + (4 * (_i))) /* 2 of these (0-1) */
+#define IXGBE_LSECRXPN(_i)      (0x08F18 + (4 * (_i))) /* 2 of these (0-1) */
+#define IXGBE_LSECRXKEY(_n, _m) (0x08F20 + ((0x10 * (_n)) + (4 * (_m))))
+#define IXGBE_LSECTXUT          0x08A3C /* OutPktsUntagged */
+#define IXGBE_LSECTXPKTE        0x08A40 /* OutPktsEncrypted */
+#define IXGBE_LSECTXPKTP        0x08A44 /* OutPktsProtected */
+#define IXGBE_LSECTXOCTE        0x08A48 /* OutOctetsEncrypted */
+#define IXGBE_LSECTXOCTP        0x08A4C /* OutOctetsProtected */
+#define IXGBE_LSECRXUT          0x08F40 /* InPktsUntagged/InPktsNoTag */
+#define IXGBE_LSECRXOCTD        0x08F44 /* InOctetsDecrypted */
+#define IXGBE_LSECRXOCTV        0x08F48 /* InOctetsValidated */
+#define IXGBE_LSECRXBAD         0x08F4C /* InPktsBadTag */
+#define IXGBE_LSECRXNOSCI       0x08F50 /* InPktsNoSci */
+#define IXGBE_LSECRXUNSCI       0x08F54 /* InPktsUnknownSci */
+#define IXGBE_LSECRXUNCH        0x08F58 /* InPktsUnchecked */
+#define IXGBE_LSECRXDELAY       0x08F5C /* InPktsDelayed */
+#define IXGBE_LSECRXLATE        0x08F60 /* InPktsLate */
+#define IXGBE_LSECRXOK(_n)      (0x08F64 + (0x04 * (_n))) /* InPktsOk */
+#define IXGBE_LSECRXINV(_n)     (0x08F6C + (0x04 * (_n))) /* InPktsInvalid */
+#define IXGBE_LSECRXNV(_n)      (0x08F74 + (0x04 * (_n))) /* InPktsNotValid */
+#define IXGBE_LSECRXUNSA        0x08F7C /* InPktsUnusedSa */
+#define IXGBE_LSECRXNUSA        0x08F80 /* InPktsNotUsingSa */
+
+/* LinkSec (MacSec) Bit Fields and Masks */
+#define IXGBE_LSECTXCAP_SUM_MASK        0x00FF0000
+#define IXGBE_LSECTXCAP_SUM_SHIFT       16
+#define IXGBE_LSECRXCAP_SUM_MASK        0x00FF0000
+#define IXGBE_LSECRXCAP_SUM_SHIFT       16
+
+#define IXGBE_LSECTXCTRL_EN_MASK        0x00000003
+#define IXGBE_LSECTXCTRL_DISABLE        0x0
+#define IXGBE_LSECTXCTRL_AUTH           0x1
+#define IXGBE_LSECTXCTRL_AUTH_ENCRYPT   0x2
+#define IXGBE_LSECTXCTRL_AISCI          0x00000020
+#define IXGBE_LSECTXCTRL_PNTHRSH_MASK   0xFFFFFF00
+#define IXGBE_LSECTXCTRL_RSV_MASK       0x000000D8
+
+#define IXGBE_LSECRXCTRL_EN_MASK        0x0000000C
+#define IXGBE_LSECRXCTRL_EN_SHIFT       2
+#define IXGBE_LSECRXCTRL_DISABLE        0x0
+#define IXGBE_LSECRXCTRL_CHECK          0x1
+#define IXGBE_LSECRXCTRL_STRICT         0x2
+#define IXGBE_LSECRXCTRL_DROP           0x3
+#define IXGBE_LSECRXCTRL_PLSH           0x00000040
+#define IXGBE_LSECRXCTRL_RP             0x00000080
+#define IXGBE_LSECRXCTRL_RSV_MASK       0xFFFFFF33
+
+/* IpSec Registers */
+#define IXGBE_IPSTXIDX          0x08900
+#define IXGBE_IPSTXSALT         0x08904
+#define IXGBE_IPSTXKEY(_i)      (0x08908 + (4 * (_i))) /* 4 of these (0-3) */
+#define IXGBE_IPSRXIDX          0x08E00
+#define IXGBE_IPSRXIPADDR(_i)   (0x08E04 + (4 * (_i))) /* 4 of these (0-3) */
+#define IXGBE_IPSRXSPI          0x08E14
+#define IXGBE_IPSRXIPIDX        0x08E18
+#define IXGBE_IPSRXKEY(_i)      (0x08E1C + (4 * (_i))) /* 4 of these (0-3) */
+#define IXGBE_IPSRXSALT         0x08E2C
+#define IXGBE_IPSRXMOD          0x08E30
+
+#define IXGBE_SECTXCTRL_STORE_FORWARD_ENABLE    0x4
+
+/* DCB registers */
+#define IXGBE_RTRPCS      0x02430
+#define IXGBE_RTTDCS      0x04900
+#define IXGBE_RTTPCS      0x0CD00
+#define IXGBE_RTRUP2TC    0x03020
+#define IXGBE_RTTUP2TC    0x0C800
+#define IXGBE_RTRPT4C(_i) (0x02140 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_RTRPT4S(_i) (0x02160 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_RTTDT2C(_i) (0x04910 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_RTTDT2S(_i) (0x04930 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_RTTPT2C(_i) (0x0CD20 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_RTTPT2S(_i) (0x0CD40 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_RTTDQSEL    0x04904
+#define IXGBE_RTTDT1C     0x04908
+#define IXGBE_RTTDT1S     0x0490C
+#define IXGBE_RTTDTECC    0x04990
+#define IXGBE_RTTDTECC_NO_BCN   0x00000100
+#define IXGBE_RTTBCNRC    0x04984
 
 /* Stats registers */
 #define IXGBE_CRCERRS   0x04000
 #define IXGBE_LXONRXC   0x0CF60
 #define IXGBE_LXOFFTXC  0x03F68
 #define IXGBE_LXOFFRXC  0x0CF68
+#define IXGBE_LXONRXCNT 0x041A4
+#define IXGBE_LXOFFRXCNT 0x041A8
+#define IXGBE_PXONRXCNT(_i)     (0x04140 + ((_i) * 4)) /* 8 of these */
+#define IXGBE_PXOFFRXCNT(_i)    (0x04160 + ((_i) * 4)) /* 8 of these */
+#define IXGBE_PXON2OFFCNT(_i)   (0x03240 + ((_i) * 4)) /* 8 of these */
 #define IXGBE_PXONTXC(_i)       (0x03F00 + ((_i) * 4)) /* 8 of these 3F00-3F1C*/
 #define IXGBE_PXONRXC(_i)       (0x0CF00 + ((_i) * 4)) /* 8 of these CF00-CF1C*/
 #define IXGBE_PXOFFTXC(_i)      (0x03F20 + ((_i) * 4)) /* 8 of these 3F20-3F3C*/
 #define IXGBE_MPTC      0x040F0
 #define IXGBE_BPTC      0x040F4
 #define IXGBE_XEC       0x04120
+#define IXGBE_SSVPC     0x08780
 
-#define IXGBE_RQSMR(_i) (0x02300 + ((_i) * 4)) /* 16 of these */
-#define IXGBE_TQSMR(_i) (((_i) <= 7) ? (0x07300 + ((_i) * 4)) : (0x08600 + ((_i) * 4)))
+#define IXGBE_RQSMR(_i) (0x02300 + ((_i) * 4))
+#define IXGBE_TQSMR(_i) (((_i) <= 7) ? (0x07300 + ((_i) * 4)) : \
+                         (0x08600 + ((_i) * 4)))
+#define IXGBE_TQSM(_i)  (0x08600 + ((_i) * 4))
 
 #define IXGBE_QPRC(_i) (0x01030 + ((_i) * 0x40)) /* 16 of these */
 #define IXGBE_QPTC(_i) (0x06030 + ((_i) * 0x40)) /* 16 of these */
 #define IXGBE_QBRC(_i) (0x01034 + ((_i) * 0x40)) /* 16 of these */
 #define IXGBE_QBTC(_i) (0x06034 + ((_i) * 0x40)) /* 16 of these */
+#define IXGBE_QPRDC(_i) (0x01430 + ((_i) * 0x40)) /* 16 of these */
+#define IXGBE_QBTC_L(_i) (0x08700 + ((_i) * 0x8)) /* 16 of these */
+#define IXGBE_QBTC_H(_i) (0x08704 + ((_i) * 0x8)) /* 16 of these */
 
 /* Management */
 #define IXGBE_MAVTV(_i) (0x05010 + ((_i) * 4)) /* 8 of these (0-7) */
 #define IXGBE_MMAL(_i)  (0x05910 + ((_i) * 8)) /* 4 of these (0-3) */
 #define IXGBE_MMAH(_i)  (0x05914 + ((_i) * 8)) /* 4 of these (0-3) */
 #define IXGBE_FTFT      0x09400 /* 0x9400-0x97FC */
+#define IXGBE_METF(_i)  (0x05190 + ((_i) * 4)) /* 4 of these (0-3) */
+#define IXGBE_MDEF_EXT(_i) (0x05160 + ((_i) * 4)) /* 8 of these (0-7) */
+#define IXGBE_LSWFW     0x15014
 
 /* ARC Subsystem registers */
 #define IXGBE_HICR      0x15F00
 #define IXGBE_DCA_ID    0x11070
 #define IXGBE_DCA_CTRL  0x11074
 
+/* PCIe registers 82599-specific */
+#define IXGBE_GCR_EXT           0x11050
+#define IXGBE_GSCL_5_82599      0x11030
+#define IXGBE_GSCL_6_82599      0x11034
+#define IXGBE_GSCL_7_82599      0x11038
+#define IXGBE_GSCL_8_82599      0x1103C
+#define IXGBE_PHYADR_82599      0x11040
+#define IXGBE_PHYDAT_82599      0x11044
+#define IXGBE_PHYCTL_82599      0x11048
+#define IXGBE_PBACLR_82599      0x11068
+#define IXGBE_CIAA_82599        0x11088
+#define IXGBE_CIAD_82599        0x1108C
+#define IXGBE_PCIE_DIAG_0_82599 0x11090
+#define IXGBE_PCIE_DIAG_1_82599 0x11094
+#define IXGBE_PCIE_DIAG_2_82599 0x11098
+#define IXGBE_PCIE_DIAG_3_82599 0x1109C
+#define IXGBE_PCIE_DIAG_4_82599 0x110A0
+#define IXGBE_PCIE_DIAG_5_82599 0x110A4
+#define IXGBE_PCIE_DIAG_6_82599 0x110A8
+#define IXGBE_PCIE_DIAG_7_82599 0x110C0
+#define IXGBE_INTRPT_CSR_82599  0x110B0
+#define IXGBE_INTRPT_MASK_82599 0x110B8
+#define IXGBE_CDQ_MBR_82599     0x110B4
+#define IXGBE_MISC_REG_82599    0x110F0
+#define IXGBE_ECC_CTRL_0_82599  0x11100
+#define IXGBE_ECC_CTRL_1_82599  0x11104
+#define IXGBE_ECC_STATUS_82599  0x110E0
+#define IXGBE_BAR_CTRL_82599    0x110F4
+
+/* Time Sync Registers */
+#define IXGBE_TSYNCRXCTL 0x05188 /* Rx Time Sync Control register - RW */
+#define IXGBE_TSYNCTXCTL 0x08C00 /* Tx Time Sync Control register - RW */
+#define IXGBE_RXSTMPL    0x051E8 /* Rx timestamp Low - RO */
+#define IXGBE_RXSTMPH    0x051A4 /* Rx timestamp High - RO */
+#define IXGBE_RXSATRL    0x051A0 /* Rx timestamp attribute low - RO */
+#define IXGBE_RXSATRH    0x051A8 /* Rx timestamp attribute high - RO */
+#define IXGBE_RXMTRL     0x05120 /* RX message type register low - RW */
+#define IXGBE_TXSTMPL    0x08C04 /* Tx timestamp value Low - RO */
+#define IXGBE_TXSTMPH    0x08C08 /* Tx timestamp value High - RO */
+#define IXGBE_SYSTIML    0x08C0C /* System time register Low - RO */
+#define IXGBE_SYSTIMH    0x08C10 /* System time register High - RO */
+#define IXGBE_TIMINCA    0x08C14 /* Increment attributes register - RW */
+#define IXGBE_RXUDP      0x08C1C /* Time Sync Rx UDP Port - RW */
+
 /* Diagnostic Registers */
 #define IXGBE_RDSTATCTL   0x02C20
 #define IXGBE_RDSTAT(_i)  (0x02C00 + ((_i) * 4)) /* 0x02C00-0x02C1C */
 #define IXGBE_RDHMPN      0x02F08
 #define IXGBE_RIC_DW(_i)  (0x02F10 + ((_i) * 4))
 #define IXGBE_RDPROBE     0x02F20
+#define IXGBE_RDMAM       0x02F30
+#define IXGBE_RDMAD       0x02F34
 #define IXGBE_TDSTATCTL   0x07C20
 #define IXGBE_TDSTAT(_i)  (0x07C00 + ((_i) * 4)) /* 0x07C00 - 0x07C1C */
 #define IXGBE_TDHMPN      0x07F08
+#define IXGBE_TDHMPN2     0x082FC
+#define IXGBE_TXDESCIC    0x082CC
 #define IXGBE_TIC_DW(_i)  (0x07F10 + ((_i) * 4))
+#define IXGBE_TIC_DW2(_i) (0x082B0 + ((_i) * 4))
 #define IXGBE_TDPROBE     0x07F20
 #define IXGBE_TXBUFCTRL   0x0C600
 #define IXGBE_TXBUFDATA0  0x0C610
 #define IXGBE_TXDATARDPTR(_i)   (0x0C720 + ((_i) * 4)) /* 8 of these C720-C72C*/
 #define IXGBE_TXDESCRDPTR(_i)   (0x0C730 + ((_i) * 4)) /* 8 of these C730-C73C*/
 #define IXGBE_PCIEECCCTL 0x1106C
+#define IXGBE_PCIEECCCTL0 0x11100
+#define IXGBE_PCIEECCCTL1 0x11104
 #define IXGBE_PBTXECC   0x0C300
 #define IXGBE_PBRXECC   0x03300
 #define IXGBE_GHECCR    0x110B0
 #define IXGBE_MSRWD     0x04260
 #define IXGBE_MLADD     0x04264
 #define IXGBE_MHADD     0x04268
+#define IXGBE_MAXFRS    0x04268
 #define IXGBE_TREG      0x0426C
 #define IXGBE_PCSS1     0x04288
 #define IXGBE_PCSS2     0x0428C
 #define IXGBE_XPCSS     0x04290
+#define IXGBE_MFLCN     0x04294
 #define IXGBE_SERDESC   0x04298
 #define IXGBE_MACS      0x0429C
 #define IXGBE_AUTOC     0x042A0
 #define IXGBE_LINKS     0x042A4
+#define IXGBE_LINKS2    0x04324
 #define IXGBE_AUTOC2    0x042A8
 #define IXGBE_AUTOC3    0x042AC
 #define IXGBE_ANLP1     0x042B0
 #define IXGBE_ANLP2     0x042B4
 #define IXGBE_ATLASCTL  0x04800
+#define IXGBE_MMNGC     0x042D0
+#define IXGBE_ANLPNP1   0x042D4
+#define IXGBE_ANLPNP2   0x042D8
+#define IXGBE_KRPCSFC   0x042E0
+#define IXGBE_KRPCSS    0x042E4
+#define IXGBE_FECS1     0x042E8
+#define IXGBE_FECS2     0x042EC
+#define IXGBE_SMADARCTL 0x14F10
+#define IXGBE_MPVC      0x04318
+#define IXGBE_SGMIIC    0x04314
+
+/* Omer CORECTL */
+#define IXGBE_CORECTL           0x014F00
+/* BARCTRL */
+#define IXGBE_BARCTRL           0x110F4
+#define IXGBE_BARCTRL_FLSIZE    0x0700
+#define IXGBE_BARCTRL_CSRSIZE   0x2000
 
 /* RDRXCTL Bit Masks */
 #define IXGBE_RDRXCTL_RDMTS_1_2     0x00000000 /* Rx Desc Min Threshold Size */
+#define IXGBE_RDRXCTL_CRCSTRIP      0x00000002 /* CRC Strip */
 #define IXGBE_RDRXCTL_MVMEN         0x00000020
 #define IXGBE_RDRXCTL_DMAIDONE      0x00000008 /* DMA init cycle done */
+#define IXGBE_RDRXCTL_AGGDIS        0x00010000 /* Aggregation disable */
+
+/* RQTC Bit Masks and Shifts */
+#define IXGBE_RQTC_SHIFT_TC(_i)     ((_i) * 4)
+#define IXGBE_RQTC_TC0_MASK         (0x7 << 0)
+#define IXGBE_RQTC_TC1_MASK         (0x7 << 4)
+#define IXGBE_RQTC_TC2_MASK         (0x7 << 8)
+#define IXGBE_RQTC_TC3_MASK         (0x7 << 12)
+#define IXGBE_RQTC_TC4_MASK         (0x7 << 16)
+#define IXGBE_RQTC_TC5_MASK         (0x7 << 20)
+#define IXGBE_RQTC_TC6_MASK         (0x7 << 24)
+#define IXGBE_RQTC_TC7_MASK         (0x7 << 28)
+
+/* PSRTYPE.RQPL Bit masks and shift */
+#define IXGBE_PSRTYPE_RQPL_MASK     0x7
+#define IXGBE_PSRTYPE_RQPL_SHIFT    29
 
 /* CTRL Bit Masks */
 #define IXGBE_CTRL_GIO_DIS      0x00000004 /* Global IO Master Disable bit */
 #define IXGBE_MHADD_MFS_SHIFT   16
 
 /* Extended Device Control */
+#define IXGBE_CTRL_EXT_PFRSTD   0x00004000 /* Physical Function Reset Done */
 #define IXGBE_CTRL_EXT_NS_DIS   0x00010000 /* No Snoop disable */
 #define IXGBE_CTRL_EXT_RO_DIS   0x00020000 /* Relaxed Ordering disable */
 #define IXGBE_CTRL_EXT_DRV_LOAD 0x10000000 /* Driver loaded bit for FW */
 #define IXGBE_DCA_CTRL_DCA_MODE_CB2 0x02 /* DCA Mode CB2 */
 
 #define IXGBE_DCA_RXCTRL_CPUID_MASK 0x0000001F /* Rx CPUID Mask */
+#define IXGBE_DCA_RXCTRL_CPUID_MASK_82599  0xFF000000 /* Rx CPUID Mask */
+#define IXGBE_DCA_RXCTRL_CPUID_SHIFT_82599 24 /* Rx CPUID Shift */
 #define IXGBE_DCA_RXCTRL_DESC_DCA_EN (1 << 5) /* DCA Rx Desc enable */
 #define IXGBE_DCA_RXCTRL_HEAD_DCA_EN (1 << 6) /* DCA Rx Desc header enable */
 #define IXGBE_DCA_RXCTRL_DATA_DCA_EN (1 << 7) /* DCA Rx Desc payload enable */
 #define IXGBE_DCA_RXCTRL_DESC_HSRO_EN (1 << 15) /* DCA Rx Split Header RO */
 
 #define IXGBE_DCA_TXCTRL_CPUID_MASK 0x0000001F /* Tx CPUID Mask */
+#define IXGBE_DCA_TXCTRL_CPUID_MASK_82599  0xFF000000 /* Tx CPUID Mask */
+#define IXGBE_DCA_TXCTRL_CPUID_SHIFT_82599 24 /* Tx CPUID Shift */
 #define IXGBE_DCA_TXCTRL_DESC_DCA_EN (1 << 5) /* DCA Tx Desc enable */
 #define IXGBE_DCA_TXCTRL_TX_WB_RO_EN (1 << 11) /* Tx Desc writeback RO bit */
 #define IXGBE_DCA_MAX_QUEUES_82598   16 /* DCA regs only on 16 queues */
 #define IXGBE_ATLAS_PDN_TX_1G_QL_ALL    0xF0
 #define IXGBE_ATLAS_PDN_TX_AN_QL_ALL    0xF0
 
+/* Omer bit masks */
+#define IXGBE_CORECTL_WRITE_CMD         0x00010000
 
 /* Device Type definitions for new protocol MDIO commands */
 #define IXGBE_MDIO_PMA_PMD_DEV_TYPE               0x1
 #define IXGBE_MDIO_PHY_SPEED_ABILITY   0x4 /* Speed Ability Reg */
 #define IXGBE_MDIO_PHY_SPEED_10G       0x0001 /* 10G capable */
 #define IXGBE_MDIO_PHY_SPEED_1G        0x0010 /* 1G capable */
+#define IXGBE_MDIO_PHY_EXT_ABILITY        0xB /* Ext Ability Reg */
+#define IXGBE_MDIO_PHY_10GBASET_ABILITY   0x0004 /* 10GBaseT capable */
+#define IXGBE_MDIO_PHY_1000BASET_ABILITY  0x0020 /* 1000BaseT capable */
 
-#define IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR     0xC30A /* PHY_XS SDA/SCL Address Reg */
+#define IXGBE_MDIO_PMA_PMD_SDA_SCL_ADDR     0xC30A /* PHY_XS SDA/SCL Addr Reg */
 #define IXGBE_MDIO_PMA_PMD_SDA_SCL_DATA     0xC30B /* PHY_XS SDA/SCL Data Reg */
 #define IXGBE_MDIO_PMA_PMD_SDA_SCL_STAT     0xC30C /* PHY_XS SDA/SCL Status Reg */
 
 #define IXGBE_PHY_REVISION_MASK        0xFFFFFFF0
 #define IXGBE_MAX_PHY_ADDR             32
 
-/* PHY IDs */
+/* PHY IDs*/
 #define TN1010_PHY_ID    0x00A19410
 #define TNX_FW_REV       0xB
 #define QT2022_PHY_ID    0x0043A400
 #define IXGBE_CONTROL_NL         0x000F
 #define IXGBE_CONTROL_EOL_NL     0x0FFF
 #define IXGBE_CONTROL_SOL_NL     0x0000
+#define IXGBE_PHY_ENFORCE_INTEL_SFP_OFFSET 0x002C
+#define IXGBE_PHY_ALLOW_ANY_SFP            0x1
 
 /* General purpose Interrupt Enable */
 #define IXGBE_SDP0_GPIEN         0x00000001 /* SDP0 */
 #define IXGBE_SDP1_GPIEN         0x00000002 /* SDP1 */
+#define IXGBE_SDP2_GPIEN         0x00000004 /* SDP2 */
 #define IXGBE_GPIE_MSIX_MODE     0x00000010 /* MSI-X mode */
 #define IXGBE_GPIE_OCD           0x00000020 /* Other Clear Disable */
 #define IXGBE_GPIE_EIMEN         0x00000040 /* Immediate Interrupt Enable */
 #define IXGBE_GPIE_EIAME         0x40000000
 #define IXGBE_GPIE_PBA_SUPPORT   0x80000000
+#define IXGBE_GPIE_VTMODE_MASK   0x0000C000 /* VT Mode Mask */
+#define IXGBE_GPIE_VTMODE_16     0x00004000 /* 16 VFs 8 queues per VF */
+#define IXGBE_GPIE_VTMODE_32     0x00008000 /* 32 VFs 4 queues per VF */
+#define IXGBE_GPIE_VTMODE_64     0x0000C000 /* 64 VFs 2 queues per VF */
 
 /* Transmit Flow Control status */
 #define IXGBE_TFCS_TXOFF         0x00000001
 #define IXGBE_VMD_CTL_VMDQ_EN     0x00000001
 #define IXGBE_VMD_CTL_VMDQ_FILTER 0x00000002
 
+/* VT_CTL bitmasks */
+#define IXGBE_VT_CTL_DIS_DEFPL  0x20000000 /* disable default pool */
+#define IXGBE_VT_CTL_REPLEN     0x40000000 /* replication enabled */
+#define IXGBE_VT_CTL_VT_ENABLE  0x00000001  /* Enable VT Mode */
+
+/* VMOLR bitmasks */
+#define IXGBE_VMOLR_AUPE        0x01000000 /* accept untagged packets */
+#define IXGBE_VMOLR_ROMPE       0x02000000 /* accept packets in MTA tbl */
+#define IXGBE_VMOLR_ROPE        0x04000000 /* accept packets in UC tbl */
+#define IXGBE_VMOLR_BAM         0x08000000 /* accept broadcast packets */
+#define IXGBE_VMOLR_MPE         0x10000000 /* multicast promiscuous */
+
+/* VFRE bitmask */
+#define IXGBE_VFRE_ENABLE_ALL   0xFFFFFFFF
+
 /* RDHMPN and TDHMPN bitmasks */
 #define IXGBE_RDHMPN_RDICADDR       0x007FF800
 #define IXGBE_RDHMPN_RDICRDREQ      0x00800000
 #define IXGBE_TDHMPN_TDICRDREQ      0x00800000
 #define IXGBE_TDHMPN_TDICADDR_SHIFT 11
 
+#define IXGBE_RDMAM_MEM_SEL_SHIFT   13
+#define IXGBE_RDMAM_DWORD_SHIFT     9
+#define IXGBE_RDMAM_DESC_COMP_FIFO  1
+#define IXGBE_RDMAM_DFC_CMD_FIFO    2
+#define IXGBE_RDMAM_TCN_STATUS_RAM  4
+#define IXGBE_RDMAM_WB_COLL_FIFO    5
+#define IXGBE_RDMAM_QSC_CNT_RAM     6
+#define IXGBE_RDMAM_QSC_QUEUE_CNT   8
+#define IXGBE_RDMAM_QSC_QUEUE_RAM   0xA
+#define IXGBE_RDMAM_DESC_COM_FIFO_RANGE     135
+#define IXGBE_RDMAM_DESC_COM_FIFO_COUNT     4
+#define IXGBE_RDMAM_DFC_CMD_FIFO_RANGE      48
+#define IXGBE_RDMAM_DFC_CMD_FIFO_COUNT      7
+#define IXGBE_RDMAM_TCN_STATUS_RAM_RANGE    256
+#define IXGBE_RDMAM_TCN_STATUS_RAM_COUNT    9
+#define IXGBE_RDMAM_WB_COLL_FIFO_RANGE      8
+#define IXGBE_RDMAM_WB_COLL_FIFO_COUNT      4
+#define IXGBE_RDMAM_QSC_CNT_RAM_RANGE       64
+#define IXGBE_RDMAM_QSC_CNT_RAM_COUNT       4
+#define IXGBE_RDMAM_QSC_QUEUE_CNT_RANGE     32
+#define IXGBE_RDMAM_QSC_QUEUE_CNT_COUNT     4
+#define IXGBE_RDMAM_QSC_QUEUE_RAM_RANGE     128
+#define IXGBE_RDMAM_QSC_QUEUE_RAM_COUNT     8
+
+#define IXGBE_TXDESCIC_READY        0x80000000
+
 /* Receive Checksum Control */
 #define IXGBE_RXCSUM_IPPCSE     0x00001000   /* IP payload checksum enable */
 #define IXGBE_RXCSUM_PCSD       0x00002000   /* packet checksum disabled */
 
 /* FCRTL Bit Masks */
-#define IXGBE_FCRTL_XONE        0x80000000  /* bit 31, XON enable */
-#define IXGBE_FCRTH_FCEN        0x80000000  /* Rx Flow control enable */
+#define IXGBE_FCRTL_XONE        0x80000000  /* XON enable */
+#define IXGBE_FCRTH_FCEN        0x80000000  /* Packet buffer fc enable */
 
 /* PAP bit masks*/
 #define IXGBE_PAP_TXPAUSECNT_MASK   0x0000FFFF /* Pause counter mask */
 /* Receive Arbitration Control: 0 Round Robin, 1 DFP */
 #define IXGBE_RMCS_RAC          0x00000004
 #define IXGBE_RMCS_DFP          IXGBE_RMCS_RAC /* Deficit Fixed Priority ena */
-#define IXGBE_RMCS_TFCE_802_3X  0x00000008 /* Tx Priority flow control ena */
-#define IXGBE_RMCS_TFCE_PRIORITY 0x00000010 /* Tx Priority flow control ena */
+#define IXGBE_RMCS_TFCE_802_3X         0x00000008 /* Tx Priority FC ena */
+#define IXGBE_RMCS_TFCE_PRIORITY       0x00000010 /* Tx Priority FC ena */
 #define IXGBE_RMCS_ARBDIS       0x00000040 /* Arbitration disable bit */
 
+/* FCCFG Bit Masks */
+#define IXGBE_FCCFG_TFCE_802_3X         0x00000008 /* Tx link FC enable */
+#define IXGBE_FCCFG_TFCE_PRIORITY       0x00000010 /* Tx priority FC enable */
 
 /* Interrupt register bitmasks */
 
 /* Extended Interrupt Cause Read */
 #define IXGBE_EICR_RTX_QUEUE    0x0000FFFF /* RTx Queue Interrupt */
+#define IXGBE_EICR_FLOW_DIR     0x00010000 /* FDir Exception */
+#define IXGBE_EICR_RX_MISS      0x00020000 /* Packet Buffer Overrun */
+#define IXGBE_EICR_PCI          0x00040000 /* PCI Exception */
+#define IXGBE_EICR_MAILBOX      0x00080000 /* VF to PF Mailbox Interrupt */
 #define IXGBE_EICR_LSC          0x00100000 /* Link Status Change */
+#define IXGBE_EICR_LINKSEC      0x00200000 /* PN Threshold */
 #define IXGBE_EICR_MNG          0x00400000 /* Manageability Event Interrupt */
 #define IXGBE_EICR_GPI_SDP0     0x01000000 /* Gen Purpose Interrupt on SDP0 */
 #define IXGBE_EICR_GPI_SDP1     0x02000000 /* Gen Purpose Interrupt on SDP1 */
+#define IXGBE_EICR_GPI_SDP2     0x04000000 /* Gen Purpose Interrupt on SDP2 */
+#define IXGBE_EICR_ECC          0x10000000 /* ECC Error */
 #define IXGBE_EICR_PBUR         0x10000000 /* Packet Buffer Handler Error */
 #define IXGBE_EICR_DHER         0x20000000 /* Descriptor Handler Error */
 #define IXGBE_EICR_TCP_TIMER    0x40000000 /* TCP Timer */
 
 /* Extended Interrupt Cause Set */
 #define IXGBE_EICS_RTX_QUEUE    IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EICS_FLOW_DIR     IXGBE_EICR_FLOW_DIR  /* FDir Exception */
+#define IXGBE_EICS_RX_MISS      IXGBE_EICR_RX_MISS   /* Pkt Buffer Overrun */
+#define IXGBE_EICS_PCI          IXGBE_EICR_PCI       /* PCI Exception */
+#define IXGBE_EICS_MAILBOX      IXGBE_EICR_MAILBOX   /* VF to PF Mailbox Int */
 #define IXGBE_EICS_LSC          IXGBE_EICR_LSC       /* Link Status Change */
 #define IXGBE_EICS_MNG          IXGBE_EICR_MNG       /* MNG Event Interrupt */
 #define IXGBE_EICS_GPI_SDP0     IXGBE_EICR_GPI_SDP0  /* SDP0 Gen Purpose Int */
 #define IXGBE_EICS_GPI_SDP1     IXGBE_EICR_GPI_SDP1  /* SDP1 Gen Purpose Int */
+#define IXGBE_EICS_GPI_SDP2     IXGBE_EICR_GPI_SDP2  /* SDP2 Gen Purpose Int */
+#define IXGBE_EICS_ECC          IXGBE_EICR_ECC       /* ECC Error */
 #define IXGBE_EICS_PBUR         IXGBE_EICR_PBUR      /* Pkt Buf Handler Err */
 #define IXGBE_EICS_DHER         IXGBE_EICR_DHER      /* Desc Handler Error */
 #define IXGBE_EICS_TCP_TIMER    IXGBE_EICR_TCP_TIMER /* TCP Timer */
 
 /* Extended Interrupt Mask Set */
 #define IXGBE_EIMS_RTX_QUEUE    IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EIMS_FLOW_DIR     IXGBE_EICR_FLOW_DIR  /* FDir Exception */
+#define IXGBE_EIMS_RX_MISS      IXGBE_EICR_RX_MISS   /* Packet Buffer Overrun */
+#define IXGBE_EIMS_PCI          IXGBE_EICR_PCI       /* PCI Exception */
+#define IXGBE_EIMS_MAILBOX      IXGBE_EICR_MAILBOX   /* VF to PF Mailbox Int */
 #define IXGBE_EIMS_LSC          IXGBE_EICR_LSC       /* Link Status Change */
 #define IXGBE_EIMS_MNG          IXGBE_EICR_MNG       /* MNG Event Interrupt */
 #define IXGBE_EIMS_GPI_SDP0     IXGBE_EICR_GPI_SDP0  /* SDP0 Gen Purpose Int */
 #define IXGBE_EIMS_GPI_SDP1     IXGBE_EICR_GPI_SDP1  /* SDP1 Gen Purpose Int */
+#define IXGBE_EIMS_GPI_SDP2     IXGBE_EICR_GPI_SDP2  /* SDP2 Gen Purpose Int */
+#define IXGBE_EIMS_ECC          IXGBE_EICR_ECC       /* ECC Error */
 #define IXGBE_EIMS_PBUR         IXGBE_EICR_PBUR      /* Pkt Buf Handler Err */
 #define IXGBE_EIMS_DHER         IXGBE_EICR_DHER      /* Descr Handler Error */
 #define IXGBE_EIMS_TCP_TIMER    IXGBE_EICR_TCP_TIMER /* TCP Timer */
 
 /* Extended Interrupt Mask Clear */
 #define IXGBE_EIMC_RTX_QUEUE    IXGBE_EICR_RTX_QUEUE /* RTx Queue Interrupt */
+#define IXGBE_EIMC_FLOW_DIR     IXGBE_EICR_FLOW_DIR  /* FDir Exception */
+#define IXGBE_EIMC_RX_MISS      IXGBE_EICR_RX_MISS   /* Packet Buffer Overrun */
+#define IXGBE_EIMC_PCI          IXGBE_EICR_PCI       /* PCI Exception */
+#define IXGBE_EIMC_MAILBOX      IXGBE_EICR_MAILBOX   /* VF to PF Mailbox Int */
 #define IXGBE_EIMC_LSC          IXGBE_EICR_LSC       /* Link Status Change */
 #define IXGBE_EIMC_MNG          IXGBE_EICR_MNG       /* MNG Event Interrupt */
 #define IXGBE_EIMC_GPI_SDP0     IXGBE_EICR_GPI_SDP0  /* SDP0 Gen Purpose Int */
 #define IXGBE_EIMC_GPI_SDP1     IXGBE_EICR_GPI_SDP1  /* SDP1 Gen Purpose Int */
+#define IXGBE_EIMC_GPI_SDP2     IXGBE_EICR_GPI_SDP2  /* SDP2 Gen Purpose Int */
+#define IXGBE_EIMC_ECC          IXGBE_EICR_ECC       /* ECC Error */
 #define IXGBE_EIMC_PBUR         IXGBE_EICR_PBUR      /* Pkt Buf Handler Err */
 #define IXGBE_EIMC_DHER         IXGBE_EICR_DHER      /* Desc Handler Err */
 #define IXGBE_EIMC_TCP_TIMER    IXGBE_EICR_TCP_TIMER /* TCP Timer */
 #define IXGBE_IMIREXT_CTRL_SYN    0x00020000  /* Check SYN bit in header */
 #define IXGBE_IMIREXT_CTRL_FIN    0x00040000  /* Check FIN bit in header */
 #define IXGBE_IMIREXT_CTRL_BP     0x00080000  /* Bypass check of control bits */
+#define IXGBE_IMIR_SIZE_BP_82599  0x00001000 /* Packet size bypass */
+#define IXGBE_IMIR_CTRL_URG_82599 0x00002000 /* Check URG bit in header */
+#define IXGBE_IMIR_CTRL_ACK_82599 0x00004000 /* Check ACK bit in header */
+#define IXGBE_IMIR_CTRL_PSH_82599 0x00008000 /* Check PSH bit in header */
+#define IXGBE_IMIR_CTRL_RST_82599 0x00010000 /* Check RST bit in header */
+#define IXGBE_IMIR_CTRL_SYN_82599 0x00020000 /* Check SYN bit in header */
+#define IXGBE_IMIR_CTRL_FIN_82599 0x00040000 /* Check FIN bit in header */
+#define IXGBE_IMIR_CTRL_BP_82599  0x00080000 /* Bypass check of control bits */
+#define IXGBE_IMIR_LLI_EN_82599   0x00100000 /* Enables low latency Int */
+#define IXGBE_IMIR_RX_QUEUE_MASK_82599  0x0000007F /* Rx Queue Mask */
+#define IXGBE_IMIR_RX_QUEUE_SHIFT_82599 21 /* Rx Queue Shift */
+#define IXGBE_IMIRVP_PRIORITY_MASK      0x00000007 /* VLAN priority mask */
+#define IXGBE_IMIRVP_PRIORITY_EN        0x00000008 /* VLAN priority enable */
+
+#define IXGBE_MAX_FTQF_FILTERS          128
+#define IXGBE_FTQF_PROTOCOL_MASK        0x00000003
+#define IXGBE_FTQF_PROTOCOL_TCP         0x00000000
+#define IXGBE_FTQF_PROTOCOL_UDP         0x00000001
+#define IXGBE_FTQF_PROTOCOL_SCTP        2
+#define IXGBE_FTQF_PRIORITY_MASK        0x00000007
+#define IXGBE_FTQF_PRIORITY_SHIFT       2
+#define IXGBE_FTQF_POOL_MASK            0x0000003F
+#define IXGBE_FTQF_POOL_SHIFT           8
+#define IXGBE_FTQF_5TUPLE_MASK_MASK     0x0000001F
+#define IXGBE_FTQF_5TUPLE_MASK_SHIFT    25
+#define IXGBE_FTQF_POOL_MASK_EN         0x40000000
+#define IXGBE_FTQF_QUEUE_ENABLE         0x80000000
 
 /* Interrupt clear mask */
 #define IXGBE_IRQ_CLEAR_MASK    0xFFFFFFFF
 
 #define IXGBE_IVAR_ALLOC_VAL    0x80 /* Interrupt Allocation valid */
 
+/* ETYPE Queue Filter/Select Bit Masks */
+#define IXGBE_MAX_ETQF_FILTERS  8
+#define IXGBE_ETQF_BCN          0x10000000 /* bit 28 */
+#define IXGBE_ETQF_1588         0x40000000 /* bit 30 */
+#define IXGBE_ETQF_FILTER_EN    0x80000000 /* bit 31 */
+#define IXGBE_ETQF_POOL_ENABLE   (1 << 26) /* bit 26 */
+
+#define IXGBE_ETQS_RX_QUEUE     0x007F0000 /* bits 22:16 */
+#define IXGBE_ETQS_RX_QUEUE_SHIFT       16
+#define IXGBE_ETQS_LLI          0x20000000 /* bit 29 */
+#define IXGBE_ETQS_QUEUE_EN     0x80000000 /* bit 31 */
+
+/*
+ * ETQF filter list: one static filter per filter consumer. This is
+ *                   to avoid filter collisions later. Add new filters
+ *                   here!!
+ *
+ * Current filters:
+ *    EAPOL 802.1x (0x888e): Filter 0
+ *    BCN (0x8904):          Filter 1
+ *    1588 (0x88f7):         Filter 3
+ */
+#define IXGBE_ETQF_FILTER_EAPOL          0
+#define IXGBE_ETQF_FILTER_BCN            1
+#define IXGBE_ETQF_FILTER_1588           3
 /* VLAN Control Bit Masks */
 #define IXGBE_VLNCTRL_VET       0x0000FFFF  /* bits 0-15 */
 #define IXGBE_VLNCTRL_CFI       0x10000000  /* bit 28 */
 #define IXGBE_VLNCTRL_VFE       0x40000000  /* bit 30 */
 #define IXGBE_VLNCTRL_VME       0x80000000  /* bit 31 */
 
+/* VLAN pool filtering masks */
+#define IXGBE_VLVF_VIEN         0x80000000  /* filter is valid */
+#define IXGBE_VLVF_ENTRIES      64
 
 #define IXGBE_ETHERNET_IEEE_VLAN_TYPE 0x8100  /* 802.1q protocol */
 
 /* STATUS Bit Masks */
-#define IXGBE_STATUS_LAN_ID     0x0000000C /* LAN ID */
-#define IXGBE_STATUS_GIO        0x00080000 /* GIO Master Enable Status */
+#define IXGBE_STATUS_LAN_ID         0x0000000C /* LAN ID */
+#define IXGBE_STATUS_LAN_ID_SHIFT   2          /* LAN ID Shift*/
+#define IXGBE_STATUS_GIO            0x00080000 /* GIO Master Enable Status */
 
 #define IXGBE_STATUS_LAN_ID_0   0x00000000 /* LAN ID 0 */
 #define IXGBE_STATUS_LAN_ID_1   0x00000004 /* LAN ID 1 */
 
 /* ESDP Bit Masks */
-#define IXGBE_ESDP_SDP4 0x00000001 /* SDP4 Data Value */
-#define IXGBE_ESDP_SDP5 0x00000002 /* SDP5 Data Value */
+#define IXGBE_ESDP_SDP0 0x00000001
+#define IXGBE_ESDP_SDP1 0x00000002
+#define IXGBE_ESDP_SDP4 0x00000010 /* SDP4 Data Value */
+#define IXGBE_ESDP_SDP5 0x00000020 /* SDP5 Data Value */
+#define IXGBE_ESDP_SDP6 0x00000040 /* SDP6 Data Value */
 #define IXGBE_ESDP_SDP4_DIR     0x00000004 /* SDP4 IO direction */
-#define IXGBE_ESDP_SDP5_DIR     0x00000008 /* SDP5 IO direction */
+#define IXGBE_ESDP_SDP5_DIR     0x00002000 /* SDP5 IO direction */
 
 /* LEDCTL Bit Masks */
 #define IXGBE_LED_IVRT_BASE      0x00000040
 #define IXGBE_AUTOC_AN_RX_LOOSE 0x01000000
 #define IXGBE_AUTOC_AN_RX_DRIFT 0x00800000
 #define IXGBE_AUTOC_AN_RX_ALIGN 0x007C0000
+#define IXGBE_AUTOC_FECA        0x00040000
+#define IXGBE_AUTOC_FECR        0x00020000
+#define IXGBE_AUTOC_KR_SUPP     0x00010000
 #define IXGBE_AUTOC_AN_RESTART  0x00001000
 #define IXGBE_AUTOC_FLU         0x00000001
 #define IXGBE_AUTOC_LMS_SHIFT   13
+#define IXGBE_AUTOC_LMS_10G_SERIAL      (0x3 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_KX4_KX_KR       (0x4 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_SGMII_1G_100M   (0x5 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_KX4_KX_KR_1G_AN (0x6 << IXGBE_AUTOC_LMS_SHIFT)
+#define IXGBE_AUTOC_LMS_KX4_KX_KR_SGMII (0x7 << IXGBE_AUTOC_LMS_SHIFT)
 #define IXGBE_AUTOC_LMS_MASK            (0x7 << IXGBE_AUTOC_LMS_SHIFT)
 #define IXGBE_AUTOC_LMS_1G_LINK_NO_AN   (0x0 << IXGBE_AUTOC_LMS_SHIFT)
 #define IXGBE_AUTOC_LMS_10G_LINK_NO_AN  (0x1 << IXGBE_AUTOC_LMS_SHIFT)
 #define IXGBE_AUTOC_LMS_KX4_AN_1G_AN    (0x6 << IXGBE_AUTOC_LMS_SHIFT)
 #define IXGBE_AUTOC_LMS_ATTACH_TYPE     (0x7 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
 
-#define IXGBE_AUTOC_1G_PMA_PMD         0x00000200
-#define IXGBE_AUTOC_10G_PMA_PMD        0x00000180
-#define IXGBE_AUTOC_10G_PMA_PMD_SHIFT 7
-#define IXGBE_AUTOC_1G_PMA_PMD_SHIFT 9
+#define IXGBE_AUTOC_1G_PMA_PMD_MASK    0x00000200
+#define IXGBE_AUTOC_1G_PMA_PMD_SHIFT   9
+#define IXGBE_AUTOC_10G_PMA_PMD_MASK   0x00000180
+#define IXGBE_AUTOC_10G_PMA_PMD_SHIFT  7
 #define IXGBE_AUTOC_10G_XAUI   (0x0 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
 #define IXGBE_AUTOC_10G_KX4    (0x1 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
 #define IXGBE_AUTOC_10G_CX4    (0x2 << IXGBE_AUTOC_10G_PMA_PMD_SHIFT)
 #define IXGBE_AUTOC_1G_BX      (0x0 << IXGBE_AUTOC_1G_PMA_PMD_SHIFT)
 #define IXGBE_AUTOC_1G_KX      (0x1 << IXGBE_AUTOC_1G_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC_1G_SFI     (0x0 << IXGBE_AUTOC_1G_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC_1G_KX_BX   (0x1 << IXGBE_AUTOC_1G_PMA_PMD_SHIFT)
+
+#define IXGBE_AUTOC2_UPPER_MASK  0xFFFF0000
+#define IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_MASK  0x00030000
+#define IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_SHIFT 16
+#define IXGBE_AUTOC2_10G_KR  (0x0 << IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC2_10G_XFI (0x1 << IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_SHIFT)
+#define IXGBE_AUTOC2_10G_SFI (0x2 << IXGBE_AUTOC2_10G_SERIAL_PMA_PMD_SHIFT)
 
 /* LINKS Bit Masks */
 #define IXGBE_LINKS_KX_AN_COMP  0x80000000
 #define IXGBE_LINKS_RX_MODE     0x06000000
 #define IXGBE_LINKS_TX_MODE     0x01800000
 #define IXGBE_LINKS_XGXS_EN     0x00400000
+#define IXGBE_LINKS_SGMII_EN    0x02000000
 #define IXGBE_LINKS_PCS_1G_EN   0x00200000
 #define IXGBE_LINKS_1G_AN_EN    0x00100000
 #define IXGBE_LINKS_KX_AN_IDLE  0x00080000
 #define IXGBE_LINKS_TL_FAULT    0x00001000
 #define IXGBE_LINKS_SIGNAL      0x00000F00
 
+#define IXGBE_LINKS_SPEED_82599     0x30000000
+#define IXGBE_LINKS_SPEED_10G_82599 0x30000000
+#define IXGBE_LINKS_SPEED_1G_82599  0x20000000
+#define IXGBE_LINKS_SPEED_100_82599 0x10000000
 #define IXGBE_LINK_UP_TIME      90 /* 9.0 Seconds */
 #define IXGBE_AUTO_NEG_TIME     45 /* 4.5 Seconds */
 
 #define IXGBE_FW_PTR            0x0F
 #define IXGBE_PBANUM0_PTR       0x15
 #define IXGBE_PBANUM1_PTR       0x16
+#define IXGBE_PCIE_MSIX_82599_CAPS  0x72
 #define IXGBE_PCIE_MSIX_82598_CAPS  0x62
 
 /* MSI-X capability fields masks */
 #define IXGBE_PCI_LINK_SPEED      0xF
 #define IXGBE_PCI_LINK_SPEED_2500 0x1
 #define IXGBE_PCI_LINK_SPEED_5000 0x2
+#define IXGBE_PCI_HEADER_TYPE_REGISTER  0x0E
+#define IXGBE_PCI_HEADER_TYPE_MULTIFUNC 0x80
 
 /* Number of 100 microseconds we wait for PCI Express master disable */
 #define IXGBE_PCI_MASTER_DISABLE_TIMEOUT 800
 #define IXGBE_RXCTRL_RXEN       0x00000001  /* Enable Receiver */
 #define IXGBE_RXCTRL_DMBYPS     0x00000002  /* Descriptor Monitor Bypass */
 #define IXGBE_RXDCTL_ENABLE     0x02000000  /* Enable specific Rx Queue */
+#define IXGBE_RXDCTL_VME        0x40000000  /* VLAN mode enable */
 
 #define IXGBE_FCTRL_SBP 0x00000002 /* Store Bad Packet */
 #define IXGBE_FCTRL_MPE 0x00000100 /* Multicast Promiscuous Ena*/
 /* Receive Priority Flow Control Enable */
 #define IXGBE_FCTRL_RPFCE 0x00004000
 #define IXGBE_FCTRL_RFCE 0x00008000 /* Receive Flow Control Ena */
+#define IXGBE_MFLCN_PMCF        0x00000001 /* Pass MAC Control Frames */
+#define IXGBE_MFLCN_DPF         0x00000002 /* Discard Pause Frame */
+#define IXGBE_MFLCN_RPFCE       0x00000004 /* Receive Priority FC Enable */
+#define IXGBE_MFLCN_RFCE        0x00000008 /* Receive FC Enable */
 
 /* Multiple Receive Queue Control */
 #define IXGBE_MRQC_RSSEN                 0x00000001  /* RSS Enable */
+#define IXGBE_MRQC_MRQE_MASK                    0xF /* Bits 3:0 */
+#define IXGBE_MRQC_RT8TCEN               0x00000002 /* 8 TC no RSS */
+#define IXGBE_MRQC_RT4TCEN               0x00000003 /* 4 TC no RSS */
+#define IXGBE_MRQC_RTRSS8TCEN            0x00000004 /* 8 TC w/ RSS */
+#define IXGBE_MRQC_RTRSS4TCEN            0x00000005 /* 4 TC w/ RSS */
+#define IXGBE_MRQC_VMDQEN                0x00000008 /* VMDq2 64 pools no RSS */
+#define IXGBE_MRQC_VMDQRSS32EN           0x0000000A /* VMDq2 32 pools w/ RSS */
+#define IXGBE_MRQC_VMDQRSS64EN           0x0000000B /* VMDq2 64 pools w/ RSS */
+#define IXGBE_MRQC_VMDQRT8TCEN           0x0000000C /* VMDq2/RT 16 pool 8 TC */
+#define IXGBE_MRQC_VMDQRT4TCEN           0x0000000D /* VMDq2/RT 32 pool 4 TC */
 #define IXGBE_MRQC_RSS_FIELD_MASK        0xFFFF0000
 #define IXGBE_MRQC_RSS_FIELD_IPV4_TCP    0x00010000
 #define IXGBE_MRQC_RSS_FIELD_IPV4        0x00020000
 #define IXGBE_MRQC_RSS_FIELD_IPV4_UDP    0x00400000
 #define IXGBE_MRQC_RSS_FIELD_IPV6_UDP    0x00800000
 #define IXGBE_MRQC_RSS_FIELD_IPV6_EX_UDP 0x01000000
+#define IXGBE_MRQC_L3L4TXSWEN            0x00008000
+
+/* Queue Drop Enable */
+#define IXGBE_QDE_ENABLE     0x00000001
+#define IXGBE_QDE_IDX_MASK   0x00007F00
+#define IXGBE_QDE_IDX_SHIFT           8
 
 #define IXGBE_TXD_POPTS_IXSM 0x01       /* Insert IP checksum */
 #define IXGBE_TXD_POPTS_TXSM 0x02       /* Insert TCP/UDP checksum */
 #define IXGBE_TXD_CMD_VLE    0x40000000 /* Add VLAN tag */
 #define IXGBE_TXD_STAT_DD    0x00000001 /* Descriptor Done */
 
+#define IXGBE_RXDADV_IPSEC_STATUS_SECP                  0x00020000
+#define IXGBE_RXDADV_IPSEC_ERROR_INVALID_PROTOCOL       0x08000000
+#define IXGBE_RXDADV_IPSEC_ERROR_INVALID_LENGTH         0x10000000
+#define IXGBE_RXDADV_IPSEC_ERROR_AUTH_FAILED            0x18000000
+#define IXGBE_RXDADV_IPSEC_ERROR_BIT_MASK               0x18000000
+/* Multiple Transmit Queue Command Register */
+#define IXGBE_MTQC_RT_ENA       0x1 /* DCB Enable */
+#define IXGBE_MTQC_VT_ENA       0x2 /* VMDQ2 Enable */
+#define IXGBE_MTQC_64Q_1PB      0x0 /* 64 queues 1 pack buffer */
+#define IXGBE_MTQC_64VF         0x8 /* 2 TX Queues per pool w/64VF's */
+#define IXGBE_MTQC_8TC_8TQ      0xC /* 8 TC if RT_ENA or 8 TQ if VT_ENA */
+
 /* Receive Descriptor bit definitions */
 #define IXGBE_RXD_STAT_DD       0x01    /* Descriptor Done */
 #define IXGBE_RXD_STAT_EOP      0x02    /* End of Packet */
+#define IXGBE_RXD_STAT_FLM      0x04    /* FDir Match */
 #define IXGBE_RXD_STAT_VP       0x08    /* IEEE VLAN Packet */
+#define IXGBE_RXDADV_NEXTP_MASK   0x000FFFF0 /* Next Descriptor Index */
+#define IXGBE_RXDADV_NEXTP_SHIFT  0x00000004
 #define IXGBE_RXD_STAT_UDPCS    0x10    /* UDP xsum calculated */
 #define IXGBE_RXD_STAT_L4CS     0x20    /* L4 xsum calculated */
 #define IXGBE_RXD_STAT_IPCS     0x40    /* IP xsum calculated */
 #define IXGBE_RXD_STAT_VEXT     0x200   /* 1st VLAN found */
 #define IXGBE_RXD_STAT_UDPV     0x400   /* Valid UDP checksum */
 #define IXGBE_RXD_STAT_DYNINT   0x800   /* Pkt caused INT via DYNINT */
+#define IXGBE_RXD_STAT_LLINT    0x800   /* Pkt caused Low Latency Interrupt */
+#define IXGBE_RXD_STAT_TS       0x10000 /* Time Stamp */
+#define IXGBE_RXD_STAT_SECP     0x20000 /* Security Processing */
+#define IXGBE_RXD_STAT_LB       0x40000 /* Loopback Status */
 #define IXGBE_RXD_STAT_ACK      0x8000  /* ACK Packet indication */
 #define IXGBE_RXD_ERR_CE        0x01    /* CRC Error */
 #define IXGBE_RXD_ERR_LE        0x02    /* Length Error */
 #define IXGBE_RXD_ERR_USE       0x20    /* Undersize Error */
 #define IXGBE_RXD_ERR_TCPE      0x40    /* TCP/UDP Checksum Error */
 #define IXGBE_RXD_ERR_IPE       0x80    /* IP Checksum Error */
+#define IXGBE_RXDADV_ERR_MASK           0xfff00000 /* RDESC.ERRORS mask */
+#define IXGBE_RXDADV_ERR_SHIFT          20         /* RDESC.ERRORS shift */
 #define IXGBE_RXDADV_ERR_HBO    0x00800000 /*Header Buffer Overflow */
 #define IXGBE_RXDADV_ERR_CE     0x01000000 /* CRC Error */
 #define IXGBE_RXDADV_ERR_LE     0x02000000 /* Length Error */
 #define IXGBE_RXD_CFI_MASK      0x1000  /* CFI is bit 12 */
 #define IXGBE_RXD_CFI_SHIFT     12
 
+#define IXGBE_RXDADV_STAT_DD            IXGBE_RXD_STAT_DD  /* Done */
+#define IXGBE_RXDADV_STAT_EOP           IXGBE_RXD_STAT_EOP /* End of Packet */
+#define IXGBE_RXDADV_STAT_FLM           IXGBE_RXD_STAT_FLM /* FDir Match */
+#define IXGBE_RXDADV_STAT_VP            IXGBE_RXD_STAT_VP  /* IEEE VLAN Pkt */
+#define IXGBE_RXDADV_STAT_MASK          0x000fffff /* Stat/NEXTP: bit 0-19 */
+
+/* PSRTYPE bit definitions */
+#define IXGBE_PSRTYPE_TCPHDR    0x00000010
+#define IXGBE_PSRTYPE_UDPHDR    0x00000020
+#define IXGBE_PSRTYPE_IPV4HDR   0x00000100
+#define IXGBE_PSRTYPE_IPV6HDR   0x00000200
 
 /* SRRCTL bit definitions */
 #define IXGBE_SRRCTL_BSIZEPKT_SHIFT     10     /* so many KBs */
+#define IXGBE_SRRCTL_RDMTS_SHIFT        22
+#define IXGBE_SRRCTL_RDMTS_MASK         0x01C00000
+#define IXGBE_SRRCTL_DROP_EN            0x10000000
 #define IXGBE_SRRCTL_BSIZEPKT_MASK      0x0000007F
 #define IXGBE_SRRCTL_BSIZEHDR_MASK      0x00003F00
 #define IXGBE_SRRCTL_DESCTYPE_LEGACY    0x00000000
 
 #define IXGBE_RXDADV_RSSTYPE_MASK       0x0000000F
 #define IXGBE_RXDADV_PKTTYPE_MASK       0x0000FFF0
+#define IXGBE_RXDADV_PKTTYPE_MASK_EX    0x0001FFF0
 #define IXGBE_RXDADV_HDRBUFLEN_MASK     0x00007FE0
 #define IXGBE_RXDADV_HDRBUFLEN_SHIFT    5
 #define IXGBE_RXDADV_SPLITHEADER_EN     0x00001000
 #define IXGBE_RXDADV_PKTTYPE_UDP        0x00000200 /* UDP hdr present */
 #define IXGBE_RXDADV_PKTTYPE_SCTP       0x00000400 /* SCTP hdr present */
 #define IXGBE_RXDADV_PKTTYPE_NFS        0x00000800 /* NFS hdr present */
+#define IXGBE_RXDADV_PKTTYPE_IPSEC_ESP  0x00001000 /* IPSec ESP */
+#define IXGBE_RXDADV_PKTTYPE_IPSEC_AH   0x00002000 /* IPSec AH */
+#define IXGBE_RXDADV_PKTTYPE_LINKSEC    0x00004000 /* LinkSec Encap */
+#define IXGBE_RXDADV_PKTTYPE_ETQF       0x00008000 /* PKTTYPE is ETQF index */
+#define IXGBE_RXDADV_PKTTYPE_ETQF_MASK  0x00000070 /* ETQF has 8 indices */
+#define IXGBE_RXDADV_PKTTYPE_ETQF_SHIFT 4          /* Right-shift 4 bits */
+
+/* Security Processing bit Indication */
+#define IXGBE_RXDADV_LNKSEC_STATUS_SECP         0x00020000
+#define IXGBE_RXDADV_LNKSEC_ERROR_NO_SA_MATCH   0x08000000
+#define IXGBE_RXDADV_LNKSEC_ERROR_REPLAY_ERROR  0x10000000
+#define IXGBE_RXDADV_LNKSEC_ERROR_BIT_MASK      0x18000000
+#define IXGBE_RXDADV_LNKSEC_ERROR_BAD_SIG       0x18000000
+
 /* Masks to determine if packets should be dropped due to frame errors */
 #define IXGBE_RXD_ERR_FRAME_ERR_MASK ( \
                                       IXGBE_RXD_ERR_CE | \
 #define IXGBE_RX_DESC_SPECIAL_PRI_SHIFT  0x000D /* Priority in upper 3 of 16 */
 #define IXGBE_TX_DESC_SPECIAL_PRI_SHIFT  IXGBE_RX_DESC_SPECIAL_PRI_SHIFT
 
+/* Little Endian defines */
+#ifndef __le32
+#define __le32  u32
+#endif
+#ifndef __le64
+#define __le64  u64
+
+#endif
 
 /* Transmit Descriptor - Legacy */
 struct ixgbe_legacy_tx_desc {
@@ -1176,6 +1796,9 @@ struct ixgbe_adv_tx_context_desc {
 
 /* Adv Transmit Descriptor Config Masks */
 #define IXGBE_ADVTXD_DTALEN_MASK      0x0000FFFF /* Data buf length(bytes) */
+#define IXGBE_ADVTXD_MAC_LINKSEC      0x00040000 /* Insert LinkSec */
+#define IXGBE_ADVTXD_IPSEC_SA_INDEX_MASK   0x000003FF /* IPSec SA index */
+#define IXGBE_ADVTXD_IPSEC_ESP_LEN_MASK    0x000001FF /* IPSec ESP length */
 #define IXGBE_ADVTXD_DTYP_MASK  0x00F00000 /* DTYP mask */
 #define IXGBE_ADVTXD_DTYP_CTXT  0x00200000 /* Advanced Context Desc */
 #define IXGBE_ADVTXD_DTYP_DATA  0x00300000 /* Advanced Data Descriptor */
@@ -1210,6 +1833,9 @@ struct ixgbe_adv_tx_context_desc {
 #define IXGBE_ADVTXD_TUCMD_L4T_TCP   0x00000800  /* L4 Packet TYPE of TCP */
 #define IXGBE_ADVTXD_TUCMD_L4T_SCTP  0x00001000  /* L4 Packet TYPE of SCTP */
 #define IXGBE_ADVTXD_TUCMD_MKRREQ    0x00002000 /*Req requires Markers and CRC*/
+#define IXGBE_ADVTXD_POPTS_IPSEC      0x00000400 /* IPSec offload request */
+#define IXGBE_ADVTXD_TUCMD_IPSEC_TYPE_ESP 0x00002000 /* IPSec Type ESP */
+#define IXGBE_ADVTXD_TUCMD_IPSEC_ENCRYPT_EN 0x00004000/* ESP Encrypt Enable */
 #define IXGBE_ADVTXD_L4LEN_SHIFT     8  /* Adv ctxt L4LEN shift */
 #define IXGBE_ADVTXD_MSS_SHIFT       16  /* Adv ctxt MSS shift */
 
@@ -1223,6 +1849,12 @@ typedef u32 ixgbe_link_speed;
 #define IXGBE_LINK_SPEED_10GB_FULL 0x0080
 #define IXGBE_LINK_SPEED_82598_AUTONEG (IXGBE_LINK_SPEED_1GB_FULL | \
                                         IXGBE_LINK_SPEED_10GB_FULL)
+#define IXGBE_LINK_SPEED_82599_AUTONEG (IXGBE_LINK_SPEED_100_FULL | \
+                                        IXGBE_LINK_SPEED_1GB_FULL | \
+                                        IXGBE_LINK_SPEED_10GB_FULL)
+
+#define IXGBE_PCIE_DEV_CTRL_2 0xC8
+#define PCIE_COMPL_TO_VALUE 0x05
 
 /* Physical layer type */
 typedef u32 ixgbe_physical_layer;
@@ -1239,7 +1871,6 @@ typedef u32 ixgbe_physical_layer;
 #define IXGBE_PHYSICAL_LAYER_1000BASE_KX  0x0200
 #define IXGBE_PHYSICAL_LAYER_1000BASE_BX  0x0400
 
-
 enum ixgbe_eeprom_type {
        ixgbe_eeprom_uninitialized = 0,
        ixgbe_eeprom_spi,
@@ -1249,12 +1880,14 @@ enum ixgbe_eeprom_type {
 enum ixgbe_mac_type {
        ixgbe_mac_unknown = 0,
        ixgbe_mac_82598EB,
+       ixgbe_mac_82599EB,
        ixgbe_num_macs
 };
 
 enum ixgbe_phy_type {
        ixgbe_phy_unknown = 0,
        ixgbe_phy_tn,
+       ixgbe_phy_cu_unknown,
        ixgbe_phy_qt,
        ixgbe_phy_xaui,
        ixgbe_phy_nl,
@@ -1263,22 +1896,31 @@ enum ixgbe_phy_type {
        ixgbe_phy_sfp_avago,
        ixgbe_phy_sfp_ftl,
        ixgbe_phy_sfp_unknown,
+       ixgbe_phy_sfp_intel,
        ixgbe_phy_generic
 };
 
 /*
  * SFP+ module type IDs:
  *
- * ID  Module Type
+ * ID   Module Type
  * =============
- * 0   SFP_DA_CU
- * 1   SFP_SR
- * 2   SFP_LR
+ * 0    SFP_DA_CU
+ * 1    SFP_SR
+ * 2    SFP_LR
+ * 3    SFP_DA_CU_CORE0 - 82599-specific
+ * 4    SFP_DA_CU_CORE1 - 82599-specific
+ * 5    SFP_SR/LR_CORE0 - 82599-specific
+ * 6    SFP_SR/LR_CORE1 - 82599-specific
  */
 enum ixgbe_sfp_type {
        ixgbe_sfp_type_da_cu = 0,
        ixgbe_sfp_type_sr = 1,
        ixgbe_sfp_type_lr = 2,
+       ixgbe_sfp_type_da_cu_core0 = 3,
+       ixgbe_sfp_type_da_cu_core1 = 4,
+       ixgbe_sfp_type_srlr_core0 = 5,
+       ixgbe_sfp_type_srlr_core1 = 6,
        ixgbe_sfp_type_not_present = 0xFFFE,
        ixgbe_sfp_type_unknown = 0xFFFF
 };
@@ -1300,6 +1942,40 @@ enum ixgbe_fc_mode {
        ixgbe_fc_default
 };
 
+/* PCI bus types */
+enum ixgbe_bus_type {
+       ixgbe_bus_type_unknown = 0,
+       ixgbe_bus_type_pci,
+       ixgbe_bus_type_pcix,
+       ixgbe_bus_type_pci_express,
+       ixgbe_bus_type_reserved
+};
+
+/* PCI bus speeds */
+enum ixgbe_bus_speed {
+       ixgbe_bus_speed_unknown = 0,
+       ixgbe_bus_speed_33,
+       ixgbe_bus_speed_66,
+       ixgbe_bus_speed_100,
+       ixgbe_bus_speed_120,
+       ixgbe_bus_speed_133,
+       ixgbe_bus_speed_2500,
+       ixgbe_bus_speed_5000,
+       ixgbe_bus_speed_reserved
+};
+
+/* PCI bus widths */
+enum ixgbe_bus_width {
+       ixgbe_bus_width_unknown = 0,
+       ixgbe_bus_width_pcie_x1,
+       ixgbe_bus_width_pcie_x2,
+       ixgbe_bus_width_pcie_x4 = 4,
+       ixgbe_bus_width_pcie_x8 = 8,
+       ixgbe_bus_width_32,
+       ixgbe_bus_width_64,
+       ixgbe_bus_width_reserved
+};
+
 struct ixgbe_addr_filter_info {
        u32 num_mc_addrs;
        u32 rar_used_count;
@@ -1309,6 +1985,16 @@ struct ixgbe_addr_filter_info {
        bool user_set_promisc;
 };
 
+/* Bus parameters */
+struct ixgbe_bus_info {
+       enum ixgbe_bus_speed speed;
+       enum ixgbe_bus_width width;
+       enum ixgbe_bus_type type;
+
+       u16 func;
+       u16 lan_id;
+};
+
 /* Flow control parameters */
 struct ixgbe_fc_info {
        u32 high_water; /* Flow Control High-water */
@@ -1377,6 +2063,14 @@ struct ixgbe_hw_stats {
        u64 qptc[16];
        u64 qbrc[16];
        u64 qbtc[16];
+       u64 qprdc[16];
+       u64 pxon2offc[8];
+       u64 fdirustat_add;
+       u64 fdirustat_remove;
+       u64 fdirfstat_fadd;
+       u64 fdirfstat_fremove;
+       u64 fdirmatch;
+       u64 fdirmiss;
 };
 
 /* forward declaration */
@@ -1401,12 +2095,15 @@ struct ixgbe_mac_operations {
        s32 (*start_hw)(struct ixgbe_hw *);
        s32 (*clear_hw_cntrs)(struct ixgbe_hw *);
        enum ixgbe_media_type (*get_media_type)(struct ixgbe_hw *);
-       s32 (*get_supported_physical_layer)(struct ixgbe_hw *);
+       u32 (*get_supported_physical_layer)(struct ixgbe_hw *);
        s32 (*get_mac_addr)(struct ixgbe_hw *, u8 *);
        s32 (*stop_adapter)(struct ixgbe_hw *);
        s32 (*get_bus_info)(struct ixgbe_hw *);
+       void (*set_lan_id)(struct ixgbe_hw *);
        s32 (*read_analog_reg8)(struct ixgbe_hw*, u32, u8*);
        s32 (*write_analog_reg8)(struct ixgbe_hw*, u32, u8);
+       s32 (*setup_sfp)(struct ixgbe_hw *);
+       s32 (*enable_rx_dma)(struct ixgbe_hw *, u32);
 
        /* Link */
        s32 (*setup_link)(struct ixgbe_hw *);
@@ -1462,7 +2159,7 @@ struct ixgbe_phy_operations {
 struct ixgbe_eeprom_info {
        struct ixgbe_eeprom_operations  ops;
        enum ixgbe_eeprom_type          type;
-       u32                             semaphore_delay;
+       u32                             semaphore_delay;
        u16                             word_size;
        u16                             address_bits;
 };
@@ -1508,6 +2205,7 @@ struct ixgbe_hw {
        struct ixgbe_fc_info            fc;
        struct ixgbe_phy_info           phy;
        struct ixgbe_eeprom_info        eeprom;
+       struct ixgbe_bus_info           bus;
        u16                             device_id;
        u16                             vendor_id;
        u16                             subsystem_device_id;
@@ -1546,6 +2244,7 @@ struct ixgbe_info {
 #define IXGBE_ERR_I2C                           -18
 #define IXGBE_ERR_SFP_NOT_SUPPORTED             -19
 #define IXGBE_ERR_SFP_NOT_PRESENT               -20
+#define IXGBE_ERR_SFP_NO_INIT_SEQ_PRESENT       -21
 #define IXGBE_NOT_IMPLEMENTED                   0x7FFFFFFF
 
 #endif /* _IXGBE_TYPE_H_ */
index 08b34051c646d6e4028bb30847ad793c84aedd00..860dcd98a07c1c036d3aa97286152ea5a061f05f 100644 (file)
@@ -429,10 +429,9 @@ jme_check_link(struct net_device *netdev, int testonly)
 
                jme->phylink = phylink;
 
-               ghc = jme->reg_ghc & ~(GHC_SPEED_10M |
-                                       GHC_SPEED_100M |
-                                       GHC_SPEED_1000M |
-                                       GHC_DPX);
+               ghc = jme->reg_ghc & ~(GHC_SPEED | GHC_DPX |
+                               GHC_TO_CLK_PCIE | GHC_TXMAC_CLK_PCIE |
+                               GHC_TO_CLK_GPHY | GHC_TXMAC_CLK_GPHY);
                switch (phylink & PHY_LINK_SPEED_MASK) {
                case PHY_LINK_SPEED_10M:
                        ghc |= GHC_SPEED_10M |
@@ -957,13 +956,14 @@ jme_process_receive(struct jme_adapter *jme, int limit)
                goto out_inc;
 
        i = atomic_read(&rxring->next_to_clean);
-       while (limit-- > 0) {
+       while (limit > 0) {
                rxdesc = rxring->desc;
                rxdesc += i;
 
                if ((rxdesc->descwb.flags & cpu_to_le16(RXWBFLAG_OWN)) ||
                !(rxdesc->descwb.desccnt & RXWBDCNT_WBCPL))
                        goto out;
+               --limit;
 
                desccnt = rxdesc->descwb.desccnt & RXWBDCNT_DCNT;
 
@@ -1833,7 +1833,7 @@ jme_tx_vlan(struct sk_buff *skb, __le16 *vlan, u8 *flags)
 }
 
 static int
-jme_fill_first_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx)
+jme_fill_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx)
 {
        struct jme_ring *txring = jme->txring;
        struct txdesc *txdesc;
@@ -1863,6 +1863,7 @@ jme_fill_first_tx_desc(struct jme_adapter *jme, struct sk_buff *skb, int idx)
        if (jme_tx_tso(skb, &txdesc->desc1.mss, &flags))
                jme_tx_csum(jme, skb, &flags);
        jme_tx_vlan(skb, &txdesc->desc1.vlan, &flags);
+       jme_map_tx_skb(jme, skb, idx);
        txdesc->desc1.flags = flags;
        /*
         * Set tx buffer info after telling NIC to send
@@ -1932,8 +1933,7 @@ jme_start_xmit(struct sk_buff *skb, struct net_device *netdev)
                return NETDEV_TX_BUSY;
        }
 
-       jme_map_tx_skb(jme, skb, idx);
-       jme_fill_first_tx_desc(jme, skb, idx);
+       jme_fill_tx_desc(jme, skb, idx);
 
        jwrite32(jme, JME_TXCS, jme->reg_txcs |
                                TXCS_SELECT_QUEUE0 |
@@ -2590,6 +2590,16 @@ static const struct ethtool_ops jme_ethtool_ops = {
 static int
 jme_pci_dma64(struct pci_dev *pdev)
 {
+       if (pdev->device == PCI_DEVICE_ID_JMICRON_JMC250 &&
+           !pci_set_dma_mask(pdev, DMA_64BIT_MASK))
+               if (!pci_set_consistent_dma_mask(pdev, DMA_64BIT_MASK))
+                       return 1;
+
+       if (pdev->device == PCI_DEVICE_ID_JMICRON_JMC250 &&
+           !pci_set_dma_mask(pdev, DMA_40BIT_MASK))
+               if (!pci_set_consistent_dma_mask(pdev, DMA_40BIT_MASK))
+                       return 1;
+
        if (!pci_set_dma_mask(pdev, DMA_32BIT_MASK))
                if (!pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK))
                        return 0;
@@ -2856,7 +2866,11 @@ jme_init_one(struct pci_dev *pdev,
                goto err_out_free_shadow;
        }
 
-       msg_probe(jme, "JMC250 gigabit%s ver:%x rev:%x macaddr:%pM\n",
+       msg_probe(jme, "%s%s ver:%x rev:%x macaddr:%pM\n",
+               (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC250) ?
+                       "JMC250 Gigabit Ethernet" :
+                       (jme->pdev->device == PCI_DEVICE_ID_JMICRON_JMC260) ?
+                               "JMC260 Fast Ethernet" : "Unknown",
                (jme->fpgaver != 0) ? " (FPGA)" : "",
                (jme->fpgaver != 0) ? jme->fpgaver : jme->chiprev,
                jme->rev, netdev->dev_addr);
@@ -3002,7 +3016,7 @@ static struct pci_driver jme_driver = {
 static int __init
 jme_init_module(void)
 {
-       printk(KERN_INFO PFX "JMicron JMC250 gigabit ethernet "
+       printk(KERN_INFO PFX "JMicron JMC2XX ethernet "
               "driver version %s\n", DRV_VERSION);
        return pci_register_driver(&jme_driver);
 }
index e321c678b11c098f7436a9eb950912c50d6f47f1..0996a069ac7b57aedf1b38daae8ee8a7f81264d5 100644 (file)
@@ -25,7 +25,7 @@
 #define __JME_H_INCLUDED__
 
 #define DRV_NAME       "jme"
-#define DRV_VERSION    "1.0.3"
+#define DRV_VERSION    "1.0.4"
 #define PFX            DRV_NAME ": "
 
 #define PCI_DEVICE_ID_JMICRON_JMC250   0x0250
index 7e24b50486869c8295e19d8b7339b7d56d6ef909..70d3ef4a2c5fdef238619959de7787c49cd833d7 100644 (file)
@@ -60,6 +60,47 @@ static struct macvlan_dev *macvlan_hash_lookup(const struct macvlan_port *port,
        return NULL;
 }
 
+static void macvlan_hash_add(struct macvlan_dev *vlan)
+{
+       struct macvlan_port *port = vlan->port;
+       const unsigned char *addr = vlan->dev->dev_addr;
+
+       hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[addr[5]]);
+}
+
+static void macvlan_hash_del(struct macvlan_dev *vlan)
+{
+       hlist_del_rcu(&vlan->hlist);
+       synchronize_rcu();
+}
+
+static void macvlan_hash_change_addr(struct macvlan_dev *vlan,
+                                       const unsigned char *addr)
+{
+       macvlan_hash_del(vlan);
+       /* Now that we are unhashed it is safe to change the device
+        * address without confusing packet delivery.
+        */
+       memcpy(vlan->dev->dev_addr, addr, ETH_ALEN);
+       macvlan_hash_add(vlan);
+}
+
+static int macvlan_addr_busy(const struct macvlan_port *port,
+                               const unsigned char *addr)
+{
+       /* Test to see if the specified multicast address is
+        * currently in use by the underlying device or
+        * another macvlan.
+        */
+       if (memcmp(port->dev->dev_addr, addr, ETH_ALEN) == 0)
+               return 1;
+
+       if (macvlan_hash_lookup(port, addr))
+               return 1;
+
+       return 0;
+}
+
 static void macvlan_broadcast(struct sk_buff *skb,
                              const struct macvlan_port *port)
 {
@@ -184,10 +225,13 @@ static const struct header_ops macvlan_hard_header_ops = {
 static int macvlan_open(struct net_device *dev)
 {
        struct macvlan_dev *vlan = netdev_priv(dev);
-       struct macvlan_port *port = vlan->port;
        struct net_device *lowerdev = vlan->lowerdev;
        int err;
 
+       err = -EBUSY;
+       if (macvlan_addr_busy(vlan->port, dev->dev_addr))
+               goto out;
+
        err = dev_unicast_add(lowerdev, dev->dev_addr, ETH_ALEN);
        if (err < 0)
                goto out;
@@ -196,8 +240,7 @@ static int macvlan_open(struct net_device *dev)
                if (err < 0)
                        goto del_unicast;
        }
-
-       hlist_add_head_rcu(&vlan->hlist, &port->vlan_hash[dev->dev_addr[5]]);
+       macvlan_hash_add(vlan);
        return 0;
 
 del_unicast:
@@ -217,8 +260,7 @@ static int macvlan_stop(struct net_device *dev)
 
        dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);
 
-       hlist_del_rcu(&vlan->hlist);
-       synchronize_rcu();
+       macvlan_hash_del(vlan);
        return 0;
 }
 
@@ -232,16 +274,21 @@ static int macvlan_set_mac_address(struct net_device *dev, void *p)
        if (!is_valid_ether_addr(addr->sa_data))
                return -EADDRNOTAVAIL;
 
-       if (!(dev->flags & IFF_UP))
-               goto out;
+       if (!(dev->flags & IFF_UP)) {
+               /* Just copy in the new address */
+               memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+       } else {
+               /* Rehash and update the device filters */
+               if (macvlan_addr_busy(vlan->port, addr->sa_data))
+                       return -EBUSY;
 
-       err = dev_unicast_add(lowerdev, addr->sa_data, ETH_ALEN);
-       if (err < 0)
-               return err;
-       dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);
+               if ((err = dev_unicast_add(lowerdev, addr->sa_data, ETH_ALEN)))
+                       return err;
 
-out:
-       memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+               dev_unicast_delete(lowerdev, dev->dev_addr, ETH_ALEN);
+
+               macvlan_hash_change_addr(vlan, addr->sa_data);
+       }
        return 0;
 }
 
@@ -461,12 +508,13 @@ static int macvlan_newlink(struct net_device *dev,
        if (lowerdev == NULL)
                return -ENODEV;
 
-       /* Don't allow macvlans on top of other macvlans - its not really
-        * wrong, but lockdep can't handle it and its not useful for anything
-        * you couldn't do directly on top of the real device.
+       /* When creating macvlans on top of other macvlans - use
+        * the real device as the lowerdev.
         */
-       if (lowerdev->rtnl_link_ops == dev->rtnl_link_ops)
-               return -ENODEV;
+       if (lowerdev->rtnl_link_ops == dev->rtnl_link_ops) {
+               struct macvlan_dev *lowervlan = netdev_priv(lowerdev);
+               lowerdev = lowervlan->lowerdev;
+       }
 
        if (!tb[IFLA_MTU])
                dev->mtu = lowerdev->mtu;
index bb96931952421c9c61031a8913c38f863c08eb4b..a56d9d2df73f3b108427a8ee828cb1afb0cb782d 100644 (file)
@@ -351,10 +351,8 @@ struct rx_queue {
        int rx_desc_area_size;
        struct sk_buff **rx_skb;
 
-#ifdef CONFIG_MV643XX_ETH_LRO
        struct net_lro_mgr lro_mgr;
        struct net_lro_desc lro_arr[8];
-#endif
 };
 
 struct tx_queue {
@@ -516,7 +514,6 @@ static void txq_maybe_wake(struct tx_queue *txq)
 
 
 /* rx napi ******************************************************************/
-#ifdef CONFIG_MV643XX_ETH_LRO
 static int
 mv643xx_get_skb_header(struct sk_buff *skb, void **iphdr, void **tcph,
                       u64 *hdr_flags, void *priv)
@@ -542,7 +539,6 @@ mv643xx_get_skb_header(struct sk_buff *skb, void **iphdr, void **tcph,
 
        return 0;
 }
-#endif
 
 static int rxq_process(struct rx_queue *rxq, int budget)
 {
@@ -612,13 +608,11 @@ static int rxq_process(struct rx_queue *rxq, int budget)
                        skb->ip_summed = CHECKSUM_UNNECESSARY;
                skb->protocol = eth_type_trans(skb, mp->dev);
 
-#ifdef CONFIG_MV643XX_ETH_LRO
                if (skb->dev->features & NETIF_F_LRO &&
                    skb->ip_summed == CHECKSUM_UNNECESSARY) {
                        lro_receive_skb(&rxq->lro_mgr, skb, (void *)cmd_sts);
                        lro_flush_needed = 1;
                } else
-#endif
                        netif_receive_skb(skb);
 
                continue;
@@ -640,10 +634,8 @@ err:
                dev_kfree_skb(skb);
        }
 
-#ifdef CONFIG_MV643XX_ETH_LRO
        if (lro_flush_needed)
                lro_flush_all(&rxq->lro_mgr);
-#endif
 
        if (rx < budget)
                mp->work_rx &= ~(1 << rxq->index);
@@ -1231,7 +1223,6 @@ static void mv643xx_eth_grab_lro_stats(struct mv643xx_eth_private *mp)
        u32 lro_no_desc = 0;
        int i;
 
-#ifdef CONFIG_MV643XX_ETH_LRO
        for (i = 0; i < mp->rxq_count; i++) {
                struct rx_queue *rxq = mp->rxq + i;
 
@@ -1239,7 +1230,6 @@ static void mv643xx_eth_grab_lro_stats(struct mv643xx_eth_private *mp)
                lro_flushed += rxq->lro_mgr.stats.flushed;
                lro_no_desc += rxq->lro_mgr.stats.no_desc;
        }
-#endif
 
        mp->lro_counters.lro_aggregated = lro_aggregated;
        mp->lro_counters.lro_flushed = lro_flushed;
@@ -1263,7 +1253,7 @@ static void mib_counters_update(struct mv643xx_eth_private *mp)
 {
        struct mib_counters *p = &mp->mib_counters;
 
-       spin_lock(&mp->mib_counters_lock);
+       spin_lock_bh(&mp->mib_counters_lock);
        p->good_octets_received += mib_read(mp, 0x00);
        p->good_octets_received += (u64)mib_read(mp, 0x04) << 32;
        p->bad_octets_received += mib_read(mp, 0x08);
@@ -1296,7 +1286,7 @@ static void mib_counters_update(struct mv643xx_eth_private *mp)
        p->bad_crc_event += mib_read(mp, 0x74);
        p->collision += mib_read(mp, 0x78);
        p->late_collision += mib_read(mp, 0x7c);
-       spin_unlock(&mp->mib_counters_lock);
+       spin_unlock_bh(&mp->mib_counters_lock);
 
        mod_timer(&mp->mib_counters_timer, jiffies + 30 * HZ);
 }
@@ -1831,7 +1821,7 @@ oom:
                return;
        }
 
-       mc_spec = kmalloc(0x200, GFP_KERNEL);
+       mc_spec = kmalloc(0x200, GFP_ATOMIC);
        if (mc_spec == NULL)
                goto oom;
        mc_other = mc_spec + (0x100 >> 2);
@@ -1939,7 +1929,6 @@ static int rxq_init(struct mv643xx_eth_private *mp, int index)
                                        nexti * sizeof(struct rx_desc);
        }
 
-#ifdef CONFIG_MV643XX_ETH_LRO
        rxq->lro_mgr.dev = mp->dev;
        memset(&rxq->lro_mgr.stats, 0, sizeof(rxq->lro_mgr.stats));
        rxq->lro_mgr.features = LRO_F_NAPI;
@@ -1952,7 +1941,6 @@ static int rxq_init(struct mv643xx_eth_private *mp, int index)
        rxq->lro_mgr.get_skb_header = mv643xx_get_skb_header;
 
        memset(&rxq->lro_arr, 0, sizeof(rxq->lro_arr));
-#endif
 
        return 0;
 
@@ -2300,11 +2288,6 @@ static void port_start(struct mv643xx_eth_private *mp)
                txq_set_fixed_prio_mode(txq);
        }
 
-       /*
-        * Add configured unicast address to address filter table.
-        */
-       mv643xx_eth_program_unicast_filter(mp->dev);
-
        /*
         * Receive all unmatched unicast, TCP, UDP, BPDU and broadcast
         * frames to RX queue #0, and include the pseudo-header when
@@ -2317,6 +2300,11 @@ static void port_start(struct mv643xx_eth_private *mp)
         */
        wrlp(mp, PORT_CONFIG_EXT, 0x00000000);
 
+       /*
+        * Add configured unicast addresses to address filter table.
+        */
+       mv643xx_eth_program_unicast_filter(mp->dev);
+
        /*
         * Enable the receive queues.
         */
@@ -2400,13 +2388,8 @@ static int mv643xx_eth_open(struct net_device *dev)
                }
        }
 
-       netif_carrier_off(dev);
-
        port_start(mp);
 
-       set_rx_coal(mp, 0);
-       set_tx_coal(mp, 0);
-
        wrlp(mp, INT_MASK_EXT, INT_EXT_LINK_PHY | INT_EXT_TX);
        wrlp(mp, INT_MASK, INT_TX_END | INT_RX | INT_EXT);
 
@@ -2457,8 +2440,6 @@ static int mv643xx_eth_stop(struct net_device *dev)
        wrlp(mp, INT_MASK, 0x00000000);
        rdlp(mp, INT_MASK);
 
-       del_timer_sync(&mp->mib_counters_timer);
-
        napi_disable(&mp->napi);
 
        del_timer_sync(&mp->rx_oom);
@@ -2470,6 +2451,7 @@ static int mv643xx_eth_stop(struct net_device *dev)
        port_reset(mp);
        mv643xx_eth_get_stats(dev);
        mib_counters_update(mp);
+       del_timer_sync(&mp->mib_counters_timer);
 
        skb_queue_purge(&mp->rx_recycle);
 
@@ -2874,6 +2856,21 @@ static void init_pscr(struct mv643xx_eth_private *mp, int speed, int duplex)
        wrlp(mp, PORT_SERIAL_CONTROL, pscr);
 }
 
+static const struct net_device_ops mv643xx_eth_netdev_ops = {
+       .ndo_open               = mv643xx_eth_open,
+       .ndo_stop               = mv643xx_eth_stop,
+       .ndo_start_xmit         = mv643xx_eth_xmit,
+       .ndo_set_rx_mode        = mv643xx_eth_set_rx_mode,
+       .ndo_set_mac_address    = mv643xx_eth_set_mac_address,
+       .ndo_do_ioctl           = mv643xx_eth_ioctl,
+       .ndo_change_mtu         = mv643xx_eth_change_mtu,
+       .ndo_tx_timeout         = mv643xx_eth_tx_timeout,
+       .ndo_get_stats          = mv643xx_eth_get_stats,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = mv643xx_eth_netpoll,
+#endif
+};
+
 static int mv643xx_eth_probe(struct platform_device *pdev)
 {
        struct mv643xx_eth_platform_data *pd;
@@ -2945,18 +2942,8 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
        BUG_ON(!res);
        dev->irq = res->start;
 
-       dev->get_stats = mv643xx_eth_get_stats;
-       dev->hard_start_xmit = mv643xx_eth_xmit;
-       dev->open = mv643xx_eth_open;
-       dev->stop = mv643xx_eth_stop;
-       dev->set_rx_mode = mv643xx_eth_set_rx_mode;
-       dev->set_mac_address = mv643xx_eth_set_mac_address;
-       dev->do_ioctl = mv643xx_eth_ioctl;
-       dev->change_mtu = mv643xx_eth_change_mtu;
-       dev->tx_timeout = mv643xx_eth_tx_timeout;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       dev->poll_controller = mv643xx_eth_netpoll;
-#endif
+       dev->netdev_ops = &mv643xx_eth_netdev_ops;
+
        dev->watchdog_timeo = 2 * HZ;
        dev->base_addr = 0;
 
@@ -2968,6 +2955,11 @@ static int mv643xx_eth_probe(struct platform_device *pdev)
        if (mp->shared->win_protect)
                wrl(mp, WINDOW_PROTECT(mp->port_num), mp->shared->win_protect);
 
+       netif_carrier_off(dev);
+
+       set_rx_coal(mp, 250);
+       set_tx_coal(mp, 0);
+
        err = register_netdev(dev);
        if (err)
                goto out;
index 88b52883acea0705804aa6b7ee04da7c2e963ddf..08534c08d30d669cecd97e9c258c97fbe10acd9c 100644 (file)
@@ -896,6 +896,17 @@ static const struct header_ops myri_header_ops = {
        .cache_update   = myri_header_cache_update,
 };
 
+static const struct net_device_ops myri_ops = {
+       .ndo_open               = myri_open,
+       .ndo_stop               = myri_close,
+       .ndo_start_xmit         = myri_start_xmit,
+       .ndo_set_multicast_list = myri_set_multicast,
+       .ndo_tx_timeout         = myri_tx_timeout,
+       .ndo_change_mtu         = myri_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 static int __devinit myri_sbus_probe(struct of_device *op, const struct of_device_id *match)
 {
        struct device_node *dp = op->node;
@@ -1048,13 +1059,9 @@ static int __devinit myri_sbus_probe(struct of_device *op, const struct of_devic
        sbus_writel((1 << i), mp->cregs + MYRICTRL_IRQLVL);
 
        mp->dev = dev;
-       dev->open = &myri_open;
-       dev->stop = &myri_close;
-       dev->hard_start_xmit = &myri_start_xmit;
-       dev->tx_timeout = &myri_tx_timeout;
        dev->watchdog_timeo = 5*HZ;
-       dev->set_multicast_list = &myri_set_multicast;
        dev->irq = op->irqs[0];
+       dev->netdev_ops = &myri_ops;
 
        /* Register interrupt handler now. */
        DET(("Requesting MYRIcom IRQ line.\n"));
@@ -1065,7 +1072,6 @@ static int __devinit myri_sbus_probe(struct of_device *op, const struct of_devic
        }
 
        dev->mtu                = MYRINET_MTU;
-       dev->change_mtu         = myri_change_mtu;
        dev->header_ops         = &myri_header_ops;
 
        dev->hard_header_len    = (ETH_HLEN + MYRI_PAD_LEN);
index c23a58624a33fc00ea301e57aae28424c41aca6e..c9bfe4eea189d9d113feac1a99174b73eb0f4eeb 100644 (file)
@@ -127,7 +127,7 @@ static int full_duplex[MAX_UNITS];
 #define NATSEMI_RX_LIMIT       2046    /* maximum supported by hardware */
 
 /* These identify the driver base version and may not be removed. */
-static char version[] __devinitdata =
+static const char version[] __devinitconst =
   KERN_INFO DRV_NAME " dp8381x driver, version "
       DRV_VERSION ", " DRV_RELDATE "\n"
   KERN_INFO "  originally by Donald Becker <becker@scyld.com>\n"
index f090d3b9ec94791fd69a7a89067dfa61caa927d9..eb66f658f9d1bec889f271d457a6f285a236cbad 100644 (file)
@@ -62,8 +62,9 @@ static int options[MAX_UNITS];
 #include "8390.h"
 
 /* These identify the driver base version and may not be removed. */
-static char version[] __devinitdata =
-KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE " D. Becker/P. Gortmaker\n";
+static const char version[] __devinitconst =
+       KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE
+       " D. Becker/P. Gortmaker\n";
 
 #if defined(__powerpc__)
 #define inl_le(addr)  le32_to_cpu(inl(addr))
index 8e7c4c910d2a75b3e1c6adc2610d9cd9bdf4df29..cf01a9130c916ac24f520365df7e7ffe9dc19eaa 100644 (file)
@@ -1,4 +1,4 @@
-# Copyright (C) 2003 - 2006 NetXen, Inc.
+# Copyright (C) 2003 - 2009 NetXen, Inc.
 # All rights reserved.
 # 
 # This program is free software; you can redistribute it and/or
 # 
 # Contact Information:
 #    info@netxen.com
-# NetXen,
-# 3965 Freedom Circle, Fourth floor,
-# Santa Clara, CA 95054
+# NetXen Inc,
+# 18922 Forge Drive
+# Cupertino, CA 95014-0701
 #
-# Makefile for the NetXen NIC Driver
 #
 
 
index f4dd9acb6877e78e8e2b9cf34d860bff37aefd2a..c40815169f35bee6b0b3ac188e74d001984ab425 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 - 2006 NetXen, Inc.
+ * Copyright (C) 2003 - 2009 NetXen, Inc.
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  *
  * Contact Information:
  *    info@netxen.com
- * NetXen,
- * 3965 Freedom Circle, Fourth floor,
- * Santa Clara, CA 95054
+ * NetXen Inc,
+ * 18922 Forge Drive
+ * Cupertino, CA 95014-0701
+ *
  */
 
 #ifndef _NETXEN_NIC_H_
@@ -65,8 +66,8 @@
 
 #define _NETXEN_NIC_LINUX_MAJOR 4
 #define _NETXEN_NIC_LINUX_MINOR 0
-#define _NETXEN_NIC_LINUX_SUBVERSION 11
-#define NETXEN_NIC_LINUX_VERSIONID  "4.0.11"
+#define _NETXEN_NIC_LINUX_SUBVERSION 30
+#define NETXEN_NIC_LINUX_VERSIONID  "4.0.30"
 
 #define NETXEN_VERSION_CODE(a, b, c)   (((a) << 16) + ((b) << 8) + (c))
 
 
 #define PHAN_VENDOR_ID 0x4040
 
-#define RCV_DESC_RINGSIZE      \
-       (sizeof(struct rcv_desc) * adapter->max_rx_desc_count)
-#define STATUS_DESC_RINGSIZE   \
-       (sizeof(struct status_desc)* adapter->max_rx_desc_count)
-#define LRO_DESC_RINGSIZE      \
-       (sizeof(rcvDesc_t) * adapter->max_lro_rx_desc_count)
-#define TX_RINGSIZE    \
-       (sizeof(struct netxen_cmd_buffer) * adapter->max_tx_desc_count)
-#define RCV_BUFFSIZE   \
-       (sizeof(struct netxen_rx_buffer) * rds_ring->max_rx_desc_count)
+#define RCV_DESC_RINGSIZE(rds_ring)    \
+       (sizeof(struct rcv_desc) * (rds_ring)->num_desc)
+#define RCV_BUFF_RINGSIZE(rds_ring)    \
+       (sizeof(struct netxen_rx_buffer) * rds_ring->num_desc)
+#define STATUS_DESC_RINGSIZE(sds_ring) \
+       (sizeof(struct status_desc) * (sds_ring)->num_desc)
+#define TX_BUFF_RINGSIZE(adapter)      \
+       (sizeof(struct netxen_cmd_buffer) * adapter->num_txd)
+#define TX_DESC_RINGSIZE(adapter)      \
+       (sizeof(struct cmd_desc_type0) * adapter->num_txd)
+
 #define find_diff_among(a,b,range) ((a)<(b)?((b)-(a)):((b)+(range)-(a)))
 
-#define NETXEN_NETDEV_STATUS           0x1
 #define NETXEN_RCV_PRODUCER_OFFSET     0
 #define NETXEN_RCV_PEG_DB_ID           2
 #define NETXEN_HOST_DUMMY_DMA_SIZE 1024
 /* Host writes the following to notify that it has done the init-handshake */
 #define PHAN_INITIALIZE_ACK    0xf00f
 
-#define NUM_RCV_DESC_RINGS     3       /* No of Rcv Descriptor contexts */
-
-/* descriptor types */
-#define RCV_DESC_NORMAL                0x01
-#define RCV_DESC_JUMBO         0x02
-#define RCV_DESC_LRO           0x04
-#define RCV_DESC_NORMAL_CTXID  0
-#define RCV_DESC_JUMBO_CTXID   1
-#define RCV_DESC_LRO_CTXID     2
+#define NUM_RCV_DESC_RINGS     3
+#define NUM_STS_DESC_RINGS     4
 
-#define RCV_DESC_TYPE(ID) \
-       ((ID == RCV_DESC_JUMBO_CTXID)   \
-               ? RCV_DESC_JUMBO        \
-               : ((ID == RCV_DESC_LRO_CTXID)   \
-                       ? RCV_DESC_LRO :        \
-                       (RCV_DESC_NORMAL)))
+#define RCV_RING_NORMAL        0
+#define RCV_RING_JUMBO 1
+#define RCV_RING_LRO   2
 
 #define MAX_CMD_DESCRIPTORS            4096
 #define MAX_RCV_DESCRIPTORS            16384
@@ -357,10 +348,7 @@ struct cmd_desc_type0 {
                __le64 addr_buffer1;
        };
 
-       __le16 buffer1_length;
-       __le16 buffer2_length;
-       __le16 buffer3_length;
-       __le16 buffer4_length;
+       __le16 buffer_length[4];
 
        union {
                struct {
@@ -391,11 +379,8 @@ struct rcv_desc {
 #define STATUS_CKSUM_OK                (2)
 
 /* owner bits of status_desc */
-#define STATUS_OWNER_HOST      (0x1)
-#define STATUS_OWNER_PHANTOM   (0x2)
-
-#define NETXEN_PROT_IP         (1)
-#define NETXEN_PROT_UNKNOWN    (0)
+#define STATUS_OWNER_HOST      (0x1ULL << 56)
+#define STATUS_OWNER_PHANTOM   (0x2ULL << 56)
 
 /* Note: sizeof(status_desc) should always be a mutliple of 2 */
 
@@ -421,15 +406,6 @@ struct rcv_desc {
 #define netxen_get_sts_opcode(sts_data)        \
        (((sts_data) >> 58) & 0x03F)
 
-#define netxen_get_sts_owner(status_desc)      \
-       ((le64_to_cpu((status_desc)->status_desc_data) >> 56) & 0x03)
-#define netxen_set_sts_owner(status_desc, val) { \
-       (status_desc)->status_desc_data = \
-               ((status_desc)->status_desc_data & \
-               ~cpu_to_le64(0x3ULL << 56)) | \
-               cpu_to_le64((u64)((val) & 0x3) << 56); \
-}
-
 struct status_desc {
        /* Bit pattern: 0-3 port, 4-7 status, 8-11 type, 12-27 total_length
           28-43 reference_handle, 44-47 protocol, 48-52 pkt_offset
@@ -712,6 +688,15 @@ typedef enum {
        NETXEN_FIXED_START = 0x3F0000   /* backup of crbinit */
 } netxen_flash_map_t;
 
+#define NX_FW_VERSION_OFFSET   (NETXEN_USER_START+0x408)
+#define NX_FW_SIZE_OFFSET      (NETXEN_USER_START+0x40c)
+#define NX_BIOS_VERSION_OFFSET (NETXEN_USER_START+0x83c)
+#define NX_FW_MAGIC_OFFSET     (NETXEN_BRDCFG_START+0x128)
+#define NX_FW_MIN_SIZE         (0x3fffff)
+#define NX_P2_MN_ROMIMAGE      0
+#define NX_P3_CT_ROMIMAGE      1
+#define NX_P3_MN_ROMIMAGE      2
+
 #define NETXEN_USER_START_OLD NETXEN_PXE_START /* for backward compatibility */
 
 #define NETXEN_FLASH_START             (NETXEN_CRBINIT_START)
@@ -739,7 +724,7 @@ extern char netxen_nic_driver_name[];
 #endif
 
 /* Number of status descriptors to handle per interrupt */
-#define MAX_STATUS_HANDLE      (128)
+#define MAX_STATUS_HANDLE      (64)
 
 /*
  * netxen_skb_frag{} is to contain mapping info for each SG list. This
@@ -783,9 +768,6 @@ struct netxen_rx_buffer {
        u64 dma;
        u16 ref_handle;
        u16 state;
-       u32 lro_expected_frags;
-       u32 lro_current_frags;
-       u32 lro_length;
 };
 
 /* Board types */
@@ -800,21 +782,19 @@ struct netxen_hardware_context {
        void __iomem *pci_base0;
        void __iomem *pci_base1;
        void __iomem *pci_base2;
-       unsigned long first_page_group_end;
-       unsigned long first_page_group_start;
        void __iomem *db_base;
        unsigned long db_len;
        unsigned long pci_len0;
 
-       u8 cut_through;
        int qdr_sn_window;
        int ddr_mn_window;
        unsigned long mn_win_crb;
        unsigned long ms_win_crb;
 
+       u8 cut_through;
        u8 revision_id;
-       u16 board_type;
-       struct netxen_board_info boardcfg;
+       u16 port_type;
+       int board_type;
        u32 linkup;
        /* Address of cmd ring in Phantom */
        struct cmd_desc_type0 *cmd_desc_head;
@@ -823,8 +803,6 @@ struct netxen_hardware_context {
        int pci_func;
 };
 
-#define RCV_RING_LRO   RCV_DESC_LRO
-
 #define MINIMUM_ETHERNET_FRAME_SIZE    64      /* With FCS */
 #define ETHERNET_FCS_SIZE              4
 
@@ -850,16 +828,36 @@ struct netxen_adapter_stats {
  * be one Rcv Descriptor for normal packets, one for jumbo and may be others.
  */
 struct nx_host_rds_ring {
-       u32 flags;
        u32 producer;
-       dma_addr_t phys_addr;
-       u32 crb_rcv_producer;   /* reg offset */
-       struct rcv_desc *desc_head;     /* address of rx ring in Phantom */
-       u32 max_rx_desc_count;
+       u32 crb_rcv_producer;
+       u32 num_desc;
        u32 dma_size;
        u32 skb_size;
-       struct netxen_rx_buffer *rx_buf_arr;    /* rx buffers for receive   */
+       u32 flags;
+       struct rcv_desc *desc_head;
+       struct netxen_rx_buffer *rx_buf_arr;
        struct list_head free_list;
+       spinlock_t lock;
+       dma_addr_t phys_addr;
+};
+
+struct nx_host_sds_ring {
+       u32 consumer;
+       u32 crb_sts_consumer;
+       u32 crb_intr_mask;
+       u32 num_desc;
+
+       struct status_desc *desc_head;
+       struct netxen_adapter *adapter;
+       struct napi_struct napi;
+       struct list_head free_list[NUM_RCV_DESC_RINGS];
+
+       u16 clean_tx;
+       u16 post_rxd;
+       int irq;
+
+       dma_addr_t phys_addr;
+       char name[IFNAMSIZ+4];
 };
 
 /*
@@ -874,10 +872,7 @@ struct netxen_recv_context {
        u16 virt_port;
 
        struct nx_host_rds_ring rds_rings[NUM_RCV_DESC_RINGS];
-       u32 status_rx_consumer;
-       u32 crb_sts_consumer;   /* reg offset */
-       dma_addr_t rcv_status_desc_phys_addr;
-       struct status_desc *rcv_status_desc_head;
+       struct nx_host_sds_ring sds_rings[NUM_STS_DESC_RINGS];
 };
 
 /* New HW context creation */
@@ -1203,13 +1198,13 @@ typedef struct {
 #define NETXEN_IS_MSI_FAMILY(adapter) \
        ((adapter)->flags & (NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED))
 
-#define MSIX_ENTRIES_PER_ADAPTER       1
+#define MSIX_ENTRIES_PER_ADAPTER       NUM_STS_DESC_RINGS
 #define NETXEN_MSIX_TBL_SPACE          8192
 #define NETXEN_PCI_REG_MSIX_TBL                0x44
 
 #define NETXEN_DB_MAPSIZE_BYTES        0x1000
 
-#define NETXEN_NETDEV_WEIGHT 120
+#define NETXEN_NETDEV_WEIGHT 128
 #define NETXEN_ADAPTER_UP_MAGIC 777
 #define NETXEN_NIC_PEG_TUNE 0
 
@@ -1224,7 +1219,6 @@ struct netxen_adapter {
        struct net_device *netdev;
        struct pci_dev *pdev;
        int pci_using_dac;
-       struct napi_struct napi;
        struct net_device_stats net_stats;
        int mtu;
        int portnum;
@@ -1236,7 +1230,6 @@ struct netxen_adapter {
        nx_mac_list_t   *mac_list;
 
        struct netxen_legacy_intr_set legacy_intr;
-       u32     crb_intr_mask;
 
        struct work_struct watchdog_task;
        struct timer_list watchdog_timer;
@@ -1246,20 +1239,20 @@ struct netxen_adapter {
        u32 crb_win;
        rwlock_t adapter_lock;
 
-       uint64_t dma_mask;
-
        u32 cmd_producer;
        __le32 *cmd_consumer;
        u32 last_cmd_consumer;
        u32 crb_addr_cmd_producer;
        u32 crb_addr_cmd_consumer;
+       spinlock_t tx_clean_lock;
 
-       u32 max_tx_desc_count;
-       u32 max_rx_desc_count;
-       u32 max_jumbo_rx_desc_count;
-       u32 max_lro_rx_desc_count;
+       u32 num_txd;
+       u32 num_rxd;
+       u32 num_jumbo_rxd;
+       u32 num_lro_rxd;
 
        int max_rds_rings;
+       int max_sds_rings;
 
        u32 flags;
        u32 irq;
@@ -1267,9 +1260,9 @@ struct netxen_adapter {
        u32 temp;
 
        u32 fw_major;
+       u32 fw_version;
 
-       u8 msix_supported;
-       u8 max_possible_rss_rings;
+       int msix_supported;
        struct msix_entry msix_entries[MSIX_ENTRIES_PER_ADAPTER];
 
        struct netxen_adapter_stats stats;
@@ -1279,7 +1272,6 @@ struct netxen_adapter {
        u16 state;
        u16 link_autoneg;
        int rx_csum;
-       int status;
 
        struct netxen_cmd_buffer *cmd_buf_arr;  /* Command buffers for xmit */
 
@@ -1287,7 +1279,7 @@ struct netxen_adapter {
         * Receive instances. These can be either one per port,
         * or one per peg, etc.
         */
-       struct netxen_recv_context recv_ctx[MAX_RCV_CTX];
+       struct netxen_recv_context recv_ctx;
 
        int is_up;
        struct netxen_dummy_dma dummy_dma;
@@ -1398,6 +1390,8 @@ void netxen_nic_write_w1(struct netxen_adapter *adapter, u32 index, u32 value);
 void netxen_nic_read_w1(struct netxen_adapter *adapter, u32 index, u32 *value);
 
 int netxen_nic_get_board_info(struct netxen_adapter *adapter);
+void netxen_nic_get_firmware_info(struct netxen_adapter *adapter);
+int netxen_nic_wol_supported(struct netxen_adapter *adapter);
 
 int netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter,
                ulong off, void *data, int len);
@@ -1471,15 +1465,16 @@ void netxen_initialize_adapter_ops(struct netxen_adapter *adapter);
 int netxen_init_firmware(struct netxen_adapter *adapter);
 void netxen_nic_clear_stats(struct netxen_adapter *adapter);
 void netxen_watchdog_task(struct work_struct *work);
-void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx,
-                           u32 ringid);
+void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid,
+               struct nx_host_rds_ring *rds_ring);
 int netxen_process_cmd_ring(struct netxen_adapter *adapter);
-u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctx, int max);
+int netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max);
 void netxen_p2_nic_set_multi(struct net_device *netdev);
 void netxen_p3_nic_set_multi(struct net_device *netdev);
 void netxen_p3_free_mac_list(struct netxen_adapter *adapter);
 int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32);
 int netxen_config_intr_coalesce(struct netxen_adapter *adapter);
+int netxen_config_rss(struct netxen_adapter *adapter, int enable);
 
 int nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu);
 int netxen_nic_change_mtu(struct net_device *netdev, int new_mtu);
@@ -1595,7 +1590,6 @@ dma_watchdog_wakeup(struct netxen_adapter *adapter)
 }
 
 
-int netxen_is_flash_supported(struct netxen_adapter *adapter);
 int netxen_get_flash_mac_addr(struct netxen_adapter *adapter, __le64 *mac);
 int netxen_p3_get_mac_addr(struct netxen_adapter *adapter, __le64 *mac);
 extern void netxen_change_ringparam(struct netxen_adapter *adapter);
index 746bdb4704181e94494b2ea694c4d4c9e431fe19..9234473bc08a752bfb06a45d740e30d198e9f091 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 - 2008 NetXen, Inc.
+ * Copyright (C) 2003 - 2009 NetXen, Inc.
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
@@ -22,9 +22,9 @@
  *
  * Contact Information:
  *    info@netxen.com
- * NetXen,
- * 3965 Freedom Circle, Fourth floor,
- * Santa Clara, CA 95054
+ * NetXen Inc,
+ * 18922 Forge Drive
+ * Cupertino, CA 95014-0701
  *
  */
 
@@ -141,7 +141,7 @@ int
 nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu)
 {
        u32 rcode = NX_RCODE_SUCCESS;
-       struct netxen_recv_context *recv_ctx = &adapter->recv_ctx[0];
+       struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
 
        if (recv_ctx->state == NX_HOST_CTX_STATE_ACTIVE)
                rcode = netxen_issue_cmd(adapter,
@@ -169,6 +169,7 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter)
        nx_cardrsp_rds_ring_t *prsp_rds;
        nx_cardrsp_sds_ring_t *prsp_sds;
        struct nx_host_rds_ring *rds_ring;
+       struct nx_host_sds_ring *sds_ring;
 
        dma_addr_t hostrq_phys_addr, cardrsp_phys_addr;
        u64 phys_addr;
@@ -179,11 +180,10 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter)
 
        int err;
 
-       struct netxen_recv_context *recv_ctx = &adapter->recv_ctx[0];
+       struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
 
-       /* only one sds ring for now */
        nrds_rings = adapter->max_rds_rings;
-       nsds_rings = 1;
+       nsds_rings = adapter->max_sds_rings;
 
        rq_size =
                SIZEOF_HOSTRQ_RX(nx_hostrq_rx_ctx_t, nrds_rings, nsds_rings);
@@ -231,7 +231,7 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter)
                rds_ring = &recv_ctx->rds_rings[i];
 
                prq_rds[i].host_phys_addr = cpu_to_le64(rds_ring->phys_addr);
-               prq_rds[i].ring_size = cpu_to_le32(rds_ring->max_rx_desc_count);
+               prq_rds[i].ring_size = cpu_to_le32(rds_ring->num_desc);
                prq_rds[i].ring_kind = cpu_to_le32(i);
                prq_rds[i].buff_size = cpu_to_le64(rds_ring->dma_size);
        }
@@ -239,11 +239,14 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter)
        prq_sds = (nx_hostrq_sds_ring_t *)(prq->data +
                        le32_to_cpu(prq->sds_ring_offset));
 
-       prq_sds[0].host_phys_addr =
-               cpu_to_le64(recv_ctx->rcv_status_desc_phys_addr);
-       prq_sds[0].ring_size = cpu_to_le32(adapter->max_rx_desc_count);
-       /* only one msix vector for now */
-       prq_sds[0].msi_index = cpu_to_le16(0);
+       for (i = 0; i < nsds_rings; i++) {
+
+               sds_ring = &recv_ctx->sds_rings[i];
+
+               prq_sds[i].host_phys_addr = cpu_to_le64(sds_ring->phys_addr);
+               prq_sds[i].ring_size = cpu_to_le32(sds_ring->num_desc);
+               prq_sds[i].msi_index = cpu_to_le16(i);
+       }
 
        phys_addr = hostrq_phys_addr;
        err = netxen_issue_cmd(adapter,
@@ -272,11 +275,16 @@ nx_fw_cmd_create_rx_ctx(struct netxen_adapter *adapter)
 
        prsp_sds = ((nx_cardrsp_sds_ring_t *)
                        &prsp->data[le32_to_cpu(prsp->sds_ring_offset)]);
-       reg = le32_to_cpu(prsp_sds[0].host_consumer_crb);
-       recv_ctx->crb_sts_consumer = NETXEN_NIC_REG(reg - 0x200);
 
-       reg = le32_to_cpu(prsp_sds[0].interrupt_crb);
-       adapter->crb_intr_mask = NETXEN_NIC_REG(reg - 0x200);
+       for (i = 0; i < le16_to_cpu(prsp->num_sds_rings); i++) {
+               sds_ring = &recv_ctx->sds_rings[i];
+
+               reg = le32_to_cpu(prsp_sds[i].host_consumer_crb);
+               sds_ring->crb_sts_consumer = NETXEN_NIC_REG(reg - 0x200);
+
+               reg = le32_to_cpu(prsp_sds[i].interrupt_crb);
+               sds_ring->crb_intr_mask = NETXEN_NIC_REG(reg - 0x200);
+       }
 
        recv_ctx->state = le32_to_cpu(prsp->host_ctx_state);
        recv_ctx->context_id = le16_to_cpu(prsp->context_id);
@@ -292,7 +300,7 @@ out_free_rq:
 static void
 nx_fw_cmd_destroy_rx_ctx(struct netxen_adapter *adapter)
 {
-       struct netxen_recv_context *recv_ctx = &adapter->recv_ctx[0];
+       struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
 
        if (netxen_issue_cmd(adapter,
                        adapter->ahw.pci_func,
@@ -362,7 +370,7 @@ nx_fw_cmd_create_tx_ctx(struct netxen_adapter *adapter)
        prq_cds->host_phys_addr =
                cpu_to_le64(adapter->ahw.cmd_desc_phys_addr);
 
-       prq_cds->ring_size = cpu_to_le32(adapter->max_tx_desc_count);
+       prq_cds->ring_size = cpu_to_le32(adapter->num_txd);
 
        phys_addr = rq_phys_addr;
        err = netxen_issue_cmd(adapter,
@@ -488,30 +496,28 @@ netxen_init_old_ctx(struct netxen_adapter *adapter)
 {
        struct netxen_recv_context *recv_ctx;
        struct nx_host_rds_ring *rds_ring;
-       int ctx, ring;
+       struct nx_host_sds_ring *sds_ring;
+       int ring;
        int func_id = adapter->portnum;
 
        adapter->ctx_desc->cmd_ring_addr =
                cpu_to_le64(adapter->ahw.cmd_desc_phys_addr);
        adapter->ctx_desc->cmd_ring_size =
-               cpu_to_le32(adapter->max_tx_desc_count);
+               cpu_to_le32(adapter->num_txd);
 
-       for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
-               recv_ctx = &adapter->recv_ctx[ctx];
+       recv_ctx = &adapter->recv_ctx;
 
-               for (ring = 0; ring < adapter->max_rds_rings; ring++) {
-                       rds_ring = &recv_ctx->rds_rings[ring];
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               rds_ring = &recv_ctx->rds_rings[ring];
 
-                       adapter->ctx_desc->rcv_ctx[ring].rcv_ring_addr =
-                               cpu_to_le64(rds_ring->phys_addr);
-                       adapter->ctx_desc->rcv_ctx[ring].rcv_ring_size =
-                               cpu_to_le32(rds_ring->max_rx_desc_count);
-               }
-               adapter->ctx_desc->sts_ring_addr =
-                       cpu_to_le64(recv_ctx->rcv_status_desc_phys_addr);
-               adapter->ctx_desc->sts_ring_size =
-                       cpu_to_le32(adapter->max_rx_desc_count);
+               adapter->ctx_desc->rcv_ctx[ring].rcv_ring_addr =
+                       cpu_to_le64(rds_ring->phys_addr);
+               adapter->ctx_desc->rcv_ctx[ring].rcv_ring_size =
+                       cpu_to_le32(rds_ring->num_desc);
        }
+       sds_ring = &recv_ctx->sds_rings[0];
+       adapter->ctx_desc->sts_ring_addr = cpu_to_le64(sds_ring->phys_addr);
+       adapter->ctx_desc->sts_ring_size = cpu_to_le32(sds_ring->num_desc);
 
        adapter->pci_write_normalize(adapter, CRB_CTX_ADDR_REG_LO(func_id),
                        lower32(adapter->ctx_desc_phys_addr));
@@ -533,9 +539,13 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter)
        u32 state = 0;
        void *addr;
        int err = 0;
-       int ctx, ring;
+       int ring;
        struct netxen_recv_context *recv_ctx;
        struct nx_host_rds_ring *rds_ring;
+       struct nx_host_sds_ring *sds_ring;
+
+       struct pci_dev *pdev = adapter->pdev;
+       struct net_device *netdev = adapter->netdev;
 
        err = netxen_receive_peg_ready(adapter);
        if (err) {
@@ -544,12 +554,12 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter)
                return err;
        }
 
-       addr = pci_alloc_consistent(adapter->pdev,
+       addr = pci_alloc_consistent(pdev,
                        sizeof(struct netxen_ring_ctx) + sizeof(uint32_t),
                        &adapter->ctx_desc_phys_addr);
 
        if (addr == NULL) {
-               DPRINTK(ERR, "failed to allocate hw context\n");
+               dev_err(&pdev->dev, "failed to allocate hw context\n");
                return -ENOMEM;
        }
        memset(addr, 0, sizeof(struct netxen_ring_ctx));
@@ -562,61 +572,57 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter)
                (__le32 *)(((char *)addr) + sizeof(struct netxen_ring_ctx));
 
        /* cmd desc ring */
-       addr = pci_alloc_consistent(adapter->pdev,
-                       sizeof(struct cmd_desc_type0) *
-                       adapter->max_tx_desc_count,
+       addr = pci_alloc_consistent(pdev,
+                       TX_DESC_RINGSIZE(adapter),
                        &hw->cmd_desc_phys_addr);
 
        if (addr == NULL) {
-               printk(KERN_ERR "%s failed to allocate tx desc ring\n",
-                               netxen_nic_driver_name);
+               dev_err(&pdev->dev, "%s: failed to allocate tx desc ring\n",
+                               netdev->name);
                return -ENOMEM;
        }
 
        hw->cmd_desc_head = (struct cmd_desc_type0 *)addr;
 
-       for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
-               recv_ctx = &adapter->recv_ctx[ctx];
-
-               for (ring = 0; ring < adapter->max_rds_rings; ring++) {
-                       /* rx desc ring */
-                       rds_ring = &recv_ctx->rds_rings[ring];
-                       addr = pci_alloc_consistent(adapter->pdev,
-                                       RCV_DESC_RINGSIZE,
-                                       &rds_ring->phys_addr);
-                       if (addr == NULL) {
-                               printk(KERN_ERR "%s failed to allocate rx "
-                                       "desc ring[%d]\n",
-                                       netxen_nic_driver_name, ring);
-                               err = -ENOMEM;
-                               goto err_out_free;
-                       }
-                       rds_ring->desc_head = (struct rcv_desc *)addr;
-
-                       if (adapter->fw_major < 4)
-                               rds_ring->crb_rcv_producer =
-                                       recv_crb_registers[adapter->portnum].
-                                       crb_rcv_producer[ring];
-               }
+       recv_ctx = &adapter->recv_ctx;
 
-               /* status desc ring */
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               rds_ring = &recv_ctx->rds_rings[ring];
                addr = pci_alloc_consistent(adapter->pdev,
-                               STATUS_DESC_RINGSIZE,
-                               &recv_ctx->rcv_status_desc_phys_addr);
+                               RCV_DESC_RINGSIZE(rds_ring),
+                               &rds_ring->phys_addr);
                if (addr == NULL) {
-                       printk(KERN_ERR "%s failed to allocate sts desc ring\n",
-                                       netxen_nic_driver_name);
+                       dev_err(&pdev->dev,
+                               "%s: failed to allocate rds ring [%d]\n",
+                               netdev->name, ring);
                        err = -ENOMEM;
                        goto err_out_free;
                }
-               recv_ctx->rcv_status_desc_head = (struct status_desc *)addr;
+               rds_ring->desc_head = (struct rcv_desc *)addr;
 
                if (adapter->fw_major < 4)
-                       recv_ctx->crb_sts_consumer =
+                       rds_ring->crb_rcv_producer =
                                recv_crb_registers[adapter->portnum].
-                               crb_sts_consumer;
+                               crb_rcv_producer[ring];
        }
 
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+
+               addr = pci_alloc_consistent(adapter->pdev,
+                               STATUS_DESC_RINGSIZE(sds_ring),
+                               &sds_ring->phys_addr);
+               if (addr == NULL) {
+                       dev_err(&pdev->dev,
+                               "%s: failed to allocate sds ring [%d]\n",
+                               netdev->name, ring);
+                       err = -ENOMEM;
+                       goto err_out_free;
+               }
+               sds_ring->desc_head = (struct status_desc *)addr;
+       }
+
+
        if (adapter->fw_major >= 4) {
                adapter->intr_scheme = INTR_SCHEME_PERPORT;
                adapter->msi_mode = MSI_MODE_MULTIFUNC;
@@ -628,12 +634,16 @@ int netxen_alloc_hw_resources(struct netxen_adapter *adapter)
                if (err)
                        goto err_out_free;
        } else {
+               sds_ring = &recv_ctx->sds_rings[0];
+               sds_ring->crb_sts_consumer =
+                       recv_crb_registers[adapter->portnum].crb_sts_consumer;
 
                adapter->intr_scheme = adapter->pci_read_normalize(adapter,
                                CRB_NIC_CAPABILITIES_FW);
                adapter->msi_mode = adapter->pci_read_normalize(adapter,
                                CRB_NIC_MSI_MODE_FW);
-               adapter->crb_intr_mask = sw_int_mask[adapter->portnum];
+               recv_ctx->sds_rings[0].crb_intr_mask =
+                               sw_int_mask[adapter->portnum];
 
                err = netxen_init_old_ctx(adapter);
                if (err) {
@@ -654,7 +664,8 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter)
 {
        struct netxen_recv_context *recv_ctx;
        struct nx_host_rds_ring *rds_ring;
-       int ctx, ring;
+       struct nx_host_sds_ring *sds_ring;
+       int ring;
 
        if (adapter->fw_major >= 4) {
                nx_fw_cmd_destroy_tx_ctx(adapter);
@@ -673,32 +684,34 @@ void netxen_free_hw_resources(struct netxen_adapter *adapter)
        if (adapter->ahw.cmd_desc_head != NULL) {
                pci_free_consistent(adapter->pdev,
                                sizeof(struct cmd_desc_type0) *
-                               adapter->max_tx_desc_count,
+                               adapter->num_txd,
                                adapter->ahw.cmd_desc_head,
                                adapter->ahw.cmd_desc_phys_addr);
                adapter->ahw.cmd_desc_head = NULL;
        }
 
-       for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
-               recv_ctx = &adapter->recv_ctx[ctx];
-               for (ring = 0; ring < adapter->max_rds_rings; ring++) {
-                       rds_ring = &recv_ctx->rds_rings[ring];
-
-                       if (rds_ring->desc_head != NULL) {
-                               pci_free_consistent(adapter->pdev,
-                                               RCV_DESC_RINGSIZE,
-                                               rds_ring->desc_head,
-                                               rds_ring->phys_addr);
-                               rds_ring->desc_head = NULL;
-                       }
+       recv_ctx = &adapter->recv_ctx;
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               rds_ring = &recv_ctx->rds_rings[ring];
+
+               if (rds_ring->desc_head != NULL) {
+                       pci_free_consistent(adapter->pdev,
+                                       RCV_DESC_RINGSIZE(rds_ring),
+                                       rds_ring->desc_head,
+                                       rds_ring->phys_addr);
+                       rds_ring->desc_head = NULL;
                }
+       }
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
 
-               if (recv_ctx->rcv_status_desc_head != NULL) {
+               if (sds_ring->desc_head != NULL) {
                        pci_free_consistent(adapter->pdev,
-                                       STATUS_DESC_RINGSIZE,
-                                       recv_ctx->rcv_status_desc_head,
-                                       recv_ctx->rcv_status_desc_phys_addr);
-                       recv_ctx->rcv_status_desc_head = NULL;
+                               STATUS_DESC_RINGSIZE(sds_ring),
+                               sds_ring->desc_head,
+                               sds_ring->phys_addr);
+                       sds_ring->desc_head = NULL;
                }
        }
 }
index 0894a7be02259cdd3e495405558a23ee7a39e5de..a677ff8951844e3451a6f5d6b93d67aa38322796 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 - 2006 NetXen, Inc.
+ * Copyright (C) 2003 - 2009 NetXen, Inc.
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  *
  * Contact Information:
  *    info@netxen.com
- * NetXen,
- * 3965 Freedom Circle, Fourth floor,
- * Santa Clara, CA 95054
- *
- *
- * ethtool support for netxen nic
+ * NetXen Inc,
+ * 18922 Forge Drive
+ * Cupertino, CA 95014-0701
  *
  */
 
@@ -118,10 +115,9 @@ static int
 netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
 {
        struct netxen_adapter *adapter = netdev_priv(dev);
-       struct netxen_board_info *boardinfo = &adapter->ahw.boardcfg;
 
        /* read which mode */
-       if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
+       if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
                ecmd->supported = (SUPPORTED_10baseT_Half |
                                   SUPPORTED_10baseT_Full |
                                   SUPPORTED_100baseT_Half |
@@ -140,7 +136,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
                ecmd->duplex = adapter->link_duplex;
                ecmd->autoneg = adapter->link_autoneg;
 
-       } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
+       } else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) {
                u32 val;
 
                adapter->hw_read_wx(adapter, NETXEN_PORT_MODE_ADDR, &val, 4);
@@ -172,7 +168,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
        ecmd->phy_address = adapter->physical_port;
        ecmd->transceiver = XCVR_EXTERNAL;
 
-       switch ((netxen_brdtype_t) boardinfo->board_type) {
+       switch ((netxen_brdtype_t)adapter->ahw.board_type) {
        case NETXEN_BRDTYPE_P2_SB35_4G:
        case NETXEN_BRDTYPE_P2_SB31_2G:
        case NETXEN_BRDTYPE_P3_REF_QG:
@@ -188,7 +184,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
                ecmd->supported |= SUPPORTED_TP;
                ecmd->advertising |= ADVERTISED_TP;
                ecmd->port = PORT_TP;
-               ecmd->autoneg = (boardinfo->board_type ==
+               ecmd->autoneg = (adapter->ahw.board_type ==
                                 NETXEN_BRDTYPE_P2_SB31_10G_CX4) ?
                    (AUTONEG_DISABLE) : (adapter->link_autoneg);
                break;
@@ -215,7 +211,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
                ecmd->autoneg = AUTONEG_DISABLE;
                break;
        case NETXEN_BRDTYPE_P3_10G_TP:
-               if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
+               if (adapter->ahw.port_type == NETXEN_NIC_XGBE) {
                        ecmd->autoneg = AUTONEG_DISABLE;
                        ecmd->supported |= (SUPPORTED_FIBRE | SUPPORTED_TP);
                        ecmd->advertising |=
@@ -231,7 +227,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
                break;
        default:
                printk(KERN_ERR "netxen-nic: Unsupported board model %d\n",
-                      (netxen_brdtype_t) boardinfo->board_type);
+                      (netxen_brdtype_t)adapter->ahw.board_type);
                return -EIO;
        }
 
@@ -245,7 +241,7 @@ netxen_nic_set_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
        __u32 status;
 
        /* read which mode */
-       if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
+       if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
                /* autonegotiation */
                if (adapter->phy_write
                    && adapter->phy_write(adapter,
@@ -433,7 +429,7 @@ static u32 netxen_nic_test_link(struct net_device *dev)
        int val;
 
        /* read which mode */
-       if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
+       if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
                if (adapter->phy_read
                    && adapter->phy_read(adapter,
                                         NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
@@ -443,7 +439,7 @@ static u32 netxen_nic_test_link(struct net_device *dev)
                        val = netxen_get_phy_link(status);
                        return !val;
                }
-       } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
+       } else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) {
                val = adapter->pci_read_normalize(adapter, CRB_XG_STATE);
                return (val == XG_LINK_UP) ? 0 : 1;
        }
@@ -473,95 +469,20 @@ netxen_nic_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        return 0;
 }
 
-#if 0
-static int
-netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
-                       u8 * bytes)
-{
-       struct netxen_adapter *adapter = netdev_priv(dev);
-       int offset = eeprom->offset;
-       static int flash_start;
-       static int ready_to_flash;
-       int ret;
-
-       if (flash_start == 0) {
-               netxen_halt_pegs(adapter);
-               ret = netxen_flash_unlock(adapter);
-               if (ret < 0) {
-                       printk(KERN_ERR "%s: Flash unlock failed.\n",
-                               netxen_nic_driver_name);
-                       return ret;
-               }
-               printk(KERN_INFO "%s: flash unlocked. \n",
-                       netxen_nic_driver_name);
-               ret = netxen_flash_erase_secondary(adapter);
-               if (ret != FLASH_SUCCESS) {
-                       printk(KERN_ERR "%s: Flash erase failed.\n",
-                               netxen_nic_driver_name);
-                       return ret;
-               }
-               printk(KERN_INFO "%s: secondary flash erased successfully.\n",
-                       netxen_nic_driver_name);
-               flash_start = 1;
-               return 0;
-       }
-
-       if (offset == NETXEN_BOOTLD_START) {
-               ret = netxen_flash_erase_primary(adapter);
-               if (ret != FLASH_SUCCESS) {
-                       printk(KERN_ERR "%s: Flash erase failed.\n",
-                               netxen_nic_driver_name);
-                       return ret;
-               }
-
-               ret = netxen_rom_se(adapter, NETXEN_USER_START);
-               if (ret != FLASH_SUCCESS)
-                       return ret;
-               ret = netxen_rom_se(adapter, NETXEN_FIXED_START);
-               if (ret != FLASH_SUCCESS)
-                       return ret;
-
-               printk(KERN_INFO "%s: primary flash erased successfully\n",
-                       netxen_nic_driver_name);
-
-               ret = netxen_backup_crbinit(adapter);
-               if (ret != FLASH_SUCCESS) {
-                       printk(KERN_ERR "%s: CRBinit backup failed.\n",
-                               netxen_nic_driver_name);
-                       return ret;
-               }
-               printk(KERN_INFO "%s: CRBinit backup done.\n",
-                       netxen_nic_driver_name);
-               ready_to_flash = 1;
-       }
-
-       if (!ready_to_flash) {
-               printk(KERN_ERR "%s: Invalid write sequence, returning...\n",
-                       netxen_nic_driver_name);
-               return -EINVAL;
-       }
-
-       return netxen_rom_fast_write_words(adapter, offset, bytes, eeprom->len);
-}
-#endif /* 0 */
-
 static void
 netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam *ring)
 {
        struct netxen_adapter *adapter = netdev_priv(dev);
-       int i;
 
        ring->rx_pending = 0;
        ring->rx_jumbo_pending = 0;
-       for (i = 0; i < MAX_RCV_CTX; ++i) {
-               ring->rx_pending += adapter->recv_ctx[i].
-                   rds_rings[RCV_DESC_NORMAL_CTXID].max_rx_desc_count;
-               ring->rx_jumbo_pending += adapter->recv_ctx[i].
-                   rds_rings[RCV_DESC_JUMBO_CTXID].max_rx_desc_count;
-       }
-       ring->tx_pending = adapter->max_tx_desc_count;
+       ring->rx_pending += adapter->recv_ctx.
+               rds_rings[RCV_RING_NORMAL].num_desc;
+       ring->rx_jumbo_pending += adapter->recv_ctx.
+               rds_rings[RCV_RING_JUMBO].num_desc;
+       ring->tx_pending = adapter->num_txd;
 
-       if (adapter->ahw.board_type == NETXEN_NIC_GBE)
+       if (adapter->ahw.port_type == NETXEN_NIC_GBE)
                ring->rx_max_pending = MAX_RCV_DESCRIPTORS_1G;
        else
                ring->rx_max_pending = MAX_RCV_DESCRIPTORS_10G;
@@ -579,7 +500,7 @@ netxen_nic_get_pauseparam(struct net_device *dev,
        __u32 val;
        int port = adapter->physical_port;
 
-       if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
+       if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
                if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
                        return;
                /* get flow control settings */
@@ -602,7 +523,7 @@ netxen_nic_get_pauseparam(struct net_device *dev,
                                pause->tx_pause = !(netxen_gb_get_gb3_mask(val));
                                break;
                }
-       } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
+       } else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) {
                if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
                        return;
                pause->rx_pause = 1;
@@ -613,7 +534,7 @@ netxen_nic_get_pauseparam(struct net_device *dev,
                        pause->tx_pause = !(netxen_xg_get_xg1_mask(val));
        } else {
                printk(KERN_ERR"%s: Unknown board type: %x\n",
-                               netxen_nic_driver_name, adapter->ahw.board_type);
+                               netxen_nic_driver_name, adapter->ahw.port_type);
        }
 }
 
@@ -625,7 +546,7 @@ netxen_nic_set_pauseparam(struct net_device *dev,
        __u32 val;
        int port = adapter->physical_port;
        /* read mode */
-       if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
+       if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
                if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
                        return -EIO;
                /* set flow control */
@@ -669,7 +590,7 @@ netxen_nic_set_pauseparam(struct net_device *dev,
                                break;
                }
                netxen_nic_write_w0(adapter, NETXEN_NIU_GB_PAUSE_CTL, val);
-       } else if (adapter->ahw.board_type == NETXEN_NIC_XGBE) {
+       } else if (adapter->ahw.port_type == NETXEN_NIC_XGBE) {
                if ((port < 0) || (port > NETXEN_NIU_MAX_XG_PORTS))
                        return -EIO;
                netxen_nic_read_w0(adapter, NETXEN_NIU_XG_PAUSE_CTL, &val);
@@ -688,7 +609,7 @@ netxen_nic_set_pauseparam(struct net_device *dev,
        } else {
                printk(KERN_ERR "%s: Unknown board type: %x\n",
                                netxen_nic_driver_name,
-                               adapter->ahw.board_type);
+                               adapter->ahw.port_type);
        }
        return 0;
 }
@@ -810,6 +731,53 @@ static int netxen_nic_set_tso(struct net_device *dev, u32 data)
        return 0;
 }
 
+static void
+netxen_nic_get_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+       struct netxen_adapter *adapter = netdev_priv(dev);
+       u32 wol_cfg = 0;
+
+       wol->supported = 0;
+       wol->wolopts = 0;
+
+       if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
+               return;
+
+       wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG_NV);
+       if (wol_cfg & (1UL << adapter->portnum))
+               wol->supported |= WAKE_MAGIC;
+
+       wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG);
+       if (wol_cfg & (1UL << adapter->portnum))
+               wol->wolopts |= WAKE_MAGIC;
+}
+
+static int
+netxen_nic_set_wol(struct net_device *dev, struct ethtool_wolinfo *wol)
+{
+       struct netxen_adapter *adapter = netdev_priv(dev);
+       u32 wol_cfg = 0;
+
+       if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
+               return -EOPNOTSUPP;
+
+       if (wol->wolopts & ~WAKE_MAGIC)
+               return -EOPNOTSUPP;
+
+       wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG_NV);
+       if (!(wol_cfg & (1 << adapter->portnum)))
+               return -EOPNOTSUPP;
+
+       wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG);
+       if (wol->wolopts & WAKE_MAGIC)
+               wol_cfg |= 1UL << adapter->portnum;
+       else
+               wol_cfg &= ~(1UL << adapter->portnum);
+       netxen_nic_reg_write(adapter, NETXEN_WOL_CONFIG, wol_cfg);
+
+       return 0;
+}
+
 /*
  * Set the coalescing parameters. Currently only normal is supported.
  * If rx_coalesce_usecs == 0 or rx_max_coalesced_frames == 0 then set the
@@ -906,9 +874,6 @@ struct ethtool_ops netxen_nic_ethtool_ops = {
        .get_link = ethtool_op_get_link,
        .get_eeprom_len = netxen_nic_get_eeprom_len,
        .get_eeprom = netxen_nic_get_eeprom,
-#if 0
-       .set_eeprom = netxen_nic_set_eeprom,
-#endif
        .get_ringparam = netxen_nic_get_ringparam,
        .get_pauseparam = netxen_nic_get_pauseparam,
        .set_pauseparam = netxen_nic_set_pauseparam,
@@ -916,6 +881,8 @@ struct ethtool_ops netxen_nic_ethtool_ops = {
        .set_sg = ethtool_op_set_sg,
        .get_tso = netxen_nic_get_tso,
        .set_tso = netxen_nic_set_tso,
+       .get_wol = netxen_nic_get_wol,
+       .set_wol = netxen_nic_set_wol,
        .self_test = netxen_nic_diag_test,
        .get_strings = netxen_nic_get_strings,
        .get_ethtool_stats = netxen_nic_get_ethtool_stats,
index e80f9e3e59731fb08ccadefa1da9cb9d0a007768..016c62129c766c2cf9ef9415c381fa7eacacbac5 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 - 2006 NetXen, Inc.
+ * Copyright (C) 2003 - 2009 NetXen, Inc.
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  *
  * Contact Information:
  *    info@netxen.com
- * NetXen,
- * 3965 Freedom Circle, Fourth floor,
- * Santa Clara, CA 95054
+ * NetXen Inc,
+ * 18922 Forge Drive
+ * Cupertino, CA 95014-0701
+ *
  */
 
 #ifndef __NETXEN_NIC_HDR_H_
@@ -362,12 +363,6 @@ enum {
 #define NETXEN_HW_CRB_HUB_AGT_ADR_LPC  \
        ((NETXEN_HW_H6_CH_HUB_ADR << 7) | NETXEN_HW_LPC_CRB_AGT_ADR)
 
-/*
- * MAX_RCV_CTX : The number of receive contexts that are available on
- * the phantom.
- */
-#define MAX_RCV_CTX                    1
-
 #define NETXEN_SRE_INT_STATUS          (NETXEN_CRB_SRE + 0x00034)
 #define NETXEN_SRE_PBI_ACTIVE_STATUS   (NETXEN_CRB_SRE + 0x01014)
 #define NETXEN_SRE_L1RE_CTL            (NETXEN_CRB_SRE + 0x03000)
@@ -858,6 +853,12 @@ enum {
 #define NETXEN_PORT_MODE_ADDR          (NETXEN_CAM_RAM(0x24))
 #define NETXEN_WOL_PORT_MODE           (NETXEN_CAM_RAM(0x198))
 
+#define NETXEN_WOL_CONFIG_NV           (NETXEN_CAM_RAM(0x184))
+#define NETXEN_WOL_CONFIG              (NETXEN_CAM_RAM(0x188))
+
+#define NX_PEG_TUNE_MN_PRESENT         0x1
+#define NX_PEG_TUNE_CAPABILITY         (NETXEN_CAM_RAM(0x02c))
+
 #define NETXEN_CAM_RAM_DMA_WATCHDOG_CTRL               (0x14)
 
 #define        ISR_MSI_INT_TRIGGER(FUNC) (NETXEN_PCIX_PS_REG(PCIX_MSI_F(FUNC)))
index 821cff68b3f302c9fa7260215583e113e971b051..5026811c04ced0a1d1d4effe7dc033c47d083dba 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 - 2006 NetXen, Inc.
+ * Copyright (C) 2003 - 2009 NetXen, Inc.
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  *
  * Contact Information:
  *    info@netxen.com
- * NetXen,
- * 3965 Freedom Circle, Fourth floor,
- * Santa Clara, CA 95054
- *
- *
- * Source file for NIC routines to access the Phantom hardware
+ * NetXen Inc,
+ * 18922 Forge Drive
+ * Cupertino, CA 95014-0701
  *
  */
 
@@ -35,7 +32,7 @@
 #include "netxen_nic_hw.h"
 #include "netxen_nic_phan_reg.h"
 
-
+#include <linux/firmware.h>
 #include <net/ip.h>
 
 #define MASK(n) ((1ULL<<(n))-1)
@@ -518,7 +515,7 @@ netxen_send_cmd_descs(struct netxen_adapter *adapter,
                        &cmd_desc_arr[i], sizeof(struct cmd_desc_type0));
 
                producer = get_next_index(producer,
-                               adapter->max_tx_desc_count);
+                               adapter->num_txd);
                i++;
 
        } while (i != nr_elements);
@@ -673,6 +670,53 @@ int netxen_config_intr_coalesce(struct netxen_adapter *adapter)
        return rv;
 }
 
+#define RSS_HASHTYPE_IP_TCP    0x3
+
+int netxen_config_rss(struct netxen_adapter *adapter, int enable)
+{
+       nx_nic_req_t req;
+       u64 word;
+       int i, rv;
+
+       u64 key[] = { 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL,
+                       0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL,
+                       0x255b0ec26d5a56daULL };
+
+
+       memset(&req, 0, sizeof(nx_nic_req_t));
+       req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23);
+
+       word = NX_NIC_H2C_OPCODE_CONFIG_RSS | ((u64)adapter->portnum << 16);
+       req.req_hdr = cpu_to_le64(word);
+
+       /*
+        * RSS request:
+        * bits 3-0: hash_method
+        *      5-4: hash_type_ipv4
+        *      7-6: hash_type_ipv6
+        *        8: enable
+        *        9: use indirection table
+        *    47-10: reserved
+        *    63-48: indirection table mask
+        */
+       word =  ((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 4) |
+               ((u64)(RSS_HASHTYPE_IP_TCP & 0x3) << 6) |
+               ((u64)(enable & 0x1) << 8) |
+               ((0x7ULL) << 48);
+       req.words[0] = cpu_to_le64(word);
+       for (i = 0; i < 5; i++)
+               req.words[i+1] = cpu_to_le64(key[i]);
+
+
+       rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
+       if (rv != 0) {
+               printk(KERN_ERR "%s: could not configure RSS\n",
+                               adapter->netdev->name);
+       }
+
+       return rv;
+}
+
 /*
  * netxen_nic_change_mtu - Change the Maximum Transfer Unit
  * @returns 0 on success, negative on failure
@@ -706,34 +750,11 @@ int netxen_nic_change_mtu(struct net_device *netdev, int mtu)
        return rc;
 }
 
-int netxen_is_flash_supported(struct netxen_adapter *adapter)
-{
-       const int locs[] = { 0, 0x4, 0x100, 0x4000, 0x4128 };
-       int addr, val01, val02, i, j;
-
-       /* if the flash size less than 4Mb, make huge war cry and die */
-       for (j = 1; j < 4; j++) {
-               addr = j * NETXEN_NIC_WINDOW_MARGIN;
-               for (i = 0; i < ARRAY_SIZE(locs); i++) {
-                       if (netxen_rom_fast_read(adapter, locs[i], &val01) == 0
-                           && netxen_rom_fast_read(adapter, (addr + locs[i]),
-                                                   &val02) == 0) {
-                               if (val01 == val02)
-                                       return -1;
-                       } else
-                               return -1;
-               }
-       }
-
-       return 0;
-}
-
 static int netxen_get_flash_block(struct netxen_adapter *adapter, int base,
                                  int size, __le32 * buf)
 {
-       int i, addr;
+       int i, v, addr;
        __le32 *ptr32;
-       u32 v;
 
        addr = base;
        ptr32 = buf;
@@ -936,13 +957,12 @@ netxen_nic_pci_set_crbwindow_2M(struct netxen_adapter *adapter, ulong *off)
        u32 win_read;
 
        adapter->crb_win = CRB_HI(*off);
-       writel(adapter->crb_win, (void *)(CRB_WINDOW_2M +
-               adapter->ahw.pci_base0));
+       writel(adapter->crb_win, (adapter->ahw.pci_base0 + CRB_WINDOW_2M));
        /*
         * Read back value to make sure write has gone through before trying
         * to use it.
         */
-       win_read = readl((void *)(CRB_WINDOW_2M + adapter->ahw.pci_base0));
+       win_read = readl(adapter->ahw.pci_base0 + CRB_WINDOW_2M);
        if (win_read != adapter->crb_win) {
                printk(KERN_ERR "%s: Written crbwin (0x%x) != "
                                "Read crbwin (0x%x), off=0x%lx\n",
@@ -952,24 +972,69 @@ netxen_nic_pci_set_crbwindow_2M(struct netxen_adapter *adapter, ulong *off)
                (ulong)adapter->ahw.pci_base0;
 }
 
-int netxen_load_firmware(struct netxen_adapter *adapter)
+static int
+netxen_do_load_firmware(struct netxen_adapter *adapter, const char *fwname,
+               const struct firmware *fw)
 {
-       int i;
-       u32 data, size = 0;
-       u32 flashaddr = NETXEN_BOOTLD_START;
+       u64 *ptr64;
+       u32 i, flashaddr, size;
+       struct pci_dev *pdev = adapter->pdev;
 
-       size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START)/4;
+       if (fw)
+               dev_info(&pdev->dev, "loading firmware from file %s\n", fwname);
+       else
+               dev_info(&pdev->dev, "loading firmware from flash\n");
 
        if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
                adapter->pci_write_normalize(adapter,
                                NETXEN_ROMUSB_GLB_CAS_RST, 1);
 
-       for (i = 0; i < size; i++) {
-               if (netxen_rom_fast_read(adapter, flashaddr, (int *)&data) != 0)
-                       return -EIO;
+       if (fw) {
+               __le64 data;
+
+               size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 8;
+
+               ptr64 = (u64 *)&fw->data[NETXEN_BOOTLD_START];
+               flashaddr = NETXEN_BOOTLD_START;
+
+               for (i = 0; i < size; i++) {
+                       data = cpu_to_le64(ptr64[i]);
+                       adapter->pci_mem_write(adapter, flashaddr, &data, 8);
+                       flashaddr += 8;
+               }
+
+               size = *(u32 *)&fw->data[NX_FW_SIZE_OFFSET];
+               size = (__force u32)cpu_to_le32(size) / 8;
+
+               ptr64 = (u64 *)&fw->data[NETXEN_IMAGE_START];
+               flashaddr = NETXEN_IMAGE_START;
+
+               for (i = 0; i < size; i++) {
+                       data = cpu_to_le64(ptr64[i]);
+
+                       if (adapter->pci_mem_write(adapter,
+                                               flashaddr, &data, 8))
+                               return -EIO;
+
+                       flashaddr += 8;
+               }
+       } else {
+               u32 data;
+
+               size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 4;
+               flashaddr = NETXEN_BOOTLD_START;
+
+               for (i = 0; i < size; i++) {
+                       if (netxen_rom_fast_read(adapter,
+                                       flashaddr, (int *)&data) != 0)
+                               return -EIO;
+
+                       if (adapter->pci_mem_write(adapter,
+                                               flashaddr, &data, 4))
+                               return -EIO;
 
-               adapter->pci_mem_write(adapter, flashaddr, &data, 4);
-               flashaddr += 4;
+                       flashaddr += 4;
+               }
        }
        msleep(1);
 
@@ -986,12 +1051,135 @@ int netxen_load_firmware(struct netxen_adapter *adapter)
        return 0;
 }
 
+static int
+netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname,
+               const struct firmware *fw)
+{
+       __le32 val;
+       u32 major, minor, build, ver, min_ver, bios;
+       struct pci_dev *pdev = adapter->pdev;
+
+       if (fw->size < NX_FW_MIN_SIZE)
+               return -EINVAL;
+
+       val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_MAGIC_OFFSET]);
+       if ((__force u32)val != NETXEN_BDINFO_MAGIC)
+               return -EINVAL;
+
+       val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_VERSION_OFFSET]);
+       major = (__force u32)val & 0xff;
+       minor = ((__force u32)val >> 8) & 0xff;
+       build = (__force u32)val >> 16;
+
+       if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+               min_ver = NETXEN_VERSION_CODE(4, 0, 216);
+       else
+               min_ver = NETXEN_VERSION_CODE(3, 4, 216);
+
+       ver = NETXEN_VERSION_CODE(major, minor, build);
+
+       if ((major > _NETXEN_NIC_LINUX_MAJOR) || (ver < min_ver)) {
+               dev_err(&pdev->dev,
+                               "%s: firmware version %d.%d.%d unsupported\n",
+                               fwname, major, minor, build);
+               return -EINVAL;
+       }
+
+       val = cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]);
+       netxen_rom_fast_read(adapter, NX_BIOS_VERSION_OFFSET, (int *)&bios);
+       if ((__force u32)val != bios) {
+               dev_err(&pdev->dev, "%s: firmware bios is incompatible\n",
+                               fwname);
+               return -EINVAL;
+       }
+
+       /* check if flashed firmware is newer */
+       if (netxen_rom_fast_read(adapter,
+                       NX_FW_VERSION_OFFSET, (int *)&val))
+               return -EIO;
+       major = (__force u32)val & 0xff;
+       minor = ((__force u32)val >> 8) & 0xff;
+       build = (__force u32)val >> 16;
+       if (NETXEN_VERSION_CODE(major, minor, build) > ver)
+               return -EINVAL;
+
+       netxen_nic_reg_write(adapter, NETXEN_CAM_RAM(0x1fc),
+                       NETXEN_BDINFO_MAGIC);
+       return 0;
+}
+
+static char *fw_name[] = { "nxromimg.bin", "nx3fwct.bin", "nx3fwmn.bin" };
+
+int netxen_load_firmware(struct netxen_adapter *adapter)
+{
+       u32 capability, flashed_ver;
+       const struct firmware *fw;
+       int fw_type;
+       struct pci_dev *pdev = adapter->pdev;
+       int rc = 0;
+
+       if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
+               fw_type = NX_P2_MN_ROMIMAGE;
+               goto request_fw;
+       } else {
+               fw_type = NX_P3_CT_ROMIMAGE;
+               goto request_fw;
+       }
+
+request_mn:
+       capability = 0;
+
+       netxen_rom_fast_read(adapter,
+                       NX_FW_VERSION_OFFSET, (int *)&flashed_ver);
+       if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) {
+               adapter->hw_read_wx(adapter,
+                               NX_PEG_TUNE_CAPABILITY, &capability, 4);
+               if (capability & NX_PEG_TUNE_MN_PRESENT) {
+                       fw_type = NX_P3_MN_ROMIMAGE;
+                       goto request_fw;
+               }
+       }
+
+request_fw:
+       rc = request_firmware(&fw, fw_name[fw_type], &pdev->dev);
+       if (rc != 0) {
+               if (fw_type == NX_P3_CT_ROMIMAGE) {
+                       msleep(1);
+                       goto request_mn;
+               }
+
+               fw = NULL;
+               goto load_fw;
+       }
+
+       rc = netxen_validate_firmware(adapter, fw_name[fw_type], fw);
+       if (rc != 0) {
+               release_firmware(fw);
+
+               if (fw_type == NX_P3_CT_ROMIMAGE) {
+                       msleep(1);
+                       goto request_mn;
+               }
+
+               fw = NULL;
+       }
+
+load_fw:
+       rc = netxen_do_load_firmware(adapter, fw_name[fw_type], fw);
+
+       if (fw)
+               release_firmware(fw);
+       return rc;
+}
+
 int
 netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter,
                ulong off, void *data, int len)
 {
        void __iomem *addr;
 
+       BUG_ON(len != 4);
+
        if (ADDR_IN_WINDOW1(off)) {
                addr = NETXEN_CRB_NORMALIZE(adapter, off);
        } else {                /* Window 0 */
@@ -999,37 +1187,13 @@ netxen_nic_hw_write_wx_128M(struct netxen_adapter *adapter,
                netxen_nic_pci_change_crbwindow_128M(adapter, 0);
        }
 
-       DPRINTK(INFO, "writing to base %lx offset %llx addr %p"
-               " data %llx len %d\n",
-               pci_base(adapter, off), off, addr,
-               *(unsigned long long *)data, len);
        if (!addr) {
                netxen_nic_pci_change_crbwindow_128M(adapter, 1);
                return 1;
        }
 
-       switch (len) {
-       case 1:
-               writeb(*(u8 *) data, addr);
-               break;
-       case 2:
-               writew(*(u16 *) data, addr);
-               break;
-       case 4:
-               writel(*(u32 *) data, addr);
-               break;
-       case 8:
-               writeq(*(u64 *) data, addr);
-               break;
-       default:
-               DPRINTK(INFO,
-                       "writing data %lx to offset %llx, num words=%d\n",
-                       *(unsigned long *)data, off, (len >> 3));
+       writel(*(u32 *) data, addr);
 
-               netxen_nic_hw_block_write64((u64 __iomem *) data, addr,
-                                           (len >> 3));
-               break;
-       }
        if (!ADDR_IN_WINDOW1(off))
                netxen_nic_pci_change_crbwindow_128M(adapter, 1);
 
@@ -1042,6 +1206,8 @@ netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter,
 {
        void __iomem *addr;
 
+       BUG_ON(len != 4);
+
        if (ADDR_IN_WINDOW1(off)) {     /* Window 1 */
                addr = NETXEN_CRB_NORMALIZE(adapter, off);
        } else {                /* Window 0 */
@@ -1049,31 +1215,12 @@ netxen_nic_hw_read_wx_128M(struct netxen_adapter *adapter,
                netxen_nic_pci_change_crbwindow_128M(adapter, 0);
        }
 
-       DPRINTK(INFO, "reading from base %lx offset %llx addr %p\n",
-               pci_base(adapter, off), off, addr);
        if (!addr) {
                netxen_nic_pci_change_crbwindow_128M(adapter, 1);
                return 1;
        }
-       switch (len) {
-       case 1:
-               *(u8 *) data = readb(addr);
-               break;
-       case 2:
-               *(u16 *) data = readw(addr);
-               break;
-       case 4:
-               *(u32 *) data = readl(addr);
-               break;
-       case 8:
-               *(u64 *) data = readq(addr);
-               break;
-       default:
-               netxen_nic_hw_block_read64((u64 __iomem *) data, addr,
-                                          (len >> 3));
-               break;
-       }
-       DPRINTK(INFO, "read %lx\n", *(unsigned long *)data);
+
+       *(u32 *)data = readl(addr);
 
        if (!ADDR_IN_WINDOW1(off))
                netxen_nic_pci_change_crbwindow_128M(adapter, 1);
@@ -1088,6 +1235,8 @@ netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter,
        unsigned long flags = 0;
        int rv;
 
+       BUG_ON(len != 4);
+
        rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off, len);
 
        if (rv == -1) {
@@ -1101,34 +1250,12 @@ netxen_nic_hw_write_wx_2M(struct netxen_adapter *adapter,
                write_lock_irqsave(&adapter->adapter_lock, flags);
                crb_win_lock(adapter);
                netxen_nic_pci_set_crbwindow_2M(adapter, &off);
-       }
-
-       DPRINTK(1, INFO, "write data %lx to offset %llx, len=%d\n",
-                       *(unsigned long *)data, off, len);
-
-       switch (len) {
-       case 1:
-               writeb(*(uint8_t *)data, (void *)off);
-               break;
-       case 2:
-               writew(*(uint16_t *)data, (void *)off);
-               break;
-       case 4:
-               writel(*(uint32_t *)data, (void *)off);
-               break;
-       case 8:
-               writeq(*(uint64_t *)data, (void *)off);
-               break;
-       default:
-               DPRINTK(1, INFO,
-                       "writing data %lx to offset %llx, num words=%d\n",
-                       *(unsigned long *)data, off, (len>>3));
-               break;
-       }
-       if (rv == 1) {
+               writel(*(uint32_t *)data, (void __iomem *)off);
                crb_win_unlock(adapter);
                write_unlock_irqrestore(&adapter->adapter_lock, flags);
-       }
+       } else
+               writel(*(uint32_t *)data, (void __iomem *)off);
+
 
        return 0;
 }
@@ -1140,6 +1267,8 @@ netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter,
        unsigned long flags = 0;
        int rv;
 
+       BUG_ON(len != 4);
+
        rv = netxen_nic_pci_get_crb_addr_2M(adapter, &off, len);
 
        if (rv == -1) {
@@ -1153,33 +1282,11 @@ netxen_nic_hw_read_wx_2M(struct netxen_adapter *adapter,
                write_lock_irqsave(&adapter->adapter_lock, flags);
                crb_win_lock(adapter);
                netxen_nic_pci_set_crbwindow_2M(adapter, &off);
-       }
-
-       DPRINTK(1, INFO, "read from offset %lx, len=%d\n", off, len);
-
-       switch (len) {
-       case 1:
-               *(uint8_t *)data = readb((void *)off);
-               break;
-       case 2:
-               *(uint16_t *)data = readw((void *)off);
-               break;
-       case 4:
-               *(uint32_t *)data = readl((void *)off);
-               break;
-       case 8:
-               *(uint64_t *)data = readq((void *)off);
-               break;
-       default:
-               break;
-       }
-
-       DPRINTK(1, INFO, "read %lx\n", *(unsigned long *)data);
-
-       if (rv == 1) {
+               *(uint32_t *)data = readl((void __iomem *)off);
                crb_win_unlock(adapter);
                write_unlock_irqrestore(&adapter->adapter_lock, flags);
-       }
+       } else
+               *(uint32_t *)data = readl((void __iomem *)off);
 
        return 0;
 }
@@ -1441,10 +1548,9 @@ static int netxen_nic_pci_mem_read_direct(struct netxen_adapter *adapter,
                        u64 off, void *data, int size)
 {
        unsigned long flags;
-       void *addr;
+       void __iomem *addr, *mem_ptr = NULL;
        int ret = 0;
        u64 start;
-       uint8_t *mem_ptr = NULL;
        unsigned long mem_base;
        unsigned long mem_page;
 
@@ -1464,7 +1570,7 @@ static int netxen_nic_pci_mem_read_direct(struct netxen_adapter *adapter,
                return -1;
        }
 
-       addr = (void *)(pci_base_offset(adapter, start));
+       addr = pci_base_offset(adapter, start);
        if (!addr) {
                write_unlock_irqrestore(&adapter->adapter_lock, flags);
                mem_base = pci_resource_start(adapter->pdev, 0);
@@ -1503,7 +1609,6 @@ static int netxen_nic_pci_mem_read_direct(struct netxen_adapter *adapter,
                break;
        }
        write_unlock_irqrestore(&adapter->adapter_lock, flags);
-       DPRINTK(1, INFO, "read %llx\n", *(unsigned long long *)data);
 
        if (mem_ptr)
                iounmap(mem_ptr);
@@ -1515,10 +1620,9 @@ netxen_nic_pci_mem_write_direct(struct netxen_adapter *adapter, u64 off,
                void *data, int size)
 {
        unsigned long flags;
-       void *addr;
+       void __iomem *addr, *mem_ptr = NULL;
        int ret = 0;
        u64 start;
-       uint8_t *mem_ptr = NULL;
        unsigned long mem_base;
        unsigned long mem_page;
 
@@ -1538,7 +1642,7 @@ netxen_nic_pci_mem_write_direct(struct netxen_adapter *adapter, u64 off,
                return -1;
        }
 
-       addr = (void *)(pci_base_offset(adapter, start));
+       addr = pci_base_offset(adapter, start);
        if (!addr) {
                write_unlock_irqrestore(&adapter->adapter_lock, flags);
                mem_base = pci_resource_start(adapter->pdev, 0);
@@ -1575,8 +1679,6 @@ netxen_nic_pci_mem_write_direct(struct netxen_adapter *adapter, u64 off,
                break;
        }
        write_unlock_irqrestore(&adapter->adapter_lock, flags);
-       DPRINTK(1, INFO, "writing data %llx to offset %llx\n",
-                       *(unsigned long long *)data, start);
        if (mem_ptr)
                iounmap(mem_ptr);
        return ret;
@@ -1588,10 +1690,11 @@ int
 netxen_nic_pci_mem_write_128M(struct netxen_adapter *adapter,
                u64 off, void *data, int size)
 {
-       unsigned long   flags, mem_crb;
+       unsigned long   flags;
        int          i, j, ret = 0, loop, sz[2], off0;
        uint32_t      temp;
        uint64_t      off8, tmpw, word[2] = {0, 0};
+       void __iomem *mem_crb;
 
        /*
         * If not MN, go check for MS or invalid.
@@ -1605,7 +1708,7 @@ netxen_nic_pci_mem_write_128M(struct netxen_adapter *adapter,
        sz[0] = (size < (8 - off0)) ? size : (8 - off0);
        sz[1] = size - sz[0];
        loop = ((off0 + size - 1) >> 3) + 1;
-       mem_crb = (unsigned long)pci_base_offset(adapter, NETXEN_CRB_DDR_NET);
+       mem_crb = pci_base_offset(adapter, NETXEN_CRB_DDR_NET);
 
        if ((size != 8) || (off0 != 0))  {
                for (i = 0; i < loop; i++) {
@@ -1643,28 +1746,29 @@ netxen_nic_pci_mem_write_128M(struct netxen_adapter *adapter,
 
        for (i = 0; i < loop; i++) {
                writel((uint32_t)(off8 + (i << 3)),
-                       (void *)(mem_crb+MIU_TEST_AGT_ADDR_LO));
+                       (mem_crb+MIU_TEST_AGT_ADDR_LO));
                writel(0,
-                       (void *)(mem_crb+MIU_TEST_AGT_ADDR_HI));
+                       (mem_crb+MIU_TEST_AGT_ADDR_HI));
                writel(word[i] & 0xffffffff,
-                       (void *)(mem_crb+MIU_TEST_AGT_WRDATA_LO));
+                       (mem_crb+MIU_TEST_AGT_WRDATA_LO));
                writel((word[i] >> 32) & 0xffffffff,
-                       (void *)(mem_crb+MIU_TEST_AGT_WRDATA_HI));
+                       (mem_crb+MIU_TEST_AGT_WRDATA_HI));
                writel(MIU_TA_CTL_ENABLE|MIU_TA_CTL_WRITE,
-                       (void *)(mem_crb+MIU_TEST_AGT_CTRL));
+                       (mem_crb+MIU_TEST_AGT_CTRL));
                writel(MIU_TA_CTL_START|MIU_TA_CTL_ENABLE|MIU_TA_CTL_WRITE,
-                       (void *)(mem_crb+MIU_TEST_AGT_CTRL));
+                       (mem_crb+MIU_TEST_AGT_CTRL));
 
                for (j = 0; j < MAX_CTL_CHECK; j++) {
                        temp = readl(
-                            (void *)(mem_crb+MIU_TEST_AGT_CTRL));
+                            (mem_crb+MIU_TEST_AGT_CTRL));
                        if ((temp & MIU_TA_CTL_BUSY) == 0)
                                break;
                }
 
                if (j >= MAX_CTL_CHECK) {
-                       printk("%s: %s Fail to write through agent\n",
-                                       __func__, netxen_nic_driver_name);
+                       if (printk_ratelimit())
+                               dev_err(&adapter->pdev->dev,
+                                       "failed to write through agent\n");
                        ret = -1;
                        break;
                }
@@ -1679,10 +1783,11 @@ int
 netxen_nic_pci_mem_read_128M(struct netxen_adapter *adapter,
                u64 off, void *data, int size)
 {
-       unsigned long   flags, mem_crb;
+       unsigned long   flags;
        int          i, j = 0, k, start, end, loop, sz[2], off0[2];
        uint32_t      temp;
        uint64_t      off8, val, word[2] = {0, 0};
+       void __iomem *mem_crb;
 
 
        /*
@@ -1697,31 +1802,32 @@ netxen_nic_pci_mem_read_128M(struct netxen_adapter *adapter,
        sz[0] = (size < (8 - off0[0])) ? size : (8 - off0[0]);
        sz[1] = size - sz[0];
        loop = ((off0[0] + size - 1) >> 3) + 1;
-       mem_crb = (unsigned long)pci_base_offset(adapter, NETXEN_CRB_DDR_NET);
+       mem_crb = pci_base_offset(adapter, NETXEN_CRB_DDR_NET);
 
        write_lock_irqsave(&adapter->adapter_lock, flags);
        netxen_nic_pci_change_crbwindow_128M(adapter, 0);
 
        for (i = 0; i < loop; i++) {
                writel((uint32_t)(off8 + (i << 3)),
-                       (void *)(mem_crb+MIU_TEST_AGT_ADDR_LO));
+                       (mem_crb+MIU_TEST_AGT_ADDR_LO));
                writel(0,
-                       (void *)(mem_crb+MIU_TEST_AGT_ADDR_HI));
+                       (mem_crb+MIU_TEST_AGT_ADDR_HI));
                writel(MIU_TA_CTL_ENABLE,
-                       (void *)(mem_crb+MIU_TEST_AGT_CTRL));
+                       (mem_crb+MIU_TEST_AGT_CTRL));
                writel(MIU_TA_CTL_START|MIU_TA_CTL_ENABLE,
-                       (void *)(mem_crb+MIU_TEST_AGT_CTRL));
+                       (mem_crb+MIU_TEST_AGT_CTRL));
 
                for (j = 0; j < MAX_CTL_CHECK; j++) {
                        temp = readl(
-                             (void *)(mem_crb+MIU_TEST_AGT_CTRL));
+                             (mem_crb+MIU_TEST_AGT_CTRL));
                        if ((temp & MIU_TA_CTL_BUSY) == 0)
                                break;
                }
 
                if (j >= MAX_CTL_CHECK) {
-                       printk(KERN_ERR "%s: %s Fail to read through agent\n",
-                                       __func__, netxen_nic_driver_name);
+                       if (printk_ratelimit())
+                               dev_err(&adapter->pdev->dev,
+                                       "failed to read through agent\n");
                        break;
                }
 
@@ -1729,7 +1835,7 @@ netxen_nic_pci_mem_read_128M(struct netxen_adapter *adapter,
                end   = (off0[i] + sz[i] - 1) >> 2;
                for (k = start; k <= end; k++) {
                        word[i] |= ((uint64_t) readl(
-                                   (void *)(mem_crb +
+                                   (mem_crb +
                                    MIU_TEST_AGT_RDDATA(k))) << (32*k));
                }
        }
@@ -1761,7 +1867,6 @@ netxen_nic_pci_mem_read_128M(struct netxen_adapter *adapter,
                *(uint64_t *)data = val;
                break;
        }
-       DPRINTK(1, INFO, "read %llx\n", *(unsigned long long *)data);
        return 0;
 }
 
@@ -1857,8 +1962,9 @@ netxen_nic_pci_mem_write_2M(struct netxen_adapter *adapter,
                }
 
                if (j >= MAX_CTL_CHECK) {
-                       printk(KERN_ERR "%s: Fail to write through agent\n",
-                                       netxen_nic_driver_name);
+                       if (printk_ratelimit())
+                               dev_err(&adapter->pdev->dev,
+                                       "failed to write through agent\n");
                        ret = -1;
                        break;
                }
@@ -1927,8 +2033,9 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter,
                }
 
                if (j >= MAX_CTL_CHECK) {
-                       printk(KERN_ERR "%s: Fail to read through agent\n",
-                                       netxen_nic_driver_name);
+                       if (printk_ratelimit())
+                               dev_err(&adapter->pdev->dev,
+                                       "failed to read through agent\n");
                        break;
                }
 
@@ -1970,7 +2077,6 @@ netxen_nic_pci_mem_read_2M(struct netxen_adapter *adapter,
                *(uint64_t *)data = val;
                break;
        }
-       DPRINTK(1, INFO, "read %llx\n", *(unsigned long long *)data);
        return 0;
 }
 
@@ -2005,62 +2111,46 @@ u32 netxen_nic_pci_read_normalize_2M(struct netxen_adapter *adapter, u64 off)
        return temp;
 }
 
-#if 0
-int
-netxen_nic_erase_pxe(struct netxen_adapter *adapter)
-{
-       if (netxen_rom_fast_write(adapter, NETXEN_PXE_START, 0) == -1) {
-               printk(KERN_ERR "%s: erase pxe failed\n",
-                       netxen_nic_driver_name);
-               return -1;
-       }
-       return 0;
-}
-#endif  /*  0  */
-
 int netxen_nic_get_board_info(struct netxen_adapter *adapter)
 {
-       int rv = 0;
-       int addr = NETXEN_BRDCFG_START;
-       struct netxen_board_info *boardinfo;
-       int index;
-       u32 *ptr32;
-
-       boardinfo = &adapter->ahw.boardcfg;
-       ptr32 = (u32 *) boardinfo;
-
-       for (index = 0; index < sizeof(struct netxen_board_info) / sizeof(u32);
-            index++) {
-               if (netxen_rom_fast_read(adapter, addr, ptr32) == -1) {
-                       return -EIO;
-               }
-               ptr32++;
-               addr += sizeof(u32);
-       }
-       if (boardinfo->magic != NETXEN_BDINFO_MAGIC) {
-               printk("%s: ERROR reading %s board config."
-                      " Read %x, expected %x\n", netxen_nic_driver_name,
-                      netxen_nic_driver_name,
-                      boardinfo->magic, NETXEN_BDINFO_MAGIC);
-               rv = -1;
-       }
-       if (boardinfo->header_version != NETXEN_BDINFO_VERSION) {
-               printk("%s: Unknown board config version."
-                      " Read %x, expected %x\n", netxen_nic_driver_name,
-                      boardinfo->header_version, NETXEN_BDINFO_VERSION);
-               rv = -1;
+       int offset, board_type, magic, header_version;
+       struct pci_dev *pdev = adapter->pdev;
+
+       offset = NETXEN_BRDCFG_START +
+               offsetof(struct netxen_board_info, magic);
+       if (netxen_rom_fast_read(adapter, offset, &magic))
+               return -EIO;
+
+       offset = NETXEN_BRDCFG_START +
+               offsetof(struct netxen_board_info, header_version);
+       if (netxen_rom_fast_read(adapter, offset, &header_version))
+               return -EIO;
+
+       if (magic != NETXEN_BDINFO_MAGIC ||
+                       header_version != NETXEN_BDINFO_VERSION) {
+               dev_err(&pdev->dev,
+                       "invalid board config, magic=%08x, version=%08x\n",
+                       magic, header_version);
+               return -EIO;
        }
 
-       if (boardinfo->board_type == NETXEN_BRDTYPE_P3_4_GB_MM) {
+       offset = NETXEN_BRDCFG_START +
+               offsetof(struct netxen_board_info, board_type);
+       if (netxen_rom_fast_read(adapter, offset, &board_type))
+               return -EIO;
+
+       adapter->ahw.board_type = board_type;
+
+       if (board_type == NETXEN_BRDTYPE_P3_4_GB_MM) {
                u32 gpio = netxen_nic_reg_read(adapter,
                                NETXEN_ROMUSB_GLB_PAD_GPIO_I);
                if ((gpio & 0x8000) == 0)
-                       boardinfo->board_type = NETXEN_BRDTYPE_P3_10G_TP;
+                       board_type = NETXEN_BRDTYPE_P3_10G_TP;
        }
 
-       switch ((netxen_brdtype_t) boardinfo->board_type) {
+       switch ((netxen_brdtype_t)board_type) {
        case NETXEN_BRDTYPE_P2_SB35_4G:
-               adapter->ahw.board_type = NETXEN_NIC_GBE;
+               adapter->ahw.port_type = NETXEN_NIC_GBE;
                break;
        case NETXEN_BRDTYPE_P2_SB31_10G:
        case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ:
@@ -2076,7 +2166,7 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter)
        case NETXEN_BRDTYPE_P3_10G_SFP_QT:
        case NETXEN_BRDTYPE_P3_10G_XFP:
        case NETXEN_BRDTYPE_P3_10000_BASE_T:
-               adapter->ahw.board_type = NETXEN_NIC_XGBE;
+               adapter->ahw.port_type = NETXEN_NIC_XGBE;
                break;
        case NETXEN_BRDTYPE_P1_BD:
        case NETXEN_BRDTYPE_P1_SB:
@@ -2085,20 +2175,19 @@ int netxen_nic_get_board_info(struct netxen_adapter *adapter)
        case NETXEN_BRDTYPE_P3_REF_QG:
        case NETXEN_BRDTYPE_P3_4_GB:
        case NETXEN_BRDTYPE_P3_4_GB_MM:
-               adapter->ahw.board_type = NETXEN_NIC_GBE;
+               adapter->ahw.port_type = NETXEN_NIC_GBE;
                break;
        case NETXEN_BRDTYPE_P3_10G_TP:
-               adapter->ahw.board_type = (adapter->portnum < 2) ?
+               adapter->ahw.port_type = (adapter->portnum < 2) ?
                        NETXEN_NIC_XGBE : NETXEN_NIC_GBE;
                break;
        default:
-               printk("%s: Unknown(%x)\n", netxen_nic_driver_name,
-                      boardinfo->board_type);
-               rv = -ENODEV;
+               dev_err(&pdev->dev, "unknown board type %x\n", board_type);
+               adapter->ahw.port_type = NETXEN_NIC_XGBE;
                break;
        }
 
-       return rv;
+       return 0;
 }
 
 /* NIU access sections */
@@ -2144,7 +2233,7 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter)
                return;
        }
 
-       if (adapter->ahw.board_type == NETXEN_NIC_GBE) {
+       if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
                adapter->hw_read_wx(adapter,
                                NETXEN_PORT_MODE_ADDR, &port_mode, 4);
                if (port_mode == NETXEN_PORT_MODE_802_3_AP) {
@@ -2199,32 +2288,27 @@ void netxen_nic_set_link_parameters(struct netxen_adapter *adapter)
        }
 }
 
-void netxen_nic_flash_print(struct netxen_adapter *adapter)
+void netxen_nic_get_firmware_info(struct netxen_adapter *adapter)
 {
-       u32 fw_major = 0;
-       u32 fw_minor = 0;
-       u32 fw_build = 0;
+       u32 fw_major, fw_minor, fw_build;
        char brd_name[NETXEN_MAX_SHORT_NAME];
        char serial_num[32];
-       int i, addr;
-       __le32 *ptr32;
-
-       struct netxen_board_info *board_info = &(adapter->ahw.boardcfg);
+       int i, addr, val;
+       int *ptr32;
+       struct pci_dev *pdev = adapter->pdev;
 
        adapter->driver_mismatch = 0;
 
-       ptr32 = (u32 *)&serial_num;
+       ptr32 = (int *)&serial_num;
        addr = NETXEN_USER_START +
               offsetof(struct netxen_new_user_info, serial_num);
        for (i = 0; i < 8; i++) {
-               if (netxen_rom_fast_read(adapter, addr, ptr32) == -1) {
-                       printk("%s: ERROR reading %s board userarea.\n",
-                              netxen_nic_driver_name,
-                              netxen_nic_driver_name);
+               if (netxen_rom_fast_read(adapter, addr, &val) == -1) {
+                       dev_err(&pdev->dev, "error reading board info\n");
                        adapter->driver_mismatch = 1;
                        return;
                }
-               ptr32++;
+               ptr32[i] = cpu_to_le32(val);
                addr += sizeof(u32);
        }
 
@@ -2233,23 +2317,48 @@ void netxen_nic_flash_print(struct netxen_adapter *adapter)
        adapter->hw_read_wx(adapter, NETXEN_FW_VERSION_SUB, &fw_build, 4);
 
        adapter->fw_major = fw_major;
+       adapter->fw_version = NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build);
 
        if (adapter->portnum == 0) {
-               get_brd_name_by_type(board_info->board_type, brd_name);
+               get_brd_name_by_type(adapter->ahw.board_type, brd_name);
 
                printk(KERN_INFO "NetXen %s Board S/N %s  Chip rev 0x%x\n",
                                brd_name, serial_num, adapter->ahw.revision_id);
-               printk(KERN_INFO "NetXen Firmware version %d.%d.%d\n",
-                               fw_major, fw_minor, fw_build);
        }
 
-       if (NETXEN_VERSION_CODE(fw_major, fw_minor, fw_build) <
-                       NETXEN_VERSION_CODE(3, 4, 216)) {
+       if (adapter->fw_version < NETXEN_VERSION_CODE(3, 4, 216)) {
                adapter->driver_mismatch = 1;
-               printk(KERN_ERR "%s: firmware version %d.%d.%d unsupported\n",
-                               netxen_nic_driver_name,
+               dev_warn(&pdev->dev, "firmware version %d.%d.%d unsupported\n",
                                fw_major, fw_minor, fw_build);
                return;
        }
+
+       dev_info(&pdev->dev, "firmware version %d.%d.%d\n",
+                       fw_major, fw_minor, fw_build);
+
+       if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
+               adapter->hw_read_wx(adapter,
+                               NETXEN_MIU_MN_CONTROL, &i, 4);
+               adapter->ahw.cut_through = (i & 0x4) ? 1 : 0;
+               dev_info(&pdev->dev, "firmware running in %s mode\n",
+               adapter->ahw.cut_through ? "cut-through" : "legacy");
+       }
 }
 
+int
+netxen_nic_wol_supported(struct netxen_adapter *adapter)
+{
+       u32 wol_cfg;
+
+       if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
+               return 0;
+
+       wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG_NV);
+       if (wol_cfg & (1UL << adapter->portnum)) {
+               wol_cfg = netxen_nic_reg_read(adapter, NETXEN_WOL_CONFIG);
+               if (wol_cfg & (1 << adapter->portnum))
+                       return 1;
+       }
+
+       return 0;
+}
index aae737dc77a8aafaa0d1453c542c2f27694d22a0..04b47a7993cd67da7269dcbcd7c50853d9d784a0 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 - 2006 NetXen, Inc.
+ * Copyright (C) 2003 - 2009 NetXen, Inc.
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  *
  * Contact Information:
  *    info@netxen.com
- * NetXen,
- * 3965 Freedom Circle, Fourth floor,
- * Santa Clara, CA 95054
- *
- *
- * Structures, enums, and macros for the MAC
+ * NetXen Inc,
+ * 18922 Forge Drive
+ * Cupertino, CA 95014-0701
  *
  */
 
@@ -54,37 +51,12 @@ static inline void writeq(u64 val, void __iomem * addr)
 }
 #endif
 
-static inline void netxen_nic_hw_block_write64(u64 __iomem * data_ptr,
-                                              u64 __iomem * addr,
-                                              int num_words)
-{
-       int num;
-       for (num = 0; num < num_words; num++) {
-               writeq(readq((void __iomem *)data_ptr), addr);
-               addr++;
-               data_ptr++;
-       }
-}
-
-static inline void netxen_nic_hw_block_read64(u64 __iomem * data_ptr,
-                                             u64 __iomem * addr, int num_words)
-{
-       int num;
-       for (num = 0; num < num_words; num++) {
-               writeq(readq((void __iomem *)addr), data_ptr);
-               addr++;
-               data_ptr++;
-       }
-
-}
-
 struct netxen_adapter;
 
 #define NETXEN_PCI_MAPSIZE_BYTES  (NETXEN_PCI_MAPSIZE << 20)
 
 struct netxen_port;
 void netxen_nic_set_link_parameters(struct netxen_adapter *adapter);
-void netxen_nic_flash_print(struct netxen_adapter *adapter);
 
 typedef u8 netxen_ethernet_macaddr_t[6];
 
@@ -148,33 +120,6 @@ typedef enum {
 #define netxen_gb_get_soft_reset(config_word)  \
                _netxen_crb_get_bit((config_word), 31)
 
-/*
- * NIU GB MAC Config Register 1 (applies to GB0, GB1, GB2, GB3)
- *
- *     Bit 0       : duplex => 1:full duplex mode, 0:half duplex
- *     Bit 1       : crc_enable => 1:append CRC to xmit frames, 0:dont append
- *     Bit 2       : padshort => 1:pad short frames and add CRC, 0:dont pad
- *     Bit 4       : checklength => 1:check framelen with actual,0:dont check
- *     Bit 5       : hugeframes => 1:allow oversize xmit frames, 0:dont allow
- *     Bits 8-9    : intfmode => 01:nibble (10/100), 10:byte (1000)
- *     Bits 12-15  : preamblelen => preamble field length in bytes, default 7
- */
-
-#define netxen_gb_set_duplex(config_word)      \
-               ((config_word) |= 1 << 0)
-#define netxen_gb_set_crc_enable(config_word)  \
-               ((config_word) |= 1 << 1)
-#define netxen_gb_set_padshort(config_word)    \
-               ((config_word) |= 1 << 2)
-#define netxen_gb_set_checklength(config_word) \
-               ((config_word) |= 1 << 4)
-#define netxen_gb_set_hugeframes(config_word)  \
-               ((config_word) |= 1 << 5)
-#define netxen_gb_set_preamblelen(config_word, val)    \
-               ((config_word) |= ((val) << 12) & 0xF000)
-#define netxen_gb_set_intfmode(config_word, val)               \
-               ((config_word) |= ((val) << 8) & 0x300)
-
 #define netxen_gb_get_stationaddress_low(config_word) ((config_word) >> 16)
 
 #define netxen_gb_set_mii_mgmt_clockselect(config_word, val)   \
index ffd37bea1628b43452cf2749be07e5c9376591dc..0759c35f16ac6005416b8986f74f548b1221cbd4 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 - 2006 NetXen, Inc.
+ * Copyright (C) 2003 - 2009 NetXen, Inc.
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  *
  * Contact Information:
  *    info@netxen.com
- * NetXen,
- * 3965 Freedom Circle, Fourth floor,
- * Santa Clara, CA 95054
- *
- *
- * Source file for NIC routines to initialize the Phantom Hardware
+ * NetXen Inc,
+ * 18922 Forge Drive
+ * Cupertino, CA 95014-0701
  *
  */
 
@@ -52,17 +49,9 @@ static unsigned int crb_addr_xform[NETXEN_MAX_CRB_XFORM];
 
 #define NETXEN_NIC_XDMA_RESET 0x8000ff
 
-static void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter,
-                                       uint32_t ctx, uint32_t ringid);
-
-#if 0
-static void netxen_nic_locked_write_reg(struct netxen_adapter *adapter,
-                                       unsigned long off, int *data)
-{
-       void __iomem *addr = pci_base_offset(adapter, off);
-       writel(*data, addr);
-}
-#endif  /*  0  */
+static void
+netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter,
+               struct nx_host_rds_ring *rds_ring);
 
 static void crb_addr_transform_setup(void)
 {
@@ -160,23 +149,21 @@ void netxen_release_rx_buffers(struct netxen_adapter *adapter)
        struct netxen_recv_context *recv_ctx;
        struct nx_host_rds_ring *rds_ring;
        struct netxen_rx_buffer *rx_buf;
-       int i, ctxid, ring;
-
-       for (ctxid = 0; ctxid < MAX_RCV_CTX; ++ctxid) {
-               recv_ctx = &adapter->recv_ctx[ctxid];
-               for (ring = 0; ring < adapter->max_rds_rings; ring++) {
-                       rds_ring = &recv_ctx->rds_rings[ring];
-                       for (i = 0; i < rds_ring->max_rx_desc_count; ++i) {
-                               rx_buf = &(rds_ring->rx_buf_arr[i]);
-                               if (rx_buf->state == NETXEN_BUFFER_FREE)
-                                       continue;
-                               pci_unmap_single(adapter->pdev,
-                                               rx_buf->dma,
-                                               rds_ring->dma_size,
-                                               PCI_DMA_FROMDEVICE);
-                               if (rx_buf->skb != NULL)
-                                       dev_kfree_skb_any(rx_buf->skb);
-                       }
+       int i, ring;
+
+       recv_ctx = &adapter->recv_ctx;
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               rds_ring = &recv_ctx->rds_rings[ring];
+               for (i = 0; i < rds_ring->num_desc; ++i) {
+                       rx_buf = &(rds_ring->rx_buf_arr[i]);
+                       if (rx_buf->state == NETXEN_BUFFER_FREE)
+                               continue;
+                       pci_unmap_single(adapter->pdev,
+                                       rx_buf->dma,
+                                       rds_ring->dma_size,
+                                       PCI_DMA_FROMDEVICE);
+                       if (rx_buf->skb != NULL)
+                               dev_kfree_skb_any(rx_buf->skb);
                }
        }
 }
@@ -188,7 +175,7 @@ void netxen_release_tx_buffers(struct netxen_adapter *adapter)
        int i, j;
 
        cmd_buf = adapter->cmd_buf_arr;
-       for (i = 0; i < adapter->max_tx_desc_count; i++) {
+       for (i = 0; i < adapter->num_txd; i++) {
                buffrag = cmd_buf->frag_array;
                if (buffrag->dma) {
                        pci_unmap_single(adapter->pdev, buffrag->dma,
@@ -204,7 +191,6 @@ void netxen_release_tx_buffers(struct netxen_adapter *adapter)
                                buffrag->dma = 0ULL;
                        }
                }
-               /* Free the skb we received in netxen_nic_xmit_frame */
                if (cmd_buf->skb) {
                        dev_kfree_skb_any(cmd_buf->skb);
                        cmd_buf->skb = NULL;
@@ -217,18 +203,17 @@ void netxen_free_sw_resources(struct netxen_adapter *adapter)
 {
        struct netxen_recv_context *recv_ctx;
        struct nx_host_rds_ring *rds_ring;
-       int ctx, ring;
-
-       for (ctx = 0; ctx < MAX_RCV_CTX; ctx++) {
-               recv_ctx = &adapter->recv_ctx[ctx];
-               for (ring = 0; ring < adapter->max_rds_rings; ring++) {
-                       rds_ring = &recv_ctx->rds_rings[ring];
-                       if (rds_ring->rx_buf_arr) {
-                               vfree(rds_ring->rx_buf_arr);
-                               rds_ring->rx_buf_arr = NULL;
-                       }
+       int ring;
+
+       recv_ctx = &adapter->recv_ctx;
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               rds_ring = &recv_ctx->rds_rings[ring];
+               if (rds_ring->rx_buf_arr) {
+                       vfree(rds_ring->rx_buf_arr);
+                       rds_ring->rx_buf_arr = NULL;
                }
        }
+
        if (adapter->cmd_buf_arr)
                vfree(adapter->cmd_buf_arr);
        return;
@@ -238,90 +223,97 @@ int netxen_alloc_sw_resources(struct netxen_adapter *adapter)
 {
        struct netxen_recv_context *recv_ctx;
        struct nx_host_rds_ring *rds_ring;
+       struct nx_host_sds_ring *sds_ring;
        struct netxen_rx_buffer *rx_buf;
-       int ctx, ring, i, num_rx_bufs;
+       int ring, i, num_rx_bufs;
 
        struct netxen_cmd_buffer *cmd_buf_arr;
        struct net_device *netdev = adapter->netdev;
 
-       cmd_buf_arr = (struct netxen_cmd_buffer *)vmalloc(TX_RINGSIZE);
+       cmd_buf_arr =
+               (struct netxen_cmd_buffer *)vmalloc(TX_BUFF_RINGSIZE(adapter));
        if (cmd_buf_arr == NULL) {
                printk(KERN_ERR "%s: Failed to allocate cmd buffer ring\n",
                       netdev->name);
                return -ENOMEM;
        }
-       memset(cmd_buf_arr, 0, TX_RINGSIZE);
+       memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(adapter));
        adapter->cmd_buf_arr = cmd_buf_arr;
 
-       for (ctx = 0; ctx < MAX_RCV_CTX; ctx++) {
-               recv_ctx = &adapter->recv_ctx[ctx];
-               for (ring = 0; ring < adapter->max_rds_rings; ring++) {
-                       rds_ring = &recv_ctx->rds_rings[ring];
-                       switch (RCV_DESC_TYPE(ring)) {
-                       case RCV_DESC_NORMAL:
-                               rds_ring->max_rx_desc_count =
-                                       adapter->max_rx_desc_count;
-                               rds_ring->flags = RCV_DESC_NORMAL;
-                               if (adapter->ahw.cut_through) {
-                                       rds_ring->dma_size =
-                                               NX_CT_DEFAULT_RX_BUF_LEN;
-                                       rds_ring->skb_size =
-                                               NX_CT_DEFAULT_RX_BUF_LEN;
-                               } else {
-                                       rds_ring->dma_size = RX_DMA_MAP_LEN;
-                                       rds_ring->skb_size =
-                                               MAX_RX_BUFFER_LENGTH;
-                               }
-                               break;
-
-                       case RCV_DESC_JUMBO:
-                               rds_ring->max_rx_desc_count =
-                                       adapter->max_jumbo_rx_desc_count;
-                               rds_ring->flags = RCV_DESC_JUMBO;
-                               if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
-                                       rds_ring->dma_size =
-                                               NX_P3_RX_JUMBO_BUF_MAX_LEN;
-                               else
-                                       rds_ring->dma_size =
-                                               NX_P2_RX_JUMBO_BUF_MAX_LEN;
+       recv_ctx = &adapter->recv_ctx;
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               rds_ring = &recv_ctx->rds_rings[ring];
+               switch (ring) {
+               case RCV_RING_NORMAL:
+                       rds_ring->num_desc = adapter->num_rxd;
+                       if (adapter->ahw.cut_through) {
+                               rds_ring->dma_size =
+                                       NX_CT_DEFAULT_RX_BUF_LEN;
                                rds_ring->skb_size =
-                                       rds_ring->dma_size + NET_IP_ALIGN;
-                               break;
+                                       NX_CT_DEFAULT_RX_BUF_LEN;
+                       } else {
+                               rds_ring->dma_size = RX_DMA_MAP_LEN;
+                               rds_ring->skb_size =
+                                       MAX_RX_BUFFER_LENGTH;
+                       }
+                       break;
 
-                       case RCV_RING_LRO:
-                               rds_ring->max_rx_desc_count =
-                                       adapter->max_lro_rx_desc_count;
-                               rds_ring->flags = RCV_DESC_LRO;
-                               rds_ring->dma_size = RX_LRO_DMA_MAP_LEN;
-                               rds_ring->skb_size = MAX_RX_LRO_BUFFER_LENGTH;
-                               break;
+               case RCV_RING_JUMBO:
+                       rds_ring->num_desc = adapter->num_jumbo_rxd;
+                       if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+                               rds_ring->dma_size =
+                                       NX_P3_RX_JUMBO_BUF_MAX_LEN;
+                       else
+                               rds_ring->dma_size =
+                                       NX_P2_RX_JUMBO_BUF_MAX_LEN;
+                       rds_ring->skb_size =
+                               rds_ring->dma_size + NET_IP_ALIGN;
+                       break;
 
-                       }
-                       rds_ring->rx_buf_arr = (struct netxen_rx_buffer *)
-                               vmalloc(RCV_BUFFSIZE);
-                       if (rds_ring->rx_buf_arr == NULL) {
-                               printk(KERN_ERR "%s: Failed to allocate "
-                                       "rx buffer ring %d\n",
-                                       netdev->name, ring);
-                               /* free whatever was already allocated */
-                               goto err_out;
-                       }
-                       memset(rds_ring->rx_buf_arr, 0, RCV_BUFFSIZE);
-                       INIT_LIST_HEAD(&rds_ring->free_list);
-                       /*
-                        * Now go through all of them, set reference handles
-                        * and put them in the queues.
-                        */
-                       num_rx_bufs = rds_ring->max_rx_desc_count;
-                       rx_buf = rds_ring->rx_buf_arr;
-                       for (i = 0; i < num_rx_bufs; i++) {
-                               list_add_tail(&rx_buf->list,
-                                               &rds_ring->free_list);
-                               rx_buf->ref_handle = i;
-                               rx_buf->state = NETXEN_BUFFER_FREE;
-                               rx_buf++;
-                       }
+               case RCV_RING_LRO:
+                       rds_ring->num_desc = adapter->num_lro_rxd;
+                       rds_ring->dma_size = RX_LRO_DMA_MAP_LEN;
+                       rds_ring->skb_size = MAX_RX_LRO_BUFFER_LENGTH;
+                       break;
+
+               }
+               rds_ring->rx_buf_arr = (struct netxen_rx_buffer *)
+                       vmalloc(RCV_BUFF_RINGSIZE(rds_ring));
+               if (rds_ring->rx_buf_arr == NULL) {
+                       printk(KERN_ERR "%s: Failed to allocate "
+                               "rx buffer ring %d\n",
+                               netdev->name, ring);
+                       /* free whatever was already allocated */
+                       goto err_out;
+               }
+               memset(rds_ring->rx_buf_arr, 0, RCV_BUFF_RINGSIZE(rds_ring));
+               INIT_LIST_HEAD(&rds_ring->free_list);
+               /*
+                * Now go through all of them, set reference handles
+                * and put them in the queues.
+                */
+               num_rx_bufs = rds_ring->num_desc;
+               rx_buf = rds_ring->rx_buf_arr;
+               for (i = 0; i < num_rx_bufs; i++) {
+                       list_add_tail(&rx_buf->list,
+                                       &rds_ring->free_list);
+                       rx_buf->ref_handle = i;
+                       rx_buf->state = NETXEN_BUFFER_FREE;
+                       rx_buf++;
                }
+               spin_lock_init(&rds_ring->lock);
+       }
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               sds_ring->irq = adapter->msix_entries[ring].vector;
+               sds_ring->clean_tx = (ring == 0);
+               sds_ring->post_rxd = (ring == 0);
+               sds_ring->adapter = adapter;
+               sds_ring->num_desc = adapter->num_rxd;
+
+               for (i = 0; i < NUM_RCV_DESC_RINGS; i++)
+                       INIT_LIST_HEAD(&sds_ring->free_list[i]);
        }
 
        return 0;
@@ -333,7 +325,7 @@ err_out:
 
 void netxen_initialize_adapter_ops(struct netxen_adapter *adapter)
 {
-       switch (adapter->ahw.board_type) {
+       switch (adapter->ahw.port_type) {
        case NETXEN_NIC_GBE:
                adapter->enable_phy_interrupts =
                    netxen_niu_gbe_enable_phy_interrupts;
@@ -399,9 +391,6 @@ static u32 netxen_decode_crb_addr(u32 addr)
 
 static long rom_max_timeout = 100;
 static long rom_lock_timeout = 10000;
-#if 0
-static long rom_write_timeout = 700;
-#endif
 
 static int rom_lock(struct netxen_adapter *adapter)
 {
@@ -452,38 +441,6 @@ static int netxen_wait_rom_done(struct netxen_adapter *adapter)
        return 0;
 }
 
-#if 0
-static int netxen_rom_wren(struct netxen_adapter *adapter)
-{
-       /* Set write enable latch in ROM status register */
-       netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0);
-       netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE,
-                            M25P_INSTR_WREN);
-       if (netxen_wait_rom_done(adapter)) {
-               return -1;
-       }
-       return 0;
-}
-
-static unsigned int netxen_rdcrbreg(struct netxen_adapter *adapter,
-                                   unsigned int addr)
-{
-       unsigned int data = 0xdeaddead;
-       data = netxen_nic_reg_read(adapter, addr);
-       return data;
-}
-
-static int netxen_do_rom_rdsr(struct netxen_adapter *adapter)
-{
-       netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE,
-                            M25P_INSTR_RDSR);
-       if (netxen_wait_rom_done(adapter)) {
-               return -1;
-       }
-       return netxen_rdcrbreg(adapter, NETXEN_ROMUSB_ROM_RDATA);
-}
-#endif
-
 static void netxen_rom_unlock(struct netxen_adapter *adapter)
 {
        u32 val;
@@ -493,44 +450,6 @@ static void netxen_rom_unlock(struct netxen_adapter *adapter)
 
 }
 
-#if 0
-static int netxen_rom_wip_poll(struct netxen_adapter *adapter)
-{
-       long timeout = 0;
-       long wip = 1;
-       int val;
-       netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0);
-       while (wip != 0) {
-               val = netxen_do_rom_rdsr(adapter);
-               wip = val & 1;
-               timeout++;
-               if (timeout > rom_max_timeout) {
-                       return -1;
-               }
-       }
-       return 0;
-}
-
-static int do_rom_fast_write(struct netxen_adapter *adapter, int addr,
-                            int data)
-{
-       if (netxen_rom_wren(adapter)) {
-               return -1;
-       }
-       netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_WDATA, data);
-       netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr);
-       netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3);
-       netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE,
-                            M25P_INSTR_PP);
-       if (netxen_wait_rom_done(adapter)) {
-               netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0);
-               return -1;
-       }
-
-       return netxen_rom_wip_poll(adapter);
-}
-#endif
-
 static int do_rom_fast_read(struct netxen_adapter *adapter,
                            int addr, int *valp)
 {
@@ -597,284 +516,6 @@ int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
        return ret;
 }
 
-#if 0
-int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data)
-{
-       int ret = 0;
-
-       if (rom_lock(adapter) != 0) {
-               return -1;
-       }
-       ret = do_rom_fast_write(adapter, addr, data);
-       netxen_rom_unlock(adapter);
-       return ret;
-}
-
-static int do_rom_fast_write_words(struct netxen_adapter *adapter,
-                                  int addr, u8 *bytes, size_t size)
-{
-       int addridx = addr;
-       int ret = 0;
-
-       while (addridx < (addr + size)) {
-               int last_attempt = 0;
-               int timeout = 0;
-               int data;
-
-               data = le32_to_cpu((*(__le32*)bytes));
-               ret = do_rom_fast_write(adapter, addridx, data);
-               if (ret < 0)
-                       return ret;
-
-               while(1) {
-                       int data1;
-
-                       ret = do_rom_fast_read(adapter, addridx, &data1);
-                       if (ret < 0)
-                               return ret;
-
-                       if (data1 == data)
-                               break;
-
-                       if (timeout++ >= rom_write_timeout) {
-                               if (last_attempt++ < 4) {
-                                       ret = do_rom_fast_write(adapter,
-                                                               addridx, data);
-                                       if (ret < 0)
-                                               return ret;
-                               }
-                               else {
-                                       printk(KERN_INFO "Data write did not "
-                                          "succeed at address 0x%x\n", addridx);
-                                       break;
-                               }
-                       }
-               }
-
-               bytes += 4;
-               addridx += 4;
-       }
-
-       return ret;
-}
-
-int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr,
-                                       u8 *bytes, size_t size)
-{
-       int ret = 0;
-
-       ret = rom_lock(adapter);
-       if (ret < 0)
-               return ret;
-
-       ret = do_rom_fast_write_words(adapter, addr, bytes, size);
-       netxen_rom_unlock(adapter);
-
-       return ret;
-}
-
-static int netxen_rom_wrsr(struct netxen_adapter *adapter, int data)
-{
-       int ret;
-
-       ret = netxen_rom_wren(adapter);
-       if (ret < 0)
-               return ret;
-
-       netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_ROM_WDATA, data);
-       netxen_crb_writelit_adapter(adapter,
-                                       NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0x1);
-
-       ret = netxen_wait_rom_done(adapter);
-       if (ret < 0)
-               return ret;
-
-       return netxen_rom_wip_poll(adapter);
-}
-
-static int netxen_rom_rdsr(struct netxen_adapter *adapter)
-{
-       int ret;
-
-       ret = rom_lock(adapter);
-       if (ret < 0)
-               return ret;
-
-       ret = netxen_do_rom_rdsr(adapter);
-       netxen_rom_unlock(adapter);
-       return ret;
-}
-
-int netxen_backup_crbinit(struct netxen_adapter *adapter)
-{
-       int ret = FLASH_SUCCESS;
-       int val;
-       char *buffer = kmalloc(NETXEN_FLASH_SECTOR_SIZE, GFP_KERNEL);
-
-       if (!buffer)
-               return -ENOMEM;
-       /* unlock sector 63 */
-       val = netxen_rom_rdsr(adapter);
-       val = val & 0xe3;
-       ret = netxen_rom_wrsr(adapter, val);
-       if (ret != FLASH_SUCCESS)
-               goto out_kfree;
-
-       ret = netxen_rom_wip_poll(adapter);
-       if (ret != FLASH_SUCCESS)
-               goto out_kfree;
-
-       /* copy  sector 0 to sector 63 */
-       ret = netxen_rom_fast_read_words(adapter, NETXEN_CRBINIT_START,
-                                       buffer, NETXEN_FLASH_SECTOR_SIZE);
-       if (ret != FLASH_SUCCESS)
-               goto out_kfree;
-
-       ret = netxen_rom_fast_write_words(adapter, NETXEN_FIXED_START,
-                                       buffer, NETXEN_FLASH_SECTOR_SIZE);
-       if (ret != FLASH_SUCCESS)
-               goto out_kfree;
-
-       /* lock sector 63 */
-       val = netxen_rom_rdsr(adapter);
-       if (!(val & 0x8)) {
-               val |= (0x1 << 2);
-               /* lock sector 63 */
-               if (netxen_rom_wrsr(adapter, val) == 0) {
-                       ret = netxen_rom_wip_poll(adapter);
-                       if (ret != FLASH_SUCCESS)
-                               goto out_kfree;
-
-                       /* lock SR writes */
-                       ret = netxen_rom_wip_poll(adapter);
-                       if (ret != FLASH_SUCCESS)
-                               goto out_kfree;
-               }
-       }
-
-out_kfree:
-       kfree(buffer);
-       return ret;
-}
-
-static int netxen_do_rom_se(struct netxen_adapter *adapter, int addr)
-{
-       netxen_rom_wren(adapter);
-       netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr);
-       netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3);
-       netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE,
-                            M25P_INSTR_SE);
-       if (netxen_wait_rom_done(adapter)) {
-               netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0);
-               return -1;
-       }
-       return netxen_rom_wip_poll(adapter);
-}
-
-static void check_erased_flash(struct netxen_adapter *adapter, int addr)
-{
-       int i;
-       int val;
-       int count = 0, erased_errors = 0;
-       int range;
-
-       range = (addr == NETXEN_USER_START) ?
-               NETXEN_FIXED_START : addr + NETXEN_FLASH_SECTOR_SIZE;
-
-       for (i = addr; i < range; i += 4) {
-               netxen_rom_fast_read(adapter, i, &val);
-               if (val != 0xffffffff)
-                       erased_errors++;
-               count++;
-       }
-
-       if (erased_errors)
-               printk(KERN_INFO "0x%x out of 0x%x words fail to be erased "
-                       "for sector address: %x\n", erased_errors, count, addr);
-}
-
-int netxen_rom_se(struct netxen_adapter *adapter, int addr)
-{
-       int ret = 0;
-       if (rom_lock(adapter) != 0) {
-               return -1;
-       }
-       ret = netxen_do_rom_se(adapter, addr);
-       netxen_rom_unlock(adapter);
-       msleep(30);
-       check_erased_flash(adapter, addr);
-
-       return ret;
-}
-
-static int netxen_flash_erase_sections(struct netxen_adapter *adapter,
-                                      int start, int end)
-{
-       int ret = FLASH_SUCCESS;
-       int i;
-
-       for (i = start; i < end; i++) {
-               ret = netxen_rom_se(adapter, i * NETXEN_FLASH_SECTOR_SIZE);
-               if (ret)
-                       break;
-               ret = netxen_rom_wip_poll(adapter);
-               if (ret < 0)
-                       return ret;
-       }
-
-       return ret;
-}
-
-int
-netxen_flash_erase_secondary(struct netxen_adapter *adapter)
-{
-       int ret = FLASH_SUCCESS;
-       int start, end;
-
-       start = NETXEN_SECONDARY_START / NETXEN_FLASH_SECTOR_SIZE;
-       end   = NETXEN_USER_START / NETXEN_FLASH_SECTOR_SIZE;
-       ret = netxen_flash_erase_sections(adapter, start, end);
-
-       return ret;
-}
-
-int
-netxen_flash_erase_primary(struct netxen_adapter *adapter)
-{
-       int ret = FLASH_SUCCESS;
-       int start, end;
-
-       start = NETXEN_PRIMARY_START / NETXEN_FLASH_SECTOR_SIZE;
-       end   = NETXEN_SECONDARY_START / NETXEN_FLASH_SECTOR_SIZE;
-       ret = netxen_flash_erase_sections(adapter, start, end);
-
-       return ret;
-}
-
-void netxen_halt_pegs(struct netxen_adapter *adapter)
-{
-        netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_0 + 0x3c, 1);
-        netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_1 + 0x3c, 1);
-        netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_2 + 0x3c, 1);
-        netxen_crb_writelit_adapter(adapter, NETXEN_CRB_PEG_NET_3 + 0x3c, 1);
-}
-
-int netxen_flash_unlock(struct netxen_adapter *adapter)
-{
-       int ret = 0;
-
-       ret = netxen_rom_wrsr(adapter, 0);
-       if (ret < 0)
-               return ret;
-
-       ret = netxen_rom_wren(adapter);
-       if (ret < 0)
-               return ret;
-
-       return ret;
-}
-#endif  /*  0  */
-
 #define NETXEN_BOARDTYPE               0x4008
 #define NETXEN_BOARDNUM                0x400c
 #define NETXEN_CHIPNUM                 0x4010
@@ -1168,6 +809,40 @@ int netxen_receive_peg_ready(struct netxen_adapter *adapter)
        return 0;
 }
 
+static int
+netxen_alloc_rx_skb(struct netxen_adapter *adapter,
+               struct nx_host_rds_ring *rds_ring,
+               struct netxen_rx_buffer *buffer)
+{
+       struct sk_buff *skb;
+       dma_addr_t dma;
+       struct pci_dev *pdev = adapter->pdev;
+
+       buffer->skb = dev_alloc_skb(rds_ring->skb_size);
+       if (!buffer->skb)
+               return 1;
+
+       skb = buffer->skb;
+
+       if (!adapter->ahw.cut_through)
+               skb_reserve(skb, 2);
+
+       dma = pci_map_single(pdev, skb->data,
+                       rds_ring->dma_size, PCI_DMA_FROMDEVICE);
+
+       if (pci_dma_mapping_error(pdev, dma)) {
+               dev_kfree_skb_any(skb);
+               buffer->skb = NULL;
+               return 1;
+       }
+
+       buffer->skb = skb;
+       buffer->dma = dma;
+       buffer->state = NETXEN_BUFFER_BUSY;
+
+       return 0;
+}
+
 static struct sk_buff *netxen_process_rxbuf(struct netxen_adapter *adapter,
                struct nx_host_rds_ring *rds_ring, u16 index, u16 cksum)
 {
@@ -1192,164 +867,121 @@ static struct sk_buff *netxen_process_rxbuf(struct netxen_adapter *adapter,
        skb->dev = adapter->netdev;
 
        buffer->skb = NULL;
-
 no_skb:
        buffer->state = NETXEN_BUFFER_FREE;
-       buffer->lro_current_frags = 0;
-       buffer->lro_expected_frags = 0;
-       list_add_tail(&buffer->list, &rds_ring->free_list);
        return skb;
 }
 
-/*
- * netxen_process_rcv() send the received packet to the protocol stack.
- * and if the number of receives exceeds RX_BUFFERS_REFILL, then we
- * invoke the routine to send more rx buffers to the Phantom...
- */
-static void netxen_process_rcv(struct netxen_adapter *adapter, int ctxid,
-               struct status_desc *desc, struct status_desc *frag_desc)
+static struct netxen_rx_buffer *
+netxen_process_rcv(struct netxen_adapter *adapter,
+               int ring, int index, int length, int cksum, int pkt_offset)
 {
        struct net_device *netdev = adapter->netdev;
-       u64 sts_data = le64_to_cpu(desc->status_desc_data);
-       int index = netxen_get_sts_refhandle(sts_data);
-       struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctxid]);
+       struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
        struct netxen_rx_buffer *buffer;
        struct sk_buff *skb;
-       u32 length = netxen_get_sts_totallength(sts_data);
-       u32 desc_ctx;
-       u16 pkt_offset = 0, cksum;
-       struct nx_host_rds_ring *rds_ring;
+       struct nx_host_rds_ring *rds_ring = &recv_ctx->rds_rings[ring];
 
-       desc_ctx = netxen_get_sts_type(sts_data);
-       if (unlikely(desc_ctx >= NUM_RCV_DESC_RINGS)) {
-               printk("%s: %s Bad Rcv descriptor ring\n",
-                      netxen_nic_driver_name, netdev->name);
-               return;
-       }
+       if (unlikely(index > rds_ring->num_desc))
+               return NULL;
 
-       rds_ring = &recv_ctx->rds_rings[desc_ctx];
-       if (unlikely(index > rds_ring->max_rx_desc_count)) {
-               DPRINTK(ERR, "Got a buffer index:%x Max is %x\n",
-                       index, rds_ring->max_rx_desc_count);
-               return;
-       }
        buffer = &rds_ring->rx_buf_arr[index];
-       if (desc_ctx == RCV_DESC_LRO_CTXID) {
-               buffer->lro_current_frags++;
-               if (netxen_get_sts_desc_lro_last_frag(desc)) {
-                       buffer->lro_expected_frags =
-                           netxen_get_sts_desc_lro_cnt(desc);
-                       buffer->lro_length = length;
-               }
-               if (buffer->lro_current_frags != buffer->lro_expected_frags) {
-                       if (buffer->lro_expected_frags != 0) {
-                               printk("LRO: (refhandle:%x) recv frag. "
-                                      "wait for last. flags: %x expected:%d "
-                                      "have:%d\n", index,
-                                      netxen_get_sts_desc_lro_last_frag(desc),
-                                      buffer->lro_expected_frags,
-                                      buffer->lro_current_frags);
-                       }
-                       return;
-               }
-       }
-
-       cksum = netxen_get_sts_status(sts_data);
 
        skb = netxen_process_rxbuf(adapter, rds_ring, index, cksum);
        if (!skb)
-               return;
+               return buffer;
 
-       if (desc_ctx == RCV_DESC_LRO_CTXID) {
-               /* True length was only available on the last pkt */
-               skb_put(skb, buffer->lro_length);
-       } else {
-               if (length > rds_ring->skb_size)
-                       skb_put(skb, rds_ring->skb_size);
-               else
-                       skb_put(skb, length);
+       if (length > rds_ring->skb_size)
+               skb_put(skb, rds_ring->skb_size);
+       else
+               skb_put(skb, length);
 
-               pkt_offset = netxen_get_sts_pkt_offset(sts_data);
-               if (pkt_offset)
-                       skb_pull(skb, pkt_offset);
-       }
+
+       if (pkt_offset)
+               skb_pull(skb, pkt_offset);
 
        skb->protocol = eth_type_trans(skb, netdev);
 
-       /*
-        * rx buffer chaining is disabled, walk and free
-        * any spurious rx buffer chain.
-        */
-       if (frag_desc) {
-               u16 i, nr_frags = desc->nr_frags;
+       netif_receive_skb(skb);
 
-               dev_kfree_skb_any(skb);
-               for (i = 0; i < nr_frags; i++) {
-                       index = le16_to_cpu(frag_desc->frag_handles[i]);
-                       skb = netxen_process_rxbuf(adapter,
-                                       rds_ring, index, cksum);
-                       if (skb)
-                               dev_kfree_skb_any(skb);
-               }
-               adapter->stats.rxdropped++;
-       } else {
-               netif_receive_skb(skb);
+       adapter->stats.no_rcv++;
+       adapter->stats.rxbytes += length;
 
-               adapter->stats.no_rcv++;
-               adapter->stats.rxbytes += length;
-       }
+       return buffer;
 }
 
-/* Process Receive status ring */
-u32 netxen_process_rcv_ring(struct netxen_adapter *adapter, int ctxid, int max)
+#define netxen_merge_rx_buffers(list, head) \
+       do { list_splice_tail_init(list, head); } while (0);
+
+int
+netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max)
 {
-       struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctxid]);
-       struct status_desc *desc_head = recv_ctx->rcv_status_desc_head;
-       struct status_desc *desc, *frag_desc;
-       u32 consumer = recv_ctx->status_rx_consumer;
-       int count = 0, ring;
+       struct netxen_adapter *adapter = sds_ring->adapter;
+
+       struct list_head *cur;
+
+       struct status_desc *desc;
+       struct netxen_rx_buffer *rxbuf;
+
+       u32 consumer = sds_ring->consumer;
+
+       int count = 0;
        u64 sts_data;
-       u16 opcode;
+       int opcode, ring, index, length, cksum, pkt_offset;
 
        while (count < max) {
-               desc = &desc_head[consumer];
-               if (!(netxen_get_sts_owner(desc) & STATUS_OWNER_HOST)) {
-                       DPRINTK(ERR, "desc %p ownedby %x\n", desc,
-                               netxen_get_sts_owner(desc));
+               desc = &sds_ring->desc_head[consumer];
+               sts_data = le64_to_cpu(desc->status_desc_data);
+
+               if (!(sts_data & STATUS_OWNER_HOST))
                        break;
-               }
 
-               sts_data = le64_to_cpu(desc->status_desc_data);
+               ring   = netxen_get_sts_type(sts_data);
+               if (ring > RCV_RING_JUMBO)
+                       continue;
+
                opcode = netxen_get_sts_opcode(sts_data);
-               frag_desc = NULL;
-               if (opcode == NETXEN_NIC_RXPKT_DESC) {
-                       if (desc->nr_frags) {
-                               consumer = get_next_index(consumer,
-                                               adapter->max_rx_desc_count);
-                               frag_desc = &desc_head[consumer];
-                               netxen_set_sts_owner(frag_desc,
-                                               STATUS_OWNER_PHANTOM);
-                       }
-               }
 
-               netxen_process_rcv(adapter, ctxid, desc, frag_desc);
+               index  = netxen_get_sts_refhandle(sts_data);
+               length = netxen_get_sts_totallength(sts_data);
+               cksum  = netxen_get_sts_status(sts_data);
+               pkt_offset = netxen_get_sts_pkt_offset(sts_data);
+
+               rxbuf = netxen_process_rcv(adapter, ring, index,
+                               length, cksum, pkt_offset);
+
+               if (rxbuf)
+                       list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
 
-               netxen_set_sts_owner(desc, STATUS_OWNER_PHANTOM);
+               desc->status_desc_data = cpu_to_le64(STATUS_OWNER_PHANTOM);
 
-               consumer = get_next_index(consumer,
-                               adapter->max_rx_desc_count);
+               consumer = get_next_index(consumer, sds_ring->num_desc);
                count++;
        }
-       for (ring = 0; ring < adapter->max_rds_rings; ring++)
-               netxen_post_rx_buffers_nodb(adapter, ctxid, ring);
 
-       /* update the consumer index in phantom */
-       if (count) {
-               recv_ctx->status_rx_consumer = consumer;
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               struct nx_host_rds_ring *rds_ring =
+                       &adapter->recv_ctx.rds_rings[ring];
 
-               /* Window = 1 */
+               if (!list_empty(&sds_ring->free_list[ring])) {
+                       list_for_each(cur, &sds_ring->free_list[ring]) {
+                               rxbuf = list_entry(cur,
+                                               struct netxen_rx_buffer, list);
+                               netxen_alloc_rx_skb(adapter, rds_ring, rxbuf);
+                       }
+                       spin_lock(&rds_ring->lock);
+                       netxen_merge_rx_buffers(&sds_ring->free_list[ring],
+                                               &rds_ring->free_list);
+                       spin_unlock(&rds_ring->lock);
+               }
+
+               netxen_post_rx_buffers_nodb(adapter, rds_ring);
+       }
+
+       if (count) {
+               sds_ring->consumer = consumer;
                adapter->pci_write_normalize(adapter,
-                               recv_ctx->crb_sts_consumer, consumer);
+                               sds_ring->crb_sts_consumer, consumer);
        }
 
        return count;
@@ -1366,7 +998,11 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter)
        struct netxen_skb_frag *frag;
        int done = 0;
 
+       if (!spin_trylock(&adapter->tx_clean_lock))
+               return 1;
+
        last_consumer = adapter->last_cmd_consumer;
+       barrier(); /* cmd_consumer can change underneath */
        consumer = le32_to_cpu(*(adapter->cmd_consumer));
 
        while (last_consumer != consumer) {
@@ -1389,7 +1025,7 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter)
                }
 
                last_consumer = get_next_index(last_consumer,
-                                              adapter->max_tx_desc_count);
+                                              adapter->num_txd);
                if (++count >= MAX_STATUS_HANDLE)
                        break;
        }
@@ -1417,75 +1053,55 @@ int netxen_process_cmd_ring(struct netxen_adapter *adapter)
         * There is still a possible race condition and the host could miss an
         * interrupt. The card has to take care of this.
         */
+       barrier(); /* cmd_consumer can change underneath */
        consumer = le32_to_cpu(*(adapter->cmd_consumer));
        done = (last_consumer == consumer);
+       spin_unlock(&adapter->tx_clean_lock);
 
        return (done);
 }
 
-/*
- * netxen_post_rx_buffers puts buffer in the Phantom memory
- */
-void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
+void
+netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ringid,
+       struct nx_host_rds_ring *rds_ring)
 {
-       struct pci_dev *pdev = adapter->pdev;
-       struct sk_buff *skb;
-       struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctx]);
-       struct nx_host_rds_ring *rds_ring = NULL;
-       uint producer;
        struct rcv_desc *pdesc;
        struct netxen_rx_buffer *buffer;
-       int count = 0;
+       int producer, count = 0;
        netxen_ctx_msg msg = 0;
-       dma_addr_t dma;
        struct list_head *head;
 
-       rds_ring = &recv_ctx->rds_rings[ringid];
-
        producer = rds_ring->producer;
-       head = &rds_ring->free_list;
 
-       /* We can start writing rx descriptors into the phantom memory. */
+       spin_lock(&rds_ring->lock);
+       head = &rds_ring->free_list;
        while (!list_empty(head)) {
 
-               skb = dev_alloc_skb(rds_ring->skb_size);
-               if (unlikely(!skb)) {
-                       break;
-               }
-
-               if (!adapter->ahw.cut_through)
-                       skb_reserve(skb, 2);
+               buffer = list_entry(head->next, struct netxen_rx_buffer, list);
 
-               dma = pci_map_single(pdev, skb->data,
-                               rds_ring->dma_size, PCI_DMA_FROMDEVICE);
-               if (pci_dma_mapping_error(pdev, dma)) {
-                       dev_kfree_skb_any(skb);
-                       break;
+               if (!buffer->skb) {
+                       if (netxen_alloc_rx_skb(adapter, rds_ring, buffer))
+                               break;
                }
 
                count++;
-               buffer = list_entry(head->next, struct netxen_rx_buffer, list);
                list_del(&buffer->list);
 
-               buffer->skb = skb;
-               buffer->state = NETXEN_BUFFER_BUSY;
-               buffer->dma = dma;
-
                /* make a rcv descriptor  */
                pdesc = &rds_ring->desc_head[producer];
-               pdesc->addr_buffer = cpu_to_le64(dma);
+               pdesc->addr_buffer = cpu_to_le64(buffer->dma);
                pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
                pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
 
-               producer = get_next_index(producer, rds_ring->max_rx_desc_count);
+               producer = get_next_index(producer, rds_ring->num_desc);
        }
-       /* if we did allocate buffers, then write the count to Phantom */
+       spin_unlock(&rds_ring->lock);
+
        if (count) {
                rds_ring->producer = producer;
-                       /* Window = 1 */
                adapter->pci_write_normalize(adapter,
                                rds_ring->crb_rcv_producer,
-                               (producer-1) & (rds_ring->max_rx_desc_count-1));
+                               (producer-1) & (rds_ring->num_desc-1));
 
                if (adapter->fw_major < 4) {
                        /*
@@ -1496,9 +1112,8 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
                        netxen_set_msg_peg_id(msg, NETXEN_RCV_PEG_DB_ID);
                        netxen_set_msg_privid(msg);
                        netxen_set_msg_count(msg,
-                                            ((producer -
-                                              1) & (rds_ring->
-                                                    max_rx_desc_count - 1)));
+                                            ((producer - 1) &
+                                             (rds_ring->num_desc - 1)));
                        netxen_set_msg_ctxid(msg, adapter->portnum);
                        netxen_set_msg_opcode(msg, NETXEN_RCV_PRODUCER(ringid));
                        writel(msg,
@@ -1508,68 +1123,49 @@ void netxen_post_rx_buffers(struct netxen_adapter *adapter, u32 ctx, u32 ringid)
        }
 }
 
-static void netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter,
-                                       uint32_t ctx, uint32_t ringid)
+static void
+netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter,
+               struct nx_host_rds_ring *rds_ring)
 {
-       struct pci_dev *pdev = adapter->pdev;
-       struct sk_buff *skb;
-       struct netxen_recv_context *recv_ctx = &(adapter->recv_ctx[ctx]);
-       struct nx_host_rds_ring *rds_ring = NULL;
-       u32 producer;
        struct rcv_desc *pdesc;
        struct netxen_rx_buffer *buffer;
-       int count = 0;
+       int producer, count = 0;
        struct list_head *head;
-       dma_addr_t dma;
-
-       rds_ring = &recv_ctx->rds_rings[ringid];
 
        producer = rds_ring->producer;
+       if (!spin_trylock(&rds_ring->lock))
+               return;
+
        head = &rds_ring->free_list;
-       /* We can start writing rx descriptors into the phantom memory. */
        while (!list_empty(head)) {
 
-               skb = dev_alloc_skb(rds_ring->skb_size);
-               if (unlikely(!skb)) {
-                       break;
-               }
-
-               if (!adapter->ahw.cut_through)
-                       skb_reserve(skb, 2);
+               buffer = list_entry(head->next, struct netxen_rx_buffer, list);
 
-               dma = pci_map_single(pdev, skb->data,
-                               rds_ring->dma_size, PCI_DMA_FROMDEVICE);
-               if (pci_dma_mapping_error(pdev, dma)) {
-                       dev_kfree_skb_any(skb);
-                       break;
+               if (!buffer->skb) {
+                       if (netxen_alloc_rx_skb(adapter, rds_ring, buffer))
+                               break;
                }
 
                count++;
-               buffer = list_entry(head->next, struct netxen_rx_buffer, list);
                list_del(&buffer->list);
 
-               buffer->skb = skb;
-               buffer->state = NETXEN_BUFFER_BUSY;
-               buffer->dma = dma;
-
                /* make a rcv descriptor  */
                pdesc = &rds_ring->desc_head[producer];
                pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
                pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
                pdesc->addr_buffer = cpu_to_le64(buffer->dma);
 
-               producer = get_next_index(producer, rds_ring->max_rx_desc_count);
+               producer = get_next_index(producer, rds_ring->num_desc);
        }
 
-       /* if we did allocate buffers, then write the count to Phantom */
        if (count) {
                rds_ring->producer = producer;
-                       /* Window = 1 */
                adapter->pci_write_normalize(adapter,
                        rds_ring->crb_rcv_producer,
-                               (producer-1) & (rds_ring->max_rx_desc_count-1));
+                               (producer - 1) & (rds_ring->num_desc - 1));
                        wmb();
        }
+       spin_unlock(&rds_ring->lock);
 }
 
 void netxen_nic_clear_stats(struct netxen_adapter *adapter)
index 4fe20ecdbc6b075194d3f15aa50d8a904883c920..1af47257ba821d9a06c7e37d1a2b77425d01327e 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 - 2006 NetXen, Inc.
+ * Copyright (C) 2003 - 2009 NetXen, Inc.
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  *
  * Contact Information:
  *    info@netxen.com
- * NetXen,
- * 3965 Freedom Circle, Fourth floor,
- * Santa Clara, CA 95054
- *
- *
- *  Main source file for NetXen NIC Driver on Linux
+ * NetXen Inc,
+ * 18922 Forge Drive
+ * Cupertino, CA 95014-0701
  *
  */
 
@@ -97,20 +94,6 @@ static struct pci_device_id netxen_pci_tbl[] __devinitdata = {
 
 MODULE_DEVICE_TABLE(pci, netxen_pci_tbl);
 
-/*
- * In netxen_nic_down(), we must wait for any pending callback requests into
- * netxen_watchdog_task() to complete; eg otherwise the watchdog_timer could be
- * reenabled right after it is deleted in netxen_nic_down().
- * FLUSH_SCHEDULED_WORK()  does this synchronization.
- *
- * Normally, schedule_work()/flush_scheduled_work() could have worked, but
- * netxen_nic_close() is invoked with kernel rtnl lock held. netif_carrier_off()
- * call in netxen_nic_close() triggers a schedule_work(&linkwatch_work), and a
- * subsequent call to flush_scheduled_work() in netxen_nic_down() would cause
- * linkwatch_event() to be executed which also attempts to acquire the rtnl
- * lock thus causing a deadlock.
- */
-
 static struct workqueue_struct *netxen_workq;
 #define SCHEDULE_WORK(tp)      queue_work(netxen_workq, tp)
 #define FLUSH_SCHEDULED_WORK() flush_workqueue(netxen_workq)
@@ -152,130 +135,148 @@ static uint32_t msi_tgt_status[8] = {
 
 static struct netxen_legacy_intr_set legacy_intr[] = NX_LEGACY_INTR_CONFIG;
 
-static inline void netxen_nic_disable_int(struct netxen_adapter *adapter)
+static inline void netxen_nic_disable_int(struct nx_host_sds_ring *sds_ring)
 {
-       adapter->pci_write_normalize(adapter, adapter->crb_intr_mask, 0);
+       struct netxen_adapter *adapter = sds_ring->adapter;
+
+       adapter->pci_write_normalize(adapter, sds_ring->crb_intr_mask, 0);
 }
 
-static inline void netxen_nic_enable_int(struct netxen_adapter *adapter)
+static inline void netxen_nic_enable_int(struct nx_host_sds_ring *sds_ring)
 {
-       adapter->pci_write_normalize(adapter, adapter->crb_intr_mask, 0x1);
+       struct netxen_adapter *adapter = sds_ring->adapter;
+
+       adapter->pci_write_normalize(adapter, sds_ring->crb_intr_mask, 0x1);
 
        if (!NETXEN_IS_MSI_FAMILY(adapter))
                adapter->pci_write_immediate(adapter,
                                adapter->legacy_intr.tgt_mask_reg, 0xfbff);
 }
 
+static void
+netxen_napi_add(struct netxen_adapter *adapter, struct net_device *netdev)
+{
+       int ring;
+       struct nx_host_sds_ring *sds_ring;
+       struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
+
+       if (adapter->flags & NETXEN_NIC_MSIX_ENABLED)
+               adapter->max_sds_rings = (num_online_cpus() >= 4) ? 4 : 2;
+       else
+               adapter->max_sds_rings = 1;
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               netif_napi_add(netdev, &sds_ring->napi,
+                               netxen_nic_poll, NETXEN_NETDEV_WEIGHT);
+       }
+}
+
+static void
+netxen_napi_enable(struct netxen_adapter *adapter)
+{
+       int ring;
+       struct nx_host_sds_ring *sds_ring;
+       struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               napi_enable(&sds_ring->napi);
+               netxen_nic_enable_int(sds_ring);
+       }
+}
+
+static void
+netxen_napi_disable(struct netxen_adapter *adapter)
+{
+       int ring;
+       struct nx_host_sds_ring *sds_ring;
+       struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               netxen_nic_disable_int(sds_ring);
+               napi_disable(&sds_ring->napi);
+       }
+}
+
 static int nx_set_dma_mask(struct netxen_adapter *adapter, uint8_t revision_id)
 {
        struct pci_dev *pdev = adapter->pdev;
-       int err;
-       uint64_t mask;
-
-#ifdef CONFIG_IA64
-       adapter->dma_mask = DMA_32BIT_MASK;
-#else
-       if (revision_id >= NX_P3_B0) {
-               /* should go to DMA_64BIT_MASK */
-               adapter->dma_mask = DMA_39BIT_MASK;
-               mask = DMA_39BIT_MASK;
-       } else if (revision_id == NX_P3_A2) {
-               adapter->dma_mask = DMA_39BIT_MASK;
-               mask = DMA_39BIT_MASK;
-       } else if (revision_id == NX_P2_C1) {
-               adapter->dma_mask = DMA_35BIT_MASK;
-               mask = DMA_35BIT_MASK;
-       } else {
-               adapter->dma_mask = DMA_32BIT_MASK;
-               mask = DMA_32BIT_MASK;
-               goto set_32_bit_mask;
-       }
+       uint64_t mask, cmask;
+
+       adapter->pci_using_dac = 0;
 
+       mask = DMA_32BIT_MASK;
        /*
         * Consistent DMA mask is set to 32 bit because it cannot be set to
         * 35 bits. For P3 also leave it at 32 bits for now. Only the rings
         * come off this pool.
         */
+       cmask = DMA_32BIT_MASK;
+
+#ifndef CONFIG_IA64
+       if (revision_id >= NX_P3_B0)
+               mask = DMA_39BIT_MASK;
+       else if (revision_id == NX_P2_C1)
+               mask = DMA_35BIT_MASK;
+#endif
        if (pci_set_dma_mask(pdev, mask) == 0 &&
-               pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK) == 0) {
+               pci_set_consistent_dma_mask(pdev, cmask) == 0) {
                adapter->pci_using_dac = 1;
                return 0;
        }
-set_32_bit_mask:
-#endif /* CONFIG_IA64 */
 
-       err = pci_set_dma_mask(pdev, DMA_32BIT_MASK);
-       if (!err)
-               err = pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK);
-       if (err) {
-               DPRINTK(ERR, "No usable DMA configuration, aborting:%d\n", err);
-               return err;
+       return -EIO;
+}
+
+/* Update addressable range if firmware supports it */
+static int
+nx_update_dma_mask(struct netxen_adapter *adapter)
+{
+       int change, shift, err;
+       uint64_t mask, old_mask;
+       struct pci_dev *pdev = adapter->pdev;
+
+       change = 0;
+
+       shift = netxen_nic_reg_read(adapter, CRB_DMA_SHIFT);
+       if (shift >= 32)
+               return 0;
+
+       if (NX_IS_REVISION_P3(adapter->ahw.revision_id) && (shift > 9))
+               change = 1;
+       else if ((adapter->ahw.revision_id == NX_P2_C1) && (shift <= 4))
+               change = 1;
+
+       if (change) {
+               old_mask = pdev->dma_mask;
+               mask = (1ULL<<(32+shift)) - 1;
+
+               err = pci_set_dma_mask(pdev, mask);
+               if (err)
+                       return pci_set_dma_mask(pdev, old_mask);
        }
 
-       adapter->pci_using_dac = 0;
        return 0;
 }
 
 static void netxen_check_options(struct netxen_adapter *adapter)
 {
-       switch (adapter->ahw.boardcfg.board_type) {
-       case NETXEN_BRDTYPE_P3_HMEZ:
-       case NETXEN_BRDTYPE_P3_XG_LOM:
-       case NETXEN_BRDTYPE_P3_10G_CX4:
-       case NETXEN_BRDTYPE_P3_10G_CX4_LP:
-       case NETXEN_BRDTYPE_P3_IMEZ:
-       case NETXEN_BRDTYPE_P3_10G_SFP_PLUS:
-       case NETXEN_BRDTYPE_P3_10G_SFP_QT:
-       case NETXEN_BRDTYPE_P3_10G_SFP_CT:
-       case NETXEN_BRDTYPE_P3_10G_XFP:
-       case NETXEN_BRDTYPE_P3_10000_BASE_T:
-               adapter->msix_supported = !!use_msi_x;
-               adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_10G;
-               break;
+       if (adapter->ahw.port_type == NETXEN_NIC_XGBE)
+               adapter->num_rxd = MAX_RCV_DESCRIPTORS_10G;
+       else if (adapter->ahw.port_type == NETXEN_NIC_GBE)
+               adapter->num_rxd = MAX_RCV_DESCRIPTORS_1G;
 
-       case NETXEN_BRDTYPE_P2_SB31_10G:
-       case NETXEN_BRDTYPE_P2_SB31_10G_CX4:
-       case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ:
-       case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ:
-               adapter->msix_supported = 0;
-               adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_10G;
-               break;
-
-       case NETXEN_BRDTYPE_P3_REF_QG:
-       case NETXEN_BRDTYPE_P3_4_GB:
-       case NETXEN_BRDTYPE_P3_4_GB_MM:
+       if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
                adapter->msix_supported = !!use_msi_x;
-               adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
-               break;
-
-       case NETXEN_BRDTYPE_P2_SB35_4G:
-       case NETXEN_BRDTYPE_P2_SB31_2G:
+       else
                adapter->msix_supported = 0;
-               adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
-               break;
-
-       case NETXEN_BRDTYPE_P3_10G_TP:
-               adapter->msix_supported = !!use_msi_x;
-               if (adapter->ahw.board_type == NETXEN_NIC_XGBE)
-                       adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_10G;
-               else
-                       adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
-               break;
 
-       default:
-               adapter->msix_supported = 0;
-               adapter->max_rx_desc_count = MAX_RCV_DESCRIPTORS_1G;
+       adapter->num_txd = MAX_CMD_DESCRIPTORS_HOST;
+       adapter->num_jumbo_rxd = MAX_JUMBO_RCV_DESCRIPTORS;
+       adapter->num_lro_rxd = MAX_LRO_RCV_DESCRIPTORS;
 
-               printk(KERN_WARNING "Unknown board type(0x%x)\n",
-                               adapter->ahw.boardcfg.board_type);
-               break;
-       }
-
-       adapter->max_tx_desc_count = MAX_CMD_DESCRIPTORS_HOST;
-       adapter->max_jumbo_rx_desc_count = MAX_JUMBO_RCV_DESCRIPTORS;
-       adapter->max_lro_rx_desc_count = MAX_LRO_RCV_DESCRIPTORS;
-
-       adapter->max_possible_rss_rings = 1;
        return;
 }
 
@@ -336,7 +337,7 @@ static void netxen_set_port_mode(struct netxen_adapter *adapter)
 {
        u32 val, data;
 
-       val = adapter->ahw.boardcfg.board_type;
+       val = adapter->ahw.board_type;
        if ((val == NETXEN_BRDTYPE_P3_HMEZ) ||
                (val == NETXEN_BRDTYPE_P3_XG_LOM)) {
                if (port_mode == NETXEN_PORT_MODE_802_3_AP) {
@@ -405,9 +406,6 @@ netxen_read_mac_addr(struct netxen_adapter *adapter)
        struct net_device *netdev = adapter->netdev;
        struct pci_dev *pdev = adapter->pdev;
 
-       if (netxen_is_flash_supported(adapter) != 0)
-               return -EIO;
-
        if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
                if (netxen_p3_get_mac_addr(adapter, &mac_addr) != 0)
                        return -EIO;
@@ -457,91 +455,91 @@ static const struct net_device_ops netxen_netdev_ops = {
 #endif
 };
 
-/*
- * netxen_nic_probe()
- *
- * The Linux system will invoke this after identifying the vendor ID and
- * device Id in the pci_tbl supported by this module.
- *
- * A quad port card has one operational PCI config space, (function 0),
- * which is used to access all four ports.
- *
- * This routine will initialize the adapter, and setup the global parameters
- * along with the port's specific structure.
- */
-static int __devinit
-netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+static void
+netxen_setup_intr(struct netxen_adapter *adapter)
 {
-       struct net_device *netdev = NULL;
-       struct netxen_adapter *adapter = NULL;
-       void __iomem *mem_ptr0 = NULL;
-       void __iomem *mem_ptr1 = NULL;
-       void __iomem *mem_ptr2 = NULL;
-       unsigned long first_page_group_end;
-       unsigned long first_page_group_start;
+       struct netxen_legacy_intr_set *legacy_intrp;
+       struct pci_dev *pdev = adapter->pdev;
 
+       adapter->flags &= ~(NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED);
+       adapter->intr_scheme = -1;
+       adapter->msi_mode = -1;
 
-       u8 __iomem *db_ptr = NULL;
-       unsigned long mem_base, mem_len, db_base, db_len, pci_len0 = 0;
-       int i = 0, err;
-       int first_driver, first_boot;
-       u32 val;
-       int pci_func_id = PCI_FUNC(pdev->devfn);
-       struct netxen_legacy_intr_set *legacy_intrp;
-       uint8_t revision_id;
+       if (adapter->ahw.revision_id >= NX_P3_B0)
+               legacy_intrp = &legacy_intr[adapter->ahw.pci_func];
+       else
+               legacy_intrp = &legacy_intr[0];
+       adapter->legacy_intr.int_vec_bit = legacy_intrp->int_vec_bit;
+       adapter->legacy_intr.tgt_status_reg = legacy_intrp->tgt_status_reg;
+       adapter->legacy_intr.tgt_mask_reg = legacy_intrp->tgt_mask_reg;
+       adapter->legacy_intr.pci_int_reg = legacy_intrp->pci_int_reg;
 
-       if (pci_func_id == 0)
-               printk(KERN_INFO "%s\n", netxen_nic_driver_string);
+       netxen_set_msix_bit(pdev, 0);
 
-       if (pdev->class != 0x020000) {
-               printk(KERN_DEBUG "NetXen function %d, class %x will not "
-                               "be enabled.\n",pci_func_id, pdev->class);
-               return -ENODEV;
-       }
+       if (adapter->msix_supported) {
 
-       if (pdev->revision >= NX_P3_A0 && pdev->revision < NX_P3_B1) {
-               printk(KERN_WARNING "NetXen chip revisions between 0x%x-0x%x"
-                               "will not be enabled.\n",
-                               NX_P3_A0, NX_P3_B1);
-               return -ENODEV;
-       }
+               netxen_init_msix_entries(adapter);
+               if (pci_enable_msix(pdev, adapter->msix_entries,
+                                       MSIX_ENTRIES_PER_ADAPTER))
+                       goto request_msi;
 
-       if ((err = pci_enable_device(pdev)))
-               return err;
+               adapter->flags |= NETXEN_NIC_MSIX_ENABLED;
+               netxen_set_msix_bit(pdev, 1);
+               dev_info(&pdev->dev, "using msi-x interrupts\n");
 
-       if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
-               err = -ENODEV;
-               goto err_out_disable_pdev;
+       } else {
+request_msi:
+               if (use_msi && !pci_enable_msi(pdev)) {
+                       adapter->flags |= NETXEN_NIC_MSI_ENABLED;
+                       dev_info(&pdev->dev, "using msi interrupts\n");
+               } else
+                       dev_info(&pdev->dev, "using legacy interrupts\n");
+               adapter->msix_entries[0].vector = pdev->irq;
        }
+}
 
-       if ((err = pci_request_regions(pdev, netxen_nic_driver_name)))
-               goto err_out_disable_pdev;
-
-       pci_set_master(pdev);
+static void
+netxen_teardown_intr(struct netxen_adapter *adapter)
+{
+       if (adapter->flags & NETXEN_NIC_MSIX_ENABLED)
+               pci_disable_msix(adapter->pdev);
+       if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
+               pci_disable_msi(adapter->pdev);
+}
 
-       netdev = alloc_etherdev(sizeof(struct netxen_adapter));
-       if(!netdev) {
-               printk(KERN_ERR"%s: Failed to allocate memory for the "
-                               "device block.Check system memory resource"
-                               " usage.\n", netxen_nic_driver_name);
-               goto err_out_free_res;
-       }
+static void
+netxen_cleanup_pci_map(struct netxen_adapter *adapter)
+{
+       if (adapter->ahw.db_base != NULL)
+               iounmap(adapter->ahw.db_base);
+       if (adapter->ahw.pci_base0 != NULL)
+               iounmap(adapter->ahw.pci_base0);
+       if (adapter->ahw.pci_base1 != NULL)
+               iounmap(adapter->ahw.pci_base1);
+       if (adapter->ahw.pci_base2 != NULL)
+               iounmap(adapter->ahw.pci_base2);
+}
 
-       SET_NETDEV_DEV(netdev, &pdev->dev);
+static int
+netxen_setup_pci_map(struct netxen_adapter *adapter)
+{
+       void __iomem *mem_ptr0 = NULL;
+       void __iomem *mem_ptr1 = NULL;
+       void __iomem *mem_ptr2 = NULL;
+       void __iomem *db_ptr = NULL;
 
-       adapter = netdev_priv(netdev);
-       adapter->netdev  = netdev;
-       adapter->pdev    = pdev;
-       adapter->ahw.pci_func  = pci_func_id;
+       unsigned long mem_base, mem_len, db_base, db_len = 0, pci_len0 = 0;
 
-       revision_id = pdev->revision;
-       adapter->ahw.revision_id = revision_id;
+       struct pci_dev *pdev = adapter->pdev;
+       int pci_func = adapter->ahw.pci_func;
 
-       err = nx_set_dma_mask(adapter, revision_id);
-       if (err)
-               goto err_out_free_netdev;
+       int err = 0;
 
-       rwlock_init(&adapter->adapter_lock);
+       /*
+        * Set the CRB window to invalid. If any register in window 0 is
+        * accessed it should set the window to 0 and then reset it to 1.
+        */
+       adapter->curr_window = 255;
        adapter->ahw.qdr_sn_window = -1;
        adapter->ahw.ddr_mn_window = -1;
 
@@ -567,14 +565,10 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                                SECOND_PAGE_GROUP_SIZE);
                mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START,
                                THIRD_PAGE_GROUP_SIZE);
-               first_page_group_start = FIRST_PAGE_GROUP_START;
-               first_page_group_end   = FIRST_PAGE_GROUP_END;
        } else if (mem_len == NETXEN_PCI_32MB_SIZE) {
                mem_ptr1 = ioremap(mem_base, SECOND_PAGE_GROUP_SIZE);
                mem_ptr2 = ioremap(mem_base + THIRD_PAGE_GROUP_START -
                        SECOND_PAGE_GROUP_START, THIRD_PAGE_GROUP_SIZE);
-               first_page_group_start = 0;
-               first_page_group_end   = 0;
        } else if (mem_len == NETXEN_PCI_2MB_SIZE) {
                adapter->hw_write_wx = netxen_nic_hw_write_wx_2M;
                adapter->hw_read_wx = netxen_nic_hw_read_wx_2M;
@@ -588,79 +582,388 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                adapter->pci_mem_read = netxen_nic_pci_mem_read_2M;
                adapter->pci_mem_write = netxen_nic_pci_mem_write_2M;
 
-               mem_ptr0 = ioremap(mem_base, mem_len);
-               pci_len0 = mem_len;
-               first_page_group_start = 0;
-               first_page_group_end   = 0;
+               mem_ptr0 = pci_ioremap_bar(pdev, 0);
+               if (mem_ptr0 == NULL) {
+                       dev_err(&pdev->dev, "failed to map PCI bar 0\n");
+                       return -EIO;
+               }
+               pci_len0 = mem_len;
+
+               adapter->ahw.ddr_mn_window = 0;
+               adapter->ahw.qdr_sn_window = 0;
+
+               adapter->ahw.mn_win_crb = 0x100000 + PCIX_MN_WINDOW +
+                       (pci_func * 0x20);
+               adapter->ahw.ms_win_crb = 0x100000 + PCIX_SN_WINDOW;
+               if (pci_func < 4)
+                       adapter->ahw.ms_win_crb += (pci_func * 0x20);
+               else
+                       adapter->ahw.ms_win_crb +=
+                                       0xA0 + ((pci_func - 4) * 0x10);
+       } else {
+               return -EIO;
+       }
+
+       dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20));
+
+       adapter->ahw.pci_base0 = mem_ptr0;
+       adapter->ahw.pci_len0 = pci_len0;
+       adapter->ahw.pci_base1 = mem_ptr1;
+       adapter->ahw.pci_base2 = mem_ptr2;
+
+       if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+               goto skip_doorbell;
+
+       db_base = pci_resource_start(pdev, 4);  /* doorbell is on bar 4 */
+       db_len = pci_resource_len(pdev, 4);
+
+       if (db_len == 0) {
+               printk(KERN_ERR "%s: doorbell is disabled\n",
+                               netxen_nic_driver_name);
+               err = -EIO;
+               goto err_out;
+       }
+
+       db_ptr = ioremap(db_base, NETXEN_DB_MAPSIZE_BYTES);
+       if (!db_ptr) {
+               printk(KERN_ERR "%s: Failed to allocate doorbell map.",
+                               netxen_nic_driver_name);
+               err = -EIO;
+               goto err_out;
+       }
+
+skip_doorbell:
+       adapter->ahw.db_base = db_ptr;
+       adapter->ahw.db_len = db_len;
+       return 0;
+
+err_out:
+       netxen_cleanup_pci_map(adapter);
+       return err;
+}
+
+static int
+netxen_start_firmware(struct netxen_adapter *adapter)
+{
+       int val, err, first_boot;
+       struct pci_dev *pdev = adapter->pdev;
+
+       int first_driver = 0;
+       if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
+               if (adapter->ahw.pci_func == 0)
+                       first_driver = 1;
+       } else {
+               if (adapter->portnum == 0)
+                       first_driver = 1;
+       }
+
+       if (!first_driver)
+               return 0;
+
+       first_boot = adapter->pci_read_normalize(adapter,
+                       NETXEN_CAM_RAM(0x1fc));
+
+       err = netxen_check_hw_init(adapter, first_boot);
+       if (err) {
+               dev_err(&pdev->dev, "error in init HW init sequence\n");
+               return err;
+       }
+
+       if (first_boot != 0x55555555) {
+               adapter->pci_write_normalize(adapter,
+                                       CRB_CMDPEG_STATE, 0);
+               netxen_pinit_from_rom(adapter, 0);
+               msleep(1);
+       }
+
+       netxen_nic_reg_write(adapter, CRB_DMA_SHIFT, 0x55555555);
+       if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
+               netxen_set_port_mode(adapter);
+
+       netxen_load_firmware(adapter);
+
+       if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
+
+               /* Initialize multicast addr pool owners */
+               val = 0x7654;
+               if (adapter->ahw.port_type == NETXEN_NIC_XGBE)
+                       val |= 0x0f000000;
+               netxen_crb_writelit_adapter(adapter,
+                               NETXEN_MAC_ADDR_CNTL_REG, val);
+
+       }
+
+       err = netxen_initialize_adapter_offload(adapter);
+       if (err)
+               return err;
+
+       /*
+        * Tell the hardware our version number.
+        */
+       val = (_NETXEN_NIC_LINUX_MAJOR << 16)
+               | ((_NETXEN_NIC_LINUX_MINOR << 8))
+               | (_NETXEN_NIC_LINUX_SUBVERSION);
+       adapter->pci_write_normalize(adapter, CRB_DRIVER_VERSION, val);
+
+       /* Handshake with the card before we register the devices. */
+       err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
+       if (err) {
+               netxen_free_adapter_offload(adapter);
+               return err;
+       }
+
+       return 0;
+}
+
+static int
+netxen_nic_request_irq(struct netxen_adapter *adapter)
+{
+       irq_handler_t handler;
+       struct nx_host_sds_ring *sds_ring;
+       int err, ring;
+
+       unsigned long flags = IRQF_SAMPLE_RANDOM;
+       struct net_device *netdev = adapter->netdev;
+       struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
+
+       if ((adapter->msi_mode != MSI_MODE_MULTIFUNC) ||
+               (adapter->intr_scheme != INTR_SCHEME_PERPORT)) {
+               printk(KERN_ERR "%s: Firmware interrupt scheme is "
+                               "incompatible with driver\n",
+                               netdev->name);
+               adapter->driver_mismatch = 1;
+               return -EINVAL;
+       }
+
+       if (adapter->flags & NETXEN_NIC_MSIX_ENABLED)
+               handler = netxen_msix_intr;
+       else if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
+               handler = netxen_msi_intr;
+       else {
+               flags |= IRQF_SHARED;
+               handler = netxen_intr;
+       }
+       adapter->irq = netdev->irq;
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               sprintf(sds_ring->name, "%16s[%d]", netdev->name, ring);
+               err = request_irq(sds_ring->irq, handler,
+                                 flags, sds_ring->name, sds_ring);
+               if (err)
+                       return err;
+       }
+
+       return 0;
+}
+
+static void
+netxen_nic_free_irq(struct netxen_adapter *adapter)
+{
+       int ring;
+       struct nx_host_sds_ring *sds_ring;
+
+       struct netxen_recv_context *recv_ctx = &adapter->recv_ctx;
+
+       for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+               sds_ring = &recv_ctx->sds_rings[ring];
+               free_irq(sds_ring->irq, sds_ring);
+       }
+}
+
+static int
+netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev)
+{
+       int err;
+
+       err = adapter->init_port(adapter, adapter->physical_port);
+       if (err) {
+               printk(KERN_ERR "%s: Failed to initialize port %d\n",
+                               netxen_nic_driver_name, adapter->portnum);
+               return err;
+       }
+       adapter->macaddr_set(adapter, netdev->dev_addr);
+
+       netxen_nic_set_link_parameters(adapter);
+
+       netxen_set_multicast_list(netdev);
+       if (adapter->set_mtu)
+               adapter->set_mtu(adapter, netdev->mtu);
+
+       adapter->ahw.linkup = 0;
+       mod_timer(&adapter->watchdog_timer, jiffies);
+
+       netxen_napi_enable(adapter);
+
+       if (adapter->max_sds_rings > 1)
+               netxen_config_rss(adapter, 1);
+
+       return 0;
+}
+
+static void
+netxen_nic_down(struct netxen_adapter *adapter, struct net_device *netdev)
+{
+       netif_carrier_off(netdev);
+       netif_stop_queue(netdev);
+       netxen_napi_disable(adapter);
+
+       if (adapter->stop_port)
+               adapter->stop_port(adapter);
+
+       netxen_release_tx_buffers(adapter);
+
+       FLUSH_SCHEDULED_WORK();
+       del_timer_sync(&adapter->watchdog_timer);
+}
+
+
+static int
+netxen_nic_attach(struct netxen_adapter *adapter)
+{
+       struct net_device *netdev = adapter->netdev;
+       struct pci_dev *pdev = adapter->pdev;
+       int err, ring;
+       struct nx_host_rds_ring *rds_ring;
+
+       err = netxen_init_firmware(adapter);
+       if (err != 0) {
+               printk(KERN_ERR "Failed to init firmware\n");
+               return -EIO;
+       }
+
+       if (adapter->fw_major < 4)
+               adapter->max_rds_rings = 3;
+       else
+               adapter->max_rds_rings = 2;
+
+       err = netxen_alloc_sw_resources(adapter);
+       if (err) {
+               printk(KERN_ERR "%s: Error in setting sw resources\n",
+                               netdev->name);
+               return err;
+       }
+
+       netxen_nic_clear_stats(adapter);
+
+       err = netxen_alloc_hw_resources(adapter);
+       if (err) {
+               printk(KERN_ERR "%s: Error in setting hw resources\n",
+                               netdev->name);
+               goto err_out_free_sw;
+       }
+
+       if (adapter->fw_major < 4) {
+               adapter->crb_addr_cmd_producer =
+                       crb_cmd_producer[adapter->portnum];
+               adapter->crb_addr_cmd_consumer =
+                       crb_cmd_consumer[adapter->portnum];
+
+               netxen_nic_update_cmd_producer(adapter, 0);
+               netxen_nic_update_cmd_consumer(adapter, 0);
+       }
+
+       for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+               rds_ring = &adapter->recv_ctx.rds_rings[ring];
+               netxen_post_rx_buffers(adapter, ring, rds_ring);
+       }
+
+       err = netxen_nic_request_irq(adapter);
+       if (err) {
+               dev_err(&pdev->dev, "%s: failed to setup interrupt\n",
+                               netdev->name);
+               goto err_out_free_rxbuf;
+       }
+
+       adapter->is_up = NETXEN_ADAPTER_UP_MAGIC;
+       return 0;
+
+err_out_free_rxbuf:
+       netxen_release_rx_buffers(adapter);
+       netxen_free_hw_resources(adapter);
+err_out_free_sw:
+       netxen_free_sw_resources(adapter);
+       return err;
+}
+
+static void
+netxen_nic_detach(struct netxen_adapter *adapter)
+{
+       netxen_nic_free_irq(adapter);
+
+       netxen_release_rx_buffers(adapter);
+       netxen_free_hw_resources(adapter);
+       netxen_free_sw_resources(adapter);
+
+       adapter->is_up = 0;
+}
+
+static int __devinit
+netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
+{
+       struct net_device *netdev = NULL;
+       struct netxen_adapter *adapter = NULL;
+       int i = 0, err;
+       int pci_func_id = PCI_FUNC(pdev->devfn);
+       uint8_t revision_id;
+
+       if (pdev->class != 0x020000) {
+               printk(KERN_DEBUG "NetXen function %d, class %x will not "
+                               "be enabled.\n",pci_func_id, pdev->class);
+               return -ENODEV;
+       }
 
-               adapter->ahw.ddr_mn_window = 0;
-               adapter->ahw.qdr_sn_window = 0;
+       if (pdev->revision >= NX_P3_A0 && pdev->revision < NX_P3_B1) {
+               printk(KERN_WARNING "NetXen chip revisions between 0x%x-0x%x"
+                               "will not be enabled.\n",
+                               NX_P3_A0, NX_P3_B1);
+               return -ENODEV;
+       }
 
-               adapter->ahw.mn_win_crb = 0x100000 + PCIX_MN_WINDOW +
-                       (pci_func_id * 0x20);
-               adapter->ahw.ms_win_crb = 0x100000 + PCIX_SN_WINDOW;
-               if (pci_func_id < 4)
-                       adapter->ahw.ms_win_crb += (pci_func_id * 0x20);
-               else
-                       adapter->ahw.ms_win_crb +=
-                                       0xA0 + ((pci_func_id - 4) * 0x10);
-       } else {
-               err = -EIO;
-               goto err_out_free_netdev;
+       if ((err = pci_enable_device(pdev)))
+               return err;
+
+       if (!(pci_resource_flags(pdev, 0) & IORESOURCE_MEM)) {
+               err = -ENODEV;
+               goto err_out_disable_pdev;
        }
 
-       dev_info(&pdev->dev, "%dMB memory map\n", (int)(mem_len>>20));
+       if ((err = pci_request_regions(pdev, netxen_nic_driver_name)))
+               goto err_out_disable_pdev;
 
-       db_base = pci_resource_start(pdev, 4);  /* doorbell is on bar 4 */
-       db_len = pci_resource_len(pdev, 4);
+       pci_set_master(pdev);
 
-       if (db_len == 0) {
-               printk(KERN_ERR "%s: doorbell is disabled\n",
-                               netxen_nic_driver_name);
-               err = -EIO;
-               goto err_out_iounmap;
+       netdev = alloc_etherdev(sizeof(struct netxen_adapter));
+       if(!netdev) {
+               printk(KERN_ERR"%s: Failed to allocate memory for the "
+                               "device block.Check system memory resource"
+                               " usage.\n", netxen_nic_driver_name);
+               goto err_out_free_res;
        }
-       DPRINTK(INFO, "doorbell ioremap from %lx a size of %lx\n", db_base,
-               db_len);
 
-       db_ptr = ioremap(db_base, NETXEN_DB_MAPSIZE_BYTES);
-       if (!db_ptr) {
-               printk(KERN_ERR "%s: Failed to allocate doorbell map.",
-                               netxen_nic_driver_name);
-               err = -EIO;
-               goto err_out_iounmap;
-       }
-       DPRINTK(INFO, "doorbell ioremaped at %p\n", db_ptr);
+       SET_NETDEV_DEV(netdev, &pdev->dev);
 
-       adapter->ahw.pci_base0 = mem_ptr0;
-       adapter->ahw.pci_len0 = pci_len0;
-       adapter->ahw.first_page_group_start = first_page_group_start;
-       adapter->ahw.first_page_group_end   = first_page_group_end;
-       adapter->ahw.pci_base1 = mem_ptr1;
-       adapter->ahw.pci_base2 = mem_ptr2;
-       adapter->ahw.db_base = db_ptr;
-       adapter->ahw.db_len = db_len;
+       adapter = netdev_priv(netdev);
+       adapter->netdev  = netdev;
+       adapter->pdev    = pdev;
+       adapter->ahw.pci_func  = pci_func_id;
 
-       netif_napi_add(netdev, &adapter->napi,
-                       netxen_nic_poll, NETXEN_NETDEV_WEIGHT);
+       revision_id = pdev->revision;
+       adapter->ahw.revision_id = revision_id;
 
-       if (revision_id >= NX_P3_B0)
-               legacy_intrp = &legacy_intr[pci_func_id];
-       else
-               legacy_intrp = &legacy_intr[0];
+       err = nx_set_dma_mask(adapter, revision_id);
+       if (err)
+               goto err_out_free_netdev;
 
-       adapter->legacy_intr.int_vec_bit = legacy_intrp->int_vec_bit;
-       adapter->legacy_intr.tgt_status_reg = legacy_intrp->tgt_status_reg;
-       adapter->legacy_intr.tgt_mask_reg = legacy_intrp->tgt_mask_reg;
-       adapter->legacy_intr.pci_int_reg = legacy_intrp->pci_int_reg;
+       rwlock_init(&adapter->adapter_lock);
+       spin_lock_init(&adapter->tx_clean_lock);
 
-       /* this will be read from FW later */
-       adapter->intr_scheme = -1;
-       adapter->msi_mode = -1;
+       err = netxen_setup_pci_map(adapter);
+       if (err)
+               goto err_out_free_netdev;
 
        /* This will be reset for mezz cards  */
        adapter->portnum = pci_func_id;
-       adapter->status   &= ~NETXEN_NETDEV_STATUS;
        adapter->rx_csum = 1;
        adapter->mc_enabled = 0;
        if (NX_IS_REVISION_P3(revision_id))
@@ -688,12 +991,6 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                netdev->vlan_features |= NETIF_F_HIGHDMA;
        }
 
-       /*
-        * Set the CRB window to invalid. If any register in window 0 is
-        * accessed it should set the window to 0 and then reset it to 1.
-        */
-       adapter->curr_window = 255;
-
        if (netxen_nic_get_board_info(adapter) != 0) {
                printk("%s: Error getting board config info.\n",
                                netxen_nic_driver_name);
@@ -704,7 +1001,7 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        netxen_initialize_adapter_ops(adapter);
 
        /* Mezz cards have PCI function 0,2,3 enabled */
-       switch (adapter->ahw.boardcfg.board_type) {
+       switch (adapter->ahw.board_type) {
        case NETXEN_BRDTYPE_P2_SB31_10G_IMEZ:
        case NETXEN_BRDTYPE_P2_SB31_10G_HMEZ:
                if (pci_func_id >= 2)
@@ -714,126 +1011,32 @@ netxen_nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
                break;
        }
 
-       /*
-        * This call will setup various max rx/tx counts.
-        * It must be done before any buffer/ring allocations.
-        */
-       netxen_check_options(adapter);
-
-       first_driver = 0;
-       if (NX_IS_REVISION_P3(revision_id)) {
-               if (adapter->ahw.pci_func == 0)
-                       first_driver = 1;
-       } else {
-               if (adapter->portnum == 0)
-                       first_driver = 1;
-       }
-
-       if (first_driver) {
-               first_boot = adapter->pci_read_normalize(adapter,
-                               NETXEN_CAM_RAM(0x1fc));
-
-               err = netxen_check_hw_init(adapter, first_boot);
-               if (err) {
-                       printk(KERN_ERR "%s: error in init HW init sequence\n",
-                                       netxen_nic_driver_name);
-                       goto err_out_iounmap;
-               }
-
-               if (NX_IS_REVISION_P3(revision_id))
-                       netxen_set_port_mode(adapter);
-
-               if (first_boot != 0x55555555) {
-                       adapter->pci_write_normalize(adapter,
-                                               CRB_CMDPEG_STATE, 0);
-                       netxen_pinit_from_rom(adapter, 0);
-                       msleep(1);
-               }
-               netxen_load_firmware(adapter);
-
-               if (NX_IS_REVISION_P2(revision_id)) {
-
-                       /* Initialize multicast addr pool owners */
-                       val = 0x7654;
-                       if (adapter->ahw.board_type == NETXEN_NIC_XGBE)
-                               val |= 0x0f000000;
-                       netxen_crb_writelit_adapter(adapter,
-                                       NETXEN_MAC_ADDR_CNTL_REG, val);
-
-               }
-
-               err = netxen_initialize_adapter_offload(adapter);
-               if (err)
-                       goto err_out_iounmap;
-
-               /*
-                * Tell the hardware our version number.
-                */
-               i = (_NETXEN_NIC_LINUX_MAJOR << 16)
-                       | ((_NETXEN_NIC_LINUX_MINOR << 8))
-                       | (_NETXEN_NIC_LINUX_SUBVERSION);
-               adapter->pci_write_normalize(adapter, CRB_DRIVER_VERSION, i);
-
-               /* Handshake with the card before we register the devices. */
-               err = netxen_phantom_init(adapter, NETXEN_NIC_PEG_TUNE);
-               if (err)
-                       goto err_out_free_offload;
-
-       }       /* first_driver */
+       err = netxen_start_firmware(adapter);
+       if (err)
+               goto err_out_iounmap;
 
-       netxen_nic_flash_print(adapter);
+       nx_update_dma_mask(adapter);
 
-       if (NX_IS_REVISION_P3(revision_id)) {
-               adapter->hw_read_wx(adapter,
-                               NETXEN_MIU_MN_CONTROL, &val, 4);
-               adapter->ahw.cut_through = (val & 0x4) ? 1 : 0;
-               dev_info(&pdev->dev, "firmware running in %s mode\n",
-               adapter->ahw.cut_through ? "cut through" : "legacy");
-       }
+       netxen_nic_get_firmware_info(adapter);
 
        /*
         * See if the firmware gave us a virtual-physical port mapping.
         */
        adapter->physical_port = adapter->portnum;
-       i = adapter->pci_read_normalize(adapter, CRB_V2P(adapter->portnum));
-       if (i != 0x55555555)
-               adapter->physical_port = i;
-
-       adapter->flags &= ~(NETXEN_NIC_MSI_ENABLED | NETXEN_NIC_MSIX_ENABLED);
-
-       netxen_set_msix_bit(pdev, 0);
-
-       if (NX_IS_REVISION_P3(revision_id)) {
-               if ((mem_len != NETXEN_PCI_128MB_SIZE) &&
-                       mem_len != NETXEN_PCI_2MB_SIZE)
-                       adapter->msix_supported = 0;
+       if (adapter->fw_major < 4) {
+               i = adapter->pci_read_normalize(adapter,
+                               CRB_V2P(adapter->portnum));
+               if (i != 0x55555555)
+                       adapter->physical_port = i;
        }
 
-       if (adapter->msix_supported) {
-
-               netxen_init_msix_entries(adapter);
-
-               if (pci_enable_msix(pdev, adapter->msix_entries,
-                                       MSIX_ENTRIES_PER_ADAPTER))
-                       goto request_msi;
+       netxen_check_options(adapter);
 
-               adapter->flags |= NETXEN_NIC_MSIX_ENABLED;
-               netxen_set_msix_bit(pdev, 1);
-               dev_info(&pdev->dev, "using msi-x interrupts\n");
+       netxen_setup_intr(adapter);
 
-       } else {
-request_msi:
-               if (use_msi && !pci_enable_msi(pdev)) {
-                       adapter->flags |= NETXEN_NIC_MSI_ENABLED;
-                       dev_info(&pdev->dev, "using msi interrupts\n");
-               } else
-                       dev_info(&pdev->dev, "using legacy interrupts\n");
-       }
+       netdev->irq = adapter->msix_entries[0].vector;
 
-       if (adapter->flags & NETXEN_NIC_MSIX_ENABLED)
-               netdev->irq = adapter->msix_entries[0].vector;
-       else
-               netdev->irq = pdev->irq;
+       netxen_napi_add(adapter, netdev);
 
        err = netxen_receive_peg_ready(adapter);
        if (err)
@@ -862,7 +1065,7 @@ request_msi:
 
        pci_set_drvdata(pdev, adapter);
 
-       switch (adapter->ahw.board_type) {
+       switch (adapter->ahw.port_type) {
        case NETXEN_NIC_GBE:
                dev_info(&adapter->pdev->dev, "%s: GbE port initialized\n",
                                adapter->netdev->name);
@@ -876,25 +1079,12 @@ request_msi:
        return 0;
 
 err_out_disable_msi:
-       if (adapter->flags & NETXEN_NIC_MSIX_ENABLED)
-               pci_disable_msix(pdev);
-       if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
-               pci_disable_msi(pdev);
+       netxen_teardown_intr(adapter);
 
-err_out_free_offload:
-       if (first_driver)
-               netxen_free_adapter_offload(adapter);
+       netxen_free_adapter_offload(adapter);
 
 err_out_iounmap:
-       if (db_ptr)
-               iounmap(db_ptr);
-
-       if (mem_ptr0)
-               iounmap(mem_ptr0);
-       if (mem_ptr1)
-               iounmap(mem_ptr1);
-       if (mem_ptr2)
-               iounmap(mem_ptr2);
+       netxen_cleanup_pci_map(adapter);
 
 err_out_free_netdev:
        free_netdev(netdev);
@@ -922,9 +1112,7 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
        unregister_netdev(netdev);
 
        if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC) {
-               netxen_free_hw_resources(adapter);
-               netxen_release_rx_buffers(adapter);
-               netxen_free_sw_resources(adapter);
+               netxen_nic_detach(adapter);
 
                if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
                        netxen_p3_free_mac_list(adapter);
@@ -933,20 +1121,9 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
        if (adapter->portnum == 0)
                netxen_free_adapter_offload(adapter);
 
-       if (adapter->irq)
-               free_irq(adapter->irq, adapter);
+       netxen_teardown_intr(adapter);
 
-       if (adapter->flags & NETXEN_NIC_MSIX_ENABLED)
-               pci_disable_msix(pdev);
-       if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
-               pci_disable_msi(pdev);
-
-       iounmap(adapter->ahw.db_base);
-       iounmap(adapter->ahw.pci_base0);
-       if (adapter->ahw.pci_base1 != NULL)
-               iounmap(adapter->ahw.pci_base1);
-       if (adapter->ahw.pci_base2 != NULL)
-               iounmap(adapter->ahw.pci_base2);
+       netxen_cleanup_pci_map(adapter);
 
        pci_release_regions(pdev);
        pci_disable_device(pdev);
@@ -955,125 +1132,95 @@ static void __devexit netxen_nic_remove(struct pci_dev *pdev)
        free_netdev(netdev);
 }
 
-/*
- * Called when a network interface is made active
- * @returns 0 on success, negative value on failure
- */
-static int netxen_nic_open(struct net_device *netdev)
+static int
+netxen_nic_suspend(struct pci_dev *pdev, pm_message_t state)
 {
-       struct netxen_adapter *adapter = netdev_priv(netdev);
-       int err = 0;
-       int ctx, ring;
-       irq_handler_t handler;
-       unsigned long flags = IRQF_SAMPLE_RANDOM;
 
-       if (adapter->driver_mismatch)
-               return -EIO;
+       struct netxen_adapter *adapter = pci_get_drvdata(pdev);
+       struct net_device *netdev = adapter->netdev;
 
-       if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) {
-               err = netxen_init_firmware(adapter);
-               if (err != 0) {
-                       printk(KERN_ERR "Failed to init firmware\n");
-                       return -EIO;
-               }
+       netif_device_detach(netdev);
 
-               if (adapter->fw_major < 4)
-                       adapter->max_rds_rings = 3;
-               else
-                       adapter->max_rds_rings = 2;
+       if (netif_running(netdev))
+               netxen_nic_down(adapter, netdev);
 
-               err = netxen_alloc_sw_resources(adapter);
-               if (err) {
-                       printk(KERN_ERR "%s: Error in setting sw resources\n",
-                                       netdev->name);
-                       return err;
-               }
+       if (adapter->is_up == NETXEN_ADAPTER_UP_MAGIC)
+               netxen_nic_detach(adapter);
 
-               netxen_nic_clear_stats(adapter);
+       pci_save_state(pdev);
 
-               err = netxen_alloc_hw_resources(adapter);
-               if (err) {
-                       printk(KERN_ERR "%s: Error in setting hw resources\n",
-                                       netdev->name);
-                       goto err_out_free_sw;
-               }
+       if (netxen_nic_wol_supported(adapter)) {
+               pci_enable_wake(pdev, PCI_D3cold, 1);
+               pci_enable_wake(pdev, PCI_D3hot, 1);
+       }
 
-               if ((adapter->msi_mode != MSI_MODE_MULTIFUNC) ||
-                       (adapter->intr_scheme != INTR_SCHEME_PERPORT)) {
-                       printk(KERN_ERR "%s: Firmware interrupt scheme is "
-                                       "incompatible with driver\n",
-                                       netdev->name);
-                       adapter->driver_mismatch = 1;
-                       goto err_out_free_hw;
-               }
+       pci_disable_device(pdev);
+       pci_set_power_state(pdev, pci_choose_state(pdev, state));
 
-               if (adapter->fw_major < 4) {
-                       adapter->crb_addr_cmd_producer =
-                               crb_cmd_producer[adapter->portnum];
-                       adapter->crb_addr_cmd_consumer =
-                               crb_cmd_consumer[adapter->portnum];
+       return 0;
+}
 
-                       netxen_nic_update_cmd_producer(adapter, 0);
-                       netxen_nic_update_cmd_consumer(adapter, 0);
-               }
+static int
+netxen_nic_resume(struct pci_dev *pdev)
+{
+       struct netxen_adapter *adapter = pci_get_drvdata(pdev);
+       struct net_device *netdev = adapter->netdev;
+       int err;
 
-               for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
-                       for (ring = 0; ring < adapter->max_rds_rings; ring++)
-                               netxen_post_rx_buffers(adapter, ctx, ring);
-               }
-               if (adapter->flags & NETXEN_NIC_MSIX_ENABLED)
-                       handler = netxen_msix_intr;
-               else if (adapter->flags & NETXEN_NIC_MSI_ENABLED)
-                       handler = netxen_msi_intr;
-               else {
-                       flags |= IRQF_SHARED;
-                       handler = netxen_intr;
-               }
-               adapter->irq = netdev->irq;
-               err = request_irq(adapter->irq, handler,
-                                 flags, netdev->name, adapter);
-               if (err) {
-                       printk(KERN_ERR "request_irq failed with: %d\n", err);
-                       goto err_out_free_rxbuf;
-               }
+       pci_set_power_state(pdev, PCI_D0);
+       pci_restore_state(pdev);
 
-               adapter->is_up = NETXEN_ADAPTER_UP_MAGIC;
-       }
+       err = pci_enable_device(pdev);
+       if (err)
+               return err;
 
-       /* Done here again so that even if phantom sw overwrote it,
-        * we set it */
-       err = adapter->init_port(adapter, adapter->physical_port);
+       adapter->curr_window = 255;
+
+       err = netxen_start_firmware(adapter);
        if (err) {
-               printk(KERN_ERR "%s: Failed to initialize port %d\n",
-                               netxen_nic_driver_name, adapter->portnum);
-               goto err_out_free_irq;
+               dev_err(&pdev->dev, "failed to start firmware\n");
+               return err;
        }
-       adapter->macaddr_set(adapter, netdev->dev_addr);
 
-       netxen_nic_set_link_parameters(adapter);
+       if (netif_running(netdev)) {
+               err = netxen_nic_attach(adapter);
+               if (err)
+                       return err;
 
-       netxen_set_multicast_list(netdev);
-       if (adapter->set_mtu)
-               adapter->set_mtu(adapter, netdev->mtu);
+               err = netxen_nic_up(adapter, netdev);
+               if (err)
+                       return err;
 
-       adapter->ahw.linkup = 0;
-       mod_timer(&adapter->watchdog_timer, jiffies);
+               netif_device_attach(netdev);
+       }
+
+       return 0;
+}
+
+static int netxen_nic_open(struct net_device *netdev)
+{
+       struct netxen_adapter *adapter = netdev_priv(netdev);
+       int err = 0;
+
+       if (adapter->driver_mismatch)
+               return -EIO;
+
+       if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC) {
+               err = netxen_nic_attach(adapter);
+               if (err)
+                       return err;
+       }
 
-       napi_enable(&adapter->napi);
-       netxen_nic_enable_int(adapter);
+       err = netxen_nic_up(adapter, netdev);
+       if (err)
+               goto err_out;
 
        netif_start_queue(netdev);
 
        return 0;
 
-err_out_free_irq:
-       free_irq(adapter->irq, adapter);
-err_out_free_rxbuf:
-       netxen_release_rx_buffers(adapter);
-err_out_free_hw:
-       netxen_free_hw_resources(adapter);
-err_out_free_sw:
-       netxen_free_sw_resources(adapter);
+err_out:
+       netxen_nic_detach(adapter);
        return err;
 }
 
@@ -1084,20 +1231,7 @@ static int netxen_nic_close(struct net_device *netdev)
 {
        struct netxen_adapter *adapter = netdev_priv(netdev);
 
-       netif_carrier_off(netdev);
-       netif_stop_queue(netdev);
-       napi_disable(&adapter->napi);
-
-       if (adapter->stop_port)
-               adapter->stop_port(adapter);
-
-       netxen_nic_disable_int(adapter);
-
-       netxen_release_tx_buffers(adapter);
-
-       FLUSH_SCHEDULED_WORK();
-       del_timer_sync(&adapter->watchdog_timer);
-
+       netxen_nic_down(adapter, netdev);
        return 0;
 }
 
@@ -1169,7 +1303,16 @@ netxen_clean_tx_dma_mapping(struct pci_dev *pdev,
        }
 }
 
-static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+static inline void
+netxen_clear_cmddesc(u64 *desc)
+{
+       int i;
+       for (i = 0; i < 8; i++)
+               desc[i] = 0ULL;
+}
+
+static int
+netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 {
        struct netxen_adapter *adapter = netdev_priv(netdev);
        struct netxen_hardware_context *hw = &adapter->ahw;
@@ -1183,7 +1326,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        u32 producer, consumer;
        int frag_count, no_of_desc;
-       u32 num_txd = adapter->max_tx_desc_count;
+       u32 num_txd = adapter->num_txd;
        bool is_tso = false;
 
        frag_count = skb_shinfo(skb)->nr_frags + 1;
@@ -1202,7 +1345,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
 
        /* Copy the descriptors into the hardware    */
        hwdesc = &hw->cmd_desc_head[producer];
-       memset(hwdesc, 0, sizeof(struct cmd_desc_type0));
+       netxen_clear_cmddesc((u64 *)hwdesc);
        /* Take skb->data itself */
        pbuf = &adapter->cmd_buf_arr[producer];
 
@@ -1221,7 +1364,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
        netxen_set_tx_frags_len(hwdesc, frag_count, skb->len);
        netxen_set_tx_port(hwdesc, adapter->portnum);
 
-       hwdesc->buffer1_length = cpu_to_le16(first_seg_len);
+       hwdesc->buffer_length[0] = cpu_to_le16(first_seg_len);
        hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
 
        for (i = 1, k = 1; i < frag_count; i++, k++) {
@@ -1234,7 +1377,7 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                        k = 0;
                        producer = get_next_index(producer, num_txd);
                        hwdesc = &hw->cmd_desc_head[producer];
-                       memset(hwdesc, 0, sizeof(struct cmd_desc_type0));
+                       netxen_clear_cmddesc((u64 *)hwdesc);
                        pbuf = &adapter->cmd_buf_arr[producer];
                        pbuf->skb = NULL;
                }
@@ -1254,21 +1397,18 @@ static int netxen_nic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
                buffrag->dma = temp_dma;
                buffrag->length = temp_len;
 
+               hwdesc->buffer_length[k] = cpu_to_le16(temp_len);
                switch (k) {
                case 0:
-                       hwdesc->buffer1_length = cpu_to_le16(temp_len);
                        hwdesc->addr_buffer1 = cpu_to_le64(temp_dma);
                        break;
                case 1:
-                       hwdesc->buffer2_length = cpu_to_le16(temp_len);
                        hwdesc->addr_buffer2 = cpu_to_le64(temp_dma);
                        break;
                case 2:
-                       hwdesc->buffer3_length = cpu_to_le16(temp_len);
                        hwdesc->addr_buffer3 = cpu_to_le64(temp_dma);
                        break;
                case 3:
-                       hwdesc->buffer4_length = cpu_to_le16(temp_len);
                        hwdesc->addr_buffer4 = cpu_to_le64(temp_dma);
                        break;
                }
@@ -1383,7 +1523,7 @@ static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter)
                linkup = (val == XG_LINK_UP_P3);
        } else {
                val = adapter->pci_read_normalize(adapter, CRB_XG_STATE);
-               if (adapter->ahw.board_type == NETXEN_NIC_GBE)
+               if (adapter->ahw.port_type == NETXEN_NIC_GBE)
                        linkup = (val >> port) & 1;
                else {
                        val = (val >> port*8) & 0xff;
@@ -1450,13 +1590,11 @@ static void netxen_tx_timeout_task(struct work_struct *work)
        printk(KERN_ERR "%s %s: transmit timeout, resetting.\n",
               netxen_nic_driver_name, adapter->netdev->name);
 
-       netxen_nic_disable_int(adapter);
-       napi_disable(&adapter->napi);
+       netxen_napi_disable(adapter);
 
        adapter->netdev->trans_start = jiffies;
 
-       napi_enable(&adapter->napi);
-       netxen_nic_enable_int(adapter);
+       netxen_napi_enable(adapter);
        netif_wake_queue(adapter->netdev);
 }
 
@@ -1494,7 +1632,8 @@ struct net_device_stats *netxen_nic_get_stats(struct net_device *netdev)
 
 static irqreturn_t netxen_intr(int irq, void *data)
 {
-       struct netxen_adapter *adapter = data;
+       struct nx_host_sds_ring *sds_ring = data;
+       struct netxen_adapter *adapter = sds_ring->adapter;
        u32 status = 0;
 
        status = adapter->pci_read_immediate(adapter, ISR_INT_VECTOR);
@@ -1525,7 +1664,7 @@ static irqreturn_t netxen_intr(int irq, void *data)
 
        /* clear interrupt */
        if (adapter->fw_major < 4)
-               netxen_nic_disable_int(adapter);
+               netxen_nic_disable_int(sds_ring);
 
        adapter->pci_write_immediate(adapter,
                        adapter->legacy_intr.tgt_status_reg,
@@ -1534,61 +1673,49 @@ static irqreturn_t netxen_intr(int irq, void *data)
        adapter->pci_read_immediate(adapter, ISR_INT_VECTOR);
        adapter->pci_read_immediate(adapter, ISR_INT_VECTOR);
 
-       napi_schedule(&adapter->napi);
+       napi_schedule(&sds_ring->napi);
 
        return IRQ_HANDLED;
 }
 
 static irqreturn_t netxen_msi_intr(int irq, void *data)
 {
-       struct netxen_adapter *adapter = data;
+       struct nx_host_sds_ring *sds_ring = data;
+       struct netxen_adapter *adapter = sds_ring->adapter;
 
        /* clear interrupt */
        adapter->pci_write_immediate(adapter,
                        msi_tgt_status[adapter->ahw.pci_func], 0xffffffff);
 
-       napi_schedule(&adapter->napi);
+       napi_schedule(&sds_ring->napi);
        return IRQ_HANDLED;
 }
 
 static irqreturn_t netxen_msix_intr(int irq, void *data)
 {
-       struct netxen_adapter *adapter = data;
+       struct nx_host_sds_ring *sds_ring = data;
 
-       napi_schedule(&adapter->napi);
+       napi_schedule(&sds_ring->napi);
        return IRQ_HANDLED;
 }
 
 static int netxen_nic_poll(struct napi_struct *napi, int budget)
 {
-       struct netxen_adapter *adapter = container_of(napi, struct netxen_adapter, napi);
+       struct nx_host_sds_ring *sds_ring =
+               container_of(napi, struct nx_host_sds_ring, napi);
+
+       struct netxen_adapter *adapter = sds_ring->adapter;
+
        int tx_complete;
-       int ctx;
        int work_done;
 
        tx_complete = netxen_process_cmd_ring(adapter);
 
-       work_done = 0;
-       for (ctx = 0; ctx < MAX_RCV_CTX; ++ctx) {
-               /*
-                * Fairness issue. This will give undue weight to the
-                * receive context 0.
-                */
-
-               /*
-                * To avoid starvation, we give each of our receivers,
-                * a fraction of the quota. Sometimes, it might happen that we
-                * have enough quota to process every packet, but since all the
-                * packets are on one context, it gets only half of the quota,
-                * and ends up not processing it.
-                */
-               work_done += netxen_process_rcv_ring(adapter, ctx,
-                                                    budget / MAX_RCV_CTX);
-       }
+       work_done = netxen_process_rcv_ring(sds_ring, budget);
 
        if ((work_done < budget) && tx_complete) {
-               napi_complete(&adapter->napi);
-               netxen_nic_enable_int(adapter);
+               napi_complete(&sds_ring->napi);
+               netxen_nic_enable_int(sds_ring);
        }
 
        return work_done;
@@ -1608,13 +1735,17 @@ static struct pci_driver netxen_driver = {
        .name = netxen_nic_driver_name,
        .id_table = netxen_pci_tbl,
        .probe = netxen_nic_probe,
-       .remove = __devexit_p(netxen_nic_remove)
+       .remove = __devexit_p(netxen_nic_remove),
+       .suspend = netxen_nic_suspend,
+       .resume = netxen_nic_resume
 };
 
 /* Driver Registration on NetXen card    */
 
 static int __init netxen_init_module(void)
 {
+       printk(KERN_INFO "%s\n", netxen_nic_driver_string);
+
        if ((netxen_workq = create_singlethread_workqueue("netxen")) == NULL)
                return -ENOMEM;
 
index c3b9c83b32fe5205925a4686e0874c2f4aa7e96b..d85203203d4d2afb5c9f3cfc888d0c5b1419776b 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 - 2006 NetXen, Inc.
+ * Copyright (C) 2003 - 2009 NetXen, Inc.
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  *
  * Contact Information:
  *    info@netxen.com
- * NetXen,
- * 3965 Freedom Circle, Fourth floor,
- * Santa Clara, CA 95054
- *
- *
- * Provides access to the Network Interface Unit h/w block.
+ * NetXen Inc,
+ * 18922 Forge Drive
+ * Cupertino, CA 95014-0701
  *
  */
 
@@ -299,14 +296,6 @@ int netxen_niu_gbe_disable_phy_interrupts(struct netxen_adapter *adapter)
        return result;
 }
 
-#if 0
-int netxen_niu_xgbe_clear_phy_interrupts(struct netxen_adapter *adapter)
-{
-       netxen_crb_writelit_adapter(adapter, NETXEN_NIU_ACTIVE_INT, -1);
-       return 0;
-}
-#endif  /*  0  */
-
 static int netxen_niu_gbe_clear_phy_interrupts(struct netxen_adapter *adapter)
 {
        int result = 0;
@@ -467,104 +456,6 @@ int netxen_niu_xg_init_port(struct netxen_adapter *adapter, int port)
        return 0;
 }
 
-#if 0
-/*
- * netxen_niu_gbe_handle_phy_interrupt - Handles GbE PHY interrupts
- * @param enable 0 means don't enable the port
- *              1 means enable (or re-enable) the port
- */
-int netxen_niu_gbe_handle_phy_interrupt(struct netxen_adapter *adapter,
-                                       int port, long enable)
-{
-       int result = 0;
-       __u32 int_src;
-
-       printk(KERN_INFO PFX "NETXEN: Handling PHY interrupt on port %d"
-              " (device enable = %d)\n", (int)port, (int)enable);
-
-       /*
-        * The read of the PHY INT status will clear the pending
-        * interrupt status
-        */
-       if (netxen_niu_gbe_phy_read(adapter,
-                                   NETXEN_NIU_GB_MII_MGMT_ADDR_INT_STATUS,
-                                   &int_src) != 0)
-               result = -EINVAL;
-       else {
-               printk(KERN_INFO PFX "PHY Interrupt source = 0x%x \n", int_src);
-               if (netxen_get_phy_int_jabber(int_src))
-                       printk(KERN_INFO PFX "jabber Interrupt ");
-               if (netxen_get_phy_int_polarity_changed(int_src))
-                       printk(KERN_INFO PFX "polarity changed ");
-               if (netxen_get_phy_int_energy_detect(int_src))
-                       printk(KERN_INFO PFX "energy detect \n");
-               if (netxen_get_phy_int_downshift(int_src))
-                       printk(KERN_INFO PFX "downshift \n");
-               if (netxen_get_phy_int_mdi_xover_changed(int_src))
-                       printk(KERN_INFO PFX "mdi_xover_changed ");
-               if (netxen_get_phy_int_fifo_over_underflow(int_src))
-                       printk(KERN_INFO PFX "fifo_over_underflow ");
-               if (netxen_get_phy_int_false_carrier(int_src))
-                       printk(KERN_INFO PFX "false_carrier ");
-               if (netxen_get_phy_int_symbol_error(int_src))
-                       printk(KERN_INFO PFX "symbol_error ");
-               if (netxen_get_phy_int_autoneg_completed(int_src))
-                       printk(KERN_INFO PFX "autoneg_completed ");
-               if (netxen_get_phy_int_page_received(int_src))
-                       printk(KERN_INFO PFX "page_received ");
-               if (netxen_get_phy_int_duplex_changed(int_src))
-                       printk(KERN_INFO PFX "duplex_changed ");
-               if (netxen_get_phy_int_autoneg_error(int_src))
-                       printk(KERN_INFO PFX "autoneg_error ");
-               if ((netxen_get_phy_int_speed_changed(int_src))
-                   || (netxen_get_phy_int_link_status_changed(int_src))) {
-                       __u32 status;
-
-                       printk(KERN_INFO PFX
-                              "speed_changed or link status changed");
-                       if (netxen_niu_gbe_phy_read
-                           (adapter,
-                            NETXEN_NIU_GB_MII_MGMT_ADDR_PHY_STATUS,
-                            &status) == 0) {
-                               if (netxen_get_phy_speed(status) == 2) {
-                                       printk
-                                           (KERN_INFO PFX "Link speed changed"
-                                            " to 1000 Mbps\n");
-                                       netxen_niu_gbe_set_gmii_mode(adapter,
-                                                                    port,
-                                                                    enable);
-                               } else if (netxen_get_phy_speed(status) == 1) {
-                                       printk
-                                           (KERN_INFO PFX "Link speed changed"
-                                            " to 100 Mbps\n");
-                                       netxen_niu_gbe_set_mii_mode(adapter,
-                                                                   port,
-                                                                   enable);
-                               } else if (netxen_get_phy_speed(status) == 0) {
-                                       printk
-                                           (KERN_INFO PFX "Link speed changed"
-                                            " to 10 Mbps\n");
-                                       netxen_niu_gbe_set_mii_mode(adapter,
-                                                                   port,
-                                                                   enable);
-                               } else {
-                                       printk(KERN_ERR PFX "ERROR reading "
-                                              "PHY status. Invalid speed.\n");
-                                       result = -1;
-                               }
-                       } else {
-                               printk(KERN_ERR PFX
-                                      "ERROR reading PHY status.\n");
-                               result = -1;
-                       }
-
-               }
-               printk(KERN_INFO "\n");
-       }
-       return result;
-}
-#endif  /*  0  */
-
 /*
  * Return the current station MAC address.
  * Note that the passed-in value must already be in network byte order.
@@ -641,86 +532,6 @@ int netxen_niu_macaddr_set(struct netxen_adapter *adapter,
        return 0;
 }
 
-#if 0
-/* Enable a GbE interface */
-int netxen_niu_enable_gbe_port(struct netxen_adapter *adapter,
-                              int port, netxen_niu_gbe_ifmode_t mode)
-{
-       __u32 mac_cfg0;
-       __u32 mac_cfg1;
-       __u32 mii_cfg;
-
-       if ((port < 0) || (port > NETXEN_NIU_MAX_GBE_PORTS))
-               return -EINVAL;
-
-       mac_cfg0 = 0;
-       netxen_gb_soft_reset(mac_cfg0);
-       if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
-                                  &mac_cfg0, 4))
-               return -EIO;
-       mac_cfg0 = 0;
-       netxen_gb_enable_tx(mac_cfg0);
-       netxen_gb_enable_rx(mac_cfg0);
-       netxen_gb_unset_rx_flowctl(mac_cfg0);
-       netxen_gb_tx_reset_pb(mac_cfg0);
-       netxen_gb_rx_reset_pb(mac_cfg0);
-       netxen_gb_tx_reset_mac(mac_cfg0);
-       netxen_gb_rx_reset_mac(mac_cfg0);
-
-       if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
-                                  &mac_cfg0, 4))
-               return -EIO;
-       mac_cfg1 = 0;
-       netxen_gb_set_preamblelen(mac_cfg1, 0xf);
-       netxen_gb_set_duplex(mac_cfg1);
-       netxen_gb_set_crc_enable(mac_cfg1);
-       netxen_gb_set_padshort(mac_cfg1);
-       netxen_gb_set_checklength(mac_cfg1);
-       netxen_gb_set_hugeframes(mac_cfg1);
-
-       if (mode == NETXEN_NIU_10_100_MB) {
-               netxen_gb_set_intfmode(mac_cfg1, 1);
-               if (adapter->hw_write_wx(adapter,
-                                          NETXEN_NIU_GB_MAC_CONFIG_1(port),
-                                          &mac_cfg1, 4))
-                       return -EIO;
-
-               /* set mii mode */
-               netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB0_GMII_MODE +
-                                           (port << 3), 0);
-               netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB0_MII_MODE +
-                                           (port << 3), 1);
-
-       } else if (mode == NETXEN_NIU_1000_MB) {
-               netxen_gb_set_intfmode(mac_cfg1, 2);
-               if (adapter->hw_write_wx(adapter,
-                                          NETXEN_NIU_GB_MAC_CONFIG_1(port),
-                                          &mac_cfg1, 4))
-                       return -EIO;
-               /* set gmii mode */
-               netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB0_MII_MODE +
-                                           (port << 3), 0);
-               netxen_crb_writelit_adapter(adapter, NETXEN_NIU_GB0_GMII_MODE +
-                                           (port << 3), 1);
-       }
-       mii_cfg = 0;
-       netxen_gb_set_mii_mgmt_clockselect(mii_cfg, 7);
-       if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MII_MGMT_CONFIG(port),
-                                  &mii_cfg, 4))
-               return -EIO;
-       mac_cfg0 = 0;
-       netxen_gb_enable_tx(mac_cfg0);
-       netxen_gb_enable_rx(mac_cfg0);
-       netxen_gb_unset_rx_flowctl(mac_cfg0);
-       netxen_gb_unset_tx_flowctl(mac_cfg0);
-
-       if (adapter->hw_write_wx(adapter, NETXEN_NIU_GB_MAC_CONFIG_0(port),
-                                  &mac_cfg0, 4))
-               return -EIO;
-       return 0;
-}
-#endif  /*  0  */
-
 /* Disable a GbE interface */
 int netxen_niu_disable_gbe_port(struct netxen_adapter *adapter)
 {
@@ -869,39 +680,6 @@ int netxen_niu_xg_macaddr_set(struct netxen_adapter *adapter,
        return 0;
 }
 
-#if 0
-/*
- * Return the current station MAC address.
- * Note that the passed-in value must already be in network byte order.
- */
-int netxen_niu_xg_macaddr_get(struct netxen_adapter *adapter,
-                             netxen_ethernet_macaddr_t * addr)
-{
-       int phy = adapter->physical_port;
-       u32 stationhigh;
-       u32 stationlow;
-       u8 val[8];
-
-       if (addr == NULL)
-               return -EINVAL;
-       if (phy != 0)
-               return -EINVAL;
-
-       if (adapter->hw_read_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_HI,
-                                 &stationhigh, 4))
-               return -EIO;
-       if (adapter->hw_read_wx(adapter, NETXEN_NIU_XGE_STATION_ADDR_0_1,
-                                 &stationlow, 4))
-               return -EIO;
-       ((__le32 *)val)[1] = cpu_to_le32(stationhigh);
-       ((__le32 *)val)[0] = cpu_to_le32(stationlow);
-
-       memcpy(addr, val + 2, 6);
-
-       return 0;
-}
-#endif  /*  0  */
-
 int netxen_niu_xg_set_promiscuous_mode(struct netxen_adapter *adapter,
                u32 mode)
 {
index b293adcc95ab192481e0ec731f98c8d32b5452f2..50183335e43afcf47ce6b5fa41177f0b9d2a77d2 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (C) 2003 - 2006 NetXen, Inc.
+ * Copyright (C) 2003 - 2009 NetXen, Inc.
  * All rights reserved.
  *
  * This program is free software; you can redistribute it and/or
  *
  * Contact Information:
  *    info@netxen.com
- * NetXen,
- * 3965 Freedom Circle, Fourth floor,
- * Santa Clara, CA 95054
+ * NetXen Inc,
+ * 18922 Forge Drive
+ * Cupertino, CA 95014-0701
+ *
  */
 
 #ifndef __NIC_PHAN_REG_H_
@@ -90,6 +91,7 @@
 #define CRB_RX_LRO_START_NUM        NETXEN_NIC_REG(0xc0)
 #define CRB_MPORT_MODE              NETXEN_NIC_REG(0xc4)       /* Multiport Mode */
 #define CRB_CMD_RING_SIZE           NETXEN_NIC_REG(0xc8)
+#define CRB_DMA_SHIFT               NETXEN_NIC_REG(0xcc)
 #define CRB_INT_VECTOR              NETXEN_NIC_REG(0xd4)
 #define CRB_CTX_RESET               NETXEN_NIC_REG(0xd8)
 #define CRB_HOST_STS_PROD           NETXEN_NIC_REG(0xdc)
index 32374a1c123ba58686cb92c61bf3dd551c94c8f1..50c11126a3db5adaa6dbb5d48ccfad1dafe95aa6 100644 (file)
@@ -1115,6 +1115,130 @@ static int link_status_10g_serdes(struct niu *np, int *link_up_p)
        return 0;
 }
 
+static int link_status_mii(struct niu *np, int *link_up_p)
+{
+       struct niu_link_config *lp = &np->link_config;
+       int err;
+       int bmsr, advert, ctrl1000, stat1000, lpa, bmcr, estatus;
+       int supported, advertising, active_speed, active_duplex;
+
+       err = mii_read(np, np->phy_addr, MII_BMCR);
+       if (unlikely(err < 0))
+               return err;
+       bmcr = err;
+
+       err = mii_read(np, np->phy_addr, MII_BMSR);
+       if (unlikely(err < 0))
+               return err;
+       bmsr = err;
+
+       err = mii_read(np, np->phy_addr, MII_ADVERTISE);
+       if (unlikely(err < 0))
+               return err;
+       advert = err;
+
+       err = mii_read(np, np->phy_addr, MII_LPA);
+       if (unlikely(err < 0))
+               return err;
+       lpa = err;
+
+       if (likely(bmsr & BMSR_ESTATEN)) {
+               err = mii_read(np, np->phy_addr, MII_ESTATUS);
+               if (unlikely(err < 0))
+                       return err;
+               estatus = err;
+
+               err = mii_read(np, np->phy_addr, MII_CTRL1000);
+               if (unlikely(err < 0))
+                       return err;
+               ctrl1000 = err;
+
+               err = mii_read(np, np->phy_addr, MII_STAT1000);
+               if (unlikely(err < 0))
+                       return err;
+               stat1000 = err;
+       } else
+               estatus = ctrl1000 = stat1000 = 0;
+
+       supported = 0;
+       if (bmsr & BMSR_ANEGCAPABLE)
+               supported |= SUPPORTED_Autoneg;
+       if (bmsr & BMSR_10HALF)
+               supported |= SUPPORTED_10baseT_Half;
+       if (bmsr & BMSR_10FULL)
+               supported |= SUPPORTED_10baseT_Full;
+       if (bmsr & BMSR_100HALF)
+               supported |= SUPPORTED_100baseT_Half;
+       if (bmsr & BMSR_100FULL)
+               supported |= SUPPORTED_100baseT_Full;
+       if (estatus & ESTATUS_1000_THALF)
+               supported |= SUPPORTED_1000baseT_Half;
+       if (estatus & ESTATUS_1000_TFULL)
+               supported |= SUPPORTED_1000baseT_Full;
+       lp->supported = supported;
+
+       advertising = 0;
+       if (advert & ADVERTISE_10HALF)
+               advertising |= ADVERTISED_10baseT_Half;
+       if (advert & ADVERTISE_10FULL)
+               advertising |= ADVERTISED_10baseT_Full;
+       if (advert & ADVERTISE_100HALF)
+               advertising |= ADVERTISED_100baseT_Half;
+       if (advert & ADVERTISE_100FULL)
+               advertising |= ADVERTISED_100baseT_Full;
+       if (ctrl1000 & ADVERTISE_1000HALF)
+               advertising |= ADVERTISED_1000baseT_Half;
+       if (ctrl1000 & ADVERTISE_1000FULL)
+               advertising |= ADVERTISED_1000baseT_Full;
+
+       if (bmcr & BMCR_ANENABLE) {
+               int neg, neg1000;
+
+               lp->active_autoneg = 1;
+               advertising |= ADVERTISED_Autoneg;
+
+               neg = advert & lpa;
+               neg1000 = (ctrl1000 << 2) & stat1000;
+
+               if (neg1000 & (LPA_1000FULL | LPA_1000HALF))
+                       active_speed = SPEED_1000;
+               else if (neg & LPA_100)
+                       active_speed = SPEED_100;
+               else if (neg & (LPA_10HALF | LPA_10FULL))
+                       active_speed = SPEED_10;
+               else
+                       active_speed = SPEED_INVALID;
+
+               if ((neg1000 & LPA_1000FULL) || (neg & LPA_DUPLEX))
+                       active_duplex = DUPLEX_FULL;
+               else if (active_speed != SPEED_INVALID)
+                       active_duplex = DUPLEX_HALF;
+               else
+                       active_duplex = DUPLEX_INVALID;
+       } else {
+               lp->active_autoneg = 0;
+
+               if ((bmcr & BMCR_SPEED1000) && !(bmcr & BMCR_SPEED100))
+                       active_speed = SPEED_1000;
+               else if (bmcr & BMCR_SPEED100)
+                       active_speed = SPEED_100;
+               else
+                       active_speed = SPEED_10;
+
+               if (bmcr & BMCR_FULLDPLX)
+                       active_duplex = DUPLEX_FULL;
+               else
+                       active_duplex = DUPLEX_HALF;
+       }
+
+       lp->active_advertising = advertising;
+       lp->active_speed = active_speed;
+       lp->active_duplex = active_duplex;
+       *link_up_p = !!(bmsr & BMSR_LSTATUS);
+
+       return 0;
+}
+
 static int link_status_1g_rgmii(struct niu *np, int *link_up_p)
 {
        struct niu_link_config *lp = &np->link_config;
@@ -1171,6 +1295,22 @@ out:
        return err;
 }
 
+static int link_status_1g(struct niu *np, int *link_up_p)
+{
+       struct niu_link_config *lp = &np->link_config;
+       unsigned long flags;
+       int err;
+
+       spin_lock_irqsave(&np->lock, flags);
+
+       err = link_status_mii(np, link_up_p);
+       lp->supported |= SUPPORTED_TP;
+       lp->active_advertising |= ADVERTISED_TP;
+
+       spin_unlock_irqrestore(&np->lock, flags);
+       return err;
+}
+
 static int bcm8704_reset(struct niu *np)
 {
        int err, limit;
@@ -1676,39 +1816,88 @@ static int mii_init_common(struct niu *np)
                        return err;
        }
 
-       /* XXX configurable XXX */
-       /* XXX for now don't advertise half-duplex or asym pause... XXX */
-       adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
-       if (bmsr & BMSR_10FULL)
-               adv |= ADVERTISE_10FULL;
-       if (bmsr & BMSR_100FULL)
-               adv |= ADVERTISE_100FULL;
-       err = mii_write(np, np->phy_addr, MII_ADVERTISE, adv);
-       if (err)
-               return err;
-
-       if (bmsr & BMSR_ESTATEN) {
-               u16 ctrl1000 = 0;
-
-               if (estat & ESTATUS_1000_TFULL)
-                       ctrl1000 |= ADVERTISE_1000FULL;
-               err = mii_write(np, np->phy_addr, MII_CTRL1000, ctrl1000);
+       if (lp->autoneg) {
+               u16 ctrl1000;
+
+               adv = ADVERTISE_CSMA | ADVERTISE_PAUSE_CAP;
+               if ((bmsr & BMSR_10HALF) &&
+                       (lp->advertising & ADVERTISED_10baseT_Half))
+                       adv |= ADVERTISE_10HALF;
+               if ((bmsr & BMSR_10FULL) &&
+                       (lp->advertising & ADVERTISED_10baseT_Full))
+                       adv |= ADVERTISE_10FULL;
+               if ((bmsr & BMSR_100HALF) &&
+                       (lp->advertising & ADVERTISED_100baseT_Half))
+                       adv |= ADVERTISE_100HALF;
+               if ((bmsr & BMSR_100FULL) &&
+                       (lp->advertising & ADVERTISED_100baseT_Full))
+                       adv |= ADVERTISE_100FULL;
+               err = mii_write(np, np->phy_addr, MII_ADVERTISE, adv);
                if (err)
                        return err;
+
+               if (likely(bmsr & BMSR_ESTATEN)) {
+                       ctrl1000 = 0;
+                       if ((estat & ESTATUS_1000_THALF) &&
+                               (lp->advertising & ADVERTISED_1000baseT_Half))
+                               ctrl1000 |= ADVERTISE_1000HALF;
+                       if ((estat & ESTATUS_1000_TFULL) &&
+                               (lp->advertising & ADVERTISED_1000baseT_Full))
+                               ctrl1000 |= ADVERTISE_1000FULL;
+                       err = mii_write(np, np->phy_addr,
+                                       MII_CTRL1000, ctrl1000);
+                       if (err)
+                               return err;
+               }
+
+               bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
+       } else {
+               /* !lp->autoneg */
+               int fulldpx;
+
+               if (lp->duplex == DUPLEX_FULL) {
+                       bmcr |= BMCR_FULLDPLX;
+                       fulldpx = 1;
+               } else if (lp->duplex == DUPLEX_HALF)
+                       fulldpx = 0;
+               else
+                       return -EINVAL;
+
+               if (lp->speed == SPEED_1000) {
+                       /* if X-full requested while not supported, or
+                          X-half requested while not supported... */
+                       if ((fulldpx && !(estat & ESTATUS_1000_TFULL)) ||
+                               (!fulldpx && !(estat & ESTATUS_1000_THALF)))
+                               return -EINVAL;
+                       bmcr |= BMCR_SPEED1000;
+               } else if (lp->speed == SPEED_100) {
+                       if ((fulldpx && !(bmsr & BMSR_100FULL)) ||
+                               (!fulldpx && !(bmsr & BMSR_100HALF)))
+                               return -EINVAL;
+                       bmcr |= BMCR_SPEED100;
+               } else if (lp->speed == SPEED_10) {
+                       if ((fulldpx && !(bmsr & BMSR_10FULL)) ||
+                               (!fulldpx && !(bmsr & BMSR_10HALF)))
+                               return -EINVAL;
+               } else
+                       return -EINVAL;
        }
-       bmcr |= (BMCR_ANENABLE | BMCR_ANRESTART);
 
        err = mii_write(np, np->phy_addr, MII_BMCR, bmcr);
        if (err)
                return err;
 
+#if 0
        err = mii_read(np, np->phy_addr, MII_BMCR);
        if (err < 0)
                return err;
+       bmcr = err;
+
        err = mii_read(np, np->phy_addr, MII_BMSR);
        if (err < 0)
                return err;
-#if 0
+       bmsr = err;
+
        pr_info(PFX "Port %u after MII init bmcr[%04x] bmsr[%04x]\n",
                np->port, bmcr, bmsr);
 #endif
@@ -2054,87 +2243,6 @@ static int link_status_10g_hotplug(struct niu *np, int *link_up_p)
        return err;
 }
 
-static int link_status_1g(struct niu *np, int *link_up_p)
-{
-       struct niu_link_config *lp = &np->link_config;
-       u16 current_speed, bmsr;
-       unsigned long flags;
-       u8 current_duplex;
-       int err, link_up;
-
-       link_up = 0;
-       current_speed = SPEED_INVALID;
-       current_duplex = DUPLEX_INVALID;
-
-       spin_lock_irqsave(&np->lock, flags);
-
-       err = -EINVAL;
-       if (np->link_config.loopback_mode != LOOPBACK_DISABLED)
-               goto out;
-
-       err = mii_read(np, np->phy_addr, MII_BMSR);
-       if (err < 0)
-               goto out;
-
-       bmsr = err;
-       if (bmsr & BMSR_LSTATUS) {
-               u16 adv, lpa, common, estat;
-
-               err = mii_read(np, np->phy_addr, MII_ADVERTISE);
-               if (err < 0)
-                       goto out;
-               adv = err;
-
-               err = mii_read(np, np->phy_addr, MII_LPA);
-               if (err < 0)
-                       goto out;
-               lpa = err;
-
-               common = adv & lpa;
-
-               err = mii_read(np, np->phy_addr, MII_ESTATUS);
-               if (err < 0)
-                       goto out;
-               estat = err;
-
-               link_up = 1;
-               if (estat & (ESTATUS_1000_TFULL | ESTATUS_1000_THALF)) {
-                       current_speed = SPEED_1000;
-                       if (estat & ESTATUS_1000_TFULL)
-                               current_duplex = DUPLEX_FULL;
-                       else
-                               current_duplex = DUPLEX_HALF;
-               } else {
-                       if (common & ADVERTISE_100BASE4) {
-                               current_speed = SPEED_100;
-                               current_duplex = DUPLEX_HALF;
-                       } else if (common & ADVERTISE_100FULL) {
-                               current_speed = SPEED_100;
-                               current_duplex = DUPLEX_FULL;
-                       } else if (common & ADVERTISE_100HALF) {
-                               current_speed = SPEED_100;
-                               current_duplex = DUPLEX_HALF;
-                       } else if (common & ADVERTISE_10FULL) {
-                               current_speed = SPEED_10;
-                               current_duplex = DUPLEX_FULL;
-                       } else if (common & ADVERTISE_10HALF) {
-                               current_speed = SPEED_10;
-                               current_duplex = DUPLEX_HALF;
-                       } else
-                               link_up = 0;
-               }
-       }
-       lp->active_speed = current_speed;
-       lp->active_duplex = current_duplex;
-       err = 0;
-
-out:
-       spin_unlock_irqrestore(&np->lock, flags);
-
-       *link_up_p = link_up;
-       return err;
-}
-
 static int niu_link_status(struct niu *np, int *link_up_p)
 {
        const struct niu_phy_ops *ops = np->phy_ops;
@@ -2456,7 +2564,7 @@ static int niu_determine_phy_disposition(struct niu *np)
 
                case NIU_FLAGS_10G:
                        /* 10G copper */
-                       tp = &phy_template_1g_copper;
+                       tp = &phy_template_10g_copper;
                        break;
 
                case NIU_FLAGS_FIBER:
@@ -2873,7 +2981,6 @@ static int tcam_user_ip_class_enable(struct niu *np, unsigned long class,
        return 0;
 }
 
-#if 0
 static int tcam_user_ip_class_set(struct niu *np, unsigned long class,
                                  int ipv6, u64 protocol_id,
                                  u64 tos_mask, u64 tos_val)
@@ -2901,7 +3008,6 @@ static int tcam_user_ip_class_set(struct niu *np, unsigned long class,
 
        return 0;
 }
-#endif
 
 static int tcam_early_init(struct niu *np)
 {
@@ -3168,6 +3274,27 @@ static int niu_set_tcam_key(struct niu *np, unsigned long class_code, u64 key)
        return 0;
 }
 
+/* Entries for the ports are interleaved in the TCAM */
+static u16 tcam_get_index(struct niu *np, u16 idx)
+{
+       /* One entry reserved for IP fragment rule */
+       if (idx >= (np->clas.tcam_sz - 1))
+               idx = 0;
+       return (np->clas.tcam_top + ((idx+1) * np->parent->num_ports));
+}
+
+static u16 tcam_get_size(struct niu *np)
+{
+       /* One entry reserved for IP fragment rule */
+       return np->clas.tcam_sz - 1;
+}
+
+static u16 tcam_get_valid_entry_cnt(struct niu *np)
+{
+       /* One entry reserved for IP fragment rule */
+       return np->clas.tcam_valid_entries - 1;
+}
+
 static void niu_rx_skb_append(struct sk_buff *skb, struct page *page,
                              u32 offset, u32 size)
 {
@@ -4891,8 +5018,7 @@ static int niu_set_ip_frag_rule(struct niu *np)
        struct niu_tcam_entry *tp;
        int index, err;
 
-       /* XXX fix this allocation scheme XXX */
-       index = cp->tcam_index;
+       index = cp->tcam_top;
        tp = &parent->tcam[index];
 
        /* Note that the noport bit is the same in both ipv4 and
@@ -4909,6 +5035,8 @@ static int niu_set_ip_frag_rule(struct niu *np)
        err = tcam_assoc_write(np, index, tp->assoc_data);
        if (err)
                return err;
+       tp->valid = 1;
+       cp->tcam_valid_entries++;
 
        return 0;
 }
@@ -5212,10 +5340,10 @@ static void niu_init_xif_xmac(struct niu *np)
        if (np->flags & NIU_FLAGS_10G) {
                val |= XMAC_CONFIG_MODE_XGMII;
        } else {
-               if (lp->active_speed == SPEED_100)
-                       val |= XMAC_CONFIG_MODE_MII;
-               else
+               if (lp->active_speed == SPEED_1000)
                        val |= XMAC_CONFIG_MODE_GMII;
+               else
+                       val |= XMAC_CONFIG_MODE_MII;
        }
 
        nw64_mac(XMAC_CONFIG, val);
@@ -6703,17 +6831,27 @@ static int niu_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
        memset(cmd, 0, sizeof(*cmd));
        cmd->phy_address = np->phy_addr;
        cmd->supported = lp->supported;
-       cmd->advertising = lp->advertising;
-       cmd->autoneg = lp->autoneg;
+       cmd->advertising = lp->active_advertising;
+       cmd->autoneg = lp->active_autoneg;
        cmd->speed = lp->active_speed;
        cmd->duplex = lp->active_duplex;
+       cmd->port = (np->flags & NIU_FLAGS_FIBER) ? PORT_FIBRE : PORT_TP;
+       cmd->transceiver = (np->flags & NIU_FLAGS_XCVR_SERDES) ?
+               XCVR_EXTERNAL : XCVR_INTERNAL;
 
        return 0;
 }
 
 static int niu_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
 {
-       return -EINVAL;
+       struct niu *np = netdev_priv(dev);
+       struct niu_link_config *lp = &np->link_config;
+
+       lp->advertising = cmd->advertising;
+       lp->speed = cmd->speed;
+       lp->duplex = cmd->duplex;
+       lp->autoneg = cmd->autoneg;
+       return niu_init_link(np);
 }
 
 static u32 niu_get_msglevel(struct net_device *dev)
@@ -6728,6 +6866,16 @@ static void niu_set_msglevel(struct net_device *dev, u32 value)
        np->msg_enable = value;
 }
 
+static int niu_nway_reset(struct net_device *dev)
+{
+       struct niu *np = netdev_priv(dev);
+
+       if (np->link_config.autoneg)
+               return niu_init_link(np);
+
+       return 0;
+}
+
 static int niu_get_eeprom_len(struct net_device *dev)
 {
        struct niu *np = netdev_priv(dev);
@@ -6779,6 +6927,75 @@ static int niu_get_eeprom(struct net_device *dev,
        return 0;
 }
 
+static void niu_ethflow_to_l3proto(int flow_type, u8 *pid)
+{
+       switch (flow_type) {
+       case TCP_V4_FLOW:
+       case TCP_V6_FLOW:
+               *pid = IPPROTO_TCP;
+               break;
+       case UDP_V4_FLOW:
+       case UDP_V6_FLOW:
+               *pid = IPPROTO_UDP;
+               break;
+       case SCTP_V4_FLOW:
+       case SCTP_V6_FLOW:
+               *pid = IPPROTO_SCTP;
+               break;
+       case AH_V4_FLOW:
+       case AH_V6_FLOW:
+               *pid = IPPROTO_AH;
+               break;
+       case ESP_V4_FLOW:
+       case ESP_V6_FLOW:
+               *pid = IPPROTO_ESP;
+               break;
+       default:
+               *pid = 0;
+               break;
+       }
+}
+
+static int niu_class_to_ethflow(u64 class, int *flow_type)
+{
+       switch (class) {
+       case CLASS_CODE_TCP_IPV4:
+               *flow_type = TCP_V4_FLOW;
+               break;
+       case CLASS_CODE_UDP_IPV4:
+               *flow_type = UDP_V4_FLOW;
+               break;
+       case CLASS_CODE_AH_ESP_IPV4:
+               *flow_type = AH_V4_FLOW;
+               break;
+       case CLASS_CODE_SCTP_IPV4:
+               *flow_type = SCTP_V4_FLOW;
+               break;
+       case CLASS_CODE_TCP_IPV6:
+               *flow_type = TCP_V6_FLOW;
+               break;
+       case CLASS_CODE_UDP_IPV6:
+               *flow_type = UDP_V6_FLOW;
+               break;
+       case CLASS_CODE_AH_ESP_IPV6:
+               *flow_type = AH_V6_FLOW;
+               break;
+       case CLASS_CODE_SCTP_IPV6:
+               *flow_type = SCTP_V6_FLOW;
+               break;
+       case CLASS_CODE_USER_PROG1:
+       case CLASS_CODE_USER_PROG2:
+       case CLASS_CODE_USER_PROG3:
+       case CLASS_CODE_USER_PROG4:
+               *flow_type = IP_USER_FLOW;
+               break;
+       default:
+               return 0;
+       }
+
+       return 1;
+}
+
 static int niu_ethflow_to_class(int flow_type, u64 *class)
 {
        switch (flow_type) {
@@ -6788,7 +7005,8 @@ static int niu_ethflow_to_class(int flow_type, u64 *class)
        case UDP_V4_FLOW:
                *class = CLASS_CODE_UDP_IPV4;
                break;
-       case AH_ESP_V4_FLOW:
+       case AH_V4_FLOW:
+       case ESP_V4_FLOW:
                *class = CLASS_CODE_AH_ESP_IPV4;
                break;
        case SCTP_V4_FLOW:
@@ -6800,7 +7018,8 @@ static int niu_ethflow_to_class(int flow_type, u64 *class)
        case UDP_V6_FLOW:
                *class = CLASS_CODE_UDP_IPV6;
                break;
-       case AH_ESP_V6_FLOW:
+       case AH_V6_FLOW:
+       case ESP_V6_FLOW:
                *class = CLASS_CODE_AH_ESP_IPV6;
                break;
        case SCTP_V6_FLOW:
@@ -6817,8 +7036,6 @@ static u64 niu_flowkey_to_ethflow(u64 flow_key)
 {
        u64 ethflow = 0;
 
-       if (flow_key & FLOW_KEY_PORT)
-               ethflow |= RXH_DEV_PORT;
        if (flow_key & FLOW_KEY_L2DA)
                ethflow |= RXH_L2DA;
        if (flow_key & FLOW_KEY_VLAN)
@@ -6842,8 +7059,6 @@ static int niu_ethflow_to_flowkey(u64 ethflow, u64 *flow_key)
 {
        u64 key = 0;
 
-       if (ethflow & RXH_DEV_PORT)
-               key |= FLOW_KEY_PORT;
        if (ethflow & RXH_L2DA)
                key |= FLOW_KEY_L2DA;
        if (ethflow & RXH_VLAN)
@@ -6865,41 +7080,279 @@ static int niu_ethflow_to_flowkey(u64 ethflow, u64 *flow_key)
 
 }
 
-static int niu_get_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd)
+static int niu_get_hash_opts(struct niu *np, struct ethtool_rxnfc *nfc)
 {
-       struct niu *np = netdev_priv(dev);
        u64 class;
 
-       cmd->data = 0;
+       nfc->data = 0;
 
-       if (!niu_ethflow_to_class(cmd->flow_type, &class))
+       if (!niu_ethflow_to_class(nfc->flow_type, &class))
                return -EINVAL;
 
        if (np->parent->tcam_key[class - CLASS_CODE_USER_PROG1] &
            TCAM_KEY_DISC)
-               cmd->data = RXH_DISCARD;
+               nfc->data = RXH_DISCARD;
        else
-
-               cmd->data = niu_flowkey_to_ethflow(np->parent->flow_key[class -
+               nfc->data = niu_flowkey_to_ethflow(np->parent->flow_key[class -
                                                      CLASS_CODE_USER_PROG1]);
        return 0;
 }
 
-static int niu_set_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd)
+static void niu_get_ip4fs_from_tcam_key(struct niu_tcam_entry *tp,
+                                       struct ethtool_rx_flow_spec *fsp)
+{
+
+       fsp->h_u.tcp_ip4_spec.ip4src = (tp->key[3] & TCAM_V4KEY3_SADDR) >>
+               TCAM_V4KEY3_SADDR_SHIFT;
+       fsp->h_u.tcp_ip4_spec.ip4dst = (tp->key[3] & TCAM_V4KEY3_DADDR) >>
+               TCAM_V4KEY3_DADDR_SHIFT;
+       fsp->m_u.tcp_ip4_spec.ip4src = (tp->key_mask[3] & TCAM_V4KEY3_SADDR) >>
+               TCAM_V4KEY3_SADDR_SHIFT;
+       fsp->m_u.tcp_ip4_spec.ip4dst = (tp->key_mask[3] & TCAM_V4KEY3_DADDR) >>
+               TCAM_V4KEY3_DADDR_SHIFT;
+
+       fsp->h_u.tcp_ip4_spec.ip4src =
+               cpu_to_be32(fsp->h_u.tcp_ip4_spec.ip4src);
+       fsp->m_u.tcp_ip4_spec.ip4src =
+               cpu_to_be32(fsp->m_u.tcp_ip4_spec.ip4src);
+       fsp->h_u.tcp_ip4_spec.ip4dst =
+               cpu_to_be32(fsp->h_u.tcp_ip4_spec.ip4dst);
+       fsp->m_u.tcp_ip4_spec.ip4dst =
+               cpu_to_be32(fsp->m_u.tcp_ip4_spec.ip4dst);
+
+       fsp->h_u.tcp_ip4_spec.tos = (tp->key[2] & TCAM_V4KEY2_TOS) >>
+               TCAM_V4KEY2_TOS_SHIFT;
+       fsp->m_u.tcp_ip4_spec.tos = (tp->key_mask[2] & TCAM_V4KEY2_TOS) >>
+               TCAM_V4KEY2_TOS_SHIFT;
+
+       switch (fsp->flow_type) {
+       case TCP_V4_FLOW:
+       case UDP_V4_FLOW:
+       case SCTP_V4_FLOW:
+               fsp->h_u.tcp_ip4_spec.psrc =
+                       ((tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
+                        TCAM_V4KEY2_PORT_SPI_SHIFT) >> 16;
+               fsp->h_u.tcp_ip4_spec.pdst =
+                       ((tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
+                        TCAM_V4KEY2_PORT_SPI_SHIFT) & 0xffff;
+               fsp->m_u.tcp_ip4_spec.psrc =
+                       ((tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
+                        TCAM_V4KEY2_PORT_SPI_SHIFT) >> 16;
+               fsp->m_u.tcp_ip4_spec.pdst =
+                       ((tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
+                        TCAM_V4KEY2_PORT_SPI_SHIFT) & 0xffff;
+
+               fsp->h_u.tcp_ip4_spec.psrc =
+                       cpu_to_be16(fsp->h_u.tcp_ip4_spec.psrc);
+               fsp->h_u.tcp_ip4_spec.pdst =
+                       cpu_to_be16(fsp->h_u.tcp_ip4_spec.pdst);
+               fsp->m_u.tcp_ip4_spec.psrc =
+                       cpu_to_be16(fsp->m_u.tcp_ip4_spec.psrc);
+               fsp->m_u.tcp_ip4_spec.pdst =
+                       cpu_to_be16(fsp->m_u.tcp_ip4_spec.pdst);
+               break;
+       case AH_V4_FLOW:
+       case ESP_V4_FLOW:
+               fsp->h_u.ah_ip4_spec.spi =
+                       (tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
+                       TCAM_V4KEY2_PORT_SPI_SHIFT;
+               fsp->m_u.ah_ip4_spec.spi =
+                       (tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
+                       TCAM_V4KEY2_PORT_SPI_SHIFT;
+
+               fsp->h_u.ah_ip4_spec.spi =
+                       cpu_to_be32(fsp->h_u.ah_ip4_spec.spi);
+               fsp->m_u.ah_ip4_spec.spi =
+                       cpu_to_be32(fsp->m_u.ah_ip4_spec.spi);
+               break;
+       case IP_USER_FLOW:
+               fsp->h_u.usr_ip4_spec.l4_4_bytes =
+                       (tp->key[2] & TCAM_V4KEY2_PORT_SPI) >>
+                       TCAM_V4KEY2_PORT_SPI_SHIFT;
+               fsp->m_u.usr_ip4_spec.l4_4_bytes =
+                       (tp->key_mask[2] & TCAM_V4KEY2_PORT_SPI) >>
+                       TCAM_V4KEY2_PORT_SPI_SHIFT;
+
+               fsp->h_u.usr_ip4_spec.l4_4_bytes =
+                       cpu_to_be32(fsp->h_u.usr_ip4_spec.l4_4_bytes);
+               fsp->m_u.usr_ip4_spec.l4_4_bytes =
+                       cpu_to_be32(fsp->m_u.usr_ip4_spec.l4_4_bytes);
+
+               fsp->h_u.usr_ip4_spec.proto =
+                       (tp->key[2] & TCAM_V4KEY2_PROTO) >>
+                       TCAM_V4KEY2_PROTO_SHIFT;
+               fsp->m_u.usr_ip4_spec.proto =
+                       (tp->key_mask[2] & TCAM_V4KEY2_PROTO) >>
+                       TCAM_V4KEY2_PROTO_SHIFT;
+
+               fsp->h_u.usr_ip4_spec.ip_ver = ETH_RX_NFC_IP4;
+               break;
+       default:
+               break;
+       }
+}
+
+static int niu_get_ethtool_tcam_entry(struct niu *np,
+                                     struct ethtool_rxnfc *nfc)
+{
+       struct niu_parent *parent = np->parent;
+       struct niu_tcam_entry *tp;
+       struct ethtool_rx_flow_spec *fsp = &nfc->fs;
+       u16 idx;
+       u64 class;
+       int ret = 0;
+
+       idx = tcam_get_index(np, (u16)nfc->fs.location);
+
+       tp = &parent->tcam[idx];
+       if (!tp->valid) {
+               pr_info(PFX "niu%d: %s entry [%d] invalid for idx[%d]\n",
+               parent->index, np->dev->name, (u16)nfc->fs.location, idx);
+               return -EINVAL;
+       }
+
+       /* fill the flow spec entry */
+       class = (tp->key[0] & TCAM_V4KEY0_CLASS_CODE) >>
+               TCAM_V4KEY0_CLASS_CODE_SHIFT;
+       ret = niu_class_to_ethflow(class, &fsp->flow_type);
+
+       if (ret < 0) {
+               pr_info(PFX "niu%d: %s niu_class_to_ethflow failed\n",
+               parent->index, np->dev->name);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (fsp->flow_type == AH_V4_FLOW || fsp->flow_type == AH_V6_FLOW) {
+               u32 proto = (tp->key[2] & TCAM_V4KEY2_PROTO) >>
+                       TCAM_V4KEY2_PROTO_SHIFT;
+               if (proto == IPPROTO_ESP) {
+                       if (fsp->flow_type == AH_V4_FLOW)
+                               fsp->flow_type = ESP_V4_FLOW;
+                       else
+                               fsp->flow_type = ESP_V6_FLOW;
+               }
+       }
+
+       switch (fsp->flow_type) {
+       case TCP_V4_FLOW:
+       case UDP_V4_FLOW:
+       case SCTP_V4_FLOW:
+       case AH_V4_FLOW:
+       case ESP_V4_FLOW:
+               niu_get_ip4fs_from_tcam_key(tp, fsp);
+               break;
+       case TCP_V6_FLOW:
+       case UDP_V6_FLOW:
+       case SCTP_V6_FLOW:
+       case AH_V6_FLOW:
+       case ESP_V6_FLOW:
+               /* Not yet implemented */
+               ret = -EINVAL;
+               break;
+       case IP_USER_FLOW:
+               niu_get_ip4fs_from_tcam_key(tp, fsp);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       if (ret < 0)
+               goto out;
+
+       if (tp->assoc_data & TCAM_ASSOCDATA_DISC)
+               fsp->ring_cookie = RX_CLS_FLOW_DISC;
+       else
+               fsp->ring_cookie = (tp->assoc_data & TCAM_ASSOCDATA_OFFSET) >>
+                       TCAM_ASSOCDATA_OFFSET_SHIFT;
+
+       /* put the tcam size here */
+       nfc->data = tcam_get_size(np);
+out:
+       return ret;
+}
+
+static int niu_get_ethtool_tcam_all(struct niu *np,
+                                   struct ethtool_rxnfc *nfc,
+                                   u32 *rule_locs)
+{
+       struct niu_parent *parent = np->parent;
+       struct niu_tcam_entry *tp;
+       int i, idx, cnt;
+       u16 n_entries;
+       unsigned long flags;
+
+
+       /* put the tcam size here */
+       nfc->data = tcam_get_size(np);
+
+       niu_lock_parent(np, flags);
+       n_entries = nfc->rule_cnt;
+       for (cnt = 0, i = 0; i < nfc->data; i++) {
+               idx = tcam_get_index(np, i);
+               tp = &parent->tcam[idx];
+               if (!tp->valid)
+                       continue;
+               rule_locs[cnt] = i;
+               cnt++;
+       }
+       niu_unlock_parent(np, flags);
+
+       if (n_entries != cnt) {
+               /* print warning, this should not happen */
+               pr_info(PFX "niu%d: %s In niu_get_ethtool_tcam_all, "
+                       "n_entries[%d] != cnt[%d]!!!\n\n",
+                       np->parent->index, np->dev->name, n_entries, cnt);
+       }
+
+       return 0;
+}
+
+static int niu_get_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd,
+                      void *rule_locs)
 {
        struct niu *np = netdev_priv(dev);
+       int ret = 0;
+
+       switch (cmd->cmd) {
+       case ETHTOOL_GRXFH:
+               ret = niu_get_hash_opts(np, cmd);
+               break;
+       case ETHTOOL_GRXRINGS:
+               cmd->data = np->num_rx_rings;
+               break;
+       case ETHTOOL_GRXCLSRLCNT:
+               cmd->rule_cnt = tcam_get_valid_entry_cnt(np);
+               break;
+       case ETHTOOL_GRXCLSRULE:
+               ret = niu_get_ethtool_tcam_entry(np, cmd);
+               break;
+       case ETHTOOL_GRXCLSRLALL:
+               ret = niu_get_ethtool_tcam_all(np, cmd, (u32 *)rule_locs);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
+static int niu_set_hash_opts(struct niu *np, struct ethtool_rxnfc *nfc)
+{
        u64 class;
        u64 flow_key = 0;
        unsigned long flags;
 
-       if (!niu_ethflow_to_class(cmd->flow_type, &class))
+       if (!niu_ethflow_to_class(nfc->flow_type, &class))
                return -EINVAL;
 
        if (class < CLASS_CODE_USER_PROG1 ||
            class > CLASS_CODE_SCTP_IPV6)
                return -EINVAL;
 
-       if (cmd->data & RXH_DISCARD) {
+       if (nfc->data & RXH_DISCARD) {
                niu_lock_parent(np, flags);
                flow_key = np->parent->tcam_key[class -
                                               CLASS_CODE_USER_PROG1];
@@ -6924,7 +7377,7 @@ static int niu_set_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd)
                }
        }
 
-       if (!niu_ethflow_to_flowkey(cmd->data, &flow_key))
+       if (!niu_ethflow_to_flowkey(nfc->data, &flow_key))
                return -EINVAL;
 
        niu_lock_parent(np, flags);
@@ -6935,6 +7388,331 @@ static int niu_set_hash_opts(struct net_device *dev, struct ethtool_rxnfc *cmd)
        return 0;
 }
 
+static void niu_get_tcamkey_from_ip4fs(struct ethtool_rx_flow_spec *fsp,
+                                      struct niu_tcam_entry *tp,
+                                      int l2_rdc_tab, u64 class)
+{
+       u8 pid = 0;
+       u32 sip, dip, sipm, dipm, spi, spim;
+       u16 sport, dport, spm, dpm;
+
+       sip = be32_to_cpu(fsp->h_u.tcp_ip4_spec.ip4src);
+       sipm = be32_to_cpu(fsp->m_u.tcp_ip4_spec.ip4src);
+       dip = be32_to_cpu(fsp->h_u.tcp_ip4_spec.ip4dst);
+       dipm = be32_to_cpu(fsp->m_u.tcp_ip4_spec.ip4dst);
+
+       tp->key[0] = class << TCAM_V4KEY0_CLASS_CODE_SHIFT;
+       tp->key_mask[0] = TCAM_V4KEY0_CLASS_CODE;
+       tp->key[1] = (u64)l2_rdc_tab << TCAM_V4KEY1_L2RDCNUM_SHIFT;
+       tp->key_mask[1] = TCAM_V4KEY1_L2RDCNUM;
+
+       tp->key[3] = (u64)sip << TCAM_V4KEY3_SADDR_SHIFT;
+       tp->key[3] |= dip;
+
+       tp->key_mask[3] = (u64)sipm << TCAM_V4KEY3_SADDR_SHIFT;
+       tp->key_mask[3] |= dipm;
+
+       tp->key[2] |= ((u64)fsp->h_u.tcp_ip4_spec.tos <<
+                      TCAM_V4KEY2_TOS_SHIFT);
+       tp->key_mask[2] |= ((u64)fsp->m_u.tcp_ip4_spec.tos <<
+                           TCAM_V4KEY2_TOS_SHIFT);
+       switch (fsp->flow_type) {
+       case TCP_V4_FLOW:
+       case UDP_V4_FLOW:
+       case SCTP_V4_FLOW:
+               sport = be16_to_cpu(fsp->h_u.tcp_ip4_spec.psrc);
+               spm = be16_to_cpu(fsp->m_u.tcp_ip4_spec.psrc);
+               dport = be16_to_cpu(fsp->h_u.tcp_ip4_spec.pdst);
+               dpm = be16_to_cpu(fsp->m_u.tcp_ip4_spec.pdst);
+
+               tp->key[2] |= (((u64)sport << 16) | dport);
+               tp->key_mask[2] |= (((u64)spm << 16) | dpm);
+               niu_ethflow_to_l3proto(fsp->flow_type, &pid);
+               break;
+       case AH_V4_FLOW:
+       case ESP_V4_FLOW:
+               spi = be32_to_cpu(fsp->h_u.ah_ip4_spec.spi);
+               spim = be32_to_cpu(fsp->m_u.ah_ip4_spec.spi);
+
+               tp->key[2] |= spi;
+               tp->key_mask[2] |= spim;
+               niu_ethflow_to_l3proto(fsp->flow_type, &pid);
+               break;
+       case IP_USER_FLOW:
+               spi = be32_to_cpu(fsp->h_u.usr_ip4_spec.l4_4_bytes);
+               spim = be32_to_cpu(fsp->m_u.usr_ip4_spec.l4_4_bytes);
+
+               tp->key[2] |= spi;
+               tp->key_mask[2] |= spim;
+               pid = fsp->h_u.usr_ip4_spec.proto;
+               break;
+       default:
+               break;
+       }
+
+       tp->key[2] |= ((u64)pid << TCAM_V4KEY2_PROTO_SHIFT);
+       if (pid) {
+               tp->key_mask[2] |= TCAM_V4KEY2_PROTO;
+       }
+}
+
+static int niu_add_ethtool_tcam_entry(struct niu *np,
+                                     struct ethtool_rxnfc *nfc)
+{
+       struct niu_parent *parent = np->parent;
+       struct niu_tcam_entry *tp;
+       struct ethtool_rx_flow_spec *fsp = &nfc->fs;
+       struct niu_rdc_tables *rdc_table = &parent->rdc_group_cfg[np->port];
+       int l2_rdc_table = rdc_table->first_table_num;
+       u16 idx;
+       u64 class;
+       unsigned long flags;
+       int err, ret;
+
+       ret = 0;
+
+       idx = nfc->fs.location;
+       if (idx >= tcam_get_size(np))
+               return -EINVAL;
+
+       if (fsp->flow_type == IP_USER_FLOW) {
+               int i;
+               int add_usr_cls = 0;
+               int ipv6 = 0;
+               struct ethtool_usrip4_spec *uspec = &fsp->h_u.usr_ip4_spec;
+               struct ethtool_usrip4_spec *umask = &fsp->m_u.usr_ip4_spec;
+
+               niu_lock_parent(np, flags);
+
+               for (i = 0; i < NIU_L3_PROG_CLS; i++) {
+                       if (parent->l3_cls[i]) {
+                               if (uspec->proto == parent->l3_cls_pid[i]) {
+                                       class = parent->l3_cls[i];
+                                       parent->l3_cls_refcnt[i]++;
+                                       add_usr_cls = 1;
+                                       break;
+                               }
+                       } else {
+                               /* Program new user IP class */
+                               switch (i) {
+                               case 0:
+                                       class = CLASS_CODE_USER_PROG1;
+                                       break;
+                               case 1:
+                                       class = CLASS_CODE_USER_PROG2;
+                                       break;
+                               case 2:
+                                       class = CLASS_CODE_USER_PROG3;
+                                       break;
+                               case 3:
+                                       class = CLASS_CODE_USER_PROG4;
+                                       break;
+                               default:
+                                       break;
+                               }
+                               if (uspec->ip_ver == ETH_RX_NFC_IP6)
+                                       ipv6 = 1;
+                               ret = tcam_user_ip_class_set(np, class, ipv6,
+                                                            uspec->proto,
+                                                            uspec->tos,
+                                                            umask->tos);
+                               if (ret)
+                                       goto out;
+
+                               ret = tcam_user_ip_class_enable(np, class, 1);
+                               if (ret)
+                                       goto out;
+                               parent->l3_cls[i] = class;
+                               parent->l3_cls_pid[i] = uspec->proto;
+                               parent->l3_cls_refcnt[i]++;
+                               add_usr_cls = 1;
+                               break;
+                       }
+               }
+               if (!add_usr_cls) {
+                       pr_info(PFX "niu%d: %s niu_add_ethtool_tcam_entry: "
+                               "Could not find/insert class for pid %d\n",
+                               parent->index, np->dev->name, uspec->proto);
+                       ret = -EINVAL;
+                       goto out;
+               }
+               niu_unlock_parent(np, flags);
+       } else {
+               if (!niu_ethflow_to_class(fsp->flow_type, &class)) {
+                       return -EINVAL;
+               }
+       }
+
+       niu_lock_parent(np, flags);
+
+       idx = tcam_get_index(np, idx);
+       tp = &parent->tcam[idx];
+
+       memset(tp, 0, sizeof(*tp));
+
+       /* fill in the tcam key and mask */
+       switch (fsp->flow_type) {
+       case TCP_V4_FLOW:
+       case UDP_V4_FLOW:
+       case SCTP_V4_FLOW:
+       case AH_V4_FLOW:
+       case ESP_V4_FLOW:
+               niu_get_tcamkey_from_ip4fs(fsp, tp, l2_rdc_table, class);
+               break;
+       case TCP_V6_FLOW:
+       case UDP_V6_FLOW:
+       case SCTP_V6_FLOW:
+       case AH_V6_FLOW:
+       case ESP_V6_FLOW:
+               /* Not yet implemented */
+               pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: "
+                       "flow %d for IPv6 not implemented\n\n",
+                       parent->index, np->dev->name, fsp->flow_type);
+               ret = -EINVAL;
+               goto out;
+       case IP_USER_FLOW:
+               if (fsp->h_u.usr_ip4_spec.ip_ver == ETH_RX_NFC_IP4) {
+                       niu_get_tcamkey_from_ip4fs(fsp, tp, l2_rdc_table,
+                                                  class);
+               } else {
+                       /* Not yet implemented */
+                       pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: "
+                       "usr flow for IPv6 not implemented\n\n",
+                       parent->index, np->dev->name);
+                       ret = -EINVAL;
+                       goto out;
+               }
+               break;
+       default:
+               pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: "
+                       "Unknown flow type %d\n\n",
+                       parent->index, np->dev->name, fsp->flow_type);
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* fill in the assoc data */
+       if (fsp->ring_cookie == RX_CLS_FLOW_DISC) {
+               tp->assoc_data = TCAM_ASSOCDATA_DISC;
+       } else {
+               if (fsp->ring_cookie >= np->num_rx_rings) {
+                       pr_info(PFX "niu%d: %s In niu_add_ethtool_tcam_entry: "
+                               "Invalid RX ring %lld\n\n",
+                               parent->index, np->dev->name,
+                               (long long) fsp->ring_cookie);
+                       ret = -EINVAL;
+                       goto out;
+               }
+               tp->assoc_data = (TCAM_ASSOCDATA_TRES_USE_OFFSET |
+                                 (fsp->ring_cookie <<
+                                  TCAM_ASSOCDATA_OFFSET_SHIFT));
+       }
+
+       err = tcam_write(np, idx, tp->key, tp->key_mask);
+       if (err) {
+               ret = -EINVAL;
+               goto out;
+       }
+       err = tcam_assoc_write(np, idx, tp->assoc_data);
+       if (err) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* validate the entry */
+       tp->valid = 1;
+       np->clas.tcam_valid_entries++;
+out:
+       niu_unlock_parent(np, flags);
+
+       return ret;
+}
+
+static int niu_del_ethtool_tcam_entry(struct niu *np, u32 loc)
+{
+       struct niu_parent *parent = np->parent;
+       struct niu_tcam_entry *tp;
+       u16 idx;
+       unsigned long flags;
+       u64 class;
+       int ret = 0;
+
+       if (loc >= tcam_get_size(np))
+               return -EINVAL;
+
+       niu_lock_parent(np, flags);
+
+       idx = tcam_get_index(np, loc);
+       tp = &parent->tcam[idx];
+
+       /* if the entry is of a user defined class, then update*/
+       class = (tp->key[0] & TCAM_V4KEY0_CLASS_CODE) >>
+               TCAM_V4KEY0_CLASS_CODE_SHIFT;
+
+       if (class >= CLASS_CODE_USER_PROG1 && class <= CLASS_CODE_USER_PROG4) {
+               int i;
+               for (i = 0; i < NIU_L3_PROG_CLS; i++) {
+                       if (parent->l3_cls[i] == class) {
+                               parent->l3_cls_refcnt[i]--;
+                               if (!parent->l3_cls_refcnt[i]) {
+                                       /* disable class */
+                                       ret = tcam_user_ip_class_enable(np,
+                                                                       class,
+                                                                       0);
+                                       if (ret)
+                                               goto out;
+                                       parent->l3_cls[i] = 0;
+                                       parent->l3_cls_pid[i] = 0;
+                               }
+                               break;
+                       }
+               }
+               if (i == NIU_L3_PROG_CLS) {
+                       pr_info(PFX "niu%d: %s In niu_del_ethtool_tcam_entry,"
+                               "Usr class 0x%llx not found \n",
+                               parent->index, np->dev->name,
+                               (unsigned long long) class);
+                       ret = -EINVAL;
+                       goto out;
+               }
+       }
+
+       ret = tcam_flush(np, idx);
+       if (ret)
+               goto out;
+
+       /* invalidate the entry */
+       tp->valid = 0;
+       np->clas.tcam_valid_entries--;
+out:
+       niu_unlock_parent(np, flags);
+
+       return ret;
+}
+
+static int niu_set_nfc(struct net_device *dev, struct ethtool_rxnfc *cmd)
+{
+       struct niu *np = netdev_priv(dev);
+       int ret = 0;
+
+       switch (cmd->cmd) {
+       case ETHTOOL_SRXFH:
+               ret = niu_set_hash_opts(np, cmd);
+               break;
+       case ETHTOOL_SRXCLSRLINS:
+               ret = niu_add_ethtool_tcam_entry(np, cmd);
+               break;
+       case ETHTOOL_SRXCLSRLDEL:
+               ret = niu_del_ethtool_tcam_entry(np, cmd->fs.location);
+               break;
+       default:
+               ret = -EINVAL;
+               break;
+       }
+
+       return ret;
+}
+
 static const struct {
        const char string[ETH_GSTRING_LEN];
 } niu_xmac_stat_keys[] = {
@@ -7159,6 +7937,7 @@ static const struct ethtool_ops niu_ethtool_ops = {
        .get_link               = ethtool_op_get_link,
        .get_msglevel           = niu_get_msglevel,
        .set_msglevel           = niu_set_msglevel,
+       .nway_reset             = niu_nway_reset,
        .get_eeprom_len         = niu_get_eeprom_len,
        .get_eeprom             = niu_get_eeprom,
        .get_settings           = niu_get_settings,
@@ -7167,8 +7946,8 @@ static const struct ethtool_ops niu_ethtool_ops = {
        .get_stats_count        = niu_get_stats_count,
        .get_ethtool_stats      = niu_get_ethtool_stats,
        .phys_id                = niu_phys_id,
-       .get_rxhash             = niu_get_hash_opts,
-       .set_rxhash             = niu_set_hash_opts,
+       .get_rxnfc              = niu_get_nfc,
+       .set_rxnfc              = niu_set_nfc,
 };
 
 static int niu_ldg_assign_ldn(struct niu *np, struct niu_parent *parent,
@@ -8238,7 +9017,8 @@ static int __devinit niu_classifier_swstate_init(struct niu *np)
        niudbg(PROBE, "niu_classifier_swstate_init: num_tcam(%d)\n",
               np->parent->tcam_num_entries);
 
-       cp->tcam_index = (u16) np->port;
+       cp->tcam_top = (u16) np->port;
+       cp->tcam_sz = np->parent->tcam_num_entries / np->parent->num_ports;
        cp->h1_init = 0xffffffff;
        cp->h2_init = 0xffff;
 
@@ -8258,7 +9038,9 @@ static void __devinit niu_link_config_init(struct niu *np)
                           ADVERTISED_10000baseT_Full |
                           ADVERTISED_Autoneg);
        lp->speed = lp->active_speed = SPEED_INVALID;
-       lp->duplex = lp->active_duplex = DUPLEX_INVALID;
+       lp->duplex = DUPLEX_FULL;
+       lp->active_duplex = DUPLEX_INVALID;
+       lp->autoneg = 1;
 #if 0
        lp->loopback_mode = LOOPBACK_MAC;
        lp->active_speed = SPEED_10000;
index e1a7392e8d70a61bb7b4c6703f3e74bb9b0cd44e..8754e44cadaeceed4e2c11b1f38250adc74e01c2 100644 (file)
@@ -3004,7 +3004,9 @@ struct niu_classifier {
        struct niu_altmac_rdc   alt_mac_mappings[16];
        struct niu_vlan_rdc     vlan_mappings[ENET_VLAN_TBL_NUM_ENTRIES];
 
-       u16                     tcam_index;
+       u16                     tcam_top;
+       u16                     tcam_sz;
+       u16                     tcam_valid_entries;
        u16                     num_alt_mac_mappings;
 
        u32                     h1_init;
@@ -3040,6 +3042,7 @@ struct phy_probe_info {
 };
 
 struct niu_tcam_entry {
+       u8                      valid;
        u64                     key[4];
        u64                     key_mask[4];
        u64                     assoc_data;
@@ -3107,10 +3110,15 @@ struct niu_parent {
        struct phy_probe_info   phy_probe_info;
 
        struct niu_tcam_entry   tcam[NIU_TCAM_ENTRIES_MAX];
-       u64                     l2_cls[2];
-       u64                     l3_cls[4];
+
+#define        NIU_L2_PROG_CLS         2
+#define        NIU_L3_PROG_CLS         4
+       u64                     l2_cls[NIU_L2_PROG_CLS];
+       u64                     l3_cls[NIU_L3_PROG_CLS];
        u64                     tcam_key[12];
        u64                     flow_key[12];
+       u16                     l3_cls_refcnt[NIU_L3_PROG_CLS];
+       u8                      l3_cls_pid[NIU_L3_PROG_CLS];
 };
 
 struct niu_ops {
@@ -3131,16 +3139,19 @@ struct niu_ops {
 };
 
 struct niu_link_config {
+       u32                             supported;
+
        /* Describes what we're trying to get. */
        u32                             advertising;
-       u32                             supported;
        u16                             speed;
        u8                              duplex;
        u8                              autoneg;
 
        /* Describes what we actually have. */
+       u32                             active_advertising;
        u16                             active_speed;
        u8                              active_duplex;
+       u8                              active_autoneg;
 #define SPEED_INVALID          0xffff
 #define DUPLEX_INVALID         0xff
 #define AUTONEG_INVALID                0xff
index 9266502b5588d92006510b7b7f04841e4e153a2e..221b0c4c824a36bdb3e0ea1ece9e0e5497517a01 100644 (file)
@@ -822,8 +822,7 @@ static void ns83820_cleanup_rx(struct ns83820 *dev)
                struct sk_buff *skb = dev->rx_info.skbs[i];
                dev->rx_info.skbs[i] = NULL;
                clear_rx_desc(dev, i);
-               if (skb)
-                       kfree_skb(skb);
+               kfree_skb(skb);
        }
 }
 
index e5cb6b1f0ebd8be1aada0898403e79cb3a25d40f..8f3872b8985d10fd72c51498c1cd987166fcb49b 100644 (file)
@@ -257,6 +257,18 @@ static void tc574_detach(struct pcmcia_device *p_dev);
        local data structures for one device.  The device is registered
        with Card Services.
 */
+static const struct net_device_ops el3_netdev_ops = {
+       .ndo_open               = el3_open,
+       .ndo_stop               = el3_close,
+       .ndo_start_xmit         = el3_start_xmit,
+       .ndo_tx_timeout         = el3_tx_timeout,
+       .ndo_get_stats          = el3_get_stats,
+       .ndo_do_ioctl           = el3_ioctl,
+       .ndo_set_multicast_list = set_rx_mode,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
 
 static int tc574_probe(struct pcmcia_device *link)
 {
@@ -284,18 +296,9 @@ static int tc574_probe(struct pcmcia_device *link)
        link->conf.IntType = INT_MEMORY_AND_IO;
        link->conf.ConfigIndex = 1;
 
-       /* The EL3-specific entries in the device structure. */
-       dev->hard_start_xmit = &el3_start_xmit;
-       dev->get_stats = &el3_get_stats;
-       dev->do_ioctl = &el3_ioctl;
+       dev->netdev_ops = &el3_netdev_ops;
        SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
-       dev->set_multicast_list = &set_rx_mode;
-       dev->open = &el3_open;
-       dev->stop = &el3_close;
-#ifdef HAVE_TX_TIMEOUT
-       dev->tx_timeout = el3_tx_timeout;
        dev->watchdog_timeo = TX_TIMEOUT;
-#endif
 
        return tc574_config(link);
 } /* tc574_attach */
@@ -1035,7 +1038,8 @@ static int el3_rx(struct net_device *dev, int worklimit)
        DEBUG(3, "%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n",
                  dev->name, inw(ioaddr+EL3_STATUS), inw(ioaddr+RxStatus));
        while (!((rx_status = inw(ioaddr + RxStatus)) & 0x8000) &&
-                  (--worklimit >= 0)) {
+                       worklimit > 0) {
+               worklimit--;
                if (rx_status & 0x4000) { /* Error, update stats. */
                        short error = rx_status & 0x3800;
                        dev->stats.rx_errors++;
index 73ecc657999d69e899e4ddb2537e6aa1db376b1d..cdf661a6092c8b7f697886c22b1983473ac07bec 100644 (file)
@@ -169,6 +169,19 @@ static void tc589_detach(struct pcmcia_device *p_dev);
 
 ======================================================================*/
 
+static const struct net_device_ops el3_netdev_ops = {
+       .ndo_open               = el3_open,
+       .ndo_stop               = el3_close,
+       .ndo_start_xmit         = el3_start_xmit,
+       .ndo_tx_timeout         = el3_tx_timeout,
+       .ndo_set_config         = el3_config,
+       .ndo_get_stats          = el3_get_stats,
+       .ndo_set_multicast_list = set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 static int tc589_probe(struct pcmcia_device *link)
 {
     struct el3_private *lp;
@@ -195,17 +208,9 @@ static int tc589_probe(struct pcmcia_device *link)
     link->conf.IntType = INT_MEMORY_AND_IO;
     link->conf.ConfigIndex = 1;
 
-    /* The EL3-specific entries in the device structure. */
-    dev->hard_start_xmit = &el3_start_xmit;
-    dev->set_config = &el3_config;
-    dev->get_stats = &el3_get_stats;
-    dev->set_multicast_list = &set_multicast_list;
-    dev->open = &el3_open;
-    dev->stop = &el3_close;
-#ifdef HAVE_TX_TIMEOUT
-    dev->tx_timeout = el3_tx_timeout;
+    dev->netdev_ops = &el3_netdev_ops;
     dev->watchdog_timeo = TX_TIMEOUT;
-#endif
+
     SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
     return tc589_config(link);
@@ -857,7 +862,8 @@ static int el3_rx(struct net_device *dev)
     DEBUG(3, "%s: in rx_packet(), status %4.4x, rx_status %4.4x.\n",
          dev->name, inw(ioaddr+EL3_STATUS), inw(ioaddr+RX_STATUS));
     while (!((rx_status = inw(ioaddr + RX_STATUS)) & 0x8000) &&
-          (--worklimit >= 0)) {
+                   worklimit > 0) {
+       worklimit--;
        if (rx_status & 0x4000) { /* Error, update stats. */
            short error = rx_status & 0x3800;
            dev->stats.rx_errors++;
index 871ad2958ff6e8c0b9e5c3ad622b61f00df1422f..501a8d7ac2beccf70c34a14903c0178dbea07d2c 100644 (file)
@@ -35,6 +35,7 @@
 #include <linux/spinlock.h>
 #include <linux/ethtool.h>
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 #include <linux/crc32.h>
 #include "../8390.h"
 
@@ -91,6 +92,10 @@ static void axnet_release(struct pcmcia_device *link);
 static int axnet_open(struct net_device *dev);
 static int axnet_close(struct net_device *dev);
 static int axnet_ioctl(struct net_device *dev, struct ifreq *rq, int cmd);
+static int axnet_start_xmit(struct sk_buff *skb, struct net_device *dev);
+static struct net_device_stats *get_stats(struct net_device *dev);
+static void set_multicast_list(struct net_device *dev);
+static void axnet_tx_timeout(struct net_device *dev);
 static const struct ethtool_ops netdev_ethtool_ops;
 static irqreturn_t ei_irq_wrapper(int irq, void *dev_id);
 static void ei_watchdog(u_long arg);
@@ -108,7 +113,6 @@ static void block_output(struct net_device *dev, int count,
 
 static void axnet_detach(struct pcmcia_device *p_dev);
 
-static void axdev_setup(struct net_device *dev);
 static void AX88190_init(struct net_device *dev, int startp);
 static int ax_open(struct net_device *dev);
 static int ax_close(struct net_device *dev);
@@ -134,6 +138,19 @@ static inline axnet_dev_t *PRIV(struct net_device *dev)
        return p;
 }
 
+static const struct net_device_ops axnet_netdev_ops = {
+       .ndo_open               = axnet_open,
+       .ndo_stop               = axnet_close,
+       .ndo_do_ioctl           = axnet_ioctl,
+       .ndo_start_xmit         = axnet_start_xmit,
+       .ndo_tx_timeout         = axnet_tx_timeout,
+       .ndo_get_stats          = get_stats,
+       .ndo_set_multicast_list = set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 /*======================================================================
 
     axnet_attach() creates an "instance" of the driver, allocating
@@ -146,15 +163,17 @@ static int axnet_probe(struct pcmcia_device *link)
 {
     axnet_dev_t *info;
     struct net_device *dev;
+    struct ei_device *ei_local;
 
     DEBUG(0, "axnet_attach()\n");
 
-    dev = alloc_netdev(sizeof(struct ei_device) + sizeof(axnet_dev_t),
-                       "eth%d", axdev_setup);
-
+    dev = alloc_etherdev(sizeof(struct ei_device) + sizeof(axnet_dev_t));
     if (!dev)
        return -ENOMEM;
 
+    ei_local = netdev_priv(dev);
+    spin_lock_init(&ei_local->page_lock);
+
     info = PRIV(dev);
     info->p_dev = link;
     link->priv = dev;
@@ -163,10 +182,10 @@ static int axnet_probe(struct pcmcia_device *link)
     link->conf.Attributes = CONF_ENABLE_IRQ;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
-    dev->open = &axnet_open;
-    dev->stop = &axnet_close;
-    dev->do_ioctl = &axnet_ioctl;
+    dev->netdev_ops = &axnet_netdev_ops;
+
     SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
+    dev->watchdog_timeo = TX_TIMEOUT;
 
     return axnet_config(link);
 } /* axnet_attach */
@@ -905,14 +924,12 @@ int ei_debug = 1;
 /* Index to functions. */
 static void ei_tx_intr(struct net_device *dev);
 static void ei_tx_err(struct net_device *dev);
-static void axnet_tx_timeout(struct net_device *dev);
 static void ei_receive(struct net_device *dev);
 static void ei_rx_overrun(struct net_device *dev);
 
 /* Routines generic to NS8390-based boards. */
 static void NS8390_trigger_send(struct net_device *dev, unsigned int length,
                                                                int start_page);
-static void set_multicast_list(struct net_device *dev);
 static void do_set_multicast_list(struct net_device *dev);
 
 /*
@@ -954,15 +971,6 @@ static int ax_open(struct net_device *dev)
        unsigned long flags;
        struct ei_device *ei_local = (struct ei_device *) netdev_priv(dev);
 
-#ifdef HAVE_TX_TIMEOUT
-       /* The card I/O part of the driver (e.g. 3c503) can hook a Tx timeout
-           wrapper that does e.g. media check & then calls axnet_tx_timeout. */
-       if (dev->tx_timeout == NULL)
-                dev->tx_timeout = axnet_tx_timeout;
-       if (dev->watchdog_timeo <= 0)
-                dev->watchdog_timeo = TX_TIMEOUT;
-#endif
-
        /*
         *      Grab the page lock so we own the register set, then call
         *      the init function.
@@ -1701,30 +1709,6 @@ static void set_multicast_list(struct net_device *dev)
        spin_unlock_irqrestore(&dev_lock(dev), flags);
 }      
 
-/**
- * axdev_setup - init rest of 8390 device struct
- * @dev: network device structure to init
- *
- * Initialize the rest of the 8390 device structure.  Do NOT __init
- * this, as it is used by 8390 based modular drivers too.
- */
-
-static void axdev_setup(struct net_device *dev)
-{
-       struct ei_device *ei_local;
-       if (ei_debug > 1)
-               printk(version_8390);
-    
-       ei_local = (struct ei_device *)netdev_priv(dev);
-       spin_lock_init(&ei_local->page_lock);
-    
-       dev->hard_start_xmit = &axnet_start_xmit;
-       dev->get_stats  = get_stats;
-       dev->set_multicast_list = &set_multicast_list;
-
-       ether_setup(dev);
-}
-
 /* This page of functions should be 8390 generic */
 /* Follow National Semi's recommendations for initializing the "NIC". */
 
index 69dcfbbabe825229ca4f709315b9e29c9049cd76..81e6660a433ad9dcd892d3aebf5d3a885ce5e334 100644 (file)
@@ -100,7 +100,6 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t fjn_interrupt(int irq, void *dev_id);
 static void fjn_rx(struct net_device *dev);
 static void fjn_reset(struct net_device *dev);
-static struct net_device_stats *fjn_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
 static void fjn_tx_timeout(struct net_device *dev);
 static const struct ethtool_ops netdev_ethtool_ops;
@@ -118,7 +117,6 @@ typedef enum { MBH10302, MBH10304, TDK, CONTEC, LA501, UNGERMANN,
 typedef struct local_info_t {
        struct pcmcia_device    *p_dev;
     dev_node_t node;
-    struct net_device_stats stats;
     long open_time;
     uint tx_started:1;
     uint tx_queue;
@@ -229,6 +227,18 @@ typedef struct local_info_t {
 #define BANK_1U              0x24 /* bank 1 (CONFIG_1) */
 #define BANK_2U              0x28 /* bank 2 (CONFIG_1) */
 
+static const struct net_device_ops fjn_netdev_ops = {
+       .ndo_open               = fjn_open,
+       .ndo_stop               = fjn_close,
+       .ndo_start_xmit         = fjn_start_xmit,
+       .ndo_tx_timeout         = fjn_tx_timeout,
+       .ndo_set_config         = fjn_config,
+       .ndo_set_multicast_list = set_rx_mode,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 static int fmvj18x_probe(struct pcmcia_device *link)
 {
     local_info_t *lp;
@@ -260,17 +270,9 @@ static int fmvj18x_probe(struct pcmcia_device *link)
     link->conf.Attributes = CONF_ENABLE_IRQ;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
-    /* The FMVJ18x specific entries in the device structure. */
-    dev->hard_start_xmit = &fjn_start_xmit;
-    dev->set_config = &fjn_config;
-    dev->get_stats = &fjn_get_stats;
-    dev->set_multicast_list = &set_rx_mode;
-    dev->open = &fjn_open;
-    dev->stop = &fjn_close;
-#ifdef HAVE_TX_TIMEOUT
-    dev->tx_timeout = fjn_tx_timeout;
+    dev->netdev_ops = &fjn_netdev_ops;
     dev->watchdog_timeo = TX_TIMEOUT;
-#endif
+
     SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
     return fmvj18x_config(link);
@@ -793,7 +795,7 @@ static irqreturn_t fjn_interrupt(int dummy, void *dev_id)
        fjn_rx(dev);
     }
     if (tx_stat & F_TMT_RDY) {
-       lp->stats.tx_packets += lp->sent ;
+       dev->stats.tx_packets += lp->sent ;
         lp->sent = 0 ;
        if (lp->tx_queue) {
            outb(DO_TX | lp->tx_queue, ioaddr + TX_START);
@@ -840,7 +842,7 @@ static void fjn_tx_timeout(struct net_device *dev)
           htons(inw(ioaddr + 6)), htons(inw(ioaddr + 8)),
           htons(inw(ioaddr +10)), htons(inw(ioaddr +12)),
           htons(inw(ioaddr +14)));
-    lp->stats.tx_errors++;
+    dev->stats.tx_errors++;
     /* ToDo: We should try to restart the adaptor... */
     local_irq_disable();
     fjn_reset(dev);
@@ -880,7 +882,7 @@ static int fjn_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        DEBUG(4, "%s: Transmitting a packet of length %lu.\n",
              dev->name, (unsigned long)skb->len);
-       lp->stats.tx_bytes += skb->len;
+       dev->stats.tx_bytes += skb->len;
 
        /* Disable both interrupts. */
        outw(0x0000, ioaddr + TX_INTR);
@@ -1008,7 +1010,6 @@ static void fjn_reset(struct net_device *dev)
 
 static void fjn_rx(struct net_device *dev)
 {
-    struct local_info_t *lp = netdev_priv(dev);
     unsigned int ioaddr = dev->base_addr;
     int boguscount = 10;       /* 5 -> 10: by agy 19940922 */
 
@@ -1027,11 +1028,11 @@ static void fjn_rx(struct net_device *dev)
        }
 #endif
        if ((status & 0xF0) != 0x20) {  /* There was an error. */
-           lp->stats.rx_errors++;
-           if (status & F_LEN_ERR) lp->stats.rx_length_errors++;
-           if (status & F_ALG_ERR) lp->stats.rx_frame_errors++;
-           if (status & F_CRC_ERR) lp->stats.rx_crc_errors++;
-           if (status & F_OVR_FLO) lp->stats.rx_over_errors++;
+           dev->stats.rx_errors++;
+           if (status & F_LEN_ERR) dev->stats.rx_length_errors++;
+           if (status & F_ALG_ERR) dev->stats.rx_frame_errors++;
+           if (status & F_CRC_ERR) dev->stats.rx_crc_errors++;
+           if (status & F_OVR_FLO) dev->stats.rx_over_errors++;
        } else {
            u_short pkt_len = inw(ioaddr + DATAPORT);
            /* Malloc up new buffer. */
@@ -1041,7 +1042,7 @@ static void fjn_rx(struct net_device *dev)
                printk(KERN_NOTICE "%s: The FMV-18x claimed a very "
                       "large packet, size %d.\n", dev->name, pkt_len);
                outb(F_SKP_PKT, ioaddr + RX_SKIP);
-               lp->stats.rx_errors++;
+               dev->stats.rx_errors++;
                break;
            }
            skb = dev_alloc_skb(pkt_len+2);
@@ -1049,7 +1050,7 @@ static void fjn_rx(struct net_device *dev)
                printk(KERN_NOTICE "%s: Memory squeeze, dropping "
                       "packet (len %d).\n", dev->name, pkt_len);
                outb(F_SKP_PKT, ioaddr + RX_SKIP);
-               lp->stats.rx_dropped++;
+               dev->stats.rx_dropped++;
                break;
            }
 
@@ -1070,8 +1071,8 @@ static void fjn_rx(struct net_device *dev)
 #endif
 
            netif_rx(skb);
-           lp->stats.rx_packets++;
-           lp->stats.rx_bytes += pkt_len;
+           dev->stats.rx_packets++;
+           dev->stats.rx_bytes += pkt_len;
        }
        if (--boguscount <= 0)
            break;
@@ -1191,14 +1192,6 @@ static int fjn_close(struct net_device *dev)
 
 /*====================================================================*/
 
-static struct net_device_stats *fjn_get_stats(struct net_device *dev)
-{
-    local_info_t *lp = netdev_priv(dev);
-    return &lp->stats;
-} /* fjn_get_stats */
-
-/*====================================================================*/
-
 /*
   Set the multicast/promiscuous mode for this adaptor.
 */
index ec7c588c9ae5cf77eec416fa1c929a0f152a13af..02ef63ed1f99ba6b6d630822baa6b5ddf897e2d2 100644 (file)
@@ -436,6 +436,19 @@ static const struct ethtool_ops netdev_ethtool_ops;
 
 static void nmclan_detach(struct pcmcia_device *p_dev);
 
+static const struct net_device_ops mace_netdev_ops = {
+       .ndo_open               = mace_open,
+       .ndo_stop               = mace_close,
+       .ndo_start_xmit         = mace_start_xmit,
+       .ndo_tx_timeout         = mace_tx_timeout,
+       .ndo_set_config         = mace_config,
+       .ndo_get_stats          = mace_get_stats,
+       .ndo_set_multicast_list = set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 /* ----------------------------------------------------------------------------
 nmclan_attach
        Creates an "instance" of the driver, allocating local data
@@ -474,17 +487,9 @@ static int nmclan_probe(struct pcmcia_device *link)
 
     lp->tx_free_frames=AM2150_MAX_TX_FRAMES;
 
-    dev->hard_start_xmit = &mace_start_xmit;
-    dev->set_config = &mace_config;
-    dev->get_stats = &mace_get_stats;
-    dev->set_multicast_list = &set_multicast_list;
+    dev->netdev_ops = &mace_netdev_ops;
     SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
-    dev->open = &mace_open;
-    dev->stop = &mace_close;
-#ifdef HAVE_TX_TIMEOUT
-    dev->tx_timeout = mace_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
-#endif
 
     return nmclan_config(link);
 } /* nmclan_attach */
index a6999403f37b27c63eb770a23e521f9517362a96..2fbf9f9ddd3751e39fbf00c7e6d6edd144ea0f01 100644 (file)
@@ -39,6 +39,7 @@
 #include <linux/ethtool.h>
 #include <linux/netdevice.h>
 #include <linux/log2.h>
+#include <linux/etherdevice.h>
 #include "../8390.h"
 
 #include <pcmcia/cs_types.h>
@@ -233,6 +234,23 @@ static inline pcnet_dev_t *PRIV(struct net_device *dev)
        return (pcnet_dev_t *)(p + sizeof(struct ei_device));
 }
 
+static const struct net_device_ops pcnet_netdev_ops = {
+       .ndo_open               = pcnet_open,
+       .ndo_stop               = pcnet_close,
+       .ndo_set_config         = set_config,
+       .ndo_start_xmit         = ei_start_xmit,
+       .ndo_get_stats          = ei_get_stats,
+       .ndo_do_ioctl           = ei_ioctl,
+       .ndo_set_multicast_list = ei_set_multicast_list,
+       .ndo_tx_timeout         = ei_tx_timeout,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = ei_poll,
+#endif
+};
+
 /*======================================================================
 
     pcnet_attach() creates an "instance" of the driver, allocating
@@ -260,9 +278,7 @@ static int pcnet_probe(struct pcmcia_device *link)
     link->conf.Attributes = CONF_ENABLE_IRQ;
     link->conf.IntType = INT_MEMORY_AND_IO;
 
-    dev->open = &pcnet_open;
-    dev->stop = &pcnet_close;
-    dev->set_config = &set_config;
+    dev->netdev_ops = &pcnet_netdev_ops;
 
     return pcnet_config(link);
 } /* pcnet_attach */
@@ -640,18 +656,12 @@ static int pcnet_config(struct pcmcia_device *link)
 
     SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
 
-    if (info->flags & (IS_DL10019|IS_DL10022)) {
-       dev->do_ioctl = &ei_ioctl;
+    if (info->flags & (IS_DL10019|IS_DL10022))
        mii_phy_probe(dev);
-    }
 
     link->dev_node = &info->node;
     SET_NETDEV_DEV(dev, &handle_to_dev(link));
 
-#ifdef CONFIG_NET_POLL_CONTROLLER
-    dev->poll_controller = ei_poll;
-#endif
-
     if (register_netdev(dev) != 0) {
        printk(KERN_NOTICE "pcnet_cs: register_netdev() failed\n");
        link->dev_node = NULL;
@@ -1183,6 +1193,10 @@ static int ei_ioctl(struct net_device *dev, struct ifreq *rq, int cmd)
     pcnet_dev_t *info = PRIV(dev);
     u16 *data = (u16 *)&rq->ifr_ifru;
     unsigned int mii_addr = dev->base_addr + DLINK_GPIO;
+
+    if (!(info->flags & (IS_DL10019|IS_DL10022)))
+       return -EINVAL;
+
     switch (cmd) {
     case SIOCGMIIPHY:
        data[0] = info->phy_id;
index fccd53ef3c64738c2cb7d5141895f3c5e3251d30..774232c13b3188db1d163ee167dd3982ea4acaf1 100644 (file)
@@ -108,7 +108,7 @@ struct smc_private {
     spinlock_t                 lock;
     u_short                    manfid;
     u_short                    cardid;
-    struct net_device_stats    stats;
+
     dev_node_t                 node;
     struct sk_buff             *saved_skb;
     int                                packets_waiting;
@@ -289,7 +289,6 @@ static void smc_tx_timeout(struct net_device *dev);
 static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static irqreturn_t smc_interrupt(int irq, void *dev_id);
 static void smc_rx(struct net_device *dev);
-static struct net_device_stats *smc_get_stats(struct net_device *dev);
 static void set_rx_mode(struct net_device *dev);
 static int s9k_config(struct net_device *dev, struct ifmap *map);
 static void smc_set_xcvr(struct net_device *dev, int if_port);
@@ -301,6 +300,19 @@ static void mdio_write(struct net_device *dev, int phy_id, int loc, int value);
 static int smc_link_ok(struct net_device *dev);
 static const struct ethtool_ops ethtool_ops;
 
+static const struct net_device_ops smc_netdev_ops = {
+       .ndo_open               = smc_open,
+       .ndo_stop               = smc_close,
+       .ndo_start_xmit         = smc_start_xmit,
+       .ndo_tx_timeout         = smc_tx_timeout,
+       .ndo_set_config         = s9k_config,
+       .ndo_set_multicast_list = set_rx_mode,
+       .ndo_do_ioctl           = &smc_ioctl,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 /*======================================================================
 
   smc91c92_attach() creates an "instance" of the driver, allocating
@@ -336,18 +348,9 @@ static int smc91c92_probe(struct pcmcia_device *link)
     link->conf.IntType = INT_MEMORY_AND_IO;
 
     /* The SMC91c92-specific entries in the device structure. */
-    dev->hard_start_xmit = &smc_start_xmit;
-    dev->get_stats = &smc_get_stats;
-    dev->set_config = &s9k_config;
-    dev->set_multicast_list = &set_rx_mode;
-    dev->open = &smc_open;
-    dev->stop = &smc_close;
-    dev->do_ioctl = &smc_ioctl;
+    dev->netdev_ops = &smc_netdev_ops;
     SET_ETHTOOL_OPS(dev, &ethtool_ops);
-#ifdef HAVE_TX_TIMEOUT
-    dev->tx_timeout = smc_tx_timeout;
     dev->watchdog_timeo = TX_TIMEOUT;
-#endif
 
     smc->mii_if.dev = dev;
     smc->mii_if.mdio_read = mdio_read;
@@ -1291,7 +1294,7 @@ static void smc_hardware_send_packet(struct net_device * dev)
        return;
     }
 
-    smc->stats.tx_bytes += skb->len;
+    dev->stats.tx_bytes += skb->len;
     /* The card should use the just-allocated buffer. */
     outw(packet_no, ioaddr + PNR_ARR);
     /* point to the beginning of the packet */
@@ -1340,7 +1343,7 @@ static void smc_tx_timeout(struct net_device *dev)
     printk(KERN_NOTICE "%s: SMC91c92 transmit timed out, "
           "Tx_status %2.2x status %4.4x.\n",
           dev->name, inw(ioaddr)&0xff, inw(ioaddr + 2));
-    smc->stats.tx_errors++;
+    dev->stats.tx_errors++;
     smc_reset(dev);
     dev->trans_start = jiffies;
     smc->saved_skb = NULL;
@@ -1362,7 +1365,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
     if (smc->saved_skb) {
        /* THIS SHOULD NEVER HAPPEN. */
-       smc->stats.tx_aborted_errors++;
+       dev->stats.tx_aborted_errors++;
        printk(KERN_DEBUG "%s: Internal error -- sent packet while busy.\n",
               dev->name);
        return 1;
@@ -1375,7 +1378,7 @@ static int smc_start_xmit(struct sk_buff *skb, struct net_device *dev)
        printk(KERN_ERR "%s: Far too big packet error.\n", dev->name);
        dev_kfree_skb (skb);
        smc->saved_skb = NULL;
-       smc->stats.tx_dropped++;
+       dev->stats.tx_dropped++;
        return 0;               /* Do not re-queue this packet. */
     }
     /* A packet is now waiting. */
@@ -1433,11 +1436,11 @@ static void smc_tx_err(struct net_device * dev)
 
     tx_status = inw(ioaddr + DATA_1);
 
-    smc->stats.tx_errors++;
-    if (tx_status & TS_LOSTCAR) smc->stats.tx_carrier_errors++;
-    if (tx_status & TS_LATCOL)  smc->stats.tx_window_errors++;
+    dev->stats.tx_errors++;
+    if (tx_status & TS_LOSTCAR) dev->stats.tx_carrier_errors++;
+    if (tx_status & TS_LATCOL)  dev->stats.tx_window_errors++;
     if (tx_status & TS_16COL) {
-       smc->stats.tx_aborted_errors++;
+       dev->stats.tx_aborted_errors++;
        smc->tx_err++;
     }
 
@@ -1474,10 +1477,10 @@ static void smc_eph_irq(struct net_device *dev)
     /* Could be a counter roll-over warning: update stats. */
     card_stats = inw(ioaddr + COUNTER);
     /* single collisions */
-    smc->stats.collisions += card_stats & 0xF;
+    dev->stats.collisions += card_stats & 0xF;
     card_stats >>= 4;
     /* multiple collisions */
-    smc->stats.collisions += card_stats & 0xF;
+    dev->stats.collisions += card_stats & 0xF;
 #if 0          /* These are for when linux supports these statistics */
     card_stats >>= 4;                  /* deferred */
     card_stats >>= 4;                  /* excess deferred */
@@ -1551,7 +1554,7 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id)
        if (status & IM_TX_EMPTY_INT) {
            outw(IM_TX_EMPTY_INT, ioaddr + INTERRUPT);
            mask &= ~IM_TX_EMPTY_INT;
-           smc->stats.tx_packets += smc->packets_waiting;
+           dev->stats.tx_packets += smc->packets_waiting;
            smc->packets_waiting = 0;
        }
        if (status & IM_ALLOC_INT) {
@@ -1567,8 +1570,8 @@ static irqreturn_t smc_interrupt(int irq, void *dev_id)
            netif_wake_queue(dev);
        }
        if (status & IM_RX_OVRN_INT) {
-           smc->stats.rx_errors++;
-           smc->stats.rx_fifo_errors++;
+           dev->stats.rx_errors++;
+           dev->stats.rx_fifo_errors++;
            if (smc->duplex)
                smc->rx_ovrn = 1; /* need MC_RESET outside smc_interrupt */
            outw(IM_RX_OVRN_INT, ioaddr + INTERRUPT);
@@ -1618,7 +1621,6 @@ irq_done:
 
 static void smc_rx(struct net_device *dev)
 {
-    struct smc_private *smc = netdev_priv(dev);
     unsigned int ioaddr = dev->base_addr;
     int rx_status;
     int packet_length; /* Caution: not frame length, rather words
@@ -1649,7 +1651,7 @@ static void smc_rx(struct net_device *dev)
        
        if (skb == NULL) {
            DEBUG(1, "%s: Low memory, packet dropped.\n", dev->name);
-           smc->stats.rx_dropped++;
+           dev->stats.rx_dropped++;
            outw(MC_RELEASE, ioaddr + MMU_CMD);
            return;
        }
@@ -1662,18 +1664,18 @@ static void smc_rx(struct net_device *dev)
        
        netif_rx(skb);
        dev->last_rx = jiffies;
-       smc->stats.rx_packets++;
-       smc->stats.rx_bytes += packet_length;
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += packet_length;
        if (rx_status & RS_MULTICAST)
-           smc->stats.multicast++;
+           dev->stats.multicast++;
     } else {
        /* error ... */
-       smc->stats.rx_errors++;
+       dev->stats.rx_errors++;
        
-       if (rx_status & RS_ALGNERR)  smc->stats.rx_frame_errors++;
+       if (rx_status & RS_ALGNERR)  dev->stats.rx_frame_errors++;
        if (rx_status & (RS_TOOSHORT | RS_TOOLONG))
-           smc->stats.rx_length_errors++;
-       if (rx_status & RS_BADCRC)      smc->stats.rx_crc_errors++;
+           dev->stats.rx_length_errors++;
+       if (rx_status & RS_BADCRC)      dev->stats.rx_crc_errors++;
     }
     /* Let the MMU free the memory of this packet. */
     outw(MC_RELEASE, ioaddr + MMU_CMD);
@@ -1681,15 +1683,6 @@ static void smc_rx(struct net_device *dev)
     return;
 }
 
-/*====================================================================*/
-
-static struct net_device_stats *smc_get_stats(struct net_device *dev)
-{
-    struct smc_private *smc = netdev_priv(dev);
-    /* Nothing to update - the 91c92 is a pretty primative chip. */
-    return &smc->stats;
-}
-
 /*======================================================================
 
     Calculate values for the hardware multicast filter hash table.
index fef7e1861d6a3fbf25922e92ed68b7f4e8924138..a3685c0d22fc3a2fd26a072019386395862586f5 100644 (file)
@@ -335,7 +335,7 @@ typedef struct local_info_t {
        struct net_device       *dev;
        struct pcmcia_device    *p_dev;
     dev_node_t node;
-    struct net_device_stats stats;
+
     int card_type;
     int probe_port;
     int silicon; /* silicon revision. 0=old CE2, 1=Scipper, 4=Mohawk */
@@ -355,7 +355,6 @@ typedef struct local_info_t {
 static int do_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static void xirc_tx_timeout(struct net_device *dev);
 static void xirc2ps_tx_timeout_task(struct work_struct *work);
-static struct net_device_stats *do_get_stats(struct net_device *dev);
 static void set_addresses(struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
 static int set_card_type(struct pcmcia_device *link, const void *s);
@@ -546,6 +545,19 @@ mii_wr(unsigned int ioaddr, u_char phyaddr, u_char phyreg, unsigned data,
 
 /*============= Main bulk of functions =========================*/
 
+static const struct net_device_ops netdev_ops = {
+       .ndo_open               = do_open,
+       .ndo_stop               = do_stop,
+       .ndo_start_xmit         = do_start_xmit,
+       .ndo_tx_timeout         = xirc_tx_timeout,
+       .ndo_set_config         = do_config,
+       .ndo_do_ioctl           = do_ioctl,
+       .ndo_set_multicast_list = set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 /****************
  * xirc2ps_attach() creates an "instance" of the driver, allocating
  * local data structures for one device.  The device is registered
@@ -581,19 +593,10 @@ xirc2ps_probe(struct pcmcia_device *link)
     link->irq.Instance = dev;
 
     /* Fill in card specific entries */
-    dev->hard_start_xmit = &do_start_xmit;
-    dev->set_config = &do_config;
-    dev->get_stats = &do_get_stats;
-    dev->do_ioctl = &do_ioctl;
-    SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
-    dev->set_multicast_list = &set_multicast_list;
-    dev->open = &do_open;
-    dev->stop = &do_stop;
-#ifdef HAVE_TX_TIMEOUT
-    dev->tx_timeout = xirc_tx_timeout;
+    dev->netdev_ops = &netdev_ops;
+    dev->ethtool_ops = &netdev_ethtool_ops;
     dev->watchdog_timeo = TX_TIMEOUT;
     INIT_WORK(&local->tx_timeout_task, xirc2ps_tx_timeout_task);
-#endif
 
     return xirc2ps_config(link);
 } /* xirc2ps_attach */
@@ -1172,7 +1175,7 @@ xirc2ps_interrupt(int irq, void *dev_id)
        if (bytes_rcvd > maxrx_bytes && (rsr & PktRxOk)) {
            /* too many bytes received during this int, drop the rest of the
             * packets */
-           lp->stats.rx_dropped++;
+           dev->stats.rx_dropped++;
            DEBUG(2, "%s: RX drop, too much done\n", dev->name);
        } else if (rsr & PktRxOk) {
            struct sk_buff *skb;
@@ -1186,7 +1189,7 @@ xirc2ps_interrupt(int irq, void *dev_id)
            if (!skb) {
                printk(KNOT_XIRC "low memory, packet dropped (size=%u)\n",
                       pktlen);
-               lp->stats.rx_dropped++;
+               dev->stats.rx_dropped++;
            } else { /* okay get the packet */
                skb_reserve(skb, 2);
                if (lp->silicon == 0 ) { /* work around a hardware bug */
@@ -1242,24 +1245,24 @@ xirc2ps_interrupt(int irq, void *dev_id)
                }
                skb->protocol = eth_type_trans(skb, dev);
                netif_rx(skb);
-               lp->stats.rx_packets++;
-               lp->stats.rx_bytes += pktlen;
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += pktlen;
                if (!(rsr & PhyPkt))
-                   lp->stats.multicast++;
+                   dev->stats.multicast++;
            }
        } else { /* bad packet */
            DEBUG(5, "rsr=%#02x\n", rsr);
        }
        if (rsr & PktTooLong) {
-           lp->stats.rx_frame_errors++;
+           dev->stats.rx_frame_errors++;
            DEBUG(3, "%s: Packet too long\n", dev->name);
        }
        if (rsr & CRCErr) {
-           lp->stats.rx_crc_errors++;
+           dev->stats.rx_crc_errors++;
            DEBUG(3, "%s: CRC error\n", dev->name);
        }
        if (rsr & AlignErr) {
-           lp->stats.rx_fifo_errors++; /* okay ? */
+           dev->stats.rx_fifo_errors++; /* okay ? */
            DEBUG(3, "%s: Alignment error\n", dev->name);
        }
 
@@ -1270,7 +1273,7 @@ xirc2ps_interrupt(int irq, void *dev_id)
        eth_status = GetByte(XIRCREG_ESR);
     }
     if (rx_status & 0x10) { /* Receive overrun */
-       lp->stats.rx_over_errors++;
+       dev->stats.rx_over_errors++;
        PutByte(XIRCREG_CR, ClearRxOvrun);
        DEBUG(3, "receive overrun cleared\n");
     }
@@ -1283,11 +1286,11 @@ xirc2ps_interrupt(int irq, void *dev_id)
        nn = GetByte(XIRCREG0_PTR);
        lp->last_ptr_value = nn;
        if (nn < n) /* rollover */
-           lp->stats.tx_packets += 256 - n;
+           dev->stats.tx_packets += 256 - n;
        else if (n == nn) { /* happens sometimes - don't know why */
            DEBUG(0, "PTR not changed?\n");
        } else
-           lp->stats.tx_packets += lp->last_ptr_value - n;
+           dev->stats.tx_packets += lp->last_ptr_value - n;
        netif_wake_queue(dev);
     }
     if (tx_status & 0x0002) {  /* Execessive collissions */
@@ -1295,7 +1298,7 @@ xirc2ps_interrupt(int irq, void *dev_id)
        PutByte(XIRCREG_CR, RestartTx);  /* restart transmitter process */
     }
     if (tx_status & 0x0040)
-       lp->stats.tx_aborted_errors++;
+       dev->stats.tx_aborted_errors++;
 
     /* recalculate our work chunk so that we limit the duration of this
      * ISR to about 1/10 of a second.
@@ -1353,7 +1356,7 @@ static void
 xirc_tx_timeout(struct net_device *dev)
 {
     local_info_t *lp = netdev_priv(dev);
-    lp->stats.tx_errors++;
+    dev->stats.tx_errors++;
     printk(KERN_NOTICE "%s: transmit timed out\n", dev->name);
     schedule_work(&lp->tx_timeout_task);
 }
@@ -1409,20 +1412,11 @@ do_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
     dev_kfree_skb (skb);
     dev->trans_start = jiffies;
-    lp->stats.tx_bytes += pktlen;
+    dev->stats.tx_bytes += pktlen;
     netif_start_queue(dev);
     return 0;
 }
 
-static struct net_device_stats *
-do_get_stats(struct net_device *dev)
-{
-    local_info_t *lp = netdev_priv(dev);
-
-    /* lp->stats.rx_missed_errors = GetByte(?) */
-    return &lp->stats;
-}
-
 /****************
  * Set all addresses: This first one is the individual address,
  * the next 9 addresses are taken from the multicast list and
index bb29ae3ff17dc6765fac1db21c532c1c5660b93c..b754020cbe75c731c1da255082fe382a59e1bf72 100644 (file)
@@ -99,7 +99,7 @@ int mdiobus_register(struct mii_bus *bus)
        bus->dev.parent = bus->parent;
        bus->dev.class = &mdio_bus_class;
        bus->dev.groups = NULL;
-       dev_set_name(&bus->dev, bus->id);
+       dev_set_name(&bus->dev, "%s", bus->id);
 
        err = device_register(&bus->dev);
        if (err) {
index e4ede6080c9dcd327acfa37530263c6382d050db..58b73b08dde08503b35d6e8d3c7ef4f6620ad8c2 100644 (file)
@@ -414,7 +414,6 @@ EXPORT_SYMBOL(phy_start_aneg);
 
 static void phy_change(struct work_struct *work);
 static void phy_state_machine(struct work_struct *work);
-static void phy_timer(unsigned long data);
 
 /**
  * phy_start_machine - start PHY state machine tracking
@@ -434,11 +433,8 @@ void phy_start_machine(struct phy_device *phydev,
 {
        phydev->adjust_state = handler;
 
-       INIT_WORK(&phydev->state_queue, phy_state_machine);
-       init_timer(&phydev->phy_timer);
-       phydev->phy_timer.function = &phy_timer;
-       phydev->phy_timer.data = (unsigned long) phydev;
-       mod_timer(&phydev->phy_timer, jiffies + HZ);
+       INIT_DELAYED_WORK(&phydev->state_queue, phy_state_machine);
+       schedule_delayed_work(&phydev->state_queue, jiffies + HZ);
 }
 
 /**
@@ -451,8 +447,7 @@ void phy_start_machine(struct phy_device *phydev,
  */
 void phy_stop_machine(struct phy_device *phydev)
 {
-       del_timer_sync(&phydev->phy_timer);
-       cancel_work_sync(&phydev->state_queue);
+       cancel_delayed_work_sync(&phydev->state_queue);
 
        mutex_lock(&phydev->lock);
        if (phydev->state > PHY_UP)
@@ -680,11 +675,9 @@ static void phy_change(struct work_struct *work)
        if (err)
                goto irq_enable_err;
 
-       /* Stop timer and run the state queue now.  The work function for
-        * state_queue will start the timer up again.
-        */
-       del_timer(&phydev->phy_timer);
-       schedule_work(&phydev->state_queue);
+       /* reschedule state queue work to run as soon as possible */
+       cancel_delayed_work_sync(&phydev->state_queue);
+       schedule_delayed_work(&phydev->state_queue, 0);
 
        return;
 
@@ -761,14 +754,13 @@ EXPORT_SYMBOL(phy_start);
 /**
  * phy_state_machine - Handle the state machine
  * @work: work_struct that describes the work to be done
- *
- * Description: Scheduled by the state_queue workqueue each time
- *   phy_timer is triggered.
  */
 static void phy_state_machine(struct work_struct *work)
 {
+       struct delayed_work *dwork =
+                       container_of(work, struct delayed_work, work);
        struct phy_device *phydev =
-                       container_of(work, struct phy_device, state_queue);
+                       container_of(dwork, struct phy_device, state_queue);
        int needs_aneg = 0;
        int err = 0;
 
@@ -946,17 +938,6 @@ static void phy_state_machine(struct work_struct *work)
        if (err < 0)
                phy_error(phydev);
 
-       mod_timer(&phydev->phy_timer, jiffies + PHY_STATE_TIME * HZ);
-}
-
-/* PHY timer which schedules the state machine work */
-static void phy_timer(unsigned long data)
-{
-       struct phy_device *phydev = (struct phy_device *)data;
-
-       /*
-        * PHY I/O operations can potentially sleep so we ensure that
-        * it's done from a process context
-        */
-       schedule_work(&phydev->state_queue);
+       schedule_delayed_work(&phydev->state_queue,
+                               jiffies + PHY_STATE_TIME * HZ);
 }
index 6567fabd2e132a4ab4296a8283d32632b299c9d0..6de8399d6dd92d26875cca679ec332c19082d736 100644 (file)
@@ -157,6 +157,7 @@ ppp_asynctty_open(struct tty_struct *tty)
 {
        struct asyncppp *ap;
        int err;
+       int speed;
 
        if (tty->ops->write == NULL)
                return -EOPNOTSUPP;
@@ -187,6 +188,8 @@ ppp_asynctty_open(struct tty_struct *tty)
        ap->chan.private = ap;
        ap->chan.ops = &async_ops;
        ap->chan.mtu = PPP_MRU;
+       speed = tty_get_baud_rate(tty);
+       ap->chan.speed = speed;
        err = ppp_register_channel(&ap->chan);
        if (err)
                goto out_free;
@@ -233,11 +236,9 @@ ppp_asynctty_close(struct tty_struct *tty)
        tasklet_kill(&ap->tsk);
 
        ppp_unregister_channel(&ap->chan);
-       if (ap->rpkt)
-               kfree_skb(ap->rpkt);
+       kfree_skb(ap->rpkt);
        skb_queue_purge(&ap->rqueue);
-       if (ap->tpkt)
-               kfree_skb(ap->tpkt);
+       kfree_skb(ap->tpkt);
        kfree(ap);
 }
 
index 81e7fcced4b98173ffeb74392f50f73593979dd8..8ee91421db12133634a922d2d8d70c933e22c248 100644 (file)
@@ -167,6 +167,7 @@ struct channel {
        u8              avail;          /* flag used in multilink stuff */
        u8              had_frag;       /* >= 1 fragments have been sent */
        u32             lastseq;        /* MP: last sequence # received */
+       int     speed;          /* speed of the corresponding ppp channel*/
 #endif /* CONFIG_PPP_MULTILINK */
 };
 
@@ -991,7 +992,7 @@ ppp_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
  outf:
        kfree_skb(skb);
-       ++ppp->dev->stats.tx_dropped;
+       ++dev->stats.tx_dropped;
        return 0;
 }
 
@@ -1245,8 +1246,7 @@ ppp_send_frame(struct ppp *ppp, struct sk_buff *skb)
        return;
 
  drop:
-       if (skb)
-               kfree_skb(skb);
+       kfree_skb(skb);
        ++ppp->dev->stats.tx_errors;
 }
 
@@ -1308,138 +1308,181 @@ ppp_push(struct ppp *ppp)
  */
 static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
 {
-       int len, fragsize;
-       int i, bits, hdrlen, mtu;
-       int flen;
-       int navail, nfree;
-       int nbigger;
+       int     len, totlen;
+       int     i, bits, hdrlen, mtu;
+       int     flen;
+       int     navail, nfree, nzero;
+       int     nbigger;
+       int     totspeed;
+       int     totfree;
        unsigned char *p, *q;
        struct list_head *list;
        struct channel *pch;
        struct sk_buff *frag;
        struct ppp_channel *chan;
 
-       nfree = 0;      /* # channels which have no packet already queued */
+       totspeed = 0; /*total bitrate of the bundle*/
+       nfree = 0;      /* # channels which     have no packet already queued */
        navail = 0;     /* total # of usable channels (not deregistered) */
+       nzero = 0; /* number of channels with zero speed associated*/
+       totfree = 0; /*total # of channels available and
+                                 *having no queued packets before
+                                 *starting the fragmentation*/
+
        hdrlen = (ppp->flags & SC_MP_XSHORTSEQ)? MPHDRLEN_SSN: MPHDRLEN;
-       i = 0;
-       list_for_each_entry(pch, &ppp->channels, clist) {
+       i =     0;
+       list_for_each_entry(pch, &ppp->channels, clist) {
                navail += pch->avail = (pch->chan != NULL);
-               if (pch->avail) {
+               pch->speed = pch->chan->speed;
+               if (pch->avail) {
                        if (skb_queue_empty(&pch->file.xq) ||
-                           !pch->had_frag) {
-                               pch->avail = 2;
-                               ++nfree;
-                       }
-                       if (!pch->had_frag && i < ppp->nxchan)
-                               ppp->nxchan = i;
+                               !pch->had_frag) {
+                                       if (pch->speed == 0)
+                                               nzero++;
+                                       else
+                                               totspeed += pch->speed;
+
+                                       pch->avail = 2;
+                                       ++nfree;
+                                       ++totfree;
+                               }
+                       if (!pch->had_frag && i < ppp->nxchan)
+                               ppp->nxchan     = i;
                }
                ++i;
        }
-
        /*
-        * Don't start sending this packet unless at least half of
-        * the channels are free.  This gives much better TCP
-        * performance if we have a lot of channels.
+        * Don't start sending this     packet unless at least half     of
+        * the channels are     free.  This     gives much better TCP
+        * performance if we have a     lot     of channels.
         */
-       if (nfree == 0 || nfree < navail / 2)
-               return 0;       /* can't take now, leave it in xmit_pending */
+       if (nfree == 0 || nfree < navail / 2)
+               return 0; /* can't take now, leave it in xmit_pending   */
 
        /* Do protocol field compression (XXX this should be optional) */
-       p = skb->data;
-       len = skb->len;
+       p =     skb->data;
+       len     = skb->len;
        if (*p == 0) {
                ++p;
                --len;
        }
 
-       /*
-        * Decide on fragment size.
-        * We create a fragment for each free channel regardless of
-        * how small they are (i.e. even 0 length) in order to minimize
-        * the time that it will take to detect when a channel drops
-        * a fragment.
-        */
-       fragsize = len;
-       if (nfree > 1)
-               fragsize = DIV_ROUND_UP(fragsize, nfree);
-       /* nbigger channels get fragsize bytes, the rest get fragsize-1,
-          except if nbigger==0, then they all get fragsize. */
-       nbigger = len % nfree;
-
-       /* skip to the channel after the one we last used
-          and start at that one */
+       totlen = len;
+       nbigger = len % nfree;
+
+       /* skip to the channel after the one we last used
+          and start at that one */
        list = &ppp->channels;
-       for (i = 0; i < ppp->nxchan; ++i) {
+       for     (i = 0; i <     ppp->nxchan; ++i) {
                list = list->next;
-               if (list == &ppp->channels) {
-                       i = 0;
+               if (list ==     &ppp->channels) {
+                       i =     0;
                        break;
                }
        }
 
-       /* create a fragment for each channel */
+       /* create a     fragment for each channel */
        bits = B;
-       while (nfree > 0 || len > 0) {
+       while (nfree > 0 &&     len     > 0) {
                list = list->next;
-               if (list == &ppp->channels) {
-                       i = 0;
+               if (list ==     &ppp->channels) {
+                       i =     0;
                        continue;
                }
-               pch = list_entry(list, struct channel, clist);
+               pch     = list_entry(list, struct channel, clist);
                ++i;
                if (!pch->avail)
                        continue;
 
                /*
-                * Skip this channel if it has a fragment pending already and
-                * we haven't given a fragment to all of the free channels.
+                * Skip this channel if it has a fragment pending already and
+                * we haven't given     a fragment to all of the free channels.
                 */
                if (pch->avail == 1) {
-                       if (nfree > 0)
+                       if (nfree >     0)
                                continue;
                } else {
-                       --nfree;
                        pch->avail = 1;
                }
 
                /* check the channel's mtu and whether it is still attached. */
                spin_lock_bh(&pch->downl);
                if (pch->chan == NULL) {
-                       /* can't use this channel, it's being deregistered */
+                       /* can't use this channel, it's being deregistered */
+                       if (pch->speed == 0)
+                               nzero--;
+                       else
+                               totspeed -=     pch->speed;
+
                        spin_unlock_bh(&pch->downl);
                        pch->avail = 0;
-                       if (--navail == 0)
+                       totlen = len;
+                       totfree--;
+                       nfree--;
+                       if (--navail == 0)
                                break;
                        continue;
                }
 
                /*
-                * Create a fragment for this channel of
-                * min(max(mtu+2-hdrlen, 4), fragsize, len) bytes.
-                * If mtu+2-hdrlen < 4, that is a ridiculously small
-                * MTU, so we use mtu = 2 + hdrlen.
+               *if the channel speed is not set divide
+               *the packet     evenly among the free channels;
+               *otherwise divide it according to the speed
+               *of the channel we are going to transmit on
+               */
+               if (pch->speed == 0) {
+                       flen = totlen/nfree     ;
+                       if (nbigger > 0) {
+                               flen++;
+                               nbigger--;
+                       }
+               } else {
+                       flen = (((totfree - nzero)*(totlen + hdrlen*totfree)) /
+                               ((totspeed*totfree)/pch->speed)) - hdrlen;
+                       if (nbigger > 0) {
+                               flen += ((totfree - nzero)*pch->speed)/totspeed;
+                               nbigger -= ((totfree - nzero)*pch->speed)/
+                                                       totspeed;
+                       }
+               }
+               nfree--;
+
+               /*
+                *check if we are on the last channel or
+                *we exceded the lenght of the data     to
+                *fragment
                 */
-               if (fragsize > len)
-                       fragsize = len;
-               flen = fragsize;
-               mtu = pch->chan->mtu + 2 - hdrlen;
-               if (mtu < 4)
-                       mtu = 4;
+               if ((nfree == 0) || (flen > len))
+                       flen = len;
+               /*
+                *it is not worth to tx on slow channels:
+                *in that case from the resulting flen according to the
+                *above formula will be equal or less than zero.
+                *Skip the channel in this case
+                */
+               if (flen <=     0) {
+                       pch->avail = 2;
+                       spin_unlock_bh(&pch->downl);
+                       continue;
+               }
+
+               mtu     = pch->chan->mtu + 2 - hdrlen;
+               if (mtu < 4)
+                       mtu     = 4;
                if (flen > mtu)
                        flen = mtu;
-               if (flen == len && nfree == 0)
-                       bits |= E;
-               frag = alloc_skb(flen + hdrlen + (flen == 0), GFP_ATOMIC);
+               if (flen ==     len)
+                       bits |= E;
+               frag = alloc_skb(flen + hdrlen + (flen == 0), GFP_ATOMIC);
                if (!frag)
                        goto noskb;
-               q = skb_put(frag, flen + hdrlen);
+               q =     skb_put(frag, flen + hdrlen);
 
-               /* make the MP header */
+               /* make the     MP header */
                q[0] = PPP_MP >> 8;
                q[1] = PPP_MP;
                if (ppp->flags & SC_MP_XSHORTSEQ) {
-                       q[2] = bits + ((ppp->nxseq >> 8) & 0xf);
+                       q[2] = bits     + ((ppp->nxseq >> 8) & 0xf);
                        q[3] = ppp->nxseq;
                } else {
                        q[2] = bits;
@@ -1448,43 +1491,28 @@ static int ppp_mp_explode(struct ppp *ppp, struct sk_buff *skb)
                        q[5] = ppp->nxseq;
                }
 
-               /*
-                * Copy the data in.
-                * Unfortunately there is a bug in older versions of
-                * the Linux PPP multilink reconstruction code where it
-                * drops 0-length fragments.  Therefore we make sure the
-                * fragment has at least one byte of data.  Any bytes
-                * we add in this situation will end up as padding on the
-                * end of the reconstructed packet.
-                */
-               if (flen == 0)
-                       *skb_put(frag, 1) = 0;
-               else
-                       memcpy(q + hdrlen, p, flen);
+               memcpy(q + hdrlen, p, flen);
 
                /* try to send it down the channel */
                chan = pch->chan;
-               if (!skb_queue_empty(&pch->file.xq) ||
-                   !chan->ops->start_xmit(chan, frag))
+               if (!skb_queue_empty(&pch->file.xq)     ||
+                       !chan->ops->start_xmit(chan, frag))
                        skb_queue_tail(&pch->file.xq, frag);
-               pch->had_frag = 1;
+               pch->had_frag = 1;
                p += flen;
-               len -= flen;
+               len     -= flen;
                ++ppp->nxseq;
                bits = 0;
                spin_unlock_bh(&pch->downl);
-
-               if (--nbigger == 0 && fragsize > 0)
-                       --fragsize;
        }
-       ppp->nxchan = i;
+       ppp->nxchan     = i;
 
        return 1;
 
  noskb:
        spin_unlock_bh(&pch->downl);
        if (ppp->debug & 1)
-               printk(KERN_ERR "PPP: no memory (fragment)\n");
+               printk(KERN_ERR "PPP: no memory (fragment)\n");
        ++ppp->dev->stats.tx_errors;
        ++ppp->nxseq;
        return 1;       /* abandon the frame */
@@ -2658,8 +2686,7 @@ static void ppp_destroy_interface(struct ppp *ppp)
        ppp->active_filter = NULL;
 #endif /* CONFIG_PPP_FILTER */
 
-       if (ppp->xmit_pending)
-               kfree_skb(ppp->xmit_pending);
+       kfree_skb(ppp->xmit_pending);
 
        free_netdev(ppp->dev);
 }
index 1e892b7b1f8cf997764e7a29ffe09bbf745f69ff..d2fa2db1358633771439013546758654444c6a00 100644 (file)
@@ -206,6 +206,7 @@ ppp_sync_open(struct tty_struct *tty)
 {
        struct syncppp *ap;
        int err;
+       int speed;
 
        if (tty->ops->write == NULL)
                return -EOPNOTSUPP;
@@ -234,6 +235,8 @@ ppp_sync_open(struct tty_struct *tty)
        ap->chan.ops = &sync_ops;
        ap->chan.mtu = PPP_MRU;
        ap->chan.hdrlen = 2;    /* for A/C bytes */
+       speed = tty_get_baud_rate(tty);
+       ap->chan.speed = speed;
        err = ppp_register_channel(&ap->chan);
        if (err)
                goto out_free;
@@ -281,8 +284,7 @@ ppp_sync_close(struct tty_struct *tty)
 
        ppp_unregister_channel(&ap->chan);
        skb_queue_purge(&ap->rqueue);
-       if (ap->tpkt)
-               kfree_skb(ap->tpkt);
+       kfree_skb(ap->tpkt);
        kfree(ap);
 }
 
index e2968f0844394d9674540332885cc2edfd3a687d..f0031f1f97e5e1b7bd52d825021fa3783c93885a 100644 (file)
@@ -513,17 +513,17 @@ out:
        return NET_RX_SUCCESS; /* Lies... :-) */
 }
 
-static struct packet_type pppoes_ptype = {
+static struct packet_type pppoes_ptype __read_mostly = {
        .type   = cpu_to_be16(ETH_P_PPP_SES),
        .func   = pppoe_rcv,
 };
 
-static struct packet_type pppoed_ptype = {
+static struct packet_type pppoed_ptype __read_mostly = {
        .type   = cpu_to_be16(ETH_P_PPP_DISC),
        .func   = pppoe_disc_rcv,
 };
 
-static struct proto pppoe_sk_proto = {
+static struct proto pppoe_sk_proto __read_mostly = {
        .name     = "PPPOE",
        .owner    = THIS_MODULE,
        .obj_size = sizeof(struct pppox_sock),
index e6fdce9206cc994863c7d0e451558700310ade77..fcb159e4df54e75231a17bcd48c115c778fa242a 100644 (file)
@@ -28,8 +28,8 @@
        } while (0)
 
 #define QLGE_VENDOR_ID    0x1077
-#define QLGE_DEVICE_ID    0x8012
-
+#define QLGE_DEVICE_ID_8012    0x8012
+#define QLGE_DEVICE_ID_8000    0x8000
 #define MAX_CPUS 8
 #define MAX_TX_RINGS MAX_CPUS
 #define MAX_RX_RINGS ((MAX_CPUS * 2) + 1)
@@ -164,7 +164,7 @@ enum {
        CSR_RP = (1 << 10),
        CSR_CMD_PARM_SHIFT = 22,
        CSR_CMD_NOP = 0x00000000,
-       CSR_CMD_SET_RST = 0x1000000,
+       CSR_CMD_SET_RST = 0x10000000,
        CSR_CMD_CLR_RST = 0x20000000,
        CSR_CMD_SET_PAUSE = 0x30000000,
        CSR_CMD_CLR_PAUSE = 0x40000000,
@@ -424,7 +424,7 @@ enum {
        RX_SYMBOL_ERR = 0x00000370,
        RX_MAC_ERR = 0x00000378,
        RX_CTL_PKTS = 0x00000380,
-       RX_PAUSE_PKTS = 0x00000384,
+       RX_PAUSE_PKTS = 0x00000388,
        RX_64_PKTS = 0x00000390,
        RX_65_TO_127_PKTS = 0x00000398,
        RX_128_255_PKTS = 0x000003a0,
@@ -733,6 +733,11 @@ enum {
        AEN_LINK_DOWN = 0x00008012,
        AEN_IDC_CMPLT = 0x00008100,
        AEN_IDC_REQ = 0x00008101,
+       AEN_IDC_EXT = 0x00008102,
+       AEN_DCBX_CHG = 0x00008110,
+       AEN_AEN_LOST = 0x00008120,
+       AEN_AEN_SFP_IN = 0x00008130,
+       AEN_AEN_SFP_OUT = 0x00008131,
        AEN_FW_INIT_DONE = 0x00008400,
        AEN_FW_INIT_FAIL = 0x00008401,
 
@@ -742,40 +747,48 @@ enum {
        MB_CMD_MB_TEST = 0x00000006,
        MB_CMD_CSUM_TEST = 0x00000007,  /* Verify Checksum */
        MB_CMD_ABOUT_FW = 0x00000008,
+       MB_CMD_COPY_RISC_RAM = 0x0000000a,
        MB_CMD_LOAD_RISC_RAM = 0x0000000b,
        MB_CMD_DUMP_RISC_RAM = 0x0000000c,
        MB_CMD_WRITE_RAM = 0x0000000d,
+       MB_CMD_INIT_RISC_RAM = 0x0000000e,
        MB_CMD_READ_RAM = 0x0000000f,
        MB_CMD_STOP_FW = 0x00000014,
        MB_CMD_MAKE_SYS_ERR = 0x0000002a,
+       MB_CMD_WRITE_SFP = 0x00000030,
+       MB_CMD_READ_SFP = 0x00000031,
        MB_CMD_INIT_FW = 0x00000060,
-       MB_CMD_GET_INIT_CB = 0x00000061,
+       MB_CMD_GET_IFCB = 0x00000061,
        MB_CMD_GET_FW_STATE = 0x00000069,
        MB_CMD_IDC_REQ = 0x00000100,    /* Inter-Driver Communication */
        MB_CMD_IDC_ACK = 0x00000101,    /* Inter-Driver Communication */
        MB_CMD_SET_WOL_MODE = 0x00000110,       /* Wake On Lan */
-       MB_WOL_DISABLE = 0x00000000,
-       MB_WOL_MAGIC_PKT = 0x00000001,
-       MB_WOL_FLTR = 0x00000002,
-       MB_WOL_UCAST = 0x00000004,
-       MB_WOL_MCAST = 0x00000008,
-       MB_WOL_BCAST = 0x00000010,
-       MB_WOL_LINK_UP = 0x00000020,
-       MB_WOL_LINK_DOWN = 0x00000040,
+       MB_WOL_DISABLE = 0,
+       MB_WOL_MAGIC_PKT = (1 << 1),
+       MB_WOL_FLTR = (1 << 2),
+       MB_WOL_UCAST = (1 << 3),
+       MB_WOL_MCAST = (1 << 4),
+       MB_WOL_BCAST = (1 << 5),
+       MB_WOL_LINK_UP = (1 << 6),
+       MB_WOL_LINK_DOWN = (1 << 7),
        MB_CMD_SET_WOL_FLTR = 0x00000111,       /* Wake On Lan Filter */
-       MB_CMD_CLEAR_WOL_FLTR = 0x00000112,     /* Wake On Lan Filter */
+       MB_CMD_CLEAR_WOL_FLTR = 0x00000112, /* Wake On Lan Filter */
        MB_CMD_SET_WOL_MAGIC = 0x00000113,      /* Wake On Lan Magic Packet */
-       MB_CMD_CLEAR_WOL_MAGIC = 0x00000114,    /* Wake On Lan Magic Packet */
+       MB_CMD_CLEAR_WOL_MAGIC = 0x00000114,/* Wake On Lan Magic Packet */
+       MB_CMD_SET_WOL_IMMED = 0x00000115,
        MB_CMD_PORT_RESET = 0x00000120,
        MB_CMD_SET_PORT_CFG = 0x00000122,
        MB_CMD_GET_PORT_CFG = 0x00000123,
-       MB_CMD_SET_ASIC_VOLTS = 0x00000130,
-       MB_CMD_GET_SNS_DATA = 0x00000131,       /* Temp and Volt Sense data. */
+       MB_CMD_GET_LINK_STS = 0x00000124,
 
        /* Mailbox Command Status. */
        MB_CMD_STS_GOOD = 0x00004000,   /* Success. */
        MB_CMD_STS_INTRMDT = 0x00001000,        /* Intermediate Complete. */
-       MB_CMD_STS_ERR = 0x00004005,    /* Error. */
+       MB_CMD_STS_INVLD_CMD = 0x00004001,      /* Invalid. */
+       MB_CMD_STS_XFC_ERR = 0x00004002,        /* Interface Error. */
+       MB_CMD_STS_CSUM_ERR = 0x00004003,       /* Csum Error. */
+       MB_CMD_STS_ERR = 0x00004005,    /* System Error. */
+       MB_CMD_STS_PARAM_ERR = 0x00004006,      /* Parameter Error. */
 };
 
 struct mbox_params {
@@ -785,7 +798,7 @@ struct mbox_params {
        int out_count;
 };
 
-struct flash_params {
+struct flash_params_8012 {
        u8 dev_id_str[4];
        __le16 size;
        __le16 csum;
@@ -795,6 +808,43 @@ struct flash_params {
        __le16 res;
 };
 
+/* 8000 device's flash is a different structure
+ * at a different offset in flash.
+ */
+#define FUNC0_FLASH_OFFSET 0x140200
+#define FUNC1_FLASH_OFFSET 0x140600
+
+/* Flash related data structures. */
+struct flash_params_8000 {
+       u8 dev_id_str[4];       /* "8000" */
+       __le16 ver;
+       __le16 size;
+       __le16 csum;
+       __le16 reserved0;
+       __le16 total_size;
+       __le16 entry_count;
+       u8 data_type0;
+       u8 data_size0;
+       u8 mac_addr[6];
+       u8 data_type1;
+       u8 data_size1;
+       u8 mac_addr1[6];
+       u8 data_type2;
+       u8 data_size2;
+       __le16 vlan_id;
+       u8 data_type3;
+       u8 data_size3;
+       __le16 last;
+       u8 reserved1[464];
+       __le16  subsys_ven_id;
+       __le16  subsys_dev_id;
+       u8 reserved2[4];
+};
+
+union flash_params {
+       struct flash_params_8012 flash_params_8012;
+       struct flash_params_8000 flash_params_8000;
+};
 
 /*
  * doorbell space for the rx ring context
@@ -927,6 +977,7 @@ struct ib_mac_iocb_rsp {
        u8 flags1;
 #define IB_MAC_IOCB_RSP_OI     0x01    /* Overide intr delay */
 #define IB_MAC_IOCB_RSP_I      0x02    /* Disble Intr Generation */
+#define IB_MAC_CSUM_ERR_MASK 0x1c      /* A mask to use for csum errs */
 #define IB_MAC_IOCB_RSP_TE     0x04    /* Checksum error */
 #define IB_MAC_IOCB_RSP_NU     0x08    /* No checksum rcvd */
 #define IB_MAC_IOCB_RSP_IE     0x10    /* IPv4 checksum error */
@@ -967,6 +1018,7 @@ struct ib_mac_iocb_rsp {
        __le16 vlan_id;         /* 12 bits */
 #define IB_MAC_IOCB_RSP_C      0x1000  /* VLAN CFI bit */
 #define IB_MAC_IOCB_RSP_COS_SHIFT      12      /* class of service value */
+#define IB_MAC_IOCB_RSP_VLAN_MASK      0x0ffff
 
        __le16 reserved1;
        __le32 reserved2[6];
@@ -1032,6 +1084,7 @@ struct wqicb {
 #define Q_LEN_CPP_16   0x0001
 #define Q_LEN_CPP_32   0x0002
 #define Q_LEN_CPP_64   0x0003
+#define Q_LEN_CPP_512  0x0006
        __le16 flags;
 #define Q_PRI_SHIFT    1
 #define Q_FLAGS_LC     0x1000
@@ -1313,27 +1366,49 @@ enum {
        QL_DMA64 = (1 << 5),
        QL_PROMISCUOUS = (1 << 6),
        QL_ALLMULTI = (1 << 7),
+       QL_PORT_CFG = (1 << 8),
+       QL_CAM_RT_SET = (1 << 9),
 };
 
 /* link_status bit definitions */
 enum {
-       LOOPBACK_MASK = 0x00000700,
-       LOOPBACK_PCS = 0x00000100,
-       LOOPBACK_HSS = 0x00000200,
-       LOOPBACK_EXT = 0x00000300,
-       PAUSE_MASK = 0x000000c0,
-       PAUSE_STD = 0x00000040,
-       PAUSE_PRI = 0x00000080,
-       SPEED_MASK = 0x00000038,
-       SPEED_100Mb = 0x00000000,
-       SPEED_1Gb = 0x00000008,
-       SPEED_10Gb = 0x00000010,
-       LINK_TYPE_MASK = 0x00000007,
-       LINK_TYPE_XFI = 0x00000001,
-       LINK_TYPE_XAUI = 0x00000002,
-       LINK_TYPE_XFI_BP = 0x00000003,
-       LINK_TYPE_XAUI_BP = 0x00000004,
-       LINK_TYPE_10GBASET = 0x00000005,
+       STS_LOOPBACK_MASK = 0x00000700,
+       STS_LOOPBACK_PCS = 0x00000100,
+       STS_LOOPBACK_HSS = 0x00000200,
+       STS_LOOPBACK_EXT = 0x00000300,
+       STS_PAUSE_MASK = 0x000000c0,
+       STS_PAUSE_STD = 0x00000040,
+       STS_PAUSE_PRI = 0x00000080,
+       STS_SPEED_MASK = 0x00000038,
+       STS_SPEED_100Mb = 0x00000000,
+       STS_SPEED_1Gb = 0x00000008,
+       STS_SPEED_10Gb = 0x00000010,
+       STS_LINK_TYPE_MASK = 0x00000007,
+       STS_LINK_TYPE_XFI = 0x00000001,
+       STS_LINK_TYPE_XAUI = 0x00000002,
+       STS_LINK_TYPE_XFI_BP = 0x00000003,
+       STS_LINK_TYPE_XAUI_BP = 0x00000004,
+       STS_LINK_TYPE_10GBASET = 0x00000005,
+};
+
+/* link_config bit definitions */
+enum {
+       CFG_JUMBO_FRAME_SIZE = 0x00010000,
+       CFG_PAUSE_MASK = 0x00000060,
+       CFG_PAUSE_STD = 0x00000020,
+       CFG_PAUSE_PRI = 0x00000040,
+       CFG_DCBX = 0x00000010,
+       CFG_LOOPBACK_MASK = 0x00000007,
+       CFG_LOOPBACK_PCS = 0x00000002,
+       CFG_LOOPBACK_HSS = 0x00000004,
+       CFG_LOOPBACK_EXT = 0x00000006,
+       CFG_DEFAULT_MAX_FRAME_SIZE = 0x00002580,
+};
+
+struct nic_operations {
+
+       int (*get_flash) (struct ql_adapter *);
+       int (*port_initialize) (struct ql_adapter *);
 };
 
 /*
@@ -1376,6 +1451,8 @@ struct ql_adapter {
 
        u32 mailbox_in;
        u32 mailbox_out;
+       struct mbox_params idc_mbc;
+       struct mutex    mpi_mutex;
 
        int tx_ring_size;
        int rx_ring_size;
@@ -1411,8 +1488,10 @@ struct ql_adapter {
        u32 port_link_up;
        u32 port_init;
        u32 link_status;
+       u32 link_config;
+       u32 max_frame_size;
 
-       struct flash_params flash;
+       union flash_params flash;
 
        struct net_device_stats stats;
        struct workqueue_struct *q_workqueue;
@@ -1420,6 +1499,11 @@ struct ql_adapter {
        struct delayed_work asic_reset_work;
        struct delayed_work mpi_reset_work;
        struct delayed_work mpi_work;
+       struct delayed_work mpi_port_cfg_work;
+       struct delayed_work mpi_idc_work;
+       struct completion ide_completion;
+       struct nic_operations *nic_ops;
+       u16 device_id;
 };
 
 /*
@@ -1492,6 +1576,10 @@ void ql_queue_asic_error(struct ql_adapter *qdev);
 u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr);
 void ql_set_ethtool_ops(struct net_device *ndev);
 int ql_read_xgmac_reg64(struct ql_adapter *qdev, u32 reg, u64 *data);
+void ql_mpi_idc_work(struct work_struct *work);
+void ql_mpi_port_cfg_work(struct work_struct *work);
+int ql_mb_get_fw_state(struct ql_adapter *qdev);
+int ql_cam_route_initialize(struct ql_adapter *qdev);
 
 #if 1
 #define QL_ALL_DUMP
index 379b895ed6e63cbe4cd3c75cbf83658e02ccf888..40a70c36f5aee3adaaa4fd3247f024a6a8d65374 100644 (file)
@@ -83,6 +83,10 @@ static void ql_dump_cam_entries(struct ql_adapter *qdev)
 {
        int i;
        u32 value[3];
+
+       i = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
+       if (i)
+               return;
        for (i = 0; i < 4; i++) {
                if (ql_get_mac_addr_reg(qdev, MAC_ADDR_TYPE_CAM_MAC, i, value)) {
                        printk(KERN_ERR PFX
@@ -111,12 +115,16 @@ static void ql_dump_cam_entries(struct ql_adapter *qdev)
                                       qdev->ndev->name, i, value[1], value[0]);
                }
        }
+       ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
 }
 
 void ql_dump_routing_entries(struct ql_adapter *qdev)
 {
        int i;
        u32 value;
+       i = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
+       if (i)
+               return;
        for (i = 0; i < 16; i++) {
                value = 0;
                if (ql_get_routing_reg(qdev, i, &value)) {
@@ -131,6 +139,7 @@ void ql_dump_routing_entries(struct ql_adapter *qdev)
                                       qdev->ndev->name, i, value);
                }
        }
+       ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
 }
 
 void ql_dump_regs(struct ql_adapter *qdev)
index 9d922e2ff226d0753b545870fd9e0348f92fa445..a50078627fb6a40f7eeb07772f49eef5fc05131b 100644 (file)
@@ -271,7 +271,8 @@ static int ql_get_settings(struct net_device *ndev,
        ecmd->advertising = ADVERTISED_10000baseT_Full;
        ecmd->autoneg = AUTONEG_ENABLE;
        ecmd->transceiver = XCVR_EXTERNAL;
-       if ((qdev->link_status & LINK_TYPE_MASK) == LINK_TYPE_10GBASET) {
+       if ((qdev->link_status & STS_LINK_TYPE_MASK) ==
+                               STS_LINK_TYPE_10GBASET) {
                ecmd->supported |= (SUPPORTED_TP | SUPPORTED_Autoneg);
                ecmd->advertising |= (ADVERTISED_TP | ADVERTISED_Autoneg);
                ecmd->port = PORT_TP;
index fd515afb1aa5421ba6764fded89d2c7769d8399e..170d3540f9c9fb7185d66c9c0af5ce872a3f66e5 100644 (file)
@@ -58,8 +58,8 @@ static const u32 default_msg =
     NETIF_MSG_IFUP |
     NETIF_MSG_RX_ERR |
     NETIF_MSG_TX_ERR |
-    NETIF_MSG_TX_QUEUED |
-    NETIF_MSG_INTR | NETIF_MSG_TX_DONE | NETIF_MSG_RX_STATUS |
+/*  NETIF_MSG_TX_QUEUED | */
+/*  NETIF_MSG_INTR | NETIF_MSG_TX_DONE | NETIF_MSG_RX_STATUS | */
 /* NETIF_MSG_PKTDATA | */
     NETIF_MSG_HW | NETIF_MSG_WOL | 0;
 
@@ -75,7 +75,8 @@ module_param(irq_type, int, MSIX_IRQ);
 MODULE_PARM_DESC(irq_type, "0 = MSI-X, 1 = MSI, 2 = Legacy.");
 
 static struct pci_device_id qlge_pci_tbl[] __devinitdata = {
-       {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID)},
+       {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8012)},
+       {PCI_DEVICE(PCI_VENDOR_ID_QLOGIC, QLGE_DEVICE_ID_8000)},
        /* required last entry */
        {0,}
 };
@@ -247,9 +248,6 @@ int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index,
        u32 offset = 0;
        int status;
 
-       status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
-       if (status)
-               return status;
        switch (type) {
        case MAC_ADDR_TYPE_MULTI_MAC:
        case MAC_ADDR_TYPE_CAM_MAC:
@@ -308,7 +306,6 @@ int ql_get_mac_addr_reg(struct ql_adapter *qdev, u32 type, u16 index,
                status = -EPERM;
        }
 exit:
-       ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
        return status;
 }
 
@@ -321,9 +318,6 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
        u32 offset = 0;
        int status = 0;
 
-       status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
-       if (status)
-               return status;
        switch (type) {
        case MAC_ADDR_TYPE_MULTI_MAC:
        case MAC_ADDR_TYPE_CAM_MAC:
@@ -334,7 +328,7 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
                            (addr[2] << 24) | (addr[3] << 16) | (addr[4] << 8) |
                            (addr[5]);
 
-                       QPRINTK(qdev, IFUP, INFO,
+                       QPRINTK(qdev, IFUP, DEBUG,
                                "Adding %s address %pM"
                                " at index %d in the CAM.\n",
                                ((type ==
@@ -415,7 +409,6 @@ static int ql_set_mac_addr_reg(struct ql_adapter *qdev, u8 *addr, u32 type,
                status = -EPERM;
        }
 exit:
-       ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
        return status;
 }
 
@@ -426,10 +419,6 @@ int ql_get_routing_reg(struct ql_adapter *qdev, u32 index, u32 *value)
 {
        int status = 0;
 
-       status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
-       if (status)
-               goto exit;
-
        status = ql_wait_reg_rdy(qdev, RT_IDX, RT_IDX_MW, 0);
        if (status)
                goto exit;
@@ -441,7 +430,6 @@ int ql_get_routing_reg(struct ql_adapter *qdev, u32 index, u32 *value)
                goto exit;
        *value = ql_read32(qdev, RT_DATA);
 exit:
-       ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
        return status;
 }
 
@@ -453,13 +441,9 @@ exit:
 static int ql_set_routing_reg(struct ql_adapter *qdev, u32 index, u32 mask,
                              int enable)
 {
-       int status;
+       int status = -EINVAL; /* Return error if no mask match. */
        u32 value = 0;
 
-       status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
-       if (status)
-               return status;
-
        QPRINTK(qdev, IFUP, DEBUG,
                "%s %s%s%s%s%s%s%s%s%s%s%s%s%s%s%s%s mask %s the routing reg.\n",
                (enable ? "Adding" : "Removing"),
@@ -555,7 +539,6 @@ static int ql_set_routing_reg(struct ql_adapter *qdev, u32 index, u32 mask,
                ql_write32(qdev, RT_DATA, enable ? mask : 0);
        }
 exit:
-       ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
        return status;
 }
 
@@ -604,7 +587,6 @@ u32 ql_enable_completion_interrupt(struct ql_adapter *qdev, u32 intr)
 static u32 ql_disable_completion_interrupt(struct ql_adapter *qdev, u32 intr)
 {
        u32 var = 0;
-       unsigned long hw_flags;
        struct intr_context *ctx;
 
        /* HW disables for us if we're MSIX multi interrupts and
@@ -614,14 +596,14 @@ static u32 ql_disable_completion_interrupt(struct ql_adapter *qdev, u32 intr)
                return 0;
 
        ctx = qdev->intr_context + intr;
-       spin_lock_irqsave(&qdev->hw_lock, hw_flags);
+       spin_lock(&qdev->hw_lock);
        if (!atomic_read(&ctx->irq_cnt)) {
                ql_write32(qdev, INTR_EN,
                ctx->intr_dis_mask);
                var = ql_read32(qdev, STS);
        }
        atomic_inc(&ctx->irq_cnt);
-       spin_unlock_irqrestore(&qdev->hw_lock, hw_flags);
+       spin_unlock(&qdev->hw_lock);
        return var;
 }
 
@@ -641,6 +623,28 @@ static void ql_enable_all_completion_interrupts(struct ql_adapter *qdev)
 
 }
 
+static int ql_validate_flash(struct ql_adapter *qdev, u32 size, const char *str)
+{
+       int status, i;
+       u16 csum = 0;
+       __le16 *flash = (__le16 *)&qdev->flash;
+
+       status = strncmp((char *)&qdev->flash, str, 4);
+       if (status) {
+               QPRINTK(qdev, IFUP, ERR, "Invalid flash signature.\n");
+               return  status;
+       }
+
+       for (i = 0; i < size; i++)
+               csum += le16_to_cpu(*flash++);
+
+       if (csum)
+               QPRINTK(qdev, IFUP, ERR,
+                       "Invalid flash checksum, csum = 0x%.04x.\n", csum);
+
+       return csum;
+}
+
 static int ql_read_flash_word(struct ql_adapter *qdev, int offset, __le32 *data)
 {
        int status = 0;
@@ -665,23 +669,75 @@ exit:
        return status;
 }
 
-static int ql_get_flash_params(struct ql_adapter *qdev)
+static int ql_get_8000_flash_params(struct ql_adapter *qdev)
+{
+       u32 i, size;
+       int status;
+       __le32 *p = (__le32 *)&qdev->flash;
+       u32 offset;
+
+       /* Get flash offset for function and adjust
+        * for dword access.
+        */
+       if (!qdev->func)
+               offset = FUNC0_FLASH_OFFSET / sizeof(u32);
+       else
+               offset = FUNC1_FLASH_OFFSET / sizeof(u32);
+
+       if (ql_sem_spinlock(qdev, SEM_FLASH_MASK))
+               return -ETIMEDOUT;
+
+       size = sizeof(struct flash_params_8000) / sizeof(u32);
+       for (i = 0; i < size; i++, p++) {
+               status = ql_read_flash_word(qdev, i+offset, p);
+               if (status) {
+                       QPRINTK(qdev, IFUP, ERR, "Error reading flash.\n");
+                       goto exit;
+               }
+       }
+
+       status = ql_validate_flash(qdev,
+                       sizeof(struct flash_params_8000) / sizeof(u16),
+                       "8000");
+       if (status) {
+               QPRINTK(qdev, IFUP, ERR, "Invalid flash.\n");
+               status = -EINVAL;
+               goto exit;
+       }
+
+       if (!is_valid_ether_addr(qdev->flash.flash_params_8000.mac_addr)) {
+               QPRINTK(qdev, IFUP, ERR, "Invalid MAC address.\n");
+               status = -EINVAL;
+               goto exit;
+       }
+
+       memcpy(qdev->ndev->dev_addr,
+               qdev->flash.flash_params_8000.mac_addr,
+               qdev->ndev->addr_len);
+
+exit:
+       ql_sem_unlock(qdev, SEM_FLASH_MASK);
+       return status;
+}
+
+static int ql_get_8012_flash_params(struct ql_adapter *qdev)
 {
        int i;
        int status;
        __le32 *p = (__le32 *)&qdev->flash;
        u32 offset = 0;
+       u32 size = sizeof(struct flash_params_8012) / sizeof(u32);
 
        /* Second function's parameters follow the first
         * function's.
         */
        if (qdev->func)
-               offset = sizeof(qdev->flash) / sizeof(u32);
+               offset = size;
 
        if (ql_sem_spinlock(qdev, SEM_FLASH_MASK))
                return -ETIMEDOUT;
 
-       for (i = 0; i < sizeof(qdev->flash) / sizeof(u32); i++, p++) {
+       for (i = 0; i < size; i++, p++) {
                status = ql_read_flash_word(qdev, i+offset, p);
                if (status) {
                        QPRINTK(qdev, IFUP, ERR, "Error reading flash.\n");
@@ -689,6 +745,25 @@ static int ql_get_flash_params(struct ql_adapter *qdev)
                }
 
        }
+
+       status = ql_validate_flash(qdev,
+                       sizeof(struct flash_params_8012) / sizeof(u16),
+                       "8012");
+       if (status) {
+               QPRINTK(qdev, IFUP, ERR, "Invalid flash.\n");
+               status = -EINVAL;
+               goto exit;
+       }
+
+       if (!is_valid_ether_addr(qdev->flash.flash_params_8012.mac_addr)) {
+               status = -EINVAL;
+               goto exit;
+       }
+
+       memcpy(qdev->ndev->dev_addr,
+               qdev->flash.flash_params_8012.mac_addr,
+               qdev->ndev->addr_len);
+
 exit:
        ql_sem_unlock(qdev, SEM_FLASH_MASK);
        return status;
@@ -759,13 +834,25 @@ exit:
        return status;
 }
 
+static int ql_8000_port_initialize(struct ql_adapter *qdev)
+{
+       int status;
+       status = ql_mb_get_fw_state(qdev);
+       if (status)
+               goto exit;
+       /* Wake up a worker to get/set the TX/RX frame sizes. */
+       queue_delayed_work(qdev->workqueue, &qdev->mpi_port_cfg_work, 0);
+exit:
+       return status;
+}
+
 /* Take the MAC Core out of reset.
  * Enable statistics counting.
  * Take the transmitter/receiver out of reset.
  * This functionality may be done in the MPI firmware at a
  * later date.
  */
-static int ql_port_initialize(struct ql_adapter *qdev)
+static int ql_8012_port_initialize(struct ql_adapter *qdev)
 {
        int status = 0;
        u32 data;
@@ -881,7 +968,8 @@ static void ql_write_cq_idx(struct rx_ring *rx_ring)
 /* Process (refill) a large buffer queue. */
 static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
 {
-       int clean_idx = rx_ring->lbq_clean_idx;
+       u32 clean_idx = rx_ring->lbq_clean_idx;
+       u32 start_idx = clean_idx;
        struct bq_desc *lbq_desc;
        u64 map;
        int i;
@@ -928,19 +1016,23 @@ static void ql_update_lbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
                rx_ring->lbq_prod_idx += 16;
                if (rx_ring->lbq_prod_idx == rx_ring->lbq_len)
                        rx_ring->lbq_prod_idx = 0;
+               rx_ring->lbq_free_cnt -= 16;
+       }
+
+       if (start_idx != clean_idx) {
                QPRINTK(qdev, RX_STATUS, DEBUG,
                        "lbq: updating prod idx = %d.\n",
                        rx_ring->lbq_prod_idx);
                ql_write_db_reg(rx_ring->lbq_prod_idx,
                                rx_ring->lbq_prod_idx_db_reg);
-               rx_ring->lbq_free_cnt -= 16;
        }
 }
 
 /* Process (refill) a small buffer queue. */
 static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
 {
-       int clean_idx = rx_ring->sbq_clean_idx;
+       u32 clean_idx = rx_ring->sbq_clean_idx;
+       u32 start_idx = clean_idx;
        struct bq_desc *sbq_desc;
        u64 map;
        int i;
@@ -990,13 +1082,15 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
                rx_ring->sbq_prod_idx += 16;
                if (rx_ring->sbq_prod_idx == rx_ring->sbq_len)
                        rx_ring->sbq_prod_idx = 0;
+               rx_ring->sbq_free_cnt -= 16;
+       }
+
+       if (start_idx != clean_idx) {
                QPRINTK(qdev, RX_STATUS, DEBUG,
                        "sbq: updating prod idx = %d.\n",
                        rx_ring->sbq_prod_idx);
                ql_write_db_reg(rx_ring->sbq_prod_idx,
                                rx_ring->sbq_prod_idx_db_reg);
-
-               rx_ring->sbq_free_cnt -= 16;
        }
 }
 
@@ -1412,6 +1506,8 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev,
 {
        struct net_device *ndev = qdev->ndev;
        struct sk_buff *skb = NULL;
+       u16 vlan_id = (le16_to_cpu(ib_mac_rsp->vlan_id) &
+                       IB_MAC_IOCB_RSP_VLAN_MASK)
 
        QL_DUMP_IB_MAC_RSP(ib_mac_rsp);
 
@@ -1436,32 +1532,53 @@ static void ql_process_mac_rx_intr(struct ql_adapter *qdev,
        if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_P) {
                QPRINTK(qdev, RX_STATUS, DEBUG, "Promiscuous Packet.\n");
        }
-       if (ib_mac_rsp->flags1 & (IB_MAC_IOCB_RSP_IE | IB_MAC_IOCB_RSP_TE)) {
-               QPRINTK(qdev, RX_STATUS, ERR,
-                       "Bad checksum for this %s packet.\n",
-                       ((ib_mac_rsp->
-                         flags2 & IB_MAC_IOCB_RSP_T) ? "TCP" : "UDP"));
-               skb->ip_summed = CHECKSUM_NONE;
-       } else if (qdev->rx_csum &&
-                  ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) ||
-                   ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) &&
-                    !(ib_mac_rsp->flags1 & IB_MAC_IOCB_RSP_NU)))) {
-               QPRINTK(qdev, RX_STATUS, DEBUG, "RX checksum done!\n");
-               skb->ip_summed = CHECKSUM_UNNECESSARY;
+
+       skb->protocol = eth_type_trans(skb, ndev);
+       skb->ip_summed = CHECKSUM_NONE;
+
+       /* If rx checksum is on, and there are no
+        * csum or frame errors.
+        */
+       if (qdev->rx_csum &&
+               !(ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_ERR_MASK) &&
+               !(ib_mac_rsp->flags1 & IB_MAC_CSUM_ERR_MASK)) {
+               /* TCP frame. */
+               if (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_T) {
+                       QPRINTK(qdev, RX_STATUS, DEBUG,
+                                       "TCP checksum done!\n");
+                       skb->ip_summed = CHECKSUM_UNNECESSARY;
+               } else if ((ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_U) &&
+                               (ib_mac_rsp->flags3 & IB_MAC_IOCB_RSP_V4)) {
+               /* Unfragmented ipv4 UDP frame. */
+                       struct iphdr *iph = (struct iphdr *) skb->data;
+                       if (!(iph->frag_off &
+                               cpu_to_be16(IP_MF|IP_OFFSET))) {
+                               skb->ip_summed = CHECKSUM_UNNECESSARY;
+                               QPRINTK(qdev, RX_STATUS, DEBUG,
+                                               "TCP checksum done!\n");
+                       }
+               }
        }
+
        qdev->stats.rx_packets++;
        qdev->stats.rx_bytes += skb->len;
-       skb->protocol = eth_type_trans(skb, ndev);
-       skb_record_rx_queue(skb, rx_ring - &qdev->rx_ring[0]);
-       if (qdev->vlgrp && (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V)) {
-               QPRINTK(qdev, RX_STATUS, DEBUG,
-                       "Passing a VLAN packet upstream.\n");
-               vlan_hwaccel_receive_skb(skb, qdev->vlgrp,
-                               le16_to_cpu(ib_mac_rsp->vlan_id));
+       skb_record_rx_queue(skb,
+               rx_ring->cq_id - qdev->rss_ring_first_cq_id);
+       if (skb->ip_summed == CHECKSUM_UNNECESSARY) {
+               if (qdev->vlgrp &&
+                       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) &&
+                       (vlan_id != 0))
+                       vlan_gro_receive(&rx_ring->napi, qdev->vlgrp,
+                               vlan_id, skb);
+               else
+                       napi_gro_receive(&rx_ring->napi, skb);
        } else {
-               QPRINTK(qdev, RX_STATUS, DEBUG,
-                       "Passing a normal packet upstream.\n");
-               netif_receive_skb(skb);
+               if (qdev->vlgrp &&
+                       (ib_mac_rsp->flags2 & IB_MAC_IOCB_RSP_V) &&
+                       (vlan_id != 0))
+                       vlan_hwaccel_receive_skb(skb, qdev->vlgrp, vlan_id);
+               else
+                       netif_receive_skb(skb);
        }
 }
 
@@ -1508,14 +1625,12 @@ static void ql_process_mac_tx_intr(struct ql_adapter *qdev,
 /* Fire up a handler to reset the MPI processor. */
 void ql_queue_fw_error(struct ql_adapter *qdev)
 {
-       netif_stop_queue(qdev->ndev);
        netif_carrier_off(qdev->ndev);
        queue_delayed_work(qdev->workqueue, &qdev->mpi_reset_work, 0);
 }
 
 void ql_queue_asic_error(struct ql_adapter *qdev)
 {
-       netif_stop_queue(qdev->ndev);
        netif_carrier_off(qdev->ndev);
        ql_disable_interrupts(qdev);
        /* Clear adapter up bit to signal the recovery
@@ -1570,6 +1685,7 @@ static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring)
        struct ob_mac_iocb_rsp *net_rsp = NULL;
        int count = 0;
 
+       struct tx_ring *tx_ring;
        /* While there are entries in the completion queue. */
        while (prod != rx_ring->cnsmr_idx) {
 
@@ -1595,15 +1711,16 @@ static int ql_clean_outbound_rx_ring(struct rx_ring *rx_ring)
                prod = ql_read_sh_reg(rx_ring->prod_idx_sh_reg);
        }
        ql_write_cq_idx(rx_ring);
-       if (netif_queue_stopped(qdev->ndev) && net_rsp != NULL) {
-               struct tx_ring *tx_ring = &qdev->tx_ring[net_rsp->txq_idx];
+       tx_ring = &qdev->tx_ring[net_rsp->txq_idx];
+       if (__netif_subqueue_stopped(qdev->ndev, tx_ring->wq_id) &&
+                                       net_rsp != NULL) {
                if (atomic_read(&tx_ring->queue_stopped) &&
                    (atomic_read(&tx_ring->tx_count) > (tx_ring->wq_len / 4)))
                        /*
                         * The queue got stopped because the tx_ring was full.
                         * Wake it up, because it's now at least 25% empty.
                         */
-                       netif_wake_queue(qdev->ndev);
+                       netif_wake_subqueue(qdev->ndev, tx_ring->wq_id);
        }
 
        return count;
@@ -1664,7 +1781,7 @@ static int ql_napi_poll_msix(struct napi_struct *napi, int budget)
                rx_ring->cq_id);
 
        if (work_done < budget) {
-               __napi_complete(napi);
+               napi_complete(napi);
                ql_enable_completion_interrupt(qdev, rx_ring->irq);
        }
        return work_done;
@@ -1690,19 +1807,29 @@ static void ql_vlan_rx_add_vid(struct net_device *ndev, u16 vid)
 {
        struct ql_adapter *qdev = netdev_priv(ndev);
        u32 enable_bit = MAC_ADDR_E;
+       int status;
 
+       status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
+       if (status)
+               return;
        spin_lock(&qdev->hw_lock);
        if (ql_set_mac_addr_reg
            (qdev, (u8 *) &enable_bit, MAC_ADDR_TYPE_VLAN, vid)) {
                QPRINTK(qdev, IFUP, ERR, "Failed to init vlan address.\n");
        }
        spin_unlock(&qdev->hw_lock);
+       ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
 }
 
 static void ql_vlan_rx_kill_vid(struct net_device *ndev, u16 vid)
 {
        struct ql_adapter *qdev = netdev_priv(ndev);
        u32 enable_bit = 0;
+       int status;
+
+       status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
+       if (status)
+               return;
 
        spin_lock(&qdev->hw_lock);
        if (ql_set_mac_addr_reg
@@ -1710,6 +1837,7 @@ static void ql_vlan_rx_kill_vid(struct net_device *ndev, u16 vid)
                QPRINTK(qdev, IFUP, ERR, "Failed to clear vlan address.\n");
        }
        spin_unlock(&qdev->hw_lock);
+       ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
 
 }
 
@@ -1924,15 +2052,18 @@ static int qlge_send(struct sk_buff *skb, struct net_device *ndev)
        struct ql_adapter *qdev = netdev_priv(ndev);
        int tso;
        struct tx_ring *tx_ring;
-       u32 tx_ring_idx = (u32) QL_TXQ_IDX(qdev, skb);
+       u32 tx_ring_idx = (u32) skb->queue_mapping;
 
        tx_ring = &qdev->tx_ring[tx_ring_idx];
 
+       if (skb_padto(skb, ETH_ZLEN))
+               return NETDEV_TX_OK;
+
        if (unlikely(atomic_read(&tx_ring->tx_count) < 2)) {
                QPRINTK(qdev, TX_QUEUED, INFO,
                        "%s: shutting down tx queue %d du to lack of resources.\n",
                        __func__, tx_ring_idx);
-               netif_stop_queue(ndev);
+               netif_stop_subqueue(ndev, tx_ring->wq_id);
                atomic_inc(&tx_ring->queue_stopped);
                return NETDEV_TX_BUSY;
        }
@@ -2013,6 +2144,7 @@ static int ql_alloc_shadow_space(struct ql_adapter *qdev)
                        "Allocation of RX shadow space failed.\n");
                return -ENOMEM;
        }
+       memset(qdev->rx_ring_shadow_reg_area, 0, PAGE_SIZE);
        qdev->tx_ring_shadow_reg_area =
            pci_alloc_consistent(qdev->pdev, PAGE_SIZE,
                                 &qdev->tx_ring_shadow_reg_dma);
@@ -2021,6 +2153,7 @@ static int ql_alloc_shadow_space(struct ql_adapter *qdev)
                        "Allocation of TX shadow space failed.\n");
                goto err_wqp_sh_area;
        }
+       memset(qdev->tx_ring_shadow_reg_area, 0, PAGE_SIZE);
        return 0;
 
 err_wqp_sh_area:
@@ -2105,47 +2238,6 @@ static void ql_free_lbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring
        }
 }
 
-/*
- * Allocate and map a page for each element of the lbq.
- */
-static int ql_alloc_lbq_buffers(struct ql_adapter *qdev,
-                               struct rx_ring *rx_ring)
-{
-       int i;
-       struct bq_desc *lbq_desc;
-       u64 map;
-       __le64 *bq = rx_ring->lbq_base;
-
-       for (i = 0; i < rx_ring->lbq_len; i++) {
-               lbq_desc = &rx_ring->lbq[i];
-               memset(lbq_desc, 0, sizeof(lbq_desc));
-               lbq_desc->addr = bq;
-               lbq_desc->index = i;
-               lbq_desc->p.lbq_page = alloc_page(GFP_ATOMIC);
-               if (unlikely(!lbq_desc->p.lbq_page)) {
-                       QPRINTK(qdev, IFUP, ERR, "failed alloc_page().\n");
-                       goto mem_error;
-               } else {
-                       map = pci_map_page(qdev->pdev,
-                                          lbq_desc->p.lbq_page,
-                                          0, PAGE_SIZE, PCI_DMA_FROMDEVICE);
-                       if (pci_dma_mapping_error(qdev->pdev, map)) {
-                               QPRINTK(qdev, IFUP, ERR,
-                                       "PCI mapping failed.\n");
-                               goto mem_error;
-                       }
-                       pci_unmap_addr_set(lbq_desc, mapaddr, map);
-                       pci_unmap_len_set(lbq_desc, maplen, PAGE_SIZE);
-                       *lbq_desc->addr = cpu_to_le64(map);
-               }
-               bq++;
-       }
-       return 0;
-mem_error:
-       ql_free_lbq_buffers(qdev, rx_ring);
-       return -ENOMEM;
-}
-
 static void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring)
 {
        int i;
@@ -2168,63 +2260,72 @@ static void ql_free_sbq_buffers(struct ql_adapter *qdev, struct rx_ring *rx_ring
        }
 }
 
-/* Allocate and map an skb for each element of the sbq. */
-static int ql_alloc_sbq_buffers(struct ql_adapter *qdev,
+/* Free all large and small rx buffers associated
+ * with the completion queues for this device.
+ */
+static void ql_free_rx_buffers(struct ql_adapter *qdev)
+{
+       int i;
+       struct rx_ring *rx_ring;
+
+       for (i = 0; i < qdev->rx_ring_count; i++) {
+               rx_ring = &qdev->rx_ring[i];
+               if (rx_ring->lbq)
+                       ql_free_lbq_buffers(qdev, rx_ring);
+               if (rx_ring->sbq)
+                       ql_free_sbq_buffers(qdev, rx_ring);
+       }
+}
+
+static void ql_alloc_rx_buffers(struct ql_adapter *qdev)
+{
+       struct rx_ring *rx_ring;
+       int i;
+
+       for (i = 0; i < qdev->rx_ring_count; i++) {
+               rx_ring = &qdev->rx_ring[i];
+               if (rx_ring->type != TX_Q)
+                       ql_update_buffer_queues(qdev, rx_ring);
+       }
+}
+
+static void ql_init_lbq_ring(struct ql_adapter *qdev,
+                               struct rx_ring *rx_ring)
+{
+       int i;
+       struct bq_desc *lbq_desc;
+       __le64 *bq = rx_ring->lbq_base;
+
+       memset(rx_ring->lbq, 0, rx_ring->lbq_len * sizeof(struct bq_desc));
+       for (i = 0; i < rx_ring->lbq_len; i++) {
+               lbq_desc = &rx_ring->lbq[i];
+               memset(lbq_desc, 0, sizeof(*lbq_desc));
+               lbq_desc->index = i;
+               lbq_desc->addr = bq;
+               bq++;
+       }
+}
+
+static void ql_init_sbq_ring(struct ql_adapter *qdev,
                                struct rx_ring *rx_ring)
 {
        int i;
        struct bq_desc *sbq_desc;
-       struct sk_buff *skb;
-       u64 map;
        __le64 *bq = rx_ring->sbq_base;
 
+       memset(rx_ring->sbq, 0, rx_ring->sbq_len * sizeof(struct bq_desc));
        for (i = 0; i < rx_ring->sbq_len; i++) {
                sbq_desc = &rx_ring->sbq[i];
-               memset(sbq_desc, 0, sizeof(sbq_desc));
+               memset(sbq_desc, 0, sizeof(*sbq_desc));
                sbq_desc->index = i;
                sbq_desc->addr = bq;
-               skb = netdev_alloc_skb(qdev->ndev, rx_ring->sbq_buf_size);
-               if (unlikely(!skb)) {
-                       /* Better luck next round */
-                       QPRINTK(qdev, IFUP, ERR,
-                               "small buff alloc failed for %d bytes at index %d.\n",
-                               rx_ring->sbq_buf_size, i);
-                       goto mem_err;
-               }
-               skb_reserve(skb, QLGE_SB_PAD);
-               sbq_desc->p.skb = skb;
-               /*
-                * Map only half the buffer. Because the
-                * other half may get some data copied to it
-                * when the completion arrives.
-                */
-               map = pci_map_single(qdev->pdev,
-                                    skb->data,
-                                    rx_ring->sbq_buf_size / 2,
-                                    PCI_DMA_FROMDEVICE);
-               if (pci_dma_mapping_error(qdev->pdev, map)) {
-                       QPRINTK(qdev, IFUP, ERR, "PCI mapping failed.\n");
-                       goto mem_err;
-               }
-               pci_unmap_addr_set(sbq_desc, mapaddr, map);
-               pci_unmap_len_set(sbq_desc, maplen, rx_ring->sbq_buf_size / 2);
-               *sbq_desc->addr = cpu_to_le64(map);
                bq++;
        }
-       return 0;
-mem_err:
-       ql_free_sbq_buffers(qdev, rx_ring);
-       return -ENOMEM;
 }
 
 static void ql_free_rx_resources(struct ql_adapter *qdev,
                                 struct rx_ring *rx_ring)
 {
-       if (rx_ring->sbq_len)
-               ql_free_sbq_buffers(qdev, rx_ring);
-       if (rx_ring->lbq_len)
-               ql_free_lbq_buffers(qdev, rx_ring);
-
        /* Free the small buffer queue. */
        if (rx_ring->sbq_base) {
                pci_free_consistent(qdev->pdev,
@@ -2302,11 +2403,7 @@ static int ql_alloc_rx_resources(struct ql_adapter *qdev,
                        goto err_mem;
                }
 
-               if (ql_alloc_sbq_buffers(qdev, rx_ring)) {
-                       QPRINTK(qdev, IFUP, ERR,
-                               "Small buffer allocation failed.\n");
-                       goto err_mem;
-               }
+               ql_init_sbq_ring(qdev, rx_ring);
        }
 
        if (rx_ring->lbq_len) {
@@ -2334,14 +2431,7 @@ static int ql_alloc_rx_resources(struct ql_adapter *qdev,
                        goto err_mem;
                }
 
-               /*
-                * Allocate the buffers.
-                */
-               if (ql_alloc_lbq_buffers(qdev, rx_ring)) {
-                       QPRINTK(qdev, IFUP, ERR,
-                               "Large buffer allocation failed.\n");
-                       goto err_mem;
-               }
+               ql_init_lbq_ring(qdev, rx_ring);
        }
 
        return 0;
@@ -2435,6 +2525,7 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
            qdev->doorbell_area + (DB_PAGE_SIZE * (128 + rx_ring->cq_id));
        int err = 0;
        u16 bq_len;
+       u64 tmp;
 
        /* Set up the shadow registers for this ring. */
        rx_ring->prod_idx_sh_reg = shadow_reg;
@@ -2480,7 +2571,8 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
            FLAGS_LI;           /* Load irq delay values */
        if (rx_ring->lbq_len) {
                cqicb->flags |= FLAGS_LL;       /* Load lbq values */
-               *((u64 *) rx_ring->lbq_base_indirect) = rx_ring->lbq_base_dma;
+               tmp = (u64)rx_ring->lbq_base_dma;;
+               *((__le64 *) rx_ring->lbq_base_indirect) = cpu_to_le64(tmp);
                cqicb->lbq_addr =
                    cpu_to_le64(rx_ring->lbq_base_indirect_dma);
                bq_len = (rx_ring->lbq_buf_size == 65536) ? 0 :
@@ -2489,25 +2581,26 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
                bq_len = (rx_ring->lbq_len == 65536) ? 0 :
                        (u16) rx_ring->lbq_len;
                cqicb->lbq_len = cpu_to_le16(bq_len);
-               rx_ring->lbq_prod_idx = rx_ring->lbq_len - 16;
+               rx_ring->lbq_prod_idx = 0;
                rx_ring->lbq_curr_idx = 0;
-               rx_ring->lbq_clean_idx = rx_ring->lbq_prod_idx;
-               rx_ring->lbq_free_cnt = 16;
+               rx_ring->lbq_clean_idx = 0;
+               rx_ring->lbq_free_cnt = rx_ring->lbq_len;
        }
        if (rx_ring->sbq_len) {
                cqicb->flags |= FLAGS_LS;       /* Load sbq values */
-               *((u64 *) rx_ring->sbq_base_indirect) = rx_ring->sbq_base_dma;
+               tmp = (u64)rx_ring->sbq_base_dma;;
+               *((__le64 *) rx_ring->sbq_base_indirect) = cpu_to_le64(tmp);
                cqicb->sbq_addr =
                    cpu_to_le64(rx_ring->sbq_base_indirect_dma);
                cqicb->sbq_buf_size =
-                   cpu_to_le16(((rx_ring->sbq_buf_size / 2) + 8) & 0xfffffff8);
+                   cpu_to_le16((u16)(rx_ring->sbq_buf_size/2));
                bq_len = (rx_ring->sbq_len == 65536) ? 0 :
                        (u16) rx_ring->sbq_len;
                cqicb->sbq_len = cpu_to_le16(bq_len);
-               rx_ring->sbq_prod_idx = rx_ring->sbq_len - 16;
+               rx_ring->sbq_prod_idx = 0;
                rx_ring->sbq_curr_idx = 0;
-               rx_ring->sbq_clean_idx = rx_ring->sbq_prod_idx;
-               rx_ring->sbq_free_cnt = 16;
+               rx_ring->sbq_clean_idx = 0;
+               rx_ring->sbq_free_cnt = rx_ring->sbq_len;
        }
        switch (rx_ring->type) {
        case TX_Q:
@@ -2553,24 +2646,13 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
                QPRINTK(qdev, IFUP, DEBUG, "Invalid rx_ring->type = %d.\n",
                        rx_ring->type);
        }
-       QPRINTK(qdev, IFUP, INFO, "Initializing rx work queue.\n");
+       QPRINTK(qdev, IFUP, DEBUG, "Initializing rx work queue.\n");
        err = ql_write_cfg(qdev, cqicb, sizeof(struct cqicb),
                           CFG_LCQ, rx_ring->cq_id);
        if (err) {
                QPRINTK(qdev, IFUP, ERR, "Failed to load CQICB.\n");
                return err;
        }
-       QPRINTK(qdev, IFUP, INFO, "Successfully loaded CQICB.\n");
-       /*
-        * Advance the producer index for the buffer queues.
-        */
-       wmb();
-       if (rx_ring->lbq_len)
-               ql_write_db_reg(rx_ring->lbq_prod_idx,
-                               rx_ring->lbq_prod_idx_db_reg);
-       if (rx_ring->sbq_len)
-               ql_write_db_reg(rx_ring->sbq_prod_idx,
-                               rx_ring->sbq_prod_idx_db_reg);
        return err;
 }
 
@@ -2617,7 +2699,7 @@ static int ql_start_tx_ring(struct ql_adapter *qdev, struct tx_ring *tx_ring)
                QPRINTK(qdev, IFUP, ERR, "Failed to load tx_ring.\n");
                return err;
        }
-       QPRINTK(qdev, IFUP, INFO, "Successfully loaded WQICB.\n");
+       QPRINTK(qdev, IFUP, DEBUG, "Successfully loaded WQICB.\n");
        return err;
 }
 
@@ -2659,7 +2741,7 @@ static void ql_enable_msix(struct ql_adapter *qdev)
                    (qdev->pdev, qdev->msi_x_entry, qdev->rx_ring_count)) {
                        set_bit(QL_MSIX_ENABLED, &qdev->flags);
                        qdev->intr_count = qdev->rx_ring_count;
-                       QPRINTK(qdev, IFUP, INFO,
+                       QPRINTK(qdev, IFUP, DEBUG,
                                "MSI-X Enabled, got %d vectors.\n",
                                qdev->intr_count);
                        return;
@@ -2786,11 +2868,11 @@ static void ql_free_irq(struct ql_adapter *qdev)
                        if (test_bit(QL_MSIX_ENABLED, &qdev->flags)) {
                                free_irq(qdev->msi_x_entry[i].vector,
                                         &qdev->rx_ring[i]);
-                               QPRINTK(qdev, IFDOWN, ERR,
+                               QPRINTK(qdev, IFDOWN, DEBUG,
                                        "freeing msix interrupt %d.\n", i);
                        } else {
                                free_irq(qdev->pdev->irq, &qdev->rx_ring[0]);
-                               QPRINTK(qdev, IFDOWN, ERR,
+                               QPRINTK(qdev, IFDOWN, DEBUG,
                                        "freeing msi interrupt %d.\n", i);
                        }
                }
@@ -2821,7 +2903,7 @@ static int ql_request_irq(struct ql_adapter *qdev)
                                        i);
                                goto err_irq;
                        } else {
-                               QPRINTK(qdev, IFUP, INFO,
+                               QPRINTK(qdev, IFUP, DEBUG,
                                        "Hooked intr %d, queue type %s%s%s, with name %s.\n",
                                        i,
                                        qdev->rx_ring[i].type ==
@@ -2896,14 +2978,14 @@ static int ql_start_rss(struct ql_adapter *qdev)
        get_random_bytes((void *)&ricb->ipv6_hash_key[0], 40);
        get_random_bytes((void *)&ricb->ipv4_hash_key[0], 16);
 
-       QPRINTK(qdev, IFUP, INFO, "Initializing RSS.\n");
+       QPRINTK(qdev, IFUP, DEBUG, "Initializing RSS.\n");
 
        status = ql_write_cfg(qdev, ricb, sizeof(ricb), CFG_LR, 0);
        if (status) {
                QPRINTK(qdev, IFUP, ERR, "Failed to load RICB.\n");
                return status;
        }
-       QPRINTK(qdev, IFUP, INFO, "Successfully loaded RICB.\n");
+       QPRINTK(qdev, IFUP, DEBUG, "Successfully loaded RICB.\n");
        return status;
 }
 
@@ -2913,13 +2995,17 @@ static int ql_route_initialize(struct ql_adapter *qdev)
        int status = 0;
        int i;
 
+       status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
+       if (status)
+               return status;
+
        /* Clear all the entries in the routing table. */
        for (i = 0; i < 16; i++) {
                status = ql_set_routing_reg(qdev, i, 0, 0);
                if (status) {
                        QPRINTK(qdev, IFUP, ERR,
                                "Failed to init routing register for CAM packets.\n");
-                       return status;
+                       goto exit;
                }
        }
 
@@ -2927,13 +3013,13 @@ static int ql_route_initialize(struct ql_adapter *qdev)
        if (status) {
                QPRINTK(qdev, IFUP, ERR,
                        "Failed to init routing register for error packets.\n");
-               return status;
+               goto exit;
        }
        status = ql_set_routing_reg(qdev, RT_IDX_BCAST_SLOT, RT_IDX_BCAST, 1);
        if (status) {
                QPRINTK(qdev, IFUP, ERR,
                        "Failed to init routing register for broadcast packets.\n");
-               return status;
+               goto exit;
        }
        /* If we have more than one inbound queue, then turn on RSS in the
         * routing block.
@@ -2944,17 +3030,39 @@ static int ql_route_initialize(struct ql_adapter *qdev)
                if (status) {
                        QPRINTK(qdev, IFUP, ERR,
                                "Failed to init routing register for MATCH RSS packets.\n");
-                       return status;
+                       goto exit;
                }
        }
 
        status = ql_set_routing_reg(qdev, RT_IDX_CAM_HIT_SLOT,
                                    RT_IDX_CAM_HIT, 1);
-       if (status) {
+       if (status)
                QPRINTK(qdev, IFUP, ERR,
                        "Failed to init routing register for CAM packets.\n");
+exit:
+       ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
+       return status;
+}
+
+int ql_cam_route_initialize(struct ql_adapter *qdev)
+{
+       int status;
+
+       status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
+       if (status)
+               return status;
+       status = ql_set_mac_addr_reg(qdev, (u8 *) qdev->ndev->perm_addr,
+                            MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ);
+       ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
+       if (status) {
+               QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n");
                return status;
        }
+
+       status = ql_route_initialize(qdev);
+       if (status)
+               QPRINTK(qdev, IFUP, ERR, "Failed to init routing table.\n");
+
        return status;
 }
 
@@ -2971,9 +3079,9 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
        mask = value << 16;
        ql_write32(qdev, SYS, mask | value);
 
-       /* Set the default queue. */
-       value = NIC_RCV_CFG_DFQ;
-       mask = NIC_RCV_CFG_DFQ_MASK;
+       /* Set the default queue, and VLAN behavior. */
+       value = NIC_RCV_CFG_DFQ | NIC_RCV_CFG_RV;
+       mask = NIC_RCV_CFG_DFQ_MASK | (NIC_RCV_CFG_RV << 16);
        ql_write32(qdev, NIC_RCV_CFG, (mask | value));
 
        /* Set the MPI interrupt to enabled. */
@@ -3022,28 +3130,24 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
                }
        }
 
-       status = ql_port_initialize(qdev);
-       if (status) {
-               QPRINTK(qdev, IFUP, ERR, "Failed to start port.\n");
-               return status;
-       }
-
-       status = ql_set_mac_addr_reg(qdev, (u8 *) qdev->ndev->perm_addr,
-                                    MAC_ADDR_TYPE_CAM_MAC, qdev->func);
-       if (status) {
-               QPRINTK(qdev, IFUP, ERR, "Failed to init mac address.\n");
-               return status;
-       }
+       /* Initialize the port and set the max framesize. */
+       status = qdev->nic_ops->port_initialize(qdev);
+       if (status) {
+              QPRINTK(qdev, IFUP, ERR, "Failed to start port.\n");
+              return status;
+       }
 
-       status = ql_route_initialize(qdev);
+       /* Set up the MAC address and frame routing filter. */
+       status = ql_cam_route_initialize(qdev);
        if (status) {
-               QPRINTK(qdev, IFUP, ERR, "Failed to init routing table.\n");
+               QPRINTK(qdev, IFUP, ERR,
+                               "Failed to init CAM/Routing tables.\n");
                return status;
        }
 
        /* Start NAPI for the RSS queues. */
        for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++) {
-               QPRINTK(qdev, IFUP, INFO, "Enabling NAPI for rx_ring[%d].\n",
+               QPRINTK(qdev, IFUP, DEBUG, "Enabling NAPI for rx_ring[%d].\n",
                        i);
                napi_enable(&qdev->rx_ring[i].napi);
        }
@@ -3055,36 +3159,23 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
 static int ql_adapter_reset(struct ql_adapter *qdev)
 {
        u32 value;
-       int max_wait_time;
        int status = 0;
-       int resetCnt = 0;
+       unsigned long end_jiffies = jiffies +
+               max((unsigned long)1, usecs_to_jiffies(30));
 
-#define MAX_RESET_CNT   1
-issueReset:
-       resetCnt++;
-       QPRINTK(qdev, IFDOWN, DEBUG, "Issue soft reset to chip.\n");
        ql_write32(qdev, RST_FO, (RST_FO_FR << 16) | RST_FO_FR);
-       /* Wait for reset to complete. */
-       max_wait_time = 3;
-       QPRINTK(qdev, IFDOWN, DEBUG, "Wait %d seconds for reset to complete.\n",
-               max_wait_time);
+
        do {
                value = ql_read32(qdev, RST_FO);
                if ((value & RST_FO_FR) == 0)
                        break;
+               cpu_relax();
+       } while (time_before(jiffies, end_jiffies));
 
-               ssleep(1);
-       } while ((--max_wait_time));
        if (value & RST_FO_FR) {
-               QPRINTK(qdev, IFDOWN, ERR,
-                       "Stuck in SoftReset:  FSC_SR:0x%08x\n", value);
-               if (resetCnt < MAX_RESET_CNT)
-                       goto issueReset;
-       }
-       if (max_wait_time == 0) {
-               status = -ETIMEDOUT;
                QPRINTK(qdev, IFDOWN, ERR,
                        "ETIMEOUT!!! errored out of resetting the chip!\n");
+               status = -ETIMEDOUT;
        }
 
        return status;
@@ -3107,12 +3198,10 @@ static void ql_display_dev_info(struct net_device *ndev)
 
 static int ql_adapter_down(struct ql_adapter *qdev)
 {
-       struct net_device *ndev = qdev->ndev;
        int i, status = 0;
        struct rx_ring *rx_ring;
 
-       netif_stop_queue(ndev);
-       netif_carrier_off(ndev);
+       netif_carrier_off(qdev->ndev);
 
        /* Don't kill the reset worker thread if we
         * are in the process of recovery.
@@ -3121,6 +3210,8 @@ static int ql_adapter_down(struct ql_adapter *qdev)
                cancel_delayed_work_sync(&qdev->asic_reset_work);
        cancel_delayed_work_sync(&qdev->mpi_reset_work);
        cancel_delayed_work_sync(&qdev->mpi_work);
+       cancel_delayed_work_sync(&qdev->mpi_idc_work);
+       cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
 
        /* The default queue at index 0 is always processed in
         * a workqueue.
@@ -3150,6 +3241,13 @@ static int ql_adapter_down(struct ql_adapter *qdev)
 
        ql_tx_ring_clean(qdev);
 
+       /* Call netif_napi_del() from common point.
+        */
+       for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++)
+               netif_napi_del(&qdev->rx_ring[i].napi);
+
+       ql_free_rx_buffers(qdev);
+
        spin_lock(&qdev->hw_lock);
        status = ql_adapter_reset(qdev);
        if (status)
@@ -3163,21 +3261,19 @@ static int ql_adapter_up(struct ql_adapter *qdev)
 {
        int err = 0;
 
-       spin_lock(&qdev->hw_lock);
        err = ql_adapter_initialize(qdev);
        if (err) {
                QPRINTK(qdev, IFUP, INFO, "Unable to initialize adapter.\n");
                spin_unlock(&qdev->hw_lock);
                goto err_init;
        }
-       spin_unlock(&qdev->hw_lock);
        set_bit(QL_ADAPTER_UP, &qdev->flags);
+       ql_alloc_rx_buffers(qdev);
+       if ((ql_read32(qdev, STS) & qdev->port_init))
+               netif_carrier_on(qdev->ndev);
        ql_enable_interrupts(qdev);
        ql_enable_all_completion_interrupts(qdev);
-       if ((ql_read32(qdev, STS) & qdev->port_init)) {
-               netif_carrier_on(qdev->ndev);
-               netif_start_queue(qdev->ndev);
-       }
+       netif_tx_start_all_queues(qdev->ndev);
 
        return 0;
 err_init:
@@ -3185,28 +3281,6 @@ err_init:
        return err;
 }
 
-static int ql_cycle_adapter(struct ql_adapter *qdev)
-{
-       int status;
-
-       status = ql_adapter_down(qdev);
-       if (status)
-               goto error;
-
-       status = ql_adapter_up(qdev);
-       if (status)
-               goto error;
-
-       return status;
-error:
-       QPRINTK(qdev, IFUP, ALERT,
-               "Driver up/down cycle failed, closing device\n");
-       rtnl_lock();
-       dev_close(qdev->ndev);
-       rtnl_unlock();
-       return status;
-}
-
 static void ql_release_adapter_resources(struct ql_adapter *qdev)
 {
        ql_free_mem_resources(qdev);
@@ -3287,6 +3361,7 @@ static int ql_configure_rings(struct ql_adapter *qdev)
         * completion handler rx_rings.
         */
        qdev->rx_ring_count = qdev->tx_ring_count + qdev->rss_ring_count + 1;
+       netif_set_gso_max_size(qdev->ndev, 65536);
 
        for (i = 0; i < qdev->tx_ring_count; i++) {
                tx_ring = &qdev->tx_ring[i];
@@ -3393,6 +3468,8 @@ static int qlge_change_mtu(struct net_device *ndev, int new_mtu)
 
        if (ndev->mtu == 1500 && new_mtu == 9000) {
                QPRINTK(qdev, IFUP, ERR, "Changing to jumbo MTU.\n");
+               queue_delayed_work(qdev->workqueue,
+                               &qdev->mpi_port_cfg_work, 0);
        } else if (ndev->mtu == 9000 && new_mtu == 1500) {
                QPRINTK(qdev, IFUP, ERR, "Changing to normal MTU.\n");
        } else if ((ndev->mtu == 1500 && new_mtu == 1500) ||
@@ -3415,8 +3492,11 @@ static void qlge_set_multicast_list(struct net_device *ndev)
 {
        struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
        struct dev_mc_list *mc_ptr;
-       int i;
+       int i, status;
 
+       status = ql_sem_spinlock(qdev, SEM_RT_IDX_MASK);
+       if (status)
+               return;
        spin_lock(&qdev->hw_lock);
        /*
         * Set or clear promiscuous mode if a
@@ -3472,14 +3552,19 @@ static void qlge_set_multicast_list(struct net_device *ndev)
        }
 
        if (ndev->mc_count) {
+               status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
+               if (status)
+                       goto exit;
                for (i = 0, mc_ptr = ndev->mc_list; mc_ptr;
                     i++, mc_ptr = mc_ptr->next)
                        if (ql_set_mac_addr_reg(qdev, (u8 *) mc_ptr->dmi_addr,
                                                MAC_ADDR_TYPE_MULTI_MAC, i)) {
                                QPRINTK(qdev, HW, ERR,
                                        "Failed to loadmulticast address.\n");
+                               ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
                                goto exit;
                        }
+               ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
                if (ql_set_routing_reg
                    (qdev, RT_IDX_MCAST_MATCH_SLOT, RT_IDX_MCAST_MATCH, 1)) {
                        QPRINTK(qdev, HW, ERR,
@@ -3490,13 +3575,14 @@ static void qlge_set_multicast_list(struct net_device *ndev)
        }
 exit:
        spin_unlock(&qdev->hw_lock);
+       ql_sem_unlock(qdev, SEM_RT_IDX_MASK);
 }
 
 static int qlge_set_mac_address(struct net_device *ndev, void *p)
 {
        struct ql_adapter *qdev = (struct ql_adapter *)netdev_priv(ndev);
        struct sockaddr *addr = p;
-       int ret = 0;
+       int status;
 
        if (netif_running(ndev))
                return -EBUSY;
@@ -3505,15 +3591,17 @@ static int qlge_set_mac_address(struct net_device *ndev, void *p)
                return -EADDRNOTAVAIL;
        memcpy(ndev->dev_addr, addr->sa_data, ndev->addr_len);
 
+       status = ql_sem_spinlock(qdev, SEM_MAC_ADDR_MASK);
+       if (status)
+               return status;
        spin_lock(&qdev->hw_lock);
-       if (ql_set_mac_addr_reg(qdev, (u8 *) ndev->dev_addr,
-                       MAC_ADDR_TYPE_CAM_MAC, qdev->func)) {/* Unicast */
-               QPRINTK(qdev, HW, ERR, "Failed to load MAC address.\n");
-               ret = -1;
-       }
+       status = ql_set_mac_addr_reg(qdev, (u8 *) ndev->dev_addr,
+                       MAC_ADDR_TYPE_CAM_MAC, qdev->func * MAX_CQ);
        spin_unlock(&qdev->hw_lock);
-
-       return ret;
+       if (status)
+               QPRINTK(qdev, HW, ERR, "Failed to load MAC address.\n");
+       ql_sem_unlock(qdev, SEM_MAC_ADDR_MASK);
+       return status;
 }
 
 static void qlge_tx_timeout(struct net_device *ndev)
@@ -3526,9 +3614,37 @@ static void ql_asic_reset_work(struct work_struct *work)
 {
        struct ql_adapter *qdev =
            container_of(work, struct ql_adapter, asic_reset_work.work);
-       ql_cycle_adapter(qdev);
+       int status;
+
+       status = ql_adapter_down(qdev);
+       if (status)
+               goto error;
+
+       status = ql_adapter_up(qdev);
+       if (status)
+               goto error;
+
+       return;
+error:
+       QPRINTK(qdev, IFUP, ALERT,
+               "Driver up/down cycle failed, closing device\n");
+       rtnl_lock();
+       set_bit(QL_ADAPTER_UP, &qdev->flags);
+       dev_close(qdev->ndev);
+       rtnl_unlock();
 }
 
+static struct nic_operations qla8012_nic_ops = {
+       .get_flash              = ql_get_8012_flash_params,
+       .port_initialize        = ql_8012_port_initialize,
+};
+
+static struct nic_operations qla8000_nic_ops = {
+       .get_flash              = ql_get_8000_flash_params,
+       .port_initialize        = ql_8000_port_initialize,
+};
+
+
 static void ql_get_board_info(struct ql_adapter *qdev)
 {
        qdev->func =
@@ -3547,6 +3663,11 @@ static void ql_get_board_info(struct ql_adapter *qdev)
                qdev->mailbox_out = PROC_ADDR_MPI_RISC | PROC_ADDR_FUNC0_MBO;
        }
        qdev->chip_rev_id = ql_read32(qdev, REV_ID);
+       qdev->device_id = qdev->pdev->device;
+       if (qdev->device_id == QLGE_DEVICE_ID_8012)
+               qdev->nic_ops = &qla8012_nic_ops;
+       else if (qdev->device_id == QLGE_DEVICE_ID_8000)
+               qdev->nic_ops = &qla8000_nic_ops;
 }
 
 static void ql_release_all(struct pci_dev *pdev)
@@ -3639,24 +3760,20 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
                goto err_out;
        }
 
-       ql_get_board_info(qdev);
        qdev->ndev = ndev;
        qdev->pdev = pdev;
+       ql_get_board_info(qdev);
        qdev->msg_enable = netif_msg_init(debug, default_msg);
        spin_lock_init(&qdev->hw_lock);
        spin_lock_init(&qdev->stats_lock);
 
        /* make sure the EEPROM is good */
-       err = ql_get_flash_params(qdev);
+       err = qdev->nic_ops->get_flash(qdev);
        if (err) {
                dev_err(&pdev->dev, "Invalid FLASH.\n");
                goto err_out;
        }
 
-       if (!is_valid_ether_addr(qdev->flash.mac_addr))
-               goto err_out;
-
-       memcpy(ndev->dev_addr, qdev->flash.mac_addr, ndev->addr_len);
        memcpy(ndev->perm_addr, ndev->dev_addr, ndev->addr_len);
 
        /* Set up the default ring sizes. */
@@ -3679,6 +3796,10 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
        INIT_DELAYED_WORK(&qdev->asic_reset_work, ql_asic_reset_work);
        INIT_DELAYED_WORK(&qdev->mpi_reset_work, ql_mpi_reset_work);
        INIT_DELAYED_WORK(&qdev->mpi_work, ql_mpi_work);
+       INIT_DELAYED_WORK(&qdev->mpi_port_cfg_work, ql_mpi_port_cfg_work);
+       INIT_DELAYED_WORK(&qdev->mpi_idc_work, ql_mpi_idc_work);
+       mutex_init(&qdev->mpi_mutex);
+       init_completion(&qdev->ide_completion);
 
        if (!cards_found) {
                dev_info(&pdev->dev, "%s\n", DRV_STRING);
@@ -3716,7 +3837,8 @@ static int __devinit qlge_probe(struct pci_dev *pdev,
        static int cards_found = 0;
        int err = 0;
 
-       ndev = alloc_etherdev(sizeof(struct ql_adapter));
+       ndev = alloc_etherdev_mq(sizeof(struct ql_adapter),
+                       min(MAX_CPUS, (int)num_online_cpus()));
        if (!ndev)
                return -ENOMEM;
 
@@ -3736,6 +3858,7 @@ static int __devinit qlge_probe(struct pci_dev *pdev,
                          | NETIF_F_TSO_ECN
                          | NETIF_F_HW_VLAN_TX
                          | NETIF_F_HW_VLAN_RX | NETIF_F_HW_VLAN_FILTER);
+       ndev->features |= NETIF_F_GRO;
 
        if (test_bit(QL_DMA64, &qdev->flags))
                ndev->features |= NETIF_F_HIGHDMA;
@@ -3758,7 +3881,6 @@ static int __devinit qlge_probe(struct pci_dev *pdev,
                return err;
        }
        netif_carrier_off(ndev);
-       netif_stop_queue(ndev);
        ql_display_dev_info(ndev);
        cards_found++;
        return 0;
@@ -3812,7 +3934,6 @@ static pci_ers_result_t qlge_io_slot_reset(struct pci_dev *pdev)
        pci_set_master(pdev);
 
        netif_carrier_off(ndev);
-       netif_stop_queue(ndev);
        ql_adapter_reset(qdev);
 
        /* Make sure the EEPROM is good */
@@ -3854,7 +3975,7 @@ static int qlge_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct net_device *ndev = pci_get_drvdata(pdev);
        struct ql_adapter *qdev = netdev_priv(ndev);
-       int err, i;
+       int err;
 
        netif_device_detach(ndev);
 
@@ -3864,9 +3985,6 @@ static int qlge_suspend(struct pci_dev *pdev, pm_message_t state)
                        return err;
        }
 
-       for (i = qdev->rss_ring_first_cq_id; i < qdev->rx_ring_count; i++)
-               netif_napi_del(&qdev->rx_ring[i].napi);
-
        err = pci_save_state(pdev);
        if (err)
                return err;
index fa31891b6e624bf00c47c78a4d9e986804c4728c..9f81b797f10b84126151cfed392190804cc25f9e 100644 (file)
@@ -1,6 +1,26 @@
 #include "qlge.h"
 
-static int ql_read_mbox_reg(struct ql_adapter *qdev, u32 reg, u32 *data)
+static void ql_display_mb_sts(struct ql_adapter *qdev,
+                                               struct mbox_params *mbcp)
+{
+       int i;
+       static char *err_sts[] = {
+               "Command Complete",
+               "Command Not Supported",
+               "Host Interface Error",
+               "Checksum Error",
+               "Unused Completion Status",
+               "Test Failed",
+               "Command Parameter Error"};
+
+       QPRINTK(qdev, DRV, DEBUG, "%s.\n",
+               err_sts[mbcp->mbox_out[0] & 0x0000000f]);
+       for (i = 0; i < mbcp->out_count; i++)
+               QPRINTK(qdev, DRV, DEBUG, "mbox_out[%d] = 0x%.08x.\n",
+                               i, mbcp->mbox_out[i]);
+}
+
+int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data)
 {
        int status;
        /* wait for reg to come ready */
@@ -19,6 +39,32 @@ exit:
        return status;
 }
 
+int ql_write_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 data)
+{
+       int status = 0;
+       /* wait for reg to come ready */
+       status = ql_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR);
+       if (status)
+               goto exit;
+       /* write the data to the data reg */
+       ql_write32(qdev, PROC_DATA, data);
+       /* trigger the write */
+       ql_write32(qdev, PROC_ADDR, reg);
+       /* wait for reg to come ready */
+       status = ql_wait_reg_rdy(qdev, PROC_ADDR, PROC_ADDR_RDY, PROC_ADDR_ERR);
+       if (status)
+               goto exit;
+exit:
+       return status;
+}
+
+int ql_soft_reset_mpi_risc(struct ql_adapter *qdev)
+{
+       int status;
+       status = ql_write_mpi_reg(qdev, 0x00001010, 1);
+       return status;
+}
+
 static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp)
 {
        int i, status;
@@ -28,7 +74,7 @@ static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp)
                return -EBUSY;
        for (i = 0; i < mbcp->out_count; i++) {
                status =
-                   ql_read_mbox_reg(qdev, qdev->mailbox_out + i,
+                   ql_read_mpi_reg(qdev, qdev->mailbox_out + i,
                                     &mbcp->mbox_out[i]);
                if (status) {
                        QPRINTK(qdev, DRV, ERR, "Failed mailbox read.\n");
@@ -39,102 +85,762 @@ static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp)
        return status;
 }
 
+/* Wait for a single mailbox command to complete.
+ * Returns zero on success.
+ */
+static int ql_wait_mbx_cmd_cmplt(struct ql_adapter *qdev)
+{
+       int count = 50; /* TODO: arbitrary for now. */
+       u32 value;
+
+       do {
+               value = ql_read32(qdev, STS);
+               if (value & STS_PI)
+                       return 0;
+               udelay(UDELAY_DELAY); /* 10us */
+       } while (--count);
+       return -ETIMEDOUT;
+}
+
+/* Execute a single mailbox command.
+ * Caller must hold PROC_ADDR semaphore.
+ */
+static int ql_exec_mb_cmd(struct ql_adapter *qdev, struct mbox_params *mbcp)
+{
+       int i, status;
+
+       /*
+        * Make sure there's nothing pending.
+        * This shouldn't happen.
+        */
+       if (ql_read32(qdev, CSR) & CSR_HRI)
+               return -EIO;
+
+       status = ql_sem_spinlock(qdev, SEM_PROC_REG_MASK);
+       if (status)
+               return status;
+
+       /*
+        * Fill the outbound mailboxes.
+        */
+       for (i = 0; i < mbcp->in_count; i++) {
+               status = ql_write_mpi_reg(qdev, qdev->mailbox_in + i,
+                                               mbcp->mbox_in[i]);
+               if (status)
+                       goto end;
+       }
+       /*
+        * Wake up the MPI firmware.
+        */
+       ql_write32(qdev, CSR, CSR_CMD_SET_H2R_INT);
+end:
+       ql_sem_unlock(qdev, SEM_PROC_REG_MASK);
+       return status;
+}
+
+/* We are being asked by firmware to accept
+ * a change to the port.  This is only
+ * a change to max frame sizes (Tx/Rx), pause
+ * paramters, or loopback mode. We wake up a worker
+ * to handler processing this since a mailbox command
+ * will need to be sent to ACK the request.
+ */
+static int ql_idc_req_aen(struct ql_adapter *qdev)
+{
+       int status;
+       struct mbox_params *mbcp = &qdev->idc_mbc;
+
+       QPRINTK(qdev, DRV, ERR, "Enter!\n");
+       /* Get the status data and start up a thread to
+        * handle the request.
+        */
+       mbcp = &qdev->idc_mbc;
+       mbcp->out_count = 4;
+       status = ql_get_mb_sts(qdev, mbcp);
+       if (status) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Could not read MPI, resetting ASIC!\n");
+               ql_queue_asic_error(qdev);
+       } else  {
+               /* Begin polled mode early so
+                * we don't get another interrupt
+                * when we leave mpi_worker.
+                */
+               ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
+               queue_delayed_work(qdev->workqueue, &qdev->mpi_idc_work, 0);
+       }
+       return status;
+}
+
+/* Process an inter-device event completion.
+ * If good, signal the caller's completion.
+ */
+static int ql_idc_cmplt_aen(struct ql_adapter *qdev)
+{
+       int status;
+       struct mbox_params *mbcp = &qdev->idc_mbc;
+       mbcp->out_count = 4;
+       status = ql_get_mb_sts(qdev, mbcp);
+       if (status) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Could not read MPI, resetting RISC!\n");
+               ql_queue_fw_error(qdev);
+       } else
+               /* Wake up the sleeping mpi_idc_work thread that is
+                * waiting for this event.
+                */
+               complete(&qdev->ide_completion);
+
+       return status;
+}
+
 static void ql_link_up(struct ql_adapter *qdev, struct mbox_params *mbcp)
 {
+       int status;
        mbcp->out_count = 2;
 
-       if (ql_get_mb_sts(qdev, mbcp))
-               goto exit;
+       status = ql_get_mb_sts(qdev, mbcp);
+       if (status) {
+               QPRINTK(qdev, DRV, ERR,
+                       "%s: Could not get mailbox status.\n", __func__);
+               return;
+       }
 
        qdev->link_status = mbcp->mbox_out[1];
        QPRINTK(qdev, DRV, ERR, "Link Up.\n");
-       QPRINTK(qdev, DRV, INFO, "Link Status = 0x%.08x.\n", mbcp->mbox_out[1]);
-       if (!netif_carrier_ok(qdev->ndev)) {
-               QPRINTK(qdev, LINK, INFO, "Link is Up.\n");
-               netif_carrier_on(qdev->ndev);
-               netif_wake_queue(qdev->ndev);
+
+       /* If we're coming back from an IDC event
+        * then set up the CAM and frame routing.
+        */
+       if (test_bit(QL_CAM_RT_SET, &qdev->flags)) {
+               status = ql_cam_route_initialize(qdev);
+               if (status) {
+                       QPRINTK(qdev, IFUP, ERR,
+                       "Failed to init CAM/Routing tables.\n");
+                       return;
+               } else
+                       clear_bit(QL_CAM_RT_SET, &qdev->flags);
        }
-exit:
-       /* Clear the MPI firmware status. */
-       ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
+
+       /* Queue up a worker to check the frame
+        * size information, and fix it if it's not
+        * to our liking.
+        */
+       if (!test_bit(QL_PORT_CFG, &qdev->flags)) {
+               QPRINTK(qdev, DRV, ERR, "Queue Port Config Worker!\n");
+               set_bit(QL_PORT_CFG, &qdev->flags);
+               /* Begin polled mode early so
+                * we don't get another interrupt
+                * when we leave mpi_worker dpc.
+                */
+               ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
+               queue_delayed_work(qdev->workqueue,
+                               &qdev->mpi_port_cfg_work, 0);
+       }
+
+       netif_carrier_on(qdev->ndev);
 }
 
 static void ql_link_down(struct ql_adapter *qdev, struct mbox_params *mbcp)
 {
+       int status;
+
        mbcp->out_count = 3;
 
-       if (ql_get_mb_sts(qdev, mbcp)) {
-               QPRINTK(qdev, DRV, ERR, "Firmware did not initialize!\n");
-               goto exit;
-       }
+       status = ql_get_mb_sts(qdev, mbcp);
+       if (status)
+               QPRINTK(qdev, DRV, ERR, "Link down AEN broken!\n");
+
+       netif_carrier_off(qdev->ndev);
+}
+
+static int ql_sfp_in(struct ql_adapter *qdev, struct mbox_params *mbcp)
+{
+       int status;
+
+       mbcp->out_count = 5;
+
+       status = ql_get_mb_sts(qdev, mbcp);
+       if (status)
+               QPRINTK(qdev, DRV, ERR, "SFP in AEN broken!\n");
+       else
+               QPRINTK(qdev, DRV, ERR, "SFP insertion detected.\n");
+
+       return status;
+}
+
+static int ql_sfp_out(struct ql_adapter *qdev, struct mbox_params *mbcp)
+{
+       int status;
+
+       mbcp->out_count = 1;
+
+       status = ql_get_mb_sts(qdev, mbcp);
+       if (status)
+               QPRINTK(qdev, DRV, ERR, "SFP out AEN broken!\n");
+       else
+               QPRINTK(qdev, DRV, ERR, "SFP removal detected.\n");
+
+       return status;
+}
+
+static int ql_aen_lost(struct ql_adapter *qdev, struct mbox_params *mbcp)
+{
+       int status;
+
+       mbcp->out_count = 6;
+
+       status = ql_get_mb_sts(qdev, mbcp);
+       if (status)
+               QPRINTK(qdev, DRV, ERR, "Lost AEN broken!\n");
+       else {
+               int i;
+               QPRINTK(qdev, DRV, ERR, "Lost AEN detected.\n");
+               for (i = 0; i < mbcp->out_count; i++)
+                       QPRINTK(qdev, DRV, ERR, "mbox_out[%d] = 0x%.08x.\n",
+                                       i, mbcp->mbox_out[i]);
 
-       if (netif_carrier_ok(qdev->ndev)) {
-               QPRINTK(qdev, LINK, INFO, "Link is Down.\n");
-               netif_carrier_off(qdev->ndev);
-               netif_stop_queue(qdev->ndev);
        }
-       QPRINTK(qdev, DRV, ERR, "Link Down.\n");
-       QPRINTK(qdev, DRV, ERR, "Link Status = 0x%.08x.\n", mbcp->mbox_out[1]);
-exit:
-       /* Clear the MPI firmware status. */
-       ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
+
+       return status;
 }
 
 static void ql_init_fw_done(struct ql_adapter *qdev, struct mbox_params *mbcp)
 {
+       int status;
+
        mbcp->out_count = 2;
 
-       if (ql_get_mb_sts(qdev, mbcp)) {
+       status = ql_get_mb_sts(qdev, mbcp);
+       if (status) {
                QPRINTK(qdev, DRV, ERR, "Firmware did not initialize!\n");
-               goto exit;
+       } else {
+               QPRINTK(qdev, DRV, ERR, "Firmware Revision  = 0x%.08x.\n",
+                       mbcp->mbox_out[1]);
+               status = ql_cam_route_initialize(qdev);
+               if (status)
+                       QPRINTK(qdev, IFUP, ERR,
+                               "Failed to init CAM/Routing tables.\n");
        }
-       QPRINTK(qdev, DRV, ERR, "Firmware initialized!\n");
-       QPRINTK(qdev, DRV, ERR, "Firmware status = 0x%.08x.\n",
-               mbcp->mbox_out[0]);
-       QPRINTK(qdev, DRV, ERR, "Firmware Revision  = 0x%.08x.\n",
-               mbcp->mbox_out[1]);
-exit:
-       /* Clear the MPI firmware status. */
+}
+
+/* Process an async event and clear it unless it's an
+ * error condition.
+ *  This can get called iteratively from the mpi_work thread
+ *  when events arrive via an interrupt.
+ *  It also gets called when a mailbox command is polling for
+ *  it's completion. */
+static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp)
+{
+       int status;
+       int orig_count = mbcp->out_count;
+
+       /* Just get mailbox zero for now. */
+       mbcp->out_count = 1;
+       status = ql_get_mb_sts(qdev, mbcp);
+       if (status) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Could not read MPI, resetting ASIC!\n");
+               ql_queue_asic_error(qdev);
+               goto end;
+       }
+
+       switch (mbcp->mbox_out[0]) {
+
+       /* This case is only active when we arrive here
+        * as a result of issuing a mailbox command to
+        * the firmware.
+        */
+       case MB_CMD_STS_INTRMDT:
+       case MB_CMD_STS_GOOD:
+       case MB_CMD_STS_INVLD_CMD:
+       case MB_CMD_STS_XFC_ERR:
+       case MB_CMD_STS_CSUM_ERR:
+       case MB_CMD_STS_ERR:
+       case MB_CMD_STS_PARAM_ERR:
+               /* We can only get mailbox status if we're polling from an
+                * unfinished command.  Get the rest of the status data and
+                * return back to the caller.
+                * We only end up here when we're polling for a mailbox
+                * command completion.
+                */
+               mbcp->out_count = orig_count;
+               status = ql_get_mb_sts(qdev, mbcp);
+               return status;
+
+       /* We are being asked by firmware to accept
+        * a change to the port.  This is only
+        * a change to max frame sizes (Tx/Rx), pause
+        * paramters, or loopback mode.
+        */
+       case AEN_IDC_REQ:
+               status = ql_idc_req_aen(qdev);
+               break;
+
+       /* Process and inbound IDC event.
+        * This will happen when we're trying to
+        * change tx/rx max frame size, change pause
+        * paramters or loopback mode.
+        */
+       case AEN_IDC_CMPLT:
+       case AEN_IDC_EXT:
+               status = ql_idc_cmplt_aen(qdev);
+               break;
+
+       case AEN_LINK_UP:
+               ql_link_up(qdev, mbcp);
+               break;
+
+       case AEN_LINK_DOWN:
+               ql_link_down(qdev, mbcp);
+               break;
+
+       case AEN_FW_INIT_DONE:
+               /* If we're in process on executing the firmware,
+                * then convert the status to normal mailbox status.
+                */
+               if (mbcp->mbox_in[0] == MB_CMD_EX_FW) {
+                       mbcp->out_count = orig_count;
+                       status = ql_get_mb_sts(qdev, mbcp);
+                       mbcp->mbox_out[0] = MB_CMD_STS_GOOD;
+                       return status;
+               }
+               ql_init_fw_done(qdev, mbcp);
+               break;
+
+       case AEN_AEN_SFP_IN:
+               ql_sfp_in(qdev, mbcp);
+               break;
+
+       case AEN_AEN_SFP_OUT:
+               ql_sfp_out(qdev, mbcp);
+               break;
+
+       /* This event can arrive at boot time or after an
+        * MPI reset if the firmware failed to initialize.
+        */
+       case AEN_FW_INIT_FAIL:
+               /* If we're in process on executing the firmware,
+                * then convert the status to normal mailbox status.
+                */
+               if (mbcp->mbox_in[0] == MB_CMD_EX_FW) {
+                       mbcp->out_count = orig_count;
+                       status = ql_get_mb_sts(qdev, mbcp);
+                       mbcp->mbox_out[0] = MB_CMD_STS_ERR;
+                       return status;
+               }
+               QPRINTK(qdev, DRV, ERR,
+                       "Firmware initialization failed.\n");
+               status = -EIO;
+               ql_queue_fw_error(qdev);
+               break;
+
+       case AEN_SYS_ERR:
+               QPRINTK(qdev, DRV, ERR,
+                       "System Error.\n");
+               ql_queue_fw_error(qdev);
+               status = -EIO;
+               break;
+
+       case AEN_AEN_LOST:
+               ql_aen_lost(qdev, mbcp);
+               break;
+
+       default:
+               QPRINTK(qdev, DRV, ERR,
+                       "Unsupported AE %.08x.\n", mbcp->mbox_out[0]);
+               /* Clear the MPI firmware status. */
+       }
+end:
        ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
+       return status;
 }
 
-void ql_mpi_work(struct work_struct *work)
+/* Execute a single mailbox command.
+ * mbcp is a pointer to an array of u32.  Each
+ * element in the array contains the value for it's
+ * respective mailbox register.
+ */
+static int ql_mailbox_command(struct ql_adapter *qdev, struct mbox_params *mbcp)
+{
+       int status, count;
+
+       mutex_lock(&qdev->mpi_mutex);
+
+       /* Begin polled mode for MPI */
+       ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16));
+
+       /* Load the mailbox registers and wake up MPI RISC. */
+       status = ql_exec_mb_cmd(qdev, mbcp);
+       if (status)
+               goto end;
+
+
+       /* If we're generating a system error, then there's nothing
+        * to wait for.
+        */
+       if (mbcp->mbox_in[0] == MB_CMD_MAKE_SYS_ERR)
+               goto end;
+
+       /* Wait for the command to complete. We loop
+        * here because some AEN might arrive while
+        * we're waiting for the mailbox command to
+        * complete. If more than 5 arrive then we can
+        * assume something is wrong. */
+       count = 5;
+       do {
+               /* Wait for the interrupt to come in. */
+               status = ql_wait_mbx_cmd_cmplt(qdev);
+               if (status)
+                       goto end;
+
+               /* Process the event.  If it's an AEN, it
+                * will be handled in-line or a worker
+                * will be spawned. If it's our completion
+                * we will catch it below.
+                */
+               status = ql_mpi_handler(qdev, mbcp);
+               if (status)
+                       goto end;
+
+               /* It's either the completion for our mailbox
+                * command complete or an AEN.  If it's our
+                * completion then get out.
+                */
+               if (((mbcp->mbox_out[0] & 0x0000f000) ==
+                                       MB_CMD_STS_GOOD) ||
+                       ((mbcp->mbox_out[0] & 0x0000f000) ==
+                                       MB_CMD_STS_INTRMDT))
+                       break;
+       } while (--count);
+
+       if (!count) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Timed out waiting for mailbox complete.\n");
+               status = -ETIMEDOUT;
+               goto end;
+       }
+
+       /* Now we can clear the interrupt condition
+        * and look at our status.
+        */
+       ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
+
+       if (((mbcp->mbox_out[0] & 0x0000f000) !=
+                                       MB_CMD_STS_GOOD) &&
+               ((mbcp->mbox_out[0] & 0x0000f000) !=
+                                       MB_CMD_STS_INTRMDT)) {
+               ql_display_mb_sts(qdev, mbcp);
+               status = -EIO;
+       }
+end:
+       mutex_unlock(&qdev->mpi_mutex);
+       /* End polled mode for MPI */
+       ql_write32(qdev, INTR_MASK, (INTR_MASK_PI << 16) | INTR_MASK_PI);
+       return status;
+}
+
+/* Get functional state for MPI firmware.
+ * Returns zero on success.
+ */
+int ql_mb_get_fw_state(struct ql_adapter *qdev)
+{
+       struct mbox_params mbc;
+       struct mbox_params *mbcp = &mbc;
+       int status = 0;
+
+       memset(mbcp, 0, sizeof(struct mbox_params));
+
+       mbcp->in_count = 1;
+       mbcp->out_count = 2;
+
+       mbcp->mbox_in[0] = MB_CMD_GET_FW_STATE;
+
+       status = ql_mailbox_command(qdev, mbcp);
+       if (status)
+               return status;
+
+       if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Failed Get Firmware State.\n");
+               status = -EIO;
+       }
+
+       /* If bit zero is set in mbx 1 then the firmware is
+        * running, but not initialized.  This should never
+        * happen.
+        */
+       if (mbcp->mbox_out[1] & 1) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Firmware waiting for initialization.\n");
+               status = -EIO;
+       }
+
+       return status;
+}
+
+/* Send and ACK mailbox command to the firmware to
+ * let it continue with the change.
+ */
+int ql_mb_idc_ack(struct ql_adapter *qdev)
 {
-       struct ql_adapter *qdev =
-           container_of(work, struct ql_adapter, mpi_work.work);
        struct mbox_params mbc;
        struct mbox_params *mbcp = &mbc;
+       int status = 0;
+
+       memset(mbcp, 0, sizeof(struct mbox_params));
+
+       mbcp->in_count = 5;
        mbcp->out_count = 1;
 
-       while (ql_read32(qdev, STS) & STS_PI) {
-               if (ql_get_mb_sts(qdev, mbcp)) {
-                       QPRINTK(qdev, DRV, ERR,
-                               "Could not read MPI, resetting ASIC!\n");
-                       ql_queue_asic_error(qdev);
-               }
+       mbcp->mbox_in[0] = MB_CMD_IDC_ACK;
+       mbcp->mbox_in[1] = qdev->idc_mbc.mbox_out[1];
+       mbcp->mbox_in[2] = qdev->idc_mbc.mbox_out[2];
+       mbcp->mbox_in[3] = qdev->idc_mbc.mbox_out[3];
+       mbcp->mbox_in[4] = qdev->idc_mbc.mbox_out[4];
 
-               switch (mbcp->mbox_out[0]) {
-               case AEN_LINK_UP:
-                       ql_link_up(qdev, mbcp);
-                       break;
-               case AEN_LINK_DOWN:
-                       ql_link_down(qdev, mbcp);
-                       break;
-               case AEN_FW_INIT_DONE:
-                       ql_init_fw_done(qdev, mbcp);
+       status = ql_mailbox_command(qdev, mbcp);
+       if (status)
+               return status;
+
+       if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Failed IDC ACK send.\n");
+               status = -EIO;
+       }
+       return status;
+}
+
+/* Get link settings and maximum frame size settings
+ * for the current port.
+ * Most likely will block.
+ */
+static int ql_mb_set_port_cfg(struct ql_adapter *qdev)
+{
+       struct mbox_params mbc;
+       struct mbox_params *mbcp = &mbc;
+       int status = 0;
+
+       memset(mbcp, 0, sizeof(struct mbox_params));
+
+       mbcp->in_count = 3;
+       mbcp->out_count = 1;
+
+       mbcp->mbox_in[0] = MB_CMD_SET_PORT_CFG;
+       mbcp->mbox_in[1] = qdev->link_config;
+       mbcp->mbox_in[2] = qdev->max_frame_size;
+
+
+       status = ql_mailbox_command(qdev, mbcp);
+       if (status)
+               return status;
+
+       if (mbcp->mbox_out[0] == MB_CMD_STS_INTRMDT) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Port Config sent, wait for IDC.\n");
+       } else  if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Failed Set Port Configuration.\n");
+               status = -EIO;
+       }
+       return status;
+}
+
+/* Get link settings and maximum frame size settings
+ * for the current port.
+ * Most likely will block.
+ */
+static int ql_mb_get_port_cfg(struct ql_adapter *qdev)
+{
+       struct mbox_params mbc;
+       struct mbox_params *mbcp = &mbc;
+       int status = 0;
+
+       memset(mbcp, 0, sizeof(struct mbox_params));
+
+       mbcp->in_count = 1;
+       mbcp->out_count = 3;
+
+       mbcp->mbox_in[0] = MB_CMD_GET_PORT_CFG;
+
+       status = ql_mailbox_command(qdev, mbcp);
+       if (status)
+               return status;
+
+       if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Failed Get Port Configuration.\n");
+               status = -EIO;
+       } else  {
+               QPRINTK(qdev, DRV, DEBUG,
+                       "Passed Get Port Configuration.\n");
+               qdev->link_config = mbcp->mbox_out[1];
+               qdev->max_frame_size = mbcp->mbox_out[2];
+       }
+       return status;
+}
+
+/* IDC - Inter Device Communication...
+ * Some firmware commands require consent of adjacent FCOE
+ * function.  This function waits for the OK, or a
+ * counter-request for a little more time.i
+ * The firmware will complete the request if the other
+ * function doesn't respond.
+ */
+static int ql_idc_wait(struct ql_adapter *qdev)
+{
+       int status = -ETIMEDOUT;
+       long wait_time = 1 * HZ;
+       struct mbox_params *mbcp = &qdev->idc_mbc;
+       do {
+               /* Wait here for the command to complete
+                * via the IDC process.
+                */
+               wait_time =
+                       wait_for_completion_timeout(&qdev->ide_completion,
+                                                       wait_time);
+               if (!wait_time) {
+                       QPRINTK(qdev, DRV, ERR,
+                               "IDC Timeout.\n");
                        break;
-               case MB_CMD_STS_GOOD:
+               }
+               /* Now examine the response from the IDC process.
+                * We might have a good completion or a request for
+                * more wait time.
+                */
+               if (mbcp->mbox_out[0] == AEN_IDC_EXT) {
+                       QPRINTK(qdev, DRV, ERR,
+                               "IDC Time Extension from function.\n");
+                       wait_time += (mbcp->mbox_out[1] >> 8) & 0x0000000f;
+               } else if (mbcp->mbox_out[0] == AEN_IDC_CMPLT) {
+                       QPRINTK(qdev, DRV, ERR,
+                               "IDC Success.\n");
+                       status = 0;
                        break;
-               case AEN_FW_INIT_FAIL:
-               case AEN_SYS_ERR:
-               case MB_CMD_STS_ERR:
-                       ql_queue_fw_error(qdev);
-               default:
-                       /* Clear the MPI firmware status. */
-                       ql_write32(qdev, CSR, CSR_CMD_CLR_R2PCI_INT);
+               } else {
+                       QPRINTK(qdev, DRV, ERR,
+                               "IDC: Invalid State 0x%.04x.\n",
+                               mbcp->mbox_out[0]);
+                       status = -EIO;
                        break;
                }
+       } while (wait_time);
+
+       return status;
+}
+
+/* API called in work thread context to set new TX/RX
+ * maximum frame size values to match MTU.
+ */
+static int ql_set_port_cfg(struct ql_adapter *qdev)
+{
+       int status;
+       status = ql_mb_set_port_cfg(qdev);
+       if (status)
+               return status;
+       status = ql_idc_wait(qdev);
+       return status;
+}
+
+/* The following routines are worker threads that process
+ * events that may sleep waiting for completion.
+ */
+
+/* This thread gets the maximum TX and RX frame size values
+ * from the firmware and, if necessary, changes them to match
+ * the MTU setting.
+ */
+void ql_mpi_port_cfg_work(struct work_struct *work)
+{
+       struct ql_adapter *qdev =
+           container_of(work, struct ql_adapter, mpi_port_cfg_work.work);
+       struct net_device *ndev = qdev->ndev;
+       int status;
+
+       status = ql_mb_get_port_cfg(qdev);
+       if (status) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Bug: Failed to get port config data.\n");
+               goto err;
+       }
+
+       if (ndev->mtu <= 2500)
+               goto end;
+       else if (qdev->link_config & CFG_JUMBO_FRAME_SIZE &&
+                       qdev->max_frame_size ==
+                       CFG_DEFAULT_MAX_FRAME_SIZE)
+               goto end;
+
+       qdev->link_config |=    CFG_JUMBO_FRAME_SIZE;
+       qdev->max_frame_size = CFG_DEFAULT_MAX_FRAME_SIZE;
+       status = ql_set_port_cfg(qdev);
+       if (status) {
+               QPRINTK(qdev, DRV, ERR,
+                       "Bug: Failed to set port config data.\n");
+               goto err;
+       }
+end:
+       clear_bit(QL_PORT_CFG, &qdev->flags);
+       return;
+err:
+       ql_queue_fw_error(qdev);
+       goto end;
+}
+
+/* Process an inter-device request.  This is issues by
+ * the firmware in response to another function requesting
+ * a change to the port. We set a flag to indicate a change
+ * has been made and then send a mailbox command ACKing
+ * the change request.
+ */
+void ql_mpi_idc_work(struct work_struct *work)
+{
+       struct ql_adapter *qdev =
+           container_of(work, struct ql_adapter, mpi_idc_work.work);
+       int status;
+       struct mbox_params *mbcp = &qdev->idc_mbc;
+       u32 aen;
+
+       aen = mbcp->mbox_out[1] >> 16;
+
+       switch (aen) {
+       default:
+               QPRINTK(qdev, DRV, ERR,
+                       "Bug: Unhandled IDC action.\n");
+               break;
+       case MB_CMD_PORT_RESET:
+       case MB_CMD_SET_PORT_CFG:
+       case MB_CMD_STOP_FW:
+               netif_carrier_off(qdev->ndev);
+               /* Signal the resulting link up AEN
+                * that the frame routing and mac addr
+                * needs to be set.
+                * */
+               set_bit(QL_CAM_RT_SET, &qdev->flags);
+               status = ql_mb_idc_ack(qdev);
+               if (status) {
+                       QPRINTK(qdev, DRV, ERR,
+                       "Bug: No pending IDC!\n");
+               }
+       }
+}
+
+void ql_mpi_work(struct work_struct *work)
+{
+       struct ql_adapter *qdev =
+           container_of(work, struct ql_adapter, mpi_work.work);
+       struct mbox_params mbc;
+       struct mbox_params *mbcp = &mbc;
+
+       mutex_lock(&qdev->mpi_mutex);
+
+       while (ql_read32(qdev, STS) & STS_PI) {
+               memset(mbcp, 0, sizeof(struct mbox_params));
+               mbcp->out_count = 1;
+               ql_mpi_handler(qdev, mbcp);
        }
+
+       mutex_unlock(&qdev->mpi_mutex);
        ql_enable_completion_interrupt(qdev, 0);
 }
 
@@ -142,9 +848,8 @@ void ql_mpi_reset_work(struct work_struct *work)
 {
        struct ql_adapter *qdev =
            container_of(work, struct ql_adapter, mpi_reset_work.work);
-       QPRINTK(qdev, DRV, ERR,
-               "Enter, qdev = %p..\n", qdev);
-       ql_write32(qdev, CSR, CSR_CMD_SET_RST);
-       msleep(50);
-       ql_write32(qdev, CSR, CSR_CMD_CLR_RST);
+       cancel_delayed_work_sync(&qdev->mpi_work);
+       cancel_delayed_work_sync(&qdev->mpi_port_cfg_work);
+       cancel_delayed_work_sync(&qdev->mpi_idc_work);
+       ql_soft_reset_mpi_risc(qdev);
 }
index dd83f936b03644d9f27560570219cb337e944ddb..06c535222666be7e1c5a0f933268cec7b58052a0 100644 (file)
@@ -3253,13 +3253,6 @@ static int rtl8169_start_xmit(struct sk_buff *skb, struct net_device *dev)
                opts1 |= FirstFrag;
        } else {
                len = skb->len;
-
-               if (unlikely(len < ETH_ZLEN)) {
-                       if (skb_padto(skb, ETH_ZLEN))
-                               goto err_update_stats;
-                       len = ETH_ZLEN;
-               }
-
                opts1 |= FirstFrag | LastFrag;
                tp->tx_skb[entry].skb = skb;
        }
@@ -3297,7 +3290,6 @@ out:
 err_stop:
        netif_stop_queue(dev);
        ret = NETDEV_TX_BUSY;
-err_update_stats:
        dev->stats.tx_dropped++;
        goto out;
 }
index a6fd27a2cc3d25b4808ae5c85ba8c7a8e6e9da4b..ec59e29807a67ad94a79ded9d2487856ae436ec9 100644 (file)
@@ -362,8 +362,7 @@ static int rionet_close(struct net_device *ndev)
        netif_carrier_off(ndev);
 
        for (i = 0; i < RIONET_RX_RING_SIZE; i++)
-               if (rnet->rx_skb[i])
-                       kfree_skb(rnet->rx_skb[i]);
+               kfree_skb(rnet->rx_skb[i]);
 
        list_for_each_entry_safe(peer, tmp, &rionet_peers, node) {
                if (rionet_active[peer->rdev->destid]) {
index 64903496aa9af1b256f0fcc062007f2cd8842472..5182ac5a1034c2d0ccb3cce336446b0f02e04089 100644 (file)
@@ -26,7 +26,7 @@ static void blink_led_timer(unsigned long context)
 {
        struct efx_nic *efx = (struct efx_nic *)context;
        struct efx_blinker *bl = &efx->board_info.blinker;
-       efx->board_info.set_fault_led(efx, bl->state);
+       efx->board_info.set_id_led(efx, bl->state);
        bl->state = !bl->state;
        if (bl->resubmit)
                mod_timer(&bl->timer, jiffies + BLINK_INTERVAL);
@@ -48,7 +48,7 @@ static void board_blink(struct efx_nic *efx, bool blink)
                blinker->resubmit = false;
                if (blinker->timer.function)
                        del_timer_sync(&blinker->timer);
-               efx->board_info.set_fault_led(efx, false);
+               efx->board_info.init_leds(efx);
        }
 }
 
@@ -185,7 +185,7 @@ static struct i2c_board_info sfe4002_hwmon_info = {
 #define SFE4002_RX_LED    (0)  /* Green */
 #define SFE4002_TX_LED    (1)  /* Amber */
 
-static int sfe4002_init_leds(struct efx_nic *efx)
+static void sfe4002_init_leds(struct efx_nic *efx)
 {
        /* Set the TX and RX LEDs to reflect status and activity, and the
         * fault LED off */
@@ -194,11 +194,9 @@ static int sfe4002_init_leds(struct efx_nic *efx)
        xfp_set_led(efx, SFE4002_RX_LED,
                    QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACTSTAT);
        xfp_set_led(efx, SFE4002_FAULT_LED, QUAKE_LED_OFF);
-       efx->board_info.blinker.led_num = SFE4002_FAULT_LED;
-       return 0;
 }
 
-static void sfe4002_fault_led(struct efx_nic *efx, bool state)
+static void sfe4002_set_id_led(struct efx_nic *efx, bool state)
 {
        xfp_set_led(efx, SFE4002_FAULT_LED, state ? QUAKE_LED_ON :
                        QUAKE_LED_OFF);
@@ -222,7 +220,67 @@ static int sfe4002_init(struct efx_nic *efx)
                return rc;
        efx->board_info.monitor = sfe4002_check_hw;
        efx->board_info.init_leds = sfe4002_init_leds;
-       efx->board_info.set_fault_led = sfe4002_fault_led;
+       efx->board_info.set_id_led = sfe4002_set_id_led;
+       efx->board_info.blink = board_blink;
+       efx->board_info.fini = efx_fini_lm87;
+       return 0;
+}
+
+/*****************************************************************************
+ * Support for the SFN4112F
+ *
+ */
+static u8 sfn4112f_lm87_channel = 0x03; /* use AIN not FAN inputs */
+
+static const u8 sfn4112f_lm87_regs[] = {
+       LM87_IN_LIMITS(0, 0x83, 0x91),          /* 2.5V:  1.8V +/- 5% */
+       LM87_IN_LIMITS(1, 0x51, 0x5a),          /* Vccp1: 1.2V +/- 5% */
+       LM87_IN_LIMITS(2, 0xb6, 0xca),          /* 3.3V:  3.3V +/- 5% */
+       LM87_IN_LIMITS(4, 0xb0, 0xe0),          /* 12V:   11-14V */
+       LM87_IN_LIMITS(5, 0x44, 0x4b),          /* Vccp2: 1.0V +/- 5% */
+       LM87_AIN_LIMITS(1, 0x91, 0xa1),         /* AIN2:  1.5V +/- 5% */
+       LM87_TEMP_INT_LIMITS(10, 60),           /* board */
+       LM87_TEMP_EXT1_LIMITS(10, 70),          /* Falcon */
+       0
+};
+
+static struct i2c_board_info sfn4112f_hwmon_info = {
+       I2C_BOARD_INFO("lm87", 0x2e),
+       .platform_data  = &sfn4112f_lm87_channel,
+       .irq            = -1,
+};
+
+#define SFN4112F_ACT_LED       0
+#define SFN4112F_LINK_LED      1
+
+static void sfn4112f_init_leds(struct efx_nic *efx)
+{
+       xfp_set_led(efx, SFN4112F_ACT_LED,
+                   QUAKE_LED_RXLINK | QUAKE_LED_LINK_ACT);
+       xfp_set_led(efx, SFN4112F_LINK_LED,
+                   QUAKE_LED_RXLINK | QUAKE_LED_LINK_STAT);
+}
+
+static void sfn4112f_set_id_led(struct efx_nic *efx, bool state)
+{
+       xfp_set_led(efx, SFN4112F_LINK_LED,
+                   state ? QUAKE_LED_ON : QUAKE_LED_OFF);
+}
+
+static int sfn4112f_check_hw(struct efx_nic *efx)
+{
+       /* Mask out unused sensors */
+       return efx_check_lm87(efx, ~0x48);
+}
+
+static int sfn4112f_init(struct efx_nic *efx)
+{
+       int rc = efx_init_lm87(efx, &sfn4112f_hwmon_info, sfn4112f_lm87_regs);
+       if (rc)
+               return rc;
+       efx->board_info.monitor = sfn4112f_check_hw;
+       efx->board_info.init_leds = sfn4112f_init_leds;
+       efx->board_info.set_id_led = sfn4112f_set_id_led;
        efx->board_info.blink = board_blink;
        efx->board_info.fini = efx_fini_lm87;
        return 0;
@@ -243,6 +301,8 @@ static struct efx_board_data board_data[] = {
        { EFX_BOARD_SFE4002, "SFE4002", "XFP adapter", sfe4002_init },
        { EFX_BOARD_SFN4111T, "SFN4111T", "100/1000/10GBASE-T adapter",
          sfn4111t_init },
+       { EFX_BOARD_SFN4112F, "SFN4112F", "SFP+ adapter",
+         sfn4112f_init },
 };
 
 void efx_set_board_info(struct efx_nic *efx, u16 revision_info)
index d93c6c6a754864bfef4b80326b6086a8947fe350..44942de0e080a07de6377b26ce5539535dba6e59 100644 (file)
@@ -15,6 +15,7 @@ enum efx_board_type {
        EFX_BOARD_SFE4001 = 1,
        EFX_BOARD_SFE4002 = 2,
        EFX_BOARD_SFN4111T = 0x51,
+       EFX_BOARD_SFN4112F = 0x52,
 };
 
 extern void efx_set_board_info(struct efx_nic *efx, u16 revision_info);
index 75836599e43dc87a51878f81d8b1058132df7f39..6eff9ca6c6c81c87df26b418f6c31cb3a94fa908 100644 (file)
@@ -133,6 +133,16 @@ static int phy_flash_cfg;
 module_param(phy_flash_cfg, int, 0644);
 MODULE_PARM_DESC(phy_flash_cfg, "Set PHYs into reflash mode initially");
 
+static unsigned irq_adapt_low_thresh = 10000;
+module_param(irq_adapt_low_thresh, uint, 0644);
+MODULE_PARM_DESC(irq_adapt_low_thresh,
+                "Threshold score for reducing IRQ moderation");
+
+static unsigned irq_adapt_high_thresh = 20000;
+module_param(irq_adapt_high_thresh, uint, 0644);
+MODULE_PARM_DESC(irq_adapt_high_thresh,
+                "Threshold score for increasing IRQ moderation");
+
 /**************************************************************************
  *
  * Utility functions and prototypes
@@ -223,6 +233,35 @@ static int efx_poll(struct napi_struct *napi, int budget)
        rx_packets = efx_process_channel(channel, budget);
 
        if (rx_packets < budget) {
+               struct efx_nic *efx = channel->efx;
+
+               if (channel->used_flags & EFX_USED_BY_RX &&
+                   efx->irq_rx_adaptive &&
+                   unlikely(++channel->irq_count == 1000)) {
+                       unsigned old_irq_moderation = channel->irq_moderation;
+
+                       if (unlikely(channel->irq_mod_score <
+                                    irq_adapt_low_thresh)) {
+                               channel->irq_moderation =
+                                       max_t(int,
+                                             channel->irq_moderation -
+                                             FALCON_IRQ_MOD_RESOLUTION,
+                                             FALCON_IRQ_MOD_RESOLUTION);
+                       } else if (unlikely(channel->irq_mod_score >
+                                           irq_adapt_high_thresh)) {
+                               channel->irq_moderation =
+                                       min(channel->irq_moderation +
+                                           FALCON_IRQ_MOD_RESOLUTION,
+                                           efx->irq_rx_moderation);
+                       }
+
+                       if (channel->irq_moderation != old_irq_moderation)
+                               falcon_set_int_moderation(channel);
+
+                       channel->irq_count = 0;
+                       channel->irq_mod_score = 0;
+               }
+
                /* There is no race here; although napi_disable() will
                 * only wait for napi_complete(), this isn't a problem
                 * since efx_channel_processed() will have no effect if
@@ -557,6 +596,8 @@ static void efx_link_status_changed(struct efx_nic *efx)
 
 }
 
+static void efx_fini_port(struct efx_nic *efx);
+
 /* This call reinitialises the MAC to pick up new PHY settings. The
  * caller must hold the mac_lock */
 void __efx_reconfigure_port(struct efx_nic *efx)
@@ -592,8 +633,8 @@ void __efx_reconfigure_port(struct efx_nic *efx)
 
 fail:
        EFX_ERR(efx, "failed to reconfigure MAC\n");
-       efx->phy_op->fini(efx);
-       efx->port_initialized = false;
+       efx->port_enabled = false;
+       efx_fini_port(efx);
 }
 
 /* Reinitialise the MAC to pick up new PHY settings, even if the port is
@@ -989,7 +1030,7 @@ static int efx_probe_nic(struct efx_nic *efx)
        efx_set_channels(efx);
 
        /* Initialise the interrupt moderation settings */
-       efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec);
+       efx_init_irq_moderation(efx, tx_irq_mod_usec, rx_irq_mod_usec, true);
 
        return 0;
 }
@@ -1186,7 +1227,8 @@ void efx_flush_queues(struct efx_nic *efx)
  **************************************************************************/
 
 /* Set interrupt moderation parameters */
-void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs)
+void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs,
+                            bool rx_adaptive)
 {
        struct efx_tx_queue *tx_queue;
        struct efx_rx_queue *rx_queue;
@@ -1196,6 +1238,8 @@ void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs, int rx_usecs)
        efx_for_each_tx_queue(tx_queue, efx)
                tx_queue->channel->irq_moderation = tx_usecs;
 
+       efx->irq_rx_adaptive = rx_adaptive;
+       efx->irq_rx_moderation = rx_usecs;
        efx_for_each_rx_queue(rx_queue, efx)
                rx_queue->channel->irq_moderation = rx_usecs;
 }
@@ -1667,7 +1711,8 @@ int efx_reset_up(struct efx_nic *efx, enum reset_type method,
                        rc = efx->phy_op->init(efx);
                        if (rc)
                                ok = false;
-               } else
+               }
+               if (!ok)
                        efx->port_initialized = false;
        }
 
@@ -1848,8 +1893,8 @@ static struct efx_phy_operations efx_dummy_phy_operations = {
 
 static struct efx_board efx_dummy_board_info = {
        .init           = efx_port_dummy_op_int,
-       .init_leds      = efx_port_dummy_op_int,
-       .set_fault_led  = efx_port_dummy_op_blink,
+       .init_leds      = efx_port_dummy_op_void,
+       .set_id_led     = efx_port_dummy_op_blink,
        .monitor        = efx_port_dummy_op_int,
        .blink          = efx_port_dummy_op_blink,
        .fini           = efx_port_dummy_op_void,
index 8bde1d2a21db3f7108d3126e3edf9aeb76a07f3c..da157aa74b836cb5527158ef75088872aacf9873 100644 (file)
@@ -52,7 +52,7 @@ extern void efx_schedule_reset(struct efx_nic *efx, enum reset_type type);
 extern void efx_suspend(struct efx_nic *efx);
 extern void efx_resume(struct efx_nic *efx);
 extern void efx_init_irq_moderation(struct efx_nic *efx, int tx_usecs,
-                                   int rx_usecs);
+                                   int rx_usecs, bool rx_adaptive);
 extern int efx_request_power(struct efx_nic *efx, int mw, const char *name);
 extern void efx_hex_dump(const u8 *, unsigned int, const char *);
 
index 7b5924c039b31508069591b2dd977e8417614525..64309f4e8b190e440307a4da29b47753cf794416 100644 (file)
@@ -529,7 +529,14 @@ static int efx_ethtool_nway_reset(struct net_device *net_dev)
 {
        struct efx_nic *efx = netdev_priv(net_dev);
 
-       return mii_nway_restart(&efx->mii);
+       if (efx->phy_op->mmds & DEV_PRESENT_BIT(MDIO_MMD_AN)) {
+               mdio_clause45_set_flag(efx, efx->mii.phy_id, MDIO_MMD_AN,
+                                      MDIO_MMDREG_CTRL1,
+                                      __ffs(BMCR_ANRESTART), true);
+               return 0;
+       }
+
+       return -EOPNOTSUPP;
 }
 
 static u32 efx_ethtool_get_link(struct net_device *net_dev)
@@ -597,7 +604,6 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev,
 {
        struct efx_nic *efx = netdev_priv(net_dev);
        struct efx_tx_queue *tx_queue;
-       struct efx_rx_queue *rx_queue;
        struct efx_channel *channel;
 
        memset(coalesce, 0, sizeof(*coalesce));
@@ -615,14 +621,8 @@ static int efx_ethtool_get_coalesce(struct net_device *net_dev,
                }
        }
 
-       /* Find lowest IRQ moderation across all used RX queues */
-       coalesce->rx_coalesce_usecs_irq = ~((u32) 0);
-       efx_for_each_rx_queue(rx_queue, efx) {
-               channel = rx_queue->channel;
-               if (channel->irq_moderation < coalesce->rx_coalesce_usecs_irq)
-                       coalesce->rx_coalesce_usecs_irq =
-                               channel->irq_moderation;
-       }
+       coalesce->use_adaptive_rx_coalesce = efx->irq_rx_adaptive;
+       coalesce->rx_coalesce_usecs_irq = efx->irq_rx_moderation;
 
        return 0;
 }
@@ -636,10 +636,9 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev,
        struct efx_nic *efx = netdev_priv(net_dev);
        struct efx_channel *channel;
        struct efx_tx_queue *tx_queue;
-       unsigned tx_usecs, rx_usecs;
+       unsigned tx_usecs, rx_usecs, adaptive;
 
-       if (coalesce->use_adaptive_rx_coalesce ||
-           coalesce->use_adaptive_tx_coalesce)
+       if (coalesce->use_adaptive_tx_coalesce)
                return -EOPNOTSUPP;
 
        if (coalesce->rx_coalesce_usecs || coalesce->tx_coalesce_usecs) {
@@ -650,6 +649,7 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev,
 
        rx_usecs = coalesce->rx_coalesce_usecs_irq;
        tx_usecs = coalesce->tx_coalesce_usecs_irq;
+       adaptive = coalesce->use_adaptive_rx_coalesce;
 
        /* If the channel is shared only allow RX parameters to be set */
        efx_for_each_tx_queue(tx_queue, efx) {
@@ -661,7 +661,7 @@ static int efx_ethtool_set_coalesce(struct net_device *net_dev,
                }
        }
 
-       efx_init_irq_moderation(efx, tx_usecs, rx_usecs);
+       efx_init_irq_moderation(efx, tx_usecs, rx_usecs, adaptive);
 
        /* Reset channel to pick up new moderation value.  Note that
         * this may change the value of the irq_moderation field
index d5378e60fcddfcb44cb5223abb11b6a1f75a34e6..23a1b148d5b236347531e42a030bdbd912d1d3c5 100644 (file)
  * @next_buffer_table: First available buffer table id
  * @pci_dev2: The secondary PCI device if present
  * @i2c_data: Operations and state for I2C bit-bashing algorithm
+ * @int_error_count: Number of internal errors seen recently
+ * @int_error_expire: Time at which error count will be expired
  */
 struct falcon_nic_data {
        unsigned next_buffer_table;
        struct pci_dev *pci_dev2;
        struct i2c_algo_bit_data i2c_data;
+
+       unsigned int_error_count;
+       unsigned long int_error_expire;
 };
 
 /**************************************************************************
@@ -119,8 +124,12 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
 #define FALCON_EVQ_SIZE 4096
 #define FALCON_EVQ_MASK (FALCON_EVQ_SIZE - 1)
 
-/* Max number of internal errors. After this resets will not be performed */
-#define FALCON_MAX_INT_ERRORS 4
+/* If FALCON_MAX_INT_ERRORS internal errors occur within
+ * FALCON_INT_ERROR_EXPIRE seconds, we consider the NIC broken and
+ * disable it.
+ */
+#define FALCON_INT_ERROR_EXPIRE 3600
+#define FALCON_MAX_INT_ERRORS 5
 
 /* We poll for events every FLUSH_INTERVAL ms, and check FLUSH_POLL_COUNT times
  */
@@ -146,13 +155,6 @@ MODULE_PARM_DESC(rx_xon_thresh_bytes, "RX fifo XON threshold");
 /* Dummy SRAM size code */
 #define SRM_NB_BSZ_ONCHIP_ONLY (-1)
 
-/* Be nice if these (or equiv.) were in linux/pci_regs.h, but they're not. */
-#define PCI_EXP_DEVCAP_PWR_VAL_LBN     18
-#define PCI_EXP_DEVCAP_PWR_SCL_LBN     26
-#define PCI_EXP_DEVCTL_PAYLOAD_LBN     5
-#define PCI_EXP_LNKSTA_LNK_WID         0x3f0
-#define PCI_EXP_LNKSTA_LNK_WID_LBN     4
-
 #define FALCON_IS_DUAL_FUNC(efx)               \
        (falcon_rev(efx) < FALCON_REV_B0)
 
@@ -727,6 +729,9 @@ static void falcon_handle_tx_event(struct efx_channel *channel,
                tx_ev_desc_ptr = EFX_QWORD_FIELD(*event, TX_EV_DESC_PTR);
                tx_ev_q_label = EFX_QWORD_FIELD(*event, TX_EV_Q_LABEL);
                tx_queue = &efx->tx_queue[tx_ev_q_label];
+               channel->irq_mod_score +=
+                       (tx_ev_desc_ptr - tx_queue->read_count) &
+                       efx->type->txd_ring_mask;
                efx_xmit_done(tx_queue, tx_ev_desc_ptr);
        } else if (EFX_QWORD_FIELD(*event, TX_EV_WQ_FF_FULL)) {
                /* Rewrite the FIFO write pointer */
@@ -896,6 +901,8 @@ static void falcon_handle_rx_event(struct efx_channel *channel,
                        discard = true;
        }
 
+       channel->irq_mod_score += 2;
+
        /* Handle received packet */
        efx_rx_packet(rx_queue, rx_ev_desc_ptr, rx_ev_byte_cnt,
                      checksummed, discard);
@@ -1073,14 +1080,15 @@ void falcon_set_int_moderation(struct efx_channel *channel)
                 * program is based at 0.  So actual interrupt moderation
                 * achieved is ((x + 1) * res).
                 */
-               unsigned int res = 5;
-               channel->irq_moderation -= (channel->irq_moderation % res);
-               if (channel->irq_moderation < res)
-                       channel->irq_moderation = res;
+               channel->irq_moderation -= (channel->irq_moderation %
+                                           FALCON_IRQ_MOD_RESOLUTION);
+               if (channel->irq_moderation < FALCON_IRQ_MOD_RESOLUTION)
+                       channel->irq_moderation = FALCON_IRQ_MOD_RESOLUTION;
                EFX_POPULATE_DWORD_2(timer_cmd,
                                     TIMER_MODE, TIMER_MODE_INT_HLDOFF,
                                     TIMER_VAL,
-                                    (channel->irq_moderation / res) - 1);
+                                    channel->irq_moderation /
+                                    FALCON_IRQ_MOD_RESOLUTION - 1);
        } else {
                EFX_POPULATE_DWORD_2(timer_cmd,
                                     TIMER_MODE, TIMER_MODE_DIS,
@@ -1187,31 +1195,29 @@ static void falcon_poll_flush_events(struct efx_nic *efx)
        struct efx_channel *channel = &efx->channel[0];
        struct efx_tx_queue *tx_queue;
        struct efx_rx_queue *rx_queue;
-       unsigned int read_ptr, i;
+       unsigned int read_ptr = channel->eventq_read_ptr;
+       unsigned int end_ptr = (read_ptr - 1) & FALCON_EVQ_MASK;
 
-       read_ptr = channel->eventq_read_ptr;
-       for (i = 0; i < FALCON_EVQ_SIZE; ++i) {
+       do {
                efx_qword_t *event = falcon_event(channel, read_ptr);
                int ev_code, ev_sub_code, ev_queue;
                bool ev_failed;
+
                if (!falcon_event_present(event))
                        break;
 
                ev_code = EFX_QWORD_FIELD(*event, EV_CODE);
-               if (ev_code != DRIVER_EV_DECODE)
-                       continue;
-
                ev_sub_code = EFX_QWORD_FIELD(*event, DRIVER_EV_SUB_CODE);
-               switch (ev_sub_code) {
-               case TX_DESCQ_FLS_DONE_EV_DECODE:
+               if (ev_code == DRIVER_EV_DECODE &&
+                   ev_sub_code == TX_DESCQ_FLS_DONE_EV_DECODE) {
                        ev_queue = EFX_QWORD_FIELD(*event,
                                                   DRIVER_EV_TX_DESCQ_ID);
                        if (ev_queue < EFX_TX_QUEUE_COUNT) {
                                tx_queue = efx->tx_queue + ev_queue;
                                tx_queue->flushed = true;
                        }
-                       break;
-               case RX_DESCQ_FLS_DONE_EV_DECODE:
+               } else if (ev_code == DRIVER_EV_DECODE &&
+                          ev_sub_code == RX_DESCQ_FLS_DONE_EV_DECODE) {
                        ev_queue = EFX_QWORD_FIELD(*event,
                                                   DRIVER_EV_RX_DESCQ_ID);
                        ev_failed = EFX_QWORD_FIELD(*event,
@@ -1225,11 +1231,10 @@ static void falcon_poll_flush_events(struct efx_nic *efx)
                                else
                                        rx_queue->flushed = true;
                        }
-                       break;
                }
 
                read_ptr = (read_ptr + 1) & FALCON_EVQ_MASK;
-       }
+       } while (read_ptr != end_ptr);
 }
 
 /* Handle tx and rx flushes at the same time, since they run in
@@ -1377,7 +1382,6 @@ static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx)
        efx_oword_t *int_ker = efx->irq_status.addr;
        efx_oword_t fatal_intr;
        int error, mem_perr;
-       static int n_int_errors;
 
        falcon_read(efx, &fatal_intr, FATAL_INTR_REG_KER);
        error = EFX_OWORD_FIELD(fatal_intr, INT_KER_ERROR);
@@ -1404,7 +1408,14 @@ static irqreturn_t falcon_fatal_interrupt(struct efx_nic *efx)
                pci_clear_master(nic_data->pci_dev2);
        falcon_disable_interrupts(efx);
 
-       if (++n_int_errors < FALCON_MAX_INT_ERRORS) {
+       /* Count errors and reset or disable the NIC accordingly */
+       if (nic_data->int_error_count == 0 ||
+           time_after(jiffies, nic_data->int_error_expire)) {
+               nic_data->int_error_count = 0;
+               nic_data->int_error_expire =
+                       jiffies + FALCON_INT_ERROR_EXPIRE * HZ;
+       }
+       if (++nic_data->int_error_count < FALCON_MAX_INT_ERRORS) {
                EFX_ERR(efx, "SYSTEM ERROR - reset scheduled\n");
                efx_schedule_reset(efx, RESET_TYPE_INT_ERROR);
        } else {
@@ -1423,6 +1434,7 @@ static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id)
 {
        struct efx_nic *efx = dev_id;
        efx_oword_t *int_ker = efx->irq_status.addr;
+       irqreturn_t result = IRQ_NONE;
        struct efx_channel *channel;
        efx_dword_t reg;
        u32 queues;
@@ -1437,23 +1449,24 @@ static irqreturn_t falcon_legacy_interrupt_b0(int irq, void *dev_id)
        if (unlikely(syserr))
                return falcon_fatal_interrupt(efx);
 
-       if (queues == 0)
-               return IRQ_NONE;
-
-       efx->last_irq_cpu = raw_smp_processor_id();
-       EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n",
-                 irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg));
-
        /* Schedule processing of any interrupting queues */
-       channel = &efx->channel[0];
-       while (queues) {
-               if (queues & 0x01)
+       efx_for_each_channel(channel, efx) {
+               if ((queues & 1) ||
+                   falcon_event_present(
+                           falcon_event(channel, channel->eventq_read_ptr))) {
                        efx_schedule_channel(channel);
-               channel++;
+                       result = IRQ_HANDLED;
+               }
                queues >>= 1;
        }
 
-       return IRQ_HANDLED;
+       if (result == IRQ_HANDLED) {
+               efx->last_irq_cpu = raw_smp_processor_id();
+               EFX_TRACE(efx, "IRQ %d on CPU %d status " EFX_DWORD_FMT "\n",
+                         irq, raw_smp_processor_id(), EFX_DWORD_VAL(reg));
+       }
+
+       return result;
 }
 
 
@@ -2249,6 +2262,7 @@ static int falcon_probe_phy(struct efx_nic *efx)
                efx->phy_op = &falcon_sft9001_phy_ops;
                break;
        case PHY_TYPE_QT2022C2:
+       case PHY_TYPE_QT2025C:
                efx->phy_op = &falcon_xfp_phy_ops;
                break;
        default:
@@ -3113,8 +3127,10 @@ void falcon_remove_nic(struct efx_nic *efx)
        struct falcon_nic_data *nic_data = efx->nic_data;
        int rc;
 
+       /* Remove I2C adapter and clear it in preparation for a retry */
        rc = i2c_del_adapter(&efx->i2c_adap);
        BUG_ON(rc);
+       memset(&efx->i2c_adap, 0, sizeof(efx->i2c_adap));
 
        falcon_remove_spi_devices(efx);
        falcon_free_buffer(efx, &efx->irq_status);
index 7869c3d74383cc971e818bda22ec5fc78cbf2395..77f2e0db7ca109e8d8d17760ea322b0978fd7c4f 100644 (file)
@@ -85,6 +85,8 @@ extern void falcon_set_int_moderation(struct efx_channel *channel);
 extern void falcon_disable_interrupts(struct efx_nic *efx);
 extern void falcon_fini_interrupt(struct efx_nic *efx);
 
+#define FALCON_IRQ_MOD_RESOLUTION 5
+
 /* Global Resources */
 extern int falcon_probe_nic(struct efx_nic *efx);
 extern int falcon_probe_resources(struct efx_nic *efx);
index c16da3149fa9ddc6d4fde23482a3f91c08147be3..8883092dae9768ee0d0516b518b5b3cd491af251 100644 (file)
@@ -238,18 +238,21 @@ static inline void falcon_writel_page(struct efx_nic *efx, efx_dword_t *value,
 /* Write dword to Falcon page-mapped register with an extra lock.
  *
  * As for falcon_writel_page(), but for a register that suffers from
- * SFC bug 3181. Take out a lock so the BIU collector cannot be
- * confused. */
+ * SFC bug 3181.  If writing to page 0, take out a lock so the BIU
+ * collector cannot be confused.
+ */
 static inline void falcon_writel_page_locked(struct efx_nic *efx,
                                             efx_dword_t *value,
                                             unsigned int reg,
                                             unsigned int page)
 {
-       unsigned long flags;
+       unsigned long flags = 0;
 
-       spin_lock_irqsave(&efx->biu_lock, flags);
+       if (page == 0)
+               spin_lock_irqsave(&efx->biu_lock, flags);
        falcon_writel(efx, value, FALCON_PAGED_REG(page, reg));
-       spin_unlock_irqrestore(&efx->biu_lock, flags);
+       if (page == 0)
+               spin_unlock_irqrestore(&efx->biu_lock, flags);
 }
 
 #endif /* EFX_FALCON_IO_H */
index f9e2f95c3b48c9a8a175d422b68bbaf03bb6c6b1..9f5ec3eb3418c4b797b6a1a626af87b1addcd66b 100644 (file)
 #include "boards.h"
 #include "workarounds.h"
 
+unsigned mdio_id_oui(u32 id)
+{
+       unsigned oui = 0;
+       int i;
+
+       /* The bits of the OUI are designated a..x, with a=0 and b variable.
+        * In the id register c is the MSB but the OUI is conventionally
+        * written as bytes h..a, p..i, x..q.  Reorder the bits accordingly. */
+       for (i = 0; i < 22; ++i)
+               if (id & (1 << (i + 10)))
+                       oui |= 1 << (i ^ 7);
+
+       return oui;
+}
+
 int mdio_clause45_reset_mmd(struct efx_nic *port, int mmd,
                            int spins, int spintime)
 {
@@ -125,24 +140,25 @@ int mdio_clause45_wait_reset_mmds(struct efx_nic *efx,
 int mdio_clause45_check_mmds(struct efx_nic *efx,
                             unsigned int mmd_mask, unsigned int fatal_mask)
 {
+       int mmd = 0, probe_mmd, devs0, devs1;
        u32 devices;
-       int mmd = 0, probe_mmd;
 
        /* Historically we have probed the PHYXS to find out what devices are
         * present,but that doesn't work so well if the PHYXS isn't expected
         * to exist, if so just find the first item in the list supplied. */
        probe_mmd = (mmd_mask & MDIO_MMDREG_DEVS_PHYXS) ? MDIO_MMD_PHYXS :
            __ffs(mmd_mask);
-       devices = (mdio_clause45_read(efx, efx->mii.phy_id,
-                                     probe_mmd, MDIO_MMDREG_DEVS0) |
-                  mdio_clause45_read(efx, efx->mii.phy_id,
-                                     probe_mmd, MDIO_MMDREG_DEVS1) << 16);
 
        /* Check all the expected MMDs are present */
-       if (devices < 0) {
+       devs0 = mdio_clause45_read(efx, efx->mii.phy_id,
+                                  probe_mmd, MDIO_MMDREG_DEVS0);
+       devs1 = mdio_clause45_read(efx, efx->mii.phy_id,
+                                  probe_mmd, MDIO_MMDREG_DEVS1);
+       if (devs0 < 0 || devs1 < 0) {
                EFX_ERR(efx, "failed to read devices present\n");
                return -EIO;
        }
+       devices = devs0 | (devs1 << 16);
        if ((devices & mmd_mask) != mmd_mask) {
                EFX_ERR(efx, "required MMDs not present: got %x, "
                        "wanted %x\n", devices, mmd_mask);
index 8ba49773ce7e19a9f4b14ca319510b0eb0aff133..7014d2279c20f633977808647839681cfdfe7244 100644 (file)
 #define MDIO_MMDREG_STAT1_LPABLE_LBN   (1)
 #define MDIO_MMDREG_STAT1_LPABLE_WIDTH (1)
 
-/* Bits in ID reg */
-#define MDIO_ID_REV(_id32)     (_id32 & 0xf)
-#define MDIO_ID_MODEL(_id32)   ((_id32 >> 4) & 0x3f)
-#define MDIO_ID_OUI(_id32)     (_id32 >> 10)
+/* Bits in combined ID regs */
+static inline unsigned mdio_id_rev(u32 id) { return id & 0xf; }
+static inline unsigned mdio_id_model(u32 id) { return (id >> 4) & 0x3f; }
+extern unsigned mdio_id_oui(u32 id);
 
 /* Bits in MMDREG_DEVS0/1. Someone thoughtfully layed things out
  * so the 'bit present' bit number of an MMD is the number of
index 665cafb88d6a087a190b0391497a681442109018..820c233c3ea0aa6037e5d00405c3604526baf2a2 100644 (file)
@@ -15,6 +15,7 @@
 #define EFX_DRIVER_NAME "sfc_mtd"
 #include "net_driver.h"
 #include "spi.h"
+#include "efx.h"
 
 #define EFX_SPI_VERIFY_BUF_LEN 16
 
index 19930ff9df7b71dceebbb4712a9d96cbaaf5f464..e169e5dcd1e63cc2f0f39cfb11d2975271b2f8f3 100644 (file)
@@ -336,6 +336,8 @@ enum efx_rx_alloc_method {
  * @eventq_read_ptr: Event queue read pointer
  * @last_eventq_read_ptr: Last event queue read pointer value.
  * @eventq_magic: Event queue magic value for driver-generated test events
+ * @irq_count: Number of IRQs since last adaptive moderation decision
+ * @irq_mod_score: IRQ moderation score
  * @rx_alloc_level: Watermark based heuristic counter for pushing descriptors
  *     and diagnostic counters
  * @rx_alloc_push_pages: RX allocation method currently in use for pushing
@@ -364,6 +366,9 @@ struct efx_channel {
        unsigned int last_eventq_read_ptr;
        unsigned int eventq_magic;
 
+       unsigned int irq_count;
+       unsigned int irq_mod_score;
+
        int rx_alloc_level;
        int rx_alloc_push_pages;
 
@@ -385,13 +390,11 @@ struct efx_channel {
 
 /**
  * struct efx_blinker - S/W LED blinking context
- * @led_num: LED ID (board-specific meaning)
  * @state: Current state - on or off
  * @resubmit: Timer resubmission flag
  * @timer: Control timer for blinking
  */
 struct efx_blinker {
-       int led_num;
        bool state;
        bool resubmit;
        struct timer_list timer;
@@ -404,8 +407,8 @@ struct efx_blinker {
  * @major: Major rev. ('A', 'B' ...)
  * @minor: Minor rev. (0, 1, ...)
  * @init: Initialisation function
- * @init_leds: Sets up board LEDs
- * @set_fault_led: Turns the fault LED on or off
+ * @init_leds: Sets up board LEDs. May be called repeatedly.
+ * @set_id_led: Turns the identification LED on or off
  * @blink: Starts/stops blinking
  * @monitor: Board-specific health check function
  * @fini: Cleanup function
@@ -421,9 +424,9 @@ struct efx_board {
        /* As the LEDs are typically attached to the PHY, LEDs
         * have a separate init callback that happens later than
         * board init. */
-       int (*init_leds)(struct efx_nic *efx);
+       void (*init_leds)(struct efx_nic *efx);
+       void (*set_id_led) (struct efx_nic *efx, bool state);
        int (*monitor) (struct efx_nic *nic);
-       void (*set_fault_led) (struct efx_nic *efx, bool state);
        void (*blink) (struct efx_nic *efx, bool start);
        void (*fini) (struct efx_nic *nic);
        struct efx_blinker blinker;
@@ -450,6 +453,7 @@ enum phy_type {
        PHY_TYPE_QT2022C2 = 4,
        PHY_TYPE_PM8358 = 6,
        PHY_TYPE_SFT9001A = 8,
+       PHY_TYPE_QT2025C = 9,
        PHY_TYPE_SFT9001B = 10,
        PHY_TYPE_MAX    /* Insert any new items before this */
 };
@@ -704,6 +708,8 @@ union efx_multicast_hash {
  * @membase: Memory BAR value
  * @biu_lock: BIU (bus interface unit) lock
  * @interrupt_mode: Interrupt mode
+ * @irq_rx_adaptive: Adaptive IRQ moderation enabled for RX event queues
+ * @irq_rx_moderation: IRQ moderation time for RX event queues
  * @i2c_adap: I2C adapter
  * @board_info: Board-level information
  * @state: Device state flag. Serialised by the rtnl_lock.
@@ -785,6 +791,8 @@ struct efx_nic {
        void __iomem *membase;
        spinlock_t biu_lock;
        enum efx_int_mode interrupt_mode;
+       bool irq_rx_adaptive;
+       unsigned int irq_rx_moderation;
 
        struct i2c_adapter i2c_adap;
        struct efx_board board_info;
index 07e855c148bc3ce6c0eb409ff1cc87ad5e8faf84..c1cff9c0c17331db7462af39bd96ec1866406788 100644 (file)
@@ -18,12 +18,16 @@ extern struct efx_phy_operations falcon_sft9001_phy_ops;
 
 extern void tenxpress_phy_blink(struct efx_nic *efx, bool blink);
 
+/* Wait for the PHY to boot. Return 0 on success, -EINVAL if the PHY failed
+ * to boot due to corrupt flash, or some other negative error code. */
+extern int sft9001_wait_boot(struct efx_nic *efx);
+
 /****************************************************************************
- * Exported functions from the driver for XFP optical PHYs
+ * AMCC/Quake QT20xx PHYs
  */
 extern struct efx_phy_operations falcon_xfp_phy_ops;
 
-/* The QUAKE XFP PHY provides various H/W control states for LEDs */
+/* These PHYs provide various H/W control states for LEDs */
 #define QUAKE_LED_LINK_INVAL   (0)
 #define QUAKE_LED_LINK_STAT    (1)
 #define QUAKE_LED_LINK_ACT     (2)
index c0e90683162339570a03154b14ae0a46e1ce4855..4eac5da81e5aeab2816222235be680cc6d3607ac 100644 (file)
@@ -399,6 +399,7 @@ static struct i2c_board_info sfn4111t_r5_hwmon_info = {
 
 int sfn4111t_init(struct efx_nic *efx)
 {
+       int i = 0;
        int rc;
 
        efx->board_info.hwmon_client =
@@ -417,13 +418,20 @@ int sfn4111t_init(struct efx_nic *efx)
        if (rc)
                goto fail_hwmon;
 
-       if (efx->phy_mode & PHY_MODE_SPECIAL) {
-               efx_stats_disable(efx);
-               sfn4111t_reset(efx);
-       }
-
-       return 0;
+       do {
+               if (efx->phy_mode & PHY_MODE_SPECIAL) {
+                       /* PHY may not generate a 156.25 MHz clock and MAC
+                        * stats fetch will fail. */
+                       efx_stats_disable(efx);
+                       sfn4111t_reset(efx);
+               }
+               rc = sft9001_wait_boot(efx);
+               if (rc == 0)
+                       return 0;
+               efx->phy_mode = PHY_MODE_SPECIAL;
+       } while (rc == -EINVAL && ++i < 2);
 
+       device_remove_file(&efx->pci_dev->dev, &dev_attr_phy_flash_cfg);
 fail_hwmon:
        i2c_unregister_device(efx->board_info.hwmon_client);
        return rc;
index 5b0f45166628161e6a225b39137d336e50266d93..e61dc4d4741c973d59ce4c33c7d332eb0a5fa6fa 100644 (file)
 #define PCS_10GBASET_BLKLK_WIDTH 1
 
 /* Boot status register */
-#define PCS_BOOT_STATUS_REG    53248
-#define PCS_BOOT_FATAL_ERR_LBN (0)
-#define PCS_BOOT_PROGRESS_LBN  (1)
-#define PCS_BOOT_PROGRESS_WIDTH        (2)
-#define PCS_BOOT_COMPLETE_LBN  (3)
-
-#define PCS_BOOT_MAX_DELAY     (100)
-#define PCS_BOOT_POLL_DELAY    (10)
+#define PCS_BOOT_STATUS_REG            53248
+#define PCS_BOOT_FATAL_ERROR_LBN       0
+#define PCS_BOOT_PROGRESS_LBN          1
+#define PCS_BOOT_PROGRESS_WIDTH                2
+#define PCS_BOOT_PROGRESS_INIT         0
+#define PCS_BOOT_PROGRESS_WAIT_MDIO    1
+#define PCS_BOOT_PROGRESS_CHECKSUM     2
+#define PCS_BOOT_PROGRESS_JUMP         3
+#define PCS_BOOT_DOWNLOAD_WAIT_LBN     3
+#define PCS_BOOT_CODE_STARTED_LBN      4
 
 /* 100M/1G PHY registers */
 #define GPHY_XCONTROL_REG      49152
@@ -230,40 +232,62 @@ static ssize_t set_phy_short_reach(struct device *dev,
 static DEVICE_ATTR(phy_short_reach, 0644, show_phy_short_reach,
                   set_phy_short_reach);
 
-/* Check that the C166 has booted successfully */
-static int tenxpress_phy_check(struct efx_nic *efx)
+int sft9001_wait_boot(struct efx_nic *efx)
 {
-       int phy_id = efx->mii.phy_id;
-       int count = PCS_BOOT_MAX_DELAY / PCS_BOOT_POLL_DELAY;
+       unsigned long timeout = jiffies + HZ + 1;
        int boot_stat;
 
-       /* Wait for the boot to complete (or not) */
-       while (count) {
-               boot_stat = mdio_clause45_read(efx, phy_id,
+       for (;;) {
+               boot_stat = mdio_clause45_read(efx, efx->mii.phy_id,
                                               MDIO_MMD_PCS,
                                               PCS_BOOT_STATUS_REG);
-               if (boot_stat & (1 << PCS_BOOT_COMPLETE_LBN))
-                       break;
-               count--;
-               udelay(PCS_BOOT_POLL_DELAY);
-       }
+               if (boot_stat >= 0) {
+                       EFX_LOG(efx, "PHY boot status = %#x\n", boot_stat);
+                       switch (boot_stat &
+                               ((1 << PCS_BOOT_FATAL_ERROR_LBN) |
+                                (3 << PCS_BOOT_PROGRESS_LBN) |
+                                (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN) |
+                                (1 << PCS_BOOT_CODE_STARTED_LBN))) {
+                       case ((1 << PCS_BOOT_FATAL_ERROR_LBN) |
+                             (PCS_BOOT_PROGRESS_CHECKSUM <<
+                              PCS_BOOT_PROGRESS_LBN)):
+                       case ((1 << PCS_BOOT_FATAL_ERROR_LBN) |
+                             (PCS_BOOT_PROGRESS_INIT <<
+                              PCS_BOOT_PROGRESS_LBN) |
+                             (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN)):
+                               return -EINVAL;
+                       case ((PCS_BOOT_PROGRESS_WAIT_MDIO <<
+                              PCS_BOOT_PROGRESS_LBN) |
+                             (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN)):
+                               return (efx->phy_mode & PHY_MODE_SPECIAL) ?
+                                       0 : -EIO;
+                       case ((PCS_BOOT_PROGRESS_JUMP <<
+                              PCS_BOOT_PROGRESS_LBN) |
+                             (1 << PCS_BOOT_CODE_STARTED_LBN)):
+                       case ((PCS_BOOT_PROGRESS_JUMP <<
+                              PCS_BOOT_PROGRESS_LBN) |
+                             (1 << PCS_BOOT_DOWNLOAD_WAIT_LBN) |
+                             (1 << PCS_BOOT_CODE_STARTED_LBN)):
+                               return (efx->phy_mode & PHY_MODE_SPECIAL) ?
+                                       -EIO : 0;
+                       default:
+                               if (boot_stat & (1 << PCS_BOOT_FATAL_ERROR_LBN))
+                                       return -EIO;
+                               break;
+                       }
+               }
 
-       if (!count) {
-               EFX_ERR(efx, "%s: PHY boot timed out. Last status "
-                       "%x\n", __func__,
-                       (boot_stat >> PCS_BOOT_PROGRESS_LBN) &
-                       ((1 << PCS_BOOT_PROGRESS_WIDTH) - 1));
-               return -ETIMEDOUT;
-       }
+               if (time_after_eq(jiffies, timeout))
+                       return -ETIMEDOUT;
 
-       return 0;
+               msleep(50);
+       }
 }
 
 static int tenxpress_init(struct efx_nic *efx)
 {
        int phy_id = efx->mii.phy_id;
        int reg;
-       int rc;
 
        if (efx->phy_type == PHY_TYPE_SFX7101) {
                /* Enable 312.5 MHz clock */
@@ -286,10 +310,6 @@ static int tenxpress_init(struct efx_nic *efx)
                                       false);
        }
 
-       rc = tenxpress_phy_check(efx);
-       if (rc < 0)
-               return rc;
-
        /* Set the LEDs up as: Green = Link, Amber = Link/Act, Red = Off */
        if (efx->phy_type == PHY_TYPE_SFX7101) {
                mdio_clause45_set_flag(efx, phy_id, MDIO_MMD_PMAPMD,
@@ -300,7 +320,7 @@ static int tenxpress_init(struct efx_nic *efx)
                                    PMA_PMD_LED_OVERR_REG, PMA_PMD_LED_DEFAULT);
        }
 
-       return rc;
+       return 0;
 }
 
 static int tenxpress_phy_init(struct efx_nic *efx)
@@ -679,12 +699,10 @@ static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags)
 {
        struct ethtool_cmd ecmd;
        int phy_id = efx->mii.phy_id;
-       int rc = 0, rc2, i, res_reg;
-
-       if (!(flags & ETH_TEST_FL_OFFLINE))
-               return 0;
+       int rc = 0, rc2, i, ctrl_reg, res_reg;
 
-       efx->phy_op->get_settings(efx, &ecmd);
+       if (flags & ETH_TEST_FL_OFFLINE)
+               efx->phy_op->get_settings(efx, &ecmd);
 
        /* Initialise cable diagnostic results to unknown failure */
        for (i = 1; i < 9; ++i)
@@ -692,18 +710,22 @@ static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags)
 
        /* Run cable diagnostics; wait up to 5 seconds for them to complete.
         * A cable fault is not a self-test failure, but a timeout is. */
+       ctrl_reg = ((1 << CDIAG_CTRL_IMMED_LBN) |
+                   (CDIAG_CTRL_LEN_METRES << CDIAG_CTRL_LEN_UNIT_LBN));
+       if (flags & ETH_TEST_FL_OFFLINE) {
+               /* Break the link in order to run full diagnostics.  We
+                * must reset the PHY to resume normal service. */
+               ctrl_reg |= (1 << CDIAG_CTRL_BRK_LINK_LBN);
+       }
        mdio_clause45_write(efx, phy_id, MDIO_MMD_PMAPMD,
-                           PMA_PMD_CDIAG_CTRL_REG,
-                           (1 << CDIAG_CTRL_IMMED_LBN) |
-                           (1 << CDIAG_CTRL_BRK_LINK_LBN) |
-                           (CDIAG_CTRL_LEN_METRES << CDIAG_CTRL_LEN_UNIT_LBN));
+                           PMA_PMD_CDIAG_CTRL_REG, ctrl_reg);
        i = 0;
        while (mdio_clause45_read(efx, phy_id, MDIO_MMD_PMAPMD,
                                  PMA_PMD_CDIAG_CTRL_REG) &
               (1 << CDIAG_CTRL_IN_PROG_LBN)) {
                if (++i == 50) {
                        rc = -ETIMEDOUT;
-                       goto reset;
+                       goto out;
                }
                msleep(100);
        }
@@ -728,17 +750,18 @@ static int sft9001_run_tests(struct efx_nic *efx, int *results, unsigned flags)
                        results[5 + i] = len_reg;
        }
 
-       /* We must reset to exit cable diagnostic mode.  The BIST will
-        * also run when we do this. */
-reset:
-       rc2 = tenxpress_special_reset(efx);
-       results[0] = rc2 ? -1 : 1;
-       if (!rc)
-               rc = rc2;
-
-       rc2 = efx->phy_op->set_settings(efx, &ecmd);
-       if (!rc)
-               rc = rc2;
+out:
+       if (flags & ETH_TEST_FL_OFFLINE) {
+               /* Reset, running the BIST and then resuming normal service. */
+               rc2 = tenxpress_special_reset(efx);
+               results[0] = rc2 ? -1 : 1;
+               if (!rc)
+                       rc = rc2;
+
+               rc2 = efx->phy_op->set_settings(efx, &ecmd);
+               if (!rc)
+                       rc = rc2;
+       }
 
        return rc;
 }
index da3e9ff339f5e26c36b070042d86ae5810639b99..d6681edb7014d799e92ab3978abe2e38c6fd664a 100644 (file)
@@ -162,6 +162,14 @@ static int efx_enqueue_skb(struct efx_tx_queue *tx_queue,
        /* Get size of the initial fragment */
        len = skb_headlen(skb);
 
+       /* Pad if necessary */
+       if (EFX_WORKAROUND_15592(efx) && skb->len <= 32) {
+               EFX_BUG_ON_PARANOID(skb->data_len);
+               len = 32 + 1;
+               if (skb_pad(skb, len - skb->len))
+                       return NETDEV_TX_OK;
+       }
+
        fill_level = tx_queue->insert_count - tx_queue->old_read_count;
        q_space = efx->type->txd_ring_mask - 1 - fill_level;
 
@@ -376,6 +384,9 @@ int efx_hard_start_xmit(struct sk_buff *skb, struct net_device *net_dev)
        struct efx_nic *efx = netdev_priv(net_dev);
        struct efx_tx_queue *tx_queue;
 
+       if (unlikely(efx->port_inhibited))
+               return NETDEV_TX_BUSY;
+
        if (likely(skb->ip_summed == CHECKSUM_PARTIAL))
                tx_queue = &efx->tx_queue[EFX_TX_QUEUE_OFFLOAD_CSUM];
        else
@@ -397,7 +408,7 @@ void efx_xmit_done(struct efx_tx_queue *tx_queue, unsigned int index)
         * separates the update of read_count from the test of
         * stopped. */
        smp_mb();
-       if (unlikely(tx_queue->stopped)) {
+       if (unlikely(tx_queue->stopped) && likely(efx->port_enabled)) {
                fill_level = tx_queue->insert_count - tx_queue->read_count;
                if (fill_level < EFX_NETDEV_TX_THRESHOLD(tx_queue)) {
                        EFX_BUG_ON_PARANOID(!efx_dev_registered(efx));
index 78de68f4a95b47a1c1712615db98cb5965dcb955..c821c15445a0f3f9f8b3a93d0c894ab14a352d96 100644 (file)
@@ -36,6 +36,8 @@
 #define EFX_WORKAROUND_11482 EFX_WORKAROUND_ALWAYS
 /* Flush events can take a very long time to appear */
 #define EFX_WORKAROUND_11557 EFX_WORKAROUND_ALWAYS
+/* Truncated IPv4 packets can confuse the TX packet parser */
+#define EFX_WORKAROUND_15592 EFX_WORKAROUND_ALWAYS
 
 /* Spurious parity errors in TSORT buffers */
 #define EFX_WORKAROUND_5129 EFX_WORKAROUND_FALCON_A
index 2d50b6ecf5f9e92b87330dc574f12dbf3741b560..bb1ef77d5f56e5b7fcf72533f4bc66db00cdb8ae 100644 (file)
@@ -7,8 +7,8 @@
  * by the Free Software Foundation, incorporated herein by reference.
  */
 /*
- * Driver for XFP optical PHYs (plus some support specific to the Quake 2022/32)
- * See www.amcc.com for details (search for qt2032)
+ * Driver for SFP+ and XFP optical PHYs plus some support specific to the
+ * AMCC QT20xx adapters; see www.amcc.com for details
  */
 
 #include <linux/timer.h>
 /* Quake-specific MDIO registers */
 #define MDIO_QUAKE_LED0_REG    (0xD006)
 
+/* QT2025C only */
+#define PCS_FW_HEARTBEAT_REG   0xd7ee
+#define PCS_FW_HEARTB_LBN      0
+#define PCS_FW_HEARTB_WIDTH    8
+#define PCS_UC8051_STATUS_REG  0xd7fd
+#define PCS_UC_STATUS_LBN      0
+#define PCS_UC_STATUS_WIDTH    8
+#define PCS_UC_STATUS_FW_SAVE  0x20
+#define PMA_PMD_FTX_CTRL2_REG  0xc309
+#define PMA_PMD_FTX_STATIC_LBN 13
+#define PMA_PMD_VEND1_REG      0xc001
+#define PMA_PMD_VEND1_LBTXD_LBN        15
+#define PCS_VEND1_REG          0xc000
+#define PCS_VEND1_LBTXD_LBN    5
+
 void xfp_set_led(struct efx_nic *p, int led, int mode)
 {
        int addr = MDIO_QUAKE_LED0_REG + led;
@@ -45,7 +60,49 @@ struct xfp_phy_data {
 #define XFP_MAX_RESET_TIME 500
 #define XFP_RESET_WAIT 10
 
-/* Reset the PHYXS MMD. This is documented (for the Quake PHY) as doing
+static int qt2025c_wait_reset(struct efx_nic *efx)
+{
+       unsigned long timeout = jiffies + 10 * HZ;
+       int phy_id = efx->mii.phy_id;
+       int reg, old_counter = 0;
+
+       /* Wait for firmware heartbeat to start */
+       for (;;) {
+               int counter;
+               reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS,
+                                        PCS_FW_HEARTBEAT_REG);
+               if (reg < 0)
+                       return reg;
+               counter = ((reg >> PCS_FW_HEARTB_LBN) &
+                           ((1 << PCS_FW_HEARTB_WIDTH) - 1));
+               if (old_counter == 0)
+                       old_counter = counter;
+               else if (counter != old_counter)
+                       break;
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+               msleep(10);
+       }
+
+       /* Wait for firmware status to look good */
+       for (;;) {
+               reg = mdio_clause45_read(efx, phy_id, MDIO_MMD_PCS,
+                                        PCS_UC8051_STATUS_REG);
+               if (reg < 0)
+                       return reg;
+               if ((reg &
+                    ((1 << PCS_UC_STATUS_WIDTH) - 1) << PCS_UC_STATUS_LBN) >=
+                   PCS_UC_STATUS_FW_SAVE)
+                       break;
+               if (time_after(jiffies, timeout))
+                       return -ETIMEDOUT;
+               msleep(100);
+       }
+
+       return 0;
+}
+
+/* Reset the PHYXS MMD. This is documented (for the Quake PHYs) as doing
  * a complete soft reset.
  */
 static int xfp_reset_phy(struct efx_nic *efx)
@@ -58,6 +115,12 @@ static int xfp_reset_phy(struct efx_nic *efx)
        if (rc < 0)
                goto fail;
 
+       if (efx->phy_type == PHY_TYPE_QT2025C) {
+               rc = qt2025c_wait_reset(efx);
+               if (rc < 0)
+                       goto fail;
+       }
+
        /* Wait 250ms for the PHY to complete bootup */
        msleep(250);
 
@@ -73,7 +136,7 @@ static int xfp_reset_phy(struct efx_nic *efx)
        return rc;
 
  fail:
-       EFX_ERR(efx, "XFP: reset timed out!\n");
+       EFX_ERR(efx, "PHY reset timed out\n");
        return rc;
 }
 
@@ -88,15 +151,15 @@ static int xfp_phy_init(struct efx_nic *efx)
                return -ENOMEM;
        efx->phy_data = phy_data;
 
-       EFX_INFO(efx, "XFP: PHY ID reg %x (OUI %x model %x revision"
-                " %x)\n", devid, MDIO_ID_OUI(devid), MDIO_ID_MODEL(devid),
-                MDIO_ID_REV(devid));
+       EFX_INFO(efx, "PHY ID reg %x (OUI %06x model %02x revision %x)\n",
+                devid, mdio_id_oui(devid), mdio_id_model(devid),
+                mdio_id_rev(devid));
 
        phy_data->phy_mode = efx->phy_mode;
 
        rc = xfp_reset_phy(efx);
 
-       EFX_INFO(efx, "XFP: PHY init %s.\n",
+       EFX_INFO(efx, "PHY init %s.\n",
                 rc ? "failed" : "successful");
        if (rc < 0)
                goto fail;
@@ -131,12 +194,28 @@ static void xfp_phy_reconfigure(struct efx_nic *efx)
 {
        struct xfp_phy_data *phy_data = efx->phy_data;
 
-       /* Reset the PHY when moving from tx off to tx on */
-       if (!(efx->phy_mode & PHY_MODE_TX_DISABLED) &&
-           (phy_data->phy_mode & PHY_MODE_TX_DISABLED))
-               xfp_reset_phy(efx);
+       if (efx->phy_type == PHY_TYPE_QT2025C) {
+               /* There are several different register bits which can
+                * disable TX (and save power) on direct-attach cables
+                * or optical transceivers, varying somewhat between
+                * firmware versions.  Only 'static mode' appears to
+                * cover everything. */
+               mdio_clause45_set_flag(
+                       efx, efx->mii.phy_id, MDIO_MMD_PMAPMD,
+                       PMA_PMD_FTX_CTRL2_REG, PMA_PMD_FTX_STATIC_LBN,
+                       efx->phy_mode & PHY_MODE_TX_DISABLED ||
+                       efx->phy_mode & PHY_MODE_LOW_POWER ||
+                       efx->loopback_mode == LOOPBACK_PCS ||
+                       efx->loopback_mode == LOOPBACK_PMAPMD);
+       } else {
+               /* Reset the PHY when moving from tx off to tx on */
+               if (!(efx->phy_mode & PHY_MODE_TX_DISABLED) &&
+                   (phy_data->phy_mode & PHY_MODE_TX_DISABLED))
+                       xfp_reset_phy(efx);
+
+               mdio_clause45_transmit_disable(efx);
+       }
 
-       mdio_clause45_transmit_disable(efx);
        mdio_clause45_phy_reconfigure(efx);
 
        phy_data->phy_mode = efx->phy_mode;
index 7f8e514eb5e9653613383bfe515afea8240e37f0..7b1882765a0cc4647e7fd3448c35d26b544525e6 100644 (file)
@@ -687,6 +687,7 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
 {
        struct net_device *ndev = netdev;
        struct sh_eth_private *mdp = netdev_priv(ndev);
+       irqreturn_t ret = IRQ_NONE;
        u32 ioaddr, boguscnt = RX_RING_SIZE;
        u32 intr_status = 0;
 
@@ -696,7 +697,13 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
        /* Get interrpt stat */
        intr_status = ctrl_inl(ioaddr + EESR);
        /* Clear interrupt */
-       ctrl_outl(intr_status, ioaddr + EESR);
+       if (intr_status & (EESR_FRC | EESR_RMAF | EESR_RRF |
+                       EESR_RTLF | EESR_RTSF | EESR_PRE | EESR_CERF |
+                       TX_CHECK | EESR_ERR_CHECK)) {
+               ctrl_outl(intr_status, ioaddr + EESR);
+               ret = IRQ_HANDLED;
+       } else
+               goto other_irq;
 
        if (intr_status & (EESR_FRC | /* Frame recv*/
                        EESR_RMAF | /* Multi cast address recv*/
@@ -723,9 +730,10 @@ static irqreturn_t sh_eth_interrupt(int irq, void *netdev)
                       ndev->name, intr_status);
        }
 
+other_irq:
        spin_unlock(&mdp->lock);
 
-       return IRQ_HANDLED;
+       return ret;
 }
 
 static void sh_eth_timer(unsigned long data)
@@ -844,7 +852,13 @@ static int sh_eth_open(struct net_device *ndev)
        int ret = 0;
        struct sh_eth_private *mdp = netdev_priv(ndev);
 
-       ret = request_irq(ndev->irq, &sh_eth_interrupt, 0, ndev->name, ndev);
+       ret = request_irq(ndev->irq, &sh_eth_interrupt,
+#if defined(CONFIG_CPU_SUBTYPE_SH7763) || defined(CONFIG_CPU_SUBTYPE_SH7764)
+                               IRQF_SHARED,
+#else
+                               0,
+#endif
+                               ndev->name, ndev);
        if (ret) {
                printk(KERN_ERR "Can not assign IRQ number to %s\n", CARDNAME);
                return ret;
index 73bc7181cc1828cde13e1676634603e9898183e0..1537e13e623d5e650056de4453a4a3d9c8c5e25e 100644 (file)
@@ -43,8 +43,8 @@
 
 #define SH7763_SKB_ALIGN 32
 /* Chip Base Address */
-# define SH_TSU_ADDR  0xFFE01800
-# define ARSTR                   0xFFE01800
+# define SH_TSU_ADDR   0xFEE01800
+# define ARSTR                 SH_TSU_ADDR
 
 /* Chip Registers */
 /* E-DMAC */
index be4465bc0a693d642c23ec465e3ce0ad035ad625..8a70de72ea2cb8db4471d44299fb590e4dcd430c 100644 (file)
@@ -80,8 +80,8 @@
 #define SIS900_MODULE_NAME "sis900"
 #define SIS900_DRV_VERSION "v1.08.10 Apr. 2 2006"
 
-static char version[] __devinitdata =
-KERN_INFO "sis900.c: " SIS900_DRV_VERSION "\n";
+static const char version[] __devinitconst =
+       KERN_INFO "sis900.c: " SIS900_DRV_VERSION "\n";
 
 static int max_interrupt_work = 40;
 static int multicast_filter_limit = 128;
index 870b4c33f108d87b384b3fe46c506d4f1cb1107e..a45952e72018b472f112bc94aadc48fe76197c86 100644 (file)
   #define SMC_USE_16BIT                0
   #define SMC_USE_32BIT                1
   #define SMC_IRQ_SENSE                IRQF_TRIGGER_LOW
+#elif defined(CONFIG_ARCH_OMAP34XX)
+  #define SMC_USE_16BIT                0
+  #define SMC_USE_32BIT                1
+  #define SMC_IRQ_SENSE                IRQF_TRIGGER_LOW
+  #define SMC_MEM_RESERVED     1
+#elif defined(CONFIG_ARCH_OMAP24XX)
+  #define SMC_USE_16BIT                0
+  #define SMC_USE_32BIT                1
+  #define SMC_IRQ_SENSE                IRQF_TRIGGER_LOW
+  #define SMC_MEM_RESERVED     1
 #else
 /*
  * Default configuration
@@ -675,6 +685,7 @@ smc_pxa_dma_outsl(struct smc911x_local *lp, u_long physaddr,
 #define CHIP_9116      0x0116
 #define CHIP_9117      0x0117
 #define CHIP_9118      0x0118
+#define CHIP_9211      0x9211
 #define CHIP_9215      0x115A
 #define CHIP_9217      0x117A
 #define CHIP_9218      0x118A
@@ -689,6 +700,7 @@ static const struct chip_id chip_ids[] =  {
        { CHIP_9116, "LAN9116" },
        { CHIP_9117, "LAN9117" },
        { CHIP_9118, "LAN9118" },
+       { CHIP_9211, "LAN9211" },
        { CHIP_9215, "LAN9215" },
        { CHIP_9217, "LAN9217" },
        { CHIP_9218, "LAN9218" },
index 6e175e5555a11a89812af87989657c1264e006f8..ad3cbc91a8fa6f45ee2a51cdc2d4014d8483fca6 100644 (file)
@@ -895,22 +895,22 @@ static void smsc911x_tx_update_txcounters(struct net_device *dev)
                        SMSC_WARNING(HW,
                                "Packet tag reserved bit is high");
                } else {
-                       if (unlikely(tx_stat & 0x00008000)) {
+                       if (unlikely(tx_stat & TX_STS_ES_)) {
                                dev->stats.tx_errors++;
                        } else {
                                dev->stats.tx_packets++;
                                dev->stats.tx_bytes += (tx_stat >> 16);
                        }
-                       if (unlikely(tx_stat & 0x00000100)) {
+                       if (unlikely(tx_stat & TX_STS_EXCESS_COL_)) {
                                dev->stats.collisions += 16;
                                dev->stats.tx_aborted_errors += 1;
                        } else {
                                dev->stats.collisions +=
                                    ((tx_stat >> 3) & 0xF);
                        }
-                       if (unlikely(tx_stat & 0x00000800))
+                       if (unlikely(tx_stat & TX_STS_LOST_CARRIER_))
                                dev->stats.tx_carrier_errors += 1;
-                       if (unlikely(tx_stat & 0x00000200)) {
+                       if (unlikely(tx_stat & TX_STS_LATE_COL_)) {
                                dev->stats.collisions++;
                                dev->stats.tx_aborted_errors++;
                        }
@@ -924,19 +924,17 @@ smsc911x_rx_counterrors(struct net_device *dev, unsigned int rxstat)
 {
        int crc_err = 0;
 
-       if (unlikely(rxstat & 0x00008000)) {
+       if (unlikely(rxstat & RX_STS_ES_)) {
                dev->stats.rx_errors++;
-               if (unlikely(rxstat & 0x00000002)) {
+               if (unlikely(rxstat & RX_STS_CRC_ERR_)) {
                        dev->stats.rx_crc_errors++;
                        crc_err = 1;
                }
        }
        if (likely(!crc_err)) {
-               if (unlikely((rxstat & 0x00001020) == 0x00001020)) {
-                       /* Frame type indicates length,
-                        * and length error is set */
+               if (unlikely((rxstat & RX_STS_FRAME_TYPE_) &&
+                            (rxstat & RX_STS_LENGTH_ERR_)))
                        dev->stats.rx_length_errors++;
-               }
                if (rxstat & RX_STS_MCAST_)
                        dev->stats.multicast++;
        }
@@ -955,7 +953,7 @@ smsc911x_rx_fastforward(struct smsc911x_data *pdata, unsigned int pktbytes)
                do {
                        udelay(1);
                        val = smsc911x_reg_read(pdata, RX_DP_CTRL);
-               } while (--timeout && (val & RX_DP_CTRL_RX_FFWD_));
+               } while ((val & RX_DP_CTRL_RX_FFWD_) && --timeout);
 
                if (unlikely(timeout == 0))
                        SMSC_WARNING(HW, "Timed out waiting for "
@@ -1121,7 +1119,7 @@ static int smsc911x_soft_reset(struct smsc911x_data *pdata)
 
 /* Sets the device MAC address to dev_addr, called with mac_lock held */
 static void
-smsc911x_set_mac_address(struct smsc911x_data *pdata, u8 dev_addr[6])
+smsc911x_set_hw_mac_address(struct smsc911x_data *pdata, u8 dev_addr[6])
 {
        u32 mac_high16 = (dev_addr[5] << 8) | dev_addr[4];
        u32 mac_low32 = (dev_addr[3] << 24) | (dev_addr[2] << 16) |
@@ -1162,8 +1160,8 @@ static int smsc911x_open(struct net_device *dev)
 
        /* Make sure EEPROM has finished loading before setting GPIO_CFG */
        timeout = 50;
-       while ((timeout--) &&
-              (smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_)) {
+       while ((smsc911x_reg_read(pdata, E2P_CMD) & E2P_CMD_EPC_BUSY_) &&
+              --timeout) {
                udelay(10);
        }
 
@@ -1176,7 +1174,7 @@ static int smsc911x_open(struct net_device *dev)
        /* The soft reset above cleared the device's MAC address,
         * restore it from local copy (set in probe) */
        spin_lock_irq(&pdata->mac_lock);
-       smsc911x_set_mac_address(pdata, dev->dev_addr);
+       smsc911x_set_hw_mac_address(pdata, dev->dev_addr);
        spin_unlock_irq(&pdata->mac_lock);
 
        /* Initialise irqs, but leave all sources disabled */
@@ -1227,6 +1225,10 @@ static int smsc911x_open(struct net_device *dev)
        dev_info(&dev->dev, "SMSC911x/921x identified at %#08lx, IRQ: %d\n",
                 (unsigned long)pdata->ioaddr, dev->irq);
 
+       /* Reset the last known duplex and carrier */
+       pdata->last_duplex = -1;
+       pdata->last_carrier = -1;
+
        /* Bring the PHY up */
        phy_start(pdata->phy_dev);
 
@@ -1506,6 +1508,31 @@ static void smsc911x_poll_controller(struct net_device *dev)
 }
 #endif                         /* CONFIG_NET_POLL_CONTROLLER */
 
+static int smsc911x_set_mac_address(struct net_device *dev, void *p)
+{
+       struct smsc911x_data *pdata = netdev_priv(dev);
+       struct sockaddr *addr = p;
+
+       /* On older hardware revisions we cannot change the mac address
+        * registers while receiving data.  Newer devices can safely change
+        * this at any time. */
+       if (pdata->generation <= 1 && netif_running(dev))
+               return -EBUSY;
+
+       if (!is_valid_ether_addr(addr->sa_data))
+               return -EADDRNOTAVAIL;
+
+       memcpy(dev->dev_addr, addr->sa_data, ETH_ALEN);
+
+       spin_lock_irq(&pdata->mac_lock);
+       smsc911x_set_hw_mac_address(pdata, dev->dev_addr);
+       spin_unlock_irq(&pdata->mac_lock);
+
+       dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr);
+
+       return 0;
+}
+
 /* Standard ioctls for mii-tool */
 static int smsc911x_do_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 {
@@ -1619,7 +1646,7 @@ static int smsc911x_eeprom_send_cmd(struct smsc911x_data *pdata, u32 op)
        do {
                msleep(1);
                e2cmd = smsc911x_reg_read(pdata, E2P_CMD);
-       } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (timeout--));
+       } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (--timeout));
 
        if (!timeout) {
                SMSC_TRACE(DRV, "TIMED OUT");
@@ -1736,7 +1763,7 @@ static const struct net_device_ops smsc911x_netdev_ops = {
        .ndo_set_multicast_list = smsc911x_set_multicast_list,
        .ndo_do_ioctl           = smsc911x_do_ioctl,
        .ndo_validate_addr      = eth_validate_addr,
-       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_set_mac_address    = smsc911x_set_mac_address,
 #ifdef CONFIG_NET_POLL_CONTROLLER
        .ndo_poll_controller    = smsc911x_poll_controller,
 #endif
@@ -1912,7 +1939,6 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
        unsigned int intcfg = 0;
        int res_size, irq_flags;
        int retval;
-       DECLARE_MAC_BUF(mac);
 
        pr_info("%s: Driver version %s.\n", SMSC_CHIPNAME, SMSC_DRV_VERSION);
 
@@ -2025,7 +2051,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
 
        /* Check if mac address has been specified when bringing interface up */
        if (is_valid_ether_addr(dev->dev_addr)) {
-               smsc911x_set_mac_address(pdata, dev->dev_addr);
+               smsc911x_set_hw_mac_address(pdata, dev->dev_addr);
                SMSC_TRACE(PROBE, "MAC Address is specified by configuration");
        } else {
                /* Try reading mac address from device. if EEPROM is present
@@ -2039,7 +2065,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
                } else {
                        /* eeprom values are invalid, generate random MAC */
                        random_ether_addr(dev->dev_addr);
-                       smsc911x_set_mac_address(pdata, dev->dev_addr);
+                       smsc911x_set_hw_mac_address(pdata, dev->dev_addr);
                        SMSC_TRACE(PROBE,
                                "MAC Address is set to random_ether_addr");
                }
@@ -2047,8 +2073,7 @@ static int __devinit smsc911x_drv_probe(struct platform_device *pdev)
 
        spin_unlock_irq(&pdata->mac_lock);
 
-       dev_info(&dev->dev, "MAC Address: %s\n",
-                print_mac(mac, dev->dev_addr));
+       dev_info(&dev->dev, "MAC Address: %pM\n", dev->dev_addr);
 
        return 0;
 
index 2b76654bb958c665fb39fbe7a2b5bae225e61320..b5716bd8a59769874206b72cbe21df5c32de7104 100644 (file)
 
 #define RX_STATUS_FIFO                 0x40
 #define RX_STS_ES_                     0x00008000
+#define RX_STS_LENGTH_ERR_             0x00001000
 #define RX_STS_MCAST_                  0x00000400
+#define RX_STS_FRAME_TYPE_             0x00000020
+#define RX_STS_CRC_ERR_                        0x00000002
 
 #define RX_STATUS_FIFO_PEEK            0x44
 
 #define TX_STATUS_FIFO                 0x48
 #define TX_STS_ES_                     0x00008000
+#define TX_STS_LOST_CARRIER_           0x00000800
+#define TX_STS_NO_CARRIER_             0x00000400
+#define TX_STS_LATE_COL_               0x00000200
+#define TX_STS_EXCESS_COL_             0x00000100
 
 #define TX_STATUS_FIFO_PEEK            0x4C
 
index da8b977a5357338e039384a25ee885db535c1877..5959ae86e57dd6575f44c94baab0b02c693fa7c4 100644 (file)
@@ -341,7 +341,7 @@ static int smsc9420_eeprom_send_cmd(struct smsc9420_pdata *pd, u32 op)
        do {
                msleep(1);
                e2cmd = smsc9420_reg_read(pd, E2P_CMD);
-       } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (timeout--));
+       } while ((e2cmd & E2P_CMD_EPC_BUSY_) && (--timeout));
 
        if (!timeout) {
                smsc_info(HW, "TIMED OUT");
@@ -413,6 +413,7 @@ static int smsc9420_ethtool_get_eeprom(struct net_device *dev,
        }
 
        memcpy(data, &eeprom_data[eeprom->offset], len);
+       eeprom->magic = SMSC9420_EEPROM_MAGIC;
        eeprom->len = len;
        return 0;
 }
@@ -423,6 +424,9 @@ static int smsc9420_ethtool_set_eeprom(struct net_device *dev,
        struct smsc9420_pdata *pd = netdev_priv(dev);
        int ret;
 
+       if (eeprom->magic != SMSC9420_EEPROM_MAGIC)
+               return -EINVAL;
+
        smsc9420_eeprom_enable_access(pd);
        smsc9420_eeprom_send_cmd(pd, E2P_CMD_EPC_CMD_EWEN_);
        ret = smsc9420_eeprom_write_location(pd, eeprom->offset, *data);
@@ -803,7 +807,7 @@ static void smsc9420_rx_handoff(struct smsc9420_pdata *pd, const int index,
        if (pd->rx_csum) {
                u16 hw_csum = get_unaligned_le16(skb_tail_pointer(skb) +
                        NET_IP_ALIGN + packet_length + 4);
-               put_unaligned_le16(cpu_to_le16(hw_csum), &skb->csum);
+               put_unaligned_le16(hw_csum, &skb->csum);
                skb->ip_summed = CHECKSUM_COMPLETE;
        }
 
index 69c351f93f86cd3c531121411215ca692061c8b2..e441402f77a2e3134d888dd7c1cb49402f27e3d7 100644 (file)
@@ -44,6 +44,7 @@
 #define LAN_REGISTER_EXTENT            (0x400)
 
 #define SMSC9420_EEPROM_SIZE           ((u32)11)
+#define SMSC9420_EEPROM_MAGIC          (0x9420)
 
 #define PKT_BUF_SZ                     (VLAN_ETH_FRAME_LEN + NET_IP_ALIGN + 4)
 
index 7f6b4a4052eed1ef5e46a3cfcdea456fe636cc46..90e663f4515c1ad4a89338f9922497a4daa76ed0 100644 (file)
@@ -2259,6 +2259,23 @@ spider_net_tx_timeout(struct net_device *netdev)
        card->spider_stats.tx_timeouts++;
 }
 
+static const struct net_device_ops spider_net_ops = {
+       .ndo_open               = spider_net_open,
+       .ndo_stop               = spider_net_stop,
+       .ndo_start_xmit         = spider_net_xmit,
+       .ndo_set_multicast_list = spider_net_set_multi,
+       .ndo_set_mac_address    = spider_net_set_mac,
+       .ndo_change_mtu         = spider_net_change_mtu,
+       .ndo_do_ioctl           = spider_net_do_ioctl,
+       .ndo_tx_timeout         = spider_net_tx_timeout,
+       .ndo_validate_addr      = eth_validate_addr,
+       /* HW VLAN */
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       /* poll controller */
+       .ndo_poll_controller    = spider_net_poll_controller,
+#endif /* CONFIG_NET_POLL_CONTROLLER */
+};
+
 /**
  * spider_net_setup_netdev_ops - initialization of net_device operations
  * @netdev: net_device structure
@@ -2268,21 +2285,8 @@ spider_net_tx_timeout(struct net_device *netdev)
 static void
 spider_net_setup_netdev_ops(struct net_device *netdev)
 {
-       netdev->open = &spider_net_open;
-       netdev->stop = &spider_net_stop;
-       netdev->hard_start_xmit = &spider_net_xmit;
-       netdev->set_multicast_list = &spider_net_set_multi;
-       netdev->set_mac_address = &spider_net_set_mac;
-       netdev->change_mtu = &spider_net_change_mtu;
-       netdev->do_ioctl = &spider_net_do_ioctl;
-       /* tx watchdog */
-       netdev->tx_timeout = &spider_net_tx_timeout;
+       netdev->netdev_ops = &spider_net_ops;
        netdev->watchdog_timeo = SPIDER_NET_WATCHDOG_TIMEOUT;
-       /* HW VLAN */
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       /* poll controller */
-       netdev->poll_controller = &spider_net_poll_controller;
-#endif /* CONFIG_NET_POLL_CONTROLLER */
        /* ethtool ops */
        netdev->ethtool_ops = &spider_net_ethtool_ops;
 }
index 98fe79515bab97bf2f8ff8d60d5ba35c94a4fa35..fcb943fca4f128716312257bbbb6e26a1cebc40e 100644 (file)
@@ -178,7 +178,7 @@ static int full_duplex[MAX_UNITS] = {0, };
 #define FIRMWARE_TX    "adaptec/starfire_tx.bin"
 
 /* These identify the driver base version and may not be removed. */
-static char version[] =
+static const char version[] __devinitconst =
 KERN_INFO "starfire.c:v1.03 7/26/2000  Written by Donald Becker <becker@scyld.com>\n"
 KERN_INFO " (unofficial 2.2/2.4 kernel port, version " DRV_VERSION ", " DRV_RELDATE ")\n";
 
index 7f69c7f176c457f7d6d46f58fda37ab7363c4b3a..5017d7fcb40cabc262b172d0603eef8b353d4b46 100644 (file)
@@ -1074,6 +1074,18 @@ static const struct ethtool_ops bigmac_ethtool_ops = {
        .get_link               = bigmac_get_link,
 };
 
+static const struct net_device_ops bigmac_ops = {
+       .ndo_open               = bigmac_open,
+       .ndo_stop               = bigmac_close,
+       .ndo_start_xmit         = bigmac_start_xmit,
+       .ndo_get_stats          = bigmac_get_stats,
+       .ndo_set_multicast_list = bigmac_set_multicast,
+       .ndo_tx_timeout         = bigmac_tx_timeout,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 static int __devinit bigmac_ether_init(struct of_device *op,
                                       struct of_device *qec_op)
 {
@@ -1187,16 +1199,8 @@ static int __devinit bigmac_ether_init(struct of_device *op,
        bp->dev = dev;
 
        /* Set links to our BigMAC open and close routines. */
-       dev->open = &bigmac_open;
-       dev->stop = &bigmac_close;
-       dev->hard_start_xmit = &bigmac_start_xmit;
        dev->ethtool_ops = &bigmac_ethtool_ops;
-
-       /* Set links to BigMAC statistic and multi-cast loading code. */
-       dev->get_stats = &bigmac_get_stats;
-       dev->set_multicast_list = &bigmac_set_multicast;
-
-       dev->tx_timeout = &bigmac_tx_timeout;
+       dev->netdev_ops = &bigmac_ops;
        dev->watchdog_timeo = 5*HZ;
 
        /* Finish net device registration. */
index feaf0e0577d77e9decc37972b72dd5ea44a4706f..c399b1955c1eec016a037e67059f57d2f3f8eebc 100644 (file)
@@ -109,8 +109,9 @@ static char *media[MAX_UNITS];
 #endif
 
 /* These identify the driver base version and may not be removed. */
-static char version[] =
-KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE "  Written by Donald Becker\n";
+static const char version[] __devinitconst =
+       KERN_INFO DRV_NAME ".c:v" DRV_VERSION " " DRV_RELDATE
+       " Written by Donald Becker\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("Sundance Alta Ethernet driver");
@@ -909,7 +910,7 @@ static void check_duplex(struct net_device *dev)
                        printk(KERN_INFO "%s: Setting %s-duplex based on MII #%d "
                                   "negotiated capability %4.4x.\n", dev->name,
                                   duplex ? "full" : "half", np->phys[0], negotiated);
-               iowrite16(ioread16(ioaddr + MACCtrl0) | duplex ? 0x20 : 0, ioaddr + MACCtrl0);
+               iowrite16(ioread16(ioaddr + MACCtrl0) | (duplex ? 0x20 : 0), ioaddr + MACCtrl0);
        }
 }
 
index 5322bb79b2b5347cbcb58ad6f5f90d8c45a59329..c024352c92fd24facec33736b5d9305272e931dc 100644 (file)
@@ -1157,7 +1157,7 @@ static void gem_pcs_reset(struct gem *gp)
                if (limit-- <= 0)
                        break;
        }
-       if (limit <= 0)
+       if (limit < 0)
                printk(KERN_WARNING "%s: PCS reset bit would not clear.\n",
                       gp->dev->name);
 }
@@ -1229,7 +1229,7 @@ static void gem_reset(struct gem *gp)
                        break;
        } while (val & (GREG_SWRST_TXRST | GREG_SWRST_RXRST));
 
-       if (limit <= 0)
+       if (limit < 0)
                printk(KERN_ERR "%s: SW reset is ghetto.\n", gp->dev->name);
 
        if (gp->phy_type == phy_serialink || gp->phy_type == phy_serdes)
@@ -2998,8 +2998,11 @@ static const struct net_device_ops gem_netdev_ops = {
        .ndo_do_ioctl           = gem_ioctl,
        .ndo_tx_timeout         = gem_tx_timeout,
        .ndo_change_mtu         = gem_change_mtu,
-       .ndo_set_mac_address    = eth_mac_addr,
        .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_mac_address    = gem_set_mac_address,
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       .ndo_poll_controller    = gem_poll_controller,
+#endif
 };
 
 static int __devinit gem_init_one(struct pci_dev *pdev,
@@ -3161,10 +3164,6 @@ static int __devinit gem_init_one(struct pci_dev *pdev,
        dev->watchdog_timeo = 5 * HZ;
        dev->irq = pdev->irq;
        dev->dma = 0;
-       dev->set_mac_address = gem_set_mac_address;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-       dev->poll_controller = gem_poll_controller;
-#endif
 
        /* Set that now, in case PM kicks in now */
        pci_set_drvdata(pdev, dev);
index 281373281756e381d24125eb841f903eda0a8286..afc7b351e5ec43a5723290ca7e958a08806bf544 100644 (file)
@@ -343,7 +343,7 @@ static void lance_init_ring_dvma(struct net_device *dev)
        ib->phys_addr [5] = dev->dev_addr [4];
 
        /* Setup the Tx ring entries */
-       for (i = 0; i <= TX_RING_SIZE; i++) {
+       for (i = 0; i < TX_RING_SIZE; i++) {
                leptr = LANCE_ADDR(aib + libbuff_offset(tx_buf, i));
                ib->btx_ring [i].tmd0      = leptr;
                ib->btx_ring [i].tmd1_hadr = leptr >> 16;
@@ -399,7 +399,7 @@ static void lance_init_ring_pio(struct net_device *dev)
        sbus_writeb(dev->dev_addr[4], &ib->phys_addr[5]);
 
        /* Setup the Tx ring entries */
-       for (i = 0; i <= TX_RING_SIZE; i++) {
+       for (i = 0; i < TX_RING_SIZE; i++) {
                leptr = libbuff_offset(tx_buf, i);
                sbus_writew(leptr,      &ib->btx_ring [i].tmd0);
                sbus_writeb(leptr >> 16,&ib->btx_ring [i].tmd1_hadr);
@@ -1311,6 +1311,17 @@ static const struct ethtool_ops sparc_lance_ethtool_ops = {
        .get_link               = sparc_lance_get_link,
 };
 
+static const struct net_device_ops sparc_lance_ops = {
+       .ndo_open               = lance_open,
+       .ndo_stop               = lance_close,
+       .ndo_start_xmit         = lance_start_xmit,
+       .ndo_set_multicast_list = lance_set_multicast,
+       .ndo_tx_timeout         = lance_tx_timeout,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 static int __devinit sparc_lance_probe_one(struct of_device *op,
                                           struct of_device *ledma,
                                           struct of_device *lebuffer)
@@ -1462,13 +1473,9 @@ no_link_test:
 
        lp->dev = dev;
        SET_NETDEV_DEV(dev, &op->dev);
-       dev->open = &lance_open;
-       dev->stop = &lance_close;
-       dev->hard_start_xmit = &lance_start_xmit;
-       dev->tx_timeout = &lance_tx_timeout;
        dev->watchdog_timeo = 5*HZ;
-       dev->set_multicast_list = &lance_set_multicast;
        dev->ethtool_ops = &sparc_lance_ethtool_ops;
+       dev->netdev_ops = &sparc_lance_ops;
 
        dev->irq = op->irqs[0];
 
index fe0c3f2445621cf2ae5b5625f8b805db8593afc0..c6ec61e0accfaa19f41e8bdb5c3ffdb6ad45de62 100644 (file)
@@ -829,6 +829,17 @@ fail:
        return NULL;
 }
 
+static const struct net_device_ops qec_ops = {
+       .ndo_open               = qe_open,
+       .ndo_stop               = qe_close,
+       .ndo_start_xmit         = qe_start_xmit,
+       .ndo_set_multicast_list = qe_set_multicast,
+       .ndo_tx_timeout         = qe_tx_timeout,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 static int __devinit qec_ether_init(struct of_device *op)
 {
        static unsigned version_printed;
@@ -893,15 +904,11 @@ static int __devinit qec_ether_init(struct of_device *op)
 
        SET_NETDEV_DEV(dev, &op->dev);
 
-       dev->open = qe_open;
-       dev->stop = qe_close;
-       dev->hard_start_xmit = qe_start_xmit;
-       dev->set_multicast_list = qe_set_multicast;
-       dev->tx_timeout = qe_tx_timeout;
        dev->watchdog_timeo = 5*HZ;
        dev->irq = op->irqs[0];
        dev->dma = 0;
        dev->ethtool_ops = &qe_ethtool_ops;
+       dev->netdev_ops = &qec_ops;
 
        res = register_netdev(dev);
        if (res)
index 611230fef2b67a6aa683191db70f19579e274fd5..a82fb2aca4cb7d89fe52e8bb31dfe4b6eacac505 100644 (file)
@@ -1012,6 +1012,16 @@ err_out:
 static LIST_HEAD(vnet_list);
 static DEFINE_MUTEX(vnet_list_mutex);
 
+static const struct net_device_ops vnet_ops = {
+       .ndo_open               = vnet_open,
+       .ndo_stop               = vnet_close,
+       .ndo_set_multicast_list = vnet_set_rx_mode,
+       .ndo_set_mac_address    = vnet_set_mac_addr,
+       .ndo_tx_timeout         = vnet_tx_timeout,
+       .ndo_change_mtu         = vnet_change_mtu,
+       .ndo_start_xmit         = vnet_start_xmit,
+};
+
 static struct vnet * __devinit vnet_new(const u64 *local_mac)
 {
        struct net_device *dev;
@@ -1040,15 +1050,9 @@ static struct vnet * __devinit vnet_new(const u64 *local_mac)
        INIT_LIST_HEAD(&vp->list);
        vp->local_mac = *local_mac;
 
-       dev->open = vnet_open;
-       dev->stop = vnet_close;
-       dev->set_multicast_list = vnet_set_rx_mode;
-       dev->set_mac_address = vnet_set_mac_addr;
-       dev->tx_timeout = vnet_tx_timeout;
+       dev->netdev_ops = &vnet_ops;
        dev->ethtool_ops = &vnet_ethtool_ops;
        dev->watchdog_timeo = VNET_TX_TIMEOUT;
-       dev->change_mtu = vnet_change_mtu;
-       dev->hard_start_xmit = vnet_start_xmit;
 
        err = register_netdev(dev);
        if (err) {
index be9f38f8f0bfae3173d452e48df8b4db2f747bb6..7debd1e4e1f7d8c2ef18b3de5ee38d91e931c152 100644 (file)
@@ -63,7 +63,6 @@
  */
 
 #include "tehuti.h"
-#include "tehuti_fw.h"
 
 static struct pci_device_id __devinitdata bdx_pci_tbl[] = {
        {0x1FC9, 0x3009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0},
@@ -318,28 +317,41 @@ static int bdx_poll(struct napi_struct *napi, int budget)
 
 static int bdx_fw_load(struct bdx_priv *priv)
 {
+       const struct firmware *fw = NULL;
        int master, i;
+       int rc;
 
        ENTER;
        master = READ_REG(priv, regINIT_SEMAPHORE);
        if (!READ_REG(priv, regINIT_STATUS) && master) {
-               bdx_tx_push_desc_safe(priv, s_firmLoad, sizeof(s_firmLoad));
+               rc = request_firmware(&fw, "tehuti/firmware.bin", &priv->pdev->dev);
+               if (rc)
+                       goto out;
+               bdx_tx_push_desc_safe(priv, (char *)fw->data, fw->size);
                mdelay(100);
        }
        for (i = 0; i < 200; i++) {
-               if (READ_REG(priv, regINIT_STATUS))
-                       break;
+               if (READ_REG(priv, regINIT_STATUS)) {
+                       rc = 0;
+                       goto out;
+               }
                mdelay(2);
        }
+       rc = -EIO;
+out:
        if (master)
                WRITE_REG(priv, regINIT_SEMAPHORE, 1);
+       if (fw)
+               release_firmware(fw);
 
-       if (i == 200) {
+       if (rc) {
                ERR("%s: firmware loading failed\n", priv->ndev->name);
-               DBG("VPC = 0x%x VIC = 0x%x INIT_STATUS = 0x%x i=%d\n",
-                   READ_REG(priv, regVPC),
-                   READ_REG(priv, regVIC), READ_REG(priv, regINIT_STATUS), i);
-               RET(-EIO);
+               if (rc == -EIO)
+                       DBG("VPC = 0x%x VIC = 0x%x INIT_STATUS = 0x%x i=%d\n",
+                           READ_REG(priv, regVPC),
+                           READ_REG(priv, regVIC),
+                           READ_REG(priv, regINIT_STATUS), i);
+               RET(rc);
        } else {
                DBG("%s: firmware loading success\n", priv->ndev->name);
                RET(0);
@@ -617,13 +629,6 @@ err:
        RET(rc);
 }
 
-static void __init bdx_firmware_endianess(void)
-{
-       int i;
-       for (i = 0; i < ARRAY_SIZE(s_firmLoad); i++)
-               s_firmLoad[i] = CPU_CHIP_SWAP32(s_firmLoad[i]);
-}
-
 static int bdx_range_check(struct bdx_priv *priv, u32 offset)
 {
        return (offset > (u32) (BDX_REGS_SIZE / priv->nic->port_num)) ?
@@ -2501,7 +2506,6 @@ static void __init print_driver_id(void)
 static int __init bdx_module_init(void)
 {
        ENTER;
-       bdx_firmware_endianess();
        init_txd_sizes();
        print_driver_id();
        RET(pci_register_driver(&bdx_pci_driver));
@@ -2521,3 +2525,4 @@ module_exit(bdx_module_exit);
 MODULE_LICENSE("GPL");
 MODULE_AUTHOR(DRIVER_AUTHOR);
 MODULE_DESCRIPTION(BDX_DRV_DESC);
+MODULE_FIRMWARE("tehuti/firmware.bin");
index efaf84d9757d139fd88fef5b7311f9f273fc389c..dec67e0a9ca2b491a5a1636acb6eb4f4efe28bf3 100644 (file)
@@ -29,6 +29,7 @@
 #include <linux/if_vlan.h>
 #include <linux/interrupt.h>
 #include <linux/vmalloc.h>
+#include <linux/firmware.h>
 #include <asm/byteorder.h>
 
 /* Compile Time Switches */
diff --git a/drivers/net/tehuti_fw.h b/drivers/net/tehuti_fw.h
deleted file mode 100644 (file)
index 2c603a8..0000000
+++ /dev/null
@@ -1,10712 +0,0 @@
-/*
- * Tehuti Networks(R) Network Driver
- * Copyright (C) 2007 Tehuti Networks Ltd. All rights reserved
- *
- * 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.
- */
-
-/* Loading Firmware */
-/* INT_MEM Ver */
-static u32 s_firmLoad[] = {
-       0x000f0002,
-       0x40718000,
-       0x0000002d,
-       0xc0000000,
-       0x000f0002,
-       0x00718001,
-       0x0000002d,
-       0xc0800000,
-       0x000f0002,
-       0x00718002,
-       0x0000002d,
-       0xc1000000,
-       0x000f0002,
-       0x00718003,
-       0x0000002d,
-       0xc1800000,
-       0x000f0002,
-       0x00718004,
-       0x0000002d,
-       0xc2000000,
-       0x000f0002,
-       0x00718005,
-       0x0000002d,
-       0xc2800000,
-       0x000f0002,
-       0x00718006,
-       0x0000002d,
-       0xc3000000,
-       0x000f0002,
-       0x00718007,
-       0x0000002d,
-       0xc3800000,
-       0x000f0002,
-       0x00718008,
-       0x0000002d,
-       0xc4000000,
-       0x000f0002,
-       0x00718009,
-       0x0000002d,
-       0xc4800000,
-       0x000f0002,
-       0x0071800a,
-       0x0000002d,
-       0xc5000000,
-       0x000f0002,
-       0x0071800b,
-       0x0000002d,
-       0xc5800000,
-       0x000f0002,
-       0x0071800c,
-       0x0000002d,
-       0xc6000000,
-       0x000f0002,
-       0x0071800d,
-       0x0000002d,
-       0xc6800000,
-       0x000f0002,
-       0x0071800e,
-       0x0000002d,
-       0xc7000000,
-       0x000f0002,
-       0x0071800f,
-       0x0000002d,
-       0xc7800000,
-       0x000f0002,
-       0x00718010,
-       0x0000002d,
-       0xc8000000,
-       0x000f0002,
-       0x00718011,
-       0x0000002d,
-       0xc8800000,
-       0x000f0002,
-       0x00718012,
-       0x0000002d,
-       0xc9000000,
-       0x000f0002,
-       0x00718013,
-       0x0000002d,
-       0xc9800000,
-       0x000f0002,
-       0x00718014,
-       0x0000002d,
-       0xca000000,
-       0x000f0002,
-       0x00718015,
-       0x0000002d,
-       0xca800000,
-       0x000f0002,
-       0x00718016,
-       0x0000002d,
-       0xcb000000,
-       0x000f0002,
-       0x00718017,
-       0x0000002d,
-       0xcb800000,
-       0x000f0002,
-       0x00718018,
-       0x0000002d,
-       0xcc000000,
-       0x000f0002,
-       0x00718019,
-       0x0000002d,
-       0xcc800000,
-       0x000f0002,
-       0x0071801a,
-       0x0000002d,
-       0xcd000000,
-       0x000f0002,
-       0x0071801b,
-       0x0000002d,
-       0xcd800000,
-       0x000f0002,
-       0x0071801c,
-       0x0000002d,
-       0xce000000,
-       0x000f0002,
-       0x0071801d,
-       0x0000002d,
-       0xce800000,
-       0x000f0002,
-       0x0071801e,
-       0x0000002d,
-       0xcf000000,
-       0x000f0002,
-       0x0071801f,
-       0x0000002d,
-       0xcf800000,
-       0x000f0002,
-       0x00718020,
-       0x0000002d,
-       0xd0000000,
-       0x000f0002,
-       0x00718021,
-       0x0000002d,
-       0xd0800000,
-       0x000f0002,
-       0x00718022,
-       0x0000002d,
-       0xd1000000,
-       0x000f0002,
-       0x00718023,
-       0x0000002d,
-       0xd1800000,
-       0x000f0002,
-       0x00718024,
-       0x0000002d,
-       0xd2000000,
-       0x000f0002,
-       0x00718025,
-       0x0000002d,
-       0xd2800000,
-       0x000f0002,
-       0x00718026,
-       0x0000002d,
-       0xd3000000,
-       0x000f0002,
-       0x00718027,
-       0x0000002d,
-       0xd3800000,
-       0x000f0002,
-       0x00718028,
-       0x0000002d,
-       0xd4000000,
-       0x000f0002,
-       0x00718029,
-       0x0000002d,
-       0xd4800000,
-       0x000f0002,
-       0x0071802a,
-       0x0000002d,
-       0xd5000000,
-       0x000f0002,
-       0x0071802b,
-       0x0000002d,
-       0xd5800000,
-       0x000f0002,
-       0x0071802c,
-       0x0000002d,
-       0xd6000000,
-       0x000f0002,
-       0x0071802d,
-       0x0000002d,
-       0xd6800000,
-       0x000f0002,
-       0x0071802e,
-       0x0000002d,
-       0xd7000000,
-       0x000f0002,
-       0x0071802f,
-       0x0000002d,
-       0xd7800000,
-       0x000f0002,
-       0x00718030,
-       0x0000002d,
-       0xd8000000,
-       0x000f0002,
-       0x00718031,
-       0x0000002d,
-       0xd8800000,
-       0x000f0002,
-       0x00718032,
-       0x0000002d,
-       0xd9000000,
-       0x000f0002,
-       0x00718033,
-       0x0000002d,
-       0xd9800000,
-       0x000f0002,
-       0x00718034,
-       0x0000002d,
-       0xda000000,
-       0x000f0002,
-       0x00718035,
-       0x0000002d,
-       0xda800000,
-       0x000f0002,
-       0x00718036,
-       0x0000002d,
-       0xdb000000,
-       0x000f0002,
-       0x00718037,
-       0x0000002d,
-       0xdb800000,
-       0x000f0002,
-       0x00718038,
-       0x0000007b,
-       0xdd608000,
-       0x000f0002,
-       0x00718039,
-       0x0000002d,
-       0xdd000000,
-       0x000f0002,
-       0x0071803a,
-       0x0000002d,
-       0xdb800000,
-       0x000f0002,
-       0x0071803b,
-       0x0000002d,
-       0xdd000000,
-       0x000f0002,
-       0x0071803c,
-       0x0000002d,
-       0xdd000000,
-       0x000f0002,
-       0x0071803d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071803e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071803f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718040,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718041,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718042,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718043,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718044,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718045,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718046,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718047,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718048,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718049,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071804a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071804b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071804c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071804d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071804e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071804f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718050,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718051,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718052,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718053,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718054,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718055,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718056,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718057,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718058,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718059,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071805a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071805b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071805c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071805d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071805e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071805f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718060,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718061,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718062,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718063,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718064,
-       0x0000002d,
-       0xdb000000,
-       0x000f0002,
-       0x00718065,
-       0x0000003f,
-       0xdd000104,
-       0x000f0002,
-       0x00718066,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718067,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718068,
-       0x0000003f,
-       0xdd000804,
-       0x000f0002,
-       0x00718069,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071806a,
-       0x0000003f,
-       0xdd003004,
-       0x000f0002,
-       0x0071806b,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071806c,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071806d,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x0071806e,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071806f,
-       0x0000003f,
-       0xdd003d04,
-       0x000f0002,
-       0x00718070,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718071,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718072,
-       0x0000003f,
-       0xdd000704,
-       0x000f0002,
-       0x00718073,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718074,
-       0x0000003f,
-       0xdd002884,
-       0x000f0002,
-       0x00718075,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718076,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718077,
-       0x0000003f,
-       0xdd003704,
-       0x000f0002,
-       0x00718078,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718079,
-       0x0000003f,
-       0xdd002904,
-       0x000f0002,
-       0x0071807a,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071807b,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071807c,
-       0x0000003f,
-       0xdd04aa04,
-       0x000f0002,
-       0x0071807d,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071807e,
-       0x0000003f,
-       0xdd002804,
-       0x000f0002,
-       0x0071807f,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718080,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718081,
-       0x0000003f,
-       0xdd003104,
-       0x000f0002,
-       0x00718082,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718083,
-       0x0000003f,
-       0xdd002b84,
-       0x000f0002,
-       0x00718084,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718085,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718086,
-       0x0000003f,
-       0xdd01e404,
-       0x000f0002,
-       0x00718087,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718088,
-       0x0000003f,
-       0xd7800084,
-       0x000f0002,
-       0x00718089,
-       0x0000003f,
-       0xd7980001,
-       0x000f0002,
-       0x0071808a,
-       0x00000059,
-       0xd78037ef,
-       0x000f0002,
-       0x0071808b,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x0071808c,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x0071808d,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x0071808e,
-       0x0000002d,
-       0xd7d6027f,
-       0x000f0002,
-       0x0071808f,
-       0x00000018,
-       0x17ff0081,
-       0x000f0002,
-       0x00718090,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718091,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718092,
-       0x0000002d,
-       0xd7d800b8,
-       0x000f0002,
-       0x00718093,
-       0x00000018,
-       0x17eb0081,
-       0x000f0002,
-       0x00718094,
-       0x0000003f,
-       0xdd002904,
-       0x000f0002,
-       0x00718095,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718096,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718097,
-       0x0000003f,
-       0xdd04aa84,
-       0x000f0002,
-       0x00718098,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718099,
-       0x0000003f,
-       0xdd002b04,
-       0x000f0002,
-       0x0071809a,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071809b,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071809c,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x0071809d,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071809e,
-       0x0000003f,
-       0xdd002984,
-       0x000f0002,
-       0x0071809f,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x007180a0,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007180a1,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x007180a2,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007180a3,
-       0x0000003f,
-       0xdd002a04,
-       0x000f0002,
-       0x007180a4,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x007180a5,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007180a6,
-       0x0000003f,
-       0xdd009184,
-       0x000f0002,
-       0x007180a7,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007180a8,
-       0x0000003f,
-       0xd6801984,
-       0x000f0002,
-       0x007180a9,
-       0x0000003f,
-       0xd6800001,
-       0x000f0002,
-       0x007180aa,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x007180ab,
-       0x00000018,
-       0x37ff0081,
-       0x000f0002,
-       0x007180ac,
-       0x0000003f,
-       0xdd002b04,
-       0x000f0002,
-       0x007180ad,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x007180ae,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007180af,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x007180b0,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007180b1,
-       0x0000003f,
-       0xdd002a84,
-       0x000f0002,
-       0x007180b2,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x007180b3,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007180b4,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x007180b5,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007180b6,
-       0x0000003f,
-       0xd6800c84,
-       0x000f0002,
-       0x007180b7,
-       0x0000003f,
-       0xd6800001,
-       0x000f0002,
-       0x007180b8,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x007180b9,
-       0x00000018,
-       0x37ff0081,
-       0x000f0002,
-       0x007180ba,
-       0x0000003f,
-       0xdd002a84,
-       0x000f0002,
-       0x007180bb,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x007180bc,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007180bd,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x007180be,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007180bf,
-       0x0000003f,
-       0xd6800f84,
-       0x000f0002,
-       0x007180c0,
-       0x0000003f,
-       0xd6800001,
-       0x000f0002,
-       0x007180c1,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x007180c2,
-       0x00000018,
-       0x37ff0081,
-       0x000f0002,
-       0x007180c3,
-       0x0000003f,
-       0xdd002a04,
-       0x000f0002,
-       0x007180c4,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x007180c5,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007180c6,
-       0x0000003f,
-       0xdd001184,
-       0x000f0002,
-       0x007180c7,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007180c8,
-       0x0000003f,
-       0xdd002884,
-       0x000f0002,
-       0x007180c9,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x007180ca,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007180cb,
-       0x0000003f,
-       0xdd003784,
-       0x000f0002,
-       0x007180cc,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007180cd,
-       0x0000002d,
-       0xd3800000,
-       0x000f0002,
-       0x007180ce,
-       0x0000003f,
-       0xd2003780,
-       0x000f0002,
-       0x007180cf,
-       0x0000003f,
-       0xd1800404,
-       0x000f0002,
-       0x007180d0,
-       0x0000003f,
-       0xd1840001,
-       0x000f0002,
-       0x007180d1,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x007180d2,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x007180d3,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x007180d4,
-       0x0000003f,
-       0xd17fff84,
-       0x000f0002,
-       0x007180d5,
-       0x0000003f,
-       0xd17fff81,
-       0x000f0002,
-       0x007180d6,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x007180d7,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x007180d8,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x007180d9,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x007180da,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x007180db,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x007180dc,
-       0x0000003f,
-       0xd6800784,
-       0x000f0002,
-       0x007180dd,
-       0x0000003f,
-       0xd6800001,
-       0x000f0002,
-       0x007180de,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x007180df,
-       0x00000018,
-       0x37ff0081,
-       0x000f0002,
-       0x007180e0,
-       0x00000049,
-       0xdd003b63,
-       0x000f0002,
-       0x007180e1,
-       0x00000059,
-       0xdd003b76,
-       0x000f0002,
-       0x007180e2,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007180e3,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007180e4,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007180e5,
-       0x0000002d,
-       0xdd06027f,
-       0x000f0002,
-       0x007180e6,
-       0x00000018,
-       0x1d7f3d7a,
-       0x000f0002,
-       0x007180e7,
-       0x00000045,
-       0xdd003139,
-       0x000f0002,
-       0x007180e8,
-       0x00000094,
-       0x000b313b,
-       0x000f0002,
-       0x007180e9,
-       0x00000094,
-       0x0009313d,
-       0x000f0002,
-       0x007180ea,
-       0x00000094,
-       0x0007313f,
-       0x000f0002,
-       0x007180eb,
-       0x00000094,
-       0x00053b76,
-       0x000f0002,
-       0x007180ec,
-       0x00000009,
-       0xc1ed3d7a,
-       0x000f0002,
-       0x007180ed,
-       0x0000003f,
-       0xd200b780,
-       0x000f0002,
-       0x007180ee,
-       0x0000003f,
-       0xdd002884,
-       0x000f0002,
-       0x007180ef,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x007180f0,
-       0x00000069,
-       0xdd003264,
-       0x000f0002,
-       0x007180f1,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007180f2,
-       0x0000003f,
-       0xd6800784,
-       0x000f0002,
-       0x007180f3,
-       0x0000003f,
-       0xd6800001,
-       0x000f0002,
-       0x007180f4,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x007180f5,
-       0x00000018,
-       0x37ff0081,
-       0x000f0002,
-       0x007180f6,
-       0x00000049,
-       0xdd003b63,
-       0x000f0002,
-       0x007180f7,
-       0x00000059,
-       0xdd003b76,
-       0x000f0002,
-       0x007180f8,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007180f9,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007180fa,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007180fb,
-       0x0000002d,
-       0xdd06027f,
-       0x000f0002,
-       0x007180fc,
-       0x00000018,
-       0x1d7f3d7a,
-       0x000f0002,
-       0x007180fd,
-       0x00000045,
-       0xdd00313a,
-       0x000f0002,
-       0x007180fe,
-       0x00000018,
-       0x1d2d3b76,
-       0x000f0002,
-       0x007180ff,
-       0x00000045,
-       0xdd00313c,
-       0x000f0002,
-       0x00718100,
-       0x00000018,
-       0x1d133b76,
-       0x000f0002,
-       0x00718101,
-       0x00000045,
-       0xdd00313e,
-       0x000f0002,
-       0x00718102,
-       0x00000018,
-       0x1d1b3b76,
-       0x000f0002,
-       0x00718103,
-       0x0000003f,
-       0xdd003004,
-       0x000f0002,
-       0x00718104,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718105,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718106,
-       0x0000003f,
-       0xdd000104,
-       0x000f0002,
-       0x00718107,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718108,
-       0x00000009,
-       0xc52d3d7a,
-       0x000f0002,
-       0x00718109,
-       0x00000029,
-       0xd2010064,
-       0x000f0002,
-       0x0071810a,
-       0x0000003f,
-       0xdd002884,
-       0x000f0002,
-       0x0071810b,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071810c,
-       0x00000069,
-       0xdd003264,
-       0x000f0002,
-       0x0071810d,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071810e,
-       0x00000009,
-       0xc2293d7a,
-       0x000f0002,
-       0x0071810f,
-       0x00000029,
-       0xd2000064,
-       0x000f0002,
-       0x00718110,
-       0x0000003f,
-       0xdd002884,
-       0x000f0002,
-       0x00718111,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718112,
-       0x00000069,
-       0xdd003264,
-       0x000f0002,
-       0x00718113,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718114,
-       0x00000049,
-       0xdd003b63,
-       0x000f0002,
-       0x00718115,
-       0x00000059,
-       0xdd003b76,
-       0x000f0002,
-       0x00718116,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718117,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718118,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718119,
-       0x0000002d,
-       0xdd06027f,
-       0x000f0002,
-       0x0071811a,
-       0x00000018,
-       0x1d7f3d7a,
-       0x000f0002,
-       0x0071811b,
-       0x00000045,
-       0xdd00313a,
-       0x000f0002,
-       0x0071811c,
-       0x00000018,
-       0x1d0f3b76,
-       0x000f0002,
-       0x0071811d,
-       0x0000003f,
-       0xdd003004,
-       0x000f0002,
-       0x0071811e,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071811f,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718120,
-       0x0000003f,
-       0xdd000104,
-       0x000f0002,
-       0x00718121,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718122,
-       0x00000009,
-       0xc52d3d7a,
-       0x000f0002,
-       0x00718123,
-       0x0000002d,
-       0xd1080082,
-       0x000f0002,
-       0x00718124,
-       0x00000008,
-       0x23c33d7a,
-       0x000f0002,
-       0x00718125,
-       0x00000049,
-       0xd6003b0a,
-       0x000f0002,
-       0x00718126,
-       0x0000003f,
-       0xd3000004,
-       0x000f0002,
-       0x00718127,
-       0x0000003f,
-       0xd3040001,
-       0x000f0002,
-       0x00718128,
-       0x0000002f,
-       0xd6814085,
-       0x000f0002,
-       0x00718129,
-       0x0000003f,
-       0xd4ffff84,
-       0x000f0002,
-       0x0071812a,
-       0x0000003f,
-       0xd4800781,
-       0x000f0002,
-       0x0071812b,
-       0x0000003f,
-       0xd1ffff84,
-       0x000f0002,
-       0x0071812c,
-       0x0000003f,
-       0xd1800001,
-       0x000f0002,
-       0x0071812d,
-       0x00000049,
-       0xdd003666,
-       0x000f0002,
-       0x0071812e,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x0071812f,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x00718130,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x00718131,
-       0x00000069,
-       0xdd003b69,
-       0x000f0002,
-       0x00718132,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x00718133,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x00718134,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x00718135,
-       0x00000069,
-       0xdd003b69,
-       0x000f0002,
-       0x00718136,
-       0x00000061,
-       0xf600046c,
-       0x000f0002,
-       0x00718137,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x00718138,
-       0x00000018,
-       0x3d6b0081,
-       0x000f0002,
-       0x00718139,
-       0x00000049,
-       0xd600058b,
-       0x000f0002,
-       0x0071813a,
-       0x0000002f,
-       0xd6810106,
-       0x000f0002,
-       0x0071813b,
-       0x0000002d,
-       0xd2000000,
-       0x000f0002,
-       0x0071813c,
-       0x00000021,
-       0xd20000e4,
-       0x000f0002,
-       0x0071813d,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x0071813e,
-       0x0000002d,
-       0xdd06017f,
-       0x000f0002,
-       0x0071813f,
-       0x00000018,
-       0x1d7f3d7a,
-       0x000f0002,
-       0x00718140,
-       0x00000049,
-       0xd800366c,
-       0x000f0002,
-       0x00718141,
-       0x00000069,
-       0xd80033e7,
-       0x000f0002,
-       0x00718142,
-       0x00000069,
-       0xd80033e7,
-       0x000f0002,
-       0x00718143,
-       0x00000069,
-       0xd80037ef,
-       0x000f0002,
-       0x00718144,
-       0x00000031,
-       0xd600016c,
-       0x000f0002,
-       0x00718145,
-       0x0000002d,
-       0xd1000000,
-       0x000f0002,
-       0x00718146,
-       0x00000049,
-       0xd17a33e4,
-       0x000f0002,
-       0x00718147,
-       0x0000002f,
-       0xd1710162,
-       0x000f0002,
-       0x00718148,
-       0x0000002f,
-       0xd1610162,
-       0x000f0002,
-       0x00718149,
-       0x00000049,
-       0xd14033e3,
-       0x000f0002,
-       0x0071814a,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x0071814b,
-       0x0000002d,
-       0xdd06017f,
-       0x000f0002,
-       0x0071814c,
-       0x00000018,
-       0x1d7f3d7a,
-       0x000f0002,
-       0x0071814d,
-       0x00000049,
-       0xd800366c,
-       0x000f0002,
-       0x0071814e,
-       0x00000069,
-       0xd80033e7,
-       0x000f0002,
-       0x0071814f,
-       0x00000069,
-       0xd8003162,
-       0x000f0002,
-       0x00718150,
-       0x00000069,
-       0xd80037ef,
-       0x000f0002,
-       0x00718151,
-       0x00000031,
-       0xd600016c,
-       0x000f0002,
-       0x00718152,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718153,
-       0x0000002d,
-       0xdd06017f,
-       0x000f0002,
-       0x00718154,
-       0x00000018,
-       0x1d7f3d7a,
-       0x000f0002,
-       0x00718155,
-       0x00000049,
-       0xd800366c,
-       0x000f0002,
-       0x00718156,
-       0x00000069,
-       0xd80033e7,
-       0x000f0002,
-       0x00718157,
-       0x00000069,
-       0xd80033e7,
-       0x000f0002,
-       0x00718158,
-       0x00000069,
-       0xd80037ef,
-       0x000f0002,
-       0x00718159,
-       0x00000031,
-       0xd600016c,
-       0x000f0002,
-       0x0071815a,
-       0x0000002d,
-       0xd1000000,
-       0x000f0002,
-       0x0071815b,
-       0x0000002d,
-       0xd16c07e4,
-       0x000f0002,
-       0x0071815c,
-       0x00000049,
-       0xd14033e3,
-       0x000f0002,
-       0x0071815d,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x0071815e,
-       0x0000002d,
-       0xdd06017f,
-       0x000f0002,
-       0x0071815f,
-       0x00000018,
-       0x1d7f3d7a,
-       0x000f0002,
-       0x00718160,
-       0x00000049,
-       0xd800366c,
-       0x000f0002,
-       0x00718161,
-       0x00000069,
-       0xd80033e7,
-       0x000f0002,
-       0x00718162,
-       0x00000069,
-       0xd8003162,
-       0x000f0002,
-       0x00718163,
-       0x00000069,
-       0xd80037ef,
-       0x000f0002,
-       0x00718164,
-       0x00000031,
-       0xd600016c,
-       0x000f0002,
-       0x00718165,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718166,
-       0x0000002d,
-       0xdd06017f,
-       0x000f0002,
-       0x00718167,
-       0x00000018,
-       0x1d7f3d7a,
-       0x000f0002,
-       0x00718168,
-       0x00000049,
-       0xd800366c,
-       0x000f0002,
-       0x00718169,
-       0x00000069,
-       0xd80033e7,
-       0x000f0002,
-       0x0071816a,
-       0x00000069,
-       0xd80033e7,
-       0x000f0002,
-       0x0071816b,
-       0x00000069,
-       0xd80037ef,
-       0x000f0002,
-       0x0071816c,
-       0x00000031,
-       0xd600016c,
-       0x000f0002,
-       0x0071816d,
-       0x0000002d,
-       0xd1000000,
-       0x000f0002,
-       0x0071816e,
-       0x00000049,
-       0xd17833e4,
-       0x000f0002,
-       0x0071816f,
-       0x0000002f,
-       0xd1710162,
-       0x000f0002,
-       0x00718170,
-       0x0000002f,
-       0xd1610162,
-       0x000f0002,
-       0x00718171,
-       0x00000049,
-       0xd14033e3,
-       0x000f0002,
-       0x00718172,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718173,
-       0x0000002d,
-       0xdd06017f,
-       0x000f0002,
-       0x00718174,
-       0x00000018,
-       0x1d7f3d7a,
-       0x000f0002,
-       0x00718175,
-       0x00000049,
-       0xd800366c,
-       0x000f0002,
-       0x00718176,
-       0x00000069,
-       0xd80033e7,
-       0x000f0002,
-       0x00718177,
-       0x00000069,
-       0xd8003162,
-       0x000f0002,
-       0x00718178,
-       0x00000069,
-       0xd80037ef,
-       0x000f0002,
-       0x00718179,
-       0x00000031,
-       0xd600016c,
-       0x000f0002,
-       0x0071817a,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x0071817b,
-       0x0000002d,
-       0xdd06017f,
-       0x000f0002,
-       0x0071817c,
-       0x00000018,
-       0x1d7f3d7a,
-       0x000f0002,
-       0x0071817d,
-       0x00000049,
-       0xd800366c,
-       0x000f0002,
-       0x0071817e,
-       0x00000069,
-       0xd80033e7,
-       0x000f0002,
-       0x0071817f,
-       0x00000069,
-       0xd80033e7,
-       0x000f0002,
-       0x00718180,
-       0x00000069,
-       0xd80037ef,
-       0x000f0002,
-       0x00718181,
-       0x00000031,
-       0xd600016c,
-       0x000f0002,
-       0x00718182,
-       0x0000002d,
-       0xd1000000,
-       0x000f0002,
-       0x00718183,
-       0x0000002d,
-       0xd16807e4,
-       0x000f0002,
-       0x00718184,
-       0x00000049,
-       0xd14033e3,
-       0x000f0002,
-       0x00718185,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718186,
-       0x0000002d,
-       0xdd06017f,
-       0x000f0002,
-       0x00718187,
-       0x00000018,
-       0x1d7f3d7a,
-       0x000f0002,
-       0x00718188,
-       0x00000049,
-       0xd800366c,
-       0x000f0002,
-       0x00718189,
-       0x00000069,
-       0xd80033e7,
-       0x000f0002,
-       0x0071818a,
-       0x00000069,
-       0xd8003162,
-       0x000f0002,
-       0x0071818b,
-       0x00000069,
-       0xd80037ef,
-       0x000f0002,
-       0x0071818c,
-       0x00000031,
-       0xd600016c,
-       0x000f0002,
-       0x0071818d,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x0071818e,
-       0x00000008,
-       0x22790081,
-       0x000f0002,
-       0x0071818f,
-       0x00000049,
-       0xd600060c,
-       0x000f0002,
-       0x00718190,
-       0x0000002f,
-       0xd6810106,
-       0x000f0002,
-       0x00718191,
-       0x0000003f,
-       0xd4800002,
-       0x000f0002,
-       0x00718192,
-       0x0000003f,
-       0xd4800084,
-       0x000f0002,
-       0x00718193,
-       0x0000003f,
-       0xd5000102,
-       0x000f0002,
-       0x00718194,
-       0x0000003f,
-       0xd5000184,
-       0x000f0002,
-       0x00718195,
-       0x0000003f,
-       0xd5800202,
-       0x000f0002,
-       0x00718196,
-       0x0000003f,
-       0xd5800204,
-       0x000f0002,
-       0x00718197,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718198,
-       0x0000002d,
-       0xdd06017f,
-       0x000f0002,
-       0x00718199,
-       0x00000018,
-       0x1d7f3d7a,
-       0x000f0002,
-       0x0071819a,
-       0x00000049,
-       0xd800366c,
-       0x000f0002,
-       0x0071819b,
-       0x00000069,
-       0xd80034e9,
-       0x000f0002,
-       0x0071819c,
-       0x00000069,
-       0xd800356a,
-       0x000f0002,
-       0x0071819d,
-       0x00000069,
-       0xd80037ef,
-       0x000f0002,
-       0x0071819e,
-       0x00000031,
-       0xd600016c,
-       0x000f0002,
-       0x0071819f,
-       0x00000041,
-       0xd48034eb,
-       0x000f0002,
-       0x007181a0,
-       0x00000041,
-       0xd500356b,
-       0x000f0002,
-       0x007181a1,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x007181a2,
-       0x00000018,
-       0x37eb0081,
-       0x000f0002,
-       0x007181a3,
-       0x00000049,
-       0xd6003b0d,
-       0x000f0002,
-       0x007181a4,
-       0x00000049,
-       0xd6803b07,
-       0x000f0002,
-       0x007181a5,
-       0x0000002d,
-       0xd1000000,
-       0x000f0002,
-       0x007181a6,
-       0x00000049,
-       0xdd003666,
-       0x000f0002,
-       0x007181a7,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x007181a8,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x007181a9,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x007181aa,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x007181ab,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x007181ac,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x007181ad,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x007181ae,
-       0x00000069,
-       0xdd003b76,
-       0x000f0002,
-       0x007181af,
-       0x00000061,
-       0xf600046c,
-       0x000f0002,
-       0x007181b0,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x007181b1,
-       0x00000018,
-       0x37eb0081,
-       0x000f0002,
-       0x007181b2,
-       0x00000049,
-       0xd6003b0e,
-       0x000f0002,
-       0x007181b3,
-       0x00000049,
-       0xd6803b08,
-       0x000f0002,
-       0x007181b4,
-       0x00000049,
-       0xd5803b09,
-       0x000f0002,
-       0x007181b5,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007181b6,
-       0x0000002d,
-       0xdd06017f,
-       0x000f0002,
-       0x007181b7,
-       0x00000018,
-       0x1d7f3d7a,
-       0x000f0002,
-       0x007181b8,
-       0x00000049,
-       0xd800366c,
-       0x000f0002,
-       0x007181b9,
-       0x00000069,
-       0xd80035eb,
-       0x000f0002,
-       0x007181ba,
-       0x00000069,
-       0xd80033e7,
-       0x000f0002,
-       0x007181bb,
-       0x00000069,
-       0xd80037ef,
-       0x000f0002,
-       0x007181bc,
-       0x00000041,
-       0xd60007ec,
-       0x000f0002,
-       0x007181bd,
-       0x00000041,
-       0xd580086b,
-       0x000f0002,
-       0x007181be,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x007181bf,
-       0x00000018,
-       0x37ed0081,
-       0x000f0002,
-       0x007181c0,
-       0x0000003f,
-       0xd4ffff80,
-       0x000f0002,
-       0x007181c1,
-       0x0000003f,
-       0xd5020004,
-       0x000f0002,
-       0x007181c2,
-       0x0000003f,
-       0xd5180001,
-       0x000f0002,
-       0x007181c3,
-       0x00000049,
-       0xdd003b6a,
-       0x000f0002,
-       0x007181c4,
-       0x00000069,
-       0xdd003b69,
-       0x000f0002,
-       0x007181c5,
-       0x00000069,
-       0xdd003b69,
-       0x000f0002,
-       0x007181c6,
-       0x00000021,
-       0xd50000ea,
-       0x000f0002,
-       0x007181c7,
-       0x00000049,
-       0xdd0e3b6a,
-       0x000f0002,
-       0x007181c8,
-       0x00000035,
-       0xd104007a,
-       0x000f0002,
-       0x007181c9,
-       0x00000018,
-       0x37f50081,
-       0x000f0002,
-       0x007181ca,
-       0x0000003f,
-       0xd4ffff80,
-       0x000f0002,
-       0x007181cb,
-       0x0000003f,
-       0xd5040004,
-       0x000f0002,
-       0x007181cc,
-       0x0000003f,
-       0xd5180001,
-       0x000f0002,
-       0x007181cd,
-       0x00000069,
-       0xdd003b69,
-       0x000f0002,
-       0x007181ce,
-       0x00000069,
-       0xdd003b69,
-       0x000f0002,
-       0x007181cf,
-       0x00000049,
-       0xdd003b6a,
-       0x000f0002,
-       0x007181d0,
-       0x00000051,
-       0xf50000ea,
-       0x000f0002,
-       0x007181d1,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007181d2,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007181d3,
-       0x00000049,
-       0xdd0e3b6a,
-       0x000f0002,
-       0x007181d4,
-       0x00000035,
-       0xd104807a,
-       0x000f0002,
-       0x007181d5,
-       0x00000018,
-       0x37f50081,
-       0x000f0002,
-       0x007181d6,
-       0x0000003f,
-       0xc77f7f04,
-       0x000f0002,
-       0x007181d7,
-       0x0000003f,
-       0xc77f7f01,
-       0x000f0002,
-       0x007181d8,
-       0x0000003f,
-       0xd6804000,
-       0x000f0002,
-       0x007181d9,
-       0x0000003f,
-       0xd103c000,
-       0x000f0002,
-       0x007181da,
-       0x00000025,
-       0xde2000e2,
-       0x000f0002,
-       0x007181db,
-       0x00000049,
-       0xde80274e,
-       0x000f0002,
-       0x007181dc,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007181dd,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007181de,
-       0x00000035,
-       0xd10000e2,
-       0x000f0002,
-       0x007181df,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x007181e0,
-       0x00000018,
-       0x37f50081,
-       0x000f0002,
-       0x007181e1,
-       0x0000003f,
-       0xdd003004,
-       0x000f0002,
-       0x007181e2,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x007181e3,
-       0x00000069,
-       0xdd001d3a,
-       0x000f0002,
-       0x007181e4,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007181e5,
-       0x0000007d,
-       0xc760a713,
-       0x000f0002,
-       0x007181e6,
-       0x00000031,
-       0xc0800041,
-       0x000f0002,
-       0x007181e7,
-       0x00000031,
-       0xc4000048,
-       0x000f0002,
-       0x007181e8,
-       0x00000031,
-       0xc2800045,
-       0x000f0002,
-       0x007181e9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181ea,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181eb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181ec,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181ed,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181ee,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181ef,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181f0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181f1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181f2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181f3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181f4,
-       0x0000002d,
-       0xdb000000,
-       0x000f0002,
-       0x007181f5,
-       0x0000003f,
-       0xdd003004,
-       0x000f0002,
-       0x007181f6,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x007181f7,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007181f8,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x007181f9,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007181fa,
-       0x0000002d,
-       0xd3800000,
-       0x000f0002,
-       0x007181fb,
-       0x0000003f,
-       0xdd000404,
-       0x000f0002,
-       0x007181fc,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x007181fd,
-       0x00000069,
-       0xdd000a14,
-       0x000f0002,
-       0x007181fe,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x007181ff,
-       0x00000049,
-       0xd1043394,
-       0x000f0002,
-       0x00718200,
-       0x0000003f,
-       0xdd000484,
-       0x000f0002,
-       0x00718201,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718202,
-       0x00000069,
-       0xdd003162,
-       0x000f0002,
-       0x00718203,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718204,
-       0x0000003f,
-       0xdd000504,
-       0x000f0002,
-       0x00718205,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718206,
-       0x00000069,
-       0xdd000a95,
-       0x000f0002,
-       0x00718207,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718208,
-       0x00000049,
-       0xd1043395,
-       0x000f0002,
-       0x00718209,
-       0x0000003f,
-       0xdd000584,
-       0x000f0002,
-       0x0071820a,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071820b,
-       0x00000069,
-       0xdd003162,
-       0x000f0002,
-       0x0071820c,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071820d,
-       0x0000003f,
-       0xdd000604,
-       0x000f0002,
-       0x0071820e,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071820f,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718210,
-       0x0000003f,
-       0xdd000084,
-       0x000f0002,
-       0x00718211,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718212,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x00718213,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718214,
-       0x00000069,
-       0xdd000b16,
-       0x000f0002,
-       0x00718215,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718216,
-       0x0000003f,
-       0xdd001004,
-       0x000f0002,
-       0x00718217,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718218,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718219,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x0071821a,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071821b,
-       0x0000003f,
-       0xdd001084,
-       0x000f0002,
-       0x0071821c,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071821d,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071821e,
-       0x0000003f,
-       0xdd018004,
-       0x000f0002,
-       0x0071821f,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718220,
-       0x0000003f,
-       0xdd001104,
-       0x000f0002,
-       0x00718221,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718222,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718223,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x00718224,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718225,
-       0x0000003f,
-       0xdd001184,
-       0x000f0002,
-       0x00718226,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718227,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718228,
-       0x0000003f,
-       0xdd160004,
-       0x000f0002,
-       0x00718229,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071822a,
-       0x0000003f,
-       0xdd001204,
-       0x000f0002,
-       0x0071822b,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071822c,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071822d,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x0071822e,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071822f,
-       0x0000003f,
-       0xdd001284,
-       0x000f0002,
-       0x00718230,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718231,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718232,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x00718233,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718234,
-       0x0000003f,
-       0xdd001304,
-       0x000f0002,
-       0x00718235,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718236,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718237,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x00718238,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718239,
-       0x0000003f,
-       0xdd001384,
-       0x000f0002,
-       0x0071823a,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071823b,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071823c,
-       0x0000003f,
-       0xdd050004,
-       0x000f0002,
-       0x0071823d,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071823e,
-       0x0000003f,
-       0xdd002004,
-       0x000f0002,
-       0x0071823f,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718240,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718241,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x00718242,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718243,
-       0x0000003f,
-       0xdd002084,
-       0x000f0002,
-       0x00718244,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718245,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718246,
-       0x0000003f,
-       0xdd019004,
-       0x000f0002,
-       0x00718247,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718248,
-       0x0000003f,
-       0xdd002104,
-       0x000f0002,
-       0x00718249,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071824a,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071824b,
-       0x0000003f,
-       0xdd000084,
-       0x000f0002,
-       0x0071824c,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071824d,
-       0x0000003f,
-       0xdd002184,
-       0x000f0002,
-       0x0071824e,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071824f,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718250,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x00718251,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718252,
-       0x0000003f,
-       0xdd002204,
-       0x000f0002,
-       0x00718253,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718254,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718255,
-       0x0000003f,
-       0xdd000284,
-       0x000f0002,
-       0x00718256,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718257,
-       0x0000003f,
-       0xdd002284,
-       0x000f0002,
-       0x00718258,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718259,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071825a,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x0071825b,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071825c,
-       0x0000003f,
-       0xdd002304,
-       0x000f0002,
-       0x0071825d,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071825e,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071825f,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x00718260,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718261,
-       0x0000003f,
-       0xdd001804,
-       0x000f0002,
-       0x00718262,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718263,
-       0x00000069,
-       0xdd000b97,
-       0x000f0002,
-       0x00718264,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718265,
-       0x00000049,
-       0xd1043397,
-       0x000f0002,
-       0x00718266,
-       0x0000003f,
-       0xdd001884,
-       0x000f0002,
-       0x00718267,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718268,
-       0x00000069,
-       0xdd003162,
-       0x000f0002,
-       0x00718269,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071826a,
-       0x0000003f,
-       0xdd001904,
-       0x000f0002,
-       0x0071826b,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071826c,
-       0x00000069,
-       0xdd000c18,
-       0x000f0002,
-       0x0071826d,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071826e,
-       0x00000049,
-       0xd1043398,
-       0x000f0002,
-       0x0071826f,
-       0x0000003f,
-       0xdd001984,
-       0x000f0002,
-       0x00718270,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718271,
-       0x00000069,
-       0xdd003162,
-       0x000f0002,
-       0x00718272,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718273,
-       0x0000003f,
-       0xdd001a04,
-       0x000f0002,
-       0x00718274,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718275,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718276,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x00718277,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718278,
-       0x0000003f,
-       0xdd001a84,
-       0x000f0002,
-       0x00718279,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071827a,
-       0x00000069,
-       0xdd000b16,
-       0x000f0002,
-       0x0071827b,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071827c,
-       0x0000003f,
-       0xdd001c04,
-       0x000f0002,
-       0x0071827d,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071827e,
-       0x00000069,
-       0xdd000c99,
-       0x000f0002,
-       0x0071827f,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718280,
-       0x0000003f,
-       0xdd001c84,
-       0x000f0002,
-       0x00718281,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718282,
-       0x00000069,
-       0xdd000d1a,
-       0x000f0002,
-       0x00718283,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718284,
-       0x0000003f,
-       0xdd001d04,
-       0x000f0002,
-       0x00718285,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718286,
-       0x00000069,
-       0xdd000d9b,
-       0x000f0002,
-       0x00718287,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718288,
-       0x00000049,
-       0xd104339b,
-       0x000f0002,
-       0x00718289,
-       0x0000003f,
-       0xdd001d84,
-       0x000f0002,
-       0x0071828a,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071828b,
-       0x00000069,
-       0xdd003162,
-       0x000f0002,
-       0x0071828c,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x0071828d,
-       0x0000003f,
-       0xdd001e04,
-       0x000f0002,
-       0x0071828e,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071828f,
-       0x00000069,
-       0xdd000e1c,
-       0x000f0002,
-       0x00718290,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718291,
-       0x0000003f,
-       0xdd000104,
-       0x000f0002,
-       0x00718292,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x00718293,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718294,
-       0x0000003f,
-       0xdd000f04,
-       0x000f0002,
-       0x00718295,
-       0x00000069,
-       0xdd003d7a,
-       0x000f0002,
-       0x00718296,
-       0x0000007d,
-       0xc760a713,
-       0x000f0002,
-       0x00718297,
-       0x00000031,
-       0xc0800041,
-       0x000f0002,
-       0x00718298,
-       0x00000031,
-       0xc4000048,
-       0x000f0002,
-       0x00718299,
-       0x00000031,
-       0xc2800045,
-       0x000f0002,
-       0x0071829a,
-       0x00000031,
-       0xd680006d,
-/* BRDX_INIT_SDRAM */
-       0x000f000f,
-       0x00700064,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000040,
-       0x00000100,
-       0x00000400,
-       0x00000064,
-       0x00000054,
-       0x00000000,
-       0x00002400,
-       0x00002800,
-       0x00000400,
-       0x00002880,
-       0x00000180,
-       0x00000003,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000051,
-       0x0000017d,
-       0x00000008,
-       0x00000051,
-       0x0000005d,
-       0x00000000,
-       0x00000009,
-       0x00005000,
-       0x00000000,
-       0x00000000,
-/* BRDX_INIT */
-       0x000f000f,
-       0x007001f4,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000040,
-       0x00000100,
-       0x00000400,
-       0x00000064,
-       0x00000054,
-       0x00000000,
-       0x00002400,
-       0x00002800,
-       0x00000400,
-       0x00002880,
-       0x00000180,
-       0x00000003,
-       0x00000000,
-       0x00000000,
-       0x00000000,
-       0x00000051,
-       0x0000017d,
-       0x00000008,
-       0x00000051,
-       0x0000005d,
-       0x00000000,
-       0x00000009,
-       0x00005000,
-       0x00000000,
-       0x00000000,
-/* ZERO_INIT */
-       0x000f0002,
-       0x00700000,
-       0x00000001,
-       0x00000000,
-/* ZERO_INIT */
-       0x000f0002,
-       0x00700000,
-       0x00000001,
-       0x00000000,
-/* Loading operational Firmware */
-       0x000f0002,
-       0x00718000,
-       0x00000025,
-       0xdd0e0002,
-       0x000f0002,
-       0x00718001,
-       0x00000004,
-       0x01d13b76,
-       0x000f0002,
-       0x00718002,
-       0x00000025,
-       0xdd0e0082,
-       0x000f0002,
-       0x00718003,
-       0x00000004,
-       0x02893b76,
-       0x000f0002,
-       0x00718004,
-       0x00000025,
-       0xdd0e0102,
-       0x000f0002,
-       0x00718005,
-       0x00000004,
-       0x02853b76,
-       0x000f0002,
-       0x00718006,
-       0x00000025,
-       0xdd0e0182,
-       0x000f0002,
-       0x00718007,
-       0x00000004,
-       0x03fd3b76,
-       0x000f0002,
-       0x00718008,
-       0x00000009,
-       0xcf813b76,
-       0x000f0002,
-       0x00718009,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071800a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071800b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071800c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071800d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071800e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071800f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718010,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718011,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718012,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718013,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718014,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718015,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718016,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718017,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718018,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718019,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071801a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071801b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071801c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071801d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071801e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071801f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718020,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718021,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718022,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718023,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718024,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718025,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718026,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718027,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718028,
-       0x00000049,
-       0xc0003b00,
-       0x000f0002,
-       0x00718029,
-       0x00000049,
-       0xc0803b02,
-       0x000f0002,
-       0x0071802a,
-       0x00000049,
-       0xc1003b03,
-       0x000f0002,
-       0x0071802b,
-       0x00000049,
-       0xc1803b04,
-       0x000f0002,
-       0x0071802c,
-       0x00000029,
-       0xdf600076,
-       0x000f0002,
-       0x0071802d,
-       0x00000049,
-       0xdf443b7d,
-       0x000f0002,
-       0x0071802e,
-       0x00000079,
-       0xfd609076,
-       0x000f0002,
-       0x0071802f,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718030,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718031,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718032,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718033,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718034,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718035,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718036,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718037,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718038,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718039,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071803a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071803b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071803c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071803d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071803e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071803f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718040,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718041,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718042,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718043,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718044,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718045,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718046,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718047,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718048,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718049,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071804a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071804b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071804c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071804d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071804e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071804f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718050,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718051,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718052,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718053,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718054,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718055,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718056,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718057,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718058,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718059,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071805a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071805b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071805c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071805d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071805e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071805f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718060,
-       0x0000003f,
-       0xdf000003,
-       0x000f0002,
-       0x00718061,
-       0x0000002d,
-       0xdde00f81,
-       0x000f0002,
-       0x00718062,
-       0x0000003f,
-       0xdd800283,
-       0x000f0002,
-       0x00718063,
-       0x0000002d,
-       0xdd040180,
-       0x000f0002,
-       0x00718064,
-       0x0000007d,
-       0xfd150080,
-       0x000f0002,
-       0x00718065,
-       0x0000007a,
-       0x10203b76,
-       0x000f0002,
-       0x00718066,
-       0x0000007a,
-       0x30207b76,
-       0x000f0002,
-       0x00718067,
-       0x00000021,
-       0xd0240060,
-       0x000f0002,
-       0x00718068,
-       0x0000003f,
-       0xdd000104,
-       0x000f0002,
-       0x00718069,
-       0x0000003f,
-       0xdd400281,
-       0x000f0002,
-       0x0071806a,
-       0x00000079,
-       0xdd31bb03,
-       0x000f0002,
-       0x0071806b,
-       0x00000079,
-       0xdd31fb04,
-       0x000f0002,
-       0x0071806c,
-       0x00000079,
-       0xdd31bb76,
-       0x000f0002,
-       0x0071806d,
-       0x00000079,
-       0xdd31fb76,
-       0x000f0002,
-       0x0071806e,
-       0x00000079,
-       0xfd210101,
-       0x000f0002,
-       0x0071806f,
-       0x0000007d,
-       0xfd2b4081,
-       0x000f0002,
-       0x00718070,
-       0x00000040,
-       0x3d003002,
-       0x000f0002,
-       0x00718071,
-       0x00000048,
-       0x1d003b02,
-       0x000f0002,
-       0x00718072,
-       0x00000079,
-       0xdd217b76,
-       0x000f0002,
-       0x00718073,
-       0x0000002d,
-       0xdd04057f,
-       0x000f0002,
-       0x00718074,
-       0x00000018,
-       0x3d7f3b76,
-       0x000f0002,
-       0x00718075,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718076,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718077,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718078,
-       0x00000021,
-       0xe3371f76,
-       0x000f0002,
-       0x00718079,
-       0x00000049,
-       0xdd003b79,
-       0x000f0002,
-       0x0071807a,
-       0x00000079,
-       0xdd21bb76,
-       0x000f0002,
-       0x0071807b,
-       0x00000049,
-       0xdd003b79,
-       0x000f0002,
-       0x0071807c,
-       0x00000079,
-       0xdd21bb76,
-       0x000f0002,
-       0x0071807d,
-       0x00000049,
-       0xdd003b79,
-       0x000f0002,
-       0x0071807e,
-       0x00000079,
-       0xdd21bb76,
-       0x000f0002,
-       0x0071807f,
-       0x00000079,
-       0xfd609076,
-       0x000f0002,
-       0x00718080,
-       0x00000079,
-       0xdd21fb76,
-       0x000f0002,
-       0x00718081,
-       0x0000003f,
-       0xdf000083,
-       0x000f0002,
-       0x00718082,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718083,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718084,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718085,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718086,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718087,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718088,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718089,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071808a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071808b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071808c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071808d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071808e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071808f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718090,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718091,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718092,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718093,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718094,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718095,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718096,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718097,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718098,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718099,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071809a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071809b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071809c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071809d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071809e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071809f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007180a0,
-       0x0000002d,
-       0xd0080803,
-       0x000f0002,
-       0x007180a1,
-       0x00000008,
-       0x21b5fb76,
-       0x000f0002,
-       0x007180a2,
-       0x00000079,
-       0xdd010081,
-       0x000f0002,
-       0x007180a3,
-       0x00000079,
-       0xdd018102,
-       0x000f0002,
-       0x007180a4,
-       0x0000007d,
-       0xfd018083,
-       0x000f0002,
-       0x007180a5,
-       0x00000079,
-       0xd0903b76,
-       0x000f0002,
-       0x007180a6,
-       0x00000049,
-       0xd0583b7a,
-       0x000f0002,
-       0x007180a7,
-       0x00000049,
-       0xd2043b00,
-       0x000f0002,
-       0x007180a8,
-       0x0000003d,
-       0xdd400003,
-       0x000f0002,
-       0x007180a9,
-       0x00000024,
-       0x32000264,
-       0x000f0002,
-       0x007180aa,
-       0x0000003d,
-       0xdd7ff803,
-       0x000f0002,
-       0x007180ab,
-       0x00000029,
-       0xd020017a,
-       0x000f0002,
-       0x007180ac,
-       0x00000049,
-       0xd0a43b0e,
-       0x000f0002,
-       0x007180ad,
-       0x0000002d,
-       0xdd0442ff,
-       0x000f0002,
-       0x007180ae,
-       0x00000018,
-       0x3d7f3b76,
-       0x000f0002,
-       0x007180af,
-       0x0000002d,
-       0xdd060082,
-       0x000f0002,
-       0x007180b0,
-       0x00000038,
-       0x300001e0,
-       0x000f0002,
-       0x007180b1,
-       0x00000039,
-       0xd0000160,
-       0x000f0002,
-       0x007180b2,
-       0x00000079,
-       0xd1b13b7c,
-       0x000f0002,
-       0x007180b3,
-       0x0000002d,
-       0xdde00fe3,
-       0x000f0002,
-       0x007180b4,
-       0x00000049,
-       0xd08030e4,
-       0x000f0002,
-       0x007180b5,
-       0x00000079,
-       0xdd317b7c,
-       0x000f0002,
-       0x007180b6,
-       0x00000079,
-       0xdd313b7c,
-       0x000f0002,
-       0x007180b7,
-       0x0000007d,
-       0xfd374082,
-       0x000f0002,
-       0x007180b8,
-       0x00000008,
-       0x017d3b76,
-       0x000f0002,
-       0x007180b9,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007180ba,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007180bb,
-       0x00000049,
-       0xdd000387,
-       0x000f0002,
-       0x007180bc,
-       0x00000079,
-       0xdd310408,
-       0x000f0002,
-       0x007180bd,
-       0x00000079,
-       0xdd317d7a,
-       0x000f0002,
-       0x007180be,
-       0x00000049,
-       0xd3003b7c,
-       0x000f0002,
-       0x007180bf,
-       0x00000079,
-       0xd381bb7c,
-       0x000f0002,
-       0x007180c0,
-       0x0000007f,
-       0xd101b27c,
-       0x000f0002,
-       0x007180c1,
-       0x00000048,
-       0x51003264,
-       0x000f0002,
-       0x007180c2,
-       0x0000003d,
-       0xdd400003,
-       0x000f0002,
-       0x007180c3,
-       0x00000008,
-       0x01953162,
-       0x000f0002,
-       0x007180c4,
-       0x00000021,
-       0xd3000666,
-       0x000f0002,
-       0x007180c5,
-       0x00000020,
-       0x538000e7,
-       0x000f0002,
-       0x007180c6,
-       0x0000003f,
-       0xdd000800,
-       0x000f0002,
-       0x007180c7,
-       0x00000079,
-       0xdd01b366,
-       0x000f0002,
-       0x007180c8,
-       0x00000079,
-       0xdd01b3e7,
-       0x000f0002,
-       0x007180c9,
-       0x00000075,
-       0xf1018662,
-       0x000f0002,
-       0x007180ca,
-       0x00000075,
-       0xd201b164,
-       0x000f0002,
-       0x007180cb,
-       0x00000078,
-       0x1d007b76,
-       0x000f0002,
-       0x007180cc,
-       0x00000025,
-       0xdd0001e3,
-       0x000f0002,
-       0x007180cd,
-       0x00000008,
-       0x01b13162,
-       0x000f0002,
-       0x007180ce,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007180cf,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007180d0,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007180d1,
-       0x00000021,
-       0xe3379f63,
-       0x000f0002,
-       0x007180d2,
-       0x00000049,
-       0xd3003b7c,
-       0x000f0002,
-       0x007180d3,
-       0x00000079,
-       0xd381bb7c,
-       0x000f0002,
-       0x007180d4,
-       0x0000007f,
-       0xd101b27c,
-       0x000f0002,
-       0x007180d5,
-       0x00000048,
-       0x51003264,
-       0x000f0002,
-       0x007180d6,
-       0x00000075,
-       0xd201b164,
-       0x000f0002,
-       0x007180d7,
-       0x00000078,
-       0x1d007b76,
-       0x000f0002,
-       0x007180d8,
-       0x0000003f,
-       0xdd000004,
-       0x000f0002,
-       0x007180d9,
-       0x00000079,
-       0xdd01c081,
-       0x000f0002,
-       0x007180da,
-       0x00000079,
-       0xfd609076,
-       0x000f0002,
-       0x007180db,
-       0x0000002d,
-       0xdd080803,
-       0x000f0002,
-       0x007180dc,
-       0x00000078,
-       0x3d01c081,
-       0x000f0002,
-       0x007180dd,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007180de,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007180df,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007180e0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007180e1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007180e2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007180e3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007180e4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007180e5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007180e6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007180e7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007180e8,
-       0x00000049,
-       0xd18e3b03,
-       0x000f0002,
-       0x007180e9,
-       0x0000002f,
-       0xd18100e3,
-       0x000f0002,
-       0x007180ea,
-       0x0000003f,
-       0xd1801803,
-       0x000f0002,
-       0x007180eb,
-       0x00000049,
-       0xd1043b03,
-       0x000f0002,
-       0x007180ec,
-       0x0000003f,
-       0xdd800203,
-       0x000f0002,
-       0x007180ed,
-       0x00000049,
-       0xd2043b02,
-       0x000f0002,
-       0x007180ee,
-       0x00000049,
-       0xd2843b00,
-       0x000f0002,
-       0x007180ef,
-       0x00000025,
-       0xdd0000e2,
-       0x000f0002,
-       0x007180f0,
-       0x00000094,
-       0x00134162,
-       0x000f0002,
-       0x007180f1,
-       0x00000094,
-       0x000b4362,
-       0x000f0002,
-       0x007180f2,
-       0x00000094,
-       0x001548e2,
-       0x000f0002,
-       0x007180f3,
-       0x00000094,
-       0x001b4962,
-       0x000f0002,
-       0x007180f4,
-       0x00000094,
-       0x002f4076,
-       0x000f0002,
-       0x007180f5,
-       0x00000009,
-       0xcf813d7a,
-       0x000f0002,
-       0x007180f6,
-       0x0000001d,
-       0xfd2b80e5,
-       0x000f0002,
-       0x007180f7,
-       0x00000030,
-       0x31838063,
-       0x000f0002,
-       0x007180f8,
-       0x00000030,
-       0x11828063,
-       0x000f0002,
-       0x007180f9,
-       0x0000001d,
-       0xfd2580e5,
-       0x000f0002,
-       0x007180fa,
-       0x00000030,
-       0x31830063,
-       0x000f0002,
-       0x007180fb,
-       0x00000030,
-       0x11820063,
-       0x000f0002,
-       0x007180fc,
-       0x0000002f,
-       0xd18100e3,
-       0x000f0002,
-       0x007180fd,
-       0x0000001d,
-       0xfd0980e5,
-       0x000f0002,
-       0x007180fe,
-       0x00000030,
-       0x3183d363,
-       0x000f0002,
-       0x007180ff,
-       0x00000030,
-       0x1183d263,
-       0x000f0002,
-       0x00718100,
-       0x0000002f,
-       0xd18100e3,
-       0x000f0002,
-       0x00718101,
-       0x0000003f,
-       0xd6800184,
-       0x000f0002,
-       0x00718102,
-       0x0000003f,
-       0xd6800001,
-       0x000f0002,
-       0x00718103,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x00718104,
-       0x00000018,
-       0x37ff0081,
-       0x000f0002,
-       0x00718105,
-       0x00000025,
-       0xd2000264,
-       0x000f0002,
-       0x00718106,
-       0x00000018,
-       0x7d77fd7a,
-       0x000f0002,
-       0x00718107,
-       0x00000049,
-       0xde203b63,
-       0x000f0002,
-       0x00718108,
-       0x00000049,
-       0xde803b79,
-       0x000f0002,
-       0x00718109,
-       0x00000021,
-       0xd18000e3,
-       0x000f0002,
-       0x0071810a,
-       0x00000009,
-       0xcf813d7a,
-       0x000f0002,
-       0x0071810b,
-       0x00000049,
-       0xdd0031e3,
-       0x000f0002,
-       0x0071810c,
-       0x00000069,
-       0xdd0e3b78,
-       0x000f0002,
-       0x0071810d,
-       0x00000061,
-       0xdd003b76,
-       0x000f0002,
-       0x0071810e,
-       0x0000003f,
-       0xdd000184,
-       0x000f0002,
-       0x0071810f,
-       0x0000003f,
-       0xdd000001,
-       0x000f0002,
-       0x00718110,
-       0x00000035,
-       0xdd0000fa,
-       0x000f0002,
-       0x00718111,
-       0x00000018,
-       0x3b7f3b76,
-       0x000f0002,
-       0x00718112,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718113,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718114,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x00718115,
-       0x00000021,
-       0xd18000e3,
-       0x000f0002,
-       0x00718116,
-       0x00000069,
-       0xdd043b79,
-       0x000f0002,
-       0x00718117,
-       0x00000061,
-       0xf18000e3,
-       0x000f0002,
-       0x00718118,
-       0x0000003f,
-       0xd6800184,
-       0x000f0002,
-       0x00718119,
-       0x0000003f,
-       0xd6800001,
-       0x000f0002,
-       0x0071811a,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x0071811b,
-       0x00000018,
-       0x37ff0081,
-       0x000f0002,
-       0x0071811c,
-       0x00000025,
-       0xd2000264,
-       0x000f0002,
-       0x0071811d,
-       0x00000098,
-       0x605dbb76,
-       0x000f0002,
-       0x0071811e,
-       0x00000009,
-       0xcf813d7a,
-       0x000f0002,
-       0x0071811f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718120,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718121,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718122,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718123,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718124,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718125,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718126,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718127,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718128,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718129,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071812a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071812b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071812c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071812d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071812e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071812f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718130,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718131,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718132,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718133,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718134,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718135,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718136,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718137,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718138,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718139,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071813a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071813b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071813c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071813d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071813e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071813f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718140,
-       0x00000049,
-       0xd4083b01,
-       0x000f0002,
-       0x00718141,
-       0x00000009,
-       0xc28b3d7a,
-       0x000f0002,
-       0x00718142,
-       0x0000003f,
-       0xd4000380,
-       0x000f0002,
-       0x00718143,
-       0x00000009,
-       0xc28b3d7a,
-       0x000f0002,
-       0x00718144,
-       0x00000049,
-       0xd40e3b03,
-       0x000f0002,
-       0x00718145,
-       0x0000003f,
-       0xd6420000,
-       0x000f0002,
-       0x00718146,
-       0x0000002f,
-       0xd2814080,
-       0x000f0002,
-       0x00718147,
-       0x0000002d,
-       0xd2840365,
-       0x000f0002,
-       0x00718148,
-       0x0000003f,
-       0xd6800080,
-       0x000f0002,
-       0x00718149,
-       0x0000003f,
-       0xdd040004,
-       0x000f0002,
-       0x0071814a,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x0071814b,
-       0x00000069,
-       0xdd003b6d,
-       0x000f0002,
-       0x0071814c,
-       0x00000069,
-       0xdd003b6d,
-       0x000f0002,
-       0x0071814d,
-       0x00000031,
-       0xd303d265,
-       0x000f0002,
-       0x0071814e,
-       0x00000049,
-       0xde403b66,
-       0x000f0002,
-       0x0071814f,
-       0x0000003f,
-       0xd6800184,
-       0x000f0002,
-       0x00718150,
-       0x0000003f,
-       0xd6800001,
-       0x000f0002,
-       0x00718151,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x00718152,
-       0x00000018,
-       0x37ff0081,
-       0x000f0002,
-       0x00718153,
-       0x00000049,
-       0xd5803b7e,
-       0x000f0002,
-       0x00718154,
-       0x00000021,
-       0xde4000e6,
-       0x000f0002,
-       0x00718155,
-       0x0000003f,
-       0xd6800184,
-       0x000f0002,
-       0x00718156,
-       0x0000003f,
-       0xd6800001,
-       0x000f0002,
-       0x00718157,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x00718158,
-       0x00000018,
-       0x37ff0081,
-       0x000f0002,
-       0x00718159,
-       0x00000049,
-       0xd5003b7e,
-       0x000f0002,
-       0x0071815a,
-       0x00000079,
-       0xdd013b76,
-       0x000f0002,
-       0x0071815b,
-       0x0000002d,
-       0xdd04407f,
-       0x000f0002,
-       0x0071815c,
-       0x00000018,
-       0x3d7f3b76,
-       0x000f0002,
-       0x0071815d,
-       0x00000079,
-       0xdd01bb76,
-       0x000f0002,
-       0x0071815e,
-       0x00000075,
-       0xfd0180e8,
-       0x000f0002,
-       0x0071815f,
-       0x00000094,
-       0x00154168,
-       0x000f0002,
-       0x00718160,
-       0x00000094,
-       0x002544e8,
-       0x000f0002,
-       0x00718161,
-       0x00000094,
-       0x002341e8,
-       0x000f0002,
-       0x00718162,
-       0x00000094,
-       0x00174568,
-       0x000f0002,
-       0x00718163,
-       0x00000094,
-       0x00154268,
-       0x000f0002,
-       0x00718164,
-       0x00000094,
-       0x002742e8,
-       0x000f0002,
-       0x00718165,
-       0x00000094,
-       0x002d4368,
-       0x000f0002,
-       0x00718166,
-       0x00000094,
-       0x002d4468,
-       0x000f0002,
-       0x00718167,
-       0x00000094,
-       0x003343e8,
-       0x000f0002,
-       0x00718168,
-       0x00000004,
-       0x03973b76,
-       0x000f0002,
-       0x00718169,
-       0x0000000d,
-       0xe30dc165,
-       0x000f0002,
-       0x0071816a,
-       0x00000030,
-       0x32030076,
-       0x000f0002,
-       0x0071816b,
-       0x00000030,
-       0x12020076,
-       0x000f0002,
-       0x0071816c,
-       0x0000003f,
-       0xd4800000,
-       0x000f0002,
-       0x0071816d,
-       0x0000003f,
-       0xd1808000,
-       0x000f0002,
-       0x0071816e,
-       0x0000000d,
-       0xe33fc165,
-       0x000f0002,
-       0x0071816f,
-       0x00000030,
-       0x32046076,
-       0x000f0002,
-       0x00718170,
-       0x00000030,
-       0x12044076,
-       0x000f0002,
-       0x00718171,
-       0x0000003f,
-       0xd4828000,
-       0x000f0002,
-       0x00718172,
-       0x0000003f,
-       0xd1808000,
-       0x000f0002,
-       0x00718173,
-       0x0000000d,
-       0xe33fc165,
-       0x000f0002,
-       0x00718174,
-       0x00000030,
-       0x32042076,
-       0x000f0002,
-       0x00718175,
-       0x00000030,
-       0x12040076,
-       0x000f0002,
-       0x00718176,
-       0x0000003f,
-       0xd4820000,
-       0x000f0002,
-       0x00718177,
-       0x0000000d,
-       0xe363c165,
-       0x000f0002,
-       0x00718178,
-       0x00000030,
-       0x32032076,
-       0x000f0002,
-       0x00718179,
-       0x00000030,
-       0x12030076,
-       0x000f0002,
-       0x0071817a,
-       0x0000003f,
-       0xd4830000,
-       0x000f0002,
-       0x0071817b,
-       0x00000049,
-       0xd2803b76,
-       0x000f0002,
-       0x0071817c,
-       0x0000000d,
-       0xe30dc165,
-       0x000f0002,
-       0x0071817d,
-       0x00000030,
-       0x32038076,
-       0x000f0002,
-       0x0071817e,
-       0x00000030,
-       0x12028076,
-       0x000f0002,
-       0x0071817f,
-       0x0000003f,
-       0xd4810000,
-       0x000f0002,
-       0x00718180,
-       0x0000003f,
-       0xd6020000,
-       0x000f0002,
-       0x00718181,
-       0x0000003f,
-       0xd1810000,
-       0x000f0002,
-       0x00718182,
-       0x0000000d,
-       0xe33fc165,
-       0x000f0002,
-       0x00718183,
-       0x00000030,
-       0x32042076,
-       0x000f0002,
-       0x00718184,
-       0x00000030,
-       0x12040076,
-       0x000f0002,
-       0x00718185,
-       0x0000003f,
-       0xd4820000,
-       0x000f0002,
-       0x00718186,
-       0x00000041,
-       0xd48034eb,
-       0x000f0002,
-       0x00718187,
-       0x00000079,
-       0xdd01bb6a,
-       0x000f0002,
-       0x00718188,
-       0x00000079,
-       0xdd01bb76,
-       0x000f0002,
-       0x00718189,
-       0x0000003f,
-       0xd2001803,
-       0x000f0002,
-       0x0071818a,
-       0x0000003f,
-       0xd1810000,
-       0x000f0002,
-       0x0071818b,
-       0x00000075,
-       0xfd018063,
-       0x000f0002,
-       0x0071818c,
-       0x00000098,
-       0x80693b64,
-       0x000f0002,
-       0x0071818d,
-       0x00000051,
-       0xf20000e4,
-       0x000f0002,
-       0x0071818e,
-       0x0000003f,
-       0xd6800184,
-       0x000f0002,
-       0x0071818f,
-       0x0000003f,
-       0xd6800001,
-       0x000f0002,
-       0x00718190,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x00718191,
-       0x00000018,
-       0x37ff0081,
-       0x000f0002,
-       0x00718192,
-       0x0000002d,
-       0xdd04407f,
-       0x000f0002,
-       0x00718193,
-       0x00000018,
-       0x3d7f3b76,
-       0x000f0002,
-       0x00718194,
-       0x00000049,
-       0xd3c03b38,
-       0x000f0002,
-       0x00718195,
-       0x00000049,
-       0xdd003b64,
-       0x000f0002,
-       0x00718196,
-       0x00000051,
-       0xf20000e4,
-       0x000f0002,
-       0x00718197,
-       0x0000003f,
-       0xd6800184,
-       0x000f0002,
-       0x00718198,
-       0x0000003f,
-       0xd6800001,
-       0x000f0002,
-       0x00718199,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x0071819a,
-       0x00000018,
-       0x37ff0081,
-       0x000f0002,
-       0x0071819b,
-       0x00000049,
-       0xd3a03b38,
-       0x000f0002,
-       0x0071819c,
-       0x00000019,
-       0xdd61bb76,
-       0x000f0002,
-       0x0071819d,
-       0x00000049,
-       0xdd003b67,
-       0x000f0002,
-       0x0071819e,
-       0x00000075,
-       0xf1818263,
-       0x000f0002,
-       0x0071819f,
-       0x00000041,
-       0xd48034eb,
-       0x000f0002,
-       0x007181a0,
-       0x00000079,
-       0xdd01bb6a,
-       0x000f0002,
-       0x007181a1,
-       0x00000079,
-       0xdd01bb76,
-       0x000f0002,
-       0x007181a2,
-       0x0000003f,
-       0xd2001803,
-       0x000f0002,
-       0x007181a3,
-       0x0000003f,
-       0xd1808000,
-       0x000f0002,
-       0x007181a4,
-       0x00000075,
-       0xfd018063,
-       0x000f0002,
-       0x007181a5,
-       0x00000098,
-       0x80373b64,
-       0x000f0002,
-       0x007181a6,
-       0x00000051,
-       0xf20000e4,
-       0x000f0002,
-       0x007181a7,
-       0x0000003f,
-       0xd6800184,
-       0x000f0002,
-       0x007181a8,
-       0x0000003f,
-       0xd6800001,
-       0x000f0002,
-       0x007181a9,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x007181aa,
-       0x00000018,
-       0x37ff0081,
-       0x000f0002,
-       0x007181ab,
-       0x0000002d,
-       0xdd04407f,
-       0x000f0002,
-       0x007181ac,
-       0x00000018,
-       0x3d7f3b76,
-       0x000f0002,
-       0x007181ad,
-       0x00000049,
-       0xd3803b38,
-       0x000f0002,
-       0x007181ae,
-       0x00000019,
-       0xdd6fbb76,
-       0x000f0002,
-       0x007181af,
-       0x00000049,
-       0xdd003b67,
-       0x000f0002,
-       0x007181b0,
-       0x00000075,
-       0xf1818263,
-       0x000f0002,
-       0x007181b1,
-       0x00000041,
-       0xd48034eb,
-       0x000f0002,
-       0x007181b2,
-       0x00000079,
-       0xdd01bb6a,
-       0x000f0002,
-       0x007181b3,
-       0x00000079,
-       0xdd01bb63,
-       0x000f0002,
-       0x007181b4,
-       0x00000075,
-       0xfd018063,
-       0x000f0002,
-       0x007181b5,
-       0x00000098,
-       0x80173b64,
-       0x000f0002,
-       0x007181b6,
-       0x00000049,
-       0xde403b64,
-       0x000f0002,
-       0x007181b7,
-       0x0000003f,
-       0xd6800184,
-       0x000f0002,
-       0x007181b8,
-       0x0000003f,
-       0xd6800001,
-       0x000f0002,
-       0x007181b9,
-       0x00000035,
-       0xd68000ed,
-       0x000f0002,
-       0x007181ba,
-       0x00000018,
-       0x37ff0081,
-       0x000f0002,
-       0x007181bb,
-       0x0000002d,
-       0xdd04407f,
-       0x000f0002,
-       0x007181bc,
-       0x00000018,
-       0x3d7f3b76,
-       0x000f0002,
-       0x007181bd,
-       0x00000021,
-       0xd20000e4,
-       0x000f0002,
-       0x007181be,
-       0x00000019,
-       0xd3ef7b7e,
-       0x000f0002,
-       0x007181bf,
-       0x00000075,
-       0xf1818263,
-       0x000f0002,
-       0x007181c0,
-       0x0000003f,
-       0xd6800000,
-       0x000f0002,
-       0x007181c1,
-       0x0000003f,
-       0xdd040004,
-       0x000f0002,
-       0x007181c2,
-       0x0000003f,
-       0xdd180001,
-       0x000f0002,
-       0x007181c3,
-       0x00000069,
-       0xdd003b6d,
-       0x000f0002,
-       0x007181c4,
-       0x00000069,
-       0xdd003b6d,
-       0x000f0002,
-       0x007181c5,
-       0x0000003f,
-       0xdd000000,
-       0x000f0002,
-       0x007181c6,
-       0x0000002d,
-       0xdd540180,
-       0x000f0002,
-       0x007181c7,
-       0x00000079,
-       0xf3e08076,
-       0x000f0002,
-       0x007181c8,
-       0x00000049,
-       0xd600367a,
-       0x000f0002,
-       0x007181c9,
-       0x00000079,
-       0xdd01fb76,
-       0x000f0002,
-       0x007181ca,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007181cb,
-       0x00000049,
-       0xdd003b03,
-       0x000f0002,
-       0x007181cc,
-       0x00000059,
-       0xfd003b76,
-       0x000f0002,
-       0x007181cd,
-       0x0000003f,
-       0xdd801c03,
-       0x000f0002,
-       0x007181ce,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007181cf,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007181d0,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007181d1,
-       0x0000002d,
-       0xdd06027f,
-       0x000f0002,
-       0x007181d2,
-       0x00000018,
-       0x1d7f3d7a,
-       0x000f0002,
-       0x007181d3,
-       0x00000031,
-       0xd483886b,
-       0x000f0002,
-       0x007181d4,
-       0x00000079,
-       0xdd01bb6a,
-       0x000f0002,
-       0x007181d5,
-       0x00000079,
-       0xf1819076,
-       0x000f0002,
-       0x007181d6,
-       0x00000075,
-       0xfd018063,
-       0x000f0002,
-       0x007181d7,
-       0x00000098,
-       0x8053bb76,
-       0x000f0002,
-       0x007181d8,
-       0x00000019,
-       0xdd7f7b79,
-       0x000f0002,
-       0x007181d9,
-       0x00000075,
-       0xf1818263,
-       0x000f0002,
-       0x007181da,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181db,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181dc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181dd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181de,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181df,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181e0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181e1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181e2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181e3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181e4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181e5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181e6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181e7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181e8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181e9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181ea,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181eb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181ec,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181ed,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181ee,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181ef,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181f0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181f1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181f2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181f3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181f4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181f5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181f6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181f7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181f8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181f9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181fa,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181fb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181fc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181fd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007181fe,
-       0x0000003f,
-       0xdd800203,
-       0x000f0002,
-       0x007181ff,
-       0x00000049,
-       0xd1843b02,
-       0x000f0002,
-       0x00718200,
-       0x00000049,
-       0xdd003b03,
-       0x000f0002,
-       0x00718201,
-       0x00000069,
-       0xdd003b7a,
-       0x000f0002,
-       0x00718202,
-       0x00000049,
-       0xdd003b79,
-       0x000f0002,
-       0x00718203,
-       0x00000065,
-       0xf1800263,
-       0x000f0002,
-       0x00718204,
-       0x00000018,
-       0x7d7d3b76,
-       0x000f0002,
-       0x00718205,
-       0x00000009,
-       0xcf813d7a,
-       0x000f0002,
-       0x00718206,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718207,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718208,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718209,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071820a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071820b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071820c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071820d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071820e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071820f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718210,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718211,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718212,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718213,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718214,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718215,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718216,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718217,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718218,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718219,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071821a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071821b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071821c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071821d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071821e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071821f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718220,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718221,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718222,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718223,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718224,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718225,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718226,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718227,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718228,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718229,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071822a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071822b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071822c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071822d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071822e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071822f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718230,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718231,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718232,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718233,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718234,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718235,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718236,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718237,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718238,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718239,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071823a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071823b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071823c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071823d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071823e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071823f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718240,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718241,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718242,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718243,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718244,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718245,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718246,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718247,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718248,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718249,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071824a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071824b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071824c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071824d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071824e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071824f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718250,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718251,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718252,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718253,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718254,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718255,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718256,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718257,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718258,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718259,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071825a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071825b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071825c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071825d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071825e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071825f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718260,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718261,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718262,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718263,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718264,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718265,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718266,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718267,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718268,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718269,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071826a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071826b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071826c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071826d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071826e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071826f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718270,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718271,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718272,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718273,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718274,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718275,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718276,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718277,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718278,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718279,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071827a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071827b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071827c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071827d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071827e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071827f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718280,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718281,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718282,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718283,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718284,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718285,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718286,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718287,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718288,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718289,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071828a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071828b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071828c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071828d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071828e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071828f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718290,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718291,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718292,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718293,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718294,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718295,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718296,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718297,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718298,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718299,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071829a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071829b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071829c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071829d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071829e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071829f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182a0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182a1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182a2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182a3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182a4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182a5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182a6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182a7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182a8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182a9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182aa,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182ab,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182ac,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182ad,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182ae,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182af,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182b0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182b1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182b2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182b3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182b4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182b5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182b6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182b7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182b8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182b9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182ba,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182bb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182bc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182bd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182be,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182bf,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182c0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182c1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182c2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182c3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182c4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182c5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182c6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182c7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182c8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182c9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182ca,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182cb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182cc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182cd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182ce,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182cf,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182d0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182d1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182d2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182d3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182d4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182d5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182d6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182d7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182d8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182d9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182da,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182db,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182dc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182dd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182de,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182df,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182e0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182e1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182e2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182e3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182e4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182e5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182e6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182e7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182e8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182e9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182ea,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182eb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182ec,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182ed,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182ee,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182ef,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182f0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182f1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182f2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182f3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182f4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182f5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182f6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182f7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182f8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182f9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182fa,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182fb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182fc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182fd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182fe,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007182ff,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718300,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718301,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718302,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718303,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718304,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718305,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718306,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718307,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718308,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718309,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071830a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071830b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071830c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071830d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071830e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071830f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718310,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718311,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718312,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718313,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718314,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718315,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718316,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718317,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718318,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718319,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071831a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071831b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071831c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071831d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071831e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071831f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718320,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718321,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718322,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718323,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718324,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718325,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718326,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718327,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718328,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718329,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071832a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071832b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071832c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071832d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071832e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071832f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718330,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718331,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718332,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718333,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718334,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718335,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718336,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718337,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718338,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718339,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071833a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071833b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071833c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071833d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071833e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071833f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718340,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718341,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718342,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718343,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718344,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718345,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718346,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718347,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718348,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718349,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071834a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071834b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071834c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071834d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071834e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071834f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718350,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718351,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718352,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718353,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718354,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718355,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718356,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718357,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718358,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718359,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071835a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071835b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071835c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071835d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071835e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071835f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718360,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718361,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718362,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718363,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718364,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718365,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718366,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718367,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718368,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718369,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071836a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071836b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071836c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071836d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071836e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071836f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718370,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718371,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718372,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718373,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718374,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718375,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718376,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718377,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718378,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718379,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071837a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071837b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071837c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071837d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071837e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071837f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718380,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718381,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718382,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718383,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718384,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718385,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718386,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718387,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718388,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718389,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071838a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071838b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071838c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071838d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071838e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071838f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718390,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718391,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718392,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718393,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718394,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718395,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718396,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718397,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718398,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718399,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071839a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071839b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071839c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071839d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071839e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071839f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183a0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183a1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183a2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183a3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183a4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183a5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183a6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183a7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183a8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183a9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183aa,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183ab,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183ac,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183ad,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183ae,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183af,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183b0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183b1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183b2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183b3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183b4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183b5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183b6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183b7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183b8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183b9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183ba,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183bb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183bc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183bd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183be,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183bf,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183c0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183c1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183c2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183c3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183c4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183c5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183c6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183c7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183c8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183c9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183ca,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183cb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183cc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183cd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183ce,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183cf,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183d0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183d1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183d2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183d3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183d4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183d5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183d6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183d7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183d8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183d9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183da,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183db,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183dc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183dd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183de,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183df,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183e0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183e1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183e2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183e3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183e4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183e5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183e6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183e7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183e8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183e9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183ea,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183eb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183ec,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183ed,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183ee,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183ef,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183f0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183f1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183f2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183f3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183f4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183f5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183f6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183f7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183f8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183f9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183fa,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183fb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183fc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183fd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183fe,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007183ff,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718400,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718401,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718402,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718403,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718404,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718405,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718406,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718407,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718408,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718409,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071840a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071840b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071840c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071840d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071840e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071840f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718410,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718411,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718412,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718413,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718414,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718415,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718416,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718417,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718418,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718419,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071841a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071841b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071841c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071841d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071841e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071841f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718420,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718421,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718422,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718423,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718424,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718425,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718426,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718427,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718428,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718429,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071842a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071842b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071842c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071842d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071842e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071842f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718430,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718431,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718432,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718433,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718434,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718435,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718436,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718437,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718438,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718439,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071843a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071843b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071843c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071843d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071843e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071843f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718440,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718441,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718442,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718443,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718444,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718445,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718446,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718447,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718448,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718449,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071844a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071844b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071844c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071844d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071844e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071844f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718450,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718451,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718452,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718453,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718454,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718455,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718456,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718457,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718458,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718459,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071845a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071845b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071845c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071845d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071845e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071845f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718460,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718461,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718462,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718463,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718464,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718465,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718466,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718467,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718468,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718469,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071846a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071846b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071846c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071846d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071846e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071846f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718470,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718471,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718472,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718473,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718474,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718475,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718476,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718477,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718478,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718479,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071847a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071847b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071847c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071847d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071847e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071847f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718480,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718481,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718482,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718483,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718484,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718485,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718486,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718487,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718488,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718489,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071848a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071848b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071848c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071848d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071848e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071848f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718490,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718491,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718492,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718493,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718494,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718495,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718496,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718497,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718498,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718499,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071849a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071849b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071849c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071849d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071849e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071849f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184a0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184a1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184a2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184a3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184a4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184a5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184a6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184a7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184a8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184a9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184aa,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184ab,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184ac,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184ad,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184ae,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184af,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184b0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184b1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184b2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184b3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184b4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184b5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184b6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184b7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184b8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184b9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184ba,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184bb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184bc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184bd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184be,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184bf,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184c0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184c1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184c2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184c3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184c4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184c5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184c6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184c7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184c8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184c9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184ca,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184cb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184cc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184cd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184ce,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184cf,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184d0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184d1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184d2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184d3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184d4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184d5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184d6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184d7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184d8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184d9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184da,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184db,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184dc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184dd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184de,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184df,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184e0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184e1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184e2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184e3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184e4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184e5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184e6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184e7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184e8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184e9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184ea,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184eb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184ec,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184ed,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184ee,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184ef,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184f0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184f1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184f2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184f3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184f4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184f5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184f6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184f7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184f8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184f9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184fa,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184fb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184fc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184fd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184fe,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007184ff,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718500,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718501,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718502,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718503,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718504,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718505,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718506,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718507,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718508,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718509,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071850a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071850b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071850c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071850d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071850e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071850f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718510,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718511,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718512,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718513,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718514,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718515,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718516,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718517,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718518,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718519,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071851a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071851b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071851c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071851d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071851e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071851f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718520,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718521,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718522,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718523,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718524,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718525,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718526,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718527,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718528,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718529,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071852a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071852b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071852c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071852d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071852e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071852f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718530,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718531,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718532,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718533,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718534,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718535,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718536,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718537,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718538,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718539,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071853a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071853b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071853c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071853d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071853e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071853f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718540,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718541,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718542,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718543,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718544,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718545,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718546,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718547,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718548,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718549,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071854a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071854b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071854c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071854d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071854e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071854f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718550,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718551,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718552,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718553,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718554,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718555,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718556,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718557,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718558,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718559,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071855a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071855b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071855c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071855d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071855e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071855f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718560,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718561,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718562,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718563,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718564,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718565,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718566,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718567,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718568,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718569,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071856a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071856b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071856c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071856d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071856e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071856f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718570,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718571,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718572,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718573,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718574,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718575,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718576,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718577,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718578,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718579,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071857a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071857b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071857c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071857d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071857e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071857f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718580,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718581,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718582,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718583,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718584,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718585,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718586,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718587,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718588,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718589,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071858a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071858b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071858c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071858d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071858e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071858f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718590,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718591,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718592,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718593,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718594,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718595,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718596,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718597,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718598,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718599,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071859a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071859b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071859c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071859d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071859e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071859f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185a0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185a1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185a2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185a3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185a4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185a5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185a6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185a7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185a8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185a9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185aa,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185ab,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185ac,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185ad,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185ae,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185af,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185b0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185b1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185b2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185b3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185b4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185b5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185b6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185b7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185b8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185b9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185ba,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185bb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185bc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185bd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185be,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185bf,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185c0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185c1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185c2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185c3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185c4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185c5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185c6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185c7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185c8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185c9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185ca,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185cb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185cc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185cd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185ce,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185cf,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185d0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185d1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185d2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185d3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185d4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185d5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185d6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185d7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185d8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185d9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185da,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185db,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185dc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185dd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185de,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185df,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185e0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185e1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185e2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185e3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185e4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185e5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185e6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185e7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185e8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185e9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185ea,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185eb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185ec,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185ed,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185ee,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185ef,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185f0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185f1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185f2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185f3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185f4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185f5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185f6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185f7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185f8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185f9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185fa,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185fb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185fc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185fd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185fe,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007185ff,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718600,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718601,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718602,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718603,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718604,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718605,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718606,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718607,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718608,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718609,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071860a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071860b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071860c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071860d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071860e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071860f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718610,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718611,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718612,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718613,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718614,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718615,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718616,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718617,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718618,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718619,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071861a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071861b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071861c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071861d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071861e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071861f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718620,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718621,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718622,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718623,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718624,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718625,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718626,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718627,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718628,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718629,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071862a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071862b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071862c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071862d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071862e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071862f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718630,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718631,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718632,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718633,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718634,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718635,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718636,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718637,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718638,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718639,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071863a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071863b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071863c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071863d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071863e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071863f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718640,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718641,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718642,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718643,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718644,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718645,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718646,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718647,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718648,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718649,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071864a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071864b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071864c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071864d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071864e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071864f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718650,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718651,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718652,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718653,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718654,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718655,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718656,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718657,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718658,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718659,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071865a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071865b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071865c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071865d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071865e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071865f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718660,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718661,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718662,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718663,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718664,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718665,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718666,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718667,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718668,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718669,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071866a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071866b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071866c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071866d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071866e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071866f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718670,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718671,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718672,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718673,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718674,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718675,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718676,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718677,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718678,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718679,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071867a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071867b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071867c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071867d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071867e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071867f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718680,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718681,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718682,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718683,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718684,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718685,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718686,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718687,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718688,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718689,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071868a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071868b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071868c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071868d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071868e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071868f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718690,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718691,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718692,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718693,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718694,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718695,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718696,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718697,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718698,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718699,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071869a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071869b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071869c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071869d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071869e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071869f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186a0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186a1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186a2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186a3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186a4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186a5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186a6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186a7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186a8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186a9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186aa,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186ab,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186ac,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186ad,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186ae,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186af,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186b0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186b1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186b2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186b3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186b4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186b5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186b6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186b7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186b8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186b9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186ba,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186bb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186bc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186bd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186be,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186bf,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186c0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186c1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186c2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186c3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186c4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186c5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186c6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186c7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186c8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186c9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186ca,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186cb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186cc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186cd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186ce,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186cf,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186d0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186d1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186d2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186d3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186d4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186d5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186d6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186d7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186d8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186d9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186da,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186db,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186dc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186dd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186de,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186df,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186e0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186e1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186e2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186e3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186e4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186e5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186e6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186e7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186e8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186e9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186ea,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186eb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186ec,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186ed,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186ee,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186ef,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186f0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186f1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186f2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186f3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186f4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186f5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186f6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186f7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186f8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186f9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186fa,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186fb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186fc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186fd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186fe,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007186ff,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718700,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718701,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718702,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718703,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718704,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718705,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718706,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718707,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718708,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718709,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071870a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071870b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071870c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071870d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071870e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071870f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718710,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718711,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718712,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718713,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718714,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718715,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718716,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718717,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718718,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718719,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071871a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071871b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071871c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071871d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071871e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071871f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718720,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718721,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718722,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718723,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718724,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718725,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718726,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718727,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718728,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718729,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071872a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071872b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071872c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071872d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071872e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071872f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718730,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718731,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718732,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718733,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718734,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718735,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718736,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718737,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718738,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718739,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071873a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071873b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071873c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071873d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071873e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071873f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718740,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718741,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718742,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718743,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718744,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718745,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718746,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718747,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718748,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718749,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071874a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071874b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071874c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071874d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071874e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071874f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718750,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718751,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718752,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718753,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718754,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718755,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718756,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718757,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718758,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718759,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071875a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071875b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071875c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071875d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071875e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071875f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718760,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718761,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718762,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718763,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718764,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718765,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718766,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718767,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718768,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718769,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071876a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071876b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071876c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071876d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071876e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071876f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718770,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718771,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718772,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718773,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718774,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718775,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718776,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718777,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718778,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718779,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071877a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071877b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071877c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071877d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071877e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071877f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718780,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718781,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718782,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718783,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718784,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718785,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718786,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718787,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718788,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718789,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071878a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071878b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071878c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071878d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071878e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071878f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718790,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718791,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718792,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718793,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718794,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718795,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718796,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718797,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718798,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x00718799,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071879a,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071879b,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071879c,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071879d,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071879e,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x0071879f,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187a0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187a1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187a2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187a3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187a4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187a5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187a6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187a7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187a8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187a9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187aa,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187ab,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187ac,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187ad,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187ae,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187af,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187b0,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187b1,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187b2,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187b3,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187b4,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187b5,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187b6,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187b7,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187b8,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187b9,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187ba,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187bb,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187bc,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187bd,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187be,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187bf,
-       0x00000000,
-       0x00000000,
-       0x000f0002,
-       0x007187c0,
-       0x00000079,
-       0xfd609076,
-       0x000f0002,
-       0x007187c1,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007187c2,
-       0x0000003d,
-       0xf780006f,
-       0x000f0002,
-       0x007187c3,
-       0x0000003d,
-       0xf780006f,
-/* FINISH INIT Descriptor */
-       0x000f0002,
-       0x807187c4,
-       0x0000003d,
-       0xf780006f,
-};
index 479a37f75f3019c6c260804fb7263280669bc642..f7efcecc4108f44e8fcdb26a83bb653a17660a36 100644 (file)
@@ -4,7 +4,7 @@
  * Copyright (C) 2001, 2002, 2003, 2004 David S. Miller (davem@redhat.com)
  * Copyright (C) 2001, 2002, 2003 Jeff Garzik (jgarzik@pobox.com)
  * Copyright (C) 2004 Sun Microsystems Inc.
- * Copyright (C) 2005-2007 Broadcom Corporation.
+ * Copyright (C) 2005-2009 Broadcom Corporation.
  *
  * Firmware is:
  *     Derived from proprietary unpublished source code,
@@ -68,8 +68,8 @@
 
 #define DRV_MODULE_NAME                "tg3"
 #define PFX DRV_MODULE_NAME    ": "
-#define DRV_MODULE_VERSION     "3.97"
-#define DRV_MODULE_RELDATE     "December 10, 2008"
+#define DRV_MODULE_VERSION     "3.98"
+#define DRV_MODULE_RELDATE     "February 25, 2009"
 
 #define TG3_DEF_MAC_MODE       0
 #define TG3_DEF_RX_MODE                0
@@ -1473,7 +1473,8 @@ static void tg3_phy_toggle_apd(struct tg3 *tp, bool enable)
 {
        u32 reg;
 
-       if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
+       if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS) ||
+           GET_ASIC_REV(tp->pci_chip_rev_id) == ASIC_REV_5906)
                return;
 
        reg = MII_TG3_MISC_SHDW_WREN |
@@ -2049,8 +2050,6 @@ static int tg3_setup_phy(struct tg3 *, int);
 
 static void tg3_write_sig_post_reset(struct tg3 *, int);
 static int tg3_halt_cpu(struct tg3 *, u32);
-static int tg3_nvram_lock(struct tg3 *);
-static void tg3_nvram_unlock(struct tg3 *);
 
 static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
 {
@@ -2106,6 +2105,194 @@ static void tg3_power_down_phy(struct tg3 *tp, bool do_low_power)
        tg3_writephy(tp, MII_BMCR, BMCR_PDOWN);
 }
 
+/* tp->lock is held. */
+static int tg3_nvram_lock(struct tg3 *tp)
+{
+       if (tp->tg3_flags & TG3_FLAG_NVRAM) {
+               int i;
+
+               if (tp->nvram_lock_cnt == 0) {
+                       tw32(NVRAM_SWARB, SWARB_REQ_SET1);
+                       for (i = 0; i < 8000; i++) {
+                               if (tr32(NVRAM_SWARB) & SWARB_GNT1)
+                                       break;
+                               udelay(20);
+                       }
+                       if (i == 8000) {
+                               tw32(NVRAM_SWARB, SWARB_REQ_CLR1);
+                               return -ENODEV;
+                       }
+               }
+               tp->nvram_lock_cnt++;
+       }
+       return 0;
+}
+
+/* tp->lock is held. */
+static void tg3_nvram_unlock(struct tg3 *tp)
+{
+       if (tp->tg3_flags & TG3_FLAG_NVRAM) {
+               if (tp->nvram_lock_cnt > 0)
+                       tp->nvram_lock_cnt--;
+               if (tp->nvram_lock_cnt == 0)
+                       tw32_f(NVRAM_SWARB, SWARB_REQ_CLR1);
+       }
+}
+
+/* tp->lock is held. */
+static void tg3_enable_nvram_access(struct tg3 *tp)
+{
+       if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
+           !(tp->tg3_flags2 & TG3_FLG2_PROTECTED_NVRAM)) {
+               u32 nvaccess = tr32(NVRAM_ACCESS);
+
+               tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
+       }
+}
+
+/* tp->lock is held. */
+static void tg3_disable_nvram_access(struct tg3 *tp)
+{
+       if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
+           !(tp->tg3_flags2 & TG3_FLG2_PROTECTED_NVRAM)) {
+               u32 nvaccess = tr32(NVRAM_ACCESS);
+
+               tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
+       }
+}
+
+static int tg3_nvram_read_using_eeprom(struct tg3 *tp,
+                                       u32 offset, u32 *val)
+{
+       u32 tmp;
+       int i;
+
+       if (offset > EEPROM_ADDR_ADDR_MASK || (offset % 4) != 0)
+               return -EINVAL;
+
+       tmp = tr32(GRC_EEPROM_ADDR) & ~(EEPROM_ADDR_ADDR_MASK |
+                                       EEPROM_ADDR_DEVID_MASK |
+                                       EEPROM_ADDR_READ);
+       tw32(GRC_EEPROM_ADDR,
+            tmp |
+            (0 << EEPROM_ADDR_DEVID_SHIFT) |
+            ((offset << EEPROM_ADDR_ADDR_SHIFT) &
+             EEPROM_ADDR_ADDR_MASK) |
+            EEPROM_ADDR_READ | EEPROM_ADDR_START);
+
+       for (i = 0; i < 1000; i++) {
+               tmp = tr32(GRC_EEPROM_ADDR);
+
+               if (tmp & EEPROM_ADDR_COMPLETE)
+                       break;
+               msleep(1);
+       }
+       if (!(tmp & EEPROM_ADDR_COMPLETE))
+               return -EBUSY;
+
+       *val = tr32(GRC_EEPROM_DATA);
+       return 0;
+}
+
+#define NVRAM_CMD_TIMEOUT 10000
+
+static int tg3_nvram_exec_cmd(struct tg3 *tp, u32 nvram_cmd)
+{
+       int i;
+
+       tw32(NVRAM_CMD, nvram_cmd);
+       for (i = 0; i < NVRAM_CMD_TIMEOUT; i++) {
+               udelay(10);
+               if (tr32(NVRAM_CMD) & NVRAM_CMD_DONE) {
+                       udelay(10);
+                       break;
+               }
+       }
+
+       if (i == NVRAM_CMD_TIMEOUT)
+               return -EBUSY;
+
+       return 0;
+}
+
+static u32 tg3_nvram_phys_addr(struct tg3 *tp, u32 addr)
+{
+       if ((tp->tg3_flags & TG3_FLAG_NVRAM) &&
+           (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
+           (tp->tg3_flags2 & TG3_FLG2_FLASH) &&
+          !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) &&
+           (tp->nvram_jedecnum == JEDEC_ATMEL))
+
+               addr = ((addr / tp->nvram_pagesize) <<
+                       ATMEL_AT45DB0X1B_PAGE_POS) +
+                      (addr % tp->nvram_pagesize);
+
+       return addr;
+}
+
+static u32 tg3_nvram_logical_addr(struct tg3 *tp, u32 addr)
+{
+       if ((tp->tg3_flags & TG3_FLAG_NVRAM) &&
+           (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
+           (tp->tg3_flags2 & TG3_FLG2_FLASH) &&
+          !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) &&
+           (tp->nvram_jedecnum == JEDEC_ATMEL))
+
+               addr = ((addr >> ATMEL_AT45DB0X1B_PAGE_POS) *
+                       tp->nvram_pagesize) +
+                      (addr & ((1 << ATMEL_AT45DB0X1B_PAGE_POS) - 1));
+
+       return addr;
+}
+
+/* NOTE: Data read in from NVRAM is byteswapped according to
+ * the byteswapping settings for all other register accesses.
+ * tg3 devices are BE devices, so on a BE machine, the data
+ * returned will be exactly as it is seen in NVRAM.  On a LE
+ * machine, the 32-bit value will be byteswapped.
+ */
+static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val)
+{
+       int ret;
+
+       if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
+               return tg3_nvram_read_using_eeprom(tp, offset, val);
+
+       offset = tg3_nvram_phys_addr(tp, offset);
+
+       if (offset > NVRAM_ADDR_MSK)
+               return -EINVAL;
+
+       ret = tg3_nvram_lock(tp);
+       if (ret)
+               return ret;
+
+       tg3_enable_nvram_access(tp);
+
+       tw32(NVRAM_ADDR, offset);
+       ret = tg3_nvram_exec_cmd(tp, NVRAM_CMD_RD | NVRAM_CMD_GO |
+               NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE);
+
+       if (ret == 0)
+               *val = tr32(NVRAM_RDDATA);
+
+       tg3_disable_nvram_access(tp);
+
+       tg3_nvram_unlock(tp);
+
+       return ret;
+}
+
+/* Ensures NVRAM data is in bytestream format. */
+static int tg3_nvram_read_be32(struct tg3 *tp, u32 offset, __be32 *val)
+{
+       u32 v;
+       int res = tg3_nvram_read(tp, offset, &v);
+       if (!res)
+               *val = cpu_to_be32(v);
+       return res;
+}
+
 /* tp->lock is held. */
 static void __tg3_set_mac_addr(struct tg3 *tp, int skip_mac_1)
 {
@@ -2237,8 +2424,8 @@ static int tg3_set_power_state(struct tg3 *tp, pci_power_t state)
                        phyid = phydev->drv->phy_id & phydev->drv->phy_id_mask;
                        if (phyid != TG3_PHY_ID_BCMAC131) {
                                phyid &= TG3_PHY_OUI_MASK;
-                               if (phyid == TG3_PHY_OUI_1 &&
-                                   phyid == TG3_PHY_OUI_2 &&
+                               if (phyid == TG3_PHY_OUI_1 ||
+                                   phyid == TG3_PHY_OUI_2 ||
                                    phyid == TG3_PHY_OUI_3)
                                        do_low_power = true;
                        }
@@ -4338,6 +4525,13 @@ static int tg3_rx(struct tg3 *tp, int budget)
                        skb->ip_summed = CHECKSUM_NONE;
 
                skb->protocol = eth_type_trans(skb, tp->dev);
+
+               if (len > (tp->dev->mtu + ETH_HLEN) &&
+                   skb->protocol != htons(ETH_P_8021Q)) {
+                       dev_kfree_skb(skb);
+                       goto next_pkt;
+               }
+
 #if TG3_VLAN_TAG_USED
                if (tp->vlgrp != NULL &&
                    desc->type_flags & RXD_FLAG_VLAN) {
@@ -5630,62 +5824,6 @@ static int tg3_abort_hw(struct tg3 *tp, int silent)
        return err;
 }
 
-/* tp->lock is held. */
-static int tg3_nvram_lock(struct tg3 *tp)
-{
-       if (tp->tg3_flags & TG3_FLAG_NVRAM) {
-               int i;
-
-               if (tp->nvram_lock_cnt == 0) {
-                       tw32(NVRAM_SWARB, SWARB_REQ_SET1);
-                       for (i = 0; i < 8000; i++) {
-                               if (tr32(NVRAM_SWARB) & SWARB_GNT1)
-                                       break;
-                               udelay(20);
-                       }
-                       if (i == 8000) {
-                               tw32(NVRAM_SWARB, SWARB_REQ_CLR1);
-                               return -ENODEV;
-                       }
-               }
-               tp->nvram_lock_cnt++;
-       }
-       return 0;
-}
-
-/* tp->lock is held. */
-static void tg3_nvram_unlock(struct tg3 *tp)
-{
-       if (tp->tg3_flags & TG3_FLAG_NVRAM) {
-               if (tp->nvram_lock_cnt > 0)
-                       tp->nvram_lock_cnt--;
-               if (tp->nvram_lock_cnt == 0)
-                       tw32_f(NVRAM_SWARB, SWARB_REQ_CLR1);
-       }
-}
-
-/* tp->lock is held. */
-static void tg3_enable_nvram_access(struct tg3 *tp)
-{
-       if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
-           !(tp->tg3_flags2 & TG3_FLG2_PROTECTED_NVRAM)) {
-               u32 nvaccess = tr32(NVRAM_ACCESS);
-
-               tw32(NVRAM_ACCESS, nvaccess | ACCESS_ENABLE);
-       }
-}
-
-/* tp->lock is held. */
-static void tg3_disable_nvram_access(struct tg3 *tp)
-{
-       if ((tp->tg3_flags2 & TG3_FLG2_5750_PLUS) &&
-           !(tp->tg3_flags2 & TG3_FLG2_PROTECTED_NVRAM)) {
-               u32 nvaccess = tr32(NVRAM_ACCESS);
-
-               tw32(NVRAM_ACCESS, nvaccess & ~ACCESS_ENABLE);
-       }
-}
-
 static void tg3_ape_send_event(struct tg3 *tp, u32 event)
 {
        int i;
@@ -6823,7 +6961,8 @@ static int tg3_reset_hw(struct tg3 *tp, int reset_phy)
        __tg3_set_mac_addr(tp, 0);
 
        /* MTU + ethernet header + FCS + optional VLAN tag */
-       tw32(MAC_RX_MTU_SIZE, tp->dev->mtu + ETH_HLEN + 8);
+       tw32(MAC_RX_MTU_SIZE,
+            tp->dev->mtu + ETH_HLEN + ETH_FCS_LEN + VLAN_HLEN);
 
        /* The slot time is changed by tg3_setup_phy if we
         * run at gigabit with half duplex.
@@ -8385,17 +8524,13 @@ static int tg3_get_eeprom_len(struct net_device *dev)
        return tp->nvram_size;
 }
 
-static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val);
-static int tg3_nvram_read_le(struct tg3 *tp, u32 offset, __le32 *val);
-static int tg3_nvram_read_swab(struct tg3 *tp, u32 offset, u32 *val);
-
 static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom, u8 *data)
 {
        struct tg3 *tp = netdev_priv(dev);
        int ret;
        u8  *pd;
        u32 i, offset, len, b_offset, b_count;
-       __le32 val;
+       __be32 val;
 
        if (tp->link_config.phy_is_low_power)
                return -EAGAIN;
@@ -8414,7 +8549,7 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                        /* i.e. offset=1 len=2 */
                        b_count = len;
                }
-               ret = tg3_nvram_read_le(tp, offset-b_offset, &val);
+               ret = tg3_nvram_read_be32(tp, offset-b_offset, &val);
                if (ret)
                        return ret;
                memcpy(data, ((char*)&val) + b_offset, b_count);
@@ -8426,7 +8561,7 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        /* read bytes upto the last 4 byte boundary */
        pd = &data[eeprom->len];
        for (i = 0; i < (len - (len & 3)); i += 4) {
-               ret = tg3_nvram_read_le(tp, offset + i, &val);
+               ret = tg3_nvram_read_be32(tp, offset + i, &val);
                if (ret) {
                        eeprom->len += i;
                        return ret;
@@ -8440,7 +8575,7 @@ static int tg3_get_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                pd = &data[eeprom->len];
                b_count = len & 3;
                b_offset = offset + len - b_count;
-               ret = tg3_nvram_read_le(tp, b_offset, &val);
+               ret = tg3_nvram_read_be32(tp, b_offset, &val);
                if (ret)
                        return ret;
                memcpy(pd, &val, b_count);
@@ -8457,7 +8592,7 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
        int ret;
        u32 offset, len, b_offset, odd_len;
        u8 *buf;
-       __le32 start, end;
+       __be32 start, end;
 
        if (tp->link_config.phy_is_low_power)
                return -EAGAIN;
@@ -8470,7 +8605,7 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
 
        if ((b_offset = (offset & 3))) {
                /* adjustments to start on required 4 byte boundary */
-               ret = tg3_nvram_read_le(tp, offset-b_offset, &start);
+               ret = tg3_nvram_read_be32(tp, offset-b_offset, &start);
                if (ret)
                        return ret;
                len += b_offset;
@@ -8484,7 +8619,7 @@ static int tg3_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
                /* adjustments to end on required 4 byte boundary */
                odd_len = 1;
                len = (len + 3) & ~3;
-               ret = tg3_nvram_read_le(tp, offset+len-4, &end);
+               ret = tg3_nvram_read_be32(tp, offset+len-4, &end);
                if (ret)
                        return ret;
        }
@@ -8543,7 +8678,7 @@ static int tg3_get_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                cmd->duplex = tp->link_config.active_duplex;
        }
        cmd->phy_address = PHY_ADDR;
-       cmd->transceiver = 0;
+       cmd->transceiver = XCVR_INTERNAL;
        cmd->autoneg = tp->link_config.autoneg;
        cmd->maxtxpkt = 0;
        cmd->maxrxpkt = 0;
@@ -8560,26 +8695,58 @@ static int tg3_set_settings(struct net_device *dev, struct ethtool_cmd *cmd)
                return phy_ethtool_sset(tp->mdio_bus->phy_map[PHY_ADDR], cmd);
        }
 
-       if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
-               /* These are the only valid advertisement bits allowed.  */
-               if (cmd->autoneg == AUTONEG_ENABLE &&
-                   (cmd->advertising & ~(ADVERTISED_1000baseT_Half |
-                                         ADVERTISED_1000baseT_Full |
-                                         ADVERTISED_Autoneg |
-                                         ADVERTISED_FIBRE)))
-                       return -EINVAL;
-               /* Fiber can only do SPEED_1000.  */
-               else if ((cmd->autoneg != AUTONEG_ENABLE) &&
-                        (cmd->speed != SPEED_1000))
-                       return -EINVAL;
-       /* Copper cannot force SPEED_1000.  */
-       } else if ((cmd->autoneg != AUTONEG_ENABLE) &&
-                  (cmd->speed == SPEED_1000))
+       if (cmd->autoneg != AUTONEG_ENABLE &&
+           cmd->autoneg != AUTONEG_DISABLE)
                return -EINVAL;
-       else if ((cmd->speed == SPEED_1000) &&
-                (tp->tg3_flags & TG3_FLAG_10_100_ONLY))
+
+       if (cmd->autoneg == AUTONEG_DISABLE &&
+           cmd->duplex != DUPLEX_FULL &&
+           cmd->duplex != DUPLEX_HALF)
                return -EINVAL;
 
+       if (cmd->autoneg == AUTONEG_ENABLE) {
+               u32 mask = ADVERTISED_Autoneg |
+                          ADVERTISED_Pause |
+                          ADVERTISED_Asym_Pause;
+
+               if (!(tp->tg3_flags2 & TG3_FLAG_10_100_ONLY))
+                       mask |= ADVERTISED_1000baseT_Half |
+                               ADVERTISED_1000baseT_Full;
+
+               if (!(tp->tg3_flags2 & TG3_FLG2_ANY_SERDES))
+                       mask |= ADVERTISED_100baseT_Half |
+                               ADVERTISED_100baseT_Full |
+                               ADVERTISED_10baseT_Half |
+                               ADVERTISED_10baseT_Full |
+                               ADVERTISED_TP;
+               else
+                       mask |= ADVERTISED_FIBRE;
+
+               if (cmd->advertising & ~mask)
+                       return -EINVAL;
+
+               mask &= (ADVERTISED_1000baseT_Half |
+                        ADVERTISED_1000baseT_Full |
+                        ADVERTISED_100baseT_Half |
+                        ADVERTISED_100baseT_Full |
+                        ADVERTISED_10baseT_Half |
+                        ADVERTISED_10baseT_Full);
+
+               cmd->advertising &= mask;
+       } else {
+               if (tp->tg3_flags2 & TG3_FLG2_ANY_SERDES) {
+                       if (cmd->speed != SPEED_1000)
+                               return -EINVAL;
+
+                       if (cmd->duplex != DUPLEX_FULL)
+                               return -EINVAL;
+               } else {
+                       if (cmd->speed != SPEED_100 &&
+                           cmd->speed != SPEED_10)
+                               return -EINVAL;
+               }
+       }
+
        tg3_full_lock(tp, 0);
 
        tp->link_config.autoneg = cmd->autoneg;
@@ -9024,10 +9191,10 @@ static void tg3_get_ethtool_stats (struct net_device *dev,
 static int tg3_test_nvram(struct tg3 *tp)
 {
        u32 csum, magic;
-       __le32 *buf;
+       __be32 *buf;
        int i, j, k, err = 0, size;
 
-       if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
+       if (tg3_nvram_read(tp, 0, &magic) != 0)
                return -EIO;
 
        if (magic == TG3_EEPROM_MAGIC)
@@ -9061,14 +9228,15 @@ static int tg3_test_nvram(struct tg3 *tp)
 
        err = -EIO;
        for (i = 0, j = 0; i < size; i += 4, j++) {
-               if ((err = tg3_nvram_read_le(tp, i, &buf[j])) != 0)
+               err = tg3_nvram_read_be32(tp, i, &buf[j]);
+               if (err)
                        break;
        }
        if (i < size)
                goto out;
 
        /* Selfboot format */
-       magic = swab32(le32_to_cpu(buf[0]));
+       magic = be32_to_cpu(buf[0]);
        if ((magic & TG3_EEPROM_MAGIC_FW_MSK) ==
            TG3_EEPROM_MAGIC_FW) {
                u8 *buf8 = (u8 *) buf, csum8 = 0;
@@ -9097,7 +9265,7 @@ static int tg3_test_nvram(struct tg3 *tp)
        if ((magic & TG3_EEPROM_MAGIC_HW_MSK) ==
            TG3_EEPROM_MAGIC_HW) {
                u8 data[NVRAM_SELFBOOT_DATA_SIZE];
-               u8 parity[NVRAM_SELFBOOT_DATA_SIZE];
+               u8 parity[NVRAM_SELFBOOT_DATA_SIZE];
                u8 *buf8 = (u8 *) buf;
 
                /* Separate the parity bits and the data bytes.  */
@@ -9140,13 +9308,13 @@ static int tg3_test_nvram(struct tg3 *tp)
 
        /* Bootstrap checksum at offset 0x10 */
        csum = calc_crc((unsigned char *) buf, 0x10);
-       if(csum != le32_to_cpu(buf[0x10/4]))
+       if (csum != be32_to_cpu(buf[0x10/4]))
                goto out;
 
        /* Manufacturing block starts at offset 0x74, checksum at 0xfc */
        csum = calc_crc((unsigned char *) &buf[0x74/4], 0x88);
-       if (csum != le32_to_cpu(buf[0xfc/4]))
-                goto out;
+       if (csum != be32_to_cpu(buf[0xfc/4]))
+               goto out;
 
        err = 0;
 
@@ -9855,8 +10023,12 @@ static void tg3_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
 {
        struct tg3 *tp = netdev_priv(dev);
 
-       if (netif_running(dev))
-               tg3_netif_stop(tp);
+       if (!netif_running(dev)) {
+               tp->vlgrp = grp;
+               return;
+       }
+
+       tg3_netif_stop(tp);
 
        tg3_full_lock(tp, 0);
 
@@ -9865,8 +10037,7 @@ static void tg3_vlan_rx_register(struct net_device *dev, struct vlan_group *grp)
        /* Update RX_MODE_KEEP_VLAN_TAG bit in RX_MODE register. */
        __tg3_set_rx_mode(dev);
 
-       if (netif_running(dev))
-               tg3_netif_start(tp);
+       tg3_netif_start(tp);
 
        tg3_full_unlock(tp);
 }
@@ -9973,7 +10144,7 @@ static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
 
        tp->nvram_size = EEPROM_CHIP_SIZE;
 
-       if (tg3_nvram_read_swab(tp, 0, &magic) != 0)
+       if (tg3_nvram_read(tp, 0, &magic) != 0)
                return;
 
        if ((magic != TG3_EEPROM_MAGIC) &&
@@ -9989,7 +10160,7 @@ static void __devinit tg3_get_eeprom_size(struct tg3 *tp)
        cursize = 0x10;
 
        while (cursize < tp->nvram_size) {
-               if (tg3_nvram_read_swab(tp, cursize, &val) != 0)
+               if (tg3_nvram_read(tp, cursize, &val) != 0)
                        return;
 
                if (val == magic)
@@ -10005,7 +10176,7 @@ static void __devinit tg3_get_nvram_size(struct tg3 *tp)
 {
        u32 val;
 
-       if (tg3_nvram_read_swab(tp, 0, &val) != 0)
+       if (tg3_nvram_read(tp, 0, &val) != 0)
                return;
 
        /* Selfboot format */
@@ -10016,7 +10187,18 @@ static void __devinit tg3_get_nvram_size(struct tg3 *tp)
 
        if (tg3_nvram_read(tp, 0xf0, &val) == 0) {
                if (val != 0) {
-                       tp->nvram_size = (val >> 16) * 1024;
+                       /* This is confusing.  We want to operate on the
+                        * 16-bit value at offset 0xf2.  The tg3_nvram_read()
+                        * call will read from NVRAM and byteswap the data
+                        * according to the byteswapping settings for all
+                        * other register accesses.  This ensures the data we
+                        * want will always reside in the lower 16-bits.
+                        * However, the data in NVRAM is in LE format, which
+                        * means the data from the NVRAM read will always be
+                        * opposite the endianness of the CPU.  The 16-bit
+                        * byteswap then brings the data to CPU endianness.
+                        */
+                       tp->nvram_size = swab16((u16)(val & 0x0000ffff)) * 1024;
                        return;
                }
        }
@@ -10467,141 +10649,6 @@ static void __devinit tg3_nvram_init(struct tg3 *tp)
        }
 }
 
-static int tg3_nvram_read_using_eeprom(struct tg3 *tp,
-                                       u32 offset, u32 *val)
-{
-       u32 tmp;
-       int i;
-
-       if (offset > EEPROM_ADDR_ADDR_MASK ||
-           (offset % 4) != 0)
-               return -EINVAL;
-
-       tmp = tr32(GRC_EEPROM_ADDR) & ~(EEPROM_ADDR_ADDR_MASK |
-                                       EEPROM_ADDR_DEVID_MASK |
-                                       EEPROM_ADDR_READ);
-       tw32(GRC_EEPROM_ADDR,
-            tmp |
-            (0 << EEPROM_ADDR_DEVID_SHIFT) |
-            ((offset << EEPROM_ADDR_ADDR_SHIFT) &
-             EEPROM_ADDR_ADDR_MASK) |
-            EEPROM_ADDR_READ | EEPROM_ADDR_START);
-
-       for (i = 0; i < 1000; i++) {
-               tmp = tr32(GRC_EEPROM_ADDR);
-
-               if (tmp & EEPROM_ADDR_COMPLETE)
-                       break;
-               msleep(1);
-       }
-       if (!(tmp & EEPROM_ADDR_COMPLETE))
-               return -EBUSY;
-
-       *val = tr32(GRC_EEPROM_DATA);
-       return 0;
-}
-
-#define NVRAM_CMD_TIMEOUT 10000
-
-static int tg3_nvram_exec_cmd(struct tg3 *tp, u32 nvram_cmd)
-{
-       int i;
-
-       tw32(NVRAM_CMD, nvram_cmd);
-       for (i = 0; i < NVRAM_CMD_TIMEOUT; i++) {
-               udelay(10);
-               if (tr32(NVRAM_CMD) & NVRAM_CMD_DONE) {
-                       udelay(10);
-                       break;
-               }
-       }
-       if (i == NVRAM_CMD_TIMEOUT) {
-               return -EBUSY;
-       }
-       return 0;
-}
-
-static u32 tg3_nvram_phys_addr(struct tg3 *tp, u32 addr)
-{
-       if ((tp->tg3_flags & TG3_FLAG_NVRAM) &&
-           (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
-           (tp->tg3_flags2 & TG3_FLG2_FLASH) &&
-          !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) &&
-           (tp->nvram_jedecnum == JEDEC_ATMEL))
-
-               addr = ((addr / tp->nvram_pagesize) <<
-                       ATMEL_AT45DB0X1B_PAGE_POS) +
-                      (addr % tp->nvram_pagesize);
-
-       return addr;
-}
-
-static u32 tg3_nvram_logical_addr(struct tg3 *tp, u32 addr)
-{
-       if ((tp->tg3_flags & TG3_FLAG_NVRAM) &&
-           (tp->tg3_flags & TG3_FLAG_NVRAM_BUFFERED) &&
-           (tp->tg3_flags2 & TG3_FLG2_FLASH) &&
-          !(tp->tg3_flags3 & TG3_FLG3_NO_NVRAM_ADDR_TRANS) &&
-           (tp->nvram_jedecnum == JEDEC_ATMEL))
-
-               addr = ((addr >> ATMEL_AT45DB0X1B_PAGE_POS) *
-                       tp->nvram_pagesize) +
-                      (addr & ((1 << ATMEL_AT45DB0X1B_PAGE_POS) - 1));
-
-       return addr;
-}
-
-static int tg3_nvram_read(struct tg3 *tp, u32 offset, u32 *val)
-{
-       int ret;
-
-       if (!(tp->tg3_flags & TG3_FLAG_NVRAM))
-               return tg3_nvram_read_using_eeprom(tp, offset, val);
-
-       offset = tg3_nvram_phys_addr(tp, offset);
-
-       if (offset > NVRAM_ADDR_MSK)
-               return -EINVAL;
-
-       ret = tg3_nvram_lock(tp);
-       if (ret)
-               return ret;
-
-       tg3_enable_nvram_access(tp);
-
-       tw32(NVRAM_ADDR, offset);
-       ret = tg3_nvram_exec_cmd(tp, NVRAM_CMD_RD | NVRAM_CMD_GO |
-               NVRAM_CMD_FIRST | NVRAM_CMD_LAST | NVRAM_CMD_DONE);
-
-       if (ret == 0)
-               *val = swab32(tr32(NVRAM_RDDATA));
-
-       tg3_disable_nvram_access(tp);
-
-       tg3_nvram_unlock(tp);
-
-       return ret;
-}
-
-static int tg3_nvram_read_le(struct tg3 *tp, u32 offset, __le32 *val)
-{
-       u32 v;
-       int res = tg3_nvram_read(tp, offset, &v);
-       if (!res)
-               *val = cpu_to_le32(v);
-       return res;
-}
-
-static int tg3_nvram_read_swab(struct tg3 *tp, u32 offset, u32 *val)
-{
-       int err;
-       u32 tmp;
-
-       err = tg3_nvram_read(tp, offset, &tmp);
-       *val = swab32(tmp);
-       return err;
-}
-
 static int tg3_nvram_write_block_using_eeprom(struct tg3 *tp,
                                    u32 offset, u32 len, u8 *buf)
 {
@@ -10610,13 +10657,13 @@ static int tg3_nvram_write_block_using_eeprom(struct tg3 *tp,
 
        for (i = 0; i < len; i += 4) {
                u32 addr;
-               __le32 data;
+               __be32 data;
 
                addr = offset + i;
 
                memcpy(&data, buf + i, 4);
 
-               tw32(GRC_EEPROM_DATA, le32_to_cpu(data));
+               tw32(GRC_EEPROM_DATA, be32_to_cpu(data));
 
                val = tr32(GRC_EEPROM_ADDR);
                tw32(GRC_EEPROM_ADDR, val | EEPROM_ADDR_COMPLETE);
@@ -10666,8 +10713,9 @@ static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
                phy_addr = offset & ~pagemask;
 
                for (j = 0; j < pagesize; j += 4) {
-                       if ((ret = tg3_nvram_read_le(tp, phy_addr + j,
-                                               (__le32 *) (tmp + j))))
+                       ret = tg3_nvram_read_be32(tp, phy_addr + j,
+                                                 (__be32 *) (tmp + j));
+                       if (ret)
                                break;
                }
                if (ret)
@@ -10714,7 +10762,7 @@ static int tg3_nvram_write_block_unbuffered(struct tg3 *tp, u32 offset, u32 len,
                        __be32 data;
 
                        data = *((__be32 *) (tmp + j));
-                       /* swab32(le32_to_cpu(data)), actually */
+
                        tw32(NVRAM_WRDATA, be32_to_cpu(data));
 
                        tw32(NVRAM_ADDR, phy_addr + j);
@@ -11300,24 +11348,25 @@ skip_phy_reset:
 
 static void __devinit tg3_read_partno(struct tg3 *tp)
 {
-       unsigned char vpd_data[256];
+       unsigned char vpd_data[256];   /* in little-endian format */
        unsigned int i;
        u32 magic;
 
-       if (tg3_nvram_read_swab(tp, 0x0, &magic))
+       if (tg3_nvram_read(tp, 0x0, &magic))
                goto out_not_found;
 
        if (magic == TG3_EEPROM_MAGIC) {
                for (i = 0; i < 256; i += 4) {
                        u32 tmp;
 
-                       if (tg3_nvram_read(tp, 0x100 + i, &tmp))
+                       /* The data is in little-endian format in NVRAM.
+                        * Use the big-endian read routines to preserve
+                        * the byte order as it exists in NVRAM.
+                        */
+                       if (tg3_nvram_read_be32(tp, 0x100 + i, &tmp))
                                goto out_not_found;
 
-                       vpd_data[i + 0] = ((tmp >>  0) & 0xff);
-                       vpd_data[i + 1] = ((tmp >>  8) & 0xff);
-                       vpd_data[i + 2] = ((tmp >> 16) & 0xff);
-                       vpd_data[i + 3] = ((tmp >> 24) & 0xff);
+                       memcpy(&vpd_data[i], &tmp, sizeof(tmp));
                }
        } else {
                int vpd_cap;
@@ -11343,7 +11392,7 @@ static void __devinit tg3_read_partno(struct tg3 *tp)
                        pci_read_config_dword(tp->pdev, vpd_cap + PCI_VPD_DATA,
                                              &tmp);
                        v = cpu_to_le32(tmp);
-                       memcpy(&vpd_data[i], &v, 4);
+                       memcpy(&vpd_data[i], &v, sizeof(v));
                }
        }
 
@@ -11403,15 +11452,79 @@ static int __devinit tg3_fw_img_is_valid(struct tg3 *tp, u32 offset)
 {
        u32 val;
 
-       if (tg3_nvram_read_swab(tp, offset, &val) ||
+       if (tg3_nvram_read(tp, offset, &val) ||
            (val & 0xfc000000) != 0x0c000000 ||
-           tg3_nvram_read_swab(tp, offset + 4, &val) ||
+           tg3_nvram_read(tp, offset + 4, &val) ||
            val != 0)
                return 0;
 
        return 1;
 }
 
+static void __devinit tg3_read_bc_ver(struct tg3 *tp)
+{
+       u32 val, offset, start, ver_offset;
+       int i;
+       bool newver = false;
+
+       if (tg3_nvram_read(tp, 0xc, &offset) ||
+           tg3_nvram_read(tp, 0x4, &start))
+               return;
+
+       offset = tg3_nvram_logical_addr(tp, offset);
+
+       if (tg3_nvram_read(tp, offset, &val))
+               return;
+
+       if ((val & 0xfc000000) == 0x0c000000) {
+               if (tg3_nvram_read(tp, offset + 4, &val))
+                       return;
+
+               if (val == 0)
+                       newver = true;
+       }
+
+       if (newver) {
+               if (tg3_nvram_read(tp, offset + 8, &ver_offset))
+                       return;
+
+               offset = offset + ver_offset - start;
+               for (i = 0; i < 16; i += 4) {
+                       __be32 v;
+                       if (tg3_nvram_read_be32(tp, offset + i, &v))
+                               return;
+
+                       memcpy(tp->fw_ver + i, &v, sizeof(v));
+               }
+       } else {
+               u32 major, minor;
+
+               if (tg3_nvram_read(tp, TG3_NVM_PTREV_BCVER, &ver_offset))
+                       return;
+
+               major = (ver_offset & TG3_NVM_BCVER_MAJMSK) >>
+                       TG3_NVM_BCVER_MAJSFT;
+               minor = ver_offset & TG3_NVM_BCVER_MINMSK;
+               snprintf(&tp->fw_ver[0], 32, "v%d.%02d", major, minor);
+       }
+}
+
+static void __devinit tg3_read_hwsb_ver(struct tg3 *tp)
+{
+       u32 val, major, minor;
+
+       /* Use native endian representation */
+       if (tg3_nvram_read(tp, TG3_NVM_HWSB_CFG1, &val))
+               return;
+
+       major = (val & TG3_NVM_HWSB_CFG1_MAJMSK) >>
+               TG3_NVM_HWSB_CFG1_MAJSFT;
+       minor = (val & TG3_NVM_HWSB_CFG1_MINMSK) >>
+               TG3_NVM_HWSB_CFG1_MINSFT;
+
+       snprintf(&tp->fw_ver[0], 32, "sb v%d.%02d", major, minor);
+}
+
 static void __devinit tg3_read_sb_ver(struct tg3 *tp, u32 val)
 {
        u32 offset, major, minor, build;
@@ -11437,7 +11550,7 @@ static void __devinit tg3_read_sb_ver(struct tg3 *tp, u32 val)
                return;
        }
 
-       if (tg3_nvram_read_swab(tp, offset, &val))
+       if (tg3_nvram_read(tp, offset, &val))
                return;
 
        build = (val & TG3_EEPROM_SB_EDH_BLD_MASK) >>
@@ -11457,49 +11570,15 @@ static void __devinit tg3_read_sb_ver(struct tg3 *tp, u32 val)
        }
 }
 
-static void __devinit tg3_read_fw_ver(struct tg3 *tp)
+static void __devinit tg3_read_mgmtfw_ver(struct tg3 *tp)
 {
        u32 val, offset, start;
-       u32 ver_offset;
-       int i, bcnt;
-
-       if (tg3_nvram_read_swab(tp, 0, &val))
-               return;
-
-       if (val != TG3_EEPROM_MAGIC) {
-               if ((val & TG3_EEPROM_MAGIC_FW_MSK) == TG3_EEPROM_MAGIC_FW)
-                       tg3_read_sb_ver(tp, val);
-
-               return;
-       }
-
-       if (tg3_nvram_read_swab(tp, 0xc, &offset) ||
-           tg3_nvram_read_swab(tp, 0x4, &start))
-               return;
-
-       offset = tg3_nvram_logical_addr(tp, offset);
-
-       if (!tg3_fw_img_is_valid(tp, offset) ||
-           tg3_nvram_read_swab(tp, offset + 8, &ver_offset))
-               return;
-
-       offset = offset + ver_offset - start;
-       for (i = 0; i < 16; i += 4) {
-               __le32 v;
-               if (tg3_nvram_read_le(tp, offset + i, &v))
-                       return;
-
-               memcpy(tp->fw_ver + i, &v, 4);
-       }
-
-       if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
-            (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
-               return;
+       int i, vlen;
 
        for (offset = TG3_NVM_DIR_START;
             offset < TG3_NVM_DIR_END;
             offset += TG3_NVM_DIRENT_SIZE) {
-               if (tg3_nvram_read_swab(tp, offset, &val))
+               if (tg3_nvram_read(tp, offset, &val))
                        return;
 
                if ((val >> TG3_NVM_DIRTYPE_SHIFT) == TG3_NVM_DIRTYPE_ASFINI)
@@ -11511,36 +11590,87 @@ static void __devinit tg3_read_fw_ver(struct tg3 *tp)
 
        if (!(tp->tg3_flags2 & TG3_FLG2_5705_PLUS))
                start = 0x08000000;
-       else if (tg3_nvram_read_swab(tp, offset - 4, &start))
+       else if (tg3_nvram_read(tp, offset - 4, &start))
                return;
 
-       if (tg3_nvram_read_swab(tp, offset + 4, &offset) ||
+       if (tg3_nvram_read(tp, offset + 4, &offset) ||
            !tg3_fw_img_is_valid(tp, offset) ||
-           tg3_nvram_read_swab(tp, offset + 8, &val))
+           tg3_nvram_read(tp, offset + 8, &val))
                return;
 
        offset += val - start;
 
-       bcnt = strlen(tp->fw_ver);
+       vlen = strlen(tp->fw_ver);
 
-       tp->fw_ver[bcnt++] = ',';
-       tp->fw_ver[bcnt++] = ' ';
+       tp->fw_ver[vlen++] = ',';
+       tp->fw_ver[vlen++] = ' ';
 
        for (i = 0; i < 4; i++) {
-               __le32 v;
-               if (tg3_nvram_read_le(tp, offset, &v))
+               __be32 v;
+               if (tg3_nvram_read_be32(tp, offset, &v))
                        return;
 
                offset += sizeof(v);
 
-               if (bcnt > TG3_VER_SIZE - sizeof(v)) {
-                       memcpy(&tp->fw_ver[bcnt], &v, TG3_VER_SIZE - bcnt);
+               if (vlen > TG3_VER_SIZE - sizeof(v)) {
+                       memcpy(&tp->fw_ver[vlen], &v, TG3_VER_SIZE - vlen);
                        break;
                }
 
-               memcpy(&tp->fw_ver[bcnt], &v, sizeof(v));
-               bcnt += sizeof(v);
+               memcpy(&tp->fw_ver[vlen], &v, sizeof(v));
+               vlen += sizeof(v);
        }
+}
+
+static void __devinit tg3_read_dash_ver(struct tg3 *tp)
+{
+       int vlen;
+       u32 apedata;
+
+       if (!(tp->tg3_flags3 & TG3_FLG3_ENABLE_APE) ||
+           !(tp->tg3_flags  & TG3_FLAG_ENABLE_ASF))
+               return;
+
+       apedata = tg3_ape_read32(tp, TG3_APE_SEG_SIG);
+       if (apedata != APE_SEG_SIG_MAGIC)
+               return;
+
+       apedata = tg3_ape_read32(tp, TG3_APE_FW_STATUS);
+       if (!(apedata & APE_FW_STATUS_READY))
+               return;
+
+       apedata = tg3_ape_read32(tp, TG3_APE_FW_VERSION);
+
+       vlen = strlen(tp->fw_ver);
+
+       snprintf(&tp->fw_ver[vlen], TG3_VER_SIZE - vlen, " DASH v%d.%d.%d.%d",
+                (apedata & APE_FW_VERSION_MAJMSK) >> APE_FW_VERSION_MAJSFT,
+                (apedata & APE_FW_VERSION_MINMSK) >> APE_FW_VERSION_MINSFT,
+                (apedata & APE_FW_VERSION_REVMSK) >> APE_FW_VERSION_REVSFT,
+                (apedata & APE_FW_VERSION_BLDMSK));
+}
+
+static void __devinit tg3_read_fw_ver(struct tg3 *tp)
+{
+       u32 val;
+
+       if (tg3_nvram_read(tp, 0, &val))
+               return;
+
+       if (val == TG3_EEPROM_MAGIC)
+               tg3_read_bc_ver(tp);
+       else if ((val & TG3_EEPROM_MAGIC_FW_MSK) == TG3_EEPROM_MAGIC_FW)
+               tg3_read_sb_ver(tp, val);
+       else if ((val & TG3_EEPROM_MAGIC_HW_MSK) == TG3_EEPROM_MAGIC_HW)
+               tg3_read_hwsb_ver(tp);
+       else
+               return;
+
+       if (!(tp->tg3_flags & TG3_FLAG_ENABLE_ASF) ||
+            (tp->tg3_flags3 & TG3_FLG3_ENABLE_APE))
+               return;
+
+       tg3_read_mgmtfw_ver(tp);
 
        tp->fw_ver[TG3_VER_SIZE - 1] = 0;
 }
@@ -12311,14 +12441,10 @@ static int __devinit tg3_get_device_address(struct tg3 *tp)
        }
        if (!addr_ok) {
                /* Next, try NVRAM. */
-               if (!tg3_nvram_read(tp, mac_offset + 0, &hi) &&
-                   !tg3_nvram_read(tp, mac_offset + 4, &lo)) {
-                       dev->dev_addr[0] = ((hi >> 16) & 0xff);
-                       dev->dev_addr[1] = ((hi >> 24) & 0xff);
-                       dev->dev_addr[2] = ((lo >>  0) & 0xff);
-                       dev->dev_addr[3] = ((lo >>  8) & 0xff);
-                       dev->dev_addr[4] = ((lo >> 16) & 0xff);
-                       dev->dev_addr[5] = ((lo >> 24) & 0xff);
+               if (!tg3_nvram_read_be32(tp, mac_offset + 0, &hi) &&
+                   !tg3_nvram_read_be32(tp, mac_offset + 4, &lo)) {
+                       memcpy(&dev->dev_addr[0], ((char *)&hi) + 2, 2);
+                       memcpy(&dev->dev_addr[2], (char *)&lo, sizeof(lo));
                }
                /* Finally just fetch it out of the MAC control regs. */
                else {
@@ -13199,6 +13325,9 @@ static int __devinit tg3_init_one(struct pci_dev *pdev,
                }
 
                tg3_ape_lock_init(tp);
+
+               if (tp->tg3_flags & TG3_FLAG_ENABLE_ASF)
+                       tg3_read_dash_ver(tp);
        }
 
        /*
index 508def3e077f9e1d86e5c4d8e1da7c8132157601..cb4c62abdd2142c9295fc170f8463a79c8358d18 100644 (file)
 
 #define TG3_OTP_DEFAULT                        0x286c1640
 
+/* Hardware Selfboot NVRAM layout */
+#define TG3_NVM_HWSB_CFG1              0x00000004
+#define  TG3_NVM_HWSB_CFG1_MAJMSK      0xf8000000
+#define  TG3_NVM_HWSB_CFG1_MAJSFT      27
+#define  TG3_NVM_HWSB_CFG1_MINMSK      0x07c00000
+#define  TG3_NVM_HWSB_CFG1_MINSFT      22
 
 #define TG3_EEPROM_MAGIC               0x669955aa
 #define TG3_EEPROM_MAGIC_FW            0xa5000000
 #define TG3_NVM_DIRENT_SIZE            0xc
 #define TG3_NVM_DIRTYPE_SHIFT          24
 #define TG3_NVM_DIRTYPE_ASFINI         1
+#define TG3_NVM_PTREV_BCVER            0x94
+#define TG3_NVM_BCVER_MAJMSK           0x0000ff00
+#define TG3_NVM_BCVER_MAJSFT           8
+#define TG3_NVM_BCVER_MINMSK           0x000000ff
 
 #define TG3_EEPROM_SB_F1R0_EDH_OFF     0x10
 #define TG3_EEPROM_SB_F1R2_EDH_OFF     0x14
 /* APE shared memory.  Accessible through BAR1 */
 #define TG3_APE_FW_STATUS              0x400c
 #define  APE_FW_STATUS_READY            0x00000100
+#define TG3_APE_FW_VERSION             0x4018
+#define  APE_FW_VERSION_MAJMSK          0xff000000
+#define  APE_FW_VERSION_MAJSFT          24
+#define  APE_FW_VERSION_MINMSK          0x00ff0000
+#define  APE_FW_VERSION_MINSFT          16
+#define  APE_FW_VERSION_REVMSK          0x0000ff00
+#define  APE_FW_VERSION_REVSFT          8
+#define  APE_FW_VERSION_BLDMSK          0x000000ff
 #define TG3_APE_HOST_SEG_SIG           0x4200
 #define  APE_HOST_SEG_SIG_MAGIC                 0x484f5354
 #define TG3_APE_HOST_SEG_LEN           0x4204
index b397e8785d6d3e5c3f7eb9ba8e3683214dddf9e1..f92fe86fdcae2266c08eb773049c86883aeed81e 100644 (file)
@@ -121,11 +121,6 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic
                goto err_out_trdev;
        }
 
-       ret = request_irq(pdev->irq, tms380tr_interrupt, IRQF_SHARED,
-                         dev->name, dev);
-       if (ret)
-               goto err_out_region;
-
        dev->base_addr  = pci_ioaddr;
        dev->irq        = pci_irq_line;
        dev->dma        = 0;
@@ -142,7 +137,7 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic
        ret = tmsdev_init(dev, &pdev->dev);
        if (ret) {
                printk("%s: unable to get memory for dev->priv.\n", dev->name);
-               goto err_out_irq;
+               goto err_out_region;
        }
 
        tp = netdev_priv(dev);
@@ -159,20 +154,25 @@ static int __devinit tms_pci_attach(struct pci_dev *pdev, const struct pci_devic
 
        dev->netdev_ops = &tms380tr_netdev_ops;
 
+       ret = request_irq(pdev->irq, tms380tr_interrupt, IRQF_SHARED,
+                         dev->name, dev);
+       if (ret)
+               goto err_out_tmsdev;
+
        pci_set_drvdata(pdev, dev);
        SET_NETDEV_DEV(dev, &pdev->dev);
 
        ret = register_netdev(dev);
        if (ret)
-               goto err_out_tmsdev;
+               goto err_out_irq;
        
        return 0;
 
+err_out_irq:
+       free_irq(pdev->irq, dev);
 err_out_tmsdev:
        pci_set_drvdata(pdev, NULL);
        tmsdev_term(dev);
-err_out_irq:
-       free_irq(pdev->irq, dev);
 err_out_region:
        release_region(pci_ioaddr, TMS_PCI_IO_EXTENT);
 err_out_trdev:
index 6430a2ec6db198649ea40421533d030cc432fa71..f9491bd787d1ac06c0032a2524b5cc52b31c7f60 100644 (file)
 
 #include "de4x5.h"
 
-static const char version[] __devinitdata =
+static const char version[] __devinitconst =
        KERN_INFO "de4x5.c:V0.546 2001/02/22 davies@maniac.ultranet.com\n";
 
 #define c_char const char
index 2e5c99941f35306b711c315be2585ea6452f4e35..e2c9d0f5a75507c39ce512824deccee80d002e4c 100644 (file)
@@ -288,7 +288,7 @@ enum dmfe_CR6_bits {
 
 /* Global variable declaration ----------------------------- */
 static int __devinitdata printed_version;
-static char version[] __devinitdata =
+static const char version[] __devinitconst =
        KERN_INFO DRV_NAME ": Davicom DM9xxx net driver, version "
        DRV_VERSION " (" DRV_RELDATE ")\n";
 
index 9f946d4210885f3650ece6ece8629fc8a1c0724e..c8d220cf2cce34c328318b77befa50ac92e0e285 100644 (file)
@@ -140,6 +140,7 @@ int tulip_poll(struct napi_struct *napi, int budget)
                /* If we own the next entry, it is a new packet. Send it up. */
                while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
                        s32 status = le32_to_cpu(tp->rx_ring[entry].status);
+                      short pkt_len;
 
                        if (tp->dirty_rx + RX_RING_SIZE == tp->cur_rx)
                                break;
@@ -151,8 +152,28 @@ int tulip_poll(struct napi_struct *napi, int budget)
                       if (++work_done >= budget)
                                goto not_done;
 
-                       if ((status & 0x38008300) != 0x0300) {
-                               if ((status & 0x38000300) != 0x0300) {
+                      /*
+                       * Omit the four octet CRC from the length.
+                       * (May not be considered valid until we have
+                       * checked status for RxLengthOver2047 bits)
+                       */
+                      pkt_len = ((status >> 16) & 0x7ff) - 4;
+
+                      /*
+                       * Maximum pkt_len is 1518 (1514 + vlan header)
+                       * Anything higher than this is always invalid
+                       * regardless of RxLengthOver2047 bits
+                       */
+
+                      if ((status & (RxLengthOver2047 |
+                                     RxDescCRCError |
+                                     RxDescCollisionSeen |
+                                     RxDescRunt |
+                                     RxDescDescErr |
+                                     RxWholePkt)) != RxWholePkt
+                          || pkt_len > 1518) {
+                              if ((status & (RxLengthOver2047 |
+                                             RxWholePkt)) != RxWholePkt) {
                                 /* Ingore earlier buffers. */
                                        if ((status & 0xffff) != 0x7fff) {
                                                if (tulip_debug > 1)
@@ -161,30 +182,23 @@ int tulip_poll(struct napi_struct *napi, int budget)
                                                               dev->name, status);
                                                tp->stats.rx_length_errors++;
                                        }
-                               } else if (status & RxDescFatalErr) {
+                              } else {
                                 /* There was a fatal error. */
                                        if (tulip_debug > 2)
                                                printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
                                                       dev->name, status);
                                        tp->stats.rx_errors++; /* end of a packet.*/
-                                       if (status & 0x0890) tp->stats.rx_length_errors++;
+                                      if (pkt_len > 1518 ||
+                                          (status & RxDescRunt))
+                                              tp->stats.rx_length_errors++;
+
                                        if (status & 0x0004) tp->stats.rx_frame_errors++;
                                        if (status & 0x0002) tp->stats.rx_crc_errors++;
                                        if (status & 0x0001) tp->stats.rx_fifo_errors++;
                                }
                        } else {
-                               /* Omit the four octet CRC from the length. */
-                               short pkt_len = ((status >> 16) & 0x7ff) - 4;
                                struct sk_buff *skb;
 
-#ifndef final_version
-                               if (pkt_len > 1518) {
-                                       printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n",
-                                              dev->name, pkt_len, pkt_len);
-                                       pkt_len = 1518;
-                                       tp->stats.rx_length_errors++;
-                               }
-#endif
                                /* Check if the packet is long enough to accept without copying
                                   to a minimally-sized skbuff. */
                                if (pkt_len < tulip_rx_copybreak
@@ -356,14 +370,35 @@ static int tulip_rx(struct net_device *dev)
        /* If we own the next entry, it is a new packet. Send it up. */
        while ( ! (tp->rx_ring[entry].status & cpu_to_le32(DescOwned))) {
                s32 status = le32_to_cpu(tp->rx_ring[entry].status);
+               short pkt_len;
 
                if (tulip_debug > 5)
                        printk(KERN_DEBUG "%s: In tulip_rx(), entry %d %8.8x.\n",
                                   dev->name, entry, status);
                if (--rx_work_limit < 0)
                        break;
-               if ((status & 0x38008300) != 0x0300) {
-                       if ((status & 0x38000300) != 0x0300) {
+
+               /*
+                 Omit the four octet CRC from the length.
+                 (May not be considered valid until we have
+                 checked status for RxLengthOver2047 bits)
+               */
+               pkt_len = ((status >> 16) & 0x7ff) - 4;
+               /*
+                 Maximum pkt_len is 1518 (1514 + vlan header)
+                 Anything higher than this is always invalid
+                 regardless of RxLengthOver2047 bits
+               */
+
+               if ((status & (RxLengthOver2047 |
+                              RxDescCRCError |
+                              RxDescCollisionSeen |
+                              RxDescRunt |
+                              RxDescDescErr |
+                              RxWholePkt))        != RxWholePkt
+                    || pkt_len > 1518) {
+                       if ((status & (RxLengthOver2047 |
+                            RxWholePkt))         != RxWholePkt) {
                                /* Ingore earlier buffers. */
                                if ((status & 0xffff) != 0x7fff) {
                                        if (tulip_debug > 1)
@@ -372,31 +407,22 @@ static int tulip_rx(struct net_device *dev)
                                                           dev->name, status);
                                        tp->stats.rx_length_errors++;
                                }
-                       } else if (status & RxDescFatalErr) {
+                       } else {
                                /* There was a fatal error. */
                                if (tulip_debug > 2)
                                        printk(KERN_DEBUG "%s: Receive error, Rx status %8.8x.\n",
                                                   dev->name, status);
                                tp->stats.rx_errors++; /* end of a packet.*/
-                               if (status & 0x0890) tp->stats.rx_length_errors++;
+                               if (pkt_len > 1518 ||
+                                   (status & RxDescRunt))
+                                       tp->stats.rx_length_errors++;
                                if (status & 0x0004) tp->stats.rx_frame_errors++;
                                if (status & 0x0002) tp->stats.rx_crc_errors++;
                                if (status & 0x0001) tp->stats.rx_fifo_errors++;
                        }
                } else {
-                       /* Omit the four octet CRC from the length. */
-                       short pkt_len = ((status >> 16) & 0x7ff) - 4;
                        struct sk_buff *skb;
 
-#ifndef final_version
-                       if (pkt_len > 1518) {
-                               printk(KERN_WARNING "%s: Bogus packet size of %d (%#x).\n",
-                                          dev->name, pkt_len, pkt_len);
-                               pkt_len = 1518;
-                               tp->stats.rx_length_errors++;
-                       }
-#endif
-
                        /* Check if the packet is long enough to accept without copying
                           to a minimally-sized skbuff. */
                        if (pkt_len < tulip_rx_copybreak
index 19abbc36b60a62cfba4af9db9dc2cce703e2b8c3..0afa2d4f9472163c6fd8797725bfdb3957681ffa 100644 (file)
@@ -201,8 +201,38 @@ enum desc_status_bits {
        DescStartPkt = 0x20000000,
        DescEndRing  = 0x02000000,
        DescUseLink  = 0x01000000,
-       RxDescFatalErr = 0x008000,
+
+       /*
+        * Error summary flag is logical or of 'CRC Error', 'Collision Seen',
+        * 'Frame Too Long', 'Runt' and 'Descriptor Error' flags generated
+        * within tulip chip.
+        */
+       RxDescErrorSummary = 0x8000,
+       RxDescCRCError = 0x0002,
+       RxDescCollisionSeen = 0x0040,
+
+       /*
+        * 'Frame Too Long' flag is set if packet length including CRC exceeds
+        * 1518.  However, a full sized VLAN tagged frame is 1522 bytes
+        * including CRC.
+        *
+        * The tulip chip does not block oversized frames, and if this flag is
+        * set on a receive descriptor it does not indicate the frame has been
+        * truncated.  The receive descriptor also includes the actual length.
+        * Therefore we can safety ignore this flag and check the length
+        * ourselves.
+        */
+       RxDescFrameTooLong = 0x0080,
+       RxDescRunt = 0x0800,
+       RxDescDescErr = 0x4000,
        RxWholePkt   = 0x00000300,
+       /*
+        * Top three bits of 14 bit frame length (status bits 27-29) should
+        * never be set as that would make frame over 2047 bytes. The Receive
+        * Watchdog flag (bit 4) may indicate the length is over 2048 and the
+        * length field is invalid.
+        */
+       RxLengthOver2047 = 0x38000010
 };
 
 
index bee75fa87a9c458cd67e62bff2b80f770a60583c..2abb5d3becc6d2d98ec7613b42c0f05b8b439352 100644 (file)
@@ -255,6 +255,7 @@ const char tulip_media_cap[32] =
 
 static void tulip_tx_timeout(struct net_device *dev);
 static void tulip_init_ring(struct net_device *dev);
+static void tulip_free_ring(struct net_device *dev);
 static int tulip_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static int tulip_open(struct net_device *dev);
 static int tulip_close(struct net_device *dev);
@@ -502,16 +503,21 @@ tulip_open(struct net_device *dev)
 {
        int retval;
 
-       if ((retval = request_irq(dev->irq, &tulip_interrupt, IRQF_SHARED, dev->name, dev)))
-               return retval;
-
        tulip_init_ring (dev);
 
+       retval = request_irq(dev->irq, &tulip_interrupt, IRQF_SHARED, dev->name, dev);
+       if (retval)
+               goto free_ring;
+
        tulip_up (dev);
 
        netif_start_queue (dev);
 
        return 0;
+
+free_ring:
+       tulip_free_ring (dev);
+       return retval;
 }
 
 
@@ -768,23 +774,11 @@ static void tulip_down (struct net_device *dev)
        tulip_set_power_state (tp, 0, 1);
 }
 
-
-static int tulip_close (struct net_device *dev)
+static void tulip_free_ring (struct net_device *dev)
 {
        struct tulip_private *tp = netdev_priv(dev);
-       void __iomem *ioaddr = tp->base_addr;
        int i;
 
-       netif_stop_queue (dev);
-
-       tulip_down (dev);
-
-       if (tulip_debug > 1)
-               printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
-                       dev->name, ioread32 (ioaddr + CSR5));
-
-       free_irq (dev->irq, dev);
-
        /* Free all the skbuffs in the Rx queue. */
        for (i = 0; i < RX_RING_SIZE; i++) {
                struct sk_buff *skb = tp->rx_buffers[i].skb;
@@ -803,6 +797,7 @@ static int tulip_close (struct net_device *dev)
                        dev_kfree_skb (skb);
                }
        }
+
        for (i = 0; i < TX_RING_SIZE; i++) {
                struct sk_buff *skb = tp->tx_buffers[i].skb;
 
@@ -814,6 +809,24 @@ static int tulip_close (struct net_device *dev)
                tp->tx_buffers[i].skb = NULL;
                tp->tx_buffers[i].mapping = 0;
        }
+}
+
+static int tulip_close (struct net_device *dev)
+{
+       struct tulip_private *tp = netdev_priv(dev);
+       void __iomem *ioaddr = tp->base_addr;
+
+       netif_stop_queue (dev);
+
+       tulip_down (dev);
+
+       if (tulip_debug > 1)
+               printk (KERN_DEBUG "%s: Shutting down ethercard, status was %2.2x.\n",
+                       dev->name, ioread32 (ioaddr + CSR5));
+
+       free_irq (dev->irq, dev);
+
+       tulip_free_ring (dev);
 
        return 0;
 }
index 030e02e630239099528248327b497ed62922b6ed..c227db0796214b011a2f268bea94ed95f5f33fd9 100644 (file)
@@ -200,7 +200,7 @@ enum uli526x_CR6_bits {
 
 /* Global variable declaration ----------------------------- */
 static int __devinitdata printed_version;
-static char version[] __devinitdata =
+static const char version[] __devinitconst =
        KERN_INFO DRV_NAME ": ULi M5261/M5263 net driver, version "
        DRV_VERSION " (" DRV_RELDATE ")\n";
 
index 426b7c73e36abf1415a00bdd29002baf90ed95db..c61a01b029af78439addf39c35a2a4e9c6e43346 100644 (file)
@@ -139,9 +139,10 @@ static int full_duplex[MAX_UNITS] = {-1, -1, -1, -1, -1, -1, -1, -1};
 #define PKT_BUF_SZ             1536    /* Size of each temporary Rx buffer.*/
 
 /* These identify the driver base version and may not be removed. */
-static const char version[] __initdata =
-KERN_INFO DRV_NAME ".c:v" DRV_VERSION " (2.4 port) " DRV_RELDATE "  Donald Becker <becker@scyld.com>\n"
-KERN_INFO "  http://www.scyld.com/network/drivers.html\n";
+static const char version[] __initconst =
+       KERN_INFO DRV_NAME ".c:v" DRV_VERSION " (2.4 port) "
+       DRV_RELDATE "  Donald Becker <becker@scyld.com>\n"
+       KERN_INFO "  http://www.scyld.com/network/drivers.html\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("Winbond W89c840 Ethernet driver");
diff --git a/drivers/net/typhoon-firmware.h b/drivers/net/typhoon-firmware.h
deleted file mode 100644 (file)
index 182d69e..0000000
+++ /dev/null
@@ -1,3778 +0,0 @@
-/*
- * Copyright 1999-2004 3Com Corporation.  All Rights Reserved.
- *
- * Redistribution and use in source and binary forms of the 3c990img.h
- * microcode software are permitted provided that the following conditions
- * are met:
- * 1. Redistribution of source code must retain the above copyright
- *    notice, this list of conditions and the following disclaimer.
- * 2. Redistribution in binary form must reproduce the above copyright
- *    notice, this list of conditions and the following disclaimer in the
- *    documentation and/or other materials provided with the distribution.
- * 3. The name of 3Com may not be used to endorse or promote products
- *    derived from this software without specific prior written permission
- *
- * THIS SOFTWARE IS PROVIDED BY 3COM ``AS IS'' AND ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
- * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
- * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
- * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
- * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
- * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
- * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
- * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
- * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
- *
- * USER ACKNOWLEDGES AND AGREES THAT PURCHASE OR USE OF THE 3c990img.h
- * MICROCODE SOFTWARE WILL NOT CREATE OR GIVE GROUNDS FOR A LICENSE BY
- * IMPLICATION, ESTOPPEL, OR OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS
- * (PATENT, COPYRIGHT, TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT)
- * EMBODIED IN ANY OTHER 3COM HARDWARE OR SOFTWARE EITHER SOLELY OR IN
- * COMBINATION WITH THE 3c990img.h MICROCODE SOFTWARE
- */
-
- /* ver 03.001.008 */
-static const u8 typhoon_firmware_image[] = {
-0x54, 0x59, 0x50, 0x48, 0x4f, 0x4f, 0x4e, 0x00, 0x02, 0x00, 0x00, 0x00,
-0x09, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xcb, 0x99, 0xb1, 0xd4,
-0x4c, 0xb8, 0xd0, 0x4b, 0x32, 0x02, 0xd4, 0xee, 0x73, 0x7e, 0x0b, 0x13,
-0x9b, 0xc0, 0xae, 0xf4, 0x40, 0x01, 0x00, 0x00, 0xe8, 0xfc, 0x00, 0x00,
-0x00, 0x00, 0xff, 0xff, 0x39, 0x00, 0x00, 0xea, 0x05, 0x00, 0x00, 0xea,
-0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x00, 0xea,
-0x01, 0x00, 0x00, 0xea, 0x32, 0x02, 0x00, 0xea, 0xc5, 0x14, 0x00, 0xea,
-0x07, 0x00, 0x2d, 0xe9, 0x0e, 0x00, 0xa0, 0xe1, 0x00, 0x10, 0x0f, 0xe1,
-0xd0, 0x20, 0x9f, 0xe5, 0x12, 0xff, 0x2f, 0xe1, 0xfe, 0xff, 0xff, 0xea,
-0x01, 0x00, 0x80, 0xe0, 0x04, 0x20, 0x81, 0xe4, 0x01, 0x00, 0x50, 0xe1,
-0xfc, 0xff, 0xff, 0x1a, 0x0e, 0xf0, 0xa0, 0xe1, 0x00, 0xa0, 0xa0, 0xe1,
-0x0e, 0xb0, 0xa0, 0xe1, 0x00, 0x00, 0xa0, 0xe3, 0xa8, 0x10, 0x9f, 0xe5,
-0x00, 0x00, 0x81, 0xe5, 0xa4, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0x81, 0xe5,
-0x01, 0x16, 0xa0, 0xe3, 0x00, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x80, 0xe3,
-0x00, 0x00, 0x81, 0xe5, 0xd7, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
-0x88, 0xd0, 0x9f, 0xe5, 0xdb, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
-0x7c, 0xd0, 0x9f, 0xe5, 0xd2, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
-0x74, 0xd0, 0x9f, 0xe5, 0xd1, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
-0x6c, 0xd0, 0x9f, 0xe5, 0x9b, 0x14, 0x00, 0xeb, 0xd3, 0x00, 0xa0, 0xe3,
-0x00, 0xf0, 0x21, 0xe1, 0x60, 0xd0, 0x9f, 0xe5, 0x60, 0x00, 0x9f, 0xe5,
-0x60, 0x10, 0x9f, 0xe5, 0x60, 0x20, 0x9f, 0xe5, 0xdb, 0xff, 0xff, 0xeb,
-0x5c, 0x00, 0x9f, 0xe5, 0x5c, 0x10, 0x9f, 0xe5, 0x00, 0x20, 0xa0, 0xe3,
-0xd7, 0xff, 0xff, 0xeb, 0x54, 0x00, 0x9f, 0xe5, 0x54, 0x10, 0x9f, 0xe5,
-0xd4, 0xff, 0xff, 0xeb, 0x0a, 0x00, 0xa0, 0xe1, 0x0b, 0xf0, 0xa0, 0xe1,
-0xd3, 0x10, 0xa0, 0xe3, 0x01, 0xf0, 0x21, 0xe1, 0xd4, 0xff, 0xff, 0xeb,
-0x3c, 0xa0, 0x9f, 0xe5, 0x1a, 0xff, 0x2f, 0xe1, 0xc6, 0xff, 0xff, 0xea,
-0x15, 0x21, 0xff, 0xff, 0x0c, 0x00, 0x10, 0x00, 0x1c, 0x00, 0x10, 0x00,
-0x3c, 0x38, 0x00, 0x80, 0xfc, 0x37, 0x00, 0x80, 0xfc, 0x3f, 0x00, 0x80,
-0x7c, 0x34, 0x00, 0x80, 0x80, 0x0f, 0x00, 0x00, 0x80, 0x30, 0x00, 0x80,
-0xad, 0xde, 0xad, 0xde, 0xb0, 0xbb, 0x00, 0x00, 0x24, 0xab, 0x20, 0x40,
-0x48, 0x29, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80, 0xbd, 0xba, 0x21, 0x40,
-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x58, 0x57, 0x00, 0x00, 0x86, 0x4b, 0x00, 0x00, 0x60, 0x01, 0xff, 0xff,
-0xb0, 0xb5, 0x07, 0x1c, 0x12, 0x4d, 0x00, 0x24, 0x28, 0x68, 0x00, 0x28,
-0x1e, 0xd0, 0x38, 0x1c, 0x10, 0x49, 0x04, 0xf0, 0x7b, 0xfd, 0x29, 0x68,
-0xc0, 0x46, 0x08, 0x60, 0x00, 0x28, 0x15, 0xd0, 0x38, 0x01, 0x0d, 0x49,
-0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x80, 0x29,
-0x0c, 0xd2, 0x01, 0x31, 0x41, 0x63, 0x28, 0x68, 0xc1, 0x69, 0xc0, 0x46,
-0x29, 0x60, 0x39, 0x07, 0x41, 0x60, 0x04, 0x62, 0xc7, 0x62, 0xb0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x20, 0x1c, 0xfa, 0xe7, 0xe8, 0x17, 0x00, 0x80,
-0xee, 0x05, 0x00, 0x00, 0xa0, 0x1c, 0x00, 0x80, 0x02, 0x49, 0x0a, 0x68,
-0xc0, 0x46, 0xc2, 0x61, 0x08, 0x60, 0x70, 0x47,
-0xe8, 0x17, 0x00, 0x80, 0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00,
-0x70, 0x47, 0x00, 0x00, 0x00, 0x00, 0x0f, 0xe1, 0x00, 0x10, 0xa0, 0xe1,
-0xc0, 0x10, 0x81, 0xe3, 0x01, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1,
-0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1,
-0xc0, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1,
-0x00, 0x00, 0x0f, 0xe1, 0xc0, 0x00, 0xc0, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
-0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, 0x40, 0x00, 0x80, 0xe3,
-0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1,
-0x80, 0x00, 0x10, 0xe3, 0x80, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x21, 0xe1,
-0x00, 0x00, 0x00, 0x12, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x50, 0xe3,
-0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0x13, 0x00, 0xf0, 0x21, 0xe1,
-0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0xe3,
-0x00, 0xf0, 0x21, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0x91, 0x00, 0x00, 0xe0,
-0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x20, 0x80, 0xe0, 0x01, 0x00, 0x80, 0xe0,
-0x1e, 0xff, 0x2f, 0xe1, 0x80, 0xb5, 0x08, 0x4f, 0x64, 0x28, 0x04, 0xd3,
-0x64, 0x20, 0x38, 0x63, 0x00, 0x20, 0xc0, 0x43, 0x03, 0xe0, 0x38, 0x63,
-0x04, 0x49, 0x05, 0xf0, 0x01, 0xfb, 0x78, 0x63, 0xb8, 0x63, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x88, 0x13, 0x00, 0x00,
-0x80, 0xb4, 0x10, 0x4b, 0x00, 0x22, 0x1f, 0x6b, 0x64, 0x2f, 0x03, 0xd2,
-0x09, 0x68, 0x09, 0x68, 0x49, 0x08, 0x02, 0xd2, 0x10, 0x1c, 0x80, 0xbc,
-0x70, 0x47, 0x19, 0x1c, 0xdb, 0x6b, 0x4f, 0x6b, 0xbb, 0x42, 0x05, 0xd2,
-0x40, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x18, 0x18, 0xc8, 0x63, 0xf1, 0xe7,
-0x41, 0x68, 0x05, 0x4b, 0x19, 0x43, 0x41, 0x60, 0x04, 0x48, 0xc1, 0x6b,
-0x01, 0x31, 0xc1, 0x63, 0x02, 0x20, 0xe8, 0xe7, 0x68, 0x0e, 0x00, 0x80,
-0x00, 0x00, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c,
-0x15, 0x4c, 0x00, 0x20, 0x21, 0x6b, 0x64, 0x29, 0x0b, 0xd2, 0xb9, 0x6e,
-0x49, 0x08, 0x08, 0xd3, 0x21, 0x6c, 0xa2, 0x6b, 0x91, 0x42, 0x07, 0xd2,
-0xfa, 0x1d, 0x39, 0x32, 0x52, 0x8b, 0x89, 0x18, 0x21, 0x64, 0x90, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 0x48, 0x62,
-0x38, 0x6b, 0x02, 0xf0, 0x2d, 0xfe, 0x38, 0x1c, 0x02, 0xf0, 0xe8, 0xfa,
-0x01, 0x20, 0xbb, 0x23, 0x1b, 0x01, 0xe1, 0x18, 0xc8, 0x73, 0x05, 0x49,
-0x0a, 0x6c, 0x12, 0x18, 0x0a, 0x64, 0x04, 0x49, 0x8a, 0x6d, 0x12, 0x18,
-0x8a, 0x65, 0xe4, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80,
-0xa4, 0x2a, 0x00, 0x80, 0x80, 0xb4, 0x0a, 0x48, 0xc0, 0x6d, 0x02, 0x23,
-0x18, 0x40, 0x09, 0x4a, 0x00, 0x21, 0x00, 0x28, 0x03, 0xd0, 0xd1, 0x63,
-0x11, 0x64, 0x80, 0xbc, 0x70, 0x47, 0x06, 0x48, 0x07, 0x68, 0x7b, 0x1c,
-0x03, 0x60, 0x0a, 0x2f, 0xf7, 0xd3, 0x01, 0x60, 0xf3, 0xe7, 0x00, 0x00,
-0xa4, 0x2a, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80, 0xe0, 0x01, 0x00, 0x80,
-0x70, 0x47, 0x02, 0x04, 0x12, 0x0c, 0x00, 0x0c, 0x10, 0x18, 0x0a, 0x04,
-0x12, 0x0c, 0x09, 0x0c, 0x51, 0x18, 0x08, 0x18, 0x01, 0x0c, 0x05, 0xd0,
-0x01, 0x04, 0x09, 0x0c, 0x00, 0x0c, 0x08, 0x18, 0x01, 0x0c, 0xf9, 0xd1,
-0x00, 0x04, 0x00, 0x0c, 0x70, 0x47, 0x80, 0xb4, 0x00, 0x22, 0x00, 0x29,
-0x18, 0xd0, 0x4f, 0x08, 0x7b, 0x1e, 0x00, 0x2f,
-0x06, 0xd0, 0x07, 0x88, 0xba, 0x18, 0x02, 0x30, 0x1f, 0x1c, 0x01, 0x3b,
-0x00, 0x2f, 0xf8, 0xd1, 0x49, 0x08, 0x03, 0xd3, 0x00, 0x88, 0x00, 0x06,
-0x00, 0x0e, 0x82, 0x18, 0x10, 0x0c, 0x05, 0xd0, 0x10, 0x04, 0x00, 0x0c,
-0x11, 0x0c, 0x42, 0x18, 0x10, 0x0c, 0xf9, 0xd1, 0x10, 0x04, 0x00, 0x0c,
-0x80, 0xbc, 0x70, 0x47, 0x80, 0xb5, 0x83, 0x89, 0xc7, 0x89, 0xfb, 0x18,
-0x07, 0x8a, 0xfb, 0x18, 0x47, 0x8a, 0xfb, 0x18, 0x40, 0x7a, 0x00, 0x02,
-0xc7, 0x18, 0x38, 0x0c, 0x05, 0xd0, 0x38, 0x04, 0x00, 0x0c, 0x3b, 0x0c,
-0xc7, 0x18, 0x38, 0x0c, 0xf9, 0xd1, 0x08, 0x1c, 0x11, 0x1c, 0xff, 0xf7,
-0xc8, 0xff, 0x01, 0x1c, 0x38, 0x1c, 0xff, 0xf7, 0xb0, 0xff, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x02, 0x23, 0x82, 0x68, 0x1a, 0x40,
-0x00, 0x27, 0x00, 0x2a, 0x0f, 0xd0, 0x0a, 0x4a, 0x93, 0x69, 0x01, 0x33,
-0x93, 0x61, 0x0a, 0x68, 0x8b, 0x68, 0x9a, 0x18, 0x00, 0x68, 0x1c, 0x18,
-0x57, 0x81, 0x09, 0x69, 0x10, 0x1c, 0xff, 0xf7, 0xac, 0xff, 0xc0, 0x43,
-0x60, 0x81, 0x38, 0x1c, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x23, 0x82, 0x68, 0x1a, 0x40,
-0x00, 0x27, 0x00, 0x2a, 0x11, 0xd0, 0x4a, 0x68, 0x52, 0x09, 0x0e, 0xd3,
-0x09, 0x4a, 0x13, 0x6a, 0x01, 0x33, 0x13, 0x62, 0xcb, 0x68, 0x02, 0x68,
-0x9c, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x3a, 0x1a, 0x43, 0x12, 0x68,
-0x00, 0xf0, 0x2e, 0xf8, 0x20, 0x82, 0x38, 0x1c, 0x90, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x80, 0x23,
-0x82, 0x68, 0x1a, 0x40, 0x00, 0x24, 0x00, 0x2a, 0x15, 0xd0, 0x4a, 0x68,
-0x92, 0x09, 0x12, 0xd3, 0x0b, 0x4a, 0xd3, 0x69, 0x01, 0x33, 0xd3, 0x61,
-0xcb, 0x68, 0x02, 0x68, 0x9f, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x3a,
-0x1a, 0x43, 0x12, 0x68, 0x00, 0xf0, 0x0e, 0xf8, 0x00, 0x28, 0x00, 0xd1,
-0x04, 0x48, 0xc0, 0x46, 0xf8, 0x80, 0x20, 0x1c, 0x90, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
-0xb0, 0xb5, 0x14, 0x1c, 0x05, 0x1c, 0x0f, 0x1c, 0x38, 0x69, 0xb9, 0x68,
-0x41, 0x18, 0x38, 0x68, 0xff, 0xf7, 0x53, 0xff, 0xc0, 0x43, 0x01, 0x04,
-0x09, 0x0c, 0x20, 0x1c, 0xff, 0xf7, 0x39, 0xff, 0x04, 0x1c, 0xb8, 0x68,
-0x79, 0x69, 0x40, 0x18, 0x69, 0x68, 0x88, 0x42, 0x0c, 0xd2, 0x2a, 0x68,
-0x12, 0x18, 0x09, 0x1a, 0x10, 0x1c, 0x00, 0xf0, 0x05, 0xf9, 0xc0, 0x43,
-0x01, 0x04, 0x09, 0x0c, 0x20, 0x1c, 0xff, 0xf7, 0x26, 0xff, 0x04, 0x1c,
-0xe0, 0x43, 0x00, 0x04, 0x00, 0x0c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0xc0, 0x08, 0x1a, 0xd3, 0xb8, 0x6a,
-0xf9, 0x6b, 0x40, 0x18, 0x79, 0x6c, 0x00, 0xf0, 0xed, 0xf8, 0xc0, 0x43,
-0x01, 0x04, 0x09, 0x0c, 0x0a, 0x48, 0x07, 0xd0, 0x20, 0x23, 0xb9, 0x69,
-0x19, 0x43, 0xb9, 0x61, 0x01, 0x6b, 0x01, 0x31, 0x01, 0x63, 0x07, 0xe0,
-0xff, 0x23, 0x01, 0x33, 0xb9, 0x69, 0x19, 0x43, 0xb9, 0x61, 0x41, 0x6a,
-0x01, 0x31, 0x41, 0x62, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x0c, 0x2b, 0x00, 0x80, 0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0x41, 0x09,
-0x1c, 0xd3, 0xc0, 0x08, 0x1a, 0xd3, 0xf8, 0x1d, 0x39, 0x30, 0x00, 0x7b,
-0x06, 0x28, 0x15, 0xd1, 0x38, 0x1c, 0x00, 0xf0, 0x53, 0xf8, 0x01, 0x1c,
-0x0a, 0x48, 0x07, 0xd0, 0x40, 0x23, 0xb9, 0x69,
-0x19, 0x43, 0xb9, 0x61, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, 0x07, 0xe0,
-0x01, 0x23, 0x9b, 0x02, 0xb9, 0x69, 0x19, 0x43, 0xb9, 0x61, 0xc1, 0x6a,
-0x01, 0x31, 0xc1, 0x62, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x0c, 0x2b, 0x00, 0x80, 0xb0, 0xb5, 0x07, 0x1c, 0xb8, 0x6b, 0x81, 0x09,
-0x2c, 0xd3, 0xc0, 0x08, 0x2a, 0xd3, 0xf8, 0x1d, 0x39, 0x30, 0x00, 0x7b,
-0x11, 0x28, 0x25, 0xd1, 0xb8, 0x6a, 0x39, 0x6c, 0x40, 0x18, 0x01, 0x23,
-0x9b, 0x07, 0x06, 0x30, 0x18, 0x43, 0x00, 0x68, 0x05, 0x04, 0x2d, 0x0c,
-0x0f, 0x4c, 0x11, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x1f, 0xf8, 0x00, 0x28,
-0x0c, 0xd0, 0xa8, 0x42, 0x02, 0xd1, 0x0c, 0x4b, 0x98, 0x42, 0x07, 0xd0,
-0x80, 0x23, 0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61, 0x60, 0x6b, 0x01, 0x30,
-0x60, 0x63, 0x07, 0xe0, 0x01, 0x23, 0x5b, 0x02, 0xb8, 0x69, 0x18, 0x43,
-0xb8, 0x61, 0xa0, 0x6a, 0x01, 0x30, 0xa0, 0x62, 0x00, 0x20, 0xb0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
-0xf0, 0xb5, 0xff, 0xb0, 0x99, 0xb0, 0x04, 0x1c, 0xe0, 0x6b, 0x61, 0x6c,
-0x09, 0x18, 0x03, 0xaa, 0x85, 0x18, 0xa3, 0x6a, 0x00, 0x20, 0x8a, 0x08,
-0x01, 0x32, 0x97, 0x92, 0x07, 0xd0, 0x82, 0x00, 0x9f, 0x58, 0x03, 0xae,
-0xb7, 0x50, 0x97, 0x9a, 0x01, 0x30, 0x82, 0x42, 0xf7, 0xd8, 0x60, 0x6a,
-0x01, 0x23, 0x9b, 0x07, 0x04, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46,
-0x02, 0x90, 0x02, 0xaf, 0x3f, 0x88, 0x03, 0xa8, 0xff, 0xf7, 0x87, 0xfe,
-0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0xff, 0xf7, 0x6d, 0xfe,
-0x07, 0x1c, 0xe0, 0x6b, 0xa1, 0x6c, 0x40, 0x18, 0x61, 0x6a, 0x01, 0x23,
-0x9b, 0x07, 0x08, 0x31, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46, 0x01, 0x91,
-0x01, 0xa9, 0x09, 0x88, 0x01, 0x31, 0x88, 0x42, 0x0c, 0xd2, 0xa2, 0x6a,
-0x12, 0x18, 0x09, 0x1a, 0x10, 0x1c, 0x00, 0xf0, 0x2f, 0xf8, 0xc0, 0x43,
-0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0xff, 0xf7, 0x50, 0xfe, 0x07, 0x1c,
-0xa8, 0x89, 0xe9, 0x89, 0x08, 0x18, 0x29, 0x8a, 0x08, 0x18, 0x69, 0x8a,
-0x08, 0x18, 0x69, 0x7a, 0x09, 0x02, 0x08, 0x18, 0xa1, 0x6c, 0x62, 0x6c,
-0x89, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, 0x12, 0x0a, 0x11, 0x43,
-0x09, 0x04, 0x09, 0x0c, 0x09, 0x18, 0x08, 0x0c, 0x05, 0xd0, 0x08, 0x04,
-0x00, 0x0c, 0x09, 0x0c, 0x41, 0x18, 0x08, 0x0c, 0xf9, 0xd1, 0x38, 0x1c,
-0xff, 0xf7, 0x2f, 0xfe, 0xc0, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x7f, 0xb0,
-0x19, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb4, 0x00, 0x22,
-0x00, 0x29, 0x2e, 0xd0, 0x83, 0x07, 0x9b, 0x0f, 0xdc, 0x00, 0x47, 0x18,
-0x04, 0x25, 0xef, 0x1b, 0xbf, 0x07, 0xbf, 0x0f, 0xff, 0x00, 0x80, 0x08,
-0x80, 0x00, 0x59, 0x18, 0x03, 0x31, 0x89, 0x08, 0x4d, 0x1e, 0x02, 0xc8,
-0xe1, 0x40, 0xa1, 0x40, 0x6b, 0x1e, 0x00, 0x2d, 0x09, 0xd0, 0x0c, 0x04,
-0x24, 0x0c, 0xa2, 0x18, 0x09, 0x0c, 0x8a, 0x18, 0x02, 0xc8, 0x1c, 0x1c,
-0x01, 0x3b, 0x00, 0x2c, 0xf5, 0xd1, 0xb9, 0x40, 0x08, 0x1c, 0xf8, 0x40,
-0x01, 0x04, 0x09, 0x0c, 0x89, 0x18, 0x00, 0x0c, 0x42, 0x18, 0x10, 0x0c,
-0x05, 0xd0, 0x10, 0x04, 0x00, 0x0c, 0x11, 0x0c, 0x42, 0x18, 0x10, 0x0c,
-0xf9, 0xd1, 0x10, 0x04, 0x00, 0x0c, 0xb0, 0xbc, 0x70, 0x47, 0x00, 0x00,
-0x90, 0xb4, 0x00, 0x20, 0x01, 0x27, 0x11, 0x49, 0x42, 0x00, 0x12, 0x18,
-0xd2, 0x00, 0x53, 0x18, 0x9c, 0x68, 0x01, 0x23,
-0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x1b, 0x03, 0x1b, 0x0b, 0x8a, 0x58,
-0x12, 0x03, 0x12, 0x0b, 0x93, 0x42, 0x0c, 0xd1, 0x01, 0x30, 0x04, 0x28,
-0xec, 0xd3, 0x08, 0x48, 0xc0, 0x6a, 0x01, 0x03, 0x09, 0x0b, 0x07, 0x48,
-0x00, 0x6f, 0x00, 0x03, 0x00, 0x0b, 0x81, 0x42, 0x02, 0xd0, 0x38, 0x1c,
-0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 0xfb, 0xe7, 0xa8, 0x03, 0x00, 0x80,
-0x00, 0x40, 0x14, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x98, 0xb4, 0x14, 0x4a,
-0xc0, 0x46, 0x00, 0x92, 0x83, 0x00, 0x13, 0x48, 0xc0, 0x58, 0x07, 0x03,
-0x3f, 0x0b, 0x12, 0x48, 0xc0, 0x58, 0x02, 0x03, 0x12, 0x0b, 0x11, 0x48,
-0xc0, 0x58, 0x00, 0x03, 0x00, 0x0b, 0x10, 0x4c, 0xe4, 0x58, 0x01, 0x23,
-0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x9b, 0x00, 0xcc, 0x00, 0x01, 0x21,
-0x98, 0x42, 0x01, 0xd1, 0x08, 0x1c, 0x09, 0xe0, 0x98, 0x42, 0x03, 0xd9,
-0x10, 0x1a, 0xda, 0x1b, 0x80, 0x18, 0x00, 0xe0, 0x18, 0x1a, 0x84, 0x42,
-0xf4, 0xd3, 0x00, 0x20, 0x98, 0xbc, 0x70, 0x47, 0x55, 0x55, 0x55, 0x55,
-0x20, 0x04, 0x00, 0x80, 0x28, 0x04, 0x00, 0x80, 0x08, 0x04, 0x00, 0x80,
-0x18, 0x04, 0x00, 0x80, 0x80, 0xb4, 0x13, 0x04, 0x00, 0xd0, 0x01, 0x3a,
-0x80, 0x00, 0x0b, 0x1c, 0x13, 0x49, 0x0f, 0x58, 0xc0, 0x46, 0x3b, 0x60,
-0x0b, 0x58, 0xc0, 0x46, 0x5a, 0x60, 0x0a, 0x58, 0x08, 0x32, 0x10, 0x4b,
-0x1b, 0x58, 0x9a, 0x42, 0x01, 0xd3, 0x0f, 0x4a, 0x12, 0x58, 0x0f, 0x4b,
-0x1f, 0x58, 0x01, 0x23, 0x9b, 0x07, 0x3b, 0x43, 0x1b, 0x68, 0x9b, 0x00,
-0x17, 0x03, 0x3f, 0x0b, 0x9f, 0x42, 0x06, 0xd1, 0x0a, 0x48, 0xc1, 0x68,
-0x01, 0x31, 0xc1, 0x60, 0x01, 0x20, 0x80, 0xbc, 0x70, 0x47, 0x08, 0x4b,
-0x1b, 0x58, 0xc0, 0x46, 0x1a, 0x60, 0x0a, 0x50, 0x00, 0x20, 0xf6, 0xe7,
-0x08, 0x04, 0x00, 0x80, 0x28, 0x04, 0x00, 0x80, 0x20, 0x04, 0x00, 0x80,
-0x18, 0x04, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x10, 0x04, 0x00, 0x80,
-0xff, 0x5f, 0x2d, 0xe9, 0x48, 0xfe, 0xff, 0xeb, 0x01, 0xb6, 0xa0, 0xe3,
-0x01, 0xb1, 0x8b, 0xe2, 0x02, 0x8a, 0xa0, 0xe3, 0x01, 0x7a, 0xa0, 0xe3,
-0x01, 0xa9, 0xa0, 0xe3, 0x01, 0x56, 0xa0, 0xe3, 0xc8, 0x60, 0x9f, 0xe5,
-0xc8, 0x90, 0x9f, 0xe5, 0x14, 0x40, 0x9b, 0xe5, 0x00, 0x00, 0x54, 0xe3,
-0x2c, 0x00, 0x00, 0x0a, 0x03, 0x0a, 0x14, 0xe3, 0x11, 0x00, 0x00, 0x0a,
-0x0c, 0x00, 0x96, 0xe5, 0x00, 0x00, 0x50, 0xe3, 0x21, 0x00, 0x00, 0x0a,
-0x01, 0x0a, 0x14, 0xe3, 0x05, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5,
-0x01, 0x0a, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5,
-0x14, 0x70, 0x85, 0xe5, 0x06, 0x00, 0x00, 0xea, 0x02, 0x0a, 0x14, 0xe3,
-0x04, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5, 0x02, 0x0a, 0xc0, 0xe3,
-0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5, 0x14, 0x80, 0x85, 0xe5,
-0x01, 0x09, 0x14, 0xe3, 0x04, 0x00, 0x00, 0x0a, 0x1c, 0x00, 0x96, 0xe5,
-0x01, 0x09, 0xc0, 0xe3, 0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5,
-0x14, 0xa0, 0x85, 0xe5, 0x02, 0x00, 0x14, 0xe3, 0x40, 0x00, 0x00, 0x1b,
-0x01, 0x00, 0x14, 0xe3, 0x54, 0x00, 0x00, 0x1b, 0x02, 0x0b, 0x14, 0xe3,
-0x67, 0x00, 0x00, 0x1b, 0x01, 0x0b, 0x14, 0xe3, 0x20, 0x00, 0x00, 0x1b,
-0x18, 0x00, 0x99, 0xe5, 0x01, 0x00, 0x80, 0xe2, 0x18, 0x00, 0x89, 0xe5,
-0xd5, 0xff, 0xff, 0xea, 0x1c, 0x00, 0x96, 0xe5, 0x01, 0x0a, 0xc0, 0xe3,
-0x1c, 0x00, 0x86, 0xe5, 0x1c, 0x00, 0x85, 0xe5,
-0x14, 0x70, 0x85, 0xe5, 0xe1, 0xff, 0xff, 0xea, 0xff, 0x5f, 0xbd, 0xe8,
-0x04, 0xf0, 0x5e, 0xe2, 0x68, 0x0e, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40,
-0x10, 0x10, 0x1f, 0xe5, 0x14, 0x30, 0x91, 0xe5, 0x00, 0x20, 0xc3, 0xe1,
-0x14, 0x20, 0x81, 0xe5, 0x01, 0x16, 0xa0, 0xe3, 0x0c, 0x20, 0x81, 0xe5,
-0x0b, 0x12, 0xa0, 0xe3, 0x00, 0x00, 0x81, 0xe5, 0x18, 0x10, 0x9f, 0xe5,
-0xb0, 0x24, 0xd1, 0xe1, 0x01, 0x20, 0x82, 0xe2, 0xb0, 0x24, 0xc1, 0xe1,
-0x3c, 0x20, 0x91, 0xe5, 0x00, 0x00, 0x82, 0xe1, 0x3c, 0x00, 0x81, 0xe5,
-0x1e, 0xff, 0x2f, 0xe1, 0xa0, 0x82, 0x20, 0x40, 0xff, 0xff, 0xff, 0xea,
-0xfe, 0xff, 0xff, 0xea, 0x01, 0x0b, 0xa0, 0xe3, 0x01, 0x16, 0xa0, 0xe3,
-0x14, 0x00, 0x81, 0xe5, 0x00, 0x1a, 0x81, 0xe1, 0x24, 0x20, 0x91, 0xe5,
-0x70, 0x00, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x24, 0x20, 0x80, 0xe5,
-0x28, 0x10, 0x91, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x28, 0x10, 0x80, 0xe5,
-0x2c, 0x20, 0x90, 0xe5, 0x01, 0x20, 0x82, 0xe2, 0x2c, 0x20, 0x80, 0xe5,
-0x3f, 0x00, 0x01, 0xe2, 0x3f, 0x00, 0x50, 0xe3, 0x1e, 0xff, 0x2f, 0x11,
-0x18, 0x00, 0x9f, 0xe5, 0x00, 0x10, 0x90, 0xe5, 0x01, 0x10, 0x81, 0xe2,
-0x00, 0x10, 0x80, 0xe5, 0x02, 0x18, 0xa0, 0xe3, 0x0b, 0x02, 0xa0, 0xe3,
-0x00, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x30, 0x04, 0x00, 0x80,
-0x01, 0x06, 0xa0, 0xe3, 0x01, 0x01, 0x80, 0xe2, 0x00, 0x10, 0x90, 0xe5,
-0x01, 0x08, 0x11, 0xe3, 0x0b, 0x10, 0xa0, 0xe3, 0x02, 0x19, 0x81, 0xe2,
-0x05, 0x00, 0x00, 0x1a, 0x00, 0x20, 0x90, 0xe5, 0x42, 0x28, 0xb0, 0xe1,
-0x05, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x90, 0xe5, 0x02, 0x0c, 0x10, 0xe3,
-0x02, 0x00, 0x00, 0x0a, 0x06, 0x07, 0xa0, 0xe3, 0x4c, 0x11, 0x80, 0xe5,
-0x03, 0x00, 0x00, 0xea, 0x0c, 0x00, 0x9f, 0xe5, 0x00, 0x00, 0x00, 0x00,
-0x40, 0x10, 0x80, 0xe5, 0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea,
-0x00, 0x00, 0x00, 0x80, 0x01, 0x06, 0xa0, 0xe3, 0x01, 0x01, 0x80, 0xe2,
-0x00, 0x10, 0x90, 0xe5, 0x01, 0x08, 0x11, 0xe3, 0x0c, 0x10, 0xa0, 0xe3,
-0x02, 0x19, 0x81, 0xe2, 0x05, 0x00, 0x00, 0x1a, 0x00, 0x20, 0x90, 0xe5,
-0x42, 0x28, 0xb0, 0xe1, 0x05, 0x00, 0x00, 0x1a, 0x00, 0x00, 0x90, 0xe5,
-0x02, 0x0c, 0x10, 0xe3, 0x02, 0x00, 0x00, 0x0a, 0x06, 0x07, 0xa0, 0xe3,
-0x4c, 0x11, 0x80, 0xe5, 0x03, 0x00, 0x00, 0xea, 0x4c, 0x00, 0x1f, 0xe5,
-0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x80, 0xe5, 0xff, 0xff, 0xff, 0xea,
-0xfe, 0xff, 0xff, 0xea, 0x02, 0x1b, 0xa0, 0xe3, 0x01, 0x06, 0xa0, 0xe3,
-0x14, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0x21, 0x1f, 0xe5,
-0x14, 0x30, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x80, 0xe5,
-0x1c, 0x00, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x81, 0xe5,
-0x00, 0x10, 0xa0, 0xe3, 0x14, 0x10, 0x82, 0xe5, 0x01, 0x06, 0xa0, 0xe3,
-0x1c, 0x10, 0x82, 0xe5, 0x0c, 0x10, 0x80, 0xe5, 0x1c, 0x10, 0x92, 0xe5,
-0x00, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1,
-0xc0, 0x21, 0x1f, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x10, 0x82, 0xe5,
-0x01, 0x16, 0xa0, 0xe3, 0x14, 0x00, 0x82, 0xe5, 0x0c, 0x00, 0x81, 0xe5,
-0x1c, 0x00, 0x92, 0xe5, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x81, 0xe5,
-0x1e, 0xff, 0x2f, 0xe1, 0x80, 0xb5, 0x0f, 0x1c, 0x38, 0x1c, 0x00, 0xf0,
-0x17, 0xf8, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x1c,
-0x00, 0xf0, 0x92, 0xf8, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x80, 0xb5, 0x0f, 0x1c, 0x38, 0x1c, 0x00, 0xf0, 0x09, 0xf8, 0x00, 0x28,
-0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x84, 0xf8, 0x00, 0x20, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb4, 0x07, 0x68, 0x3a, 0x78, 0xd2, 0x07,
-0xd2, 0x0f, 0x00, 0x24, 0x00, 0x2a, 0x03, 0xd0, 0xff, 0x22, 0x01, 0x32,
-0x42, 0x60, 0x00, 0xe0, 0x44, 0x60, 0x3a, 0x7b, 0x7b, 0x7b, 0x1b, 0x02,
-0x1a, 0x43, 0x81, 0x2a, 0x08, 0xd1, 0x01, 0x23, 0x5b, 0x02, 0x42, 0x68,
-0x1a, 0x43, 0x42, 0x60, 0x04, 0x22, 0xbf, 0x18, 0x82, 0x60, 0x00, 0xe0,
-0x84, 0x60, 0x3a, 0x7b, 0x7b, 0x7b, 0x1b, 0x02, 0x1a, 0x43, 0x08, 0x2a,
-0x06, 0xd1, 0x06, 0x23, 0x41, 0x68, 0x19, 0x43, 0x41, 0x60, 0x81, 0x68,
-0x0e, 0x31, 0x3c, 0xe0, 0xc1, 0x23, 0xdb, 0x00, 0x9a, 0x42, 0x03, 0xd1,
-0x41, 0x68, 0x24, 0x4b, 0x19, 0x43, 0x3e, 0xe0, 0x23, 0x4b, 0x9a, 0x42,
-0x04, 0xd1, 0x01, 0x23, 0x1b, 0x03, 0x41, 0x68, 0x19, 0x43, 0x36, 0xe0,
-0x13, 0x02, 0x12, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04,
-0x12, 0x0c, 0x2e, 0x3a, 0x1c, 0x4b, 0x9a, 0x42, 0x2d, 0xd8, 0x01, 0x25,
-0x42, 0x68, 0x15, 0x43, 0x45, 0x60, 0xba, 0x7b, 0xfb, 0x7b, 0x1b, 0x02,
-0x1a, 0x43, 0x18, 0x4b, 0x9a, 0x42, 0x22, 0xd1, 0xfb, 0x1d, 0x09, 0x33,
-0x44, 0xcb, 0x9b, 0x07, 0xdb, 0x0e, 0xda, 0x40, 0x5b, 0x42, 0x20, 0x33,
-0x9e, 0x40, 0x16, 0x43, 0x03, 0x2e, 0x18, 0xd1, 0x39, 0x7d, 0x7b, 0x7d,
-0x1b, 0x02, 0x19, 0x43, 0x08, 0x29, 0x07, 0xd1, 0x04, 0x21, 0x29, 0x43,
-0x41, 0x60, 0x81, 0x68, 0x16, 0x31, 0x81, 0x60, 0x01, 0x21, 0x0a, 0xe0,
-0xc1, 0x23, 0xdb, 0x00, 0x99, 0x42, 0x04, 0xd1, 0x01, 0x21, 0x89, 0x03,
-0x29, 0x43, 0x41, 0x60, 0x00, 0xe0, 0x84, 0x60, 0x00, 0x21, 0x08, 0x1c,
-0xf0, 0xbc, 0x70, 0x47, 0x02, 0x40, 0x00, 0x00, 0x81, 0x80, 0x00, 0x00,
-0xae, 0x05, 0x00, 0x00, 0xaa, 0xaa, 0x00, 0x00, 0x80, 0xb4, 0x42, 0x68,
-0xd1, 0x08, 0x3f, 0xd3, 0x01, 0x68, 0x83, 0x68, 0x59, 0x18, 0x02, 0x39,
-0x8f, 0x78, 0x3f, 0x07, 0x3f, 0x0f, 0x05, 0x2f, 0x03, 0xd1, 0xda, 0x1d,
-0x0d, 0x32, 0xc2, 0x60, 0x05, 0xe0, 0xbf, 0x00, 0xdb, 0x19, 0xc3, 0x60,
-0x08, 0x23, 0x1a, 0x43, 0x42, 0x60, 0x8a, 0x78, 0x12, 0x07, 0x12, 0x0f,
-0x92, 0x00, 0x02, 0x61, 0x0a, 0x79, 0x4b, 0x79, 0x1b, 0x02, 0x1a, 0x43,
-0x13, 0x02, 0x12, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04,
-0x12, 0x0c, 0x42, 0x61, 0xca, 0x7a, 0x06, 0x2a, 0x03, 0xd1, 0x10, 0x23,
-0x42, 0x68, 0x1a, 0x43, 0x10, 0xe0, 0x11, 0x2a, 0x03, 0xd1, 0x20, 0x23,
-0x42, 0x68, 0x1a, 0x43, 0x0a, 0xe0, 0x33, 0x2a, 0x03, 0xd1, 0x40, 0x23,
-0x42, 0x68, 0x1a, 0x43, 0x04, 0xe0, 0x32, 0x2a, 0x03, 0xd1, 0x80, 0x23,
-0x42, 0x68, 0x1a, 0x43, 0x42, 0x60, 0xc9, 0x7a, 0xc0, 0x46, 0x01, 0x76,
-0x80, 0xbc, 0x70, 0x47, 0x0a, 0x78, 0xc0, 0x46, 0x02, 0x60, 0x4b, 0x78,
-0x1b, 0x02, 0x1a, 0x43, 0x02, 0x60, 0x8b, 0x78, 0x1b, 0x04, 0x1a, 0x43,
-0x02, 0x60, 0xc9, 0x78, 0x09, 0x06, 0x11, 0x43, 0x01, 0x60, 0x70, 0x47,
-0x80, 0xb5, 0x07, 0x1c, 0x48, 0x68, 0x80, 0x09, 0x26, 0xd3, 0xb8, 0x6a,
-0xc9, 0x68, 0x40, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x02, 0x30, 0x18, 0x43,
-0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x11, 0x23, 0x9b, 0x02, 0x98, 0x42,
-0x18, 0xd1, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46,
-0x48, 0x62, 0x38, 0x6b, 0x02, 0xf0, 0xda, 0xf8, 0x38, 0x1c, 0x01, 0xf0,
-0x95, 0xfd, 0x01, 0x20, 0x07, 0x49, 0xc0, 0x46, 0xc8, 0x73, 0x07, 0x49,
-0x4a, 0x6c, 0x12, 0x18, 0x4a, 0x64, 0x06, 0x49, 0x8a, 0x6d, 0x12, 0x18,
-0x8a, 0x65, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0xfa, 0xe7,
-0x18, 0x1a, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80, 0xa4, 0x2a, 0x00, 0x80,
-0x81, 0x07, 0x19, 0xd0, 0x80, 0x08, 0x80, 0x00, 0x01, 0x23, 0x9b, 0x07,
-0x01, 0x1d, 0x18, 0x43, 0x00, 0x68, 0x19, 0x43, 0x09, 0x68, 0x02, 0x02,
-0x12, 0x0e, 0x12, 0x06, 0x00, 0x0a, 0xff, 0x23, 0x1b, 0x04, 0x18, 0x40,
-0x10, 0x43, 0x0a, 0x0a, 0x12, 0x06, 0x12, 0x0e, 0x10, 0x43, 0x09, 0x02,
-0x1b, 0x0a, 0x19, 0x40, 0x08, 0x43, 0x70, 0x47, 0x01, 0x23, 0x9b, 0x07,
-0x18, 0x43, 0x00, 0x68, 0x01, 0x06, 0x02, 0x02, 0xff, 0x23, 0x1b, 0x04,
-0x1a, 0x40, 0x11, 0x43, 0x02, 0x0a, 0x1b, 0x0a, 0x1a, 0x40, 0x11, 0x43,
-0x00, 0x0e, 0x08, 0x43, 0xed, 0xe7, 0x00, 0x00, 0xf0, 0xb5, 0x04, 0x23,
-0x81, 0x6b, 0x19, 0x40, 0x00, 0x22, 0x00, 0x29, 0x46, 0xd0, 0xc7, 0x1d,
-0x39, 0x37, 0x39, 0x7b, 0x33, 0x29, 0x01, 0xd0, 0x32, 0x29, 0x3f, 0xd1,
-0x01, 0x6b, 0xc0, 0x46, 0x4a, 0x65, 0xc4, 0x1d, 0x2d, 0x34, 0xcd, 0x1d,
-0x2d, 0x35, 0x00, 0x22, 0x93, 0x00, 0xe6, 0x58, 0xc0, 0x46, 0xee, 0x50,
-0x01, 0x32, 0x07, 0x2a, 0xf8, 0xd3, 0x82, 0x6a, 0xc0, 0x46, 0x4a, 0x63,
-0x82, 0x6a, 0xc0, 0x46, 0x8a, 0x62, 0x7a, 0x8b, 0xcb, 0x1d, 0x39, 0x33,
-0x5a, 0x83, 0x40, 0x6a, 0xc0, 0x46, 0x48, 0x62, 0x12, 0x48, 0x01, 0x27,
-0x42, 0x68, 0x00, 0x2a, 0x10, 0xd1, 0xc2, 0x68, 0x00, 0x2a, 0x13, 0xd1,
-0x42, 0x69, 0x00, 0x2a, 0x0d, 0xd1, 0x01, 0x61, 0xc1, 0x60, 0x01, 0x6a,
-0x02, 0x29, 0x02, 0xd3, 0x20, 0x30, 0x07, 0x71, 0x0c, 0xe0, 0x00, 0xf0,
-0x13, 0xf8, 0x09, 0xe0, 0xc2, 0x68, 0x00, 0x2a, 0x02, 0xd1, 0x01, 0x61,
-0xc1, 0x60, 0x03, 0xe0, 0x02, 0x69, 0xc0, 0x46, 0x51, 0x65, 0x01, 0x61,
-0x38, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x10, 0x1c, 0xfa, 0xe7,
-0x6c, 0x06, 0x00, 0x80, 0x80, 0xb5, 0x1e, 0x49, 0x00, 0x22, 0xcb, 0x68,
-0x00, 0x2b, 0x34, 0xd0, 0xc8, 0x1d, 0xf9, 0x30, 0x83, 0x62, 0xcb, 0x68,
-0x9b, 0x6a, 0xc0, 0x46, 0xc3, 0x62, 0xcf, 0x69, 0x7b, 0x00, 0xdf, 0x19,
-0x7f, 0x02, 0x17, 0x4b, 0xff, 0x18, 0xff, 0x37, 0x65, 0x37, 0x83, 0x63,
-0x07, 0x63, 0xcb, 0x1d, 0xff, 0x33, 0x5a, 0x33, 0x1a, 0x72, 0xcb, 0x69,
-0x00, 0x2b, 0x01, 0xd0, 0xca, 0x61, 0x01, 0xe0, 0x01, 0x23, 0xcb, 0x61,
-0x0f, 0x1c, 0xc9, 0x68, 0x49, 0x6a, 0x09, 0x89, 0x01, 0x31, 0x41, 0x63,
-0xf8, 0x1d, 0xff, 0x30, 0x3a, 0x30, 0x42, 0x60, 0x02, 0x82, 0x82, 0x60,
-0xc2, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xce, 0xfa, 0x38, 0x6a, 0x01, 0x30,
-0x38, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0x0a, 0xf8, 0x80, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x10, 0x1c, 0xfa, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
-0xac, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x07, 0x1c, 0xf9, 0x1d, 0xf9, 0x31,
-0x88, 0x6a, 0xc2, 0x1d, 0x2d, 0x32, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x32,
-0x1a, 0x43, 0xc8, 0x6a, 0x12, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x80, 0x18,
-0x82, 0x79, 0xc3, 0x79, 0x1b, 0x02, 0x1a, 0x43, 0x13, 0x02, 0x12, 0x0a,
-0x12, 0x06, 0x12, 0x0e, 0x1a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x02, 0x38,
-0x92, 0x04, 0x92, 0x0c, 0x00, 0x26, 0x25, 0x4d,
-0xec, 0x1d, 0xff, 0x34, 0x3a, 0x34, 0x00, 0x2a, 0x04, 0xd0, 0x20, 0x8a,
-0x01, 0x23, 0x9b, 0x02, 0x18, 0x43, 0x2b, 0xe0, 0x01, 0x23, 0x9b, 0x07,
-0xc2, 0x1d, 0x0d, 0x32, 0x1a, 0x43, 0x12, 0x68, 0x12, 0x04, 0x12, 0x30,
-0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x10, 0x43, 0x03, 0x1c,
-0xf8, 0x1d, 0xff, 0x30, 0x4a, 0x30, 0x82, 0x78, 0xc8, 0x6b, 0x19, 0x1c,
-0x02, 0xf0, 0x02, 0xf8, 0x00, 0x28, 0x04, 0xda, 0x20, 0x8a, 0xff, 0x23,
-0x01, 0x33, 0x18, 0x43, 0x0e, 0xe0, 0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31,
-0x08, 0x60, 0x01, 0x04, 0x09, 0x0c, 0x38, 0x1c, 0x00, 0xf0, 0x1c, 0xf8,
-0x00, 0x28, 0x14, 0xd1, 0x20, 0x8a, 0x01, 0x23, 0x5b, 0x02, 0x18, 0x43,
-0x20, 0x82, 0x21, 0x8a, 0x38, 0x1c, 0x00, 0xf0, 0xa2, 0xfb, 0xe8, 0x68,
-0x01, 0x23, 0x9b, 0x07, 0x54, 0x30, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46,
-0xe8, 0x60, 0x30, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20,
-0xfa, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0xf8, 0xb5, 0x07, 0x1c,
-0xfc, 0x1d, 0xf9, 0x34, 0xa0, 0x6b, 0xa6, 0x6a, 0xc5, 0x1d, 0x0d, 0x35,
-0x38, 0x48, 0xc0, 0x6a, 0x4b, 0x00, 0x59, 0x18, 0x49, 0x01, 0x42, 0x18,
-0x01, 0x20, 0x80, 0x07, 0x10, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c,
-0x00, 0x90, 0x01, 0x23, 0x9b, 0x07, 0xd0, 0x1d, 0x05, 0x30, 0x18, 0x43,
-0x00, 0x68, 0x38, 0x1c, 0x29, 0x1c, 0x00, 0xf0, 0xc2, 0xfa, 0xa8, 0x88,
-0x41, 0x07, 0x01, 0xd0, 0x00, 0x20, 0x51, 0xe0, 0x29, 0x89, 0x09, 0x18,
-0x60, 0x6b, 0x81, 0x42, 0xf8, 0xd8, 0x69, 0x89, 0xea, 0x88, 0x89, 0x18,
-0x81, 0x42, 0xf3, 0xd8, 0x00, 0x98, 0x01, 0x28, 0x25, 0xd1, 0xe0, 0x6a,
-0xf1, 0x6b, 0x40, 0x18, 0x71, 0x6c, 0xfa, 0x1d, 0xcd, 0x32, 0x01, 0xf0,
-0x33, 0xf9, 0xfa, 0x1d, 0xff, 0x32, 0x3a, 0x32, 0xe0, 0x6a, 0x51, 0x69,
-0x40, 0x18, 0xc3, 0x1d, 0x03, 0x33, 0x00, 0x20, 0x81, 0x00, 0x5e, 0x58,
-0xc9, 0x19, 0xff, 0x31, 0x01, 0x31, 0x4e, 0x61, 0x01, 0x30, 0x04, 0x28,
-0xf6, 0xd3, 0xe0, 0x6a, 0x51, 0x69, 0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31,
-0x00, 0x20, 0x00, 0x22, 0x43, 0x00, 0xca, 0x52, 0x01, 0x30, 0x06, 0x28,
-0xfa, 0xd3, 0x29, 0x1c, 0x11, 0x4a, 0x00, 0x20, 0xff, 0xf7, 0xae, 0xfb,
-0x01, 0x22, 0x52, 0x04, 0x60, 0x6b, 0x02, 0x43, 0x01, 0x20, 0x21, 0x6b,
-0xff, 0xf7, 0xa6, 0xfb, 0x01, 0x22, 0x52, 0x04, 0x60, 0x6b, 0x02, 0x43,
-0x00, 0x20, 0xe1, 0x6a, 0xff, 0xf7, 0x9e, 0xfb, 0xa1, 0x6b, 0x08, 0x4a,
-0x01, 0x20, 0xff, 0xf7, 0x99, 0xfb, 0x03, 0x20, 0x06, 0x49, 0xc0, 0x46,
-0x48, 0x62, 0x01, 0x20, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x4c, 0x2a, 0x00, 0x80, 0x54, 0x00, 0x03, 0x00, 0x14, 0x00, 0x0f, 0x00,
-0x6c, 0x07, 0x00, 0x80, 0xf0, 0xb5, 0x8d, 0xb0, 0x00, 0x20, 0xb5, 0x4a,
-0xd5, 0x1d, 0xf9, 0x35, 0x68, 0x62, 0x01, 0x20, 0x00, 0x05, 0xb3, 0x49,
-0xc0, 0x46, 0x08, 0x60, 0xa8, 0x6a, 0xc4, 0x1d, 0x2d, 0x34, 0xb1, 0x48,
-0xc0, 0x6a, 0xd7, 0x1d, 0xff, 0x37, 0x3a, 0x37, 0x39, 0x68, 0x4b, 0x00,
-0x59, 0x18, 0x49, 0x01, 0x40, 0x18, 0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d,
-0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0x08, 0x30, 0x18, 0x43, 0x00, 0x68,
-0xc0, 0x46, 0x09, 0x90, 0xff, 0x23, 0x1b, 0x02, 0x18, 0x40, 0x00, 0x0a,
-0x0a, 0x90, 0x0a, 0x98, 0xa4, 0x4e, 0x01, 0x28, 0x59, 0xd1, 0x28, 0x6b,
-0xa2, 0x68, 0x80, 0x18, 0xa2, 0x4a, 0x21, 0x69,
-0x09, 0x04, 0x09, 0x0c, 0x01, 0xf0, 0x26, 0xf9, 0x28, 0x6b, 0x79, 0x69,
-0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20, 0x82, 0x00, 0x98, 0x4b,
-0xd3, 0x18, 0xff, 0x33, 0x01, 0x33, 0x5b, 0x69, 0xc0, 0x46, 0x8b, 0x50,
-0x01, 0x30, 0x04, 0x28, 0xf4, 0xd3, 0x00, 0x20, 0x31, 0x1c, 0x82, 0x00,
-0x56, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x04, 0xae,
-0xb3, 0x50, 0x01, 0x30, 0x03, 0x28, 0xf4, 0xd3, 0x00, 0x20, 0x08, 0x90,
-0x90, 0x49, 0x42, 0x00, 0x8b, 0x5a, 0xb2, 0x5a, 0x93, 0x42, 0x13, 0xd0,
-0x8e, 0x48, 0xc1, 0x89, 0x01, 0x31, 0xc1, 0x81, 0xb8, 0x68, 0x00, 0x28,
-0x03, 0xd1, 0x38, 0x8a, 0x10, 0x23, 0x18, 0x43, 0x71, 0xe0, 0x38, 0x8a,
-0x40, 0x23, 0x18, 0x43, 0x6d, 0xe0, 0x00, 0xf0, 0x11, 0xf9, 0x01, 0xf0,
-0x67, 0xff, 0xf5, 0xe0, 0x01, 0x30, 0x06, 0x28, 0xe3, 0xd3, 0x08, 0x98,
-0x00, 0x28, 0x0c, 0xd1, 0xb8, 0x68, 0x41, 0x1c, 0xb9, 0x60, 0x00, 0x28,
-0x03, 0xd1, 0x38, 0x8a, 0x01, 0x23, 0x18, 0x43, 0x02, 0xe0, 0x38, 0x8a,
-0x04, 0x23, 0x18, 0x43, 0x38, 0x82, 0x78, 0x68, 0x01, 0x30, 0x78, 0x60,
-0x62, 0xe0, 0x0a, 0x98, 0x02, 0x28, 0x5f, 0xd1, 0x09, 0x98, 0x40, 0x0c,
-0x73, 0xd3, 0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x01, 0x30, 0x18, 0x43,
-0x00, 0x68, 0xe1, 0x1d, 0x0d, 0x31, 0x19, 0x43, 0x09, 0x68, 0x40, 0x18,
-0x0c, 0x38, 0x00, 0x04, 0x00, 0x0c, 0x00, 0x21, 0x8a, 0x00, 0x6b, 0x4b,
-0xd6, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x04, 0xae,
-0xb3, 0x50, 0x01, 0x31, 0x03, 0x29, 0xf3, 0xd3, 0x00, 0x21, 0x83, 0x1e,
-0x0c, 0x93, 0x68, 0x4a, 0x16, 0x6b, 0xc0, 0x46, 0x0b, 0x96, 0x8a, 0x00,
-0x0c, 0x9b, 0x9b, 0x18, 0x0b, 0x9e, 0x9e, 0x19, 0x01, 0x23, 0x9b, 0x07,
-0x33, 0x43, 0x1b, 0x68, 0x6e, 0x46, 0xb3, 0x50, 0x01, 0x31, 0x04, 0x29,
-0xf1, 0xd3, 0x69, 0x46, 0x8b, 0x1c, 0x07, 0x93, 0x00, 0x21, 0x08, 0x91,
-0x04, 0xae, 0x4a, 0x00, 0x07, 0x9b, 0x9b, 0x5a, 0xb2, 0x5a, 0x93, 0x42,
-0x11, 0xd0, 0x58, 0x48, 0xc1, 0x89, 0x01, 0x31, 0xc1, 0x81, 0xf8, 0x68,
-0x41, 0x1c, 0xf9, 0x60, 0x00, 0x28, 0x03, 0xd1, 0x38, 0x8a, 0x20, 0x23,
-0x18, 0x43, 0x02, 0xe0, 0x38, 0x8a, 0x80, 0x23, 0x18, 0x43, 0x38, 0x82,
-0x8f, 0xe7, 0x01, 0x31, 0x06, 0x29, 0xe4, 0xd3, 0x08, 0x99, 0x00, 0x29,
-0x0d, 0xd1, 0xf9, 0x68, 0x4a, 0x1c, 0xfa, 0x60, 0x00, 0x29, 0x04, 0xd1,
-0x39, 0x8a, 0x02, 0x23, 0x19, 0x43, 0x03, 0xe0, 0x0c, 0xe0, 0x39, 0x8a,
-0x08, 0x23, 0x19, 0x43, 0x39, 0x82, 0x29, 0x6b, 0x08, 0x18, 0x01, 0x23,
-0x9b, 0x07, 0x01, 0x38, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0x20, 0x76,
-0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x11, 0x30, 0x18, 0x43, 0x00, 0x68,
-0x01, 0x06, 0x09, 0x0e, 0x00, 0xe0, 0x19, 0xe0, 0x35, 0x48, 0x2a, 0x6b,
-0xc0, 0x46, 0xea, 0x62, 0x04, 0x29, 0x4f, 0xd1, 0x01, 0x21, 0xc6, 0x1d,
-0xff, 0x36, 0x5a, 0x36, 0x31, 0x72, 0x0a, 0x99, 0x02, 0x29, 0x1e, 0xd1,
-0x09, 0x99, 0x09, 0x0e, 0x49, 0x06, 0x1a, 0xd1, 0xe1, 0x1d, 0x05, 0x31,
-0x19, 0x43, 0x09, 0x68, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x39, 0x1a, 0xe0,
-0x01, 0x23, 0x9b, 0x07, 0xe0, 0x1d, 0x01, 0x30, 0x18, 0x43, 0x00, 0x68,
-0xe1, 0x1d, 0x0d, 0x31, 0x19, 0x43, 0x09, 0x68, 0x40, 0x18, 0x00, 0x04,
-0x00, 0x0c, 0xf9, 0x68, 0x4a, 0x1c, 0xfa, 0x60, 0x00, 0x29, 0xbc, 0xd1,
-0xb6, 0xe7, 0x01, 0x23, 0x9b, 0x07, 0xe1, 0x1d,
-0x05, 0x31, 0x19, 0x43, 0x09, 0x68, 0x09, 0x06, 0x09, 0x0e, 0xa1, 0x60,
-0xe8, 0x6a, 0xc0, 0x46, 0x20, 0x60, 0x20, 0x1c, 0xff, 0xf7, 0x88, 0xfc,
-0x20, 0x7e, 0x33, 0x28, 0x01, 0xd0, 0x32, 0x28, 0x11, 0xd1, 0x01, 0x21,
-0x14, 0x4c, 0xc0, 0x46, 0xf9, 0x60, 0xb9, 0x60, 0x20, 0x1c, 0x00, 0xf0,
-0x85, 0xf8, 0x28, 0x6b, 0xa9, 0x6a, 0xc0, 0x46, 0x88, 0x62, 0x20, 0x1c,
-0xff, 0xf7, 0xc0, 0xfd, 0x00, 0x28, 0x11, 0xd1, 0x0e, 0xe0, 0x00, 0x20,
-0x30, 0x72, 0x11, 0xe0, 0x33, 0x29, 0x01, 0xd0, 0x32, 0x29, 0x0d, 0xd1,
-0x07, 0x1c, 0x00, 0xf0, 0x71, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0xb0, 0xfd,
-0x00, 0x28, 0x01, 0xd1, 0x01, 0xf0, 0x70, 0xfe, 0x0d, 0xb0, 0xf0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0xf0, 0x12, 0xf8, 0xf6, 0xe7, 0x00, 0x00,
-0x6c, 0x06, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0x4c, 0x2a, 0x00, 0x80,
-0xac, 0xab, 0x20, 0x40, 0x40, 0x07, 0x00, 0x80, 0x82, 0x07, 0x00, 0x80,
-0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x07, 0x00, 0x80, 0xf0, 0xb5, 0x25, 0x48,
-0x41, 0x68, 0x01, 0x31, 0x41, 0x60, 0x24, 0x4f, 0xf9, 0x1d, 0xf9, 0x31,
-0x00, 0x24, 0x88, 0x6a, 0xfa, 0x68, 0xc0, 0x46, 0x94, 0x61, 0x04, 0x22,
-0xfb, 0x68, 0xc0, 0x46, 0xda, 0x60, 0x10, 0x22, 0xfb, 0x68, 0xc0, 0x46,
-0x9a, 0x61, 0xfa, 0x1d, 0xff, 0x32, 0x5a, 0x32, 0x13, 0x7a, 0x1b, 0x4a,
-0x00, 0x2b, 0x0b, 0xd0, 0x15, 0x8a, 0x2e, 0x0a, 0x36, 0x02, 0x33, 0x23,
-0x2b, 0x40, 0x9b, 0x00, 0x1e, 0x43, 0xcc, 0x23, 0x2b, 0x40, 0x9b, 0x08,
-0x33, 0x43, 0x13, 0x82, 0x12, 0x8a, 0xfb, 0x68, 0xc0, 0x46, 0xda, 0x83,
-0x4a, 0x6b, 0xfb, 0x68, 0xc0, 0x46, 0xda, 0x81, 0x0a, 0x6b, 0xc0, 0x46,
-0x82, 0x62, 0xc4, 0x62, 0xc3, 0x1d, 0x39, 0x33, 0x4a, 0x6b, 0xc0, 0x46,
-0x5a, 0x83, 0x04, 0x23, 0x02, 0x68, 0x1a, 0x43, 0x02, 0x60, 0x88, 0x6a,
-0x01, 0xf0, 0x32, 0xfa, 0xf8, 0x68, 0x01, 0x23, 0x9b, 0x07, 0x54, 0x30,
-0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xf8, 0x60, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80,
-0xac, 0x07, 0x00, 0x80, 0x80, 0xb5, 0xc1, 0x1d, 0xf9, 0x31, 0x8a, 0x6a,
-0x01, 0x23, 0x9b, 0x07, 0xd1, 0x1d, 0x45, 0x31, 0x19, 0x43, 0x09, 0x68,
-0x0b, 0x06, 0x1b, 0x0e, 0x01, 0x27, 0xc1, 0x1d, 0xff, 0x31, 0x4a, 0x31,
-0x33, 0x2b, 0x05, 0xd1, 0x8b, 0x70, 0x01, 0x1c, 0x10, 0x1c, 0x00, 0xf0,
-0x0f, 0xf8, 0x06, 0xe0, 0x32, 0x2b, 0x08, 0xd1, 0x8b, 0x70, 0x01, 0x1c,
-0x10, 0x1c, 0x00, 0xf0, 0x3c, 0xf8, 0x38, 0x1c, 0x80, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x20, 0x88, 0x70, 0xf9, 0xe7, 0x90, 0xb4, 0xca, 0x1d,
-0xf9, 0x32, 0x33, 0x27, 0xcc, 0x1d, 0xff, 0x34, 0x4a, 0x34, 0xd3, 0x6a,
-0xc0, 0x46, 0xa7, 0x70, 0xff, 0x31, 0x41, 0x31, 0x07, 0x6c, 0xc0, 0x46,
-0x4f, 0x61, 0xfb, 0x18, 0x39, 0x1c, 0x9f, 0x1e, 0x01, 0x23, 0x9b, 0x07,
-0xfc, 0x1c, 0x23, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 0x9b, 0x00,
-0x1b, 0x04, 0x1b, 0x0c, 0xc9, 0x18, 0x08, 0x31, 0x01, 0x64, 0x01, 0x23,
-0x9b, 0x07, 0xb9, 0x1c, 0x19, 0x43, 0x09, 0x68, 0x34, 0x30, 0x01, 0x76,
-0xf8, 0x1d, 0x01, 0x30, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0xb9, 0x1d,
-0x19, 0x43, 0xd0, 0x63, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x08, 0x43,
-0xd0, 0x63, 0x90, 0xbc, 0x70, 0x47, 0xb0, 0xb5, 0xca, 0x1d, 0xf9, 0x32,
-0xc5, 0x1d, 0x2d, 0x35, 0x32, 0x20, 0xcf, 0x1d,
-0xff, 0x37, 0x4a, 0x37, 0xd3, 0x6a, 0xc0, 0x46, 0xb8, 0x70, 0xcc, 0x1d,
-0xff, 0x34, 0x3a, 0x34, 0xe8, 0x68, 0xc0, 0x46, 0x60, 0x61, 0x10, 0x30,
-0xe8, 0x60, 0x60, 0x69, 0xc0, 0x18, 0x87, 0x1e, 0x01, 0x23, 0x9b, 0x07,
-0x38, 0x1d, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0xb9, 0x1c, 0x19, 0x43,
-0xd0, 0x63, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x08, 0x43, 0xd0, 0x63,
-0xf8, 0x1d, 0x03, 0x30, 0xff, 0xf7, 0xfc, 0xfb, 0x20, 0x62, 0xf8, 0x1d,
-0x07, 0x30, 0xff, 0xf7, 0xf7, 0xfb, 0x60, 0x62, 0x00, 0x20, 0x28, 0x76,
-0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf7, 0xb5, 0x81, 0xb0, 0x01, 0x98,
-0xc7, 0x1d, 0xf9, 0x37, 0xb8, 0x6a, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d,
-0x05, 0x34, 0x23, 0x43, 0x1c, 0x68, 0xff, 0x23, 0xfe, 0x33, 0x23, 0x40,
-0x7f, 0x6b, 0x3f, 0x04, 0x3b, 0x43, 0x0b, 0x60, 0x34, 0x30, 0x1c, 0x1c,
-0x80, 0x23, 0x23, 0x40, 0x01, 0x9f, 0xff, 0x37, 0x41, 0x37, 0x00, 0x2b,
-0x3c, 0xd0, 0x0c, 0x23, 0x00, 0x93, 0x00, 0x23, 0x9d, 0x00, 0xae, 0x18,
-0x36, 0x69, 0x6d, 0x18, 0x6e, 0x61, 0x01, 0x33, 0x05, 0x2b, 0xf7, 0xd3,
-0x00, 0x23, 0x9d, 0x00, 0xae, 0x18, 0x76, 0x6a, 0x6d, 0x18, 0xae, 0x62,
-0x01, 0x33, 0x05, 0x2b, 0xf7, 0xd3, 0x01, 0x9b, 0xff, 0x33, 0x51, 0x33,
-0x9b, 0x78, 0x33, 0x2b, 0x0e, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xc5, 0x1d,
-0x01, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x4b, 0x81, 0x01, 0x23,
-0x9b, 0x07, 0xc5, 0x1d, 0x0d, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0x16, 0xe0,
-0x7b, 0x69, 0xc0, 0x46, 0x4b, 0x81, 0x01, 0x23, 0x9b, 0x07, 0xc5, 0x1d,
-0x0d, 0x35, 0x2b, 0x43, 0x1b, 0x68, 0x7d, 0x69, 0x5d, 0x1b, 0x01, 0x23,
-0x9b, 0x07, 0xc6, 0x1d, 0x01, 0x36, 0x33, 0x43, 0x1b, 0x68, 0xeb, 0x18,
-0x0c, 0x3b, 0x02, 0xe0, 0x00, 0x23, 0x00, 0x93, 0x4b, 0x81, 0xcb, 0x80,
-0x63, 0x09, 0x49, 0xd3, 0x01, 0x23, 0x9b, 0x07, 0xc4, 0x1d, 0x05, 0x34,
-0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x81, 0x01, 0x23, 0x9b, 0x07,
-0xc4, 0x1d, 0x0d, 0x34, 0x23, 0x43, 0x1b, 0x68, 0x0c, 0x89, 0x1b, 0x1b,
-0x00, 0x9c, 0x1c, 0x1b, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x30, 0x18, 0x43,
-0x00, 0x68, 0x20, 0x18, 0x88, 0x80, 0x38, 0x6a, 0x04, 0x0e, 0xff, 0x23,
-0x1b, 0x04, 0x03, 0x40, 0x1b, 0x0a, 0x1c, 0x43, 0xff, 0x23, 0x1b, 0x02,
-0x03, 0x40, 0x1b, 0x02, 0x23, 0x43, 0x00, 0x06, 0x18, 0x43, 0xc8, 0x60,
-0x78, 0x6a, 0x07, 0x0e, 0xff, 0x23, 0x1b, 0x04, 0x03, 0x40, 0x1b, 0x0a,
-0x1f, 0x43, 0xff, 0x23, 0x1b, 0x02, 0x03, 0x40, 0x1b, 0x02, 0x3b, 0x43,
-0x00, 0x06, 0x18, 0x43, 0x08, 0x61, 0xd0, 0x6b, 0xc0, 0x46, 0xc8, 0x63,
-0x90, 0x6b, 0xc0, 0x46, 0x08, 0x64, 0x50, 0x6c, 0xc0, 0x46, 0x48, 0x64,
-0x10, 0x6c, 0xc0, 0x46, 0x88, 0x64, 0xd0, 0x6c, 0xc0, 0x46, 0xc8, 0x64,
-0x90, 0x6c, 0xc0, 0x46, 0x08, 0x65, 0x02, 0xe0, 0x00, 0x23, 0x0b, 0x81,
-0x8b, 0x80, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
-0x0f, 0x4a, 0x93, 0x89, 0x01, 0x33, 0x93, 0x81, 0xc2, 0x1d, 0xf9, 0x32,
-0x04, 0x23, 0x90, 0x6a, 0xc0, 0x46, 0xc3, 0x60, 0x10, 0x23, 0x83, 0x61,
-0xcb, 0x0a, 0x01, 0xd3, 0x18, 0x23, 0x83, 0x61, 0xc1, 0x83, 0x51, 0x6b,
-0xc0, 0x46, 0xc1, 0x81, 0x51, 0x6b, 0xc2, 0x1d, 0x39, 0x32, 0x51, 0x83,
-0x04, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x01, 0xf0, 0xc2, 0xf8,
-0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80,
-0xb0, 0xb5, 0x1b, 0x4c, 0x20, 0x6a, 0x02, 0x28, 0x1b, 0xd2, 0x00, 0x20,
-0xe7, 0x1d, 0x19, 0x37, 0x38, 0x71, 0xe1, 0x68, 0xe0, 0x1d, 0xf9, 0x30,
-0x00, 0x29, 0x15, 0xd0, 0x42, 0x6a, 0x00, 0x2a, 0x12, 0xd1, 0x01, 0x25,
-0x0a, 0xe0, 0xff, 0xf7, 0x89, 0xfb, 0x00, 0x28, 0x09, 0xd1, 0x20, 0x6a,
-0x02, 0x28, 0x00, 0xd3, 0x3d, 0x71, 0xe0, 0x68, 0x00, 0x28, 0x02, 0xd0,
-0x38, 0x79, 0x00, 0x28, 0xf1, 0xd0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x40, 0x6a, 0x00, 0x28, 0xf9, 0xd1, 0x00, 0x29, 0xf7, 0xd1, 0x60, 0x69,
-0x00, 0x28, 0x04, 0xd0, 0x06, 0x48, 0x00, 0x68, 0x03, 0xf0, 0xa8, 0xfc,
-0xef, 0xe7, 0x60, 0x68, 0x00, 0x28, 0xec, 0xd0, 0x00, 0xf0, 0x5a, 0xf8,
-0xe9, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0x34, 0x04, 0x00, 0x80,
-0xb0, 0xb5, 0x07, 0x1c, 0x20, 0x23, 0xb8, 0x68, 0x18, 0x40, 0x01, 0x24,
-0x00, 0x25, 0x00, 0x28, 0x0b, 0xd1, 0x38, 0x6a, 0x00, 0x28, 0x03, 0xd1,
-0x28, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x1f, 0x48, 0x01, 0x6e,
-0x01, 0x31, 0x01, 0x66, 0x03, 0xe0, 0x48, 0x68, 0xc4, 0x23, 0x18, 0x40,
-0x03, 0xd1, 0x38, 0x6a, 0x00, 0xf0, 0x0c, 0xfc, 0x2f, 0xe0, 0x38, 0x1c,
-0x00, 0xf0, 0x1c, 0xfc, 0x38, 0x1c, 0x00, 0xf0, 0x7b, 0xfa, 0xb8, 0x68,
-0xc0, 0x08, 0x02, 0xd3, 0x38, 0x6a, 0x00, 0xf0, 0xd1, 0xfb, 0xb8, 0x68,
-0x39, 0x6a, 0xc0, 0x46, 0x88, 0x60, 0x38, 0x6a, 0xc0, 0x46, 0xc5, 0x60,
-0x10, 0x48, 0x41, 0x68, 0x00, 0x29, 0x11, 0xd1, 0xc1, 0x68, 0x00, 0x29,
-0x09, 0xd1, 0x41, 0x69, 0x00, 0x29, 0x06, 0xd1, 0x39, 0x6a, 0xc0, 0x46,
-0x81, 0x60, 0x41, 0x60, 0x00, 0xf0, 0x14, 0xf8, 0x0b, 0xe0, 0x39, 0x6a,
-0xc0, 0x46, 0x81, 0x60, 0x41, 0x60, 0x06, 0xe0, 0x39, 0x6a, 0x82, 0x68,
-0xc0, 0x46, 0xd1, 0x60, 0x39, 0x6a, 0xc0, 0x46, 0x81, 0x60, 0x20, 0x1c,
-0xbd, 0xe7, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80,
-0x90, 0xb5, 0x0b, 0x4c, 0x67, 0x68, 0x00, 0x2f, 0x0f, 0xd0, 0x38, 0x1c,
-0x00, 0xf0, 0x12, 0xf8, 0x00, 0x28, 0x0a, 0xd1, 0x60, 0x68, 0xc0, 0x68,
-0xc0, 0x46, 0x60, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xc3, 0xfb, 0x00, 0x20,
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 0xfa, 0xe7, 0x00, 0x00,
-0x6c, 0x06, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c, 0xfe, 0x1d, 0x49, 0x36,
-0x30, 0x78, 0x40, 0x00, 0xc0, 0x19, 0x85, 0x8b, 0x33, 0x4c, 0x34, 0x4b,
-0x9d, 0x42, 0x3c, 0xd0, 0x38, 0x1c, 0x21, 0x1c, 0x2a, 0x1c, 0x00, 0xf0,
-0x1d, 0xf9, 0x31, 0x48, 0x80, 0x6a, 0x58, 0x21, 0x69, 0x43, 0x40, 0x18,
-0x01, 0x23, 0x9b, 0x07, 0x18, 0x43, 0x00, 0x68, 0x00, 0x04, 0x00, 0x0c,
-0x2c, 0x4d, 0x01, 0x28, 0x1a, 0xd1, 0x30, 0x78, 0xc0, 0x19, 0xc1, 0x1d,
-0x19, 0x31, 0x08, 0x7a, 0x3a, 0x68, 0x80, 0x18, 0x09, 0x7b, 0xea, 0x1d,
-0x21, 0x32, 0x00, 0xf0, 0xe3, 0xfc, 0x30, 0x78, 0xc0, 0x19, 0x20, 0x30,
-0x00, 0x79, 0x39, 0x68, 0x40, 0x18, 0xc1, 0x1d, 0x05, 0x31, 0x00, 0x20,
-0x00, 0x23, 0x42, 0x00, 0x8b, 0x52, 0x01, 0x30, 0x06, 0x28, 0xfa, 0xd3,
-0xa0, 0x88, 0x41, 0x07, 0x0b, 0xd1, 0x21, 0x89, 0x09, 0x18, 0x78, 0x68,
-0x00, 0x04, 0x00, 0x0c, 0x81, 0x42, 0x04, 0xd8, 0x61, 0x89, 0xe2, 0x88,
-0x89, 0x18, 0x81, 0x42, 0x03, 0xd9, 0x00, 0x20, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x21, 0x1c, 0x14, 0x4a, 0x00, 0x20, 0xfe, 0xf7, 0x5a, 0xff,
-0x01, 0x22, 0x52, 0x04, 0x78, 0x68, 0x02, 0x43,
-0x01, 0x20, 0x39, 0x68, 0xfe, 0xf7, 0x52, 0xff, 0x01, 0x22, 0x52, 0x04,
-0x78, 0x68, 0x02, 0x43, 0x00, 0x20, 0x39, 0x68, 0xfe, 0xf7, 0x4a, 0xff,
-0x0b, 0x49, 0x0c, 0x4a, 0x01, 0x20, 0xfe, 0xf7, 0x45, 0xff, 0x01, 0x20,
-0xe9, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x02, 0x21, 0xea, 0x1d, 0xf9, 0x32,
-0x51, 0x62, 0xd9, 0xe7, 0x28, 0xac, 0x20, 0x40, 0xff, 0xff, 0x00, 0x00,
-0x4c, 0x2a, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 0x54, 0x00, 0x03, 0x00,
-0x14, 0xac, 0x20, 0x40, 0x14, 0x00, 0x07, 0x00, 0xf0, 0xb5, 0x83, 0xb0,
-0x00, 0x21, 0x4f, 0x48, 0xc2, 0x1d, 0xf9, 0x32, 0x51, 0x62, 0x01, 0x21,
-0xc9, 0x04, 0x4d, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0xc1, 0x1d, 0x19, 0x31,
-0x49, 0x79, 0x00, 0x29, 0x04, 0xd1, 0x4a, 0x48, 0x00, 0x68, 0x03, 0xf0,
-0x9b, 0xfb, 0x87, 0xe0, 0x45, 0x48, 0x47, 0x68, 0xfc, 0x1d, 0x49, 0x34,
-0x21, 0x78, 0x48, 0x00, 0xc0, 0x19, 0x80, 0x8b, 0x44, 0x4a, 0x92, 0x6a,
-0x58, 0x23, 0x58, 0x43, 0x15, 0x18, 0x01, 0x23, 0x9b, 0x07, 0xea, 0x1d,
-0x05, 0x32, 0x1a, 0x43, 0x12, 0x68, 0x08, 0x35, 0x2b, 0x43, 0x1d, 0x68,
-0xff, 0x23, 0x1b, 0x02, 0x2b, 0x40, 0x1b, 0x0a, 0x3c, 0x4d, 0x01, 0x2b,
-0x24, 0xd1, 0xc8, 0x19, 0xc1, 0x1d, 0x19, 0x31, 0x08, 0x7a, 0x3a, 0x68,
-0x80, 0x18, 0x39, 0x4a, 0x09, 0x7b, 0x00, 0xf0, 0xc5, 0xfc, 0x20, 0x78,
-0xc0, 0x19, 0x20, 0x30, 0x00, 0x79, 0x39, 0x68, 0x41, 0x18, 0x00, 0x20,
-0x82, 0x00, 0x53, 0x19, 0x9b, 0x6e, 0x6e, 0x46, 0xb3, 0x50, 0x01, 0x30,
-0x03, 0x28, 0xf7, 0xd3, 0xca, 0x1d, 0x05, 0x32, 0x69, 0x46, 0x00, 0x20,
-0x43, 0x00, 0xcd, 0x5a, 0xc0, 0x46, 0xd5, 0x52, 0x01, 0x30, 0x06, 0x28,
-0xf8, 0xd3, 0x2d, 0xe0, 0x02, 0x2b, 0x2b, 0xd1, 0x11, 0x0a, 0x29, 0xd3,
-0x00, 0x21, 0x8a, 0x00, 0x53, 0x19, 0x9b, 0x6e, 0x6e, 0x46, 0xb3, 0x50,
-0x01, 0x31, 0x03, 0x29, 0xf7, 0xd3, 0x21, 0x78, 0x49, 0x00, 0xc9, 0x19,
-0x09, 0x8f, 0x3a, 0x68, 0x8b, 0x18, 0x6a, 0x46, 0x00, 0x21, 0x4d, 0x00,
-0x56, 0x5b, 0xc0, 0x46, 0x5e, 0x53, 0x01, 0x31, 0x06, 0x29, 0xf8, 0xd3,
-0x19, 0x49, 0x8a, 0x6a, 0x13, 0x18, 0x1a, 0x6d, 0x00, 0x9d, 0x55, 0x40,
-0x19, 0x4a, 0xd6, 0x68, 0x75, 0x40, 0x1d, 0x65, 0x89, 0x6a, 0x08, 0x18,
-0x41, 0x6d, 0x02, 0x9b, 0x59, 0x40, 0x92, 0x69, 0x51, 0x40, 0x41, 0x65,
-0x20, 0x78, 0x41, 0x1e, 0x21, 0x70, 0x00, 0x28, 0x0d, 0xd0, 0x38, 0x1c,
-0xff, 0xf7, 0xf4, 0xfe, 0x00, 0x28, 0x0d, 0xd1, 0x08, 0x4a, 0x50, 0x68,
-0xc0, 0x68, 0xc0, 0x46, 0x50, 0x60, 0x38, 0x1c, 0x00, 0xf0, 0xa4, 0xfa,
-0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0, 0x73, 0xfa, 0x01, 0xf0, 0xde, 0xfa,
-0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x6c, 0x06, 0x00, 0x80,
-0x00, 0x00, 0x00, 0xb0, 0x38, 0x04, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80,
-0xac, 0xab, 0x20, 0x40, 0x94, 0x06, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40,
-0xf0, 0xb5, 0x82, 0xb0, 0x69, 0x4b, 0x9f, 0x6a, 0x58, 0x23, 0x5a, 0x43,
-0xba, 0x18, 0xc3, 0x1d, 0x49, 0x33, 0x1f, 0x78, 0x01, 0x23, 0x9b, 0x07,
-0xd4, 0x1d, 0x01, 0x34, 0x23, 0x43, 0x1d, 0x68, 0x43, 0x68, 0x1c, 0x04,
-0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x05, 0x36, 0x33, 0x43, 0x1b, 0x68,
-0x1c, 0x43, 0x42, 0x23, 0x1c, 0x43, 0x0c, 0x60, 0xff, 0x26, 0x36, 0x02,
-0x2e, 0x40, 0x01, 0x23, 0x5b, 0x02, 0x9e, 0x42, 0x74, 0xd1, 0x6b, 0x0c,
-0x2b, 0xd3, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x79,
-0xc0, 0x46, 0x4b, 0x81, 0x7b, 0x00, 0x1b, 0x18, 0x1b, 0x8f, 0x4c, 0x89,
-0x1b, 0x1b, 0xcb, 0x80, 0x00, 0x24, 0xa6, 0x00, 0x01, 0x96, 0xb3, 0x18,
-0xde, 0x1d, 0x09, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68,
-0x01, 0x9e, 0x76, 0x18, 0x73, 0x61, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3,
-0x00, 0x24, 0xa6, 0x00, 0x00, 0x96, 0xb3, 0x18, 0xde, 0x1d, 0x1d, 0x36,
-0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x00, 0x9e, 0x76, 0x18,
-0xb3, 0x62, 0x01, 0x34, 0x05, 0x2c, 0xf0, 0xd3, 0x06, 0xe0, 0x00, 0x23,
-0x4b, 0x81, 0xcb, 0x80, 0x40, 0x23, 0x9c, 0x43, 0x0c, 0x60, 0x23, 0x1c,
-0x6b, 0x0e, 0x4a, 0xd3, 0xc3, 0x19, 0x20, 0x33, 0x1b, 0x79, 0x10, 0x33,
-0x0b, 0x81, 0x7b, 0x00, 0x1b, 0x18, 0x1b, 0x8f, 0x0f, 0x89, 0xdb, 0x1b,
-0x8b, 0x80, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x35, 0x34, 0x23, 0x43,
-0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x63, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d,
-0x31, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x64, 0xab, 0x0e,
-0x21, 0xd2, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x3d, 0x34, 0x23, 0x43,
-0x1b, 0x68, 0xc0, 0x46, 0x4b, 0x64, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d,
-0x39, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0x8b, 0x64, 0x01, 0x23,
-0x9b, 0x07, 0xd4, 0x1d, 0x45, 0x34, 0x23, 0x43, 0x1b, 0x68, 0xc0, 0x46,
-0xcb, 0x64, 0x01, 0x23, 0x9b, 0x07, 0xd4, 0x1d, 0x41, 0x34, 0x23, 0x43,
-0x1b, 0x68, 0xc0, 0x46, 0x0b, 0x65, 0x00, 0xe0, 0x0f, 0xe0, 0xfb, 0x1f,
-0x01, 0x3b, 0x1b, 0x04, 0x1b, 0x0c, 0x07, 0x68, 0xff, 0x18, 0x03, 0x69,
-0x08, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x34, 0xf8, 0x2c, 0xe0, 0x00, 0x23,
-0x0b, 0x81, 0x8b, 0x80, 0x28, 0xe0, 0x00, 0x23, 0x8b, 0x80, 0x0b, 0x81,
-0xc3, 0x19, 0x20, 0x33, 0x1b, 0x7a, 0xc0, 0x46, 0x4b, 0x81, 0x7b, 0x00,
-0x18, 0x18, 0x00, 0x8e, 0xc0, 0x46, 0xc8, 0x80, 0x00, 0x20, 0x87, 0x00,
-0xbb, 0x18, 0xdc, 0x1d, 0x09, 0x34, 0x01, 0x23, 0x9b, 0x07, 0x23, 0x43,
-0x1b, 0x68, 0x7f, 0x18, 0x7b, 0x61, 0x01, 0x30, 0x05, 0x28, 0xf2, 0xd3,
-0x00, 0x20, 0x87, 0x00, 0xbb, 0x18, 0xdc, 0x1d, 0x1d, 0x34, 0x01, 0x23,
-0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x7f, 0x18, 0xbb, 0x62, 0x01, 0x30,
-0x05, 0x28, 0xf2, 0xd3, 0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x4c, 0x2a, 0x00, 0x80, 0x80, 0xb4, 0x1f, 0x1c, 0x3b, 0x0c, 0x18, 0xd2,
-0x17, 0x6d, 0x11, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 0x52, 0x6d, 0xc0, 0x46,
-0x1a, 0x61, 0xc7, 0x60, 0x1a, 0x69, 0xc0, 0x46, 0x02, 0x61, 0xd8, 0x68,
-0xc0, 0x46, 0x08, 0x80, 0xd8, 0x68, 0x00, 0x0c, 0x48, 0x80, 0x18, 0x69,
-0xc0, 0x46, 0x88, 0x80, 0x18, 0x69, 0x00, 0x0c, 0xc8, 0x80, 0x80, 0xbc,
-0x70, 0x47, 0x4a, 0x88, 0x12, 0x04, 0x0b, 0x88, 0x1a, 0x43, 0xc2, 0x60,
-0x8a, 0x88, 0xc9, 0x88, 0x09, 0x04, 0x11, 0x43, 0x01, 0x61, 0xf2, 0xe7,
-0x2c, 0x07, 0x00, 0x80, 0xf1, 0xb5, 0x88, 0xb0, 0x00, 0x22, 0x08, 0x98,
-0x00, 0x6a, 0x08, 0x9b, 0x99, 0x68, 0x49, 0x0a, 0x02, 0xd3, 0x01, 0x27,
-0xff, 0x03, 0x00, 0xe0, 0x00, 0x27, 0x03, 0x8b, 0x00, 0x2b, 0x19, 0xd0,
-0xa3, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43, 0xc9, 0x18,
-0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 0x19, 0x43, 0x09, 0x68, 0x09, 0x04,
-0x09, 0x0c, 0x02, 0x29, 0x02, 0xd1, 0x08, 0x23, 0x1f, 0x43, 0x07, 0xe0,
-0x41, 0x8b, 0x00, 0x29, 0x02, 0xd0, 0x0c, 0x23,
-0x1f, 0x43, 0x01, 0xe0, 0x04, 0x23, 0x1f, 0x43, 0x83, 0x8a, 0x00, 0x2b,
-0x18, 0xd0, 0x95, 0x49, 0x89, 0x6a, 0x1c, 0x1c, 0x58, 0x23, 0x63, 0x43,
-0xc9, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x58, 0x39, 0x19, 0x43, 0x09, 0x68,
-0x09, 0x04, 0x09, 0x0c, 0x02, 0x29, 0x01, 0xd1, 0x0f, 0x43, 0x07, 0xe0,
-0xc1, 0x8a, 0x00, 0x29, 0x02, 0xd0, 0x03, 0x23, 0x1f, 0x43, 0x01, 0xe0,
-0x01, 0x23, 0x1f, 0x43, 0xc1, 0x1d, 0x39, 0x31, 0x07, 0x91, 0x4b, 0x89,
-0x0c, 0x89, 0x1c, 0x19, 0x24, 0x04, 0x24, 0x0c, 0x08, 0x9d, 0x2d, 0x68,
-0xc0, 0x46, 0x01, 0x95, 0xc9, 0x88, 0x7d, 0x08, 0x1a, 0xd3, 0x1a, 0x1c,
-0xc3, 0x1d, 0x19, 0x33, 0x1a, 0x72, 0x07, 0x9a, 0x92, 0x89, 0xc0, 0x46,
-0x1a, 0x73, 0x07, 0x9a, 0x12, 0x89, 0xc0, 0x46, 0x02, 0x86, 0x04, 0x87,
-0x82, 0x8a, 0x01, 0x3a, 0x82, 0x83, 0x01, 0x22, 0x19, 0x71, 0x08, 0x9b,
-0x1b, 0x68, 0x5b, 0x18, 0x5b, 0x78, 0x9b, 0x00, 0x1b, 0x04, 0x1b, 0x0c,
-0x08, 0x33, 0x59, 0x18, 0xbb, 0x08, 0x47, 0xd3, 0x07, 0x9b, 0x5b, 0x89,
-0x85, 0x18, 0x06, 0x95, 0x20, 0x35, 0x2b, 0x72, 0x07, 0x9b, 0x9b, 0x89,
-0xc0, 0x46, 0x2b, 0x73, 0x07, 0x9b, 0x1b, 0x89, 0x2e, 0x1c, 0x55, 0x00,
-0x2d, 0x18, 0x05, 0x95, 0x2b, 0x86, 0x00, 0x2a, 0x01, 0xd0, 0xc3, 0x8a,
-0x00, 0xe0, 0x83, 0x8a, 0x01, 0x3b, 0x05, 0x9d, 0xc0, 0x46, 0xab, 0x83,
-0x31, 0x71, 0x65, 0x4b, 0x9d, 0x6a, 0x05, 0x9b, 0x9e, 0x8b, 0x58, 0x23,
-0x73, 0x43, 0xeb, 0x18, 0xdd, 0x1d, 0x01, 0x35, 0x01, 0x23, 0x9b, 0x07,
-0x2b, 0x43, 0x1d, 0x68, 0x2b, 0x0e, 0x5b, 0x06, 0x01, 0xd1, 0x08, 0x31,
-0x00, 0xe0, 0x10, 0x31, 0x81, 0x23, 0x5b, 0x02, 0x1d, 0x40, 0x9d, 0x42,
-0x03, 0xd1, 0xe3, 0x1f, 0x05, 0x3b, 0x1c, 0x04, 0x24, 0x0c, 0x05, 0x9b,
-0xc0, 0x46, 0x1c, 0x87, 0x08, 0x9b, 0x1b, 0x68, 0x1b, 0x19, 0x10, 0x3b,
-0x9b, 0x7b, 0x06, 0x9d, 0x40, 0x35, 0x2b, 0x70, 0x2b, 0x78, 0x02, 0x33,
-0xe3, 0x1a, 0x1c, 0x04, 0x24, 0x0c, 0x01, 0x32, 0xbb, 0x08, 0x9b, 0x07,
-0x6d, 0xd0, 0x83, 0x18, 0x20, 0x33, 0x04, 0x93, 0x19, 0x72, 0x01, 0x9b,
-0x5d, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1b, 0x68, 0x1b, 0x07,
-0x1b, 0x0f, 0x9b, 0x00, 0x04, 0x9e, 0xc0, 0x46, 0x33, 0x73, 0x00, 0x95,
-0x2b, 0x78, 0x1b, 0x07, 0x1b, 0x0f, 0x9b, 0x00, 0x04, 0x9d, 0xc0, 0x46,
-0x2b, 0x73, 0x00, 0x9d, 0xeb, 0x78, 0xad, 0x78, 0x1b, 0x02, 0x1d, 0x43,
-0x2b, 0x02, 0x2d, 0x0a, 0x2d, 0x06, 0x2d, 0x0e, 0x2b, 0x43, 0x55, 0x00,
-0x2d, 0x18, 0x2b, 0x86, 0x04, 0x9b, 0xc0, 0x46, 0x59, 0x72, 0x04, 0x9b,
-0x1b, 0x7b, 0x2e, 0x1c, 0x04, 0x9d, 0xc0, 0x46, 0x6b, 0x73, 0x33, 0x8e,
-0xc0, 0x46, 0x73, 0x86, 0x00, 0x9d, 0x2b, 0x78, 0x1b, 0x07, 0x1b, 0x0f,
-0x9b, 0x00, 0x1b, 0x04, 0x1b, 0x0c, 0x59, 0x18, 0x04, 0x25, 0x3d, 0x40,
-0x0e, 0xd0, 0x34, 0x87, 0x03, 0x8b, 0x01, 0x3b, 0xb3, 0x83, 0x13, 0x1c,
-0x1b, 0x18, 0x20, 0x33, 0x19, 0x71, 0x01, 0x9b, 0x5b, 0x18, 0x5b, 0x78,
-0x9b, 0x00, 0x59, 0x18, 0x08, 0x31, 0x01, 0x32, 0x3b, 0x09, 0x37, 0xd3,
-0x00, 0x2d, 0x01, 0xd0, 0x43, 0x8b, 0x00, 0xe0, 0x03, 0x8b, 0x55, 0x00,
-0x2d, 0x18, 0x01, 0x3b, 0xab, 0x83, 0x83, 0x18, 0x03, 0x93, 0x20, 0x33,
-0x19, 0x71, 0x20, 0x4b, 0x9d, 0x6a, 0x53, 0x00, 0x1b, 0x18, 0x02, 0x93,
-0x9e, 0x8b, 0x58, 0x23, 0x73, 0x43, 0xeb, 0x18, 0xdd, 0x1d, 0x01, 0x35,
-0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43, 0x1d, 0x68,
-0x2b, 0x0e, 0x5b, 0x06, 0x02, 0xd1, 0x08, 0x31, 0x01, 0xe0, 0x15, 0xe0,
-0x10, 0x31, 0x81, 0x23, 0x5b, 0x02, 0x1d, 0x40, 0x9d, 0x42, 0x03, 0xd1,
-0xe3, 0x1f, 0x05, 0x3b, 0x1c, 0x04, 0x24, 0x0c, 0x02, 0x9b, 0xc0, 0x46,
-0x1c, 0x87, 0x08, 0x9b, 0x1b, 0x68, 0x1b, 0x19, 0x10, 0x3b, 0x9b, 0x7b,
-0x03, 0x9c, 0x40, 0x34, 0x23, 0x70, 0x01, 0x32, 0x07, 0x9b, 0xc0, 0x46,
-0xd9, 0x80, 0x51, 0x1e, 0xc3, 0x1d, 0x49, 0x33, 0x19, 0x70, 0x07, 0x61,
-0x04, 0x2a, 0x06, 0xd2, 0x06, 0x49, 0x53, 0x00, 0x1b, 0x18, 0x99, 0x83,
-0x01, 0x32, 0x04, 0x2a, 0xf9, 0xd3, 0x09, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
-0x70, 0x47, 0x80, 0xb5, 0x8c, 0xb0, 0x07, 0x1c, 0x12, 0x48, 0x01, 0x68,
-0x01, 0x31, 0x01, 0x60, 0x38, 0x68, 0xc0, 0x46, 0x00, 0x90, 0x78, 0x68,
-0xc0, 0x46, 0x01, 0x90, 0xb8, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x0d, 0x48,
-0x41, 0x68, 0xc9, 0x68, 0xc0, 0x46, 0x41, 0x60, 0x38, 0x1c, 0x00, 0xf0,
-0x4f, 0xf8, 0xb8, 0x68, 0x40, 0x09, 0x06, 0xd3, 0x10, 0x23, 0x02, 0x98,
-0x18, 0x43, 0x02, 0x90, 0x68, 0x46, 0x02, 0xf0, 0xe1, 0xff, 0x68, 0x46,
-0x02, 0xf0, 0x9a, 0xfe, 0x0c, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x0c, 0x2b, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80, 0x00, 0xb5, 0x8c, 0xb0,
-0x01, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x68, 0x05, 0x4b, 0x19, 0x43,
-0x01, 0x91, 0x00, 0xf0, 0x2f, 0xf8, 0x68, 0x46, 0x02, 0xf0, 0x84, 0xfe,
-0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xa0,
-0x02, 0x6a, 0x03, 0x68, 0xc0, 0x46, 0x13, 0x60, 0x40, 0x68, 0xc0, 0x46,
-0x50, 0x60, 0x40, 0x32, 0x48, 0x68, 0xc0, 0x46, 0x90, 0x80, 0xc8, 0x68,
-0xc0, 0x46, 0xd0, 0x80, 0x48, 0x69, 0xc0, 0x46, 0x10, 0x81, 0x88, 0x68,
-0xc0, 0x46, 0x50, 0x81, 0x08, 0x7e, 0xc0, 0x46, 0x90, 0x73, 0x08, 0x69,
-0xc0, 0x46, 0x90, 0x81, 0x70, 0x47, 0x04, 0x49, 0x08, 0x68, 0x00, 0x28,
-0x00, 0xd1, 0x70, 0x47, 0xc2, 0x68, 0xc0, 0x46, 0x0a, 0x60, 0xfa, 0xe7,
-0x6c, 0x06, 0x00, 0x80, 0x02, 0x49, 0x0a, 0x68, 0xc0, 0x46, 0xc2, 0x60,
-0x08, 0x60, 0x70, 0x47, 0x6c, 0x06, 0x00, 0x80, 0xb0, 0xb4, 0x00, 0x22,
-0x12, 0x4f, 0x7c, 0x7f, 0x01, 0x34, 0x7c, 0x77, 0x03, 0x23, 0xfc, 0x1d,
-0x19, 0x34, 0x38, 0x62, 0x79, 0x62, 0x23, 0x72, 0x0e, 0x4c, 0x25, 0x68,
-0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68, 0x1b, 0x0c, 0x10, 0xd1, 0x24, 0x68,
-0xa3, 0x0a, 0x0d, 0xd3, 0x01, 0x23, 0x0a, 0x4f, 0xc0, 0x46, 0xfb, 0x62,
-0x09, 0x4f, 0x0a, 0x4b, 0xc0, 0x46, 0xdf, 0x60, 0x99, 0x60, 0x58, 0x60,
-0x10, 0x1c, 0x18, 0x60, 0x01, 0x32, 0xfb, 0xe7, 0x10, 0x1c, 0x38, 0x64,
-0x01, 0x32, 0xfb, 0xe7, 0x00, 0x00, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40,
-0xc0, 0x00, 0x18, 0x00, 0x02, 0x81, 0x00, 0x00, 0x40, 0x01, 0x18, 0x00,
-0xf0, 0xb5, 0x47, 0x4f, 0x38, 0x68, 0x47, 0x4e, 0x47, 0x4d, 0x07, 0x23,
-0x5b, 0x02, 0xec, 0x18, 0x00, 0x28, 0x1d, 0xd1, 0x20, 0x6b, 0x01, 0x30,
-0x20, 0x63, 0x44, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x43, 0x48, 0x41, 0x69,
-0x00, 0x29, 0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, 0x09, 0x7b, 0x00, 0x29,
-0x0e, 0xd0, 0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, 0x19, 0x43, 0x09, 0x68,
-0xc0, 0x46, 0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, 0x04, 0xd0, 0xf1, 0x6c,
-0x01, 0x31, 0xf1, 0x64, 0x01, 0xf0, 0x50, 0xfe,
-0x38, 0x68, 0x01, 0x28, 0x17, 0xd1, 0x37, 0x48, 0x41, 0x69, 0x00, 0x29,
-0x13, 0xd0, 0xc1, 0x1d, 0x69, 0x31, 0x09, 0x7b, 0x00, 0x29, 0x0e, 0xd0,
-0x01, 0x23, 0x9b, 0x07, 0x01, 0x6d, 0x19, 0x43, 0x09, 0x68, 0xc0, 0x46,
-0x81, 0x61, 0xc2, 0x69, 0x91, 0x42, 0x04, 0xd0, 0xf1, 0x6c, 0x01, 0x31,
-0xf1, 0x64, 0x01, 0xf0, 0x35, 0xfe, 0x38, 0x68, 0x02, 0x28, 0x2f, 0xd1,
-0xbb, 0x23, 0x1b, 0x01, 0xee, 0x18, 0x70, 0x7b, 0x00, 0x28, 0x03, 0xd0,
-0x00, 0x20, 0x70, 0x73, 0x00, 0xf0, 0x4a, 0xfd, 0x30, 0x7b, 0x00, 0x28,
-0x02, 0xd0, 0x78, 0x68, 0x02, 0xf0, 0xaa, 0xff, 0x1b, 0x23, 0xdb, 0x01,
-0xe8, 0x18, 0xc0, 0x8b, 0x04, 0x26, 0x06, 0x40, 0xe0, 0x6a, 0xb0, 0x42,
-0x14, 0xd0, 0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, 0x19, 0x28, 0x11, 0xd3,
-0x1b, 0x48, 0x01, 0x7b, 0x00, 0x29, 0x0d, 0xd1, 0xff, 0x30, 0x41, 0x30,
-0x40, 0x78, 0x00, 0x28, 0x08, 0xd1, 0xb8, 0x68, 0x02, 0xf0, 0x90, 0xff,
-0x00, 0x20, 0xf8, 0x60, 0xe6, 0x62, 0x01, 0xe0, 0x00, 0x20, 0xf8, 0x60,
-0x38, 0x68, 0x03, 0x28, 0x0b, 0xd1, 0xec, 0x1d, 0x79, 0x34, 0xe0, 0x6b,
-0x80, 0x08, 0x02, 0xd3, 0x02, 0x20, 0x02, 0xf0, 0x07, 0xfc, 0x02, 0x23,
-0xe0, 0x6b, 0x98, 0x43, 0xe0, 0x63, 0x38, 0x68, 0x01, 0x30, 0x38, 0x60,
-0x03, 0x28, 0x01, 0xd9, 0x00, 0x20, 0x38, 0x60, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x3c, 0x04, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40,
-0x68, 0x0e, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, 0x64, 0x2d, 0x00, 0x80,
-0xe4, 0x2c, 0x00, 0x80, 0x28, 0x05, 0x00, 0x80, 0xb0, 0xb4, 0x1d, 0x48,
-0x84, 0x8a, 0x1d, 0x4a, 0x13, 0x8a, 0xc1, 0x1d, 0x09, 0x31, 0x01, 0x27,
-0x9c, 0x42, 0x03, 0xd1, 0x43, 0x8a, 0x54, 0x8a, 0xa3, 0x42, 0x10, 0xd0,
-0x0b, 0x78, 0x00, 0x2b, 0x0d, 0xd0, 0x4b, 0x78, 0x00, 0x2b, 0x0a, 0xd0,
-0x44, 0x8b, 0x93, 0x8a, 0x9c, 0x42, 0x04, 0xdc, 0x13, 0x4b, 0xc0, 0x46,
-0x5f, 0x60, 0x97, 0x82, 0x01, 0xe0, 0x01, 0x33, 0x93, 0x82, 0xc3, 0x8b,
-0x5c, 0x1c, 0xc4, 0x83, 0x84, 0x8b, 0xa3, 0x42, 0x0e, 0xdb, 0x84, 0x8a,
-0x05, 0x8b, 0x00, 0x23, 0xac, 0x42, 0x05, 0xda, 0x44, 0x8a, 0xc5, 0x8a,
-0xac, 0x42, 0x01, 0xda, 0x4b, 0x70, 0x00, 0xe0, 0x4f, 0x70, 0x43, 0x82,
-0x83, 0x82, 0xc3, 0x83, 0x41, 0x8a, 0xc0, 0x46, 0x51, 0x82, 0x80, 0x8a,
-0xc0, 0x46, 0x10, 0x82, 0xb0, 0xbc, 0x70, 0x47, 0xe8, 0x0e, 0x00, 0x80,
-0x3c, 0x04, 0x00, 0x80, 0x40, 0x01, 0x18, 0x00, 0xf7, 0xb5, 0x91, 0xb0,
-0x6b, 0x46, 0x84, 0x1e, 0x12, 0x99, 0x14, 0x29, 0x1a, 0xd9, 0x00, 0x20,
-0x81, 0x00, 0x67, 0x58, 0xc0, 0x46, 0x57, 0x50, 0x01, 0x30, 0x00, 0x06,
-0x00, 0x0e, 0x10, 0x28, 0xf6, 0xd3, 0x00, 0x21, 0x05, 0x20, 0x87, 0x00,
-0xd6, 0x59, 0x4f, 0x1c, 0x3d, 0x06, 0x2d, 0x0e, 0x0f, 0x1c, 0xbf, 0x00,
-0xde, 0x51, 0x29, 0x1c, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0x28,
-0xf1, 0xd3, 0x09, 0xe0, 0x00, 0x20, 0x81, 0x00, 0x63, 0x58, 0xc0, 0x46,
-0x53, 0x50, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x06, 0x28, 0xf6, 0xd3,
-0x00, 0x20, 0xe0, 0x70, 0x20, 0x72, 0x60, 0x72, 0xa0, 0x72, 0x20, 0x73,
-0x60, 0x73, 0x12, 0x99, 0x14, 0x29, 0x37, 0xd9, 0x69, 0x46, 0x8e, 0x1c,
-0x91, 0x78, 0x09, 0x07, 0x09, 0x0f, 0x89, 0x00, 0x14, 0x39, 0x0d, 0x06,
-0x2d, 0x16, 0x00, 0x27, 0x00, 0x2d, 0x1b, 0xdd, 0xf0, 0x19, 0x10, 0xa9,
-0x00, 0xf0, 0x3d, 0xf8, 0x00, 0x28, 0x0e, 0xd0,
-0x00, 0x20, 0x10, 0xa9, 0x09, 0x78, 0x00, 0x29, 0x09, 0xdd, 0x00, 0x22,
-0x39, 0x18, 0x72, 0x54, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x10, 0xa9,
-0x09, 0x78, 0x88, 0x42, 0xf6, 0xdb, 0x10, 0xa8, 0x00, 0x78, 0x38, 0x18,
-0x07, 0x06, 0x3f, 0x0e, 0xaf, 0x42, 0xe3, 0xdb, 0x68, 0x46, 0xe2, 0x1d,
-0x0d, 0x32, 0x00, 0x21, 0xab, 0x08, 0x5f, 0x1c, 0x08, 0xd0, 0x8b, 0x00,
-0xc4, 0x58, 0xc0, 0x46, 0xd4, 0x50, 0x01, 0x31, 0x09, 0x06, 0x09, 0x0e,
-0x8f, 0x42, 0xf6, 0xd8, 0x14, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x90, 0xb4, 0x87, 0x1e, 0x00, 0x20, 0x89, 0x08, 0x4b, 0x1c, 0x08, 0xd0,
-0x81, 0x00, 0x54, 0x58, 0xc0, 0x46, 0x7c, 0x50, 0x01, 0x30, 0x00, 0x06,
-0x00, 0x0e, 0x83, 0x42, 0xf6, 0xd8, 0x90, 0xbc, 0x70, 0x47, 0x80, 0xb4,
-0x02, 0x78, 0xd2, 0x06, 0xd2, 0x0e, 0x00, 0x23, 0x01, 0x27, 0x01, 0x2a,
-0x01, 0xdc, 0x0f, 0x70, 0x11, 0xe0, 0x40, 0x78, 0xc0, 0x46, 0x08, 0x70,
-0x14, 0x2a, 0x04, 0xd1, 0x08, 0x48, 0x01, 0x7a, 0x01, 0x31, 0x01, 0x72,
-0x07, 0xe0, 0x02, 0x2a, 0x05, 0xd0, 0x05, 0x2a, 0x03, 0xd0, 0x06, 0x2a,
-0x01, 0xd0, 0x15, 0x2a, 0x02, 0xd1, 0x18, 0x1c, 0x80, 0xbc, 0x70, 0x47,
-0x38, 0x1c, 0xfb, 0xe7, 0xe0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x0f, 0x48,
-0x01, 0x23, 0x1b, 0x06, 0x41, 0x69, 0x99, 0x43, 0x1a, 0x09, 0x41, 0x61,
-0xd1, 0x60, 0x00, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x91, 0x61, 0x19, 0x1c,
-0x09, 0x4a, 0xc0, 0x46, 0x11, 0x60, 0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18,
-0x80, 0x69, 0x00, 0x28, 0x03, 0xd0, 0x02, 0xf0, 0x61, 0xfe, 0x08, 0xbc,
-0x18, 0x47, 0x04, 0x48, 0x41, 0x88, 0x01, 0x31, 0x41, 0x80, 0xf8, 0xe7,
-0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0, 0xe0, 0x82, 0x20, 0x40,
-0x70, 0x47, 0x00, 0x00, 0xf0, 0xb5, 0x86, 0xb0, 0x95, 0x4a, 0xd0, 0x68,
-0xd7, 0x1d, 0x79, 0x37, 0x01, 0x28, 0x09, 0xd1, 0x38, 0x89, 0x00, 0x28,
-0x06, 0xd1, 0xd0, 0x6f, 0x02, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60,
-0x14, 0x20, 0x38, 0x81, 0x8e, 0x4c, 0x61, 0x6a, 0x8e, 0x48, 0xc3, 0x6b,
-0x59, 0x18, 0xc1, 0x63, 0xa0, 0x6a, 0x19, 0x23, 0xdb, 0x01, 0xd4, 0x18,
-0xa0, 0x62, 0x21, 0x6a, 0x09, 0x03, 0x09, 0x0b, 0x81, 0x42, 0x05, 0xd1,
-0x01, 0x20, 0x40, 0x04, 0x87, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xf3, 0xe0,
-0xbb, 0x8a, 0x58, 0x1c, 0xb8, 0x82, 0x3d, 0x8b, 0x01, 0x20, 0x00, 0x21,
-0xab, 0x42, 0x04, 0xdb, 0xd3, 0x1d, 0x89, 0x33, 0x58, 0x70, 0xb9, 0x82,
-0xf9, 0x83, 0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x05, 0x93, 0x5b, 0x69,
-0x0f, 0x2b, 0x73, 0xd2, 0x00, 0x21, 0x7c, 0x4f, 0xc0, 0x46, 0x39, 0x61,
-0x21, 0x6a, 0x8a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x4b, 0x68, 0x1e, 0x0c,
-0x36, 0x04, 0xfd, 0x1f, 0x09, 0x3d, 0x00, 0x2e, 0x05, 0xd1, 0x3b, 0x2a,
-0x03, 0xd3, 0x01, 0x23, 0xdb, 0x02, 0x9a, 0x42, 0x01, 0xd9, 0xa8, 0x73,
-0xc8, 0xe0, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x31, 0x19, 0x43, 0x09, 0x68,
-0xc0, 0x46, 0x03, 0x91, 0x03, 0xa9, 0x09, 0x88, 0x01, 0x31, 0x09, 0x04,
-0x09, 0x0c, 0x79, 0x82, 0x49, 0x09, 0x05, 0x31, 0x09, 0x06, 0x09, 0x0e,
-0x69, 0x4e, 0xc0, 0x46, 0x02, 0x96, 0x69, 0x48, 0x43, 0x6a, 0xc0, 0x46,
-0x01, 0x93, 0x83, 0x6a, 0xc0, 0x46, 0x00, 0x93, 0xc2, 0x1d, 0x11, 0x32,
-0x80, 0x69, 0x00, 0x03, 0x00, 0x0b, 0x92, 0x68, 0xb3, 0x07, 0x1a, 0x43,
-0x12, 0x68, 0x90, 0x42, 0x01, 0xd1, 0x01, 0x20,
-0x0d, 0xe0, 0x90, 0x42, 0x05, 0xd9, 0x00, 0x9b, 0x18, 0x1a, 0x01, 0x9b,
-0xd2, 0x1a, 0x82, 0x18, 0x00, 0xe0, 0x12, 0x1a, 0x01, 0x20, 0x09, 0x01,
-0x91, 0x42, 0x00, 0xd3, 0x00, 0x20, 0x01, 0x28, 0x65, 0xd1, 0x51, 0x49,
-0x20, 0x69, 0x00, 0x28, 0x62, 0xd0, 0x05, 0x99, 0x48, 0x69, 0x01, 0x30,
-0x48, 0x61, 0x02, 0x20, 0x21, 0x6a, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0,
-0xa7, 0xfc, 0x78, 0x63, 0xbe, 0x60, 0x49, 0x49, 0x22, 0x6a, 0xa3, 0x6b,
-0xd3, 0x18, 0x66, 0x6b, 0xb3, 0x42, 0x00, 0xd9, 0x22, 0x6b, 0xc0, 0x46,
-0xba, 0x62, 0xba, 0x6a, 0x0c, 0x32, 0xfa, 0x62, 0x00, 0x22, 0xfa, 0x61,
-0x03, 0xaa, 0x52, 0x88, 0xd2, 0x09, 0x03, 0xd3, 0x01, 0x22, 0x00, 0xe0,
-0x7b, 0xe0, 0x00, 0xe0, 0x00, 0x22, 0x7a, 0x60, 0x7a, 0x68, 0xc0, 0x46,
-0x02, 0x60, 0x78, 0x8a, 0x41, 0x4e, 0x60, 0x28, 0x04, 0xdc, 0xb0, 0x83,
-0x78, 0x8a, 0xc0, 0x46, 0xf0, 0x83, 0x08, 0xe0, 0x60, 0x20, 0xb0, 0x83,
-0x79, 0x8a, 0xf8, 0x6a, 0x42, 0x18, 0x63, 0x6b, 0x9a, 0x42, 0x03, 0xd8,
-0xf1, 0x83, 0x00, 0x22, 0x3a, 0x63, 0x05, 0xe0, 0x21, 0x6b, 0xc0, 0x46,
-0x39, 0x63, 0x61, 0x6b, 0x08, 0x1a, 0xf0, 0x83, 0x2d, 0x49, 0x78, 0x6b,
-0x42, 0x68, 0xc0, 0x46, 0xba, 0x60, 0x82, 0x68, 0xc0, 0x46, 0xfa, 0x60,
-0x02, 0x69, 0xc0, 0x46, 0x7a, 0x61, 0x40, 0x69, 0xc0, 0x46, 0xb8, 0x61,
-0x2e, 0x4b, 0xc8, 0x18, 0x04, 0x90, 0x00, 0xf0, 0x37, 0xf9, 0x04, 0x98,
-0x00, 0xf0, 0x88, 0xf8, 0x00, 0xf0, 0xf6, 0xfa, 0x78, 0x8a, 0xf1, 0x8b,
-0x88, 0x42, 0x04, 0xd1, 0xf9, 0x6a, 0x08, 0x18, 0x04, 0xe0, 0x38, 0xe0,
-0x32, 0xe0, 0x3a, 0x6b, 0x10, 0x18, 0x40, 0x1a, 0x81, 0x07, 0x02, 0xd0,
-0x80, 0x08, 0x80, 0x00, 0x04, 0x30, 0x61, 0x6b, 0x09, 0x1a, 0xa2, 0x6b,
-0x91, 0x42, 0x00, 0xd2, 0x20, 0x6b, 0xc0, 0x46, 0x20, 0x62, 0xe8, 0x7b,
-0x00, 0x28, 0x08, 0xd0, 0x00, 0x22, 0xea, 0x73, 0x05, 0x99, 0x48, 0x69,
-0x01, 0x38, 0x48, 0x61, 0x78, 0x6b, 0x00, 0xf0, 0x73, 0xfa, 0x18, 0x48,
-0x80, 0x6a, 0x80, 0x06, 0x80, 0x0e, 0x01, 0x28, 0x0a, 0xd1, 0x20, 0x6a,
-0x00, 0x03, 0x00, 0x0b, 0x0b, 0x4c, 0xa1, 0x6a, 0x88, 0x42, 0x03, 0xd0,
-0x06, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x20, 0x40, 0x04,
-0x08, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x06, 0xe0, 0xe0, 0x68, 0x00, 0x28,
-0x01, 0xd0, 0x00, 0xf0, 0xb5, 0xfa, 0x01, 0x20, 0xa8, 0x73, 0xed, 0xe7,
-0x68, 0x0e, 0x00, 0x80, 0x00, 0x40, 0x14, 0x40, 0xa4, 0x2a, 0x00, 0x80,
-0x00, 0x00, 0x00, 0xb0, 0x28, 0x1a, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55,
-0xa8, 0x03, 0x00, 0x80, 0x68, 0x1a, 0x00, 0x80, 0xc4, 0x0b, 0x00, 0x00,
-0x00, 0x00, 0x10, 0x40, 0x80, 0xb5, 0x07, 0x1c, 0x78, 0x6a, 0x40, 0x89,
-0xff, 0x21, 0x01, 0x31, 0x01, 0x40, 0x10, 0x48, 0x02, 0xd1, 0x81, 0x6c,
-0x01, 0x31, 0x81, 0x64, 0x79, 0x6a, 0x49, 0x89, 0x49, 0x0b, 0x02, 0xd2,
-0x41, 0x6c, 0x01, 0x31, 0x41, 0x64, 0x0b, 0x48, 0x41, 0x6a, 0x01, 0x31,
-0x41, 0x62, 0x78, 0x6a, 0x39, 0x6b, 0xc0, 0x46, 0x48, 0x62, 0x38, 0x6b,
-0x00, 0xf0, 0xf8, 0xfb, 0x38, 0x1c, 0x00, 0xf0, 0xb3, 0xf8, 0x01, 0x20,
-0x04, 0x49, 0xc0, 0x46, 0xc8, 0x73, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0xa4, 0x2a, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x18, 0x1a, 0x00, 0x80,
-0xf8, 0xb5, 0x07, 0x1c, 0x00, 0x22, 0xf9, 0x1d, 0x61, 0x31, 0x0d, 0x1c,
-0x78, 0x6a, 0xc0, 0x46, 0x00, 0x90, 0x40, 0x89,
-0x03, 0x0c, 0x01, 0xd2, 0x40, 0x0a, 0x03, 0xd2, 0x38, 0x1c, 0xff, 0xf7,
-0xc1, 0xff, 0x67, 0xe0, 0x35, 0x48, 0xc0, 0x6b, 0x00, 0x09, 0x1f, 0xd3,
-0x08, 0x78, 0x40, 0x08, 0x1c, 0xd2, 0x00, 0x20, 0x43, 0x00, 0xcc, 0x5a,
-0x31, 0x4e, 0x9e, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0x1b, 0x88,
-0x9c, 0x42, 0x0e, 0xd0, 0xb8, 0x69, 0x39, 0x6b, 0xc0, 0x46, 0x88, 0x61,
-0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 0x38, 0x1c, 0x00, 0xf0,
-0x27, 0xf9, 0x38, 0x1c, 0x00, 0xf0, 0x74, 0xf8, 0x46, 0xe0, 0x01, 0x30,
-0x03, 0x28, 0xe3, 0xdb, 0x02, 0x20, 0x43, 0x00, 0x5c, 0x18, 0xe4, 0x88,
-0x22, 0x4e, 0x9e, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0x1b, 0x88,
-0x9c, 0x42, 0x03, 0xd1, 0x01, 0x23, 0x01, 0x38, 0xd8, 0x42, 0xf0, 0xdc,
-0x01, 0x23, 0xd8, 0x42, 0xc4, 0xd0, 0x1b, 0x4e, 0x0b, 0x23, 0x1b, 0x02,
-0xf0, 0x18, 0x40, 0x69, 0x00, 0x28, 0x24, 0xd0, 0x7d, 0x63, 0x00, 0x98,
-0x40, 0x89, 0x00, 0x0c, 0x1f, 0xd2, 0x00, 0x24, 0x2d, 0x23, 0x9b, 0x01,
-0xf0, 0x18, 0xc0, 0x6b, 0x35, 0x1c, 0x00, 0x28, 0x17, 0xd0, 0xfe, 0x1d,
-0x2d, 0x36, 0xa2, 0x00, 0x52, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xd2, 0x18,
-0xd2, 0x6b, 0x38, 0x1c, 0x31, 0x1c, 0x02, 0xf0, 0x7b, 0xfc, 0x01, 0x28,
-0x0e, 0xd0, 0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, 0x2d, 0x23, 0x9b, 0x01,
-0xc0, 0x18, 0xc0, 0x6b, 0x00, 0x28, 0xea, 0xd1, 0x01, 0xe0, 0x01, 0x2a,
-0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, 0xf8, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80,
-0x80, 0xb5, 0x07, 0x1c, 0xb8, 0x69, 0x39, 0x6b, 0xc0, 0x46, 0x88, 0x61,
-0xf8, 0x68, 0x39, 0x6b, 0xc0, 0x46, 0xc8, 0x60, 0x78, 0x6a, 0x40, 0x89,
-0x01, 0x0c, 0x0e, 0xd2, 0x40, 0x0a, 0x0c, 0xd3, 0x38, 0x68, 0x40, 0x08,
-0x02, 0xd3, 0x38, 0x1c, 0x02, 0xf0, 0x0c, 0xfc, 0x38, 0x1c, 0x00, 0xf0,
-0xbb, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0x08, 0xf8, 0x02, 0xe0, 0x38, 0x1c,
-0xff, 0xf7, 0x30, 0xff, 0x01, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x01, 0x21, 0x00, 0x6b, 0x40, 0x6a, 0xc0, 0x46, 0x01, 0x60, 0x70, 0x47,
-0xb0, 0xb4, 0xc1, 0x1d, 0x39, 0x31, 0x09, 0x8b, 0x89, 0x08, 0x09, 0x04,
-0x09, 0x0c, 0x84, 0x6a, 0xc2, 0x1d, 0x61, 0x32, 0x00, 0x20, 0x00, 0x29,
-0x0c, 0xdd, 0x87, 0x00, 0x3d, 0x19, 0x01, 0x23, 0x9b, 0x07, 0x2b, 0x43,
-0x1b, 0x68, 0xc0, 0x46, 0xd3, 0x51, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c,
-0x88, 0x42, 0xf2, 0xdb, 0xb0, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0xa0, 0xb0,
-0x01, 0x23, 0x9b, 0x07, 0xc1, 0x1d, 0x21, 0x31, 0x19, 0x43, 0x09, 0x68,
-0xc0, 0x46, 0x0b, 0x91, 0xc1, 0x1d, 0x53, 0x31, 0x19, 0x43, 0x1f, 0x91,
-0x09, 0x68, 0x01, 0xaf, 0xfa, 0x1d, 0x39, 0x32, 0x1e, 0x92, 0x17, 0xab,
-0x59, 0x80, 0x3a, 0x49, 0x01, 0x23, 0x9b, 0x07, 0x0a, 0x6a, 0x13, 0x43,
-0xcc, 0x1d, 0x11, 0x34, 0x89, 0x69, 0x09, 0x03, 0x09, 0x0b, 0x22, 0x69,
-0xe5, 0x68, 0xc0, 0x46, 0x1d, 0x95, 0xfc, 0x1d, 0x39, 0x34, 0x64, 0x8b,
-0x64, 0x09, 0x05, 0x34, 0x24, 0x06, 0x24, 0x0e, 0x1c, 0x94, 0x56, 0x1a,
-0x1b, 0x96, 0x1c, 0x9c, 0x2e, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x26,
-0x1d, 0x9d, 0x1a, 0x68, 0x91, 0x42, 0x01, 0xd1, 0x32, 0x1c, 0x0b, 0xe0,
-0x91, 0x42, 0x03, 0xd9, 0x52, 0x1b, 0x1b, 0x9e, 0xb5, 0x18, 0x00, 0xe0,
-0x55, 0x1a, 0x01, 0x22, 0x24, 0x01, 0xac, 0x42,
-0x00, 0xd3, 0x00, 0x22, 0x01, 0x2a, 0xe6, 0xd1, 0x91, 0x07, 0x01, 0x43,
-0x09, 0x68, 0xc0, 0x46, 0x39, 0x60, 0x93, 0x07, 0x01, 0x1d, 0x19, 0x43,
-0x09, 0x68, 0xc0, 0x46, 0x79, 0x60, 0xc1, 0x1d, 0x01, 0x31, 0x19, 0x43,
-0x09, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0x1f, 0x99, 0x09, 0x68, 0x1e, 0x9a,
-0xc0, 0x46, 0x51, 0x83, 0xc1, 0x1d, 0x1d, 0x31, 0x19, 0x43, 0x09, 0x68,
-0xc0, 0x46, 0x38, 0x63, 0x79, 0x62, 0xc1, 0x1d, 0x11, 0x31, 0x19, 0x43,
-0x09, 0x68, 0xc0, 0x46, 0xb9, 0x61, 0xc1, 0x1d, 0x05, 0x31, 0x19, 0x43,
-0x09, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0xc1, 0x1d, 0x17, 0x31, 0x19, 0x43,
-0x09, 0x68, 0xc0, 0x46, 0xf9, 0x83, 0x0e, 0x30, 0x18, 0x43, 0x00, 0x68,
-0xc0, 0x46, 0xf8, 0x81, 0x38, 0x68, 0x40, 0x08, 0x02, 0xd3, 0x38, 0x1c,
-0x02, 0xf0, 0x5c, 0xfb, 0x38, 0x1c, 0x00, 0xf0, 0x0b, 0xf8, 0x38, 0x1c,
-0xff, 0xf7, 0x58, 0xff, 0x20, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0xa8, 0x03, 0x00, 0x80, 0x55, 0x55, 0x55, 0x55, 0xf8, 0xb5, 0x07, 0x1c,
-0xf8, 0x1d, 0x39, 0x30, 0x41, 0x8b, 0x39, 0x4a, 0x91, 0x42, 0x00, 0xdd,
-0x42, 0x83, 0x42, 0x8b, 0xc0, 0x46, 0x00, 0x92, 0x01, 0x20, 0x3a, 0x1d,
-0x06, 0xca, 0xbb, 0x6a, 0x02, 0xf0, 0x0e, 0xff, 0x33, 0x4a, 0xc0, 0x46,
-0x00, 0x92, 0x33, 0x4e, 0x30, 0x6a, 0x33, 0x4c, 0xe1, 0x6d, 0x41, 0x18,
-0x38, 0x6b, 0xc3, 0x1d, 0x05, 0x33, 0x01, 0x20, 0x72, 0x6a, 0x02, 0xf0,
-0xfb, 0xfe, 0xe0, 0x6d, 0x18, 0x30, 0x00, 0x25, 0xb1, 0x6a, 0x81, 0x42,
-0x01, 0xd8, 0xe5, 0x65, 0x00, 0xe0, 0xe0, 0x65, 0x2f, 0x23, 0x9b, 0x01,
-0x20, 0x1c, 0xe1, 0x6d, 0xe4, 0x18, 0x22, 0x68, 0x92, 0x00, 0x27, 0x4b,
-0xc0, 0x46, 0x99, 0x50, 0x26, 0x48, 0xc1, 0x6b, 0x4a, 0x08, 0x05, 0xd3,
-0x49, 0x08, 0x49, 0x00, 0xc1, 0x63, 0x01, 0x20, 0x01, 0xf0, 0xd6, 0xff,
-0x22, 0x4a, 0x1f, 0x48, 0xc1, 0x1d, 0x89, 0x31, 0x0b, 0x78, 0x00, 0x2b,
-0x02, 0xd0, 0x49, 0x78, 0x00, 0x29, 0x00, 0xd1, 0x1e, 0x4a, 0xc0, 0x46,
-0x00, 0x92, 0x20, 0x68, 0x80, 0x00, 0x19, 0x4b, 0xc3, 0x18, 0x05, 0xce,
-0xc1, 0x1d, 0x11, 0x31, 0x01, 0x20, 0x02, 0xf0, 0xc7, 0xfe, 0x14, 0x48,
-0x21, 0x68, 0x01, 0x31, 0x21, 0x60, 0x17, 0x29, 0x00, 0xd3, 0x25, 0x60,
-0x39, 0x6b, 0xc0, 0x46, 0x0d, 0x65, 0x79, 0x6a, 0x3a, 0x6b, 0xc0, 0x46,
-0x51, 0x62, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x68, 0x00, 0x29,
-0x03, 0xd1, 0x39, 0x6b, 0xc0, 0x46, 0x81, 0x60, 0x04, 0xe0, 0x39, 0x6b,
-0xc2, 0x68, 0xc0, 0x46, 0x11, 0x65, 0x39, 0x6b, 0xc0, 0x46, 0xc1, 0x60,
-0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xea, 0x05, 0x00, 0x00,
-0x18, 0x00, 0x14, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x68, 0x0e, 0x00, 0x80,
-0x44, 0x82, 0x20, 0x40, 0xe8, 0x0e, 0x00, 0x80, 0x04, 0x00, 0x00, 0x02,
-0x04, 0x00, 0x00, 0x03, 0xf0, 0xb5, 0x11, 0x4e, 0xff, 0x25, 0x01, 0x35,
-0x10, 0x4f, 0xc0, 0x46, 0x35, 0x60, 0x78, 0x69, 0x01, 0x38, 0x78, 0x61,
-0xbc, 0x68, 0x00, 0x2c, 0x10, 0xd0, 0x20, 0x6d, 0xc0, 0x46, 0xb8, 0x60,
-0x20, 0x1c, 0x00, 0xf0, 0x21, 0xf8, 0x20, 0x1c, 0x00, 0xf0, 0x04, 0xfa,
-0x08, 0x48, 0x80, 0x6a, 0x00, 0x0c, 0x00, 0x07, 0xe9, 0xd1, 0xf0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x05, 0x48, 0xc1, 0x79, 0x01, 0x31, 0xc1, 0x71,
-0xf7, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x28, 0x1b, 0x00, 0x80,
-0x00, 0x00, 0x10, 0x40, 0xa0, 0x82, 0x20, 0x40,
-0x01, 0x20, 0x80, 0x03, 0x01, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x70, 0x47,
-0x00, 0x00, 0x00, 0xb0, 0x90, 0xb5, 0x07, 0x1c, 0x38, 0x68, 0xc0, 0x08,
-0x09, 0xd3, 0x1d, 0x48, 0x01, 0x6a, 0x01, 0x39, 0x01, 0x62, 0x20, 0x30,
-0x00, 0x79, 0x00, 0x28, 0x01, 0xd0, 0xfe, 0xf7, 0xe9, 0xfd, 0x01, 0x23,
-0x9b, 0x07, 0xf8, 0x1d, 0x1d, 0x30, 0x18, 0x43, 0x00, 0x68, 0x16, 0x4c,
-0x61, 0x6a, 0x81, 0x42, 0x21, 0xd1, 0x01, 0x1c, 0x19, 0x43, 0x09, 0x68,
-0x09, 0x04, 0x09, 0x0c, 0x01, 0x29, 0x1a, 0xd1, 0x00, 0xf0, 0x22, 0xf8,
-0x60, 0x62, 0x60, 0x6a, 0x21, 0x6a, 0x88, 0x42, 0x05, 0xd0, 0x01, 0x21,
-0x89, 0x07, 0x01, 0x43, 0x09, 0x68, 0x09, 0x04, 0xf2, 0xd0, 0x51, 0x21,
-0x89, 0x03, 0x62, 0x6a, 0x23, 0x6b, 0x9a, 0x42, 0x02, 0xd1, 0x60, 0x6b,
-0xa2, 0x6b, 0x80, 0x1a, 0x04, 0x38, 0xc8, 0x60, 0x90, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x20, 0x79, 0x6a, 0xc0, 0x46, 0x08, 0x60, 0xf7, 0xe7,
-0x6c, 0x06, 0x00, 0x80, 0xe8, 0x1a, 0x00, 0x80, 0x01, 0x23, 0x9b, 0x07,
-0xc1, 0x1d, 0x01, 0x31, 0x19, 0x43, 0x09, 0x68, 0x09, 0x04, 0x09, 0x0c,
-0x08, 0x18, 0x0d, 0x30, 0x81, 0x07, 0x02, 0xd0, 0x80, 0x08, 0x80, 0x00,
-0x04, 0x30, 0x04, 0x49, 0x8a, 0x6b, 0x12, 0x18, 0x4b, 0x6b, 0x9a, 0x42,
-0x00, 0xd9, 0x08, 0x6b, 0x70, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80,
-0x00, 0xb5, 0x04, 0x48, 0xc0, 0x68, 0x10, 0x28, 0x01, 0xd3, 0x00, 0xf0,
-0x05, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80,
-0x88, 0xb5, 0x0c, 0x4f, 0x38, 0x79, 0x00, 0x28, 0x11, 0xd1, 0x0b, 0x49,
-0x10, 0x20, 0x02, 0xf0, 0xf5, 0xfd, 0x00, 0x28, 0x0b, 0xd0, 0x01, 0x20,
-0x38, 0x71, 0x08, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x07, 0x48, 0x42, 0x68,
-0x07, 0x4b, 0x01, 0x68, 0x00, 0x20, 0x02, 0xf0, 0xdf, 0xfd, 0x88, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0xf8, 0x1a, 0x00, 0x80, 0xf5, 0x2c, 0xff, 0xff,
-0x10, 0x00, 0x35, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40,
-0x90, 0xb5, 0x01, 0x20, 0x40, 0x02, 0x10, 0x49, 0xc0, 0x46, 0x08, 0x60,
-0x0f, 0x4f, 0x10, 0x21, 0xf8, 0x1d, 0x3d, 0x30, 0x02, 0xf0, 0x4c, 0xfc,
-0x19, 0x23, 0xdb, 0x01, 0xfc, 0x18, 0xe0, 0x68, 0x00, 0x28, 0x01, 0xd0,
-0x00, 0xf0, 0x14, 0xf8, 0x00, 0x20, 0xc9, 0x23, 0x1b, 0x01, 0xf9, 0x18,
-0x08, 0x71, 0xe0, 0x68, 0x10, 0x28, 0x04, 0xd3, 0x01, 0x20, 0xbb, 0x23,
-0x1b, 0x01, 0xf9, 0x18, 0x48, 0x73, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 0xf8, 0xb5, 0x37, 0x48,
-0x19, 0x23, 0xdb, 0x01, 0xc1, 0x18, 0xc9, 0x68, 0x35, 0x4d, 0x10, 0x29,
-0x00, 0xd9, 0x10, 0x21, 0x69, 0x62, 0x32, 0x48, 0xc1, 0x6c, 0x00, 0x6e,
-0x81, 0x42, 0x07, 0xd9, 0x08, 0x1a, 0x07, 0x09, 0x00, 0x24, 0x68, 0x6a,
-0xb8, 0x42, 0x12, 0xd2, 0x07, 0x1c, 0x10, 0xe0, 0x81, 0x42, 0x2a, 0xd2,
-0x2c, 0x4a, 0x52, 0x6b, 0x10, 0x1a, 0x07, 0x09, 0x68, 0x6a, 0xb8, 0x42,
-0x05, 0xd9, 0x0c, 0x09, 0x39, 0x19, 0x88, 0x42, 0x03, 0xd2, 0xc4, 0x1b,
-0x01, 0xe0, 0x00, 0x24, 0x07, 0x1c, 0x3e, 0x19, 0x30, 0x01, 0x25, 0x49,
-0x02, 0xf0, 0x84, 0xfd, 0x00, 0x28, 0x3d, 0xd0, 0x23, 0x48, 0x00, 0x2c,
-0x1a, 0xd1, 0x1e, 0x49, 0x3a, 0x01, 0x6f, 0x62, 0x09, 0x6e, 0x8c, 0x18,
-0x1d, 0x4d, 0x6b, 0x6b, 0xa3, 0x42, 0x00, 0xd8, 0xe4, 0x1a, 0x1e, 0x4b,
-0x1a, 0x43, 0x00, 0x92, 0xea, 0x6a, 0x51, 0x18,
-0x2a, 0x6b, 0x03, 0x1c, 0x20, 0xe0, 0x1b, 0x48, 0x01, 0x6b, 0x01, 0x31,
-0x01, 0x63, 0x00, 0x20, 0x68, 0x62, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x10, 0x49, 0x24, 0x01, 0x3f, 0x01, 0x11, 0x22, 0x52, 0x05, 0x3a, 0x43,
-0x6e, 0x62, 0x00, 0x92, 0x0e, 0x4d, 0xea, 0x6a, 0x09, 0x6e, 0x51, 0x18,
-0x03, 0x1c, 0x06, 0x1c, 0x00, 0x20, 0x2a, 0x6b, 0x02, 0xf0, 0x4a, 0xfd,
-0x0c, 0x4a, 0x22, 0x43, 0x00, 0x92, 0xbb, 0x19, 0xe9, 0x6a, 0x2a, 0x6b,
-0x00, 0x20, 0x02, 0xf0, 0x41, 0xfd, 0x03, 0x48, 0xc0, 0x46, 0x04, 0x66,
-0x00, 0xf0, 0x10, 0xf8, 0x01, 0x20, 0xda, 0xe7, 0x68, 0x0e, 0x00, 0x80,
-0x28, 0x1b, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 0x5d, 0x2e, 0xff, 0xff,
-0x44, 0x80, 0x20, 0x40, 0x00, 0x00, 0x36, 0x02, 0xa0, 0x82, 0x20, 0x40,
-0x04, 0x48, 0x01, 0x6e, 0x04, 0x4a, 0x80, 0x30, 0xd1, 0x60, 0x02, 0x23,
-0xc1, 0x6b, 0x19, 0x43, 0xc1, 0x63, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80,
-0x90, 0xee, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, 0x01, 0x20, 0x80, 0x02,
-0x1c, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0x27, 0x1b, 0x4e, 0x33, 0x23,
-0x9b, 0x01, 0xf5, 0x18, 0x68, 0x6a, 0x00, 0x28, 0x1d, 0xd9, 0x19, 0x4c,
-0x68, 0x46, 0x10, 0x21, 0x02, 0xf0, 0x90, 0xfb, 0x68, 0x46, 0x00, 0xf0,
-0x33, 0xf8, 0x00, 0x28, 0x04, 0xd0, 0x15, 0x49, 0x48, 0x69, 0x01, 0x30,
-0x48, 0x61, 0x0a, 0xe0, 0x13, 0x49, 0x60, 0x7b, 0x01, 0x30, 0x60, 0x73,
-0x88, 0x79, 0x01, 0x30, 0x88, 0x71, 0x11, 0x48, 0x00, 0x68, 0x02, 0xf0,
-0x65, 0xf9, 0x68, 0x6a, 0x01, 0x37, 0xb8, 0x42, 0xe2, 0xd8, 0xbb, 0x23,
-0x1b, 0x01, 0xf0, 0x18, 0x81, 0x7b, 0x00, 0x29, 0x03, 0xd0, 0x00, 0x21,
-0x81, 0x73, 0xff, 0xf7, 0x05, 0xfb, 0xff, 0xf7, 0xe3, 0xfe, 0x04, 0xb0,
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
-0x68, 0x0e, 0x00, 0x80, 0xb0, 0x82, 0x20, 0x40, 0x08, 0x83, 0x20, 0x40,
-0xa0, 0x82, 0x20, 0x40, 0x58, 0x04, 0x00, 0x80, 0x90, 0xb4, 0x17, 0x4f,
-0x19, 0x23, 0xdb, 0x01, 0xf9, 0x18, 0x00, 0x22, 0xcb, 0x68, 0x00, 0x2b,
-0x23, 0xd0, 0x01, 0x3b, 0xcb, 0x60, 0x33, 0x23, 0x9b, 0x01, 0xff, 0x18,
-0xbb, 0x69, 0x1c, 0x6d, 0xc0, 0x46, 0xbc, 0x61, 0x04, 0x68, 0xc0, 0x46,
-0x5c, 0x60, 0x44, 0x68, 0xc0, 0x46, 0x9c, 0x60, 0x84, 0x68, 0xc0, 0x46,
-0x1c, 0x61, 0xc0, 0x68, 0xc0, 0x46, 0x58, 0x61, 0x1a, 0x65, 0x08, 0x69,
-0x42, 0x1c, 0x0a, 0x61, 0x00, 0x28, 0x03, 0xd0, 0x38, 0x6a, 0xc0, 0x46,
-0x03, 0x65, 0x00, 0xe0, 0xfb, 0x61, 0x3b, 0x62, 0x18, 0x1c, 0x90, 0xbc,
-0x70, 0x47, 0x10, 0x1c, 0xfb, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0x0a, 0x4a, 0x33, 0x23, 0x9b, 0x01, 0xd1, 0x18, 0xc8, 0x69, 0x19, 0x23,
-0xdb, 0x01, 0xd2, 0x18, 0x13, 0x69, 0x00, 0x2b, 0x06, 0xd0, 0x01, 0x3b,
-0x13, 0x61, 0xca, 0x69, 0x12, 0x6d, 0xc0, 0x46, 0xca, 0x61, 0x70, 0x47,
-0x00, 0x21, 0x11, 0x61, 0xfb, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0x06, 0x4a, 0x11, 0x69, 0x4b, 0x1c, 0x13, 0x61, 0x40, 0x32, 0x00, 0x29,
-0x01, 0xd0, 0xd1, 0x69, 0x00, 0xe0, 0x00, 0x21, 0x01, 0x65, 0xd0, 0x61,
-0x70, 0x47, 0x00, 0x00, 0xe8, 0x1a, 0x00, 0x80, 0x06, 0x4a, 0xd1, 0x68,
-0x4b, 0x1c, 0xd3, 0x60, 0x40, 0x32, 0x00, 0x29, 0x01, 0xd0, 0x91, 0x69,
-0x00, 0xe0, 0x00, 0x21, 0x01, 0x65, 0x90, 0x61, 0x70, 0x47, 0x00, 0x00,
-0xe8, 0x1a, 0x00, 0x80, 0x90, 0xb4, 0x00, 0x21,
-0x0f, 0x4a, 0x97, 0x89, 0x92, 0x6a, 0x4b, 0x00, 0x1b, 0x18, 0x9b, 0x8a,
-0x00, 0x2b, 0x12, 0xd0, 0xbb, 0x42, 0x10, 0xdc, 0x1c, 0x1c, 0x58, 0x23,
-0x63, 0x43, 0xd3, 0x18, 0xdc, 0x1f, 0x49, 0x3c, 0x01, 0x23, 0x9b, 0x07,
-0x23, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x1b, 0x0e, 0x03, 0x2b, 0x02, 0xd0,
-0x00, 0x20, 0x90, 0xbc, 0x70, 0x47, 0x01, 0x31, 0x04, 0x29, 0xe4, 0xd3,
-0x01, 0x20, 0xf8, 0xe7, 0x4c, 0x2a, 0x00, 0x80, 0xf7, 0xb5, 0x86, 0xb0,
-0x3d, 0x4a, 0x07, 0x1c, 0xd1, 0x69, 0x8f, 0x40, 0x03, 0x1c, 0x14, 0x6a,
-0xe3, 0x40, 0x5f, 0x40, 0x07, 0x9e, 0x8e, 0x40, 0x77, 0x40, 0xcf, 0x40,
-0x94, 0x69, 0xc0, 0x46, 0x05, 0x94, 0x03, 0x1c, 0xa3, 0x40, 0x00, 0x25,
-0x14, 0x69, 0xc0, 0x46, 0x04, 0x94, 0x00, 0x2c, 0x5d, 0xd9, 0x1c, 0x1c,
-0x32, 0x4e, 0x26, 0x43, 0x94, 0x69, 0xe6, 0x40, 0x33, 0x1c, 0x03, 0x96,
-0x53, 0x6a, 0xc0, 0x46, 0x02, 0x93, 0xd2, 0x6a, 0xc0, 0x46, 0x01, 0x92,
-0xbb, 0x00, 0x02, 0x9a, 0xd2, 0x58, 0x13, 0x1c, 0x05, 0x9c, 0xe3, 0x40,
-0x03, 0x9c, 0xa3, 0x42, 0x3e, 0xd1, 0x8a, 0x40, 0xca, 0x40, 0x14, 0x1c,
-0x63, 0x00, 0x1b, 0x19, 0x5b, 0x01, 0x01, 0x9a, 0xd2, 0x18, 0x01, 0x23,
-0x9b, 0x07, 0xd6, 0x1d, 0x01, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06,
-0x1b, 0x0e, 0x03, 0x2b, 0x2c, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d,
-0x51, 0x36, 0x33, 0x43, 0x1b, 0x68, 0x07, 0x9e, 0x1e, 0x40, 0x00, 0x96,
-0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x49, 0x36, 0x33, 0x43, 0x1b, 0x68,
-0x83, 0x42, 0x1b, 0xd1, 0x01, 0x23, 0x9b, 0x07, 0xd6, 0x1d, 0x4d, 0x36,
-0x33, 0x43, 0x1b, 0x68, 0x00, 0x9e, 0xb3, 0x42, 0x12, 0xd1, 0x01, 0x23,
-0x9b, 0x07, 0x1a, 0x43, 0x12, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x08, 0x9b,
-0x32, 0x2b, 0x04, 0xd1, 0x02, 0x2a, 0x07, 0xd1, 0x20, 0x04, 0x00, 0x14,
-0x0f, 0xe0, 0x08, 0x9b, 0x33, 0x2b, 0x01, 0xd1, 0x01, 0x2a, 0xf7, 0xd0,
-0x04, 0x9a, 0x01, 0x37, 0x97, 0x42, 0x00, 0xd3, 0x00, 0x27, 0x04, 0x9a,
-0x01, 0x35, 0xaa, 0x42, 0xae, 0xd8, 0x00, 0x20, 0xc0, 0x43, 0x09, 0xb0,
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80,
-0x00, 0x00, 0x00, 0x80, 0xf0, 0xb5, 0x27, 0x4d, 0x68, 0x69, 0x00, 0x28,
-0x06, 0xd0, 0x26, 0x48, 0x00, 0x68, 0x02, 0xf0, 0x2b, 0xf8, 0xf0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x23, 0x4c, 0x00, 0x26, 0xa0, 0x68, 0x23, 0x4f,
-0x00, 0x28, 0x16, 0xd0, 0x0f, 0xe0, 0x28, 0x6a, 0x02, 0x28, 0x02, 0xd3,
-0x01, 0x20, 0x38, 0x71, 0x0f, 0xe0, 0xa6, 0x60, 0xfd, 0xf7, 0xde, 0xfe,
-0x00, 0x28, 0xea, 0xd1, 0x28, 0x6a, 0x02, 0x28, 0x01, 0xd3, 0x01, 0x20,
-0x38, 0x71, 0xe8, 0x68, 0x00, 0x28, 0x02, 0xd0, 0x38, 0x79, 0x00, 0x28,
-0xe9, 0xd0, 0x68, 0x68, 0x00, 0x28, 0x1b, 0xd0, 0x01, 0x20, 0xa0, 0x60,
-0xfe, 0xf7, 0xbc, 0xfb, 0x00, 0x28, 0xd6, 0xd1, 0x68, 0x68, 0x00, 0x28,
-0xf6, 0xd1, 0x11, 0xe0, 0x00, 0x28, 0xd0, 0xd1, 0x28, 0x6a, 0x02, 0x28,
-0x02, 0xd3, 0x01, 0x20, 0x38, 0x71, 0xca, 0xe7, 0xa6, 0x60, 0xfd, 0xf7,
-0xb9, 0xfe, 0x00, 0x28, 0xc5, 0xd1, 0x28, 0x6a, 0x02, 0x28, 0x01, 0xd3,
-0x01, 0x20, 0x38, 0x71, 0xe8, 0x68, 0x00, 0x28, 0xbd, 0xd0, 0x38, 0x79,
-0x00, 0x28, 0xe7, 0xd0, 0xb9, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
-0x5c, 0x04, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80, 0x8c, 0x06, 0x00, 0x80,
-0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00,
-0x70, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x40, 0x20, 0x1d, 0x49, 0xc0, 0x46,
-0x08, 0x60, 0x01, 0xf0, 0x9d, 0xfc, 0x03, 0x23, 0x1b, 0x07, 0x41, 0x68,
-0x19, 0x40, 0x0c, 0x0f, 0x61, 0x01, 0x09, 0x1b, 0x89, 0x00, 0x18, 0x4a,
-0x8f, 0x18, 0x01, 0x21, 0x39, 0x80, 0x81, 0x6a, 0xc0, 0x46, 0x79, 0x65,
-0x41, 0x6a, 0xc0, 0x46, 0x79, 0x67, 0xb9, 0x6c, 0xfa, 0x6c, 0x89, 0x18,
-0xb9, 0x64, 0x00, 0x21, 0xf9, 0x64, 0xba, 0x6b, 0x3b, 0x6d, 0xd2, 0x18,
-0xba, 0x63, 0x39, 0x65, 0x42, 0x6a, 0x20, 0x32, 0x51, 0x71, 0x79, 0x6d,
-0x7a, 0x6f, 0xd2, 0x6d, 0xc0, 0x46, 0x11, 0x60, 0xfc, 0xf7, 0xca, 0xff,
-0x20, 0x01, 0x09, 0x49, 0x40, 0x18, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18,
-0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0x78, 0x6f, 0x01, 0xf0, 0xc6, 0xfb,
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
-0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80, 0xf0, 0xb5, 0x40, 0x20,
-0x12, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x01, 0xf0, 0x59, 0xfc, 0x07, 0x1c,
-0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 0x06, 0x0f, 0x70, 0x01,
-0x80, 0x1b, 0x80, 0x00, 0x0c, 0x49, 0x44, 0x18, 0xb8, 0x6a, 0xc0, 0x46,
-0x60, 0x65, 0x78, 0x6a, 0xc0, 0x46, 0x60, 0x67, 0x80, 0x6f, 0x05, 0x1d,
-0xe5, 0x63, 0xb9, 0x69, 0x28, 0x1c, 0x02, 0xf0, 0x89, 0xf9, 0x38, 0x1c,
-0x21, 0x1c, 0x32, 0x1c, 0x2b, 0x1c, 0x00, 0xf0, 0x20, 0xf8, 0xf0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x5c, 0x2b, 0x00, 0x80,
-0xf0, 0xb5, 0x4b, 0x6f, 0x9b, 0x6f, 0x1f, 0x1d, 0xcf, 0x63, 0x05, 0x68,
-0x00, 0x23, 0x84, 0x69, 0xa4, 0x08, 0x08, 0xd0, 0x9c, 0x00, 0x2e, 0x59,
-0xc0, 0x46, 0x3e, 0x51, 0x84, 0x69, 0xa4, 0x08, 0x01, 0x33, 0x9c, 0x42,
-0xf6, 0xd8, 0x3b, 0x1c, 0x00, 0xf0, 0x03, 0xf8, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0xff, 0xb5, 0x81, 0xb0, 0x04, 0x1c, 0x1d, 0x1c, 0x0f, 0x1c,
-0x46, 0x48, 0x01, 0x69, 0x01, 0x31, 0x01, 0x61, 0xf9, 0x1d, 0x51, 0x31,
-0xbd, 0x65, 0x00, 0x91, 0x20, 0x1c, 0xfd, 0xf7, 0x5d, 0xfc, 0xf8, 0x6d,
-0x40, 0x09, 0x36, 0xd2, 0xb8, 0x6d, 0x06, 0x7b, 0x43, 0x7b, 0x1b, 0x02,
-0x1e, 0x43, 0x17, 0x21, 0x49, 0x02, 0x01, 0x73, 0x0b, 0x0a, 0x43, 0x73,
-0x00, 0x99, 0x20, 0x1c, 0xfd, 0xf7, 0x4c, 0xfc, 0xb8, 0x6d, 0xc0, 0x46,
-0x06, 0x73, 0x33, 0x0a, 0x43, 0x73, 0xf8, 0x6d, 0x40, 0x09, 0x20, 0xd2,
-0x60, 0x68, 0x01, 0x04, 0x09, 0x0c, 0x03, 0x98, 0x01, 0xf0, 0xcc, 0xfc,
-0x60, 0x68, 0x32, 0x4b, 0x18, 0x43, 0x60, 0x60, 0x20, 0x1c, 0x01, 0xf0,
-0x35, 0xfd, 0x00, 0x25, 0x7d, 0x60, 0xbd, 0x60, 0x3d, 0x64, 0x7d, 0x64,
-0x20, 0x1c, 0xfc, 0xf7, 0x31, 0xff, 0x38, 0x88, 0x40, 0x23, 0x18, 0x43,
-0x38, 0x80, 0x7d, 0x62, 0x29, 0x48, 0xc0, 0x46, 0xb8, 0x62, 0x38, 0x1c,
-0x00, 0xf0, 0xa0, 0xfb, 0x44, 0xe0, 0x20, 0x68, 0x01, 0x23, 0x9b, 0x07,
-0x08, 0x38, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0x78, 0x64, 0x60, 0x68,
-0x02, 0x04, 0x12, 0x0c, 0x78, 0x6e, 0x01, 0x26, 0xc1, 0x1d, 0x0d, 0x31,
-0x8a, 0x42, 0x02, 0xd2, 0x3a, 0x64, 0x08, 0x1c, 0x0e, 0xe0, 0x41, 0x19,
-0x89, 0x89, 0xf0, 0x23, 0x19, 0x40, 0x09, 0x09, 0x89, 0x00, 0x40, 0x18,
-0xf8, 0x60, 0xf9, 0x61, 0x61, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x81, 0x42,
-0x16, 0xd2, 0x39, 0x64, 0x63, 0x68, 0x19, 0x04, 0x09, 0x0c, 0x40, 0x1a,
-0x03, 0x30, 0x80, 0x08, 0x82, 0x00, 0xa0, 0x61,
-0x20, 0x68, 0x09, 0x18, 0x9b, 0x18, 0x63, 0x60, 0xc3, 0x1f, 0x05, 0x3b,
-0x38, 0x1c, 0x00, 0xf0, 0xb6, 0xfa, 0x7e, 0x80, 0x20, 0x1c, 0x00, 0xf0,
-0xbf, 0xfb, 0x0b, 0xe0, 0xb9, 0x68, 0x08, 0x1a, 0x00, 0x25, 0x78, 0x62,
-0xbd, 0x62, 0x38, 0x1c, 0x00, 0xf0, 0x3c, 0xfc, 0x20, 0x1c, 0x39, 0x1c,
-0x00, 0xf0, 0x64, 0xf8, 0x05, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x0c, 0x2b, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0x01, 0x00, 0x00, 0xc0,
-0xf0, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0x38, 0x6c, 0xf9, 0x6b, 0x0d, 0x18,
-0x21, 0x68, 0x41, 0x18, 0x00, 0x20, 0xa2, 0x69, 0x00, 0x2a, 0x0b, 0xd9,
-0x82, 0x00, 0x56, 0x18, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68,
-0xc0, 0x46, 0xab, 0x50, 0xa2, 0x69, 0x01, 0x30, 0x82, 0x42, 0xf3, 0xd8,
-0x78, 0x6e, 0xf9, 0x6b, 0x09, 0x18, 0x89, 0x89, 0xf0, 0x23, 0x19, 0x40,
-0x09, 0x09, 0x89, 0x00, 0x40, 0x18, 0xf8, 0x60, 0xf9, 0x61, 0x20, 0x68,
-0x01, 0x23, 0x9b, 0x07, 0x08, 0x38, 0x18, 0x43, 0x01, 0x68, 0x78, 0x6c,
-0xfc, 0xf7, 0x95, 0xff, 0x78, 0x64, 0x60, 0x68, 0x01, 0x04, 0x09, 0x0c,
-0xf8, 0x68, 0x81, 0x42, 0x19, 0xd2, 0x39, 0x64, 0x63, 0x68, 0x19, 0x04,
-0x09, 0x0c, 0x40, 0x1a, 0x03, 0x30, 0x80, 0x08, 0x82, 0x00, 0xa0, 0x61,
-0x20, 0x68, 0x09, 0x18, 0x9b, 0x18, 0x63, 0x60, 0xc3, 0x1f, 0x05, 0x3b,
-0x38, 0x1c, 0x00, 0xf0, 0x56, 0xfa, 0x01, 0x20, 0x78, 0x80, 0x20, 0x1c,
-0x00, 0xf0, 0x5e, 0xfb, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xb9, 0x68,
-0x08, 0x1a, 0x78, 0x62, 0x00, 0x20, 0xb8, 0x62, 0x38, 0x1c, 0x00, 0xf0,
-0xd9, 0xfb, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x01, 0xf8, 0xef, 0xe7,
-0xf0, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x0f, 0x1c, 0x8e, 0x48, 0x41, 0x69,
-0x01, 0x31, 0x41, 0x61, 0x03, 0x20, 0x00, 0x07, 0x61, 0x68, 0x08, 0x40,
-0x06, 0x0f, 0x0a, 0x04, 0x12, 0x0c, 0x20, 0x68, 0x11, 0x18, 0xfb, 0x68,
-0xd2, 0x1a, 0x7b, 0x68, 0x9d, 0x1a, 0xc3, 0x1f, 0x05, 0x3b, 0x38, 0x1c,
-0x2a, 0x1c, 0x00, 0xf0, 0x26, 0xfa, 0x00, 0x20, 0x78, 0x80, 0x20, 0x1c,
-0x00, 0xf0, 0x2e, 0xfb, 0x60, 0x68, 0x40, 0x19, 0x01, 0x04, 0x09, 0x0c,
-0x60, 0x60, 0x30, 0x1c, 0x01, 0xf0, 0xe0, 0xfb, 0x7d, 0x4e, 0x0b, 0x23,
-0x1b, 0x02, 0xf0, 0x18, 0x00, 0x69, 0x00, 0x28, 0x19, 0xd0, 0x00, 0x25,
-0x2d, 0x23, 0x9b, 0x01, 0xf0, 0x18, 0xc0, 0x68, 0x00, 0x28, 0x12, 0xd0,
-0xaa, 0x00, 0x92, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xd2, 0x18, 0xd2, 0x68,
-0x20, 0x1c, 0x39, 0x1c, 0x01, 0xf0, 0x1c, 0xfe, 0x01, 0x35, 0xa8, 0x00,
-0x80, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0xc0, 0x68, 0x00, 0x28,
-0xec, 0xd1, 0xf8, 0x6b, 0x01, 0x1f, 0x8a, 0x1c, 0xfa, 0x63, 0xfa, 0x68,
-0x7d, 0x6c, 0x00, 0xf0, 0xbb, 0xf9, 0xc0, 0x43, 0x01, 0x04, 0x09, 0x0c,
-0x28, 0x1c, 0xfc, 0xf7, 0x10, 0xff, 0x03, 0x90, 0xf9, 0x6b, 0x3a, 0x6e,
-0x8e, 0x18, 0x20, 0x68, 0x12, 0x18, 0x01, 0x92, 0x7a, 0x6e, 0x8d, 0x18,
-0x11, 0x18, 0x02, 0x91, 0xc8, 0x1d, 0x09, 0x30, 0xe0, 0x60, 0xb1, 0x88,
-0x08, 0x02, 0x09, 0x0a, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x43, 0x00, 0x04,
-0x00, 0x0c, 0x78, 0x61, 0x68, 0x68, 0x01, 0x0e, 0xff, 0x22, 0x12, 0x04,
-0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 0x02, 0x40,
-0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x08, 0x43, 0x38, 0x61, 0xa8, 0x89,
-0x09, 0x23, 0x1b, 0x02, 0x18, 0x40, 0xb8, 0x61,
-0xa8, 0x89, 0x98, 0x43, 0xa8, 0x81, 0xa8, 0x89, 0x02, 0x99, 0xc0, 0x46,
-0x88, 0x81, 0x00, 0x20, 0x70, 0x80, 0xb0, 0x80, 0x70, 0x81, 0x68, 0x60,
-0x28, 0x82, 0xb9, 0x6e, 0x30, 0x1c, 0xfc, 0xf7, 0xe8, 0xfe, 0x38, 0x86,
-0xfa, 0x69, 0x30, 0x1c, 0x29, 0x1c, 0xfc, 0xf7, 0x03, 0xff, 0x78, 0x86,
-0x3d, 0x8e, 0x78, 0x8e, 0x03, 0x99, 0xfc, 0xf7, 0xc8, 0xfe, 0x00, 0x90,
-0x60, 0x68, 0x00, 0x04, 0x00, 0x0c, 0x39, 0x6e, 0x41, 0x1a, 0x09, 0x04,
-0x09, 0x0c, 0x7a, 0x6e, 0x82, 0x1a, 0x13, 0x04, 0x1b, 0x0c, 0x1a, 0x02,
-0x1b, 0x0a, 0x1a, 0x43, 0x16, 0x04, 0x36, 0x0c, 0xba, 0x68, 0x82, 0x42,
-0x01, 0xd2, 0x00, 0x20, 0x00, 0xe0, 0x10, 0x1a, 0xb8, 0x60, 0x08, 0x02,
-0x09, 0x12, 0x09, 0x06, 0x09, 0x0e, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c,
-0x01, 0x98, 0xc0, 0x46, 0x41, 0x80, 0x28, 0x1c, 0xfc, 0xf7, 0xa3, 0xfe,
-0x05, 0x1c, 0x00, 0x98, 0x31, 0x1c, 0xfc, 0xf7, 0x9e, 0xfe, 0x06, 0x1c,
-0x78, 0x69, 0x00, 0x04, 0x00, 0x0c, 0x01, 0x02, 0x00, 0x0a, 0x08, 0x43,
-0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 0x81, 0x80, 0x28, 0x1c,
-0xfc, 0xf7, 0x8f, 0xfe, 0x79, 0x69, 0x01, 0x31, 0xc0, 0x43, 0x79, 0x61,
-0x01, 0x9a, 0xc0, 0x46, 0x50, 0x81, 0x38, 0x69, 0x01, 0x0e, 0xff, 0x22,
-0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02,
-0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x01, 0x43, 0x30, 0x1c,
-0xfc, 0xf7, 0x77, 0xfe, 0x39, 0x69, 0x7a, 0x68, 0x89, 0x18, 0x39, 0x61,
-0xb9, 0x68, 0x00, 0x29, 0x09, 0xd1, 0x02, 0x99, 0x89, 0x89, 0xba, 0x69,
-0x11, 0x43, 0x02, 0x9a, 0xc0, 0x46, 0x91, 0x81, 0xb9, 0x69, 0xfc, 0xf7,
-0x66, 0xfe, 0x20, 0x82, 0x00, 0x20, 0x60, 0x82, 0xf8, 0x6d, 0x41, 0x08,
-0x16, 0xd3, 0x80, 0x0a, 0x0a, 0xd3, 0x60, 0x68, 0x10, 0x38, 0x01, 0x04,
-0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x21, 0x68, 0xc0, 0x46,
-0x08, 0x82, 0x09, 0xe0, 0x60, 0x68, 0x0c, 0x38, 0x01, 0x04, 0x09, 0x0c,
-0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x21, 0x68, 0xc0, 0x46, 0x88, 0x81,
-0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80,
-0x68, 0x0e, 0x00, 0x80, 0xf1, 0xb5, 0x84, 0xb0, 0x6e, 0x4d, 0x28, 0x69,
-0x01, 0x22, 0x04, 0x99, 0x8a, 0x40, 0x90, 0x43, 0x28, 0x61, 0x04, 0x98,
-0x43, 0x01, 0x18, 0x1a, 0x80, 0x00, 0x16, 0x1c, 0x69, 0x49, 0x44, 0x18,
-0xe0, 0x6b, 0xc0, 0x46, 0x00, 0x90, 0xa0, 0x68, 0x00, 0x28, 0x01, 0xd1,
-0x00, 0x26, 0x26, 0xe0, 0x65, 0x48, 0x41, 0x69, 0x01, 0x31, 0x41, 0x61,
-0x04, 0x98, 0xfc, 0xf7, 0x09, 0xfd, 0x07, 0x1c, 0x03, 0xd1, 0x28, 0x69,
-0x30, 0x43, 0x28, 0x61, 0xb5, 0xe0, 0xa0, 0x68, 0x65, 0x68, 0xa8, 0x42,
-0x00, 0xd2, 0x05, 0x1c, 0xa1, 0x6c, 0xa9, 0x42, 0x16, 0xd2, 0x40, 0x1a,
-0x62, 0x6a, 0x10, 0x1a, 0x00, 0x26, 0x60, 0x62, 0xa6, 0x60, 0xa6, 0x62,
-0x20, 0x88, 0x48, 0x23, 0x18, 0x43, 0x20, 0x80, 0x0d, 0x1c, 0x09, 0xd1,
-0x38, 0x1c, 0xfc, 0xf7, 0x19, 0xfd, 0x03, 0x20, 0x60, 0x80, 0x66, 0x60,
-0x20, 0x1c, 0x00, 0xf0, 0x8d, 0xf9, 0x96, 0xe0, 0xe1, 0x68, 0x38, 0x68,
-0x09, 0x18, 0xc3, 0x1f, 0x05, 0x3b, 0x20, 0x1c, 0x02, 0x39, 0x2a, 0x1c,
-0x00, 0xf0, 0xcd, 0xf8, 0x38, 0x1c, 0x00, 0xf0, 0xd7, 0xf9, 0xe0, 0x68,
-0x46, 0x19, 0x78, 0x68, 0x30, 0x43, 0x78, 0x60, 0x04, 0x98, 0x31, 0x1c,
-0x01, 0xf0, 0x88, 0xfa, 0x21, 0x6e, 0x00, 0x98,
-0x08, 0x18, 0x01, 0x90, 0x70, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x61, 0x6e,
-0x71, 0x1a, 0x0a, 0x04, 0x12, 0x0c, 0x11, 0x02, 0x12, 0x0a, 0x11, 0x43,
-0x09, 0x04, 0x09, 0x0c, 0x02, 0x91, 0x01, 0x02, 0x00, 0x0a, 0x08, 0x43,
-0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46, 0x41, 0x80, 0x20, 0x8e,
-0xfc, 0xf7, 0xcb, 0xfd, 0x06, 0x1c, 0x60, 0x8e, 0x02, 0x99, 0xfc, 0xf7,
-0xc6, 0xfd, 0x03, 0x90, 0x60, 0x69, 0x01, 0x04, 0x09, 0x0c, 0x08, 0x02,
-0x09, 0x0a, 0x08, 0x43, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x98, 0xc0, 0x46,
-0x81, 0x80, 0x30, 0x1c, 0xfc, 0xf7, 0xb7, 0xfd, 0x61, 0x69, 0x01, 0x31,
-0xc0, 0x43, 0x61, 0x61, 0x01, 0x99, 0xc0, 0x46, 0x48, 0x81, 0x60, 0x6e,
-0x00, 0x99, 0x46, 0x18, 0x20, 0x69, 0x01, 0x0e, 0xff, 0x22, 0x12, 0x04,
-0x02, 0x40, 0x12, 0x0a, 0x11, 0x43, 0xff, 0x22, 0x12, 0x02, 0x02, 0x40,
-0x12, 0x02, 0x11, 0x43, 0x00, 0x06, 0x01, 0x43, 0x71, 0x60, 0x03, 0x98,
-0xfc, 0xf7, 0x9b, 0xfd, 0x21, 0x69, 0x49, 0x19, 0x21, 0x61, 0xa1, 0x68,
-0x49, 0x1b, 0xa1, 0x60, 0x06, 0xd1, 0xb1, 0x89, 0xa2, 0x69, 0x11, 0x43,
-0xb1, 0x81, 0xa1, 0x69, 0xfc, 0xf7, 0x8d, 0xfd, 0x38, 0x82, 0x61, 0x6e,
-0x38, 0x68, 0x09, 0x18, 0x0e, 0x31, 0xf9, 0x60, 0xe2, 0x68, 0x00, 0x99,
-0x04, 0x38, 0x00, 0xf0, 0x4c, 0xf8, 0x02, 0x20, 0x78, 0x82, 0xe0, 0x6d,
-0x41, 0x08, 0x16, 0xd3, 0x80, 0x0a, 0x0a, 0xd3, 0x78, 0x68, 0x10, 0x38,
-0x01, 0x04, 0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x39, 0x68,
-0xc0, 0x46, 0xc8, 0x81, 0x09, 0xe0, 0x78, 0x68, 0x0c, 0x38, 0x01, 0x04,
-0x09, 0x0c, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x39, 0x68, 0xc0, 0x46,
-0x48, 0x81, 0x05, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0xd0, 0x2c, 0x00, 0x80, 0x5c, 0x2b, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80,
-0xf7, 0xb5, 0x03, 0x1c, 0x0f, 0x1c, 0x00, 0x20, 0x1c, 0x68, 0x26, 0x04,
-0x31, 0x1c, 0x1d, 0x1d, 0xfc, 0xf7, 0x51, 0xfd, 0x40, 0xc7, 0x02, 0x9a,
-0xd1, 0x1c, 0x89, 0x08, 0x01, 0x39, 0x4a, 0x1e, 0x02, 0x92, 0x00, 0x29,
-0x0d, 0xd0, 0x21, 0x0c, 0x10, 0xcd, 0x22, 0x04, 0x0a, 0x43, 0x11, 0x1c,
-0x16, 0x1c, 0xfc, 0xf7, 0x40, 0xfd, 0x40, 0xc7, 0x02, 0x99, 0x4a, 0x1e,
-0x02, 0x92, 0x00, 0x29, 0xf1, 0xd1, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x80, 0x08, 0x80, 0x00, 0x89, 0x08, 0x89, 0x00, 0x03, 0x32,
-0x93, 0x08, 0x5a, 0x1e, 0x00, 0x2b, 0x05, 0xd0, 0x08, 0xc9, 0x08, 0xc0,
-0x13, 0x1c, 0x01, 0x3a, 0x00, 0x2b, 0xf9, 0xd1, 0x70, 0x47, 0xff, 0xb5,
-0x86, 0xb0, 0x17, 0x1c, 0x00, 0x26, 0x06, 0x98, 0x80, 0x6c, 0xc0, 0x1b,
-0x06, 0x99, 0xc0, 0x46, 0x88, 0x64, 0x01, 0x20, 0xc0, 0x05, 0x06, 0x99,
-0x89, 0x6b, 0xc0, 0x46, 0x01, 0x91, 0x06, 0x99, 0x4c, 0x6b, 0x67, 0xe0,
-0x21, 0x68, 0xc0, 0x46, 0x02, 0x91, 0x61, 0x68, 0xc0, 0x46, 0x03, 0x91,
-0xa1, 0x68, 0xc0, 0x46, 0x04, 0x91, 0x02, 0xa9, 0x49, 0x88, 0xb9, 0x42,
-0x08, 0xd2, 0x02, 0xad, 0x6d, 0x88, 0x02, 0xa9, 0x49, 0x88, 0x7f, 0x1a,
-0x00, 0x21, 0x02, 0xab, 0x59, 0x80, 0x19, 0xe0, 0x02, 0xa9, 0x49, 0x88,
-0xc9, 0x1b, 0x02, 0xab, 0x59, 0x80, 0x3d, 0x1c, 0x00, 0x27, 0x01, 0x21,
-0x49, 0x06, 0x07, 0x9b, 0x9a, 0x07, 0x92, 0x0f, 0x0d, 0xd0, 0xeb, 0x06,
-0xdb, 0x0e, 0x08, 0xd0, 0x1e, 0x2b, 0x08, 0xd3, 0x1e, 0x2b, 0x02, 0xd1,
-0x03, 0x2a, 0x04, 0xd1, 0x01, 0xe0, 0x02, 0x2a,
-0x01, 0xd3, 0x01, 0x26, 0x00, 0x21, 0x29, 0x43, 0x01, 0x43, 0x0a, 0x1c,
-0x00, 0x91, 0x00, 0x20, 0x03, 0x99, 0x04, 0x9a, 0x07, 0x9b, 0x01, 0xf0,
-0x5b, 0xff, 0x07, 0x99, 0x49, 0x19, 0x07, 0x91, 0x00, 0x2e, 0x0a, 0xd0,
-0x1d, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x1d, 0x48, 0x01, 0x6d, 0x42, 0x6d,
-0x00, 0x20, 0x07, 0x9b, 0x01, 0xf0, 0x4c, 0xff, 0x00, 0x26, 0x02, 0xa8,
-0x40, 0x88, 0x00, 0x28, 0x0c, 0xd0, 0x03, 0x98, 0x40, 0x19, 0x03, 0x90,
-0x02, 0x98, 0xc0, 0x46, 0x20, 0x60, 0x03, 0x98, 0xc0, 0x46, 0x60, 0x60,
-0x04, 0x98, 0xc0, 0x46, 0xa0, 0x60, 0x03, 0xe0, 0x01, 0x98, 0x01, 0x38,
-0x01, 0x90, 0x10, 0x34, 0x06, 0x98, 0xc0, 0x46, 0x44, 0x63, 0x01, 0x98,
-0x06, 0x99, 0xc0, 0x46, 0x88, 0x63, 0x00, 0x20, 0x00, 0x2f, 0x02, 0xd0,
-0x01, 0x99, 0x00, 0x29, 0x92, 0xd1, 0x09, 0x4a, 0xc0, 0x46, 0x00, 0x92,
-0x06, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x09, 0x9b, 0x01, 0xf0,
-0x1f, 0xff, 0x0a, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x01, 0x00, 0x00, 0x02, 0x7c, 0x29, 0x00, 0x80, 0x04, 0x00, 0x53, 0x02,
-0x90, 0xb5, 0x0c, 0x1c, 0x07, 0x1c, 0x38, 0x68, 0x01, 0x23, 0x9b, 0x07,
-0x08, 0x38, 0x18, 0x43, 0x01, 0x68, 0x38, 0x8a, 0xfc, 0xf7, 0x85, 0xfc,
-0xc0, 0x43, 0xf9, 0x68, 0xc0, 0x46, 0x08, 0x80, 0x78, 0x8a, 0x39, 0x68,
-0x08, 0x1a, 0x38, 0x60, 0x38, 0x1c, 0x01, 0xf0, 0x8b, 0xf9, 0x38, 0x1c,
-0xfc, 0xf7, 0x8c, 0xfb, 0x20, 0x1c, 0xff, 0xf7, 0x33, 0xfe, 0x90, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x01, 0x88, 0x8a, 0x09, 0x21, 0xd3,
-0xca, 0x09, 0x1f, 0xd2, 0x8a, 0x08, 0x1d, 0xd3, 0x00, 0x21, 0x01, 0x80,
-0x41, 0x80, 0x47, 0x6f, 0x40, 0x6d, 0xfa, 0x1d, 0x19, 0x32, 0x51, 0x71,
-0xfa, 0x6d, 0xc0, 0x46, 0x10, 0x60, 0x3a, 0x6e, 0xc0, 0x46, 0x10, 0x60,
-0x0c, 0x48, 0xc0, 0x46, 0x81, 0x63, 0xc1, 0x6b, 0x49, 0x08, 0x49, 0x00,
-0xc1, 0x63, 0x01, 0x20, 0x00, 0xf0, 0xcc, 0xff, 0x38, 0x1c, 0x00, 0xf0,
-0x6b, 0xff, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0x23, 0x19, 0x43,
-0x01, 0x80, 0x01, 0x88, 0x49, 0x09, 0xf6, 0xd2, 0x00, 0xf0, 0xb0, 0xf8,
-0xf3, 0xe7, 0x00, 0x00, 0xe8, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x07, 0x1c,
-0x10, 0x1c, 0x0d, 0x1c, 0x00, 0x24, 0x5e, 0x1e, 0x00, 0x2b, 0x19, 0xd0,
-0x01, 0x68, 0xc0, 0x46, 0x39, 0x60, 0x41, 0x88, 0x0c, 0x19, 0x41, 0x68,
-0xc0, 0x46, 0x79, 0x60, 0x81, 0x68, 0xc0, 0x46, 0xb9, 0x60, 0xc1, 0x68,
-0xc0, 0x46, 0xf9, 0x60, 0x10, 0x30, 0x10, 0x37, 0xe9, 0x6a, 0x81, 0x42,
-0x02, 0xd8, 0x28, 0x1c, 0x00, 0xf0, 0xec, 0xff, 0x31, 0x1c, 0x01, 0x3e,
-0x00, 0x29, 0xe5, 0xd1, 0x20, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x0a, 0x68, 0x00, 0x2a, 0x01, 0xd1,
-0x08, 0x60, 0x02, 0xe0, 0x4a, 0x68, 0xc0, 0x46, 0xd0, 0x61, 0x48, 0x60,
-0x70, 0x47, 0x00, 0x00, 0xd0, 0x2c, 0x00, 0x80, 0x03, 0x49, 0x08, 0x68,
-0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, 0x0a, 0x60, 0x70, 0x47,
-0xd0, 0x2c, 0x00, 0x80, 0x00, 0x21, 0x81, 0x67, 0x05, 0x49, 0x8a, 0x68,
-0x00, 0x2a, 0x01, 0xd1, 0x88, 0x60, 0x02, 0xe0, 0xca, 0x68, 0xc0, 0x46,
-0x90, 0x67, 0xc8, 0x60, 0x70, 0x47, 0x00, 0x00, 0xd0, 0x2c, 0x00, 0x80,
-0x03, 0x49, 0x88, 0x68, 0x00, 0x28, 0x02, 0xd0, 0x82, 0x6f, 0xc0, 0x46,
-0x8a, 0x60, 0x70, 0x47, 0xd0, 0x2c, 0x00, 0x80,
-0x00, 0xb5, 0x80, 0x20, 0x13, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xff, 0xf7,
-0xd5, 0xff, 0x00, 0x28, 0x1b, 0xd0, 0x03, 0x23, 0x1b, 0x07, 0x41, 0x68,
-0x19, 0x40, 0x0a, 0x0f, 0x51, 0x01, 0x89, 0x1a, 0x89, 0x00, 0x0d, 0x4b,
-0xc9, 0x18, 0x4b, 0x88, 0x00, 0x2b, 0x04, 0xd1, 0x11, 0x1c, 0xff, 0xf7,
-0x3b, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x01, 0x2b, 0x02, 0xd1, 0xff, 0xf7,
-0x05, 0xfc, 0xf8, 0xe7, 0x02, 0x2b, 0xf6, 0xd1, 0xff, 0xf7, 0x4e, 0xfb,
-0xf3, 0xe7, 0x04, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0xee, 0xe7,
-0x00, 0x00, 0x00, 0xb0, 0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40,
-0x00, 0xb5, 0x20, 0x20, 0x0d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xff, 0xf7,
-0xbf, 0xff, 0x00, 0x28, 0x0e, 0xd0, 0x01, 0x88, 0x20, 0x23, 0x19, 0x43,
-0x01, 0x80, 0x01, 0x88, 0x10, 0x23, 0x99, 0x43, 0x01, 0x80, 0x01, 0x88,
-0x09, 0x0a, 0x01, 0xd3, 0xff, 0xf7, 0x2e, 0xff, 0x08, 0xbc, 0x18, 0x47,
-0x03, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0xf8, 0xe7, 0x00, 0x00,
-0x00, 0x00, 0x00, 0xb0, 0xa0, 0x82, 0x20, 0x40, 0x98, 0xb5, 0x07, 0x1c,
-0x22, 0x48, 0xc0, 0x46, 0x00, 0x90, 0x22, 0x48, 0xc3, 0x1d, 0x41, 0x33,
-0x41, 0x6d, 0x82, 0x6d, 0x80, 0x6c, 0x00, 0x03, 0x00, 0x0b, 0x9c, 0x68,
-0x01, 0x23, 0x9b, 0x07, 0x23, 0x43, 0x1b, 0x68, 0x98, 0x42, 0x00, 0xd1,
-0x0c, 0xe0, 0x98, 0x42, 0x03, 0xd9, 0x10, 0x1a, 0x59, 0x1a, 0x41, 0x18,
-0x00, 0xe0, 0x19, 0x1a, 0x01, 0x20, 0x10, 0x29, 0x00, 0xd8, 0x00, 0x20,
-0x00, 0x28, 0x1f, 0xd0, 0x78, 0x6a, 0xf9, 0x6a, 0xc0, 0x46, 0x08, 0x60,
-0xb8, 0x6a, 0xf9, 0x6a, 0xc0, 0x46, 0x48, 0x60, 0x10, 0x4a, 0xc0, 0x46,
-0x00, 0x92, 0xfb, 0x6a, 0x0f, 0x48, 0x42, 0x6d, 0x03, 0x20, 0x39, 0x6a,
-0x01, 0xf0, 0xe2, 0xfd, 0x38, 0x88, 0x10, 0x23, 0x18, 0x43, 0x38, 0x80,
-0x38, 0x88, 0x40, 0x23, 0x98, 0x43, 0x38, 0x80, 0x38, 0x1c, 0xff, 0xf7,
-0x55, 0xff, 0x98, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x38, 0x88, 0x40, 0x23,
-0x18, 0x43, 0x38, 0x80, 0xf7, 0xe7, 0x00, 0x00, 0x55, 0x55, 0x55, 0x55,
-0xa8, 0x03, 0x00, 0x80, 0x08, 0x00, 0x11, 0x02, 0x7c, 0x29, 0x00, 0x80,
-0xb0, 0xb5, 0x40, 0x20, 0x2c, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0,
-0xfd, 0xfe, 0x07, 0x1c, 0x40, 0x68, 0x03, 0x23, 0x1b, 0x07, 0x18, 0x40,
-0x05, 0x0f, 0x68, 0x01, 0x40, 0x1b, 0x80, 0x00, 0x26, 0x49, 0x44, 0x18,
-0x20, 0x88, 0x02, 0x23, 0x18, 0x43, 0x20, 0x80, 0x20, 0x88, 0x41, 0x08,
-0x34, 0xd3, 0x40, 0x08, 0x40, 0x00, 0x20, 0x80, 0xa0, 0x6c, 0xe1, 0x6c,
-0x40, 0x18, 0xa0, 0x64, 0x00, 0x20, 0xe0, 0x64, 0xa1, 0x6b, 0x22, 0x6d,
-0x89, 0x18, 0xa1, 0x63, 0x20, 0x65, 0xb8, 0x6a, 0xc0, 0x46, 0x60, 0x65,
-0x03, 0x23, 0x1b, 0x07, 0x78, 0x68, 0x18, 0x40, 0x78, 0x60, 0x61, 0x68,
-0x36, 0x31, 0x94, 0x29, 0x04, 0xd8, 0x38, 0x23, 0x18, 0x43, 0x78, 0x60,
-0x38, 0x20, 0x03, 0xe0, 0x94, 0x23, 0x18, 0x43, 0x78, 0x60, 0x94, 0x20,
-0xb8, 0x61, 0x39, 0x68, 0x78, 0x68, 0x02, 0x04, 0x12, 0x0c, 0x20, 0x1c,
-0xcb, 0x1f, 0x05, 0x3b, 0xff, 0xf7, 0xd7, 0xfd, 0x02, 0x20, 0x60, 0x80,
-0x38, 0x1c, 0xff, 0xf7, 0xdf, 0xfe, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x38, 0x1c, 0xfc, 0xf7, 0x07, 0xfa, 0x28, 0x01, 0x06, 0x49, 0x40, 0x18,
-0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x41, 0x6b, 0x01, 0x39, 0x41, 0x63,
-0xef, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
-0x5c, 0x2b, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80, 0x90, 0xb5, 0x00, 0x27,
-0x0f, 0x4c, 0x0d, 0xe0, 0x42, 0x6b, 0x01, 0x3a, 0x42, 0x63, 0x00, 0x2a,
-0x05, 0xdc, 0x02, 0x6b, 0xc0, 0x46, 0x42, 0x63, 0xc0, 0x6a, 0x01, 0xf0,
-0xc6, 0xf9, 0x01, 0x37, 0x0b, 0x2f, 0x07, 0xd2, 0x38, 0x01, 0x00, 0x19,
-0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x6a, 0x00, 0x29, 0xe9, 0xd1,
-0x01, 0x20, 0x40, 0x06, 0x03, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x90, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0,
-0x10, 0x48, 0xc1, 0x68, 0x01, 0x31, 0xc1, 0x60, 0x0f, 0x49, 0xc8, 0x68,
-0x01, 0x28, 0x17, 0xd1, 0xc8, 0x1d, 0x79, 0x30, 0x02, 0x89, 0x00, 0x2a,
-0x12, 0xd0, 0x01, 0x3a, 0x02, 0x81, 0x02, 0x89, 0x00, 0x2a, 0x0d, 0xd1,
-0x42, 0x89, 0x00, 0x2a, 0x08, 0xd1, 0xc9, 0x6f, 0x02, 0x23, 0x0a, 0x68,
-0x1a, 0x43, 0x0a, 0x60, 0x04, 0x21, 0x01, 0x81, 0x01, 0x21, 0x00, 0xe0,
-0x00, 0x21, 0x41, 0x81, 0x70, 0x47, 0x00, 0x00, 0x08, 0x83, 0x20, 0x40,
-0x68, 0x0e, 0x00, 0x80, 0xb0, 0xb5, 0x07, 0x1c, 0x01, 0x23, 0xf8, 0x1d,
-0x69, 0x30, 0x03, 0x73, 0x1e, 0x48, 0xc2, 0x1d, 0x79, 0x32, 0x54, 0x8a,
-0x61, 0x1c, 0x51, 0x82, 0xd5, 0x8a, 0x00, 0x21, 0xac, 0x42, 0x04, 0xdb,
-0xc4, 0x1d, 0x89, 0x34, 0x63, 0x70, 0x51, 0x82, 0xd1, 0x83, 0x01, 0x23,
-0x9b, 0x07, 0x3a, 0x6d, 0x1a, 0x43, 0x12, 0x68, 0xc0, 0x46, 0xba, 0x61,
-0xfb, 0x69, 0x9a, 0x42, 0x06, 0xd1, 0xf8, 0x6c, 0x12, 0x49, 0xc0, 0x46,
-0x08, 0x60, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x79, 0x61, 0x41, 0x69,
-0xfa, 0x6c, 0x91, 0x43, 0x41, 0x61, 0x01, 0x20, 0x00, 0x05, 0xc1, 0x60,
-0x38, 0x69, 0x02, 0x28, 0xf1, 0xd0, 0xb8, 0x69, 0xf9, 0x69, 0x41, 0x1a,
-0x01, 0xd5, 0x78, 0x6d, 0x41, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8,
-0xf9, 0x69, 0x09, 0x18, 0xf9, 0x61, 0x78, 0x6d, 0x81, 0x42, 0xe2, 0xd3,
-0x08, 0x1a, 0xf8, 0x61, 0xdf, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0x00, 0x00, 0x00, 0xb0, 0xf8, 0xb5, 0x04, 0x1c, 0x0f, 0x1c, 0xff, 0x23,
-0x21, 0x33, 0x9f, 0x42, 0x01, 0xd9, 0xff, 0x27, 0x21, 0x37, 0xe1, 0x6e,
-0x38, 0x1c, 0x01, 0xf0, 0xcb, 0xfc, 0x2d, 0x4d, 0x00, 0x28, 0x13, 0xd1,
-0xe0, 0x1d, 0x49, 0x30, 0x01, 0x7a, 0x01, 0x23, 0x19, 0x43, 0x01, 0x72,
-0x29, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x29, 0x48, 0x01, 0x6d, 0x42, 0x6d,
-0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0xb0, 0xfc, 0x00, 0x20, 0xf8, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x20, 0x69, 0x01, 0x30, 0x20, 0x61, 0x23, 0x49,
-0xc8, 0x1d, 0xb9, 0x30, 0x02, 0x6b, 0x92, 0x00, 0x51, 0x18, 0xc0, 0x31,
-0x0f, 0x61, 0x01, 0x6b, 0x01, 0x31, 0x89, 0x07, 0x89, 0x0f, 0x01, 0x63,
-0x20, 0x6b, 0xc2, 0x19, 0x61, 0x6d, 0x8a, 0x42, 0x03, 0xd8, 0x23, 0x22,
-0x12, 0x05, 0x3a, 0x43, 0x05, 0xe0, 0x09, 0x1a, 0x7e, 0x1a, 0x07, 0xd1,
-0x23, 0x22, 0x12, 0x05, 0x0a, 0x43, 0x00, 0x92, 0x61, 0x6e, 0x09, 0x18,
-0xa2, 0x6e, 0x10, 0xe0, 0x11, 0x22, 0x52, 0x05, 0x0a, 0x43, 0x00, 0x92,
-0x61, 0x6e, 0x09, 0x18, 0x00, 0x20, 0xa2, 0x6e, 0x2b, 0x1c, 0x01, 0xf0,
-0x7d, 0xfc, 0x23, 0x22, 0x12, 0x05, 0x32, 0x43, 0x00, 0x92, 0x61, 0x6e,
-0xa2, 0x6e, 0x00, 0x20, 0x2b, 0x1c, 0x01, 0xf0, 0x73, 0xfc, 0x20, 0x6b,
-0xc0, 0x19, 0x00, 0x09, 0x00, 0x01, 0x61, 0x6d, 0x81, 0x42, 0x00, 0xd8,
-0x40, 0x1a, 0x20, 0x63, 0x38, 0x1c, 0xb8, 0xe7,
-0x44, 0x80, 0x20, 0x40, 0x04, 0x00, 0x1b, 0x02, 0x7c, 0x29, 0x00, 0x80,
-0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x01, 0x20, 0xc0, 0x03, 0x0d, 0x49,
-0xc0, 0x46, 0x08, 0x60, 0x0c, 0x49, 0xc8, 0x1d, 0x49, 0x30, 0x02, 0x7a,
-0x00, 0x27, 0x00, 0x2a, 0x03, 0xd0, 0x07, 0x72, 0x08, 0x1c, 0xff, 0xf7,
-0x37, 0xff, 0x08, 0x49, 0xc8, 0x1d, 0x49, 0x30, 0x02, 0x7a, 0x00, 0x2a,
-0x03, 0xd0, 0x07, 0x72, 0x08, 0x1c, 0xff, 0xf7, 0x2d, 0xff, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0, 0x64, 0x2d, 0x00, 0x80,
-0xe4, 0x2c, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c, 0x10, 0x20, 0x18, 0x49,
-0xc0, 0x46, 0x08, 0x60, 0xf8, 0x68, 0x01, 0x30, 0xf8, 0x60, 0x16, 0x48,
-0xc4, 0x1d, 0xb9, 0x34, 0x61, 0x6b, 0x89, 0x00, 0x09, 0x18, 0xc0, 0x31,
-0x09, 0x69, 0x7a, 0x68, 0x92, 0x00, 0xd2, 0x19, 0x51, 0x64, 0x61, 0x6b,
-0x89, 0x00, 0x08, 0x18, 0xc0, 0x30, 0x01, 0x69, 0x78, 0x68, 0x80, 0x00,
-0xc0, 0x19, 0xc0, 0x6b, 0x01, 0xf0, 0xa2, 0xfa, 0x01, 0x23, 0x78, 0x68,
-0x58, 0x40, 0x78, 0x60, 0x60, 0x6b, 0x01, 0x30, 0x80, 0x07, 0x80, 0x0f,
-0x60, 0x63, 0xf8, 0x1d, 0x19, 0x30, 0x40, 0x79, 0x00, 0x28, 0x02, 0xd1,
-0x38, 0x1c, 0x00, 0xf0, 0x07, 0xf8, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x07, 0x1c,
-0x39, 0x48, 0xc0, 0x68, 0x00, 0x28, 0x05, 0xd0, 0xb8, 0x6a, 0xc0, 0x68,
-0x80, 0x09, 0x01, 0xd3, 0x02, 0x20, 0x00, 0xe0, 0x78, 0x6f, 0xfc, 0xf7,
-0x59, 0xf8, 0x04, 0x1c, 0x06, 0xd1, 0x01, 0x20, 0xf9, 0x1d, 0x19, 0x31,
-0x08, 0x71, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf8, 0x6c, 0x2f, 0x49,
-0xc0, 0x46, 0x08, 0x60, 0xba, 0x6a, 0x38, 0x1c, 0x21, 0x1c, 0x00, 0xf0,
-0x59, 0xf8, 0x67, 0x62, 0x00, 0x28, 0x03, 0xd1, 0x20, 0x1c, 0x00, 0xf0,
-0x0b, 0xfd, 0xec, 0xe7, 0xf9, 0x6d, 0x09, 0x68, 0x09, 0x18, 0x09, 0x09,
-0x09, 0x01, 0x7a, 0x6d, 0x8a, 0x42, 0x00, 0xd8, 0x89, 0x1a, 0xa1, 0x62,
-0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x4a, 0x6c, 0x00, 0x2a, 0x07, 0xd0,
-0x4a, 0x6c, 0x12, 0x1a, 0x4a, 0x64, 0x80, 0x08, 0x80, 0x00, 0xb9, 0x6a,
-0x08, 0x18, 0xb8, 0x62, 0x38, 0x68, 0xb9, 0x6a, 0x80, 0x00, 0xc0, 0x19,
-0x42, 0x6b, 0x91, 0x42, 0x0e, 0xd3, 0x00, 0x21, 0x41, 0x64, 0xb8, 0x6a,
-0x39, 0x68, 0x89, 0x00, 0xc9, 0x19, 0x49, 0x6b, 0x40, 0x1a, 0xb8, 0x62,
-0xb9, 0x68, 0x89, 0x00, 0xc9, 0x19, 0xc9, 0x6b, 0x40, 0x18, 0xb8, 0x62,
-0xb8, 0x68, 0x81, 0x00, 0xc9, 0x19, 0x49, 0x6c, 0x00, 0x29, 0xb8, 0xd1,
-0xb9, 0x6a, 0xfa, 0x6b, 0x91, 0x42, 0xb4, 0xd0, 0x3a, 0x6c, 0x91, 0x42,
-0xb1, 0xd0, 0x01, 0x23, 0x58, 0x40, 0xb8, 0x60, 0x80, 0x00, 0xc0, 0x19,
-0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf8, 0x68, 0x00, 0x28, 0x01, 0xd0,
-0x01, 0x38, 0xf8, 0x60, 0x38, 0x69, 0x00, 0x28, 0xa1, 0xd0, 0x01, 0x38,
-0x38, 0x61, 0x9e, 0xe7, 0x68, 0x19, 0x00, 0x80, 0x00, 0x00, 0x00, 0xb0,
-0xf7, 0xb5, 0x90, 0xb0, 0x04, 0x1c, 0x0d, 0x1c, 0x00, 0x20, 0x05, 0x90,
-0x02, 0x90, 0x00, 0x22, 0x01, 0x92, 0xf9, 0x48, 0xc0, 0x6a, 0xc0, 0x46,
-0xa8, 0x61, 0xa0, 0x68, 0x81, 0x00, 0x09, 0x19, 0x49, 0x6b, 0xc0, 0x46,
-0x20, 0x60, 0xe1, 0x62, 0x12, 0x9a, 0xd0, 0x68, 0xc0, 0x46, 0xa8, 0x60,
-0x12, 0x9a, 0x51, 0x78, 0xc0, 0x46, 0x0c, 0x91, 0xf0, 0x48, 0xc0, 0x46,
-0x03, 0x90, 0xd7, 0x1d, 0x09, 0x37, 0xe0, 0x6a,
-0xc1, 0x1b, 0x09, 0x09, 0xe3, 0x1d, 0x19, 0x33, 0x0c, 0x9a, 0xc0, 0x46,
-0x0f, 0x93, 0xeb, 0x4b, 0xc0, 0x46, 0x0e, 0x93, 0x91, 0x42, 0x01, 0xd3,
-0xb8, 0x42, 0x21, 0xd8, 0xe1, 0x68, 0x02, 0x29, 0x1e, 0xd2, 0x01, 0x20,
-0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71, 0x00, 0x20, 0x03, 0x99, 0x01, 0xf0,
-0x57, 0xfb, 0x00, 0x28, 0x03, 0xd1, 0x0e, 0x9b, 0xd8, 0x6b, 0x01, 0x30,
-0xd8, 0x63, 0x01, 0x20, 0x80, 0x06, 0x00, 0x27, 0x68, 0x60, 0xaf, 0x61,
-0xdd, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0xdd, 0x48, 0x01, 0x6d, 0x42, 0x6d,
-0xdc, 0x4b, 0x00, 0x20, 0x01, 0xf0, 0x3a, 0xfb, 0x38, 0x1c, 0x5c, 0xe3,
-0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x7b, 0xfc, 0x07, 0x1c,
-0xd7, 0x48, 0xc0, 0x68, 0x00, 0x28, 0x64, 0xd0, 0x38, 0x78, 0x40, 0x07,
-0x40, 0x0f, 0x03, 0x28, 0x60, 0xd1, 0x05, 0x98, 0x01, 0x30, 0x00, 0x06,
-0x00, 0x0e, 0x05, 0x90, 0x38, 0x78, 0xf0, 0x23, 0x18, 0x40, 0x58, 0xd1,
-0xe0, 0x6a, 0xc0, 0x1b, 0x00, 0x09, 0x0c, 0x99, 0x88, 0x42, 0x02, 0xd2,
-0xe0, 0x68, 0x02, 0x28, 0x05, 0xd3, 0xcb, 0x49, 0x88, 0x68, 0x00, 0xf0,
-0x83, 0xff, 0x06, 0x1c, 0x06, 0xd1, 0x03, 0x9b, 0x28, 0x1c, 0x39, 0x1c,
-0x22, 0x1c, 0x00, 0xf0, 0x8b, 0xfc, 0x16, 0xe1, 0x2e, 0x62, 0xf8, 0x68,
-0x00, 0x28, 0x0d, 0xd0, 0xb8, 0x89, 0x00, 0x28, 0x03, 0xd0, 0xc1, 0x49,
-0xc9, 0x68, 0x00, 0xf0, 0x70, 0xff, 0xf8, 0x89, 0x00, 0x28, 0x03, 0xd0,
-0xbd, 0x49, 0xc9, 0x68, 0x00, 0xf0, 0x69, 0xff, 0x7a, 0x68, 0xc0, 0x46,
-0x72, 0x61, 0xb9, 0x68, 0xc0, 0x46, 0xb1, 0x61, 0x30, 0x1c, 0xb8, 0x49,
-0x09, 0x68, 0x00, 0xf0, 0x5e, 0xff, 0x00, 0x28, 0x17, 0xd1, 0x30, 0x1c,
-0xb4, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x57, 0xff, 0x10, 0x37, 0xe0, 0x6a,
-0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x27, 0xfc, 0x07, 0x1c,
-0x68, 0x68, 0xaf, 0x4b, 0x18, 0x43, 0x68, 0x60, 0x00, 0x20, 0xa8, 0x61,
-0xac, 0x23, 0xa8, 0x68, 0x98, 0x43, 0xa8, 0x60, 0xb0, 0xe0, 0xa8, 0x69,
-0xa8, 0x28, 0x01, 0xd2, 0xa8, 0x20, 0xa8, 0x61, 0x10, 0x37, 0xe0, 0x6a,
-0xb8, 0x42, 0x6c, 0xd8, 0x9c, 0xe0, 0xa5, 0xe0, 0xa4, 0xe0, 0x10, 0x28,
-0x68, 0xd1, 0x03, 0x23, 0x1b, 0x07, 0x68, 0x68, 0x18, 0x40, 0x01, 0x0f,
-0x48, 0x01, 0x40, 0x1a, 0x80, 0x00, 0xa0, 0x4a, 0x82, 0x18, 0x01, 0x92,
-0x78, 0x88, 0x42, 0x0b, 0x31, 0xd3, 0x82, 0x0b, 0x2f, 0xd3, 0x9d, 0x48,
-0xc0, 0x46, 0x03, 0x90, 0x02, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x10, 0x80,
-0x78, 0x88, 0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x60,
-0xb8, 0x68, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, 0x01, 0x9a,
-0xc0, 0x46, 0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x64,
-0x01, 0x9a, 0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 0x8f, 0x49, 0x40, 0x18,
-0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, 0x01, 0x9a, 0x50, 0x68, 0x36, 0x30,
-0x94, 0x28, 0x01, 0xd8, 0x38, 0x20, 0x00, 0xe0, 0x94, 0x20, 0xa8, 0x61,
-0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x28, 0xd8, 0x58, 0xe0, 0x7a, 0x88,
-0x92, 0x0b, 0x03, 0xd3, 0x85, 0x48, 0xc0, 0x46, 0x03, 0x90, 0x23, 0xe0,
-0x01, 0x22, 0x12, 0x03, 0x02, 0x40, 0x83, 0x4b, 0x1d, 0xd0, 0x03, 0x93,
-0x00, 0x05, 0x00, 0x0d, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x60, 0xb8, 0x68,
-0x01, 0x9a, 0xc0, 0x46, 0x90, 0x60, 0x78, 0x68, 0x01, 0x9a, 0xc0, 0x46,
-0x10, 0x62, 0x00, 0x20, 0x01, 0x9a, 0xc0, 0x46,
-0x90, 0x64, 0x01, 0x9a, 0xc0, 0x46, 0x90, 0x63, 0x88, 0x02, 0x75, 0x49,
-0x40, 0x18, 0x01, 0x9a, 0xc0, 0x46, 0x50, 0x63, 0x02, 0xe0, 0x33, 0xe0,
-0x2a, 0xe0, 0x03, 0x93, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46, 0x48, 0x71,
-0x12, 0x9a, 0x50, 0x78, 0x05, 0x99, 0x43, 0x1a, 0x0b, 0x93, 0x10, 0x37,
-0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x92, 0xfb,
-0x07, 0x1c, 0x01, 0x9a, 0x50, 0x6b, 0x91, 0x6b, 0x09, 0x01, 0x40, 0x18,
-0x0b, 0x9b, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, 0x7d, 0xfb, 0x01, 0x9a,
-0xc0, 0x46, 0xd0, 0x64, 0x01, 0x9a, 0x0b, 0x9b, 0xc0, 0x46, 0x13, 0x65,
-0x01, 0x23, 0x5b, 0x06, 0x68, 0x68, 0x18, 0x43, 0x68, 0x60, 0x00, 0x20,
-0xa8, 0x61, 0x0d, 0xe0, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8,
-0x20, 0x1c, 0x00, 0xf0, 0x71, 0xfb, 0x07, 0x1c, 0x38, 0x78, 0x40, 0x07,
-0x40, 0x0f, 0x03, 0x28, 0x00, 0xd1, 0xf8, 0xe6, 0xa8, 0x69, 0x03, 0x99,
-0x01, 0xf0, 0x26, 0xfa, 0x00, 0x28, 0x2a, 0xd1, 0x38, 0x1c, 0x21, 0x1c,
-0x00, 0xf0, 0x79, 0xfb, 0xa8, 0x68, 0x80, 0x09, 0x04, 0xd3, 0x30, 0x1c,
-0x49, 0x49, 0x49, 0x68, 0x00, 0xf0, 0x81, 0xfe, 0x41, 0x49, 0x00, 0x20,
-0x01, 0xf0, 0x14, 0xfa, 0x00, 0x28, 0x04, 0xd1, 0x0e, 0x9b, 0xd8, 0x6b,
-0x01, 0x30, 0xd8, 0x63, 0x11, 0xe0, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46,
-0x48, 0x71, 0x80, 0x06, 0x00, 0x27, 0x68, 0x60, 0xaf, 0x61, 0x3a, 0x4a,
-0xc0, 0x46, 0x00, 0x92, 0x39, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x39, 0x4b,
-0x00, 0x20, 0x01, 0xf0, 0xf3, 0xf9, 0x00, 0x20, 0x15, 0xe2, 0x05, 0x98,
-0x0c, 0x99, 0x08, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x0c, 0x90, 0x0b, 0x90,
-0x0c, 0x98, 0x00, 0x28, 0x03, 0xd0, 0x01, 0x20, 0x0f, 0x99, 0xc0, 0x46,
-0x48, 0x71, 0x28, 0x68, 0xc0, 0x46, 0x04, 0x90, 0x00, 0x26, 0x00, 0x20,
-0x08, 0x90, 0x00, 0x22, 0x0a, 0x92, 0x0c, 0x98, 0x01, 0x38, 0x0d, 0x90,
-0xa3, 0xe0, 0x78, 0x88, 0x8a, 0x1b, 0x12, 0x04, 0x12, 0x0c, 0x90, 0x42,
-0x05, 0xdd, 0x07, 0x92, 0x80, 0x1a, 0x00, 0x04, 0x00, 0x0c, 0x08, 0x90,
-0x00, 0xe0, 0x07, 0x90, 0x08, 0x98, 0x00, 0x28, 0x07, 0xd1, 0x0d, 0x98,
-0x0a, 0x9a, 0x90, 0x42, 0x07, 0xdd, 0x07, 0x98, 0x30, 0x18, 0x88, 0x42,
-0x03, 0xd8, 0x01, 0x20, 0x40, 0x05, 0x06, 0x90, 0x1c, 0xe0, 0x11, 0x20,
-0x40, 0x05, 0x06, 0x90, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd1,
-0x20, 0x48, 0xc0, 0x46, 0x06, 0x90, 0xb1, 0x07, 0x89, 0x0f, 0x0f, 0xd0,
-0x07, 0x98, 0xc0, 0x06, 0xc0, 0x0e, 0x08, 0xd0, 0x1e, 0x28, 0x09, 0xdb,
-0x1e, 0x28, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, 0x01, 0xe0, 0x02, 0x29,
-0x02, 0xd3, 0x01, 0x20, 0x02, 0x90, 0xde, 0xe7, 0x0a, 0x9a, 0x00, 0x2a,
-0x04, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x06, 0x98, 0x18, 0x43, 0x06, 0x90,
-0x07, 0x98, 0x06, 0x99, 0x08, 0x43, 0x02, 0x1c, 0x00, 0x90, 0x04, 0x98,
-0x83, 0x19, 0x1d, 0xe0, 0xe8, 0x0e, 0x00, 0x80, 0x01, 0x49, 0xff, 0xff,
-0x28, 0x0f, 0x00, 0x80, 0x04, 0x00, 0x12, 0x02, 0x7c, 0x29, 0x00, 0x80,
-0x44, 0x80, 0x20, 0x40, 0x68, 0x19, 0x00, 0x80, 0x60, 0x04, 0x00, 0x80,
-0x00, 0x00, 0x00, 0x80, 0x5c, 0x2b, 0x00, 0x80, 0x55, 0x32, 0xff, 0xff,
-0xac, 0x5e, 0x21, 0x40, 0x0d, 0x3d, 0xff, 0xff, 0xcd, 0x31, 0xff, 0xff,
-0x00, 0x00, 0x32, 0x02, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0,
-0x6b, 0xf9, 0x07, 0x98, 0x36, 0x18, 0x02, 0x98,
-0x00, 0x28, 0x16, 0xd0, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x04, 0xd1,
-0x09, 0x23, 0x5b, 0x04, 0x06, 0x98, 0x18, 0x43, 0x06, 0x90, 0x06, 0x98,
-0xc2, 0x4a, 0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0xc1, 0x48,
-0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0x51, 0xf9, 0x00, 0x20,
-0x02, 0x90, 0x08, 0x98, 0x00, 0x28, 0x0b, 0xd1, 0x0b, 0x9b, 0x01, 0x3b,
-0x0b, 0x93, 0x10, 0x37, 0xe0, 0x6a, 0xb8, 0x42, 0x0c, 0xd8, 0x20, 0x1c,
-0x00, 0xf0, 0x8a, 0xfa, 0x07, 0x1c, 0x07, 0xe0, 0x78, 0x68, 0x07, 0x9a,
-0x80, 0x18, 0x78, 0x60, 0x78, 0x88, 0x07, 0x9a, 0x80, 0x1a, 0x78, 0x80,
-0x0a, 0x9a, 0x50, 0x1c, 0x02, 0x04, 0x12, 0x0c, 0x0a, 0x92, 0x0c, 0x98,
-0x0a, 0x9a, 0x82, 0x42, 0x03, 0xda, 0xa9, 0x69, 0xb1, 0x42, 0x00, 0xd9,
-0x53, 0xe7, 0xa8, 0x69, 0xb0, 0x42, 0x6b, 0xd1, 0xa8, 0x68, 0x01, 0x09,
-0x69, 0xd2, 0x08, 0x9a, 0x00, 0x2a, 0x56, 0xd0, 0x0c, 0x99, 0x0a, 0x9a,
-0x8a, 0x42, 0x3e, 0xdb, 0xb1, 0x07, 0x89, 0x0f, 0x0c, 0xd0, 0x08, 0x9a,
-0xd2, 0x06, 0xd2, 0x0e, 0x0b, 0xd0, 0x1e, 0x2a, 0x06, 0xdb, 0x1e, 0x2a,
-0x02, 0xd1, 0x03, 0x29, 0x05, 0xd0, 0x01, 0xe0, 0x02, 0x29, 0x02, 0xd2,
-0x02, 0x99, 0x00, 0x29, 0x21, 0xd0, 0x08, 0x9a, 0xc0, 0x46, 0x00, 0x92,
-0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0,
-0x01, 0xf9, 0x08, 0x98, 0x36, 0x18, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40,
-0x02, 0xd0, 0x01, 0x20, 0x40, 0x06, 0x00, 0xe0, 0x92, 0x48, 0x01, 0x22,
-0x02, 0x43, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x8e, 0x48, 0x01, 0x6d,
-0x42, 0x6d, 0x00, 0x20, 0x01, 0xf0, 0xec, 0xf8, 0x00, 0x20, 0x02, 0x90,
-0x15, 0xe0, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20, 0x40, 0x06,
-0x00, 0xe0, 0x88, 0x48, 0x08, 0x9a, 0x02, 0x43, 0x00, 0xe0, 0x08, 0x9a,
-0xc0, 0x46, 0x00, 0x92, 0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d,
-0x06, 0xca, 0x01, 0xf0, 0xd5, 0xf8, 0x08, 0x98, 0x36, 0x18, 0x10, 0x37,
-0xe0, 0x6a, 0xb8, 0x42, 0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0x14, 0xfa,
-0x07, 0x1c, 0x68, 0x68, 0x80, 0x0e, 0x6b, 0xd2, 0x0a, 0x98, 0xc0, 0x46,
-0x09, 0x90, 0x0c, 0x99, 0x88, 0x42, 0x5c, 0xda, 0x0d, 0x98, 0x09, 0x99,
-0x88, 0x42, 0x03, 0xd0, 0x7a, 0x88, 0x1e, 0xe0, 0x5f, 0xe0, 0x5e, 0xe0,
-0x78, 0x88, 0x01, 0x22, 0x52, 0x06, 0x02, 0x43, 0xa9, 0x68, 0x8c, 0x23,
-0x19, 0x40, 0x02, 0xd1, 0x09, 0x23, 0x5b, 0x04, 0x1a, 0x43, 0xb1, 0x07,
-0x89, 0x0f, 0x0e, 0xd0, 0xc3, 0x06, 0xdb, 0x0e, 0x08, 0xd0, 0x1e, 0x2b,
-0x09, 0xdb, 0x1e, 0x2b, 0x02, 0xd1, 0x03, 0x29, 0x05, 0xd1, 0x01, 0xe0,
-0x02, 0x29, 0x02, 0xd3, 0x01, 0x21, 0x02, 0x91, 0x02, 0x1c, 0x09, 0x98,
-0x00, 0x28, 0x02, 0xd1, 0x01, 0x23, 0xdb, 0x05, 0x1a, 0x43, 0x00, 0x92,
-0x04, 0x98, 0x83, 0x19, 0x00, 0x20, 0x3a, 0x1d, 0x06, 0xca, 0x01, 0xf0,
-0x8f, 0xf8, 0x78, 0x88, 0x86, 0x19, 0x10, 0x37, 0x02, 0x98, 0x00, 0x28,
-0x14, 0xd0, 0xa8, 0x68, 0x8c, 0x23, 0x18, 0x40, 0x02, 0xd0, 0x01, 0x20,
-0x40, 0x06, 0x00, 0xe0, 0x57, 0x48, 0x01, 0x22, 0x02, 0x43, 0x00, 0x92,
-0x04, 0x98, 0x83, 0x19, 0x53, 0x48, 0x01, 0x6d, 0x42, 0x6d, 0x00, 0x20,
-0x01, 0xf0, 0x76, 0xf8, 0x00, 0x20, 0x02, 0x90, 0xe0, 0x6a, 0xb8, 0x42,
-0x03, 0xd8, 0x20, 0x1c, 0x00, 0xf0, 0xb6, 0xf9, 0x07, 0x1c, 0x09, 0x98,
-0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x09, 0x90,
-0x0c, 0x99, 0x88, 0x42, 0xa2, 0xdb, 0x68, 0x68, 0x30, 0x43, 0x01, 0x04,
-0x09, 0x0c, 0x68, 0x60, 0xe8, 0x6a, 0x00, 0xf0, 0x7b, 0xfa, 0x28, 0xe0,
-0x27, 0xe0, 0xa8, 0x68, 0x00, 0x09, 0x14, 0xd3, 0x68, 0x68, 0x80, 0x0e,
-0x15, 0xd2, 0x01, 0x9a, 0x00, 0x2a, 0x12, 0xd0, 0x01, 0x9a, 0x50, 0x6b,
-0x0b, 0x9b, 0x21, 0x1c, 0x3a, 0x1c, 0xff, 0xf7, 0x89, 0xf9, 0x01, 0x9a,
-0xc0, 0x46, 0x90, 0x64, 0x01, 0x9a, 0x0b, 0x9b, 0xc0, 0x46, 0x93, 0x63,
-0x03, 0xe0, 0xe8, 0x6a, 0x31, 0x1c, 0x00, 0xf0, 0x5d, 0xfa, 0x68, 0x68,
-0x30, 0x43, 0x68, 0x60, 0xa8, 0x69, 0xb0, 0x42, 0x05, 0xd9, 0x00, 0x04,
-0x00, 0x0c, 0x80, 0x1b, 0x00, 0xf0, 0xee, 0xf9, 0xae, 0x61, 0xa8, 0x68,
-0x8c, 0x23, 0x18, 0x40, 0x0b, 0xd0, 0x2f, 0x4a, 0xc0, 0x46, 0x00, 0x92,
-0x04, 0x98, 0xc3, 0x1f, 0x05, 0x3b, 0x2a, 0x48, 0x01, 0x6d, 0x42, 0x6d,
-0x00, 0x20, 0x01, 0xf0, 0x23, 0xf8, 0x01, 0x23, 0x9b, 0x07, 0x20, 0x6d,
-0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xa0, 0x61, 0xe1, 0x69, 0x81, 0x42,
-0x12, 0xd0, 0x22, 0x69, 0x02, 0x2a, 0x0f, 0xd2, 0x41, 0x1a, 0x01, 0xd5,
-0x60, 0x6d, 0x41, 0x18, 0x20, 0x1c, 0xff, 0xf7, 0x3f, 0xfb, 0xe1, 0x69,
-0x40, 0x18, 0xe0, 0x61, 0x61, 0x6d, 0x88, 0x42, 0x24, 0xd3, 0x40, 0x1a,
-0xe0, 0x61, 0x21, 0xe0, 0x81, 0x42, 0x1f, 0xd1, 0x20, 0x69, 0x02, 0x28,
-0x1c, 0xd2, 0x01, 0x20, 0x60, 0x61, 0x18, 0x48, 0x41, 0x69, 0xe2, 0x6c,
-0x0a, 0x43, 0x42, 0x61, 0x81, 0x69, 0xe3, 0x6c, 0x99, 0x43, 0x81, 0x61,
-0x01, 0x21, 0x09, 0x05, 0xca, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x08, 0x61,
-0x8b, 0x02, 0x20, 0x6d, 0x18, 0x43, 0x00, 0x68, 0xc0, 0x46, 0xa0, 0x61,
-0xe1, 0x69, 0x81, 0x42, 0x02, 0xd0, 0x20, 0x1c, 0xff, 0xf7, 0xcc, 0xfa,
-0x28, 0x1c, 0x00, 0xf0, 0x0f, 0xf9, 0x0c, 0x98, 0x05, 0x99, 0x40, 0x18,
-0x00, 0x01, 0x10, 0x30, 0x68, 0x61, 0x13, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x01, 0x00, 0x00, 0x02, 0x7c, 0x29, 0x00, 0x80,
-0x00, 0x00, 0x12, 0x02, 0x04, 0x00, 0x52, 0x02, 0x68, 0x0e, 0x00, 0x80,
-0xf0, 0xb5, 0x40, 0x20, 0x2d, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x00, 0xf0,
-0x03, 0xf9, 0x07, 0x1c, 0x81, 0x69, 0x44, 0x6a, 0xa0, 0x6f, 0x00, 0xf0,
-0x45, 0xfe, 0x00, 0x20, 0xe1, 0x1d, 0x19, 0x31, 0x48, 0x71, 0x79, 0x68,
-0xc9, 0x0e, 0x09, 0xd3, 0xf8, 0x6a, 0x00, 0x01, 0x24, 0x49, 0x40, 0x18,
-0x24, 0x4b, 0xc0, 0x18, 0x01, 0x68, 0x01, 0x39, 0x01, 0x60, 0x36, 0xe0,
-0xe1, 0x6d, 0x09, 0x68, 0x22, 0x6e, 0xc0, 0x46, 0x11, 0x60, 0x20, 0x4e,
-0xf5, 0x1d, 0x79, 0x35, 0x01, 0x23, 0xe9, 0x6b, 0x19, 0x43, 0xe9, 0x63,
-0xb9, 0x6a, 0xe2, 0x6d, 0xc0, 0x46, 0x11, 0x60, 0xb9, 0x6a, 0x22, 0x6e,
-0xc0, 0x46, 0x11, 0x60, 0x61, 0x69, 0x00, 0x29, 0x04, 0xd1, 0xa9, 0x6b,
-0x01, 0x31, 0xa9, 0x63, 0x08, 0x29, 0x07, 0xd3, 0xa8, 0x63, 0x01, 0x20,
-0x00, 0xf0, 0x86, 0xf8, 0xe8, 0x6b, 0x40, 0x08, 0x40, 0x00, 0xe8, 0x63,
-0x78, 0x68, 0x81, 0x0e, 0x0f, 0xd2, 0x0b, 0x23, 0x1b, 0x02, 0xf1, 0x18,
-0xc9, 0x68, 0x00, 0x29, 0x06, 0xd0, 0x00, 0x08, 0x04, 0xd2, 0x20, 0x1c,
-0x39, 0x1c, 0x00, 0xf0, 0x43, 0xf8, 0x02, 0xe0, 0x38, 0x1c, 0x00, 0xf0,
-0x05, 0xfa, 0x38, 0x1c, 0xfb, 0xf7, 0x06, 0xfc, 0x20, 0x1c, 0x00, 0xf0,
-0x0b, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0xb0,
-0xa0, 0x1c, 0x00, 0x80, 0xb4, 0x0c, 0x00, 0x00,
-0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x07, 0x1c, 0xf8, 0x1d, 0x19, 0x30,
-0x01, 0x79, 0x00, 0x29, 0x04, 0xd0, 0x00, 0x21, 0x01, 0x71, 0x38, 0x1c,
-0xff, 0xf7, 0x56, 0xfb, 0xf8, 0x68, 0x02, 0x28, 0x0d, 0xd0, 0xb8, 0x68,
-0x80, 0x00, 0xc2, 0x19, 0x50, 0x6c, 0x00, 0x28, 0x11, 0xd0, 0xb8, 0x6a,
-0x41, 0x78, 0x09, 0x01, 0x10, 0x31, 0x52, 0x6b, 0x10, 0x1a, 0x88, 0x42,
-0x05, 0xd3, 0x38, 0x1c, 0xff, 0xf7, 0x42, 0xfb, 0x80, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x38, 0x1c, 0xff, 0xf7, 0x28, 0xfa, 0xf8, 0xe7, 0x78, 0x68,
-0x80, 0x00, 0xc0, 0x19, 0xc0, 0x6b, 0xc0, 0x46, 0xb8, 0x62, 0xf1, 0xe7,
-0xb0, 0xb5, 0x87, 0xb0, 0x0f, 0x1c, 0x80, 0x6f, 0xc0, 0x46, 0x00, 0x90,
-0x00, 0x24, 0x13, 0x4d, 0x0b, 0x23, 0x1b, 0x02, 0xe8, 0x18, 0x80, 0x69,
-0x00, 0x28, 0x17, 0xd0, 0x69, 0x46, 0xa2, 0x00, 0x52, 0x19, 0x0b, 0x23,
-0x1b, 0x02, 0xd2, 0x18, 0x92, 0x69, 0x38, 0x1c, 0x00, 0xf0, 0x92, 0xfb,
-0x00, 0x28, 0x09, 0xd1, 0x01, 0x34, 0xa0, 0x00, 0x40, 0x19, 0x0b, 0x23,
-0x1b, 0x02, 0xc0, 0x18, 0x80, 0x69, 0x00, 0x28, 0xea, 0xd1, 0x01, 0xe0,
-0x01, 0x28, 0x02, 0xd0, 0x38, 0x1c, 0x00, 0xf0, 0x9d, 0xf9, 0x07, 0xb0,
-0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0xb8, 0xb5, 0xc2, 0x07, 0xd2, 0x0f, 0x16, 0x4c, 0x16, 0x49, 0x01, 0xd0,
-0x08, 0x22, 0x08, 0xe0, 0x82, 0x08, 0x05, 0xd3, 0x0c, 0x22, 0xa4, 0x18,
-0x0b, 0x68, 0xdf, 0x1d, 0x15, 0x37, 0x03, 0xe0, 0x1c, 0x22, 0x0b, 0x68,
-0xdf, 0x1d, 0x09, 0x37, 0x0f, 0x4b, 0x1d, 0x78, 0x00, 0x2d, 0x13, 0xd0,
-0x5b, 0x78, 0x00, 0x2b, 0x10, 0xd0, 0x01, 0x23, 0x5b, 0x06, 0x1a, 0x43,
-0x00, 0x28, 0x01, 0xd1, 0x5b, 0x08, 0x1a, 0x43, 0x00, 0x92, 0x4a, 0x68,
-0x01, 0x20, 0x39, 0x1c, 0x23, 0x1c, 0x00, 0xf0, 0xdf, 0xfe, 0xb8, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x03, 0x23, 0x1b, 0x06, 0x1a, 0x43, 0xf1, 0xe7,
-0x90, 0xee, 0x20, 0x40, 0x7c, 0x29, 0x00, 0x80, 0xf8, 0x0e, 0x00, 0x80,
-0x00, 0x21, 0xc1, 0x61, 0x05, 0x49, 0x8a, 0x68, 0x00, 0x2a, 0x01, 0xd1,
-0x88, 0x60, 0x02, 0xe0, 0xca, 0x68, 0xc0, 0x46, 0xd0, 0x61, 0xc8, 0x60,
-0x70, 0x47, 0x00, 0x00, 0x28, 0x0f, 0x00, 0x80, 0x03, 0x49, 0x88, 0x68,
-0x00, 0x28, 0x02, 0xd0, 0xc2, 0x69, 0xc0, 0x46, 0x8a, 0x60, 0x70, 0x47,
-0x28, 0x0f, 0x00, 0x80, 0x01, 0x1c, 0x01, 0x23, 0x88, 0x68, 0x58, 0x40,
-0x88, 0x60, 0xca, 0x68, 0x01, 0x3a, 0xca, 0x60, 0x0a, 0x69, 0x01, 0x3a,
-0x80, 0x00, 0x0a, 0x61, 0x42, 0x18, 0xd0, 0x6b, 0x53, 0x6b, 0xc0, 0x46,
-0xcb, 0x62, 0x0b, 0x68, 0x9b, 0x00, 0x59, 0x18, 0x49, 0x6c, 0x53, 0x6c,
-0xc9, 0x18, 0x51, 0x64, 0x70, 0x47, 0x8a, 0x68, 0x92, 0x00, 0x52, 0x18,
-0xd3, 0x6b, 0x83, 0x42, 0x17, 0xd1, 0xd0, 0x1d, 0x3d, 0x30, 0x0a, 0x68,
-0x92, 0x00, 0x52, 0x18, 0x52, 0x6c, 0x03, 0x68, 0x9a, 0x1a, 0x02, 0x60,
-0x01, 0x23, 0x88, 0x68, 0x58, 0x40, 0x88, 0x60, 0xca, 0x68, 0x01, 0x32,
-0xca, 0x60, 0x0a, 0x69, 0x01, 0x32, 0x80, 0x00, 0x40, 0x18, 0x0a, 0x61,
-0x40, 0x6b, 0xc0, 0x46, 0xc8, 0x62, 0x70, 0x47, 0xb8, 0xb5, 0x04, 0x1c,
-0x1d, 0x1c, 0x17, 0x1c, 0x08, 0x1c, 0x39, 0x1c, 0xff, 0xf7, 0xd9, 0xff,
-0x00, 0x20, 0x29, 0x1c, 0x00, 0xf0, 0x7c, 0xfe, 0x01, 0x20, 0xf9, 0x1d,
-0x19, 0x31, 0x48, 0x71, 0x80, 0x06, 0x60, 0x60, 0x00, 0x20, 0xa0, 0x61,
-0x06, 0x4a, 0xc0, 0x46, 0x00, 0x92, 0x06, 0x48,
-0x01, 0x6d, 0x42, 0x6d, 0x05, 0x4b, 0x00, 0x20, 0x00, 0xf0, 0x62, 0xfe,
-0xb8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x04, 0x00, 0x12, 0x02,
-0x7c, 0x29, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40, 0x06, 0x49, 0x0a, 0x68,
-0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9,
-0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0x00, 0x00,
-0xe4, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40, 0x80, 0x08, 0x80, 0x00,
-0x06, 0x49, 0x0a, 0x68, 0x10, 0x18, 0x08, 0x60, 0x01, 0x23, 0x5b, 0x02,
-0x98, 0x42, 0x03, 0xd9, 0x03, 0x49, 0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71,
-0x70, 0x47, 0x00, 0x00, 0xe4, 0x2d, 0x00, 0x80, 0xa0, 0x82, 0x20, 0x40,
-0x03, 0x30, 0x80, 0x08, 0x80, 0x00, 0x06, 0x49, 0x0a, 0x68, 0x10, 0x18,
-0x08, 0x60, 0x01, 0x23, 0x5b, 0x02, 0x98, 0x42, 0x03, 0xd9, 0x03, 0x49,
-0x0a, 0x79, 0x01, 0x32, 0x0a, 0x71, 0x70, 0x47, 0xe4, 0x2d, 0x00, 0x80,
-0xa0, 0x82, 0x20, 0x40, 0x02, 0x48, 0x41, 0x79, 0x01, 0x31, 0x41, 0x71,
-0x70, 0x47, 0x00, 0x00, 0xa0, 0x82, 0x20, 0x40, 0x90, 0xb4, 0x82, 0x00,
-0x17, 0x4b, 0x9a, 0x58, 0x8b, 0x07, 0x02, 0xd0, 0x89, 0x08, 0x0b, 0x1d,
-0x01, 0xe0, 0x89, 0x08, 0xcb, 0x1c, 0x11, 0x69, 0xd7, 0x68, 0x12, 0x4c,
-0x80, 0x00, 0x20, 0x58, 0x40, 0x68, 0xb9, 0x42, 0x03, 0xd1, 0x81, 0x42,
-0x19, 0xd9, 0x11, 0x68, 0x17, 0xe0, 0x00, 0x24, 0xb9, 0x42, 0x09, 0xd9,
-0x81, 0x42, 0x12, 0xd9, 0x11, 0x68, 0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30,
-0x80, 0x10, 0x98, 0x42, 0x0b, 0xd8, 0x07, 0xe0, 0x81, 0x42, 0x05, 0xd8,
-0x78, 0x1a, 0x00, 0xd5, 0x03, 0x30, 0x80, 0x10, 0x98, 0x42, 0x02, 0xd8,
-0x20, 0x1c, 0x90, 0xbc, 0x70, 0x47, 0xc8, 0x1d, 0x05, 0x30, 0xfa, 0xe7,
-0x70, 0x04, 0x00, 0x80, 0x80, 0xb5, 0x80, 0x00, 0x0f, 0x4a, 0x17, 0x58,
-0x88, 0x07, 0x02, 0xd0, 0x88, 0x08, 0x04, 0x30, 0x01, 0xe0, 0x88, 0x08,
-0x03, 0x30, 0x39, 0x69, 0x7a, 0x68, 0x91, 0x42, 0x09, 0xd9, 0x39, 0x68,
-0xc0, 0x46, 0x39, 0x61, 0xf9, 0x68, 0x7a, 0x68, 0x91, 0x42, 0x02, 0xd9,
-0x39, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x81, 0x00, 0x38, 0x69, 0x00, 0xf0,
-0xd1, 0xfd, 0x38, 0x61, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x70, 0x04, 0x00, 0x80, 0x90, 0xb5, 0x03, 0x21, 0x09, 0x07, 0x01, 0x40,
-0x0c, 0x0f, 0x01, 0x04, 0x09, 0x0c, 0x01, 0x22, 0x92, 0x07, 0x02, 0x40,
-0xa3, 0x00, 0x1c, 0x4f, 0xff, 0x58, 0x89, 0x07, 0x89, 0x0f, 0x00, 0x04,
-0x00, 0x0c, 0x80, 0x08, 0x00, 0x29, 0x00, 0xd0, 0x01, 0x30, 0x00, 0x2a,
-0x01, 0xd0, 0x02, 0x30, 0x00, 0xe0, 0x03, 0x30, 0xf9, 0x68, 0x7a, 0x68,
-0x91, 0x42, 0x02, 0xd9, 0x39, 0x68, 0xc0, 0x46, 0xf9, 0x60, 0x81, 0x00,
-0xf8, 0x68, 0x00, 0xf0, 0xa5, 0xfd, 0xf8, 0x60, 0x0f, 0x48, 0x00, 0x69,
-0x00, 0x28, 0x05, 0xd0, 0x01, 0x20, 0xa0, 0x40, 0x02, 0xd0, 0x20, 0x1c,
-0xfe, 0xf7, 0xca, 0xfc, 0x0b, 0x49, 0xc8, 0x1d, 0x19, 0x30, 0x03, 0x79,
-0x00, 0x22, 0x00, 0x2b, 0x05, 0xd1, 0x09, 0x49, 0xc8, 0x1d, 0x19, 0x30,
-0x03, 0x79, 0x00, 0x2b, 0x03, 0xd0, 0x02, 0x71, 0x08, 0x1c, 0xff, 0xf7,
-0x79, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x04, 0x00, 0x80,
-0xd0, 0x2c, 0x00, 0x80, 0x64, 0x2d, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80,
-0xb0, 0xb5, 0x2b, 0x49, 0x09, 0x79, 0x00, 0x29, 0x03, 0xd1, 0x41, 0x68,
-0x29, 0x4b, 0x19, 0x43, 0x41, 0x60, 0x81, 0x68,
-0x49, 0x08, 0x02, 0xd3, 0x09, 0x21, 0x09, 0x04, 0x01, 0xe0, 0x0d, 0x21,
-0x09, 0x04, 0x0c, 0xc8, 0x08, 0x38, 0x19, 0x43, 0x87, 0x68, 0xbb, 0x0a,
-0x03, 0xd3, 0x43, 0x68, 0x5b, 0x08, 0x00, 0xd3, 0x01, 0x31, 0x40, 0x68,
-0x03, 0x23, 0x1b, 0x07, 0x18, 0x40, 0x07, 0x0f, 0xf8, 0x00, 0x1d, 0x4c,
-0x00, 0x19, 0x23, 0x68, 0xc0, 0x18, 0x50, 0x30, 0x00, 0x79, 0x01, 0x28,
-0x10, 0xd1, 0x60, 0x68, 0x01, 0x28, 0x0d, 0xd0, 0x10, 0x1c, 0x00, 0xf0,
-0x71, 0xf8, 0x38, 0x01, 0x00, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18,
-0x41, 0x6b, 0x01, 0x39, 0x41, 0x63, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x38, 0x01, 0x00, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x03, 0x6b,
-0x5d, 0x1c, 0x05, 0x63, 0xbd, 0x02, 0x2d, 0x19, 0xdb, 0x00, 0xeb, 0x18,
-0x80, 0x33, 0x19, 0x63, 0xda, 0x62, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63,
-0x01, 0x21, 0xb9, 0x40, 0x22, 0x68, 0x11, 0x43, 0x21, 0x60, 0x01, 0x6b,
-0x80, 0x29, 0xe2, 0xd3, 0x00, 0x21, 0x01, 0x63, 0xdf, 0xe7, 0x00, 0x00,
-0x28, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80,
-0xf0, 0xb5, 0x1f, 0x4e, 0x70, 0x68, 0x00, 0x28, 0x36, 0xd1, 0x00, 0x24,
-0xb1, 0x68, 0x48, 0x1c, 0xc9, 0x00, 0x89, 0x19, 0xb0, 0x60, 0x32, 0x68,
-0x89, 0x18, 0x60, 0x31, 0x0d, 0x7b, 0x08, 0x28, 0x00, 0xd3, 0xb4, 0x60,
-0x28, 0x01, 0x80, 0x19, 0x19, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x87, 0x6b,
-0x00, 0x2f, 0x21, 0xd0, 0xc1, 0x6a, 0x4b, 0x1c, 0xaa, 0x02, 0x92, 0x19,
-0xc9, 0x00, 0x51, 0x18, 0x80, 0x31, 0xc3, 0x62, 0xca, 0x6a, 0x09, 0x6b,
-0x01, 0x3f, 0x87, 0x63, 0x80, 0x2b, 0x00, 0xd3, 0xc4, 0x62, 0x00, 0x2f,
-0x06, 0xd1, 0x01, 0x27, 0xaf, 0x40, 0x3b, 0x1c, 0xdb, 0x43, 0x37, 0x68,
-0x3b, 0x40, 0x33, 0x60, 0x43, 0x6b, 0x01, 0x3b, 0x43, 0x63, 0x10, 0x1c,
-0x37, 0x1c, 0x00, 0xf0, 0x09, 0xf8, 0x78, 0x68, 0x00, 0x28, 0xc9, 0xd0,
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xa0, 0x1c, 0x00, 0x80,
-0xf0, 0xb5, 0xcd, 0x0f, 0xed, 0x07, 0x01, 0x24, 0x00, 0x27, 0x2e, 0x4b,
-0x2e, 0x4a, 0x00, 0x2d, 0x1d, 0xd0, 0xd8, 0x6a, 0x01, 0x30, 0xd8, 0x62,
-0x10, 0x1c, 0x52, 0x69, 0x00, 0x2a, 0x12, 0xd0, 0x02, 0x69, 0x53, 0x1c,
-0x92, 0x00, 0x12, 0x18, 0x03, 0x61, 0x91, 0x61, 0x41, 0x69, 0x01, 0x31,
-0x41, 0x61, 0x02, 0x69, 0x0f, 0x2a, 0x00, 0xd3, 0x07, 0x61, 0x0f, 0x29,
-0x00, 0xd3, 0x44, 0x60, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x08, 0x1c,
-0xff, 0xf7, 0xee, 0xfe, 0xf8, 0xe7, 0x15, 0x69, 0x6e, 0x1c, 0xad, 0x00,
-0xad, 0x18, 0x16, 0x61, 0xa9, 0x61, 0x55, 0x69, 0x01, 0x35, 0x55, 0x61,
-0x16, 0x69, 0x0f, 0x2e, 0x00, 0xd3, 0x17, 0x61, 0x0f, 0x2d, 0x00, 0xd3,
-0x54, 0x60, 0x8c, 0x02, 0xa4, 0x0a, 0x16, 0x4f, 0x3a, 0x6f, 0xfd, 0x68,
-0xf9, 0x1d, 0x79, 0x31, 0x01, 0x2d, 0x0c, 0xd1, 0xdb, 0x6d, 0x5b, 0x08,
-0x09, 0xd3, 0x0b, 0x89, 0x00, 0x2b, 0x06, 0xd1, 0xfd, 0x6f, 0x03, 0x3b,
-0x2e, 0x68, 0x33, 0x40, 0x2b, 0x60, 0x14, 0x23, 0x0b, 0x81, 0x10, 0x60,
-0x80, 0x07, 0x80, 0x0a, 0x20, 0x43, 0x03, 0x04, 0x00, 0xd0, 0x01, 0x38,
-0x50, 0x60, 0x09, 0x6a, 0x08, 0x32, 0x91, 0x42, 0x00, 0xd8, 0x07, 0x4a,
-0x00, 0x0d, 0x02, 0xd3, 0x51, 0x20, 0x80, 0x03, 0x82, 0x61, 0x3a, 0x67,
-0xbe, 0xe7, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0xa0, 0x1c, 0x00, 0x80,
-0x68, 0x0e, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40,
-0xb0, 0xb5, 0x00, 0x28, 0x04, 0xd1, 0x01, 0x20, 0xc0, 0x05, 0x16, 0x49,
-0xc0, 0x46, 0x08, 0x60, 0x15, 0x4c, 0x00, 0x25, 0x67, 0x69, 0x00, 0x2f,
-0x16, 0xd0, 0xe0, 0x68, 0x41, 0x1c, 0x80, 0x00, 0x00, 0x19, 0xe1, 0x60,
-0x80, 0x69, 0x01, 0x3f, 0xff, 0xf7, 0x94, 0xfe, 0xe0, 0x68, 0x0f, 0x28,
-0x00, 0xd3, 0xe5, 0x60, 0xe0, 0x68, 0x80, 0x00, 0x00, 0x19, 0x80, 0x69,
-0x00, 0x08, 0x01, 0xd3, 0x00, 0x2f, 0xea, 0xd1, 0x67, 0x61, 0x03, 0xe0,
-0x08, 0x48, 0x01, 0x6d, 0x01, 0x31, 0x01, 0x65, 0x65, 0x60, 0x20, 0x68,
-0x00, 0x28, 0x01, 0xd0, 0xff, 0xf7, 0x26, 0xff, 0xb0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa0, 0x1c, 0x00, 0x80,
-0xa0, 0x82, 0x20, 0x40, 0x00, 0x20, 0x70, 0x47, 0xb0, 0xb4, 0x10, 0x23,
-0x82, 0x68, 0x13, 0x40, 0x00, 0x21, 0x00, 0x2b, 0x15, 0xd0, 0x0c, 0x4b,
-0x1a, 0x40, 0x12, 0x01, 0x81, 0x24, 0x14, 0x43, 0x02, 0x68, 0x15, 0x68,
-0x13, 0x1d, 0x80, 0xcb, 0x1b, 0x68, 0x04, 0x3a, 0x02, 0x60, 0x20, 0xc2,
-0x80, 0xc2, 0x08, 0xc2, 0x14, 0x60, 0x42, 0x68, 0x01, 0x23, 0x9b, 0x07,
-0x04, 0x32, 0x1a, 0x43, 0x42, 0x60, 0x08, 0x1c, 0xb0, 0xbc, 0x70, 0x47,
-0x00, 0xf0, 0xff, 0x0f, 0xf0, 0xb4, 0x82, 0x68, 0x53, 0x09, 0x34, 0xd3,
-0x1b, 0x4b, 0x1a, 0x40, 0x12, 0x01, 0x81, 0x26, 0x16, 0x43, 0x03, 0x68,
-0x1d, 0x68, 0x1f, 0x1d, 0x10, 0xcf, 0x3f, 0x68, 0x04, 0x3b, 0x03, 0x60,
-0x20, 0xc3, 0x10, 0xc3, 0x80, 0xc3, 0x1e, 0x60, 0x43, 0x68, 0x1f, 0x1d,
-0x01, 0x23, 0x9b, 0x07, 0x3b, 0x43, 0x43, 0x60, 0xcb, 0x6b, 0x18, 0x1f,
-0xc8, 0x63, 0x80, 0xcb, 0x80, 0xc0, 0x1c, 0x68, 0x1f, 0x1d, 0x03, 0x1d,
-0x04, 0x60, 0x38, 0x1c, 0x3f, 0x68, 0xc0, 0x46, 0x1f, 0x60, 0x1f, 0x1d,
-0x43, 0x68, 0x1c, 0x04, 0x24, 0x0c, 0x81, 0x23, 0x23, 0x43, 0x3b, 0x60,
-0x40, 0x68, 0x00, 0x0c, 0x00, 0x04, 0x10, 0x43, 0x78, 0x60, 0x08, 0x6e,
-0x04, 0x30, 0x08, 0x66, 0x48, 0x6e, 0x04, 0x30, 0x48, 0x66, 0x00, 0x20,
-0xf0, 0xbc, 0x70, 0x47, 0x00, 0xf0, 0xff, 0x0f, 0x80, 0xb4, 0x81, 0x6a,
-0x01, 0x23, 0x9b, 0x07, 0xca, 0x1d, 0x05, 0x32, 0x1a, 0x43, 0x12, 0x68,
-0xcf, 0x1d, 0x01, 0x37, 0x3b, 0x43, 0x1b, 0x68, 0xc0, 0x46, 0xcb, 0x60,
-0x01, 0x23, 0x9b, 0x07, 0x0f, 0x1d, 0x3b, 0x43, 0x1b, 0x68, 0xc0, 0x46,
-0x8b, 0x60, 0x01, 0x23, 0x9b, 0x07, 0x0b, 0x43, 0x1b, 0x68, 0x0c, 0xc1,
-0x02, 0x62, 0x01, 0x6b, 0xc0, 0x46, 0x0a, 0x62, 0x04, 0x23, 0x81, 0x69,
-0x19, 0x43, 0x81, 0x61, 0x02, 0x6b, 0xc0, 0x46, 0x91, 0x61, 0x81, 0x6a,
-0x04, 0x31, 0x81, 0x62, 0x02, 0x6b, 0xc0, 0x46, 0x91, 0x62, 0xc1, 0x1d,
-0x39, 0x31, 0x4a, 0x8b, 0x04, 0x3a, 0x4a, 0x83, 0x49, 0x8b, 0x02, 0x6b,
-0x40, 0x32, 0x51, 0x83, 0xc1, 0x89, 0x04, 0x39, 0xc1, 0x81, 0xc1, 0x68,
-0x00, 0x6b, 0xc0, 0x46, 0xc1, 0x60, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47,
-0x00, 0x47, 0x08, 0x47, 0x10, 0x47, 0x18, 0x47, 0x20, 0x47, 0x28, 0x47,
-0x30, 0x47, 0x38, 0x47, 0x30, 0x40, 0x2d, 0xe9, 0x0c, 0xc0, 0x9d, 0xe5,
-0x0c, 0x48, 0xa0, 0xe1, 0x24, 0x48, 0xb0, 0xe1, 0x1e, 0x00, 0x00, 0x0a,
-0x01, 0xc0, 0x4c, 0xe2, 0x18, 0x40, 0xa0, 0xe3, 0x64, 0x51, 0x9f, 0xe5,
-0x94, 0x50, 0x20, 0xe0, 0x00, 0x50, 0x90, 0xe5, 0x14, 0x40, 0x90, 0xe5,
-0x00, 0x30, 0x85, 0xe5, 0x04, 0xc0, 0x85, 0xe5, 0x08, 0x10, 0x85, 0xe5,
-0x0c, 0x20, 0x85, 0xe5, 0x10, 0x10, 0x90, 0xe5,
-0x10, 0x50, 0x85, 0xe2, 0x01, 0x00, 0x55, 0xe1, 0x0c, 0x50, 0x90, 0x55,
-0x04, 0x00, 0x55, 0xe1, 0x05, 0x00, 0x00, 0x0a, 0x04, 0x10, 0x90, 0xe5,
-0x00, 0x50, 0x80, 0xe5, 0x00, 0x50, 0x81, 0xe5, 0x00, 0x00, 0xa0, 0xe3,
-0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x00, 0x30, 0x93, 0xe5,
-0x08, 0x20, 0x90, 0xe5, 0x01, 0x31, 0x83, 0xe3, 0x02, 0x36, 0x83, 0xe3,
-0x03, 0x00, 0x55, 0xe1, 0x14, 0x30, 0x80, 0xe5, 0xf2, 0xff, 0xff, 0x1a,
-0x01, 0x00, 0xa0, 0xe3, 0xf4, 0xff, 0xff, 0xea, 0x01, 0x06, 0x1c, 0xe3,
-0xf1, 0xff, 0xff, 0x0a, 0xec, 0x10, 0x9f, 0xe5, 0x02, 0xc6, 0xcc, 0xe3,
-0x54, 0x20, 0x91, 0xe5, 0xe4, 0x30, 0x9f, 0xe5, 0x50, 0x10, 0x91, 0xe5,
-0xd9, 0xff, 0xff, 0xea, 0xf0, 0x47, 0x2d, 0xe9, 0x20, 0xc0, 0x9d, 0xe5,
-0x0c, 0x68, 0xa0, 0xe1, 0x26, 0x68, 0xb0, 0xe1, 0x25, 0x00, 0x00, 0x0a,
-0x18, 0x40, 0xa0, 0xe3, 0xb8, 0x50, 0x9f, 0xe5, 0x94, 0x00, 0x00, 0xe0,
-0x05, 0x00, 0x80, 0xe0, 0x08, 0x40, 0x90, 0xe5, 0x04, 0x80, 0x90, 0xe5,
-0x00, 0x70, 0xa0, 0xe3, 0x1f, 0xc0, 0xa0, 0xe3, 0x02, 0xc4, 0x8c, 0xe3,
-0x00, 0x50, 0x90, 0xe5, 0x10, 0x90, 0x90, 0xe5, 0x14, 0xa0, 0x90, 0xe5,
-0x00, 0x30, 0x85, 0xe5, 0x04, 0xc0, 0x85, 0xe5, 0x08, 0x10, 0x85, 0xe5,
-0x0c, 0x20, 0x85, 0xe5, 0x10, 0x50, 0x85, 0xe2, 0x09, 0x00, 0x55, 0xe1,
-0x0c, 0x50, 0x90, 0x55, 0x0a, 0x00, 0x55, 0xe1, 0x15, 0x00, 0x00, 0x0a,
-0x03, 0x70, 0x17, 0xe2, 0x20, 0x10, 0x81, 0xe2, 0x20, 0x30, 0x83, 0xe2,
-0x0a, 0x00, 0x00, 0x0a, 0x00, 0x60, 0x96, 0xe2, 0x01, 0x70, 0x87, 0xe2,
-0x09, 0x00, 0x00, 0x0a, 0x20, 0x60, 0x46, 0xe2, 0x20, 0x00, 0x56, 0xe3,
-0xec, 0xff, 0xff, 0xca, 0x00, 0x70, 0xa0, 0xe3, 0x01, 0xc0, 0x46, 0xe2,
-0x02, 0xc4, 0x8c, 0xe3, 0x00, 0x60, 0xa0, 0xe3, 0xe7, 0xff, 0xff, 0xea,
-0x00, 0x50, 0x88, 0xe5, 0xf2, 0xff, 0xff, 0xea, 0x00, 0x10, 0xa0, 0xe3,
-0x00, 0x50, 0x80, 0xe5, 0x01, 0x00, 0xa0, 0xe1, 0xf0, 0x47, 0xbd, 0xe8,
-0x1e, 0xff, 0x2f, 0xe1, 0x00, 0xa0, 0x94, 0xe5, 0x0a, 0x00, 0x55, 0xe1,
-0x14, 0xa0, 0x80, 0xe5, 0xe5, 0xff, 0xff, 0x1a, 0x01, 0x10, 0xa0, 0xe3,
-0xf5, 0xff, 0xff, 0xea, 0xa8, 0x03, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80,
-0x00, 0x80, 0x20, 0x40, 0x68, 0x82, 0x9f, 0xe5, 0x0b, 0x92, 0xa0, 0xe3,
-0x64, 0xa2, 0x9f, 0xe5, 0x58, 0xb0, 0x9a, 0xe5, 0x0e, 0xf0, 0xa0, 0xe1,
-0x54, 0xb0, 0x9a, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0x3f, 0x40, 0x2d, 0xe9,
-0x00, 0x00, 0x4f, 0xe1, 0x1f, 0x00, 0x00, 0xe2, 0x12, 0x00, 0x50, 0xe3,
-0x54, 0x00, 0x00, 0x0a, 0x00, 0x00, 0x0f, 0xe1, 0x80, 0x00, 0xc0, 0xe3,
-0x00, 0xf0, 0x21, 0xe1, 0x04, 0x50, 0xa0, 0xe3, 0x00, 0x40, 0x99, 0xe5,
-0x09, 0x00, 0x00, 0xea, 0x02, 0x00, 0x14, 0xe3, 0x53, 0x00, 0x00, 0x1b,
-0x80, 0x00, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 0x20, 0x00, 0x14, 0xe3,
-0x59, 0x00, 0x00, 0x1b, 0x02, 0x07, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b,
-0x01, 0x06, 0x14, 0xe3, 0x59, 0x00, 0x00, 0x1b, 0x08, 0x00, 0x14, 0xe3,
-0x45, 0x00, 0x00, 0x1b, 0x02, 0x05, 0x14, 0xe3, 0x4a, 0x00, 0x00, 0x1b,
-0x02, 0x08, 0x14, 0xe3, 0x4b, 0x00, 0x00, 0x1b, 0xe5, 0x0e, 0x14, 0xe3,
-0x07, 0x00, 0x00, 0x0a, 0x04, 0x20, 0x98, 0xe5, 0x0c, 0x10, 0x98, 0xe5,
-0x04, 0x30, 0x52, 0xe2, 0x3c, 0x30, 0xa0, 0xb3, 0x04, 0x30, 0x88, 0xe5,
-0x02, 0x00, 0x91, 0xe7, 0x0f, 0xe0, 0xa0, 0xe1,
-0x10, 0xff, 0x2f, 0xe1, 0x01, 0x50, 0x55, 0xe2, 0x03, 0x00, 0x00, 0x0a,
-0x00, 0x40, 0x99, 0xe5, 0x0c, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1,
-0x1b, 0xff, 0x2f, 0x11, 0x08, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1,
-0x0b, 0x00, 0x00, 0x0a, 0x01, 0x0c, 0x14, 0xe3, 0x98, 0x01, 0x9f, 0x15,
-0x0f, 0xe0, 0xa0, 0x11, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x04, 0x14, 0xe3,
-0x8c, 0x01, 0x9f, 0x15, 0x0f, 0xe0, 0xa0, 0x11, 0x10, 0xff, 0x2f, 0x11,
-0x01, 0x09, 0x14, 0xe3, 0x80, 0x01, 0x9f, 0x15, 0x0f, 0xe0, 0xa0, 0x11,
-0x10, 0xff, 0x2f, 0x11, 0x04, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1,
-0x16, 0x00, 0x00, 0x0a, 0x54, 0xe0, 0x8f, 0xe2, 0x04, 0x00, 0x14, 0xe3,
-0x40, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x0a, 0x14, 0xe3,
-0x44, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x02, 0x09, 0x14, 0xe3,
-0x48, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x02, 0x14, 0xe3,
-0x4c, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x04, 0x14, 0xe3,
-0x50, 0x00, 0x9a, 0x15, 0x10, 0xff, 0x2f, 0x11, 0x01, 0x0a, 0x14, 0xe3,
-0x21, 0x00, 0x00, 0x1b, 0x02, 0x00, 0x14, 0xe3, 0x0e, 0x00, 0x00, 0x1b,
-0x10, 0x00, 0x9a, 0xe5, 0x00, 0x00, 0x14, 0xe1, 0x1c, 0x00, 0x00, 0x1b,
-0x00, 0x40, 0x99, 0xe5, 0x04, 0x50, 0xa0, 0xe3, 0x00, 0x40, 0x94, 0xe2,
-0x1b, 0xff, 0x2f, 0x11, 0x3f, 0x40, 0xbd, 0xe8, 0x04, 0xf0, 0x5e, 0xe2,
-0xc0, 0x00, 0x80, 0xe3, 0x00, 0xf0, 0x61, 0xe1, 0xfa, 0xff, 0xff, 0xea,
-0x18, 0x00, 0x9a, 0xe5, 0x1c, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1,
-0x54, 0xb0, 0x9a, 0xe5, 0x1c, 0x10, 0x9a, 0xe5, 0x14, 0x00, 0x9a, 0xe5,
-0x11, 0xff, 0x2f, 0xe1, 0x20, 0x10, 0x9a, 0xe5, 0x00, 0x00, 0xa0, 0xe3,
-0x11, 0xff, 0x2f, 0xe1, 0x24, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1,
-0x28, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x2c, 0x10, 0x9a, 0xe5,
-0x11, 0xff, 0x2f, 0xe1, 0x30, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1,
-0x34, 0x10, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0xfe, 0xff, 0xff, 0xea,
-0x38, 0xe0, 0x9a, 0xe5, 0x3c, 0x10, 0x9a, 0xe5, 0x18, 0x00, 0x9a, 0xe5,
-0x11, 0xff, 0x2f, 0xe1, 0x38, 0xe0, 0x9a, 0xe5, 0x3c, 0x10, 0x9a, 0xe5,
-0x14, 0x00, 0x9a, 0xe5, 0x11, 0xff, 0x2f, 0xe1, 0x64, 0x20, 0x9f, 0xe5,
-0x00, 0x30, 0x92, 0xe5, 0x00, 0x30, 0x53, 0xe0, 0x0a, 0x00, 0x00, 0xba,
-0x00, 0x30, 0x82, 0xe5, 0x0c, 0x00, 0x92, 0xe5, 0x08, 0x30, 0x92, 0xe5,
-0x00, 0x10, 0x91, 0xe2, 0x03, 0x00, 0x00, 0x0a, 0x03, 0x10, 0x80, 0xe7,
-0x04, 0x30, 0x53, 0xe2, 0x3c, 0x30, 0xa0, 0xb3, 0x08, 0x30, 0x82, 0xe5,
-0x01, 0x00, 0xa0, 0xe3, 0x1e, 0xff, 0x2f, 0xe1, 0x3c, 0x10, 0x9f, 0xe5,
-0x00, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x80, 0xe2, 0x00, 0x00, 0x81, 0xe5,
-0x00, 0x00, 0xa0, 0xe3, 0xf8, 0xff, 0xff, 0xea, 0x10, 0x00, 0x9f, 0xe5,
-0x08, 0x10, 0x90, 0xe5, 0x04, 0x10, 0x51, 0xe2, 0x3c, 0x10, 0xa0, 0xb3,
-0x08, 0x10, 0x80, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xe4, 0x2d, 0x00, 0x80,
-0xcc, 0x04, 0x00, 0x80, 0x71, 0x2b, 0xff, 0xff, 0xd1, 0x3d, 0xff, 0xff,
-0xc9, 0x2b, 0xff, 0xff, 0xa0, 0x82, 0x20, 0x40, 0xc9, 0x1c, 0x89, 0x08,
-0x89, 0x00, 0x01, 0x23, 0x85, 0x4a, 0x5b, 0x07, 0x18, 0x43, 0x13, 0x68,
-0x5b, 0x18, 0x13, 0x60, 0x00, 0x1f, 0x81, 0xa3, 0x5b, 0x1a, 0x18, 0x47,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5, 0x04, 0x20, 0xa0, 0xe5,
-0x1e, 0xff, 0x2f, 0xe1, 0xe4, 0x2d, 0x00, 0x80,
-0x98, 0x00, 0x9f, 0xe5, 0x98, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0,
-0x94, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5, 0x03, 0x00, 0x50, 0xe1,
-0x03, 0x00, 0x00, 0x1a, 0x04, 0x10, 0x81, 0xe2, 0x04, 0x20, 0x52, 0xe2,
-0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea, 0x78, 0x00, 0x9f, 0xe5,
-0x00, 0x20, 0x80, 0xe5, 0x74, 0x00, 0x9f, 0xe5, 0x74, 0x10, 0x9f, 0xe5,
-0x01, 0x20, 0x40, 0xe0, 0x60, 0x30, 0x9f, 0xe5, 0x00, 0x00, 0x91, 0xe5,
-0x03, 0x00, 0x50, 0xe1, 0x03, 0x00, 0x00, 0x1a, 0x04, 0x10, 0x81, 0xe2,
-0x04, 0x20, 0x52, 0xe2, 0x00, 0x00, 0x00, 0x0a, 0xf8, 0xff, 0xff, 0xea,
-0x50, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5, 0x4c, 0x00, 0x9f, 0xe5,
-0x4c, 0x10, 0x9f, 0xe5, 0x01, 0x20, 0x40, 0xe0, 0x2c, 0x30, 0x9f, 0xe5,
-0x00, 0x00, 0x91, 0xe5, 0x03, 0x00, 0x50, 0xe1, 0x03, 0x00, 0x00, 0x1a,
-0x04, 0x10, 0x81, 0xe2, 0x04, 0x20, 0x52, 0xe2, 0x00, 0x00, 0x00, 0x0a,
-0xf8, 0xff, 0xff, 0xea, 0x28, 0x00, 0x9f, 0xe5, 0x00, 0x20, 0x80, 0xe5,
-0x1e, 0xff, 0x2f, 0xe1, 0x7c, 0x34, 0x00, 0x80, 0x80, 0x30, 0x00, 0x80,
-0xad, 0xde, 0xad, 0xde, 0xc0, 0x04, 0x00, 0x80, 0xfc, 0x37, 0x00, 0x80,
-0x80, 0x34, 0x00, 0x80, 0xc4, 0x04, 0x00, 0x80, 0xfc, 0x3f, 0x00, 0x80,
-0x40, 0x38, 0x00, 0x80, 0xc8, 0x04, 0x00, 0x80, 0x78, 0x47, 0x00, 0x00,
-0x71, 0xea, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 0x39, 0xfe, 0xff, 0xea,
-0x78, 0x47, 0x00, 0x00, 0x63, 0xfe, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00,
-0x1b, 0xff, 0xff, 0xea, 0x78, 0x47, 0x00, 0x00, 0x6b, 0xea, 0xff, 0xea,
-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-0x28, 0x04, 0x00, 0x00, 0xf8, 0x3d, 0x00, 0x00, 0x00, 0x01, 0x00, 0x80,
-0x00, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb9, 0x0b, 0xff, 0xff,
-0x00, 0x00, 0x00, 0x00, 0xd5, 0x0b, 0xff, 0xff, 0x03, 0xff, 0x06, 0x54,
-0x03, 0x00, 0x00, 0x00, 0x75, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
-0xa1, 0x05, 0xff, 0xff, 0x04, 0xff, 0x07, 0x54, 0x03, 0x00, 0x00, 0x00,
-0xb5, 0x04, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x05, 0xff, 0xff,
-0x05, 0xff, 0x05, 0x54, 0x03, 0x00, 0x00, 0x00, 0x39, 0x04, 0xff, 0xff,
-0x00, 0x00, 0x00, 0x00, 0x55, 0x05, 0xff, 0xff, 0x01, 0xff, 0x04, 0x00,
-0x03, 0x00, 0x00, 0x00, 0x41, 0x18, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00,
-0x61, 0x0e, 0xff, 0xff, 0x02, 0xff, 0x02, 0x08, 0x00, 0x00, 0x00, 0x00,
-0xa1, 0x02, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xf1, 0x02, 0xff, 0xff,
-0xff, 0xff, 0x01, 0x44, 0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x9d, 0x0d, 0xff, 0xff, 0x06, 0x00, 0xff, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x3d, 0x50, 0xff, 0xff, 0x81, 0x50, 0xff, 0xff,
-0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0xff, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0xff, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x48, 0x05, 0x00, 0x80, 0x11, 0x75, 0x21, 0x40, 0x1b, 0x75, 0x21, 0x40,
-0x31, 0x75, 0x21, 0x40, 0x49, 0x75, 0x21, 0x40,
-0x55, 0x75, 0x21, 0x40, 0x63, 0x75, 0x21, 0x40, 0x7d, 0x75, 0x21, 0x40,
-0xa9, 0x75, 0x21, 0x40, 0x6d, 0x76, 0x21, 0x40, 0xc5, 0x76, 0x21, 0x40,
-0xd3, 0x76, 0x21, 0x40, 0xdd, 0x76, 0x21, 0x40, 0xe7, 0x76, 0x21, 0x40,
-0x99, 0x77, 0x21, 0x40, 0xa7, 0x77, 0x21, 0x40, 0xb5, 0x77, 0x21, 0x40,
-0x61, 0x78, 0x21, 0x40, 0x5f, 0x7c, 0x21, 0x40, 0xe9, 0x7c, 0x21, 0x40,
-0x89, 0x7d, 0x21, 0x40, 0xbd, 0x7e, 0x21, 0x40, 0xc9, 0x7e, 0x21, 0x40,
-0x29, 0x7f, 0x21, 0x40, 0x8d, 0x7f, 0x21, 0x40, 0xb9, 0x7f, 0x21, 0x40,
-0xdd, 0x7f, 0x21, 0x40, 0x1d, 0x80, 0x21, 0x40, 0x45, 0x80, 0x21, 0x40,
-0x8d, 0x80, 0x21, 0x40, 0x9d, 0x80, 0x21, 0x40, 0xc5, 0x80, 0x21, 0x40,
-0xd5, 0x80, 0x21, 0x40, 0x1d, 0x81, 0x21, 0x40, 0x5b, 0x81, 0x21, 0x40,
-0xb1, 0x81, 0x21, 0x40, 0x11, 0x82, 0x21, 0x40, 0x1b, 0x82, 0x21, 0x40,
-0x1f, 0x82, 0x21, 0x40, 0x8d, 0x82, 0x21, 0x40, 0xd9, 0x82, 0x21, 0x40,
-0x31, 0x83, 0x21, 0x40, 0x6d, 0x83, 0x21, 0x40, 0xd1, 0x83, 0x21, 0x40,
-0x09, 0x84, 0x21, 0x40, 0x19, 0x84, 0x21, 0x40, 0x51, 0x84, 0x21, 0x40,
-0x61, 0x84, 0x21, 0x40, 0x75, 0x84, 0x21, 0x40, 0x9d, 0x84, 0x21, 0x40,
-0xa7, 0x84, 0x21, 0x40, 0xb1, 0x84, 0x21, 0x40, 0x15, 0x85, 0x21, 0x40,
-0x45, 0x85, 0x21, 0x40, 0x51, 0x85, 0x21, 0x40, 0xc5, 0x85, 0x21, 0x40,
-0xcf, 0x85, 0x21, 0x40, 0xd9, 0x85, 0x21, 0x40, 0xe3, 0x85, 0x21, 0x40,
-0xed, 0x85, 0x21, 0x40, 0xf7, 0x85, 0x21, 0x40, 0x01, 0x86, 0x21, 0x40,
-0x0b, 0x86, 0x21, 0x40, 0x15, 0x86, 0x21, 0x40, 0x01, 0x89, 0x21, 0x40,
-0x1f, 0x86, 0x21, 0x40, 0x29, 0x86, 0x21, 0x40, 0x33, 0x86, 0x21, 0x40,
-0x3d, 0x86, 0x21, 0x40, 0x65, 0x86, 0x21, 0x40, 0x6f, 0x86, 0x21, 0x40,
-0xd1, 0x86, 0x21, 0x40, 0xdb, 0x86, 0x21, 0x40, 0xe5, 0x86, 0x21, 0x40,
-0xef, 0x86, 0x21, 0x40, 0xf9, 0x86, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
-0x03, 0x87, 0x21, 0x40, 0x69, 0x87, 0x21, 0x40, 0xb5, 0x87, 0x21, 0x40,
-0xf9, 0x87, 0x21, 0x40, 0x09, 0x88, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
-0x55, 0x88, 0x21, 0x40, 0x59, 0x88, 0x21, 0x40, 0x5d, 0x88, 0x21, 0x40,
-0xb5, 0x88, 0x21, 0x40, 0xdd, 0x88, 0x21, 0x40, 0xe9, 0x88, 0x21, 0x40,
-0xed, 0x88, 0x21, 0x40, 0xf1, 0x88, 0x21, 0x40, 0xf5, 0x88, 0x21, 0x40,
-0xf9, 0x88, 0x21, 0x40, 0xfd, 0x88, 0x21, 0x40, 0x2d, 0x85, 0x21, 0x40,
-0x89, 0x85, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
-0x0d, 0x89, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0xe1, 0x74, 0x21, 0x40,
-0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
-0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40, 0x9d, 0x74, 0x21, 0x40,
-0x6b, 0x78, 0x21, 0x40, 0xf5, 0x7b, 0x21, 0x40, 0x31, 0x7c, 0x21, 0x40,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x5c, 0x01, 0x18, 0x40, 0x58, 0x01, 0x18, 0x40,
-0x24, 0xa3, 0x20, 0x40, 0x24, 0xa7, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x6c, 0x01, 0x18, 0x40, 0x68, 0x01, 0x18, 0x40,
-0x24, 0x83, 0x20, 0x40, 0x24, 0xa3, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x7c, 0x01, 0x18, 0x40, 0x78, 0x01, 0x18, 0x40,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x8c, 0x01, 0x18, 0x40,
-0x88, 0x01, 0x18, 0x40, 0x24, 0xa9, 0x20, 0x40, 0x24, 0xab, 0x20, 0x40,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x08, 0x00, 0x12, 0x00, 0x18, 0x00, 0x12, 0x00, 0x0c, 0x00, 0x12, 0x00,
-0x1c, 0x00, 0x12, 0x00, 0x24, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40,
-0xa4, 0xa8, 0x20, 0x40, 0x24, 0xa9, 0x20, 0x40, 0x00, 0x00, 0x00, 0x00,
-0xd1, 0xa8, 0x21, 0x40, 0x2d, 0xaa, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00,
-0x89, 0x70, 0x21, 0x40, 0xc9, 0xa1, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x57, 0x89, 0x21, 0x40, 0xd1, 0xa8, 0x21, 0x40, 0xc5, 0x2f, 0xff, 0xff,
-0x05, 0x21, 0xff, 0xff, 0xef, 0x20, 0xff, 0xff, 0x59, 0xa7, 0x21, 0x40,
-0x34, 0x2e, 0x00, 0x80, 0x48, 0x2e, 0x00, 0x80, 0x5c, 0x2e, 0x00, 0x80,
-0x30, 0x33, 0x3a, 0x31, 0x31, 0x3a, 0x31, 0x31, 0x00, 0x30, 0x37, 0x2f,
-0x32, 0x33, 0x2f, 0x30, 0x31, 0x00, 0x30, 0x30, 0x30, 0x30, 0x31, 0x35,
-0x36, 0x39, 0x00, 0x43, 0x6f, 0x70, 0x79, 0x72, 0x69, 0x67, 0x68, 0x74,
-0x20, 0x28, 0x63, 0x29, 0x20, 0x32, 0x30, 0x30, 0x31, 0x20, 0x33, 0x43,
-0x6f, 0x6d, 0x20, 0x43, 0x6f, 0x72, 0x70, 0x6f, 0x72, 0x61, 0x74, 0x69,
-0x6f, 0x6e, 0x0a, 0x00, 0x08, 0x10, 0x00, 0x03, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x8c, 0x53, 0xff, 0xff,
-0x27, 0xf0, 0x7d, 0xfd, 0x00, 0x01, 0x00, 0x02, 0xda, 0x0e, 0x82, 0x00,
-0x01, 0x40, 0x64, 0x04, 0x64, 0x2d, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80,
-0x69, 0x3e, 0xff, 0xff, 0xc9, 0x4f, 0xff, 0xff, 0xd5, 0x24, 0xff, 0xff,
-0xc9, 0x3b, 0xff, 0xff, 0x29, 0x3c, 0xff, 0xff, 0x19, 0x1a, 0xff, 0xff,
-0x65, 0x11, 0xff, 0xff, 0xcc, 0x53, 0xff, 0xff, 0x21, 0x40, 0xff, 0xff,
-0x89, 0x70, 0x21, 0x40, 0x49, 0x72, 0x21, 0x40, 0xd9, 0x3f, 0xff, 0xff,
-0x21, 0x9a, 0x21, 0x40, 0x85, 0x24, 0xff, 0xff, 0x64, 0x53, 0xff, 0xff,
-0x8c, 0x53, 0xff, 0xff, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-0x80, 0x30, 0x00, 0x80, 0x00, 0x00, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-0x00, 0x00, 0x20, 0x40, 0xb0, 0x50, 0x00, 0x00, 0x7b, 0x0e, 0x00, 0x00,
-0x00, 0x6e, 0x21, 0x40, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0xed, 0x89, 0x21, 0x40, 0x8b, 0x89, 0x21, 0x40, 0xa5, 0x8c, 0x21, 0x40,
-0x05, 0x8d, 0x21, 0x40, 0xcd, 0x8d, 0x21, 0x40, 0x8b, 0x8b, 0x21, 0x40,
-0xa9, 0x8e, 0x21, 0x40, 0x15, 0x8f, 0x21, 0x40, 0x69, 0x8b, 0x21, 0x40,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
-0x59, 0xbd, 0x21, 0x40, 0xc1, 0xbd, 0x21, 0x40, 0x2d, 0xbe, 0x21, 0x40,
-0x00, 0x20, 0x0a, 0x4a, 0x0b, 0x23, 0x1b, 0x02, 0xd1, 0x18, 0x2d, 0x23,
-0x9b, 0x01, 0xd3, 0x18, 0x88, 0x61, 0xd8, 0x60, 0xd8, 0x63, 0x80, 0x32,
-0xc8, 0x60, 0x08, 0x61, 0x48, 0x61, 0xd0, 0x62, 0x03, 0x48, 0xc0, 0x46,
-0x48, 0x60, 0x88, 0x60, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0xfe, 0x03, 0x00, 0x00, 0xf0, 0xb5, 0x84, 0xb0, 0x0c, 0x1c, 0x05, 0x1c,
-0x00, 0x23, 0x00, 0x93, 0xff, 0xf7, 0xde, 0xff, 0x68, 0x49, 0x0b, 0x23,
-0x1b, 0x02, 0xcf, 0x18, 0x78, 0x68, 0x28, 0x40,
-0x00, 0x22, 0xf8, 0x60, 0x3a, 0x61, 0xba, 0x68, 0x22, 0x40, 0x7a, 0x61,
-0x0c, 0x1c, 0x41, 0x09, 0x03, 0xd2, 0x51, 0x09, 0x01, 0xd2, 0x80, 0x0a,
-0x02, 0xd3, 0x60, 0x48, 0x00, 0xf0, 0xc2, 0xf8, 0x01, 0x20, 0xf9, 0x68,
-0x49, 0x09, 0x03, 0xd2, 0x79, 0x69, 0x49, 0x09, 0x00, 0xd2, 0x00, 0x20,
-0x00, 0x06, 0x00, 0x0e, 0x03, 0xf0, 0xd4, 0xfa, 0xf8, 0x68, 0x00, 0x28,
-0x70, 0xd0, 0x00, 0x23, 0x02, 0x93, 0x01, 0x93, 0x54, 0x4a, 0x01, 0x23,
-0x18, 0x43, 0xf8, 0x60, 0x00, 0x20, 0xd5, 0x1d, 0x79, 0x35, 0x03, 0x95,
-0x01, 0x24, 0x00, 0x21, 0x4f, 0x4d, 0xfa, 0x68, 0x22, 0x40, 0x39, 0xd0,
-0x8a, 0x00, 0x52, 0x18, 0x92, 0x00, 0x4e, 0x4b, 0x9b, 0x5c, 0x1e, 0x1c,
-0x83, 0x42, 0x04, 0xd0, 0x4b, 0x4b, 0xd3, 0x18, 0x5b, 0x78, 0x83, 0x42,
-0x2c, 0xd1, 0x49, 0x4b, 0xd2, 0x18, 0xd3, 0x78, 0x03, 0x9d, 0xed, 0x6a,
-0xab, 0x42, 0x02, 0xd9, 0x03, 0x9d, 0xc0, 0x46, 0xeb, 0x62, 0x53, 0x68,
-0x5b, 0x08, 0x01, 0xd3, 0x01, 0x23, 0x00, 0x93, 0x86, 0x42, 0x0a, 0xd1,
-0x95, 0x68, 0x02, 0x9b, 0x5e, 0x1c, 0x02, 0x96, 0x9b, 0x00, 0x3c, 0x4e,
-0x9e, 0x19, 0x0b, 0x23, 0x1b, 0x02, 0xf3, 0x18, 0x9d, 0x61, 0x53, 0x78,
-0x83, 0x42, 0x0d, 0xd1, 0xd2, 0x68, 0x01, 0x9b, 0x5d, 0x1c, 0x01, 0x95,
-0x9b, 0x00, 0x35, 0x4d, 0x5d, 0x19, 0x2d, 0x23, 0x9b, 0x01, 0xeb, 0x18,
-0xda, 0x60, 0x3a, 0x69, 0x01, 0x32, 0x3a, 0x61, 0x64, 0x00, 0x01, 0x31,
-0x0b, 0x29, 0xbd, 0xd3, 0x01, 0x30, 0x09, 0x28, 0xb8, 0xd3, 0x00, 0x20,
-0x02, 0x9b, 0x99, 0x00, 0x2b, 0x4a, 0x89, 0x18, 0x0b, 0x23, 0x1b, 0x02,
-0xc9, 0x18, 0x88, 0x61, 0x01, 0x9b, 0x99, 0x00, 0x89, 0x18, 0x2d, 0x23,
-0x9b, 0x01, 0xc9, 0x18, 0xc8, 0x60, 0x00, 0x9b, 0x00, 0x2b, 0x0c, 0xd1,
-0x81, 0x00, 0x89, 0x18, 0x0b, 0x23, 0x1b, 0x02, 0xc9, 0x18, 0xcb, 0x69,
-0xc0, 0x46, 0x8b, 0x61, 0x01, 0x30, 0x0b, 0x28, 0xf4, 0xd3, 0x08, 0xe0,
-0x07, 0xe0, 0x03, 0x9d, 0xe8, 0x6a, 0x30, 0x28, 0x03, 0xd2, 0x30, 0x20,
-0x03, 0x9d, 0xc0, 0x46, 0xe8, 0x62, 0x19, 0x4a, 0x78, 0x69, 0x00, 0x28,
-0x2a, 0xd0, 0x00, 0x21, 0x01, 0x23, 0x18, 0x43, 0x78, 0x61, 0x00, 0x20,
-0x01, 0x24, 0x00, 0x22, 0x13, 0x4e, 0x7b, 0x69, 0x23, 0x40, 0x10, 0xd0,
-0x93, 0x00, 0x9b, 0x18, 0x9b, 0x00, 0x12, 0x4d, 0x5b, 0x19, 0x9d, 0x78,
-0x85, 0x42, 0x08, 0xd1, 0x1d, 0x69, 0x0b, 0x1c, 0x9b, 0x00, 0x9e, 0x19,
-0x2d, 0x23, 0x9b, 0x01, 0xf3, 0x18, 0xdd, 0x63, 0x01, 0x31, 0x64, 0x00,
-0x01, 0x32, 0x0b, 0x2a, 0xe6, 0xd3, 0x01, 0x30, 0x09, 0x28, 0xe1, 0xd3,
-0x00, 0x20, 0x89, 0x00, 0x04, 0x4a, 0x89, 0x18, 0x2d, 0x23, 0x9b, 0x01,
-0xc9, 0x18, 0xc8, 0x63, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x68, 0x0e, 0x00, 0x80, 0x30, 0x53, 0xff, 0xff, 0x00, 0x01, 0x00, 0x80,
-0x00, 0x47, 0x08, 0x47, 0x10, 0x47, 0x18, 0x47, 0x78, 0x47, 0xc0, 0x46,
-0x18, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x78, 0x47, 0xc0, 0x46,
-0x10, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x78, 0x47, 0xc0, 0x46,
-0x08, 0xc0, 0x9f, 0xe5, 0x1c, 0xff, 0x2f, 0xe1, 0x38, 0x52, 0xff, 0xff,
-0x88, 0x51, 0xff, 0xff, 0xd5, 0xb0, 0x21, 0x40, 0xf0, 0xb5, 0x04, 0x20,
-0x1a, 0x49, 0x01, 0x25, 0x08, 0x60, 0x1a, 0x4f, 0xbb, 0x23, 0x1b, 0x01,
-0xf8, 0x18, 0x05, 0x73, 0x18, 0x48, 0x41, 0x6b, 0x2c, 0x05, 0x00, 0x20,
-0x7a, 0x6e, 0x17, 0x4b, 0x8a, 0x42, 0x1d, 0xd0,
-0x19, 0x7b, 0x00, 0x29, 0x17, 0xd1, 0xd9, 0x1d, 0xff, 0x31, 0x3a, 0x31,
-0x49, 0x78, 0x1e, 0x1c, 0x00, 0x29, 0x10, 0xd1, 0xb0, 0x60, 0x10, 0x20,
-0x70, 0x60, 0x10, 0x4a, 0x10, 0x49, 0xff, 0xf7, 0xc3, 0xff, 0x00, 0x28,
-0x07, 0xd0, 0x35, 0x73, 0x04, 0x23, 0xb8, 0x69, 0x18, 0x43, 0xb8, 0x61,
-0x20, 0x61, 0x00, 0xf0, 0x17, 0xf8, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x18, 0x73, 0x04, 0x23, 0xb8, 0x69, 0x98, 0x43, 0xb8, 0x61, 0x20, 0x61,
-0xf5, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x68, 0x0e, 0x00, 0x80,
-0x00, 0x01, 0x18, 0x40, 0x28, 0x05, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff,
-0x7d, 0x71, 0x21, 0x40, 0xf8, 0xb5, 0x15, 0x4f, 0x39, 0x6c, 0x15, 0x48,
-0x40, 0x6e, 0x0c, 0x1a, 0x14, 0x4e, 0x71, 0x68, 0x14, 0x4d, 0xa1, 0x42,
-0x06, 0xd8, 0x14, 0x4a, 0x0a, 0x43, 0x00, 0x92, 0xb9, 0x6b, 0x09, 0x18,
-0xfa, 0x6b, 0x11, 0xe0, 0x11, 0x22, 0x52, 0x05, 0x22, 0x43, 0x00, 0x92,
-0xb9, 0x6b, 0x09, 0x18, 0x00, 0x20, 0xfa, 0x6b, 0x2b, 0x1c, 0xff, 0xf7,
-0x8d, 0xff, 0x70, 0x68, 0x00, 0x1b, 0x0a, 0x4a, 0x02, 0x43, 0x00, 0x92,
-0xb9, 0x6b, 0xfa, 0x6b, 0x00, 0x20, 0x2b, 0x1c, 0xff, 0xf7, 0x82, 0xff,
-0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x7c, 0x29, 0x00, 0x80,
-0x68, 0x0e, 0x00, 0x80, 0x28, 0x05, 0x00, 0x80, 0x44, 0x80, 0x20, 0x40,
-0x00, 0x00, 0x37, 0x02, 0xf0, 0xb5, 0x2b, 0x4f, 0xb8, 0x68, 0x79, 0x68,
-0xc0, 0x19, 0x20, 0x30, 0x29, 0x4a, 0xff, 0xf7, 0x63, 0xff, 0x01, 0x20,
-0xc0, 0x02, 0x28, 0x49, 0xc0, 0x46, 0x08, 0x60, 0xb9, 0x68, 0x38, 0x1c,
-0x26, 0x4d, 0x00, 0x24, 0x26, 0x4e, 0xef, 0x1d, 0x79, 0x37, 0x00, 0x29,
-0x31, 0xd1, 0x31, 0x68, 0x0a, 0x78, 0x12, 0x0a, 0x03, 0xd2, 0x04, 0x73,
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x49, 0x78, 0x00, 0x29, 0x0c, 0xd1,
-0x05, 0x1c, 0x40, 0x68, 0x00, 0xf0, 0x3e, 0xf9, 0x30, 0x68, 0x00, 0xf0,
-0x67, 0xf8, 0x00, 0x28, 0x26, 0xd1, 0x2c, 0x73, 0xff, 0xf7, 0x58, 0xff,
-0x22, 0xe0, 0x09, 0x01, 0x07, 0x1c, 0x41, 0x60, 0x08, 0x1c, 0x17, 0x4a,
-0x17, 0x49, 0xff, 0xf7, 0x35, 0xff, 0x00, 0x28, 0x07, 0xd1, 0x3c, 0x73,
-0x04, 0x23, 0xa8, 0x69, 0x98, 0x43, 0x99, 0x04, 0xa8, 0x61, 0x08, 0x61,
-0xda, 0xe7, 0x10, 0x20, 0x00, 0xf0, 0x20, 0xf9, 0x10, 0x20, 0xb8, 0x60,
-0xff, 0xf7, 0x82, 0xff, 0xd2, 0xe7, 0x05, 0x1c, 0x40, 0x68, 0x00, 0xf0,
-0x17, 0xf9, 0x30, 0x68, 0x00, 0xf0, 0x40, 0xf8, 0x00, 0x28, 0xd8, 0xd0,
-0x02, 0x23, 0xf8, 0x6b, 0x18, 0x43, 0xf8, 0x63, 0xc4, 0xe7, 0x00, 0x00,
-0x28, 0x05, 0x00, 0x80, 0xa5, 0x55, 0xff, 0xff, 0x00, 0x00, 0x00, 0xb0,
-0x68, 0x0e, 0x00, 0x80, 0xe4, 0x01, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff,
-0x7d, 0x71, 0x21, 0x40, 0x90, 0xb5, 0x01, 0x20, 0x40, 0x03, 0x10, 0x49,
-0x00, 0x27, 0x08, 0x60, 0x0f, 0x4c, 0xe0, 0x1d, 0xff, 0x30, 0x3a, 0x30,
-0x47, 0x70, 0xe0, 0x69, 0x80, 0x00, 0x00, 0x19, 0x00, 0x69, 0x00, 0xf0,
-0xd7, 0xf8, 0xe0, 0x69, 0x00, 0x28, 0x01, 0xd0, 0xe7, 0x61, 0x01, 0xe0,
-0x01, 0x20, 0xe0, 0x61, 0x07, 0x48, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43,
-0xc1, 0x63, 0x27, 0x73, 0xff, 0xf7, 0x00, 0xff, 0x90, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0x28, 0x05, 0x00, 0x80,
-0xe8, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x78, 0x88,
-0x6d, 0x28, 0x03, 0xdb, 0x38, 0x1c, 0x00, 0xf0,
-0xf7, 0xf8, 0x17, 0xe0, 0x80, 0x00, 0x0d, 0x49, 0x09, 0x58, 0x38, 0x1c,
-0xff, 0xf7, 0xcb, 0xfe, 0x00, 0x28, 0x0f, 0xd1, 0x39, 0x78, 0xc9, 0x09,
-0x0c, 0xd3, 0x69, 0x46, 0x38, 0x1c, 0x00, 0xf0, 0xcf, 0xf8, 0x68, 0x46,
-0x00, 0x21, 0x00, 0xf0, 0x0b, 0xf8, 0x00, 0x28, 0x01, 0xd1, 0x01, 0x20,
-0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0xe8, 0x01, 0x00, 0x80, 0xf0, 0xb5, 0x82, 0xb0, 0x02, 0x1c, 0x41, 0x4b,
-0xdd, 0x1d, 0xff, 0x35, 0x3a, 0x35, 0x2f, 0x78, 0x00, 0x2f, 0x01, 0xd0,
-0x00, 0x27, 0x00, 0xe0, 0x01, 0x27, 0x2f, 0x70, 0x2f, 0x78, 0xfb, 0x00,
-0xdb, 0x19, 0x5b, 0x01, 0x3a, 0x4f, 0xdc, 0x19, 0x40, 0x78, 0x00, 0x01,
-0xc7, 0x1d, 0x09, 0x37, 0x00, 0x20, 0x83, 0x00, 0xd6, 0x58, 0xc0, 0x46,
-0xe6, 0x50, 0x01, 0x30, 0x04, 0x28, 0xf8, 0xd3, 0x00, 0x29, 0x0f, 0xd0,
-0x00, 0x22, 0xbb, 0x08, 0x01, 0x93, 0x83, 0x42, 0x0b, 0xd9, 0x13, 0x1c,
-0x9b, 0x00, 0xcb, 0x58, 0x86, 0x00, 0xa3, 0x51, 0x01, 0x9b, 0x01, 0x30,
-0x01, 0x32, 0x83, 0x42, 0xf5, 0xd8, 0x00, 0xe0, 0x10, 0x27, 0x2b, 0x48,
-0x02, 0x6d, 0x80, 0x6e, 0x2a, 0x49, 0x82, 0x42, 0x03, 0xd8, 0x82, 0x1a,
-0xcb, 0x6c, 0x9a, 0x1a, 0x00, 0xe0, 0x12, 0x1a, 0xba, 0x42, 0x05, 0xd8,
-0x26, 0x48, 0x81, 0x6b, 0x01, 0x31, 0x81, 0x63, 0x01, 0x20, 0x37, 0xe0,
-0xc3, 0x19, 0xca, 0x6c, 0x93, 0x42, 0x08, 0xd8, 0x22, 0x4a, 0x3a, 0x43,
-0x00, 0x92, 0x0a, 0x1c, 0x49, 0x6c, 0x09, 0x18, 0x92, 0x6c, 0x23, 0x1c,
-0x12, 0xe0, 0x16, 0x1a, 0x00, 0x96, 0x1b, 0x49, 0x49, 0x6c, 0x09, 0x18,
-0x19, 0x48, 0x82, 0x6c, 0x03, 0x20, 0x23, 0x1c, 0xff, 0xf7, 0x5e, 0xfe,
-0xb8, 0x1b, 0x18, 0x4a, 0x02, 0x43, 0x00, 0x92, 0xa3, 0x19, 0x14, 0x48,
-0x82, 0x6c, 0x41, 0x6c, 0x03, 0x20, 0xff, 0xf7, 0x53, 0xfe, 0x01, 0x20,
-0x0d, 0x49, 0xc0, 0x46, 0x68, 0x70, 0x8a, 0x69, 0x92, 0x00, 0x52, 0x18,
-0x17, 0x61, 0x8a, 0x69, 0x00, 0x2a, 0x02, 0xd0, 0x00, 0x27, 0x8f, 0x61,
-0x00, 0xe0, 0x88, 0x61, 0x0c, 0x48, 0x02, 0x23, 0xc1, 0x6b, 0x19, 0x43,
-0xc1, 0x63, 0x00, 0x20, 0x01, 0x27, 0x0a, 0x49, 0xc0, 0x46, 0x4f, 0x73,
-0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x28, 0x05, 0x00, 0x80,
-0x50, 0xba, 0x20, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80,
-0xa0, 0x82, 0x20, 0x40, 0x00, 0x00, 0x19, 0x02, 0xe8, 0x0e, 0x00, 0x80,
-0x18, 0x1a, 0x00, 0x80, 0x07, 0x49, 0x8a, 0x6e, 0x10, 0x18, 0x07, 0x4a,
-0xd2, 0x6c, 0x13, 0x04, 0x1b, 0x0c, 0x83, 0x42, 0x00, 0xd8, 0x80, 0x1a,
-0x88, 0x66, 0x88, 0x6e, 0x03, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x70, 0x47,
-0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80, 0x90, 0xee, 0x20, 0x40,
-0x06, 0x49, 0x4a, 0x6e, 0x10, 0x18, 0x06, 0x4a, 0x12, 0x6c, 0x82, 0x42,
-0x00, 0xd8, 0x80, 0x1a, 0x48, 0x66, 0x48, 0x6e, 0x03, 0x49, 0xc0, 0x46,
-0x08, 0x61, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x29, 0x00, 0x80,
-0x90, 0xee, 0x20, 0x40, 0x05, 0x22, 0x0a, 0x60, 0x82, 0x88, 0xc0, 0x46,
-0x8a, 0x80, 0x00, 0x22, 0x4a, 0x70, 0x40, 0x88, 0xc0, 0x46, 0x48, 0x80,
-0xca, 0x80, 0x8a, 0x60, 0xca, 0x60, 0x70, 0x47, 0x05, 0x22, 0x02, 0x60,
-0x00, 0x22, 0x82, 0x80, 0x42, 0x70, 0x41, 0x80, 0xc2, 0x80, 0x82, 0x60,
-0xc2, 0x60, 0x70, 0x47, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x0e, 0x48,
-0x41, 0x6b, 0x01, 0x31, 0x41, 0x63, 0x69, 0x46,
-0x38, 0x1c, 0xff, 0xf7, 0xdd, 0xff, 0x38, 0x68, 0xc0, 0x46, 0x00, 0x90,
-0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x01, 0x27, 0xdf, 0x80, 0x68, 0x46,
-0x00, 0x21, 0xff, 0xf7, 0x11, 0xff, 0x00, 0x28, 0x01, 0xd1, 0x38, 0x1c,
-0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0xa0, 0x82, 0x20, 0x40, 0x00, 0xb5, 0x84, 0xb0, 0xc1, 0x88, 0x09, 0x4a,
-0xc0, 0x46, 0x91, 0x81, 0x69, 0x46, 0xff, 0xf7, 0xbd, 0xff, 0x01, 0x20,
-0x40, 0x02, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7,
-0xf5, 0xfe, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0xe8, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0xff, 0xf7, 0xc3, 0xff, 0x08, 0xbc,
-0x18, 0x47, 0x01, 0x20, 0x03, 0x49, 0xc0, 0x46, 0x08, 0x71, 0xa1, 0x21,
-0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47, 0x28, 0x0f, 0x00, 0x80,
-0x00, 0x20, 0x04, 0x49, 0xc0, 0x46, 0x08, 0x71, 0xff, 0x21, 0xa1, 0x22,
-0x52, 0x03, 0x01, 0x31, 0x91, 0x60, 0x70, 0x47, 0x28, 0x0f, 0x00, 0x80,
-0x02, 0x20, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20, 0x70, 0x47,
-0x01, 0x20, 0x40, 0x02, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x20,
-0x70, 0x47, 0xc0, 0x88, 0xc0, 0x06, 0xc0, 0x0e, 0xa1, 0x21, 0x49, 0x03,
-0x48, 0x61, 0x02, 0x49, 0xc0, 0x46, 0xc8, 0x63, 0x00, 0x20, 0x70, 0x47,
-0xe8, 0x1a, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0, 0x08, 0x49, 0x0f, 0x6b,
-0x69, 0x46, 0xff, 0xf7, 0x71, 0xff, 0xf8, 0x06, 0xc0, 0x0e, 0x01, 0xab,
-0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xa9, 0xfe, 0x01, 0x20,
-0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0x00, 0x14, 0x40,
-0x80, 0xb5, 0x85, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7,
-0x5b, 0xff, 0xf8, 0x88, 0x04, 0xa9, 0x03, 0xf0, 0xc9, 0xff, 0x01, 0xab,
-0x58, 0x80, 0x01, 0xa8, 0x40, 0x88, 0x00, 0x28, 0x0f, 0xd0, 0x01, 0xa8,
-0x40, 0x88, 0x80, 0x08, 0x03, 0x38, 0x80, 0x08, 0x01, 0x30, 0x04, 0x3b,
-0x58, 0x70, 0x04, 0x98, 0x01, 0x68, 0xc0, 0x46, 0x02, 0x91, 0x40, 0x68,
-0xc0, 0x46, 0x03, 0x90, 0x05, 0xe0, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23,
-0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x04, 0x98, 0xc1, 0x1d, 0x01, 0x31,
-0x68, 0x46, 0xff, 0xf7, 0x75, 0xfe, 0x01, 0x20, 0x05, 0xb0, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x14, 0x4f, 0x39, 0x7b,
-0x00, 0x29, 0x20, 0xd1, 0xf9, 0x1d, 0xff, 0x31, 0x3a, 0x31, 0x49, 0x78,
-0x00, 0x29, 0x1a, 0xd1, 0x10, 0x49, 0x05, 0x22, 0x00, 0x92, 0x08, 0x22,
-0x00, 0xab, 0x5a, 0x80, 0x98, 0x80, 0x06, 0x20, 0x00, 0xab, 0x58, 0x70,
-0x00, 0x24, 0xdc, 0x80, 0x08, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x48, 0x68,
-0xc0, 0x46, 0x03, 0x90, 0x01, 0x20, 0x38, 0x73, 0x68, 0x46, 0x08, 0x31,
-0xff, 0xf7, 0x4c, 0xfe, 0x00, 0x28, 0x00, 0xd0, 0x3c, 0x73, 0x04, 0xb0,
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x28, 0x05, 0x00, 0x80,
-0xa4, 0x2a, 0x00, 0x80, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46,
-0x38, 0x1c, 0xff, 0xf7, 0xf9, 0xfe, 0xba, 0x68, 0x0d, 0x4c, 0x0e, 0x48,
-0x00, 0x2a, 0x05, 0xd1, 0x0d, 0x49, 0xff, 0xf7, 0xe4, 0xfc, 0x00, 0x28,
-0x0c, 0xda, 0x05, 0xe0, 0xb9, 0x88, 0x0b, 0x4b, 0xff, 0xf7, 0xdf, 0xfc,
-0x00, 0x28, 0x05, 0xda, 0x01, 0xab, 0x5c, 0x80, 0x68, 0x46, 0x00, 0x21,
-0xff, 0xf7, 0x22, 0xfe, 0x00, 0x20, 0x04, 0xb0,
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00,
-0x0d, 0x76, 0x21, 0x40, 0xc1, 0xbd, 0x21, 0x40, 0x59, 0xbd, 0x21, 0x40,
-0x00, 0xb5, 0xc0, 0x88, 0x03, 0xf0, 0x2e, 0xff, 0x00, 0x20, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0xb5, 0xff, 0xf7, 0xe2, 0xfe, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0xb5, 0xff, 0xf7, 0xdd, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
-0x01, 0x1c, 0x02, 0x20, 0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc, 0x18, 0x47,
-0xb0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0x08, 0x1c, 0x69, 0x46, 0xff, 0xf7,
-0xb5, 0xfe, 0x21, 0x48, 0xff, 0xf7, 0xa4, 0xfc, 0x04, 0x1c, 0x20, 0x4a,
-0x00, 0x21, 0x38, 0x1c, 0xff, 0xf7, 0xa0, 0xfc, 0x00, 0x28, 0x27, 0xd0,
-0x04, 0xa9, 0x1d, 0x4a, 0x38, 0x1c, 0xff, 0xf7, 0x99, 0xfc, 0x04, 0xa8,
-0x00, 0x23, 0x01, 0x2f, 0x06, 0xd1, 0x0c, 0xaa, 0x02, 0x32, 0x00, 0x21,
-0x13, 0x60, 0x01, 0x31, 0x10, 0x29, 0xfb, 0xd3, 0x01, 0x68, 0x04, 0x29,
-0x04, 0xd9, 0x89, 0x08, 0x03, 0x39, 0x89, 0x08, 0x01, 0x31, 0x00, 0xe0,
-0x19, 0x1c, 0x00, 0xab, 0x59, 0x70, 0x06, 0xa9, 0x09, 0x78, 0xc0, 0x46,
-0xd9, 0x80, 0x00, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x07, 0x98, 0xc0, 0x46,
-0x03, 0x90, 0x04, 0x33, 0x08, 0xad, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab,
-0x18, 0x70, 0x09, 0x49, 0x20, 0x1c, 0xff, 0xf7, 0x6e, 0xfc, 0x68, 0x46,
-0x29, 0x1c, 0xff, 0xf7, 0xb7, 0xfd, 0x01, 0x20, 0x46, 0xb0, 0xb0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 0x59, 0xb1, 0x21, 0x40,
-0x9d, 0xaf, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0x01, 0x1c,
-0x02, 0x20, 0x00, 0xf0, 0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
-0x01, 0x1c, 0x01, 0x20, 0xff, 0xf7, 0xa2, 0xff, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0xb5, 0x01, 0x1c, 0x01, 0x20, 0x00, 0xf0, 0x02, 0xf8, 0x08, 0xbc,
-0x18, 0x47, 0xf0, 0xb5, 0xc7, 0xb0, 0x04, 0x1c, 0x0f, 0x1c, 0x38, 0x1c,
-0x01, 0xa9, 0xff, 0xf7, 0x4d, 0xfe, 0x21, 0x48, 0xff, 0xf7, 0x3c, 0xfc,
-0x00, 0x90, 0x78, 0x78, 0x00, 0x01, 0xba, 0x68, 0x04, 0x30, 0xfc, 0x2a,
-0x25, 0xd8, 0xff, 0x23, 0x09, 0x33, 0x98, 0x42, 0x21, 0xd8, 0x19, 0x2c,
-0x1f, 0xd8, 0xfd, 0x88, 0xf8, 0x68, 0xc0, 0x46, 0x05, 0x90, 0xf9, 0x1d,
-0x09, 0x31, 0x06, 0xab, 0x00, 0x20, 0x7e, 0x78, 0x00, 0x2e, 0x0d, 0xdd,
-0x40, 0xc9, 0x40, 0xc3, 0x40, 0xc9, 0x40, 0xc3, 0x40, 0xc9, 0x40, 0xc3,
-0x40, 0xc9, 0x40, 0xc3, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x7e, 0x78,
-0x86, 0x42, 0xf1, 0xdc, 0x20, 0x1c, 0x05, 0xa9, 0x2b, 0x1c, 0xff, 0xf7,
-0x21, 0xfc, 0x00, 0x28, 0x05, 0xd0, 0x01, 0xa8, 0x00, 0x78, 0x40, 0x23,
-0x18, 0x43, 0x01, 0xab, 0x18, 0x70, 0x07, 0x49, 0x00, 0x98, 0xff, 0xf7,
-0x06, 0xfc, 0x00, 0x21, 0x01, 0xa8, 0xff, 0xf7, 0x4f, 0xfd, 0x01, 0x20,
-0x47, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff,
-0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7, 0x1b, 0xfe, 0x08, 0xbc,
-0x18, 0x47, 0xf0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0xfc, 0x88, 0x25, 0x4d,
-0x68, 0x68, 0x01, 0x30, 0x69, 0x46, 0x68, 0x60, 0x38, 0x1c, 0xff, 0xf7,
-0xf5, 0xfd, 0x10, 0x2c, 0x08, 0xd3, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23,
-0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x17, 0xe0,
-0x78, 0x78, 0x82, 0x00, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x20, 0xb9, 0x68,
-0x00, 0x2a, 0x15, 0xd9, 0x40, 0xcb, 0x0f, 0x1c,
-0x01, 0x31, 0xbe, 0x42, 0x0d, 0xd0, 0x00, 0xaa, 0x12, 0x78, 0x40, 0x23,
-0x1a, 0x43, 0x00, 0xab, 0x1a, 0x70, 0x04, 0x22, 0xda, 0x80, 0x02, 0x90,
-0x03, 0x91, 0x04, 0x33, 0x68, 0x46, 0x00, 0x21, 0x15, 0xe0, 0x01, 0x30,
-0x90, 0x42, 0xe9, 0xd3, 0x00, 0xab, 0x5c, 0x70, 0x02, 0x94, 0x69, 0x68,
-0xc0, 0x46, 0x03, 0x91, 0xa2, 0x00, 0x00, 0x20, 0x10, 0x33, 0x00, 0x2a,
-0x05, 0xd9, 0x0f, 0x1c, 0x80, 0xc3, 0x01, 0x30, 0x01, 0x31, 0x90, 0x42,
-0xf9, 0xd3, 0x68, 0x46, 0x04, 0xa9, 0xff, 0xf7, 0xf7, 0xfc, 0x01, 0x20,
-0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x9c, 0x03, 0x00, 0x80,
-0x90, 0xb4, 0x23, 0x48, 0x00, 0x68, 0x01, 0x21, 0x42, 0x09, 0x00, 0xd3,
-0x00, 0x21, 0x00, 0x27, 0x3a, 0x1c, 0x43, 0x0b, 0x00, 0xd2, 0x02, 0x22,
-0x11, 0x43, 0x1e, 0x4a, 0x20, 0x24, 0xd3, 0x68, 0x01, 0x2b, 0x2e, 0xd1,
-0x80, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 0x20, 0x1c, 0x1b, 0x23,
-0xdb, 0x01, 0xd1, 0x18, 0x89, 0x8b, 0x09, 0x0b, 0x00, 0xd2, 0x04, 0x27,
-0x38, 0x43, 0xd1, 0x6f, 0x09, 0x68, 0x09, 0x0a, 0x07, 0xd2, 0xd1, 0x1d,
-0x79, 0x31, 0x09, 0x68, 0x09, 0x68, 0x09, 0x0a, 0x01, 0xd3, 0x08, 0x23,
-0x18, 0x43, 0xe3, 0x23, 0x1b, 0x01, 0xd1, 0x18, 0x89, 0x79, 0x03, 0x29,
-0x02, 0xd1, 0xff, 0x23, 0x01, 0x33, 0x18, 0x43, 0x0b, 0x49, 0x09, 0x6a,
-0x10, 0x22, 0x4b, 0x0a, 0x00, 0xd2, 0x00, 0x22, 0x10, 0x43, 0x89, 0x07,
-0x89, 0x0f, 0x89, 0x01, 0x08, 0x43, 0x90, 0xbc, 0x70, 0x47, 0x40, 0x0c,
-0x00, 0xd2, 0x00, 0x24, 0x0c, 0x43, 0x20, 0x1c, 0xec, 0xe7, 0x00, 0x00,
-0x00, 0x00, 0x10, 0x40, 0x68, 0x0e, 0x00, 0x80, 0xc0, 0x00, 0x18, 0x40,
-0xf0, 0xb5, 0x3a, 0x4c, 0x20, 0x1c, 0x04, 0xf0, 0x07, 0xfa, 0x39, 0x48,
-0xe3, 0x23, 0x1b, 0x01, 0xc7, 0x18, 0xb9, 0x79, 0x37, 0x4e, 0xc5, 0x1d,
-0x79, 0x35, 0x06, 0x29, 0x62, 0xd2, 0x02, 0xa3, 0x5b, 0x5c, 0x5b, 0x00,
-0x9f, 0x44, 0x00, 0x1c, 0x03, 0x0e, 0x1e, 0x37, 0x4e, 0x55, 0x01, 0x20,
-0xb8, 0x71, 0x00, 0x20, 0xb0, 0x60, 0xff, 0xf7, 0x95, 0xff, 0x05, 0x23,
-0x98, 0x43, 0x00, 0xf0, 0x6f, 0xf8, 0x0c, 0xe0, 0xff, 0xf7, 0x8e, 0xff,
-0xc0, 0x08, 0x06, 0xd3, 0xb0, 0x68, 0x41, 0x1c, 0xb1, 0x60, 0x0a, 0x28,
-0x03, 0xd9, 0x04, 0x20, 0x00, 0xe0, 0x02, 0x20, 0xb8, 0x71, 0x64, 0x22,
-0x20, 0x1c, 0x2b, 0xe0, 0x06, 0x1c, 0xc0, 0x6f, 0x80, 0x23, 0x01, 0x68,
-0x19, 0x43, 0x01, 0x60, 0x03, 0x20, 0xb8, 0x71, 0x20, 0x1c, 0x20, 0x4a,
-0x00, 0x21, 0x04, 0xf0, 0x99, 0xf9, 0xf0, 0x6f, 0x04, 0x23, 0x01, 0x68,
-0x99, 0x43, 0x01, 0x60, 0x28, 0x68, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60,
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x05, 0x21, 0xb9, 0x71, 0x29, 0x68,
-0x04, 0x23, 0x0a, 0x68, 0x9a, 0x43, 0x0a, 0x60, 0xc0, 0x6f, 0x01, 0x68,
-0x19, 0x43, 0x01, 0x60, 0xff, 0xf7, 0x5a, 0xff, 0x08, 0x23, 0x18, 0x43,
-0x00, 0xf0, 0x34, 0xf8, 0x20, 0x1c, 0x10, 0x4a, 0x00, 0x21, 0x04, 0xf0,
-0x77, 0xf9, 0xe5, 0xe7, 0xff, 0xf7, 0x4e, 0xff, 0x04, 0x23, 0x18, 0x43,
-0x00, 0xf0, 0x28, 0xf8, 0xde, 0xe7, 0x00, 0x20, 0x29, 0x68, 0x60, 0x23,
-0x0a, 0x68, 0x9a, 0x43, 0x0a, 0x60, 0xff, 0xf7, 0xe3, 0xfa, 0xd5, 0xe7,
-0x06, 0x20, 0xb8, 0x71, 0xd2, 0xe7, 0x00, 0x00, 0xa9, 0x79, 0x21, 0x40,
-0x68, 0x0e, 0x00, 0x80, 0x9c, 0x03, 0x00, 0x80, 0x30, 0x75, 0x00, 0x00,
-0x10, 0x27, 0x00, 0x00, 0x00, 0xb5, 0x00, 0x20,
-0x04, 0x49, 0xc0, 0x46, 0x88, 0x71, 0x04, 0x48, 0x01, 0x22, 0x00, 0x21,
-0x04, 0xf0, 0x4e, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x98, 0x1c, 0x00, 0x80,
-0xa9, 0x79, 0x21, 0x40, 0x90, 0xb5, 0x07, 0x1c, 0x31, 0x48, 0x00, 0x68,
-0x79, 0x08, 0x03, 0xd3, 0x10, 0x23, 0x01, 0x1c, 0x99, 0x43, 0x01, 0xe0,
-0x10, 0x21, 0x01, 0x43, 0x2d, 0x4c, 0xe2, 0x68, 0x01, 0x2a, 0x05, 0xd1,
-0x22, 0x79, 0x00, 0x2a, 0x02, 0xd0, 0x01, 0x23, 0x9b, 0x02, 0x19, 0x43,
-0x81, 0x42, 0x02, 0xd0, 0x01, 0x20, 0x00, 0x05, 0x01, 0x60, 0xe0, 0x68,
-0x01, 0x28, 0x20, 0xd1, 0x1b, 0x23, 0xdb, 0x01, 0xe0, 0x18, 0x80, 0x8b,
-0xf9, 0x08, 0x04, 0xd3, 0x01, 0x23, 0xdb, 0x02, 0x01, 0x1c, 0x99, 0x43,
-0x01, 0xe0, 0x01, 0x21, 0xc9, 0x02, 0x81, 0x42, 0x02, 0xd0, 0x00, 0x20,
-0x02, 0xf0, 0x1a, 0xfb, 0x38, 0x09, 0x07, 0xd3, 0xe0, 0x6f, 0x80, 0x23,
-0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0xe0, 0x18, 0x00, 0x68, 0x00, 0xe0,
-0xe0, 0x6f, 0x80, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x15, 0x48,
-0x01, 0x6a, 0x78, 0x09, 0x03, 0xd3, 0xff, 0x20, 0x01, 0x30, 0x08, 0x43,
-0x03, 0xe0, 0xff, 0x23, 0x08, 0x1c, 0x01, 0x33, 0x98, 0x43, 0x80, 0x08,
-0x80, 0x00, 0xba, 0x09, 0x92, 0x07, 0x92, 0x0f, 0x10, 0x43, 0x88, 0x42,
-0x02, 0xd0, 0x0c, 0x49, 0xc0, 0x46, 0x08, 0x62, 0xe1, 0x68, 0x01, 0x29,
-0x08, 0xd1, 0x79, 0x0a, 0x06, 0xd3, 0xff, 0x23, 0x04, 0x33, 0x18, 0x40,
-0x03, 0x28, 0x01, 0xd1, 0xff, 0xf7, 0x8e, 0xff, 0x90, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x68, 0x0e, 0x00, 0x80,
-0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x80, 0xb5, 0xff, 0xf7,
-0xb1, 0xfe, 0x80, 0x09, 0x1b, 0xd2, 0x0f, 0x48, 0xe3, 0x23, 0x1b, 0x01,
-0xc1, 0x18, 0x4a, 0x79, 0x00, 0x2a, 0x14, 0xd1, 0x01, 0x22, 0x4a, 0x71,
-0x00, 0x27, 0x80, 0x30, 0x00, 0x68, 0x60, 0x23, 0x01, 0x68, 0x99, 0x43,
-0x01, 0x60, 0x08, 0x48, 0x06, 0xe0, 0x02, 0x20, 0x02, 0xf0, 0x8c, 0xfc,
-0x07, 0x20, 0x02, 0xf0, 0x5b, 0xfc, 0x38, 0x1c, 0xff, 0xf7, 0x36, 0xfa,
-0xf5, 0xe7, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
-0xf4, 0x01, 0xff, 0xff, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7,
-0x37, 0xfc, 0xff, 0xf7, 0x85, 0xfe, 0x01, 0xab, 0x58, 0x80, 0x08, 0x48,
-0x00, 0x68, 0xc0, 0x46, 0x02, 0x90, 0x07, 0x48, 0x00, 0x6a, 0xc0, 0x46,
-0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x67, 0xfb, 0x01, 0x20,
-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40,
-0xc0, 0x00, 0x18, 0x40, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46,
-0x38, 0x1c, 0xff, 0xf7, 0x17, 0xfc, 0xf8, 0x88, 0xff, 0xf7, 0x42, 0xff,
-0xff, 0xf7, 0x62, 0xfe, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21,
-0xff, 0xf7, 0x4c, 0xfb, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0xb0, 0xb5, 0xc6, 0xb0, 0xc7, 0x88, 0x69, 0x46, 0xff, 0xf7,
-0x01, 0xfc, 0x01, 0x24, 0x1a, 0x4b, 0x9f, 0x42, 0x0a, 0xd9, 0x00, 0xa8,
-0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20,
-0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, 0x20, 0xe0, 0x14, 0x48, 0xff, 0xf7,
-0xe1, 0xf9, 0x05, 0x1c, 0x13, 0x4a, 0x38, 0x1c, 0x04, 0xa9, 0xff, 0xf7,
-0xdd, 0xf9, 0x12, 0x49, 0x28, 0x1c, 0xff, 0xf7, 0xd8, 0xf9, 0x01, 0x2f,
-0x06, 0xd1, 0x0c, 0xa9, 0x00, 0x20, 0x00, 0x22,
-0x0a, 0x60, 0x01, 0x30, 0x10, 0x28, 0xfb, 0xd3, 0x10, 0x20, 0x00, 0xab,
-0x58, 0x70, 0x04, 0x98, 0xc0, 0x46, 0x02, 0x90, 0x05, 0x98, 0xc0, 0x46,
-0x03, 0x90, 0x68, 0x46, 0x06, 0xa9, 0xff, 0xf7, 0x0f, 0xfb, 0x20, 0x1c,
-0x46, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0x01, 0x00, 0x00,
-0x24, 0x02, 0xff, 0xff, 0x9d, 0xaf, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff,
-0xf0, 0xb5, 0xc6, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7,
-0xbb, 0xfb, 0xfc, 0x88, 0x78, 0x78, 0x01, 0x25, 0x10, 0x28, 0x01, 0xd1,
-0x19, 0x2c, 0x09, 0xd9, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43,
-0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x04, 0x33, 0x27, 0xe0,
-0xb8, 0x68, 0xc0, 0x46, 0x04, 0x90, 0xf8, 0x68, 0xc0, 0x46, 0x05, 0x90,
-0x06, 0xaa, 0xfb, 0x1d, 0x09, 0x33, 0x00, 0x21, 0x78, 0x78, 0x00, 0x28,
-0x0d, 0xdd, 0x00, 0x20, 0x40, 0xcb, 0x40, 0xc2, 0x01, 0x30, 0x00, 0x04,
-0x00, 0x0c, 0x04, 0x28, 0xf8, 0xdb, 0x48, 0x1c, 0x01, 0x04, 0x09, 0x0c,
-0x78, 0x78, 0x88, 0x42, 0xf1, 0xdc, 0x0b, 0x48, 0xff, 0xf7, 0x7e, 0xf9,
-0x07, 0x1c, 0x0a, 0x4a, 0x20, 0x1c, 0x04, 0xa9, 0xff, 0xf7, 0x7a, 0xf9,
-0x08, 0x49, 0x38, 0x1c, 0xff, 0xf7, 0x75, 0xf9, 0x68, 0x46, 0x00, 0x21,
-0xff, 0xf7, 0xbe, 0xfa, 0x28, 0x1c, 0x46, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x24, 0x02, 0xff, 0xff, 0xc5, 0xaf, 0x21, 0x40,
-0x3c, 0x02, 0xff, 0xff, 0xf0, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x00, 0x27,
-0xe6, 0x88, 0xa2, 0x68, 0x47, 0x49, 0x08, 0x79, 0x00, 0x28, 0x08, 0xd0,
-0x00, 0x2e, 0x01, 0xd0, 0x01, 0x2e, 0x01, 0xd1, 0x01, 0x27, 0x01, 0xe0,
-0x04, 0x2e, 0x00, 0xd1, 0x03, 0x26, 0x01, 0x25, 0x41, 0x48, 0x05, 0x2e,
-0x66, 0xd2, 0x02, 0xa3, 0x9b, 0x5d, 0x5b, 0x00, 0x9f, 0x44, 0x00, 0x1c,
-0x03, 0x06, 0x08, 0x0c, 0x10, 0x00, 0x05, 0x80, 0x00, 0x23, 0x03, 0xe0,
-0x05, 0x80, 0x05, 0xe0, 0x00, 0x23, 0x03, 0x80, 0x43, 0x80, 0x06, 0xe0,
-0x00, 0x23, 0x03, 0x80, 0x45, 0x80, 0x02, 0xe0, 0xff, 0x23, 0x01, 0x33,
-0x03, 0x80, 0xcb, 0x1d, 0x79, 0x33, 0x9e, 0x89, 0x01, 0x23, 0x5b, 0x02,
-0x9e, 0x42, 0x02, 0xdb, 0xd2, 0x07, 0xd2, 0x0f, 0x00, 0xe0, 0x01, 0x22,
-0x6d, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x89, 0x88, 0xff, 0x23, 0xe1, 0x33,
-0x99, 0x43, 0x01, 0x23, 0x19, 0x43, 0x06, 0x88, 0xff, 0x33, 0x9e, 0x42,
-0x0d, 0xd1, 0xff, 0x20, 0xe1, 0x30, 0x08, 0x43, 0x00, 0x2a, 0x04, 0xd1,
-0x01, 0x23, 0x9b, 0x02, 0x98, 0x43, 0x01, 0x1c, 0x20, 0xe0, 0x01, 0x21,
-0x89, 0x02, 0x01, 0x43, 0x1c, 0xe0, 0x01, 0x2e, 0x0a, 0xd1, 0x40, 0x88,
-0x01, 0x28, 0x04, 0xd1, 0x60, 0x23, 0x19, 0x43, 0x00, 0x2a, 0x13, 0xd0,
-0x0c, 0xe0, 0x20, 0x23, 0x19, 0x43, 0x0f, 0xe0, 0x00, 0x2e, 0x0d, 0xd1,
-0x40, 0x88, 0x01, 0x28, 0x08, 0xd1, 0xff, 0x23, 0x81, 0x33, 0x19, 0x43,
-0x00, 0x2a, 0x05, 0xd0, 0x01, 0x23, 0x9b, 0x02, 0x19, 0x43, 0x01, 0xe0,
-0x80, 0x23, 0x19, 0x43, 0x04, 0x20, 0x02, 0xf0, 0x75, 0xf9, 0x09, 0x21,
-0x49, 0x02, 0x00, 0x20, 0x02, 0xf0, 0x70, 0xf9, 0x00, 0x2f, 0x02, 0xd1,
-0x00, 0x20, 0x12, 0xe0, 0xff, 0xe7, 0x69, 0x46, 0x20, 0x1c, 0xff, 0xf7,
-0xef, 0xfa, 0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab,
-0x18, 0x70, 0x02, 0x20, 0xd8, 0x80, 0x68, 0x46, 0x00, 0x21, 0x04, 0x33,
-0xff, 0xf7, 0x22, 0xfa, 0x28, 0x1c, 0x04, 0xb0,
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0x88, 0x1c, 0x00, 0x80, 0xc0, 0x88, 0x51, 0x21, 0x89, 0x03, 0x08, 0x62,
-0x00, 0x20, 0x70, 0x47, 0x80, 0xb5, 0x16, 0x4f, 0xf8, 0x68, 0x01, 0x28,
-0x07, 0xd1, 0x37, 0x23, 0x9b, 0x01, 0xf8, 0x18, 0x40, 0x8a, 0x80, 0x21,
-0x01, 0x43, 0x1b, 0x20, 0x07, 0xe0, 0x6d, 0x23, 0x5b, 0x01, 0xf8, 0x18,
-0x80, 0x8b, 0x01, 0x21, 0x49, 0x03, 0x01, 0x43, 0x10, 0x20, 0x02, 0xf0,
-0x33, 0xf9, 0x01, 0x20, 0x71, 0x23, 0x5b, 0x01, 0xf9, 0x18, 0x08, 0x80,
-0x48, 0x80, 0x1b, 0x23, 0xdb, 0x01, 0xf8, 0x18, 0x80, 0x8b, 0x01, 0x23,
-0x1b, 0x03, 0x98, 0x43, 0x41, 0x21, 0x09, 0x02, 0x01, 0x43, 0x00, 0x20,
-0x02, 0xf0, 0x20, 0xf9, 0x00, 0x20, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x17, 0x4f, 0xf8, 0x68, 0x01, 0x28,
-0x08, 0xd1, 0x37, 0x23, 0x9b, 0x01, 0xf8, 0x18, 0x40, 0x8a, 0x80, 0x23,
-0x98, 0x43, 0x01, 0x1c, 0x1b, 0x20, 0x08, 0xe0, 0x6d, 0x23, 0x5b, 0x01,
-0xf8, 0x18, 0x80, 0x8b, 0x01, 0x23, 0x5b, 0x03, 0x98, 0x43, 0x01, 0x1c,
-0x10, 0x20, 0x02, 0xf0, 0x01, 0xf9, 0xff, 0x20, 0x71, 0x23, 0x5b, 0x01,
-0xf9, 0x18, 0x01, 0x30, 0x08, 0x80, 0x1b, 0x23, 0xdb, 0x01, 0xf8, 0x18,
-0x80, 0x8b, 0x41, 0x23, 0x1b, 0x02, 0x98, 0x43, 0x09, 0x21, 0x49, 0x02,
-0x01, 0x43, 0x00, 0x20, 0x02, 0xf0, 0xee, 0xf8, 0x00, 0x20, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb5, 0x84, 0xb0,
-0x08, 0x49, 0xcf, 0x6a, 0x69, 0x46, 0xff, 0xf7, 0x69, 0xfa, 0xb8, 0x05,
-0x80, 0x0d, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7,
-0xa1, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x40, 0x00, 0x14, 0x40, 0xc0, 0x88, 0x9f, 0x23, 0x18, 0x40, 0x05, 0x49,
-0xc9, 0x6a, 0x1b, 0x23, 0x5b, 0x01, 0x19, 0x40, 0x08, 0x43, 0x03, 0x49,
-0xc0, 0x46, 0xc8, 0x62, 0x00, 0x20, 0x70, 0x47, 0x40, 0x00, 0x14, 0x40,
-0x40, 0x00, 0x14, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x0d, 0x49, 0x0f, 0x6a,
-0x01, 0x2f, 0x01, 0xd1, 0xff, 0x03, 0x07, 0xe0, 0x02, 0x2f, 0x01, 0xd1,
-0x3f, 0x03, 0x03, 0xe0, 0x00, 0x2f, 0x01, 0xd1, 0x01, 0x27, 0xff, 0x02,
-0x69, 0x46, 0xff, 0xf7, 0x35, 0xfa, 0x01, 0xab, 0x5f, 0x80, 0x68, 0x46,
-0x00, 0x21, 0xff, 0xf7, 0x6f, 0xf9, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x14, 0x40, 0xc2, 0x88, 0xa1, 0x20,
-0x40, 0x03, 0x00, 0x21, 0x01, 0x23, 0x5b, 0x03, 0x9a, 0x42, 0x01, 0xd1,
-0x02, 0x22, 0x04, 0xe0, 0x01, 0x23, 0xdb, 0x03, 0x9a, 0x42, 0x02, 0xd1,
-0x01, 0x22, 0x02, 0x62, 0x00, 0xe0, 0x01, 0x62, 0x08, 0x1c, 0x70, 0x47,
-0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x02, 0xf0, 0x9f, 0xf8, 0x69, 0x46,
-0x04, 0x1c, 0x38, 0x1c, 0xff, 0xf7, 0x0a, 0xfa, 0x01, 0xab, 0x5c, 0x80,
-0x09, 0x4f, 0xf8, 0x6d, 0xc0, 0x46, 0x02, 0x90, 0x68, 0x46, 0x00, 0x21,
-0xff, 0xf7, 0x40, 0xf9, 0xf8, 0x6d, 0xc0, 0x07, 0xc0, 0x0f, 0x05, 0x49,
-0xc0, 0x46, 0xc8, 0x62, 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80, 0x68, 0x1c, 0x00, 0x80,
-0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x48, 0x61, 0x00, 0x20, 0x70, 0x47,
-0x80, 0x00, 0x14, 0x00, 0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xff, 0xf7,
-0xe3, 0xf9, 0x06, 0x48, 0xc0, 0x68, 0x01, 0xab,
-0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0x1b, 0xf9, 0x01, 0x20,
-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x40,
-0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0xc8, 0x60, 0x00, 0x20, 0x70, 0x47,
-0x80, 0x00, 0x14, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0x87, 0x68,
-0xff, 0xf7, 0xc6, 0xf9, 0x20, 0x2f, 0x07, 0xd2, 0x78, 0x00, 0x0c, 0x49,
-0x40, 0x18, 0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x80, 0x8b, 0x06, 0xe0,
-0x00, 0xa8, 0x00, 0x78, 0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70,
-0x02, 0x20, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7,
-0xef, 0xf8, 0x01, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0x84, 0xb0, 0xc1, 0x88, 0x82, 0x68,
-0x20, 0x2a, 0x04, 0xd2, 0x10, 0x1c, 0x02, 0xf0, 0x17, 0xf8, 0x00, 0x20,
-0x10, 0xe0, 0x69, 0x46, 0xff, 0xf7, 0x9a, 0xf9, 0x00, 0xa8, 0x00, 0x78,
-0x40, 0x23, 0x18, 0x43, 0x00, 0xab, 0x18, 0x70, 0x02, 0x20, 0xd8, 0x80,
-0x68, 0x46, 0x00, 0x21, 0x04, 0x33, 0xff, 0xf7, 0xcd, 0xf8, 0x01, 0x20,
-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0xc7, 0x88,
-0x69, 0x46, 0xff, 0xf7, 0x83, 0xf9, 0x10, 0x48, 0xfe, 0xf7, 0x72, 0xff,
-0x02, 0x20, 0x39, 0x1c, 0x02, 0xf0, 0xf2, 0xff, 0x00, 0x28, 0x06, 0xd0,
-0x02, 0x20, 0x39, 0x1c, 0x02, 0xf0, 0x36, 0xff, 0x01, 0xab, 0x58, 0x80,
-0x02, 0xe0, 0x45, 0x20, 0x00, 0xab, 0x18, 0x70, 0x07, 0x49, 0x20, 0x1c,
-0xfe, 0xf7, 0x5f, 0xff, 0x68, 0x46, 0x00, 0x21, 0xff, 0xf7, 0xa8, 0xf8,
-0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x24, 0x02, 0xff, 0xff, 0x3c, 0x02, 0xff, 0xff, 0xb0, 0xb5, 0x84, 0xb0,
-0xc7, 0x88, 0x69, 0x46, 0x84, 0x68, 0xff, 0xf7, 0x57, 0xf9, 0x10, 0x48,
-0xfe, 0xf7, 0x46, 0xff, 0x0f, 0x4a, 0x02, 0x20, 0x39, 0x1c, 0xfe, 0xf7,
-0x43, 0xff, 0x00, 0x28, 0x06, 0xd0, 0x0d, 0x4b, 0x02, 0x20, 0x39, 0x1c,
-0x22, 0x1c, 0xfe, 0xf7, 0x3c, 0xff, 0x02, 0xe0, 0x45, 0x20, 0x00, 0xab,
-0x18, 0x70, 0x09, 0x49, 0x28, 0x1c, 0xfe, 0xf7, 0x32, 0xff, 0x68, 0x46,
-0x00, 0x21, 0xff, 0xf7, 0x7b, 0xf8, 0x01, 0x20, 0x04, 0xb0, 0xb0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x24, 0x02, 0xff, 0xff, 0x59, 0xb1, 0x21, 0x40,
-0x59, 0xb0, 0x21, 0x40, 0x3c, 0x02, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7,
-0x43, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x70, 0x47, 0x80, 0xb4,
-0xc2, 0x88, 0x19, 0x4b, 0xa1, 0x21, 0x49, 0x03, 0x00, 0x2a, 0x03, 0xd1,
-0x18, 0x6b, 0x10, 0x23, 0x98, 0x43, 0x04, 0xe0, 0x01, 0x2a, 0x04, 0xd1,
-0x18, 0x6b, 0x10, 0x23, 0x18, 0x43, 0x48, 0x61, 0x1f, 0xe0, 0x02, 0x2a,
-0x1d, 0xd1, 0xc2, 0x68, 0x87, 0x68, 0x00, 0x20, 0x3b, 0x1c, 0xc3, 0x40,
-0xdb, 0x07, 0xdb, 0x0f, 0x9b, 0x02, 0x03, 0x43, 0x0b, 0x61, 0x01, 0x30,
-0x00, 0x04, 0x00, 0x0c, 0x20, 0x28, 0xf3, 0xdb, 0x00, 0x20, 0x13, 0x1c,
-0xc3, 0x40, 0xdb, 0x07, 0xdb, 0x0f, 0x9b, 0x02, 0xc7, 0x1d, 0x19, 0x37,
-0x3b, 0x43, 0x0b, 0x61, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x20, 0x28,
-0xf1, 0xdb, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47, 0x80, 0x00, 0x14, 0x40,
-0x80, 0xb4, 0xc2, 0x88, 0x81, 0x68, 0x10, 0x02, 0x12, 0x0a, 0x10, 0x43,
-0x02, 0x04, 0x12, 0x0c, 0x0c, 0x48, 0xc0, 0x46, 0x02, 0x60, 0x0c, 0x4b,
-0xc0, 0x46, 0x1a, 0x80, 0x0a, 0x0c, 0x17, 0x02,
-0x12, 0x12, 0x3a, 0x43, 0x12, 0x04, 0x12, 0x0c, 0x42, 0x60, 0x5a, 0x80,
-0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02, 0x09, 0x0a, 0x11, 0x43, 0x09, 0x04,
-0x09, 0x0c, 0x81, 0x60, 0x99, 0x80, 0x00, 0x20, 0x80, 0xbc, 0x70, 0x47,
-0x40, 0x00, 0x14, 0x00, 0x28, 0x1b, 0x00, 0x80, 0xb0, 0xb5, 0x84, 0xb0,
-0x13, 0x49, 0x0a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x13, 0x02, 0x12, 0x12,
-0x13, 0x43, 0x4a, 0x68, 0x12, 0x04, 0x12, 0x0c, 0x1f, 0x1c, 0x13, 0x02,
-0x12, 0x12, 0x13, 0x43, 0x89, 0x68, 0x09, 0x04, 0x09, 0x0c, 0x0a, 0x02,
-0x09, 0x12, 0x11, 0x43, 0x0c, 0x04, 0x24, 0x0c, 0x69, 0x46, 0x1d, 0x1c,
-0xff, 0xf7, 0xae, 0xf8, 0x01, 0xab, 0x5f, 0x80, 0x28, 0x04, 0x20, 0x43,
-0x02, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xe5, 0xff, 0x01, 0x20,
-0x04, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0x00, 0x14, 0x40,
-0xc1, 0x88, 0x82, 0x68, 0x08, 0x02, 0x09, 0x0a, 0x08, 0x43, 0x00, 0x04,
-0x00, 0x0c, 0x0a, 0x49, 0xc0, 0x46, 0xc8, 0x60, 0x10, 0x0c, 0x03, 0x02,
-0x00, 0x12, 0x18, 0x43, 0x00, 0x04, 0x00, 0x0c, 0x08, 0x61, 0x10, 0x04,
-0x00, 0x0c, 0x02, 0x02, 0x00, 0x0a, 0x10, 0x43, 0x00, 0x04, 0x00, 0x0c,
-0x48, 0x61, 0x00, 0x20, 0x70, 0x47, 0x00, 0x00, 0x40, 0x00, 0x14, 0x00,
-0x90, 0xb5, 0x84, 0xb0, 0x16, 0x4b, 0xd9, 0x68, 0x09, 0x04, 0x09, 0x0c,
-0x0a, 0x02, 0x09, 0x12, 0x11, 0x43, 0x1a, 0x69, 0x12, 0x04, 0x12, 0x0c,
-0x17, 0x02, 0x12, 0x12, 0x3a, 0x43, 0x5b, 0x69, 0x1b, 0x04, 0x1b, 0x0c,
-0x1f, 0x02, 0x1b, 0x12, 0x3b, 0x43, 0x1f, 0x04, 0x3f, 0x0c, 0x05, 0x23,
-0x00, 0x93, 0x84, 0x88, 0x01, 0xab, 0x1c, 0x80, 0x00, 0x24, 0x04, 0x3b,
-0x5c, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xd9, 0x80, 0x10, 0x04,
-0x38, 0x43, 0x02, 0x90, 0x03, 0x94, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7,
-0x95, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x40, 0x00, 0x14, 0x40, 0x00, 0xb5, 0x84, 0xb0, 0x0b, 0x49, 0x8a, 0x6a,
-0x05, 0x21, 0x00, 0x91, 0x81, 0x88, 0x01, 0xab, 0x19, 0x80, 0x00, 0x21,
-0x04, 0x3b, 0x59, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xda, 0x80,
-0x02, 0x91, 0x03, 0x91, 0x68, 0x46, 0xfe, 0xf7, 0x79, 0xff, 0x01, 0x20,
-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x40,
-0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x88, 0x62, 0x00, 0x20, 0x70, 0x47,
-0xc0, 0x00, 0x14, 0x00, 0x00, 0xb5, 0x84, 0xb0, 0x0b, 0x49, 0x0a, 0x6a,
-0x05, 0x21, 0x00, 0x91, 0x81, 0x88, 0x01, 0xab, 0x19, 0x80, 0x00, 0x21,
-0x04, 0x3b, 0x59, 0x70, 0x40, 0x88, 0x00, 0xab, 0x58, 0x80, 0xda, 0x80,
-0x02, 0x91, 0x03, 0x91, 0x68, 0x46, 0xfe, 0xf7, 0x55, 0xff, 0x01, 0x20,
-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x14, 0x40,
-0xc0, 0x88, 0x02, 0x49, 0xc0, 0x46, 0x08, 0x62, 0x00, 0x20, 0x70, 0x47,
-0xc0, 0x00, 0x14, 0x00, 0x00, 0xb5, 0xc0, 0x88, 0x02, 0x49, 0xfe, 0xf7,
-0xf4, 0xfd, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x75, 0x02, 0xff, 0xff,
-0x00, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xfe, 0xf7, 0xf7, 0xff, 0x06, 0x48,
-0x00, 0x6b, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7,
-0x2f, 0xff, 0x01, 0x20, 0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, 0xfd, 0xff, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xf8, 0xff,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xf3, 0xff, 0x08, 0xbc,
-0x18, 0x47, 0x80, 0xb5, 0x07, 0x1c, 0x10, 0x48, 0xfe, 0xf7, 0xc6, 0xfd,
-0x01, 0x20, 0x40, 0x02, 0xa1, 0x21, 0x49, 0x03, 0x88, 0x60, 0x00, 0x21,
-0x0c, 0x48, 0xc0, 0x46, 0x01, 0x71, 0x0c, 0x48, 0x02, 0x68, 0x52, 0x0c,
-0x05, 0xd2, 0x02, 0x68, 0x12, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a,
-0x03, 0xd3, 0x08, 0x48, 0xc0, 0x46, 0xc7, 0x60, 0x02, 0xe0, 0x07, 0x48,
-0xc0, 0x46, 0x07, 0x64, 0x08, 0x1c, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0xd5, 0x94, 0x21, 0x40, 0x28, 0x0f, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40,
-0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x20,
-0x03, 0x49, 0xc0, 0x46, 0x08, 0x72, 0x12, 0x20, 0xff, 0xf7, 0xcb, 0xff,
-0x08, 0xbc, 0x18, 0x47, 0x88, 0x1c, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x20,
-0x03, 0x49, 0xc0, 0x46, 0x48, 0x72, 0x15, 0x20, 0xff, 0xf7, 0xbf, 0xff,
-0x08, 0xbc, 0x18, 0x47, 0x88, 0x1c, 0x00, 0x80, 0x00, 0xb5, 0x01, 0xf0,
-0xf9, 0xff, 0x01, 0x20, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0,
-0x07, 0x1c, 0xf8, 0x88, 0x02, 0xf0, 0xfe, 0xf8, 0x00, 0x28, 0x0c, 0xd1,
-0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x82, 0xff, 0x06, 0x48, 0x01, 0xab,
-0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0xbb, 0xfe, 0x01, 0x20,
-0x00, 0xe0, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0xff, 0xff, 0x00, 0x00, 0x80, 0xb5, 0x84, 0xb0, 0x69, 0x46, 0xfe, 0xf7,
-0x6d, 0xff, 0x01, 0x27, 0x01, 0xab, 0x5f, 0x80, 0x09, 0x48, 0x81, 0x89,
-0x09, 0x04, 0xc2, 0x89, 0x11, 0x43, 0x02, 0x91, 0x81, 0x88, 0x09, 0x04,
-0xc0, 0x88, 0x08, 0x43, 0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7,
-0x9b, 0xfe, 0x38, 0x1c, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x4c, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0xfe, 0xf7, 0x69, 0xff, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x64, 0xff, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0xb5, 0xfe, 0xf7, 0x5f, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
-0xfe, 0xf7, 0x5a, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
-0x55, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x50, 0xff,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x4b, 0xff, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x46, 0xff, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0xb5, 0xfe, 0xf7, 0x41, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
-0xfe, 0xf7, 0x3c, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
-0x37, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0x32, 0xff,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x8c, 0xb0, 0x08, 0xa9, 0xfe, 0xf7,
-0x13, 0xff, 0x69, 0x46, 0x08, 0xa8, 0x02, 0xf0, 0xa9, 0xff, 0x02, 0x20,
-0x08, 0xab, 0x58, 0x70, 0x69, 0x46, 0x08, 0xa8, 0xfe, 0xf7, 0x48, 0xfe,
-0x01, 0x20, 0x0c, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
-0x19, 0xff, 0x08, 0xbc, 0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c,
-0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0xf8, 0xfe, 0xfa, 0x88, 0x12, 0x49,
-0x01, 0x24, 0xc8, 0x1d, 0x89, 0x30, 0x00, 0x2a, 0x0f, 0xd0, 0x04, 0x70,
-0x44, 0x70, 0xb8, 0x68, 0x00, 0x0c, 0x80, 0x31, 0xc8, 0x82, 0xb8, 0x68,
-0xc0, 0x46, 0x08, 0x83, 0xf8, 0x68, 0x00, 0x0c, 0x48, 0x83, 0xf8, 0x68,
-0xc0, 0x46, 0x88, 0x83, 0x02, 0xe0, 0x00, 0x21,
-0x01, 0x70, 0x41, 0x70, 0x06, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46,
-0x00, 0x21, 0xfe, 0xf7, 0x17, 0xfe, 0x20, 0x1c, 0x04, 0xb0, 0x90, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xff, 0xff, 0x00, 0x00,
-0x00, 0xb5, 0xfe, 0xf7, 0xe3, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5,
-0xfe, 0xf7, 0xde, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7,
-0xd9, 0xfe, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xd4, 0xfe,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0xfe, 0xf7, 0xcf, 0xfe, 0x08, 0xbc,
-0x18, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c,
-0xfe, 0xf7, 0xae, 0xfe, 0xf8, 0x88, 0x03, 0x24, 0xe4, 0x04, 0x04, 0x43,
-0x03, 0x23, 0xdb, 0x04, 0x9c, 0x42, 0x02, 0xd3, 0x0f, 0x4b, 0x9c, 0x42,
-0x06, 0xd9, 0x0f, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46, 0x00, 0x21,
-0xfe, 0xf7, 0xdc, 0xfd, 0x01, 0x20, 0x80, 0x07, 0x20, 0x43, 0x00, 0x68,
-0x00, 0x21, 0x00, 0xab, 0x59, 0x70, 0xfa, 0x88, 0xc0, 0x46, 0xda, 0x80,
-0x02, 0x90, 0x03, 0x91, 0x68, 0x46, 0x04, 0x33, 0xfe, 0xf7, 0xcc, 0xfd,
-0x01, 0x20, 0x04, 0xb0, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0xe0, 0x00, 0x18, 0x00, 0xff, 0xff, 0x00, 0x00, 0x80, 0xb5, 0x84, 0xb0,
-0x07, 0x1c, 0x69, 0x46, 0x38, 0x1c, 0xfe, 0xf7, 0x7b, 0xfe, 0xf8, 0x88,
-0x03, 0x23, 0xdb, 0x04, 0x18, 0x43, 0x98, 0x42, 0x02, 0xd3, 0x0a, 0x4b,
-0x98, 0x42, 0x08, 0xd9, 0x09, 0x48, 0x01, 0xab, 0x58, 0x80, 0x68, 0x46,
-0x00, 0x21, 0xfe, 0xf7, 0xab, 0xfd, 0x01, 0x20, 0x03, 0xe0, 0xb9, 0x68,
-0xc0, 0x46, 0x01, 0x60, 0x00, 0x20, 0x04, 0xb0, 0x80, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0xe0, 0x00, 0x18, 0x00, 0xff, 0xff, 0x00, 0x00,
-0x80, 0xb5, 0x86, 0xb0, 0x02, 0xa9, 0xfe, 0xf7, 0x57, 0xfe, 0x01, 0x27,
-0x02, 0xab, 0x5f, 0x70, 0x00, 0x20, 0xd8, 0x80, 0x0a, 0x48, 0x41, 0x68,
-0xc0, 0x46, 0x04, 0x91, 0x81, 0x68, 0xc0, 0x46, 0x05, 0x91, 0xc1, 0x68,
-0xc0, 0x46, 0x00, 0x91, 0x40, 0x69, 0xc0, 0x46, 0x01, 0x90, 0x69, 0x46,
-0x02, 0xa8, 0xfe, 0xf7, 0x81, 0xfd, 0x38, 0x1c, 0x06, 0xb0, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x19, 0x00, 0x80, 0x00, 0xb5, 0xc1, 0x68,
-0x80, 0x68, 0xfe, 0xf7, 0x47, 0xfb, 0x00, 0x20, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0x20, 0x70, 0x47, 0x90, 0xb5, 0x84, 0xb0, 0x04, 0x1c, 0x0f, 0x1c,
-0x68, 0x46, 0x50, 0x21, 0xfe, 0xf7, 0x36, 0xfe, 0x01, 0xab, 0x5c, 0x80,
-0x02, 0x97, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x61, 0xfd, 0x04, 0xb0,
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x84, 0xb0, 0x07, 0x1c,
-0x68, 0x46, 0x51, 0x21, 0xfe, 0xf7, 0x24, 0xfe, 0x01, 0xab, 0x5f, 0x80,
-0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x50, 0xfd, 0x04, 0xb0, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47,
-0x90, 0xb5, 0x84, 0xb0, 0x00, 0x27, 0x12, 0x49, 0x09, 0x68, 0x12, 0x4a,
-0x12, 0x6b, 0x10, 0x23, 0x1a, 0x40, 0x01, 0x24, 0x00, 0x2a, 0x00, 0xd0,
-0x01, 0x27, 0x8a, 0x0c, 0x03, 0xd3, 0x3a, 0x04, 0x12, 0x0c, 0x02, 0x27,
-0x17, 0x43, 0xc9, 0x0c, 0x03, 0xd3, 0x39, 0x04, 0x09, 0x0c, 0x04, 0x27,
-0x0f, 0x43, 0x69, 0x46, 0xfe, 0xf7, 0xec, 0xfd, 0x01, 0xab, 0x5f, 0x80,
-0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x26, 0xfd, 0x20, 0x1c, 0x04, 0xb0,
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x40, 0x00, 0xb5, 0x84, 0xb0,
-0x69, 0x46, 0xfe, 0xf7, 0xd7, 0xfd, 0x06, 0x48, 0xc0, 0x6d, 0x01, 0xab,
-0x58, 0x80, 0x68, 0x46, 0x00, 0x21, 0xfe, 0xf7, 0x0f, 0xfd, 0x01, 0x20,
-0x04, 0xb0, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80,
-0x00, 0xb5, 0xfe, 0xf7, 0xdd, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x70, 0x47,
-0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47,
-0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47, 0x00, 0x20, 0x70, 0x47,
-0x00, 0xb5, 0xfe, 0xf7, 0xcb, 0xfd, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x80, 0xb5, 0x85, 0xb0, 0x01, 0xa9, 0xfe, 0xf7, 0xab, 0xfd, 0x00, 0x20,
-0x01, 0xab, 0x58, 0x70, 0x0c, 0x49, 0xc9, 0x68, 0x01, 0x27, 0x01, 0x29,
-0x02, 0xd1, 0x03, 0x97, 0x04, 0x97, 0x01, 0xe0, 0x03, 0x97, 0x04, 0x90,
-0x68, 0x46, 0x01, 0xf0, 0x33, 0xfd, 0x02, 0xab, 0x00, 0x98, 0xc0, 0x46,
-0x58, 0x80, 0x00, 0x21, 0x01, 0xa8, 0xfe, 0xf7, 0xd3, 0xfc, 0x38, 0x1c,
-0x05, 0xb0, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
-0x70, 0x47, 0x04, 0x49, 0x00, 0x20, 0x00, 0x22, 0x0a, 0x70, 0x01, 0x30,
-0x01, 0x31, 0x68, 0x28, 0xfa, 0xd3, 0x70, 0x47, 0xa0, 0x82, 0x20, 0x40,
-0x00, 0x22, 0x88, 0x42, 0x03, 0xd3, 0x40, 0x1a, 0x01, 0x32, 0x88, 0x42,
-0xfb, 0xd2, 0x10, 0x1c, 0x70, 0x47, 0x88, 0x42, 0x02, 0xd3, 0x40, 0x1a,
-0x88, 0x42, 0xfc, 0xd2, 0x70, 0x47, 0x90, 0xb4, 0x01, 0x1c, 0xff, 0x27,
-0x04, 0x29, 0x27, 0xda, 0x00, 0x20, 0x14, 0x4a, 0x43, 0x00, 0x1b, 0x18,
-0xdb, 0x00, 0xd4, 0x58, 0x63, 0x0c, 0x1a, 0xd2, 0x4b, 0x00, 0x59, 0x18,
-0xc9, 0x00, 0x57, 0x58, 0x43, 0x00, 0x1b, 0x18, 0xdb, 0x00, 0xd7, 0x50,
-0x89, 0x18, 0x9a, 0x18, 0x4f, 0x68, 0xc0, 0x46, 0x57, 0x60, 0x8b, 0x68,
-0xc0, 0x46, 0x93, 0x60, 0x0b, 0x69, 0xc0, 0x46, 0x13, 0x61, 0x4b, 0x69,
-0xc0, 0x46, 0x53, 0x61, 0xc9, 0x68, 0xc0, 0x46, 0xd1, 0x60, 0x90, 0xbc,
-0x70, 0x47, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x04, 0x28, 0xd9, 0xdb,
-0x38, 0x1c, 0xf6, 0xe7, 0x40, 0xab, 0x20, 0x40, 0xf7, 0xb5, 0xc4, 0xb0,
-0x04, 0x1c, 0x00, 0x20, 0x46, 0x9a, 0x11, 0x21, 0x11, 0x40, 0x6e, 0xd0,
-0x00, 0x27, 0x79, 0x00, 0xc9, 0x19, 0xc9, 0x00, 0x57, 0x4a, 0x51, 0x58,
-0x49, 0x0c, 0x03, 0xd2, 0x01, 0x30, 0x00, 0x06, 0x00, 0x0e, 0x04, 0xe0,
-0x79, 0x1c, 0x0f, 0x06, 0x3f, 0x0e, 0x04, 0x2f, 0xef, 0xdb, 0x00, 0x28,
-0x5b, 0xd0, 0x00, 0x26, 0x00, 0x22, 0x00, 0x92, 0x40, 0x23, 0x00, 0x21,
-0x00, 0x20, 0x02, 0xaa, 0x00, 0xf0, 0x88, 0xfa, 0x04, 0xa9, 0x00, 0x20,
-0x82, 0x00, 0x8a, 0x58, 0x12, 0x06, 0x12, 0x0e, 0xa2, 0x42, 0x03, 0xd1,
-0x72, 0x1c, 0x16, 0x06, 0x36, 0x0e, 0x04, 0xe0, 0x01, 0x30, 0x00, 0x06,
-0x00, 0x0e, 0x10, 0x28, 0xf0, 0xdb, 0x00, 0x2e, 0x3d, 0xd0, 0x04, 0x2c,
-0x3e, 0xd1, 0x80, 0x00, 0x08, 0x58, 0x40, 0x01, 0x80, 0x0d, 0x00, 0x22,
-0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x02, 0xaa, 0x00, 0xf0, 0x68, 0xfa,
-0x00, 0x21, 0x01, 0x91, 0x02, 0xa8, 0x05, 0x99, 0x49, 0x0c, 0x89, 0x05,
-0x29, 0xd0, 0xc1, 0x68, 0x0a, 0x06, 0x12, 0x0e, 0x45, 0x9b, 0x9a, 0x42,
-0x11, 0xd1, 0xc0, 0x68, 0x40, 0x01, 0x86, 0x0d, 0x00, 0x22, 0x00, 0x92,
-0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0, 0x50, 0xfa,
-0x01, 0x99, 0x02, 0x9d, 0x48, 0x1c, 0x01, 0x06,
-0x09, 0x0e, 0x01, 0x91, 0x0e, 0xe0, 0x48, 0x01, 0x86, 0x0d, 0x00, 0x22,
-0x00, 0x92, 0x10, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0,
-0x3f, 0xfa, 0x02, 0xa8, 0x05, 0x99, 0x49, 0x0c, 0x89, 0x05, 0xd8, 0xd1,
-0x01, 0x99, 0x00, 0x29, 0x0f, 0xd1, 0xff, 0x20, 0x3d, 0xe0, 0x40, 0xe0,
-0x80, 0x00, 0x08, 0x58, 0x40, 0x01, 0x86, 0x0d, 0x00, 0x22, 0x00, 0x92,
-0x0c, 0x23, 0x00, 0x21, 0x30, 0x1c, 0x02, 0xaa, 0x00, 0xf0, 0x28, 0xfa,
-0x02, 0x9d, 0x01, 0x20, 0x00, 0x04, 0x46, 0x9a, 0x10, 0x43, 0x79, 0x00,
-0xc9, 0x19, 0xc9, 0x00, 0x17, 0x4a, 0xc0, 0x46, 0x50, 0x50, 0x30, 0x1c,
-0x8e, 0x18, 0x70, 0x60, 0x10, 0x20, 0x04, 0x2c, 0x00, 0xd0, 0x0c, 0x20,
-0x04, 0x1c, 0xb0, 0x60, 0x00, 0x20, 0x20, 0x21, 0x46, 0x9a, 0x11, 0x40,
-0x20, 0x29, 0x00, 0xd0, 0x28, 0x1c, 0x30, 0x61, 0x28, 0x19, 0xff, 0x21,
-0xff, 0x30, 0x08, 0x30, 0x09, 0x31, 0xff, 0xf7, 0x19, 0xff, 0x43, 0x01,
-0x18, 0x18, 0xc0, 0x00, 0x00, 0x1b, 0x70, 0x61, 0x00, 0x20, 0x50, 0x21,
-0x46, 0x9a, 0x11, 0x40, 0x50, 0x29, 0x00, 0xd1, 0x28, 0x1c, 0xf0, 0x60,
-0x38, 0x1c, 0x47, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xff, 0x20,
-0xf9, 0xe7, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40, 0x80, 0xb4, 0x00, 0x23,
-0x00, 0x22, 0x00, 0x29, 0x06, 0xd9, 0x87, 0x5c, 0x7b, 0x40, 0x1b, 0x06,
-0x1b, 0x0e, 0x01, 0x32, 0x8a, 0x42, 0xf8, 0xd3, 0xd8, 0x43, 0x00, 0x06,
-0x00, 0x0e, 0x80, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0xc6, 0xb0, 0x04, 0x28,
-0x07, 0xda, 0x41, 0x00, 0x09, 0x18, 0xc9, 0x00, 0x45, 0x91, 0x41, 0x4a,
-0x51, 0x58, 0x4b, 0x0c, 0x02, 0xd2, 0x00, 0x20, 0xc0, 0x43, 0x76, 0xe0,
-0x01, 0x23, 0x5b, 0x04, 0x19, 0x40, 0x43, 0x00, 0x18, 0x18, 0xc0, 0x00,
-0x3a, 0x4a, 0x14, 0x18, 0x00, 0x29, 0x61, 0xd0, 0x00, 0x21, 0x02, 0x91,
-0x20, 0x69, 0xa1, 0x68, 0x45, 0x18, 0x30, 0xd0, 0xff, 0x21, 0x68, 0x1e,
-0x09, 0x31, 0xff, 0xf7, 0xcd, 0xfe, 0x61, 0x68, 0x40, 0x18, 0x01, 0x90,
-0x01, 0x98, 0x81, 0x42, 0x02, 0xd1, 0xa6, 0x68, 0xaf, 0x1b, 0x09, 0xe0,
-0x00, 0x26, 0xff, 0x21, 0x28, 0x1c, 0x09, 0x31, 0xff, 0xf7, 0xc7, 0xfe,
-0x07, 0x1c, 0x01, 0xd1, 0xff, 0x27, 0x09, 0x37, 0x00, 0x22, 0x00, 0x92,
-0x01, 0x98, 0x31, 0x1c, 0x03, 0xaa, 0x3b, 0x1c, 0x00, 0xf0, 0x9e, 0xf9,
-0x03, 0xa8, 0x39, 0x1c, 0xff, 0xf7, 0xac, 0xff, 0xc0, 0x43, 0x02, 0x99,
-0x48, 0x40, 0x01, 0x06, 0x09, 0x0e, 0x02, 0x91, 0xed, 0x1b, 0xa0, 0x68,
-0xa8, 0x42, 0x00, 0xd1, 0x00, 0x25, 0x00, 0x2d, 0xce, 0xd8, 0x02, 0x99,
-0xcf, 0x43, 0x00, 0x22, 0x00, 0x92, 0x0c, 0x23, 0x00, 0x21, 0x60, 0x68,
-0x03, 0xaa, 0x00, 0xf0, 0x83, 0xf9, 0x20, 0x69, 0xc0, 0x46, 0x03, 0x90,
-0x05, 0x98, 0x00, 0x0a, 0x00, 0x02, 0x39, 0x06, 0x09, 0x0e, 0x08, 0x43,
-0x05, 0x90, 0xff, 0x23, 0x1b, 0x02, 0x98, 0x43, 0x05, 0x90, 0x0c, 0x21,
-0x03, 0xa8, 0xff, 0xf7, 0x83, 0xff, 0xff, 0x23, 0x1b, 0x02, 0x05, 0x99,
-0x99, 0x43, 0x00, 0x06, 0x00, 0x0e, 0x00, 0x02, 0x08, 0x43, 0x05, 0x90,
-0x0c, 0x23, 0x00, 0x21, 0x60, 0x68, 0x03, 0xaa, 0x00, 0xf0, 0xca, 0xf9,
-0x00, 0x20, 0x45, 0x99, 0x06, 0x4a, 0xc0, 0x46, 0x50, 0x50, 0xc1, 0x43,
-0x61, 0x60, 0xa1, 0x60, 0xe1, 0x60, 0x21, 0x61, 0x61, 0x61, 0x46, 0xb0,
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40,
-0xb0, 0xb4, 0x4c, 0x42, 0x00, 0x29, 0x00, 0xdb,
-0x0c, 0x1c, 0x00, 0x27, 0xff, 0x43, 0x04, 0x28, 0x21, 0xda, 0x12, 0x4d,
-0x43, 0x00, 0x18, 0x18, 0xc0, 0x00, 0x40, 0x19, 0x01, 0x2a, 0x05, 0xd0,
-0x02, 0x2a, 0x09, 0xd0, 0x03, 0x2a, 0x16, 0xd1, 0x01, 0x69, 0x0b, 0xe0,
-0x00, 0x29, 0x12, 0xdb, 0x02, 0x69, 0x8a, 0x42, 0x0f, 0xd3, 0x05, 0xe0,
-0x00, 0x29, 0x07, 0xda, 0xc1, 0x68, 0xa1, 0x42, 0x09, 0xd3, 0x09, 0x1b,
-0xc1, 0x60, 0xc0, 0x68, 0xb0, 0xbc, 0x70, 0x47, 0xc1, 0x68, 0x09, 0x19,
-0x02, 0x69, 0x91, 0x42, 0xf6, 0xd9, 0x38, 0x1c, 0xf6, 0xe7, 0x00, 0x00,
-0x40, 0xab, 0x20, 0x40, 0xf0, 0xb5, 0x84, 0xb0, 0x17, 0x1c, 0x0d, 0x1c,
-0x00, 0x21, 0x02, 0x91, 0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x2c, 0x49,
-0x8b, 0x58, 0x1b, 0x06, 0x1b, 0x0e, 0x01, 0x93, 0x00, 0x23, 0xdb, 0x43,
-0x04, 0x28, 0x02, 0xda, 0x01, 0x98, 0x40, 0x08, 0x01, 0xd2, 0x18, 0x1c,
-0x46, 0xe0, 0x54, 0x18, 0xe0, 0x68, 0xc2, 0x19, 0x21, 0x69, 0x8a, 0x42,
-0x00, 0xd9, 0x0f, 0x1a, 0x00, 0x2f, 0x3c, 0xd9, 0xa0, 0x68, 0xe1, 0x68,
-0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, 0x0d, 0xfe, 0x61, 0x68,
-0x46, 0x18, 0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21, 0x09, 0x31,
-0xff, 0xf7, 0x0d, 0xfe, 0xc2, 0x19, 0xff, 0x21, 0x09, 0x31, 0x8a, 0x42,
-0x14, 0xd9, 0x01, 0x9a, 0xc0, 0x46, 0x00, 0x92, 0x0b, 0x1a, 0x03, 0x93,
-0x01, 0x1c, 0x30, 0x1c, 0x2a, 0x1c, 0x00, 0xf0, 0xe1, 0xf8, 0xe0, 0x68,
-0x03, 0x9b, 0xc0, 0x18, 0xe0, 0x60, 0x03, 0x9b, 0x5d, 0x19, 0xff, 0x1a,
-0x02, 0x98, 0x18, 0x18, 0x02, 0x90, 0x10, 0xe0, 0x01, 0x9a, 0xc0, 0x46,
-0x00, 0x92, 0x01, 0x1c, 0x30, 0x1c, 0x2a, 0x1c, 0x3b, 0x1c, 0x00, 0xf0,
-0xcd, 0xf8, 0xe0, 0x68, 0xc0, 0x19, 0xed, 0x19, 0xe0, 0x60, 0x02, 0x98,
-0xc0, 0x19, 0x02, 0x90, 0x00, 0x27, 0x00, 0x2f, 0xc2, 0xd8, 0x02, 0x98,
-0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x40, 0xab, 0x20, 0x40,
-0xf0, 0xb5, 0x83, 0xb0, 0x17, 0x1c, 0x0d, 0x1c, 0x00, 0x21, 0x01, 0x91,
-0x42, 0x00, 0x12, 0x18, 0xd2, 0x00, 0x02, 0x92, 0x30, 0x49, 0x8a, 0x58,
-0x12, 0x06, 0x12, 0x0e, 0x00, 0x24, 0xe4, 0x43, 0x04, 0x28, 0x01, 0xda,
-0x50, 0x09, 0x01, 0xd2, 0x20, 0x1c, 0x51, 0xe0, 0x02, 0x9a, 0x54, 0x18,
-0xe0, 0x68, 0xc2, 0x19, 0x60, 0x69, 0x82, 0x42, 0x01, 0xd9, 0x22, 0x69,
-0x87, 0x1a, 0x00, 0x2f, 0x45, 0xd9, 0x25, 0x4e, 0xa0, 0x68, 0xe1, 0x68,
-0x40, 0x18, 0xff, 0x21, 0x09, 0x31, 0xff, 0xf7, 0xa7, 0xfd, 0x61, 0x68,
-0x40, 0x18, 0x00, 0x90, 0xa0, 0x68, 0xe1, 0x68, 0x40, 0x18, 0xff, 0x21,
-0x09, 0x31, 0xff, 0xf7, 0xa6, 0xfd, 0x02, 0x9a, 0xb1, 0x58, 0x01, 0x23,
-0x5b, 0x04, 0x19, 0x43, 0xb1, 0x50, 0xc1, 0x19, 0xff, 0x22, 0x09, 0x32,
-0x91, 0x42, 0x13, 0xd9, 0x13, 0x1a, 0x01, 0x1c, 0x00, 0x98, 0x2a, 0x1c,
-0x1e, 0x1c, 0x00, 0xf0, 0xdf, 0xf8, 0xe0, 0x68, 0x80, 0x19, 0x75, 0x19,
-0xe0, 0x60, 0x21, 0x69, 0x88, 0x42, 0x00, 0xd9, 0x20, 0x61, 0xbf, 0x1b,
-0x01, 0x98, 0x30, 0x18, 0x01, 0x90, 0x12, 0xe0, 0x01, 0x1c, 0x00, 0x9e,
-0x30, 0x1c, 0x2a, 0x1c, 0x3b, 0x1c, 0x00, 0xf0, 0xcb, 0xf8, 0xe0, 0x68,
-0xc0, 0x19, 0xed, 0x19, 0xe0, 0x60, 0x21, 0x69, 0x88, 0x42, 0x00, 0xd9,
-0x20, 0x61, 0x01, 0x98, 0xc0, 0x19, 0x01, 0x90, 0x00, 0x27, 0x00, 0x2f,
-0xb9, 0xd8, 0x01, 0x98, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x40, 0xab, 0x20, 0x40, 0xb0, 0xb5, 0xc3, 0xb0,
-0x0c, 0x1c, 0x00, 0x27, 0xfa, 0x43, 0x04, 0x28, 0x06, 0xda, 0x41, 0x00,
-0x09, 0x18, 0xc9, 0x00, 0x14, 0x48, 0x45, 0x58, 0x6b, 0x0c, 0x04, 0xd2,
-0x10, 0x1c, 0x43, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x62, 0x09,
-0x1b, 0xd3, 0x00, 0x22, 0x00, 0x92, 0x08, 0x18, 0x40, 0x68, 0x0c, 0x23,
-0x00, 0x21, 0x01, 0xaa, 0x00, 0xf0, 0x30, 0xf8, 0x11, 0x2c, 0x0d, 0xd0,
-0x12, 0x2c, 0x0d, 0xd0, 0x13, 0x2c, 0x05, 0xd0, 0x14, 0x2c, 0x0a, 0xd1,
-0x03, 0x98, 0x00, 0x04, 0x07, 0x0e, 0x06, 0xe0, 0x03, 0x98, 0x07, 0x06,
-0x3f, 0x0e, 0x02, 0xe0, 0x01, 0x9f, 0x00, 0xe0, 0x02, 0x9f, 0x38, 0x1c,
-0xdb, 0xe7, 0x00, 0x00, 0x40, 0xab, 0x20, 0x40, 0x03, 0x49, 0x00, 0x20,
-0x00, 0x22, 0x0a, 0x54, 0x01, 0x30, 0x60, 0x28, 0xfb, 0xd3, 0x70, 0x47,
-0x40, 0xab, 0x20, 0x40, 0x00, 0xb5, 0x02, 0xf0, 0x6f, 0xfa, 0x57, 0x20,
-0x02, 0xf0, 0xcc, 0xf9, 0x02, 0xf0, 0x40, 0xf9, 0x00, 0x0a, 0xfb, 0xd3,
-0x02, 0xf0, 0x4e, 0xfa, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5, 0x82, 0xb0,
-0x07, 0x9d, 0x14, 0x1c, 0x1f, 0x1c, 0x30, 0x4a, 0xd2, 0x6f, 0x20, 0x23,
-0x16, 0x68, 0x9e, 0x43, 0x16, 0x60, 0x33, 0x1c, 0xff, 0x22, 0x01, 0x32,
-0x2a, 0x40, 0x40, 0x02, 0x08, 0x43, 0x05, 0x0a, 0x06, 0x1c, 0x00, 0x0c,
-0x01, 0x90, 0x00, 0x2a, 0x20, 0xd0, 0x02, 0xf0, 0x4b, 0xfa, 0x53, 0x20,
-0x02, 0xf0, 0xa8, 0xf9, 0x01, 0x98, 0xc0, 0x46, 0x00, 0x90, 0x02, 0xf0,
-0xa3, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0xa0, 0xf9, 0x30, 0x1c, 0x02, 0xf0,
-0x9d, 0xf9, 0x02, 0xf0, 0x23, 0xfa, 0xff, 0xf7, 0xc7, 0xff, 0x02, 0xf0,
-0x37, 0xfa, 0x54, 0x20, 0x02, 0xf0, 0x94, 0xf9, 0x00, 0x98, 0x02, 0xf0,
-0x91, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x8e, 0xf9, 0x30, 0x1c, 0x14, 0xe0,
-0x02, 0xf0, 0x2a, 0xfa, 0x52, 0x20, 0x02, 0xf0, 0x87, 0xf9, 0x01, 0x98,
-0x02, 0xf0, 0x84, 0xf9, 0x28, 0x1c, 0x02, 0xf0, 0x81, 0xf9, 0x30, 0x1c,
-0x02, 0xf0, 0x7e, 0xf9, 0x00, 0x20, 0x02, 0xf0, 0x7b, 0xf9, 0x00, 0x20,
-0x02, 0xf0, 0x78, 0xf9, 0x00, 0x20, 0x02, 0xf0, 0x75, 0xf9, 0x00, 0x20,
-0x02, 0xf0, 0x72, 0xf9, 0x00, 0x2f, 0x05, 0xd9, 0x02, 0xf0, 0xe4, 0xf8,
-0x20, 0x70, 0x01, 0x34, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0xf0, 0xf9,
-0x04, 0x4a, 0xd0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60,
-0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
-0xf0, 0xb5, 0x82, 0xb0, 0x14, 0x1c, 0x1f, 0x1c, 0x42, 0x02, 0x0a, 0x43,
-0x15, 0x1c, 0x01, 0x28, 0x54, 0xd0, 0x2c, 0x49, 0xc8, 0x6f, 0x20, 0x23,
-0x02, 0x68, 0x9a, 0x43, 0x02, 0x60, 0xc8, 0x6f, 0x40, 0x23, 0x01, 0x68,
-0x19, 0x43, 0x01, 0x60, 0x02, 0xf0, 0xe6, 0xf9, 0x53, 0x20, 0x02, 0xf0,
-0x43, 0xf9, 0x28, 0x0c, 0x06, 0x1c, 0x02, 0xf0, 0x3f, 0xf9, 0x28, 0x0a,
-0x01, 0x90, 0x00, 0x90, 0x02, 0xf0, 0x3a, 0xf9, 0x28, 0x1c, 0x02, 0xf0,
-0x37, 0xf9, 0x02, 0xf0, 0xbd, 0xf9, 0xff, 0xf7, 0x61, 0xff, 0x02, 0xf0,
-0xd1, 0xf9, 0x84, 0x20, 0x02, 0xf0, 0x2e, 0xf9, 0x30, 0x1c, 0x02, 0xf0,
-0x2b, 0xf9, 0x00, 0x98, 0x02, 0xf0, 0x28, 0xf9, 0x28, 0x1c, 0x02, 0xf0,
-0x25, 0xf9, 0x00, 0x2f, 0x05, 0xd9, 0x20, 0x78, 0x01, 0x34, 0x02, 0xf0,
-0x1f, 0xf9, 0x01, 0x3f, 0xf9, 0xd1, 0x02, 0xf0, 0xa3, 0xf9, 0x02, 0xf0,
-0xb9, 0xf9, 0x83, 0x20, 0x02, 0xf0, 0x16, 0xf9, 0x30, 0x1c, 0x02, 0xf0,
-0x13, 0xf9, 0x01, 0x98, 0x02, 0xf0, 0x10, 0xf9,
-0x28, 0x1c, 0x02, 0xf0, 0x0d, 0xf9, 0x02, 0xf0, 0x93, 0xf9, 0xff, 0xf7,
-0x37, 0xff, 0x07, 0x49, 0xc8, 0x6f, 0x40, 0x23, 0x02, 0x68, 0x9a, 0x43,
-0x02, 0x60, 0xc8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60,
-0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
-0x70, 0x47, 0x00, 0x00, 0x80, 0xb5, 0x01, 0xf0, 0x8f, 0xf8, 0x06, 0x4f,
-0xc0, 0x46, 0xf8, 0x60, 0x01, 0xf0, 0xf2, 0xf8, 0x78, 0x80, 0x01, 0xf0,
-0xb1, 0xf8, 0x38, 0x71, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x68, 0x0e, 0x00, 0x80, 0x00, 0xb5, 0x01, 0xf0, 0x05, 0xf9, 0x02, 0x49,
-0xc0, 0x46, 0x08, 0x80, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
-0x0b, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x11, 0xd1, 0xc1, 0x6f, 0x02, 0x23,
-0x0a, 0x68, 0x1a, 0x43, 0x0a, 0x60, 0xc1, 0x6f, 0x80, 0x23, 0x0a, 0x68,
-0x1a, 0x43, 0x0a, 0x60, 0xc1, 0x18, 0x08, 0x68, 0x82, 0x23, 0x02, 0x68,
-0x1a, 0x43, 0x02, 0x60, 0x00, 0x20, 0x08, 0x81, 0x70, 0x47, 0x00, 0x00,
-0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb4, 0x4a, 0x49, 0xca, 0x1d, 0x9d, 0x32,
-0x00, 0x20, 0x00, 0x27, 0x83, 0x00, 0xd7, 0x50, 0x01, 0x30, 0x17, 0x28,
-0xfa, 0xd3, 0x46, 0x4c, 0x00, 0x20, 0x82, 0x00, 0xa7, 0x50, 0x01, 0x30,
-0x20, 0x28, 0xfa, 0xd3, 0x43, 0x4a, 0x00, 0x20, 0x83, 0x00, 0xd7, 0x50,
-0x01, 0x30, 0x20, 0x28, 0xfa, 0xd3, 0xa7, 0x61, 0x97, 0x61, 0x4f, 0x65,
-0x8f, 0x65, 0x3f, 0x4d, 0xc0, 0x46, 0x2f, 0x60, 0x6f, 0x60, 0xaf, 0x60,
-0xaf, 0x61, 0xef, 0x60, 0x2f, 0x61, 0x6f, 0x61, 0x00, 0x20, 0xc1, 0x00,
-0x09, 0x18, 0x49, 0x01, 0x35, 0x4b, 0xc9, 0x18, 0x86, 0x00, 0xcb, 0x1d,
-0xf9, 0x33, 0x34, 0x4c, 0x34, 0x19, 0xe3, 0x63, 0x11, 0x23, 0x5b, 0x01,
-0xcb, 0x18, 0x63, 0x63, 0x0d, 0x23, 0x9b, 0x01, 0xcb, 0x18, 0xb4, 0x18,
-0xe3, 0x63, 0x23, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x61, 0x63, 0x01, 0x30,
-0x02, 0x28, 0xe4, 0xdb, 0x29, 0x48, 0xc1, 0x1d, 0xf9, 0x31, 0x29, 0x4c,
-0xc0, 0x46, 0xa1, 0x62, 0x61, 0x6b, 0x0d, 0x23, 0x9b, 0x01, 0xe1, 0x62,
-0xc1, 0x18, 0x91, 0x62, 0x51, 0x6b, 0xc0, 0x46, 0xd1, 0x62, 0x08, 0x21,
-0xe1, 0x64, 0x25, 0x49, 0xc0, 0x46, 0x21, 0x65, 0x24, 0x49, 0x0b, 0x69,
-0xc0, 0x46, 0x63, 0x65, 0xc3, 0x1d, 0x4d, 0x33, 0xe3, 0x65, 0x25, 0x66,
-0x8b, 0x68, 0xc0, 0x46, 0x63, 0x66, 0xcb, 0x68, 0xc0, 0x46, 0xa3, 0x66,
-0x1e, 0x4b, 0xc0, 0x46, 0xe3, 0x66, 0x27, 0x67, 0x0b, 0x23, 0xdb, 0x01,
-0xc3, 0x18, 0xa3, 0x67, 0x67, 0x67, 0x01, 0x26, 0xe3, 0x1d, 0x69, 0x33,
-0x66, 0x61, 0xe7, 0x61, 0x1f, 0x73, 0x02, 0x23, 0xd3, 0x64, 0x17, 0x4b,
-0xc0, 0x46, 0x13, 0x65, 0xcb, 0x69, 0xc0, 0x46, 0x53, 0x65, 0xc3, 0x1d,
-0x51, 0x33, 0xd3, 0x65, 0x2b, 0x1d, 0x13, 0x66, 0x4b, 0x69, 0xc0, 0x46,
-0x53, 0x66, 0x89, 0x69, 0xc0, 0x46, 0x91, 0x66, 0x0f, 0x49, 0xc0, 0x46,
-0xd1, 0x66, 0x16, 0x67, 0x0f, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x90, 0x67,
-0x56, 0x67, 0xd7, 0x61, 0xd0, 0x1d, 0x69, 0x30, 0x56, 0x61, 0x07, 0x73,
-0xf0, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xe4, 0x2c, 0x00, 0x80,
-0x64, 0x2d, 0x00, 0x80, 0x90, 0xee, 0x20, 0x40, 0x30, 0x01, 0x18, 0x00,
-0x7c, 0x29, 0x00, 0x80, 0x00, 0x55, 0xff, 0xff, 0x38, 0x01, 0x18, 0x00,
-0x10, 0x55, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x21, 0x1e, 0x4a, 0xbb, 0x23,
-0x1b, 0x01, 0xd7, 0x18, 0xf9, 0x73, 0x19, 0x23,
-0xdb, 0x01, 0xd0, 0x18, 0x01, 0x24, 0xcd, 0x23, 0x1b, 0x01, 0xd3, 0x18,
-0xc1, 0x61, 0x1c, 0x70, 0x33, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x99, 0x60,
-0xb9, 0x73, 0x59, 0x61, 0x2f, 0x23, 0x9b, 0x01, 0xd3, 0x18, 0x19, 0x60,
-0x13, 0x4b, 0x51, 0x27, 0xbf, 0x03, 0x03, 0x63, 0x3b, 0x60, 0x84, 0x69,
-0xe4, 0x18, 0x44, 0x63, 0x04, 0x3c, 0x7c, 0x60, 0x01, 0x24, 0xe4, 0x02,
-0x84, 0x63, 0x0e, 0x4c, 0xc0, 0x46, 0xbc, 0x60, 0x04, 0x6b, 0xc0, 0x46,
-0x44, 0x62, 0x84, 0x69, 0xe4, 0x18, 0x0b, 0x4b, 0xe3, 0x18, 0xfb, 0x60,
-0x03, 0x6b, 0xc0, 0x46, 0x83, 0x62, 0x43, 0x6a, 0xc0, 0x46, 0x03, 0x62,
-0xc1, 0x63, 0x51, 0x64, 0x91, 0x64, 0xd1, 0x65, 0xd1, 0x66, 0x90, 0xbc,
-0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40,
-0xfc, 0x07, 0x00, 0x00, 0xfc, 0xf7, 0xff, 0xff, 0x90, 0xb4, 0x00, 0x22,
-0x1b, 0x49, 0xc9, 0x23, 0x1b, 0x01, 0xc8, 0x18, 0x02, 0x71, 0x01, 0x20,
-0xbb, 0x23, 0x1b, 0x01, 0xcb, 0x18, 0x58, 0x73, 0x17, 0x48, 0x03, 0x1c,
-0x00, 0x27, 0xdc, 0x1d, 0xc1, 0x34, 0x1c, 0x65, 0x23, 0x1c, 0x01, 0x37,
-0x3f, 0x2f, 0xf8, 0xd3, 0x1a, 0x65, 0x19, 0x23, 0xdb, 0x01, 0xcf, 0x18,
-0x33, 0x23, 0x9b, 0x01, 0xcb, 0x18, 0x3a, 0x61, 0x98, 0x61, 0x40, 0x20,
-0xf8, 0x60, 0xda, 0x61, 0x1a, 0x62, 0xca, 0x64, 0x0a, 0x66, 0x0c, 0x48,
-0xc0, 0x46, 0xc2, 0x60, 0x0b, 0x48, 0x00, 0x6b, 0xc0, 0x06, 0xc0, 0x0e,
-0xf8, 0x63, 0x0a, 0x48, 0x01, 0x68, 0xc0, 0x46, 0x19, 0x80, 0x41, 0x68,
-0xc0, 0x46, 0x59, 0x80, 0x80, 0x68, 0xc0, 0x46, 0x98, 0x80, 0x90, 0xbc,
-0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xbc, 0x20, 0x40,
-0x90, 0xee, 0x20, 0x40, 0x80, 0x00, 0x14, 0x40, 0x40, 0x00, 0x14, 0x40,
-0x00, 0x20, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x73, 0xcb, 0x1d, 0xff, 0x33,
-0x3a, 0x33, 0x88, 0x61, 0xc8, 0x61, 0x18, 0x70, 0x06, 0x4a, 0xc0, 0x46,
-0x10, 0x65, 0x50, 0x66, 0x90, 0x66, 0x08, 0x70, 0x58, 0x70, 0xbb, 0x23,
-0x1b, 0x01, 0xd1, 0x18, 0x08, 0x73, 0x70, 0x47, 0x28, 0x05, 0x00, 0x80,
-0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb4, 0x2f, 0x49, 0x2f, 0x4a, 0xc0, 0x46,
-0x11, 0x61, 0x01, 0x23, 0x9b, 0x02, 0xc8, 0x18, 0x50, 0x61, 0x2d, 0x48,
-0xc0, 0x46, 0x10, 0x62, 0xdb, 0x00, 0xc3, 0x18, 0x53, 0x62, 0x00, 0x23,
-0x13, 0x63, 0x53, 0x63, 0x29, 0x4a, 0x2a, 0x4f, 0xd4, 0x1d, 0xff, 0x34,
-0xfa, 0x34, 0x14, 0xc7, 0x08, 0x3f, 0x3b, 0x61, 0x1c, 0x1f, 0x7c, 0x61,
-0x26, 0x4f, 0xc0, 0x46, 0x39, 0x60, 0xb8, 0x61, 0x79, 0x61, 0xf8, 0x62,
-0x3b, 0x63, 0x7b, 0x64, 0xba, 0x64, 0xfa, 0x65, 0x22, 0x4f, 0xfe, 0x1d,
-0xf9, 0x36, 0x22, 0x4d, 0xec, 0x1d, 0x79, 0x34, 0x26, 0x62, 0x51, 0x26,
-0xb6, 0x03, 0x37, 0x61, 0x24, 0x6a, 0xc0, 0x46, 0x74, 0x61, 0x2f, 0x67,
-0x1d, 0x4d, 0x09, 0x27, 0x7f, 0x04, 0xec, 0x1d, 0x75, 0x34, 0x7c, 0x60,
-0x3d, 0x60, 0x1b, 0x4c, 0xc0, 0x46, 0x3c, 0x61, 0xe6, 0x1d, 0x75, 0x36,
-0x7e, 0x61, 0x19, 0x4f, 0xc0, 0x46, 0x7c, 0x60, 0x3d, 0x60, 0x0f, 0x1c,
-0x00, 0x21, 0xff, 0x24, 0x01, 0x34, 0x1d, 0x1c, 0x8b, 0x00, 0xfd, 0x50,
-0x01, 0x31, 0xa1, 0x42, 0xfa, 0xd3, 0x01, 0x1c, 0x00, 0x20, 0x01, 0x27,
-0xff, 0x02, 0x83, 0x00, 0xcd, 0x50, 0x01, 0x30, 0xb8, 0x42, 0xfa, 0xd3,
-0x00, 0x20, 0x81, 0x00, 0x55, 0x50, 0x01, 0x30, 0x80, 0x28, 0xfa, 0xd3,
-0xf0, 0xbc, 0x70, 0x47, 0x24, 0xa3, 0x20, 0x40,
-0x40, 0x01, 0x18, 0x00, 0x24, 0x83, 0x20, 0x40, 0x24, 0xa9, 0x20, 0x40,
-0x80, 0x01, 0x18, 0x00, 0xa8, 0x03, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40,
-0x68, 0x0e, 0x00, 0x80, 0x24, 0xa8, 0x20, 0x40, 0xa4, 0xa8, 0x20, 0x40,
-0x08, 0x04, 0x00, 0x80, 0xb8, 0xb5, 0x2c, 0x48, 0xfd, 0xf7, 0xba, 0xfd,
-0x01, 0x20, 0x2b, 0x49, 0x0a, 0x68, 0x52, 0x0c, 0x06, 0xd2, 0x0a, 0x68,
-0x12, 0x0c, 0x02, 0xd1, 0x0a, 0x68, 0x92, 0x0a, 0x00, 0xd2, 0x00, 0x20,
-0x04, 0x06, 0x24, 0x0e, 0x25, 0x4a, 0xd7, 0x1d, 0x0d, 0x37, 0x00, 0x23,
-0x00, 0x20, 0x9d, 0x00, 0x78, 0x51, 0x01, 0x33, 0x04, 0x2b, 0xfa, 0xd3,
-0x01, 0x27, 0x3f, 0x05, 0x50, 0x61, 0xf8, 0x60, 0xd0, 0x61, 0xf8, 0x61,
-0x00, 0x23, 0xdb, 0x43, 0x93, 0x61, 0x3b, 0x61, 0x13, 0x62, 0x3b, 0x62,
-0x00, 0x27, 0x1b, 0x4b, 0x8d, 0x68, 0xc0, 0x46, 0x00, 0x95, 0x8d, 0x69,
-0xc0, 0x46, 0x00, 0x95, 0x00, 0x2c, 0x0b, 0xd0, 0xdd, 0x6b, 0xc0, 0x46,
-0x00, 0x95, 0x9d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x5d, 0x6b, 0xc0, 0x46,
-0x00, 0x95, 0x1d, 0x6b, 0xc0, 0x46, 0x00, 0x95, 0x01, 0x37, 0x40, 0x2f,
-0xe8, 0xd3, 0x00, 0x27, 0x6c, 0x46, 0x01, 0x23, 0x5b, 0x07, 0x1c, 0x43,
-0x01, 0xe0, 0x20, 0x60, 0x01, 0x37, 0x0d, 0x68, 0x2b, 0x09, 0x02, 0xd2,
-0x80, 0x2f, 0xf8, 0xd3, 0x01, 0xe0, 0x80, 0x2f, 0x03, 0xd3, 0x08, 0x49,
-0x4b, 0x6e, 0x01, 0x33, 0x4b, 0x66, 0xd0, 0x62, 0xb8, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0xf4, 0x01, 0xff, 0xff, 0x00, 0x00, 0x10, 0x40,
-0x68, 0x0e, 0x00, 0x80, 0x00, 0x01, 0x18, 0x40, 0xa0, 0x82, 0x20, 0x40,
-0x90, 0xb4, 0x00, 0x21, 0x0e, 0x4f, 0x0f, 0x4a, 0x00, 0x20, 0x4c, 0x01,
-0x64, 0x1a, 0xa4, 0x00, 0xa3, 0x18, 0x58, 0x60, 0x98, 0x60, 0x18, 0x64,
-0x58, 0x64, 0x10, 0x53, 0x58, 0x80, 0xcc, 0x00, 0xe4, 0x19, 0x98, 0x67,
-0xdc, 0x62, 0x01, 0x31, 0x03, 0x29, 0xee, 0xd3, 0x06, 0x49, 0xc0, 0x46,
-0x08, 0x60, 0x48, 0x60, 0x88, 0x60, 0xc8, 0x60, 0x08, 0x61, 0x90, 0xbc,
-0x70, 0x47, 0x00, 0x00, 0xac, 0x66, 0x21, 0x40, 0x5c, 0x2b, 0x00, 0x80,
-0xd0, 0x2c, 0x00, 0x80, 0x64, 0x21, 0x05, 0x48, 0xc0, 0x46, 0x01, 0x63,
-0x00, 0x21, 0xc9, 0x43, 0x41, 0x63, 0x81, 0x63, 0x00, 0x21, 0xc1, 0x63,
-0x01, 0x64, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x80, 0xb4, 0x01, 0x20,
-0x40, 0x02, 0x0a, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x3c, 0x20, 0x48, 0x60,
-0x88, 0x60, 0x08, 0x48, 0xc0, 0x46, 0xc8, 0x60, 0x00, 0x20, 0x07, 0x4a,
-0x87, 0x00, 0xcb, 0x68, 0xc0, 0x46, 0xda, 0x51, 0x01, 0x30, 0x10, 0x28,
-0xf8, 0xd3, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, 0xe4, 0x2d, 0x00, 0x80,
-0xf4, 0x2d, 0x00, 0x80, 0x5d, 0x4c, 0xff, 0xff, 0x12, 0x49, 0x13, 0x48,
-0x67, 0x23, 0x9b, 0x01, 0xca, 0x18, 0x06, 0xc0, 0x08, 0x38, 0x11, 0x4b,
-0xca, 0x18, 0xc1, 0x60, 0x82, 0x60, 0x01, 0x61, 0x0f, 0x49, 0x10, 0x48,
-0xa7, 0x23, 0x9b, 0x01, 0xca, 0x18, 0x06, 0xc0, 0x08, 0x38, 0x0e, 0x4b,
-0xca, 0x18, 0xc1, 0x60, 0x82, 0x60, 0x01, 0x61, 0x0c, 0x48, 0x0d, 0x49,
-0x67, 0x23, 0x9b, 0x01, 0xc2, 0x18, 0x05, 0xc1, 0x08, 0x39, 0x05, 0x4b,
-0xc2, 0x18, 0xc8, 0x60, 0x8a, 0x60, 0x08, 0x61, 0x70, 0x47, 0x00, 0x00,
-0xac, 0x1e, 0x21, 0x40, 0x48, 0x2e, 0x00, 0x80, 0xfc, 0x1f, 0x00, 0x00,
-0xac, 0xee, 0x20, 0x40, 0x34, 0x2e, 0x00, 0x80, 0xfc, 0x2f, 0x00, 0x00,
-0xac, 0x3e, 0x21, 0x40, 0x5c, 0x2e, 0x00, 0x80,
-0x90, 0xb4, 0x00, 0x21, 0x40, 0x4c, 0x00, 0x20, 0x0a, 0x01, 0x12, 0x19,
-0x19, 0x23, 0xdb, 0x01, 0xd2, 0x18, 0xd0, 0x62, 0x10, 0x63, 0x50, 0x63,
-0x90, 0x63, 0x01, 0x31, 0x03, 0x29, 0xf3, 0xd3, 0x3a, 0x49, 0xc0, 0x46,
-0x08, 0x63, 0x48, 0x63, 0x88, 0x63, 0x20, 0x60, 0x01, 0x21, 0xe3, 0x1d,
-0x59, 0x33, 0x60, 0x60, 0x19, 0x71, 0x18, 0x72, 0x98, 0x71, 0x98, 0x72,
-0x59, 0x71, 0x58, 0x72, 0xd8, 0x71, 0xd8, 0x72, 0xe2, 0x1d, 0x49, 0x32,
-0x11, 0x73, 0x19, 0x70, 0x90, 0x73, 0x98, 0x70, 0x51, 0x73, 0x59, 0x70,
-0xd0, 0x73, 0xd8, 0x70, 0x11, 0x71, 0x11, 0x72, 0x90, 0x71, 0x90, 0x72,
-0x50, 0x71, 0x50, 0x72, 0xd0, 0x71, 0xd0, 0x72, 0x18, 0x73, 0x02, 0x22,
-0xe7, 0x1d, 0x69, 0x37, 0x3a, 0x70, 0x99, 0x73, 0xba, 0x70, 0x58, 0x73,
-0x78, 0x70, 0xd8, 0x73, 0xf8, 0x70, 0x39, 0x71, 0x3a, 0x72, 0xb9, 0x71,
-0xb9, 0x72, 0x78, 0x71, 0x7a, 0x72, 0xf9, 0x71, 0xf9, 0x72, 0x39, 0x73,
-0xe3, 0x1d, 0x79, 0x33, 0x1a, 0x70, 0xb9, 0x73, 0x99, 0x70, 0x78, 0x73,
-0x5a, 0x70, 0xf9, 0x73, 0xd9, 0x70, 0x1a, 0x71, 0x1a, 0x72, 0x99, 0x71,
-0x9a, 0x72, 0x58, 0x71, 0x5a, 0x72, 0xd9, 0x71, 0xda, 0x72, 0x19, 0x73,
-0xe7, 0x1d, 0x89, 0x37, 0x3a, 0x70, 0x99, 0x73, 0xb9, 0x70, 0x58, 0x73,
-0x7a, 0x70, 0xd9, 0x73, 0xf9, 0x70, 0x39, 0x71, 0x3a, 0x72, 0xb9, 0x71,
-0xb9, 0x72, 0x78, 0x71, 0x7a, 0x72, 0xf9, 0x71, 0xf9, 0x72, 0x3a, 0x73,
-0xe3, 0x1d, 0x99, 0x33, 0x1a, 0x70, 0xb9, 0x73, 0x9a, 0x70, 0x78, 0x73,
-0x5a, 0x70, 0xf9, 0x73, 0xda, 0x70, 0x19, 0x71, 0x1a, 0x72, 0x99, 0x71,
-0x99, 0x72, 0x58, 0x71, 0x5a, 0x72, 0xd9, 0x71, 0xd9, 0x72, 0x20, 0x61,
-0xe0, 0x60, 0x60, 0x61, 0xa0, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x00,
-0xa0, 0x1c, 0x00, 0x80, 0xe8, 0x19, 0x00, 0x80, 0x81, 0x20, 0x00, 0x02,
-0x01, 0x49, 0xc0, 0x46, 0x88, 0x62, 0x70, 0x47, 0xc0, 0x00, 0x14, 0x00,
-0x09, 0x49, 0x0a, 0x4b, 0xc8, 0x18, 0x04, 0x3b, 0xc9, 0x18, 0x08, 0x60,
-0x00, 0x21, 0xc2, 0x1d, 0x29, 0x32, 0xc2, 0x61, 0x10, 0x1c, 0x01, 0x31,
-0x08, 0x29, 0xf8, 0xd3, 0xc1, 0x1f, 0x29, 0x39, 0x00, 0x20, 0xc8, 0x61,
-0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x84, 0x09, 0x00, 0x00,
-0x06, 0x48, 0x07, 0x49, 0xc0, 0x46, 0x08, 0x80, 0x48, 0x80, 0x00, 0x20,
-0x88, 0x80, 0xc8, 0x80, 0x88, 0x60, 0x04, 0x49, 0xc0, 0x46, 0x48, 0x61,
-0x88, 0x61, 0x70, 0x47, 0xff, 0xff, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80,
-0x6c, 0x06, 0x00, 0x80, 0x00, 0x21, 0x06, 0x48, 0xc2, 0x1d, 0x19, 0x32,
-0xc1, 0x60, 0x01, 0x61, 0xc1, 0x61, 0x01, 0x62, 0x11, 0x71, 0xff, 0x30,
-0x01, 0x30, 0x41, 0x62, 0x70, 0x47, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
-0x09, 0x48, 0x0a, 0x4b, 0xc0, 0x46, 0x18, 0x60, 0x00, 0x21, 0xc2, 0x1d,
-0x4d, 0x32, 0xc2, 0x60, 0x10, 0x1c, 0x01, 0x31, 0x14, 0x29, 0xf8, 0xd3,
-0xc1, 0x1f, 0x4d, 0x39, 0x00, 0x20, 0xc8, 0x60, 0x58, 0x60, 0x98, 0x60,
-0x70, 0x47, 0x00, 0x00, 0xd8, 0x07, 0x00, 0x80, 0x6c, 0x06, 0x00, 0x80,
-0x00, 0xb5, 0x0b, 0x49, 0x0b, 0x48, 0xfd, 0xf7, 0xea, 0xfb, 0x0b, 0x48,
-0x00, 0x6a, 0x01, 0x23, 0xdb, 0x03, 0x98, 0x43, 0x09, 0x49, 0xc0, 0x46,
-0x08, 0x62, 0x09, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x04, 0xd1, 0xc0, 0x6f,
-0x80, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x08, 0xbc, 0x18, 0x47,
-0xc1, 0xbd, 0x21, 0x40, 0x75, 0x98, 0x21, 0x40,
-0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0x00, 0xb5, 0x0f, 0x48, 0xc1, 0x68, 0x01, 0x29, 0x04, 0xd1, 0xc0, 0x6f,
-0x80, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0x0b, 0x4b, 0x0c, 0x48,
-0x0c, 0x4a, 0x00, 0x21, 0xfd, 0xf7, 0xbf, 0xfb, 0x0b, 0x48, 0x41, 0x8d,
-0x01, 0x31, 0x41, 0x85, 0x00, 0x21, 0xc1, 0x85, 0x09, 0x48, 0x00, 0x6a,
-0x01, 0x23, 0xdb, 0x03, 0x18, 0x43, 0x08, 0x49, 0xc0, 0x46, 0x08, 0x62,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x59, 0xbd, 0x21, 0x40,
-0x75, 0x98, 0x21, 0x40, 0xb8, 0x0b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
-0xc0, 0x00, 0x18, 0x40, 0xc0, 0x00, 0x18, 0x00, 0xf0, 0xb5, 0x1b, 0x4c,
-0x10, 0x26, 0xe0, 0x68, 0x01, 0x28, 0x08, 0xd1, 0x60, 0x88, 0x00, 0x28,
-0x05, 0xd1, 0x20, 0x79, 0x00, 0x28, 0x02, 0xd1, 0x19, 0x20, 0xa0, 0x67,
-0x00, 0xe0, 0xa6, 0x67, 0x00, 0x20, 0x07, 0x23, 0x5b, 0x02, 0xe5, 0x18,
-0xc1, 0x43, 0xe8, 0x61, 0x69, 0x62, 0x59, 0x08, 0xa1, 0x27, 0x7f, 0x03,
-0x79, 0x60, 0x0f, 0x21, 0x79, 0x60, 0xe1, 0x1d, 0xb9, 0x31, 0x08, 0x71,
-0x01, 0x20, 0xb8, 0x60, 0x40, 0x02, 0xb8, 0x60, 0x00, 0xf0, 0x4c, 0xfa,
-0x00, 0xf0, 0xf0, 0xfa, 0x04, 0x20, 0xb8, 0x60, 0x07, 0x20, 0x78, 0x61,
-0x7e, 0x60, 0x1b, 0x23, 0xdb, 0x01, 0xe0, 0x18, 0xc0, 0x8b, 0x04, 0x23,
-0x18, 0x40, 0xe8, 0x62, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x68, 0x0e, 0x00, 0x80, 0x90, 0xb4, 0x02, 0x1c, 0x00, 0x20, 0xff, 0x23,
-0x01, 0x33, 0x9a, 0x42, 0x08, 0xd0, 0x01, 0x29, 0x00, 0xd1, 0x01, 0x20,
-0x00, 0x2a, 0x01, 0xd1, 0x02, 0x23, 0x18, 0x43, 0x90, 0xbc, 0x70, 0x47,
-0x1b, 0x4a, 0xd7, 0x68, 0x1a, 0x4b, 0x19, 0x79, 0x1c, 0x1c, 0x37, 0x23,
-0x9b, 0x01, 0xe3, 0x18, 0x01, 0x2f, 0x0d, 0xd1, 0x57, 0x88, 0x00, 0x2f,
-0x0a, 0xd1, 0x00, 0x29, 0x0a, 0xd1, 0x59, 0x8b, 0x0a, 0x09, 0x00, 0xd3,
-0x02, 0x20, 0x49, 0x09, 0xe8, 0xd3, 0x01, 0x23, 0x18, 0x43, 0xe5, 0xe7,
-0x00, 0x29, 0x03, 0xd0, 0x98, 0x8a, 0x80, 0x07, 0x80, 0x0f, 0xdf, 0xe7,
-0x6d, 0x23, 0x5b, 0x01, 0xd1, 0x18, 0x8a, 0x88, 0xff, 0x27, 0x01, 0x37,
-0x17, 0x40, 0x0a, 0x49, 0xc9, 0x88, 0x03, 0xd0, 0x4b, 0x0a, 0x01, 0xd3,
-0x03, 0x20, 0xd1, 0xe7, 0x13, 0x0a, 0x03, 0xd3, 0x0b, 0x0a, 0x01, 0xd3,
-0x02, 0x20, 0xcb, 0xe7, 0xd2, 0x09, 0xc9, 0xd3, 0xc9, 0x09, 0xc7, 0xd3,
-0x01, 0x20, 0xc5, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0x08, 0x1c, 0x00, 0x80,
-0xf0, 0xb5, 0xc1, 0xb0, 0x01, 0x20, 0x00, 0x07, 0x52, 0x49, 0xc0, 0x46,
-0x08, 0x60, 0x52, 0x48, 0x42, 0x69, 0x40, 0x0d, 0xa1, 0x21, 0x49, 0x03,
-0x48, 0x60, 0x50, 0x48, 0xc0, 0x6a, 0x50, 0x4b, 0x18, 0x43, 0x00, 0x21,
-0x03, 0x03, 0x1b, 0x0b, 0x4e, 0x4c, 0x27, 0x6f, 0x3d, 0x03, 0x2d, 0x0b,
-0xe7, 0x1d, 0x79, 0x37, 0xab, 0x42, 0x1c, 0xd0, 0xe3, 0x1d, 0x79, 0x33,
-0x1b, 0x6a, 0xc0, 0x46, 0x40, 0x93, 0x01, 0x23, 0x9b, 0x07, 0x03, 0x43,
-0x1b, 0x68, 0xcc, 0x00, 0x6e, 0x46, 0x33, 0x51, 0x01, 0x23, 0x9b, 0x07,
-0x06, 0x1d, 0x33, 0x43, 0x1b, 0x68, 0x6c, 0x44, 0x63, 0x60, 0x08, 0x30,
-0x01, 0x31, 0x40, 0x9b, 0x83, 0x42, 0x00, 0xd8, 0x3f, 0x48, 0x03, 0x03,
-0x1b, 0x0b, 0xab, 0x42, 0xe7, 0xd1, 0x00, 0x20, 0x01, 0x23, 0x1b, 0x03,
-0x13, 0x40, 0x3c, 0x4c, 0x03, 0xd0, 0x63, 0x6a, 0x01, 0x33, 0x63, 0x62,
-0x09, 0xe0, 0x13, 0x0b, 0x03, 0xd3, 0x23, 0x6a,
-0x01, 0x33, 0x23, 0x62, 0x03, 0xe0, 0x37, 0x4b, 0x5c, 0x6d, 0x01, 0x34,
-0x5c, 0x65, 0x00, 0x29, 0x09, 0xd0, 0x03, 0x1c, 0xdc, 0x00, 0x23, 0x1c,
-0x6b, 0x44, 0x5c, 0x68, 0x01, 0x30, 0x23, 0x0d, 0x01, 0xd2, 0x88, 0x42,
-0xf5, 0xd1, 0x30, 0x4c, 0x25, 0x68, 0x6b, 0x0c, 0x05, 0xd2, 0x23, 0x68,
-0x1b, 0x0c, 0x08, 0xd1, 0x24, 0x68, 0xa3, 0x0a, 0x05, 0xd3, 0x20, 0x24,
-0x2b, 0x4b, 0xc0, 0x46, 0x5c, 0x62, 0x00, 0x24, 0x5c, 0x62, 0x25, 0x4b,
-0x23, 0x4c, 0x51, 0x26, 0xb6, 0x03, 0x23, 0x67, 0x33, 0x61, 0x3d, 0x6a,
-0xc0, 0x46, 0x75, 0x61, 0x02, 0x25, 0xa1, 0x26, 0x76, 0x03, 0x75, 0x60,
-0x01, 0x25, 0xb5, 0x60, 0xe6, 0x1d, 0xb9, 0x36, 0x35, 0x71, 0x88, 0x42,
-0x21, 0xd0, 0x25, 0x1c, 0xc3, 0x00, 0x6c, 0x46, 0xe4, 0x58, 0x2e, 0x6f,
-0x6b, 0x44, 0x34, 0x60, 0x5b, 0x68, 0x2c, 0x6f, 0xc0, 0x46, 0x63, 0x60,
-0x2b, 0x6f, 0x08, 0x33, 0x2b, 0x67, 0x3c, 0x6a, 0xa3, 0x42, 0x02, 0xd3,
-0x12, 0x4b, 0xc0, 0x46, 0x2b, 0x67, 0x03, 0x1c, 0xdb, 0x00, 0x6b, 0x44,
-0x5c, 0x68, 0x01, 0x30, 0x23, 0x0d, 0x04, 0xd3, 0x51, 0x24, 0xa4, 0x03,
-0x2b, 0x6f, 0xc0, 0x46, 0xa3, 0x61, 0x88, 0x42, 0xde, 0xd1, 0x10, 0x0b,
-0x03, 0xd3, 0x0e, 0x49, 0x01, 0x20, 0xfd, 0xf7, 0x74, 0xfa, 0x41, 0xb0,
-0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0,
-0x00, 0x01, 0x14, 0x40, 0x00, 0x40, 0x14, 0x40, 0x00, 0x00, 0x20, 0x40,
-0x68, 0x0e, 0x00, 0x80, 0x24, 0xa7, 0x20, 0x40, 0xa4, 0x2a, 0x00, 0x80,
-0xa0, 0x82, 0x20, 0x40, 0x00, 0x00, 0x10, 0x40, 0xc0, 0x00, 0x18, 0x00,
-0xc9, 0x4f, 0xff, 0xff, 0xf0, 0xb4, 0x00, 0x21, 0x00, 0x23, 0x07, 0x22,
-0x06, 0x24, 0x47, 0x4f, 0xc0, 0x46, 0x3c, 0x61, 0x3a, 0x61, 0x01, 0x33,
-0x20, 0x2b, 0xf9, 0xd3, 0x04, 0x25, 0x3d, 0x61, 0x05, 0x23, 0x3b, 0x61,
-0x3c, 0x61, 0x3a, 0x61, 0x3c, 0x61, 0x3a, 0x61, 0x3d, 0x61, 0x3b, 0x61,
-0x3f, 0x4d, 0xab, 0x6f, 0xde, 0x08, 0x02, 0x23, 0x1e, 0x40, 0x04, 0x23,
-0x33, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f,
-0x9e, 0x08, 0x02, 0x23, 0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, 0x3b, 0x61,
-0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f, 0x5e, 0x08, 0x02, 0x23,
-0x1e, 0x40, 0x04, 0x23, 0x33, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x33, 0x43,
-0x3b, 0x61, 0x02, 0x23, 0xae, 0x6f, 0x1e, 0x40, 0x04, 0x23, 0x33, 0x43,
-0x3b, 0x61, 0x05, 0x23, 0x33, 0x43, 0x3b, 0x61, 0xab, 0x6f, 0x5d, 0x00,
-0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23,
-0x2b, 0x43, 0x3b, 0x61, 0xc5, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23,
-0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x85, 0x08,
-0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23,
-0x2b, 0x43, 0x3b, 0x61, 0x45, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23,
-0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x02, 0x25,
-0x05, 0x40, 0x04, 0x23, 0x2b, 0x43, 0x3b, 0x61, 0x05, 0x23, 0x2b, 0x43,
-0x3b, 0x61, 0x40, 0x00, 0x02, 0x23, 0x18, 0x40, 0x04, 0x23, 0x03, 0x43,
-0x3b, 0x61, 0x05, 0x23, 0x18, 0x43, 0x38, 0x61, 0x00, 0x25, 0x3d, 0x61,
-0x01, 0x23, 0x3b, 0x61, 0x3d, 0x61, 0x3b, 0x61, 0x00, 0x20, 0x3d, 0x61,
-0x0d, 0x4b, 0x1b, 0x69, 0x49, 0x00, 0x1e, 0x1c, 0x02, 0x23, 0x33, 0x40,
-0x19, 0x43, 0x01, 0x23, 0x3b, 0x61, 0x01, 0x30,
-0x10, 0x28, 0xf2, 0xd3, 0x02, 0x20, 0x38, 0x61, 0x03, 0x20, 0x38, 0x61,
-0x3c, 0x61, 0x3a, 0x61, 0x3c, 0x61, 0x3a, 0x61, 0x38, 0x61, 0x48, 0x08,
-0xf0, 0xbc, 0x70, 0x47, 0x80, 0x00, 0x14, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0x80, 0x00, 0x14, 0x40, 0xf0, 0xb4, 0x00, 0x24, 0x07, 0x23, 0x06, 0x27,
-0x44, 0x4a, 0xc0, 0x46, 0x17, 0x61, 0x13, 0x61, 0x01, 0x34, 0x20, 0x2c,
-0xf9, 0xd3, 0x04, 0x26, 0x16, 0x61, 0x05, 0x24, 0x14, 0x61, 0x17, 0x61,
-0x07, 0x23, 0x13, 0x61, 0x16, 0x61, 0x14, 0x61, 0x17, 0x61, 0x13, 0x61,
-0x3c, 0x4b, 0x9b, 0x6f, 0xdd, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c,
-0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x37, 0x4b, 0x9b, 0x6f,
-0x9d, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61,
-0x25, 0x43, 0x15, 0x61, 0x32, 0x4b, 0x9b, 0x6f, 0x5d, 0x08, 0x02, 0x23,
-0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61,
-0x2d, 0x4b, 0x9d, 0x6f, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43,
-0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x29, 0x4b, 0x9b, 0x6f, 0x5d, 0x00,
-0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43,
-0x15, 0x61, 0xc5, 0x08, 0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43,
-0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x85, 0x08, 0x02, 0x23, 0x1d, 0x40,
-0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43, 0x15, 0x61, 0x45, 0x08,
-0x02, 0x23, 0x1d, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61, 0x25, 0x43,
-0x15, 0x61, 0x02, 0x25, 0x05, 0x40, 0x2b, 0x1c, 0x33, 0x43, 0x13, 0x61,
-0x25, 0x43, 0x15, 0x61, 0x40, 0x00, 0x02, 0x23, 0x18, 0x40, 0x03, 0x1c,
-0x33, 0x43, 0x13, 0x61, 0x20, 0x43, 0x10, 0x61, 0x17, 0x61, 0x07, 0x23,
-0x13, 0x61, 0x16, 0x61, 0x14, 0x61, 0x4c, 0x00, 0x00, 0x20, 0x0f, 0x21,
-0x25, 0x1c, 0xcd, 0x40, 0x02, 0x23, 0x1d, 0x40, 0x04, 0x23, 0x2b, 0x43,
-0x13, 0x61, 0x05, 0x23, 0x2b, 0x43, 0x13, 0x61, 0x01, 0x30, 0x01, 0x39,
-0x10, 0x28, 0xf1, 0xd3, 0x17, 0x61, 0x07, 0x23, 0x13, 0x61, 0x17, 0x61,
-0x13, 0x61, 0x03, 0x20, 0x10, 0x61, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00,
-0x80, 0x00, 0x14, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x4f, 0x4d,
-0x08, 0x21, 0x02, 0x20, 0x2a, 0x1c, 0xfd, 0xf7, 0x27, 0xf9, 0x4d, 0x4c,
-0x71, 0x23, 0x5b, 0x01, 0xe7, 0x18, 0x38, 0x80, 0x1a, 0x21, 0x02, 0x20,
-0x2a, 0x1c, 0xfd, 0xf7, 0x1d, 0xf9, 0x78, 0x80, 0x20, 0x79, 0x00, 0x28,
-0x0b, 0xd0, 0x00, 0x20, 0x38, 0x80, 0xe0, 0x68, 0x01, 0x28, 0x10, 0xd1,
-0x44, 0x48, 0x00, 0x68, 0x01, 0x23, 0x9b, 0x02, 0x18, 0x43, 0x99, 0x02,
-0x08, 0x60, 0xe0, 0x68, 0x01, 0x28, 0x06, 0xd1, 0x60, 0x88, 0x00, 0x28,
-0x03, 0xd1, 0xf9, 0x21, 0x12, 0x20, 0xff, 0xf7, 0x43, 0xff, 0x01, 0x21,
-0xc9, 0x03, 0x00, 0x20, 0xff, 0xf7, 0x3e, 0xff, 0x00, 0x25, 0x7d, 0x26,
-0xf6, 0x00, 0x00, 0xe0, 0x01, 0x35, 0x00, 0x20, 0xff, 0xf7, 0x9c, 0xfe,
-0x00, 0x0c, 0x01, 0xd3, 0xb5, 0x42, 0xf7, 0xd3, 0x00, 0x25, 0x05, 0xe0,
-0x03, 0x21, 0x09, 0x03, 0x00, 0x20, 0xff, 0xf7, 0x2b, 0xff, 0x01, 0x35,
-0x00, 0x20, 0xff, 0xf7, 0x8d, 0xfe, 0x40, 0x0b, 0x01, 0xd2, 0xb5, 0x42,
-0xf2, 0xd3, 0x04, 0x20, 0xff, 0xf7, 0x86, 0xfe, 0xff, 0x23, 0xe1, 0x33,
-0x98, 0x43, 0x01, 0x21, 0x01, 0x43, 0x38, 0x88, 0xff, 0x23, 0x01, 0x33,
-0x98, 0x42, 0x03, 0xd1, 0x2f, 0x23, 0x5b, 0x01,
-0x19, 0x43, 0x16, 0xe0, 0x01, 0x28, 0x09, 0xd1, 0x78, 0x88, 0x01, 0x28,
-0x03, 0xd1, 0x23, 0x23, 0x5b, 0x01, 0x19, 0x43, 0x0d, 0xe0, 0x20, 0x23,
-0x19, 0x43, 0x0a, 0xe0, 0x00, 0x28, 0x08, 0xd1, 0x78, 0x88, 0x01, 0x28,
-0x03, 0xd1, 0x0b, 0x23, 0xdb, 0x01, 0x19, 0x43, 0x01, 0xe0, 0x80, 0x23,
-0x19, 0x43, 0x04, 0x20, 0xff, 0xf7, 0xf8, 0xfe, 0x09, 0x21, 0x49, 0x02,
-0x00, 0x20, 0xff, 0xf7, 0xf3, 0xfe, 0xe0, 0x68, 0x00, 0x28, 0x0c, 0xd1,
-0x00, 0x21, 0x1b, 0x20, 0xff, 0xf7, 0xec, 0xfe, 0x1a, 0x20, 0xff, 0xf7,
-0x4f, 0xfe, 0x01, 0x21, 0xc9, 0x03, 0x01, 0x43, 0x1a, 0x20, 0xff, 0xf7,
-0xe3, 0xfe, 0x00, 0x27, 0x03, 0xe0, 0x08, 0x2f, 0x01, 0xd3, 0x0f, 0x2f,
-0x08, 0xd9, 0x38, 0x1c, 0xff, 0xf7, 0x40, 0xfe, 0x79, 0x00, 0x09, 0x19,
-0x1b, 0x23, 0xdb, 0x01, 0xc9, 0x18, 0x88, 0x83, 0x01, 0x37, 0x20, 0x2f,
-0xef, 0xd3, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xed, 0xaf, 0x21, 0x40,
-0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 0x81, 0xb0, 0x13, 0x48,
-0x01, 0x68, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x68, 0xc0, 0x46, 0x00, 0x91,
-0x81, 0x68, 0xc0, 0x46, 0x00, 0x91, 0xc1, 0x68, 0xc0, 0x46, 0x00, 0x91,
-0x01, 0x69, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x69, 0xc0, 0x46, 0x00, 0x91,
-0x81, 0x69, 0xc0, 0x46, 0x00, 0x91, 0xc1, 0x69, 0xc0, 0x46, 0x00, 0x91,
-0x01, 0x6a, 0xc0, 0x46, 0x00, 0x91, 0x41, 0x6a, 0xc0, 0x46, 0x00, 0x91,
-0x81, 0x6a, 0xc0, 0x46, 0x00, 0x91, 0xc0, 0x6a, 0xc0, 0x46, 0x00, 0x90,
-0x01, 0xb0, 0x70, 0x47, 0x00, 0x08, 0x14, 0x40, 0xf0, 0xb5, 0x83, 0xb0,
-0x68, 0x4d, 0x1b, 0x23, 0xdb, 0x01, 0xef, 0x18, 0xf8, 0x8b, 0x04, 0x22,
-0x02, 0x40, 0x02, 0x92, 0x71, 0x23, 0x5b, 0x01, 0xe8, 0x18, 0x01, 0x88,
-0xc0, 0x46, 0x01, 0x91, 0x40, 0x88, 0xc0, 0x46, 0x00, 0x90, 0x00, 0x24,
-0x03, 0xe0, 0x08, 0x2c, 0x01, 0xd3, 0x0f, 0x2c, 0x08, 0xd9, 0x20, 0x1c,
-0xff, 0xf7, 0xe8, 0xfd, 0x61, 0x00, 0x49, 0x19, 0x1b, 0x23, 0xdb, 0x01,
-0xc9, 0x18, 0x88, 0x83, 0x01, 0x34, 0x20, 0x2c, 0xef, 0xd3, 0x58, 0x4c,
-0xe0, 0x69, 0x00, 0x28, 0x15, 0xd0, 0x57, 0x4e, 0x20, 0x25, 0x01, 0x3d,
-0x53, 0x49, 0xe0, 0x69, 0x30, 0x40, 0x0b, 0xd0, 0x68, 0x00, 0x40, 0x18,
-0x37, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x81, 0x8b, 0x28, 0x1c, 0xff, 0xf7,
-0x65, 0xfe, 0xe0, 0x69, 0xb0, 0x43, 0xe0, 0x61, 0x76, 0x08, 0x00, 0x2d,
-0xeb, 0xd1, 0x01, 0x20, 0xff, 0xf7, 0xc2, 0xfd, 0x48, 0x49, 0xc0, 0x46,
-0xf8, 0x83, 0xf8, 0x8b, 0xc2, 0x08, 0x25, 0xd3, 0xca, 0x68, 0x01, 0x2a,
-0x13, 0xd1, 0x0a, 0x79, 0x00, 0x2a, 0x1f, 0xd1, 0x49, 0x88, 0x00, 0x29,
-0x1c, 0xd1, 0x01, 0x99, 0x43, 0x4a, 0x00, 0x29, 0x05, 0xd0, 0x01, 0x29,
-0x16, 0xd1, 0x51, 0x8b, 0xc9, 0x08, 0x13, 0xd2, 0x0f, 0xe0, 0x51, 0x8b,
-0x09, 0x09, 0x0f, 0xd2, 0x0b, 0xe0, 0x0a, 0x79, 0x00, 0x2a, 0x0b, 0xd1,
-0x6d, 0x23, 0x5b, 0x01, 0xc9, 0x18, 0x8a, 0x88, 0xc9, 0x88, 0x11, 0x40,
-0x49, 0x09, 0x09, 0x07, 0x02, 0xd1, 0x04, 0x23, 0x98, 0x43, 0xf8, 0x83,
-0xf8, 0x8b, 0x04, 0x21, 0x01, 0x40, 0x02, 0x9a, 0x1f, 0xd0, 0xb9, 0x8b,
-0x4a, 0x0b, 0x27, 0xd3, 0x80, 0x09, 0x25, 0xd3, 0xff, 0x23, 0x01, 0x98,
-0x01, 0x33, 0x98, 0x42, 0x20, 0xd0, 0x00, 0x25, 0x00, 0x98, 0x01, 0x28,
-0x00, 0xd1, 0x05, 0x02, 0x01, 0x98, 0x00, 0x28, 0x02, 0xd1, 0x01, 0x23,
-0x5b, 0x03, 0x1d, 0x43, 0xa9, 0x42, 0x13, 0xd0,
-0x00, 0x20, 0x29, 0x1c, 0xff, 0xf7, 0x10, 0xfe, 0xbd, 0x83, 0x00, 0x20,
-0xc0, 0x43, 0x60, 0x62, 0x0a, 0xe0, 0xb8, 0x8b, 0x40, 0x0b, 0x07, 0xd2,
-0x09, 0x21, 0x49, 0x02, 0x00, 0x20, 0xff, 0xf7, 0x03, 0xfe, 0x09, 0x20,
-0x40, 0x02, 0xb8, 0x83, 0xf8, 0x8b, 0xc0, 0x08, 0x2d, 0xd3, 0x1d, 0x48,
-0xc7, 0x6a, 0x01, 0x98, 0x00, 0x99, 0xff, 0xf7, 0x51, 0xfc, 0xc2, 0x07,
-0xd2, 0x0f, 0x1a, 0x49, 0x03, 0xd0, 0x04, 0x23, 0xcd, 0x6d, 0x2b, 0x43,
-0x03, 0xe0, 0x04, 0x23, 0xcd, 0x6d, 0x9d, 0x43, 0x2b, 0x1c, 0xcb, 0x65,
-0x83, 0x08, 0x03, 0xd3, 0x02, 0x23, 0xcd, 0x6d, 0x2b, 0x43, 0x03, 0xe0,
-0x02, 0x23, 0xcd, 0x6d, 0x9d, 0x43, 0x2b, 0x1c, 0xcb, 0x65, 0x61, 0x6a,
-0x81, 0x42, 0x0c, 0xd0, 0x60, 0x62, 0x0e, 0x48, 0x00, 0x2a, 0x03, 0xd0,
-0xff, 0x21, 0x21, 0x31, 0x39, 0x43, 0x03, 0xe0, 0xff, 0x23, 0x21, 0x33,
-0x9f, 0x43, 0x39, 0x1c, 0xc1, 0x62, 0x03, 0xb0, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0x68, 0x1c, 0x00, 0x80,
-0x00, 0x00, 0x00, 0x80, 0x28, 0x1c, 0x00, 0x80, 0x40, 0x00, 0x14, 0x40,
-0xa4, 0x2a, 0x00, 0x80, 0x40, 0x00, 0x14, 0x00, 0x90, 0xb4, 0x01, 0x22,
-0x20, 0x28, 0x0f, 0xd2, 0x43, 0x00, 0x0f, 0x1c, 0x07, 0x49, 0x5c, 0x18,
-0x37, 0x23, 0x9b, 0x01, 0xe3, 0x18, 0x9f, 0x83, 0x82, 0x40, 0x07, 0x23,
-0x5b, 0x02, 0xc9, 0x18, 0x10, 0x1c, 0xca, 0x69, 0x10, 0x43, 0xc8, 0x61,
-0x90, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x0b, 0x48, 0x40, 0x69,
-0x0b, 0x49, 0xc9, 0x8b, 0x04, 0x22, 0x0a, 0x40, 0x0a, 0x49, 0x06, 0xd0,
-0x01, 0x23, 0xdb, 0x02, 0x98, 0x43, 0x01, 0x23, 0xca, 0x6d, 0x1a, 0x43,
-0x05, 0xe0, 0x01, 0x23, 0xdb, 0x02, 0x18, 0x43, 0xca, 0x6d, 0x52, 0x08,
-0x52, 0x00, 0xca, 0x65, 0x70, 0x47, 0x00, 0x00, 0x80, 0x00, 0x14, 0x40,
-0xe8, 0x1b, 0x00, 0x80, 0xa4, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0x84, 0xb0,
-0xff, 0xf7, 0xde, 0xff, 0x01, 0x1c, 0x05, 0x20, 0x00, 0x90, 0x00, 0x20,
-0x01, 0xab, 0x18, 0x80, 0x04, 0x3b, 0x58, 0x70, 0x1b, 0x22, 0x00, 0xab,
-0x5a, 0x80, 0xd9, 0x80, 0x05, 0x49, 0xc9, 0x6d, 0xc0, 0x46, 0x02, 0x91,
-0x03, 0x90, 0x68, 0x46, 0x00, 0x21, 0xfd, 0xf7, 0x79, 0xf8, 0x04, 0xb0,
-0x08, 0xbc, 0x18, 0x47, 0xa4, 0x2a, 0x00, 0x80, 0x0f, 0x48, 0x01, 0x68,
-0x49, 0x0c, 0x05, 0xd2, 0x01, 0x68, 0x09, 0x0c, 0x06, 0xd1, 0x00, 0x68,
-0x80, 0x0a, 0x03, 0xd3, 0x0b, 0x48, 0x00, 0x68, 0x00, 0x0c, 0x01, 0xe0,
-0x0a, 0x48, 0x80, 0x6c, 0x00, 0x04, 0x00, 0x0c, 0x09, 0x4b, 0x98, 0x42,
-0x05, 0xd0, 0x02, 0x33, 0x98, 0x42, 0x02, 0xd0, 0x07, 0x4b, 0x98, 0x42,
-0x01, 0xd1, 0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 0x00, 0x00,
-0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80,
-0x04, 0x99, 0x00, 0x00, 0x07, 0x99, 0x00, 0x00, 0x90, 0xb4, 0x01, 0x24,
-0x21, 0x1c, 0x18, 0x48, 0x02, 0x68, 0x52, 0x0c, 0x06, 0xd2, 0x02, 0x68,
-0x12, 0x0c, 0x02, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x00, 0xd2, 0x00, 0x21,
-0x09, 0x06, 0x09, 0x0e, 0x12, 0x4f, 0x13, 0x4a, 0x02, 0xd0, 0x38, 0x68,
-0x00, 0x0c, 0x00, 0xe0, 0x90, 0x6c, 0x00, 0x04, 0x00, 0x0c, 0x10, 0x4b,
-0x98, 0x42, 0x08, 0xd0, 0x02, 0x33, 0x98, 0x42, 0x05, 0xd0, 0x0e, 0x4b,
-0x98, 0x42, 0x02, 0xd0, 0x02, 0x3b, 0x98, 0x42, 0x0c, 0xd1, 0x00, 0x29,
-0x02, 0xd0, 0xf8, 0x6a, 0x00, 0x0c, 0x00, 0xe0,
-0xd0, 0x6c, 0x40, 0x0a, 0x00, 0xd2, 0x00, 0x24, 0x20, 0x06, 0x00, 0x0e,
-0x90, 0xbc, 0x70, 0x47, 0x00, 0x20, 0xfb, 0xe7, 0x00, 0x00, 0x10, 0x40,
-0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 0x04, 0x99, 0x00, 0x00,
-0x07, 0x99, 0x00, 0x00, 0x0c, 0x48, 0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2,
-0x01, 0x68, 0x09, 0x0c, 0x05, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x02, 0xd3,
-0x08, 0x48, 0x80, 0x68, 0x01, 0xe0, 0x08, 0x48, 0x40, 0x6c, 0x00, 0x04,
-0x00, 0x0c, 0x00, 0x21, 0x03, 0x28, 0x03, 0xd0, 0x40, 0x08, 0x01, 0xd3,
-0x01, 0x20, 0x70, 0x47, 0x08, 0x1c, 0xfc, 0xe7, 0x00, 0x00, 0x10, 0x40,
-0x00, 0x00, 0x18, 0x40, 0x00, 0x00, 0x00, 0x80, 0xf0, 0xb5, 0x01, 0x27,
-0x1a, 0x4c, 0x25, 0x68, 0xff, 0xf7, 0x72, 0xff, 0x03, 0x1c, 0x19, 0x4a,
-0x02, 0x21, 0x01, 0x26, 0x18, 0x48, 0x01, 0x2b, 0x1b, 0xd1, 0xcb, 0x04,
-0x1e, 0x60, 0x55, 0x23, 0x03, 0x60, 0x00, 0x23, 0x43, 0x60, 0x06, 0x68,
-0x55, 0x2e, 0x1b, 0xd1, 0xaa, 0x26, 0x06, 0x60, 0x43, 0x60, 0x03, 0x68,
-0xaa, 0x2b, 0x15, 0xd1, 0x09, 0x23, 0x03, 0x60, 0x05, 0x23, 0x0f, 0x4f,
-0xc0, 0x46, 0x3b, 0x60, 0x03, 0x23, 0x0e, 0x4f, 0xc0, 0x46, 0x3b, 0x60,
-0x11, 0x60, 0x07, 0x68, 0x08, 0xe0, 0x08, 0x23, 0x23, 0x60, 0x04, 0x23,
-0x0a, 0x4f, 0xc0, 0x46, 0x3b, 0x60, 0x11, 0x60, 0x06, 0x60, 0x27, 0x68,
-0xc0, 0x46, 0x25, 0x60, 0x38, 0x1c, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0x00, 0x20, 0x40, 0x00, 0x00, 0x24, 0x40, 0x00, 0x00, 0x22, 0x40,
-0x00, 0x00, 0x2a, 0x40, 0x00, 0x00, 0x26, 0x40, 0x00, 0x00, 0x28, 0x40,
-0x80, 0xb5, 0x07, 0x1c, 0xff, 0xf7, 0x30, 0xff, 0x01, 0x28, 0x05, 0xd1,
-0x19, 0x48, 0x00, 0x68, 0x19, 0x49, 0x49, 0x6b, 0x08, 0x40, 0x22, 0xe0,
-0x18, 0x48, 0x01, 0x68, 0x49, 0x0c, 0x05, 0xd2, 0x01, 0x68, 0x09, 0x0c,
-0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x03, 0xd3, 0x14, 0x48, 0x00, 0x68,
-0x00, 0x0c, 0x01, 0xe0, 0x13, 0x48, 0x80, 0x6c, 0x00, 0x04, 0x00, 0x0c,
-0x12, 0x4b, 0xc0, 0x18, 0x08, 0x28, 0x0b, 0xd2, 0x01, 0xa3, 0x1b, 0x5c,
-0x5b, 0x00, 0x9f, 0x44, 0x05, 0x03, 0x07, 0x03, 0x07, 0x07, 0x05, 0x03,
-0x03, 0x20, 0x02, 0xe0, 0x01, 0x20, 0x00, 0xe0, 0x00, 0x20, 0x01, 0x21,
-0x38, 0x60, 0x80, 0x07, 0x00, 0xd1, 0x00, 0x21, 0x08, 0x06, 0x00, 0x0e,
-0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x34, 0x6e, 0x21, 0x40,
-0x00, 0x00, 0x11, 0x40, 0x00, 0x00, 0x10, 0x40, 0x00, 0x00, 0x18, 0x40,
-0x00, 0x00, 0x00, 0x80, 0xfe, 0x66, 0xff, 0xff, 0xf0, 0xb5, 0x82, 0xb0,
-0x07, 0x1c, 0x01, 0x20, 0x01, 0x90, 0xff, 0xf7, 0xe7, 0xfe, 0x01, 0x28,
-0x13, 0xd1, 0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x07, 0xd1, 0x00, 0x26,
-0xf6, 0x43, 0x34, 0x1c, 0xa8, 0x2f, 0x02, 0xd1, 0x30, 0x1c, 0x00, 0x96,
-0x35, 0x1c, 0x11, 0x20, 0x00, 0x04, 0x06, 0x62, 0x44, 0x62, 0x85, 0x62,
-0x00, 0x99, 0xc0, 0x46, 0xc1, 0x62, 0x00, 0x21, 0x08, 0x48, 0xc0, 0x46,
-0x01, 0x60, 0x38, 0x2f, 0x01, 0xd0, 0xa8, 0x2f, 0x05, 0xd1, 0x01, 0x21,
-0x01, 0x60, 0xa8, 0x2f, 0x01, 0xd1, 0x03, 0x21, 0x01, 0x60, 0x01, 0x98,
-0x02, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x34, 0x6e, 0x21, 0x40,
-0x70, 0x47, 0x00, 0x00, 0x70, 0x47, 0x00, 0x00, 0x90, 0xb5, 0x07, 0x1c,
-0x12, 0x4c, 0x21, 0x68, 0x12, 0x48, 0x81, 0x42, 0x0b, 0xd0, 0x00, 0x23,
-0x21, 0x1c, 0xe2, 0x1d, 0xc1, 0x32, 0x00, 0xe0,
-0x08, 0xc1, 0x91, 0x42, 0xfc, 0xd3, 0x20, 0x60, 0xc8, 0x20, 0xa0, 0x80,
-0x67, 0x72, 0x38, 0x01, 0x00, 0xf0, 0x18, 0xf8, 0x27, 0x72, 0x0a, 0x48,
-0xc0, 0x46, 0xe0, 0x60, 0x09, 0x2f, 0x00, 0xdb, 0x00, 0x27, 0xe0, 0x19,
-0x01, 0x7d, 0x01, 0x31, 0x01, 0x75, 0xe0, 0x88, 0x01, 0x30, 0xe0, 0x80,
-0x01, 0x20, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x00, 0x80,
-0xee, 0xff, 0xc0, 0xd0, 0x08, 0x10, 0x00, 0x03, 0x80, 0xb4, 0x08, 0x4a,
-0xd1, 0x1d, 0x89, 0x31, 0x0b, 0x7a, 0x20, 0x2b, 0x01, 0xd3, 0x00, 0x23,
-0x0b, 0x72, 0x07, 0x1c, 0x08, 0x7a, 0x43, 0x1c, 0x0b, 0x72, 0x80, 0x18,
-0x90, 0x30, 0x47, 0x72, 0x80, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x00, 0x80,
-0x07, 0x49, 0x01, 0x22, 0x12, 0x04, 0x08, 0x68, 0x02, 0x40, 0x01, 0x20,
-0x00, 0x2a, 0x06, 0xd1, 0x0a, 0x68, 0x12, 0x0c, 0x02, 0xd1, 0x09, 0x68,
-0x89, 0x0a, 0x00, 0xd2, 0x00, 0x20, 0x70, 0x47, 0x00, 0x00, 0x10, 0x40,
-0x90, 0xb5, 0x07, 0x1c, 0x09, 0x4c, 0x38, 0x1c, 0x21, 0x1c, 0xfc, 0xf7,
-0x91, 0xff, 0x38, 0x1c, 0x00, 0xf0, 0x0e, 0xf8, 0x01, 0x23, 0xd8, 0x42,
-0x01, 0xd1, 0x00, 0x0c, 0xe0, 0x80, 0x00, 0x21, 0x20, 0x1c, 0xfc, 0xf7,
-0xc5, 0xfe, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xc4, 0x66, 0x21, 0x40,
-0xf8, 0xb5, 0x07, 0x1c, 0x79, 0x7a, 0x76, 0x48, 0x00, 0x23, 0x76, 0x4c,
-0x01, 0x29, 0x5d, 0xd1, 0xa2, 0x88, 0xc0, 0x46, 0x00, 0x92, 0xa1, 0x89,
-0x8a, 0x42, 0x74, 0xda, 0xfa, 0x7a, 0x00, 0x2a, 0x15, 0xd0, 0x7a, 0x6c,
-0x00, 0x2a, 0x12, 0xd0, 0x8a, 0x42, 0x10, 0xd8, 0x00, 0x9a, 0x51, 0x1c,
-0xa1, 0x80, 0xa1, 0x88, 0xc0, 0x46, 0x41, 0x81, 0x78, 0x6c, 0x6b, 0x4e,
-0xc0, 0x46, 0xf0, 0x80, 0xa0, 0x6a, 0x58, 0x23, 0x79, 0x6c, 0x59, 0x43,
-0x40, 0x18, 0xc1, 0x1a, 0x28, 0xe0, 0x22, 0x88, 0x01, 0x32, 0x12, 0x04,
-0x12, 0x0c, 0x22, 0x80, 0x8a, 0x42, 0x00, 0xdb, 0x23, 0x80, 0x00, 0x22,
-0x00, 0x29, 0x69, 0xdd, 0x5f, 0x4c, 0xa4, 0x6a, 0x5e, 0x4b, 0x1d, 0x88,
-0x58, 0x23, 0x6b, 0x43, 0xe3, 0x18, 0xde, 0x1d, 0x01, 0x36, 0x01, 0x23,
-0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06, 0x15, 0xd1, 0x58, 0x49,
-0x00, 0x9a, 0x01, 0x32, 0x8a, 0x80, 0x8a, 0x88, 0xc0, 0x46, 0x42, 0x81,
-0x08, 0x88, 0x01, 0x30, 0x54, 0x4e, 0xc0, 0x46, 0xf0, 0x80, 0x58, 0x20,
-0x68, 0x43, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0x39, 0xfb, 0xf0, 0x88,
-0x00, 0x04, 0x00, 0x14, 0x95, 0xe0, 0x4d, 0x4b, 0x01, 0x35, 0x2d, 0x04,
-0x2d, 0x0c, 0x1d, 0x80, 0x8d, 0x42, 0x01, 0xdb, 0x00, 0x25, 0x1d, 0x80,
-0x01, 0x32, 0x12, 0x04, 0x12, 0x14, 0x91, 0x42, 0xce, 0xdc, 0x81, 0xe0,
-0xe1, 0x88, 0xe2, 0x89, 0x91, 0x42, 0x18, 0xda, 0xf9, 0x7a, 0x00, 0x29,
-0x2f, 0xd0, 0x79, 0x6c, 0x49, 0x04, 0x49, 0x0c, 0x79, 0x64, 0x2a, 0xd0,
-0xe2, 0x89, 0x91, 0x42, 0x27, 0xd8, 0xe1, 0x88, 0x01, 0x31, 0xe1, 0x80,
-0xe1, 0x88, 0xc0, 0x46, 0x81, 0x81, 0x01, 0x23, 0xdb, 0x03, 0x78, 0x6c,
-0x18, 0x43, 0x3a, 0x4e, 0xc0, 0x46, 0xf0, 0x80, 0x00, 0xe0, 0x63, 0xe0,
-0xe0, 0x6a, 0x79, 0x6c, 0x4b, 0x00, 0x59, 0x18, 0x49, 0x01, 0x40, 0x18,
-0xc1, 0x1f, 0x59, 0x39, 0x38, 0x1c, 0x00, 0xf0, 0x0f, 0xfb, 0xe0, 0x6a,
-0x79, 0x6c, 0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, 0x80, 0x18, 0x01, 0x39,
-0x09, 0x04, 0x09, 0x0c, 0x60, 0x38, 0x00, 0xf0, 0x89, 0xfb, 0xb6, 0xe7,
-0x4a, 0xe0, 0x61, 0x88, 0x01, 0x31, 0x09, 0x04,
-0x09, 0x0c, 0x61, 0x80, 0xe2, 0x89, 0x91, 0x42, 0x00, 0xdb, 0x63, 0x80,
-0x00, 0x21, 0x00, 0x2a, 0x3e, 0xdd, 0x24, 0x4c, 0xe4, 0x6a, 0x23, 0x4b,
-0x5d, 0x88, 0x6b, 0x00, 0x5b, 0x19, 0x5b, 0x01, 0xe3, 0x18, 0xde, 0x1d,
-0x01, 0x36, 0x01, 0x23, 0x9b, 0x07, 0x33, 0x43, 0x1b, 0x68, 0x1b, 0x06,
-0x20, 0xd1, 0x1c, 0x4e, 0xf1, 0x88, 0x01, 0x31, 0xf1, 0x80, 0xf1, 0x88,
-0xc0, 0x46, 0x81, 0x81, 0x70, 0x88, 0x01, 0x23, 0xdb, 0x03, 0x01, 0x30,
-0x18, 0x43, 0x17, 0x49, 0xc0, 0x46, 0xc8, 0x80, 0x68, 0x00, 0x40, 0x19,
-0x40, 0x01, 0x21, 0x18, 0x38, 0x1c, 0x00, 0xf0, 0xcf, 0xfa, 0x71, 0x88,
-0x4a, 0x00, 0x52, 0x18, 0x52, 0x01, 0xf0, 0x6a, 0x80, 0x18, 0x00, 0xf0,
-0x4d, 0xfb, 0x0e, 0x49, 0xc8, 0x88, 0x79, 0xe7, 0x0b, 0x4b, 0x01, 0x35,
-0x2d, 0x04, 0x2d, 0x0c, 0x5d, 0x80, 0x95, 0x42, 0x01, 0xdb, 0x00, 0x25,
-0x5d, 0x80, 0x01, 0x31, 0x09, 0x04, 0x09, 0x14, 0x8a, 0x42, 0xc2, 0xdc,
-0x01, 0x89, 0x01, 0x31, 0x01, 0x81, 0x00, 0x20, 0xc0, 0x43, 0xf8, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x4c, 0x2b, 0x00, 0x80, 0x4c, 0x2a, 0x00, 0x80,
-0xc4, 0x66, 0x21, 0x40, 0xf0, 0xb4, 0x06, 0x1c, 0x01, 0x23, 0xdb, 0x03,
-0x33, 0x40, 0x01, 0x24, 0x44, 0x4f, 0x00, 0x20, 0x44, 0x4a, 0x45, 0x4d,
-0xd1, 0x1d, 0x39, 0x31, 0x00, 0x2b, 0x41, 0xd0, 0xe3, 0x03, 0xf3, 0x1a,
-0x73, 0xd0, 0xee, 0x89, 0x9e, 0x42, 0x71, 0xd3, 0xee, 0x88, 0x00, 0x2e,
-0x6d, 0xd0, 0xed, 0x6a, 0x5e, 0x1e, 0x73, 0x00, 0x9b, 0x19, 0x5b, 0x01,
-0xed, 0x18, 0xae, 0x68, 0x36, 0x06, 0x36, 0x0e, 0x03, 0x2e, 0x02, 0xd0,
-0xce, 0x89, 0x01, 0x36, 0xce, 0x81, 0x40, 0x35, 0xad, 0x8b, 0xad, 0x00,
-0x35, 0x4e, 0x76, 0x6a, 0xc0, 0x46, 0x70, 0x51, 0x55, 0x89, 0x01, 0x35,
-0x55, 0x81, 0x32, 0x4e, 0xf2, 0x6a, 0xd2, 0x18, 0x90, 0x60, 0xf2, 0x6a,
-0xd2, 0x18, 0x90, 0x63, 0xf2, 0x6a, 0xd2, 0x18, 0xd0, 0x63, 0xf2, 0x6a,
-0xd2, 0x18, 0x10, 0x64, 0xf2, 0x6a, 0xd2, 0x18, 0x50, 0x64, 0xf2, 0x6a,
-0xd2, 0x18, 0x90, 0x64, 0xf2, 0x6a, 0xd2, 0x18, 0xd0, 0x64, 0xf0, 0x88,
-0x01, 0x38, 0xf0, 0x80, 0xf0, 0x88, 0xc0, 0x46, 0x88, 0x81, 0x24, 0x49,
-0x00, 0x28, 0x39, 0xd1, 0x4f, 0x80, 0x37, 0xe0, 0x00, 0x2e, 0x38, 0xd9,
-0xab, 0x89, 0xb3, 0x42, 0x30, 0xd3, 0xab, 0x88, 0x00, 0x2b, 0x2c, 0xd0,
-0x53, 0x89, 0x01, 0x33, 0x53, 0x81, 0x2a, 0x1c, 0xad, 0x6a, 0x58, 0x23,
-0x01, 0x3e, 0x73, 0x43, 0xed, 0x18, 0xae, 0x68, 0x36, 0x06, 0x36, 0x0e,
-0x03, 0x2e, 0x02, 0xd0, 0xce, 0x89, 0x01, 0x36, 0xce, 0x81, 0xa8, 0x60,
-0x95, 0x6a, 0xed, 0x18, 0xa8, 0x63, 0x95, 0x6a, 0xed, 0x18, 0xe8, 0x63,
-0x95, 0x6a, 0xed, 0x18, 0x28, 0x64, 0x95, 0x6a, 0xed, 0x18, 0x68, 0x64,
-0x95, 0x6a, 0xed, 0x18, 0xa8, 0x64, 0x95, 0x6a, 0xeb, 0x18, 0xd8, 0x64,
-0x90, 0x88, 0x01, 0x38, 0x90, 0x80, 0x90, 0x88, 0xc0, 0x46, 0x48, 0x81,
-0x00, 0x28, 0x03, 0xd1, 0x01, 0xe0, 0x04, 0xe0, 0x03, 0xe0, 0x17, 0x80,
-0x20, 0x1c, 0xf0, 0xbc, 0x70, 0x47, 0xca, 0x89, 0x01, 0x32, 0xca, 0x81,
-0xf9, 0xe7, 0x00, 0x00, 0xff, 0xff, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80,
-0x4c, 0x2a, 0x00, 0x80, 0x00, 0xb5, 0x00, 0x21, 0x41, 0x60, 0x10, 0x49,
-0x4a, 0x68, 0x00, 0x2a, 0x10, 0xd1, 0xca, 0x68, 0x00, 0x2a, 0x04, 0xd0,
-0xca, 0x1d, 0x19, 0x32, 0x12, 0x79, 0x00, 0x2a, 0x08, 0xd0, 0x4a, 0x69,
-0x00, 0x2a, 0x0b, 0xd1, 0x88, 0x61, 0x48, 0x61,
-0x00, 0xf0, 0x10, 0xf8, 0x08, 0xbc, 0x18, 0x47, 0x4a, 0x69, 0x00, 0x2a,
-0x02, 0xd1, 0x88, 0x61, 0x48, 0x61, 0xf7, 0xe7, 0x8a, 0x69, 0xc0, 0x46,
-0x50, 0x60, 0x88, 0x61, 0xf2, 0xe7, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80,
-0xb0, 0xb5, 0x2a, 0x48, 0x40, 0x69, 0x00, 0x28, 0x4c, 0xd0, 0x08, 0x22,
-0xc1, 0x68, 0x0a, 0x40, 0x00, 0x27, 0x27, 0x4b, 0xd9, 0x1d, 0xb9, 0x31,
-0x00, 0x2a, 0x11, 0xd0, 0x04, 0x22, 0x25, 0x4c, 0xc0, 0x46, 0x0c, 0x61,
-0x24, 0x4c, 0xc0, 0x46, 0x4c, 0x62, 0x24, 0x4c, 0xc0, 0x46, 0x8c, 0x62,
-0x23, 0x4c, 0xc0, 0x46, 0xcc, 0x62, 0x23, 0x4c, 0xc0, 0x46, 0x0c, 0x63,
-0x4f, 0x63, 0x12, 0xe0, 0x05, 0x22, 0x21, 0x4c, 0xc0, 0x46, 0x0c, 0x61,
-0x20, 0x4c, 0xc0, 0x46, 0x4c, 0x62, 0x20, 0x4c, 0xc0, 0x46, 0x8c, 0x62,
-0x1f, 0x4c, 0xc0, 0x46, 0xcc, 0x62, 0x1f, 0x4c, 0xc0, 0x46, 0x0c, 0x63,
-0x1e, 0x4c, 0xc0, 0x46, 0x4c, 0x63, 0x40, 0x24, 0xcc, 0x82, 0x4f, 0x83,
-0x1c, 0x4f, 0x00, 0x21, 0x00, 0x2a, 0x0c, 0xd9, 0x8c, 0x00, 0x05, 0x19,
-0x6d, 0x6a, 0x7d, 0x40, 0xe4, 0x18, 0xff, 0x34, 0x01, 0x34, 0x65, 0x62,
-0x01, 0x31, 0x91, 0x42, 0xf4, 0xd3, 0x10, 0x29, 0x07, 0xd2, 0x8a, 0x00,
-0xd2, 0x18, 0xff, 0x32, 0x01, 0x32, 0x57, 0x62, 0x01, 0x31, 0x10, 0x29,
-0xf7, 0xd3, 0x11, 0x49, 0x00, 0xf0, 0x22, 0xf8, 0xb0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x6c, 0x06, 0x00, 0x80, 0xac, 0xab, 0x20, 0x40,
-0x28, 0x01, 0x40, 0x00, 0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xcd, 0xef,
-0xfe, 0xdc, 0xba, 0x98, 0x76, 0x54, 0x32, 0x10, 0x20, 0x01, 0x40, 0x00,
-0x67, 0x45, 0x23, 0x01, 0xef, 0xcd, 0xab, 0x89, 0x98, 0xba, 0xdc, 0xfe,
-0x10, 0x32, 0x54, 0x76, 0xc3, 0xd2, 0xe1, 0xf0, 0x36, 0x36, 0x36, 0x36,
-0x30, 0x80, 0x20, 0x40, 0xb0, 0xb5, 0x0f, 0x1c, 0x15, 0x4d, 0xe9, 0x1d,
-0xc9, 0x31, 0x15, 0x4c, 0x23, 0x1c, 0x15, 0x4a, 0x00, 0x20, 0xfc, 0xf7,
-0x44, 0xfb, 0xe9, 0x1d, 0xff, 0x31, 0x1e, 0x31, 0x23, 0x1c, 0x0d, 0x1c,
-0x11, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x3b, 0xfb, 0x29, 0x1c, 0x23, 0x1c,
-0x0e, 0x4a, 0x00, 0x20, 0xfc, 0xf7, 0x35, 0xfb, 0x39, 0x1c, 0x23, 0x1c,
-0x0c, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x2f, 0xfb, 0x00, 0x21, 0x0b, 0x48,
-0xc2, 0x1d, 0x19, 0x32, 0x51, 0x71, 0x01, 0x21, 0xff, 0x30, 0x01, 0x30,
-0x41, 0x62, 0x08, 0x1c, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0xac, 0xab, 0x20, 0x40, 0x75, 0x08, 0xff, 0xff, 0x28, 0x00, 0x03, 0x00,
-0x40, 0x00, 0x02, 0x00, 0x14, 0x00, 0x07, 0x00, 0x6c, 0x06, 0x00, 0x80,
-0xf0, 0xb5, 0x37, 0x4a, 0x50, 0x69, 0x01, 0x23, 0x9b, 0x07, 0x08, 0x30,
-0x18, 0x43, 0x00, 0x68, 0x01, 0x06, 0x09, 0x0e, 0x33, 0x4b, 0x01, 0x29,
-0x49, 0xd1, 0x1f, 0x68, 0x19, 0x1c, 0x32, 0x4b, 0x9f, 0x42, 0x04, 0xd1,
-0xff, 0xf7, 0x3e, 0xff, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x23,
-0x9f, 0x00, 0xcc, 0x59, 0x55, 0x69, 0xef, 0x19, 0x3c, 0x61, 0x01, 0x33,
-0x05, 0x2b, 0xf7, 0xd3, 0x00, 0x0a, 0x00, 0x02, 0x02, 0x23, 0x18, 0x43,
-0x53, 0x69, 0xc0, 0x46, 0x98, 0x60, 0x50, 0x69, 0x08, 0x23, 0xc2, 0x68,
-0x13, 0x40, 0x25, 0x4f, 0xfa, 0x1d, 0xb9, 0x32, 0x00, 0x2b, 0x02, 0xd0,
-0x04, 0x23, 0x23, 0x4c, 0x01, 0xe0, 0x05, 0x23, 0x22, 0x4c, 0xc0, 0x46,
-0x14, 0x61, 0x40, 0x24, 0xd4, 0x82, 0x00, 0x24, 0x54, 0x83, 0x20, 0x4c,
-0x00, 0x22, 0x00, 0x2b, 0x0c, 0xd9, 0x95, 0x00,
-0x46, 0x19, 0x76, 0x6a, 0x66, 0x40, 0xed, 0x19, 0xff, 0x35, 0x01, 0x35,
-0x6e, 0x62, 0x01, 0x32, 0x9a, 0x42, 0xf4, 0xd3, 0x10, 0x2a, 0x07, 0xd2,
-0x93, 0x00, 0xdb, 0x19, 0xff, 0x33, 0x01, 0x33, 0x5c, 0x62, 0x01, 0x32,
-0x10, 0x2a, 0xf7, 0xd3, 0xff, 0xf7, 0x70, 0xff, 0xbc, 0xe7, 0x00, 0x21,
-0x8f, 0x00, 0xdc, 0x59, 0x55, 0x69, 0xef, 0x19, 0x7c, 0x62, 0x01, 0x31,
-0x05, 0x29, 0xf7, 0xd3, 0x00, 0x0a, 0x00, 0x02, 0x03, 0x23, 0x18, 0x43,
-0x51, 0x69, 0xc0, 0x46, 0x88, 0x60, 0x50, 0x69, 0x40, 0x68, 0xc0, 0x46,
-0x50, 0x61, 0x09, 0x48, 0xfc, 0xf7, 0xa4, 0xfa, 0xa4, 0xe7, 0x00, 0x00,
-0x6c, 0x06, 0x00, 0x80, 0x30, 0x80, 0x20, 0x40, 0x67, 0x45, 0x23, 0x01,
-0xac, 0xab, 0x20, 0x40, 0x28, 0x01, 0x40, 0x00, 0x20, 0x01, 0x40, 0x00,
-0x5c, 0x5c, 0x5c, 0x5c, 0x11, 0x31, 0xff, 0xff, 0xf0, 0xb5, 0x07, 0x1c,
-0x3b, 0x48, 0x3c, 0x4c, 0x08, 0x21, 0x20, 0x60, 0xa1, 0x80, 0x00, 0x20,
-0x20, 0x81, 0xe1, 0x80, 0x60, 0x81, 0x39, 0x48, 0xc0, 0x46, 0xe0, 0x60,
-0x38, 0x48, 0xc0, 0x46, 0x20, 0x61, 0x38, 0x48, 0xc0, 0x46, 0x60, 0x61,
-0x37, 0x48, 0xc0, 0x46, 0xa0, 0x61, 0x37, 0x48, 0xc0, 0x46, 0xe0, 0x61,
-0x36, 0x48, 0xc0, 0x46, 0x20, 0x62, 0x36, 0x48, 0xc0, 0x46, 0x60, 0x62,
-0x35, 0x48, 0xc0, 0x46, 0xa0, 0x62, 0x35, 0x48, 0xc0, 0x46, 0xe0, 0x62,
-0x34, 0x48, 0xc0, 0x46, 0x20, 0x63, 0x34, 0x48, 0xc0, 0x46, 0x60, 0x63,
-0x33, 0x48, 0xc0, 0x46, 0xa0, 0x63, 0x33, 0x48, 0xc0, 0x46, 0xe0, 0x63,
-0x32, 0x48, 0xc0, 0x46, 0x20, 0x64, 0x32, 0x48, 0xc0, 0x46, 0x60, 0x64,
-0x31, 0x48, 0xc0, 0x46, 0xa0, 0x64, 0x31, 0x48, 0xc0, 0x46, 0xe0, 0x64,
-0x30, 0x48, 0xc0, 0x46, 0x20, 0x65, 0x30, 0x49, 0xc8, 0x68, 0x02, 0x04,
-0x89, 0x69, 0x4a, 0x40, 0xe3, 0x1d, 0x79, 0x33, 0x09, 0x04, 0xc9, 0x43,
-0xc0, 0x43, 0x48, 0x40, 0xe1, 0x1d, 0xb9, 0x31, 0xda, 0x63, 0x08, 0x60,
-0x29, 0x4d, 0x21, 0x1c, 0x2b, 0x1c, 0x29, 0x4a, 0x00, 0x20, 0xfc, 0xf7,
-0x3e, 0xfa, 0x28, 0x4a, 0xe1, 0x1d, 0xb5, 0x31, 0x01, 0x20, 0x2b, 0x1c,
-0x0e, 0x1c, 0xfc, 0xf7, 0x36, 0xfa, 0x24, 0x4a, 0x00, 0x20, 0x31, 0x1c,
-0x2b, 0x1c, 0xfc, 0xf7, 0x30, 0xfa, 0xe1, 0x1d, 0x4d, 0x31, 0x2b, 0x1c,
-0x20, 0x4a, 0x01, 0x20, 0xfc, 0xf7, 0x29, 0xfa, 0xe0, 0x1d, 0x5d, 0x30,
-0x01, 0x68, 0x00, 0x29, 0xfc, 0xd0, 0x60, 0x6d, 0xc0, 0x46, 0x38, 0x65,
-0x20, 0x6e, 0xc0, 0x46, 0x78, 0x65, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x80, 0x00, 0x08, 0x00, 0x8c, 0xb9, 0x20, 0x40, 0x81, 0x81, 0x48, 0xbd,
-0x79, 0x56, 0x23, 0x8c, 0x93, 0x0c, 0x82, 0x95, 0x1d, 0x0e, 0x12, 0xcf,
-0x9b, 0x3b, 0xc0, 0xe9, 0xe6, 0x55, 0x7c, 0x82, 0x99, 0xf6, 0x78, 0x02,
-0xd1, 0xd7, 0x25, 0x73, 0x72, 0x8c, 0x33, 0x10, 0xf7, 0x03, 0xf1, 0x42,
-0x6c, 0x9b, 0x4a, 0xa7, 0x82, 0x8e, 0x23, 0xa9, 0x90, 0xb1, 0x82, 0x8e,
-0xdc, 0x3f, 0xfb, 0x29, 0x00, 0x62, 0x22, 0x45, 0x88, 0x2b, 0xf1, 0x85,
-0x12, 0x61, 0xd1, 0x73, 0x6e, 0xb1, 0x11, 0x16, 0x08, 0x83, 0x20, 0x40,
-0x75, 0x08, 0xff, 0xff, 0x54, 0x00, 0x03, 0x00, 0x08, 0x00, 0x02, 0x00,
-0x14, 0x00, 0x03, 0x00, 0x80, 0xb5, 0x0f, 0x1c, 0x39, 0x1c, 0x00, 0xf0,
-0x33, 0xf8, 0x38, 0x1c, 0xff, 0xf7, 0x4c, 0xff, 0x03, 0x48, 0x01, 0x89,
-0x01, 0x31, 0x01, 0x81, 0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x0c, 0x2b, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c,
-0x0f, 0x1c, 0x20, 0x1c, 0x39, 0x1c, 0x00, 0xf0, 0x1f, 0xf8, 0xe0, 0x68,
-0x01, 0x0e, 0xff, 0x22, 0x12, 0x04, 0x02, 0x40, 0x12, 0x0a, 0x11, 0x43,
-0xff, 0x22, 0x12, 0x02, 0x02, 0x40, 0x12, 0x02, 0x11, 0x43, 0x00, 0x06,
-0x08, 0x43, 0x38, 0x65, 0x20, 0x69, 0xc0, 0x46, 0x78, 0x65, 0x60, 0x69,
-0xc0, 0x46, 0xb8, 0x65, 0x03, 0x48, 0x01, 0x89, 0x01, 0x31, 0x01, 0x81,
-0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x0c, 0x2b, 0x00, 0x80,
-0x90, 0xb5, 0x00, 0x22, 0x93, 0x00, 0x1f, 0x18, 0xbf, 0x69, 0x5b, 0x18,
-0x5f, 0x62, 0x01, 0x32, 0x05, 0x2a, 0xf7, 0xd3, 0x07, 0x7a, 0xfb, 0x08,
-0x03, 0xd3, 0x00, 0x23, 0x92, 0x00, 0x52, 0x18, 0x13, 0x62, 0x07, 0x6b,
-0xc0, 0x46, 0x8f, 0x63, 0xc7, 0x6a, 0xc0, 0x46, 0xcf, 0x63, 0x87, 0x6b,
-0xc0, 0x46, 0x0f, 0x64, 0x47, 0x6b, 0xc0, 0x46, 0x4f, 0x64, 0x07, 0x6c,
-0xc0, 0x46, 0x8f, 0x64, 0xc2, 0x6b, 0xc0, 0x46, 0xca, 0x64, 0xc2, 0x88,
-0xc0, 0x46, 0x0a, 0x80, 0x82, 0x7a, 0x12, 0x06, 0x03, 0x7a, 0x1b, 0x04,
-0x1a, 0x43, 0xc3, 0x88, 0x1b, 0x02, 0x1a, 0x43, 0x43, 0x7a, 0xdb, 0x07,
-0x1a, 0x43, 0x8a, 0x60, 0x17, 0x1c, 0x83, 0x7a, 0x5a, 0x08, 0x05, 0xd3,
-0x14, 0x22, 0x1c, 0x1c, 0xa3, 0x08, 0x02, 0xd2, 0x15, 0x22, 0x00, 0xe0,
-0x00, 0x22, 0x00, 0x7a, 0x43, 0x08, 0x10, 0xd3, 0xc0, 0x08, 0x02, 0xd3,
-0x88, 0x20, 0x10, 0x43, 0x01, 0xe0, 0x80, 0x20, 0x10, 0x43, 0x3a, 0x0a,
-0x12, 0x02, 0x01, 0x23, 0x1a, 0x43, 0xc8, 0x60, 0x8a, 0x60, 0x08, 0x1c,
-0xff, 0xf7, 0x78, 0xfd, 0x05, 0xe0, 0x38, 0x0a, 0x00, 0x02, 0x03, 0x23,
-0x18, 0x43, 0x88, 0x60, 0xca, 0x60, 0x03, 0x48, 0x01, 0x89, 0x01, 0x31,
-0x01, 0x81, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x0c, 0x2b, 0x00, 0x80,
-0xf0, 0xb4, 0x02, 0x6d, 0x14, 0x4c, 0x15, 0x1c, 0xe7, 0x69, 0xbd, 0x40,
-0x13, 0x1c, 0x26, 0x6a, 0xf3, 0x40, 0x5d, 0x40, 0x2e, 0x1c, 0x45, 0x6d,
-0xbd, 0x40, 0x6e, 0x40, 0x2b, 0x1c, 0x35, 0x1c, 0xfd, 0x40, 0x2f, 0x1c,
-0xbb, 0x00, 0x65, 0x6a, 0xeb, 0x58, 0x00, 0x2b, 0x08, 0xd0, 0x23, 0x69,
-0x01, 0x37, 0x9f, 0x42, 0x00, 0xd3, 0x00, 0x27, 0xbe, 0x00, 0xae, 0x59,
-0x00, 0x2e, 0xf7, 0xd1, 0xa4, 0x69, 0xa2, 0x40, 0x11, 0x43, 0x05, 0x4b,
-0x19, 0x43, 0xba, 0x00, 0xa9, 0x50, 0x40, 0x30, 0x87, 0x83, 0xf0, 0xbc,
-0x70, 0x47, 0x00, 0x00, 0x4c, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x00, 0x80,
-0x80, 0xb4, 0x00, 0x22, 0x00, 0x23, 0x00, 0x29, 0x05, 0xd9, 0x07, 0x78,
-0x7a, 0x40, 0x01, 0x30, 0x01, 0x33, 0x8b, 0x42, 0xf9, 0xd3, 0xd0, 0x43,
-0x00, 0x06, 0x00, 0x0e, 0x80, 0xbc, 0x70, 0x47, 0xf0, 0xb5, 0x07, 0x1c,
-0x00, 0x24, 0xff, 0x26, 0x09, 0x36, 0x20, 0x1c, 0x00, 0xf0, 0x9a, 0xf8,
-0x00, 0xf0, 0xb8, 0xf9, 0x05, 0x1c, 0x00, 0xf0, 0xc7, 0xfa, 0x3d, 0x70,
-0x28, 0x1c, 0x01, 0x37, 0x01, 0x34, 0xb4, 0x42, 0xf1, 0xd3, 0xf0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x80, 0xb5, 0x00, 0xf0, 0x93, 0xf8, 0x00, 0xf0,
-0xa7, 0xf9, 0x07, 0x1c, 0x00, 0xf0, 0xb6, 0xfa, 0x38, 0x0a, 0xf6, 0xd3,
-0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf3, 0xb5, 0x82, 0xb0, 0x02, 0x98,
-0x41, 0x02, 0x53, 0x20, 0x00, 0xf0, 0x64, 0xf8, 0x00, 0xf0, 0xa8, 0xfa,
-0xff, 0xf7, 0xe8, 0xff, 0x00, 0x24, 0x00, 0x20, 0x01, 0x90, 0x2e, 0x20,
-0x00, 0x90, 0x00, 0x25, 0x00, 0x27, 0x02, 0x98, 0x01, 0x28, 0x04, 0xd1,
-0x00, 0x98, 0x84, 0x42, 0x01, 0xd3, 0x00, 0x26,
-0x09, 0xe0, 0x01, 0x98, 0x41, 0x1c, 0x01, 0x91, 0x00, 0xf0, 0x60, 0xf8,
-0x00, 0xf0, 0x7e, 0xf9, 0x06, 0x1c, 0x00, 0xf0, 0x8d, 0xfa, 0xf8, 0x00,
-0x86, 0x40, 0x35, 0x43, 0x01, 0x34, 0x01, 0x37, 0x04, 0x2f, 0xe6, 0xd3,
-0x03, 0x99, 0x20, 0xc1, 0x03, 0x91, 0xff, 0x23, 0x09, 0x33, 0x9c, 0x42,
-0xdd, 0xd3, 0x04, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0xf0, 0xb5,
-0x04, 0x1c, 0x0f, 0x1c, 0x01, 0x2c, 0x2a, 0xd0, 0x16, 0x48, 0xc0, 0x6f,
-0x40, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x00, 0x26, 0x20, 0xcf,
-0xb1, 0x00, 0x84, 0x20, 0x00, 0xf0, 0x24, 0xf8, 0x28, 0x1c, 0x00, 0xf0,
-0xdf, 0xf9, 0x28, 0x0a, 0x00, 0xf0, 0xdc, 0xf9, 0x28, 0x0c, 0x00, 0xf0,
-0xd9, 0xf9, 0x28, 0x0e, 0x00, 0xf0, 0xd6, 0xf9, 0x00, 0xf0, 0x5c, 0xfa,
-0x01, 0x36, 0x42, 0x2e, 0xe9, 0xd3, 0x61, 0x02, 0x83, 0x20, 0x00, 0xf0,
-0x0f, 0xf8, 0x00, 0xf0, 0x53, 0xfa, 0xff, 0xf7, 0x93, 0xff, 0x04, 0x48,
-0xc0, 0x6f, 0x40, 0x23, 0x01, 0x68, 0x99, 0x43, 0x01, 0x60, 0xf0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x04, 0x1c,
-0x0f, 0x1c, 0x00, 0xf0, 0x59, 0xfa, 0x20, 0x1c, 0x00, 0xf0, 0xb6, 0xf9,
-0x38, 0x0c, 0x00, 0xf0, 0xb3, 0xf9, 0x38, 0x0a, 0x00, 0xf0, 0xb0, 0xf9,
-0x38, 0x1c, 0x00, 0xf0, 0xad, 0xf9, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x00, 0xb5, 0x01, 0x1c, 0x54, 0x20, 0xff, 0xf7, 0xe7, 0xff, 0x00, 0x20,
-0x00, 0xf0, 0xa2, 0xf9, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0,
-0x3d, 0xfa, 0x57, 0x20, 0x00, 0xf0, 0x9a, 0xf9, 0x08, 0xbc, 0x18, 0x47,
-0x90, 0xb5, 0x08, 0x4f, 0xfa, 0x6f, 0x20, 0x23, 0x14, 0x68, 0x9c, 0x43,
-0x14, 0x60, 0x23, 0x1c, 0xff, 0xf7, 0x65, 0xff, 0xf8, 0x6f, 0x20, 0x23,
-0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x68, 0x0e, 0x00, 0x80, 0x90, 0xb5, 0x08, 0x4f, 0xfa, 0x6f, 0x20, 0x23,
-0x14, 0x68, 0x9c, 0x43, 0x14, 0x60, 0x23, 0x1c, 0xff, 0xf7, 0x87, 0xff,
-0xf8, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0x90, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0x04, 0x1c,
-0x0f, 0x1c, 0x18, 0x4e, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x99, 0x43,
-0x01, 0x60, 0x61, 0x02, 0x53, 0x20, 0xff, 0xf7, 0xa5, 0xff, 0x00, 0xf0,
-0xe9, 0xf9, 0xff, 0xf7, 0x29, 0xff, 0xf8, 0x1d, 0x05, 0x30, 0x01, 0x2c,
-0x03, 0xd1, 0x22, 0x2f, 0x01, 0xd3, 0x00, 0x27, 0x0f, 0xe0, 0x44, 0x1c,
-0xff, 0xf7, 0xaa, 0xff, 0x00, 0xf0, 0xc8, 0xf8, 0x07, 0x1c, 0x00, 0xf0,
-0xd7, 0xf9, 0x20, 0x1c, 0xff, 0xf7, 0xa2, 0xff, 0x00, 0xf0, 0xc0, 0xf8,
-0x05, 0x1c, 0x00, 0xf0, 0xcf, 0xf9, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68,
-0x19, 0x43, 0x01, 0x60, 0x28, 0x02, 0x38, 0x43, 0xf0, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xf0, 0xb5, 0xc2, 0xb0,
-0x14, 0x1c, 0x0d, 0x1c, 0x07, 0x1c, 0x01, 0x2f, 0x2f, 0xd0, 0x79, 0x02,
-0x19, 0x4e, 0xf0, 0x6f, 0x20, 0x23, 0x02, 0x68, 0x9a, 0x43, 0x02, 0x60,
-0x53, 0x20, 0xff, 0xf7, 0x6b, 0xff, 0x00, 0xf0, 0xaf, 0xf9, 0xff, 0xf7,
-0xef, 0xfe, 0x68, 0x46, 0xff, 0xf7, 0xd6, 0xfe, 0x6a, 0x46, 0xe8, 0x1d,
-0x05, 0x30, 0x14, 0x54, 0x21, 0x0a, 0x68, 0x44, 0x41, 0x70, 0x68, 0x46,
-0x00, 0x99, 0x0c, 0x30, 0xff, 0xf7, 0xba, 0xfe, 0x02, 0xab, 0x18, 0x70,
-0x00, 0x20, 0x58, 0x70, 0x68, 0x46, 0x0c, 0x21,
-0xff, 0xf7, 0xb2, 0xfe, 0x02, 0xab, 0x58, 0x70, 0x69, 0x46, 0x38, 0x1c,
-0xff, 0xf7, 0x15, 0xff, 0xf0, 0x6f, 0x20, 0x23, 0x01, 0x68, 0x19, 0x43,
-0x01, 0x60, 0x42, 0xb0, 0xf0, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x68, 0x0e, 0x00, 0x80, 0xff, 0xb5, 0xc2, 0xb0, 0x07, 0x1c, 0x01, 0x2f,
-0x01, 0xd1, 0x01, 0x20, 0x36, 0xe0, 0x6b, 0x46, 0x00, 0x20, 0xc4, 0x43,
-0x10, 0xc3, 0x01, 0x30, 0x42, 0x28, 0xfb, 0xd3, 0x68, 0x46, 0x0c, 0x30,
-0x03, 0x1c, 0x00, 0x24, 0x00, 0x2a, 0x0a, 0xd9, 0x0e, 0x88, 0xc0, 0x46,
-0x06, 0x70, 0x0e, 0x88, 0x36, 0x12, 0x46, 0x70, 0x02, 0x30, 0x02, 0x31,
-0x02, 0x34, 0x94, 0x42, 0xf4, 0xd3, 0x00, 0x92, 0x18, 0x1c, 0x11, 0x1c,
-0xff, 0xf7, 0x7c, 0xfe, 0x04, 0x1c, 0x00, 0x20, 0x01, 0x90, 0x02, 0xab,
-0x1c, 0x70, 0x58, 0x70, 0x9d, 0x70, 0x68, 0x46, 0x0c, 0x21, 0xff, 0xf7,
-0x71, 0xfe, 0x02, 0xab, 0x58, 0x70, 0x45, 0x9b, 0x1d, 0x06, 0x2d, 0x0e,
-0xac, 0x42, 0x03, 0xd1, 0x69, 0x46, 0x38, 0x1c, 0xff, 0xf7, 0x3e, 0xff,
-0x01, 0x20, 0xac, 0x42, 0x00, 0xd1, 0x00, 0x20, 0x46, 0xb0, 0xf0, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0xb0, 0xb5, 0xc2, 0xb0, 0x0f, 0x1c, 0x41, 0x02,
-0x14, 0x4c, 0xe0, 0x6f, 0x20, 0x23, 0x02, 0x68, 0x9a, 0x43, 0x02, 0x60,
-0x53, 0x20, 0xff, 0xf7, 0xef, 0xfe, 0x00, 0xf0, 0x33, 0xf9, 0xff, 0xf7,
-0x73, 0xfe, 0x68, 0x46, 0xff, 0xf7, 0x5a, 0xfe, 0xe0, 0x6f, 0x20, 0x23,
-0x01, 0x68, 0x19, 0x43, 0x02, 0xad, 0x01, 0x60, 0x6d, 0x78, 0x00, 0x24,
-0x02, 0xab, 0x5c, 0x70, 0x68, 0x46, 0x0c, 0x21, 0xff, 0xf7, 0x3c, 0xfe,
-0xa8, 0x42, 0x02, 0xd1, 0x00, 0x98, 0x87, 0x42, 0x01, 0xd3, 0x20, 0x1c,
-0x00, 0xe0, 0x01, 0x20, 0x42, 0xb0, 0xb0, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x68, 0x0e, 0x00, 0x80, 0xfc, 0x46, 0x60, 0x47, 0x00, 0x00, 0xa0, 0xe3,
-0xb4, 0x22, 0x9f, 0xe5, 0xb4, 0x32, 0x9f, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
-0x81, 0x03, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x01, 0x03, 0x80, 0xe1,
-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x93, 0xe5, 0x81, 0x02, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
-0x01, 0x02, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5, 0x81, 0x01, 0x80, 0xe1,
-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x93, 0xe5, 0x01, 0x01, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
-0x81, 0x00, 0x80, 0xe1, 0x01, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x93, 0xe5,
-0x01, 0x00, 0x80, 0xe1, 0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47,
-0xa4, 0x21, 0x9f, 0xe5, 0xa8, 0x31, 0x9f, 0xe5, 0xa0, 0x13, 0xa0, 0xe1,
-0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x20, 0x13, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5,
-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0xa0, 0x12, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x20, 0x12, 0xa0, 0xe1,
-0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0xa0, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5,
-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x20, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5, 0xa0, 0x10, 0xa0, 0xe1,
-0x00, 0x10, 0x83, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0xa0, 0xe1, 0x00, 0x10, 0x83, 0xe5,
-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5, 0x00, 0x10, 0x82, 0xe5,
-0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0xa0, 0x30, 0x9f, 0xe5,
-0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
-0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0x70, 0x30, 0x9f, 0xe5,
-0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
-0x1e, 0xff, 0x2f, 0xe1, 0xfc, 0x46, 0x60, 0x47, 0x34, 0x20, 0x9f, 0xe5,
-0x3c, 0x30, 0x9f, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x82, 0xe5,
-0x00, 0x10, 0x82, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x83, 0xe5,
-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
-0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5, 0x00, 0x10, 0x83, 0xe5,
-0x00, 0x10, 0x83, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xf8, 0x00, 0x18, 0x40,
-0x04, 0x01, 0x18, 0x40, 0x00, 0x01, 0x18, 0x40, 0xfc, 0x00, 0x18, 0x40,
-0x80, 0xb5, 0x00, 0xf0, 0x0c, 0xf8, 0x00, 0x27, 0x38, 0x1c, 0x00, 0xf0,
-0x47, 0xf8, 0x78, 0x1c, 0x07, 0x04, 0x3f, 0x0c, 0x0c, 0x2f, 0xf7, 0xdd,
-0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x1d, 0x48,
-0x02, 0x68, 0x1d, 0x49, 0x8b, 0x69, 0xd2, 0x18, 0x02, 0x60, 0x02, 0x66,
-0x8a, 0x6a, 0x43, 0x68, 0x9b, 0x18, 0x43, 0x60, 0x93, 0x42, 0x02, 0xd2,
-0x82, 0x68, 0x01, 0x32, 0x82, 0x60, 0xc2, 0x68, 0x0b, 0x6a, 0xd2, 0x18,
-0xc2, 0x60, 0x42, 0x69, 0xcb, 0x68, 0xd2, 0x18, 0x42, 0x61, 0xc2, 0x69,
-0x8b, 0x68, 0xd2, 0x18, 0xc2, 0x61, 0x02, 0x69, 0x0b, 0x69, 0xd2, 0x18,
-0x02, 0x61, 0x82, 0x69, 0x0b, 0x68, 0xd2, 0x18, 0x82, 0x61, 0x02, 0x6b,
-0xcb, 0x69, 0xd2, 0x18, 0x02, 0x63, 0x4a, 0x6a, 0x43, 0x6b, 0x9b, 0x18,
-0x43, 0x63, 0x93, 0x42, 0x02, 0xd2, 0x82, 0x6b, 0x01, 0x32, 0x82, 0x63,
-0xc2, 0x6b, 0x4b, 0x69, 0xd2, 0x18, 0xc2, 0x63, 0x02, 0x6c, 0xc9, 0x6a,
-0x51, 0x18, 0x01, 0x64, 0x70, 0x47, 0x00, 0x00, 0xa4, 0x2a, 0x00, 0x80,
-0x00, 0x08, 0x14, 0x40, 0x88, 0xb5, 0x69, 0x46, 0x00, 0xf0, 0x17, 0xf8,
-0x81, 0x08, 0x0a, 0xd0, 0x00, 0x20, 0x00, 0x29, 0x07, 0xd9, 0x00, 0x22,
-0x83, 0x00, 0x00, 0x9f, 0xc0, 0x46, 0xfa, 0x50, 0x01, 0x30, 0x88, 0x42,
-0xf8, 0xd3, 0x88, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0xb5, 0x00, 0xf0,
-0x04, 0xf8, 0x00, 0x04, 0x00, 0x0c, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x22,
-0x00, 0x28, 0x0a, 0xd0, 0x01, 0x28, 0x0a, 0xd0, 0x02, 0x28, 0x0c, 0xd0,
-0x03, 0x28, 0x02, 0xd1, 0x07, 0x48, 0x1c, 0x22, 0x08, 0x60, 0x10, 0x1c,
-0x70, 0x47, 0x06, 0x48, 0x04, 0xe0, 0x06, 0x48, 0x50, 0x22, 0x08, 0x60,
-0xf7, 0xe7, 0x05, 0x48, 0x68, 0x22, 0x08, 0x60, 0xf3, 0xe7, 0x00, 0x00,
-0x08, 0x83, 0x20, 0x40, 0xa4, 0x2a, 0x00, 0x80, 0x0c, 0x2b, 0x00, 0x80,
-0xa0, 0x82, 0x20, 0x40, 0x80, 0xb4, 0x03, 0x22, 0xc2, 0x80, 0x15, 0x4a,
-0xc0, 0x46, 0x82, 0x60, 0x14, 0x4a, 0x12, 0x88, 0x01, 0x32, 0xc2, 0x60,
-0x00, 0x20, 0x13, 0x4a, 0x13, 0x5c, 0xc0, 0x46, 0x0b, 0x70, 0x01, 0x30,
-0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x20, 0x22, 0x0a, 0x70, 0x01, 0x31,
-0x00, 0x20, 0x0e, 0x4b, 0x1f, 0x5c, 0xc0, 0x46, 0x0f, 0x70, 0x01, 0x30,
-0x01, 0x31, 0x08, 0x28, 0xf8, 0xd3, 0x0a, 0x70, 0x01, 0x31, 0x00, 0x20,
-0x09, 0x4a, 0x13, 0x5c, 0xc0, 0x46, 0x0b, 0x70, 0x01, 0x30, 0x01, 0x31,
-0x08, 0x28, 0xf8, 0xd3, 0x00, 0x20, 0x08, 0x70, 0x80, 0xbc, 0x70, 0x47,
-0x08, 0x10, 0x00, 0x03, 0x68, 0x0e, 0x00, 0x80, 0x7c, 0x04, 0x00, 0x80,
-0x85, 0x04, 0x00, 0x80, 0x8e, 0x04, 0x00, 0x80, 0x00, 0xb5, 0x01, 0x23,
-0x0a, 0x48, 0xc1, 0x1d, 0x89, 0x31, 0x4b, 0x70, 0x00, 0x22, 0x0a, 0x70,
-0x64, 0x21, 0x80, 0x30, 0xc1, 0x82, 0x01, 0x83, 0x43, 0x83, 0x7d, 0x21,
-0xc9, 0x00, 0x81, 0x83, 0xc2, 0x83, 0x04, 0x48, 0x01, 0x22, 0x00, 0x21,
-0x00, 0xf0, 0x8e, 0xfb, 0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80,
-0xb5, 0x22, 0xff, 0xff, 0x00, 0xb5, 0xff, 0xf7, 0xe1, 0xff, 0x13, 0x48,
-0x02, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x80, 0xfb, 0x01, 0x23, 0xd8, 0x42,
-0x0a, 0xd1, 0x10, 0x48, 0xc1, 0x1d, 0x39, 0x31, 0xca, 0x88, 0x01, 0x32,
-0xca, 0x80, 0x81, 0x79, 0x01, 0x31, 0x81, 0x71, 0xfd, 0xf7, 0x70, 0xf9,
-0x0b, 0x48, 0xc0, 0x68, 0x01, 0x28, 0x05, 0xd1, 0x0a, 0x48, 0x7d, 0x22,
-0xd2, 0x00, 0x00, 0x21, 0x00, 0xf0, 0x68, 0xfb, 0x08, 0x48, 0xfb, 0xf7,
-0xe1, 0xfc, 0x08, 0x48, 0x28, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x60, 0xfb,
-0x08, 0xbc, 0x18, 0x47, 0x79, 0x21, 0xff, 0xff, 0xa0, 0x82, 0x20, 0x40,
-0x68, 0x0e, 0x00, 0x80, 0xa5, 0x7b, 0x21, 0x40,
-0x95, 0x2c, 0xff, 0xff, 0x59, 0x03, 0xff, 0xff, 0x00, 0xb5, 0x10, 0x20,
-0x0f, 0x49, 0xc0, 0x46, 0x08, 0x60, 0x0f, 0x4a, 0x0f, 0x48, 0x64, 0x21,
-0xfb, 0xf7, 0xc6, 0xfc, 0x0e, 0x48, 0x01, 0x22, 0x12, 0x04, 0x01, 0x68,
-0x0a, 0x40, 0x08, 0x21, 0x00, 0x2a, 0x05, 0xd1, 0x02, 0x68, 0x12, 0x0c,
-0x07, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x04, 0xd3, 0x08, 0x48, 0xc0, 0x46,
-0xc1, 0x60, 0x08, 0xbc, 0x18, 0x47, 0x07, 0x48, 0xc0, 0x46, 0x01, 0x64,
-0xf9, 0xe7, 0x00, 0x00, 0x00, 0x00, 0x00, 0xb0, 0xa5, 0x55, 0xff, 0xff,
-0x7c, 0x29, 0x00, 0x80, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00,
-0x00, 0x00, 0x00, 0x80, 0xf8, 0xb5, 0x27, 0x48, 0x01, 0x22, 0x12, 0x04,
-0x01, 0x68, 0x0a, 0x40, 0x07, 0x21, 0x00, 0x2a, 0x05, 0xd1, 0x02, 0x68,
-0x12, 0x0c, 0x06, 0xd1, 0x00, 0x68, 0x80, 0x0a, 0x03, 0xd3, 0x21, 0x48,
-0xc0, 0x46, 0xc1, 0x60, 0x02, 0xe0, 0x20, 0x48, 0xc0, 0x46, 0x01, 0x64,
-0x1f, 0x48, 0xfb, 0xf7, 0x87, 0xfc, 0x1f, 0x48, 0xc1, 0x6b, 0xff, 0x29,
-0xfc, 0xd1, 0x81, 0x6b, 0x42, 0x6b, 0x16, 0x1c, 0x0f, 0x1c, 0x1c, 0x4c,
-0x10, 0x23, 0x60, 0x69, 0x18, 0x43, 0x60, 0x61, 0xa1, 0x69, 0x99, 0x43,
-0x1d, 0x04, 0xa1, 0x61, 0xe8, 0x60, 0xa0, 0x69, 0xc0, 0x46, 0x28, 0x61,
-0x16, 0x4a, 0x17, 0x49, 0x64, 0x20, 0xfb, 0xf7, 0x6f, 0xfc, 0x16, 0x4a,
-0xc0, 0x46, 0x00, 0x92, 0x15, 0x4b, 0x00, 0x20, 0x39, 0x1c, 0x32, 0x1c,
-0xfb, 0xf7, 0x6e, 0xfc, 0x13, 0x48, 0xc1, 0x68, 0x08, 0x29, 0xfc, 0xd1,
-0x12, 0x48, 0xfb, 0xf7, 0x5d, 0xfc, 0x10, 0x23, 0x60, 0x69, 0x98, 0x43,
-0x60, 0x61, 0xe8, 0x60, 0x01, 0x20, 0xe3, 0x23, 0x1b, 0x01, 0xe1, 0x18,
-0xc8, 0x71, 0xf8, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00, 0x10, 0x40,
-0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x02, 0xff, 0xff,
-0x00, 0x01, 0x18, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x20, 0x55, 0xff, 0xff,
-0xb5, 0xb6, 0x21, 0x40, 0x64, 0x00, 0x30, 0x02, 0x44, 0x80, 0x20, 0x40,
-0x40, 0x01, 0x18, 0x40, 0xf4, 0x01, 0xff, 0xff, 0x00, 0xb5, 0xfd, 0xf7,
-0x01, 0xff, 0x06, 0x48, 0xfb, 0xf7, 0x32, 0xfc, 0xfd, 0xf7, 0xd6, 0xfe,
-0xfe, 0xf7, 0x04, 0xf8, 0xfe, 0xf7, 0x16, 0xf8, 0xfe, 0xf7, 0x24, 0xf8,
-0x08, 0xbc, 0x18, 0x47, 0x91, 0x03, 0xff, 0xff, 0x90, 0xb5, 0xfd, 0xf7,
-0x6b, 0xfc, 0x34, 0x4f, 0x00, 0x24, 0xf9, 0x68, 0xf8, 0x1d, 0x79, 0x30,
-0x01, 0x29, 0x0f, 0xd1, 0x31, 0x49, 0xc0, 0x46, 0xf9, 0x67, 0x31, 0x49,
-0xc0, 0x46, 0x01, 0x60, 0x30, 0x49, 0xc0, 0x46, 0x0c, 0x60, 0x4c, 0x60,
-0x8c, 0x60, 0xcc, 0x60, 0x0c, 0x61, 0x4c, 0x61, 0x8c, 0x61, 0x04, 0xe0,
-0xf9, 0x1d, 0x7d, 0x31, 0xf9, 0x67, 0x12, 0xc0, 0x08, 0x38, 0x00, 0x68,
-0x60, 0x23, 0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0xf8, 0x6f, 0x20, 0x23,
-0x01, 0x68, 0x19, 0x43, 0x01, 0x60, 0xf8, 0x6f, 0x40, 0x23, 0x01, 0x68,
-0x99, 0x43, 0x01, 0x60, 0x00, 0xf0, 0x54, 0xf8, 0xfd, 0xf7, 0x4e, 0xfc,
-0x00, 0xf0, 0x5e, 0xf9, 0xfd, 0xf7, 0x73, 0xf8, 0xff, 0xf7, 0x0c, 0xfe,
-0xfd, 0xf7, 0x2e, 0xfe, 0xfd, 0xf7, 0xb6, 0xfd, 0xfd, 0xf7, 0xc2, 0xfe,
-0xfd, 0xf7, 0x54, 0xfd, 0xfd, 0xf7, 0x0a, 0xfd, 0xfd, 0xf7, 0x94, 0xfd,
-0x00, 0xf0, 0x1a, 0xfa, 0xfd, 0xf7, 0x9c, 0xff, 0xfd, 0xf7, 0x0a, 0xff,
-0xfd, 0xf7, 0xd2, 0xfe, 0xfd, 0xf7, 0x3c, 0xfc, 0xfb, 0xf7, 0xdc, 0xfa,
-0xff, 0xf7, 0x9c, 0xff, 0x71, 0x23, 0x5b, 0x01,
-0xf8, 0x18, 0x04, 0x72, 0x44, 0x72, 0x07, 0x23, 0x5b, 0x02, 0xf8, 0x18,
-0x04, 0x63, 0xf8, 0x68, 0x01, 0x28, 0x02, 0xd1, 0xa8, 0x20, 0xfe, 0xf7,
-0xb1, 0xfd, 0x09, 0x48, 0xc0, 0x46, 0x44, 0x62, 0x00, 0xf0, 0x18, 0xfa,
-0x07, 0x48, 0xfb, 0xf7, 0xbd, 0xfb, 0x90, 0xbc, 0x08, 0xbc, 0x18, 0x47,
-0x68, 0x0e, 0x00, 0x80, 0x00, 0x01, 0x11, 0x40, 0x04, 0x01, 0x11, 0x40,
-0x00, 0x01, 0x11, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x15, 0x8f, 0x21, 0x40,
-0x00, 0xb5, 0x04, 0x48, 0xfb, 0xf7, 0xaa, 0xfb, 0xfd, 0xf7, 0x5e, 0xff,
-0xfd, 0xf7, 0x24, 0xfc, 0x08, 0xbc, 0x18, 0x47, 0x15, 0x99, 0x21, 0x40,
-0xfa, 0x21, 0x03, 0x48, 0xc0, 0x46, 0x41, 0x62, 0x40, 0x21, 0x41, 0x62,
-0x70, 0x47, 0x00, 0x00, 0xc0, 0x00, 0x18, 0x00, 0x07, 0x48, 0x41, 0x69,
-0x07, 0x4b, 0x19, 0x43, 0x41, 0x61, 0x82, 0x69, 0x9a, 0x43, 0x82, 0x61,
-0x01, 0x22, 0x12, 0x05, 0xd1, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x10, 0x61,
-0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80, 0xfe, 0xaf, 0x9a, 0x10,
-0x00, 0xb5, 0x02, 0x48, 0xfb, 0xf7, 0x80, 0xfb, 0x08, 0xbc, 0x18, 0x47,
-0xc8, 0x57, 0xff, 0xff, 0xf0, 0xb5, 0x24, 0x4c, 0x01, 0x21, 0x09, 0x04,
-0x20, 0x68, 0x01, 0x40, 0x09, 0x20, 0x22, 0x4e, 0x22, 0x4d, 0x00, 0x29,
-0x05, 0xd1, 0x21, 0x68, 0x09, 0x0c, 0x04, 0xd1, 0x21, 0x68, 0x89, 0x0a,
-0x01, 0xd3, 0xf0, 0x60, 0x00, 0xe0, 0x28, 0x64, 0x1d, 0x48, 0xfb, 0xf7,
-0x65, 0xfb, 0x1d, 0x4f, 0x1d, 0x49, 0x88, 0x69, 0x01, 0x30, 0x88, 0x61,
-0x38, 0x7a, 0x00, 0x28, 0x02, 0xd1, 0x78, 0x7a, 0x00, 0x28, 0x1f, 0xd0,
-0x19, 0x48, 0xfb, 0xf7, 0x57, 0xfb, 0x19, 0x48, 0xfb, 0xf7, 0x54, 0xfb,
-0x00, 0x28, 0xfa, 0xd1, 0x38, 0x7a, 0x00, 0x28, 0x02, 0xd0, 0x16, 0x48,
-0xfb, 0xf7, 0x4c, 0xfb, 0x01, 0x21, 0x09, 0x04, 0x20, 0x68, 0x01, 0x40,
-0x14, 0x20, 0x00, 0x29, 0x05, 0xd1, 0x21, 0x68, 0x09, 0x0c, 0x04, 0xd1,
-0x21, 0x68, 0x89, 0x0a, 0x01, 0xd3, 0xf0, 0x60, 0x01, 0xe0, 0x28, 0x64,
-0xff, 0xe7, 0xfe, 0xe7, 0xff, 0xf7, 0x65, 0xfd, 0x0b, 0x48, 0xfb, 0xf7,
-0x35, 0xfb, 0xff, 0xf7, 0xaf, 0xff, 0xcd, 0xe7, 0x00, 0x00, 0x10, 0x40,
-0x40, 0x01, 0x18, 0x00, 0x00, 0x00, 0x00, 0x80, 0x04, 0x02, 0xff, 0xff,
-0x88, 0x1c, 0x00, 0x80, 0x08, 0x83, 0x20, 0x40, 0xf4, 0x01, 0xff, 0xff,
-0xb5, 0x07, 0xff, 0xff, 0x00, 0x00, 0xff, 0xff, 0x99, 0x9f, 0x21, 0x40,
-0x00, 0x20, 0x07, 0x4a, 0x01, 0x21, 0x09, 0x05, 0x50, 0x61, 0xc8, 0x60,
-0xd0, 0x61, 0xc8, 0x61, 0x03, 0x23, 0xdb, 0x04, 0x03, 0x4a, 0x01, 0x21,
-0xd1, 0x63, 0x58, 0x60, 0xfc, 0xe7, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0xc0, 0x00, 0x18, 0x00, 0x80, 0xb5, 0xc0, 0xb0, 0x01, 0x22, 0x00, 0x21,
-0x0a, 0x20, 0xfc, 0xf7, 0xd1, 0xff, 0x07, 0x1c, 0xff, 0x2f, 0x28, 0xd0,
-0x69, 0x46, 0xff, 0x22, 0x38, 0x1c, 0x01, 0x32, 0xfd, 0xf7, 0x54, 0xf9,
-0xff, 0x23, 0x01, 0x33, 0x98, 0x42, 0x1b, 0xd1, 0x0d, 0x98, 0x00, 0x09,
-0x18, 0xd3, 0x38, 0x1c, 0xfd, 0xf7, 0x8d, 0xf8, 0x0e, 0x49, 0x01, 0x22,
-0x12, 0x04, 0x08, 0x68, 0x02, 0x40, 0x0d, 0x48, 0x05, 0xd1, 0x0a, 0x68,
-0x12, 0x0c, 0x06, 0xd1, 0x09, 0x68, 0x89, 0x0a, 0x03, 0xd3, 0x0a, 0x49,
-0xc0, 0x46, 0xc8, 0x60, 0x02, 0xe0, 0x09, 0x49, 0xc0, 0x46, 0x08, 0x64,
-0xff, 0xf7, 0xbc, 0xff, 0x38, 0x1c, 0xfd, 0xf7, 0x74, 0xf8, 0x40, 0xb0,
-0x80, 0xbc, 0x08, 0xbc, 0x18, 0x47, 0x00, 0x00,
-0x00, 0x00, 0x10, 0x40, 0x07, 0x80, 0x00, 0x00, 0x40, 0x01, 0x18, 0x00,
-0x00, 0x00, 0x00, 0x80, 0x00, 0xb5, 0x17, 0x49, 0x01, 0x22, 0x12, 0x04,
-0x08, 0x68, 0x02, 0x40, 0x06, 0x20, 0x00, 0x2a, 0x05, 0xd1, 0x0a, 0x68,
-0x12, 0x0c, 0x06, 0xd1, 0x09, 0x68, 0x89, 0x0a, 0x03, 0xd3, 0x11, 0x49,
-0xc0, 0x46, 0xc8, 0x60, 0x02, 0xe0, 0x10, 0x49, 0xc0, 0x46, 0x08, 0x64,
-0x03, 0x20, 0xfe, 0xf7, 0xd3, 0xfc, 0xfb, 0xf7, 0x0d, 0xff, 0x01, 0x23,
-0x18, 0x43, 0xfb, 0xf7, 0xe7, 0xff, 0xff, 0xf7, 0x83, 0xfe, 0xff, 0xf7,
-0x9d, 0xff, 0xff, 0xf7, 0x05, 0xfe, 0xff, 0xf7, 0xf5, 0xfe, 0xff, 0xf7,
-0x09, 0xff, 0xff, 0xf7, 0x9b, 0xfd, 0xff, 0xf7, 0x21, 0xff, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00, 0x00, 0x00, 0x10, 0x40, 0x40, 0x01, 0x18, 0x00,
-0x00, 0x00, 0x00, 0x80, 0xf0, 0xb4, 0x46, 0x4a, 0x01, 0x21, 0xc9, 0x03,
-0x45, 0x4d, 0x19, 0x23, 0xdb, 0x01, 0xec, 0x18, 0xa1, 0x61, 0x28, 0x88,
-0x40, 0x04, 0x43, 0x4b, 0xc0, 0x18, 0x87, 0x1a, 0x04, 0x20, 0xaf, 0x60,
-0x41, 0x4e, 0xc0, 0x46, 0xb0, 0x61, 0x08, 0x20, 0xc8, 0x23, 0x43, 0x43,
-0xbb, 0x42, 0x21, 0xd9, 0x41, 0x00, 0x3d, 0x4e, 0xc0, 0x46, 0x31, 0x61,
-0xb6, 0x69, 0x20, 0x23, 0x9b, 0x1b, 0x3a, 0x4e, 0xc0, 0x46, 0xf3, 0x61,
-0x10, 0x3b, 0x33, 0x62, 0x8b, 0x00, 0xff, 0x1a, 0x40, 0x08, 0x81, 0x42,
-0x17, 0xd3, 0xb8, 0x23, 0x43, 0x43, 0xbb, 0x42, 0x08, 0xd9, 0x41, 0x1e,
-0x32, 0x4b, 0xc0, 0x46, 0x99, 0x81, 0xd9, 0x81, 0x40, 0x00, 0x02, 0x38,
-0x58, 0x61, 0x0a, 0xe0, 0x01, 0x30, 0x81, 0x42, 0xef, 0xd2, 0x06, 0xe0,
-0x2c, 0x4e, 0xb3, 0x69, 0x01, 0x33, 0xb3, 0x61, 0x40, 0x00, 0x88, 0x42,
-0xd2, 0xd9, 0x2a, 0x49, 0x00, 0x20, 0xa3, 0x69, 0x9b, 0x08, 0x07, 0xd0,
-0x28, 0x4b, 0x87, 0x00, 0xcb, 0x51, 0xa7, 0x69, 0xbf, 0x08, 0x01, 0x30,
-0x87, 0x42, 0xf8, 0xd8, 0x22, 0x49, 0xc0, 0x46, 0x8a, 0x62, 0x8c, 0x89,
-0x58, 0x20, 0x60, 0x43, 0x87, 0x18, 0x00, 0x20, 0x00, 0x22, 0x00, 0x2c,
-0x0a, 0xdd, 0x58, 0x23, 0x43, 0x43, 0x8c, 0x6a, 0xe3, 0x18, 0x01, 0x30,
-0x00, 0x04, 0x00, 0x0c, 0x9a, 0x60, 0x8b, 0x89, 0x83, 0x42, 0xf4, 0xdc,
-0xcf, 0x62, 0xcc, 0x89, 0x60, 0x00, 0x00, 0x19, 0x40, 0x01, 0xc7, 0x19,
-0x00, 0x20, 0x00, 0x2c, 0x0b, 0xdd, 0x43, 0x00, 0x1b, 0x18, 0x5b, 0x01,
-0xcc, 0x6a, 0xe3, 0x18, 0x01, 0x30, 0x00, 0x04, 0x00, 0x0c, 0x9a, 0x60,
-0xcb, 0x89, 0x83, 0x42, 0xf3, 0xdc, 0x4f, 0x62, 0x00, 0x20, 0x0b, 0x69,
-0x00, 0x2b, 0x07, 0xd9, 0x87, 0x00, 0x4b, 0x6a, 0xc0, 0x46, 0xda, 0x51,
-0x0b, 0x69, 0x01, 0x30, 0x83, 0x42, 0xf7, 0xd8, 0x49, 0x6a, 0x80, 0x00,
-0x08, 0x18, 0x04, 0x38, 0x28, 0x61, 0xf0, 0xbc, 0x70, 0x47, 0x00, 0x00,
-0xb0, 0xbe, 0x21, 0x40, 0x68, 0x0e, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40,
-0x4c, 0x2a, 0x00, 0x80, 0x00, 0x00, 0x20, 0x40, 0x00, 0xad, 0xde, 0x00,
-0x0a, 0x48, 0x01, 0x23, 0x1b, 0x06, 0x41, 0x69, 0x99, 0x43, 0x1a, 0x09,
-0x41, 0x61, 0xd1, 0x60, 0x00, 0x21, 0xa1, 0x22, 0x52, 0x03, 0x91, 0x61,
-0x1b, 0x23, 0xdb, 0x01, 0xc0, 0x18, 0x81, 0x61, 0x01, 0x20, 0x00, 0x06,
-0x59, 0x05, 0x08, 0x60, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0x80, 0xb4, 0x02, 0x1c, 0x0b, 0x48, 0x1b, 0x23, 0xdb, 0x01, 0xc3, 0x18,
-0x9a, 0x61, 0x01, 0x23, 0x1b, 0x06, 0x42, 0x69, 0x1a, 0x43, 0x42, 0x61,
-0x87, 0x69, 0x9f, 0x43, 0x01, 0x23, 0x1b, 0x05,
-0x87, 0x61, 0xda, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x18, 0x61, 0xa1, 0x20,
-0x40, 0x03, 0x81, 0x61, 0x80, 0xbc, 0x70, 0x47, 0x68, 0x0e, 0x00, 0x80,
-0x80, 0xb5, 0xff, 0xf7, 0xc9, 0xff, 0x00, 0x20, 0x00, 0xf0, 0x20, 0xf8,
-0x00, 0x20, 0x09, 0x49, 0x00, 0x22, 0x03, 0x01, 0x5f, 0x18, 0x33, 0x23,
-0x9b, 0x01, 0xfb, 0x18, 0x9a, 0x62, 0x01, 0x30, 0x0b, 0x28, 0xf6, 0xd3,
-0x04, 0x48, 0x01, 0x22, 0x00, 0x21, 0x00, 0xf0, 0x33, 0xf8, 0x80, 0xbc,
-0x08, 0xbc, 0x18, 0x47, 0x68, 0x0e, 0x00, 0x80, 0x1d, 0x3e, 0xff, 0xff,
-0x00, 0xb5, 0x02, 0x48, 0x00, 0xf0, 0x04, 0xf8, 0x08, 0xbc, 0x18, 0x47,
-0xa8, 0x61, 0x00, 0x00, 0x80, 0xb4, 0x01, 0x22, 0x12, 0x05, 0x0f, 0x4b,
-0xa1, 0x21, 0x49, 0x03, 0x00, 0x28, 0x0e, 0xd0, 0xc8, 0x61, 0x18, 0x1c,
-0x59, 0x69, 0x53, 0x01, 0x19, 0x43, 0x41, 0x61, 0x87, 0x69, 0x9f, 0x43,
-0x87, 0x61, 0xd1, 0x60, 0x80, 0x69, 0xc0, 0x46, 0x10, 0x61, 0x80, 0xbc,
-0x70, 0x47, 0x18, 0x1c, 0x5f, 0x69, 0x01, 0x23, 0x5b, 0x06, 0x9f, 0x43,
-0x47, 0x61, 0xd7, 0x60, 0x00, 0x20, 0xc8, 0x61, 0xf3, 0xe7, 0x00, 0x00,
-0x68, 0x0e, 0x00, 0x80, 0xb0, 0xb4, 0x07, 0x1c, 0x00, 0x20, 0x17, 0x4c,
-0x03, 0x01, 0x1d, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xeb, 0x18, 0x9d, 0x6a,
-0xbd, 0x42, 0x05, 0xd1, 0x1d, 0x6b, 0x95, 0x42, 0x02, 0xd1, 0xdb, 0x6a,
-0x8b, 0x42, 0x1c, 0xd0, 0x01, 0x30, 0x0b, 0x28, 0xee, 0xd3, 0x00, 0x20,
-0x03, 0x01, 0x1d, 0x19, 0x33, 0x23, 0x9b, 0x01, 0xeb, 0x18, 0x9b, 0x6a,
-0x00, 0x2b, 0x09, 0xd1, 0x03, 0x01, 0x1c, 0x19, 0x33, 0x23, 0x9b, 0x01,
-0xe3, 0x18, 0x1a, 0x63, 0xd9, 0x62, 0x5a, 0x63, 0x9f, 0x62, 0x02, 0xe0,
-0x01, 0x30, 0x0b, 0x28, 0xea, 0xd3, 0x0b, 0x28, 0x01, 0xd1, 0x00, 0x20,
-0xc0, 0x43, 0xb0, 0xbc, 0x70, 0x47, 0x00, 0x00, 0x68, 0x0e, 0x00, 0x80,
-0x90, 0xb4, 0x01, 0x1c, 0x00, 0x22, 0x01, 0x20, 0x16, 0x4f, 0x01, 0xe0,
-0x00, 0x2a, 0x07, 0xd1, 0x03, 0x01, 0xdc, 0x19, 0x33, 0x23, 0x9b, 0x01,
-0xe3, 0x18, 0x9b, 0x69, 0x8b, 0x42, 0x11, 0xd1, 0x02, 0x01, 0xd2, 0x19,
-0x33, 0x23, 0x9b, 0x01, 0xd2, 0x18, 0x93, 0x6a, 0xc0, 0x46, 0x93, 0x61,
-0xd3, 0x6a, 0xc0, 0x46, 0xd3, 0x61, 0x13, 0x6b, 0xc0, 0x46, 0x13, 0x62,
-0x53, 0x6b, 0xc0, 0x46, 0x53, 0x62, 0x01, 0x22, 0x01, 0x30, 0x0b, 0x28,
-0xe0, 0xd3, 0x07, 0x4b, 0x00, 0x2a, 0x02, 0xd1, 0x9a, 0x68, 0x8a, 0x42,
-0x03, 0xd1, 0x00, 0x21, 0x99, 0x60, 0x90, 0xbc, 0x70, 0x47, 0x00, 0x20,
-0xc0, 0x43, 0xfa, 0xe7, 0x68, 0x0e, 0x00, 0x80, 0xe8, 0x1b, 0x00, 0x80,
-0x0b, 0x28, 0x17, 0xda, 0x0c, 0x49, 0x01, 0x23, 0x5b, 0x06, 0x8a, 0x69,
-0x13, 0x43, 0x01, 0x22, 0x12, 0x05, 0x8b, 0x61, 0x13, 0x61, 0x00, 0x01,
-0x40, 0x18, 0x33, 0x23, 0x9b, 0x01, 0xc0, 0x18, 0x03, 0x6b, 0xc0, 0x46,
-0x43, 0x63, 0x53, 0x01, 0x88, 0x69, 0x98, 0x43, 0x88, 0x61, 0x10, 0x61,
-0x01, 0x20, 0x70, 0x47, 0x00, 0x20, 0xfc, 0xe7, 0x68, 0x0e, 0x00, 0x80,
-0x90, 0xb4, 0x08, 0x4a, 0xd0, 0x69, 0x00, 0x21, 0x07, 0x4f, 0xd3, 0x69,
-0x83, 0x42, 0x02, 0xd9, 0xfc, 0x1a, 0x20, 0x18, 0x00, 0xe0, 0xc0, 0x1a,
-0x09, 0x18, 0x18, 0x1c, 0xb9, 0x42, 0xf4, 0xd9, 0x90, 0xbc, 0x70, 0x47,
-0x00, 0x20, 0x14, 0x40, 0xa8, 0x61, 0x00, 0x00, 0x90, 0xb5, 0x07, 0x1c,
-0x00, 0x24, 0x00, 0x2f, 0x04, 0xd3, 0xff, 0xf7, 0xe3, 0xff, 0x01, 0x34,
-0xbc, 0x42, 0xfa, 0xd9, 0x90, 0xbc, 0x08, 0xbc,
-0x18, 0x47, 0x00, 0x00,
-};
index a8e5651f31654bfb328545efe07cf1dbfd43276b..9dd4f76a2ff5846ee4c14f066939593768e2a328 100644 (file)
@@ -100,10 +100,11 @@ static const int multicast_filter_limit = 32;
 #define PKT_BUF_SZ             1536
 
 #define DRV_MODULE_NAME                "typhoon"
-#define DRV_MODULE_VERSION     "1.5.8"
-#define DRV_MODULE_RELDATE     "06/11/09"
+#define DRV_MODULE_VERSION     "1.5.9"
+#define DRV_MODULE_RELDATE     "Mar 2, 2009"
 #define PFX                    DRV_MODULE_NAME ": "
 #define ERR_PFX                        KERN_ERR PFX
+#define FIRMWARE_NAME          "3com/typhoon.bin"
 
 #include <linux/module.h>
 #include <linux/kernel.h>
@@ -129,9 +130,9 @@ static const int multicast_filter_limit = 32;
 #include <asm/uaccess.h>
 #include <linux/in6.h>
 #include <linux/dma-mapping.h>
+#include <linux/firmware.h>
 
 #include "typhoon.h"
-#include "typhoon-firmware.h"
 
 static char version[] __devinitdata =
     "typhoon.c: version " DRV_MODULE_VERSION " (" DRV_MODULE_RELDATE ")\n";
@@ -139,6 +140,7 @@ static char version[] __devinitdata =
 MODULE_AUTHOR("David Dillow <dave@thedillows.org>");
 MODULE_VERSION(DRV_MODULE_VERSION);
 MODULE_LICENSE("GPL");
+MODULE_FIRMWARE(FIRMWARE_NAME);
 MODULE_DESCRIPTION("3Com Typhoon Family (3C990, 3CR990, and variants)");
 MODULE_PARM_DESC(rx_copybreak, "Packets smaller than this are copied and "
                               "the buffer given back to the NIC. Default "
@@ -1344,14 +1346,74 @@ typhoon_init_rings(struct typhoon *tp)
        tp->txHiRing.lastRead = 0;
 }
 
+static const struct firmware *typhoon_fw;
+
+static int
+typhoon_request_firmware(struct typhoon *tp)
+{
+       const struct typhoon_file_header *fHdr;
+       const struct typhoon_section_header *sHdr;
+       const u8 *image_data;
+       u32 numSections;
+       u32 section_len;
+       u32 remaining;
+       int err;
+
+       if (typhoon_fw)
+               return 0;
+
+       err = request_firmware(&typhoon_fw, FIRMWARE_NAME, &tp->pdev->dev);
+       if (err) {
+               printk(KERN_ERR "%s: Failed to load firmware \"%s\"\n",
+                               tp->name, FIRMWARE_NAME);
+               return err;
+       }
+
+       image_data = (u8 *) typhoon_fw->data;
+       remaining = typhoon_fw->size;
+       if (remaining < sizeof(struct typhoon_file_header))
+               goto invalid_fw;
+
+       fHdr = (struct typhoon_file_header *) image_data;
+       if (memcmp(fHdr->tag, "TYPHOON", 8))
+               goto invalid_fw;
+
+       numSections = le32_to_cpu(fHdr->numSections);
+       image_data += sizeof(struct typhoon_file_header);
+       remaining -= sizeof(struct typhoon_file_header);
+
+       while (numSections--) {
+               if (remaining < sizeof(struct typhoon_section_header))
+                       goto invalid_fw;
+
+               sHdr = (struct typhoon_section_header *) image_data;
+               image_data += sizeof(struct typhoon_section_header);
+               section_len = le32_to_cpu(sHdr->len);
+
+               if (remaining < section_len)
+                       goto invalid_fw;
+
+               image_data += section_len;
+               remaining -= section_len;
+       }
+
+       return 0;
+
+invalid_fw:
+       printk(KERN_ERR "%s: Invalid firmware image\n", tp->name);
+       release_firmware(typhoon_fw);
+       typhoon_fw = NULL;
+       return -EINVAL;
+}
+
 static int
 typhoon_download_firmware(struct typhoon *tp)
 {
        void __iomem *ioaddr = tp->ioaddr;
        struct pci_dev *pdev = tp->pdev;
-       struct typhoon_file_header *fHdr;
-       struct typhoon_section_header *sHdr;
-       u8 *image_data;
+       const struct typhoon_file_header *fHdr;
+       const struct typhoon_section_header *sHdr;
+       const u8 *image_data;
        void *dpage;
        dma_addr_t dpage_dma;
        __sum16 csum;
@@ -1365,20 +1427,12 @@ typhoon_download_firmware(struct typhoon *tp)
        int i;
        int err;
 
-       err = -EINVAL;
-       fHdr = (struct typhoon_file_header *) typhoon_firmware_image;
-       image_data = (u8 *) fHdr;
-
-       if(memcmp(fHdr->tag, "TYPHOON", 8)) {
-               printk(KERN_ERR "%s: Invalid firmware image!\n", tp->name);
-               goto err_out;
-       }
+       image_data = (u8 *) typhoon_fw->data;
+       fHdr = (struct typhoon_file_header *) image_data;
 
        /* Cannot just map the firmware image using pci_map_single() as
-        * the firmware is part of the kernel/module image, so we allocate
-        * some consistent memory to copy the sections into, as it is simpler,
-        * and short-lived. If we ever split out and require a userland
-        * firmware loader, then we can revisit this.
+        * the firmware is vmalloc()'d and may not be physically contiguous,
+        * so we allocate some consistent memory to copy the sections into.
         */
        err = -ENOMEM;
        dpage = pci_alloc_consistent(pdev, PAGE_SIZE, &dpage_dma);
@@ -2086,6 +2140,10 @@ typhoon_open(struct net_device *dev)
        struct typhoon *tp = netdev_priv(dev);
        int err;
 
+       err = typhoon_request_firmware(tp);
+       if (err)
+               goto out;
+
        err = typhoon_wakeup(tp, WaitSleep);
        if(err < 0) {
                printk(KERN_ERR "%s: unable to wakeup device\n", dev->name);
@@ -2624,6 +2682,8 @@ typhoon_init(void)
 static void __exit
 typhoon_cleanup(void)
 {
+       if (typhoon_fw)
+               release_firmware(typhoon_fw);
        pci_unregister_driver(&typhoon_driver);
 }
 
index 1c095c63f98f482b10cf7ee71c3b84f472da12cf..0b675127e83bc0a3f451fef57652138015a17aa7 100644 (file)
@@ -1536,32 +1536,15 @@ static void adjust_link(struct net_device *dev)
 static int init_phy(struct net_device *dev)
 {
        struct ucc_geth_private *priv = netdev_priv(dev);
-       struct device_node *np = priv->node;
-       struct device_node *phy, *mdio;
-       const phandle *ph;
-       char bus_name[MII_BUS_ID_SIZE];
-       const unsigned int *id;
+       struct ucc_geth_info *ug_info = priv->ug_info;
        struct phy_device *phydev;
-       char phy_id[BUS_ID_SIZE];
 
        priv->oldlink = 0;
        priv->oldspeed = 0;
        priv->oldduplex = -1;
 
-       ph = of_get_property(np, "phy-handle", NULL);
-       phy = of_find_node_by_phandle(*ph);
-       mdio = of_get_parent(phy);
-
-       id = of_get_property(phy, "reg", NULL);
-
-       of_node_put(phy);
-       of_node_put(mdio);
-
-       fsl_pq_mdio_bus_name(bus_name, mdio);
-       snprintf(phy_id, sizeof(phy_id), "%s:%02x",
-                                bus_name, *id);
-
-       phydev = phy_connect(dev, phy_id, &adjust_link, 0, priv->phy_interface);
+       phydev = phy_connect(dev, ug_info->phy_bus_id, &adjust_link, 0,
+                            priv->phy_interface);
 
        if (IS_ERR(phydev)) {
                printk("%s: Could not attach to PHY\n", dev->name);
@@ -3629,10 +3612,12 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
        ug_info->uf_info.irq = irq_of_parse_and_map(np, 0);
        fixed_link = of_get_property(np, "fixed-link", NULL);
        if (fixed_link) {
-               snprintf(ug_info->mdio_bus, MII_BUS_ID_SIZE, "0");
-               ug_info->phy_address = fixed_link[0];
+               snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id),
+                        PHY_ID_FMT, "0", fixed_link[0]);
                phy = NULL;
        } else {
+               char bus_name[MII_BUS_ID_SIZE];
+
                ph = of_get_property(np, "phy-handle", NULL);
                phy = of_find_node_by_phandle(*ph);
 
@@ -3643,7 +3628,6 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
                prop = of_get_property(phy, "reg", NULL);
                if (prop == NULL)
                        return -1;
-               ug_info->phy_address = *prop;
 
                /* Set the bus id */
                mdio = of_get_parent(phy);
@@ -3657,8 +3641,9 @@ static int ucc_geth_probe(struct of_device* ofdev, const struct of_device_id *ma
                if (err)
                        return -1;
 
-               snprintf(ug_info->mdio_bus, MII_BUS_ID_SIZE, "%x",
-                               res.start&0xfffff);
+               fsl_pq_mdio_bus_name(bus_name, mdio);
+               snprintf(ug_info->phy_bus_id, sizeof(ug_info->phy_bus_id),
+                       "%s:%02x", bus_name, *prop);
        }
 
        /* get the phy interface type, or default to MII */
index 66d18971fa0c74cf2dbd7b127fd7ebcdc5beac2f..e3a25e64a6525f38a2329125b09e01bb116e8ae2 100644 (file)
@@ -1101,8 +1101,7 @@ struct ucc_geth_info {
        u32 eventRegMask;
        u16 pausePeriod;
        u16 extensionField;
-       u8 phy_address;
-       char mdio_bus[MII_BUS_ID_SIZE];
+       char phy_bus_id[BUS_ID_SIZE];
        u8 weightfactor[NUM_TX_QUEUES];
        u8 interruptcoalescingmaxvalue[NUM_RX_QUEUES];
        u8 l2qt[UCC_GETH_VLAN_PRIORITY_MAX];
index e009481c606c740cea0b2a30fd7bad7f30f3fe8d..87b4a0289919d1d96e52262a7b28bb88e88ed390 100644 (file)
@@ -807,6 +807,18 @@ static int ax88172_link_reset(struct usbnet *dev)
        return 0;
 }
 
+static const struct net_device_ops ax88172_netdev_ops = {
+       .ndo_open               = usbnet_open,
+       .ndo_stop               = usbnet_stop,
+       .ndo_start_xmit         = usbnet_start_xmit,
+       .ndo_tx_timeout         = usbnet_tx_timeout,
+       .ndo_change_mtu         = usbnet_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_do_ioctl           = asix_ioctl,
+       .ndo_set_multicast_list = ax88172_set_multicast,
+};
+
 static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
 {
        int ret = 0;
@@ -846,9 +858,8 @@ static int ax88172_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->mii.phy_id_mask = 0x3f;
        dev->mii.reg_num_mask = 0x1f;
        dev->mii.phy_id = asix_get_phy_addr(dev);
-       dev->net->do_ioctl = asix_ioctl;
 
-       dev->net->set_multicast_list = ax88172_set_multicast;
+       dev->net->netdev_ops = &ax88172_netdev_ops;
        dev->net->ethtool_ops = &ax88172_ethtool_ops;
 
        asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
@@ -898,6 +909,18 @@ static int ax88772_link_reset(struct usbnet *dev)
        return 0;
 }
 
+static const struct net_device_ops ax88772_netdev_ops = {
+       .ndo_open               = usbnet_open,
+       .ndo_stop               = usbnet_stop,
+       .ndo_start_xmit         = usbnet_start_xmit,
+       .ndo_tx_timeout         = usbnet_tx_timeout,
+       .ndo_change_mtu         = usbnet_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_do_ioctl           = asix_ioctl,
+       .ndo_set_multicast_list = asix_set_multicast,
+};
+
 static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
 {
        int ret, embd_phy;
@@ -962,7 +985,6 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->mii.mdio_write = asix_mdio_write;
        dev->mii.phy_id_mask = 0x1f;
        dev->mii.reg_num_mask = 0x1f;
-       dev->net->do_ioctl = asix_ioctl;
        dev->mii.phy_id = asix_get_phy_addr(dev);
 
        phyid = asix_get_phyid(dev);
@@ -978,7 +1000,7 @@ static int ax88772_bind(struct usbnet *dev, struct usb_interface *intf)
 
        msleep(150);
 
-       dev->net->set_multicast_list = asix_set_multicast;
+       dev->net->netdev_ops = &ax88772_netdev_ops;
        dev->net->ethtool_ops = &ax88772_ethtool_ops;
 
        asix_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
@@ -1181,6 +1203,18 @@ static int ax88178_change_mtu(struct net_device *net, int new_mtu)
        return 0;
 }
 
+static const struct net_device_ops ax88178_netdev_ops = {
+       .ndo_open               = usbnet_open,
+       .ndo_stop               = usbnet_stop,
+       .ndo_start_xmit         = usbnet_start_xmit,
+       .ndo_tx_timeout         = usbnet_tx_timeout,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_set_multicast_list = asix_set_multicast,
+       .ndo_do_ioctl           = asix_ioctl,
+       .ndo_change_mtu         = ax88178_change_mtu,
+};
+
 static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
 {
        struct asix_data *data = (struct asix_data *)&dev->data;
@@ -1247,11 +1281,10 @@ static int ax88178_bind(struct usbnet *dev, struct usb_interface *intf)
        dev->mii.phy_id_mask = 0x1f;
        dev->mii.reg_num_mask = 0xff;
        dev->mii.supports_gmii = 1;
-       dev->net->do_ioctl = asix_ioctl;
        dev->mii.phy_id = asix_get_phy_addr(dev);
-       dev->net->set_multicast_list = asix_set_multicast;
+
+       dev->net->netdev_ops = &ax88178_netdev_ops;
        dev->net->ethtool_ops = &ax88178_ethtool_ops;
-       dev->net->change_mtu = &ax88178_change_mtu;
 
        phyid = asix_get_phyid(dev);
        dbg("PHYID=0x%08x", phyid);
@@ -1451,6 +1484,14 @@ static const struct usb_device_id        products [] = {
        // Cables-to-Go USB Ethernet Adapter
        USB_DEVICE(0x0b95, 0x772a),
        .driver_info = (unsigned long) &ax88772_info,
+}, {
+       // ABOCOM for pci
+       USB_DEVICE(0x14ea, 0xab11),
+       .driver_info = (unsigned long) &ax88178_info,
+}, {
+       // ASIX 88772a
+       USB_DEVICE(0x0db0, 0xa877),
+       .driver_info = (unsigned long) &ax88772_info,
 },
        { },            // END
 };
index cb7acbbb279875893a1fa3f398a8fe5eaa5fe22e..b9dd425742881ac4c79c0fe32b647dab8c841a1d 100644 (file)
@@ -163,7 +163,6 @@ struct catc {
        struct net_device *netdev;
        struct usb_device *usbdev;
 
-       struct net_device_stats stats;
        unsigned long flags;
 
        unsigned int tx_ptr, tx_idx;
@@ -245,8 +244,8 @@ static void catc_rx_done(struct urb *urb)
                if(!catc->is_f5u011) {
                        pkt_len = le16_to_cpup((__le16*)pkt_start);
                        if (pkt_len > urb->actual_length) {
-                               catc->stats.rx_length_errors++;
-                               catc->stats.rx_errors++;
+                               catc->netdev->stats.rx_length_errors++;
+                               catc->netdev->stats.rx_errors++;
                                break;
                        }
                } else {
@@ -262,8 +261,8 @@ static void catc_rx_done(struct urb *urb)
                skb->protocol = eth_type_trans(skb, catc->netdev);
                netif_rx(skb);
 
-               catc->stats.rx_packets++;
-               catc->stats.rx_bytes += pkt_len;
+               catc->netdev->stats.rx_packets++;
+               catc->netdev->stats.rx_bytes += pkt_len;
 
                /* F5U011 only does one packet per RX */
                if (catc->is_f5u011)
@@ -386,7 +385,7 @@ static void catc_tx_done(struct urb *urb)
                dbg("Tx Reset.");
                urb->status = 0;
                catc->netdev->trans_start = jiffies;
-               catc->stats.tx_errors++;
+               catc->netdev->stats.tx_errors++;
                clear_bit(TX_RUNNING, &catc->flags);
                netif_wake_queue(catc->netdev);
                return;
@@ -412,7 +411,7 @@ static void catc_tx_done(struct urb *urb)
        spin_unlock_irqrestore(&catc->tx_lock, flags);
 }
 
-static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
+static int catc_start_xmit(struct sk_buff *skb, struct net_device *netdev)
 {
        struct catc *catc = netdev_priv(netdev);
        unsigned long flags;
@@ -443,8 +442,8 @@ static int catc_hard_start_xmit(struct sk_buff *skb, struct net_device *netdev)
        spin_unlock_irqrestore(&catc->tx_lock, flags);
 
        if (r >= 0) {
-               catc->stats.tx_bytes += skb->len;
-               catc->stats.tx_packets++;
+               catc->netdev->stats.tx_bytes += skb->len;
+               catc->netdev->stats.tx_packets++;
        }
 
        dev_kfree_skb(skb);
@@ -588,15 +587,15 @@ static void catc_stats_done(struct catc *catc, struct ctrl_queue *q)
        switch (index) {
                case TxSingleColl:
                case TxMultiColl:
-                       catc->stats.collisions += data - last;
+                       catc->netdev->stats.collisions += data - last;
                        break;
                case TxExcessColl:
-                       catc->stats.tx_aborted_errors += data - last;
-                       catc->stats.tx_errors += data - last;
+                       catc->netdev->stats.tx_aborted_errors += data - last;
+                       catc->netdev->stats.tx_errors += data - last;
                        break;
                case RxFramErr:
-                       catc->stats.rx_frame_errors += data - last;
-                       catc->stats.rx_errors += data - last;
+                       catc->netdev->stats.rx_frame_errors += data - last;
+                       catc->netdev->stats.rx_errors += data - last;
                        break;
        }
 
@@ -614,12 +613,6 @@ static void catc_stats_timer(unsigned long data)
        mod_timer(&catc->timer, jiffies + STATS_UPDATE);
 }
 
-static struct net_device_stats *catc_get_stats(struct net_device *netdev)
-{
-       struct catc *catc = netdev_priv(netdev);
-       return &catc->stats;
-}
-
 /*
  * Receive modes. Broadcast, Multicast, Promisc.
  */
@@ -750,6 +743,18 @@ static int catc_stop(struct net_device *netdev)
        return 0;
 }
 
+static const struct net_device_ops catc_netdev_ops = {
+       .ndo_open               = catc_open,
+       .ndo_stop               = catc_stop,
+       .ndo_start_xmit         = catc_start_xmit,
+
+       .ndo_tx_timeout         = catc_tx_timeout,
+       .ndo_set_multicast_list = catc_set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 /*
  * USB probe, disconnect.
  */
@@ -774,13 +779,8 @@ static int catc_probe(struct usb_interface *intf, const struct usb_device_id *id
 
        catc = netdev_priv(netdev);
 
-       netdev->open = catc_open;
-       netdev->hard_start_xmit = catc_hard_start_xmit;
-       netdev->stop = catc_stop;
-       netdev->get_stats = catc_get_stats;
-       netdev->tx_timeout = catc_tx_timeout;
+       netdev->netdev_ops = &catc_netdev_ops;
        netdev->watchdog_timeo = TX_TIMEOUT;
-       netdev->set_multicast_list = catc_set_multicast_list;
        SET_ETHTOOL_OPS(netdev, &ops);
 
        catc->usbdev = usbdev;
index 0e061dfea78d15226e65da13e5aa1f764c09bd30..55e8ecc3a9e5d5bd6eb88038530ccada469bb2c6 100644 (file)
@@ -559,6 +559,11 @@ static const struct usb_device_id  products [] = {
        USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ETHERNET,
                        USB_CDC_PROTO_NONE),
        .driver_info = (unsigned long) &cdc_info,
+}, {
+       /* Ericsson F3507g */
+       USB_DEVICE_AND_INTERFACE_INFO(0x0bdb, 0x1900, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
+       .driver_info = (unsigned long) &cdc_info,
 },
        { },            // END
 };
index 5b67bbf1987e33b8015f11de5faeb8dd2644978d..6fc4f82b0bebdd4d1fb7688675a680511d2a7f99 100644 (file)
@@ -419,6 +419,18 @@ static int dm9601_set_mac_address(struct net_device *net, void *p)
        return 0;
 }
 
+static const struct net_device_ops dm9601_netdev_ops = {
+       .ndo_open               = usbnet_open,
+       .ndo_stop               = usbnet_stop,
+       .ndo_start_xmit         = usbnet_start_xmit,
+       .ndo_tx_timeout         = usbnet_tx_timeout,
+       .ndo_change_mtu         = usbnet_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_do_ioctl           = dm9601_ioctl,
+       .ndo_set_multicast_list = dm9601_set_multicast,
+       .ndo_set_mac_address    = dm9601_set_mac_address,
+};
+
 static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)
 {
        int ret;
@@ -428,9 +440,7 @@ static int dm9601_bind(struct usbnet *dev, struct usb_interface *intf)
        if (ret)
                goto out;
 
-       dev->net->do_ioctl = dm9601_ioctl;
-       dev->net->set_multicast_list = dm9601_set_multicast;
-       dev->net->set_mac_address = dm9601_set_mac_address;
+       dev->net->netdev_ops = &dm9601_netdev_ops;
        dev->net->ethtool_ops = &dm9601_ethtool_ops;
        dev->net->hard_header_len += DM_TX_OVERHEAD;
        dev->hard_mtu = dev->net->mtu + dev->net->hard_header_len;
@@ -633,6 +643,10 @@ static const struct usb_device_id products[] = {
         },
        {
        USB_DEVICE(0x0a47, 0x9601),     /* Hirose USB-100 */
+       .driver_info = (unsigned long)&dm9601_info,
+        },
+       {
+       USB_DEVICE(0x0fe6, 0x8101),     /* DM9601 USB to Fast Ethernet Adapter */
        .driver_info = (unsigned long)&dm9601_info,
         },
        {},                     // END
index a074c16e2a62c0ca2f6f87da709cfb158d74dc9c..cde423c6d040d1174bc88571802f52ad94d50e85 100644 (file)
@@ -2363,12 +2363,6 @@ exit:
        return -1;
 }
 
-/* Frees a general hso device */
-static void hso_free_device(struct hso_device *hso_dev)
-{
-       kfree(hso_dev);
-}
-
 /* Creates a general hso device */
 static struct hso_device *hso_create_device(struct usb_interface *intf,
                                            int port_spec)
@@ -2431,9 +2425,16 @@ static void hso_free_net_device(struct hso_device *hso_dev)
                free_netdev(hso_net->net);
        }
 
-       hso_free_device(hso_dev);
+       kfree(hso_dev);
 }
 
+static const struct net_device_ops hso_netdev_ops = {
+       .ndo_open       = hso_net_open,
+       .ndo_stop       = hso_net_close,
+       .ndo_start_xmit = hso_net_start_xmit,
+       .ndo_tx_timeout = hso_net_tx_timeout,
+};
+
 /* initialize the network interface */
 static void hso_net_init(struct net_device *net)
 {
@@ -2442,10 +2443,7 @@ static void hso_net_init(struct net_device *net)
        D1("sizeof hso_net is %d", (int)sizeof(*hso_net));
 
        /* fill in the other fields */
-       net->open = hso_net_open;
-       net->stop = hso_net_close;
-       net->hard_start_xmit = hso_net_start_xmit;
-       net->tx_timeout = hso_net_tx_timeout;
+       net->netdev_ops = &hso_netdev_ops;
        net->watchdog_timeo = HSO_NET_TX_TIMEOUT;
        net->flags = IFF_POINTOPOINT | IFF_NOARP | IFF_MULTICAST;
        net->type = ARPHRD_NONE;
@@ -2645,7 +2643,7 @@ static void hso_free_serial_device(struct hso_device *hso_dev)
        }
        hso_free_tiomget(serial);
        kfree(serial);
-       hso_free_device(hso_dev);
+       kfree(hso_dev);
 }
 
 /* Creates a bulk AT channel */
@@ -2726,7 +2724,7 @@ exit2:
 exit:
        hso_free_tiomget(serial);
        kfree(serial);
-       hso_free_device(hso_dev);
+       kfree(hso_dev);
        return NULL;
 }
 
@@ -2785,7 +2783,7 @@ exit:
                kfree(serial);
        }
        if (hso_dev)
-               hso_free_device(hso_dev);
+               kfree(hso_dev);
        return NULL;
 
 }
@@ -2978,8 +2976,6 @@ static int hso_probe(struct usb_interface *interface,
                goto exit;
        }
 
-       usb_driver_claim_interface(&hso_driver, interface, hso_dev);
-
        /* save our data pointer in this device */
        usb_set_intfdata(interface, hso_dev);
 
@@ -2997,8 +2993,6 @@ static void hso_disconnect(struct usb_interface *interface)
 
        /* remove reference of our private data */
        usb_set_intfdata(interface, NULL);
-
-       usb_driver_release_interface(&hso_driver, interface);
 }
 
 static void async_get_intf(struct work_struct *data)
index ced8f36ebd011617c0a42196b09549e59a634435..7ae9afe99a4f410c582806f8b28cf1784fc08d94 100644 (file)
@@ -486,6 +486,18 @@ static int mcs7830_set_mac_address(struct net_device *netdev, void *p)
        return 0;
 }
 
+static const struct net_device_ops mcs7830_netdev_ops = {
+       .ndo_open               = usbnet_open,
+       .ndo_stop               = usbnet_stop,
+       .ndo_start_xmit         = usbnet_start_xmit,
+       .ndo_tx_timeout         = usbnet_tx_timeout,
+       .ndo_change_mtu         = usbnet_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_do_ioctl           = mcs7830_ioctl,
+       .ndo_set_multicast_list = mcs7830_set_multicast,
+       .ndo_set_mac_address     = mcs7830_set_mac_address,
+};
+
 static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev)
 {
        struct net_device *net = dev->net;
@@ -495,11 +507,9 @@ static int mcs7830_bind(struct usbnet *dev, struct usb_interface *udev)
        if (ret)
                goto out;
 
-       net->do_ioctl = mcs7830_ioctl;
        net->ethtool_ops = &mcs7830_ethtool_ops;
-       net->set_multicast_list = mcs7830_set_multicast;
+       net->netdev_ops = &mcs7830_netdev_ops;
        mcs7830_set_multicast(net);
-       net->set_mac_address = mcs7830_set_mac_address;
 
        /* reserve space for the status byte on rx */
        dev->rx_urb_size = ETH_FRAME_LEN + 1;
index b7f763e1298ccb781e68a0e5b1040bf5ef5493fe..1bf243ef950e264e4a11ec86c900812db31e6a99 100644 (file)
@@ -266,6 +266,16 @@ response_error:
        return -EDOM;
 }
 
+/* same as usbnet_netdev_ops but MTU change not allowed */
+static const struct net_device_ops rndis_netdev_ops = {
+       .ndo_open               = usbnet_open,
+       .ndo_stop               = usbnet_stop,
+       .ndo_start_xmit         = usbnet_start_xmit,
+       .ndo_tx_timeout         = usbnet_tx_timeout,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 int
 generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags)
 {
@@ -327,7 +337,8 @@ generic_rndis_bind(struct usbnet *dev, struct usb_interface *intf, int flags)
        dev->rx_urb_size &= ~(dev->maxpacket - 1);
        u.init->max_transfer_size = cpu_to_le32(dev->rx_urb_size);
 
-       net->change_mtu = NULL;
+       net->netdev_ops = &rndis_netdev_ops;
+
        retval = rndis_command(dev, u.header, CONTROL_BUFFER_SIZE);
        if (unlikely(retval < 0)) {
                /* it might not even be an RNDIS device!! */
index d8664bf18c0000bd77a93426d39a10e0f48b6589..f9fb454ffa8bab25db07ce78f50e30c4fbbc3e80 100644 (file)
@@ -155,7 +155,6 @@ struct rtl8150 {
        unsigned long flags;
        struct usb_device *udev;
        struct tasklet_struct tl;
-       struct net_device_stats stats;
        struct net_device *netdev;
        struct urb *rx_urb, *tx_urb, *intr_urb, *ctrl_urb;
        struct sk_buff *tx_skb, *rx_skb;
@@ -463,8 +462,8 @@ static void read_bulk_callback(struct urb *urb)
        skb_put(dev->rx_skb, pkt_len);
        dev->rx_skb->protocol = eth_type_trans(dev->rx_skb, netdev);
        netif_rx(dev->rx_skb);
-       dev->stats.rx_packets++;
-       dev->stats.rx_bytes += pkt_len;
+       netdev->stats.rx_packets++;
+       netdev->stats.rx_bytes += pkt_len;
 
        spin_lock(&dev->rx_pool_lock);
        skb = pull_skb(dev);
@@ -573,13 +572,13 @@ static void intr_callback(struct urb *urb)
 
        d = urb->transfer_buffer;
        if (d[0] & TSR_ERRORS) {
-               dev->stats.tx_errors++;
+               dev->netdev->stats.tx_errors++;
                if (d[INT_TSR] & (TSR_ECOL | TSR_JBR))
-                       dev->stats.tx_aborted_errors++;
+                       dev->netdev->stats.tx_aborted_errors++;
                if (d[INT_TSR] & TSR_LCOL)
-                       dev->stats.tx_window_errors++;
+                       dev->netdev->stats.tx_window_errors++;
                if (d[INT_TSR] & TSR_LOSS_CRS)
-                       dev->stats.tx_carrier_errors++;
+                       dev->netdev->stats.tx_carrier_errors++;
        }
        /* Report link status changes to the network stack */
        if ((d[INT_MSR] & MSR_LINK) == 0) {
@@ -697,17 +696,12 @@ static void disable_net_traffic(rtl8150_t * dev)
        set_registers(dev, CR, 1, &cr);
 }
 
-static struct net_device_stats *rtl8150_netdev_stats(struct net_device *dev)
-{
-       return &((rtl8150_t *)netdev_priv(dev))->stats;
-}
-
 static void rtl8150_tx_timeout(struct net_device *netdev)
 {
        rtl8150_t *dev = netdev_priv(netdev);
        dev_warn(&netdev->dev, "Tx timeout.\n");
        usb_unlink_urb(dev->tx_urb);
-       dev->stats.tx_errors++;
+       netdev->stats.tx_errors++;
 }
 
 static void rtl8150_set_multicast(struct net_device *netdev)
@@ -747,12 +741,12 @@ static int rtl8150_start_xmit(struct sk_buff *skb, struct net_device *netdev)
                        netif_device_detach(dev->netdev);
                else {
                        dev_warn(&netdev->dev, "failed tx_urb %d\n", res);
-                       dev->stats.tx_errors++;
+                       netdev->stats.tx_errors++;
                        netif_start_queue(netdev);
                }
        } else {
-               dev->stats.tx_packets++;
-               dev->stats.tx_bytes += skb->len;
+               netdev->stats.tx_packets++;
+               netdev->stats.tx_bytes += skb->len;
                netdev->trans_start = jiffies;
        }
 
@@ -897,6 +891,19 @@ static int rtl8150_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd)
        return res;
 }
 
+static const struct net_device_ops rtl8150_netdev_ops = {
+       .ndo_open               = rtl8150_open,
+       .ndo_stop               = rtl8150_close,
+       .ndo_do_ioctl           = rtl8150_ioctl,
+       .ndo_start_xmit         = rtl8150_start_xmit,
+       .ndo_tx_timeout         = rtl8150_tx_timeout,
+       .ndo_set_multicast_list = rtl8150_set_multicast,
+       .ndo_set_mac_address    = rtl8150_set_mac_address,
+
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 static int rtl8150_probe(struct usb_interface *intf,
                         const struct usb_device_id *id)
 {
@@ -923,15 +930,8 @@ static int rtl8150_probe(struct usb_interface *intf,
        
        dev->udev = udev;
        dev->netdev = netdev;
-       netdev->open = rtl8150_open;
-       netdev->stop = rtl8150_close;
-       netdev->do_ioctl = rtl8150_ioctl;
+       netdev->netdev_ops = &rtl8150_netdev_ops;
        netdev->watchdog_timeo = RTL8150_TX_TIMEOUT;
-       netdev->tx_timeout = rtl8150_tx_timeout;
-       netdev->hard_start_xmit = rtl8150_start_xmit;
-       netdev->set_multicast_list = rtl8150_set_multicast;
-       netdev->set_mac_address = rtl8150_set_mac_address;
-       netdev->get_stats = rtl8150_netdev_stats;
        SET_ETHTOOL_OPS(netdev, &ops);
        dev->intr_interval = 100;       /* 100ms */
 
index 3e6155a38f0cdec848c26736e1c269a088a3d585..dc1665326592703ce0f7bf6ff3d2e91caa560632 100644 (file)
@@ -1008,6 +1008,18 @@ static int smsc95xx_reset(struct usbnet *dev)
        return 0;
 }
 
+static const struct net_device_ops smsc95xx_netdev_ops = {
+       .ndo_open               = usbnet_open,
+       .ndo_stop               = usbnet_stop,
+       .ndo_start_xmit         = usbnet_start_xmit,
+       .ndo_tx_timeout         = usbnet_tx_timeout,
+       .ndo_change_mtu         = usbnet_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+       .ndo_do_ioctl           = smsc95xx_ioctl,
+       .ndo_set_multicast_list = smsc95xx_set_multicast,
+};
+
 static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
 {
        struct smsc95xx_priv *pdata = NULL;
@@ -1038,9 +1050,8 @@ static int smsc95xx_bind(struct usbnet *dev, struct usb_interface *intf)
        /* Init all registers */
        ret = smsc95xx_reset(dev);
 
-       dev->net->do_ioctl = smsc95xx_ioctl;
+       dev->net->netdev_ops = &smsc95xx_netdev_ops;
        dev->net->ethtool_ops = &smsc95xx_ethtool_ops;
-       dev->net->set_multicast_list = smsc95xx_set_multicast;
        dev->net->flags |= IFF_MULTICAST;
        dev->net->hard_header_len += SMSC95XX_TX_OVERHEAD;
        return 0;
index aa31490788880bb3b609acae0a9ab7332cce28c7..659654f458806b36eeab21a8f84bb4aa450c0af2 100644 (file)
@@ -223,7 +223,7 @@ EXPORT_SYMBOL_GPL(usbnet_skb_return);
  *
  *-------------------------------------------------------------------------*/
 
-static int usbnet_change_mtu (struct net_device *net, int new_mtu)
+int usbnet_change_mtu (struct net_device *net, int new_mtu)
 {
        struct usbnet   *dev = netdev_priv(net);
        int             ll_mtu = new_mtu + net->hard_header_len;
@@ -246,14 +246,7 @@ static int usbnet_change_mtu (struct net_device *net, int new_mtu)
 
        return 0;
 }
-
-/*-------------------------------------------------------------------------*/
-
-static struct net_device_stats *usbnet_get_stats (struct net_device *net)
-{
-       struct usbnet   *dev = netdev_priv(net);
-       return &dev->stats;
-}
+EXPORT_SYMBOL_GPL(usbnet_change_mtu);
 
 /*-------------------------------------------------------------------------*/
 
@@ -548,7 +541,7 @@ EXPORT_SYMBOL_GPL(usbnet_unlink_rx_urbs);
 
 // precondition: never called in_interrupt
 
-static int usbnet_stop (struct net_device *net)
+int usbnet_stop (struct net_device *net)
 {
        struct usbnet           *dev = netdev_priv(net);
        int                     temp;
@@ -592,6 +585,7 @@ static int usbnet_stop (struct net_device *net)
 
        return 0;
 }
+EXPORT_SYMBOL_GPL(usbnet_stop);
 
 /*-------------------------------------------------------------------------*/
 
@@ -599,7 +593,7 @@ static int usbnet_stop (struct net_device *net)
 
 // precondition: never called in_interrupt
 
-static int usbnet_open (struct net_device *net)
+int usbnet_open (struct net_device *net)
 {
        struct usbnet           *dev = netdev_priv(net);
        int                     retval;
@@ -674,6 +668,7 @@ done:
 done_nopm:
        return retval;
 }
+EXPORT_SYMBOL_GPL(usbnet_open);
 
 /*-------------------------------------------------------------------------*/
 
@@ -723,8 +718,8 @@ u32 usbnet_get_link (struct net_device *net)
        if (dev->mii.mdio_read)
                return mii_link_ok(&dev->mii);
 
-       /* Otherwise, say we're up (to avoid breaking scripts) */
-       return 1;
+       /* Otherwise, dtrt for drivers calling netif_carrier_{on,off} */
+       return ethtool_op_get_link(net);
 }
 EXPORT_SYMBOL_GPL(usbnet_get_link);
 
@@ -908,7 +903,7 @@ static void tx_complete (struct urb *urb)
 
 /*-------------------------------------------------------------------------*/
 
-static void usbnet_tx_timeout (struct net_device *net)
+void usbnet_tx_timeout (struct net_device *net)
 {
        struct usbnet           *dev = netdev_priv(net);
 
@@ -917,10 +912,11 @@ static void usbnet_tx_timeout (struct net_device *net)
 
        // FIXME: device recovery -- reset?
 }
+EXPORT_SYMBOL_GPL(usbnet_tx_timeout);
 
 /*-------------------------------------------------------------------------*/
 
-static int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
+int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net)
 {
        struct usbnet           *dev = netdev_priv(net);
        int                     length;
@@ -1003,7 +999,7 @@ drop:
        }
        return retval;
 }
-
+EXPORT_SYMBOL_GPL(usbnet_start_xmit);
 
 /*-------------------------------------------------------------------------*/
 
@@ -1110,6 +1106,15 @@ void usbnet_disconnect (struct usb_interface *intf)
 }
 EXPORT_SYMBOL_GPL(usbnet_disconnect);
 
+static const struct net_device_ops usbnet_netdev_ops = {
+       .ndo_open               = usbnet_open,
+       .ndo_stop               = usbnet_stop,
+       .ndo_start_xmit         = usbnet_start_xmit,
+       .ndo_tx_timeout         = usbnet_tx_timeout,
+       .ndo_change_mtu         = usbnet_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
 
 /*-------------------------------------------------------------------------*/
 
@@ -1179,13 +1184,14 @@ usbnet_probe (struct usb_interface *udev, const struct usb_device_id *prod)
                net->features |= NETIF_F_HIGHDMA;
 #endif
 
-       net->change_mtu = usbnet_change_mtu;
-       net->get_stats = usbnet_get_stats;
+       net->netdev_ops = &usbnet_netdev_ops;
+#ifdef CONFIG_COMPAT_NET_DEV_OPS
        net->hard_start_xmit = usbnet_start_xmit;
        net->open = usbnet_open;
        net->stop = usbnet_stop;
-       net->watchdog_timeo = TX_TIMEOUT_JIFFIES;
        net->tx_timeout = usbnet_tx_timeout;
+#endif
+       net->watchdog_timeo = TX_TIMEOUT_JIFFIES;
        net->ethtool_ops = &usbnet_ethtool_ops;
 
        // allow device-specific bind/init procedures
index e24f7b3ace4bd470fcfbf65dffc69bf2df20f383..04882c8f9bf18dfd547802704c72012f18e57761 100644 (file)
@@ -341,6 +341,11 @@ static const struct usb_device_id  products [] = {
        USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_MDLM,
                        USB_CDC_PROTO_NONE),
        .driver_info = (unsigned long) &bogus_mdlm_info,
+}, {
+       /* Motorola MOTOMAGX phones */
+       USB_DEVICE_AND_INTERFACE_INFO(0x22b8, 0x6425, USB_CLASS_COMM,
+                       USB_CDC_SUBCLASS_MDLM, USB_CDC_PROTO_NONE),
+       .driver_info = (unsigned long) &bogus_mdlm_info,
 },
 
 /* Olympus has some models with a Zaurus-compatible option.
index 852d0e7c4e62abbfb13421664293dd70182c4126..015db1cece72f5351ffdcb36c8e3789daec96ddc 100644 (file)
 #define DRV_NAME       "veth"
 #define DRV_VERSION    "1.0"
 
+#define MIN_MTU 68             /* Min L3 MTU */
+#define MAX_MTU 65535          /* Max L3 MTU (arbitrary) */
+#define MTU_PAD (ETH_HLEN + 4)  /* Max difference between L2 and L3 size MTU */
+
 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;
 };
 
 struct veth_priv {
@@ -147,7 +152,7 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        struct net_device *rcv = NULL;
        struct veth_priv *priv, *rcv_priv;
-       struct veth_net_stats *stats;
+       struct veth_net_stats *stats, *rcv_stats;
        int length, cpu;
 
        skb_orphan(skb);
@@ -158,9 +163,13 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
 
        cpu = smp_processor_id();
        stats = per_cpu_ptr(priv->stats, cpu);
+       rcv_stats = per_cpu_ptr(rcv_priv->stats, cpu);
 
        if (!(rcv->flags & IFF_UP))
-               goto outf;
+               goto tx_drop;
+
+       if (skb->len > (rcv->mtu + MTU_PAD))
+               goto rx_drop;
 
        skb->pkt_type = PACKET_HOST;
        skb->protocol = eth_type_trans(skb, rcv);
@@ -178,17 +187,21 @@ static int veth_xmit(struct sk_buff *skb, struct net_device *dev)
        stats->tx_bytes += length;
        stats->tx_packets++;
 
-       stats = per_cpu_ptr(rcv_priv->stats, cpu);
-       stats->rx_bytes += length;
-       stats->rx_packets++;
+       rcv_stats->rx_bytes += length;
+       rcv_stats->rx_packets++;
 
        netif_rx(skb);
        return 0;
 
-outf:
+tx_drop:
        kfree_skb(skb);
        stats->tx_dropped++;
        return 0;
+
+rx_drop:
+       kfree_skb(skb);
+       rcv_stats->rx_dropped++;
+       return 0;
 }
 
 /*
@@ -210,6 +223,7 @@ static struct net_device_stats *veth_get_stats(struct net_device *dev)
        dev_stats->rx_bytes = 0;
        dev_stats->tx_bytes = 0;
        dev_stats->tx_dropped = 0;
+       dev_stats->rx_dropped = 0;
 
        for_each_online_cpu(cpu) {
                stats = per_cpu_ptr(priv->stats, cpu);
@@ -219,6 +233,7 @@ static struct net_device_stats *veth_get_stats(struct net_device *dev)
                dev_stats->rx_bytes += stats->rx_bytes;
                dev_stats->tx_bytes += stats->tx_bytes;
                dev_stats->tx_dropped += stats->tx_dropped;
+               dev_stats->rx_dropped += stats->rx_dropped;
        }
 
        return dev_stats;
@@ -239,6 +254,29 @@ static int veth_open(struct net_device *dev)
        return 0;
 }
 
+static int veth_close(struct net_device *dev)
+{
+       struct veth_priv *priv = netdev_priv(dev);
+
+       netif_carrier_off(dev);
+       netif_carrier_off(priv->peer);
+
+       return 0;
+}
+
+static int is_valid_veth_mtu(int new_mtu)
+{
+       return (new_mtu >= MIN_MTU && new_mtu <= MAX_MTU);
+}
+
+static int veth_change_mtu(struct net_device *dev, int new_mtu)
+{
+       if (!is_valid_veth_mtu(new_mtu))
+               return -EINVAL;
+       dev->mtu = new_mtu;
+       return 0;
+}
+
 static int veth_dev_init(struct net_device *dev)
 {
        struct veth_net_stats *stats;
@@ -263,10 +301,13 @@ static void veth_dev_free(struct net_device *dev)
 }
 
 static const struct net_device_ops veth_netdev_ops = {
-       .ndo_init       = veth_dev_init,
-       .ndo_open       = veth_open,
-       .ndo_start_xmit = veth_xmit,
-       .ndo_get_stats  = veth_get_stats,
+       .ndo_init            = veth_dev_init,
+       .ndo_open            = veth_open,
+       .ndo_stop            = veth_close,
+       .ndo_start_xmit      = veth_xmit,
+       .ndo_change_mtu      = veth_change_mtu,
+       .ndo_get_stats       = veth_get_stats,
+       .ndo_set_mac_address = eth_mac_addr,
 };
 
 static void veth_setup(struct net_device *dev)
@@ -279,44 +320,6 @@ static void veth_setup(struct net_device *dev)
        dev->destructor = veth_dev_free;
 }
 
-static void veth_change_state(struct net_device *dev)
-{
-       struct net_device *peer;
-       struct veth_priv *priv;
-
-       priv = netdev_priv(dev);
-       peer = priv->peer;
-
-       if (netif_carrier_ok(peer)) {
-               if (!netif_carrier_ok(dev))
-                       netif_carrier_on(dev);
-       } else {
-               if (netif_carrier_ok(dev))
-                       netif_carrier_off(dev);
-       }
-}
-
-static int veth_device_event(struct notifier_block *unused,
-                            unsigned long event, void *ptr)
-{
-       struct net_device *dev = ptr;
-
-       if (dev->netdev_ops->ndo_open != veth_open)
-               goto out;
-
-       switch (event) {
-       case NETDEV_CHANGE:
-               veth_change_state(dev);
-               break;
-       }
-out:
-       return NOTIFY_DONE;
-}
-
-static struct notifier_block veth_notifier_block __read_mostly = {
-       .notifier_call  = veth_device_event,
-};
-
 /*
  * netlink interface
  */
@@ -329,6 +332,10 @@ static int veth_validate(struct nlattr *tb[], struct nlattr *data[])
                if (!is_valid_ether_addr(nla_data(tb[IFLA_ADDRESS])))
                        return -EADDRNOTAVAIL;
        }
+       if (tb[IFLA_MTU]) {
+               if (!is_valid_veth_mtu(nla_get_u32(tb[IFLA_MTU])))
+                       return -EINVAL;
+       }
        return 0;
 }
 
@@ -467,14 +474,12 @@ static struct rtnl_link_ops veth_link_ops = {
 
 static __init int veth_init(void)
 {
-       register_netdevice_notifier(&veth_notifier_block);
        return rtnl_link_register(&veth_link_ops);
 }
 
 static __exit void veth_exit(void)
 {
        rtnl_link_unregister(&veth_link_ops);
-       unregister_netdevice_notifier(&veth_notifier_block);
 }
 
 module_init(veth_init);
index 4671436ecf0ed236d3263e9f0ac70096fbe4e6ec..880eaf07413b0fc33ce99a404d27bf859a60e207 100644 (file)
@@ -109,8 +109,9 @@ static const int multicast_filter_limit = 32;
 #include <linux/dmi.h>
 
 /* These identify the driver base version and may not be removed. */
-static char version[] __devinitdata =
-KERN_INFO DRV_NAME ".c:v1.10-LK" DRV_VERSION " " DRV_RELDATE " Written by Donald Becker\n";
+static const char version[] __devinitconst =
+       KERN_INFO DRV_NAME ".c:v1.10-LK" DRV_VERSION " " DRV_RELDATE
+       " Written by Donald Becker\n";
 
 /* This driver was written to use PCI memory space. Some early versions
    of the Rhine may only work correctly with I/O space accesses. */
index c5691fdb70799a6f56d00a0d1e65bcdc7408de31..fb53ef872df33183d5e2ac1c259bac126ac630ea 100644 (file)
@@ -1838,17 +1838,19 @@ static void velocity_free_tx_buf(struct velocity_info *vptr, struct velocity_td_
 {
        struct sk_buff *skb = tdinfo->skb;
        int i;
+       int pktlen;
 
        /*
         *      Don't unmap the pre-allocated tx_bufs
         */
        if (tdinfo->skb_dma) {
 
+               pktlen = (skb->len > ETH_ZLEN ? : ETH_ZLEN);
                for (i = 0; i < tdinfo->nskb_dma; i++) {
 #ifdef VELOCITY_ZERO_COPY_SUPPORT
                        pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], le16_to_cpu(td->tdesc1.len), PCI_DMA_TODEVICE);
 #else
-                       pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], skb->len, PCI_DMA_TODEVICE);
+                       pci_unmap_single(vptr->pdev, tdinfo->skb_dma[i], pktlen, PCI_DMA_TODEVICE);
 #endif
                        tdinfo->skb_dma[i] = 0;
                }
@@ -2080,17 +2082,14 @@ static int velocity_xmit(struct sk_buff *skb, struct net_device *dev)
        struct tx_desc *td_ptr;
        struct velocity_td_info *tdinfo;
        unsigned long flags;
-       int pktlen = skb->len;
+       int pktlen;
        __le16 len;
        int index;
 
 
-
-       if (skb->len < ETH_ZLEN) {
-               if (skb_padto(skb, ETH_ZLEN))
-                       goto out;
-               pktlen = ETH_ZLEN;
-       }
+       if (skb_padto(skb, ETH_ZLEN))
+               goto out;
+       pktlen = max_t(unsigned int, skb->len, ETH_ZLEN);
 
        len = cpu_to_le16(pktlen);
 
index 3d0033920224715360c67a75c608f9a7f42da17b..a6f1e19159d8e19b1d581c48cf28f96aec93cffe 100644 (file)
@@ -953,6 +953,7 @@ static int virtnet_probe(struct virtio_device *vdev)
 
        vi->status = VIRTIO_NET_S_LINK_UP;
        virtnet_update_status(vi);
+       netif_carrier_on(dev);
 
        pr_debug("virtnet: registered device %s\n", dev->name);
        return 0;
index 0d7ba117ef608debcafeb4185809a882487d6134..d276d72ee3b78027c2fa09d20fdd34571d6475c0 100644 (file)
@@ -731,8 +731,7 @@ static char *cosa_net_setup_rx(struct channel_data *chan, int size)
         * We can safely fall back to non-dma-able memory, because we have
         * the cosa->bouncebuf pre-allocated.
         */
-       if (chan->rx_skb)
-               kfree_skb(chan->rx_skb);
+       kfree_skb(chan->rx_skb);
        chan->rx_skb = dev_alloc_skb(size);
        if (chan->rx_skb == NULL) {
                printk(KERN_NOTICE "%s: Memory squeeze, dropping packet\n",
index 5fa52923efa80e7401852c11dfee6864874ded5b..35dea3bea95dfe91490a39274e938753ae729147 100644 (file)
@@ -355,12 +355,6 @@ static int cycx_wan_update(struct wan_device *wandev)
        return 0;
 }
 
-/* callback to initialize device */
-static void cycx_x25_chan_setup(struct net_device *dev)
-{
-       dev->init = cycx_netdevice_init;
-}
-
 /* Create new logical channel.
  * This routine is called by the router when ROUTER_IFNEW IOCTL is being
  * handled.
@@ -476,6 +470,27 @@ static const struct header_ops cycx_header_ops = {
        .rebuild = cycx_netdevice_rebuild_header,
 };
 
+static const struct net_device_ops cycx_netdev_ops = {
+       .ndo_init       = cycx_netdevice_init,
+       .ndo_open       = cycx_netdevice_open,
+       .ndo_stop       = cycx_netdevice_stop,
+       .ndo_start_xmit = cycx_netdevice_hard_start_xmit,
+       .ndo_get_stats  = cycx_netdevice_get_stats,
+};
+
+static void cycx_x25_chan_setup(struct net_device *dev)
+{
+       /* Initialize device driver entry points */
+       dev->netdev_ops         = &cycx_netdev_ops;
+       dev->header_ops         = &cycx_header_ops;
+
+       /* Initialize media-specific parameters */
+       dev->mtu                = CYCX_X25_CHAN_MTU;
+       dev->type               = ARPHRD_HWX25; /* ARP h/w type */
+       dev->hard_header_len    = 0;            /* media header length */
+       dev->addr_len           = 0;            /* hardware address length */
+}
+
 /* Initialize Linux network interface.
  *
  * This routine is called only once for each interface, during Linux network
@@ -487,20 +502,6 @@ static int cycx_netdevice_init(struct net_device *dev)
        struct cycx_device *card = chan->card;
        struct wan_device *wandev = &card->wandev;
 
-       /* Initialize device driver entry points */
-       dev->open               = cycx_netdevice_open;
-       dev->stop               = cycx_netdevice_stop;
-       dev->header_ops         = &cycx_header_ops;
-
-       dev->hard_start_xmit    = cycx_netdevice_hard_start_xmit;
-       dev->get_stats          = cycx_netdevice_get_stats;
-
-       /* Initialize media-specific parameters */
-       dev->mtu                = CYCX_X25_CHAN_MTU;
-       dev->type               = ARPHRD_HWX25; /* ARP h/w type */
-       dev->hard_header_len    = 0;            /* media header length */
-       dev->addr_len           = 0;            /* hardware address length */
-
        if (!chan->svc)
                *(__be16*)dev->dev_addr = htons(chan->lcn);
 
index a297e3efa05dd32369d0c1c23c14378675c51436..e8d155c3e59f5bdf53bc6a2f3e426d99bac6c407 100644 (file)
@@ -114,7 +114,7 @@ static void dlci_receive(struct sk_buff *skb, struct net_device *dev)
        if (!pskb_may_pull(skb, sizeof(*hdr))) {
                printk(KERN_NOTICE "%s: invalid data no header\n",
                       dev->name);
-               dlp->stats.rx_errors++;
+               dev->stats.rx_errors++;
                kfree_skb(skb);
                return;
        }
@@ -127,7 +127,7 @@ static void dlci_receive(struct sk_buff *skb, struct net_device *dev)
        if (hdr->control != FRAD_I_UI)
        {
                printk(KERN_NOTICE "%s: Invalid header flag 0x%02X.\n", dev->name, hdr->control);
-               dlp->stats.rx_errors++;
+               dev->stats.rx_errors++;
        }
        else
                switch(hdr->IP_NLPID)
@@ -136,14 +136,14 @@ static void dlci_receive(struct sk_buff *skb, struct net_device *dev)
                                if (hdr->NLPID != FRAD_P_SNAP)
                                {
                                        printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->NLPID);
-                                       dlp->stats.rx_errors++;
+                                       dev->stats.rx_errors++;
                                        break;
                                }
         
                                if (hdr->OUI[0] + hdr->OUI[1] + hdr->OUI[2] != 0)
                                {
                                        printk(KERN_NOTICE "%s: Unsupported organizationally unique identifier 0x%02X-%02X-%02X.\n", dev->name, hdr->OUI[0], hdr->OUI[1], hdr->OUI[2]);
-                                       dlp->stats.rx_errors++;
+                                       dev->stats.rx_errors++;
                                        break;
                                }
 
@@ -164,12 +164,12 @@ static void dlci_receive(struct sk_buff *skb, struct net_device *dev)
                        case FRAD_P_Q933:
                        case FRAD_P_CLNP:
                                printk(KERN_NOTICE "%s: Unsupported NLPID 0x%02X.\n", dev->name, hdr->pad);
-                               dlp->stats.rx_errors++;
+                               dev->stats.rx_errors++;
                                break;
 
                        default:
                                printk(KERN_NOTICE "%s: Invalid pad byte 0x%02X.\n", dev->name, hdr->pad);
-                               dlp->stats.rx_errors++;
+                               dev->stats.rx_errors++;
                                break;                          
                }
 
@@ -178,9 +178,9 @@ static void dlci_receive(struct sk_buff *skb, struct net_device *dev)
                /* we've set up the protocol, so discard the header */
                skb_reset_mac_header(skb);
                skb_pull(skb, header);
-               dlp->stats.rx_bytes += skb->len;
+               dev->stats.rx_bytes += skb->len;
                netif_rx(skb);
-               dlp->stats.rx_packets++;
+               dev->stats.rx_packets++;
        }
        else
                dev_kfree_skb(skb);
@@ -200,19 +200,19 @@ static int dlci_transmit(struct sk_buff *skb, struct net_device *dev)
 
        netif_stop_queue(dev);
        
-       ret = dlp->slave->hard_start_xmit(skb, dlp->slave);
+       ret = dlp->slave->netdev_ops->ndo_start_xmit(skb, dlp->slave);
        switch (ret)
        {
                case DLCI_RET_OK:
-                       dlp->stats.tx_packets++;
+                       dev->stats.tx_packets++;
                        ret = 0;
                        break;
                        case DLCI_RET_ERR:
-                       dlp->stats.tx_errors++;
+                       dev->stats.tx_errors++;
                        ret = 0;
                        break;
                        case DLCI_RET_DROP:
-                       dlp->stats.tx_dropped++;
+                       dev->stats.tx_dropped++;
                        ret = 1;
                        break;
        }
@@ -295,11 +295,9 @@ static int dlci_dev_ioctl(struct net_device *dev, struct ifreq *ifr, int cmd)
 
 static int dlci_change_mtu(struct net_device *dev, int new_mtu)
 {
-       struct dlci_local *dlp;
-
-       dlp = netdev_priv(dev);
+       struct dlci_local *dlp = netdev_priv(dev);
 
-       return((*dlp->slave->change_mtu)(dlp->slave, new_mtu));
+       return dev_set_mtu(dlp->slave, new_mtu);
 }
 
 static int dlci_open(struct net_device *dev)
@@ -342,15 +340,6 @@ static int dlci_close(struct net_device *dev)
        return 0;
 }
 
-static struct net_device_stats *dlci_get_stats(struct net_device *dev)
-{
-       struct dlci_local *dlp;
-
-       dlp = netdev_priv(dev);
-
-       return(&dlp->stats);
-}
-
 static int dlci_add(struct dlci_add *dlci)
 {
        struct net_device       *master, *slave;
@@ -488,18 +477,21 @@ static const struct header_ops dlci_header_ops = {
        .create = dlci_header,
 };
 
+static const struct net_device_ops dlci_netdev_ops = {
+       .ndo_open       = dlci_open,
+       .ndo_stop       = dlci_close,
+       .ndo_do_ioctl   = dlci_dev_ioctl,
+       .ndo_start_xmit = dlci_transmit,
+       .ndo_change_mtu = dlci_change_mtu,
+};
+
 static void dlci_setup(struct net_device *dev)
 {
        struct dlci_local *dlp = netdev_priv(dev);
 
        dev->flags              = 0;
-       dev->open               = dlci_open;
-       dev->stop               = dlci_close;
-       dev->do_ioctl           = dlci_dev_ioctl;
-       dev->hard_start_xmit    = dlci_transmit;
        dev->header_ops         = &dlci_header_ops;
-       dev->get_stats          = dlci_get_stats;
-       dev->change_mtu         = dlci_change_mtu;
+       dev->netdev_ops         = &dlci_netdev_ops;
        dev->destructor         = free_netdev;
 
        dlp->receive            = dlci_receive;
index 5ce4372055582bcb652a3aaa14562470bbf2c6c1..7596eae1b35cbb424fbb382214179fb519086369 100644 (file)
@@ -348,7 +348,7 @@ EXPORT_SYMBOL(unregister_hdlc_protocol);
 EXPORT_SYMBOL(attach_hdlc_protocol);
 EXPORT_SYMBOL(detach_hdlc_protocol);
 
-static struct packet_type hdlc_packet_type = {
+static struct packet_type hdlc_packet_type __read_mostly = {
        .type = cpu_to_be16(ETH_P_HDLC),
        .func = hdlc_rcv,
 };
index 06beba47ffdf5f7267e2bb88843a0ed760b58922..2dd78d20eb05fedde9e7bea0ca2a228e1fb2b4d1 100644 (file)
@@ -55,7 +55,6 @@ struct lapbethdev {
        struct list_head        node;
        struct net_device       *ethdev;        /* link to ethernet device */
        struct net_device       *axdev;         /* lapbeth device (lapb#) */
-       struct net_device_stats stats;          /* some statistics */
 };
 
 static LIST_HEAD(lapbeth_devices);
@@ -107,10 +106,9 @@ static int lapbeth_rcv(struct sk_buff *skb, struct net_device *dev, struct packe
        if (!netif_running(lapbeth->axdev))
                goto drop_unlock;
 
-       lapbeth->stats.rx_packets++;
-
        len = skb->data[0] + skb->data[1] * 256;
-       lapbeth->stats.rx_bytes += len;
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += len;
 
        skb_pull(skb, 2);       /* Remove the length bytes */
        skb_trim(skb, len);     /* Set the length of the data */
@@ -210,8 +208,8 @@ static void lapbeth_data_transmit(struct net_device *ndev, struct sk_buff *skb)
        *ptr++ = size % 256;
        *ptr++ = size / 256;
 
-       lapbeth->stats.tx_packets++;
-       lapbeth->stats.tx_bytes += size;
+       ndev->stats.tx_packets++;
+       ndev->stats.tx_bytes += size;
 
        skb->dev = dev = lapbeth->ethdev;
 
@@ -254,15 +252,6 @@ static void lapbeth_disconnected(struct net_device *dev, int reason)
        netif_rx(skb);
 }
 
-/*
- *     Statistics
- */
-static struct net_device_stats *lapbeth_get_stats(struct net_device *dev)
-{
-       struct lapbethdev *lapbeth = netdev_priv(dev);
-       return &lapbeth->stats;
-}
-
 /*
  *     Set AX.25 callsign
  */
@@ -314,14 +303,17 @@ static int lapbeth_close(struct net_device *dev)
 
 /* ------------------------------------------------------------------------ */
 
+static const struct net_device_ops lapbeth_netdev_ops = {
+       .ndo_open            = lapbeth_open,
+       .ndo_stop            = lapbeth_close,
+       .ndo_start_xmit      = lapbeth_xmit,
+       .ndo_set_mac_address = lapbeth_set_mac_address,
+};
+
 static void lapbeth_setup(struct net_device *dev)
 {
-       dev->hard_start_xmit = lapbeth_xmit;
-       dev->open            = lapbeth_open;
-       dev->stop            = lapbeth_close;
+       dev->netdev_ops      = &lapbeth_netdev_ops;
        dev->destructor      = free_netdev;
-       dev->set_mac_address = lapbeth_set_mac_address;
-       dev->get_stats       = lapbeth_get_stats;
        dev->type            = ARPHRD_X25;
        dev->hard_header_len = 3;
        dev->mtu             = 1000;
@@ -421,7 +413,7 @@ static int lapbeth_device_event(struct notifier_block *this,
 
 /* ------------------------------------------------------------------------ */
 
-static struct packet_type lapbeth_packet_type = {
+static struct packet_type lapbeth_packet_type __read_mostly = {
        .type = cpu_to_be16(ETH_P_DEC),
        .func = lapbeth_rcv,
 };
@@ -430,7 +422,7 @@ static struct notifier_block lapbeth_dev_notifier = {
        .notifier_call = lapbeth_device_event,
 };
 
-static const char banner[] __initdata =
+static const char banner[] __initconst =
        KERN_INFO "LAPB Ethernet driver version 0.02\n";
 
 static int __init lapbeth_init_driver(void)
index 78f7bc92cbe88732dfcb8eed0cb225e4bcf3c00d..f4211fe0f445138af27ebe3fbf8f2dc7ef6c2371 100644 (file)
@@ -68,7 +68,6 @@
 /* device private data */
 
 struct net_local {
-       struct net_device_stats stats;
        struct timer_list       watchdog;
 
        spinlock_t      lock;
@@ -117,7 +116,6 @@ static int  sbni_open( struct net_device * );
 static int  sbni_close( struct net_device * );
 static int  sbni_start_xmit( struct sk_buff *, struct net_device * );
 static int  sbni_ioctl( struct net_device *, struct ifreq *, int );
-static struct net_device_stats  *sbni_get_stats( struct net_device * );
 static void  set_multicast_list( struct net_device * );
 
 static irqreturn_t sbni_interrupt( int, void * );
@@ -208,15 +206,21 @@ sbni_isa_probe( struct net_device  *dev )
        }
 }
 
+static const struct net_device_ops sbni_netdev_ops = {
+       .ndo_open               = sbni_open,
+       .ndo_stop               = sbni_close,
+       .ndo_start_xmit         = sbni_start_xmit,
+       .ndo_set_multicast_list = set_multicast_list,
+       .ndo_do_ioctl           = sbni_ioctl,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 static void __init sbni_devsetup(struct net_device *dev)
 {
        ether_setup( dev );
-       dev->open               = &sbni_open;
-       dev->stop               = &sbni_close;
-       dev->hard_start_xmit    = &sbni_start_xmit;
-       dev->get_stats          = &sbni_get_stats;
-       dev->set_multicast_list = &set_multicast_list;
-       dev->do_ioctl           = &sbni_ioctl;
+       dev->netdev_ops = &sbni_netdev_ops;
 }
 
 int __init sbni_probe(int unit)
@@ -229,6 +233,8 @@ int __init sbni_probe(int unit)
        if (!dev)
                return -ENOMEM;
 
+       dev->netdev_ops = &sbni_netdev_ops;
+
        sprintf(dev->name, "sbni%d", unit);
        netdev_boot_setup_check(dev);
 
@@ -723,13 +729,11 @@ upload_data( struct net_device  *dev,  unsigned  framelen,  unsigned  frameno,
                        nl->wait_frameno = 0,
                        nl->inppos = 0,
 #ifdef CONFIG_SBNI_MULTILINE
-                       ((struct net_local *)netdev_priv(nl->master))
-                               ->stats.rx_errors++,
-                       ((struct net_local *)netdev_priv(nl->master))
-                               ->stats.rx_missed_errors++;
+                       nl->master->stats.rx_errors++,
+                       nl->master->stats.rx_missed_errors++;
 #else
-                       nl->stats.rx_errors++,
-                       nl->stats.rx_missed_errors++;
+                       dev->stats.rx_errors++,
+                       dev->stats.rx_missed_errors++;
 #endif
                        /* now skip all frames until is_first != 0 */
        } else
@@ -742,13 +746,11 @@ upload_data( struct net_device  *dev,  unsigned  framelen,  unsigned  frameno,
                 */
                nl->wait_frameno = 0,
 #ifdef CONFIG_SBNI_MULTILINE
-               ((struct net_local *)netdev_priv(nl->master))
-                       ->stats.rx_errors++,
-               ((struct net_local *)netdev_priv(nl->master))
-                       ->stats.rx_crc_errors++;
+               nl->master->stats.rx_errors++,
+               nl->master->stats.rx_crc_errors++;
 #else
-               nl->stats.rx_errors++,
-               nl->stats.rx_crc_errors++;
+               dev->stats.rx_errors++,
+               dev->stats.rx_crc_errors++;
 #endif
 
        return  frame_ok;
@@ -756,15 +758,16 @@ upload_data( struct net_device  *dev,  unsigned  framelen,  unsigned  frameno,
 
 
 static inline void
-send_complete( struct net_local  *nl )
+send_complete( struct net_device *dev )
 {
+       struct net_local  *nl = netdev_priv(dev);
+
 #ifdef CONFIG_SBNI_MULTILINE
-       ((struct net_local *)netdev_priv(nl->master))->stats.tx_packets++;
-       ((struct net_local *)netdev_priv(nl->master))->stats.tx_bytes
-               += nl->tx_buf_p->len;
+       nl->master->stats.tx_packets++;
+       nl->master->stats.tx_bytes += nl->tx_buf_p->len;
 #else
-       nl->stats.tx_packets++;
-       nl->stats.tx_bytes += nl->tx_buf_p->len;
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += nl->tx_buf_p->len;
 #endif
        dev_kfree_skb_irq( nl->tx_buf_p );
 
@@ -792,7 +795,7 @@ interpret_ack( struct net_device  *dev,  unsigned  ack )
                                                   nl->maxframe,
                                                   nl->tx_buf_p->len - nl->outpos);
                        else
-                               send_complete( nl ),
+                               send_complete( dev ),
 #ifdef CONFIG_SBNI_MULTILINE
                                netif_wake_queue( nl->master );
 #else
@@ -881,13 +884,11 @@ drop_xmit_queue( struct net_device  *dev )
                dev_kfree_skb_any( nl->tx_buf_p ),
                nl->tx_buf_p = NULL,
 #ifdef CONFIG_SBNI_MULTILINE
-               ((struct net_local *)netdev_priv(nl->master))
-                       ->stats.tx_errors++,
-               ((struct net_local *)netdev_priv(nl->master))
-                       ->stats.tx_carrier_errors++;
+               nl->master->stats.tx_errors++,
+               nl->master->stats.tx_carrier_errors++;
 #else
-               nl->stats.tx_errors++,
-               nl->stats.tx_carrier_errors++;
+               dev->stats.tx_errors++,
+               dev->stats.tx_carrier_errors++;
 #endif
 
        nl->tx_frameno  = 0;
@@ -1017,14 +1018,13 @@ indicate_pkt( struct net_device  *dev )
 #ifdef CONFIG_SBNI_MULTILINE
        skb->protocol = eth_type_trans( skb, nl->master );
        netif_rx( skb );
-       ++((struct net_local *)netdev_priv(nl->master))->stats.rx_packets;
-       ((struct net_local *)netdev_priv(nl->master))->stats.rx_bytes +=
-               nl->inppos;
+       ++nl->master->stats.rx_packets;
+       nl->master->stats.rx_bytes += nl->inppos;
 #else
        skb->protocol = eth_type_trans( skb, dev );
        netif_rx( skb );
-       ++nl->stats.rx_packets;
-       nl->stats.rx_bytes += nl->inppos;
+       ++dev->stats.rx_packets;
+       dev->stats.rx_bytes += nl->inppos;
 #endif
        nl->rx_buf_p = NULL;    /* protocol driver will clear this sk_buff */
 }
@@ -1197,7 +1197,7 @@ sbni_open( struct net_device  *dev )
 handler_attached:
 
        spin_lock( &nl->lock );
-       memset( &nl->stats, 0, sizeof(struct net_device_stats) );
+       memset( &dev->stats, 0, sizeof(struct net_device_stats) );
        memset( &nl->in_stats, 0, sizeof(struct sbni_in_stats) );
 
        card_start( dev );
@@ -1413,7 +1413,7 @@ enslave( struct net_device  *dev,  struct net_device  *slave_dev )
 
        /* Summary statistics of MultiLine operation will be stored
           in master's counters */
-       memset( &snl->stats, 0, sizeof(struct net_device_stats) );
+       memset( &slave_dev->stats, 0, sizeof(struct net_device_stats) );
        netif_stop_queue( slave_dev );
        netif_wake_queue( dev );        /* Now we are able to transmit */
 
@@ -1464,14 +1464,6 @@ emancipate( struct net_device  *dev )
 
 #endif
 
-
-static struct net_device_stats *
-sbni_get_stats( struct net_device  *dev )
-{
-       return  &((struct net_local *)netdev_priv(dev))->stats;
-}
-
-
 static void
 set_multicast_list( struct net_device  *dev )
 {
index e6e2ce3e7bcf6a1b15d8b9f3cc79ccf1f2ba57f4..d67e208ab3759941c6be1344d63114af8e8d3d14 100644 (file)
@@ -142,7 +142,7 @@ static int x25_asy_change_mtu(struct net_device *dev, int newmtu)
                        memcpy(sl->xbuff, sl->xhead, sl->xleft);
                } else  {
                        sl->xleft = 0;
-                       sl->stats.tx_dropped++;
+                       dev->stats.tx_dropped++;
                }
        }
        sl->xhead = sl->xbuff;
@@ -153,7 +153,7 @@ static int x25_asy_change_mtu(struct net_device *dev, int newmtu)
                        memcpy(sl->rbuff, rbuff, sl->rcount);
                } else  {
                        sl->rcount = 0;
-                       sl->stats.rx_over_errors++;
+                       dev->stats.rx_over_errors++;
                        set_bit(SLF_ERROR, &sl->flags);
                }
        }
@@ -188,18 +188,19 @@ static inline void x25_asy_unlock(struct x25_asy *sl)
 
 static void x25_asy_bump(struct x25_asy *sl)
 {
+       struct net_device *dev = sl->dev;
        struct sk_buff *skb;
        int count;
        int err;
 
        count = sl->rcount;
-       sl->stats.rx_bytes += count;
+       dev->stats.rx_bytes += count;
 
        skb = dev_alloc_skb(count+1);
        if (skb == NULL) {
                printk(KERN_WARNING "%s: memory squeeze, dropping packet.\n",
                        sl->dev->name);
-               sl->stats.rx_dropped++;
+               dev->stats.rx_dropped++;
                return;
        }
        skb_push(skb, 1);       /* LAPB internal control */
@@ -211,7 +212,7 @@ static void x25_asy_bump(struct x25_asy *sl)
                printk(KERN_DEBUG "x25_asy: data received err - %d\n", err);
        } else {
                netif_rx(skb);
-               sl->stats.rx_packets++;
+               dev->stats.rx_packets++;
        }
 }
 
@@ -226,7 +227,7 @@ static void x25_asy_encaps(struct x25_asy *sl, unsigned char *icp, int len)
                len = mtu;
                printk(KERN_DEBUG "%s: truncating oversized transmit packet!\n",
                                        sl->dev->name);
-               sl->stats.tx_dropped++;
+               sl->dev->stats.tx_dropped++;
                x25_asy_unlock(sl);
                return;
        }
@@ -266,7 +267,7 @@ static void x25_asy_write_wakeup(struct tty_struct *tty)
        if (sl->xleft <= 0) {
                /* Now serial buffer is almost free & we can start
                 * transmission of another packet */
-               sl->stats.tx_packets++;
+               sl->dev->stats.tx_packets++;
                clear_bit(TTY_DO_WRITE_WAKEUP, &tty->flags);
                x25_asy_unlock(sl);
                return;
@@ -383,7 +384,7 @@ static void x25_asy_data_transmit(struct net_device *dev, struct sk_buff *skb)
        /* We were not busy, so we are now... :-) */
        if (skb != NULL) {
                x25_asy_lock(sl);
-               sl->stats.tx_bytes += skb->len;
+               dev->stats.tx_bytes += skb->len;
                x25_asy_encaps(sl, skb->data, skb->len);
                dev_kfree_skb(skb);
        }
@@ -533,7 +534,7 @@ static void x25_asy_receive_buf(struct tty_struct *tty,
        while (count--) {
                if (fp && *fp++) {
                        if (!test_and_set_bit(SLF_ERROR, &sl->flags))
-                               sl->stats.rx_errors++;
+                               sl->dev->stats.rx_errors++;
                        cp++;
                        continue;
                }
@@ -608,14 +609,6 @@ static void x25_asy_close_tty(struct tty_struct *tty)
        x25_asy_free(sl);
 }
 
-
-static struct net_device_stats *x25_asy_get_stats(struct net_device *dev)
-{
-       struct x25_asy *sl = netdev_priv(dev);
-       return &sl->stats;
-}
-
-
  /************************************************************************
   *                    STANDARD X.25 ENCAPSULATION                      *
   ************************************************************************/
@@ -682,7 +675,7 @@ static void x25_asy_unesc(struct x25_asy *sl, unsigned char s)
                        sl->rbuff[sl->rcount++] = s;
                        return;
                }
-               sl->stats.rx_over_errors++;
+               sl->dev->stats.rx_over_errors++;
                set_bit(SLF_ERROR, &sl->flags);
        }
 }
@@ -719,6 +712,14 @@ static int x25_asy_open_dev(struct net_device *dev)
        return 0;
 }
 
+static const struct net_device_ops x25_asy_netdev_ops = {
+       .ndo_open       = x25_asy_open_dev,
+       .ndo_stop       = x25_asy_close,
+       .ndo_start_xmit = x25_asy_xmit,
+       .ndo_tx_timeout = x25_asy_timeout,
+       .ndo_change_mtu = x25_asy_change_mtu,
+};
+
 /* Initialise the X.25 driver.  Called by the device init code */
 static void x25_asy_setup(struct net_device *dev)
 {
@@ -734,13 +735,8 @@ static void x25_asy_setup(struct net_device *dev)
         */
 
        dev->mtu                = SL_MTU;
-       dev->hard_start_xmit    = x25_asy_xmit;
-       dev->tx_timeout         = x25_asy_timeout;
+       dev->netdev_ops         = &x25_asy_netdev_ops;
        dev->watchdog_timeo     = HZ*20;
-       dev->open               = x25_asy_open_dev;
-       dev->stop               = x25_asy_close;
-       dev->get_stats          = x25_asy_get_stats;
-       dev->change_mtu         = x25_asy_change_mtu;
        dev->hard_header_len    = 0;
        dev->addr_len           = 0;
        dev->type               = ARPHRD_X25;
index 41770200ceb6ac17246849400269a39c5746e871..8f0fc2e57e2be06fce081c6f835bb0ea72243859 100644 (file)
@@ -28,10 +28,6 @@ struct x25_asy {
   unsigned char                *xbuff;         /* transmitter buffer           */
   unsigned char         *xhead;         /* pointer to next byte to XMIT */
   int                   xleft;          /* bytes left in XMIT queue     */
-
-  /* X.25 interface statistics. */
-  struct net_device_stats stats;
-
   int                   buffsize;       /* Max buffers sizes            */
 
   unsigned long                flags;          /* Flag values/ mode etc        */
index 1696e936cf5a5ae590d410acced0826d951ddb62..5d9e018d31afc60d9161c70418a56440d4a36717 100644 (file)
@@ -8,6 +8,7 @@ i2400m-y :=             \
        driver.o        \
        fw.o            \
        op-rfkill.o     \
+       sysfs.o         \
        netdev.o        \
        tx.o            \
        rx.o
index 15d9f51b292c8e5ac1787c8ef5d94174b19b8434..b3cadb626fe0af97b2861ad195d6be1a183c7164 100644 (file)
@@ -52,7 +52,6 @@
  *
  * i2400m_dev_initalize()       Called by i2400m_dev_start()
  *   i2400m_set_init_config()
- *   i2400m_firmware_check()
  *   i2400m_cmd_get_state()
  * i2400m_dev_shutdown()        Called by i2400m_dev_stop()
  *   i2400m->bus_reset()
@@ -942,8 +941,8 @@ error_cmd_failed:
 /* Firmware interface versions we support */
 enum {
        I2400M_HDIv_MAJOR = 9,
-       I2400M_HDIv_MAJOR_2 = 8,
        I2400M_HDIv_MINOR = 1,
+       I2400M_HDIv_MINOR_2 = 2,
 };
 
 
@@ -959,6 +958,10 @@ enum {
  * Long function, but quite simple; first chunk launches the command
  * and double checks the reply for the right TLV. Then we process the
  * TLV (where the meat is).
+ *
+ * Once we process the TLV that gives us the firmware's interface
+ * version, we encode it and save it in i2400m->fw_version for future
+ * reference.
  */
 int i2400m_firmware_check(struct i2400m *i2400m)
 {
@@ -1009,22 +1012,20 @@ int i2400m_firmware_check(struct i2400m *i2400m)
        minor = le16_to_cpu(l4mv->minor);
        branch = le16_to_cpu(l4mv->branch);
        result = -EINVAL;
-       if (major != I2400M_HDIv_MAJOR
-           && major != I2400M_HDIv_MAJOR_2) {
-               dev_err(dev, "unsupported major fw interface version "
+       if (major != I2400M_HDIv_MAJOR) {
+               dev_err(dev, "unsupported major fw version "
                        "%u.%u.%u\n", major, minor, branch);
                goto error_bad_major;
        }
-       if (major == I2400M_HDIv_MAJOR_2)
-               dev_err(dev, "deprecated major fw interface version "
-                       "%u.%u.%u\n", major, minor, branch);
        result = 0;
-       if (minor != I2400M_HDIv_MINOR)
-               dev_warn(dev, "untested minor fw firmware version %u.%u.%u\n",
+       if (minor < I2400M_HDIv_MINOR_2 && minor > I2400M_HDIv_MINOR)
+               dev_warn(dev, "untested minor fw version %u.%u.%u\n",
                         major, minor, branch);
-error_bad_major:
+       /* Yes, we ignore the branch -- we don't have to track it */
+       i2400m->fw_version = major << 16 | minor;
        dev_info(dev, "firmware interface version %u.%u.%u\n",
                 major, minor, branch);
+error_bad_major:
 error_no_tlv:
 error_cmd_failed:
        kfree_skb(ack_skb);
@@ -1220,6 +1221,77 @@ none:
 EXPORT_SYMBOL_GPL(i2400m_set_init_config);
 
 
+/**
+ * i2400m_set_idle_timeout - Set the device's idle mode timeout
+ *
+ * @i2400m: i2400m device descriptor
+ *
+ * @msecs: milliseconds for the timeout to enter idle mode. Between
+ *     100 to 300000 (5m); 0 to disable. In increments of 100.
+ *
+ * After this @msecs of the link being idle (no data being sent or
+ * received), the device will negotiate with the basestation entering
+ * idle mode for saving power. The connection is maintained, but
+ * getting out of it (done in tx.c) will require some negotiation,
+ * possible crypto re-handshake and a possible DHCP re-lease.
+ *
+ * Only available if fw_version >= 0x00090002.
+ *
+ * Returns: 0 if ok, < 0 errno code on error.
+ */
+int i2400m_set_idle_timeout(struct i2400m *i2400m, unsigned msecs)
+{
+       int result;
+       struct device *dev = i2400m_dev(i2400m);
+       struct sk_buff *ack_skb;
+       struct {
+               struct i2400m_l3l4_hdr hdr;
+               struct i2400m_tlv_config_idle_timeout cit;
+       } *cmd;
+       const struct i2400m_l3l4_hdr *ack;
+       size_t ack_len;
+       char strerr[32];
+
+       result = -ENOSYS;
+       if (i2400m_le_v1_3(i2400m))
+               goto error_alloc;
+       result = -ENOMEM;
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               goto error_alloc;
+       cmd->hdr.type = cpu_to_le16(I2400M_MT_GET_STATE);
+       cmd->hdr.length = cpu_to_le16(sizeof(*cmd) - sizeof(cmd->hdr));
+       cmd->hdr.version = cpu_to_le16(I2400M_L3L4_VERSION);
+
+       cmd->cit.hdr.type =
+               cpu_to_le16(I2400M_TLV_CONFIG_IDLE_TIMEOUT);
+       cmd->cit.hdr.length = cpu_to_le16(sizeof(cmd->cit.timeout));
+       cmd->cit.timeout = cpu_to_le32(msecs);
+
+       ack_skb = i2400m_msg_to_dev(i2400m, cmd, sizeof(*cmd));
+       if (IS_ERR(ack_skb)) {
+               dev_err(dev, "Failed to issue 'set idle timeout' command: "
+                       "%ld\n", PTR_ERR(ack_skb));
+               result = PTR_ERR(ack_skb);
+               goto error_msg_to_dev;
+       }
+       ack = wimax_msg_data_len(ack_skb, &ack_len);
+       result = i2400m_msg_check_status(ack, strerr, sizeof(strerr));
+       if (result < 0) {
+               dev_err(dev, "'set idle timeout' (0x%04x) command failed: "
+                       "%d - %s\n", I2400M_MT_GET_STATE, result, strerr);
+               goto error_cmd_failed;
+       }
+       result = 0;
+       kfree_skb(ack_skb);
+error_cmd_failed:
+error_msg_to_dev:
+       kfree(cmd);
+error_alloc:
+       return result;
+}
+
+
 /**
  * i2400m_dev_initialize - Initialize the device once communications are ready
  *
@@ -1238,24 +1310,53 @@ int i2400m_dev_initialize(struct i2400m *i2400m)
        int result;
        struct device *dev = i2400m_dev(i2400m);
        struct i2400m_tlv_config_idle_parameters idle_params;
+       struct i2400m_tlv_config_idle_timeout idle_timeout;
+       struct i2400m_tlv_config_d2h_data_format df;
+       struct i2400m_tlv_config_dl_host_reorder dlhr;
        const struct i2400m_tlv_hdr *args[9];
        unsigned argc = 0;
 
        d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
-       /* Useless for now...might change */
+       /* Disable idle mode? (enabled by default) */
        if (i2400m_idle_mode_disabled) {
-               idle_params.hdr.type =
-                       cpu_to_le16(I2400M_TLV_CONFIG_IDLE_PARAMETERS);
-               idle_params.hdr.length = cpu_to_le16(
-                       sizeof(idle_params) - sizeof(idle_params.hdr));
-               idle_params.idle_timeout = 0;
-               idle_params.idle_paging_interval = 0;
-               args[argc++] = &idle_params.hdr;
+               if (i2400m_le_v1_3(i2400m)) {
+                       idle_params.hdr.type =
+                               cpu_to_le16(I2400M_TLV_CONFIG_IDLE_PARAMETERS);
+                       idle_params.hdr.length = cpu_to_le16(
+                               sizeof(idle_params) - sizeof(idle_params.hdr));
+                       idle_params.idle_timeout = 0;
+                       idle_params.idle_paging_interval = 0;
+                       args[argc++] = &idle_params.hdr;
+               } else {
+                       idle_timeout.hdr.type =
+                               cpu_to_le16(I2400M_TLV_CONFIG_IDLE_TIMEOUT);
+                       idle_timeout.hdr.length = cpu_to_le16(
+                               sizeof(idle_timeout) - sizeof(idle_timeout.hdr));
+                       idle_timeout.timeout = 0;
+                       args[argc++] = &idle_timeout.hdr;
+               }
+       }
+       if (i2400m_ge_v1_4(i2400m)) {
+               /* Enable extended RX data format? */
+               df.hdr.type =
+                       cpu_to_le16(I2400M_TLV_CONFIG_D2H_DATA_FORMAT);
+               df.hdr.length = cpu_to_le16(
+                       sizeof(df) - sizeof(df.hdr));
+               df.format = 1;
+               args[argc++] = &df.hdr;
+
+               /* Enable RX data reordering?
+                * (switch flipped in rx.c:i2400m_rx_setup() after fw upload) */
+               if (i2400m->rx_reorder) {
+                       dlhr.hdr.type =
+                               cpu_to_le16(I2400M_TLV_CONFIG_DL_HOST_REORDER);
+                       dlhr.hdr.length = cpu_to_le16(
+                               sizeof(dlhr) - sizeof(dlhr.hdr));
+                       dlhr.reorder = 1;
+                       args[argc++] = &dlhr.hdr;
+               }
        }
        result = i2400m_set_init_config(i2400m, args, argc);
-       if (result < 0)
-               goto error;
-       result = i2400m_firmware_check(i2400m); /* fw versions ok? */
        if (result < 0)
                goto error;
        /*
@@ -1266,6 +1367,8 @@ int i2400m_dev_initialize(struct i2400m *i2400m)
         */
        result = i2400m_cmd_get_state(i2400m);
 error:
+       if (result < 0)
+               dev_err(dev, "failed to initialize the device: %d\n", result);
        d_fnend(3, dev, "(i2400m %p) = %d\n", i2400m, result);
        return result;
 }
index 3183baa16a522a014b1099a4b8244166f970a67b..48fbfaa0d403354902af9d14e787a4c4925e5c85 100644 (file)
@@ -38,6 +38,7 @@ enum d_module {
        D_SUBMODULE_DECLARE(netdev),
        D_SUBMODULE_DECLARE(rfkill),
        D_SUBMODULE_DECLARE(rx),
+       D_SUBMODULE_DECLARE(sysfs),
        D_SUBMODULE_DECLARE(tx),
 };
 
index e80a0b65a7549d4fb2fec512a363586aac65f04b..07a54bad237b3aefc999208425a515b634a7d337 100644 (file)
@@ -48,6 +48,7 @@
  *       i2400m_dev_bootstrap()
  *       i2400m_tx_setup()
  *       i2400m->bus_dev_start()
+ *       i2400m_firmware_check()
  *       i2400m_check_mac_addr()
  *   wimax_dev_add()
  *
@@ -75,6 +76,11 @@ MODULE_PARM_DESC(idle_mode_disabled,
                 "If true, the device will not enable idle mode negotiation "
                 "with the base station (when connected) to save power.");
 
+int i2400m_rx_reorder_disabled;        /* 0 (rx reorder enabled) by default */
+module_param_named(rx_reorder_disabled, i2400m_rx_reorder_disabled, int, 0644);
+MODULE_PARM_DESC(rx_reorder_disabled,
+                "If true, RX reordering will be disabled.");
+
 /**
  * i2400m_queue_work - schedule work on a i2400m's queue
  *
@@ -395,6 +401,9 @@ retry:
        result = i2400m_tx_setup(i2400m);
        if (result < 0)
                goto error_tx_setup;
+       result = i2400m_rx_setup(i2400m);
+       if (result < 0)
+               goto error_rx_setup;
        result = i2400m->bus_dev_start(i2400m);
        if (result < 0)
                goto error_bus_dev_start;
@@ -404,6 +413,9 @@ retry:
                dev_err(dev, "cannot create workqueue\n");
                goto error_create_workqueue;
        }
+       result = i2400m_firmware_check(i2400m); /* fw versions ok? */
+       if (result < 0)
+               goto error_fw_check;
        /* At this point is ok to send commands to the device */
        result = i2400m_check_mac_addr(i2400m);
        if (result < 0)
@@ -421,10 +433,13 @@ retry:
 
 error_dev_initialize:
 error_check_mac_addr:
+error_fw_check:
        destroy_workqueue(i2400m->work_queue);
 error_create_workqueue:
        i2400m->bus_dev_stop(i2400m);
 error_bus_dev_start:
+       i2400m_rx_release(i2400m);
+error_rx_setup:
        i2400m_tx_release(i2400m);
 error_tx_setup:
 error_bootstrap:
@@ -472,6 +487,7 @@ void __i2400m_dev_stop(struct i2400m *i2400m)
        i2400m->ready = 0;
        destroy_workqueue(i2400m->work_queue);
        i2400m->bus_dev_stop(i2400m);
+       i2400m_rx_release(i2400m);
        i2400m_tx_release(i2400m);
        wimax_state_change(wimax_dev, WIMAX_ST_DOWN);
        d_fnend(3, dev, "(i2400m %p) = 0\n", i2400m);
@@ -613,7 +629,7 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
        d_fnstart(3, dev, "(i2400m %p)\n", i2400m);
 
        snprintf(wimax_dev->name, sizeof(wimax_dev->name),
-                "i2400m-%s:%s", dev->bus->name, dev->bus_id);
+                "i2400m-%s:%s", dev->bus->name, dev_name(dev));
 
        i2400m->bm_cmd_buf = kzalloc(I2400M_BM_CMD_BUF_SIZE, GFP_KERNEL);
        if (i2400m->bm_cmd_buf == NULL) {
@@ -657,6 +673,11 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
        wimax_state_change(wimax_dev, WIMAX_ST_UNINITIALIZED);
 
        /* Now setup all that requires a registered net and wimax device. */
+       result = sysfs_create_group(&net_dev->dev.kobj, &i2400m_dev_attr_group);
+       if (result < 0) {
+               dev_err(dev, "cannot setup i2400m's sysfs: %d\n", result);
+               goto error_sysfs_setup;
+       }
        result = i2400m_debugfs_add(i2400m);
        if (result < 0) {
                dev_err(dev, "cannot setup i2400m's debugfs: %d\n", result);
@@ -666,6 +687,9 @@ int i2400m_setup(struct i2400m *i2400m, enum i2400m_bri bm_flags)
        return result;
 
 error_debugfs_setup:
+       sysfs_remove_group(&i2400m->wimax_dev.net_dev->dev.kobj,
+                          &i2400m_dev_attr_group);
+error_sysfs_setup:
        wimax_dev_rm(&i2400m->wimax_dev);
 error_wimax_dev_add:
        i2400m_dev_stop(i2400m);
@@ -697,6 +721,8 @@ void i2400m_release(struct i2400m *i2400m)
        netif_stop_queue(i2400m->wimax_dev.net_dev);
 
        i2400m_debugfs_rm(i2400m);
+       sysfs_remove_group(&i2400m->wimax_dev.net_dev->dev.kobj,
+                          &i2400m_dev_attr_group);
        wimax_dev_rm(&i2400m->wimax_dev);
        i2400m_dev_stop(i2400m);
        unregister_netdev(i2400m->wimax_dev.net_dev);
index ecd0cfaefdcc583785484b6b4c1cedadead9bc60..675c6ce810c01dbf0f39ddc65b16edc9d0882771 100644 (file)
@@ -483,7 +483,7 @@ ssize_t i2400m_dnload_bcf(struct i2400m *i2400m,
                if (offset + section_size > bcf_len) {
                        dev_err(dev, "fw %s: bad section #%zu, "
                                "end (@%zu) beyond EOF (@%zu)\n",
-                               i2400m->bus_fw_name, section,
+                               i2400m->fw_name, section,
                                offset + section_size,  bcf_len);
                        ret = -EINVAL;
                        goto error_section_beyond_eof;
@@ -493,7 +493,7 @@ ssize_t i2400m_dnload_bcf(struct i2400m *i2400m,
                                    &ack, sizeof(ack), I2400M_BM_CMD_RAW);
                if (ret < 0) {
                        dev_err(dev, "fw %s: section #%zu (@%zu %zu B) "
-                               "failed %d\n", i2400m->bus_fw_name, section,
+                               "failed %d\n", i2400m->fw_name, section,
                                offset, sizeof(*bh) + data_size, (int) ret);
                        goto error_send;
                }
@@ -874,7 +874,7 @@ int i2400m_dnload_init(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf)
                if (result < 0)
                        dev_err(dev, "fw %s: non-signed download "
                                "initialization failed: %d\n",
-                               i2400m->bus_fw_name, result);
+                               i2400m->fw_name, result);
        } else if (i2400m->sboot == 0
                 && (module_id & I2400M_BCF_MOD_ID_POKES)) {
                /* non-signed boot process with pokes, nothing to do */
@@ -886,7 +886,7 @@ int i2400m_dnload_init(struct i2400m *i2400m, const struct i2400m_bcf_hdr *bcf)
                if (result < 0)
                        dev_err(dev, "fw %s: signed boot download "
                                "initialization failed: %d\n",
-                               i2400m->bus_fw_name, result);
+                               i2400m->fw_name, result);
        }
        return result;
 }
@@ -915,7 +915,7 @@ int i2400m_fw_check(struct i2400m *i2400m,
        if (bcf_size < sizeof(*bcf)) {  /* big enough header? */
                dev_err(dev, "firmware %s too short: "
                        "%zu B vs %zu (at least) expected\n",
-                       i2400m->bus_fw_name, bcf_size, sizeof(*bcf));
+                       i2400m->fw_name, bcf_size, sizeof(*bcf));
                goto error;
        }
 
@@ -931,7 +931,7 @@ int i2400m_fw_check(struct i2400m *i2400m,
        if (bcf_size != size) {         /* annoyingly paranoid */
                dev_err(dev, "firmware %s: bad size, got "
                        "%zu B vs %u expected\n",
-                       i2400m->bus_fw_name, bcf_size, size);
+                       i2400m->fw_name, bcf_size, size);
                goto error;
        }
 
@@ -943,7 +943,7 @@ int i2400m_fw_check(struct i2400m *i2400m,
 
        if (module_type != 6) {         /* built for the right hardware? */
                dev_err(dev, "bad fw %s: unexpected module type 0x%x; "
-                       "aborting\n", i2400m->bus_fw_name, module_type);
+                       "aborting\n", i2400m->fw_name, module_type);
                goto error;
        }
 
@@ -951,10 +951,10 @@ int i2400m_fw_check(struct i2400m *i2400m,
        result = 0;
        if (module_vendor != 0x8086)
                dev_err(dev, "bad fw %s? unexpected vendor 0x%04x\n",
-                       i2400m->bus_fw_name, module_vendor);
+                       i2400m->fw_name, module_vendor);
        if (date < 0x20080300)
                dev_err(dev, "bad fw %s? build date too old %08x\n",
-                       i2400m->bus_fw_name, date);
+                       i2400m->fw_name, date);
 error:
        return result;
 }
@@ -1016,7 +1016,7 @@ hw_reboot:
                goto error_dev_rebooted;
        if (ret < 0) {
                dev_err(dev, "fw %s: download failed: %d\n",
-                       i2400m->bus_fw_name, ret);
+                       i2400m->fw_name, ret);
                goto error_dnload_bcf;
        }
 
@@ -1026,12 +1026,12 @@ hw_reboot:
        if (ret < 0) {
                dev_err(dev, "fw %s: "
                        "download finalization failed: %d\n",
-                       i2400m->bus_fw_name, ret);
+                       i2400m->fw_name, ret);
                goto error_dnload_finalize;
        }
 
        d_printf(2, dev, "fw %s successfully uploaded\n",
-                i2400m->bus_fw_name);
+                i2400m->fw_name);
        i2400m->boot_mode = 0;
 error_dnload_finalize:
 error_dnload_bcf:
@@ -1067,28 +1067,41 @@ error_dev_rebooted:
  */
 int i2400m_dev_bootstrap(struct i2400m *i2400m, enum i2400m_bri flags)
 {
-       int ret = 0;
+       int ret = 0, itr = 0;
        struct device *dev = i2400m_dev(i2400m);
        const struct firmware *fw;
        const struct i2400m_bcf_hdr *bcf;       /* Firmware data */
+       const char *fw_name;
 
        d_fnstart(5, dev, "(i2400m %p)\n", i2400m);
+
        /* Load firmware files to memory. */
-       ret = request_firmware(&fw, i2400m->bus_fw_name, dev);
-       if (ret) {
-               dev_err(dev, "fw %s: request failed: %d\n",
-                       i2400m->bus_fw_name, ret);
-               goto error_fw_req;
+       itr = 0;
+       while(1) {
+               fw_name = i2400m->bus_fw_names[itr];
+               if (fw_name == NULL) {
+                       dev_err(dev, "Could not find a usable firmware image\n");
+                       ret = -ENOENT;
+                       goto error_no_fw;
+               }
+               ret = request_firmware(&fw, fw_name, dev);
+               if (ret == 0)
+                       break;          /* got it */
+               if (ret < 0)
+                       dev_err(dev, "fw %s: cannot load file: %d\n",
+                               fw_name, ret);
+               itr++;
        }
-       bcf = (void *) fw->data;
 
+       bcf = (void *) fw->data;
+       i2400m->fw_name = fw_name;
        ret = i2400m_fw_check(i2400m, bcf, fw->size);
        if (ret < 0)
                goto error_fw_bad;
        ret = i2400m_fw_dnload(i2400m, bcf, fw->size, flags);
 error_fw_bad:
        release_firmware(fw);
-error_fw_req:
+error_no_fw:
        d_fnend(5, dev, "(i2400m %p) = %d\n", i2400m, ret);
        return ret;
 }
index 236f19ea4c853c72f7e27ce1bb5eece628b837aa..3ae2df38b59a7cc0bb4ceff1ba2e1700c11ec646 100644 (file)
@@ -156,10 +156,6 @@ enum {
 };
 
 
-/* Firmware version we request when pulling the fw image file */
-#define I2400M_FW_VERSION "1.3"
-
-
 /**
  * i2400m_reset_type - methods to reset a device
  *
@@ -178,6 +174,7 @@ enum i2400m_reset_type {
 };
 
 struct i2400m_reset_ctx;
+struct i2400m_roq;
 
 /**
  * struct i2400m - descriptor for an Intel 2400m
@@ -242,10 +239,14 @@ struct i2400m_reset_ctx;
  *     The caller to this function will check if the response is a
  *     barker that indicates the device going into reset mode.
  *
- * @bus_fw_name: [fill] name of the firmware image (in most cases,
- *     they are all the same for a single release, except that they
- *     have the type of the bus embedded in the name (eg:
- *     i2400m-fw-X-VERSION.sbcf, where X is the bus name).
+ * @bus_fw_names: [fill] a NULL-terminated array with the names of the
+ *     firmware images to try loading. This is made a list so we can
+ *     support backward compatibility of firmware releases (eg: if we
+ *     can't find the default v1.4, we try v1.3). In general, the name
+ *     should be i2400m-fw-X-VERSION.sbcf, where X is the bus name.
+ *     The list is tried in order and the first one that loads is
+ *     used. The fw loader will set i2400m->fw_name to point to the
+ *     active firmware image.
  *
  * @bus_bm_mac_addr_impaired: [fill] Set to true if the device's MAC
  *     address provided in boot mode is kind of broken and needs to
@@ -257,6 +258,9 @@ struct i2400m_reset_ctx;
  *     force this to be the first field so that we can get from
  *     netdev_priv() the right pointer.
  *
+ * @rx_reorder: 1 if RX reordering is enabled; this can only be
+ *     set at probe time.
+ *
  * @state: device's state (as reported by it)
  *
  * @state_wq: waitqueue that is woken up whenever the state changes
@@ -313,6 +317,12 @@ struct i2400m_reset_ctx;
  *
  * @rx_size_max: buggest RX message received.
  *
+ * @rx_roq: RX ReOrder queues. (fw >= v1.4) When packets are received
+ *     out of order, the device will ask the driver to hold certain
+ *     packets until the ones that are received out of order can be
+ *     delivered. Then the driver can release them to the host. See
+ *     drivers/net/i2400m/rx.c for details.
+ *
  * @init_mutex: Mutex used for serializing the device bringup
  *     sequence; this way if the device reboots in the middle, we
  *     don't try to do a bringup again while we are tearing down the
@@ -364,6 +374,11 @@ struct i2400m_reset_ctx;
  *     These have to be in a separate directory, a child of
  *     (wimax_dev->debugfs_dentry) so they can be removed when the
  *     module unloads, as we don't keep each dentry.
+ *
+ * @fw_name: name of the firmware image that is currently being used.
+ *
+ * @fw_version: version of the firmware interface, Major.minor,
+ *     encoded in the high word and low word (major << 16 | minor).
  */
 struct i2400m {
        struct wimax_dev wimax_dev;     /* FIRST! See doc */
@@ -372,6 +387,7 @@ struct i2400m {
        unsigned boot_mode:1;           /* is the device in boot mode? */
        unsigned sboot:1;               /* signed or unsigned fw boot */
        unsigned ready:1;               /* all probing steps done */
+       unsigned rx_reorder:1;          /* RX reorder is enabled */
        u8 trace_msg_from_user;         /* echo rx msgs to 'trace' pipe */
                                        /* typed u8 so debugfs/u8 can tweak */
        enum i2400m_system_state state;
@@ -388,7 +404,7 @@ struct i2400m {
                                   size_t, int flags);
        ssize_t (*bus_bm_wait_for_ack)(struct i2400m *,
                                       struct i2400m_bootrom_header *, size_t);
-       const char *bus_fw_name;
+       const char **bus_fw_names;
        unsigned bus_bm_mac_addr_impaired:1;
 
        spinlock_t tx_lock;             /* protect TX state */
@@ -400,10 +416,11 @@ struct i2400m {
        unsigned tx_pl_num, tx_pl_max, tx_pl_min,
                tx_num, tx_size_acc, tx_size_min, tx_size_max;
 
-       /* RX stats */
+       /* RX stuff */
        spinlock_t rx_lock;             /* protect RX state */
        unsigned rx_pl_num, rx_pl_max, rx_pl_min,
                rx_num, rx_size_acc, rx_size_min, rx_size_max;
+       struct i2400m_roq *rx_roq;      /* not under rx_lock! */
 
        struct mutex msg_mutex;         /* serialize command execution */
        struct completion msg_completion;
@@ -421,6 +438,8 @@ struct i2400m {
        struct sk_buff *wake_tx_skb;
 
        struct dentry *debugfs_dentry;
+       const char *fw_name;            /* name of the current firmware image */
+       unsigned long fw_version;       /* version of the firmware interface */
 };
 
 
@@ -435,6 +454,7 @@ void i2400m_init(struct i2400m *i2400m)
        wimax_dev_init(&i2400m->wimax_dev);
 
        i2400m->boot_mode = 1;
+       i2400m->rx_reorder = 1;
        init_waitqueue_head(&i2400m->state_wq);
 
        spin_lock_init(&i2400m->tx_lock);
@@ -578,12 +598,19 @@ unsigned i2400m_brh_get_signature(const struct i2400m_bootrom_header *hdr)
  * Driver / device setup and internal functions
  */
 extern void i2400m_netdev_setup(struct net_device *net_dev);
+extern int i2400m_sysfs_setup(struct device_driver *);
+extern void i2400m_sysfs_release(struct device_driver *);
 extern int i2400m_tx_setup(struct i2400m *);
 extern void i2400m_wake_tx_work(struct work_struct *);
 extern void i2400m_tx_release(struct i2400m *);
 
+extern int i2400m_rx_setup(struct i2400m *);
+extern void i2400m_rx_release(struct i2400m *);
+
 extern void i2400m_net_rx(struct i2400m *, struct sk_buff *, unsigned,
                          const void *, int);
+extern void i2400m_net_erx(struct i2400m *, struct sk_buff *,
+                          enum i2400m_cs);
 enum i2400m_pt;
 extern int i2400m_tx(struct i2400m *, const void *, size_t, enum i2400m_pt);
 
@@ -721,6 +748,7 @@ extern struct sk_buff *i2400m_get_device_info(struct i2400m *);
 extern int i2400m_firmware_check(struct i2400m *);
 extern int i2400m_set_init_config(struct i2400m *,
                                  const struct i2400m_tlv_hdr **, size_t);
+extern int i2400m_set_idle_timeout(struct i2400m *, unsigned);
 
 static inline
 struct usb_endpoint_descriptor *usb_get_epd(struct usb_interface *iface, int ep)
@@ -733,6 +761,32 @@ extern int i2400m_op_rfkill_sw_toggle(struct wimax_dev *,
 extern void i2400m_report_tlv_rf_switches_status(
        struct i2400m *, const struct i2400m_tlv_rf_switches_status *);
 
+/*
+ * Helpers for firmware backwards compability
+ *
+ * As we aim to support at least the firmware version that was
+ * released with the previous kernel/driver release, some code will be
+ * conditionally executed depending on the firmware version. On each
+ * release, the code to support fw releases past the last two ones
+ * will be purged.
+ *
+ * By making it depend on this macros, it is easier to keep it a tab
+ * on what has to go and what not.
+ */
+static inline
+unsigned i2400m_le_v1_3(struct i2400m *i2400m)
+{
+       /* running fw is lower or v1.3 */
+       return i2400m->fw_version <= 0x00090001;
+}
+
+static inline
+unsigned i2400m_ge_v1_4(struct i2400m *i2400m)
+{
+       /* running fw is higher or v1.4 */
+       return i2400m->fw_version >= 0x00090002;
+}
+
 
 /*
  * Do a millisecond-sleep for allowing wireshark to dump all the data
@@ -750,6 +804,7 @@ void __i2400m_msleep(unsigned ms)
 /* Module parameters */
 
 extern int i2400m_idle_mode_disabled;
+extern int i2400m_rx_reorder_disabled;
 
 
 #endif /* #ifndef __I2400M_H__ */
index be8be4d0709c0963006b0243bce14b6d1e3e75ce..6b1fe7a81f25f4a2a0314fe6c30c721092e4a788 100644 (file)
  * space and from the other side. The world is (sadly) configured to
  * take in only Ethernet devices...
  *
- * Because of this, currently there is an copy-each-rxed-packet
- * overhead on the RX path. Each IP packet has to be reallocated to
- * add an ethernet header (as there is no space in what we get from
- * the device). This is a known drawback and coming versions of the
- * device's firmware are being changed to add header space that can be
- * used to insert the ethernet header without having to reallocate and
- * copy.
+ * Because of this, when using firmwares <= v1.3, there is an
+ * copy-each-rxed-packet overhead on the RX path. Each IP packet has
+ * to be reallocated to add an ethernet header (as there is no space
+ * in what we get from the device). This is a known drawback and
+ * firmwares >= 1.4 add header space that can be used to insert the
+ * ethernet header without having to reallocate and copy.
  *
  * TX error handling is tricky; because we have to FIFO/queue the
  * buffers for transmission (as the hardware likes it aggregated), we
@@ -67,7 +66,9 @@
  * i2400m_tx_timeout      Called when the device times out
  *
  * i2400m_net_rx          Called by the RX code when a data frame is
- *                        available.
+ *                        available (firmware <= 1.3)
+ * i2400m_net_erx         Called by the RX code when a data frame is
+ *                        available (firmware >= 1.4).
  * i2400m_netdev_setup    Called to setup all the netdev stuff from
  *                        alloc_netdev.
  */
@@ -396,30 +397,18 @@ void i2400m_tx_timeout(struct net_device *net_dev)
  * Create a fake ethernet header
  *
  * For emulating an ethernet device, every received IP header has to
- * be prefixed with an ethernet header.
- *
- * What we receive has (potentially) many IP packets concatenated with
- * no ETH_HLEN bytes prefixed. Thus there is no space for an eth
- * header.
- *
- * We would have to reallocate or do ugly fragment tricks in order to
- * add it.
- *
- * But what we do is use the header space of the RX transaction
- * (*msg_hdr) as we don't need it anymore; then we'll point all the
- * data skbs there, as they share the same backing store.
- *
- * We only support IPv4 for v3 firmware.
+ * be prefixed with an ethernet header. Fake it with the given
+ * protocol.
  */
 static
 void i2400m_rx_fake_eth_header(struct net_device *net_dev,
-                              void *_eth_hdr)
+                              void *_eth_hdr, __be16 protocol)
 {
        struct ethhdr *eth_hdr = _eth_hdr;
 
        memcpy(eth_hdr->h_dest, net_dev->dev_addr, sizeof(eth_hdr->h_dest));
        memset(eth_hdr->h_source, 0, sizeof(eth_hdr->h_dest));
-       eth_hdr->h_proto = cpu_to_be16(ETH_P_IP);
+       eth_hdr->h_proto = protocol;
 }
 
 
@@ -432,6 +421,13 @@ void i2400m_rx_fake_eth_header(struct net_device *net_dev,
  * @buf: pointer to the buffer containing the data
  * @len: buffer's length
  *
+ * This is only used now for the v1.3 firmware. It will be deprecated
+ * in >= 2.6.31.
+ *
+ * Note that due to firmware limitations, we don't have space to add
+ * an ethernet header, so we need to copy each packet. Firmware
+ * versions >= v1.4 fix this [see i2400m_net_erx()].
+ *
  * We just clone the skb and set it up so that it's skb->data pointer
  * points to "buf" and it's length.
  *
@@ -478,7 +474,8 @@ void i2400m_net_rx(struct i2400m *i2400m, struct sk_buff *skb_rx,
                memcpy(skb_put(skb, buf_len), buf, buf_len);
        }
        i2400m_rx_fake_eth_header(i2400m->wimax_dev.net_dev,
-                                 skb->data - ETH_HLEN);
+                                 skb->data - ETH_HLEN,
+                                 cpu_to_be16(ETH_P_IP));
        skb_set_mac_header(skb, -ETH_HLEN);
        skb->dev = i2400m->wimax_dev.net_dev;
        skb->protocol = htons(ETH_P_IP);
@@ -493,6 +490,65 @@ error_skb_realloc:
                i2400m, buf, buf_len);
 }
 
+
+/*
+ * i2400m_net_erx - pass a network packet to the stack (extended version)
+ *
+ * @i2400m: device descriptor
+ * @skb: the skb where the packet is - the skb should be set to point
+ *     at the IP packet; this function will add ethernet headers if
+ *     needed.
+ * @cs: packet type
+ *
+ * This is only used now for firmware >= v1.4. Note it is quite
+ * similar to i2400m_net_rx() (used only for v1.3 firmware).
+ *
+ * This function is normally run from a thread context. However, we
+ * still use netif_rx() instead of netif_receive_skb() as was
+ * recommended in the mailing list. Reason is in some stress tests
+ * when sending/receiving a lot of data we seem to hit a softlock in
+ * the kernel's TCP implementation [aroudn tcp_delay_timer()]. Using
+ * netif_rx() took care of the issue.
+ *
+ * This is, of course, still open to do more research on why running
+ * with netif_receive_skb() hits this softlock. FIXME.
+ */
+void i2400m_net_erx(struct i2400m *i2400m, struct sk_buff *skb,
+                   enum i2400m_cs cs)
+{
+       struct net_device *net_dev = i2400m->wimax_dev.net_dev;
+       struct device *dev = i2400m_dev(i2400m);
+       int protocol;
+
+       d_fnstart(2, dev, "(i2400m %p skb %p [%u] cs %d)\n",
+                 i2400m, skb, skb->len, cs);
+       switch(cs) {
+       case I2400M_CS_IPV4_0:
+       case I2400M_CS_IPV4:
+               protocol = ETH_P_IP;
+               i2400m_rx_fake_eth_header(i2400m->wimax_dev.net_dev,
+                                         skb->data - ETH_HLEN,
+                                         cpu_to_be16(ETH_P_IP));
+               skb_set_mac_header(skb, -ETH_HLEN);
+               skb->dev = i2400m->wimax_dev.net_dev;
+               skb->protocol = htons(ETH_P_IP);
+               net_dev->stats.rx_packets++;
+               net_dev->stats.rx_bytes += skb->len;
+               break;
+       default:
+               dev_err(dev, "ERX: BUG? CS type %u unsupported\n", cs);
+               goto error;
+
+       }
+       d_printf(3, dev, "ERX: receiving %d bytes to the network stack\n",
+                skb->len);
+       d_dump(4, dev, skb->data, skb->len);
+       netif_rx_ni(skb);       /* see notes in function header */
+error:
+       d_fnend(2, dev, "(i2400m %p skb %p [%u] cs %d) = void\n",
+               i2400m, skb, skb->len, cs);
+}
+
 static const struct net_device_ops i2400m_netdev_ops = {
        .ndo_open = i2400m_open,
        .ndo_stop = i2400m_stop,
index 6922022710ac584371ff9d35e24f0d8e6711c7e7..02419bfd64b59460241dfab92a49247563d121d6 100644 (file)
@@ -39,7 +39,7 @@
  *  - Use skb_clone(), break up processing in chunks
  *  - Split transport/device specific
  *  - Make buffer size dynamic to exert less memory pressure
- *
+ *  - RX reorder support
  *
  * This handles the RX path.
  *
  * See tx.c for a deeper description on alignment requirements and
  * other fun facts of it.
  *
+ * DATA PACKETS
+ *
+ * In firmwares <= v1.3, data packets have no header for RX, but they
+ * do for TX (currently unused).
+ *
+ * In firmware >= 1.4, RX packets have an extended header (16
+ * bytes). This header conveys information for management of host
+ * reordering of packets (the device offloads storage of the packets
+ * for reordering to the host). Read below for more information.
+ *
+ * The header is used as dummy space to emulate an ethernet header and
+ * thus be able to act as an ethernet device without having to reallocate.
+ *
+ * DATA RX REORDERING
+ *
+ * Starting in firmware v1.4, the device can deliver packets for
+ * delivery with special reordering information; this allows it to
+ * more effectively do packet management when some frames were lost in
+ * the radio traffic.
+ *
+ * Thus, for RX packets that come out of order, the device gives the
+ * driver enough information to queue them properly and then at some
+ * point, the signal to deliver the whole (or part) of the queued
+ * packets to the networking stack. There are 16 such queues.
+ *
+ * This only happens when a packet comes in with the "need reorder"
+ * flag set in the RX header. When such bit is set, the following
+ * operations might be indicated:
+ *
+ *  - reset queue: send all queued packets to the OS
+ *
+ *  - queue: queue a packet
+ *
+ *  - update ws: update the queue's window start and deliver queued
+ *    packets that meet the criteria
+ *
+ *  - queue & update ws: queue a packet, update the window start and
+ *    deliver queued packets that meet the criteria
+ *
+ * (delivery criteria: the packet's [normalized] sequence number is
+ * lower than the new [normalized] window start).
+ *
+ * See the i2400m_roq_*() functions for details.
+ *
  * ROADMAP
  *
  * i2400m_rx
  *   i2400m_rx_pl_descr_check
  *   i2400m_rx_payload
  *     i2400m_net_rx
+ *     i2400m_rx_edata
+ *       i2400m_net_erx
+ *       i2400m_roq_reset
+ *         i2400m_net_erx
+ *       i2400m_roq_queue
+ *         __i2400m_roq_queue
+ *       i2400m_roq_update_ws
+ *         __i2400m_roq_update_ws
+ *           i2400m_net_erx
+ *       i2400m_roq_queue_update_ws
+ *         __i2400m_roq_queue
+ *         __i2400m_roq_update_ws
+ *           i2400m_net_erx
  *     i2400m_rx_ctl
  *       i2400m_msg_size_check
  *       i2400m_report_hook_work    [in a workqueue]
@@ -177,8 +234,7 @@ void i2400m_rx_ctl_ack(struct i2400m *i2400m,
        return;
 
 error_waiter_cancelled:
-       if (ack_skb)
-               kfree_skb(ack_skb);
+       kfree_skb(ack_skb);
 error_no_waiter:
        spin_unlock_irqrestore(&i2400m->rx_lock, flags);
        return;
@@ -265,8 +321,6 @@ error_check:
 }
 
 
-
-
 /*
  * Receive and send up a trace
  *
@@ -316,31 +370,629 @@ error_check:
 }
 
 
+/*
+ * Reorder queue data stored on skb->cb while the skb is queued in the
+ * reorder queues.
+ */
+struct i2400m_roq_data {
+       unsigned sn;            /* Serial number for the skb */
+       enum i2400m_cs cs;      /* packet type for the skb */
+};
+
+
+/*
+ * ReOrder Queue
+ *
+ * @ws: Window Start; sequence number where the current window start
+ *     is for this queue
+ * @queue: the skb queue itself
+ * @log: circular ring buffer used to log information about the
+ *     reorder process in this queue that can be displayed in case of
+ *     error to help diagnose it.
+ *
+ * This is the head for a list of skbs. In the skb->cb member of the
+ * skb when queued here contains a 'struct i2400m_roq_data' were we
+ * store the sequence number (sn) and the cs (packet type) coming from
+ * the RX payload header from the device.
+ */
+struct i2400m_roq
+{
+       unsigned ws;
+       struct sk_buff_head queue;
+       struct i2400m_roq_log *log;
+};
+
+
+static
+void __i2400m_roq_init(struct i2400m_roq *roq)
+{
+       roq->ws = 0;
+       skb_queue_head_init(&roq->queue);
+}
+
+
+static
+unsigned __i2400m_roq_index(struct i2400m *i2400m, struct i2400m_roq *roq)
+{
+       return ((unsigned long) roq - (unsigned long) i2400m->rx_roq)
+               / sizeof(*roq);
+}
+
+
+/*
+ * Normalize a sequence number based on the queue's window start
+ *
+ * nsn = (sn - ws) % 2048
+ *
+ * Note that if @sn < @roq->ws, we still need a positive number; %'s
+ * sign is implementation specific, so we normalize it by adding 2048
+ * to bring it to be positive.
+ */
+static
+unsigned __i2400m_roq_nsn(struct i2400m_roq *roq, unsigned sn)
+{
+       int r;
+       r =  ((int) sn - (int) roq->ws) % 2048;
+       if (r < 0)
+               r += 2048;
+       return r;
+}
+
+
+/*
+ * Circular buffer to keep the last N reorder operations
+ *
+ * In case something fails, dumb then to try to come up with what
+ * happened.
+ */
+enum {
+       I2400M_ROQ_LOG_LENGTH = 32,
+};
+
+struct i2400m_roq_log {
+       struct i2400m_roq_log_entry {
+               enum i2400m_ro_type type;
+               unsigned ws, count, sn, nsn, new_ws;
+       } entry[I2400M_ROQ_LOG_LENGTH];
+       unsigned in, out;
+};
+
+
+/* Print a log entry */
+static
+void i2400m_roq_log_entry_print(struct i2400m *i2400m, unsigned index,
+                               unsigned e_index,
+                               struct i2400m_roq_log_entry *e)
+{
+       struct device *dev = i2400m_dev(i2400m);
+
+       switch(e->type) {
+       case I2400M_RO_TYPE_RESET:
+               dev_err(dev, "q#%d reset           ws %u cnt %u sn %u/%u"
+                       " - new nws %u\n",
+                       index, e->ws, e->count, e->sn, e->nsn, e->new_ws);
+               break;
+       case I2400M_RO_TYPE_PACKET:
+               dev_err(dev, "q#%d queue           ws %u cnt %u sn %u/%u\n",
+                       index, e->ws, e->count, e->sn, e->nsn);
+               break;
+       case I2400M_RO_TYPE_WS:
+               dev_err(dev, "q#%d update_ws       ws %u cnt %u sn %u/%u"
+                       " - new nws %u\n",
+                       index, e->ws, e->count, e->sn, e->nsn, e->new_ws);
+               break;
+       case I2400M_RO_TYPE_PACKET_WS:
+               dev_err(dev, "q#%d queue_update_ws ws %u cnt %u sn %u/%u"
+                       " - new nws %u\n",
+                       index, e->ws, e->count, e->sn, e->nsn, e->new_ws);
+               break;
+       default:
+               dev_err(dev, "q#%d BUG? entry %u - unknown type %u\n",
+                       index, e_index, e->type);
+               break;
+       }
+}
+
+
+static
+void i2400m_roq_log_add(struct i2400m *i2400m,
+                       struct i2400m_roq *roq, enum i2400m_ro_type type,
+                       unsigned ws, unsigned count, unsigned sn,
+                       unsigned nsn, unsigned new_ws)
+{
+       struct i2400m_roq_log_entry *e;
+       unsigned cnt_idx;
+       int index = __i2400m_roq_index(i2400m, roq);
+
+       /* if we run out of space, we eat from the end */
+       if (roq->log->in - roq->log->out == I2400M_ROQ_LOG_LENGTH)
+               roq->log->out++;
+       cnt_idx = roq->log->in++ % I2400M_ROQ_LOG_LENGTH;
+       e = &roq->log->entry[cnt_idx];
+
+       e->type = type;
+       e->ws = ws;
+       e->count = count;
+       e->sn = sn;
+       e->nsn = nsn;
+       e->new_ws = new_ws;
+
+       if (d_test(1))
+               i2400m_roq_log_entry_print(i2400m, index, cnt_idx, e);
+}
+
+
+/* Dump all the entries in the FIFO and reinitialize it */
+static
+void i2400m_roq_log_dump(struct i2400m *i2400m, struct i2400m_roq *roq)
+{
+       unsigned cnt, cnt_idx;
+       struct i2400m_roq_log_entry *e;
+       int index = __i2400m_roq_index(i2400m, roq);
+
+       BUG_ON(roq->log->out > roq->log->in);
+       for (cnt = roq->log->out; cnt < roq->log->in; cnt++) {
+               cnt_idx = cnt % I2400M_ROQ_LOG_LENGTH;
+               e = &roq->log->entry[cnt_idx];
+               i2400m_roq_log_entry_print(i2400m, index, cnt_idx, e);
+               memset(e, 0, sizeof(*e));
+       }
+       roq->log->in = roq->log->out = 0;
+}
+
+
+/*
+ * Backbone for the queuing of an skb (by normalized sequence number)
+ *
+ * @i2400m: device descriptor
+ * @roq: reorder queue where to add
+ * @skb: the skb to add
+ * @sn: the sequence number of the skb
+ * @nsn: the normalized sequence number of the skb (pre-computed by the
+ *     caller from the @sn and @roq->ws).
+ *
+ * We try first a couple of quick cases:
+ *
+ *   - the queue is empty
+ *   - the skb would be appended to the queue
+ *
+ * These will be the most common operations.
+ *
+ * If these fail, then we have to do a sorted insertion in the queue,
+ * which is the slowest path.
+ *
+ * We don't have to acquire a reference count as we are going to own it.
+ */
+static
+void __i2400m_roq_queue(struct i2400m *i2400m, struct i2400m_roq *roq,
+                       struct sk_buff *skb, unsigned sn, unsigned nsn)
+{
+       struct device *dev = i2400m_dev(i2400m);
+       struct sk_buff *skb_itr;
+       struct i2400m_roq_data *roq_data_itr, *roq_data;
+       unsigned nsn_itr;
+
+       d_fnstart(4, dev, "(i2400m %p roq %p skb %p sn %u nsn %u)\n",
+                 i2400m, roq, skb, sn, nsn);
+
+       roq_data = (struct i2400m_roq_data *) &skb->cb;
+       BUILD_BUG_ON(sizeof(*roq_data) > sizeof(skb->cb));
+       roq_data->sn = sn;
+       d_printf(3, dev, "ERX: roq %p [ws %u] nsn %d sn %u\n",
+                roq, roq->ws, nsn, roq_data->sn);
+
+       /* Queues will be empty on not-so-bad environments, so try
+        * that first */
+       if (skb_queue_empty(&roq->queue)) {
+               d_printf(2, dev, "ERX: roq %p - first one\n", roq);
+               __skb_queue_head(&roq->queue, skb);
+               goto out;
+       }
+       /* Now try append, as most of the operations will be that */
+       skb_itr = skb_peek_tail(&roq->queue);
+       roq_data_itr = (struct i2400m_roq_data *) &skb_itr->cb;
+       nsn_itr = __i2400m_roq_nsn(roq, roq_data_itr->sn);
+       /* NSN bounds assumed correct (checked when it was queued) */
+       if (nsn >= nsn_itr) {
+               d_printf(2, dev, "ERX: roq %p - appended after %p (nsn %d sn %u)\n",
+                        roq, skb_itr, nsn_itr, roq_data_itr->sn);
+               __skb_queue_tail(&roq->queue, skb);
+               goto out;
+       }
+       /* None of the fast paths option worked. Iterate to find the
+        * right spot where to insert the packet; we know the queue is
+        * not empty, so we are not the first ones; we also know we
+        * are not going to be the last ones. The list is sorted, so
+        * we have to insert before the the first guy with an nsn_itr
+        * greater that our nsn. */
+       skb_queue_walk(&roq->queue, skb_itr) {
+               roq_data_itr = (struct i2400m_roq_data *) &skb_itr->cb;
+               nsn_itr = __i2400m_roq_nsn(roq, roq_data_itr->sn);
+               /* NSN bounds assumed correct (checked when it was queued) */
+               if (nsn_itr > nsn) {
+                       d_printf(2, dev, "ERX: roq %p - queued before %p "
+                                "(nsn %d sn %u)\n", roq, skb_itr, nsn_itr,
+                                roq_data_itr->sn);
+                       __skb_queue_before(&roq->queue, skb_itr, skb);
+                       goto out;
+               }
+       }
+       /* If we get here, that is VERY bad -- print info to help
+        * diagnose and crash it */
+       dev_err(dev, "SW BUG? failed to insert packet\n");
+       dev_err(dev, "ERX: roq %p [ws %u] skb %p nsn %d sn %u\n",
+               roq, roq->ws, skb, nsn, roq_data->sn);
+       skb_queue_walk(&roq->queue, skb_itr) {
+               roq_data_itr = (struct i2400m_roq_data *) &skb_itr->cb;
+               nsn_itr = __i2400m_roq_nsn(roq, roq_data_itr->sn);
+               /* NSN bounds assumed correct (checked when it was queued) */
+               dev_err(dev, "ERX: roq %p skb_itr %p nsn %d sn %u\n",
+                       roq, skb_itr, nsn_itr, roq_data_itr->sn);
+       }
+       BUG();
+out:
+       d_fnend(4, dev, "(i2400m %p roq %p skb %p sn %u nsn %d) = void\n",
+               i2400m, roq, skb, sn, nsn);
+       return;
+}
+
+
+/*
+ * Backbone for the update window start operation
+ *
+ * @i2400m: device descriptor
+ * @roq: Reorder queue
+ * @sn: New sequence number
+ *
+ * Updates the window start of a queue; when doing so, it must deliver
+ * to the networking stack all the queued skb's whose normalized
+ * sequence number is lower than the new normalized window start.
+ */
+static
+unsigned __i2400m_roq_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq,
+                               unsigned sn)
+{
+       struct device *dev = i2400m_dev(i2400m);
+       struct sk_buff *skb_itr, *tmp_itr;
+       struct i2400m_roq_data *roq_data_itr;
+       unsigned new_nws, nsn_itr;
+
+       new_nws = __i2400m_roq_nsn(roq, sn);
+       if (unlikely(new_nws >= 1024) && d_test(1)) {
+               dev_err(dev, "SW BUG? __update_ws new_nws %u (sn %u ws %u)\n",
+                       new_nws, sn, roq->ws);
+               WARN_ON(1);
+               i2400m_roq_log_dump(i2400m, roq);
+       }
+       skb_queue_walk_safe(&roq->queue, skb_itr, tmp_itr) {
+               roq_data_itr = (struct i2400m_roq_data *) &skb_itr->cb;
+               nsn_itr = __i2400m_roq_nsn(roq, roq_data_itr->sn);
+               /* NSN bounds assumed correct (checked when it was queued) */
+               if (nsn_itr < new_nws) {
+                       d_printf(2, dev, "ERX: roq %p - release skb %p "
+                                "(nsn %u/%u new nws %u)\n",
+                                roq, skb_itr, nsn_itr, roq_data_itr->sn,
+                                new_nws);
+                       __skb_unlink(skb_itr, &roq->queue);
+                       i2400m_net_erx(i2400m, skb_itr, roq_data_itr->cs);
+               }
+               else
+                       break;  /* rest of packets all nsn_itr > nws */
+       }
+       roq->ws = sn;
+       return new_nws;
+}
+
+
+/*
+ * Reset a queue
+ *
+ * @i2400m: device descriptor
+ * @cin: Queue Index
+ *
+ * Deliver all the packets and reset the window-start to zero. Name is
+ * kind of misleading.
+ */
+static
+void i2400m_roq_reset(struct i2400m *i2400m, struct i2400m_roq *roq)
+{
+       struct device *dev = i2400m_dev(i2400m);
+       struct sk_buff *skb_itr, *tmp_itr;
+       struct i2400m_roq_data *roq_data_itr;
+
+       d_fnstart(2, dev, "(i2400m %p roq %p)\n", i2400m, roq);
+       i2400m_roq_log_add(i2400m, roq, I2400M_RO_TYPE_RESET,
+                            roq->ws, skb_queue_len(&roq->queue),
+                            ~0, ~0, 0);
+       skb_queue_walk_safe(&roq->queue, skb_itr, tmp_itr) {
+               roq_data_itr = (struct i2400m_roq_data *) &skb_itr->cb;
+               d_printf(2, dev, "ERX: roq %p - release skb %p (sn %u)\n",
+                        roq, skb_itr, roq_data_itr->sn);
+               __skb_unlink(skb_itr, &roq->queue);
+               i2400m_net_erx(i2400m, skb_itr, roq_data_itr->cs);
+       }
+       roq->ws = 0;
+       d_fnend(2, dev, "(i2400m %p roq %p) = void\n", i2400m, roq);
+       return;
+}
+
+
+/*
+ * Queue a packet
+ *
+ * @i2400m: device descriptor
+ * @cin: Queue Index
+ * @skb: containing the packet data
+ * @fbn: First block number of the packet in @skb
+ * @lbn: Last block number of the packet in @skb
+ *
+ * The hardware is asking the driver to queue a packet for later
+ * delivery to the networking stack.
+ */
+static
+void i2400m_roq_queue(struct i2400m *i2400m, struct i2400m_roq *roq,
+                     struct sk_buff * skb, unsigned lbn)
+{
+       struct device *dev = i2400m_dev(i2400m);
+       unsigned nsn, len;
+
+       d_fnstart(2, dev, "(i2400m %p roq %p skb %p lbn %u) = void\n",
+                 i2400m, roq, skb, lbn);
+       len = skb_queue_len(&roq->queue);
+       nsn = __i2400m_roq_nsn(roq, lbn);
+       if (unlikely(nsn >= 1024)) {
+               dev_err(dev, "SW BUG? queue nsn %d (lbn %u ws %u)\n",
+                       nsn, lbn, roq->ws);
+               i2400m_roq_log_dump(i2400m, roq);
+               i2400m->bus_reset(i2400m, I2400M_RT_WARM);
+       } else {
+               __i2400m_roq_queue(i2400m, roq, skb, lbn, nsn);
+               i2400m_roq_log_add(i2400m, roq, I2400M_RO_TYPE_PACKET,
+                                    roq->ws, len, lbn, nsn, ~0);
+       }
+       d_fnend(2, dev, "(i2400m %p roq %p skb %p lbn %u) = void\n",
+               i2400m, roq, skb, lbn);
+       return;
+}
+
+
+/*
+ * Update the window start in a reorder queue and deliver all skbs
+ * with a lower window start
+ *
+ * @i2400m: device descriptor
+ * @roq: Reorder queue
+ * @sn: New sequence number
+ */
+static
+void i2400m_roq_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq,
+                         unsigned sn)
+{
+       struct device *dev = i2400m_dev(i2400m);
+       unsigned old_ws, nsn, len;
+
+       d_fnstart(2, dev, "(i2400m %p roq %p sn %u)\n", i2400m, roq, sn);
+       old_ws = roq->ws;
+       len = skb_queue_len(&roq->queue);
+       nsn = __i2400m_roq_update_ws(i2400m, roq, sn);
+       i2400m_roq_log_add(i2400m, roq, I2400M_RO_TYPE_WS,
+                            old_ws, len, sn, nsn, roq->ws);
+       d_fnstart(2, dev, "(i2400m %p roq %p sn %u) = void\n", i2400m, roq, sn);
+       return;
+}
+
+
+/*
+ * Queue a packet and update the window start
+ *
+ * @i2400m: device descriptor
+ * @cin: Queue Index
+ * @skb: containing the packet data
+ * @fbn: First block number of the packet in @skb
+ * @sn: Last block number of the packet in @skb
+ *
+ * Note that unlike i2400m_roq_update_ws(), which sets the new window
+ * start to @sn, in here we'll set it to @sn + 1.
+ */
+static
+void i2400m_roq_queue_update_ws(struct i2400m *i2400m, struct i2400m_roq *roq,
+                               struct sk_buff * skb, unsigned sn)
+{
+       struct device *dev = i2400m_dev(i2400m);
+       unsigned nsn, old_ws, len;
+
+       d_fnstart(2, dev, "(i2400m %p roq %p skb %p sn %u)\n",
+                 i2400m, roq, skb, sn);
+       len = skb_queue_len(&roq->queue);
+       nsn = __i2400m_roq_nsn(roq, sn);
+       old_ws = roq->ws;
+       if (unlikely(nsn >= 1024)) {
+               dev_err(dev, "SW BUG? queue_update_ws nsn %u (sn %u ws %u)\n",
+                       nsn, sn, roq->ws);
+               i2400m_roq_log_dump(i2400m, roq);
+               i2400m->bus_reset(i2400m, I2400M_RT_WARM);
+       } else {
+               /* if the queue is empty, don't bother as we'd queue
+                * it and inmediately unqueue it -- just deliver it */
+               if (len == 0) {
+                       struct i2400m_roq_data *roq_data;
+                       roq_data = (struct i2400m_roq_data *) &skb->cb;
+                       i2400m_net_erx(i2400m, skb, roq_data->cs);
+               }
+               else {
+                       __i2400m_roq_queue(i2400m, roq, skb, sn, nsn);
+                       __i2400m_roq_update_ws(i2400m, roq, sn + 1);
+               }
+               i2400m_roq_log_add(i2400m, roq, I2400M_RO_TYPE_PACKET_WS,
+                                  old_ws, len, sn, nsn, roq->ws);
+       }
+       d_fnend(2, dev, "(i2400m %p roq %p skb %p sn %u) = void\n",
+               i2400m, roq, skb, sn);
+       return;
+}
+
+
+/*
+ * Receive and send up an extended data packet
+ *
+ * @i2400m: device descriptor
+ * @skb_rx: skb that contains the extended data packet
+ * @single_last: 1 if the payload is the only one or the last one of
+ *     the skb.
+ * @payload: pointer to the packet's data inside the skb
+ * @size: size of the payload
+ *
+ * Starting in v1.4 of the i2400m's firmware, the device can send data
+ * packets to the host in an extended format that; this incudes a 16
+ * byte header (struct i2400m_pl_edata_hdr). Using this header's space
+ * we can fake ethernet headers for ethernet device emulation without
+ * having to copy packets around.
+ *
+ * This function handles said path.
+ *
+ *
+ * Receive and send up an extended data packet that requires no reordering
+ *
+ * @i2400m: device descriptor
+ * @skb_rx: skb that contains the extended data packet
+ * @single_last: 1 if the payload is the only one or the last one of
+ *     the skb.
+ * @payload: pointer to the packet's data (past the actual extended
+ *     data payload header).
+ * @size: size of the payload
+ *
+ * Pass over to the networking stack a data packet that might have
+ * reordering requirements.
+ *
+ * This needs to the decide if the skb in which the packet is
+ * contained can be reused or if it needs to be cloned. Then it has to
+ * be trimmed in the edges so that the beginning is the space for eth
+ * header and then pass it to i2400m_net_erx() for the stack
+ *
+ * Assumes the caller has verified the sanity of the payload (size,
+ * etc) already.
+ */
+static
+void i2400m_rx_edata(struct i2400m *i2400m, struct sk_buff *skb_rx,
+                    unsigned single_last, const void *payload, size_t size)
+{
+       struct device *dev = i2400m_dev(i2400m);
+       const struct i2400m_pl_edata_hdr *hdr = payload;
+       struct net_device *net_dev = i2400m->wimax_dev.net_dev;
+       struct sk_buff *skb;
+       enum i2400m_cs cs;
+       u32 reorder;
+       unsigned ro_needed, ro_type, ro_cin, ro_sn;
+       struct i2400m_roq *roq;
+       struct i2400m_roq_data *roq_data;
+
+       BUILD_BUG_ON(ETH_HLEN > sizeof(*hdr));
+
+       d_fnstart(2, dev, "(i2400m %p skb_rx %p single %u payload %p "
+                 "size %zu)\n", i2400m, skb_rx, single_last, payload, size);
+       if (size < sizeof(*hdr)) {
+               dev_err(dev, "ERX: HW BUG? message with short header (%zu "
+                       "vs %zu bytes expected)\n", size, sizeof(*hdr));
+               goto error;
+       }
+
+       if (single_last) {
+               skb = skb_get(skb_rx);
+               d_printf(3, dev, "ERX: skb %p reusing\n", skb);
+       } else {
+               skb = skb_clone(skb_rx, GFP_KERNEL);
+               if (skb == NULL) {
+                       dev_err(dev, "ERX: no memory to clone skb\n");
+                       net_dev->stats.rx_dropped++;
+                       goto error_skb_clone;
+               }
+               d_printf(3, dev, "ERX: skb %p cloned from %p\n", skb, skb_rx);
+       }
+       /* now we have to pull and trim so that the skb points to the
+        * beginning of the IP packet; the netdev part will add the
+        * ethernet header as needed - we know there is enough space
+        * because we checked in i2400m_rx_edata(). */
+       skb_pull(skb, payload + sizeof(*hdr) - (void *) skb->data);
+       skb_trim(skb, (void *) skb_end_pointer(skb) - payload - sizeof(*hdr));
+
+       reorder = le32_to_cpu(hdr->reorder);
+       ro_needed = reorder & I2400M_RO_NEEDED;
+       cs = hdr->cs;
+       if (ro_needed) {
+               ro_type = (reorder >> I2400M_RO_TYPE_SHIFT) & I2400M_RO_TYPE;
+               ro_cin = (reorder >> I2400M_RO_CIN_SHIFT) & I2400M_RO_CIN;
+               ro_sn = (reorder >> I2400M_RO_SN_SHIFT) & I2400M_RO_SN;
+
+               roq = &i2400m->rx_roq[ro_cin];
+               roq_data = (struct i2400m_roq_data *) &skb->cb;
+               roq_data->sn = ro_sn;
+               roq_data->cs = cs;
+               d_printf(2, dev, "ERX: reorder needed: "
+                        "type %u cin %u [ws %u] sn %u/%u len %zuB\n",
+                        ro_type, ro_cin, roq->ws, ro_sn,
+                        __i2400m_roq_nsn(roq, ro_sn), size);
+               d_dump(2, dev, payload, size);
+               switch(ro_type) {
+               case I2400M_RO_TYPE_RESET:
+                       i2400m_roq_reset(i2400m, roq);
+                       kfree_skb(skb); /* no data here */
+                       break;
+               case I2400M_RO_TYPE_PACKET:
+                       i2400m_roq_queue(i2400m, roq, skb, ro_sn);
+                       break;
+               case I2400M_RO_TYPE_WS:
+                       i2400m_roq_update_ws(i2400m, roq, ro_sn);
+                       kfree_skb(skb); /* no data here */
+                       break;
+               case I2400M_RO_TYPE_PACKET_WS:
+                       i2400m_roq_queue_update_ws(i2400m, roq, skb, ro_sn);
+                       break;
+               default:
+                       dev_err(dev, "HW BUG? unknown reorder type %u\n", ro_type);
+               }
+       }
+       else
+               i2400m_net_erx(i2400m, skb, cs);
+error_skb_clone:
+error:
+       d_fnend(2, dev, "(i2400m %p skb_rx %p single %u payload %p "
+               "size %zu) = void\n", i2400m, skb_rx, single_last, payload, size);
+       return;
+}
+
+
 /*
  * Act on a received payload
  *
  * @i2400m: device instance
  * @skb_rx: skb where the transaction was received
- * @single: 1 if there is only one payload, 0 otherwise
+ * @single_last: 1 this is the only payload or the last one (so the
+ *     skb can be reused instead of cloned).
  * @pld: payload descriptor
  * @payload: payload data
  *
  * Upon reception of a payload, look at its guts in the payload
- * descriptor and decide what to do with it.
+ * descriptor and decide what to do with it. If it is a single payload
+ * skb or if the last skb is a data packet, the skb will be referenced
+ * and modified (so it doesn't have to be cloned).
  */
 static
 void i2400m_rx_payload(struct i2400m *i2400m, struct sk_buff *skb_rx,
-                      unsigned single, const struct i2400m_pld *pld,
+                      unsigned single_last, const struct i2400m_pld *pld,
                       const void *payload)
 {
        struct device *dev = i2400m_dev(i2400m);
        size_t pl_size = i2400m_pld_size(pld);
        enum i2400m_pt pl_type = i2400m_pld_type(pld);
 
+       d_printf(7, dev, "RX: received payload type %u, %zu bytes\n",
+                pl_type, pl_size);
+       d_dump(8, dev, payload, pl_size);
+
        switch (pl_type) {
        case I2400M_PT_DATA:
                d_printf(3, dev, "RX: data payload %zu bytes\n", pl_size);
-               i2400m_net_rx(i2400m, skb_rx, single, payload, pl_size);
+               i2400m_net_rx(i2400m, skb_rx, single_last, payload, pl_size);
                break;
        case I2400M_PT_CTRL:
                i2400m_rx_ctl(i2400m, skb_rx, payload, pl_size);
@@ -348,6 +1000,10 @@ void i2400m_rx_payload(struct i2400m *i2400m, struct sk_buff *skb_rx,
        case I2400M_PT_TRACE:
                i2400m_rx_trace(i2400m, payload, pl_size);
                break;
+       case I2400M_PT_EDATA:
+               d_printf(3, dev, "ERX: data payload %zu bytes\n", pl_size);
+               i2400m_rx_edata(i2400m, skb_rx, single_last, payload, pl_size);
+               break;
        default:        /* Anything else shouldn't come to the host */
                if (printk_ratelimit())
                        dev_err(dev, "RX: HW BUG? unexpected payload type %u\n",
@@ -475,7 +1131,7 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb)
        const struct i2400m_msg_hdr *msg_hdr;
        size_t pl_itr, pl_size, skb_len;
        unsigned long flags;
-       unsigned num_pls;
+       unsigned num_pls, single_last;
 
        skb_len = skb->len;
        d_fnstart(4, dev, "(i2400m %p skb %p [size %zu])\n",
@@ -504,7 +1160,8 @@ int i2400m_rx(struct i2400m *i2400m, struct sk_buff *skb)
                                                  pl_itr, skb->len);
                if (result < 0)
                        goto error_pl_descr_check;
-               i2400m_rx_payload(i2400m, skb, num_pls == 1, &msg_hdr->pld[i],
+               single_last = num_pls == 1 || i == num_pls - 1;
+               i2400m_rx_payload(i2400m, skb, single_last, &msg_hdr->pld[i],
                                  skb->data + pl_itr);
                pl_itr += ALIGN(pl_size, I2400M_PL_PAD);
                cond_resched();         /* Don't monopolize */
@@ -532,3 +1189,73 @@ error_msg_hdr_check:
        return result;
 }
 EXPORT_SYMBOL_GPL(i2400m_rx);
+
+
+/*
+ * Initialize the RX queue and infrastructure
+ *
+ * This sets up all the RX reordering infrastructures, which will not
+ * be used if reordering is not enabled or if the firmware does not
+ * support it. The device is told to do reordering in
+ * i2400m_dev_initialize(), where it also looks at the value of the
+ * i2400m->rx_reorder switch before taking a decission.
+ *
+ * Note we allocate the roq queues in one chunk and the actual logging
+ * support for it (logging) in another one and then we setup the
+ * pointers from the first to the last.
+ */
+int i2400m_rx_setup(struct i2400m *i2400m)
+{
+       int result = 0;
+       struct device *dev = i2400m_dev(i2400m);
+
+       i2400m->rx_reorder = i2400m_rx_reorder_disabled? 0 : 1;
+       if (i2400m->rx_reorder) {
+               unsigned itr;
+               size_t size;
+               struct i2400m_roq_log *rd;
+
+               result = -ENOMEM;
+
+               size = sizeof(i2400m->rx_roq[0]) * (I2400M_RO_CIN + 1);
+               i2400m->rx_roq = kzalloc(size, GFP_KERNEL);
+               if (i2400m->rx_roq == NULL) {
+                       dev_err(dev, "RX: cannot allocate %zu bytes for "
+                               "reorder queues\n", size);
+                       goto error_roq_alloc;
+               }
+
+               size = sizeof(*i2400m->rx_roq[0].log) * (I2400M_RO_CIN + 1);
+               rd = kzalloc(size, GFP_KERNEL);
+               if (rd == NULL) {
+                       dev_err(dev, "RX: cannot allocate %zu bytes for "
+                               "reorder queues log areas\n", size);
+                       result = -ENOMEM;
+                       goto error_roq_log_alloc;
+               }
+
+               for(itr = 0; itr < I2400M_RO_CIN + 1; itr++) {
+                       __i2400m_roq_init(&i2400m->rx_roq[itr]);
+                       i2400m->rx_roq[itr].log = &rd[itr];
+               }
+       }
+       return 0;
+
+error_roq_log_alloc:
+       kfree(i2400m->rx_roq);
+error_roq_alloc:
+       return result;
+}
+
+
+/* Tear down the RX queue and infrastructure */
+void i2400m_rx_release(struct i2400m *i2400m)
+{
+       if (i2400m->rx_reorder) {
+               unsigned itr;
+               for(itr = 0; itr < I2400M_RO_CIN + 1; itr++)
+                       __skb_queue_purge(&i2400m->rx_roq[itr].queue);
+               kfree(i2400m->rx_roq[0].log);
+               kfree(i2400m->rx_roq);
+       }
+}
index 123a5f8db6adddbe27966e18dd194dcd3210270d..5ac5e76701cd8d3761764c1424d78f1b51a828e9 100644 (file)
 static int ioe_timeout = 2;
 module_param(ioe_timeout, int, 0);
 
-/* Our firmware file name */
-#define I2400MS_FW_FILE_NAME "i2400m-fw-sdio-" I2400M_FW_VERSION ".sbcf"
+/* Our firmware file name list */
+static const char *i2400ms_bus_fw_names[] = {
+#define I2400MS_FW_FILE_NAME "i2400m-fw-sdio-1.3.sbcf"
+       I2400MS_FW_FILE_NAME,
+       NULL
+};
+
 
 /*
  * Enable the SDIO function
@@ -401,7 +406,7 @@ int i2400ms_probe(struct sdio_func *func,
        i2400m->bus_reset = i2400ms_bus_reset;
        i2400m->bus_bm_cmd_send = i2400ms_bus_bm_cmd_send;
        i2400m->bus_bm_wait_for_ack = i2400ms_bus_bm_wait_for_ack;
-       i2400m->bus_fw_name = I2400MS_FW_FILE_NAME;
+       i2400m->bus_fw_names = i2400ms_bus_fw_names;
        i2400m->bus_bm_mac_addr_impaired = 1;
 
        result = i2400ms_enable_function(i2400ms->func);
diff --git a/drivers/net/wimax/i2400m/sysfs.c b/drivers/net/wimax/i2400m/sysfs.c
new file mode 100644 (file)
index 0000000..1237109
--- /dev/null
@@ -0,0 +1,80 @@
+/*
+ * Intel Wireless WiMAX Connection 2400m
+ * Sysfs interfaces to show driver and device information
+ *
+ *
+ * Copyright (C) 2007 Intel Corporation <linux-wimax@intel.com>
+ * Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.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.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
+ * 02110-1301, USA.
+ */
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/spinlock.h>
+#include <linux/device.h>
+#include "i2400m.h"
+
+
+#define D_SUBMODULE sysfs
+#include "debug-levels.h"
+
+
+/*
+ * Set the idle timeout (msecs)
+ *
+ * FIXME: eventually this should be a common WiMAX stack method, but
+ * would like to wait to see how other devices manage it.
+ */
+static
+ssize_t i2400m_idle_timeout_store(struct device *dev,
+                                 struct device_attribute *attr,
+                                 const char *buf, size_t size)
+{
+       ssize_t result;
+       struct i2400m *i2400m = net_dev_to_i2400m(to_net_dev(dev));
+       unsigned val;
+
+       result = -EINVAL;
+       if (sscanf(buf, "%u\n", &val) != 1)
+               goto error_no_unsigned;
+       if (val != 0 && (val < 100 || val > 300000 || val % 100 != 0)) {
+               dev_err(dev, "idle_timeout: %u: invalid msecs specification; "
+                       "valid values are 0, 100-300000 in 100 increments\n",
+                       val);
+               goto error_bad_value;
+       }
+       result = i2400m_set_idle_timeout(i2400m, val);
+       if (result >= 0)
+               result = size;
+error_no_unsigned:
+error_bad_value:
+       return result;
+}
+
+static
+DEVICE_ATTR(i2400m_idle_timeout, S_IWUSR,
+           NULL, i2400m_idle_timeout_store);
+
+static
+struct attribute *i2400m_dev_attrs[] = {
+       &dev_attr_i2400m_idle_timeout.attr,
+       NULL,
+};
+
+struct attribute_group i2400m_dev_attr_group = {
+       .name = NULL,           /* we want them in the same directory */
+       .attrs = i2400m_dev_attrs,
+};
index 9702c22b24974052ac7664b82475378b8cbe5bcd..6add27c3f35cb0b6eace046c2a20d27b931dd77b 100644 (file)
@@ -102,7 +102,7 @@ int i2400mu_notification_grok(struct i2400mu *i2400mu, const void *buf,
                dev_err(dev, "HW BUG? Unknown/unexpected data in notification "
                        "message (%zu bytes)\n", buf_len);
                snprintf(prefix, sizeof(prefix), "%s %s: ",
-                        dev_driver_string(dev) , dev->bus_id);
+                        dev_driver_string(dev), dev_name(dev));
                if (buf_len > 64) {
                        print_hex_dump(KERN_ERR, prefix, DUMP_PREFIX_OFFSET,
                                       8, 4, buf, 64, 0);
index 7c28610da6f32b7382c1b48dd6f2b434f9721901..ca4151a9e2229a20b88149577db093e98a942aae 100644 (file)
 
 
 /* Our firmware file name */
-#define I2400MU_FW_FILE_NAME "i2400m-fw-usb-" I2400M_FW_VERSION ".sbcf"
+static const char *i2400mu_bus_fw_names[] = {
+#define I2400MU_FW_FILE_NAME_v1_4 "i2400m-fw-usb-1.4.sbcf"
+       I2400MU_FW_FILE_NAME_v1_4,
+#define I2400MU_FW_FILE_NAME_v1_3 "i2400m-fw-usb-1.3.sbcf"
+       I2400MU_FW_FILE_NAME_v1_3,
+       NULL,
+};
+
 
 static
 int i2400mu_bus_dev_start(struct i2400m *i2400m)
@@ -394,7 +401,7 @@ int i2400mu_probe(struct usb_interface *iface,
        i2400m->bus_reset = i2400mu_bus_reset;
        i2400m->bus_bm_cmd_send = i2400mu_bus_bm_cmd_send;
        i2400m->bus_bm_wait_for_ack = i2400mu_bus_bm_wait_for_ack;
-       i2400m->bus_fw_name = I2400MU_FW_FILE_NAME;
+       i2400m->bus_fw_names = i2400mu_bus_fw_names;
        i2400m->bus_bm_mac_addr_impaired = 0;
 
 #ifdef CONFIG_PM
@@ -594,4 +601,5 @@ module_exit(i2400mu_driver_exit);
 MODULE_AUTHOR("Intel Corporation <linux-wimax@intel.com>");
 MODULE_DESCRIPTION("Intel 2400M WiMAX networking for USB");
 MODULE_LICENSE("GPL");
-MODULE_FIRMWARE(I2400MU_FW_FILE_NAME);
+MODULE_FIRMWARE(I2400MU_FW_FILE_NAME_v1_4);
+MODULE_FIRMWARE(I2400MU_FW_FILE_NAME_v1_3);
index fe819a785714f50f5f30299b0d677e595c51b33e..612fffe100a68f19274d50bf5c0526f617e2d75d 100644 (file)
@@ -228,6 +228,14 @@ config PCMCIA_ATMEL
          Enable support for PCMCIA cards containing the
          Atmel at76c502 and at76c504 chips.
 
+config AT76C50X_USB
+        tristate "Atmel at76c503/at76c505/at76c505a USB cards"
+        depends on MAC80211 && WLAN_80211 && USB
+        select FW_LOADER
+        ---help---
+          Enable support for USB Wireless devices using Atmel at76c503,
+          at76c505 or at76c505a chips.
+
 config AIRO_CS
        tristate "Cisco/Aironet 34X/35X/4500/4800 PCMCIA cards"
        depends on PCMCIA && (BROKEN || !M32R) && WLAN_80211
@@ -465,6 +473,15 @@ config MAC80211_HWSIM
          To compile this driver as a module, choose M here: the module will be
          called mac80211_hwsim.  If unsure, say N.
 
+config MWL8K
+       tristate "Marvell 88W8xxx PCI/PCIe Wireless support"
+       depends on MAC80211 && PCI && WLAN_80211 && EXPERIMENTAL
+       ---help---
+         This driver supports Marvell TOPDOG 802.11 wireless cards.
+
+         To compile this driver as a module, choose M here: the module
+         will be called mwl8k.  If unsure, say N.
+
 source "drivers/net/wireless/p54/Kconfig"
 source "drivers/net/wireless/ath5k/Kconfig"
 source "drivers/net/wireless/ath9k/Kconfig"
index ac590e1ca8beecf788cbe10a2d36f4e043e44799..d780487c420f69126e691ebf69d3ac760b0eeedb 100644 (file)
@@ -24,6 +24,8 @@ obj-$(CONFIG_ATMEL)             += atmel.o
 obj-$(CONFIG_PCI_ATMEL)         += atmel_pci.o 
 obj-$(CONFIG_PCMCIA_ATMEL)      += atmel_cs.o
 
+obj-$(CONFIG_AT76C50X_USB)      += at76c50x-usb.o
+
 obj-$(CONFIG_PRISM54)          += prism54/
 
 obj-$(CONFIG_HOSTAP)           += hostap/
@@ -46,6 +48,8 @@ obj-$(CONFIG_LIBERTAS_THINFIRM)       += libertas_tf/
 
 obj-$(CONFIG_ADM8211)  += adm8211.o
 
+obj-$(CONFIG_MWL8K)    += mwl8k.o
+
 obj-$(CONFIG_IWLWIFI)  += iwlwifi/
 obj-$(CONFIG_RT2X00)   += rt2x00/
 
index c44f38895fbe6c3db7aed02202c7594130d2c922..7e80aba8a148dbb821e6096181378f3768f4455a 100644 (file)
@@ -2646,17 +2646,21 @@ static const struct header_ops airo_header_ops = {
        .parse = wll_header_parse,
 };
 
+static const struct net_device_ops airo11_netdev_ops = {
+       .ndo_open               = airo_open,
+       .ndo_stop               = airo_close,
+       .ndo_start_xmit         = airo_start_xmit11,
+       .ndo_get_stats          = airo_get_stats,
+       .ndo_set_mac_address    = airo_set_mac_address,
+       .ndo_do_ioctl           = airo_ioctl,
+       .ndo_change_mtu         = airo_change_mtu,
+};
+
 static void wifi_setup(struct net_device *dev)
 {
+       dev->netdev_ops = &airo11_netdev_ops;
        dev->header_ops = &airo_header_ops;
-       dev->hard_start_xmit = &airo_start_xmit11;
-       dev->get_stats = &airo_get_stats;
-       dev->set_mac_address = &airo_set_mac_address;
-       dev->do_ioctl = &airo_ioctl;
        dev->wireless_handlers = &airo_handler_def;
-       dev->change_mtu = &airo_change_mtu;
-       dev->open = &airo_open;
-       dev->stop = &airo_close;
 
        dev->type               = ARPHRD_IEEE80211;
        dev->hard_header_len    = ETH_HLEN;
@@ -2739,6 +2743,33 @@ static void airo_networks_initialize(struct airo_info *ai)
                              &ai->network_free_list);
 }
 
+static const struct net_device_ops airo_netdev_ops = {
+       .ndo_open               = airo_open,
+       .ndo_stop               = airo_close,
+       .ndo_start_xmit         = airo_start_xmit,
+       .ndo_get_stats          = airo_get_stats,
+       .ndo_set_multicast_list = airo_set_multicast_list,
+       .ndo_set_mac_address    = airo_set_mac_address,
+       .ndo_do_ioctl           = airo_ioctl,
+       .ndo_change_mtu         = airo_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+static const struct net_device_ops mpi_netdev_ops = {
+       .ndo_open               = airo_open,
+       .ndo_stop               = airo_close,
+       .ndo_start_xmit         = mpi_start_xmit,
+       .ndo_get_stats          = airo_get_stats,
+       .ndo_set_multicast_list = airo_set_multicast_list,
+       .ndo_set_mac_address    = airo_set_mac_address,
+       .ndo_do_ioctl           = airo_ioctl,
+       .ndo_change_mtu         = airo_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+
 static struct net_device *_init_airo_card( unsigned short irq, int port,
                                           int is_pcmcia, struct pci_dev *pci,
                                           struct device *dmdev )
@@ -2776,22 +2807,16 @@ static struct net_device *_init_airo_card( unsigned short irq, int port,
                goto err_out_free;
        airo_networks_initialize (ai);
 
+       skb_queue_head_init (&ai->txq);
+
        /* The Airo-specific entries in the device structure. */
-       if (test_bit(FLAG_MPI,&ai->flags)) {
-               skb_queue_head_init (&ai->txq);
-               dev->hard_start_xmit = &mpi_start_xmit;
-       } else
-               dev->hard_start_xmit = &airo_start_xmit;
-       dev->get_stats = &airo_get_stats;
-       dev->set_multicast_list = &airo_set_multicast_list;
-       dev->set_mac_address = &airo_set_mac_address;
-       dev->do_ioctl = &airo_ioctl;
+       if (test_bit(FLAG_MPI,&ai->flags))
+               dev->netdev_ops = &mpi_netdev_ops;
+       else
+               dev->netdev_ops = &airo_netdev_ops;
        dev->wireless_handlers = &airo_handler_def;
        ai->wireless_data.spy_data = &ai->spy_data;
        dev->wireless_data = &ai->wireless_data;
-       dev->change_mtu = &airo_change_mtu;
-       dev->open = &airo_open;
-       dev->stop = &airo_close;
        dev->irq = irq;
        dev->base_addr = port;
 
@@ -4727,7 +4752,7 @@ static int proc_stats_rid_open( struct inode *inode,
        StatsRid stats;
        int i, j;
        __le32 *vals = stats.vals;
-       int len = le16_to_cpu(stats.len);
+       int len;
 
        if ((file->private_data = kzalloc(sizeof(struct proc_data ), GFP_KERNEL)) == NULL)
                return -ENOMEM;
@@ -4738,6 +4763,7 @@ static int proc_stats_rid_open( struct inode *inode,
        }
 
        readStatsRid(apriv, &stats, rid, 1);
+       len = le16_to_cpu(stats.len);
 
         j = 0;
        for(i=0; statsLabels[i]!=(char *)-1 && i*4<len; i++) {
@@ -7147,11 +7173,15 @@ static int airo_get_aplist(struct net_device *dev,
 {
        struct airo_info *local = dev->ml_priv;
        struct sockaddr *address = (struct sockaddr *) extra;
-       struct iw_quality qual[IW_MAX_AP];
+       struct iw_quality *qual;
        BSSListRid BSSList;
        int i;
        int loseSync = capable(CAP_NET_ADMIN) ? 1: -1;
 
+       qual = kmalloc(IW_MAX_AP * sizeof(*qual), GFP_KERNEL);
+       if (!qual)
+               return -ENOMEM;
+
        for (i = 0; i < IW_MAX_AP; i++) {
                u16 dBm;
                if (readBSSListRid(local, loseSync, &BSSList))
@@ -7206,6 +7236,7 @@ static int airo_get_aplist(struct net_device *dev,
        }
        dwrq->length = i;
 
+       kfree(qual);
        return 0;
 }
 
index 27696c20f4c2cf4d8fd10a8abaa41d843fd0974e..d0593ed9170eb281d820a8e3aadaa3b3f04e71fd 100644 (file)
@@ -16,8 +16,8 @@
     In addition this module was derived from dummy_cs.
     The initial developer of dummy_cs is David A. Hinds
     <dahinds@users.sourceforge.net>.  Portions created by David A. Hinds
-    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.    
-    
+    are Copyright (C) 1999 David A. Hinds.  All Rights Reserved.
+
 ======================================================================*/
 
 #ifdef __IN_PCMCIA_PACKAGE__
@@ -38,7 +38,7 @@
 #include <pcmcia/cisreg.h>
 #include <pcmcia/ds.h>
 
-#include <asm/io.h>
+#include <linux/io.h>
 #include <asm/system.h>
 
 #include "airo.h"
@@ -54,7 +54,7 @@
 static int pc_debug = PCMCIA_DEBUG;
 module_param(pc_debug, int, 0);
 static char *version = "$Revision: 1.2 $";
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args);
+#define DEBUG(n, args...) if (pc_debug > (n)) printk(KERN_DEBUG args);
 #else
 #define DEBUG(n, args...)
 #endif
@@ -62,9 +62,9 @@ static char *version = "$Revision: 1.2 $";
 /*====================================================================*/
 
 MODULE_AUTHOR("Benjamin Reed");
-MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet \
-                   cards.  This is the module that links the PCMCIA card \
-                  with the airo module.");
+MODULE_DESCRIPTION("Support for Cisco/Aironet 802.11 wireless ethernet "
+                  "cards.  This is the module that links the PCMCIA card "
+                  "with the airo module.");
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340 PCMCIA cards");
 
@@ -76,7 +76,7 @@ MODULE_SUPPORTED_DEVICE("Aironet 4500, 4800 and Cisco 340 PCMCIA cards");
    event is received.  The config() and release() entry points are
    used to configure or release a socket, in response to card
    insertion and ejection events.  They are invoked from the airo_cs
-   event handler. 
+   event handler.
 */
 
 static int airo_config(struct pcmcia_device *link);
@@ -103,8 +103,9 @@ static void airo_detach(struct pcmcia_device *p_dev);
    by one struct pcmcia_device structure (defined in ds.h).
 
    You may not want to use a linked list for this -- for example, the
-   memory card driver uses an array of struct pcmcia_device pointers, where minor
-   device numbers are used to derive the corresponding array index.
+   memory card driver uses an array of struct pcmcia_device pointers,
+   where minor device numbers are used to derive the corresponding
+   array index.
 */
 
 /*
@@ -122,22 +123,22 @@ static void airo_detach(struct pcmcia_device *p_dev);
    device IO routines can use a flag like this to throttle IO to a
    card that is not ready to accept it.
 */
-   
+
 typedef struct local_info_t {
        dev_node_t      node;
        struct net_device *eth_dev;
 } local_info_t;
 
 /*======================================================================
-  
+
   airo_attach() creates an "instance" of the driver, allocating
   local data structures for one device.  The device is registered
   with Card Services.
-  
+
   The dev_link structure is initialized, but we don't actually
   configure the card at this point -- we wait until we receive a
   card insertion event.
-  
+
   ======================================================================*/
 
 static int airo_probe(struct pcmcia_device *p_dev)
@@ -150,7 +151,7 @@ static int airo_probe(struct pcmcia_device *p_dev)
        p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING;
        p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
        p_dev->irq.Handler = NULL;
-       
+
        /*
          General socket configuration defaults can go here.  In this
          client, we assume very little, and rely on the CIS for almost
@@ -160,7 +161,7 @@ static int airo_probe(struct pcmcia_device *p_dev)
        */
        p_dev->conf.Attributes = 0;
        p_dev->conf.IntType = INT_MEMORY_AND_IO;
-       
+
        /* Allocate space for private device-specific data */
        local = kzalloc(sizeof(local_info_t), GFP_KERNEL);
        if (!local) {
@@ -173,12 +174,12 @@ static int airo_probe(struct pcmcia_device *p_dev)
 } /* airo_attach */
 
 /*======================================================================
-  
+
   This deletes a driver "instance".  The device is de-registered
   with Card Services.  If it has been released, all local data
   structures are freed.  Otherwise, the structures will be freed
   when the device is released.
-  
+
   ======================================================================*/
 
 static void airo_detach(struct pcmcia_device *link)
@@ -187,20 +188,20 @@ static void airo_detach(struct pcmcia_device *link)
 
        airo_release(link);
 
-       if ( ((local_info_t*)link->priv)->eth_dev ) {
-               stop_airo_card( ((local_info_t*)link->priv)->eth_dev, 0 );
+       if (((local_info_t *)link->priv)->eth_dev) {
+               stop_airo_card(((local_info_t *)link->priv)->eth_dev, 0);
        }
-       ((local_info_t*)link->priv)->eth_dev = NULL;
+       ((local_info_t *)link->priv)->eth_dev = NULL;
 
        kfree(link->priv);
 } /* airo_detach */
 
 /*======================================================================
-  
+
   airo_config() is scheduled to run after a CARD_INSERTION event
   is received, to configure the PCMCIA socket, and to make the
   device available to the system.
-  
+
   ======================================================================*/
 
 #define CS_CHECK(fn, ret) \
@@ -325,26 +326,28 @@ static int airo_config(struct pcmcia_device *link)
        */
        if (link->conf.Attributes & CONF_ENABLE_IRQ)
                CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
-       
+
        /*
          This actually configures the PCMCIA socket -- setting up
          the I/O windows and the interrupt mapping, and putting the
          card and host interface into "Memory and IO" mode.
        */
-       CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
-       ((local_info_t*)link->priv)->eth_dev = 
-               init_airo_card( link->irq.AssignedIRQ,
-                               link->io.BasePort1, 1, &handle_to_dev(link) );
-       if (!((local_info_t*)link->priv)->eth_dev) goto cs_failed;
-       
+       CS_CHECK(RequestConfiguration,
+                pcmcia_request_configuration(link, &link->conf));
+       ((local_info_t *)link->priv)->eth_dev =
+               init_airo_card(link->irq.AssignedIRQ,
+                              link->io.BasePort1, 1, &handle_to_dev(link));
+       if (!((local_info_t *)link->priv)->eth_dev)
+               goto cs_failed;
+
        /*
          At this point, the dev_node_t structure(s) need to be
          initialized and arranged in a linked list at link->dev_node.
        */
-       strcpy(dev->node.dev_name, ((local_info_t*)link->priv)->eth_dev->name );
+       strcpy(dev->node.dev_name, ((local_info_t *)link->priv)->eth_dev->name);
        dev->node.major = dev->node.minor = 0;
        link->dev_node = &dev->node;
-       
+
        /* Finally, report what we've done */
        printk(KERN_INFO "%s: index 0x%02x: ",
               dev->node.dev_name, link->conf.ConfigIndex);
@@ -374,11 +377,11 @@ static int airo_config(struct pcmcia_device *link)
 } /* airo_config */
 
 /*======================================================================
-  
+
   After a card is removed, airo_release() will unregister the
   device, and release the PCMCIA configuration.  If the device is
   still open, this will be postponed until it is closed.
-  
+
   ======================================================================*/
 
 static void airo_release(struct pcmcia_device *link)
@@ -475,7 +478,7 @@ static void airo_cs_cleanup(void)
     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.    
+    POSSIBILITY OF SUCH DAMAGE.
 */
 
 module_init(airo_cs_init);
diff --git a/drivers/net/wireless/at76c50x-usb.c b/drivers/net/wireless/at76c50x-usb.c
new file mode 100644 (file)
index 0000000..0c02f1c
--- /dev/null
@@ -0,0 +1,2501 @@
+/*
+ * at76c503/at76c505 USB driver
+ *
+ * Copyright (c) 2002 - 2003 Oliver Kurth
+ * Copyright (c) 2004 Joerg Albert <joerg.albert@gmx.de>
+ * Copyright (c) 2004 Nick Jones
+ * Copyright (c) 2004 Balint Seeber <n0_5p4m_p13453@hotmail.com>
+ * Copyright (c) 2007 Guido Guenther <agx@sigxcpu.org>
+ * Copyright (c) 2007 Kalle Valo <kalle.valo@iki.fi>
+ *
+ * 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 file is part of the Berlios driver for WLAN USB devices based on the
+ * Atmel AT76C503A/505/505A.
+ *
+ * Some iw_handler code was taken from airo.c, (C) 1999 Benjamin Reed
+ *
+ * TODO list is at the wiki:
+ *
+ * http://wireless.kernel.org/en/users/Drivers/at76c50x-usb#TODO
+ *
+ */
+
+#include <linux/init.h>
+#include <linux/kernel.h>
+#include <linux/sched.h>
+#include <linux/errno.h>
+#include <linux/slab.h>
+#include <linux/module.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/usb.h>
+#include <linux/netdevice.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/wireless.h>
+#include <net/iw_handler.h>
+#include <net/ieee80211_radiotap.h>
+#include <linux/firmware.h>
+#include <linux/leds.h>
+#include <net/mac80211.h>
+
+#include "at76c50x-usb.h"
+
+/* Version information */
+#define DRIVER_NAME "at76c50x-usb"
+#define DRIVER_VERSION "0.17"
+#define DRIVER_DESC "Atmel at76x USB Wireless LAN Driver"
+
+/* at76_debug bits */
+#define DBG_PROGRESS           0x00000001      /* authentication/accociation */
+#define DBG_BSS_TABLE          0x00000002      /* show BSS table after scans */
+#define DBG_IOCTL              0x00000004      /* ioctl calls / settings */
+#define DBG_MAC_STATE          0x00000008      /* MAC state transitions */
+#define DBG_TX_DATA            0x00000010      /* tx header */
+#define DBG_TX_DATA_CONTENT    0x00000020      /* tx content */
+#define DBG_TX_MGMT            0x00000040      /* tx management */
+#define DBG_RX_DATA            0x00000080      /* rx data header */
+#define DBG_RX_DATA_CONTENT    0x00000100      /* rx data content */
+#define DBG_RX_MGMT            0x00000200      /* rx mgmt frame headers */
+#define DBG_RX_BEACON          0x00000400      /* rx beacon */
+#define DBG_RX_CTRL            0x00000800      /* rx control */
+#define DBG_RX_MGMT_CONTENT    0x00001000      /* rx mgmt content */
+#define DBG_RX_FRAGS           0x00002000      /* rx data fragment handling */
+#define DBG_DEVSTART           0x00004000      /* fw download, device start */
+#define DBG_URB                        0x00008000      /* rx urb status, ... */
+#define DBG_RX_ATMEL_HDR       0x00010000      /* Atmel-specific Rx headers */
+#define DBG_PROC_ENTRY         0x00020000      /* procedure entries/exits */
+#define DBG_PM                 0x00040000      /* power management settings */
+#define DBG_BSS_MATCH          0x00080000      /* BSS match failures */
+#define DBG_PARAMS             0x00100000      /* show configured parameters */
+#define DBG_WAIT_COMPLETE      0x00200000      /* command completion */
+#define DBG_RX_FRAGS_SKB       0x00400000      /* skb header of Rx fragments */
+#define DBG_BSS_TABLE_RM       0x00800000      /* purging bss table entries */
+#define DBG_MONITOR_MODE       0x01000000      /* monitor mode */
+#define DBG_MIB                        0x02000000      /* dump all MIBs on startup */
+#define DBG_MGMT_TIMER         0x04000000      /* dump mgmt_timer ops */
+#define DBG_WE_EVENTS          0x08000000      /* dump wireless events */
+#define DBG_FW                 0x10000000      /* firmware download */
+#define DBG_DFU                        0x20000000      /* device firmware upgrade */
+#define DBG_CMD                        0x40000000
+#define DBG_MAC80211           0x80000000
+
+#define DBG_DEFAULTS           0
+
+/* Use our own dbg macro */
+#define at76_dbg(bits, format, arg...) \
+       do { \
+               if (at76_debug & (bits))                                 \
+                       printk(KERN_DEBUG DRIVER_NAME ": " format "\n" , \
+                              ## arg);                                  \
+       } while (0)
+
+#define at76_dbg_dump(bits, buf, len, format, arg...)  \
+       do { \
+               if (at76_debug & (bits)) { \
+                       printk(KERN_DEBUG DRIVER_NAME ": " format "\n" , \
+                              ## arg);                                  \
+                       print_hex_dump_bytes("", DUMP_PREFIX_OFFSET,     \
+                                            buf, len);                  \
+               }                                                        \
+       } while (0)
+
+static uint at76_debug = DBG_DEFAULTS;
+
+/* Protect against concurrent firmware loading and parsing */
+static struct mutex fw_mutex;
+
+static struct fwentry firmwares[] = {
+       [0] = { "" },
+       [BOARD_503_ISL3861] = { "atmel_at76c503-i3861.bin" },
+       [BOARD_503_ISL3863] = { "atmel_at76c503-i3863.bin" },
+       [BOARD_503] = { "atmel_at76c503-rfmd.bin" },
+       [BOARD_503_ACC] = { "atmel_at76c503-rfmd-acc.bin" },
+       [BOARD_505] = { "atmel_at76c505-rfmd.bin" },
+       [BOARD_505_2958] = { "atmel_at76c505-rfmd2958.bin" },
+       [BOARD_505A] = { "atmel_at76c505a-rfmd2958.bin" },
+       [BOARD_505AMX] = { "atmel_at76c505amx-rfmd.bin" },
+};
+
+#define USB_DEVICE_DATA(__ops) .driver_info = (kernel_ulong_t)(__ops)
+
+static struct usb_device_id dev_table[] = {
+       /*
+        * at76c503-i3861
+        */
+       /* Generic AT76C503/3861 device */
+       { USB_DEVICE(0x03eb, 0x7603), USB_DEVICE_DATA(BOARD_503_ISL3861) },
+       /* Linksys WUSB11 v2.1/v2.6 */
+       { USB_DEVICE(0x066b, 0x2211), USB_DEVICE_DATA(BOARD_503_ISL3861) },
+       /* Netgear MA101 rev. A */
+       { USB_DEVICE(0x0864, 0x4100), USB_DEVICE_DATA(BOARD_503_ISL3861) },
+       /* Tekram U300C / Allnet ALL0193 */
+       { USB_DEVICE(0x0b3b, 0x1612), USB_DEVICE_DATA(BOARD_503_ISL3861) },
+       /* HP HN210W J7801A */
+       { USB_DEVICE(0x03f0, 0x011c), USB_DEVICE_DATA(BOARD_503_ISL3861) },
+       /* Sitecom/Z-Com/Zyxel M4Y-750 */
+       { USB_DEVICE(0x0cde, 0x0001), USB_DEVICE_DATA(BOARD_503_ISL3861) },
+       /* Dynalink/Askey WLL013 (intersil) */
+       { USB_DEVICE(0x069a, 0x0320), USB_DEVICE_DATA(BOARD_503_ISL3861) },
+       /* EZ connect 11Mpbs Wireless USB Adapter SMC2662W v1 */
+       { USB_DEVICE(0x0d5c, 0xa001), USB_DEVICE_DATA(BOARD_503_ISL3861) },
+       /* BenQ AWL300 */
+       { USB_DEVICE(0x04a5, 0x9000), USB_DEVICE_DATA(BOARD_503_ISL3861) },
+       /* Addtron AWU-120, Compex WLU11 */
+       { USB_DEVICE(0x05dd, 0xff31), USB_DEVICE_DATA(BOARD_503_ISL3861) },
+       /* Intel AP310 AnyPoint II USB */
+       { USB_DEVICE(0x8086, 0x0200), USB_DEVICE_DATA(BOARD_503_ISL3861) },
+       /* Dynalink L11U */
+       { USB_DEVICE(0x0d8e, 0x7100), USB_DEVICE_DATA(BOARD_503_ISL3861) },
+       /* Arescom WL-210, FCC id 07J-GL2411USB */
+       { USB_DEVICE(0x0d8e, 0x7110), USB_DEVICE_DATA(BOARD_503_ISL3861) },
+       /* I-O DATA WN-B11/USB */
+       { USB_DEVICE(0x04bb, 0x0919), USB_DEVICE_DATA(BOARD_503_ISL3861) },
+       /* BT Voyager 1010 */
+       { USB_DEVICE(0x069a, 0x0821), USB_DEVICE_DATA(BOARD_503_ISL3861) },
+       /*
+        * at76c503-i3863
+        */
+       /* Generic AT76C503/3863 device */
+       { USB_DEVICE(0x03eb, 0x7604), USB_DEVICE_DATA(BOARD_503_ISL3863) },
+       /* Samsung SWL-2100U */
+       { USB_DEVICE(0x055d, 0xa000), USB_DEVICE_DATA(BOARD_503_ISL3863) },
+       /*
+        * at76c503-rfmd
+        */
+       /* Generic AT76C503/RFMD device */
+       { USB_DEVICE(0x03eb, 0x7605), USB_DEVICE_DATA(BOARD_503) },
+       /* Dynalink/Askey WLL013 (rfmd) */
+       { USB_DEVICE(0x069a, 0x0321), USB_DEVICE_DATA(BOARD_503) },
+       /* Linksys WUSB11 v2.6 */
+       { USB_DEVICE(0x077b, 0x2219), USB_DEVICE_DATA(BOARD_503) },
+       /* Network Everywhere NWU11B */
+       { USB_DEVICE(0x077b, 0x2227), USB_DEVICE_DATA(BOARD_503) },
+       /* Netgear MA101 rev. B */
+       { USB_DEVICE(0x0864, 0x4102), USB_DEVICE_DATA(BOARD_503) },
+       /* D-Link DWL-120 rev. E */
+       { USB_DEVICE(0x2001, 0x3200), USB_DEVICE_DATA(BOARD_503) },
+       /* Actiontec 802UAT1, HWU01150-01UK */
+       { USB_DEVICE(0x1668, 0x7605), USB_DEVICE_DATA(BOARD_503) },
+       /* AirVast W-Buddie WN210 */
+       { USB_DEVICE(0x03eb, 0x4102), USB_DEVICE_DATA(BOARD_503) },
+       /* Dick Smith Electronics XH1153 802.11b USB adapter */
+       { USB_DEVICE(0x1371, 0x5743), USB_DEVICE_DATA(BOARD_503) },
+       /* CNet CNUSB611 */
+       { USB_DEVICE(0x1371, 0x0001), USB_DEVICE_DATA(BOARD_503) },
+       /* FiberLine FL-WL200U */
+       { USB_DEVICE(0x1371, 0x0002), USB_DEVICE_DATA(BOARD_503) },
+       /* BenQ AWL400 USB stick */
+       { USB_DEVICE(0x04a5, 0x9001), USB_DEVICE_DATA(BOARD_503) },
+       /* 3Com 3CRSHEW696 */
+       { USB_DEVICE(0x0506, 0x0a01), USB_DEVICE_DATA(BOARD_503) },
+       /* Siemens Santis ADSL WLAN USB adapter WLL 013 */
+       { USB_DEVICE(0x0681, 0x001b), USB_DEVICE_DATA(BOARD_503) },
+       /* Belkin F5D6050, version 2 */
+       { USB_DEVICE(0x050d, 0x0050), USB_DEVICE_DATA(BOARD_503) },
+       /* iBlitzz, BWU613 (not *B or *SB) */
+       { USB_DEVICE(0x07b8, 0xb000), USB_DEVICE_DATA(BOARD_503) },
+       /* Gigabyte GN-WLBM101 */
+       { USB_DEVICE(0x1044, 0x8003), USB_DEVICE_DATA(BOARD_503) },
+       /* Planex GW-US11S */
+       { USB_DEVICE(0x2019, 0x3220), USB_DEVICE_DATA(BOARD_503) },
+       /* Internal WLAN adapter in h5[4,5]xx series iPAQs */
+       { USB_DEVICE(0x049f, 0x0032), USB_DEVICE_DATA(BOARD_503) },
+       /* Corega Wireless LAN USB-11 mini */
+       { USB_DEVICE(0x07aa, 0x0011), USB_DEVICE_DATA(BOARD_503) },
+       /* Corega Wireless LAN USB-11 mini2 */
+       { USB_DEVICE(0x07aa, 0x0018), USB_DEVICE_DATA(BOARD_503) },
+       /* Uniden PCW100 */
+       { USB_DEVICE(0x05dd, 0xff35), USB_DEVICE_DATA(BOARD_503) },
+       /*
+        * at76c503-rfmd-acc
+        */
+       /* SMC2664W */
+       { USB_DEVICE(0x083a, 0x3501), USB_DEVICE_DATA(BOARD_503_ACC) },
+       /* Belkin F5D6050, SMC2662W v2, SMC2662W-AR */
+       { USB_DEVICE(0x0d5c, 0xa002), USB_DEVICE_DATA(BOARD_503_ACC) },
+       /*
+        * at76c505-rfmd
+        */
+       /* Generic AT76C505/RFMD */
+       { USB_DEVICE(0x03eb, 0x7606), USB_DEVICE_DATA(BOARD_505) },
+       /*
+        * at76c505-rfmd2958
+        */
+       /* Generic AT76C505/RFMD, OvisLink WL-1130USB */
+       { USB_DEVICE(0x03eb, 0x7613), USB_DEVICE_DATA(BOARD_505_2958) },
+       /* Fiberline FL-WL240U */
+       { USB_DEVICE(0x1371, 0x0014), USB_DEVICE_DATA(BOARD_505_2958) },
+       /* CNet CNUSB-611G */
+       { USB_DEVICE(0x1371, 0x0013), USB_DEVICE_DATA(BOARD_505_2958) },
+       /* Linksys WUSB11 v2.8 */
+       { USB_DEVICE(0x1915, 0x2233), USB_DEVICE_DATA(BOARD_505_2958) },
+       /* Xterasys XN-2122B, IBlitzz BWU613B/BWU613SB */
+       { USB_DEVICE(0x12fd, 0x1001), USB_DEVICE_DATA(BOARD_505_2958) },
+       /* Corega WLAN USB Stick 11 */
+       { USB_DEVICE(0x07aa, 0x7613), USB_DEVICE_DATA(BOARD_505_2958) },
+       /* Microstar MSI Box MS6978 */
+       { USB_DEVICE(0x0db0, 0x1020), USB_DEVICE_DATA(BOARD_505_2958) },
+       /*
+        * at76c505a-rfmd2958
+        */
+       /* Generic AT76C505A device */
+       { USB_DEVICE(0x03eb, 0x7614), USB_DEVICE_DATA(BOARD_505A) },
+       /* Generic AT76C505AS device */
+       { USB_DEVICE(0x03eb, 0x7617), USB_DEVICE_DATA(BOARD_505A) },
+       /* Siemens Gigaset USB WLAN Adapter 11 */
+       { USB_DEVICE(0x1690, 0x0701), USB_DEVICE_DATA(BOARD_505A) },
+       /*
+        * at76c505amx-rfmd
+        */
+       /* Generic AT76C505AMX device */
+       { USB_DEVICE(0x03eb, 0x7615), USB_DEVICE_DATA(BOARD_505AMX) },
+       { }
+};
+
+MODULE_DEVICE_TABLE(usb, dev_table);
+
+/* Supported rates of this hardware, bit 7 marks basic rates */
+static const u8 hw_rates[] = { 0x82, 0x84, 0x0b, 0x16 };
+
+static const char *const preambles[] = { "long", "short", "auto" };
+
+/* Firmware download */
+/* DFU states */
+#define STATE_IDLE                     0x00
+#define STATE_DETACH                   0x01
+#define STATE_DFU_IDLE                 0x02
+#define STATE_DFU_DOWNLOAD_SYNC                0x03
+#define STATE_DFU_DOWNLOAD_BUSY                0x04
+#define STATE_DFU_DOWNLOAD_IDLE                0x05
+#define STATE_DFU_MANIFEST_SYNC                0x06
+#define STATE_DFU_MANIFEST             0x07
+#define STATE_DFU_MANIFEST_WAIT_RESET  0x08
+#define STATE_DFU_UPLOAD_IDLE          0x09
+#define STATE_DFU_ERROR                        0x0a
+
+/* DFU commands */
+#define DFU_DETACH                     0
+#define DFU_DNLOAD                     1
+#define DFU_UPLOAD                     2
+#define DFU_GETSTATUS                  3
+#define DFU_CLRSTATUS                  4
+#define DFU_GETSTATE                   5
+#define DFU_ABORT                      6
+
+#define FW_BLOCK_SIZE 1024
+
+struct dfu_status {
+       unsigned char status;
+       unsigned char poll_timeout[3];
+       unsigned char state;
+       unsigned char string;
+} __attribute__((packed));
+
+static inline int at76_is_intersil(enum board_type board)
+{
+       return (board == BOARD_503_ISL3861 || board == BOARD_503_ISL3863);
+}
+
+static inline int at76_is_503rfmd(enum board_type board)
+{
+       return (board == BOARD_503 || board == BOARD_503_ACC);
+}
+
+static inline int at76_is_505a(enum board_type board)
+{
+       return (board == BOARD_505A || board == BOARD_505AMX);
+}
+
+/* Load a block of the first (internal) part of the firmware */
+static int at76_load_int_fw_block(struct usb_device *udev, int blockno,
+                                 void *block, int size)
+{
+       return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), DFU_DNLOAD,
+                              USB_TYPE_CLASS | USB_DIR_OUT |
+                              USB_RECIP_INTERFACE, blockno, 0, block, size,
+                              USB_CTRL_GET_TIMEOUT);
+}
+
+static int at76_dfu_get_status(struct usb_device *udev,
+                              struct dfu_status *status)
+{
+       int ret;
+
+       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), DFU_GETSTATUS,
+                             USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
+                             0, 0, status, sizeof(struct dfu_status),
+                             USB_CTRL_GET_TIMEOUT);
+       return ret;
+}
+
+static u8 at76_dfu_get_state(struct usb_device *udev, u8 *state)
+{
+       int ret;
+
+       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), DFU_GETSTATE,
+                             USB_TYPE_CLASS | USB_DIR_IN | USB_RECIP_INTERFACE,
+                             0, 0, state, 1, USB_CTRL_GET_TIMEOUT);
+       return ret;
+}
+
+/* Convert timeout from the DFU status to jiffies */
+static inline unsigned long at76_get_timeout(struct dfu_status *s)
+{
+       return msecs_to_jiffies((s->poll_timeout[2] << 16)
+                               | (s->poll_timeout[1] << 8)
+                               | (s->poll_timeout[0]));
+}
+
+/* Load internal firmware from the buffer.  If manifest_sync_timeout > 0, use
+ * its value in jiffies in the MANIFEST_SYNC state.  */
+static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
+                               int manifest_sync_timeout)
+{
+       u8 *block;
+       struct dfu_status dfu_stat_buf;
+       int ret = 0;
+       int need_dfu_state = 1;
+       int is_done = 0;
+       u8 dfu_state = 0;
+       u32 dfu_timeout = 0;
+       int bsize = 0;
+       int blockno = 0;
+
+       at76_dbg(DBG_DFU, "%s( %p, %u, %d)", __func__, buf, size,
+                manifest_sync_timeout);
+
+       if (!size) {
+               dev_printk(KERN_ERR, &udev->dev, "FW buffer length invalid!\n");
+               return -EINVAL;
+       }
+
+       block = kmalloc(FW_BLOCK_SIZE, GFP_KERNEL);
+       if (!block)
+               return -ENOMEM;
+
+       do {
+               if (need_dfu_state) {
+                       ret = at76_dfu_get_state(udev, &dfu_state);
+                       if (ret < 0) {
+                               dev_printk(KERN_ERR, &udev->dev,
+                                          "cannot get DFU state: %d\n", ret);
+                               goto exit;
+                       }
+                       need_dfu_state = 0;
+               }
+
+               switch (dfu_state) {
+               case STATE_DFU_DOWNLOAD_SYNC:
+                       at76_dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_SYNC");
+                       ret = at76_dfu_get_status(udev, &dfu_stat_buf);
+                       if (ret >= 0) {
+                               dfu_state = dfu_stat_buf.state;
+                               dfu_timeout = at76_get_timeout(&dfu_stat_buf);
+                               need_dfu_state = 0;
+                       } else
+                               dev_printk(KERN_ERR, &udev->dev,
+                                          "at76_dfu_get_status returned %d\n",
+                                          ret);
+                       break;
+
+               case STATE_DFU_DOWNLOAD_BUSY:
+                       at76_dbg(DBG_DFU, "STATE_DFU_DOWNLOAD_BUSY");
+                       need_dfu_state = 1;
+
+                       at76_dbg(DBG_DFU, "DFU: Resetting device");
+                       schedule_timeout_interruptible(dfu_timeout);
+                       break;
+
+               case STATE_DFU_DOWNLOAD_IDLE:
+                       at76_dbg(DBG_DFU, "DOWNLOAD...");
+                       /* fall through */
+               case STATE_DFU_IDLE:
+                       at76_dbg(DBG_DFU, "DFU IDLE");
+
+                       bsize = min_t(int, size, FW_BLOCK_SIZE);
+                       memcpy(block, buf, bsize);
+                       at76_dbg(DBG_DFU, "int fw, size left = %5d, "
+                                "bsize = %4d, blockno = %2d", size, bsize,
+                                blockno);
+                       ret =
+                           at76_load_int_fw_block(udev, blockno, block, bsize);
+                       buf += bsize;
+                       size -= bsize;
+                       blockno++;
+
+                       if (ret != bsize)
+                               dev_printk(KERN_ERR, &udev->dev,
+                                          "at76_load_int_fw_block "
+                                          "returned %d\n", ret);
+                       need_dfu_state = 1;
+                       break;
+
+               case STATE_DFU_MANIFEST_SYNC:
+                       at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST_SYNC");
+
+                       ret = at76_dfu_get_status(udev, &dfu_stat_buf);
+                       if (ret < 0)
+                               break;
+
+                       dfu_state = dfu_stat_buf.state;
+                       dfu_timeout = at76_get_timeout(&dfu_stat_buf);
+                       need_dfu_state = 0;
+
+                       /* override the timeout from the status response,
+                          needed for AT76C505A */
+                       if (manifest_sync_timeout > 0)
+                               dfu_timeout = manifest_sync_timeout;
+
+                       at76_dbg(DBG_DFU, "DFU: Waiting for manifest phase");
+                       schedule_timeout_interruptible(dfu_timeout);
+                       break;
+
+               case STATE_DFU_MANIFEST:
+                       at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST");
+                       is_done = 1;
+                       break;
+
+               case STATE_DFU_MANIFEST_WAIT_RESET:
+                       at76_dbg(DBG_DFU, "STATE_DFU_MANIFEST_WAIT_RESET");
+                       is_done = 1;
+                       break;
+
+               case STATE_DFU_UPLOAD_IDLE:
+                       at76_dbg(DBG_DFU, "STATE_DFU_UPLOAD_IDLE");
+                       break;
+
+               case STATE_DFU_ERROR:
+                       at76_dbg(DBG_DFU, "STATE_DFU_ERROR");
+                       ret = -EPIPE;
+                       break;
+
+               default:
+                       at76_dbg(DBG_DFU, "DFU UNKNOWN STATE (%d)", dfu_state);
+                       ret = -EINVAL;
+                       break;
+               }
+       } while (!is_done && (ret >= 0));
+
+exit:
+       kfree(block);
+       if (ret >= 0)
+               ret = 0;
+
+       return ret;
+}
+
+#define HEX2STR_BUFFERS 4
+#define HEX2STR_MAX_LEN 64
+#define BIN2HEX(x) ((x) < 10 ? '0' + (x) : (x) + 'A' - 10)
+
+/* Convert binary data into hex string */
+static char *hex2str(void *buf, int len)
+{
+       static atomic_t a = ATOMIC_INIT(0);
+       static char bufs[HEX2STR_BUFFERS][3 * HEX2STR_MAX_LEN + 1];
+       char *ret = bufs[atomic_inc_return(&a) & (HEX2STR_BUFFERS - 1)];
+       char *obuf = ret;
+       u8 *ibuf = buf;
+
+       if (len > HEX2STR_MAX_LEN)
+               len = HEX2STR_MAX_LEN;
+
+       if (len <= 0) {
+               ret[0] = '\0';
+               return ret;
+       }
+
+       while (len--) {
+               *obuf++ = BIN2HEX(*ibuf >> 4);
+               *obuf++ = BIN2HEX(*ibuf & 0xf);
+               *obuf++ = '-';
+               ibuf++;
+       }
+       *(--obuf) = '\0';
+
+       return ret;
+}
+
+#define MAC2STR_BUFFERS 4
+
+static inline char *mac2str(u8 *mac)
+{
+       static atomic_t a = ATOMIC_INIT(0);
+       static char bufs[MAC2STR_BUFFERS][6 * 3];
+       char *str;
+
+       str = bufs[atomic_inc_return(&a) & (MAC2STR_BUFFERS - 1)];
+       sprintf(str, "%02x:%02x:%02x:%02x:%02x:%02x",
+               mac[0], mac[1], mac[2], mac[3], mac[4], mac[5]);
+       return str;
+}
+
+/* LED trigger */
+static int tx_activity;
+static void at76_ledtrig_tx_timerfunc(unsigned long data);
+static DEFINE_TIMER(ledtrig_tx_timer, at76_ledtrig_tx_timerfunc, 0, 0);
+DEFINE_LED_TRIGGER(ledtrig_tx);
+
+static void at76_ledtrig_tx_timerfunc(unsigned long data)
+{
+       static int tx_lastactivity;
+
+       if (tx_lastactivity != tx_activity) {
+               tx_lastactivity = tx_activity;
+               led_trigger_event(ledtrig_tx, LED_FULL);
+               mod_timer(&ledtrig_tx_timer, jiffies + HZ / 4);
+       } else
+               led_trigger_event(ledtrig_tx, LED_OFF);
+}
+
+static void at76_ledtrig_tx_activity(void)
+{
+       tx_activity++;
+       if (!timer_pending(&ledtrig_tx_timer))
+               mod_timer(&ledtrig_tx_timer, jiffies + HZ / 4);
+}
+
+static int at76_remap(struct usb_device *udev)
+{
+       int ret;
+       ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0a,
+                             USB_TYPE_VENDOR | USB_DIR_OUT |
+                             USB_RECIP_INTERFACE, 0, 0, NULL, 0,
+                             USB_CTRL_GET_TIMEOUT);
+       if (ret < 0)
+               return ret;
+       return 0;
+}
+
+static int at76_get_op_mode(struct usb_device *udev)
+{
+       int ret;
+       u8 saved;
+       u8 *op_mode;
+
+       op_mode = kmalloc(1, GFP_NOIO);
+       if (!op_mode)
+               return -ENOMEM;
+       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33,
+                             USB_TYPE_VENDOR | USB_DIR_IN |
+                             USB_RECIP_INTERFACE, 0x01, 0, op_mode, 1,
+                             USB_CTRL_GET_TIMEOUT);
+       saved = *op_mode;
+       kfree(op_mode);
+
+       if (ret < 0)
+               return ret;
+       else if (ret < 1)
+               return -EIO;
+       else
+               return saved;
+}
+
+/* Load a block of the second ("external") part of the firmware */
+static inline int at76_load_ext_fw_block(struct usb_device *udev, int blockno,
+                                        void *block, int size)
+{
+       return usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0e,
+                              USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+                              0x0802, blockno, block, size,
+                              USB_CTRL_GET_TIMEOUT);
+}
+
+static inline int at76_get_hw_cfg(struct usb_device *udev,
+                                 union at76_hwcfg *buf, int buf_size)
+{
+       return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33,
+                              USB_TYPE_VENDOR | USB_DIR_IN |
+                              USB_RECIP_INTERFACE, 0x0a02, 0,
+                              buf, buf_size, USB_CTRL_GET_TIMEOUT);
+}
+
+/* Intersil boards use a different "value" for GetHWConfig requests */
+static inline int at76_get_hw_cfg_intersil(struct usb_device *udev,
+                                          union at76_hwcfg *buf, int buf_size)
+{
+       return usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33,
+                              USB_TYPE_VENDOR | USB_DIR_IN |
+                              USB_RECIP_INTERFACE, 0x0902, 0,
+                              buf, buf_size, USB_CTRL_GET_TIMEOUT);
+}
+
+/* Get the hardware configuration for the adapter and put it to the appropriate
+ * fields of 'priv' (the GetHWConfig request and interpretation of the result
+ * depends on the board type) */
+static int at76_get_hw_config(struct at76_priv *priv)
+{
+       int ret;
+       union at76_hwcfg *hwcfg = kmalloc(sizeof(*hwcfg), GFP_KERNEL);
+
+       if (!hwcfg)
+               return -ENOMEM;
+
+       if (at76_is_intersil(priv->board_type)) {
+               ret = at76_get_hw_cfg_intersil(priv->udev, hwcfg,
+                                              sizeof(hwcfg->i));
+               if (ret < 0)
+                       goto exit;
+               memcpy(priv->mac_addr, hwcfg->i.mac_addr, ETH_ALEN);
+               priv->regulatory_domain = hwcfg->i.regulatory_domain;
+       } else if (at76_is_503rfmd(priv->board_type)) {
+               ret = at76_get_hw_cfg(priv->udev, hwcfg, sizeof(hwcfg->r3));
+               if (ret < 0)
+                       goto exit;
+               memcpy(priv->mac_addr, hwcfg->r3.mac_addr, ETH_ALEN);
+               priv->regulatory_domain = hwcfg->r3.regulatory_domain;
+       } else {
+               ret = at76_get_hw_cfg(priv->udev, hwcfg, sizeof(hwcfg->r5));
+               if (ret < 0)
+                       goto exit;
+               memcpy(priv->mac_addr, hwcfg->r5.mac_addr, ETH_ALEN);
+               priv->regulatory_domain = hwcfg->r5.regulatory_domain;
+       }
+
+exit:
+       kfree(hwcfg);
+       if (ret < 0)
+               printk(KERN_ERR "%s: cannot get HW Config (error %d)\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+
+       return ret;
+}
+
+static struct reg_domain const *at76_get_reg_domain(u16 code)
+{
+       int i;
+       static struct reg_domain const fd_tab[] = {
+               { 0x10, "FCC (USA)", 0x7ff },   /* ch 1-11 */
+               { 0x20, "IC (Canada)", 0x7ff }, /* ch 1-11 */
+               { 0x30, "ETSI (most of Europe)", 0x1fff },      /* ch 1-13 */
+               { 0x31, "Spain", 0x600 },       /* ch 10-11 */
+               { 0x32, "France", 0x1e00 },     /* ch 10-13 */
+               { 0x40, "MKK (Japan)", 0x2000 },        /* ch 14 */
+               { 0x41, "MKK1 (Japan)", 0x3fff },       /* ch 1-14 */
+               { 0x50, "Israel", 0x3fc },      /* ch 3-9 */
+               { 0x00, "<unknown>", 0xffffffff }       /* ch 1-32 */
+       };
+
+       /* Last entry is fallback for unknown domain code */
+       for (i = 0; i < ARRAY_SIZE(fd_tab) - 1; i++)
+               if (code == fd_tab[i].code)
+                       break;
+
+       return &fd_tab[i];
+}
+
+static inline int at76_get_mib(struct usb_device *udev, u16 mib, void *buf,
+                              int buf_size)
+{
+       int ret;
+
+       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x33,
+                             USB_TYPE_VENDOR | USB_DIR_IN |
+                             USB_RECIP_INTERFACE, mib << 8, 0, buf, buf_size,
+                             USB_CTRL_GET_TIMEOUT);
+       if (ret >= 0 && ret != buf_size)
+               return -EIO;
+       return ret;
+}
+
+/* Return positive number for status, negative for an error */
+static inline int at76_get_cmd_status(struct usb_device *udev, u8 cmd)
+{
+       u8 *stat_buf;
+       int ret;
+
+       stat_buf = kmalloc(40, GFP_NOIO);
+       if (!stat_buf)
+               return -ENOMEM;
+
+       ret = usb_control_msg(udev, usb_rcvctrlpipe(udev, 0), 0x22,
+                       USB_TYPE_VENDOR | USB_DIR_IN |
+                       USB_RECIP_INTERFACE, cmd, 0, stat_buf,
+                       40, USB_CTRL_GET_TIMEOUT);
+       if (ret >= 0)
+               ret = stat_buf[5];
+       kfree(stat_buf);
+
+       return ret;
+}
+
+#define MAKE_CMD_CASE(c) case (c): return #c
+static const char *at76_get_cmd_string(u8 cmd_status)
+{
+       switch (cmd_status) {
+               MAKE_CMD_CASE(CMD_SET_MIB);
+               MAKE_CMD_CASE(CMD_GET_MIB);
+               MAKE_CMD_CASE(CMD_SCAN);
+               MAKE_CMD_CASE(CMD_JOIN);
+               MAKE_CMD_CASE(CMD_START_IBSS);
+               MAKE_CMD_CASE(CMD_RADIO_ON);
+               MAKE_CMD_CASE(CMD_RADIO_OFF);
+               MAKE_CMD_CASE(CMD_STARTUP);
+       }
+
+       return "UNKNOWN";
+}
+
+static int at76_set_card_command(struct usb_device *udev, u8 cmd, void *buf,
+                                int buf_size)
+{
+       int ret;
+       struct at76_command *cmd_buf = kmalloc(sizeof(struct at76_command) +
+                                              buf_size, GFP_KERNEL);
+
+       if (!cmd_buf)
+               return -ENOMEM;
+
+       cmd_buf->cmd = cmd;
+       cmd_buf->reserved = 0;
+       cmd_buf->size = cpu_to_le16(buf_size);
+       memcpy(cmd_buf->data, buf, buf_size);
+
+       at76_dbg_dump(DBG_CMD, cmd_buf, sizeof(struct at76_command) + buf_size,
+                     "issuing command %s (0x%02x)",
+                     at76_get_cmd_string(cmd), cmd);
+
+       ret = usb_control_msg(udev, usb_sndctrlpipe(udev, 0), 0x0e,
+                             USB_TYPE_VENDOR | USB_DIR_OUT | USB_RECIP_DEVICE,
+                             0, 0, cmd_buf,
+                             sizeof(struct at76_command) + buf_size,
+                             USB_CTRL_GET_TIMEOUT);
+       kfree(cmd_buf);
+       return ret;
+}
+
+#define MAKE_CMD_STATUS_CASE(c)        case (c): return #c
+static const char *at76_get_cmd_status_string(u8 cmd_status)
+{
+       switch (cmd_status) {
+               MAKE_CMD_STATUS_CASE(CMD_STATUS_IDLE);
+               MAKE_CMD_STATUS_CASE(CMD_STATUS_COMPLETE);
+               MAKE_CMD_STATUS_CASE(CMD_STATUS_UNKNOWN);
+               MAKE_CMD_STATUS_CASE(CMD_STATUS_INVALID_PARAMETER);
+               MAKE_CMD_STATUS_CASE(CMD_STATUS_FUNCTION_NOT_SUPPORTED);
+               MAKE_CMD_STATUS_CASE(CMD_STATUS_TIME_OUT);
+               MAKE_CMD_STATUS_CASE(CMD_STATUS_IN_PROGRESS);
+               MAKE_CMD_STATUS_CASE(CMD_STATUS_HOST_FAILURE);
+               MAKE_CMD_STATUS_CASE(CMD_STATUS_SCAN_FAILED);
+       }
+
+       return "UNKNOWN";
+}
+
+/* Wait until the command is completed */
+static int at76_wait_completion(struct at76_priv *priv, int cmd)
+{
+       int status = 0;
+       unsigned long timeout = jiffies + CMD_COMPLETION_TIMEOUT;
+
+       do {
+               status = at76_get_cmd_status(priv->udev, cmd);
+               if (status < 0) {
+                       printk(KERN_ERR "%s: at76_get_cmd_status failed: %d\n",
+                              wiphy_name(priv->hw->wiphy), status);
+                       break;
+               }
+
+               at76_dbg(DBG_WAIT_COMPLETE,
+                        "%s: Waiting on cmd %d, status = %d (%s)",
+                        wiphy_name(priv->hw->wiphy), cmd, status,
+                        at76_get_cmd_status_string(status));
+
+               if (status != CMD_STATUS_IN_PROGRESS
+                   && status != CMD_STATUS_IDLE)
+                       break;
+
+               schedule_timeout_interruptible(HZ / 10);        /* 100 ms */
+               if (time_after(jiffies, timeout)) {
+                       printk(KERN_ERR
+                              "%s: completion timeout for command %d\n",
+                              wiphy_name(priv->hw->wiphy), cmd);
+                       status = -ETIMEDOUT;
+                       break;
+               }
+       } while (1);
+
+       return status;
+}
+
+static int at76_set_mib(struct at76_priv *priv, struct set_mib_buffer *buf)
+{
+       int ret;
+
+       ret = at76_set_card_command(priv->udev, CMD_SET_MIB, buf,
+                                   offsetof(struct set_mib_buffer,
+                                            data) + buf->size);
+       if (ret < 0)
+               return ret;
+
+       ret = at76_wait_completion(priv, CMD_SET_MIB);
+       if (ret != CMD_STATUS_COMPLETE) {
+               printk(KERN_INFO
+                      "%s: set_mib: at76_wait_completion failed "
+                      "with %d\n", wiphy_name(priv->hw->wiphy), ret);
+               ret = -EIO;
+       }
+
+       return ret;
+}
+
+/* Return < 0 on error, == 0 if no command sent, == 1 if cmd sent */
+static int at76_set_radio(struct at76_priv *priv, int enable)
+{
+       int ret;
+       int cmd;
+
+       if (priv->radio_on == enable)
+               return 0;
+
+       cmd = enable ? CMD_RADIO_ON : CMD_RADIO_OFF;
+
+       ret = at76_set_card_command(priv->udev, cmd, NULL, 0);
+       if (ret < 0)
+               printk(KERN_ERR "%s: at76_set_card_command(%d) failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), cmd, ret);
+       else
+               ret = 1;
+
+       priv->radio_on = enable;
+       return ret;
+}
+
+/* Set current power save mode (AT76_PM_OFF/AT76_PM_ON/AT76_PM_SMART) */
+static int at76_set_pm_mode(struct at76_priv *priv)
+{
+       int ret = 0;
+
+       priv->mib_buf.type = MIB_MAC_MGMT;
+       priv->mib_buf.size = 1;
+       priv->mib_buf.index = offsetof(struct mib_mac_mgmt, power_mgmt_mode);
+       priv->mib_buf.data.byte = priv->pm_mode;
+
+       ret = at76_set_mib(priv, &priv->mib_buf);
+       if (ret < 0)
+               printk(KERN_ERR "%s: set_mib (pm_mode) failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+
+       return ret;
+}
+
+static int at76_set_preamble(struct at76_priv *priv, u8 type)
+{
+       int ret = 0;
+
+       priv->mib_buf.type = MIB_LOCAL;
+       priv->mib_buf.size = 1;
+       priv->mib_buf.index = offsetof(struct mib_local, preamble_type);
+       priv->mib_buf.data.byte = type;
+
+       ret = at76_set_mib(priv, &priv->mib_buf);
+       if (ret < 0)
+               printk(KERN_ERR "%s: set_mib (preamble) failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+
+       return ret;
+}
+
+static int at76_set_frag(struct at76_priv *priv, u16 size)
+{
+       int ret = 0;
+
+       priv->mib_buf.type = MIB_MAC;
+       priv->mib_buf.size = 2;
+       priv->mib_buf.index = offsetof(struct mib_mac, frag_threshold);
+       priv->mib_buf.data.word = cpu_to_le16(size);
+
+       ret = at76_set_mib(priv, &priv->mib_buf);
+       if (ret < 0)
+               printk(KERN_ERR "%s: set_mib (frag threshold) failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+
+       return ret;
+}
+
+static int at76_set_rts(struct at76_priv *priv, u16 size)
+{
+       int ret = 0;
+
+       priv->mib_buf.type = MIB_MAC;
+       priv->mib_buf.size = 2;
+       priv->mib_buf.index = offsetof(struct mib_mac, rts_threshold);
+       priv->mib_buf.data.word = cpu_to_le16(size);
+
+       ret = at76_set_mib(priv, &priv->mib_buf);
+       if (ret < 0)
+               printk(KERN_ERR "%s: set_mib (rts) failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+
+       return ret;
+}
+
+static int at76_set_autorate_fallback(struct at76_priv *priv, int onoff)
+{
+       int ret = 0;
+
+       priv->mib_buf.type = MIB_LOCAL;
+       priv->mib_buf.size = 1;
+       priv->mib_buf.index = offsetof(struct mib_local, txautorate_fallback);
+       priv->mib_buf.data.byte = onoff;
+
+       ret = at76_set_mib(priv, &priv->mib_buf);
+       if (ret < 0)
+               printk(KERN_ERR "%s: set_mib (autorate fallback) failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+
+       return ret;
+}
+
+static void at76_dump_mib_mac_addr(struct at76_priv *priv)
+{
+       int i;
+       int ret;
+       struct mib_mac_addr *m = kmalloc(sizeof(struct mib_mac_addr),
+                                        GFP_KERNEL);
+
+       if (!m)
+               return;
+
+       ret = at76_get_mib(priv->udev, MIB_MAC_ADDR, m,
+                          sizeof(struct mib_mac_addr));
+       if (ret < 0) {
+               printk(KERN_ERR "%s: at76_get_mib (MAC_ADDR) failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+               goto exit;
+       }
+
+       at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: mac_addr %s res 0x%x 0x%x",
+                wiphy_name(priv->hw->wiphy),
+                mac2str(m->mac_addr), m->res[0], m->res[1]);
+       for (i = 0; i < ARRAY_SIZE(m->group_addr); i++)
+               at76_dbg(DBG_MIB, "%s: MIB MAC_ADDR: group addr %d: %s, "
+                        "status %d", wiphy_name(priv->hw->wiphy), i,
+                        mac2str(m->group_addr[i]), m->group_addr_status[i]);
+exit:
+       kfree(m);
+}
+
+static void at76_dump_mib_mac_wep(struct at76_priv *priv)
+{
+       int i;
+       int ret;
+       int key_len;
+       struct mib_mac_wep *m = kmalloc(sizeof(struct mib_mac_wep), GFP_KERNEL);
+
+       if (!m)
+               return;
+
+       ret = at76_get_mib(priv->udev, MIB_MAC_WEP, m,
+                          sizeof(struct mib_mac_wep));
+       if (ret < 0) {
+               printk(KERN_ERR "%s: at76_get_mib (MAC_WEP) failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+               goto exit;
+       }
+
+       at76_dbg(DBG_MIB, "%s: MIB MAC_WEP: priv_invoked %u def_key_id %u "
+                "key_len %u excl_unencr %u wep_icv_err %u wep_excluded %u "
+                "encr_level %u key %d", wiphy_name(priv->hw->wiphy),
+                m->privacy_invoked, m->wep_default_key_id,
+                m->wep_key_mapping_len, m->exclude_unencrypted,
+                le32_to_cpu(m->wep_icv_error_count),
+                le32_to_cpu(m->wep_excluded_count), m->encryption_level,
+                m->wep_default_key_id);
+
+       key_len = (m->encryption_level == 1) ?
+           WEP_SMALL_KEY_LEN : WEP_LARGE_KEY_LEN;
+
+       for (i = 0; i < WEP_KEYS; i++)
+               at76_dbg(DBG_MIB, "%s: MIB MAC_WEP: key %d: %s",
+                        wiphy_name(priv->hw->wiphy), i,
+                        hex2str(m->wep_default_keyvalue[i], key_len));
+exit:
+       kfree(m);
+}
+
+static void at76_dump_mib_mac_mgmt(struct at76_priv *priv)
+{
+       int ret;
+       struct mib_mac_mgmt *m = kmalloc(sizeof(struct mib_mac_mgmt),
+                                        GFP_KERNEL);
+
+       if (!m)
+               return;
+
+       ret = at76_get_mib(priv->udev, MIB_MAC_MGMT, m,
+                          sizeof(struct mib_mac_mgmt));
+       if (ret < 0) {
+               printk(KERN_ERR "%s: at76_get_mib (MAC_MGMT) failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+               goto exit;
+       }
+
+       at76_dbg(DBG_MIB, "%s: MIB MAC_MGMT: beacon_period %d CFP_max_duration "
+                "%d medium_occupancy_limit %d station_id 0x%x ATIM_window %d "
+                "CFP_mode %d privacy_opt_impl %d DTIM_period %d CFP_period %d "
+                "current_bssid %s current_essid %s current_bss_type %d "
+                "pm_mode %d ibss_change %d res %d "
+                "multi_domain_capability_implemented %d "
+                "international_roaming %d country_string %.3s",
+                wiphy_name(priv->hw->wiphy), le16_to_cpu(m->beacon_period),
+                le16_to_cpu(m->CFP_max_duration),
+                le16_to_cpu(m->medium_occupancy_limit),
+                le16_to_cpu(m->station_id), le16_to_cpu(m->ATIM_window),
+                m->CFP_mode, m->privacy_option_implemented, m->DTIM_period,
+                m->CFP_period, mac2str(m->current_bssid),
+                hex2str(m->current_essid, IW_ESSID_MAX_SIZE),
+                m->current_bss_type, m->power_mgmt_mode, m->ibss_change,
+                m->res, m->multi_domain_capability_implemented,
+                m->multi_domain_capability_enabled, m->country_string);
+exit:
+       kfree(m);
+}
+
+static void at76_dump_mib_mac(struct at76_priv *priv)
+{
+       int ret;
+       struct mib_mac *m = kmalloc(sizeof(struct mib_mac), GFP_KERNEL);
+
+       if (!m)
+               return;
+
+       ret = at76_get_mib(priv->udev, MIB_MAC, m, sizeof(struct mib_mac));
+       if (ret < 0) {
+               printk(KERN_ERR "%s: at76_get_mib (MAC) failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+               goto exit;
+       }
+
+       at76_dbg(DBG_MIB, "%s: MIB MAC: max_tx_msdu_lifetime %d "
+                "max_rx_lifetime %d frag_threshold %d rts_threshold %d "
+                "cwmin %d cwmax %d short_retry_time %d long_retry_time %d "
+                "scan_type %d scan_channel %d probe_delay %u "
+                "min_channel_time %d max_channel_time %d listen_int %d "
+                "desired_ssid %s desired_bssid %s desired_bsstype %d",
+                wiphy_name(priv->hw->wiphy),
+                le32_to_cpu(m->max_tx_msdu_lifetime),
+                le32_to_cpu(m->max_rx_lifetime),
+                le16_to_cpu(m->frag_threshold), le16_to_cpu(m->rts_threshold),
+                le16_to_cpu(m->cwmin), le16_to_cpu(m->cwmax),
+                m->short_retry_time, m->long_retry_time, m->scan_type,
+                m->scan_channel, le16_to_cpu(m->probe_delay),
+                le16_to_cpu(m->min_channel_time),
+                le16_to_cpu(m->max_channel_time),
+                le16_to_cpu(m->listen_interval),
+                hex2str(m->desired_ssid, IW_ESSID_MAX_SIZE),
+                mac2str(m->desired_bssid), m->desired_bsstype);
+exit:
+       kfree(m);
+}
+
+static void at76_dump_mib_phy(struct at76_priv *priv)
+{
+       int ret;
+       struct mib_phy *m = kmalloc(sizeof(struct mib_phy), GFP_KERNEL);
+
+       if (!m)
+               return;
+
+       ret = at76_get_mib(priv->udev, MIB_PHY, m, sizeof(struct mib_phy));
+       if (ret < 0) {
+               printk(KERN_ERR "%s: at76_get_mib (PHY) failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+               goto exit;
+       }
+
+       at76_dbg(DBG_MIB, "%s: MIB PHY: ed_threshold %d slot_time %d "
+                "sifs_time %d preamble_length %d plcp_header_length %d "
+                "mpdu_max_length %d cca_mode_supported %d operation_rate_set "
+                "0x%x 0x%x 0x%x 0x%x channel_id %d current_cca_mode %d "
+                "phy_type %d current_reg_domain %d",
+                wiphy_name(priv->hw->wiphy), le32_to_cpu(m->ed_threshold),
+                le16_to_cpu(m->slot_time), le16_to_cpu(m->sifs_time),
+                le16_to_cpu(m->preamble_length),
+                le16_to_cpu(m->plcp_header_length),
+                le16_to_cpu(m->mpdu_max_length),
+                le16_to_cpu(m->cca_mode_supported), m->operation_rate_set[0],
+                m->operation_rate_set[1], m->operation_rate_set[2],
+                m->operation_rate_set[3], m->channel_id, m->current_cca_mode,
+                m->phy_type, m->current_reg_domain);
+exit:
+       kfree(m);
+}
+
+static void at76_dump_mib_local(struct at76_priv *priv)
+{
+       int ret;
+       struct mib_local *m = kmalloc(sizeof(struct mib_phy), GFP_KERNEL);
+
+       if (!m)
+               return;
+
+       ret = at76_get_mib(priv->udev, MIB_LOCAL, m, sizeof(struct mib_local));
+       if (ret < 0) {
+               printk(KERN_ERR "%s: at76_get_mib (LOCAL) failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+               goto exit;
+       }
+
+       at76_dbg(DBG_MIB, "%s: MIB LOCAL: beacon_enable %d "
+                "txautorate_fallback %d ssid_size %d promiscuous_mode %d "
+                "preamble_type %d", wiphy_name(priv->hw->wiphy),
+                m->beacon_enable,
+                m->txautorate_fallback, m->ssid_size, m->promiscuous_mode,
+                m->preamble_type);
+exit:
+       kfree(m);
+}
+
+static void at76_dump_mib_mdomain(struct at76_priv *priv)
+{
+       int ret;
+       struct mib_mdomain *m = kmalloc(sizeof(struct mib_mdomain), GFP_KERNEL);
+
+       if (!m)
+               return;
+
+       ret = at76_get_mib(priv->udev, MIB_MDOMAIN, m,
+                          sizeof(struct mib_mdomain));
+       if (ret < 0) {
+               printk(KERN_ERR "%s: at76_get_mib (MDOMAIN) failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+               goto exit;
+       }
+
+       at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: channel_list %s",
+                wiphy_name(priv->hw->wiphy),
+                hex2str(m->channel_list, sizeof(m->channel_list)));
+
+       at76_dbg(DBG_MIB, "%s: MIB MDOMAIN: tx_powerlevel %s",
+                wiphy_name(priv->hw->wiphy),
+                hex2str(m->tx_powerlevel, sizeof(m->tx_powerlevel)));
+exit:
+       kfree(m);
+}
+
+/* Enable monitor mode */
+static int at76_start_monitor(struct at76_priv *priv)
+{
+       struct at76_req_scan scan;
+       int ret;
+
+       memset(&scan, 0, sizeof(struct at76_req_scan));
+       memset(scan.bssid, 0xff, ETH_ALEN);
+
+       scan.channel = priv->channel;
+       scan.scan_type = SCAN_TYPE_PASSIVE;
+       scan.international_scan = 0;
+
+       ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan));
+       if (ret >= 0)
+               ret = at76_get_cmd_status(priv->udev, CMD_SCAN);
+
+       return ret;
+}
+
+/* Calculate padding from txbuf->wlength (which excludes the USB TX header),
+   likely to compensate a flaw in the AT76C503A USB part ... */
+static inline int at76_calc_padding(int wlen)
+{
+       /* add the USB TX header */
+       wlen += AT76_TX_HDRLEN;
+
+       wlen = wlen % 64;
+
+       if (wlen < 50)
+               return 50 - wlen;
+
+       if (wlen >= 61)
+               return 64 + 50 - wlen;
+
+       return 0;
+}
+
+static void at76_rx_callback(struct urb *urb)
+{
+       struct at76_priv *priv = urb->context;
+
+       priv->rx_tasklet.data = (unsigned long)urb;
+       tasklet_schedule(&priv->rx_tasklet);
+       return;
+}
+
+static int at76_submit_rx_urb(struct at76_priv *priv)
+{
+       int ret;
+       int size;
+       struct sk_buff *skb = priv->rx_skb;
+
+       if (!priv->rx_urb) {
+               printk(KERN_ERR "%s: %s: priv->rx_urb is NULL\n",
+                      wiphy_name(priv->hw->wiphy), __func__);
+               return -EFAULT;
+       }
+
+       if (!skb) {
+               skb = dev_alloc_skb(sizeof(struct at76_rx_buffer));
+               if (!skb) {
+                       printk(KERN_ERR "%s: cannot allocate rx skbuff\n",
+                              wiphy_name(priv->hw->wiphy));
+                       ret = -ENOMEM;
+                       goto exit;
+               }
+               priv->rx_skb = skb;
+       } else {
+               skb_push(skb, skb_headroom(skb));
+               skb_trim(skb, 0);
+       }
+
+       size = skb_tailroom(skb);
+       usb_fill_bulk_urb(priv->rx_urb, priv->udev, priv->rx_pipe,
+                         skb_put(skb, size), size, at76_rx_callback, priv);
+       ret = usb_submit_urb(priv->rx_urb, GFP_ATOMIC);
+       if (ret < 0) {
+               if (ret == -ENODEV)
+                       at76_dbg(DBG_DEVSTART,
+                                "usb_submit_urb returned -ENODEV");
+               else
+                       printk(KERN_ERR "%s: rx, usb_submit_urb failed: %d\n",
+                              wiphy_name(priv->hw->wiphy), ret);
+       }
+
+exit:
+       if (ret < 0 && ret != -ENODEV)
+               printk(KERN_ERR "%s: cannot submit rx urb - please unload the "
+                      "driver and/or power cycle the device\n",
+                      wiphy_name(priv->hw->wiphy));
+
+       return ret;
+}
+
+/* Download external firmware */
+static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe)
+{
+       int ret;
+       int op_mode;
+       int blockno = 0;
+       int bsize;
+       u8 *block;
+       u8 *buf = fwe->extfw;
+       int size = fwe->extfw_size;
+
+       if (!buf || !size)
+               return -ENOENT;
+
+       op_mode = at76_get_op_mode(udev);
+       at76_dbg(DBG_DEVSTART, "opmode %d", op_mode);
+
+       if (op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) {
+               dev_printk(KERN_ERR, &udev->dev, "unexpected opmode %d\n",
+                          op_mode);
+               return -EINVAL;
+       }
+
+       block = kmalloc(FW_BLOCK_SIZE, GFP_KERNEL);
+       if (!block)
+               return -ENOMEM;
+
+       at76_dbg(DBG_DEVSTART, "downloading external firmware");
+
+       /* for fw >= 0.100, the device needs an extra empty block */
+       do {
+               bsize = min_t(int, size, FW_BLOCK_SIZE);
+               memcpy(block, buf, bsize);
+               at76_dbg(DBG_DEVSTART,
+                        "ext fw, size left = %5d, bsize = %4d, blockno = %2d",
+                        size, bsize, blockno);
+               ret = at76_load_ext_fw_block(udev, blockno, block, bsize);
+               if (ret != bsize) {
+                       dev_printk(KERN_ERR, &udev->dev,
+                                  "loading %dth firmware block failed: %d\n",
+                                  blockno, ret);
+                       goto exit;
+               }
+               buf += bsize;
+               size -= bsize;
+               blockno++;
+       } while (bsize > 0);
+
+       if (at76_is_505a(fwe->board_type)) {
+               at76_dbg(DBG_DEVSTART, "200 ms delay for 505a");
+               schedule_timeout_interruptible(HZ / 5 + 1);
+       }
+
+exit:
+       kfree(block);
+       if (ret < 0)
+               dev_printk(KERN_ERR, &udev->dev,
+                          "downloading external firmware failed: %d\n", ret);
+       return ret;
+}
+
+/* Download internal firmware */
+static int at76_load_internal_fw(struct usb_device *udev, struct fwentry *fwe)
+{
+       int ret;
+       int need_remap = !at76_is_505a(fwe->board_type);
+
+       ret = at76_usbdfu_download(udev, fwe->intfw, fwe->intfw_size,
+                                  need_remap ? 0 : 2 * HZ);
+
+       if (ret < 0) {
+               dev_printk(KERN_ERR, &udev->dev,
+                          "downloading internal fw failed with %d\n", ret);
+               goto exit;
+       }
+
+       at76_dbg(DBG_DEVSTART, "sending REMAP");
+
+       /* no REMAP for 505A (see SF driver) */
+       if (need_remap) {
+               ret = at76_remap(udev);
+               if (ret < 0) {
+                       dev_printk(KERN_ERR, &udev->dev,
+                                  "sending REMAP failed with %d\n", ret);
+                       goto exit;
+               }
+       }
+
+       at76_dbg(DBG_DEVSTART, "sleeping for 2 seconds");
+       schedule_timeout_interruptible(2 * HZ + 1);
+       usb_reset_device(udev);
+
+exit:
+       return ret;
+}
+
+static int at76_startup_device(struct at76_priv *priv)
+{
+       struct at76_card_config *ccfg = &priv->card_config;
+       int ret;
+
+       at76_dbg(DBG_PARAMS,
+                "%s param: ssid %.*s (%s) mode %s ch %d wep %s key %d "
+                "keylen %d", wiphy_name(priv->hw->wiphy), priv->essid_size,
+                priv->essid, hex2str(priv->essid, IW_ESSID_MAX_SIZE),
+                priv->iw_mode == IW_MODE_ADHOC ? "adhoc" : "infra",
+                priv->channel, priv->wep_enabled ? "enabled" : "disabled",
+                priv->wep_key_id, priv->wep_keys_len[priv->wep_key_id]);
+       at76_dbg(DBG_PARAMS,
+                "%s param: preamble %s rts %d retry %d frag %d "
+                "txrate %s auth_mode %d", wiphy_name(priv->hw->wiphy),
+                preambles[priv->preamble_type], priv->rts_threshold,
+                priv->short_retry_limit, priv->frag_threshold,
+                priv->txrate == TX_RATE_1MBIT ? "1MBit" : priv->txrate ==
+                TX_RATE_2MBIT ? "2MBit" : priv->txrate ==
+                TX_RATE_5_5MBIT ? "5.5MBit" : priv->txrate ==
+                TX_RATE_11MBIT ? "11MBit" : priv->txrate ==
+                TX_RATE_AUTO ? "auto" : "<invalid>", priv->auth_mode);
+       at76_dbg(DBG_PARAMS,
+                "%s param: pm_mode %d pm_period %d auth_mode %s "
+                "scan_times %d %d scan_mode %s",
+                wiphy_name(priv->hw->wiphy), priv->pm_mode, priv->pm_period,
+                priv->auth_mode == WLAN_AUTH_OPEN ? "open" : "shared_secret",
+                priv->scan_min_time, priv->scan_max_time,
+                priv->scan_mode == SCAN_TYPE_ACTIVE ? "active" : "passive");
+
+       memset(ccfg, 0, sizeof(struct at76_card_config));
+       ccfg->promiscuous_mode = 0;
+       ccfg->short_retry_limit = priv->short_retry_limit;
+
+       if (priv->wep_enabled) {
+               if (priv->wep_keys_len[priv->wep_key_id] > WEP_SMALL_KEY_LEN)
+                       ccfg->encryption_type = 2;
+               else
+                       ccfg->encryption_type = 1;
+
+               /* jal: always exclude unencrypted if WEP is active */
+               ccfg->exclude_unencrypted = 1;
+       } else {
+               ccfg->exclude_unencrypted = 0;
+               ccfg->encryption_type = 0;
+       }
+
+       ccfg->rts_threshold = cpu_to_le16(priv->rts_threshold);
+       ccfg->fragmentation_threshold = cpu_to_le16(priv->frag_threshold);
+
+       memcpy(ccfg->basic_rate_set, hw_rates, 4);
+       /* jal: really needed, we do a set_mib for autorate later ??? */
+       ccfg->auto_rate_fallback = (priv->txrate == TX_RATE_AUTO ? 1 : 0);
+       ccfg->channel = priv->channel;
+       ccfg->privacy_invoked = priv->wep_enabled;
+       memcpy(ccfg->current_ssid, priv->essid, IW_ESSID_MAX_SIZE);
+       ccfg->ssid_len = priv->essid_size;
+
+       ccfg->wep_default_key_id = priv->wep_key_id;
+       memcpy(ccfg->wep_default_key_value, priv->wep_keys,
+              sizeof(priv->wep_keys));
+
+       ccfg->short_preamble = priv->preamble_type;
+       ccfg->beacon_period = cpu_to_le16(priv->beacon_period);
+
+       ret = at76_set_card_command(priv->udev, CMD_STARTUP, &priv->card_config,
+                                   sizeof(struct at76_card_config));
+       if (ret < 0) {
+               printk(KERN_ERR "%s: at76_set_card_command failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+               return ret;
+       }
+
+       at76_wait_completion(priv, CMD_STARTUP);
+
+       /* remove BSSID from previous run */
+       memset(priv->bssid, 0, ETH_ALEN);
+
+       if (at76_set_radio(priv, 1) == 1)
+               at76_wait_completion(priv, CMD_RADIO_ON);
+
+       ret = at76_set_preamble(priv, priv->preamble_type);
+       if (ret < 0)
+               return ret;
+
+       ret = at76_set_frag(priv, priv->frag_threshold);
+       if (ret < 0)
+               return ret;
+
+       ret = at76_set_rts(priv, priv->rts_threshold);
+       if (ret < 0)
+               return ret;
+
+       ret = at76_set_autorate_fallback(priv,
+                                        priv->txrate == TX_RATE_AUTO ? 1 : 0);
+       if (ret < 0)
+               return ret;
+
+       ret = at76_set_pm_mode(priv);
+       if (ret < 0)
+               return ret;
+
+       if (at76_debug & DBG_MIB) {
+               at76_dump_mib_mac(priv);
+               at76_dump_mib_mac_addr(priv);
+               at76_dump_mib_mac_mgmt(priv);
+               at76_dump_mib_mac_wep(priv);
+               at76_dump_mib_mdomain(priv);
+               at76_dump_mib_phy(priv);
+               at76_dump_mib_local(priv);
+       }
+
+       return 0;
+}
+
+/* Enable or disable promiscuous mode */
+static void at76_work_set_promisc(struct work_struct *work)
+{
+       struct at76_priv *priv = container_of(work, struct at76_priv,
+                                             work_set_promisc);
+       int ret = 0;
+
+       if (priv->device_unplugged)
+               return;
+
+       mutex_lock(&priv->mtx);
+
+       priv->mib_buf.type = MIB_LOCAL;
+       priv->mib_buf.size = 1;
+       priv->mib_buf.index = offsetof(struct mib_local, promiscuous_mode);
+       priv->mib_buf.data.byte = priv->promisc ? 1 : 0;
+
+       ret = at76_set_mib(priv, &priv->mib_buf);
+       if (ret < 0)
+               printk(KERN_ERR "%s: set_mib (promiscuous_mode) failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+
+       mutex_unlock(&priv->mtx);
+}
+
+/* Submit Rx urb back to the device */
+static void at76_work_submit_rx(struct work_struct *work)
+{
+       struct at76_priv *priv = container_of(work, struct at76_priv,
+                                             work_submit_rx);
+
+       mutex_lock(&priv->mtx);
+       at76_submit_rx_urb(priv);
+       mutex_unlock(&priv->mtx);
+}
+
+static void at76_rx_tasklet(unsigned long param)
+{
+       struct urb *urb = (struct urb *)param;
+       struct at76_priv *priv = urb->context;
+       struct at76_rx_buffer *buf;
+       struct ieee80211_rx_status rx_status = { 0 };
+
+       if (priv->device_unplugged) {
+               at76_dbg(DBG_DEVSTART, "device unplugged");
+               if (urb)
+                       at76_dbg(DBG_DEVSTART, "urb status %d", urb->status);
+               return;
+       }
+
+       if (!priv->rx_skb || !priv->rx_skb->data)
+               return;
+
+       buf = (struct at76_rx_buffer *)priv->rx_skb->data;
+
+       if (urb->status != 0) {
+               if (urb->status != -ENOENT && urb->status != -ECONNRESET)
+                       at76_dbg(DBG_URB,
+                                "%s %s: - nonzero Rx bulk status received: %d",
+                                __func__, wiphy_name(priv->hw->wiphy),
+                                urb->status);
+               return;
+       }
+
+       at76_dbg(DBG_RX_ATMEL_HDR,
+                "%s: rx frame: rate %d rssi %d noise %d link %d",
+                wiphy_name(priv->hw->wiphy), buf->rx_rate, buf->rssi,
+                buf->noise_level, buf->link_quality);
+
+       skb_pull(priv->rx_skb, AT76_RX_HDRLEN);
+       skb_trim(priv->rx_skb, le16_to_cpu(buf->wlength));
+       at76_dbg_dump(DBG_RX_DATA, priv->rx_skb->data,
+                     priv->rx_skb->len, "RX: len=%d", priv->rx_skb->len);
+
+       rx_status.signal = buf->rssi;
+       rx_status.flag |= RX_FLAG_DECRYPTED;
+       rx_status.flag |= RX_FLAG_IV_STRIPPED;
+
+       at76_dbg(DBG_MAC80211, "calling ieee80211_rx_irqsafe(): %d/%d",
+                priv->rx_skb->len, priv->rx_skb->data_len);
+       ieee80211_rx_irqsafe(priv->hw, priv->rx_skb, &rx_status);
+
+       /* Use a new skb for the next receive */
+       priv->rx_skb = NULL;
+
+       at76_submit_rx_urb(priv);
+}
+
+/* Load firmware into kernel memory and parse it */
+static struct fwentry *at76_load_firmware(struct usb_device *udev,
+                                         enum board_type board_type)
+{
+       int ret;
+       char *str;
+       struct at76_fw_header *fwh;
+       struct fwentry *fwe = &firmwares[board_type];
+
+       mutex_lock(&fw_mutex);
+
+       if (fwe->loaded) {
+               at76_dbg(DBG_FW, "re-using previously loaded fw");
+               goto exit;
+       }
+
+       at76_dbg(DBG_FW, "downloading firmware %s", fwe->fwname);
+       ret = request_firmware(&fwe->fw, fwe->fwname, &udev->dev);
+       if (ret < 0) {
+               dev_printk(KERN_ERR, &udev->dev, "firmware %s not found!\n",
+                          fwe->fwname);
+               dev_printk(KERN_ERR, &udev->dev,
+                          "you may need to download the firmware from "
+                          "http://developer.berlios.de/projects/at76c503a/\n");
+               goto exit;
+       }
+
+       at76_dbg(DBG_FW, "got it.");
+       fwh = (struct at76_fw_header *)(fwe->fw->data);
+
+       if (fwe->fw->size <= sizeof(*fwh)) {
+               dev_printk(KERN_ERR, &udev->dev,
+                          "firmware is too short (0x%zx)\n", fwe->fw->size);
+               goto exit;
+       }
+
+       /* CRC currently not checked */
+       fwe->board_type = le32_to_cpu(fwh->board_type);
+       if (fwe->board_type != board_type) {
+               dev_printk(KERN_ERR, &udev->dev,
+                          "board type mismatch, requested %u, got %u\n",
+                          board_type, fwe->board_type);
+               goto exit;
+       }
+
+       fwe->fw_version.major = fwh->major;
+       fwe->fw_version.minor = fwh->minor;
+       fwe->fw_version.patch = fwh->patch;
+       fwe->fw_version.build = fwh->build;
+
+       str = (char *)fwh + le32_to_cpu(fwh->str_offset);
+       fwe->intfw = (u8 *)fwh + le32_to_cpu(fwh->int_fw_offset);
+       fwe->intfw_size = le32_to_cpu(fwh->int_fw_len);
+       fwe->extfw = (u8 *)fwh + le32_to_cpu(fwh->ext_fw_offset);
+       fwe->extfw_size = le32_to_cpu(fwh->ext_fw_len);
+
+       fwe->loaded = 1;
+
+       dev_printk(KERN_DEBUG, &udev->dev,
+                  "using firmware %s (version %d.%d.%d-%d)\n",
+                  fwe->fwname, fwh->major, fwh->minor, fwh->patch, fwh->build);
+
+       at76_dbg(DBG_DEVSTART, "board %u, int %d:%d, ext %d:%d", board_type,
+                le32_to_cpu(fwh->int_fw_offset), le32_to_cpu(fwh->int_fw_len),
+                le32_to_cpu(fwh->ext_fw_offset), le32_to_cpu(fwh->ext_fw_len));
+       at76_dbg(DBG_DEVSTART, "firmware id %s", str);
+
+exit:
+       mutex_unlock(&fw_mutex);
+
+       if (fwe->loaded)
+               return fwe;
+       else
+               return NULL;
+}
+
+static void at76_mac80211_tx_callback(struct urb *urb)
+{
+       struct at76_priv *priv = urb->context;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(priv->tx_skb);
+
+       at76_dbg(DBG_MAC80211, "%s()", __func__);
+
+       switch (urb->status) {
+       case 0:
+               /* success */
+               info->flags |= IEEE80211_TX_STAT_ACK;
+               break;
+       case -ENOENT:
+       case -ECONNRESET:
+               /* fail, urb has been unlinked */
+               /* FIXME: add error message */
+               break;
+       default:
+               at76_dbg(DBG_URB, "%s - nonzero tx status received: %d",
+                        __func__, urb->status);
+               break;
+       }
+
+       memset(&info->status, 0, sizeof(info->status));
+
+       ieee80211_tx_status_irqsafe(priv->hw, priv->tx_skb);
+
+       priv->tx_skb = NULL;
+
+       ieee80211_wake_queues(priv->hw);
+}
+
+static int at76_mac80211_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+       struct at76_priv *priv = hw->priv;
+       struct at76_tx_buffer *tx_buffer = priv->bulk_out_buffer;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       int padding, submit_len, ret;
+
+       at76_dbg(DBG_MAC80211, "%s()", __func__);
+
+       if (priv->tx_urb->status == -EINPROGRESS) {
+               printk(KERN_ERR "%s: %s called while tx urb is pending\n",
+                      wiphy_name(priv->hw->wiphy), __func__);
+               return NETDEV_TX_BUSY;
+       }
+
+       ieee80211_stop_queues(hw);
+
+       at76_ledtrig_tx_activity();     /* tell ledtrigger we send a packet */
+
+       WARN_ON(priv->tx_skb != NULL);
+
+       priv->tx_skb = skb;
+       padding = at76_calc_padding(skb->len);
+       submit_len = AT76_TX_HDRLEN + skb->len + padding;
+
+       /* setup 'Atmel' header */
+       memset(tx_buffer, 0, sizeof(*tx_buffer));
+       tx_buffer->padding = padding;
+       tx_buffer->wlength = cpu_to_le16(skb->len);
+       tx_buffer->tx_rate = ieee80211_get_tx_rate(hw, info)->hw_value;
+       memset(tx_buffer->reserved, 0, sizeof(tx_buffer->reserved));
+       memcpy(tx_buffer->packet, skb->data, skb->len);
+
+       at76_dbg(DBG_TX_DATA, "%s tx: wlen 0x%x pad 0x%x rate %d hdr",
+                wiphy_name(priv->hw->wiphy), le16_to_cpu(tx_buffer->wlength),
+                tx_buffer->padding, tx_buffer->tx_rate);
+
+       /* send stuff */
+       at76_dbg_dump(DBG_TX_DATA_CONTENT, tx_buffer, submit_len,
+                     "%s(): tx_buffer %d bytes:", __func__, submit_len);
+       usb_fill_bulk_urb(priv->tx_urb, priv->udev, priv->tx_pipe, tx_buffer,
+                         submit_len, at76_mac80211_tx_callback, priv);
+       ret = usb_submit_urb(priv->tx_urb, GFP_ATOMIC);
+       if (ret) {
+               printk(KERN_ERR "%s: error in tx submit urb: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+               if (ret == -EINVAL)
+                       printk(KERN_ERR
+                              "%s: -EINVAL: tx urb %p hcpriv %p complete %p\n",
+                              wiphy_name(priv->hw->wiphy), priv->tx_urb,
+                              priv->tx_urb->hcpriv, priv->tx_urb->complete);
+       }
+
+       return 0;
+}
+
+static int at76_mac80211_start(struct ieee80211_hw *hw)
+{
+       struct at76_priv *priv = hw->priv;
+       int ret;
+
+       at76_dbg(DBG_MAC80211, "%s()", __func__);
+
+       mutex_lock(&priv->mtx);
+
+       ret = at76_submit_rx_urb(priv);
+       if (ret < 0) {
+               printk(KERN_ERR "%s: open: submit_rx_urb failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+               goto error;
+       }
+
+       at76_startup_device(priv);
+
+       at76_start_monitor(priv);
+
+error:
+       mutex_unlock(&priv->mtx);
+
+       return 0;
+}
+
+static void at76_mac80211_stop(struct ieee80211_hw *hw)
+{
+       struct at76_priv *priv = hw->priv;
+
+       at76_dbg(DBG_MAC80211, "%s()", __func__);
+
+       mutex_lock(&priv->mtx);
+
+       if (!priv->device_unplugged) {
+               /* We are called by "ifconfig ethX down", not because the
+                * device is not available anymore. */
+               at76_set_radio(priv, 0);
+
+               /* We unlink rx_urb because at76_open() re-submits it.
+                * If unplugged, at76_delete_device() takes care of it. */
+               usb_kill_urb(priv->rx_urb);
+       }
+
+       mutex_unlock(&priv->mtx);
+}
+
+static int at76_add_interface(struct ieee80211_hw *hw,
+                             struct ieee80211_if_init_conf *conf)
+{
+       struct at76_priv *priv = hw->priv;
+       int ret = 0;
+
+       at76_dbg(DBG_MAC80211, "%s()", __func__);
+
+       mutex_lock(&priv->mtx);
+
+       switch (conf->type) {
+       case NL80211_IFTYPE_STATION:
+               priv->iw_mode = IW_MODE_INFRA;
+               break;
+       default:
+               ret = -EOPNOTSUPP;
+               goto exit;
+       }
+
+exit:
+       mutex_unlock(&priv->mtx);
+
+       return ret;
+}
+
+static void at76_remove_interface(struct ieee80211_hw *hw,
+                                 struct ieee80211_if_init_conf *conf)
+{
+       at76_dbg(DBG_MAC80211, "%s()", __func__);
+}
+
+static int at76_join(struct at76_priv *priv)
+{
+       struct at76_req_join join;
+       int ret;
+
+       memset(&join, 0, sizeof(struct at76_req_join));
+       memcpy(join.essid, priv->essid, priv->essid_size);
+       join.essid_size = priv->essid_size;
+       memcpy(join.bssid, priv->bssid, ETH_ALEN);
+       join.bss_type = INFRASTRUCTURE_MODE;
+       join.channel = priv->channel;
+       join.timeout = cpu_to_le16(2000);
+
+       at76_dbg(DBG_MAC80211, "%s: sending CMD_JOIN", __func__);
+       ret = at76_set_card_command(priv->udev, CMD_JOIN, &join,
+                                   sizeof(struct at76_req_join));
+
+       if (ret < 0) {
+               printk(KERN_ERR "%s: at76_set_card_command failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+               return 0;
+       }
+
+       ret = at76_wait_completion(priv, CMD_JOIN);
+       at76_dbg(DBG_MAC80211, "%s: CMD_JOIN returned: 0x%02x", __func__, ret);
+       if (ret != CMD_STATUS_COMPLETE) {
+               printk(KERN_ERR "%s: at76_wait_completion failed: %d\n",
+                      wiphy_name(priv->hw->wiphy), ret);
+               return 0;
+       }
+
+       at76_set_pm_mode(priv);
+
+       return 0;
+}
+
+static void at76_dwork_hw_scan(struct work_struct *work)
+{
+       struct at76_priv *priv = container_of(work, struct at76_priv,
+                                             dwork_hw_scan.work);
+       int ret;
+
+       if (priv->device_unplugged)
+               return;
+
+       mutex_lock(&priv->mtx);
+
+       ret = at76_get_cmd_status(priv->udev, CMD_SCAN);
+       at76_dbg(DBG_MAC80211, "%s: CMD_SCAN status 0x%02x", __func__, ret);
+
+       /* FIXME: add maximum time for scan to complete */
+
+       if (ret != CMD_STATUS_COMPLETE) {
+               queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan,
+                                  SCAN_POLL_INTERVAL);
+               goto exit;
+       }
+
+       ieee80211_scan_completed(priv->hw, false);
+
+       if (is_valid_ether_addr(priv->bssid))
+               at76_join(priv);
+
+       ieee80211_wake_queues(priv->hw);
+
+exit:
+       mutex_unlock(&priv->mtx);
+}
+
+static int at76_hw_scan(struct ieee80211_hw *hw,
+                       struct cfg80211_scan_request *req)
+{
+       struct at76_priv *priv = hw->priv;
+       struct at76_req_scan scan;
+       u8 *ssid = NULL;
+       int ret, len = 0;
+
+       at76_dbg(DBG_MAC80211, "%s():", __func__);
+
+       if (priv->device_unplugged)
+               return 0;
+
+       mutex_lock(&priv->mtx);
+
+       ieee80211_stop_queues(hw);
+
+       memset(&scan, 0, sizeof(struct at76_req_scan));
+       memset(scan.bssid, 0xFF, ETH_ALEN);
+
+       if (req->n_ssids) {
+               scan.scan_type = SCAN_TYPE_ACTIVE;
+               ssid = req->ssids[0].ssid;
+               len = req->ssids[0].ssid_len;
+       } else {
+               scan.scan_type = SCAN_TYPE_PASSIVE;
+       }
+
+       if (len) {
+               memcpy(scan.essid, ssid, len);
+               scan.essid_size = len;
+       }
+
+       scan.min_channel_time = cpu_to_le16(priv->scan_min_time);
+       scan.max_channel_time = cpu_to_le16(priv->scan_max_time);
+       scan.probe_delay = cpu_to_le16(priv->scan_min_time * 1000);
+       scan.international_scan = 0;
+
+       at76_dbg(DBG_MAC80211, "%s: sending CMD_SCAN", __func__);
+       ret = at76_set_card_command(priv->udev, CMD_SCAN, &scan, sizeof(scan));
+
+       if (ret < 0) {
+               err("CMD_SCAN failed: %d", ret);
+               goto exit;
+       }
+
+       queue_delayed_work(priv->hw->workqueue, &priv->dwork_hw_scan,
+                          SCAN_POLL_INTERVAL);
+
+exit:
+       mutex_unlock(&priv->mtx);
+
+       return 0;
+}
+
+static int at76_config(struct ieee80211_hw *hw, u32 changed)
+{
+       struct at76_priv *priv = hw->priv;
+
+       at76_dbg(DBG_MAC80211, "%s(): channel %d radio %d",
+                __func__, hw->conf.channel->hw_value,
+                hw->conf.radio_enabled);
+       at76_dbg_dump(DBG_MAC80211, priv->bssid, ETH_ALEN, "bssid:");
+
+       mutex_lock(&priv->mtx);
+
+       priv->channel = hw->conf.channel->hw_value;
+
+       if (is_valid_ether_addr(priv->bssid))
+               at76_join(priv);
+       else
+               at76_start_monitor(priv);
+
+       mutex_unlock(&priv->mtx);
+
+       return 0;
+}
+
+static int at76_config_interface(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif,
+                                struct ieee80211_if_conf *conf)
+{
+       struct at76_priv *priv = hw->priv;
+
+       at76_dbg(DBG_MAC80211, "%s():", __func__);
+       at76_dbg_dump(DBG_MAC80211, conf->bssid, ETH_ALEN, "bssid:");
+
+       mutex_lock(&priv->mtx);
+
+       memcpy(priv->bssid, conf->bssid, ETH_ALEN);
+
+       if (is_valid_ether_addr(priv->bssid))
+               /* mac80211 is joining a bss */
+               at76_join(priv);
+
+       mutex_unlock(&priv->mtx);
+
+       return 0;
+}
+
+/* must be atomic */
+static void at76_configure_filter(struct ieee80211_hw *hw,
+                                 unsigned int changed_flags,
+                                 unsigned int *total_flags, int mc_count,
+                                 struct dev_addr_list *mc_list)
+{
+       struct at76_priv *priv = hw->priv;
+       int flags;
+
+       at76_dbg(DBG_MAC80211, "%s(): changed_flags=0x%08x "
+                "total_flags=0x%08x mc_count=%d",
+                __func__, changed_flags, *total_flags, mc_count);
+
+       flags = changed_flags & AT76_SUPPORTED_FILTERS;
+       *total_flags = AT76_SUPPORTED_FILTERS;
+
+       /* Bail out after updating flags to prevent a WARN_ON in mac80211. */
+       if (priv->device_unplugged)
+               return;
+
+       /* FIXME: access to priv->promisc should be protected with
+        * priv->mtx, but it's impossible because this function needs to be
+        * atomic */
+
+       if (flags && !priv->promisc) {
+               /* mac80211 wants us to enable promiscuous mode */
+               priv->promisc = 1;
+       } else if (!flags && priv->promisc) {
+               /* we need to disable promiscuous mode */
+               priv->promisc = 0;
+       } else
+               return;
+
+       queue_work(hw->workqueue, &priv->work_set_promisc);
+}
+
+static int at76_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
+                       struct ieee80211_vif *vif, struct ieee80211_sta *sta,
+                       struct ieee80211_key_conf *key)
+{
+       struct at76_priv *priv = hw->priv;
+
+       int i;
+
+       at76_dbg(DBG_MAC80211, "%s(): cmd %d key->alg %d key->keyidx %d "
+                "key->keylen %d",
+                __func__, cmd, key->alg, key->keyidx, key->keylen);
+
+       if (key->alg != ALG_WEP)
+               return -EOPNOTSUPP;
+
+       key->hw_key_idx = key->keyidx;
+
+       mutex_lock(&priv->mtx);
+
+       switch (cmd) {
+       case SET_KEY:
+               memcpy(priv->wep_keys[key->keyidx], key->key, key->keylen);
+               priv->wep_keys_len[key->keyidx] = key->keylen;
+
+               /* FIXME: find out how to do this properly */
+               priv->wep_key_id = key->keyidx;
+
+               break;
+       case DISABLE_KEY:
+       default:
+               priv->wep_keys_len[key->keyidx] = 0;
+               break;
+       }
+
+       priv->wep_enabled = 0;
+
+       for (i = 0; i < WEP_KEYS; i++) {
+               if (priv->wep_keys_len[i] != 0)
+                       priv->wep_enabled = 1;
+       }
+
+       at76_startup_device(priv);
+
+       mutex_unlock(&priv->mtx);
+
+       return 0;
+}
+
+static const struct ieee80211_ops at76_ops = {
+       .tx = at76_mac80211_tx,
+       .add_interface = at76_add_interface,
+       .remove_interface = at76_remove_interface,
+       .config = at76_config,
+       .config_interface = at76_config_interface,
+       .configure_filter = at76_configure_filter,
+       .start = at76_mac80211_start,
+       .stop = at76_mac80211_stop,
+       .hw_scan = at76_hw_scan,
+       .set_key = at76_set_key,
+};
+
+/* Allocate network device and initialize private data */
+static struct at76_priv *at76_alloc_new_device(struct usb_device *udev)
+{
+       struct ieee80211_hw *hw;
+       struct at76_priv *priv;
+
+       hw = ieee80211_alloc_hw(sizeof(struct at76_priv), &at76_ops);
+       if (!hw) {
+               printk(KERN_ERR DRIVER_NAME ": could not register"
+                      " ieee80211_hw\n");
+               return NULL;
+       }
+
+       priv = hw->priv;
+       priv->hw = hw;
+
+       priv->udev = udev;
+
+       mutex_init(&priv->mtx);
+       INIT_WORK(&priv->work_set_promisc, at76_work_set_promisc);
+       INIT_WORK(&priv->work_submit_rx, at76_work_submit_rx);
+       INIT_DELAYED_WORK(&priv->dwork_hw_scan, at76_dwork_hw_scan);
+
+       tasklet_init(&priv->rx_tasklet, at76_rx_tasklet, 0);
+
+       priv->pm_mode = AT76_PM_OFF;
+       priv->pm_period = 0;
+
+       /* unit us */
+       priv->hw->channel_change_time = 100000;
+
+       return priv;
+}
+
+static int at76_alloc_urbs(struct at76_priv *priv,
+                          struct usb_interface *interface)
+{
+       struct usb_endpoint_descriptor *endpoint, *ep_in, *ep_out;
+       int i;
+       int buffer_size;
+       struct usb_host_interface *iface_desc;
+
+       at76_dbg(DBG_PROC_ENTRY, "%s: ENTER", __func__);
+
+       at76_dbg(DBG_URB, "%s: NumEndpoints %d ", __func__,
+                interface->altsetting[0].desc.bNumEndpoints);
+
+       ep_in = NULL;
+       ep_out = NULL;
+       iface_desc = interface->cur_altsetting;
+       for (i = 0; i < iface_desc->desc.bNumEndpoints; i++) {
+               endpoint = &iface_desc->endpoint[i].desc;
+
+               at76_dbg(DBG_URB, "%s: %d. endpoint: addr 0x%x attr 0x%x",
+                        __func__, i, endpoint->bEndpointAddress,
+                        endpoint->bmAttributes);
+
+               if (!ep_in && usb_endpoint_is_bulk_in(endpoint))
+                       ep_in = endpoint;
+
+               if (!ep_out && usb_endpoint_is_bulk_out(endpoint))
+                       ep_out = endpoint;
+       }
+
+       if (!ep_in || !ep_out) {
+               dev_printk(KERN_ERR, &interface->dev,
+                          "bulk endpoints missing\n");
+               return -ENXIO;
+       }
+
+       priv->rx_pipe = usb_rcvbulkpipe(priv->udev, ep_in->bEndpointAddress);
+       priv->tx_pipe = usb_sndbulkpipe(priv->udev, ep_out->bEndpointAddress);
+
+       priv->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       priv->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
+       if (!priv->rx_urb || !priv->tx_urb) {
+               dev_printk(KERN_ERR, &interface->dev, "cannot allocate URB\n");
+               return -ENOMEM;
+       }
+
+       buffer_size = sizeof(struct at76_tx_buffer) + MAX_PADDING_SIZE;
+       priv->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
+       if (!priv->bulk_out_buffer) {
+               dev_printk(KERN_ERR, &interface->dev,
+                          "cannot allocate output buffer\n");
+               return -ENOMEM;
+       }
+
+       at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __func__);
+
+       return 0;
+}
+
+static struct ieee80211_rate at76_rates[] = {
+       { .bitrate = 10, .hw_value = TX_RATE_1MBIT, },
+       { .bitrate = 20, .hw_value = TX_RATE_2MBIT, },
+       { .bitrate = 55, .hw_value = TX_RATE_5_5MBIT, },
+       { .bitrate = 110, .hw_value = TX_RATE_11MBIT, },
+};
+
+static struct ieee80211_channel at76_channels[] = {
+       { .center_freq = 2412, .hw_value = 1 },
+       { .center_freq = 2417, .hw_value = 2 },
+       { .center_freq = 2422, .hw_value = 3 },
+       { .center_freq = 2427, .hw_value = 4 },
+       { .center_freq = 2432, .hw_value = 5 },
+       { .center_freq = 2437, .hw_value = 6 },
+       { .center_freq = 2442, .hw_value = 7 },
+       { .center_freq = 2447, .hw_value = 8 },
+       { .center_freq = 2452, .hw_value = 9 },
+       { .center_freq = 2457, .hw_value = 10 },
+       { .center_freq = 2462, .hw_value = 11 },
+       { .center_freq = 2467, .hw_value = 12 },
+       { .center_freq = 2472, .hw_value = 13 },
+       { .center_freq = 2484, .hw_value = 14 }
+};
+
+static struct ieee80211_supported_band at76_supported_band = {
+       .channels = at76_channels,
+       .n_channels = ARRAY_SIZE(at76_channels),
+       .bitrates = at76_rates,
+       .n_bitrates = ARRAY_SIZE(at76_rates),
+};
+
+/* Register network device and initialize the hardware */
+static int at76_init_new_device(struct at76_priv *priv,
+                               struct usb_interface *interface)
+{
+       int ret;
+
+       /* set up the endpoint information */
+       /* check out the endpoints */
+
+       at76_dbg(DBG_DEVSTART, "USB interface: %d endpoints",
+                interface->cur_altsetting->desc.bNumEndpoints);
+
+       ret = at76_alloc_urbs(priv, interface);
+       if (ret < 0)
+               goto exit;
+
+       /* MAC address */
+       ret = at76_get_hw_config(priv);
+       if (ret < 0) {
+               dev_printk(KERN_ERR, &interface->dev,
+                          "cannot get MAC address\n");
+               goto exit;
+       }
+
+       priv->domain = at76_get_reg_domain(priv->regulatory_domain);
+
+       priv->channel = DEF_CHANNEL;
+       priv->iw_mode = IW_MODE_INFRA;
+       priv->rts_threshold = DEF_RTS_THRESHOLD;
+       priv->frag_threshold = DEF_FRAG_THRESHOLD;
+       priv->short_retry_limit = DEF_SHORT_RETRY_LIMIT;
+       priv->txrate = TX_RATE_AUTO;
+       priv->preamble_type = PREAMBLE_TYPE_LONG;
+       priv->beacon_period = 100;
+       priv->auth_mode = WLAN_AUTH_OPEN;
+       priv->scan_min_time = DEF_SCAN_MIN_TIME;
+       priv->scan_max_time = DEF_SCAN_MAX_TIME;
+       priv->scan_mode = SCAN_TYPE_ACTIVE;
+       priv->device_unplugged = 0;
+
+       /* mac80211 initialisation */
+       priv->hw->wiphy->max_scan_ssids = 1;
+       priv->hw->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
+       priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &at76_supported_band;
+       priv->hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+                         IEEE80211_HW_SIGNAL_UNSPEC;
+       priv->hw->max_signal = 100;
+
+       SET_IEEE80211_DEV(priv->hw, &interface->dev);
+       SET_IEEE80211_PERM_ADDR(priv->hw, priv->mac_addr);
+
+       ret = ieee80211_register_hw(priv->hw);
+       if (ret) {
+               printk(KERN_ERR "cannot register mac80211 hw (status %d)!\n",
+                      ret);
+               goto exit;
+       }
+
+       priv->mac80211_registered = 1;
+
+       printk(KERN_INFO "%s: USB %s, MAC %s, firmware %d.%d.%d-%d\n",
+              wiphy_name(priv->hw->wiphy),
+              dev_name(&interface->dev), mac2str(priv->mac_addr),
+              priv->fw_version.major, priv->fw_version.minor,
+              priv->fw_version.patch, priv->fw_version.build);
+       printk(KERN_INFO "%s: regulatory domain 0x%02x: %s\n",
+              wiphy_name(priv->hw->wiphy),
+              priv->regulatory_domain, priv->domain->name);
+
+exit:
+       return ret;
+}
+
+static void at76_delete_device(struct at76_priv *priv)
+{
+       at76_dbg(DBG_PROC_ENTRY, "%s: ENTER", __func__);
+
+       /* The device is gone, don't bother turning it off */
+       priv->device_unplugged = 1;
+
+       tasklet_kill(&priv->rx_tasklet);
+
+       if (priv->mac80211_registered) {
+               cancel_delayed_work(&priv->dwork_hw_scan);
+               flush_workqueue(priv->hw->workqueue);
+               ieee80211_unregister_hw(priv->hw);
+       }
+
+       if (priv->tx_urb) {
+               usb_kill_urb(priv->tx_urb);
+               usb_free_urb(priv->tx_urb);
+       }
+       if (priv->rx_urb) {
+               usb_kill_urb(priv->rx_urb);
+               usb_free_urb(priv->rx_urb);
+       }
+
+       at76_dbg(DBG_PROC_ENTRY, "%s: unlinked urbs", __func__);
+
+       kfree(priv->bulk_out_buffer);
+
+       del_timer_sync(&ledtrig_tx_timer);
+
+       if (priv->rx_skb)
+               kfree_skb(priv->rx_skb);
+
+       usb_put_dev(priv->udev);
+
+       at76_dbg(DBG_PROC_ENTRY, "%s: before freeing priv/ieee80211_hw",
+                __func__);
+       ieee80211_free_hw(priv->hw);
+
+       at76_dbg(DBG_PROC_ENTRY, "%s: EXIT", __func__);
+}
+
+static int at76_probe(struct usb_interface *interface,
+                     const struct usb_device_id *id)
+{
+       int ret;
+       struct at76_priv *priv;
+       struct fwentry *fwe;
+       struct usb_device *udev;
+       int op_mode;
+       int need_ext_fw = 0;
+       struct mib_fw_version fwv;
+       int board_type = (int)id->driver_info;
+
+       udev = usb_get_dev(interface_to_usbdev(interface));
+
+       /* Load firmware into kernel memory */
+       fwe = at76_load_firmware(udev, board_type);
+       if (!fwe) {
+               ret = -ENOENT;
+               goto error;
+       }
+
+       op_mode = at76_get_op_mode(udev);
+
+       at76_dbg(DBG_DEVSTART, "opmode %d", op_mode);
+
+       /* we get OPMODE_NONE with 2.4.23, SMC2662W-AR ???
+          we get 204 with 2.4.23, Fiberline FL-WL240u (505A+RFMD2958) ??? */
+
+       if (op_mode == OPMODE_HW_CONFIG_MODE) {
+               dev_printk(KERN_ERR, &interface->dev,
+                          "cannot handle a device in HW_CONFIG_MODE\n");
+               ret = -EBUSY;
+               goto error;
+       }
+
+       if (op_mode != OPMODE_NORMAL_NIC_WITH_FLASH
+           && op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) {
+               /* download internal firmware part */
+               dev_printk(KERN_DEBUG, &interface->dev,
+                          "downloading internal firmware\n");
+               ret = at76_load_internal_fw(udev, fwe);
+               if (ret < 0) {
+                       dev_printk(KERN_ERR, &interface->dev,
+                                  "error %d downloading internal firmware\n",
+                                  ret);
+                       goto error;
+               }
+               usb_put_dev(udev);
+               return ret;
+       }
+
+       /* Internal firmware already inside the device.  Get firmware
+        * version to test if external firmware is loaded.
+        * This works only for newer firmware, e.g. the Intersil 0.90.x
+        * says "control timeout on ep0in" and subsequent
+        * at76_get_op_mode() fail too :-( */
+
+       /* if version >= 0.100.x.y or device with built-in flash we can
+        * query the device for the fw version */
+       if ((fwe->fw_version.major > 0 || fwe->fw_version.minor >= 100)
+           || (op_mode == OPMODE_NORMAL_NIC_WITH_FLASH)) {
+               ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv));
+               if (ret < 0 || (fwv.major | fwv.minor) == 0)
+                       need_ext_fw = 1;
+       } else
+               /* No way to check firmware version, reload to be sure */
+               need_ext_fw = 1;
+
+       if (need_ext_fw) {
+               dev_printk(KERN_DEBUG, &interface->dev,
+                          "downloading external firmware\n");
+
+               ret = at76_load_external_fw(udev, fwe);
+               if (ret)
+                       goto error;
+
+               /* Re-check firmware version */
+               ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv));
+               if (ret < 0) {
+                       dev_printk(KERN_ERR, &interface->dev,
+                                  "error %d getting firmware version\n", ret);
+                       goto error;
+               }
+       }
+
+       priv = at76_alloc_new_device(udev);
+       if (!priv) {
+               ret = -ENOMEM;
+               goto error;
+       }
+
+       usb_set_intfdata(interface, priv);
+
+       memcpy(&priv->fw_version, &fwv, sizeof(struct mib_fw_version));
+       priv->board_type = board_type;
+
+       ret = at76_init_new_device(priv, interface);
+       if (ret < 0)
+               at76_delete_device(priv);
+
+       return ret;
+
+error:
+       usb_put_dev(udev);
+       return ret;
+}
+
+static void at76_disconnect(struct usb_interface *interface)
+{
+       struct at76_priv *priv;
+
+       priv = usb_get_intfdata(interface);
+       usb_set_intfdata(interface, NULL);
+
+       /* Disconnect after loading internal firmware */
+       if (!priv)
+               return;
+
+       printk(KERN_INFO "%s: disconnecting\n", wiphy_name(priv->hw->wiphy));
+       at76_delete_device(priv);
+       dev_printk(KERN_INFO, &interface->dev, "disconnected\n");
+}
+
+/* Structure for registering this driver with the USB subsystem */
+static struct usb_driver at76_driver = {
+       .name = DRIVER_NAME,
+       .probe = at76_probe,
+       .disconnect = at76_disconnect,
+       .id_table = dev_table,
+};
+
+static int __init at76_mod_init(void)
+{
+       int result;
+
+       printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " loading\n");
+
+       mutex_init(&fw_mutex);
+
+       /* register this driver with the USB subsystem */
+       result = usb_register(&at76_driver);
+       if (result < 0)
+               printk(KERN_ERR DRIVER_NAME
+                      ": usb_register failed (status %d)\n", result);
+
+       led_trigger_register_simple("at76_usb-tx", &ledtrig_tx);
+       return result;
+}
+
+static void __exit at76_mod_exit(void)
+{
+       int i;
+
+       printk(KERN_INFO DRIVER_DESC " " DRIVER_VERSION " unloading\n");
+       usb_deregister(&at76_driver);
+       for (i = 0; i < ARRAY_SIZE(firmwares); i++) {
+               if (firmwares[i].fw)
+                       release_firmware(firmwares[i].fw);
+       }
+       led_trigger_unregister_simple(ledtrig_tx);
+}
+
+module_param_named(debug, at76_debug, uint, 0600);
+MODULE_PARM_DESC(debug, "Debugging level");
+
+module_init(at76_mod_init);
+module_exit(at76_mod_exit);
+
+MODULE_AUTHOR("Oliver Kurth <oku@masqmail.cx>");
+MODULE_AUTHOR("Joerg Albert <joerg.albert@gmx.de>");
+MODULE_AUTHOR("Alex <alex@foogod.com>");
+MODULE_AUTHOR("Nick Jones");
+MODULE_AUTHOR("Balint Seeber <n0_5p4m_p13453@hotmail.com>");
+MODULE_AUTHOR("Pavel Roskin <proski@gnu.org>");
+MODULE_AUTHOR("Guido Guenther <agx@sigxcpu.org>");
+MODULE_AUTHOR("Kalle Valo <kalle.valo@iki.fi>");
+MODULE_DESCRIPTION(DRIVER_DESC);
+MODULE_LICENSE("GPL");
diff --git a/drivers/net/wireless/at76c50x-usb.h b/drivers/net/wireless/at76c50x-usb.h
new file mode 100644 (file)
index 0000000..1ec5ccf
--- /dev/null
@@ -0,0 +1,463 @@
+/*
+ * Copyright (c) 2002,2003 Oliver Kurth
+ *          (c) 2003,2004 Joerg Albert <joerg.albert@gmx.de>
+ *          (c) 2007 Guido Guenther <agx@sigxcpu.org>
+ *
+ * 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 driver was based on information from the Sourceforge driver
+ * released and maintained by Atmel:
+ *
+ *  http://sourceforge.net/projects/atmelwlandriver/
+ *
+ * Although the code was completely re-written,
+ * it would have been impossible without Atmel's decision to
+ * release an Open Source driver (unfortunately the firmware was
+ * kept binary only). Thanks for that decision to Atmel!
+ */
+
+#ifndef _AT76_USB_H
+#define _AT76_USB_H
+
+/* Board types */
+enum board_type {
+       BOARD_503_ISL3861 = 1,
+       BOARD_503_ISL3863 = 2,
+       BOARD_503 = 3,
+       BOARD_503_ACC = 4,
+       BOARD_505 = 5,
+       BOARD_505_2958 = 6,
+       BOARD_505A = 7,
+       BOARD_505AMX = 8
+};
+
+#define CMD_STATUS_IDLE                                0x00
+#define CMD_STATUS_COMPLETE                    0x01
+#define CMD_STATUS_UNKNOWN                     0x02
+#define CMD_STATUS_INVALID_PARAMETER           0x03
+#define CMD_STATUS_FUNCTION_NOT_SUPPORTED      0x04
+#define CMD_STATUS_TIME_OUT                    0x07
+#define CMD_STATUS_IN_PROGRESS                 0x08
+#define CMD_STATUS_HOST_FAILURE                        0xff
+#define CMD_STATUS_SCAN_FAILED                 0xf0
+
+/* answers to get op mode */
+#define OPMODE_NONE                            0x00
+#define OPMODE_NORMAL_NIC_WITH_FLASH           0x01
+#define OPMODE_HW_CONFIG_MODE                  0x02
+#define OPMODE_DFU_MODE_WITH_FLASH             0x03
+#define OPMODE_NORMAL_NIC_WITHOUT_FLASH                0x04
+
+#define CMD_SET_MIB            0x01
+#define CMD_GET_MIB            0x02
+#define CMD_SCAN               0x03
+#define CMD_JOIN               0x04
+#define CMD_START_IBSS         0x05
+#define CMD_RADIO_ON           0x06
+#define CMD_RADIO_OFF          0x07
+#define CMD_STARTUP            0x0B
+
+#define MIB_LOCAL              0x01
+#define MIB_MAC_ADDR           0x02
+#define MIB_MAC                        0x03
+#define MIB_MAC_MGMT           0x05
+#define MIB_MAC_WEP            0x06
+#define MIB_PHY                        0x07
+#define MIB_FW_VERSION         0x08
+#define MIB_MDOMAIN            0x09
+
+#define ADHOC_MODE             1
+#define INFRASTRUCTURE_MODE    2
+
+/* values for struct mib_local, field preamble_type */
+#define PREAMBLE_TYPE_LONG     0
+#define PREAMBLE_TYPE_SHORT    1
+#define PREAMBLE_TYPE_AUTO     2
+
+/* values for tx_rate */
+#define TX_RATE_1MBIT          0
+#define TX_RATE_2MBIT          1
+#define TX_RATE_5_5MBIT        2
+#define TX_RATE_11MBIT         3
+#define TX_RATE_AUTO           4
+
+/* power management modes */
+#define AT76_PM_OFF            1
+#define AT76_PM_ON             2
+#define AT76_PM_SMART          3
+
+struct hwcfg_r505 {
+       u8 cr39_values[14];
+       u8 reserved1[14];
+       u8 bb_cr[14];
+       u8 pidvid[4];
+       u8 mac_addr[ETH_ALEN];
+       u8 regulatory_domain;
+       u8 reserved2[14];
+       u8 cr15_values[14];
+       u8 reserved3[3];
+} __attribute__((packed));
+
+struct hwcfg_rfmd {
+       u8 cr20_values[14];
+       u8 cr21_values[14];
+       u8 bb_cr[14];
+       u8 pidvid[4];
+       u8 mac_addr[ETH_ALEN];
+       u8 regulatory_domain;
+       u8 low_power_values[14];
+       u8 normal_power_values[14];
+       u8 reserved1[3];
+} __attribute__((packed));
+
+struct hwcfg_intersil {
+       u8 mac_addr[ETH_ALEN];
+       u8 cr31_values[14];
+       u8 cr58_values[14];
+       u8 pidvid[4];
+       u8 regulatory_domain;
+       u8 reserved[1];
+} __attribute__((packed));
+
+union at76_hwcfg {
+       struct hwcfg_intersil i;
+       struct hwcfg_rfmd r3;
+       struct hwcfg_r505 r5;
+};
+
+#define WEP_SMALL_KEY_LEN      (40 / 8)
+#define WEP_LARGE_KEY_LEN      (104 / 8)
+#define WEP_KEYS               (4)
+
+struct at76_card_config {
+       u8 exclude_unencrypted;
+       u8 promiscuous_mode;
+       u8 short_retry_limit;
+       u8 encryption_type;
+       __le16 rts_threshold;
+       __le16 fragmentation_threshold; /* 256..2346 */
+       u8 basic_rate_set[4];
+       u8 auto_rate_fallback;  /* 0,1 */
+       u8 channel;
+       u8 privacy_invoked;
+       u8 wep_default_key_id;  /* 0..3 */
+       u8 current_ssid[32];
+       u8 wep_default_key_value[4][WEP_LARGE_KEY_LEN];
+       u8 ssid_len;
+       u8 short_preamble;
+       __le16 beacon_period;
+} __attribute__((packed));
+
+struct at76_command {
+       u8 cmd;
+       u8 reserved;
+       __le16 size;
+       u8 data[0];
+} __attribute__((packed));
+
+/* Length of Atmel-specific Rx header before 802.11 frame */
+#define AT76_RX_HDRLEN offsetof(struct at76_rx_buffer, packet)
+
+struct at76_rx_buffer {
+       __le16 wlength;
+       u8 rx_rate;
+       u8 newbss;
+       u8 fragmentation;
+       u8 rssi;
+       u8 link_quality;
+       u8 noise_level;
+       __le32 rx_time;
+       u8 packet[IEEE80211_MAX_FRAG_THRESHOLD];
+} __attribute__((packed));
+
+/* Length of Atmel-specific Tx header before 802.11 frame */
+#define AT76_TX_HDRLEN offsetof(struct at76_tx_buffer, packet)
+
+struct at76_tx_buffer {
+       __le16 wlength;
+       u8 tx_rate;
+       u8 padding;
+       u8 reserved[4];
+       u8 packet[IEEE80211_MAX_FRAG_THRESHOLD];
+} __attribute__((packed));
+
+/* defines for scan_type below */
+#define SCAN_TYPE_ACTIVE       0
+#define SCAN_TYPE_PASSIVE      1
+
+struct at76_req_scan {
+       u8 bssid[ETH_ALEN];
+       u8 essid[32];
+       u8 scan_type;
+       u8 channel;
+       __le16 probe_delay;
+       __le16 min_channel_time;
+       __le16 max_channel_time;
+       u8 essid_size;
+       u8 international_scan;
+} __attribute__((packed));
+
+struct at76_req_ibss {
+       u8 bssid[ETH_ALEN];
+       u8 essid[32];
+       u8 bss_type;
+       u8 channel;
+       u8 essid_size;
+       u8 reserved[3];
+} __attribute__((packed));
+
+struct at76_req_join {
+       u8 bssid[ETH_ALEN];
+       u8 essid[32];
+       u8 bss_type;
+       u8 channel;
+       __le16 timeout;
+       u8 essid_size;
+       u8 reserved;
+} __attribute__((packed));
+
+struct set_mib_buffer {
+       u8 type;
+       u8 size;
+       u8 index;
+       u8 reserved;
+       union {
+               u8 byte;
+               __le16 word;
+               u8 addr[ETH_ALEN];
+       } data;
+} __attribute__((packed));
+
+struct mib_local {
+       u16 reserved0;
+       u8 beacon_enable;
+       u8 txautorate_fallback;
+       u8 reserved1;
+       u8 ssid_size;
+       u8 promiscuous_mode;
+       u16 reserved2;
+       u8 preamble_type;
+       u16 reserved3;
+} __attribute__((packed));
+
+struct mib_mac_addr {
+       u8 mac_addr[ETH_ALEN];
+       u8 res[2];              /* ??? */
+       u8 group_addr[4][ETH_ALEN];
+       u8 group_addr_status[4];
+} __attribute__((packed));
+
+struct mib_mac {
+       __le32 max_tx_msdu_lifetime;
+       __le32 max_rx_lifetime;
+       __le16 frag_threshold;
+       __le16 rts_threshold;
+       __le16 cwmin;
+       __le16 cwmax;
+       u8 short_retry_time;
+       u8 long_retry_time;
+       u8 scan_type;           /* active or passive */
+       u8 scan_channel;
+       __le16 probe_delay;     /* delay before ProbeReq in active scan, RO */
+       __le16 min_channel_time;
+       __le16 max_channel_time;
+       __le16 listen_interval;
+       u8 desired_ssid[32];
+       u8 desired_bssid[ETH_ALEN];
+       u8 desired_bsstype;     /* ad-hoc or infrastructure */
+       u8 reserved2;
+} __attribute__((packed));
+
+struct mib_mac_mgmt {
+       __le16 beacon_period;
+       __le16 CFP_max_duration;
+       __le16 medium_occupancy_limit;
+       __le16 station_id;      /* assoc id */
+       __le16 ATIM_window;
+       u8 CFP_mode;
+       u8 privacy_option_implemented;
+       u8 DTIM_period;
+       u8 CFP_period;
+       u8 current_bssid[ETH_ALEN];
+       u8 current_essid[32];
+       u8 current_bss_type;
+       u8 power_mgmt_mode;
+       /* rfmd and 505 */
+       u8 ibss_change;
+       u8 res;
+       u8 multi_domain_capability_implemented;
+       u8 multi_domain_capability_enabled;
+       u8 country_string[3];
+       u8 reserved[3];
+} __attribute__((packed));
+
+struct mib_mac_wep {
+       u8 privacy_invoked;     /* 0 disable encr., 1 enable encr */
+       u8 wep_default_key_id;
+       u8 wep_key_mapping_len;
+       u8 exclude_unencrypted;
+       __le32 wep_icv_error_count;
+       __le32 wep_excluded_count;
+       u8 wep_default_keyvalue[WEP_KEYS][WEP_LARGE_KEY_LEN];
+       u8 encryption_level;    /* 1 for 40bit, 2 for 104bit encryption */
+} __attribute__((packed));
+
+struct mib_phy {
+       __le32 ed_threshold;
+
+       __le16 slot_time;
+       __le16 sifs_time;
+       __le16 preamble_length;
+       __le16 plcp_header_length;
+       __le16 mpdu_max_length;
+       __le16 cca_mode_supported;
+
+       u8 operation_rate_set[4];
+       u8 channel_id;
+       u8 current_cca_mode;
+       u8 phy_type;
+       u8 current_reg_domain;
+} __attribute__((packed));
+
+struct mib_fw_version {
+       u8 major;
+       u8 minor;
+       u8 patch;
+       u8 build;
+} __attribute__((packed));
+
+struct mib_mdomain {
+       u8 tx_powerlevel[14];
+       u8 channel_list[14];    /* 0 for invalid channels */
+} __attribute__((packed));
+
+struct at76_fw_header {
+       __le32 crc;             /* CRC32 of the whole image */
+       __le32 board_type;      /* firmware compatibility code */
+       u8 build;               /* firmware build number */
+       u8 patch;               /* firmware patch level */
+       u8 minor;               /* firmware minor version */
+       u8 major;               /* firmware major version */
+       __le32 str_offset;      /* offset of the copyright string */
+       __le32 int_fw_offset;   /* internal firmware image offset */
+       __le32 int_fw_len;      /* internal firmware image length */
+       __le32 ext_fw_offset;   /* external firmware image offset */
+       __le32 ext_fw_len;      /* external firmware image length */
+} __attribute__((packed));
+
+/* a description of a regulatory domain and the allowed channels */
+struct reg_domain {
+       u16 code;
+       char const *name;
+       u32 channel_map;        /* if bit N is set, channel (N+1) is allowed */
+};
+
+/* Data for one loaded firmware file */
+struct fwentry {
+       const char *const fwname;
+       const struct firmware *fw;
+       int extfw_size;
+       int intfw_size;
+       /* pointer to loaded firmware, no need to free */
+       u8 *extfw;              /* external firmware, extfw_size bytes long */
+       u8 *intfw;              /* internal firmware, intfw_size bytes long */
+       enum board_type board_type;     /* board type */
+       struct mib_fw_version fw_version;
+       int loaded;             /* Loaded and parsed successfully */
+};
+
+struct at76_priv {
+       struct usb_device *udev;        /* USB device pointer */
+
+       struct sk_buff *rx_skb; /* skbuff for receiving data */
+       struct sk_buff *tx_skb; /* skbuff for transmitting data */
+       void *bulk_out_buffer;  /* buffer for sending data */
+
+       struct urb *tx_urb;     /* URB for sending data */
+       struct urb *rx_urb;     /* URB for receiving data */
+
+       unsigned int tx_pipe;   /* bulk out pipe */
+       unsigned int rx_pipe;   /* bulk in pipe */
+
+       struct mutex mtx;       /* locks this structure */
+
+       /* work queues */
+       struct work_struct work_set_promisc;
+       struct work_struct work_submit_rx;
+       struct delayed_work dwork_hw_scan;
+
+       struct tasklet_struct rx_tasklet;
+
+       /* the WEP stuff */
+       int wep_enabled;        /* 1 if WEP is enabled */
+       int wep_key_id;         /* key id to be used */
+       u8 wep_keys[WEP_KEYS][WEP_LARGE_KEY_LEN];       /* WEP keys */
+       u8 wep_keys_len[WEP_KEYS];      /* length of WEP keys */
+
+       int channel;
+       int iw_mode;
+       u8 bssid[ETH_ALEN];
+       u8 essid[IW_ESSID_MAX_SIZE];
+       int essid_size;
+       int radio_on;
+       int promisc;
+
+       int preamble_type;      /* 0 - long, 1 - short, 2 - auto */
+       int auth_mode;          /* authentication type: 0 open, 1 shared key */
+       int txrate;             /* 0,1,2,3 = 1,2,5.5,11 Mbps, 4 is auto */
+       int frag_threshold;     /* threshold for fragmentation of tx packets */
+       int rts_threshold;      /* threshold for RTS mechanism */
+       int short_retry_limit;
+
+       int scan_min_time;      /* scan min channel time */
+       int scan_max_time;      /* scan max channel time */
+       int scan_mode;          /* SCAN_TYPE_ACTIVE, SCAN_TYPE_PASSIVE */
+       int scan_need_any;      /* if set, need to scan for any ESSID */
+
+       u16 assoc_id;           /* current association ID, if associated */
+
+       u8 pm_mode;             /* power management mode */
+       u32 pm_period;          /* power management period in microseconds */
+
+       struct reg_domain const *domain;        /* reg domain description */
+
+       /* These fields contain HW config provided by the device (not all of
+        * these fields are used by all board types) */
+       u8 mac_addr[ETH_ALEN];
+       u8 regulatory_domain;
+
+       struct at76_card_config card_config;
+
+       enum board_type board_type;
+       struct mib_fw_version fw_version;
+
+       unsigned int device_unplugged:1;
+       unsigned int netdev_registered:1;
+       struct set_mib_buffer mib_buf;  /* global buffer for set_mib calls */
+
+       int beacon_period;      /* period of mgmt beacons, Kus */
+
+       struct ieee80211_hw *hw;
+       int mac80211_registered;
+};
+
+#define AT76_SUPPORTED_FILTERS FIF_PROMISC_IN_BSS
+
+#define SCAN_POLL_INTERVAL     (HZ / 4)
+
+#define CMD_COMPLETION_TIMEOUT (5 * HZ)
+
+#define DEF_RTS_THRESHOLD      1536
+#define DEF_FRAG_THRESHOLD     1536
+#define DEF_SHORT_RETRY_LIMIT  8
+#define DEF_CHANNEL            10
+#define DEF_SCAN_MIN_TIME      10
+#define DEF_SCAN_MAX_TIME      120
+
+/* the max padding size for tx in bytes (see calc_padding) */
+#define MAX_PADDING_SIZE       53
+
+#endif                         /* _AT76_USB_H */
index 719cfaef7085a29d312be491a0f12435f2d4871a..84a74c5248e545abdab2fac86b9b5d3cebfef7c9 100644 (file)
@@ -10,5 +10,6 @@ ath5k-y                               += phy.o
 ath5k-y                                += reset.o
 ath5k-y                                += attach.o
 ath5k-y                                += base.o
+ath5k-y                                += led.o
 ath5k-$(CONFIG_ATH5K_DEBUG)    += debug.o
 obj-$(CONFIG_ATH5K)            += ath5k.o
index b9af2b84c05f4bbe4810285aaca3ea6a5f81d0b8..0dc2c7321c8b69c6a45f79b607459f17b2ff47c7 100644 (file)
@@ -1129,6 +1129,12 @@ struct ath5k_hw {
 extern struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version);
 extern void ath5k_hw_detach(struct ath5k_hw *ah);
 
+/* LED functions */
+extern int ath5k_init_leds(struct ath5k_softc *sc);
+extern void ath5k_led_enable(struct ath5k_softc *sc);
+extern void ath5k_led_off(struct ath5k_softc *sc);
+extern void ath5k_unregister_leds(struct ath5k_softc *sc);
+
 /* Reset Functions */
 extern int ath5k_hw_nic_wakeup(struct ath5k_hw *ah, int flags, bool initial);
 extern int ath5k_hw_reset(struct ath5k_hw *ah, enum nl80211_iftype op_mode, struct ieee80211_channel *channel, bool change_channel);
index 05bc5cb44e881d3080b593ca864becffc24908d2..656cb9dc833b8690d99170b0e9ca35accb17098a 100644 (file)
 static int ath5k_hw_post(struct ath5k_hw *ah)
 {
 
-       int i, c;
-       u16 cur_reg;
-       u16 regs[2] = {AR5K_STA_ID0, AR5K_PHY(8)};
-       u32 var_pattern;
-       u32 static_pattern[4] = {
+       static const u32 static_pattern[4] = {
                0x55555555,     0xaaaaaaaa,
                0x66666666,     0x99999999
        };
+       static const u16 regs[2] = { AR5K_STA_ID0, AR5K_PHY(8) };
+       int i, c;
+       u16 cur_reg;
+       u32 var_pattern;
        u32 init_val;
        u32 cur_val;
 
@@ -106,7 +106,6 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
 {
        struct ath5k_hw *ah;
        struct pci_dev *pdev = sc->pdev;
-       u8 mac[ETH_ALEN] = {};
        int ret;
        u32 srev;
 
@@ -312,7 +311,7 @@ struct ath5k_hw *ath5k_hw_attach(struct ath5k_softc *sc, u8 mac_version)
        }
 
        /* MAC address is cleared until add_interface */
-       ath5k_hw_set_lladdr(ah, mac);
+       ath5k_hw_set_lladdr(ah, (u8[ETH_ALEN]){});
 
        /* Set BSSID to bcast address: ff:ff:ff:ff:ff:ff for now */
        memset(ah->ah_bssid, 0xff, ETH_ALEN);
index 6837ca9f3831ab3bc2af2859a8687eddc1c6cf02..cad3ccf61b00b378535122f880f635d28045419b 100644 (file)
@@ -79,7 +79,7 @@ MODULE_VERSION("0.6.0 (EXPERIMENTAL)");
 
 
 /* Known PCI ids */
-static struct pci_device_id ath5k_pci_id_table[] __devinitdata = {
+static const struct pci_device_id ath5k_pci_id_table[] = {
        { PCI_VDEVICE(ATHEROS, 0x0207), .driver_data = AR5K_AR5210 }, /* 5210 early */
        { PCI_VDEVICE(ATHEROS, 0x0007), .driver_data = AR5K_AR5210 }, /* 5210 */
        { PCI_VDEVICE(ATHEROS, 0x0011), .driver_data = AR5K_AR5211 }, /* 5311 - this is on AHB bus !*/
@@ -103,7 +103,7 @@ static struct pci_device_id ath5k_pci_id_table[] __devinitdata = {
 MODULE_DEVICE_TABLE(pci, ath5k_pci_id_table);
 
 /* Known SREVs */
-static struct ath5k_srev_name srev_names[] = {
+static const struct ath5k_srev_name srev_names[] = {
        { "5210",       AR5K_VERSION_MAC,       AR5K_SREV_AR5210 },
        { "5311",       AR5K_VERSION_MAC,       AR5K_SREV_AR5311 },
        { "5311A",      AR5K_VERSION_MAC,       AR5K_SREV_AR5311A },
@@ -142,7 +142,7 @@ static struct ath5k_srev_name srev_names[] = {
        { "xxxxx",      AR5K_VERSION_RAD,       AR5K_SREV_UNKNOWN },
 };
 
-static struct ieee80211_rate ath5k_rates[] = {
+static const struct ieee80211_rate ath5k_rates[] = {
        { .bitrate = 10,
          .hw_value = ATH5K_RATE_CODE_1M, },
        { .bitrate = 20,
@@ -248,7 +248,7 @@ static void ath5k_bss_info_changed(struct ieee80211_hw *hw,
                struct ieee80211_bss_conf *bss_conf,
                u32 changes);
 
-static struct ieee80211_ops ath5k_hw_ops = {
+static const struct ieee80211_ops ath5k_hw_ops = {
        .tx             = ath5k_tx,
        .start          = ath5k_start,
        .stop           = ath5k_stop,
@@ -350,6 +350,7 @@ static int  ath5k_beacon_setup(struct ath5k_softc *sc,
 static void    ath5k_beacon_send(struct ath5k_softc *sc);
 static void    ath5k_beacon_config(struct ath5k_softc *sc);
 static void    ath5k_beacon_update_timers(struct ath5k_softc *sc, u64 bc_tsf);
+static void    ath5k_tasklet_beacon(unsigned long data);
 
 static inline u64 ath5k_extend_tsf(struct ath5k_hw *ah, u32 rstamp)
 {
@@ -369,11 +370,6 @@ static irqreturn_t ath5k_intr(int irq, void *dev_id);
 static void    ath5k_tasklet_reset(unsigned long data);
 
 static void    ath5k_calibrate(unsigned long data);
-/* LED functions */
-static int     ath5k_init_leds(struct ath5k_softc *sc);
-static void    ath5k_led_enable(struct ath5k_softc *sc);
-static void    ath5k_led_off(struct ath5k_softc *sc);
-static void    ath5k_unregister_leds(struct ath5k_softc *sc);
 
 /*
  * Module init/exit functions
@@ -789,6 +785,7 @@ ath5k_attach(struct pci_dev *pdev, struct ieee80211_hw *hw)
        tasklet_init(&sc->rxtq, ath5k_tasklet_rx, (unsigned long)sc);
        tasklet_init(&sc->txtq, ath5k_tasklet_tx, (unsigned long)sc);
        tasklet_init(&sc->restq, ath5k_tasklet_reset, (unsigned long)sc);
+       tasklet_init(&sc->beacontq, ath5k_tasklet_beacon, (unsigned long)sc);
        setup_timer(&sc->calib_tim, ath5k_calibrate, (unsigned long)sc);
 
        ret = ath5k_eeprom_read_mac(ah, mac);
@@ -1098,7 +1095,8 @@ ath5k_mode_setup(struct ath5k_softc *sc)
 static inline int
 ath5k_hw_to_driver_rix(struct ath5k_softc *sc, int hw_rix)
 {
-       WARN_ON(hw_rix < 0 || hw_rix > AR5K_MAX_RATES);
+       WARN(hw_rix < 0 || hw_rix >= AR5K_MAX_RATES,
+                       "hw_rix out of bounds: %x\n", hw_rix);
        return sc->rate_idx[sc->curband->band][hw_rix];
 }
 
@@ -1218,6 +1216,10 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
 
        pktlen = skb->len;
 
+       if (info->control.hw_key) {
+               keyidx = info->control.hw_key->hw_key_idx;
+               pktlen += info->control.hw_key->icv_len;
+       }
        if (rc_flags & IEEE80211_TX_RC_USE_RTS_CTS) {
                flags |= AR5K_TXDESC_RTSENA;
                cts_rate = ieee80211_get_rts_cts_rate(sc->hw, info)->hw_value;
@@ -1230,11 +1232,6 @@ ath5k_txbuf_setup(struct ath5k_softc *sc, struct ath5k_buf *bf)
                duration = le16_to_cpu(ieee80211_ctstoself_duration(sc->hw,
                        sc->vif, pktlen, info));
        }
-
-       if (info->control.hw_key) {
-               keyidx = info->control.hw_key->hw_key_idx;
-               pktlen += info->control.hw_key->icv_len;
-       }
        ret = ah->ah_setup_tx_desc(ah, ds, pktlen,
                ieee80211_get_hdrlen_from_skb(skb), AR5K_PKT_TYPE_NORMAL,
                (sc->power_level * 2),
@@ -1700,6 +1697,34 @@ ath5k_check_ibss_tsf(struct ath5k_softc *sc, struct sk_buff *skb,
        }
 }
 
+static void ath5k_tasklet_beacon(unsigned long data)
+{
+       struct ath5k_softc *sc = (struct ath5k_softc *) data;
+
+       /*
+        * Software beacon alert--time to send a beacon.
+        *
+        * In IBSS mode we use this interrupt just to
+        * keep track of the next TBTT (target beacon
+        * transmission time) in order to detect wether
+        * automatic TSF updates happened.
+        */
+       if (sc->opmode == NL80211_IFTYPE_ADHOC) {
+               /* XXX: only if VEOL suppported */
+               u64 tsf = ath5k_hw_get_tsf64(sc->ah);
+               sc->nexttbtt += sc->bintval;
+               ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
+                               "SWBA nexttbtt: %x hw_tu: %x "
+                               "TSF: %llx\n",
+                               sc->nexttbtt,
+                               TSF_TO_TU(tsf),
+                               (unsigned long long) tsf);
+       } else {
+               spin_lock(&sc->block);
+               ath5k_beacon_send(sc);
+               spin_unlock(&sc->block);
+       }
+}
 
 static void
 ath5k_tasklet_rx(unsigned long data)
@@ -2040,9 +2065,8 @@ err_unmap:
  * frame contents are done as needed and the slot time is
  * also adjusted based on current state.
  *
- * this is usually called from interrupt context (ath5k_intr())
- * but also from ath5k_beacon_config() in IBSS mode which in turn
- * can be called from a tasklet and user context
+ * This is called from software irq context (beacontq or restq
+ * tasklets) or user context from ath5k_beacon_config.
  */
 static void
 ath5k_beacon_send(struct ath5k_softc *sc)
@@ -2216,6 +2240,7 @@ static void
 ath5k_beacon_config(struct ath5k_softc *sc)
 {
        struct ath5k_hw *ah = sc->ah;
+       unsigned long flags;
 
        ath5k_hw_set_imr(ah, 0);
        sc->bmisscount = 0;
@@ -2237,9 +2262,9 @@ ath5k_beacon_config(struct ath5k_softc *sc)
 
                if (sc->opmode == NL80211_IFTYPE_ADHOC) {
                        if (ath5k_hw_hasveol(ah)) {
-                               spin_lock(&sc->block);
+                               spin_lock_irqsave(&sc->block, flags);
                                ath5k_beacon_send(sc);
-                               spin_unlock(&sc->block);
+                               spin_unlock_irqrestore(&sc->block, flags);
                        }
                } else
                        ath5k_beacon_update_timers(sc, -1);
@@ -2391,6 +2416,7 @@ ath5k_stop_hw(struct ath5k_softc *sc)
        tasklet_kill(&sc->rxtq);
        tasklet_kill(&sc->txtq);
        tasklet_kill(&sc->restq);
+       tasklet_kill(&sc->beacontq);
 
        return ret;
 }
@@ -2408,16 +2434,9 @@ ath5k_intr(int irq, void *dev_id)
                return IRQ_NONE;
 
        do {
-               /*
-                * Figure out the reason(s) for the interrupt.  Note
-                * that get_isr returns a pseudo-ISR that may include
-                * bits we haven't explicitly enabled so we mask the
-                * value to insure we only process bits we requested.
-                */
                ath5k_hw_get_isr(ah, &status);          /* NB: clears IRQ too */
                ATH5K_DBG(sc, ATH5K_DEBUG_INTR, "status 0x%x/0x%x\n",
                                status, sc->imask);
-               status &= sc->imask; /* discard unasked for bits */
                if (unlikely(status & AR5K_INT_FATAL)) {
                        /*
                         * Fatal errors are unrecoverable.
@@ -2428,32 +2447,7 @@ ath5k_intr(int irq, void *dev_id)
                        tasklet_schedule(&sc->restq);
                } else {
                        if (status & AR5K_INT_SWBA) {
-                               /*
-                               * Software beacon alert--time to send a beacon.
-                               * Handle beacon transmission directly; deferring
-                               * this is too slow to meet timing constraints
-                               * under load.
-                               *
-                               * In IBSS mode we use this interrupt just to
-                               * keep track of the next TBTT (target beacon
-                               * transmission time) in order to detect wether
-                               * automatic TSF updates happened.
-                               */
-                               if (sc->opmode == NL80211_IFTYPE_ADHOC) {
-                                        /* XXX: only if VEOL suppported */
-                                       u64 tsf = ath5k_hw_get_tsf64(ah);
-                                       sc->nexttbtt += sc->bintval;
-                                       ATH5K_DBG(sc, ATH5K_DEBUG_BEACON,
-                                                 "SWBA nexttbtt: %x hw_tu: %x "
-                                                 "TSF: %llx\n",
-                                                 sc->nexttbtt,
-                                                 TSF_TO_TU(tsf),
-                                                 (unsigned long long) tsf);
-                               } else {
-                                       spin_lock(&sc->block);
-                                       ath5k_beacon_send(sc);
-                                       spin_unlock(&sc->block);
-                               }
+                               tasklet_schedule(&sc->beacontq);
                        }
                        if (status & AR5K_INT_RXEOL) {
                                /*
@@ -2531,141 +2525,6 @@ ath5k_calibrate(unsigned long data)
 }
 
 
-
-/***************\
-* LED functions *
-\***************/
-
-static void
-ath5k_led_enable(struct ath5k_softc *sc)
-{
-       if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
-               ath5k_hw_set_gpio_output(sc->ah, sc->led_pin);
-               ath5k_led_off(sc);
-       }
-}
-
-static void
-ath5k_led_on(struct ath5k_softc *sc)
-{
-       if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
-               return;
-       ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on);
-}
-
-static void
-ath5k_led_off(struct ath5k_softc *sc)
-{
-       if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
-               return;
-       ath5k_hw_set_gpio(sc->ah, sc->led_pin, !sc->led_on);
-}
-
-static void
-ath5k_led_brightness_set(struct led_classdev *led_dev,
-       enum led_brightness brightness)
-{
-       struct ath5k_led *led = container_of(led_dev, struct ath5k_led,
-               led_dev);
-
-       if (brightness == LED_OFF)
-               ath5k_led_off(led->sc);
-       else
-               ath5k_led_on(led->sc);
-}
-
-static int
-ath5k_register_led(struct ath5k_softc *sc, struct ath5k_led *led,
-                  const char *name, char *trigger)
-{
-       int err;
-
-       led->sc = sc;
-       strncpy(led->name, name, sizeof(led->name));
-       led->led_dev.name = led->name;
-       led->led_dev.default_trigger = trigger;
-       led->led_dev.brightness_set = ath5k_led_brightness_set;
-
-       err = led_classdev_register(&sc->pdev->dev, &led->led_dev);
-       if (err) {
-               ATH5K_WARN(sc, "could not register LED %s\n", name);
-               led->sc = NULL;
-       }
-       return err;
-}
-
-static void
-ath5k_unregister_led(struct ath5k_led *led)
-{
-       if (!led->sc)
-               return;
-       led_classdev_unregister(&led->led_dev);
-       ath5k_led_off(led->sc);
-       led->sc = NULL;
-}
-
-static void
-ath5k_unregister_leds(struct ath5k_softc *sc)
-{
-       ath5k_unregister_led(&sc->rx_led);
-       ath5k_unregister_led(&sc->tx_led);
-}
-
-
-static int
-ath5k_init_leds(struct ath5k_softc *sc)
-{
-       int ret = 0;
-       struct ieee80211_hw *hw = sc->hw;
-       struct pci_dev *pdev = sc->pdev;
-       char name[ATH5K_LED_MAX_NAME_LEN + 1];
-
-       /*
-        * Auto-enable soft led processing for IBM cards and for
-        * 5211 minipci cards.
-        */
-       if (pdev->device == PCI_DEVICE_ID_ATHEROS_AR5212_IBM ||
-           pdev->device == PCI_DEVICE_ID_ATHEROS_AR5211) {
-               __set_bit(ATH_STAT_LEDSOFT, sc->status);
-               sc->led_pin = 0;
-               sc->led_on = 0;  /* active low */
-       }
-       /* Enable softled on PIN1 on HP Compaq nc6xx, nc4000 & nx5000 laptops */
-       if (pdev->subsystem_vendor == PCI_VENDOR_ID_COMPAQ) {
-               __set_bit(ATH_STAT_LEDSOFT, sc->status);
-               sc->led_pin = 1;
-               sc->led_on = 1;  /* active high */
-       }
-       /*
-        * Pin 3 on Foxconn chips used in Acer Aspire One (0x105b:e008) and
-        * in emachines notebooks with AMBIT subsystem.
-        */
-       if (pdev->subsystem_vendor == PCI_VENDOR_ID_FOXCONN ||
-           pdev->subsystem_vendor == PCI_VENDOR_ID_AMBIT) {
-               __set_bit(ATH_STAT_LEDSOFT, sc->status);
-               sc->led_pin = 3;
-               sc->led_on = 0;  /* active low */
-       }
-
-       if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
-               goto out;
-
-       ath5k_led_enable(sc);
-
-       snprintf(name, sizeof(name), "ath5k-%s::rx", wiphy_name(hw->wiphy));
-       ret = ath5k_register_led(sc, &sc->rx_led, name,
-               ieee80211_get_rx_led_name(hw));
-       if (ret)
-               goto out;
-
-       snprintf(name, sizeof(name), "ath5k-%s::tx", wiphy_name(hw->wiphy));
-       ret = ath5k_register_led(sc, &sc->tx_led, name,
-               ieee80211_get_tx_led_name(hw));
-out:
-       return ret;
-}
-
-
 /********************\
 * Mac80211 functions *
 \********************/
index c0fb8b5c42fe75d783aac07fa9551658728a82ab..20e0d14b41eca221710c9fc6fa981c239f31c5f4 100644 (file)
@@ -169,6 +169,7 @@ struct ath5k_softc {
        struct ath5k_led        tx_led;         /* tx led */
 
        spinlock_t              block;          /* protects beacon */
+       struct tasklet_struct   beacontq;       /* beacon intr tasklet */
        struct ath5k_buf        *bbuf;          /* beacon buffer */
        unsigned int            bhalq,          /* SW q for outgoing beacons */
                                bmisscount,     /* missed beacon transmits */
index 413ed689cd5fe177527bae6414b8ac7a23ac5740..9770bb3d40f997a75b256d40785b85c6d61fcc6d 100644 (file)
@@ -82,14 +82,14 @@ static int ath5k_debugfs_open(struct inode *inode, struct file *file)
 /* debugfs: registers */
 
 struct reg {
-       char *name;
+       const char *name;
        int addr;
 };
 
 #define REG_STRUCT_INIT(r) { #r, r }
 
 /* just a few random registers, might want to add more */
-static struct reg regs[] = {
+static const struct reg regs[] = {
        REG_STRUCT_INIT(AR5K_CR),
        REG_STRUCT_INIT(AR5K_RXDP),
        REG_STRUCT_INIT(AR5K_CFG),
@@ -142,7 +142,7 @@ static struct reg regs[] = {
 
 static void *reg_start(struct seq_file *seq, loff_t *pos)
 {
-       return *pos < ARRAY_SIZE(regs) ? &regs[*pos] : NULL;
+       return *pos < ARRAY_SIZE(regs) ? (void *)&regs[*pos] : NULL;
 }
 
 static void reg_stop(struct seq_file *seq, void *p)
@@ -153,7 +153,7 @@ static void reg_stop(struct seq_file *seq, void *p)
 static void *reg_next(struct seq_file *seq, void *p, loff_t *pos)
 {
        ++*pos;
-       return *pos < ARRAY_SIZE(regs) ? &regs[*pos] : NULL;
+       return *pos < ARRAY_SIZE(regs) ? (void *)&regs[*pos] : NULL;
 }
 
 static int reg_show(struct seq_file *seq, void *p)
@@ -290,7 +290,7 @@ static const struct file_operations fops_reset = {
 
 /* debugfs: debug level */
 
-static struct {
+static const struct {
        enum ath5k_debug_level level;
        const char *name;
        const char *desc;
index a54ee7e4967b7b042575049f8058afb3309a919f..ac45ca47ca87fa483850d0295dd4a3a73b1eaa96 100644 (file)
@@ -1418,14 +1418,11 @@ ath5k_eeprom_init(struct ath5k_hw *ah)
  */
 int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
 {
-       u8 mac_d[ETH_ALEN];
+       u8 mac_d[ETH_ALEN] = {};
        u32 total, offset;
        u16 data;
        int octet, ret;
 
-       memset(mac, 0, ETH_ALEN);
-       memset(mac_d, 0, ETH_ALEN);
-
        ret = ath5k_hw_eeprom_read(ah, 0x20, &data);
        if (ret)
                return ret;
@@ -1441,11 +1438,11 @@ int ath5k_eeprom_read_mac(struct ath5k_hw *ah, u8 *mac)
                octet += 2;
        }
 
-       memcpy(mac, mac_d, ETH_ALEN);
-
        if (!total || total == 3 * 0xffff)
                return -EINVAL;
 
+       memcpy(mac, mac_d, ETH_ALEN);
+
        return 0;
 }
 
diff --git a/drivers/net/wireless/ath5k/led.c b/drivers/net/wireless/ath5k/led.c
new file mode 100644 (file)
index 0000000..0686e12
--- /dev/null
@@ -0,0 +1,174 @@
+/*
+ * Copyright (c) 2002-2005 Sam Leffler, Errno Consulting
+ * Copyright (c) 2004-2005 Atheros Communications, Inc.
+ * Copyright (c) 2007 Jiri Slaby <jirislaby@gmail.com>
+ * Copyright (c) 2009 Bob Copeland <me@bobcopeland.com>
+ *
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer,
+ *    without modification.
+ * 2. Redistributions in binary form must reproduce at minimum a disclaimer
+ *    similar to the "NO WARRANTY" disclaimer below ("Disclaimer") and any
+ *    redistribution must be conditioned upon including a substantially
+ *    similar Disclaimer requirement for further binary redistribution.
+ * 3. Neither the names of the above-listed copyright holders nor the names
+ *    of any contributors may be used to endorse or promote products derived
+ *    from this software without specific prior written permission.
+ *
+ * Alternatively, this software may be distributed under the terms of the
+ * GNU General Public License ("GPL") version 2 as published by the Free
+ * Software Foundation.
+ *
+ * NO WARRANTY
+ * 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 NONINFRINGEMENT, MERCHANTIBILITY
+ * AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * THE COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR 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 DAMAGES.
+ *
+ */
+
+#include <linux/pci.h>
+#include "ath5k.h"
+#include "base.h"
+
+#define ATH_SDEVICE(subv,subd) \
+       .vendor = PCI_ANY_ID, .device = PCI_ANY_ID, \
+       .subvendor = (subv), .subdevice = (subd)
+
+#define ATH_LED(pin,polarity) .driver_data = (((pin) << 8) | (polarity))
+#define ATH_PIN(data) ((data) >> 8)
+#define ATH_POLARITY(data) ((data) & 0xff)
+
+/* Devices we match on for LED config info (typically laptops) */
+static const struct pci_device_id ath5k_led_devices[] = {
+       /* IBM-specific AR5212 */
+       { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5212_IBM), ATH_LED(0, 0) },
+       /* AR5211 */
+       { PCI_VDEVICE(ATHEROS, PCI_DEVICE_ID_ATHEROS_AR5211), ATH_LED(0, 0) },
+       /* HP Compaq nc6xx, nc4000, nx6000 */
+       { ATH_SDEVICE(PCI_VENDOR_ID_COMPAQ, PCI_ANY_ID), ATH_LED(1, 1) },
+       /* Acer Aspire One A150 (maximlevitsky@gmail.com) */
+       { ATH_SDEVICE(PCI_VENDOR_ID_FOXCONN, 0xe008), ATH_LED(3, 0) },
+       /* Acer Ferrari 5000 (russ.dill@gmail.com) */
+       { ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0422), ATH_LED(1, 1) },
+       /* E-machines E510 (tuliom@gmail.com) */
+       { ATH_SDEVICE(PCI_VENDOR_ID_AMBIT, 0x0428), ATH_LED(3, 0) },
+       { }
+};
+
+void ath5k_led_enable(struct ath5k_softc *sc)
+{
+       if (test_bit(ATH_STAT_LEDSOFT, sc->status)) {
+               ath5k_hw_set_gpio_output(sc->ah, sc->led_pin);
+               ath5k_led_off(sc);
+       }
+}
+
+void ath5k_led_on(struct ath5k_softc *sc)
+{
+       if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
+               return;
+       ath5k_hw_set_gpio(sc->ah, sc->led_pin, sc->led_on);
+}
+
+void ath5k_led_off(struct ath5k_softc *sc)
+{
+       if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
+               return;
+       ath5k_hw_set_gpio(sc->ah, sc->led_pin, !sc->led_on);
+}
+
+static void
+ath5k_led_brightness_set(struct led_classdev *led_dev,
+       enum led_brightness brightness)
+{
+       struct ath5k_led *led = container_of(led_dev, struct ath5k_led,
+               led_dev);
+
+       if (brightness == LED_OFF)
+               ath5k_led_off(led->sc);
+       else
+               ath5k_led_on(led->sc);
+}
+
+static int
+ath5k_register_led(struct ath5k_softc *sc, struct ath5k_led *led,
+                  const char *name, char *trigger)
+{
+       int err;
+
+       led->sc = sc;
+       strncpy(led->name, name, sizeof(led->name));
+       led->led_dev.name = led->name;
+       led->led_dev.default_trigger = trigger;
+       led->led_dev.brightness_set = ath5k_led_brightness_set;
+
+       err = led_classdev_register(&sc->pdev->dev, &led->led_dev);
+       if (err) {
+               ATH5K_WARN(sc, "could not register LED %s\n", name);
+               led->sc = NULL;
+       }
+       return err;
+}
+
+static void
+ath5k_unregister_led(struct ath5k_led *led)
+{
+       if (!led->sc)
+               return;
+       led_classdev_unregister(&led->led_dev);
+       ath5k_led_off(led->sc);
+       led->sc = NULL;
+}
+
+void ath5k_unregister_leds(struct ath5k_softc *sc)
+{
+       ath5k_unregister_led(&sc->rx_led);
+       ath5k_unregister_led(&sc->tx_led);
+}
+
+int ath5k_init_leds(struct ath5k_softc *sc)
+{
+       int ret = 0;
+       struct ieee80211_hw *hw = sc->hw;
+       struct pci_dev *pdev = sc->pdev;
+       char name[ATH5K_LED_MAX_NAME_LEN + 1];
+       const struct pci_device_id *match;
+
+       match = pci_match_id(&ath5k_led_devices[0], pdev);
+       if (match) {
+               __set_bit(ATH_STAT_LEDSOFT, sc->status);
+               sc->led_pin = ATH_PIN(match->driver_data);
+               sc->led_on = ATH_POLARITY(match->driver_data);
+       }
+
+       if (!test_bit(ATH_STAT_LEDSOFT, sc->status))
+               goto out;
+
+       ath5k_led_enable(sc);
+
+       snprintf(name, sizeof(name), "ath5k-%s::rx", wiphy_name(hw->wiphy));
+       ret = ath5k_register_led(sc, &sc->rx_led, name,
+               ieee80211_get_rx_led_name(hw));
+       if (ret)
+               goto out;
+
+       snprintf(name, sizeof(name), "ath5k-%s::tx", wiphy_name(hw->wiphy));
+       ret = ath5k_register_led(sc, &sc->tx_led, name,
+               ieee80211_get_tx_led_name(hw));
+out:
+       return ret;
+}
+
index f8a4a69602707bc95256ba4c9d252cc1585fc970..55122f1e1986b49ab00f9a6625559580a1b41d8a 100644 (file)
@@ -657,9 +657,8 @@ void ath5k_hw_set_tsf64(struct ath5k_hw *ah, u64 tsf64)
 {
        ATH5K_TRACE(ah->ah_sc);
 
-       ath5k_hw_reg_write(ah, 0x00000000, AR5K_TSF_L32);
-       ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32);
        ath5k_hw_reg_write(ah, tsf64 & 0xffffffff, AR5K_TSF_L32);
+       ath5k_hw_reg_write(ah, (tsf64 >> 32) & 0xffffffff, AR5K_TSF_U32);
 }
 
 /**
index 1531ccd35066a52bfdb895f619a875bfb81ee879..685dc213edae01e8772b7f2fad6d7d612e3546ca 100644 (file)
@@ -102,7 +102,7 @@ static inline int ath5k_hw_write_ofdm_timings(struct ath5k_hw *ah,
  * index into rates for control rates, we can set it up like this because
  * this is only used for AR5212 and we know it supports G mode
  */
-static int control_rates[] =
+static const unsigned int control_rates[] =
        { 0, 1, 1, 1, 4, 4, 6, 6, 8, 8, 8, 8 };
 
 /**
index 00629587b790f8cc037ea643ad52ba7a66d6a1f9..1a4d4eab6fe8575c73e6835ed21005bd59e51c18 100644 (file)
@@ -9,6 +9,7 @@ ath9k-y +=      hw.o \
                main.o \
                recv.o \
                xmit.o \
+               virtual.o \
                rc.o
 
 ath9k-$(CONFIG_PCI) += pci.o
index 391c9fd3b64657c0af399bc886692eb91022d3cc..00cc7bb01f2ee17cb28620df66d75124b116fe69 100644 (file)
@@ -60,6 +60,7 @@ static struct ath_bus_ops ath_ahb_bus_ops  = {
 static int ath_ahb_probe(struct platform_device *pdev)
 {
        void __iomem *mem;
+       struct ath_wiphy *aphy;
        struct ath_softc *sc;
        struct ieee80211_hw *hw;
        struct resource *res;
@@ -96,7 +97,8 @@ static int ath_ahb_probe(struct platform_device *pdev)
 
        irq = res->start;
 
-       hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
+       hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) +
+                               sizeof(struct ath_softc), &ath9k_ops);
        if (hw == NULL) {
                dev_err(&pdev->dev, "no memory for ieee80211_hw\n");
                ret = -ENOMEM;
@@ -106,7 +108,11 @@ static int ath_ahb_probe(struct platform_device *pdev)
        SET_IEEE80211_DEV(hw, &pdev->dev);
        platform_set_drvdata(pdev, hw);
 
-       sc = hw->priv;
+       aphy = hw->priv;
+       sc = (struct ath_softc *) (aphy + 1);
+       aphy->sc = sc;
+       aphy->hw = hw;
+       sc->pri_wiphy = aphy;
        sc->hw = hw;
        sc->dev = &pdev->dev;
        sc->mem = mem;
@@ -156,7 +162,8 @@ static int ath_ahb_remove(struct platform_device *pdev)
        struct ieee80211_hw *hw = platform_get_drvdata(pdev);
 
        if (hw) {
-               struct ath_softc *sc = hw->priv;
+               struct ath_wiphy *aphy = hw->priv;
+               struct ath_softc *sc = aphy->sc;
 
                ath_cleanup(sc);
                platform_set_drvdata(pdev, NULL);
index d4df7e611df5703119a5bad219da9a7881f4ca8d..a39eb760cbb7e0979ef8730d3b1c260c1368a208 100644 (file)
@@ -642,14 +642,13 @@ void ath9k_enable_mib_counters(struct ath_hw *ah)
        REG_WRITE(ah, AR_PHY_ERR_MASK_2, AR_PHY_ERR_CCK_TIMING);
 }
 
+/* Freeze the MIB counters, get the stats and then clear them */
 void ath9k_hw_disable_mib_counters(struct ath_hw *ah)
 {
        DPRINTF(ah->ah_sc, ATH_DBG_ANI, "Disable MIB counters\n");
-
-       REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC | AR_MIBC_CMC);
-
+       REG_WRITE(ah, AR_MIBC, AR_MIBC_FMC);
        ath9k_hw_update_mibstats(ah, &ah->ah_mibStats);
-
+       REG_WRITE(ah, AR_MIBC, AR_MIBC_CMC);
        REG_WRITE(ah, AR_FILT_OFDM, 0);
        REG_WRITE(ah, AR_FILT_CCK, 0);
 }
index 0b0f82c83ffc979061eec52448725bc787ca28e6..b64be8e9a69029ba067b241de1a771f8a2060803 100644 (file)
@@ -292,6 +292,7 @@ struct ath_atx_ac {
 struct ath_tx_control {
        struct ath_txq *txq;
        int if_id;
+       enum ath9k_internal_frame_type frame_type;
 };
 
 struct ath_xmit_status {
@@ -373,10 +374,10 @@ int ath_tx_cleanup(struct ath_softc *sc);
 struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb);
 int ath_txq_update(struct ath_softc *sc, int qnum,
                   struct ath9k_tx_queue_info *q);
-int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
+int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
                 struct ath_tx_control *txctl);
 void ath_tx_tasklet(struct ath_softc *sc);
-void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb);
+void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb);
 bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno);
 int ath_tx_aggr_start(struct ath_softc *sc, struct ieee80211_sta *sta,
                      u16 tid, u16 *ssn);
@@ -387,22 +388,12 @@ void ath_tx_aggr_resume(struct ath_softc *sc, struct ieee80211_sta *sta, u16 tid
 /* VIFs */
 /********/
 
-/*
- * Define the scheme that we select MAC address for multiple
- * BSS on the same radio. The very first VIF will just use the MAC
- * address from the EEPROM. For the next 3 VIFs, we set the
- * U/L bit (bit 1) in MAC address, and use the next two bits as the
- * index of the VIF.
- */
-
-#define ATH_SET_VIF_BSSID_MASK(bssid_mask) \
-       ((bssid_mask)[0] &= ~(((ATH_BCBUF-1)<<2)|0x02))
-
 struct ath_vif {
        int av_bslot;
        enum nl80211_iftype av_opmode;
        struct ath_buf *av_bcbuf;
        struct ath_tx_control av_btxctl;
+       u8 bssid[ETH_ALEN]; /* current BSSID from config_interface */
 };
 
 /*******************/
@@ -426,11 +417,6 @@ struct ath_beacon_config {
        u16 dtim_period;
        u16 bmiss_timeout;
        u8 dtim_count;
-       u8 tim_offset;
-       union {
-               u64 last_tsf;
-               u8 last_tstamp[8];
-       } u; /* last received beacon/probe response timestamp of this BSS. */
 };
 
 struct ath_beacon {
@@ -444,7 +430,8 @@ struct ath_beacon {
        u32 bmisscnt;
        u32 ast_be_xmit;
        u64 bc_tstamp;
-       int bslot[ATH_BCBUF];
+       struct ieee80211_vif *bslot[ATH_BCBUF];
+       struct ath_wiphy *bslot_aphy[ATH_BCBUF];
        int slottime;
        int slotupdate;
        struct ath9k_tx_queue_info beacon_qi;
@@ -453,24 +440,21 @@ struct ath_beacon {
        struct list_head bbuf;
 };
 
-void ath9k_beacon_tasklet(unsigned long data);
-void ath_beacon_config(struct ath_softc *sc, int if_id);
+void ath_beacon_tasklet(unsigned long data);
+void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif);
 int ath_beaconq_setup(struct ath_hw *ah);
-int ath_beacon_alloc(struct ath_softc *sc, int if_id);
+int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif);
 void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp);
-void ath_beacon_sync(struct ath_softc *sc, int if_id);
 
 /*******/
 /* ANI */
 /*******/
 
-/* ANI values for STA only.
-   FIXME: Add appropriate values for AP later */
-
-#define ATH_ANI_POLLINTERVAL    100     /* 100 milliseconds between ANI poll */
-#define ATH_SHORT_CALINTERVAL   1000    /* 1 second between calibrations */
-#define ATH_LONG_CALINTERVAL    30000   /* 30 seconds between calibrations */
-#define ATH_RESTART_CALINTERVAL 1200000 /* 20 minutes between calibrations */
+#define ATH_STA_SHORT_CALINTERVAL 1000    /* 1 second */
+#define ATH_AP_SHORT_CALINTERVAL  100     /* 100 ms */
+#define ATH_ANI_POLLINTERVAL      100     /* 100 ms */
+#define ATH_LONG_CALINTERVAL      30000   /* 30 seconds */
+#define ATH_RESTART_CALINTERVAL   1200000 /* 20 minutes */
 
 struct ath_ani {
        bool caldone;
@@ -540,27 +524,27 @@ struct ath_rfkill {
  */
 #define        ATH_KEYMAX              128     /* max key cache size we handle */
 
-#define ATH_IF_ID_ANY          0xff
 #define ATH_TXPOWER_MAX         100     /* .5 dBm units */
 #define ATH_RSSI_DUMMY_MARKER   0x127
 #define ATH_RATE_DUMMY_MARKER   0
 
-#define SC_OP_INVALID          BIT(0)
-#define SC_OP_BEACONS          BIT(1)
-#define SC_OP_RXAGGR           BIT(2)
-#define SC_OP_TXAGGR           BIT(3)
-#define SC_OP_CHAINMASK_UPDATE BIT(4)
-#define SC_OP_FULL_RESET       BIT(5)
-#define SC_OP_NO_RESET         BIT(6)
-#define SC_OP_PREAMBLE_SHORT   BIT(7)
-#define SC_OP_PROTECT_ENABLE   BIT(8)
-#define SC_OP_RXFLUSH          BIT(9)
-#define SC_OP_LED_ASSOCIATED   BIT(10)
-#define SC_OP_RFKILL_REGISTERED        BIT(11)
-#define SC_OP_RFKILL_SW_BLOCKED        BIT(12)
-#define SC_OP_RFKILL_HW_BLOCKED        BIT(13)
-#define SC_OP_WAIT_FOR_BEACON  BIT(14)
-#define SC_OP_LED_ON           BIT(15)
+#define SC_OP_INVALID           BIT(0)
+#define SC_OP_BEACONS           BIT(1)
+#define SC_OP_RXAGGR            BIT(2)
+#define SC_OP_TXAGGR            BIT(3)
+#define SC_OP_CHAINMASK_UPDATE  BIT(4)
+#define SC_OP_FULL_RESET        BIT(5)
+#define SC_OP_PREAMBLE_SHORT    BIT(6)
+#define SC_OP_PROTECT_ENABLE    BIT(7)
+#define SC_OP_RXFLUSH           BIT(8)
+#define SC_OP_LED_ASSOCIATED    BIT(9)
+#define SC_OP_RFKILL_REGISTERED BIT(10)
+#define SC_OP_RFKILL_SW_BLOCKED BIT(11)
+#define SC_OP_RFKILL_HW_BLOCKED BIT(12)
+#define SC_OP_WAIT_FOR_BEACON   BIT(13)
+#define SC_OP_LED_ON            BIT(14)
+#define SC_OP_SCANNING          BIT(15)
+#define SC_OP_TSF_RESET         BIT(16)
 
 struct ath_bus_ops {
        void            (*read_cachesize)(struct ath_softc *sc, int *csz);
@@ -568,15 +552,34 @@ struct ath_bus_ops {
        bool            (*eeprom_read)(struct ath_hw *ah, u32 off, u16 *data);
 };
 
+struct ath_wiphy;
+
 struct ath_softc {
        struct ieee80211_hw *hw;
        struct device *dev;
+
+       spinlock_t wiphy_lock; /* spinlock to protect ath_wiphy data */
+       struct ath_wiphy *pri_wiphy;
+       struct ath_wiphy **sec_wiphy; /* secondary wiphys (virtual radios); may
+                                      * have NULL entries */
+       int num_sec_wiphy; /* number of sec_wiphy pointers in the array */
+       int chan_idx;
+       int chan_is_ht;
+       struct ath_wiphy *next_wiphy;
+       struct work_struct chan_work;
+       int wiphy_select_failures;
+       unsigned long wiphy_select_first_fail;
+       struct delayed_work wiphy_work;
+       unsigned long wiphy_scheduler_int;
+       int wiphy_scheduler_index;
+
        struct tasklet_struct intr_tq;
        struct tasklet_struct bcon_tasklet;
        struct ath_hw *sc_ah;
        void __iomem *mem;
        int irq;
        spinlock_t sc_resetlock;
+       spinlock_t sc_serial_rw;
        struct mutex mutex;
 
        u8 curbssid[ETH_ALEN];
@@ -602,7 +605,6 @@ struct ath_softc {
        struct ath_rx rx;
        struct ath_tx tx;
        struct ath_beacon beacon;
-       struct ieee80211_vif *vifs[ATH_BCBUF];
        struct ieee80211_rate rates[IEEE80211_NUM_BANDS][ATH_RATE_MAX];
        struct ath_rate_table *hw_rate_table[ATH9K_MODE_MAX];
        struct ath_rate_table *cur_rate_table;
@@ -627,6 +629,20 @@ struct ath_softc {
        struct ath_bus_ops *bus_ops;
 };
 
+struct ath_wiphy {
+       struct ath_softc *sc; /* shared for all virtual wiphys */
+       struct ieee80211_hw *hw;
+       enum ath_wiphy_state {
+               ATH_WIPHY_INACTIVE,
+               ATH_WIPHY_ACTIVE,
+               ATH_WIPHY_PAUSING,
+               ATH_WIPHY_PAUSED,
+               ATH_WIPHY_SCAN,
+       } state;
+       int chan_idx;
+       int chan_is_ht;
+};
+
 int ath_reset(struct ath_softc *sc, bool retry_tx);
 int ath_get_hal_qnum(u16 queue, struct ath_softc *sc);
 int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc);
@@ -650,6 +666,14 @@ int ath_attach(u16 devid, struct ath_softc *sc);
 void ath_detach(struct ath_softc *sc);
 const char *ath_mac_bb_name(u32 mac_bb_version);
 const char *ath_rf_name(u16 rf_version);
+void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw);
+void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
+                          struct ath9k_channel *ichan);
+void ath_update_chainmask(struct ath_softc *sc, int is_ht);
+int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
+                   struct ath9k_channel *hchan);
+void ath_radio_enable(struct ath_softc *sc);
+void ath_radio_disable(struct ath_softc *sc);
 
 #ifdef CONFIG_PCI
 int ath_pci_init(void);
@@ -679,8 +703,58 @@ static inline void ath9k_ps_wakeup(struct ath_softc *sc)
 static inline void ath9k_ps_restore(struct ath_softc *sc)
 {
        if (atomic_dec_and_test(&sc->ps_usecount))
-               if (sc->hw->conf.flags & IEEE80211_CONF_PS)
+               if ((sc->hw->conf.flags & IEEE80211_CONF_PS) &&
+                   !(sc->sc_flags & SC_OP_WAIT_FOR_BEACON))
                        ath9k_hw_setpower(sc->sc_ah,
                                          sc->sc_ah->restore_mode);
 }
+
+
+void ath9k_set_bssid_mask(struct ieee80211_hw *hw);
+int ath9k_wiphy_add(struct ath_softc *sc);
+int ath9k_wiphy_del(struct ath_wiphy *aphy);
+void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb);
+int ath9k_wiphy_pause(struct ath_wiphy *aphy);
+int ath9k_wiphy_unpause(struct ath_wiphy *aphy);
+int ath9k_wiphy_select(struct ath_wiphy *aphy);
+void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int);
+void ath9k_wiphy_chan_work(struct work_struct *work);
+bool ath9k_wiphy_started(struct ath_softc *sc);
+void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
+                                 struct ath_wiphy *selected);
+bool ath9k_wiphy_scanning(struct ath_softc *sc);
+void ath9k_wiphy_work(struct work_struct *work);
+
+/*
+ * Read and write, they both share the same lock. We do this to serialize
+ * reads and writes on Atheros 802.11n PCI devices only. This is required
+ * as the FIFO on these devices can only accept sanely 2 requests. After
+ * that the device goes bananas. Serializing the reads/writes prevents this
+ * from happening.
+ */
+
+static inline void ath9k_iowrite32(struct ath_hw *ah, u32 reg_offset, u32 val)
+{
+       if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
+               unsigned long flags;
+               spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags);
+               iowrite32(val, ah->ah_sc->mem + reg_offset);
+               spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags);
+       } else
+               iowrite32(val, ah->ah_sc->mem + reg_offset);
+}
+
+static inline unsigned int ath9k_ioread32(struct ath_hw *ah, u32 reg_offset)
+{
+       u32 val;
+       if (ah->config.serialize_regmode == SER_REG_MODE_ON) {
+               unsigned long flags;
+               spin_lock_irqsave(&ah->ah_sc->sc_serial_rw, flags);
+               val = ioread32(ah->ah_sc->mem + reg_offset);
+               spin_unlock_irqrestore(&ah->ah_sc->sc_serial_rw, flags);
+       } else
+               val = ioread32(ah->ah_sc->mem + reg_offset);
+       return val;
+}
+
 #endif /* ATH9K_H */
index 2e2ef352913518e1e2586da3f5cc03e1a2664fc9..039c78136c50e2b2de7b884412bb8ac7701803f7 100644 (file)
@@ -16,6 +16,8 @@
 
 #include "ath9k.h"
 
+#define FUDGE 2
+
 /*
  *  This function will modify certain transmit queue properties depending on
  *  the operating mode of the station (AP or AdHoc).  Parameters are AIFS
@@ -44,42 +46,28 @@ static int ath_beaconq_config(struct ath_softc *sc)
                        "unable to update h/w beacon queue parameters\n");
                return 0;
        } else {
-               ath9k_hw_resettxqueue(ah, sc->beacon.beaconq); /* push to h/w */
+               ath9k_hw_resettxqueue(ah, sc->beacon.beaconq);
                return 1;
        }
 }
 
-static void ath_bstuck_process(struct ath_softc *sc)
-{
-       DPRINTF(sc, ATH_DBG_BEACON,
-               "stuck beacon; resetting (bmiss count %u)\n",
-               sc->beacon.bmisscnt);
-       ath_reset(sc, false);
-}
-
 /*
  *  Associates the beacon frame buffer with a transmit descriptor.  Will set
  *  up all required antenna switch parameters, rate codes, and channel flags.
  *  Beacons are always sent out at the lowest rate, and are not retried.
 */
-static void ath_beacon_setup(struct ath_softc *sc,
-                            struct ath_vif *avp, struct ath_buf *bf)
+static void ath_beacon_setup(struct ath_softc *sc, struct ath_vif *avp,
+                            struct ath_buf *bf)
 {
        struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_desc *ds;
        struct ath9k_11n_rate_series series[4];
        struct ath_rate_table *rt;
-       int flags, antenna;
-       u8 rix, rate;
-       int ctsrate = 0;
-       int ctsduration = 0;
-
-       DPRINTF(sc, ATH_DBG_BEACON, "m %p len %u\n", skb, skb->len);
+       int flags, antenna, ctsrate = 0, ctsduration = 0;
+       u8 rate;
 
-       /* setup descriptors */
        ds = bf->bf_desc;
-
        flags = ATH9K_TXDESC_NOACK;
 
        if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC &&
@@ -92,65 +80,53 @@ static void ath_beacon_setup(struct ath_softc *sc,
                ds->ds_link = 0;
                /*
                 * Switch antenna every beacon.
-                * Should only switch every beacon period, not for every
-                * SWBA's
-                * XXX assumes two antenna
+                * Should only switch every beacon period, not for every SWBA
+                * XXX assumes two antennae
                 */
                antenna = ((sc->beacon.ast_be_xmit / sc->nbcnvifs) & 1 ? 2 : 1);
        }
 
        ds->ds_data = bf->bf_buf_addr;
 
-       /*
-        * Calculate rate code.
-        * XXX everything at min xmit rate
-        */
-       rix = 0;
        rt = sc->cur_rate_table;
-       rate = rt->info[rix].ratecode;
+       rate = rt->info[0].ratecode;
        if (sc->sc_flags & SC_OP_PREAMBLE_SHORT)
-               rate |= rt->info[rix].short_preamble;
-
-       ath9k_hw_set11n_txdesc(ah, ds,
-                              skb->len + FCS_LEN,     /* frame length */
-                              ATH9K_PKT_TYPE_BEACON,  /* Atheros packet type */
-                              MAX_RATE_POWER,         /* FIXME */
-                              ATH9K_TXKEYIX_INVALID,  /* no encryption */
-                              ATH9K_KEY_TYPE_CLEAR,   /* no encryption */
-                              flags                   /* no ack,
-                                                         veol for beacons */
-               );
+               rate |= rt->info[0].short_preamble;
+
+       ath9k_hw_set11n_txdesc(ah, ds, skb->len + FCS_LEN,
+                              ATH9K_PKT_TYPE_BEACON,
+                              MAX_RATE_POWER,
+                              ATH9K_TXKEYIX_INVALID,
+                              ATH9K_KEY_TYPE_CLEAR,
+                              flags);
 
        /* NB: beacon's BufLen must be a multiple of 4 bytes */
-       ath9k_hw_filltxdesc(ah, ds,
-                           roundup(skb->len, 4), /* buffer length */
-                           true,                 /* first segment */
-                           true,                 /* last segment */
-                           ds                    /* first descriptor */
-               );
+       ath9k_hw_filltxdesc(ah, ds, roundup(skb->len, 4),
+                           true, true, ds);
 
        memset(series, 0, sizeof(struct ath9k_11n_rate_series) * 4);
        series[0].Tries = 1;
        series[0].Rate = rate;
        series[0].ChSel = sc->tx_chainmask;
        series[0].RateFlags = (ctsrate) ? ATH9K_RATESERIES_RTS_CTS : 0;
-       ath9k_hw_set11n_ratescenario(ah, ds, ds, 0,
-               ctsrate, ctsduration, series, 4, 0);
+       ath9k_hw_set11n_ratescenario(ah, ds, ds, 0, ctsrate, ctsduration,
+                                    series, 4, 0);
 }
 
-/* Generate beacon frame and queue cab data for a VIF */
-static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
+static struct ath_buf *ath_beacon_generate(struct ieee80211_hw *hw,
+                                          struct ieee80211_vif *vif)
 {
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        struct ath_buf *bf;
        struct ath_vif *avp;
        struct sk_buff *skb;
        struct ath_txq *cabq;
-       struct ieee80211_vif *vif;
        struct ieee80211_tx_info *info;
        int cabq_depth;
 
-       vif = sc->vifs[if_id];
-       ASSERT(vif);
+       if (aphy->state != ATH_WIPHY_ACTIVE)
+               return NULL;
 
        avp = (void *)vif->drv_priv;
        cabq = sc->beacon.cabq;
@@ -161,16 +137,19 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
                return NULL;
        }
 
+       /* Release the old beacon first */
+
        bf = avp->av_bcbuf;
        skb = (struct sk_buff *)bf->bf_mpdu;
        if (skb) {
                dma_unmap_single(sc->dev, bf->bf_dmacontext,
-                                skb->len,
-                                DMA_TO_DEVICE);
+                                skb->len, DMA_TO_DEVICE);
                dev_kfree_skb_any(skb);
        }
 
-       skb = ieee80211_beacon_get(sc->hw, vif);
+       /* Get a new beacon from mac80211 */
+
+       skb = ieee80211_beacon_get(hw, vif);
        bf->bf_mpdu = skb;
        if (skb == NULL)
                return NULL;
@@ -189,17 +168,15 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
 
        bf->bf_buf_addr = bf->bf_dmacontext =
                dma_map_single(sc->dev, skb->data,
-                              skb->len,
-                              DMA_TO_DEVICE);
+                              skb->len, DMA_TO_DEVICE);
        if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
                dev_kfree_skb_any(skb);
                bf->bf_mpdu = NULL;
-               DPRINTF(sc, ATH_DBG_CONFIG,
-                       "dma_mapping_error() on beaconing\n");
+               DPRINTF(sc, ATH_DBG_FATAL, "dma_mapping_error on beaconing\n");
                return NULL;
        }
 
-       skb = ieee80211_get_buffered_bc(sc->hw, vif);
+       skb = ieee80211_get_buffered_bc(hw, vif);
 
        /*
         * if the CABQ traffic from previous DTIM is pending and the current
@@ -214,28 +191,18 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
        spin_unlock_bh(&cabq->axq_lock);
 
        if (skb && cabq_depth) {
-               /*
-                * Unlock the cabq lock as ath_tx_draintxq acquires
-                * the lock again which is a common function and that
-                * acquires txq lock inside.
-                */
                if (sc->nvifs > 1) {
-                       ath_draintxq(sc, cabq, false);
                        DPRINTF(sc, ATH_DBG_BEACON,
-                               "flush previous cabq traffic\n");
+                               "Flushing previous cabq traffic\n");
+                       ath_draintxq(sc, cabq, false);
                }
        }
 
-       /* Construct tx descriptor. */
        ath_beacon_setup(sc, avp, bf);
 
-       /*
-        * Enable the CAB queue before the beacon queue to
-        * insure cab frames are triggered by this beacon.
-        */
        while (skb) {
-               ath_tx_cabq(sc, skb);
-               skb = ieee80211_get_buffered_bc(sc->hw, vif);
+               ath_tx_cabq(hw, skb);
+               skb = ieee80211_get_buffered_bc(hw, vif);
        }
 
        return bf;
@@ -245,28 +212,22 @@ static struct ath_buf *ath_beacon_generate(struct ath_softc *sc, int if_id)
  * Startup beacon transmission for adhoc mode when they are sent entirely
  * by the hardware using the self-linked descriptor + veol trick.
 */
-static void ath_beacon_start_adhoc(struct ath_softc *sc, int if_id)
+static void ath_beacon_start_adhoc(struct ath_softc *sc,
+                                  struct ieee80211_vif *vif)
 {
-       struct ieee80211_vif *vif;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_buf *bf;
        struct ath_vif *avp;
        struct sk_buff *skb;
 
-       vif = sc->vifs[if_id];
-       ASSERT(vif);
-
        avp = (void *)vif->drv_priv;
 
-       if (avp->av_bcbuf == NULL) {
-               DPRINTF(sc, ATH_DBG_BEACON, "avp=%p av_bcbuf=%p\n",
-                       avp, avp != NULL ? avp->av_bcbuf : NULL);
+       if (avp->av_bcbuf == NULL)
                return;
-       }
+
        bf = avp->av_bcbuf;
        skb = (struct sk_buff *) bf->bf_mpdu;
 
-       /* Construct tx descriptor. */
        ath_beacon_setup(sc, avp, bf);
 
        /* NB: caller is known to have already stopped tx dma */
@@ -288,18 +249,15 @@ int ath_beaconq_setup(struct ath_hw *ah)
        return ath9k_hw_setuptxqueue(ah, ATH9K_TX_QUEUE_BEACON, &qi);
 }
 
-int ath_beacon_alloc(struct ath_softc *sc, int if_id)
+int ath_beacon_alloc(struct ath_wiphy *aphy, struct ieee80211_vif *vif)
 {
-       struct ieee80211_vif *vif;
+       struct ath_softc *sc = aphy->sc;
        struct ath_vif *avp;
        struct ieee80211_hdr *hdr;
        struct ath_buf *bf;
        struct sk_buff *skb;
        __le64 tstamp;
 
-       vif = sc->vifs[if_id];
-       ASSERT(vif);
-
        avp = (void *)vif->drv_priv;
 
        /* Allocate a beacon descriptor if we haven't done so. */
@@ -319,42 +277,37 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
                         */
                        avp->av_bslot = 0;
                        for (slot = 0; slot < ATH_BCBUF; slot++)
-                               if (sc->beacon.bslot[slot] == ATH_IF_ID_ANY) {
+                               if (sc->beacon.bslot[slot] == NULL) {
                                        /*
                                         * XXX hack, space out slots to better
                                         * deal with misses
                                         */
                                        if (slot+1 < ATH_BCBUF &&
-                                           sc->beacon.bslot[slot+1] ==
-                                               ATH_IF_ID_ANY) {
+                                           sc->beacon.bslot[slot+1] == NULL) {
                                                avp->av_bslot = slot+1;
                                                break;
                                        }
                                        avp->av_bslot = slot;
                                        /* NB: keep looking for a double slot */
                                }
-                       BUG_ON(sc->beacon.bslot[avp->av_bslot] != ATH_IF_ID_ANY);
-                       sc->beacon.bslot[avp->av_bslot] = if_id;
+                       BUG_ON(sc->beacon.bslot[avp->av_bslot] != NULL);
+                       sc->beacon.bslot[avp->av_bslot] = vif;
+                       sc->beacon.bslot_aphy[avp->av_bslot] = aphy;
                        sc->nbcnvifs++;
                }
        }
 
-       /* release the previous beacon frame , if it already exists. */
+       /* release the previous beacon frame, if it already exists. */
        bf = avp->av_bcbuf;
        if (bf->bf_mpdu != NULL) {
                skb = (struct sk_buff *)bf->bf_mpdu;
                dma_unmap_single(sc->dev, bf->bf_dmacontext,
-                                skb->len,
-                                DMA_TO_DEVICE);
+                                skb->len, DMA_TO_DEVICE);
                dev_kfree_skb_any(skb);
                bf->bf_mpdu = NULL;
        }
 
-       /*
-        * NB: the beacon data buffer must be 32-bit aligned.
-        * FIXME: Fill avp->av_btxctl.txpower and
-        * avp->av_btxctl.shortPreamble
-        */
+       /* NB: the beacon data buffer must be 32-bit aligned. */
        skb = ieee80211_beacon_get(sc->hw, vif);
        if (skb == NULL) {
                DPRINTF(sc, ATH_DBG_BEACON, "cannot get skb\n");
@@ -403,13 +356,12 @@ int ath_beacon_alloc(struct ath_softc *sc, int if_id)
        bf->bf_mpdu = skb;
        bf->bf_buf_addr = bf->bf_dmacontext =
                dma_map_single(sc->dev, skb->data,
-                              skb->len,
-                              DMA_TO_DEVICE);
+                              skb->len, DMA_TO_DEVICE);
        if (unlikely(dma_mapping_error(sc->dev, bf->bf_buf_addr))) {
                dev_kfree_skb_any(skb);
                bf->bf_mpdu = NULL;
-               DPRINTF(sc, ATH_DBG_CONFIG,
-                       "dma_mapping_error() on beacon alloc\n");
+               DPRINTF(sc, ATH_DBG_FATAL,
+                       "dma_mapping_error on beacon alloc\n");
                return -ENOMEM;
        }
 
@@ -422,7 +374,8 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
                struct ath_buf *bf;
 
                if (avp->av_bslot != -1) {
-                       sc->beacon.bslot[avp->av_bslot] = ATH_IF_ID_ANY;
+                       sc->beacon.bslot[avp->av_bslot] = NULL;
+                       sc->beacon.bslot_aphy[avp->av_bslot] = NULL;
                        sc->nbcnvifs--;
                }
 
@@ -430,8 +383,7 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
                if (bf->bf_mpdu != NULL) {
                        struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
                        dma_unmap_single(sc->dev, bf->bf_dmacontext,
-                                        skb->len,
-                                        DMA_TO_DEVICE);
+                                        skb->len, DMA_TO_DEVICE);
                        dev_kfree_skb_any(skb);
                        bf->bf_mpdu = NULL;
                }
@@ -441,92 +393,45 @@ void ath_beacon_return(struct ath_softc *sc, struct ath_vif *avp)
        }
 }
 
-void ath9k_beacon_tasklet(unsigned long data)
+void ath_beacon_tasklet(unsigned long data)
 {
        struct ath_softc *sc = (struct ath_softc *)data;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_buf *bf = NULL;
-       int slot, if_id;
-       u32 bfaddr;
-       u32 rx_clear = 0, rx_frame = 0, tx_frame = 0;
-       u32 show_cycles = 0;
-       u32 bc = 0; /* beacon count */
+       struct ieee80211_vif *vif;
+       struct ath_wiphy *aphy;
+       int slot;
+       u32 bfaddr, bc = 0, tsftu;
        u64 tsf;
-       u32 tsftu;
        u16 intval;
 
-       if (sc->sc_flags & SC_OP_NO_RESET) {
-               show_cycles = ath9k_hw_GetMibCycleCountsPct(ah,
-                                           &rx_clear, &rx_frame, &tx_frame);
-       }
-
        /*
         * Check if the previous beacon has gone out.  If
         * not don't try to post another, skip this period
         * and wait for the next.  Missed beacons indicate
         * a problem and should not occur.  If we miss too
         * many consecutive beacons reset the device.
-        *
-        * FIXME: Clean up this mess !!
         */
        if (ath9k_hw_numtxpending(ah, sc->beacon.beaconq) != 0) {
                sc->beacon.bmisscnt++;
-               /* XXX: doth needs the chanchange IE countdown decremented.
-                *      We should consider adding a mac80211 call to indicate
-                *      a beacon miss so appropriate action could be taken
-                *      (in that layer).
-                */
+
                if (sc->beacon.bmisscnt < BSTUCK_THRESH) {
-                       if (sc->sc_flags & SC_OP_NO_RESET) {
-                               DPRINTF(sc, ATH_DBG_BEACON,
-                                       "missed %u consecutive beacons\n",
-                                       sc->beacon.bmisscnt);
-                               if (show_cycles) {
-                                       /*
-                                        * Display cycle counter stats from HW
-                                        * to aide in debug of stickiness.
-                                        */
-                                       DPRINTF(sc, ATH_DBG_BEACON,
-                                               "busy times: rx_clear=%d, "
-                                               "rx_frame=%d, tx_frame=%d\n",
-                                               rx_clear, rx_frame,
-                                               tx_frame);
-                               } else {
-                                       DPRINTF(sc, ATH_DBG_BEACON,
-                                               "unable to obtain "
-                                               "busy times\n");
-                               }
-                       } else {
-                               DPRINTF(sc, ATH_DBG_BEACON,
-                                       "missed %u consecutive beacons\n",
-                                       sc->beacon.bmisscnt);
-                       }
+                       DPRINTF(sc, ATH_DBG_BEACON,
+                               "missed %u consecutive beacons\n",
+                               sc->beacon.bmisscnt);
                } else if (sc->beacon.bmisscnt >= BSTUCK_THRESH) {
-                       if (sc->sc_flags & SC_OP_NO_RESET) {
-                               if (sc->beacon.bmisscnt == BSTUCK_THRESH) {
-                                       DPRINTF(sc, ATH_DBG_BEACON,
-                                               "beacon is officially "
-                                               "stuck\n");
-                               }
-                       } else {
-                               DPRINTF(sc, ATH_DBG_BEACON,
-                                       "beacon is officially stuck\n");
-                               ath_bstuck_process(sc);
-                       }
+                       DPRINTF(sc, ATH_DBG_BEACON,
+                               "beacon is officially stuck\n");
+                       ath_reset(sc, false);
                }
+
                return;
        }
 
        if (sc->beacon.bmisscnt != 0) {
-               if (sc->sc_flags & SC_OP_NO_RESET) {
-                       DPRINTF(sc, ATH_DBG_BEACON,
-                               "resume beacon xmit after %u misses\n",
-                               sc->beacon.bmisscnt);
-               } else {
-                       DPRINTF(sc, ATH_DBG_BEACON,
-                               "resume beacon xmit after %u misses\n",
-                               sc->beacon.bmisscnt);
-               }
+               DPRINTF(sc, ATH_DBG_BEACON,
+                       "resume beacon xmit after %u misses\n",
+                       sc->beacon.bmisscnt);
                sc->beacon.bmisscnt = 0;
        }
 
@@ -542,21 +447,22 @@ void ath9k_beacon_tasklet(unsigned long data)
        tsf = ath9k_hw_gettsf64(ah);
        tsftu = TSF_TO_TU(tsf>>32, tsf);
        slot = ((tsftu % intval) * ATH_BCBUF) / intval;
-       if_id = sc->beacon.bslot[(slot + 1) % ATH_BCBUF];
+       vif = sc->beacon.bslot[(slot + 1) % ATH_BCBUF];
+       aphy = sc->beacon.bslot_aphy[(slot + 1) % ATH_BCBUF];
 
        DPRINTF(sc, ATH_DBG_BEACON,
-               "slot %d [tsf %llu tsftu %u intval %u] if_id %d\n",
-               slot, (unsigned long long)tsf, tsftu,
-               intval, if_id);
+               "slot %d [tsf %llu tsftu %u intval %u] vif %p\n",
+               slot, tsf, tsftu, intval, vif);
 
        bfaddr = 0;
-       if (if_id != ATH_IF_ID_ANY) {
-               bf = ath_beacon_generate(sc, if_id);
+       if (vif) {
+               bf = ath_beacon_generate(aphy->hw, vif);
                if (bf != NULL) {
                        bfaddr = bf->bf_daddr;
                        bc = 1;
                }
        }
+
        /*
         * Handle slot time change when a non-ERP station joins/leaves
         * an 11g network.  The 802.11 layer notifies us via callback,
@@ -573,7 +479,6 @@ void ath9k_beacon_tasklet(unsigned long data)
         *     interval has passed.  When bursting slot is always left
         *     set to ATH_BCBUF so this check is a noop.
         */
-       /* XXX locking */
        if (sc->beacon.updateslot == UPDATE) {
                sc->beacon.updateslot = COMMIT; /* commit next beacon */
                sc->beacon.slotupdate = slot;
@@ -590,7 +495,6 @@ void ath9k_beacon_tasklet(unsigned long data)
                if (!ath9k_hw_stoptxdma(ah, sc->beacon.beaconq)) {
                        DPRINTF(sc, ATH_DBG_FATAL,
                                "beacon queue %u did not stop?\n", sc->beacon.beaconq);
-                       /* NB: the HAL still stops DMA, so proceed */
                }
 
                /* NB: cabq traffic should already be queued and primed */
@@ -602,253 +506,239 @@ void ath9k_beacon_tasklet(unsigned long data)
 }
 
 /*
- * Configure the beacon and sleep timers.
- *
- * When operating as an AP this resets the TSF and sets
- * up the hardware to notify us when we need to issue beacons.
- *
- * When operating in station mode this sets up the beacon
- * timers according to the timestamp of the last received
- * beacon and the current TSF, configures PCF and DTIM
- * handling, programs the sleep registers so the hardware
- * will wakeup in time to receive beacons, and configures
- * the beacon miss handling so we'll receive a BMISS
- * interrupt when we stop seeing beacons from the AP
- * we've associated with.
+ * For multi-bss ap support beacons are either staggered evenly over N slots or
+ * burst together.  For the former arrange for the SWBA to be delivered for each
+ * slot. Slots that are not occupied will generate nothing.
  */
-void ath_beacon_config(struct ath_softc *sc, int if_id)
+static void ath_beacon_config_ap(struct ath_softc *sc,
+                                struct ath_beacon_config *conf,
+                                struct ath_vif *avp)
 {
-       struct ieee80211_vif *vif;
-       struct ath_hw *ah = sc->sc_ah;
-       struct ath_beacon_config conf;
-       struct ath_vif *avp;
-       enum nl80211_iftype opmode;
        u32 nexttbtt, intval;
 
-       if (if_id != ATH_IF_ID_ANY) {
-               vif = sc->vifs[if_id];
-               ASSERT(vif);
-               avp = (void *)vif->drv_priv;
-               opmode = avp->av_opmode;
-       } else {
-               opmode = sc->sc_ah->opmode;
-       }
+       /* Configure the timers only when the TSF has to be reset */
 
-       memset(&conf, 0, sizeof(struct ath_beacon_config));
+       if (!(sc->sc_flags & SC_OP_TSF_RESET))
+               return;
 
-       conf.beacon_interval = sc->hw->conf.beacon_int ?
-               sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL;
-       conf.listen_interval = 1;
-       conf.dtim_period = conf.beacon_interval;
-       conf.dtim_count = 1;
-       conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
+       /* NB: the beacon interval is kept internally in TU's */
+       intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
+       intval /= ATH_BCBUF;    /* for staggered beacons */
+       nexttbtt = intval;
+       intval |= ATH9K_BEACON_RESET_TSF;
 
-       /* extract tstamp from last beacon and convert to TU */
-       nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
+       /*
+        * In AP mode we enable the beacon timers and SWBA interrupts to
+        * prepare beacon frames.
+        */
+       intval |= ATH9K_BEACON_ENA;
+       sc->imask |= ATH9K_INT_SWBA;
+       ath_beaconq_config(sc);
 
-       /* XXX conditionalize multi-bss support? */
-       if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
-               /*
-                * For multi-bss ap support beacons are either staggered
-                * evenly over N slots or burst together.  For the former
-                * arrange for the SWBA to be delivered for each slot.
-                * Slots that are not occupied will generate nothing.
-                */
-               /* NB: the beacon interval is kept internally in TU's */
-               intval = conf.beacon_interval & ATH9K_BEACON_PERIOD;
-               intval /= ATH_BCBUF;    /* for staggered beacons */
-       } else {
-               intval = conf.beacon_interval & ATH9K_BEACON_PERIOD;
-       }
+       /* Set the computed AP beacon timers */
 
-       if (nexttbtt == 0)      /* e.g. for ap mode */
-               nexttbtt = intval;
-       else if (intval)        /* NB: can be 0 for monitor mode */
-               nexttbtt = roundup(nexttbtt, intval);
+       ath9k_hw_set_interrupts(sc->sc_ah, 0);
+       ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval);
+       sc->beacon.bmisscnt = 0;
+       ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
 
-       DPRINTF(sc, ATH_DBG_BEACON, "nexttbtt %u intval %u (%u)\n",
-               nexttbtt, intval, conf.beacon_interval);
+       /* Clear the reset TSF flag, so that subsequent beacon updation
+          will not reset the HW TSF. */
 
-       /* Check for NL80211_IFTYPE_AP and sc_nostabeacons for WDS client */
-       if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION) {
-               struct ath9k_beacon_state bs;
-               u64 tsf;
-               u32 tsftu;
-               int dtimperiod, dtimcount, sleepduration;
-               int cfpperiod, cfpcount;
+       sc->sc_flags &= ~SC_OP_TSF_RESET;
+}
 
-               /*
-                * Setup dtim and cfp parameters according to
-                * last beacon we received (which may be none).
-                */
-               dtimperiod = conf.dtim_period;
-               if (dtimperiod <= 0)            /* NB: 0 if not known */
-                       dtimperiod = 1;
-               dtimcount = conf.dtim_count;
-               if (dtimcount >= dtimperiod)    /* NB: sanity check */
-                       dtimcount = 0;
-               cfpperiod = 1;                  /* NB: no PCF support yet */
-               cfpcount = 0;
-
-               sleepduration = conf.listen_interval * intval;
-               if (sleepduration <= 0)
-                       sleepduration = intval;
+/*
+ * This sets up the beacon timers according to the timestamp of the last
+ * received beacon and the current TSF, configures PCF and DTIM
+ * handling, programs the sleep registers so the hardware will wakeup in
+ * time to receive beacons, and configures the beacon miss handling so
+ * we'll receive a BMISS interrupt when we stop seeing beacons from the AP
+ * we've associated with.
+ */
+static void ath_beacon_config_sta(struct ath_softc *sc,
+                                 struct ath_beacon_config *conf,
+                                 struct ath_vif *avp)
+{
+       struct ath9k_beacon_state bs;
+       int dtimperiod, dtimcount, sleepduration;
+       int cfpperiod, cfpcount;
+       u32 nexttbtt = 0, intval, tsftu;
+       u64 tsf;
 
-#define FUDGE 2
-               /*
-                * Pull nexttbtt forward to reflect the current
-                * TSF and calculate dtim+cfp state for the result.
-                */
-               tsf = ath9k_hw_gettsf64(ah);
-               tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
-               do {
-                       nexttbtt += intval;
-                       if (--dtimcount < 0) {
-                               dtimcount = dtimperiod - 1;
-                               if (--cfpcount < 0)
-                                       cfpcount = cfpperiod - 1;
-                       }
-               } while (nexttbtt < tsftu);
-#undef FUDGE
-               memset(&bs, 0, sizeof(bs));
-               bs.bs_intval = intval;
-               bs.bs_nexttbtt = nexttbtt;
-               bs.bs_dtimperiod = dtimperiod*intval;
-               bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
-               bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
-               bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
-               bs.bs_cfpmaxduration = 0;
+       memset(&bs, 0, sizeof(bs));
+       intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
 
-               /*
-                * Calculate the number of consecutive beacons to miss
-                * before taking a BMISS interrupt.  The configuration
-                * is specified in TU so we only need calculate based
-                * on the beacon interval.  Note that we clamp the
-                * result to at most 15 beacons.
-                */
-               if (sleepduration > intval) {
-                       bs.bs_bmissthreshold = conf.listen_interval *
-                               ATH_DEFAULT_BMISS_LIMIT / 2;
-               } else {
-                       bs.bs_bmissthreshold =
-                               DIV_ROUND_UP(conf.bmiss_timeout, intval);
-                       if (bs.bs_bmissthreshold > 15)
-                               bs.bs_bmissthreshold = 15;
-                       else if (bs.bs_bmissthreshold <= 0)
-                               bs.bs_bmissthreshold = 1;
-               }
+       /*
+        * Setup dtim and cfp parameters according to
+        * last beacon we received (which may be none).
+        */
+       dtimperiod = conf->dtim_period;
+       if (dtimperiod <= 0)            /* NB: 0 if not known */
+               dtimperiod = 1;
+       dtimcount = conf->dtim_count;
+       if (dtimcount >= dtimperiod)    /* NB: sanity check */
+               dtimcount = 0;
+       cfpperiod = 1;                  /* NB: no PCF support yet */
+       cfpcount = 0;
+
+       sleepduration = conf->listen_interval * intval;
+       if (sleepduration <= 0)
+               sleepduration = intval;
 
-               /*
-                * Calculate sleep duration.  The configuration is
-                * given in ms.  We insure a multiple of the beacon
-                * period is used.  Also, if the sleep duration is
-                * greater than the DTIM period then it makes senses
-                * to make it a multiple of that.
-                *
-                * XXX fixed at 100ms
-                */
+       /*
+        * Pull nexttbtt forward to reflect the current
+        * TSF and calculate dtim+cfp state for the result.
+        */
+       tsf = ath9k_hw_gettsf64(sc->sc_ah);
+       tsftu = TSF_TO_TU(tsf>>32, tsf) + FUDGE;
+       do {
+               nexttbtt += intval;
+               if (--dtimcount < 0) {
+                       dtimcount = dtimperiod - 1;
+                       if (--cfpcount < 0)
+                               cfpcount = cfpperiod - 1;
+               }
+       } while (nexttbtt < tsftu);
 
-               bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100),
-                                             sleepduration);
-               if (bs.bs_sleepduration > bs.bs_dtimperiod)
-                       bs.bs_sleepduration = bs.bs_dtimperiod;
+       bs.bs_intval = intval;
+       bs.bs_nexttbtt = nexttbtt;
+       bs.bs_dtimperiod = dtimperiod*intval;
+       bs.bs_nextdtim = bs.bs_nexttbtt + dtimcount*intval;
+       bs.bs_cfpperiod = cfpperiod*bs.bs_dtimperiod;
+       bs.bs_cfpnext = bs.bs_nextdtim + cfpcount*bs.bs_dtimperiod;
+       bs.bs_cfpmaxduration = 0;
 
-               DPRINTF(sc, ATH_DBG_BEACON,
-                       "tsf %llu "
-                       "tsf:tu %u "
-                       "intval %u "
-                       "nexttbtt %u "
-                       "dtim %u "
-                       "nextdtim %u "
-                       "bmiss %u "
-                       "sleep %u "
-                       "cfp:period %u "
-                       "maxdur %u "
-                       "next %u "
-                       "timoffset %u\n",
-                       (unsigned long long)tsf, tsftu,
-                       bs.bs_intval,
-                       bs.bs_nexttbtt,
-                       bs.bs_dtimperiod,
-                       bs.bs_nextdtim,
-                       bs.bs_bmissthreshold,
-                       bs.bs_sleepduration,
-                       bs.bs_cfpperiod,
-                       bs.bs_cfpmaxduration,
-                       bs.bs_cfpnext,
-                       bs.bs_timoffset
-                       );
-
-               ath9k_hw_set_interrupts(ah, 0);
-               ath9k_hw_set_sta_beacon_timers(ah, &bs);
-               sc->imask |= ATH9K_INT_BMISS;
-               ath9k_hw_set_interrupts(ah, sc->imask);
+       /*
+        * Calculate the number of consecutive beacons to miss* before taking
+        * a BMISS interrupt. The configuration is specified in TU so we only
+        * need calculate based on the beacon interval.  Note that we clamp the
+        * result to at most 15 beacons.
+        */
+       if (sleepduration > intval) {
+               bs.bs_bmissthreshold = conf->listen_interval *
+                       ATH_DEFAULT_BMISS_LIMIT / 2;
        } else {
-               u64 tsf;
-               u32 tsftu;
-               ath9k_hw_set_interrupts(ah, 0);
-               if (nexttbtt == intval)
-                       intval |= ATH9K_BEACON_RESET_TSF;
-               if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC) {
-                       /*
-                        * Pull nexttbtt forward to reflect the current
-                        * TSF
-                        */
-#define FUDGE 2
-                       if (!(intval & ATH9K_BEACON_RESET_TSF)) {
-                               tsf = ath9k_hw_gettsf64(ah);
-                               tsftu = TSF_TO_TU((u32)(tsf>>32),
-                                       (u32)tsf) + FUDGE;
-                               do {
-                                       nexttbtt += intval;
-                               } while (nexttbtt < tsftu);
-                       }
-#undef FUDGE
-                       DPRINTF(sc, ATH_DBG_BEACON,
-                               "IBSS nexttbtt %u intval %u (%u)\n",
-                               nexttbtt,
-                               intval & ~ATH9K_BEACON_RESET_TSF,
-                               conf.beacon_interval);
-
-                       /*
-                        * In IBSS mode enable the beacon timers but only
-                        * enable SWBA interrupts if we need to manually
-                        * prepare beacon frames.  Otherwise we use a
-                        * self-linked tx descriptor and let the hardware
-                        * deal with things.
-                        */
-                       intval |= ATH9K_BEACON_ENA;
-                       if (!(ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
-                               sc->imask |= ATH9K_INT_SWBA;
-                       ath_beaconq_config(sc);
-               } else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
-                       /*
-                        * In AP mode we enable the beacon timers and
-                        * SWBA interrupts to prepare beacon frames.
-                        */
-                       intval |= ATH9K_BEACON_ENA;
-                       sc->imask |= ATH9K_INT_SWBA;   /* beacon prepare */
-                       ath_beaconq_config(sc);
-               }
-               ath9k_hw_beaconinit(ah, nexttbtt, intval);
-               sc->beacon.bmisscnt = 0;
-               ath9k_hw_set_interrupts(ah, sc->imask);
-               /*
-                * When using a self-linked beacon descriptor in
-                * ibss mode load it once here.
-                */
-               if (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC &&
-                   (ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
-                       ath_beacon_start_adhoc(sc, 0);
+               bs.bs_bmissthreshold = DIV_ROUND_UP(conf->bmiss_timeout, intval);
+               if (bs.bs_bmissthreshold > 15)
+                       bs.bs_bmissthreshold = 15;
+               else if (bs.bs_bmissthreshold <= 0)
+                       bs.bs_bmissthreshold = 1;
        }
+
+       /*
+        * Calculate sleep duration. The configuration is given in ms.
+        * We ensure a multiple of the beacon period is used. Also, if the sleep
+        * duration is greater than the DTIM period then it makes senses
+        * to make it a multiple of that.
+        *
+        * XXX fixed at 100ms
+        */
+
+       bs.bs_sleepduration = roundup(IEEE80211_MS_TO_TU(100), sleepduration);
+       if (bs.bs_sleepduration > bs.bs_dtimperiod)
+               bs.bs_sleepduration = bs.bs_dtimperiod;
+
+       /* TSF out of range threshold fixed at 1 second */
+       bs.bs_tsfoor_threshold = ATH9K_TSFOOR_THRESHOLD;
+
+       DPRINTF(sc, ATH_DBG_BEACON, "tsf: %llu tsftu: %u\n", tsf, tsftu);
+       DPRINTF(sc, ATH_DBG_BEACON,
+               "bmiss: %u sleep: %u cfp-period: %u maxdur: %u next: %u\n",
+               bs.bs_bmissthreshold, bs.bs_sleepduration,
+               bs.bs_cfpperiod, bs.bs_cfpmaxduration, bs.bs_cfpnext);
+
+       /* Set the computed STA beacon timers */
+
+       ath9k_hw_set_interrupts(sc->sc_ah, 0);
+       ath9k_hw_set_sta_beacon_timers(sc->sc_ah, &bs);
+       sc->imask |= ATH9K_INT_BMISS;
+       ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
 }
 
-void ath_beacon_sync(struct ath_softc *sc, int if_id)
+static void ath_beacon_config_adhoc(struct ath_softc *sc,
+                                   struct ath_beacon_config *conf,
+                                   struct ath_vif *avp,
+                                   struct ieee80211_vif *vif)
 {
+       u64 tsf;
+       u32 tsftu, intval, nexttbtt;
+
+       intval = conf->beacon_interval & ATH9K_BEACON_PERIOD;
+
+       /* Pull nexttbtt forward to reflect the current TSF */
+
+       nexttbtt = TSF_TO_TU(sc->beacon.bc_tstamp >> 32, sc->beacon.bc_tstamp);
+       if (nexttbtt == 0)
+                nexttbtt = intval;
+        else if (intval)
+                nexttbtt = roundup(nexttbtt, intval);
+
+       tsf = ath9k_hw_gettsf64(sc->sc_ah);
+       tsftu = TSF_TO_TU((u32)(tsf>>32), (u32)tsf) + FUDGE;
+       do {
+               nexttbtt += intval;
+       } while (nexttbtt < tsftu);
+
+       DPRINTF(sc, ATH_DBG_BEACON,
+               "IBSS nexttbtt %u intval %u (%u)\n",
+               nexttbtt, intval, conf->beacon_interval);
+
        /*
-        * Resync beacon timers using the tsf of the
-        * beacon frame we just received.
+        * In IBSS mode enable the beacon timers but only enable SWBA interrupts
+        * if we need to manually prepare beacon frames.  Otherwise we use a
+        * self-linked tx descriptor and let the hardware deal with things.
         */
-       ath_beacon_config(sc, if_id);
-       sc->sc_flags |= SC_OP_BEACONS;
+       intval |= ATH9K_BEACON_ENA;
+       if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL))
+               sc->imask |= ATH9K_INT_SWBA;
+
+       ath_beaconq_config(sc);
+
+       /* Set the computed ADHOC beacon timers */
+
+       ath9k_hw_set_interrupts(sc->sc_ah, 0);
+       ath9k_hw_beaconinit(sc->sc_ah, nexttbtt, intval);
+       sc->beacon.bmisscnt = 0;
+       ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
+
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_VEOL)
+               ath_beacon_start_adhoc(sc, vif);
+}
+
+void ath_beacon_config(struct ath_softc *sc, struct ieee80211_vif *vif)
+{
+       struct ath_beacon_config conf;
+
+       /* Setup the beacon configuration parameters */
+
+       memset(&conf, 0, sizeof(struct ath_beacon_config));
+       conf.beacon_interval = sc->hw->conf.beacon_int ?
+               sc->hw->conf.beacon_int : ATH_DEFAULT_BINTVAL;
+       conf.listen_interval = 1;
+       conf.dtim_period = conf.beacon_interval;
+       conf.dtim_count = 1;
+       conf.bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf.beacon_interval;
+
+       if (vif) {
+               struct ath_vif *avp = (struct ath_vif *)vif->drv_priv;
+
+               switch(avp->av_opmode) {
+               case NL80211_IFTYPE_AP:
+                       ath_beacon_config_ap(sc, &conf, avp);
+                       break;
+               case NL80211_IFTYPE_ADHOC:
+                       ath_beacon_config_adhoc(sc, &conf, avp, vif);
+                       break;
+               case NL80211_IFTYPE_STATION:
+                       ath_beacon_config_sta(sc, &conf, avp);
+                       break;
+               default:
+                       DPRINTF(sc, ATH_DBG_CONFIG,
+                               "Unsupported beaconing mode\n");
+                       return;
+               }
+
+               sc->sc_flags |= SC_OP_BEACONS;
+       }
 }
index 1fc3a08e85c64b14d16c9c0dc80e06a36dd819c0..c9446fb6b15318b5b1548ceb4aca5075ce4eed89 100644 (file)
@@ -718,39 +718,31 @@ s16 ath9k_hw_getchan_noise(struct ath_hw *ah, struct ath9k_channel *chan)
        return nf;
 }
 
-bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
-                       u8 rxchainmask, bool longcal,
-                       bool *isCalDone)
+static void ath9k_olc_temp_compensation(struct ath_hw *ah)
 {
-       struct hal_cal_list *currCal = ah->cal_list_curr;
+       u32 rddata, i;
+       int delta, currPDADC, regval;
 
-       *isCalDone = true;
+       rddata = REG_READ(ah, AR_PHY_TX_PWRCTRL4);
 
-       if (currCal &&
-           (currCal->calState == CAL_RUNNING ||
-            currCal->calState == CAL_WAITING)) {
-               ath9k_hw_per_calibration(ah, chan, rxchainmask, currCal,
-                                        isCalDone);
-               if (*isCalDone) {
-                       ah->cal_list_curr = currCal = currCal->calNext;
+       currPDADC = MS(rddata, AR_PHY_TX_PWRCTRL_PD_AVG_OUT);
 
-                       if (currCal->calState == CAL_WAITING) {
-                               *isCalDone = false;
-                               ath9k_hw_reset_calibration(ah, currCal);
-                       }
-               }
-       }
+       if (ah->eep_ops->get_eeprom(ah, EEP_DAC_HPWR_5G))
+               delta = (currPDADC - ah->initPDADC + 4) / 8;
+       else
+               delta = (currPDADC - ah->initPDADC + 5) / 10;
 
-       if (longcal) {
-               ath9k_hw_getnf(ah, chan);
-               ath9k_hw_loadnf(ah, ah->curchan);
-               ath9k_hw_start_nfcal(ah);
+       if (delta != ah->PDADCdelta) {
+               ah->PDADCdelta = delta;
+               for (i = 1; i < AR9280_TX_GAIN_TABLE_SIZE; i++) {
+                       regval = ah->originalGain[i] - delta;
+                       if (regval < 0)
+                               regval = 0;
 
-               if (chan->channelFlags & CHANNEL_CW_INT)
-                       chan->channelFlags &= ~CHANNEL_CW_INT;
+                       REG_RMW_FIELD(ah, AR_PHY_TX_GAIN_TBL1 + i * 4,
+                                       AR_PHY_TX_GAIN, regval);
+               }
        }
-
-       return true;
 }
 
 static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
@@ -848,26 +840,141 @@ static inline void ath9k_hw_9285_pa_cal(struct ath_hw *ah)
 
 }
 
+bool ath9k_hw_calibrate(struct ath_hw *ah, struct ath9k_channel *chan,
+                       u8 rxchainmask, bool longcal,
+                       bool *isCalDone)
+{
+       struct hal_cal_list *currCal = ah->cal_list_curr;
+
+       *isCalDone = true;
+
+       if (currCal &&
+           (currCal->calState == CAL_RUNNING ||
+            currCal->calState == CAL_WAITING)) {
+               ath9k_hw_per_calibration(ah, chan, rxchainmask, currCal,
+                                        isCalDone);
+               if (*isCalDone) {
+                       ah->cal_list_curr = currCal = currCal->calNext;
+
+                       if (currCal->calState == CAL_WAITING) {
+                               *isCalDone = false;
+                               ath9k_hw_reset_calibration(ah, currCal);
+                       }
+               }
+       }
+
+       if (longcal) {
+               if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah))
+                       ath9k_hw_9285_pa_cal(ah);
+
+               if (OLC_FOR_AR9280_20_LATER)
+                       ath9k_olc_temp_compensation(ah);
+               ath9k_hw_getnf(ah, chan);
+               ath9k_hw_loadnf(ah, ah->curchan);
+               ath9k_hw_start_nfcal(ah);
+
+               if (chan->channelFlags & CHANNEL_CW_INT)
+                       chan->channelFlags &= ~CHANNEL_CW_INT;
+       }
+
+       return true;
+}
+
+static bool ar9285_clc(struct ath_hw *ah, struct ath9k_channel *chan)
+{
+       REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
+       if (chan->channelFlags & CHANNEL_HT20) {
+               REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
+               REG_SET_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
+               REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL,
+                           AR_PHY_AGC_CONTROL_FLTR_CAL);
+               REG_CLR_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
+               REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
+               if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
+                                 AR_PHY_AGC_CONTROL_CAL, 0, AH_WAIT_TIMEOUT)) {
+                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset "
+                               "calibration failed to complete in "
+                               "1ms; noisy ??\n");
+                       return false;
+               }
+               REG_CLR_BIT(ah, AR_PHY_TURBO, AR_PHY_FC_DYN2040_EN);
+               REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_PARALLEL_CAL_ENABLE);
+               REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
+       }
+       REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
+       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
+       REG_SET_BIT(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_CAL_ENABLE);
+       REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL);
+       if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
+                         0, AH_WAIT_TIMEOUT)) {
+               DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE, "offset calibration "
+                               "failed to complete in 1ms; noisy ??\n");
+               return false;
+       }
+
+       REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
+       REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
+       REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
+
+       return true;
+}
+
 bool ath9k_hw_init_cal(struct ath_hw *ah,
                       struct ath9k_channel *chan)
 {
+       if (AR_SREV_9285(ah) && AR_SREV_9285_12_OR_LATER(ah)) {
+               if (!ar9285_clc(ah, chan))
+                       return false;
+       } else if (AR_SREV_9280_10_OR_LATER(ah)) {
+               REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
+               REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
+               REG_CLR_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
+
+               /* Kick off the cal */
+               REG_WRITE(ah, AR_PHY_AGC_CONTROL,
+                               REG_READ(ah, AR_PHY_AGC_CONTROL) |
+                               AR_PHY_AGC_CONTROL_CAL);
+
+               if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
+                                       AR_PHY_AGC_CONTROL_CAL, 0,
+                                       AH_WAIT_TIMEOUT)) {
+                       DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
+                               "offset calibration failed to complete in 1ms; "
+                               "noisy environment?\n");
+                       return false;
+               }
+
+               REG_CLR_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
+               REG_SET_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
+               REG_SET_BIT(ah, AR_PHY_CL_CAL_CTL, AR_PHY_CL_CAL_ENABLE);
+       }
+
+       /* Calibrate the AGC */
        REG_WRITE(ah, AR_PHY_AGC_CONTROL,
-                 REG_READ(ah, AR_PHY_AGC_CONTROL) |
-                 AR_PHY_AGC_CONTROL_CAL);
+                       REG_READ(ah, AR_PHY_AGC_CONTROL) |
+                       AR_PHY_AGC_CONTROL_CAL);
 
-       if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL, 0)) {
+       if (!ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_CAL,
+                               0, AH_WAIT_TIMEOUT)) {
                DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
                        "offset calibration failed to complete in 1ms; "
                        "noisy environment?\n");
                return false;
        }
 
+       if (AR_SREV_9280_10_OR_LATER(ah)) {
+               REG_SET_BIT(ah, AR_PHY_ADC_CTL, AR_PHY_ADC_CTL_OFF_PWDADC);
+               REG_CLR_BIT(ah, AR_PHY_AGC_CONTROL, AR_PHY_AGC_CONTROL_FLTR_CAL);
+       }
+
+       /* Do PA Calibration */
        if (AR_SREV_9285(ah) && AR_SREV_9285_11_OR_LATER(ah))
                ath9k_hw_9285_pa_cal(ah);
 
+       /* Do NF Calibration */
        REG_WRITE(ah, AR_PHY_AGC_CONTROL,
-                 REG_READ(ah, AR_PHY_AGC_CONTROL) |
-                 AR_PHY_AGC_CONTROL_NF);
+                       REG_READ(ah, AR_PHY_AGC_CONTROL) |
+                       AR_PHY_AGC_CONTROL_NF);
 
        ah->cal_list = ah->cal_list_last = ah->cal_list_curr = NULL;
 
@@ -876,19 +983,19 @@ bool ath9k_hw_init_cal(struct ath_hw *ah,
                        INIT_CAL(&ah->adcgain_caldata);
                        INSERT_CAL(ah, &ah->adcgain_caldata);
                        DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                               "enabling ADC Gain Calibration.\n");
+                                       "enabling ADC Gain Calibration.\n");
                }
                if (ath9k_hw_iscal_supported(ah, ADC_DC_CAL)) {
                        INIT_CAL(&ah->adcdc_caldata);
                        INSERT_CAL(ah, &ah->adcdc_caldata);
                        DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                               "enabling ADC DC Calibration.\n");
+                                       "enabling ADC DC Calibration.\n");
                }
                if (ath9k_hw_iscal_supported(ah, IQ_MISMATCH_CAL)) {
                        INIT_CAL(&ah->iq_caldata);
                        INSERT_CAL(ah, &ah->iq_caldata);
                        DPRINTF(ah->ah_sc, ATH_DBG_CALIBRATE,
-                               "enabling IQ Calibration.\n");
+                                       "enabling IQ Calibration.\n");
                }
 
                ah->cal_list_curr = ah->cal_list;
index d2448f049c1db21b9b7ff8e2f148d3fcc736da14..32589e0c501810f41de30340418f2e9215a834e3 100644 (file)
@@ -27,7 +27,7 @@ extern const struct hal_percal_data adc_init_dc_cal;
 
 #define AR_PHY_CCA_MAX_GOOD_VALUE                      -85
 #define AR_PHY_CCA_MAX_HIGH_VALUE                      -62
-#define AR_PHY_CCA_MIN_BAD_VALUE                       -121
+#define AR_PHY_CCA_MIN_BAD_VALUE                       -140
 #define AR_PHY_CCA_FILTERWINDOW_LENGTH_INIT     3
 #define AR_PHY_CCA_FILTERWINDOW_LENGTH          5
 
index 800ad5926b6f0654e321abb1874933a27692f17a..82573cadb1abf34b28a2c603792474f9f020f0c9 100644 (file)
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
+#include <asm/unaligned.h>
+
 #include "ath9k.h"
 
 static unsigned int ath9k_debug = DBG_DEFAULT;
 module_param_named(debug, ath9k_debug, uint, 0);
 
+static struct dentry *ath9k_debugfs_root;
+
 void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...)
 {
        if (!sc)
@@ -258,13 +262,14 @@ void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb)
 
 /* FIXME: legacy rates, later on .. */
 void ath_debug_stat_retries(struct ath_softc *sc, int rix,
-                           int xretries, int retries)
+                           int xretries, int retries, u8 per)
 {
        if (conf_is_ht(&sc->hw->conf)) {
                int idx = sc->cur_rate_table->info[rix].dot11rate;
 
                sc->debug.stats.n_rcstats[idx].xretries += xretries;
                sc->debug.stats.n_rcstats[idx].retries += retries;
+               sc->debug.stats.n_rcstats[idx].per = per;
        }
 }
 
@@ -277,15 +282,16 @@ static ssize_t ath_read_file_stat_11n_rc(struct file *file,
        unsigned int len = 0;
        int i = 0;
 
-       len += sprintf(buf, "%7s %13s %8s %8s\n\n", "Rate", "Success",
-                      "Retries", "XRetries");
+       len += sprintf(buf, "%7s %13s %8s %8s %6s\n\n", "Rate", "Success",
+                      "Retries", "XRetries", "PER");
 
        for (i = 0; i <= 15; i++) {
                len += snprintf(buf + len, sizeof(buf) - len,
-                               "%5s%3d: %8u %8u %8u\n", "MCS", i,
+                               "%5s%3d: %8u %8u %8u %8u\n", "MCS", i,
                                sc->debug.stats.n_rcstats[i].success,
                                sc->debug.stats.n_rcstats[i].retries,
-                               sc->debug.stats.n_rcstats[i].xretries);
+                               sc->debug.stats.n_rcstats[i].xretries,
+                               sc->debug.stats.n_rcstats[i].per);
        }
 
        return simple_read_from_buffer(user_buf, count, ppos, buf, len);
@@ -316,6 +322,9 @@ static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
 {
        struct ath_softc *sc = file->private_data;
 
+       if (sc->cur_rate_table == NULL)
+               return 0;
+
        if (conf_is_ht(&sc->hw->conf))
                return ath_read_file_stat_11n_rc(file, user_buf, count, ppos);
        else
@@ -328,16 +337,169 @@ static const struct file_operations fops_rcstat = {
        .owner = THIS_MODULE
 };
 
+static const char * ath_wiphy_state_str(enum ath_wiphy_state state)
+{
+       switch (state) {
+       case ATH_WIPHY_INACTIVE:
+               return "INACTIVE";
+       case ATH_WIPHY_ACTIVE:
+               return "ACTIVE";
+       case ATH_WIPHY_PAUSING:
+               return "PAUSING";
+       case ATH_WIPHY_PAUSED:
+               return "PAUSED";
+       case ATH_WIPHY_SCAN:
+               return "SCAN";
+       }
+       return "?";
+}
+
+static ssize_t read_file_wiphy(struct file *file, char __user *user_buf,
+                              size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       char buf[512];
+       unsigned int len = 0;
+       int i;
+       u8 addr[ETH_ALEN];
+
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "primary: %s (%s chan=%d ht=%d)\n",
+                       wiphy_name(sc->pri_wiphy->hw->wiphy),
+                       ath_wiphy_state_str(sc->pri_wiphy->state),
+                       sc->pri_wiphy->chan_idx, sc->pri_wiphy->chan_is_ht);
+       for (i = 0; i < sc->num_sec_wiphy; i++) {
+               struct ath_wiphy *aphy = sc->sec_wiphy[i];
+               if (aphy == NULL)
+                       continue;
+               len += snprintf(buf + len, sizeof(buf) - len,
+                               "secondary: %s (%s chan=%d ht=%d)\n",
+                               wiphy_name(aphy->hw->wiphy),
+                               ath_wiphy_state_str(aphy->state),
+                               aphy->chan_idx, aphy->chan_is_ht);
+       }
+
+       put_unaligned_le32(REG_READ(sc->sc_ah, AR_STA_ID0), addr);
+       put_unaligned_le16(REG_READ(sc->sc_ah, AR_STA_ID1) & 0xffff, addr + 4);
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "addr: %pM\n", addr);
+       put_unaligned_le32(REG_READ(sc->sc_ah, AR_BSSMSKL), addr);
+       put_unaligned_le16(REG_READ(sc->sc_ah, AR_BSSMSKU) & 0xffff, addr + 4);
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "addrmask: %pM\n", addr);
+
+       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
+}
+
+static struct ath_wiphy * get_wiphy(struct ath_softc *sc, const char *name)
+{
+       int i;
+       if (strcmp(name, wiphy_name(sc->pri_wiphy->hw->wiphy)) == 0)
+               return sc->pri_wiphy;
+       for (i = 0; i < sc->num_sec_wiphy; i++) {
+               struct ath_wiphy *aphy = sc->sec_wiphy[i];
+               if (aphy && strcmp(name, wiphy_name(aphy->hw->wiphy)) == 0)
+                       return aphy;
+       }
+       return NULL;
+}
+
+static int del_wiphy(struct ath_softc *sc, const char *name)
+{
+       struct ath_wiphy *aphy = get_wiphy(sc, name);
+       if (!aphy)
+               return -ENOENT;
+       return ath9k_wiphy_del(aphy);
+}
+
+static int pause_wiphy(struct ath_softc *sc, const char *name)
+{
+       struct ath_wiphy *aphy = get_wiphy(sc, name);
+       if (!aphy)
+               return -ENOENT;
+       return ath9k_wiphy_pause(aphy);
+}
+
+static int unpause_wiphy(struct ath_softc *sc, const char *name)
+{
+       struct ath_wiphy *aphy = get_wiphy(sc, name);
+       if (!aphy)
+               return -ENOENT;
+       return ath9k_wiphy_unpause(aphy);
+}
+
+static int select_wiphy(struct ath_softc *sc, const char *name)
+{
+       struct ath_wiphy *aphy = get_wiphy(sc, name);
+       if (!aphy)
+               return -ENOENT;
+       return ath9k_wiphy_select(aphy);
+}
+
+static int schedule_wiphy(struct ath_softc *sc, const char *msec)
+{
+       ath9k_wiphy_set_scheduler(sc, simple_strtoul(msec, NULL, 0));
+       return 0;
+}
+
+static ssize_t write_file_wiphy(struct file *file, const char __user *user_buf,
+                               size_t count, loff_t *ppos)
+{
+       struct ath_softc *sc = file->private_data;
+       char buf[50];
+       size_t len;
+
+       len = min(count, sizeof(buf) - 1);
+       if (copy_from_user(buf, user_buf, len))
+               return -EFAULT;
+       buf[len] = '\0';
+       if (len > 0 && buf[len - 1] == '\n')
+               buf[len - 1] = '\0';
+
+       if (strncmp(buf, "add", 3) == 0) {
+               int res = ath9k_wiphy_add(sc);
+               if (res < 0)
+                       return res;
+       } else if (strncmp(buf, "del=", 4) == 0) {
+               int res = del_wiphy(sc, buf + 4);
+               if (res < 0)
+                       return res;
+       } else if (strncmp(buf, "pause=", 6) == 0) {
+               int res = pause_wiphy(sc, buf + 6);
+               if (res < 0)
+                       return res;
+       } else if (strncmp(buf, "unpause=", 8) == 0) {
+               int res = unpause_wiphy(sc, buf + 8);
+               if (res < 0)
+                       return res;
+       } else if (strncmp(buf, "select=", 7) == 0) {
+               int res = select_wiphy(sc, buf + 7);
+               if (res < 0)
+                       return res;
+       } else if (strncmp(buf, "schedule=", 9) == 0) {
+               int res = schedule_wiphy(sc, buf + 9);
+               if (res < 0)
+                       return res;
+       } else
+               return -EOPNOTSUPP;
+
+       return count;
+}
+
+static const struct file_operations fops_wiphy = {
+       .read = read_file_wiphy,
+       .write = write_file_wiphy,
+       .open = ath9k_debugfs_open,
+       .owner = THIS_MODULE
+};
+
+
 int ath9k_init_debug(struct ath_softc *sc)
 {
        sc->debug.debug_mask = ath9k_debug;
 
-       sc->debug.debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
-       if (!sc->debug.debugfs_root)
-               goto err;
-
        sc->debug.debugfs_phy = debugfs_create_dir(wiphy_name(sc->hw->wiphy),
-                                                     sc->debug.debugfs_root);
+                                                     ath9k_debugfs_root);
        if (!sc->debug.debugfs_phy)
                goto err;
 
@@ -360,6 +522,12 @@ int ath9k_init_debug(struct ath_softc *sc)
        if (!sc->debug.debugfs_rcstat)
                goto err;
 
+       sc->debug.debugfs_wiphy = debugfs_create_file(
+               "wiphy", S_IRUGO | S_IWUSR, sc->debug.debugfs_phy, sc,
+               &fops_wiphy);
+       if (!sc->debug.debugfs_wiphy)
+               goto err;
+
        return 0;
 err:
        ath9k_exit_debug(sc);
@@ -368,9 +536,24 @@ err:
 
 void ath9k_exit_debug(struct ath_softc *sc)
 {
+       debugfs_remove(sc->debug.debugfs_wiphy);
        debugfs_remove(sc->debug.debugfs_rcstat);
        debugfs_remove(sc->debug.debugfs_interrupt);
        debugfs_remove(sc->debug.debugfs_dma);
        debugfs_remove(sc->debug.debugfs_phy);
-       debugfs_remove(sc->debug.debugfs_root);
+}
+
+int ath9k_debug_create_root(void)
+{
+       ath9k_debugfs_root = debugfs_create_dir(KBUILD_MODNAME, NULL);
+       if (!ath9k_debugfs_root)
+               return -ENOENT;
+
+       return 0;
+}
+
+void ath9k_debug_remove_root(void)
+{
+       debugfs_remove(ath9k_debugfs_root);
+       ath9k_debugfs_root = NULL;
 }
index 61e969894c0a13cbfc9e999c6d1710d510914d7e..065268b8568f218266e68e7ee1e5fe70d7264859 100644 (file)
@@ -91,31 +91,34 @@ struct ath_11n_rc_stats {
        u32 success;
        u32 retries;
        u32 xretries;
+       u8 per;
 };
 
 struct ath_stats {
        struct ath_interrupt_stats istats;
-       struct ath_legacy_rc_stats legacy_rcstats[12]; /* max(11a,11b,11g) */
-       struct ath_11n_rc_stats n_rcstats[16]; /* 0..15 MCS rates */
+       struct ath_legacy_rc_stats legacy_rcstats[12];  /* max(11a,11b,11g) */
+       struct ath_11n_rc_stats n_rcstats[16];          /* 0..15 MCS rates */
 };
 
 struct ath9k_debug {
        int debug_mask;
-       struct dentry *debugfs_root;
        struct dentry *debugfs_phy;
        struct dentry *debugfs_dma;
        struct dentry *debugfs_interrupt;
        struct dentry *debugfs_rcstat;
+       struct dentry *debugfs_wiphy;
        struct ath_stats stats;
 };
 
 void DPRINTF(struct ath_softc *sc, int dbg_mask, const char *fmt, ...);
 int ath9k_init_debug(struct ath_softc *sc);
 void ath9k_exit_debug(struct ath_softc *sc);
+int ath9k_debug_create_root(void);
+void ath9k_debug_remove_root(void);
 void ath_debug_stat_interrupt(struct ath_softc *sc, enum ath9k_int status);
 void ath_debug_stat_rc(struct ath_softc *sc, struct sk_buff *skb);
 void ath_debug_stat_retries(struct ath_softc *sc, int rix,
-                           int xretries, int retries);
+                           int xretries, int retries, u8 per);
 
 #else
 
@@ -133,6 +136,15 @@ static inline void ath9k_exit_debug(struct ath_softc *sc)
 {
 }
 
+static inline int ath9k_debug_create_root(void)
+{
+       return 0;
+}
+
+static inline void ath9k_debug_remove_root(void)
+{
+}
+
 static inline void ath_debug_stat_interrupt(struct ath_softc *sc,
                                            enum ath9k_int status)
 {
@@ -144,7 +156,7 @@ static inline void ath_debug_stat_rc(struct ath_softc *sc,
 }
 
 static inline void ath_debug_stat_retries(struct ath_softc *sc, int rix,
-                                         int xretries, int retries)
+                                         int xretries, int retries, u8 per)
 {
 }
 
index b55e9920a5d454e3515e411383303d22367dd879..183c949bcca1b44612e10236db2d6d093875c50a 100644 (file)
@@ -179,6 +179,69 @@ static void ath9k_hw_get_legacy_target_powers(struct ath_hw *ah,
        }
 }
 
+static void ath9k_get_txgain_index(struct ath_hw *ah,
+               struct ath9k_channel *chan,
+               struct calDataPerFreqOpLoop *rawDatasetOpLoop,
+               u8 *calChans,  u16 availPiers, u8 *pwr, u8 *pcdacIdx)
+{
+       u8 pcdac, i = 0;
+       u16 idxL = 0, idxR = 0, numPiers;
+       bool match;
+       struct chan_centers centers;
+
+       ath9k_hw_get_channel_centers(ah, chan, &centers);
+
+       for (numPiers = 0; numPiers < availPiers; numPiers++)
+               if (calChans[numPiers] == AR5416_BCHAN_UNUSED)
+                       break;
+
+       match = ath9k_hw_get_lower_upper_index(
+                       (u8)FREQ2FBIN(centers.synth_center, IS_CHAN_2GHZ(chan)),
+                       calChans, numPiers, &idxL, &idxR);
+       if (match) {
+               pcdac = rawDatasetOpLoop[idxL].pcdac[0][0];
+               *pwr = rawDatasetOpLoop[idxL].pwrPdg[0][0];
+       } else {
+               pcdac = rawDatasetOpLoop[idxR].pcdac[0][0];
+               *pwr = (rawDatasetOpLoop[idxL].pwrPdg[0][0] +
+                               rawDatasetOpLoop[idxR].pwrPdg[0][0])/2;
+       }
+
+       while (pcdac > ah->originalGain[i] &&
+                       i < (AR9280_TX_GAIN_TABLE_SIZE - 1))
+               i++;
+
+       *pcdacIdx = i;
+       return;
+}
+
+static void ath9k_olc_get_pdadcs(struct ath_hw *ah,
+                               u32 initTxGain,
+                               int txPower,
+                               u8 *pPDADCValues)
+{
+       u32 i;
+       u32 offset;
+
+       REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_0,
+                       AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3);
+       REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL6_1,
+                       AR_PHY_TX_PWRCTRL_ERR_EST_MODE, 3);
+
+       REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL7,
+                       AR_PHY_TX_PWRCTRL_INIT_TX_GAIN, initTxGain);
+
+       offset = txPower;
+       for (i = 0; i < AR5416_NUM_PDADC_VALUES; i++)
+               if (i < offset)
+                       pPDADCValues[i] = 0x0;
+               else
+                       pPDADCValues[i] = 0xFF;
+}
+
+
+
+
 static void ath9k_hw_get_target_powers(struct ath_hw *ah,
                                       struct ath9k_channel *chan,
                                       struct cal_target_power_ht *powInfo,
@@ -439,7 +502,7 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
 
        switch (param) {
        case EEP_NFTHRESH_2:
-               return pModal[1].noiseFloorThreshCh[0];
+               return pModal->noiseFloorThreshCh[0];
        case AR_EEPROM_MAC(0):
                return pBase->macAddr[0] << 8 | pBase->macAddr[1];
        case AR_EEPROM_MAC(1):
@@ -466,6 +529,8 @@ static u32 ath9k_hw_4k_get_eeprom(struct ath_hw *ah,
                return pBase->txMask;
        case EEP_RX_MASK:
                return pBase->rxMask;
+       case EEP_FRAC_N_5G:
+               return 0;
        default:
                return 0;
        }
@@ -575,7 +640,7 @@ static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah,
                pPdGainBoundaries[i] =
                        min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);
 
-               if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) {
+               if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
                        minDelta = pPdGainBoundaries[0] - 23;
                        pPdGainBoundaries[0] = 23;
                } else {
@@ -614,7 +679,7 @@ static void ath9k_hw_get_4k_gain_boundaries_pdadcs(struct ath_hw *ah,
                                    vpdTableI[i][sizeCurrVpdTable - 2]);
                vpdStep = (int16_t)((vpdStep < 1) ? 1 : vpdStep);
 
-               if (tgtIndex > maxIndex) {
+               if (tgtIndex >= maxIndex) {
                        while ((ss <= tgtIndex) &&
                               (k < (AR5416_NUM_PDADC_VALUES - 1))) {
                                tmpVal = (int16_t) TMP_VAL_VPD_TABLE;
@@ -648,11 +713,11 @@ static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
        u8 *pCalBChans = NULL;
        u16 pdGainOverlap_t2;
        static u8 pdadcValues[AR5416_NUM_PDADC_VALUES];
-       u16 gainBoundaries[AR5416_PD_GAINS_IN_MASK];
+       u16 gainBoundaries[AR5416_EEP4K_PD_GAINS_IN_MASK];
        u16 numPiers, i, j;
        int16_t tMinCalPower;
        u16 numXpdGain, xpdMask;
-       u16 xpdGainValues[AR5416_NUM_PD_GAINS] = { 0, 0, 0, 0 };
+       u16 xpdGainValues[AR5416_EEP4K_NUM_PD_GAINS] = { 0, 0 };
        u32 reg32, regOffset, regChainOffset;
 
        xpdMask = pEepData->modalHeader.xpdGain;
@@ -667,16 +732,16 @@ static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
        }
 
        pCalBChans = pEepData->calFreqPier2G;
-       numPiers = AR5416_NUM_2G_CAL_PIERS;
+       numPiers = AR5416_EEP4K_NUM_2G_CAL_PIERS;
 
        numXpdGain = 0;
 
-       for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
-               if ((xpdMask >> (AR5416_PD_GAINS_IN_MASK - i)) & 1) {
-                       if (numXpdGain >= AR5416_NUM_PD_GAINS)
+       for (i = 1; i <= AR5416_EEP4K_PD_GAINS_IN_MASK; i++) {
+               if ((xpdMask >> (AR5416_EEP4K_PD_GAINS_IN_MASK - i)) & 1) {
+                       if (numXpdGain >= AR5416_EEP4K_NUM_PD_GAINS)
                                break;
                        xpdGainValues[numXpdGain] =
-                               (u16)(AR5416_PD_GAINS_IN_MASK - i);
+                               (u16)(AR5416_EEP4K_PD_GAINS_IN_MASK - i);
                        numXpdGain++;
                }
        }
@@ -687,11 +752,10 @@ static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
                      xpdGainValues[0]);
        REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_2,
                      xpdGainValues[1]);
-       REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3,
-                     xpdGainValues[2]);
+       REG_RMW_FIELD(ah, AR_PHY_TPCRG1, AR_PHY_TPCRG1_PD_GAIN_3, 0);
 
-       for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-               if (AR_SREV_5416_V20_OR_LATER(ah) &&
+       for (i = 0; i < AR5416_EEP4K_MAX_CHAINS; i++) {
+               if (AR_SREV_5416_20_OR_LATER(ah) &&
                    (ah->rxchainmask == 5 || ah->txchainmask == 5) &&
                    (i != 0)) {
                        regChainOffset = (i == 1) ? 0x2000 : 0x1000;
@@ -707,7 +771,7 @@ static bool ath9k_hw_set_4k_power_cal_table(struct ath_hw *ah,
                                            &tMinCalPower, gainBoundaries,
                                            pdadcValues, numXpdGain);
 
-                       if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
+                       if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
                                REG_WRITE(ah, AR_PHY_TPCRG5 + regChainOffset,
                                          SM(pdGainOverlap_t2,
                                             AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
@@ -1594,11 +1658,26 @@ static u32 ath9k_hw_def_get_eeprom(struct ath_hw *ah,
                return pBase->rxGainType;
        case EEP_TXGAIN_TYPE:
                return pBase->txGainType;
+       case EEP_OL_PWRCTRL:
+               if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19)
+                       return pBase->openLoopPwrCntl ? true : false;
+               else
+                       return false;
+       case EEP_RC_CHAIN_MASK:
+               if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19)
+                       return pBase->rcChainMask;
+               else
+                       return 0;
        case EEP_DAC_HPWR_5G:
                if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20)
                        return pBase->dacHiPwrMode_5G;
                else
                        return 0;
+       case EEP_FRAC_N_5G:
+               if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_22)
+                       return pBase->frac_n_5g;
+               else
+                       return 0;
        default:
                return 0;
        }
@@ -1628,7 +1707,7 @@ static bool ath9k_hw_def_set_board_values(struct ath_hw *ah,
                                break;
                }
 
-               if (AR_SREV_5416_V20_OR_LATER(ah) &&
+               if (AR_SREV_5416_20_OR_LATER(ah) &&
                    (ah->rxchainmask == 5 || ah->txchainmask == 5)
                    && (i != 0))
                        regChainOffset = (i == 1) ? 0x2000 : 0x1000;
@@ -1649,7 +1728,7 @@ static bool ath9k_hw_def_set_board_values(struct ath_hw *ah,
                          SM(pModal->iqCalQCh[i],
                             AR_PHY_TIMING_CTRL4_IQCORR_Q_Q_COFF));
 
-               if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
+               if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
                        if (AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_3) {
                                txRxAttenLocal = pModal->txRxAttenCh[i];
                                if (AR_SREV_9280_10_OR_LATER(ah)) {
@@ -1832,8 +1911,15 @@ static bool ath9k_hw_def_set_board_values(struct ath_hw *ah,
                                      pModal->swSettleHt40);
        }
 
+       if (AR_SREV_9280_20_OR_LATER(ah) &&
+                       AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_19)
+               REG_RMW_FIELD(ah, AR_PHY_CCK_TX_CTRL,
+                               AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK,
+                               pModal->miscBits);
+
+
        if (AR_SREV_9280_20(ah) && AR5416_VER_MASK >= AR5416_EEP_MINOR_VER_20) {
-               if (IS_CHAN_HT20(chan))
+               if (IS_CHAN_2GHZ(chan))
                        REG_RMW_FIELD(ah, AR_AN_TOP1, AR_AN_TOP1_DACIPMODE,
                                        eep->baseEepHeader.dacLpMode);
                else if (eep->baseEepHeader.dacHiPwrMode_5G)
@@ -1844,6 +1930,10 @@ static bool ath9k_hw_def_set_board_values(struct ath_hw *ah,
 
                REG_RMW_FIELD(ah, AR_PHY_FRAME_CTL, AR_PHY_FRAME_CTL_TX_CLIP,
                                pModal->miscBits >> 2);
+
+               REG_RMW_FIELD(ah, AR_PHY_TX_PWRCTRL9,
+                               AR_PHY_TX_DESIRED_SCALE_CCK,
+                               eep->baseEepHeader.desiredScaleCCK);
        }
 
        return true;
@@ -2004,7 +2094,7 @@ static void ath9k_hw_get_def_gain_boundaries_pdadcs(struct ath_hw *ah,
                pPdGainBoundaries[i] =
                        min((u16)AR5416_MAX_RATE_POWER, pPdGainBoundaries[i]);
 
-               if ((i == 0) && !AR_SREV_5416_V20_OR_LATER(ah)) {
+               if ((i == 0) && !AR_SREV_5416_20_OR_LATER(ah)) {
                        minDelta = pPdGainBoundaries[0] - 23;
                        pPdGainBoundaries[0] = 23;
                } else {
@@ -2073,6 +2163,10 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
                                  struct ath9k_channel *chan,
                                  int16_t *pTxPowerIndexOffset)
 {
+#define SM_PD_GAIN(x) SM(0x38, AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##x)
+#define SM_PDGAIN_B(x, y) \
+               SM((gainBoundaries[x]), AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_##y)
+
        struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
        struct cal_data_per_freq *pRawDataset;
        u8 *pCalBChans = NULL;
@@ -2106,6 +2200,12 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
                numPiers = AR5416_NUM_5G_CAL_PIERS;
        }
 
+       if (OLC_FOR_AR9280_20_LATER && IS_CHAN_2GHZ(chan)) {
+               pRawDataset = pEepData->calPierData2G[0];
+               ah->initPDADC = ((struct calDataPerFreqOpLoop *)
+                                pRawDataset)->vpdPdg[0][0];
+       }
+
        numXpdGain = 0;
 
        for (i = 1; i <= AR5416_PD_GAINS_IN_MASK; i++) {
@@ -2128,7 +2228,7 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
                      xpdGainValues[2]);
 
        for (i = 0; i < AR5416_MAX_CHAINS; i++) {
-               if (AR_SREV_5416_V20_OR_LATER(ah) &&
+               if (AR_SREV_5416_20_OR_LATER(ah) &&
                    (ah->rxchainmask == 5 || ah->txchainmask == 5) &&
                    (i != 0)) {
                        regChainOffset = (i == 1) ? 0x2000 : 0x1000;
@@ -2141,25 +2241,45 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
                        else
                                pRawDataset = pEepData->calPierData5G[i];
 
-                       ath9k_hw_get_def_gain_boundaries_pdadcs(ah, chan,
-                                           pRawDataset, pCalBChans,
-                                           numPiers, pdGainOverlap_t2,
-                                           &tMinCalPower, gainBoundaries,
-                                           pdadcValues, numXpdGain);
 
-                       if ((i == 0) || AR_SREV_5416_V20_OR_LATER(ah)) {
-                               REG_WRITE(ah,
-                                         AR_PHY_TPCRG5 + regChainOffset,
-                                         SM(pdGainOverlap_t2,
-                                            AR_PHY_TPCRG5_PD_GAIN_OVERLAP)
-                                         | SM(gainBoundaries[0],
-                                              AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_1)
-                                         | SM(gainBoundaries[1],
-                                              AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_2)
-                                         | SM(gainBoundaries[2],
-                                              AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_3)
-                                         | SM(gainBoundaries[3],
-                                      AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4));
+                       if (OLC_FOR_AR9280_20_LATER) {
+                               u8 pcdacIdx;
+                               u8 txPower;
+
+                               ath9k_get_txgain_index(ah, chan,
+                               (struct calDataPerFreqOpLoop *)pRawDataset,
+                               pCalBChans, numPiers, &txPower, &pcdacIdx);
+                               ath9k_olc_get_pdadcs(ah, pcdacIdx,
+                                                    txPower/2, pdadcValues);
+                       } else {
+                               ath9k_hw_get_def_gain_boundaries_pdadcs(ah,
+                                                       chan, pRawDataset,
+                                                       pCalBChans, numPiers,
+                                                       pdGainOverlap_t2,
+                                                       &tMinCalPower,
+                                                       gainBoundaries,
+                                                       pdadcValues,
+                                                       numXpdGain);
+                       }
+
+                       if ((i == 0) || AR_SREV_5416_20_OR_LATER(ah)) {
+                               if (OLC_FOR_AR9280_20_LATER) {
+                                       REG_WRITE(ah,
+                                               AR_PHY_TPCRG5 + regChainOffset,
+                                               SM(0x6,
+                                               AR_PHY_TPCRG5_PD_GAIN_OVERLAP) |
+                                               SM_PD_GAIN(1) | SM_PD_GAIN(2) |
+                                               SM_PD_GAIN(3) | SM_PD_GAIN(4));
+                               } else {
+                                       REG_WRITE(ah,
+                                               AR_PHY_TPCRG5 + regChainOffset,
+                                               SM(pdGainOverlap_t2,
+                                               AR_PHY_TPCRG5_PD_GAIN_OVERLAP)|
+                                               SM_PDGAIN_B(0, 1) |
+                                               SM_PDGAIN_B(1, 2) |
+                                               SM_PDGAIN_B(2, 3) |
+                                               SM_PDGAIN_B(3, 4));
+                               }
                        }
 
                        regOffset = AR_PHY_BASE + (672 << 2) + regChainOffset;
@@ -2193,6 +2313,8 @@ static bool ath9k_hw_set_def_power_cal_table(struct ath_hw *ah,
        *pTxPowerIndexOffset = 0;
 
        return true;
+#undef SM_PD_GAIN
+#undef SM_PDGAIN_B
 }
 
 static bool ath9k_hw_set_def_power_per_rate_table(struct ath_hw *ah,
@@ -2493,13 +2615,14 @@ static int ath9k_hw_def_set_txpower(struct ath_hw *ah,
                                    u8 twiceMaxRegulatoryPower,
                                    u8 powerLimit)
 {
+#define RT_AR_DELTA(x) (ratesArray[x] - cck_ofdm_delta)
        struct ar5416_eeprom_def *pEepData = &ah->eeprom.def;
        struct modal_eep_header *pModal =
                &(pEepData->modalHeader[IS_CHAN_2GHZ(chan)]);
        int16_t ratesArray[Ar5416RateSize];
        int16_t txPowerIndexOffset = 0;
        u8 ht40PowerIncForPdadc = 2;
-       int i;
+       int i, cck_ofdm_delta = 0;
 
        memset(ratesArray, 0, sizeof(ratesArray));
 
@@ -2548,16 +2671,30 @@ static int ath9k_hw_def_set_txpower(struct ath_hw *ah,
                  | ATH9K_POW_SM(ratesArray[rate24mb], 0));
 
        if (IS_CHAN_2GHZ(chan)) {
-               REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
-                         ATH9K_POW_SM(ratesArray[rate2s], 24)
-                         | ATH9K_POW_SM(ratesArray[rate2l], 16)
-                         | ATH9K_POW_SM(ratesArray[rateXr], 8)
-                         | ATH9K_POW_SM(ratesArray[rate1l], 0));
-               REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
-                         ATH9K_POW_SM(ratesArray[rate11s], 24)
-                         | ATH9K_POW_SM(ratesArray[rate11l], 16)
-                         | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
-                         | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
+               if (OLC_FOR_AR9280_20_LATER) {
+                       cck_ofdm_delta = 2;
+                       REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+                               ATH9K_POW_SM(RT_AR_DELTA(rate2s), 24)
+                               | ATH9K_POW_SM(RT_AR_DELTA(rate2l), 16)
+                               | ATH9K_POW_SM(ratesArray[rateXr], 8)
+                               | ATH9K_POW_SM(RT_AR_DELTA(rate1l), 0));
+                       REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+                               ATH9K_POW_SM(RT_AR_DELTA(rate11s), 24)
+                               | ATH9K_POW_SM(RT_AR_DELTA(rate11l), 16)
+                               | ATH9K_POW_SM(RT_AR_DELTA(rate5_5s), 8)
+                               | ATH9K_POW_SM(RT_AR_DELTA(rate5_5l), 0));
+               } else {
+                       REG_WRITE(ah, AR_PHY_POWER_TX_RATE3,
+                               ATH9K_POW_SM(ratesArray[rate2s], 24)
+                               | ATH9K_POW_SM(ratesArray[rate2l], 16)
+                               | ATH9K_POW_SM(ratesArray[rateXr], 8)
+                               | ATH9K_POW_SM(ratesArray[rate1l], 0));
+                       REG_WRITE(ah, AR_PHY_POWER_TX_RATE4,
+                               ATH9K_POW_SM(ratesArray[rate11s], 24)
+                               | ATH9K_POW_SM(ratesArray[rate11l], 16)
+                               | ATH9K_POW_SM(ratesArray[rate5_5s], 8)
+                               | ATH9K_POW_SM(ratesArray[rate5_5l], 0));
+               }
        }
 
        REG_WRITE(ah, AR_PHY_POWER_TX_RATE5,
@@ -2590,12 +2727,19 @@ static int ath9k_hw_def_set_txpower(struct ath_hw *ah,
                                         ht40PowerIncForPdadc, 8)
                          | ATH9K_POW_SM(ratesArray[rateHt40_4] +
                                         ht40PowerIncForPdadc, 0));
-
-               REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
-                         ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
-                         | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
-                         | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
-                         | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
+               if (OLC_FOR_AR9280_20_LATER) {
+                       REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+                               ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+                               | ATH9K_POW_SM(RT_AR_DELTA(rateExtCck), 16)
+                               | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+                               | ATH9K_POW_SM(RT_AR_DELTA(rateDupCck), 0));
+               } else {
+                       REG_WRITE(ah, AR_PHY_POWER_TX_RATE9,
+                               ATH9K_POW_SM(ratesArray[rateExtOfdm], 24)
+                               | ATH9K_POW_SM(ratesArray[rateExtCck], 16)
+                               | ATH9K_POW_SM(ratesArray[rateDupOfdm], 8)
+                               | ATH9K_POW_SM(ratesArray[rateDupCck], 0));
+               }
        }
 
        REG_WRITE(ah, AR_PHY_POWER_TX_SUB,
@@ -2615,6 +2759,21 @@ static int ath9k_hw_def_set_txpower(struct ath_hw *ah,
        else
                ah->regulatory.max_power_level = ratesArray[i];
 
+       switch(ar5416_get_ntxchains(ah->txchainmask)) {
+       case 1:
+               break;
+       case 2:
+               ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_TWO_CHAIN;
+               break;
+       case 3:
+               ah->regulatory.max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
+               break;
+       default:
+               DPRINTF(ah->ah_sc, ATH_DBG_EEPROM,
+                       "Invalid chainmask configuration\n");
+               break;
+       }
+
        return 0;
 }
 
index 99863b570441262a9f912b9ef54607a8ed99e099..d6f6108f63c7c7e2d6e6b60a17fa11d4aa731ee8 100644 (file)
 #define SUB_NUM_CTL_MODES_AT_5G_40 2
 #define SUB_NUM_CTL_MODES_AT_2G_40 3
 
+#define INCREASE_MAXPOW_BY_TWO_CHAIN     6  /* 10*log10(2)*2 */
+#define INCREASE_MAXPOW_BY_THREE_CHAIN   10 /* 10*log10(3)*2 */
+
+/*
+ * For AR9285 and later chipsets, the following bits are not being programmed
+ * in EEPROM and so need to be enabled always.
+ *
+ * Bit 0: en_fcc_mid
+ * Bit 1: en_jap_mid
+ * Bit 2: en_fcc_dfs_ht40
+ * Bit 3: en_jap_ht40
+ * Bit 4: en_jap_dfs_ht40
+ */
+#define AR9285_RDEXT_DEFAULT    0x1F
+
 #define AR_EEPROM_MAC(i)       (0x1d+(i))
 #define ATH9K_POW_SM(_r, _s)   (((_r) & 0x3f) << (_s))
 #define FREQ2FBIN(x, y)                ((y) ? ((x) - 2300) : (((x) - 4800) / 5))
 #define ath9k_hw_use_flash(_ah)        (!(_ah->ah_flags & AH_USE_EEPROM))
 
+#define OLC_FOR_AR9280_20_LATER (AR_SREV_9280_20_OR_LATER(ah) && \
+                                ah->eep_ops->get_eeprom(ah, EEP_OL_PWRCTRL))
+
 #define AR_EEPROM_RFSILENT_GPIO_SEL     0x001c
 #define AR_EEPROM_RFSILENT_GPIO_SEL_S   2
 #define AR_EEPROM_RFSILENT_POLARITY     0x0002
 #define AR5416_EEP_MINOR_VER_17      0x11
 #define AR5416_EEP_MINOR_VER_19      0x13
 #define AR5416_EEP_MINOR_VER_20      0x14
+#define AR5416_EEP_MINOR_VER_22      0x16
 
 #define AR5416_NUM_5G_CAL_PIERS         8
 #define AR5416_NUM_2G_CAL_PIERS         4
 #define AR5416_EEP4K_PD_GAIN_ICEPTS           5
 #define AR5416_EEP4K_MAX_CHAINS               1
 
+#define AR9280_TX_GAIN_TABLE_SIZE 22
+
 enum eeprom_param {
        EEP_NFTHRESH_5,
        EEP_NFTHRESH_2,
@@ -172,7 +193,10 @@ enum eeprom_param {
        EEP_RX_MASK,
        EEP_RXGAIN_TYPE,
        EEP_TXGAIN_TYPE,
+       EEP_OL_PWRCTRL,
+       EEP_RC_CHAIN_MASK,
        EEP_DAC_HPWR_5G,
+       EEP_FRAC_N_5G
 };
 
 enum ar5416_rates {
@@ -212,12 +236,14 @@ struct base_eep_header {
        u8 futureBase_1[2];
        u8 rxGainType;
        u8 dacHiPwrMode_5G;
-       u8 futureBase_2;
+       u8 openLoopPwrCntl;
        u8 dacLpMode;
        u8 txGainType;
        u8 rcChainMask;
        u8 desiredScaleCCK;
-       u8 futureBase_3[23];
+       u8 power_table_offset;
+       u8 frac_n_5g;
+       u8 futureBase_3[21];
 } __packed;
 
 struct base_eep_header_4k {
@@ -235,7 +261,7 @@ struct base_eep_header_4k {
        u16 deviceCap;
        u32 binBuildNumber;
        u8 deviceType;
-       u8 futureBase[1];
+       u8 txGainType;
 } __packed;
 
 
@@ -291,6 +317,13 @@ struct modal_eep_header {
        struct spur_chan spurChans[AR5416_EEPROM_MODAL_SPURS];
 } __packed;
 
+struct calDataPerFreqOpLoop {
+       u8 pwrPdg[2][5];
+       u8 vpdPdg[2][5];
+       u8 pcdac[2][5];
+       u8 empty[2][5];
+} __packed;
+
 struct modal_eep_4k_header {
        u32  antCtrlChain[AR5416_EEP4K_MAX_CHAINS];
        u32  antCtrlCommon;
index cad8e39c201eb6d3f3360b605ac0d100753363f6..d494e98ba971b3160fcd3830deb1d882fc65152a 100644 (file)
@@ -84,11 +84,13 @@ static u32 ath9k_hw_mac_to_clks(struct ath_hw *ah, u32 usecs)
                return ath9k_hw_mac_clks(ah, usecs);
 }
 
-bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val)
+bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout)
 {
        int i;
 
-       for (i = 0; i < (AH_TIMEOUT / AH_TIME_QUANTUM); i++) {
+       BUG_ON(timeout < AH_TIME_QUANTUM);
+
+       for (i = 0; i < (timeout / AH_TIME_QUANTUM); i++) {
                if ((REG_READ(ah, reg) & mask) == val)
                        return true;
 
@@ -96,8 +98,8 @@ bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val)
        }
 
        DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
-               "timeout on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
-               reg, REG_READ(ah, reg), mask, val);
+               "timeout (%d us) on reg 0x%x: 0x%08x & 0x%08x != 0x%08x\n",
+               timeout, reg, REG_READ(ah, reg), mask, val);
 
        return false;
 }
@@ -389,6 +391,25 @@ static void ath9k_hw_set_defaults(struct ath_hw *ah)
        }
 
        ah->config.intr_mitigation = 1;
+
+       /*
+        * We need this for PCI devices only (Cardbus, PCI, miniPCI)
+        * _and_ if on non-uniprocessor systems (Multiprocessor/HT).
+        * This means we use it for all AR5416 devices, and the few
+        * minor PCI AR9280 devices out there.
+        *
+        * Serialization is required because these devices do not handle
+        * well the case of two concurrent reads/writes due to the latency
+        * involved. During one read/write another read/write can be issued
+        * on another CPU while the previous read/write may still be working
+        * on our hardware, if we hit this case the hardware poops in a loop.
+        * We prevent this by serializing reads and writes.
+        *
+        * This issue is not present on PCI-Express devices or pre-AR5416
+        * devices (legacy, 802.11abg).
+        */
+       if (num_possible_cpus() > 1)
+               ah->config.serialize_regmode = SER_REG_MODE_AUTO;
 }
 
 static struct ath_hw *ath9k_hw_newstate(u16 devid, struct ath_softc *sc,
@@ -608,7 +629,8 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
        }
 
        if (ah->config.serialize_regmode == SER_REG_MODE_AUTO) {
-               if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) {
+               if (ah->hw_version.macVersion == AR_SREV_VERSION_5416_PCI ||
+                   (AR_SREV_9280(ah) && !ah->is_pciexpress)) {
                        ah->config.serialize_regmode =
                                SER_REG_MODE_ON;
                } else {
@@ -660,22 +682,16 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
                ah->supp_cals = ADC_GAIN_CAL | ADC_DC_CAL | IQ_MISMATCH_CAL;
        }
 
-       if (AR_SREV_9160(ah)) {
-               ah->config.enable_ani = 1;
-               ah->ani_function = (ATH9K_ANI_SPUR_IMMUNITY_LEVEL |
-                                       ATH9K_ANI_FIRSTEP_LEVEL);
-       } else {
-               ah->ani_function = ATH9K_ANI_ALL;
-               if (AR_SREV_9280_10_OR_LATER(ah)) {
-                       ah->ani_function &=     ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
-               }
-       }
+       ah->ani_function = ATH9K_ANI_ALL;
+       if (AR_SREV_9280_10_OR_LATER(ah))
+               ah->ani_function &= ~ATH9K_ANI_NOISE_IMMUNITY_LEVEL;
 
        DPRINTF(sc, ATH_DBG_RESET,
                "This Mac Chip Rev 0x%02x.%x is \n",
                ah->hw_version.macVersion, ah->hw_version.macRev);
 
        if (AR_SREV_9285_12_OR_LATER(ah)) {
+
                INIT_INI_ARRAY(&ah->iniModes, ar9285Modes_9285_1_2,
                               ARRAY_SIZE(ar9285Modes_9285_1_2), 6);
                INIT_INI_ARRAY(&ah->iniCommon, ar9285Common_9285_1_2,
@@ -815,6 +831,22 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
        if (ecode != 0)
                goto bad;
 
+       if (AR_SREV_9285_12_OR_LATER(ah)) {
+               u32 txgain_type = ah->eep_ops->get_eeprom(ah, EEP_TXGAIN_TYPE);
+
+               /* txgain table */
+               if (txgain_type == AR5416_EEP_TXGAIN_HIGH_POWER) {
+                       INIT_INI_ARRAY(&ah->iniModesTxGain,
+                       ar9285Modes_high_power_tx_gain_9285_1_2,
+                       ARRAY_SIZE(ar9285Modes_high_power_tx_gain_9285_1_2), 6);
+               } else {
+                       INIT_INI_ARRAY(&ah->iniModesTxGain,
+                       ar9285Modes_original_tx_gain_9285_1_2,
+                       ARRAY_SIZE(ar9285Modes_original_tx_gain_9285_1_2), 6);
+               }
+
+       }
+
        /* rxgain table */
        if (AR_SREV_9280_20(ah))
                ath9k_hw_init_rxgain_ini(ah);
@@ -823,7 +855,16 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
        if (AR_SREV_9280_20(ah))
                ath9k_hw_init_txgain_ini(ah);
 
-       if (ah->hw_version.devid == AR9280_DEVID_PCI) {
+       if (!ath9k_hw_fill_cap_info(ah)) {
+               DPRINTF(sc, ATH_DBG_RESET, "failed ath9k_hw_fill_cap_info\n");
+               ecode = -EINVAL;
+               goto bad;
+       }
+
+       if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
+           test_bit(ATH9K_MODE_11A, ah->caps.wireless_modes)) {
+
+               /* EEPROM Fixup */
                for (i = 0; i < ah->iniModes.ia_rows; i++) {
                        u32 reg = INI_RA(&ah->iniModes, i, 0);
 
@@ -838,13 +879,6 @@ static struct ath_hw *ath9k_hw_do_attach(u16 devid, struct ath_softc *sc,
                }
        }
 
-       if (!ath9k_hw_fill_cap_info(ah)) {
-               DPRINTF(sc, ATH_DBG_RESET,
-                       "failed ath9k_hw_fill_cap_info\n");
-               ecode = -EINVAL;
-               goto bad;
-       }
-
        ecode = ath9k_hw_init_macaddr(ah);
        if (ecode != 0) {
                DPRINTF(sc, ATH_DBG_RESET,
@@ -1149,7 +1183,7 @@ static void ath9k_hw_override_ini(struct ath_hw *ah,
        REG_SET_BIT(ah, AR_DIAG_SW, (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
 
 
-       if (!AR_SREV_5416_V20_OR_LATER(ah) ||
+       if (!AR_SREV_5416_20_OR_LATER(ah) ||
            AR_SREV_9280_10_OR_LATER(ah))
                return;
 
@@ -1200,6 +1234,17 @@ static u32 ath9k_hw_ini_fixup(struct ath_hw *ah,
                return ath9k_hw_def_ini_fixup(ah, pEepData, reg, value);
 }
 
+static void ath9k_olc_init(struct ath_hw *ah)
+{
+       u32 i;
+
+       for (i = 0; i < AR9280_TX_GAIN_TABLE_SIZE; i++)
+               ah->originalGain[i] =
+                       MS(REG_READ(ah, AR_PHY_TX_GAIN_TBL1 + i * 4),
+                                       AR_PHY_TX_GAIN);
+       ah->PDADCdelta = 0;
+}
+
 static int ath9k_hw_process_ini(struct ath_hw *ah,
                                struct ath9k_channel *chan,
                                enum ath9k_ht_macmode macmode)
@@ -1240,7 +1285,7 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
        REG_WRITE(ah, AR_PHY_ADC_SERIAL_CTL, AR_PHY_SEL_EXTERNAL_RADIO);
        ah->eep_ops->set_addac(ah, chan);
 
-       if (AR_SREV_5416_V22_OR_LATER(ah)) {
+       if (AR_SREV_5416_22_OR_LATER(ah)) {
                REG_WRITE_ARRAY(&ah->iniAddac, 1, regWrites);
        } else {
                struct ar5416IniArray temp;
@@ -1278,7 +1323,8 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
        if (AR_SREV_9280(ah))
                REG_WRITE_ARRAY(&ah->iniModesRxGain, modesIndex, regWrites);
 
-       if (AR_SREV_9280(ah))
+       if (AR_SREV_9280(ah) || (AR_SREV_9285(ah) &&
+           AR_SREV_9285_12_OR_LATER(ah)))
                REG_WRITE_ARRAY(&ah->iniModesTxGain, modesIndex, regWrites);
 
        for (i = 0; i < ah->iniCommon.ia_rows; i++) {
@@ -1306,6 +1352,9 @@ static int ath9k_hw_process_ini(struct ath_hw *ah,
        ath9k_hw_set_regs(ah, chan, macmode);
        ath9k_hw_init_chain_masks(ah);
 
+       if (OLC_FOR_AR9280_20_LATER)
+               ath9k_olc_init(ah);
+
        status = ah->eep_ops->set_txpower(ah, chan,
                                  ath9k_regd_get_ctl(ah, chan),
                                  channel->max_antenna_gain * 2,
@@ -1464,6 +1513,14 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
        u32 rst_flags;
        u32 tmpReg;
 
+       if (AR_SREV_9100(ah)) {
+               u32 val = REG_READ(ah, AR_RTC_DERIVED_CLK);
+               val &= ~AR_RTC_DERIVED_CLK_PERIOD;
+               val |= SM(1, AR_RTC_DERIVED_CLK_PERIOD);
+               REG_WRITE(ah, AR_RTC_DERIVED_CLK, val);
+               (void)REG_READ(ah, AR_RTC_DERIVED_CLK);
+       }
+
        REG_WRITE(ah, AR_RTC_FORCE_WAKE, AR_RTC_FORCE_WAKE_EN |
                  AR_RTC_FORCE_WAKE_ON_INT);
 
@@ -1490,7 +1547,7 @@ static bool ath9k_hw_set_reset(struct ath_hw *ah, int type)
        udelay(50);
 
        REG_WRITE(ah, AR_RTC_RC, 0);
-       if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0)) {
+       if (!ath9k_hw_wait(ah, AR_RTC_RC, AR_RTC_RC_M, 0, AH_WAIT_TIMEOUT)) {
                DPRINTF(ah->ah_sc, ATH_DBG_RESET,
                        "RTC stuck in MAC reset\n");
                return false;
@@ -1513,12 +1570,14 @@ static bool ath9k_hw_set_reset_power_on(struct ath_hw *ah)
                  AR_RTC_FORCE_WAKE_ON_INT);
 
        REG_WRITE(ah, AR_RTC_RESET, 0);
+       udelay(2);
        REG_WRITE(ah, AR_RTC_RESET, 1);
 
        if (!ath9k_hw_wait(ah,
                           AR_RTC_STATUS,
                           AR_RTC_STATUS_M,
-                          AR_RTC_STATUS_ON)) {
+                          AR_RTC_STATUS_ON,
+                          AH_WAIT_TIMEOUT)) {
                DPRINTF(ah->ah_sc, ATH_DBG_RESET, "RTC not waking up\n");
                return false;
        }
@@ -1580,7 +1639,10 @@ static void ath9k_hw_set_regs(struct ath_hw *ah, struct ath9k_channel *chan,
 static bool ath9k_hw_chip_reset(struct ath_hw *ah,
                                struct ath9k_channel *chan)
 {
-       if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
+       if (OLC_FOR_AR9280_20_LATER) {
+               if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_POWER_ON))
+                       return false;
+       } else if (!ath9k_hw_set_reset_reg(ah, ATH9K_RESET_WARM))
                return false;
 
        if (!ath9k_hw_setpower(ah, ATH9K_PM_AWAKE))
@@ -1610,7 +1672,7 @@ static bool ath9k_hw_channel_change(struct ath_hw *ah,
 
        REG_WRITE(ah, AR_PHY_RFBUS_REQ, AR_PHY_RFBUS_REQ_EN);
        if (!ath9k_hw_wait(ah, AR_PHY_RFBUS_GRANT, AR_PHY_RFBUS_GRANT_EN,
-                          AR_PHY_RFBUS_GRANT_EN)) {
+                          AR_PHY_RFBUS_GRANT_EN, AH_WAIT_TIMEOUT)) {
                DPRINTF(ah->ah_sc, ATH_DBG_REG_IO,
                        "Could not kill baseband RX\n");
                return false;
@@ -2384,14 +2446,11 @@ bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac)
 
 bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
                                 const struct ath9k_keyval *k,
-                                const u8 *mac, int xorKey)
+                                const u8 *mac)
 {
        const struct ath9k_hw_capabilities *pCap = &ah->caps;
        u32 key0, key1, key2, key3, key4;
        u32 keyType;
-       u32 xorMask = xorKey ?
-               (ATH9K_KEY_XOR << 24 | ATH9K_KEY_XOR << 16 | ATH9K_KEY_XOR << 8
-                | ATH9K_KEY_XOR) : 0;
 
        if (entry >= pCap->keycache_size) {
                DPRINTF(ah->ah_sc, ATH_DBG_KEYCACHE,
@@ -2443,26 +2502,57 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
                return false;
        }
 
-       key0 = get_unaligned_le32(k->kv_val + 0) ^ xorMask;
-       key1 = (get_unaligned_le16(k->kv_val + 4) ^ xorMask) & 0xffff;
-       key2 = get_unaligned_le32(k->kv_val + 6) ^ xorMask;
-       key3 = (get_unaligned_le16(k->kv_val + 10) ^ xorMask) & 0xffff;
-       key4 = get_unaligned_le32(k->kv_val + 12) ^ xorMask;
+       key0 = get_unaligned_le32(k->kv_val + 0);
+       key1 = get_unaligned_le16(k->kv_val + 4);
+       key2 = get_unaligned_le32(k->kv_val + 6);
+       key3 = get_unaligned_le16(k->kv_val + 10);
+       key4 = get_unaligned_le32(k->kv_val + 12);
        if (k->kv_len <= LEN_WEP104)
                key4 &= 0xff;
 
+       /*
+        * Note: Key cache registers access special memory area that requires
+        * two 32-bit writes to actually update the values in the internal
+        * memory. Consequently, the exact order and pairs used here must be
+        * maintained.
+        */
+
        if (keyType == AR_KEYTABLE_TYPE_TKIP && ATH9K_IS_MIC_ENABLED(ah)) {
                u16 micentry = entry + 64;
 
+               /*
+                * Write inverted key[47:0] first to avoid Michael MIC errors
+                * on frames that could be sent or received at the same time.
+                * The correct key will be written in the end once everything
+                * else is ready.
+                */
                REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), ~key0);
                REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), ~key1);
+
+               /* Write key[95:48] */
                REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
                REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
+
+               /* Write key[127:96] and key type */
                REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
                REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
+
+               /* Write MAC address for the entry */
                (void) ath9k_hw_keysetmac(ah, entry, mac);
 
                if (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) {
+                       /*
+                        * TKIP uses two key cache entries:
+                        * Michael MIC TX/RX keys in the same key cache entry
+                        * (idx = main index + 64):
+                        * key0 [31:0] = RX key [31:0]
+                        * key1 [15:0] = TX key [31:16]
+                        * key1 [31:16] = reserved
+                        * key2 [31:0] = RX key [63:32]
+                        * key3 [15:0] = TX key [15:0]
+                        * key3 [31:16] = reserved
+                        * key4 [31:0] = TX key [63:32]
+                        */
                        u32 mic0, mic1, mic2, mic3, mic4;
 
                        mic0 = get_unaligned_le32(k->kv_mic + 0);
@@ -2470,45 +2560,84 @@ bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
                        mic1 = get_unaligned_le16(k->kv_txmic + 2) & 0xffff;
                        mic3 = get_unaligned_le16(k->kv_txmic + 0) & 0xffff;
                        mic4 = get_unaligned_le32(k->kv_txmic + 4);
+
+                       /* Write RX[31:0] and TX[31:16] */
                        REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
                        REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), mic1);
+
+                       /* Write RX[63:32] and TX[15:0] */
                        REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
                        REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), mic3);
+
+                       /* Write TX[63:32] and keyType(reserved) */
                        REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), mic4);
                        REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
                                  AR_KEYTABLE_TYPE_CLR);
 
                } else {
+                       /*
+                        * TKIP uses four key cache entries (two for group
+                        * keys):
+                        * Michael MIC TX/RX keys are in different key cache
+                        * entries (idx = main index + 64 for TX and
+                        * main index + 32 + 96 for RX):
+                        * key0 [31:0] = TX/RX MIC key [31:0]
+                        * key1 [31:0] = reserved
+                        * key2 [31:0] = TX/RX MIC key [63:32]
+                        * key3 [31:0] = reserved
+                        * key4 [31:0] = reserved
+                        *
+                        * Upper layer code will call this function separately
+                        * for TX and RX keys when these registers offsets are
+                        * used.
+                        */
                        u32 mic0, mic2;
 
                        mic0 = get_unaligned_le32(k->kv_mic + 0);
                        mic2 = get_unaligned_le32(k->kv_mic + 4);
+
+                       /* Write MIC key[31:0] */
                        REG_WRITE(ah, AR_KEYTABLE_KEY0(micentry), mic0);
                        REG_WRITE(ah, AR_KEYTABLE_KEY1(micentry), 0);
+
+                       /* Write MIC key[63:32] */
                        REG_WRITE(ah, AR_KEYTABLE_KEY2(micentry), mic2);
                        REG_WRITE(ah, AR_KEYTABLE_KEY3(micentry), 0);
+
+                       /* Write TX[63:32] and keyType(reserved) */
                        REG_WRITE(ah, AR_KEYTABLE_KEY4(micentry), 0);
                        REG_WRITE(ah, AR_KEYTABLE_TYPE(micentry),
                                  AR_KEYTABLE_TYPE_CLR);
                }
+
+               /* MAC address registers are reserved for the MIC entry */
                REG_WRITE(ah, AR_KEYTABLE_MAC0(micentry), 0);
                REG_WRITE(ah, AR_KEYTABLE_MAC1(micentry), 0);
+
+               /*
+                * Write the correct (un-inverted) key[47:0] last to enable
+                * TKIP now that all other registers are set with correct
+                * values.
+                */
                REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
                REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
        } else {
+               /* Write key[47:0] */
                REG_WRITE(ah, AR_KEYTABLE_KEY0(entry), key0);
                REG_WRITE(ah, AR_KEYTABLE_KEY1(entry), key1);
+
+               /* Write key[95:48] */
                REG_WRITE(ah, AR_KEYTABLE_KEY2(entry), key2);
                REG_WRITE(ah, AR_KEYTABLE_KEY3(entry), key3);
+
+               /* Write key[127:96] and key type */
                REG_WRITE(ah, AR_KEYTABLE_KEY4(entry), key4);
                REG_WRITE(ah, AR_KEYTABLE_TYPE(entry), keyType);
 
+               /* Write MAC address for the entry */
                (void) ath9k_hw_keysetmac(ah, entry, mac);
        }
 
-       if (ah->curchan == NULL)
-               return true;
-
        return true;
 }
 
@@ -2801,6 +2930,8 @@ bool ath9k_hw_getisr(struct ath_hw *ah, enum ath9k_int *masked)
                                mask2 |= ATH9K_INT_GTT;
                        if (isr2 & AR_ISR_S2_CST)
                                mask2 |= ATH9K_INT_CST;
+                       if (isr2 & AR_ISR_S2_TSFOOR)
+                               mask2 |= ATH9K_INT_TSFOOR;
                }
 
                isr = REG_READ(ah, AR_ISR_RAC);
@@ -2946,7 +3077,9 @@ enum ath9k_int ath9k_hw_set_interrupts(struct ath_hw *ah, enum ath9k_int ints)
                if (ints & ATH9K_INT_DTIMSYNC)
                        mask2 |= AR_IMR_S2_DTIMSYNC;
                if (ints & ATH9K_INT_CABEND)
-                       mask2 |= (AR_IMR_S2_CABEND);
+                       mask2 |= AR_IMR_S2_CABEND;
+               if (ints & ATH9K_INT_TSFOOR)
+                       mask2 |= AR_IMR_S2_TSFOOR;
        }
 
        if (ints & (ATH9K_INT_GTT | ATH9K_INT_CST)) {
@@ -3116,6 +3249,8 @@ void ath9k_hw_set_sta_beacon_timers(struct ath_hw *ah,
                    AR_TBTT_TIMER_EN | AR_TIM_TIMER_EN |
                    AR_DTIM_TIMER_EN);
 
+       /* TSF Out of Range Threshold */
+       REG_WRITE(ah, AR_TSFOOR_THRESHOLD, bs->bs_tsfoor_threshold);
 }
 
 /*******************/
@@ -3128,10 +3263,11 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah)
        u16 capField = 0, eeval;
 
        eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_0);
-
        ah->regulatory.current_rd = eeval;
 
        eeval = ah->eep_ops->get_eeprom(ah, EEP_REG_1);
+       if (AR_SREV_9285_10_OR_LATER(ah))
+               eeval |= AR9285_RDEXT_DEFAULT;
        ah->regulatory.current_rd_ext = eeval;
 
        capField = ah->eep_ops->get_eeprom(ah, EEP_OP_CAP);
@@ -3182,14 +3318,11 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah)
        }
 
        pCap->tx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_TX_MASK);
-       if ((ah->is_pciexpress)
-           || (eeval & AR5416_OPFLAGS_11A)) {
-               pCap->rx_chainmask =
-                       ah->eep_ops->get_eeprom(ah, EEP_RX_MASK);
-       } else {
-               pCap->rx_chainmask =
-                       (ath9k_hw_gpio_get(ah, 0)) ? 0x5 : 0x7;
-       }
+       if ((ah->hw_version.devid == AR5416_DEVID_PCI) &&
+           !(eeval & AR5416_OPFLAGS_11A))
+               pCap->rx_chainmask = ath9k_hw_gpio_get(ah, 0) ? 0x5 : 0x7;
+       else
+               pCap->rx_chainmask = ah->eep_ops->get_eeprom(ah, EEP_RX_MASK);
 
        if (!(AR_SREV_9280(ah) && (ah->hw_version.macRev == 0)))
                ah->misc_mode |= AR_PCU_MIC_NEW_LOC_ENA;
@@ -3317,8 +3450,6 @@ bool ath9k_hw_fill_cap_info(struct ath_hw *ah)
 bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
                            u32 capability, u32 *result)
 {
-       const struct ath9k_hw_capabilities *pCap = &ah->caps;
-
        switch (type) {
        case ATH9K_CAP_CIPHER:
                switch (capability) {
@@ -3344,16 +3475,10 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
        case ATH9K_CAP_TKIP_SPLIT:
                return (ah->misc_mode & AR_PCU_MIC_NEW_LOC_ENA) ?
                        false : true;
-       case ATH9K_CAP_WME_TKIPMIC:
-               return 0;
-       case ATH9K_CAP_PHYCOUNTERS:
-               return ah->has_hw_phycounters ? 0 : -ENXIO;
        case ATH9K_CAP_DIVERSITY:
                return (REG_READ(ah, AR_PHY_CCK_DETECT) &
                        AR_PHY_CCK_DETECT_BB_ENABLE_ANT_FAST_DIV) ?
                        true : false;
-       case ATH9K_CAP_PHYDIAG:
-               return true;
        case ATH9K_CAP_MCAST_KEYSRCH:
                switch (capability) {
                case 0:
@@ -3368,18 +3493,6 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
                        }
                }
                return false;
-       case ATH9K_CAP_TSF_ADJUST:
-               return (ah->misc_mode & AR_PCU_TX_ADD_TSF) ?
-                       true : false;
-       case ATH9K_CAP_RFSILENT:
-               if (capability == 3)
-                       return false;
-       case ATH9K_CAP_ANT_CFG_2GHZ:
-               *result = pCap->num_antcfg_2ghz;
-               return true;
-       case ATH9K_CAP_ANT_CFG_5GHZ:
-               *result = pCap->num_antcfg_5ghz;
-               return true;
        case ATH9K_CAP_TXPOW:
                switch (capability) {
                case 0:
@@ -3395,6 +3508,10 @@ bool ath9k_hw_getcapability(struct ath_hw *ah, enum ath9k_capability_type type,
                        return 0;
                }
                return false;
+       case ATH9K_CAP_DS:
+               return (AR_SREV_9280_20_OR_LATER(ah) &&
+                       (ah->eep_ops->get_eeprom(ah, EEP_RC_CHAIN_MASK) == 1))
+                       ? false : true;
        default:
                return false;
        }
@@ -3428,12 +3545,6 @@ bool ath9k_hw_setcapability(struct ath_hw *ah, enum ath9k_capability_type type,
                else
                        ah->sta_id1_defaults &= ~AR_STA_ID1_MCAST_KSRCH;
                return true;
-       case ATH9K_CAP_TSF_ADJUST:
-               if (setting)
-                       ah->misc_mode |= AR_PCU_TX_ADD_TSF;
-               else
-                       ah->misc_mode &= ~AR_PCU_TX_ADD_TSF;
-               return true;
        default:
                return false;
        }
@@ -3700,9 +3811,8 @@ u64 ath9k_hw_gettsf64(struct ath_hw *ah)
 
 void ath9k_hw_settsf64(struct ath_hw *ah, u64 tsf64)
 {
-       REG_WRITE(ah, AR_TSF_L32, 0x00000000);
-       REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff);
        REG_WRITE(ah, AR_TSF_L32, tsf64 & 0xffffffff);
+       REG_WRITE(ah, AR_TSF_U32, (tsf64 >> 32) & 0xffffffff);
 }
 
 void ath9k_hw_reset_tsf(struct ath_hw *ah)
index 82111636c6932c7b3f77b1156487009078053b5f..dc681f011fdfa1b3be21686c6b1ce0805b7405b7 100644 (file)
@@ -42,8 +42,8 @@
 #define AR5416_MAGIC           0x19641014
 
 /* Register read/write primitives */
-#define REG_WRITE(_ah, _reg, _val) iowrite32(_val, _ah->ah_sc->mem + _reg)
-#define REG_READ(_ah, _reg) ioread32(_ah->ah_sc->mem + _reg)
+#define REG_WRITE(_ah, _reg, _val) ath9k_iowrite32((_ah), (_reg), (_val))
+#define REG_READ(_ah, _reg) ath9k_ioread32((_ah), (_reg))
 
 #define SM(_v, _f)  (((_v) << _f##_S) & _f)
 #define MS(_v, _f)  (((_v) & _f) >> _f##_S)
@@ -93,7 +93,7 @@
 #define ATH9K_NUM_QUEUES            10
 
 #define MAX_RATE_POWER              63
-#define AH_TIMEOUT                  100000
+#define AH_WAIT_TIMEOUT             100000 /* (us) */
 #define AH_TIME_QUANTUM             10
 #define AR_KEYTABLE_SIZE            128
 #define POWER_UP_TIME               200000
@@ -153,16 +153,10 @@ enum ath9k_capability_type {
        ATH9K_CAP_CIPHER = 0,
        ATH9K_CAP_TKIP_MIC,
        ATH9K_CAP_TKIP_SPLIT,
-       ATH9K_CAP_PHYCOUNTERS,
        ATH9K_CAP_DIVERSITY,
        ATH9K_CAP_TXPOW,
-       ATH9K_CAP_PHYDIAG,
        ATH9K_CAP_MCAST_KEYSRCH,
-       ATH9K_CAP_TSF_ADJUST,
-       ATH9K_CAP_WME_TKIPMIC,
-       ATH9K_CAP_RFSILENT,
-       ATH9K_CAP_ANT_CFG_2GHZ,
-       ATH9K_CAP_ANT_CFG_5GHZ
+       ATH9K_CAP_DS
 };
 
 struct ath9k_hw_capabilities {
@@ -249,6 +243,7 @@ enum ath9k_int {
        ATH9K_INT_DTIMSYNC = 0x00800000,
        ATH9K_INT_GPIO = 0x01000000,
        ATH9K_INT_CABEND = 0x02000000,
+       ATH9K_INT_TSFOOR = 0x04000000,
        ATH9K_INT_CST = 0x10000000,
        ATH9K_INT_GTT = 0x20000000,
        ATH9K_INT_FATAL = 0x40000000,
@@ -256,6 +251,7 @@ enum ath9k_int {
        ATH9K_INT_BMISC = ATH9K_INT_TIM |
                ATH9K_INT_DTIM |
                ATH9K_INT_DTIMSYNC |
+               ATH9K_INT_TSFOOR |
                ATH9K_INT_CABEND,
        ATH9K_INT_COMMON = ATH9K_INT_RXNOFRM |
                ATH9K_INT_RXDESC |
@@ -385,6 +381,7 @@ struct ath9k_beacon_state {
 #define ATH9K_BEACON_PERIOD       0x0000ffff
 #define ATH9K_BEACON_ENA          0x00800000
 #define ATH9K_BEACON_RESET_TSF    0x01000000
+#define ATH9K_TSFOOR_THRESHOLD    0x00004240 /* 16k us */
        u32 bs_dtimperiod;
        u16 bs_cfpperiod;
        u16 bs_cfpmaxduration;
@@ -392,6 +389,7 @@ struct ath9k_beacon_state {
        u16 bs_timoffset;
        u16 bs_bmissthreshold;
        u32 bs_sleepduration;
+       u32 bs_tsfoor_threshold;
 };
 
 struct chan_centers {
@@ -547,6 +545,10 @@ struct ath_hw {
        u8 txchainmask;
        u8 rxchainmask;
 
+       u32 originalGain[22];
+       int initPDADC;
+       int PDADCdelta;
+
        struct ar5416IniArray iniModes;
        struct ar5416IniArray iniCommon;
        struct ar5416IniArray iniBank0;
@@ -582,7 +584,7 @@ bool ath9k_hw_keyreset(struct ath_hw *ah, u16 entry);
 bool ath9k_hw_keysetmac(struct ath_hw *ah, u16 entry, const u8 *mac);
 bool ath9k_hw_set_keycache_entry(struct ath_hw *ah, u16 entry,
                                 const struct ath9k_keyval *k,
-                                const u8 *mac, int xorKey);
+                                const u8 *mac);
 bool ath9k_hw_keyisvalid(struct ath_hw *ah, u16 entry);
 
 /* GPIO / RFKILL / Antennae */
@@ -603,7 +605,7 @@ bool ath9k_hw_setantennaswitch(struct ath_hw *ah,
                               u8 *antenna_cfgd);
 
 /* General Operation */
-bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val);
+bool ath9k_hw_wait(struct ath_hw *ah, u32 reg, u32 mask, u32 val, u32 timeout);
 u32 ath9k_hw_reverse_bits(u32 val, u32 n);
 bool ath9k_get_channel_edges(struct ath_hw *ah, u16 flags, u16 *low, u16 *high);
 u16 ath9k_hw_computetxtime(struct ath_hw *ah, struct ath_rate_table *rates,
index d49236368a1c7e866df2f273517c1230e1ea5893..1d60c3706f1c204dfac5c0d32fc125717312bba1 100644 (file)
@@ -14,7 +14,7 @@
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-static const u32 ar5416Modes_9100[][6] = {
+static const u32 ar5416Modes[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
     { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
@@ -78,7 +78,7 @@ static const u32 ar5416Modes_9100[][6] = {
     { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
 };
 
-static const u32 ar5416Common_9100[][2] = {
+static const u32 ar5416Common[][2] = {
     { 0x0000000c, 0x00000000 },
     { 0x00000030, 0x00020015 },
     { 0x00000034, 0x00000005 },
@@ -456,12 +456,12 @@ static const u32 ar5416Common_9100[][2] = {
     { 0x0000a3e0, 0x000001ce },
 };
 
-static const u32 ar5416Bank0_9100[][2] = {
+static const u32 ar5416Bank0[][2] = {
     { 0x000098b0, 0x1e5795e5 },
     { 0x000098e0, 0x02008020 },
 };
 
-static const u32 ar5416BB_RfGain_9100[][3] = {
+static const u32 ar5416BB_RfGain[][3] = {
     { 0x00009a00, 0x00000000, 0x00000000 },
     { 0x00009a04, 0x00000040, 0x00000040 },
     { 0x00009a08, 0x00000080, 0x00000080 },
@@ -528,21 +528,21 @@ static const u32 ar5416BB_RfGain_9100[][3] = {
     { 0x00009afc, 0x000000f9, 0x000000f9 },
 };
 
-static const u32 ar5416Bank1_9100[][2] = {
+static const u32 ar5416Bank1[][2] = {
     { 0x000098b0, 0x02108421 },
     { 0x000098ec, 0x00000008 },
 };
 
-static const u32 ar5416Bank2_9100[][2] = {
+static const u32 ar5416Bank2[][2] = {
     { 0x000098b0, 0x0e73ff17 },
     { 0x000098e0, 0x00000420 },
 };
 
-static const u32 ar5416Bank3_9100[][3] = {
+static const u32 ar5416Bank3[][3] = {
     { 0x000098f0, 0x01400018, 0x01c00018 },
 };
 
-static const u32 ar5416Bank6_9100[][3] = {
+static const u32 ar5416Bank6[][3] = {
 
     { 0x0000989c, 0x00000000, 0x00000000 },
     { 0x0000989c, 0x00000000, 0x00000000 },
@@ -579,7 +579,7 @@ static const u32 ar5416Bank6_9100[][3] = {
     { 0x000098d0, 0x0000000f, 0x0010000f },
 };
 
-static const u32 ar5416Bank6TPC_9100[][3] = {
+static const u32 ar5416Bank6TPC[][3] = {
     { 0x0000989c, 0x00000000, 0x00000000 },
     { 0x0000989c, 0x00000000, 0x00000000 },
     { 0x0000989c, 0x00000000, 0x00000000 },
@@ -615,13 +615,13 @@ static const u32 ar5416Bank6TPC_9100[][3] = {
     { 0x000098d0, 0x0000000f, 0x0010000f },
 };
 
-static const u32 ar5416Bank7_9100[][2] = {
+static const u32 ar5416Bank7[][2] = {
     { 0x0000989c, 0x00000500 },
     { 0x0000989c, 0x00000800 },
     { 0x000098cc, 0x0000000e },
 };
 
-static const u32 ar5416Addac_9100[][2] = {
+static const u32 ar5416Addac[][2] = {
     {0x0000989c,  0x00000000 },
     {0x0000989c,  0x00000003 },
     {0x0000989c,  0x00000000 },
@@ -661,7 +661,7 @@ static const u32 ar5416Addac_9100[][2] = {
     {0x000098cc,  0x00000000 },
 };
 
-static const u32 ar5416Modes[][6] = {
+static const u32 ar5416Modes_9100[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
     { 0x000010b0, 0x00000e60, 0x00001cc0, 0x00007c70, 0x00003e38, 0x00001180 },
@@ -735,7 +735,7 @@ static const u32 ar5416Modes[][6] = {
     { 0x0000a334, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
 };
 
-static const u32 ar5416Common[][2] = {
+static const u32 ar5416Common_9100[][2] = {
     { 0x0000000c, 0x00000000 },
     { 0x00000030, 0x00020015 },
     { 0x00000034, 0x00000005 },
@@ -1109,12 +1109,12 @@ static const u32 ar5416Common[][2] = {
     { 0x0000a3e0, 0x000001ce },
 };
 
-static const u32 ar5416Bank0[][2] = {
+static const u32 ar5416Bank0_9100[][2] = {
     { 0x000098b0, 0x1e5795e5 },
     { 0x000098e0, 0x02008020 },
 };
 
-static const u32 ar5416BB_RfGain[][3] = {
+static const u32 ar5416BB_RfGain_9100[][3] = {
     { 0x00009a00, 0x00000000, 0x00000000 },
     { 0x00009a04, 0x00000040, 0x00000040 },
     { 0x00009a08, 0x00000080, 0x00000080 },
@@ -1181,21 +1181,21 @@ static const u32 ar5416BB_RfGain[][3] = {
     { 0x00009afc, 0x000000f9, 0x000000f9 },
 };
 
-static const u32 ar5416Bank1[][2] = {
+static const u32 ar5416Bank1_9100[][2] = {
     { 0x000098b0, 0x02108421},
     { 0x000098ec, 0x00000008},
 };
 
-static const u32 ar5416Bank2[][2] = {
+static const u32 ar5416Bank2_9100[][2] = {
     { 0x000098b0, 0x0e73ff17},
     { 0x000098e0, 0x00000420},
 };
 
-static const u32 ar5416Bank3[][3] = {
+static const u32 ar5416Bank3_9100[][3] = {
     { 0x000098f0, 0x01400018, 0x01c00018 },
 };
 
-static const u32 ar5416Bank6[][3] = {
+static const u32 ar5416Bank6_9100[][3] = {
 
     { 0x0000989c, 0x00000000, 0x00000000 },
     { 0x0000989c, 0x00000000, 0x00000000 },
@@ -1233,7 +1233,7 @@ static const u32 ar5416Bank6[][3] = {
 };
 
 
-static const u32 ar5416Bank6TPC[][3] = {
+static const u32 ar5416Bank6TPC_9100[][3] = {
 
     { 0x0000989c, 0x00000000, 0x00000000 },
     { 0x0000989c, 0x00000000, 0x00000000 },
@@ -1270,13 +1270,13 @@ static const u32 ar5416Bank6TPC[][3] = {
     { 0x000098d0, 0x0000000f, 0x0010000f },
 };
 
-static const u32 ar5416Bank7[][2] = {
+static const u32 ar5416Bank7_9100[][2] = {
     { 0x0000989c, 0x00000500 },
     { 0x0000989c, 0x00000800 },
     { 0x000098cc, 0x0000000e },
 };
 
-static const u32 ar5416Addac[][2] = {
+static const u32 ar5416Addac_9100[][2] = {
     {0x0000989c, 0x00000000 },
     {0x0000989c, 0x00000000 },
     {0x0000989c, 0x00000000 },
@@ -4121,6 +4121,7 @@ static const u_int32_t ar9285PciePhy_clkreq_off_L1_9285[][2] = {
     {0x00004044,  0x00000000 },
 };
 
+/* AR9285 v1_2 PCI Register Writes.  Created: 03/04/09 */
 static const u_int32_t ar9285Modes_9285_1_2[][6] = {
     { 0x00001030, 0x00000230, 0x00000460, 0x000002c0, 0x00000160, 0x000001e0 },
     { 0x00001070, 0x00000168, 0x000002d0, 0x00000318, 0x0000018c, 0x000001e0 },
@@ -4155,7 +4156,7 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
     { 0x000099bc, 0x00000600, 0x00000600, 0x00000c00, 0x00000c00, 0x00000c00 },
     { 0x000099c0, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4 },
     { 0x000099c4, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77, 0x06336f77 },
-    { 0x000099c8, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329, 0x60f65329 },
+    { 0x000099c8, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329, 0x6af65329 },
     { 0x000099cc, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8, 0x08f186c8 },
     { 0x000099d0, 0x00046384, 0x00046384, 0x00046384, 0x00046384, 0x00046384 },
     { 0x000099d4, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
@@ -4421,25 +4422,6 @@ static const u_int32_t ar9285Modes_9285_1_2[][6] = {
     { 0x0000a21c, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a, 0x1883800a },
     { 0x0000a230, 0x00000000, 0x00000000, 0x00000210, 0x00000108, 0x00000000 },
     { 0x0000a250, 0x0004f000, 0x0004f000, 0x0004a000, 0x0004a000, 0x0004a000 },
-    { 0x0000a274, 0x0a81c652, 0x0a81c652, 0x0a820652, 0x0a820652, 0x0a82a652 },
-    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
-    { 0x0000a304, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 },
-    { 0x0000a308, 0x00000000, 0x00000000, 0x00010408, 0x00010408, 0x00000000 },
-    { 0x0000a30c, 0x00000000, 0x00000000, 0x0001860a, 0x0001860a, 0x00000000 },
-    { 0x0000a310, 0x00000000, 0x00000000, 0x00020818, 0x00020818, 0x00000000 },
-    { 0x0000a314, 0x00000000, 0x00000000, 0x00024858, 0x00024858, 0x00000000 },
-    { 0x0000a318, 0x00000000, 0x00000000, 0x00026859, 0x00026859, 0x00000000 },
-    { 0x0000a31c, 0x00000000, 0x00000000, 0x0002985b, 0x0002985b, 0x00000000 },
-    { 0x0000a320, 0x00000000, 0x00000000, 0x0002b89a, 0x0002b89a, 0x00000000 },
-    { 0x0000a324, 0x00000000, 0x00000000, 0x0002d89b, 0x0002d89b, 0x00000000 },
-    { 0x0000a328, 0x00000000, 0x00000000, 0x0002f89c, 0x0002f89c, 0x00000000 },
-    { 0x0000a32c, 0x00000000, 0x00000000, 0x0003189d, 0x0003189d, 0x00000000 },
-    { 0x0000a330, 0x00000000, 0x00000000, 0x0003389e, 0x0003389e, 0x00000000 },
-    { 0x0000a334, 0x00000000, 0x00000000, 0x000368de, 0x000368de, 0x00000000 },
-    { 0x0000a338, 0x00000000, 0x00000000, 0x0003891e, 0x0003891e, 0x00000000 },
-    { 0x0000a33c, 0x00000000, 0x00000000, 0x0003a95e, 0x0003a95e, 0x00000000 },
-    { 0x0000a340, 0x00000000, 0x00000000, 0x0003e9df, 0x0003e9df, 0x00000000 },
-    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
     { 0x0000a358, 0x7999aa02, 0x7999aa02, 0x7999aa0e, 0x7999aa0e, 0x7999aa0e },
 };
 
@@ -4569,7 +4551,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
     { 0x00008110, 0x00000168 },
     { 0x00008118, 0x000100aa },
     { 0x0000811c, 0x00003210 },
-    { 0x00008120, 0x08f04800 },
+    { 0x00008120, 0x08f04810 },
     { 0x00008124, 0x00000000 },
     { 0x00008128, 0x00000000 },
     { 0x0000812c, 0x00000000 },
@@ -4585,7 +4567,7 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
     { 0x00008178, 0x00000100 },
     { 0x0000817c, 0x00000000 },
     { 0x000081c0, 0x00000000 },
-    { 0x000081d0, 0x00003210 },
+    { 0x000081d0, 0x0000320a },
     { 0x000081ec, 0x00000000 },
     { 0x000081f0, 0x00000000 },
     { 0x000081f4, 0x00000000 },
@@ -4709,8 +4691,6 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
     { 0x0000a268, 0x00000000 },
     { 0x0000a26c, 0x0ebae9e6 },
     { 0x0000d270, 0x0d820820 },
-    { 0x0000a278, 0x318c6318 },
-    { 0x0000a27c, 0x050c0318 },
     { 0x0000d35c, 0x07ffffef },
     { 0x0000d360, 0x0fffffe7 },
     { 0x0000d364, 0x17ffffe5 },
@@ -4725,8 +4705,6 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
     { 0x0000a388, 0x0c000000 },
     { 0x0000a38c, 0x20202020 },
     { 0x0000a390, 0x20202020 },
-    { 0x0000a394, 0x318c6318 },
-    { 0x0000a398, 0x00000318 },
     { 0x0000a39c, 0x00000001 },
     { 0x0000a3a0, 0x00000000 },
     { 0x0000a3a4, 0x00000000 },
@@ -4741,8 +4719,6 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
     { 0x0000a3cc, 0x20202020 },
     { 0x0000a3d0, 0x20202020 },
     { 0x0000a3d4, 0x20202020 },
-    { 0x0000a3dc, 0x318c6318 },
-    { 0x0000a3e0, 0x00000318 },
     { 0x0000a3e4, 0x00000000 },
     { 0x0000a3e8, 0x18c43433 },
     { 0x0000a3ec, 0x00f70081 },
@@ -4753,13 +4729,11 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
     { 0x00007810, 0x71c0d388 },
     { 0x00007814, 0x924934a8 },
     { 0x0000781c, 0x00000000 },
-    { 0x00007820, 0x00000c04 },
     { 0x00007824, 0x00d86fff },
     { 0x00007828, 0x26d2491b },
     { 0x0000782c, 0x6e36d97b },
     { 0x00007830, 0xedb6d96e },
     { 0x00007834, 0x71400087 },
-    { 0x00007838, 0xfac68801 },
     { 0x0000783c, 0x0001fffe },
     { 0x00007840, 0xffeb1a20 },
     { 0x00007844, 0x000c0db6 },
@@ -4772,10 +4746,81 @@ static const u_int32_t ar9285Common_9285_1_2[][2] = {
     { 0x00007860, 0x21084210 },
     { 0x00007864, 0xf7d7ffde },
     { 0x00007868, 0xc2034080 },
-    { 0x0000786c, 0x48609eb4 },
     { 0x00007870, 0x10142c00 },
 };
 
+static const u_int32_t ar9285Modes_high_power_tx_gain_9285_1_2[][6] = {
+    /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
+    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a304, 0x00000000, 0x00000000, 0x00005200, 0x00005200, 0x00000000 },
+    { 0x0000a308, 0x00000000, 0x00000000, 0x00007201, 0x00007201, 0x00000000 },
+    { 0x0000a30c, 0x00000000, 0x00000000, 0x0000b240, 0x0000b240, 0x00000000 },
+    { 0x0000a310, 0x00000000, 0x00000000, 0x0000d241, 0x0000d241, 0x00000000 },
+    { 0x0000a314, 0x00000000, 0x00000000, 0x0000f440, 0x0000f440, 0x00000000 },
+    { 0x0000a318, 0x00000000, 0x00000000, 0x00014640, 0x00014640, 0x00000000 },
+    { 0x0000a31c, 0x00000000, 0x00000000, 0x00018680, 0x00018680, 0x00000000 },
+    { 0x0000a320, 0x00000000, 0x00000000, 0x00019841, 0x00019841, 0x00000000 },
+    { 0x0000a324, 0x00000000, 0x00000000, 0x0001ca40, 0x0001ca40, 0x00000000 },
+    { 0x0000a328, 0x00000000, 0x00000000, 0x0001fa80, 0x0001fa80, 0x00000000 },
+    { 0x0000a32c, 0x00000000, 0x00000000, 0x00023ac0, 0x00023ac0, 0x00000000 },
+    { 0x0000a330, 0x00000000, 0x00000000, 0x0002ab40, 0x0002ab40, 0x00000000 },
+    { 0x0000a334, 0x00000000, 0x00000000, 0x00033d82, 0x00033d82, 0x00000000 },
+    { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
+    { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
+    { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x00007838, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803, 0xfac68803 },
+    { 0x0000786c, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe, 0x08609ebe },
+    { 0x00007820, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00, 0x00000c00 },
+    { 0x0000a274, 0x0a22a652, 0x0a22a652, 0x0a21a652, 0x0a21a652, 0x0a22a652 },
+    { 0x0000a278, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
+    { 0x0000a27c, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce, 0x050701ce },
+    { 0x0000a394, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
+    { 0x0000a398, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce },
+    { 0x0000a3dc, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce, 0x1ce739ce },
+    { 0x0000a3e0, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce, 0x000001ce },
+};
+
+static const u_int32_t ar9285Modes_original_tx_gain_9285_1_2[][6] = {
+    /* Address      5G-HT20     5G-HT40     2G-HT40     2G-HT20     Turbo   */
+    { 0x0000a300, 0x00000000, 0x00000000, 0x00000000, 0x00000000, 0x00000000 },
+    { 0x0000a304, 0x00000000, 0x00000000, 0x00009200, 0x00009200, 0x00000000 },
+    { 0x0000a308, 0x00000000, 0x00000000, 0x00010208, 0x00010208, 0x00000000 },
+    { 0x0000a30c, 0x00000000, 0x00000000, 0x00019608, 0x00019608, 0x00000000 },
+    { 0x0000a310, 0x00000000, 0x00000000, 0x00022618, 0x00022618, 0x00000000 },
+    { 0x0000a314, 0x00000000, 0x00000000, 0x0002a6c9, 0x0002a6c9, 0x00000000 },
+    { 0x0000a318, 0x00000000, 0x00000000, 0x00031710, 0x00031710, 0x00000000 },
+    { 0x0000a31c, 0x00000000, 0x00000000, 0x00035718, 0x00035718, 0x00000000 },
+    { 0x0000a320, 0x00000000, 0x00000000, 0x00038758, 0x00038758, 0x00000000 },
+    { 0x0000a324, 0x00000000, 0x00000000, 0x0003c75a, 0x0003c75a, 0x00000000 },
+    { 0x0000a328, 0x00000000, 0x00000000, 0x0004075c, 0x0004075c, 0x00000000 },
+    { 0x0000a32c, 0x00000000, 0x00000000, 0x0004475e, 0x0004475e, 0x00000000 },
+    { 0x0000a330, 0x00000000, 0x00000000, 0x0004679f, 0x0004679f, 0x00000000 },
+    { 0x0000a334, 0x00000000, 0x00000000, 0x000487df, 0x000487df, 0x00000000 },
+    { 0x0000a338, 0x0003891e, 0x0003891e, 0x0003891e, 0x0003891e, 0x00000000 },
+    { 0x0000a33c, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x0003a95e, 0x00000000 },
+    { 0x0000a340, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a344, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a348, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a34c, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a350, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x0000a354, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x0003e9df, 0x00000000 },
+    { 0x00007838, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801, 0xfac68801 },
+    { 0x0000786c, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4, 0x48609eb4 },
+    { 0x00007820, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04, 0x00000c04 },
+    { 0x0000a274, 0x0a21c652, 0x0a21c652, 0x0a21a652, 0x0a21a652, 0x0a22a652 },
+    { 0x0000a278, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
+    { 0x0000a27c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c, 0x050e039c },
+    { 0x0000a394, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
+    { 0x0000a398, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c },
+    { 0x0000a3dc, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c, 0x39ce739c },
+    { 0x0000a3e0, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c, 0x0000039c },
+};
+
 static const u_int32_t ar9285PciePhy_clkreq_always_on_L1_9285_1_2[][2] = {
     {0x00004040,  0x9248fd00 },
     {0x00004040,  0x24924924 },
index f32c622db6e7c82322e0f27b929b51a6e09b529e..f757bc7eec68da37e68889a85385712a5fa390e3 100644 (file)
@@ -285,7 +285,7 @@ int ath9k_hw_txprocdesc(struct ath_hw *ah, struct ath_desc *ds)
        ds->ds_txstat.ts_shortretry = MS(ads->ds_txstatus1, AR_RTSFailCnt);
        ds->ds_txstat.ts_longretry = MS(ads->ds_txstatus1, AR_DataFailCnt);
        ds->ds_txstat.ts_virtcol = MS(ads->ds_txstatus1, AR_VirtRetryCnt);
-       ds->ds_txstat.ts_antenna = 1;
+       ds->ds_txstat.ts_antenna = 0;
 
        return 0;
 }
@@ -886,7 +886,8 @@ bool ath9k_hw_setrxabort(struct ath_hw *ah, bool set)
                REG_SET_BIT(ah, AR_DIAG_SW,
                            (AR_DIAG_RX_DIS | AR_DIAG_RX_ABORT));
 
-               if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE, 0)) {
+               if (!ath9k_hw_wait(ah, AR_OBS_BUS_1, AR_OBS_BUS_1_RX_STATE,
+                                  0, AH_WAIT_TIMEOUT)) {
                        REG_CLR_BIT(ah, AR_DIAG_SW,
                                    (AR_DIAG_RX_DIS |
                                     AR_DIAG_RX_ABORT));
@@ -933,15 +934,32 @@ void ath9k_hw_stoppcurecv(struct ath_hw *ah)
 
 bool ath9k_hw_stopdmarecv(struct ath_hw *ah)
 {
+#define AH_RX_STOP_DMA_TIMEOUT 10000   /* usec */
+#define AH_RX_TIME_QUANTUM     100     /* usec */
+
+       int i;
+
        REG_WRITE(ah, AR_CR, AR_CR_RXD);
 
-       if (!ath9k_hw_wait(ah, AR_CR, AR_CR_RXE, 0)) {
+       /* Wait for rx enable bit to go low */
+       for (i = AH_RX_STOP_DMA_TIMEOUT / AH_TIME_QUANTUM; i != 0; i--) {
+               if ((REG_READ(ah, AR_CR) & AR_CR_RXE) == 0)
+                       break;
+               udelay(AH_TIME_QUANTUM);
+       }
+
+       if (i == 0) {
                DPRINTF(ah->ah_sc, ATH_DBG_QUEUE,
-                       "dma failed to stop in 10ms\n"
-                       "AR_CR=0x%08x\nAR_DIAG_SW=0x%08x\n",
-                       REG_READ(ah, AR_CR), REG_READ(ah, AR_DIAG_SW));
+                       "dma failed to stop in %d ms "
+                       "AR_CR=0x%08x AR_DIAG_SW=0x%08x\n",
+                       AH_RX_STOP_DMA_TIMEOUT / 1000,
+                       REG_READ(ah, AR_CR),
+                       REG_READ(ah, AR_DIAG_SW));
                return false;
        } else {
                return true;
        }
+
+#undef AH_RX_TIME_QUANTUM
+#undef AH_RX_STOP_DMA_TIMEOUT
 }
index 74b660ae8add970f9f1031cb1350a9035ccf9b58..a75f65dae1d7b5a8a818fa059664599bc9b0d844 100644 (file)
@@ -17,7 +17,7 @@
 #ifndef MAC_H
 #define MAC_H
 
-#define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_V20_OR_LATER(ah) ?                \
+#define RXSTATUS_RATE(ah, ads) (AR_SREV_5416_20_OR_LATER(ah) ?         \
                                MS(ads->ds_rxstatus0, AR_RxRate) :      \
                                (ads->ds_rxstatus3 >> 2) & 0xFF)
 
@@ -566,9 +566,11 @@ enum ath9k_rx_filter {
        ATH9K_RX_FILTER_BEACON = 0x00000010,
        ATH9K_RX_FILTER_PROM = 0x00000020,
        ATH9K_RX_FILTER_PROBEREQ = 0x00000080,
-       ATH9K_RX_FILTER_PSPOLL = 0x00004000,
        ATH9K_RX_FILTER_PHYERR = 0x00000100,
+       ATH9K_RX_FILTER_MYBEACON = 0x00000200,
+       ATH9K_RX_FILTER_PSPOLL = 0x00004000,
        ATH9K_RX_FILTER_PHYRADAR = 0x00002000,
+       ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000,
 };
 
 #define ATH9K_RATESERIES_RTS_CTS  0x0001
@@ -587,9 +589,11 @@ struct ath9k_keyval {
        u8 kv_type;
        u8 kv_pad;
        u16 kv_len;
-       u8 kv_val[16];
-       u8 kv_mic[8];
-       u8 kv_txmic[8];
+       u8 kv_val[16]; /* TK */
+       u8 kv_mic[8]; /* Michael MIC key */
+       u8 kv_txmic[8]; /* Michael MIC TX key (used only if the hardware
+                        * supports both MIC keys in the same key cache entry;
+                        * in that case, kv_mic is the RX key) */
 };
 
 enum ath9k_key_type {
index fc3460f8f7fcd6df688f4b9e8c52fc3c9c8605b5..8db75f6de53ed441c2c2549a6c09410972961a1c 100644 (file)
@@ -26,6 +26,10 @@ MODULE_DESCRIPTION("Support for Atheros 802.11n wireless LAN cards.");
 MODULE_SUPPORTED_DEVICE("Atheros 802.11n WLAN cards");
 MODULE_LICENSE("Dual BSD/GPL");
 
+static int modparam_nohwcrypt;
+module_param_named(nohwcrypt, modparam_nohwcrypt, int, 0444);
+MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption");
+
 /* We use the hw_value as an index into our private channel structure */
 
 #define CHAN2G(_freq, _idx)  { \
@@ -232,11 +236,11 @@ static void ath_setup_rates(struct ath_softc *sc, enum ieee80211_band band)
  * by reseting the chip.  To accomplish this we must first cleanup any pending
  * DMA, then restart stuff.
 */
-static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan)
+int ath_set_channel(struct ath_softc *sc, struct ieee80211_hw *hw,
+                   struct ath9k_channel *hchan)
 {
        struct ath_hw *ah = sc->sc_ah;
        bool fastcc = true, stopped;
-       struct ieee80211_hw *hw = sc->hw;
        struct ieee80211_channel *channel = hw->conf.channel;
        int r;
 
@@ -308,23 +312,23 @@ static int ath_set_channel(struct ath_softc *sc, struct ath9k_channel *hchan)
  */
 static void ath_ani_calibrate(unsigned long data)
 {
-       struct ath_softc *sc;
-       struct ath_hw *ah;
+       struct ath_softc *sc = (struct ath_softc *)data;
+       struct ath_hw *ah = sc->sc_ah;
        bool longcal = false;
        bool shortcal = false;
        bool aniflag = false;
        unsigned int timestamp = jiffies_to_msecs(jiffies);
-       u32 cal_interval;
+       u32 cal_interval, short_cal_interval;
 
-       sc = (struct ath_softc *)data;
-       ah = sc->sc_ah;
+       short_cal_interval = (ah->opmode == NL80211_IFTYPE_AP) ?
+               ATH_AP_SHORT_CALINTERVAL : ATH_STA_SHORT_CALINTERVAL;
 
        /*
        * don't calibrate when we're scanning.
        * we are most likely not on our home channel.
        */
-       if (sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC)
-               return;
+       if (sc->sc_flags & SC_OP_SCANNING)
+               goto set_timer;
 
        /* Long calibration runs independently of short calibration. */
        if ((timestamp - sc->ani.longcal_timer) >= ATH_LONG_CALINTERVAL) {
@@ -335,8 +339,7 @@ static void ath_ani_calibrate(unsigned long data)
 
        /* Short calibration applies only while caldone is false */
        if (!sc->ani.caldone) {
-               if ((timestamp - sc->ani.shortcal_timer) >=
-                   ATH_SHORT_CALINTERVAL) {
+               if ((timestamp - sc->ani.shortcal_timer) >= short_cal_interval) {
                        shortcal = true;
                        DPRINTF(sc, ATH_DBG_ANI, "shortcal @%lu\n", jiffies);
                        sc->ani.shortcal_timer = timestamp;
@@ -352,8 +355,7 @@ static void ath_ani_calibrate(unsigned long data)
        }
 
        /* Verify whether we must check ANI */
-       if ((timestamp - sc->ani.checkani_timer) >=
-          ATH_ANI_POLLINTERVAL) {
+       if ((timestamp - sc->ani.checkani_timer) >= ATH_ANI_POLLINTERVAL) {
                aniflag = true;
                sc->ani.checkani_timer = timestamp;
        }
@@ -362,8 +364,7 @@ static void ath_ani_calibrate(unsigned long data)
        if (longcal || shortcal || aniflag) {
                /* Call ANI routine if necessary */
                if (aniflag)
-                       ath9k_hw_ani_monitor(ah, &sc->nodestats,
-                                            ah->curchan);
+                       ath9k_hw_ani_monitor(ah, &sc->nodestats, ah->curchan);
 
                /* Perform calibration if necessary */
                if (longcal || shortcal) {
@@ -392,6 +393,7 @@ static void ath_ani_calibrate(unsigned long data)
                }
        }
 
+set_timer:
        /*
        * Set timer interval based on previous results.
        * The interval must be the shortest necessary to satisfy ANI,
@@ -401,7 +403,7 @@ static void ath_ani_calibrate(unsigned long data)
        if (sc->sc_ah->config.enable_ani)
                cal_interval = min(cal_interval, (u32)ATH_ANI_POLLINTERVAL);
        if (!sc->ani.caldone)
-               cal_interval = min(cal_interval, (u32)ATH_SHORT_CALINTERVAL);
+               cal_interval = min(cal_interval, (u32)short_cal_interval);
 
        mod_timer(&sc->ani.timer, jiffies + msecs_to_jiffies(cal_interval));
 }
@@ -412,7 +414,7 @@ static void ath_ani_calibrate(unsigned long data)
  * the chainmask configuration, for bt coexistence, use
  * the chainmask configuration even in legacy mode.
  */
-static void ath_update_chainmask(struct ath_softc *sc, int is_ht)
+void ath_update_chainmask(struct ath_softc *sc, int is_ht)
 {
        sc->sc_flags |= SC_OP_CHAINMASK_UPDATE;
        if (is_ht ||
@@ -514,6 +516,7 @@ irqreturn_t ath_isr(int irq, void *dev)
                        return IRQ_NONE;
 
                sc->intrstatus = status;
+               ath9k_ps_wakeup(sc);
 
                if (status & ATH9K_INT_FATAL) {
                        /* need a chip reset */
@@ -574,7 +577,12 @@ irqreturn_t ath_isr(int irq, void *dev)
                                        sc->sc_flags |= SC_OP_WAIT_FOR_BEACON;
                                }
                        }
+                       if (status & ATH9K_INT_TSFOOR) {
+                               /* FIXME: Handle this interrupt for power save */
+                               sched = true;
+                       }
                }
+               ath9k_ps_restore(sc);
        } while (0);
 
        ath_debug_stat_interrupt(sc, status);
@@ -630,20 +638,9 @@ static u32 ath_get_extchanmode(struct ath_softc *sc,
        return chanmode;
 }
 
-static int ath_keyset(struct ath_softc *sc, u16 keyix,
-              struct ath9k_keyval *hk, const u8 mac[ETH_ALEN])
-{
-       bool status;
-
-       status = ath9k_hw_set_keycache_entry(sc->sc_ah,
-               keyix, hk, mac, false);
-
-       return status != false;
-}
-
 static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
-                          struct ath9k_keyval *hk,
-                          const u8 *addr)
+                          struct ath9k_keyval *hk, const u8 *addr,
+                          bool authenticator)
 {
        const u8 *key_rxmic;
        const u8 *key_txmic;
@@ -652,26 +649,33 @@ static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
        key_rxmic = key + NL80211_TKIP_DATA_OFFSET_RX_MIC_KEY;
 
        if (addr == NULL) {
-               /* Group key installation */
-               memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
-               return ath_keyset(sc, keyix, hk, addr);
-       }
-       if (!sc->splitmic) {
                /*
-                * data key goes at first index,
-                * the hal handles the MIC keys at index+64.
+                * Group key installation - only two key cache entries are used
+                * regardless of splitmic capability since group key is only
+                * used either for TX or RX.
                 */
+               if (authenticator) {
+                       memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
+                       memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_mic));
+               } else {
+                       memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
+                       memcpy(hk->kv_txmic, key_rxmic, sizeof(hk->kv_mic));
+               }
+               return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr);
+       }
+       if (!sc->splitmic) {
+               /* TX and RX keys share the same key cache entry. */
                memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
                memcpy(hk->kv_txmic, key_txmic, sizeof(hk->kv_txmic));
-               return ath_keyset(sc, keyix, hk, addr);
+               return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, addr);
        }
-       /*
-        * TX key goes at first index, RX key at +32.
-        * The hal handles the MIC keys at index+64.
-        */
+
+       /* Separate key cache entries for TX and RX */
+
+       /* TX key goes at first index, RX key at +32. */
        memcpy(hk->kv_mic, key_txmic, sizeof(hk->kv_mic));
-       if (!ath_keyset(sc, keyix, hk, NULL)) {
-               /* Txmic entry failed. No need to proceed further */
+       if (!ath9k_hw_set_keycache_entry(sc->sc_ah, keyix, hk, NULL)) {
+               /* TX MIC entry failed. No need to proceed further */
                DPRINTF(sc, ATH_DBG_KEYCACHE,
                        "Setting TX MIC Key Failed\n");
                return 0;
@@ -679,7 +683,7 @@ static int ath_setkey_tkip(struct ath_softc *sc, u16 keyix, const u8 *key,
 
        memcpy(hk->kv_mic, key_rxmic, sizeof(hk->kv_mic));
        /* XXX delete tx key on failure? */
-       return ath_keyset(sc, keyix + 32, hk, addr);
+       return ath9k_hw_set_keycache_entry(sc->sc_ah, keyix + 32, hk, addr);
 }
 
 static int ath_reserve_key_cache_slot_tkip(struct ath_softc *sc)
@@ -763,6 +767,7 @@ static int ath_reserve_key_cache_slot(struct ath_softc *sc)
 }
 
 static int ath_key_config(struct ath_softc *sc,
+                         struct ieee80211_vif *vif,
                          struct ieee80211_sta *sta,
                          struct ieee80211_key_conf *key)
 {
@@ -795,13 +800,10 @@ static int ath_key_config(struct ath_softc *sc,
                 * need to change with virtual interfaces. */
                idx = key->keyidx;
        } else if (key->keyidx) {
-               struct ieee80211_vif *vif;
-
                if (WARN_ON(!sta))
                        return -EOPNOTSUPP;
                mac = sta->addr;
 
-               vif = sc->vifs[0];
                if (vif->type != NL80211_IFTYPE_AP) {
                        /* Only keyidx 0 should be used with unicast key, but
                         * allow this for client mode for now. */
@@ -822,9 +824,10 @@ static int ath_key_config(struct ath_softc *sc,
        }
 
        if (key->alg == ALG_TKIP)
-               ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac);
+               ret = ath_setkey_tkip(sc, idx, key->key, &hk, mac,
+                                     vif->type == NL80211_IFTYPE_AP);
        else
-               ret = ath_keyset(sc, idx, &hk, mac);
+               ret = ath9k_hw_set_keycache_entry(sc->sc_ah, idx, &hk, mac);
 
        if (!ret)
                return -EIO;
@@ -909,8 +912,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
                }
 
                /* Configure the beacon */
-               ath_beacon_config(sc, 0);
-               sc->sc_flags |= SC_OP_BEACONS;
+               ath_beacon_config(sc, vif);
 
                /* Reset rssi stats */
                sc->nodestats.ns_avgbrssi = ATH_RSSI_DUMMY_MARKER;
@@ -920,8 +922,7 @@ static void ath9k_bss_assoc_info(struct ath_softc *sc,
 
                /* Start ANI */
                mod_timer(&sc->ani.timer,
-                       jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
-
+                         jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
        } else {
                DPRINTF(sc, ATH_DBG_CONFIG, "Bss Info DISSOC\n");
                sc->curaid = 0;
@@ -1083,13 +1084,7 @@ fail:
        ath_deinit_leds(sc);
 }
 
-#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
-
-/*******************/
-/*     Rfkill     */
-/*******************/
-
-static void ath_radio_enable(struct ath_softc *sc)
+void ath_radio_enable(struct ath_softc *sc)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ieee80211_channel *channel = sc->hw->conf.channel;
@@ -1116,7 +1111,7 @@ static void ath_radio_enable(struct ath_softc *sc)
        }
 
        if (sc->sc_flags & SC_OP_BEACONS)
-               ath_beacon_config(sc, ATH_IF_ID_ANY);   /* restart beacons */
+               ath_beacon_config(sc, NULL);    /* restart beacons */
 
        /* Re-Enable  interrupts */
        ath9k_hw_set_interrupts(ah, sc->imask);
@@ -1130,7 +1125,7 @@ static void ath_radio_enable(struct ath_softc *sc)
        ath9k_ps_restore(sc);
 }
 
-static void ath_radio_disable(struct ath_softc *sc)
+void ath_radio_disable(struct ath_softc *sc)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ieee80211_channel *channel = sc->hw->conf.channel;
@@ -1165,6 +1160,12 @@ static void ath_radio_disable(struct ath_softc *sc)
        ath9k_ps_restore(sc);
 }
 
+#if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
+
+/*******************/
+/*     Rfkill     */
+/*******************/
+
 static bool ath_is_rfkill_set(struct ath_softc *sc)
 {
        struct ath_hw *ah = sc->sc_ah;
@@ -1306,6 +1307,7 @@ void ath_cleanup(struct ath_softc *sc)
        ath_detach(sc);
        free_irq(sc->irq, sc);
        ath_bus_cleanup(sc);
+       kfree(sc->sec_wiphy);
        ieee80211_free_hw(sc->hw);
 }
 
@@ -1322,7 +1324,17 @@ void ath_detach(struct ath_softc *sc)
        ath_deinit_rfkill(sc);
 #endif
        ath_deinit_leds(sc);
+       cancel_work_sync(&sc->chan_work);
+       cancel_delayed_work_sync(&sc->wiphy_work);
 
+       for (i = 0; i < sc->num_sec_wiphy; i++) {
+               struct ath_wiphy *aphy = sc->sec_wiphy[i];
+               if (aphy == NULL)
+                       continue;
+               sc->sec_wiphy[i] = NULL;
+               ieee80211_unregister_hw(aphy->hw);
+               ieee80211_free_hw(aphy->hw);
+       }
        ieee80211_unregister_hw(hw);
        ath_rx_cleanup(sc);
        ath_tx_cleanup(sc);
@@ -1356,10 +1368,12 @@ static int ath_init(u16 devid, struct ath_softc *sc)
        if (ath9k_init_debug(sc) < 0)
                printk(KERN_ERR "Unable to create debugfs files\n");
 
+       spin_lock_init(&sc->wiphy_lock);
        spin_lock_init(&sc->sc_resetlock);
+       spin_lock_init(&sc->sc_serial_rw);
        mutex_init(&sc->mutex);
        tasklet_init(&sc->intr_tq, ath9k_tasklet, (unsigned long)sc);
-       tasklet_init(&sc->bcon_tasklet, ath9k_beacon_tasklet,
+       tasklet_init(&sc->bcon_tasklet, ath_beacon_tasklet,
                     (unsigned long)sc);
 
        /*
@@ -1513,17 +1527,16 @@ static int ath_init(u16 devid, struct ath_softc *sc)
        ath9k_hw_setcapability(ah, ATH9K_CAP_DIVERSITY, 1, true, NULL);
        sc->rx.defant = ath9k_hw_getdefantenna(ah);
 
-       if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) {
+       if (ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
                memcpy(sc->bssidmask, ath_bcast_mac, ETH_ALEN);
-               ATH_SET_VIF_BSSID_MASK(sc->bssidmask);
-               ath9k_hw_setbssidmask(sc);
-       }
 
        sc->beacon.slottime = ATH9K_SLOT_TIME_9;        /* default to short slot time */
 
        /* initialize beacon slots */
-       for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++)
-               sc->beacon.bslot[i] = ATH_IF_ID_ANY;
+       for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
+               sc->beacon.bslot[i] = NULL;
+               sc->beacon.bslot_aphy[i] = NULL;
+       }
 
        /* save MISC configurations */
        sc->config.swBeaconProcess = 1;
@@ -1558,33 +1571,22 @@ bad2:
 bad:
        if (ah)
                ath9k_hw_detach(ah);
+       ath9k_exit_debug(sc);
 
        return error;
 }
 
-int ath_attach(u16 devid, struct ath_softc *sc)
+void ath_set_hw_capab(struct ath_softc *sc, struct ieee80211_hw *hw)
 {
-       struct ieee80211_hw *hw = sc->hw;
-       int error = 0;
-
-       DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n");
-
-       error = ath_init(devid, sc);
-       if (error != 0)
-               return error;
-
-       /* get mac address from hardware and set in mac80211 */
-
-       SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr);
-
        hw->flags = IEEE80211_HW_RX_INCLUDES_FCS |
                IEEE80211_HW_HOST_BROADCAST_PS_BUFFERING |
                IEEE80211_HW_SIGNAL_DBM |
                IEEE80211_HW_AMPDU_AGGREGATION |
                IEEE80211_HW_SUPPORTS_PS |
-               IEEE80211_HW_PS_NULLFUNC_STACK;
+               IEEE80211_HW_PS_NULLFUNC_STACK |
+               IEEE80211_HW_SPECTRUM_MGMT;
 
-       if (AR_SREV_9160_10_OR_LATER(sc->sc_ah))
+       if (AR_SREV_9160_10_OR_LATER(sc->sc_ah) || modparam_nohwcrypt)
                hw->flags |= IEEE80211_HW_MFP_CAPABLE;
 
        hw->wiphy->interface_modes =
@@ -1597,31 +1599,53 @@ int ath_attach(u16 devid, struct ath_softc *sc)
 
        hw->queues = 4;
        hw->max_rates = 4;
+       hw->channel_change_time = 5000;
+       hw->max_listen_interval = 10;
        hw->max_rate_tries = ATH_11N_TXMAXTRY;
        hw->sta_data_size = sizeof(struct ath_node);
        hw->vif_data_size = sizeof(struct ath_vif);
 
        hw->rate_control_algorithm = "ath9k_rate_control";
 
+       hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
+               &sc->sbands[IEEE80211_BAND_2GHZ];
+       if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
+               hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
+                       &sc->sbands[IEEE80211_BAND_5GHZ];
+}
+
+int ath_attach(u16 devid, struct ath_softc *sc)
+{
+       struct ieee80211_hw *hw = sc->hw;
+       const struct ieee80211_regdomain *regd;
+       int error = 0, i;
+
+       DPRINTF(sc, ATH_DBG_CONFIG, "Attach ATH hw\n");
+
+       error = ath_init(devid, sc);
+       if (error != 0)
+               return error;
+
+       /* get mac address from hardware and set in mac80211 */
+
+       SET_IEEE80211_PERM_ADDR(hw, sc->sc_ah->macaddr);
+
+       ath_set_hw_capab(sc, hw);
+
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT) {
                setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_2GHZ].ht_cap);
                if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
                        setup_ht_cap(sc, &sc->sbands[IEEE80211_BAND_5GHZ].ht_cap);
        }
 
-       hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &sc->sbands[IEEE80211_BAND_2GHZ];
-       if (test_bit(ATH9K_MODE_11A, sc->sc_ah->caps.wireless_modes))
-               hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
-                       &sc->sbands[IEEE80211_BAND_5GHZ];
-
        /* initialize tx/rx engine */
        error = ath_tx_init(sc, ATH_TXBUF);
        if (error != 0)
-               goto detach;
+               goto error_attach;
 
        error = ath_rx_init(sc, ATH_RXBUF);
        if (error != 0)
-               goto detach;
+               goto error_attach;
 
 #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
        /* Initialze h/w Rfkill */
@@ -1629,43 +1653,55 @@ int ath_attach(u16 devid, struct ath_softc *sc)
                INIT_DELAYED_WORK(&sc->rf_kill.rfkill_poll, ath_rfkill_poll);
 
        /* Initialize s/w rfkill */
-       if (ath_init_sw_rfkill(sc))
-               goto detach;
+       error = ath_init_sw_rfkill(sc);
+       if (error)
+               goto error_attach;
 #endif
 
        if (ath9k_is_world_regd(sc->sc_ah)) {
-               /* Anything applied here (prior to wiphy registratoin) gets
+               /* Anything applied here (prior to wiphy registration) gets
                 * saved on the wiphy orig_* parameters */
-               const struct ieee80211_regdomain *regd =
-                       ath9k_world_regdomain(sc->sc_ah);
+               regd = ath9k_world_regdomain(sc->sc_ah);
                hw->wiphy->custom_regulatory = true;
                hw->wiphy->strict_regulatory = false;
-               wiphy_apply_custom_regulatory(sc->hw->wiphy, regd);
-               ath9k_reg_apply_radar_flags(hw->wiphy);
-               ath9k_reg_apply_world_flags(hw->wiphy, REGDOM_SET_BY_INIT);
        } else {
                /* This gets applied in the case of the absense of CRDA,
-                * its our own custom world regulatory domain, similar to
+                * it's our own custom world regulatory domain, similar to
                 * cfg80211's but we enable passive scanning */
-               const struct ieee80211_regdomain *regd =
-                       ath9k_default_world_regdomain();
-               wiphy_apply_custom_regulatory(sc->hw->wiphy, regd);
-               ath9k_reg_apply_radar_flags(hw->wiphy);
-               ath9k_reg_apply_world_flags(hw->wiphy, REGDOM_SET_BY_INIT);
+               regd = ath9k_default_world_regdomain();
        }
+       wiphy_apply_custom_regulatory(hw->wiphy, regd);
+       ath9k_reg_apply_radar_flags(hw->wiphy);
+       ath9k_reg_apply_world_flags(hw->wiphy, NL80211_REGDOM_SET_BY_DRIVER);
+
+       INIT_WORK(&sc->chan_work, ath9k_wiphy_chan_work);
+       INIT_DELAYED_WORK(&sc->wiphy_work, ath9k_wiphy_work);
+       sc->wiphy_scheduler_int = msecs_to_jiffies(500);
 
        error = ieee80211_register_hw(hw);
 
-       if (!ath9k_is_world_regd(sc->sc_ah))
-               regulatory_hint(hw->wiphy, sc->sc_ah->regulatory.alpha2);
+       if (!ath9k_is_world_regd(sc->sc_ah)) {
+               error = regulatory_hint(hw->wiphy,
+                       sc->sc_ah->regulatory.alpha2);
+               if (error)
+                       goto error_attach;
+       }
 
        /* Initialize LED control */
        ath_init_leds(sc);
 
 
        return 0;
-detach:
-       ath_detach(sc);
+
+error_attach:
+       /* cleanup tx queues */
+       for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
+               if (ATH_TXQ_SETUP(sc, i))
+                       ath_tx_cleanupq(sc, &sc->tx.txq[i]);
+
+       ath9k_hw_detach(sc->sc_ah);
+       ath9k_exit_debug(sc);
+
        return error;
 }
 
@@ -1700,7 +1736,7 @@ int ath_reset(struct ath_softc *sc, bool retry_tx)
        ath_update_txpow(sc);
 
        if (sc->sc_flags & SC_OP_BEACONS)
-               ath_beacon_config(sc, ATH_IF_ID_ANY);   /* restart beacons */
+               ath_beacon_config(sc, NULL);    /* restart beacons */
 
        ath9k_hw_set_interrupts(ah, sc->imask);
 
@@ -1739,6 +1775,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
        DPRINTF(sc, ATH_DBG_CONFIG, "%s DMA: %u buffers %u desc/buf\n",
                name, nbuf, ndesc);
 
+       INIT_LIST_HEAD(head);
        /* ath_desc must be a multiple of DWORDs */
        if ((sizeof(struct ath_desc) % 4) != 0) {
                DPRINTF(sc, ATH_DBG_FATAL, "ath_desc not DWORD aligned\n");
@@ -1770,7 +1807,7 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
 
        /* allocate descriptors */
        dd->dd_desc = dma_alloc_coherent(sc->dev, dd->dd_desc_len,
-                                        &dd->dd_desc_paddr, GFP_ATOMIC);
+                                        &dd->dd_desc_paddr, GFP_KERNEL);
        if (dd->dd_desc == NULL) {
                error = -ENOMEM;
                goto fail;
@@ -1782,15 +1819,13 @@ int ath_descdma_setup(struct ath_softc *sc, struct ath_descdma *dd,
 
        /* allocate buffers */
        bsize = sizeof(struct ath_buf) * nbuf;
-       bf = kmalloc(bsize, GFP_KERNEL);
+       bf = kzalloc(bsize, GFP_KERNEL);
        if (bf == NULL) {
                error = -ENOMEM;
                goto fail2;
        }
-       memset(bf, 0, bsize);
        dd->dd_bufptr = bf;
 
-       INIT_LIST_HEAD(head);
        for (i = 0; i < nbuf; i++, bf++, ds += ndesc) {
                bf->bf_desc = ds;
                bf->bf_daddr = DS2PHYS(dd, ds);
@@ -1890,10 +1925,9 @@ int ath_get_mac80211_qnum(u32 queue, struct ath_softc *sc)
 
 /* XXX: Remove me once we don't depend on ath9k_channel for all
  * this redundant data */
-static void ath9k_update_ichannel(struct ath_softc *sc,
-                         struct ath9k_channel *ichan)
+void ath9k_update_ichannel(struct ath_softc *sc, struct ieee80211_hw *hw,
+                          struct ath9k_channel *ichan)
 {
-       struct ieee80211_hw *hw = sc->hw;
        struct ieee80211_channel *chan = hw->conf.channel;
        struct ieee80211_conf *conf = &hw->conf;
 
@@ -1925,7 +1959,8 @@ static void ath9k_update_ichannel(struct ath_softc *sc,
 
 static int ath9k_start(struct ieee80211_hw *hw)
 {
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        struct ieee80211_channel *curchan = hw->conf.channel;
        struct ath9k_channel *init_channel;
        int r, pos;
@@ -1935,12 +1970,34 @@ static int ath9k_start(struct ieee80211_hw *hw)
 
        mutex_lock(&sc->mutex);
 
+       if (ath9k_wiphy_started(sc)) {
+               if (sc->chan_idx == curchan->hw_value) {
+                       /*
+                        * Already on the operational channel, the new wiphy
+                        * can be marked active.
+                        */
+                       aphy->state = ATH_WIPHY_ACTIVE;
+                       ieee80211_wake_queues(hw);
+               } else {
+                       /*
+                        * Another wiphy is on another channel, start the new
+                        * wiphy in paused state.
+                        */
+                       aphy->state = ATH_WIPHY_PAUSED;
+                       ieee80211_stop_queues(hw);
+               }
+               mutex_unlock(&sc->mutex);
+               return 0;
+       }
+       aphy->state = ATH_WIPHY_ACTIVE;
+
        /* setup initial channel */
 
        pos = curchan->hw_value;
 
+       sc->chan_idx = pos;
        init_channel = &sc->sc_ah->channels[pos];
-       ath9k_update_ichannel(sc, init_channel);
+       ath9k_update_ichannel(sc, hw, init_channel);
 
        /* Reset SERDES registers */
        ath9k_hw_configpcipowersave(sc->sc_ah, 0);
@@ -2003,7 +2060,7 @@ static int ath9k_start(struct ieee80211_hw *hw)
        sc->imask &= ~(ATH9K_INT_SWBA | ATH9K_INT_BMISS);
        ath9k_hw_set_interrupts(sc->sc_ah, sc->imask);
 
-       ieee80211_wake_queues(sc->hw);
+       ieee80211_wake_queues(hw);
 
 #if defined(CONFIG_RFKILL) || defined(CONFIG_RFKILL_MODULE)
        r = ath_start_rfkill_poll(sc);
@@ -2019,10 +2076,17 @@ static int ath9k_tx(struct ieee80211_hw *hw,
                    struct sk_buff *skb)
 {
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        struct ath_tx_control txctl;
        int hdrlen, padsize;
 
+       if (aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN) {
+               printk(KERN_DEBUG "ath9k: %s: TX in unexpected wiphy state "
+                      "%d\n", wiphy_name(hw->wiphy), aphy->state);
+               goto exit;
+       }
+
        memset(&txctl, 0, sizeof(struct ath_tx_control));
 
        /*
@@ -2056,7 +2120,7 @@ static int ath9k_tx(struct ieee80211_hw *hw,
 
        DPRINTF(sc, ATH_DBG_XMIT, "transmitting packet, skb: %p\n", skb);
 
-       if (ath_tx_start(sc, skb, &txctl) != 0) {
+       if (ath_tx_start(hw, skb, &txctl) != 0) {
                DPRINTF(sc, ATH_DBG_XMIT, "TX failed\n");
                goto exit;
        }
@@ -2069,7 +2133,10 @@ exit:
 
 static void ath9k_stop(struct ieee80211_hw *hw)
 {
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
+
+       aphy->state = ATH_WIPHY_INACTIVE;
 
        if (sc->sc_flags & SC_OP_INVALID) {
                DPRINTF(sc, ATH_DBG_ANY, "Device not present\n");
@@ -2078,7 +2145,12 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 
        mutex_lock(&sc->mutex);
 
-       ieee80211_stop_queues(sc->hw);
+       ieee80211_stop_queues(hw);
+
+       if (ath9k_wiphy_started(sc)) {
+               mutex_unlock(&sc->mutex);
+               return; /* another wiphy still in use */
+       }
 
        /* make sure h/w will not generate any interrupt
         * before setting the invalid flag. */
@@ -2109,31 +2181,43 @@ static void ath9k_stop(struct ieee80211_hw *hw)
 static int ath9k_add_interface(struct ieee80211_hw *hw,
                               struct ieee80211_if_init_conf *conf)
 {
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        struct ath_vif *avp = (void *)conf->vif->drv_priv;
        enum nl80211_iftype ic_opmode = NL80211_IFTYPE_UNSPECIFIED;
-
-       /* Support only vif for now */
-
-       if (sc->nvifs)
-               return -ENOBUFS;
+       int ret = 0;
 
        mutex_lock(&sc->mutex);
 
+       if (!(sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK) &&
+           sc->nvifs > 0) {
+               ret = -ENOBUFS;
+               goto out;
+       }
+
        switch (conf->type) {
        case NL80211_IFTYPE_STATION:
                ic_opmode = NL80211_IFTYPE_STATION;
                break;
        case NL80211_IFTYPE_ADHOC:
+               if (sc->nbcnvifs >= ATH_BCBUF) {
+                       ret = -ENOBUFS;
+                       goto out;
+               }
                ic_opmode = NL80211_IFTYPE_ADHOC;
                break;
        case NL80211_IFTYPE_AP:
+               if (sc->nbcnvifs >= ATH_BCBUF) {
+                       ret = -ENOBUFS;
+                       goto out;
+               }
                ic_opmode = NL80211_IFTYPE_AP;
                break;
        default:
                DPRINTF(sc, ATH_DBG_FATAL,
                        "Interface type %d not yet supported\n", conf->type);
-               return -EOPNOTSUPP;
+               ret = -EOPNOTSUPP;
+               goto out;
        }
 
        DPRINTF(sc, ATH_DBG_CONFIG, "Attach a VIF of type: %d\n", ic_opmode);
@@ -2142,12 +2226,19 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
        avp->av_opmode = ic_opmode;
        avp->av_bslot = -1;
 
-       if (ic_opmode == NL80211_IFTYPE_AP)
-               ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
-
-       sc->vifs[0] = conf->vif;
        sc->nvifs++;
 
+       if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_BSSIDMASK)
+               ath9k_set_bssid_mask(hw);
+
+       if (sc->nvifs > 1)
+               goto out; /* skip global settings for secondary vif */
+
+       if (ic_opmode == NL80211_IFTYPE_AP) {
+               ath9k_hw_set_tsfadjust(sc->sc_ah, 1);
+               sc->sc_flags |= SC_OP_TSF_RESET;
+       }
+
        /* Set the device opmode */
        sc->sc_ah->opmode = ic_opmode;
 
@@ -2155,10 +2246,13 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
         * Enable MIB interrupts when there are hardware phy counters.
         * Note we only do this (at the moment) for station mode.
         */
-       if (ath9k_hw_phycounters(sc->sc_ah) &&
-           ((conf->type == NL80211_IFTYPE_STATION) ||
-            (conf->type == NL80211_IFTYPE_ADHOC)))
-               sc->imask |= ATH9K_INT_MIB;
+       if ((conf->type == NL80211_IFTYPE_STATION) ||
+           (conf->type == NL80211_IFTYPE_ADHOC)) {
+               if (ath9k_hw_phycounters(sc->sc_ah))
+                       sc->imask |= ATH9K_INT_MIB;
+               sc->imask |= ATH9K_INT_TSFOOR;
+       }
+
        /*
         * Some hardware processes the TIM IE and fires an
         * interrupt when the TIM bit is set.  For hardware
@@ -2179,16 +2273,18 @@ static int ath9k_add_interface(struct ieee80211_hw *hw,
                          jiffies + msecs_to_jiffies(ATH_ANI_POLLINTERVAL));
        }
 
+out:
        mutex_unlock(&sc->mutex);
-
-       return 0;
+       return ret;
 }
 
 static void ath9k_remove_interface(struct ieee80211_hw *hw,
                                   struct ieee80211_if_init_conf *conf)
 {
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        struct ath_vif *avp = (void *)conf->vif->drv_priv;
+       int i;
 
        DPRINTF(sc, ATH_DBG_CONFIG, "Detach Interface\n");
 
@@ -2206,7 +2302,15 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
 
        sc->sc_flags &= ~SC_OP_BEACONS;
 
-       sc->vifs[0] = NULL;
+       for (i = 0; i < ARRAY_SIZE(sc->beacon.bslot); i++) {
+               if (sc->beacon.bslot[i] == conf->vif) {
+                       printk(KERN_DEBUG "%s: vif had allocated beacon "
+                              "slot\n", __func__);
+                       sc->beacon.bslot[i] = NULL;
+                       sc->beacon.bslot_aphy[i] = NULL;
+               }
+       }
+
        sc->nvifs--;
 
        mutex_unlock(&sc->mutex);
@@ -2214,7 +2318,8 @@ static void ath9k_remove_interface(struct ieee80211_hw *hw,
 
 static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
 {
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        struct ieee80211_conf *conf = &hw->conf;
 
        mutex_lock(&sc->mutex);
@@ -2244,24 +2349,49 @@ static int ath9k_config(struct ieee80211_hw *hw, u32 changed)
                struct ieee80211_channel *curchan = hw->conf.channel;
                int pos = curchan->hw_value;
 
+               aphy->chan_idx = pos;
+               aphy->chan_is_ht = conf_is_ht(conf);
+
+               if (aphy->state == ATH_WIPHY_SCAN ||
+                   aphy->state == ATH_WIPHY_ACTIVE)
+                       ath9k_wiphy_pause_all_forced(sc, aphy);
+               else {
+                       /*
+                        * Do not change operational channel based on a paused
+                        * wiphy changes.
+                        */
+                       goto skip_chan_change;
+               }
+
                DPRINTF(sc, ATH_DBG_CONFIG, "Set channel: %d MHz\n",
                        curchan->center_freq);
 
                /* XXX: remove me eventualy */
-               ath9k_update_ichannel(sc, &sc->sc_ah->channels[pos]);
+               ath9k_update_ichannel(sc, hw, &sc->sc_ah->channels[pos]);
 
                ath_update_chainmask(sc, conf_is_ht(conf));
 
-               if (ath_set_channel(sc, &sc->sc_ah->channels[pos]) < 0) {
+               if (ath_set_channel(sc, hw, &sc->sc_ah->channels[pos]) < 0) {
                        DPRINTF(sc, ATH_DBG_FATAL, "Unable to set channel\n");
                        mutex_unlock(&sc->mutex);
                        return -EINVAL;
                }
        }
 
+skip_chan_change:
        if (changed & IEEE80211_CONF_CHANGE_POWER)
                sc->config.txpowlimit = 2 * conf->power_level;
 
+       /*
+        * The HW TSF has to be reset when the beacon interval changes.
+        * We set the flag here, and ath_beacon_config_ap() would take this
+        * into account when it gets called through the subsequent
+        * config_interface() call - with IFCC_BEACON in the changed field.
+        */
+
+       if (changed & IEEE80211_CONF_CHANGE_BEACON_INTERVAL)
+               sc->sc_flags |= SC_OP_TSF_RESET;
+
        mutex_unlock(&sc->mutex);
 
        return 0;
@@ -2271,12 +2401,15 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
                                  struct ieee80211_vif *vif,
                                  struct ieee80211_if_conf *conf)
 {
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_vif *avp = (void *)vif->drv_priv;
        u32 rfilt = 0;
        int error, i;
 
+       mutex_lock(&sc->mutex);
+
        /* TODO: Need to decide which hw opmode to use for multi-interface
         * cases */
        if (vif->type == NL80211_IFTYPE_AP &&
@@ -2297,6 +2430,7 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
                case NL80211_IFTYPE_ADHOC:
                        /* Set BSSID */
                        memcpy(sc->curbssid, conf->bssid, ETH_ALEN);
+                       memcpy(avp->bssid, conf->bssid, ETH_ALEN);
                        sc->curaid = 0;
                        ath9k_hw_write_associd(sc);
 
@@ -2331,11 +2465,13 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
                         */
                        ath9k_hw_stoptxdma(sc->sc_ah, sc->beacon.beaconq);
 
-                       error = ath_beacon_alloc(sc, 0);
-                       if (error != 0)
+                       error = ath_beacon_alloc(aphy, vif);
+                       if (error != 0) {
+                               mutex_unlock(&sc->mutex);
                                return error;
+                       }
 
-                       ath_beacon_sync(sc, 0);
+                       ath_beacon_config(sc, vif);
                }
        }
 
@@ -2352,6 +2488,8 @@ static int ath9k_config_interface(struct ieee80211_hw *hw,
        if (vif->type == NL80211_IFTYPE_ADHOC)
                ath_update_chainmask(sc, 0);
 
+       mutex_unlock(&sc->mutex);
+
        return 0;
 }
 
@@ -2370,7 +2508,8 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
                                   int mc_count,
                                   struct dev_mc_list *mclist)
 {
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        u32 rfilt;
 
        changed_flags &= SUPPORTED_FILTERS;
@@ -2380,14 +2519,6 @@ static void ath9k_configure_filter(struct ieee80211_hw *hw,
        rfilt = ath_calcrxfilter(sc);
        ath9k_hw_setrxfilter(sc->sc_ah, rfilt);
 
-       if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
-               if (*total_flags & FIF_BCN_PRBRESP_PROMISC) {
-                       memcpy(sc->curbssid, ath_bcast_mac, ETH_ALEN);
-                       sc->curaid = 0;
-                       ath9k_hw_write_associd(sc);
-               }
-       }
-
        DPRINTF(sc, ATH_DBG_CONFIG, "Set HW RX filter: 0x%x\n", sc->rx.rxfilter);
 }
 
@@ -2396,7 +2527,8 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
                             enum sta_notify_cmd cmd,
                             struct ieee80211_sta *sta)
 {
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
 
        switch (cmd) {
        case STA_NOTIFY_ADD:
@@ -2413,7 +2545,8 @@ static void ath9k_sta_notify(struct ieee80211_hw *hw,
 static int ath9k_conf_tx(struct ieee80211_hw *hw, u16 queue,
                         const struct ieee80211_tx_queue_params *params)
 {
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        struct ath9k_tx_queue_info qi;
        int ret = 0, qnum;
 
@@ -2449,16 +2582,20 @@ static int ath9k_set_key(struct ieee80211_hw *hw,
                         struct ieee80211_sta *sta,
                         struct ieee80211_key_conf *key)
 {
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        int ret = 0;
 
+       if (modparam_nohwcrypt)
+               return -ENOSPC;
+
        mutex_lock(&sc->mutex);
        ath9k_ps_wakeup(sc);
        DPRINTF(sc, ATH_DBG_KEYCACHE, "Set HW Key\n");
 
        switch (cmd) {
        case SET_KEY:
-               ret = ath_key_config(sc, sta, key);
+               ret = ath_key_config(sc, vif, sta, key);
                if (ret >= 0) {
                        key->hw_key_idx = ret;
                        /* push IV and Michael MIC generation to stack */
@@ -2488,7 +2625,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                                   struct ieee80211_bss_conf *bss_conf,
                                   u32 changed)
 {
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
 
        mutex_lock(&sc->mutex);
 
@@ -2523,7 +2661,8 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
 static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
 {
        u64 tsf;
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
 
        mutex_lock(&sc->mutex);
        tsf = ath9k_hw_gettsf64(sc->sc_ah);
@@ -2534,7 +2673,8 @@ static u64 ath9k_get_tsf(struct ieee80211_hw *hw)
 
 static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
 {
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
 
        mutex_lock(&sc->mutex);
        ath9k_hw_settsf64(sc->sc_ah, tsf);
@@ -2543,7 +2683,8 @@ static void ath9k_set_tsf(struct ieee80211_hw *hw, u64 tsf)
 
 static void ath9k_reset_tsf(struct ieee80211_hw *hw)
 {
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
 
        mutex_lock(&sc->mutex);
        ath9k_hw_reset_tsf(sc->sc_ah);
@@ -2555,7 +2696,8 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
                              struct ieee80211_sta *sta,
                              u16 tid, u16 *ssn)
 {
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        int ret = 0;
 
        switch (action) {
@@ -2591,6 +2733,40 @@ static int ath9k_ampdu_action(struct ieee80211_hw *hw,
        return ret;
 }
 
+static void ath9k_sw_scan_start(struct ieee80211_hw *hw)
+{
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
+
+       if (ath9k_wiphy_scanning(sc)) {
+               printk(KERN_DEBUG "ath9k: Two wiphys trying to scan at the "
+                      "same time\n");
+               /*
+                * Do not allow the concurrent scanning state for now. This
+                * could be improved with scanning control moved into ath9k.
+                */
+               return;
+       }
+
+       aphy->state = ATH_WIPHY_SCAN;
+       ath9k_wiphy_pause_all_forced(sc, aphy);
+
+       mutex_lock(&sc->mutex);
+       sc->sc_flags |= SC_OP_SCANNING;
+       mutex_unlock(&sc->mutex);
+}
+
+static void ath9k_sw_scan_complete(struct ieee80211_hw *hw)
+{
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
+
+       mutex_lock(&sc->mutex);
+       aphy->state = ATH_WIPHY_ACTIVE;
+       sc->sc_flags &= ~SC_OP_SCANNING;
+       mutex_unlock(&sc->mutex);
+}
+
 struct ieee80211_ops ath9k_ops = {
        .tx                 = ath9k_tx,
        .start              = ath9k_start,
@@ -2608,6 +2784,8 @@ struct ieee80211_ops ath9k_ops = {
        .set_tsf            = ath9k_set_tsf,
        .reset_tsf          = ath9k_reset_tsf,
        .ampdu_action       = ath9k_ampdu_action,
+       .sw_scan_start      = ath9k_sw_scan_start,
+       .sw_scan_complete   = ath9k_sw_scan_complete,
 };
 
 static struct {
@@ -2681,12 +2859,20 @@ static int __init ath9k_init(void)
                goto err_out;
        }
 
+       error = ath9k_debug_create_root();
+       if (error) {
+               printk(KERN_ERR
+                       "ath9k: Unable to create debugfs root: %d\n",
+                       error);
+               goto err_rate_unregister;
+       }
+
        error = ath_pci_init();
        if (error < 0) {
                printk(KERN_ERR
                        "ath9k: No PCI devices found, driver not installed.\n");
                error = -ENODEV;
-               goto err_rate_unregister;
+               goto err_remove_root;
        }
 
        error = ath_ahb_init();
@@ -2700,6 +2886,8 @@ static int __init ath9k_init(void)
  err_pci_exit:
        ath_pci_exit();
 
+ err_remove_root:
+       ath9k_debug_remove_root();
  err_rate_unregister:
        ath_rate_control_unregister();
  err_out:
@@ -2711,6 +2899,7 @@ static void __exit ath9k_exit(void)
 {
        ath_ahb_exit();
        ath_pci_exit();
+       ath9k_debug_remove_root();
        ath_rate_control_unregister();
        printk(KERN_INFO "%s: Driver unloaded\n", dev_info);
 }
index c28afe42b2694c31866306399e909228828e5910..9a58baabb9cab5c387cf216cd5873fbefa1ad547 100644 (file)
@@ -52,8 +52,8 @@ static void ath_pci_cleanup(struct ath_softc *sc)
        struct pci_dev *pdev = to_pci_dev(sc->dev);
 
        pci_iounmap(pdev, sc->mem);
-       pci_release_region(pdev, 0);
        pci_disable_device(pdev);
+       pci_release_region(pdev, 0);
 }
 
 static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data)
@@ -63,7 +63,8 @@ static bool ath_pci_eeprom_read(struct ath_hw *ah, u32 off, u16 *data)
        if (!ath9k_hw_wait(ah,
                           AR_EEPROM_STATUS_DATA,
                           AR_EEPROM_STATUS_DATA_BUSY |
-                          AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0)) {
+                          AR_EEPROM_STATUS_DATA_PROT_ACCESS, 0,
+                          AH_WAIT_TIMEOUT)) {
                return false;
        }
 
@@ -82,6 +83,7 @@ static struct ath_bus_ops ath_pci_bus_ops = {
 static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
 {
        void __iomem *mem;
+       struct ath_wiphy *aphy;
        struct ath_softc *sc;
        struct ieee80211_hw *hw;
        u8 csz;
@@ -154,7 +156,8 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
                goto bad1;
        }
 
-       hw = ieee80211_alloc_hw(sizeof(struct ath_softc), &ath9k_ops);
+       hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy) +
+                               sizeof(struct ath_softc), &ath9k_ops);
        if (hw == NULL) {
                printk(KERN_ERR "ath_pci: no memory for ieee80211_hw\n");
                goto bad2;
@@ -163,7 +166,11 @@ static int ath_pci_probe(struct pci_dev *pdev, const struct pci_device_id *id)
        SET_IEEE80211_DEV(hw, &pdev->dev);
        pci_set_drvdata(pdev, hw);
 
-       sc = hw->priv;
+       aphy = hw->priv;
+       sc = (struct ath_softc *) (aphy + 1);
+       aphy->sc = sc;
+       aphy->hw = hw;
+       sc->pri_wiphy = aphy;
        sc->hw = hw;
        sc->dev = &pdev->dev;
        sc->mem = mem;
@@ -213,7 +220,8 @@ bad:
 static void ath_pci_remove(struct pci_dev *pdev)
 {
        struct ieee80211_hw *hw = pci_get_drvdata(pdev);
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
 
        ath_cleanup(sc);
 }
@@ -223,7 +231,8 @@ static void ath_pci_remove(struct pci_dev *pdev)
 static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 {
        struct ieee80211_hw *hw = pci_get_drvdata(pdev);
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
 
        ath9k_hw_set_gpio(sc->sc_ah, ATH_LED_PIN, 1);
 
@@ -242,7 +251,8 @@ static int ath_pci_suspend(struct pci_dev *pdev, pm_message_t state)
 static int ath_pci_resume(struct pci_dev *pdev)
 {
        struct ieee80211_hw *hw = pci_get_drvdata(pdev);
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        u32 val;
        int err;
 
@@ -292,7 +302,7 @@ static struct pci_driver ath_pci_driver = {
 #endif /* CONFIG_PM */
 };
 
-int __init ath_pci_init(void)
+int ath_pci_init(void)
 {
        return pci_register_driver(&ath_pci_driver);
 }
index 52aa2a7abe7aa8b189f07fe32ea33c29363b81c1..e1494bae0f9fdc7d3f6d08f341c101c2a03f0a90 100644 (file)
@@ -132,20 +132,27 @@ ath9k_hw_ar9280_set_channel(struct ath_hw *ah,
                bMode = 0;
                fracMode = 0;
 
-               if ((freq % 20) == 0) {
-                       aModeRefSel = 3;
-               } else if ((freq % 10) == 0) {
-                       aModeRefSel = 2;
-               } else {
+               switch(ah->eep_ops->get_eeprom(ah, EEP_FRAC_N_5G)) {
+               case 0:
+                       if ((freq % 20) == 0) {
+                               aModeRefSel = 3;
+                       } else if ((freq % 10) == 0) {
+                               aModeRefSel = 2;
+                       }
+                       if (aModeRefSel)
+                               break;
+               case 1:
+               default:
                        aModeRefSel = 0;
-
                        fracMode = 1;
                        refDivA = 1;
                        channelSel = (freq * 0x8000) / 15;
 
                        REG_RMW_FIELD(ah, AR_AN_SYNTH9,
                                      AR_AN_SYNTH9_REFDIVA, refDivA);
+
                }
+
                if (!fracMode) {
                        ndiv = (freq * (refDivA >> aModeRefSel)) / 60;
                        channelSel = ndiv & 0x1ff;
index 837a598a7ae5196f28efaa32c9a1122875a181ec..1eac8c707342647da61bfebbd41da6f06f72692a 100644 (file)
@@ -387,6 +387,8 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
 
 #define AR_PHY_CCK_TX_CTRL       0xA204
 #define AR_PHY_CCK_TX_CTRL_JAPAN 0x00000010
+#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK         0x0000000C
+#define AR_PHY_CCK_TX_CTRL_TX_DAC_SCALE_CCK_S       2
 
 #define AR_PHY_CCK_DETECT                           0xA208
 #define AR_PHY_CCK_DETECT_WEAK_SIG_THR_CCK          0x0000003F
@@ -444,6 +446,32 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
 #define AR_PHY_TPCRG1_PD_GAIN_3    0x00300000
 #define AR_PHY_TPCRG1_PD_GAIN_3_S  20
 
+#define AR_PHY_TPCRG1_PD_CAL_ENABLE   0x00400000
+#define AR_PHY_TPCRG1_PD_CAL_ENABLE_S 22
+
+#define AR_PHY_TX_PWRCTRL4       0xa264
+#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID     0x00000001
+#define AR_PHY_TX_PWRCTRL_PD_AVG_VALID_S   0
+#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT       0x000001FE
+#define AR_PHY_TX_PWRCTRL_PD_AVG_OUT_S     1
+
+#define AR_PHY_TX_PWRCTRL6_0     0xa270
+#define AR_PHY_TX_PWRCTRL6_1     0xb270
+#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE     0x03000000
+#define AR_PHY_TX_PWRCTRL_ERR_EST_MODE_S   24
+
+#define AR_PHY_TX_PWRCTRL7       0xa274
+#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN     0x01F80000
+#define AR_PHY_TX_PWRCTRL_INIT_TX_GAIN_S   19
+
+#define AR_PHY_TX_PWRCTRL9       0xa27C
+#define AR_PHY_TX_DESIRED_SCALE_CCK        0x00007C00
+#define AR_PHY_TX_DESIRED_SCALE_CCK_S      10
+
+#define AR_PHY_TX_GAIN_TBL1      0xa300
+#define AR_PHY_TX_GAIN                     0x0007F000
+#define AR_PHY_TX_GAIN_S                   12
+
 #define AR_PHY_VIT_MASK2_M_46_61 0xa3a0
 #define AR_PHY_MASK2_M_31_45     0xa3a4
 #define AR_PHY_MASK2_M_16_30     0xa3a8
@@ -485,6 +513,11 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
 #define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4    0x0FC00000
 #define AR_PHY_TPCRG5_PD_GAIN_BOUNDARY_4_S  22
 
+/* Carrier leak calibration control, do it after AGC calibration */
+#define AR_PHY_CL_CAL_CTL       0xA358
+#define AR_PHY_CL_CAL_ENABLE    0x00000002
+#define AR_PHY_PARALLEL_CAL_ENABLE    0x00000001
+
 #define AR_PHY_POWER_TX_RATE5   0xA38C
 #define AR_PHY_POWER_TX_RATE6   0xA390
 
@@ -530,8 +563,6 @@ bool ath9k_hw_init_rf(struct ath_hw *ah,
                }                                                       \
        } while (0)
 
-#define ATH9K_KEY_XOR                 0xaa
-
 #define ATH9K_IS_MIC_ENABLED(ah)                                       \
        ((ah)->sta_id1_defaults & AR_STA_ID1_CRPT_MIC_ENABLE)
 
index a4e86319176669aae0cec0d49d02b8b98f032c7d..832735677a465740c6173208b0a1026e2df68c74 100644 (file)
@@ -1267,7 +1267,8 @@ static void ath_rc_update_ht(struct ath_softc *sc,
                ath_rc_priv->per_down_time = now_msec;
        }
 
-       ath_debug_stat_retries(sc, tx_rate, xretries, retries);
+       ath_debug_stat_retries(sc, tx_rate, xretries, retries,
+                              ath_rc_priv->state[tx_rate].per);
 
 #undef CHK_RSSI
 }
@@ -1386,40 +1387,18 @@ static struct ath_rate_table *ath_choose_rate_table(struct ath_softc *sc,
 static void ath_rc_init(struct ath_softc *sc,
                        struct ath_rate_priv *ath_rc_priv,
                        struct ieee80211_supported_band *sband,
-                       struct ieee80211_sta *sta)
+                       struct ieee80211_sta *sta,
+                       struct ath_rate_table *rate_table)
 {
-       struct ath_rate_table *rate_table = NULL;
        struct ath_rateset *rateset = &ath_rc_priv->neg_rates;
        u8 *ht_mcs = (u8 *)&ath_rc_priv->neg_ht_rates;
        u8 i, j, k, hi = 0, hthi = 0;
 
-       /* FIXME: Adhoc */
-       if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) ||
-           (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) {
-               bool is_cw_40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-               rate_table = ath_choose_rate_table(sc, sband->band,
-                                                  sta->ht_cap.ht_supported,
-                                                  is_cw_40);
-       } else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
-               /* cur_rate_table would be set on init through config() */
-               rate_table = sc->cur_rate_table;
-       }
-
        if (!rate_table) {
                DPRINTF(sc, ATH_DBG_FATAL, "Rate table not initialized\n");
                return;
        }
 
-       if (sta->ht_cap.ht_supported) {
-               ath_rc_priv->ht_cap = WLAN_RC_HT_FLAG;
-               if (sc->sc_ah->caps.tx_chainmask != 1)
-                       ath_rc_priv->ht_cap |= WLAN_RC_DS_FLAG;
-               if (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
-                       ath_rc_priv->ht_cap |= WLAN_RC_40_FLAG;
-               if (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40)
-                       ath_rc_priv->ht_cap |= WLAN_RC_SGI_FLAG;
-       }
-
        /* Initial rate table size. Will change depending
         * on the working rate set */
        ath_rc_priv->rate_table_size = RATE_TABLE_SIZE;
@@ -1439,7 +1418,7 @@ static void ath_rc_init(struct ath_softc *sc,
                        ath_rc_priv->valid_phy_rateidx[i][j] = 0;
                ath_rc_priv->valid_phy_ratecnt[i] = 0;
        }
-       ath_rc_priv->rc_phy_mode = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG);
+       ath_rc_priv->rc_phy_mode = ath_rc_priv->ht_cap & WLAN_RC_40_FLAG;
 
        /* Set stream capability */
        ath_rc_priv->single_stream = (ath_rc_priv->ht_cap & WLAN_RC_DS_FLAG) ? 0 : 1;
@@ -1484,9 +1463,34 @@ static void ath_rc_init(struct ath_softc *sc,
        ath_rc_sort_validrates(rate_table, ath_rc_priv);
        ath_rc_priv->rate_max_phy = ath_rc_priv->valid_rate_index[k-4];
        sc->cur_rate_table = rate_table;
+
+       DPRINTF(sc, ATH_DBG_CONFIG, "RC Initialized with capabilities: 0x%x\n",
+               ath_rc_priv->ht_cap);
 }
 
-/* Rate Control callbacks */
+static u8 ath_rc_build_ht_caps(struct ath_softc *sc, bool is_ht, bool is_cw40,
+                              bool is_sgi40)
+{
+       u8 caps = 0;
+
+       if (is_ht) {
+               caps = WLAN_RC_HT_FLAG;
+               if (sc->sc_ah->caps.tx_chainmask != 1 &&
+                   ath9k_hw_getcapability(sc->sc_ah, ATH9K_CAP_DS, 0, NULL))
+                       caps |= WLAN_RC_DS_FLAG;
+               if (is_cw40)
+                       caps |= WLAN_RC_40_FLAG;
+               if (is_sgi40)
+                       caps |= WLAN_RC_SGI_FLAG;
+       }
+
+       return caps;
+}
+
+/***********************************/
+/* mac80211 Rate Control callbacks */
+/***********************************/
+
 static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
                          struct ieee80211_sta *sta, void *priv_sta,
                          struct sk_buff *skb)
@@ -1533,7 +1537,8 @@ static void ath_tx_status(void *priv, struct ieee80211_supported_band *sband,
                         tx_info_priv->tx.ts_longretry);
 
        /* Check if aggregation has to be enabled for this tid */
-       if (conf_is_ht(&sc->hw->conf)) {
+       if (conf_is_ht(&sc->hw->conf) &&
+           !(skb->protocol == cpu_to_be16(ETH_P_PAE))) {
                if (ieee80211_is_data_qos(fc)) {
                        u8 *qc, tid;
                        struct ath_node *an;
@@ -1581,6 +1586,8 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
 {
        struct ath_softc *sc = priv;
        struct ath_rate_priv *ath_rc_priv = priv_sta;
+       struct ath_rate_table *rate_table = NULL;
+       bool is_cw40, is_sgi40;
        int i, j = 0;
 
        for (i = 0; i < sband->n_bitrates; i++) {
@@ -1602,12 +1609,72 @@ static void ath_rate_init(void *priv, struct ieee80211_supported_band *sband,
                ath_rc_priv->neg_ht_rates.rs_nrates = j;
        }
 
-       ath_rc_init(sc, priv_sta, sband, sta);
+       is_cw40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+       is_sgi40 = sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40;
+
+       /* Choose rate table first */
+
+       if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) ||
+           (sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)) {
+               rate_table = ath_choose_rate_table(sc, sband->band,
+                                                  sta->ht_cap.ht_supported,
+                                                  is_cw40);
+       } else if (sc->sc_ah->opmode == NL80211_IFTYPE_AP) {
+               /* cur_rate_table would be set on init through config() */
+               rate_table = sc->cur_rate_table;
+       }
+
+       ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc, sta->ht_cap.ht_supported,
+                                                  is_cw40, is_sgi40);
+       ath_rc_init(sc, priv_sta, sband, sta, rate_table);
+}
+
+static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
+                           struct ieee80211_sta *sta, void *priv_sta,
+                           u32 changed)
+{
+       struct ath_softc *sc = priv;
+       struct ath_rate_priv *ath_rc_priv = priv_sta;
+       struct ath_rate_table *rate_table = NULL;
+       bool oper_cw40 = false, oper_sgi40;
+       bool local_cw40 = (ath_rc_priv->ht_cap & WLAN_RC_40_FLAG) ?
+               true : false;
+       bool local_sgi40 = (ath_rc_priv->ht_cap & WLAN_RC_SGI_FLAG) ?
+               true : false;
+
+       /* FIXME: Handle AP mode later when we support CWM */
+
+       if (changed & IEEE80211_RC_HT_CHANGED) {
+               if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
+                       return;
+
+               if (sc->hw->conf.channel_type == NL80211_CHAN_HT40MINUS ||
+                   sc->hw->conf.channel_type == NL80211_CHAN_HT40PLUS)
+                       oper_cw40 = true;
+
+               oper_sgi40 = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+                       true : false;
+
+               if ((local_cw40 != oper_cw40) || (local_sgi40 != oper_sgi40)) {
+                       rate_table = ath_choose_rate_table(sc, sband->band,
+                                                  sta->ht_cap.ht_supported,
+                                                  oper_cw40);
+                       ath_rc_priv->ht_cap = ath_rc_build_ht_caps(sc,
+                                                  sta->ht_cap.ht_supported,
+                                                  oper_cw40, oper_sgi40);
+                       ath_rc_init(sc, priv_sta, sband, sta, rate_table);
+
+                       DPRINTF(sc, ATH_DBG_CONFIG,
+                               "Operating HT Bandwidth changed to: %d\n",
+                               sc->hw->conf.channel_type);
+               }
+       }
 }
 
 static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
 {
-       return hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       return aphy->sc;
 }
 
 static void ath_rate_free(void *priv)
@@ -1646,33 +1713,13 @@ static struct rate_control_ops ath_rate_ops = {
        .tx_status = ath_tx_status,
        .get_rate = ath_get_rate,
        .rate_init = ath_rate_init,
+       .rate_update = ath_rate_update,
        .alloc = ath_rate_alloc,
        .free = ath_rate_free,
        .alloc_sta = ath_rate_alloc_sta,
        .free_sta = ath_rate_free_sta,
 };
 
-static void ath_setup_rate_table(struct ath_softc *sc,
-                                struct ath_rate_table *rate_table)
-{
-       int i;
-
-       for (i = 0; i < rate_table->rate_cnt; i++) {
-               u8 cix = rate_table->info[i].ctrl_rate;
-
-               rate_table->info[i].lpAckDuration =
-                       ath9k_hw_computetxtime(sc->sc_ah, rate_table,
-                                              WLAN_CTRL_FRAME_SIZE,
-                                              cix,
-                                              false);
-               rate_table->info[i].spAckDuration =
-                       ath9k_hw_computetxtime(sc->sc_ah, rate_table,
-                                              WLAN_CTRL_FRAME_SIZE,
-                                              cix,
-                                              true);
-       }
-}
-
 void ath_rate_attach(struct ath_softc *sc)
 {
        sc->hw_rate_table[ATH9K_MODE_11B] =
@@ -1693,12 +1740,6 @@ void ath_rate_attach(struct ath_softc *sc)
                &ar5416_11ng_ratetable;
        sc->hw_rate_table[ATH9K_MODE_11NG_HT40MINUS] =
                &ar5416_11ng_ratetable;
-
-       ath_setup_rate_table(sc, &ar5416_11b_ratetable);
-       ath_setup_rate_table(sc, &ar5416_11a_ratetable);
-       ath_setup_rate_table(sc, &ar5416_11g_ratetable);
-       ath_setup_rate_table(sc, &ar5416_11na_ratetable);
-       ath_setup_rate_table(sc, &ar5416_11ng_ratetable);
 }
 
 int ath_rate_control_register(void)
index d688ec51a14fa8cca27b4266290aa58489c69d4b..db9b0b9a343100fdca3e35a03257157892fa075a 100644 (file)
@@ -120,8 +120,6 @@ struct ath_rate_table {
                u8 sgi_index;
                u8 ht_index;
                u32 max_4ms_framelen;
-               u16 lpAckDuration;
-               u16 spAckDuration;
        } info[RATE_TABLE_SIZE];
        u32 probe_interval;
        u32 rssi_reduce_interval;
@@ -196,11 +194,19 @@ struct ath_rate_priv {
        struct ath_rate_softc *asc;
 };
 
+enum ath9k_internal_frame_type {
+       ATH9K_NOT_INTERNAL,
+       ATH9K_INT_PAUSE,
+       ATH9K_INT_UNPAUSE
+};
+
 struct ath_tx_info_priv {
+       struct ath_wiphy *aphy;
        struct ath_tx_status tx;
        int n_frames;
        int n_bad_frames;
        bool update_rc;
+       enum ath9k_internal_frame_type frame_type;
 };
 
 #define ATH_TX_INFO_PRIV(tx_info) \
index 08f676af894f0cbd9d3b98185b6aba6663751774..0bba17662a1f040a2517a3e4d0478d1cc1c69c22 100644 (file)
 
 #include "ath9k.h"
 
+static struct ieee80211_hw * ath_get_virt_hw(struct ath_softc *sc,
+                                            struct ieee80211_hdr *hdr)
+{
+       struct ieee80211_hw *hw = sc->pri_wiphy->hw;
+       int i;
+
+       spin_lock_bh(&sc->wiphy_lock);
+       for (i = 0; i < sc->num_sec_wiphy; i++) {
+               struct ath_wiphy *aphy = sc->sec_wiphy[i];
+               if (aphy == NULL)
+                       continue;
+               if (compare_ether_addr(hdr->addr1, aphy->hw->wiphy->perm_addr)
+                   == 0) {
+                       hw = aphy->hw;
+                       break;
+               }
+       }
+       spin_unlock_bh(&sc->wiphy_lock);
+       return hw;
+}
+
 /*
  * Setup and link descriptors.
  *
@@ -79,7 +100,7 @@ static u64 ath_extend_tsf(struct ath_softc *sc, u32 rstamp)
        return (tsf & ~0x7fff) | rstamp;
 }
 
-static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len)
+static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len, gfp_t gfp_mask)
 {
        struct sk_buff *skb;
        u32 off;
@@ -97,7 +118,7 @@ static struct sk_buff *ath_rxbuf_alloc(struct ath_softc *sc, u32 len)
         * Unfortunately this means we may get 8 KB here from the
         * kernel... and that is actually what is observed on some
         * systems :( */
-       skb = dev_alloc_skb(len + sc->cachelsz - 1);
+       skb = __dev_alloc_skb(len + sc->cachelsz - 1, gfp_mask);
        if (skb != NULL) {
                off = ((unsigned long) skb->data) % sc->cachelsz;
                if (off != 0)
@@ -123,10 +144,12 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
        struct ieee80211_hdr *hdr;
        u8 ratecode;
        __le16 fc;
+       struct ieee80211_hw *hw;
 
        hdr = (struct ieee80211_hdr *)skb->data;
        fc = hdr->frame_control;
        memset(rx_status, 0, sizeof(struct ieee80211_rx_status));
+       hw = ath_get_virt_hw(sc, hdr);
 
        if (ds->ds_rxstat.rs_more) {
                /*
@@ -186,7 +209,6 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
                rx_status->rate_idx = ratecode & 0x7f;
        } else {
                int i = 0, cur_band, n_rates;
-               struct ieee80211_hw *hw = sc->hw;
 
                cur_band = hw->conf.channel->band;
                n_rates = sc->sbands[cur_band].n_bitrates;
@@ -208,8 +230,8 @@ static int ath_rx_prepare(struct sk_buff *skb, struct ath_desc *ds,
        }
 
        rx_status->mactime = ath_extend_tsf(sc, ds->ds_rxstat.rs_tstamp);
-       rx_status->band = sc->hw->conf.channel->band;
-       rx_status->freq =  sc->hw->conf.channel->center_freq;
+       rx_status->band = hw->conf.channel->band;
+       rx_status->freq = hw->conf.channel->center_freq;
        rx_status->noise = sc->ani.noise_floor;
        rx_status->signal = rx_status->noise + ds->ds_rxstat.rs_rssi;
        rx_status->antenna = ds->ds_rxstat.rs_antenna;
@@ -284,7 +306,7 @@ int ath_rx_init(struct ath_softc *sc, int nbufs)
                }
 
                list_for_each_entry(bf, &sc->rx.rxbuf, list) {
-                       skb = ath_rxbuf_alloc(sc, sc->rx.bufsize);
+                       skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_KERNEL);
                        if (skb == NULL) {
                                error = -ENOMEM;
                                break;
@@ -363,26 +385,36 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
        if (sc->sc_ah->opmode != NL80211_IFTYPE_STATION)
                rfilt |= ATH9K_RX_FILTER_PROBEREQ;
 
-       /* Can't set HOSTAP into promiscous mode */
+       /*
+        * Set promiscuous mode when FIF_PROMISC_IN_BSS is enabled for station
+        * mode interface or when in monitor mode. AP mode does not need this
+        * since it receives all in-BSS frames anyway.
+        */
        if (((sc->sc_ah->opmode != NL80211_IFTYPE_AP) &&
             (sc->rx.rxfilter & FIF_PROMISC_IN_BSS)) ||
-           (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR)) {
+           (sc->sc_ah->opmode == NL80211_IFTYPE_MONITOR))
                rfilt |= ATH9K_RX_FILTER_PROM;
-               /* ??? To prevent from sending ACK */
-               rfilt &= ~ATH9K_RX_FILTER_UCAST;
-       }
 
        if (sc->rx.rxfilter & FIF_CONTROL)
                rfilt |= ATH9K_RX_FILTER_CONTROL;
 
-       if (sc->sc_ah->opmode == NL80211_IFTYPE_STATION ||
-           sc->sc_ah->opmode == NL80211_IFTYPE_ADHOC)
+       if ((sc->sc_ah->opmode == NL80211_IFTYPE_STATION) &&
+           !(sc->rx.rxfilter & FIF_BCN_PRBRESP_PROMISC))
+               rfilt |= ATH9K_RX_FILTER_MYBEACON;
+       else
                rfilt |= ATH9K_RX_FILTER_BEACON;
 
-       /* If in HOSTAP mode, want to enable reception of PSPOLL frames
-          & beacon frames */
+       /* If in HOSTAP mode, want to enable reception of PSPOLL frames */
        if (sc->sc_ah->opmode == NL80211_IFTYPE_AP)
-               rfilt |= (ATH9K_RX_FILTER_BEACON | ATH9K_RX_FILTER_PSPOLL);
+               rfilt |= ATH9K_RX_FILTER_PSPOLL;
+
+       if (sc->sec_wiphy) {
+               /* TODO: only needed if more than one BSSID is in use in
+                * station/adhoc mode */
+               /* TODO: for older chips, may need to add ATH9K_RX_FILTER_PROM
+                */
+               rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
+       }
 
        return rfilt;
 
@@ -427,7 +459,6 @@ bool ath_stoprecv(struct ath_softc *sc)
        ath9k_hw_stoppcurecv(ah);
        ath9k_hw_setrxfilter(ah, 0);
        stopped = ath9k_hw_stopdmarecv(ah);
-       mdelay(3); /* 3ms is long enough for 1 frame */
        sc->rx.rxlink = NULL;
 
        return stopped;
@@ -550,7 +581,7 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
 
                /* Ensure we always have an skb to requeue once we are done
                 * processing the current buffer's skb */
-               requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize);
+               requeue_skb = ath_rxbuf_alloc(sc, sc->rx.bufsize, GFP_ATOMIC);
 
                /* If there is no memory we ignore the current RX'd frame,
                 * tell hardware it can give us a new frame using the old
@@ -604,7 +635,29 @@ int ath_rx_tasklet(struct ath_softc *sc, int flush)
                }
 
                /* Send the frame to mac80211 */
-               __ieee80211_rx(sc->hw, skb, &rx_status);
+               if (hdr->addr1[5] & 0x01) {
+                       int i;
+                       /*
+                        * Deliver broadcast/multicast frames to all suitable
+                        * virtual wiphys.
+                        */
+                       /* TODO: filter based on channel configuration */
+                       for (i = 0; i < sc->num_sec_wiphy; i++) {
+                               struct ath_wiphy *aphy = sc->sec_wiphy[i];
+                               struct sk_buff *nskb;
+                               if (aphy == NULL)
+                                       continue;
+                               nskb = skb_copy(skb, GFP_ATOMIC);
+                               if (nskb)
+                                       __ieee80211_rx(aphy->hw, nskb,
+                                                      &rx_status);
+                       }
+                       __ieee80211_rx(sc->hw, skb, &rx_status);
+               } else {
+                       /* Deliver unicast frames based on receiver address */
+                       __ieee80211_rx(ath_get_virt_hw(sc, hdr), skb,
+                                      &rx_status);
+               }
 
                /* We will now give hardware our shiny new allocated skb */
                bf->bf_mpdu = requeue_skb;
index 17ed190349a53e6088c83fe209287be7f004aa07..d86e90e38173592aee2765a92a6957495981e34a 100644 (file)
@@ -67,7 +67,7 @@
 #define AR_DMASIZE_512B      0x00000007
 
 #define AR_TXCFG             0x0030
-#define AR_TXCFG_DMASZ_MASK  0x00000003
+#define AR_TXCFG_DMASZ_MASK  0x00000007
 #define AR_TXCFG_DMASZ_4B    0
 #define AR_TXCFG_DMASZ_8B    1
 #define AR_TXCFG_DMASZ_16B   2
 #define AR_CST_TIMEOUT_LIMIT      0xFFFF0000
 #define AR_CST_TIMEOUT_LIMIT_S    16
 
-#define AR_SREV_VERSION_9100                  0x014
-
-#define AR_SREV_9100(ah) ((ah->hw_version.macVersion) == AR_SREV_VERSION_9100)
-#define AR_SREV_5416_V20_OR_LATER(_ah) \
-       (AR_SREV_9100((_ah)) || AR_SREV_5416_20_OR_LATER(_ah))
-#define AR_SREV_5416_V22_OR_LATER(_ah) \
-       (AR_SREV_9100((_ah)) || AR_SREV_5416_22_OR_LATER(_ah))
-
 #define AR_ISR               0x0080
 #define AR_ISR_RXOK          0x00000001
 #define AR_ISR_RXDESC        0x00000002
 #define AR_SREV_REVISION_5416_10               0
 #define AR_SREV_REVISION_5416_20               1
 #define AR_SREV_REVISION_5416_22               2
+#define AR_SREV_VERSION_9100                  0x14
 #define AR_SREV_VERSION_9160                 0x40
 #define AR_SREV_REVISION_9160_10             0
 #define AR_SREV_REVISION_9160_11             1
 #define AR_SREV_REVISION_9285_11              1
 #define AR_SREV_REVISION_9285_12              2
 
-#define AR_SREV_9100_OR_LATER(_ah) \
-       (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_5416_PCIE))
+#define AR_SREV_5416(_ah) \
+       (((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCI) || \
+        ((_ah)->hw_version.macVersion == AR_SREV_VERSION_5416_PCIE))
 #define AR_SREV_5416_20_OR_LATER(_ah) \
-       (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9160) || \
-               ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_20))
+       (((AR_SREV_5416(_ah)) && \
+        ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_20)) || \
+        ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100))
 #define AR_SREV_5416_22_OR_LATER(_ah) \
-       (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9160) || \
-               ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_22))
+       (((AR_SREV_5416(_ah)) && \
+        ((_ah)->hw_version.macRev >= AR_SREV_REVISION_5416_22)) || \
+        ((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100))
+
+#define AR_SREV_9100(ah) \
+       ((ah->hw_version.macVersion) == AR_SREV_VERSION_9100)
+#define AR_SREV_9100_OR_LATER(_ah) \
+       (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9100))
+
 #define AR_SREV_9160(_ah) \
        (((_ah)->hw_version.macVersion == AR_SREV_VERSION_9160))
 #define AR_SREV_9160_10_OR_LATER(_ah) \
 #define AR_SREV_9285_10_OR_LATER(_ah) \
        (((_ah)->hw_version.macVersion >= AR_SREV_VERSION_9285))
 #define AR_SREV_9285_11(_ah) \
-       (AR_SREV_9280(ah) && \
+       (AR_SREV_9285(ah) && \
         ((_ah)->hw_version.macRev == AR_SREV_REVISION_9285_11))
 #define AR_SREV_9285_11_OR_LATER(_ah) \
        (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9285) || \
         (AR_SREV_9285(ah) && ((_ah)->hw_version.macRev >= \
                               AR_SREV_REVISION_9285_11)))
 #define AR_SREV_9285_12(_ah) \
-       (AR_SREV_9280(ah) && \
+       (AR_SREV_9285(ah) && \
         ((_ah)->hw_version.macRev == AR_SREV_REVISION_9285_12))
 #define AR_SREV_9285_12_OR_LATER(_ah) \
        (((_ah)->hw_version.macVersion > AR_SREV_VERSION_9285) || \
@@ -977,8 +979,6 @@ enum {
 #define AR_RTC_PLL_CLKSEL       0x00000300
 #define AR_RTC_PLL_CLKSEL_S     8
 
-
-
 #define AR_RTC_RESET \
        ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0040) : 0x7040)
 #define AR_RTC_RESET_EN                (0x00000001)
@@ -1015,6 +1015,12 @@ enum {
 #define AR_RTC_INTR_MASK \
        ((AR_SREV_9100(ah)) ? (AR_RTC_BASE + 0x0058) : 0x7058)
 
+/* RTC_DERIVED_* - only for AR9100 */
+
+#define AR_RTC_DERIVED_CLK           (AR_RTC_BASE + 0x0038)
+#define AR_RTC_DERIVED_CLK_PERIOD    0x0000fffe
+#define AR_RTC_DERIVED_CLK_PERIOD_S  1
+
 #define        AR_SEQ_MASK     0x8060
 
 #define AR_AN_RF2G1_CH0         0x7810
@@ -1385,8 +1391,8 @@ enum {
 #define AR_PHY_COUNTMAX        (3 << 22)
 #define AR_MIBCNT_INTRMASK     (3 << 22)
 
-#define AR_TSF_THRESHOLD       0x813c
-#define AR_TSF_THRESHOLD_VAL   0x0000FFFF
+#define AR_TSFOOR_THRESHOLD       0x813c
+#define AR_TSFOOR_THRESHOLD_VAL   0x0000FFFF
 
 #define AR_PHY_ERR_EIFS_MASK   8144
 
index 8c2b56ac55ff250c68f8914d00c3c2377a8cfea6..b8f9b6d6bec442908f48d2360d168e1f9a412e28 100644 (file)
@@ -106,19 +106,20 @@ static const struct ieee80211_regdomain ath9k_world_regdom_67_68_6A = {
        }
 };
 
-static u16 ath9k_regd_get_eepromRD(struct ath_hw *ah)
+static inline bool is_wwr_sku(u16 regd)
 {
-       return ah->regulatory.current_rd & ~WORLDWIDE_ROAMING_FLAG;
+       return ((regd & WORLD_SKU_MASK) == WORLD_SKU_PREFIX) ||
+               (regd == WORLD);
 }
 
-u16 ath9k_regd_get_rd(struct ath_hw *ah)
+static u16 ath9k_regd_get_eepromRD(struct ath_hw *ah)
 {
-       return ath9k_regd_get_eepromRD(ah);
+       return ah->regulatory.current_rd & ~WORLDWIDE_ROAMING_FLAG;
 }
 
 bool ath9k_is_world_regd(struct ath_hw *ah)
 {
-       return isWwrSKU(ah);
+       return is_wwr_sku(ath9k_regd_get_eepromRD(ah));
 }
 
 const struct ieee80211_regdomain *ath9k_default_world_regdomain(void)
@@ -159,13 +160,19 @@ static bool ath9k_is_radar_freq(u16 center_freq)
 }
 
 /*
- * Enable adhoc on 5 GHz if allowed by 11d.
- * Remove passive scan if channel is allowed by 11d,
- * except when on radar frequencies.
+ * N.B: These exception rules do not apply radar freqs.
+ *
+ * - We enable adhoc (or beaconing) if allowed by 11d
+ * - We enable active scan if the channel is allowed by 11d
+ * - If no country IE has been processed and a we determine we have
+ *   received a beacon on a channel we can enable active scan and
+ *   adhoc (or beaconing).
  */
-static void ath9k_reg_apply_5ghz_beaconing_flags(struct wiphy *wiphy,
-                                            enum reg_set_by setby)
+static void ath9k_reg_apply_beaconing_flags(
+       struct wiphy *wiphy,
+       enum nl80211_reg_initiator initiator)
 {
+       enum ieee80211_band band;
        struct ieee80211_supported_band *sband;
        const struct ieee80211_reg_rule *reg_rule;
        struct ieee80211_channel *ch;
@@ -173,34 +180,56 @@ static void ath9k_reg_apply_5ghz_beaconing_flags(struct wiphy *wiphy,
        u32 bandwidth = 0;
        int r;
 
-       if (setby != REGDOM_SET_BY_COUNTRY_IE)
-               return;
-       if (!wiphy->bands[IEEE80211_BAND_5GHZ])
-               return;
+       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
 
-       sband = wiphy->bands[IEEE80211_BAND_5GHZ];
-       for (i = 0; i < sband->n_channels; i++) {
-               ch = &sband->channels[i];
-               r = freq_reg_info(wiphy, ch->center_freq,
-                       &bandwidth, &reg_rule);
-               if (r)
+               if (!wiphy->bands[band])
                        continue;
-               /* If 11d had a rule for this channel ensure we enable adhoc
-                * if it allows us to use it. Note that we would have disabled
-                * it by applying our static world regdomain by default during
-                * probe */
-               if (!(reg_rule->flags & NL80211_RRF_NO_IBSS))
-                       ch->flags &= ~IEEE80211_CHAN_NO_IBSS;
-               if (!ath9k_is_radar_freq(ch->center_freq))
-                       continue;
-               if (!(reg_rule->flags & NL80211_RRF_PASSIVE_SCAN))
-                       ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+
+               sband = wiphy->bands[band];
+
+               for (i = 0; i < sband->n_channels; i++) {
+
+                       ch = &sband->channels[i];
+
+                       if (ath9k_is_radar_freq(ch->center_freq) ||
+                           (ch->flags & IEEE80211_CHAN_RADAR))
+                               continue;
+
+                       if (initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+                               r = freq_reg_info(wiphy, ch->center_freq,
+                                       &bandwidth, &reg_rule);
+                               if (r)
+                                       continue;
+                               /*
+                                * If 11d had a rule for this channel ensure
+                                * we enable adhoc/beaconing if it allows us to
+                                * use it. Note that we would have disabled it
+                                * by applying our static world regdomain by
+                                * default during init, prior to calling our
+                                * regulatory_hint().
+                                */
+                               if (!(reg_rule->flags &
+                                   NL80211_RRF_NO_IBSS))
+                                       ch->flags &=
+                                         ~IEEE80211_CHAN_NO_IBSS;
+                               if (!(reg_rule->flags &
+                                   NL80211_RRF_PASSIVE_SCAN))
+                                       ch->flags &=
+                                         ~IEEE80211_CHAN_PASSIVE_SCAN;
+                       } else {
+                               if (ch->beacon_found)
+                                       ch->flags &= ~(IEEE80211_CHAN_NO_IBSS |
+                                         IEEE80211_CHAN_PASSIVE_SCAN);
+                       }
+               }
        }
+
 }
 
 /* Allows active scan scan on Ch 12 and 13 */
-static void ath9k_reg_apply_active_scan_flags(struct wiphy *wiphy,
-                                             enum reg_set_by setby)
+static void ath9k_reg_apply_active_scan_flags(
+       struct wiphy *wiphy,
+       enum nl80211_reg_initiator initiator)
 {
        struct ieee80211_supported_band *sband;
        struct ieee80211_channel *ch;
@@ -208,12 +237,13 @@ static void ath9k_reg_apply_active_scan_flags(struct wiphy *wiphy,
        u32 bandwidth = 0;
        int r;
 
-       /* Force passive scan on Channels 12-13 */
        sband = wiphy->bands[IEEE80211_BAND_2GHZ];
 
-       /* If no country IE has been received always enable active scan
-        * on these channels */
-       if (setby != REGDOM_SET_BY_COUNTRY_IE) {
+       /*
+        * If no country IE has been received always enable active scan
+        * on these channels. This is only done for specific regulatory SKUs
+        */
+       if (initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
                ch = &sband->channels[11]; /* CH 12 */
                if (ch->flags & IEEE80211_CHAN_PASSIVE_SCAN)
                        ch->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
@@ -223,10 +253,12 @@ static void ath9k_reg_apply_active_scan_flags(struct wiphy *wiphy,
                return;
        }
 
-       /* If a country IE has been recieved check its rule for this
+       /*
+        * If a country IE has been recieved check its rule for this
         * channel first before enabling active scan. The passive scan
-        * would have been enforced by the initial probe processing on
-        * our custom regulatory domain. */
+        * would have been enforced by the initial processing of our
+        * custom regulatory domain.
+        */
 
        ch = &sband->channels[11]; /* CH 12 */
        r = freq_reg_info(wiphy, ch->center_freq, &bandwidth, &reg_rule);
@@ -278,10 +310,12 @@ void ath9k_reg_apply_radar_flags(struct wiphy *wiphy)
        }
 }
 
-void ath9k_reg_apply_world_flags(struct wiphy *wiphy, enum reg_set_by setby)
+void ath9k_reg_apply_world_flags(struct wiphy *wiphy,
+                                enum nl80211_reg_initiator initiator)
 {
        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        struct ath_hw *ah = sc->sc_ah;
 
        switch (ah->regulatory.regpair->regDmnEnum) {
@@ -289,11 +323,11 @@ void ath9k_reg_apply_world_flags(struct wiphy *wiphy, enum reg_set_by setby)
        case 0x63:
        case 0x66:
        case 0x67:
-               ath9k_reg_apply_5ghz_beaconing_flags(wiphy, setby);
+               ath9k_reg_apply_beaconing_flags(wiphy, initiator);
                break;
        case 0x68:
-               ath9k_reg_apply_5ghz_beaconing_flags(wiphy, setby);
-               ath9k_reg_apply_active_scan_flags(wiphy, setby);
+               ath9k_reg_apply_beaconing_flags(wiphy, initiator);
+               ath9k_reg_apply_active_scan_flags(wiphy, initiator);
                break;
        }
        return;
@@ -302,18 +336,18 @@ void ath9k_reg_apply_world_flags(struct wiphy *wiphy, enum reg_set_by setby)
 int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request)
 {
        struct ieee80211_hw *hw = wiphy_to_ieee80211_hw(wiphy);
-       struct ath_softc *sc = hw->priv;
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
 
        /* We always apply this */
        ath9k_reg_apply_radar_flags(wiphy);
 
        switch (request->initiator) {
-       case REGDOM_SET_BY_DRIVER:
-       case REGDOM_SET_BY_INIT:
-       case REGDOM_SET_BY_CORE:
-       case REGDOM_SET_BY_USER:
+       case NL80211_REGDOM_SET_BY_DRIVER:
+       case NL80211_REGDOM_SET_BY_CORE:
+       case NL80211_REGDOM_SET_BY_USER:
                break;
-       case REGDOM_SET_BY_COUNTRY_IE:
+       case NL80211_REGDOM_SET_BY_COUNTRY_IE:
                if (ath9k_is_world_regd(sc->sc_ah))
                        ath9k_reg_apply_world_flags(wiphy, request->initiator);
                break;
@@ -371,11 +405,8 @@ ath9k_regd_find_country_by_rd(int regdmn)
 }
 
 /* Returns the map of the EEPROM set RD to a country code */
-static u16 ath9k_regd_get_default_country(struct ath_hw *ah)
+static u16 ath9k_regd_get_default_country(u16 rd)
 {
-       u16 rd;
-
-       rd = ath9k_regd_get_eepromRD(ah);
        if (rd & COUNTRY_ERD_FLAG) {
                struct country_code_to_enum_rd *country = NULL;
                u16 cc = rd & ~COUNTRY_ERD_FLAG;
@@ -405,7 +436,7 @@ ath9k_get_regpair(int regdmn)
 int ath9k_regd_init(struct ath_hw *ah)
 {
        struct country_code_to_enum_rd *country = NULL;
-       int regdmn;
+       u16 regdmn;
 
        if (!ath9k_regd_is_eeprom_valid(ah)) {
                DPRINTF(ah->ah_sc, ATH_DBG_REGULATORY,
@@ -413,14 +444,14 @@ int ath9k_regd_init(struct ath_hw *ah)
                return -EINVAL;
        }
 
-       ah->regulatory.country_code = ath9k_regd_get_default_country(ah);
+       regdmn = ath9k_regd_get_eepromRD(ah);
+       ah->regulatory.country_code = ath9k_regd_get_default_country(regdmn);
 
        if (ah->regulatory.country_code == CTRY_DEFAULT &&
-           ath9k_regd_get_eepromRD(ah) == CTRY_DEFAULT)
+           regdmn == CTRY_DEFAULT)
                ah->regulatory.country_code = CTRY_UNITED_STATES;
 
        if (ah->regulatory.country_code == CTRY_DEFAULT) {
-               regdmn = ath9k_regd_get_eepromRD(ah);
                country = NULL;
        } else {
                country = ath9k_regd_find_country(ah->regulatory.country_code);
@@ -433,7 +464,6 @@ int ath9k_regd_init(struct ath_hw *ah)
                        regdmn = country->regDmnEnum;
        }
 
-       ah->regulatory.current_rd_inuse = regdmn;
        ah->regulatory.regpair = ath9k_get_regpair(regdmn);
 
        if (!ah->regulatory.regpair) {
@@ -467,7 +497,8 @@ u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan)
        u32 ctl = NO_CTL;
 
        if (!ah->regulatory.regpair ||
-           (ah->regulatory.country_code == CTRY_DEFAULT && isWwrSKU(ah))) {
+           (ah->regulatory.country_code == CTRY_DEFAULT &&
+            is_wwr_sku(ath9k_regd_get_eepromRD(ah)))) {
                if (IS_CHAN_B(chan))
                        ctl = SD_NO_CTL | CTL_11B;
                else if (IS_CHAN_G(chan))
@@ -480,7 +511,7 @@ u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan)
        if (IS_CHAN_B(chan))
                ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11B;
        else if (IS_CHAN_G(chan))
-               ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11G;
+               ctl = ah->regulatory.regpair->reg_2ghz_ctl | CTL_11G;
        else
                ctl = ah->regulatory.regpair->reg_5ghz_ctl | CTL_11A;
 
index 39420de818f8c57b78645943ce319631ffe18534..8f885f3bc8dff67f100330bb9e71d00cbeff68b3 100644 (file)
 #define COUNTRY_ERD_FLAG        0x8000
 #define WORLDWIDE_ROAMING_FLAG  0x4000
 
-#define isWwrSKU(_ah) \
-       (((ath9k_regd_get_eepromRD((_ah)) & WORLD_SKU_MASK) == \
-               WORLD_SKU_PREFIX) || \
-               (ath9k_regd_get_eepromRD(_ah) == WORLD))
-
 #define MULTI_DOMAIN_MASK 0xFF00
 
 #define WORLD_SKU_MASK          0x00F0
@@ -52,7 +47,6 @@ struct ath9k_regulatory {
        u32 tp_scale;
        u16 current_rd;
        u16 current_rd_ext;
-       u16 current_rd_inuse;
        int16_t power_limit;
        struct reg_dmn_pair_mapping *regpair;
 };
@@ -239,17 +233,15 @@ enum CountryCode {
        CTRY_BELGIUM2 = 5002
 };
 
-u16 ath9k_regd_get_rd(struct ath_hw *ah);
 bool ath9k_is_world_regd(struct ath_hw *ah);
 const struct ieee80211_regdomain *ath9k_world_regdomain(struct ath_hw *ah);
 const struct ieee80211_regdomain *ath9k_default_world_regdomain(void);
-void ath9k_reg_apply_world_flags(struct wiphy *wiphy, enum reg_set_by setby);
+void ath9k_reg_apply_world_flags(struct wiphy *wiphy,
+                                enum nl80211_reg_initiator initiator);
 void ath9k_reg_apply_radar_flags(struct wiphy *wiphy);
 int ath9k_regd_init(struct ath_hw *ah);
 bool ath9k_regd_is_eeprom_valid(struct ath_hw *ah);
 u32 ath9k_regd_get_ctl(struct ath_hw *ah, struct ath9k_channel *chan);
 int ath9k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *request);
-void ath9k_regd_get_current_country(struct ath_hw *ah,
-                                   struct ath9k_country_entry *ctry);
 
 #endif
diff --git a/drivers/net/wireless/ath9k/virtual.c b/drivers/net/wireless/ath9k/virtual.c
new file mode 100644 (file)
index 0000000..1ff429b
--- /dev/null
@@ -0,0 +1,662 @@
+/*
+ * Copyright (c) 2008-2009 Atheros Communications Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "ath9k.h"
+
+struct ath9k_vif_iter_data {
+       int count;
+       u8 *addr;
+};
+
+static void ath9k_vif_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+{
+       struct ath9k_vif_iter_data *iter_data = data;
+       u8 *nbuf;
+
+       nbuf = krealloc(iter_data->addr, (iter_data->count + 1) * ETH_ALEN,
+                       GFP_ATOMIC);
+       if (nbuf == NULL)
+               return;
+
+       memcpy(nbuf + iter_data->count * ETH_ALEN, mac, ETH_ALEN);
+       iter_data->addr = nbuf;
+       iter_data->count++;
+}
+
+void ath9k_set_bssid_mask(struct ieee80211_hw *hw)
+{
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
+       struct ath9k_vif_iter_data iter_data;
+       int i, j;
+       u8 mask[ETH_ALEN];
+
+       /*
+        * Add primary MAC address even if it is not in active use since it
+        * will be configured to the hardware as the starting point and the
+        * BSSID mask will need to be changed if another address is active.
+        */
+       iter_data.addr = kmalloc(ETH_ALEN, GFP_ATOMIC);
+       if (iter_data.addr) {
+               memcpy(iter_data.addr, sc->sc_ah->macaddr, ETH_ALEN);
+               iter_data.count = 1;
+       } else
+               iter_data.count = 0;
+
+       /* Get list of all active MAC addresses */
+       spin_lock_bh(&sc->wiphy_lock);
+       ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter,
+                                                  &iter_data);
+       for (i = 0; i < sc->num_sec_wiphy; i++) {
+               if (sc->sec_wiphy[i] == NULL)
+                       continue;
+               ieee80211_iterate_active_interfaces_atomic(
+                       sc->sec_wiphy[i]->hw, ath9k_vif_iter, &iter_data);
+       }
+       spin_unlock_bh(&sc->wiphy_lock);
+
+       /* Generate an address mask to cover all active addresses */
+       memset(mask, 0, ETH_ALEN);
+       for (i = 0; i < iter_data.count; i++) {
+               u8 *a1 = iter_data.addr + i * ETH_ALEN;
+               for (j = i + 1; j < iter_data.count; j++) {
+                       u8 *a2 = iter_data.addr + j * ETH_ALEN;
+                       mask[0] |= a1[0] ^ a2[0];
+                       mask[1] |= a1[1] ^ a2[1];
+                       mask[2] |= a1[2] ^ a2[2];
+                       mask[3] |= a1[3] ^ a2[3];
+                       mask[4] |= a1[4] ^ a2[4];
+                       mask[5] |= a1[5] ^ a2[5];
+               }
+       }
+
+       kfree(iter_data.addr);
+
+       /* Invert the mask and configure hardware */
+       sc->bssidmask[0] = ~mask[0];
+       sc->bssidmask[1] = ~mask[1];
+       sc->bssidmask[2] = ~mask[2];
+       sc->bssidmask[3] = ~mask[3];
+       sc->bssidmask[4] = ~mask[4];
+       sc->bssidmask[5] = ~mask[5];
+
+       ath9k_hw_setbssidmask(sc);
+}
+
+int ath9k_wiphy_add(struct ath_softc *sc)
+{
+       int i, error;
+       struct ath_wiphy *aphy;
+       struct ieee80211_hw *hw;
+       u8 addr[ETH_ALEN];
+
+       hw = ieee80211_alloc_hw(sizeof(struct ath_wiphy), &ath9k_ops);
+       if (hw == NULL)
+               return -ENOMEM;
+
+       spin_lock_bh(&sc->wiphy_lock);
+       for (i = 0; i < sc->num_sec_wiphy; i++) {
+               if (sc->sec_wiphy[i] == NULL)
+                       break;
+       }
+
+       if (i == sc->num_sec_wiphy) {
+               /* No empty slot available; increase array length */
+               struct ath_wiphy **n;
+               n = krealloc(sc->sec_wiphy,
+                            (sc->num_sec_wiphy + 1) *
+                            sizeof(struct ath_wiphy *),
+                            GFP_ATOMIC);
+               if (n == NULL) {
+                       spin_unlock_bh(&sc->wiphy_lock);
+                       ieee80211_free_hw(hw);
+                       return -ENOMEM;
+               }
+               n[i] = NULL;
+               sc->sec_wiphy = n;
+               sc->num_sec_wiphy++;
+       }
+
+       SET_IEEE80211_DEV(hw, sc->dev);
+
+       aphy = hw->priv;
+       aphy->sc = sc;
+       aphy->hw = hw;
+       sc->sec_wiphy[i] = aphy;
+       spin_unlock_bh(&sc->wiphy_lock);
+
+       memcpy(addr, sc->sc_ah->macaddr, ETH_ALEN);
+       addr[0] |= 0x02; /* Locally managed address */
+       /*
+        * XOR virtual wiphy index into the least significant bits to generate
+        * a different MAC address for each virtual wiphy.
+        */
+       addr[5] ^= i & 0xff;
+       addr[4] ^= (i & 0xff00) >> 8;
+       addr[3] ^= (i & 0xff0000) >> 16;
+
+       SET_IEEE80211_PERM_ADDR(hw, addr);
+
+       ath_set_hw_capab(sc, hw);
+
+       error = ieee80211_register_hw(hw);
+
+       if (error == 0) {
+               /* Make sure wiphy scheduler is started (if enabled) */
+               ath9k_wiphy_set_scheduler(sc, sc->wiphy_scheduler_int);
+       }
+
+       return error;
+}
+
+int ath9k_wiphy_del(struct ath_wiphy *aphy)
+{
+       struct ath_softc *sc = aphy->sc;
+       int i;
+
+       spin_lock_bh(&sc->wiphy_lock);
+       for (i = 0; i < sc->num_sec_wiphy; i++) {
+               if (aphy == sc->sec_wiphy[i]) {
+                       sc->sec_wiphy[i] = NULL;
+                       spin_unlock_bh(&sc->wiphy_lock);
+                       ieee80211_unregister_hw(aphy->hw);
+                       ieee80211_free_hw(aphy->hw);
+                       return 0;
+               }
+       }
+       spin_unlock_bh(&sc->wiphy_lock);
+       return -ENOENT;
+}
+
+static int ath9k_send_nullfunc(struct ath_wiphy *aphy,
+                              struct ieee80211_vif *vif, const u8 *bssid,
+                              int ps)
+{
+       struct ath_softc *sc = aphy->sc;
+       struct ath_tx_control txctl;
+       struct sk_buff *skb;
+       struct ieee80211_hdr *hdr;
+       __le16 fc;
+       struct ieee80211_tx_info *info;
+
+       skb = dev_alloc_skb(24);
+       if (skb == NULL)
+               return -ENOMEM;
+       hdr = (struct ieee80211_hdr *) skb_put(skb, 24);
+       memset(hdr, 0, 24);
+       fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
+                        IEEE80211_FCTL_TODS);
+       if (ps)
+               fc |= cpu_to_le16(IEEE80211_FCTL_PM);
+       hdr->frame_control = fc;
+       memcpy(hdr->addr1, bssid, ETH_ALEN);
+       memcpy(hdr->addr2, aphy->hw->wiphy->perm_addr, ETH_ALEN);
+       memcpy(hdr->addr3, bssid, ETH_ALEN);
+
+       info = IEEE80211_SKB_CB(skb);
+       memset(info, 0, sizeof(*info));
+       info->flags = IEEE80211_TX_CTL_REQ_TX_STATUS;
+       info->control.vif = vif;
+       info->control.rates[0].idx = 0;
+       info->control.rates[0].count = 4;
+       info->control.rates[1].idx = -1;
+
+       memset(&txctl, 0, sizeof(struct ath_tx_control));
+       txctl.txq = &sc->tx.txq[sc->tx.hwq_map[ATH9K_WME_AC_VO]];
+       txctl.frame_type = ps ? ATH9K_INT_PAUSE : ATH9K_INT_UNPAUSE;
+
+       if (ath_tx_start(aphy->hw, skb, &txctl) != 0)
+               goto exit;
+
+       return 0;
+exit:
+       dev_kfree_skb_any(skb);
+       return -1;
+}
+
+static bool __ath9k_wiphy_pausing(struct ath_softc *sc)
+{
+       int i;
+       if (sc->pri_wiphy->state == ATH_WIPHY_PAUSING)
+               return true;
+       for (i = 0; i < sc->num_sec_wiphy; i++) {
+               if (sc->sec_wiphy[i] &&
+                   sc->sec_wiphy[i]->state == ATH_WIPHY_PAUSING)
+                       return true;
+       }
+       return false;
+}
+
+static bool ath9k_wiphy_pausing(struct ath_softc *sc)
+{
+       bool ret;
+       spin_lock_bh(&sc->wiphy_lock);
+       ret = __ath9k_wiphy_pausing(sc);
+       spin_unlock_bh(&sc->wiphy_lock);
+       return ret;
+}
+
+static bool __ath9k_wiphy_scanning(struct ath_softc *sc)
+{
+       int i;
+       if (sc->pri_wiphy->state == ATH_WIPHY_SCAN)
+               return true;
+       for (i = 0; i < sc->num_sec_wiphy; i++) {
+               if (sc->sec_wiphy[i] &&
+                   sc->sec_wiphy[i]->state == ATH_WIPHY_SCAN)
+                       return true;
+       }
+       return false;
+}
+
+bool ath9k_wiphy_scanning(struct ath_softc *sc)
+{
+       bool ret;
+       spin_lock_bh(&sc->wiphy_lock);
+       ret = __ath9k_wiphy_scanning(sc);
+       spin_unlock_bh(&sc->wiphy_lock);
+       return ret;
+}
+
+static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy);
+
+/* caller must hold wiphy_lock */
+static void __ath9k_wiphy_unpause_ch(struct ath_wiphy *aphy)
+{
+       if (aphy == NULL)
+               return;
+       if (aphy->chan_idx != aphy->sc->chan_idx)
+               return; /* wiphy not on the selected channel */
+       __ath9k_wiphy_unpause(aphy);
+}
+
+static void ath9k_wiphy_unpause_channel(struct ath_softc *sc)
+{
+       int i;
+       spin_lock_bh(&sc->wiphy_lock);
+       __ath9k_wiphy_unpause_ch(sc->pri_wiphy);
+       for (i = 0; i < sc->num_sec_wiphy; i++)
+               __ath9k_wiphy_unpause_ch(sc->sec_wiphy[i]);
+       spin_unlock_bh(&sc->wiphy_lock);
+}
+
+void ath9k_wiphy_chan_work(struct work_struct *work)
+{
+       struct ath_softc *sc = container_of(work, struct ath_softc, chan_work);
+       struct ath_wiphy *aphy = sc->next_wiphy;
+
+       if (aphy == NULL)
+               return;
+
+       /*
+        * All pending interfaces paused; ready to change
+        * channels.
+        */
+
+       /* Change channels */
+       mutex_lock(&sc->mutex);
+       /* XXX: remove me eventually */
+       ath9k_update_ichannel(sc, aphy->hw,
+                             &sc->sc_ah->channels[sc->chan_idx]);
+       ath_update_chainmask(sc, sc->chan_is_ht);
+       if (ath_set_channel(sc, aphy->hw,
+                           &sc->sc_ah->channels[sc->chan_idx]) < 0) {
+               printk(KERN_DEBUG "ath9k: Failed to set channel for new "
+                      "virtual wiphy\n");
+               mutex_unlock(&sc->mutex);
+               return;
+       }
+       mutex_unlock(&sc->mutex);
+
+       ath9k_wiphy_unpause_channel(sc);
+}
+
+/*
+ * ath9k version of ieee80211_tx_status() for TX frames that are generated
+ * internally in the driver.
+ */
+void ath9k_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+       struct ath_wiphy *aphy = hw->priv;
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
+       struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
+
+       if (tx_info_priv && tx_info_priv->frame_type == ATH9K_INT_PAUSE &&
+           aphy->state == ATH_WIPHY_PAUSING) {
+               if (!(info->flags & IEEE80211_TX_STAT_ACK)) {
+                       printk(KERN_DEBUG "ath9k: %s: no ACK for pause "
+                              "frame\n", wiphy_name(hw->wiphy));
+                       /*
+                        * The AP did not reply; ignore this to allow us to
+                        * continue.
+                        */
+               }
+               aphy->state = ATH_WIPHY_PAUSED;
+               if (!ath9k_wiphy_pausing(aphy->sc)) {
+                       /*
+                        * Drop from tasklet to work to allow mutex for channel
+                        * change.
+                        */
+                       queue_work(aphy->sc->hw->workqueue,
+                                  &aphy->sc->chan_work);
+               }
+       }
+
+       kfree(tx_info_priv);
+       tx_info->rate_driver_data[0] = NULL;
+
+       dev_kfree_skb(skb);
+}
+
+static void ath9k_mark_paused(struct ath_wiphy *aphy)
+{
+       struct ath_softc *sc = aphy->sc;
+       aphy->state = ATH_WIPHY_PAUSED;
+       if (!__ath9k_wiphy_pausing(sc))
+               queue_work(sc->hw->workqueue, &sc->chan_work);
+}
+
+static void ath9k_pause_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+{
+       struct ath_wiphy *aphy = data;
+       struct ath_vif *avp = (void *) vif->drv_priv;
+
+       switch (vif->type) {
+       case NL80211_IFTYPE_STATION:
+               if (!vif->bss_conf.assoc) {
+                       ath9k_mark_paused(aphy);
+                       break;
+               }
+               /* TODO: could avoid this if already in PS mode */
+               if (ath9k_send_nullfunc(aphy, vif, avp->bssid, 1)) {
+                       printk(KERN_DEBUG "%s: failed to send PS nullfunc\n",
+                              __func__);
+                       ath9k_mark_paused(aphy);
+               }
+               break;
+       case NL80211_IFTYPE_AP:
+               /* Beacon transmission is paused by aphy->state change */
+               ath9k_mark_paused(aphy);
+               break;
+       default:
+               break;
+       }
+}
+
+/* caller must hold wiphy_lock */
+static int __ath9k_wiphy_pause(struct ath_wiphy *aphy)
+{
+       ieee80211_stop_queues(aphy->hw);
+       aphy->state = ATH_WIPHY_PAUSING;
+       /*
+        * TODO: handle PAUSING->PAUSED for the case where there are multiple
+        * active vifs (now we do it on the first vif getting ready; should be
+        * on the last)
+        */
+       ieee80211_iterate_active_interfaces_atomic(aphy->hw, ath9k_pause_iter,
+                                                  aphy);
+       return 0;
+}
+
+int ath9k_wiphy_pause(struct ath_wiphy *aphy)
+{
+       int ret;
+       spin_lock_bh(&aphy->sc->wiphy_lock);
+       ret = __ath9k_wiphy_pause(aphy);
+       spin_unlock_bh(&aphy->sc->wiphy_lock);
+       return ret;
+}
+
+static void ath9k_unpause_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
+{
+       struct ath_wiphy *aphy = data;
+       struct ath_vif *avp = (void *) vif->drv_priv;
+
+       switch (vif->type) {
+       case NL80211_IFTYPE_STATION:
+               if (!vif->bss_conf.assoc)
+                       break;
+               ath9k_send_nullfunc(aphy, vif, avp->bssid, 0);
+               break;
+       case NL80211_IFTYPE_AP:
+               /* Beacon transmission is re-enabled by aphy->state change */
+               break;
+       default:
+               break;
+       }
+}
+
+/* caller must hold wiphy_lock */
+static int __ath9k_wiphy_unpause(struct ath_wiphy *aphy)
+{
+       ieee80211_iterate_active_interfaces_atomic(aphy->hw,
+                                                  ath9k_unpause_iter, aphy);
+       aphy->state = ATH_WIPHY_ACTIVE;
+       ieee80211_wake_queues(aphy->hw);
+       return 0;
+}
+
+int ath9k_wiphy_unpause(struct ath_wiphy *aphy)
+{
+       int ret;
+       spin_lock_bh(&aphy->sc->wiphy_lock);
+       ret = __ath9k_wiphy_unpause(aphy);
+       spin_unlock_bh(&aphy->sc->wiphy_lock);
+       return ret;
+}
+
+static void __ath9k_wiphy_mark_all_paused(struct ath_softc *sc)
+{
+       int i;
+       if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE)
+               sc->pri_wiphy->state = ATH_WIPHY_PAUSED;
+       for (i = 0; i < sc->num_sec_wiphy; i++) {
+               if (sc->sec_wiphy[i] &&
+                   sc->sec_wiphy[i]->state != ATH_WIPHY_INACTIVE)
+                       sc->sec_wiphy[i]->state = ATH_WIPHY_PAUSED;
+       }
+}
+
+/* caller must hold wiphy_lock */
+static void __ath9k_wiphy_pause_all(struct ath_softc *sc)
+{
+       int i;
+       if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE)
+               __ath9k_wiphy_pause(sc->pri_wiphy);
+       for (i = 0; i < sc->num_sec_wiphy; i++) {
+               if (sc->sec_wiphy[i] &&
+                   sc->sec_wiphy[i]->state == ATH_WIPHY_ACTIVE)
+                       __ath9k_wiphy_pause(sc->sec_wiphy[i]);
+       }
+}
+
+int ath9k_wiphy_select(struct ath_wiphy *aphy)
+{
+       struct ath_softc *sc = aphy->sc;
+       bool now;
+
+       spin_lock_bh(&sc->wiphy_lock);
+       if (__ath9k_wiphy_scanning(sc)) {
+               /*
+                * For now, we are using mac80211 sw scan and it expects to
+                * have full control over channel changes, so avoid wiphy
+                * scheduling during a scan. This could be optimized if the
+                * scanning control were moved into the driver.
+                */
+               spin_unlock_bh(&sc->wiphy_lock);
+               return -EBUSY;
+       }
+       if (__ath9k_wiphy_pausing(sc)) {
+               if (sc->wiphy_select_failures == 0)
+                       sc->wiphy_select_first_fail = jiffies;
+               sc->wiphy_select_failures++;
+               if (time_after(jiffies, sc->wiphy_select_first_fail + HZ / 2))
+               {
+                       printk(KERN_DEBUG "ath9k: Previous wiphy select timed "
+                              "out; disable/enable hw to recover\n");
+                       __ath9k_wiphy_mark_all_paused(sc);
+                       /*
+                        * TODO: this workaround to fix hardware is unlikely to
+                        * be specific to virtual wiphy changes. It can happen
+                        * on normal channel change, too, and as such, this
+                        * should really be made more generic. For example,
+                        * tricker radio disable/enable on GTT interrupt burst
+                        * (say, 10 GTT interrupts received without any TX
+                        * frame being completed)
+                        */
+                       spin_unlock_bh(&sc->wiphy_lock);
+                       ath_radio_disable(sc);
+                       ath_radio_enable(sc);
+                       queue_work(aphy->sc->hw->workqueue,
+                                  &aphy->sc->chan_work);
+                       return -EBUSY; /* previous select still in progress */
+               }
+               spin_unlock_bh(&sc->wiphy_lock);
+               return -EBUSY; /* previous select still in progress */
+       }
+       sc->wiphy_select_failures = 0;
+
+       /* Store the new channel */
+       sc->chan_idx = aphy->chan_idx;
+       sc->chan_is_ht = aphy->chan_is_ht;
+       sc->next_wiphy = aphy;
+
+       __ath9k_wiphy_pause_all(sc);
+       now = !__ath9k_wiphy_pausing(aphy->sc);
+       spin_unlock_bh(&sc->wiphy_lock);
+
+       if (now) {
+               /* Ready to request channel change immediately */
+               queue_work(aphy->sc->hw->workqueue, &aphy->sc->chan_work);
+       }
+
+       /*
+        * wiphys will be unpaused in ath9k_tx_status() once channel has been
+        * changed if any wiphy needs time to become paused.
+        */
+
+       return 0;
+}
+
+bool ath9k_wiphy_started(struct ath_softc *sc)
+{
+       int i;
+       spin_lock_bh(&sc->wiphy_lock);
+       if (sc->pri_wiphy->state != ATH_WIPHY_INACTIVE) {
+               spin_unlock_bh(&sc->wiphy_lock);
+               return true;
+       }
+       for (i = 0; i < sc->num_sec_wiphy; i++) {
+               if (sc->sec_wiphy[i] &&
+                   sc->sec_wiphy[i]->state != ATH_WIPHY_INACTIVE) {
+                       spin_unlock_bh(&sc->wiphy_lock);
+                       return true;
+               }
+       }
+       spin_unlock_bh(&sc->wiphy_lock);
+       return false;
+}
+
+static void ath9k_wiphy_pause_chan(struct ath_wiphy *aphy,
+                                  struct ath_wiphy *selected)
+{
+       if (selected->state == ATH_WIPHY_SCAN) {
+               if (aphy == selected)
+                       return;
+               /*
+                * Pause all other wiphys for the duration of the scan even if
+                * they are on the current channel now.
+                */
+       } else if (aphy->chan_idx == selected->chan_idx)
+               return;
+       aphy->state = ATH_WIPHY_PAUSED;
+       ieee80211_stop_queues(aphy->hw);
+}
+
+void ath9k_wiphy_pause_all_forced(struct ath_softc *sc,
+                                 struct ath_wiphy *selected)
+{
+       int i;
+       spin_lock_bh(&sc->wiphy_lock);
+       if (sc->pri_wiphy->state == ATH_WIPHY_ACTIVE)
+               ath9k_wiphy_pause_chan(sc->pri_wiphy, selected);
+       for (i = 0; i < sc->num_sec_wiphy; i++) {
+               if (sc->sec_wiphy[i] &&
+                   sc->sec_wiphy[i]->state == ATH_WIPHY_ACTIVE)
+                       ath9k_wiphy_pause_chan(sc->sec_wiphy[i], selected);
+       }
+       spin_unlock_bh(&sc->wiphy_lock);
+}
+
+void ath9k_wiphy_work(struct work_struct *work)
+{
+       struct ath_softc *sc = container_of(work, struct ath_softc,
+                                           wiphy_work.work);
+       struct ath_wiphy *aphy = NULL;
+       bool first = true;
+
+       spin_lock_bh(&sc->wiphy_lock);
+
+       if (sc->wiphy_scheduler_int == 0) {
+               /* wiphy scheduler is disabled */
+               spin_unlock_bh(&sc->wiphy_lock);
+               return;
+       }
+
+try_again:
+       sc->wiphy_scheduler_index++;
+       while (sc->wiphy_scheduler_index <= sc->num_sec_wiphy) {
+               aphy = sc->sec_wiphy[sc->wiphy_scheduler_index - 1];
+               if (aphy && aphy->state != ATH_WIPHY_INACTIVE)
+                       break;
+
+               sc->wiphy_scheduler_index++;
+               aphy = NULL;
+       }
+       if (aphy == NULL) {
+               sc->wiphy_scheduler_index = 0;
+               if (sc->pri_wiphy->state == ATH_WIPHY_INACTIVE) {
+                       if (first) {
+                               first = false;
+                               goto try_again;
+                       }
+                       /* No wiphy is ready to be scheduled */
+               } else
+                       aphy = sc->pri_wiphy;
+       }
+
+       spin_unlock_bh(&sc->wiphy_lock);
+
+       if (aphy &&
+           aphy->state != ATH_WIPHY_ACTIVE && aphy->state != ATH_WIPHY_SCAN &&
+           ath9k_wiphy_select(aphy)) {
+               printk(KERN_DEBUG "ath9k: Failed to schedule virtual wiphy "
+                      "change\n");
+       }
+
+       queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work,
+                          sc->wiphy_scheduler_int);
+}
+
+void ath9k_wiphy_set_scheduler(struct ath_softc *sc, unsigned int msec_int)
+{
+       cancel_delayed_work_sync(&sc->wiphy_work);
+       sc->wiphy_scheduler_int = msecs_to_jiffies(msec_int);
+       if (sc->wiphy_scheduler_int)
+               queue_delayed_work(sc->hw->workqueue, &sc->wiphy_work,
+                                  sc->wiphy_scheduler_int);
+}
index 3f70b1e58ae4c13159c329b359ead33bf1d096ab..e3f376611f85459ac4b0bb446e072316418e7763 100644 (file)
@@ -55,9 +55,9 @@ static u32 bits_per_symbol[][2] = {
 
 #define IS_HT_RATE(_rate)     ((_rate) & 0x80)
 
-static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
-                              struct ath_atx_tid *tid,
-                              struct list_head *bf_head);
+static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
+                                 struct ath_atx_tid *tid,
+                                 struct list_head *bf_head);
 static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
                                struct list_head *bf_q,
                                int txok, int sendbar);
@@ -152,7 +152,7 @@ static void ath_tx_flush_tid(struct ath_softc *sc, struct ath_atx_tid *tid)
                bf = list_first_entry(&tid->buf_q, struct ath_buf, list);
                ASSERT(!bf_isretried(bf));
                list_move_tail(&bf->list, &bf_head);
-               ath_tx_send_normal(sc, txq, tid, &bf_head);
+               ath_tx_send_ht_normal(sc, txq, tid, &bf_head);
        }
 
        spin_unlock_bh(&txq->axq_lock);
@@ -772,24 +772,6 @@ bool ath_tx_aggr_check(struct ath_softc *sc, struct ath_node *an, u8 tidno)
 /* Queue Management */
 /********************/
 
-static u32 ath_txq_depth(struct ath_softc *sc, int qnum)
-{
-       return sc->tx.txq[qnum].axq_depth;
-}
-
-static void ath_get_beaconconfig(struct ath_softc *sc, int if_id,
-                                struct ath_beacon_config *conf)
-{
-       struct ieee80211_hw *hw = sc->hw;
-
-       /* fill in beacon config data */
-
-       conf->beacon_interval = hw->conf.beacon_int;
-       conf->listen_interval = 100;
-       conf->dtim_count = 1;
-       conf->bmiss_timeout = ATH_DEFAULT_BMISS_LIMIT * conf->listen_interval;
-}
-
 static void ath_txq_drain_pending_buffers(struct ath_softc *sc,
                                          struct ath_txq *txq)
 {
@@ -909,7 +891,7 @@ struct ath_txq *ath_test_get_txq(struct ath_softc *sc, struct sk_buff *skb)
        spin_lock_bh(&txq->axq_lock);
 
        if (txq->axq_depth >= (ATH_TXBUF - 20)) {
-               DPRINTF(sc, ATH_DBG_FATAL,
+               DPRINTF(sc, ATH_DBG_XMIT,
                        "TX queue: %d is full, depth: %d\n",
                        qnum, txq->axq_depth);
                ieee80211_stop_queue(sc->hw, skb_get_queue_mapping(skb));
@@ -964,7 +946,6 @@ int ath_cabq_update(struct ath_softc *sc)
 {
        struct ath9k_tx_queue_info qi;
        int qnum = sc->beacon.cabq->axq_qnum;
-       struct ath_beacon_config conf;
 
        ath9k_hw_get_txq_props(sc->sc_ah, qnum, &qi);
        /*
@@ -975,9 +956,8 @@ int ath_cabq_update(struct ath_softc *sc)
        else if (sc->config.cabqReadytime > ATH9K_READY_TIME_HI_BOUND)
                sc->config.cabqReadytime = ATH9K_READY_TIME_HI_BOUND;
 
-       ath_get_beaconconfig(sc, ATH_IF_ID_ANY, &conf);
-       qi.tqi_readyTime =
-               (conf.beacon_interval * sc->config.cabqReadytime) / 100;
+       qi.tqi_readyTime = (sc->hw->conf.beacon_int *
+                           sc->config.cabqReadytime) / 100;
        ath_txq_update(sc, qnum, &qi);
 
        return 0;
@@ -1258,9 +1238,9 @@ static void ath_tx_send_ampdu(struct ath_softc *sc, struct ath_atx_tid *tid,
        ath_tx_txqaddbuf(sc, txctl->txq, bf_head);
 }
 
-static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
-                              struct ath_atx_tid *tid,
-                              struct list_head *bf_head)
+static void ath_tx_send_ht_normal(struct ath_softc *sc, struct ath_txq *txq,
+                                 struct ath_atx_tid *tid,
+                                 struct list_head *bf_head)
 {
        struct ath_buf *bf;
 
@@ -1276,6 +1256,19 @@ static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
        ath_tx_txqaddbuf(sc, txq, bf_head);
 }
 
+static void ath_tx_send_normal(struct ath_softc *sc, struct ath_txq *txq,
+                              struct list_head *bf_head)
+{
+       struct ath_buf *bf;
+
+       bf = list_first_entry(bf_head, struct ath_buf, list);
+
+       bf->bf_lastbf = bf;
+       bf->bf_nframes = 1;
+       ath_buf_set_rate(sc, bf);
+       ath_tx_txqaddbuf(sc, txq, bf_head);
+}
+
 static enum ath9k_pkt_type get_hw_packet_type(struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr;
@@ -1517,10 +1510,12 @@ static void ath_buf_set_rate(struct ath_softc *sc, struct ath_buf *bf)
                ath9k_hw_set11n_burstduration(sc->sc_ah, bf->bf_desc, 8192);
 }
 
-static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
+static int ath_tx_setup_buffer(struct ieee80211_hw *hw, struct ath_buf *bf,
                                struct sk_buff *skb,
                                struct ath_tx_control *txctl)
 {
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct ath_tx_info_priv *tx_info_priv;
@@ -1531,6 +1526,8 @@ static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
        if (unlikely(!tx_info_priv))
                return -ENOMEM;
        tx_info->rate_driver_data[0] = tx_info_priv;
+       tx_info_priv->aphy = aphy;
+       tx_info_priv->frame_type = txctl->frame_type;
        hdrlen = ieee80211_get_hdrlen_from_skb(skb);
        fc = hdr->frame_control;
 
@@ -1538,8 +1535,7 @@ static int ath_tx_setup_buffer(struct ath_softc *sc, struct ath_buf *bf,
 
        bf->bf_frmlen = skb->len + FCS_LEN - (hdrlen & 3);
 
-       if ((conf_is_ht(&sc->hw->conf) && !is_pae(skb) &&
-            (tx_info->flags & IEEE80211_TX_CTL_AMPDU)))
+       if (conf_is_ht(&sc->hw->conf) && !is_pae(skb))
                bf->bf_state.bf_type |= BUF_HT;
 
        bf->bf_flags = setup_tx_flags(sc, skb, txctl->txq);
@@ -1576,14 +1572,17 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
 {
        struct sk_buff *skb = (struct sk_buff *)bf->bf_mpdu;
        struct ieee80211_tx_info *tx_info =  IEEE80211_SKB_CB(skb);
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        struct ath_node *an = NULL;
        struct list_head bf_head;
        struct ath_desc *ds;
        struct ath_atx_tid *tid;
        struct ath_hw *ah = sc->sc_ah;
        int frm_type;
+       __le16 fc;
 
        frm_type = get_hw_packet_type(skb);
+       fc = hdr->frame_control;
 
        INIT_LIST_HEAD(&bf_head);
        list_add_tail(&bf->list, &bf_head);
@@ -1608,6 +1607,11 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
                an = (struct ath_node *)tx_info->control.sta->drv_priv;
                tid = ATH_AN_2_TID(an, bf->bf_tidno);
 
+               if (!ieee80211_is_data_qos(fc)) {
+                       ath_tx_send_normal(sc, txctl->txq, &bf_head);
+                       goto tx_done;
+               }
+
                if (ath_aggr_query(sc, an, bf->bf_tidno)) {
                        /*
                         * Try aggregation if it's a unicast data frame
@@ -1619,24 +1623,23 @@ static void ath_tx_start_dma(struct ath_softc *sc, struct ath_buf *bf,
                         * Send this frame as regular when ADDBA
                         * exchange is neither complete nor pending.
                         */
-                       ath_tx_send_normal(sc, txctl->txq,
-                                          tid, &bf_head);
+                       ath_tx_send_ht_normal(sc, txctl->txq,
+                                             tid, &bf_head);
                }
        } else {
-               bf->bf_lastbf = bf;
-               bf->bf_nframes = 1;
-
-               ath_buf_set_rate(sc, bf);
-               ath_tx_txqaddbuf(sc, txctl->txq, &bf_head);
+               ath_tx_send_normal(sc, txctl->txq, &bf_head);
        }
 
+tx_done:
        spin_unlock_bh(&txctl->txq->axq_lock);
 }
 
 /* Upon failure caller should free skb */
-int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
+int ath_tx_start(struct ieee80211_hw *hw, struct sk_buff *skb,
                 struct ath_tx_control *txctl)
 {
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        struct ath_buf *bf;
        int r;
 
@@ -1646,7 +1649,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
                return -1;
        }
 
-       r = ath_tx_setup_buffer(sc, bf, skb, txctl);
+       r = ath_tx_setup_buffer(hw, bf, skb, txctl);
        if (unlikely(r)) {
                struct ath_txq *txq = txctl->txq;
 
@@ -1657,7 +1660,7 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
                 * we will at least have to run TX completionon one buffer
                 * on the queue */
                spin_lock_bh(&txq->axq_lock);
-               if (ath_txq_depth(sc, txq->axq_qnum) > 1) {
+               if (sc->tx.txq[txq->axq_qnum].axq_depth > 1) {
                        ieee80211_stop_queue(sc->hw,
                                skb_get_queue_mapping(skb));
                        txq->stopped = 1;
@@ -1676,8 +1679,10 @@ int ath_tx_start(struct ath_softc *sc, struct sk_buff *skb,
        return 0;
 }
 
-void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb)
+void ath_tx_cabq(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
+       struct ath_wiphy *aphy = hw->priv;
+       struct ath_softc *sc = aphy->sc;
        int hdrlen, padsize;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
        struct ath_tx_control txctl;
@@ -1714,7 +1719,7 @@ void ath_tx_cabq(struct ath_softc *sc, struct sk_buff *skb)
 
        DPRINTF(sc, ATH_DBG_XMIT, "transmitting CABQ packet, skb: %p\n", skb);
 
-       if (ath_tx_start(sc, skb, &txctl) != 0) {
+       if (ath_tx_start(hw, skb, &txctl) != 0) {
                DPRINTF(sc, ATH_DBG_XMIT, "CABQ TX failed\n");
                goto exit;
        }
@@ -1735,9 +1740,15 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ath_tx_info_priv *tx_info_priv = ATH_TX_INFO_PRIV(tx_info);
        int hdrlen, padsize;
+       int frame_type = ATH9K_NOT_INTERNAL;
 
        DPRINTF(sc, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
 
+       if (tx_info_priv) {
+               hw = tx_info_priv->aphy->hw;
+               frame_type = tx_info_priv->frame_type;
+       }
+
        if (tx_info->flags & IEEE80211_TX_CTL_NO_ACK ||
            tx_info->flags & IEEE80211_TX_STAT_TX_FILTERED) {
                kfree(tx_info_priv);
@@ -1767,7 +1778,10 @@ static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
                skb_pull(skb, padsize);
        }
 
-       ieee80211_tx_status(hw, skb);
+       if (frame_type == ATH9K_NOT_INTERNAL)
+               ieee80211_tx_status(hw, skb);
+       else
+               ath9k_tx_status(hw, skb);
 }
 
 static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
@@ -1867,7 +1881,7 @@ static void ath_wake_mac80211_queue(struct ath_softc *sc, struct ath_txq *txq)
 
        spin_lock_bh(&txq->axq_lock);
        if (txq->stopped &&
-           ath_txq_depth(sc, txq->axq_qnum) <= (ATH_TXBUF - 20)) {
+           sc->tx.txq[txq->axq_qnum].axq_depth <= (ATH_TXBUF - 20)) {
                qnum = ath_get_mac80211_qnum(txq->axq_qnum, sc);
                if (qnum != -1) {
                        ieee80211_wake_queue(sc->hw, qnum);
index 91930a2c3c6b61f0c5eddd0cc56b3320a7bf1f48..857d84148b1d2d213a0a81ab76d401298eb338fe 100644 (file)
@@ -2,8 +2,8 @@
 
      Driver for Atmel at76c502 at76c504 and at76c506 wireless cards.
 
-        Copyright 2000-2001 ATMEL Corporation.
-        Copyright 2003-2004 Simon Kelley.
+       Copyright 2000-2001 ATMEL Corporation.
+       Copyright 2003-2004 Simon Kelley.
 
     This code was developed from version 2.1.1 of the Atmel drivers,
     released by Atmel corp. under the GPL in December 2002. It also
@@ -89,15 +89,15 @@ static struct {
        const char *fw_file;
        const char *fw_file_ext;
 } fw_table[] = {
-       { ATMEL_FW_TYPE_502,      "atmel_at76c502",      "bin" },
-       { ATMEL_FW_TYPE_502D,     "atmel_at76c502d",     "bin" },
-       { ATMEL_FW_TYPE_502E,     "atmel_at76c502e",     "bin" },
-       { ATMEL_FW_TYPE_502_3COM, "atmel_at76c502_3com", "bin" },
-       { ATMEL_FW_TYPE_504,      "atmel_at76c504",      "bin" },
-       { ATMEL_FW_TYPE_504_2958, "atmel_at76c504_2958", "bin" },
-       { ATMEL_FW_TYPE_504A_2958,"atmel_at76c504a_2958","bin" },
-       { ATMEL_FW_TYPE_506,      "atmel_at76c506",      "bin" },
-       { ATMEL_FW_TYPE_NONE,      NULL,                  NULL }
+       { ATMEL_FW_TYPE_502,            "atmel_at76c502",       "bin" },
+       { ATMEL_FW_TYPE_502D,           "atmel_at76c502d",      "bin" },
+       { ATMEL_FW_TYPE_502E,           "atmel_at76c502e",      "bin" },
+       { ATMEL_FW_TYPE_502_3COM,       "atmel_at76c502_3com",  "bin" },
+       { ATMEL_FW_TYPE_504,            "atmel_at76c504",       "bin" },
+       { ATMEL_FW_TYPE_504_2958,       "atmel_at76c504_2958",  "bin" },
+       { ATMEL_FW_TYPE_504A_2958,      "atmel_at76c504a_2958", "bin" },
+       { ATMEL_FW_TYPE_506,            "atmel_at76c506",       "bin" },
+       { ATMEL_FW_TYPE_NONE,           NULL,                   NULL }
 };
 
 #define MAX_SSID_LENGTH 32
@@ -106,60 +106,60 @@ static struct {
 #define MAX_BSS_ENTRIES        64
 
 /* registers */
-#define GCR  0x00    //      (SIR0)  General Configuration Register
-#define BSR  0x02    //      (SIR1)  Bank Switching Select Register
+#define GCR  0x00    /* (SIR0)  General Configuration Register */
+#define BSR  0x02    /* (SIR1)  Bank Switching Select Register */
 #define AR   0x04
 #define DR   0x08
-#define MR1  0x12    //      Mirror Register 1
-#define MR2  0x14    //      Mirror Register 2
-#define MR3  0x16    //      Mirror Register 3
-#define MR4  0x18    //      Mirror Register 4
+#define MR1  0x12    /* Mirror Register 1 */
+#define MR2  0x14    /* Mirror Register 2 */
+#define MR3  0x16    /* Mirror Register 3 */
+#define MR4  0x18    /* Mirror Register 4 */
 
 #define GPR1                            0x0c
 #define GPR2                            0x0e
 #define GPR3                            0x10
-//
-// Constants for the GCR register.
-//
-#define GCR_REMAP     0x0400          // Remap internal SRAM to 0
-#define GCR_SWRES     0x0080          // BIU reset (ARM and PAI are NOT reset)
-#define GCR_CORES     0x0060          // Core Reset (ARM and PAI are reset)
-#define GCR_ENINT     0x0002          // Enable Interrupts
-#define GCR_ACKINT    0x0008          // Acknowledge Interrupts
-
-#define BSS_SRAM      0x0200          // AMBA module selection --> SRAM
-#define BSS_IRAM      0x0100          // AMBA module selection --> IRAM
-//
-// Constants for the MR registers.
-//
-#define MAC_INIT_COMPLETE       0x0001        // MAC init has been completed
-#define MAC_BOOT_COMPLETE       0x0010        // MAC boot has been completed
-#define MAC_INIT_OK             0x0002        // MAC boot has been completed
+/*
+ * Constants for the GCR register.
+ */
+#define GCR_REMAP     0x0400          /* Remap internal SRAM to 0 */
+#define GCR_SWRES     0x0080          /* BIU reset (ARM and PAI are NOT reset) */
+#define GCR_CORES     0x0060          /* Core Reset (ARM and PAI are reset) */
+#define GCR_ENINT     0x0002          /* Enable Interrupts */
+#define GCR_ACKINT    0x0008          /* Acknowledge Interrupts */
+
+#define BSS_SRAM      0x0200          /* AMBA module selection --> SRAM */
+#define BSS_IRAM      0x0100          /* AMBA module selection --> IRAM */
+/*
+ *Constants for the MR registers.
+ */
+#define MAC_INIT_COMPLETE       0x0001        /* MAC init has been completed */
+#define MAC_BOOT_COMPLETE       0x0010        /* MAC boot has been completed */
+#define MAC_INIT_OK             0x0002        /* MAC boot has been completed */
 
 #define MIB_MAX_DATA_BYTES    212
 #define MIB_HEADER_SIZE       4    /* first four fields */
 
 struct get_set_mib {
-        u8 type;
-        u8 size;
-        u8 index;
-        u8 reserved;
-        u8 data[MIB_MAX_DATA_BYTES];
+       u8 type;
+       u8 size;
+       u8 index;
+       u8 reserved;
+       u8 data[MIB_MAX_DATA_BYTES];
 };
 
 struct rx_desc {
-        u32          Next;
-        u16          MsduPos;
-        u16          MsduSize;
-
-        u8           State;
-        u8           Status;
-        u8           Rate;
-        u8           Rssi;
-        u8           LinkQuality;
-        u8           PreambleType;
-        u16          Duration;
-        u32          RxTime;
+       u32          Next;
+       u16          MsduPos;
+       u16          MsduSize;
+
+       u8           State;
+       u8           Status;
+       u8           Rate;
+       u8           Rssi;
+       u8           LinkQuality;
+       u8           PreambleType;
+       u16          Duration;
+       u32          RxTime;
 };
 
 #define RX_DESC_FLAG_VALID       0x80
@@ -192,7 +192,7 @@ struct tx_desc {
        u8        KeyIndex;
        u8        ChiperType;
        u8        ChipreLength;
-        u8        Reserved1;
+       u8        Reserved1;
 
        u8        Reserved;
        u8        PacketType;
@@ -212,9 +212,9 @@ struct tx_desc {
 #define TX_DESC_PACKET_TYPE_OFFSET   17
 #define TX_DESC_HOST_LENGTH_OFFSET   18
 
-///////////////////////////////////////////////////////
-// Host-MAC interface
-///////////////////////////////////////////////////////
+/*
+ * Host-MAC interface
+ */
 
 #define TX_STATUS_SUCCESS       0x00
 
@@ -226,14 +226,14 @@ struct tx_desc {
 #define TX_PACKET_TYPE_DATA     0x01
 #define TX_PACKET_TYPE_MGMT     0x02
 
-#define ISR_EMPTY               0x00        // no bits set in ISR
-#define ISR_TxCOMPLETE          0x01        // packet transmitted
-#define ISR_RxCOMPLETE          0x02        // packet received
-#define ISR_RxFRAMELOST         0x04        // Rx Frame lost
-#define ISR_FATAL_ERROR         0x08        // Fatal error
-#define ISR_COMMAND_COMPLETE    0x10        // command completed
-#define ISR_OUT_OF_RANGE        0x20        // command completed
-#define ISR_IBSS_MERGE          0x40        // (4.1.2.30): IBSS merge
+#define ISR_EMPTY               0x00        /* no bits set in ISR */
+#define ISR_TxCOMPLETE          0x01        /* packet transmitted */
+#define ISR_RxCOMPLETE          0x02        /* packet received */
+#define ISR_RxFRAMELOST         0x04        /* Rx Frame lost */
+#define ISR_FATAL_ERROR         0x08        /* Fatal error */
+#define ISR_COMMAND_COMPLETE    0x10        /* command completed */
+#define ISR_OUT_OF_RANGE        0x20        /* command completed */
+#define ISR_IBSS_MERGE          0x40        /* (4.1.2.30): IBSS merge */
 #define ISR_GENERIC_IRQ         0x80
 
 #define Local_Mib_Type          0x01
@@ -311,22 +311,22 @@ struct tx_desc {
 #define MAX_ENCRYPTION_KEYS 4
 #define MAX_ENCRYPTION_KEY_SIZE 40
 
-///////////////////////////////////////////////////////////////////////////
-// 802.11 related definitions
-///////////////////////////////////////////////////////////////////////////
+/*
+ * 802.11 related definitions
+ */
 
-//
-// Regulatory Domains
-//
+/*
+ * Regulatory Domains
+ */
 
-#define REG_DOMAIN_FCC         0x10    //Channels      1-11    USA
-#define REG_DOMAIN_DOC         0x20    //Channel       1-11    Canada
-#define REG_DOMAIN_ETSI                0x30    //Channel       1-13    Europe (ex Spain/France)
-#define REG_DOMAIN_SPAIN       0x31    //Channel       10-11   Spain
-#define REG_DOMAIN_FRANCE      0x32    //Channel       10-13   France
-#define REG_DOMAIN_MKK         0x40    //Channel       14      Japan
-#define REG_DOMAIN_MKK1                0x41    //Channel       1-14    Japan(MKK1)
-#define REG_DOMAIN_ISRAEL      0x50    //Channel       3-9     ISRAEL
+#define REG_DOMAIN_FCC         0x10    /* Channels     1-11    USA                             */
+#define REG_DOMAIN_DOC         0x20    /* Channel      1-11    Canada                          */
+#define REG_DOMAIN_ETSI                0x30    /* Channel      1-13    Europe (ex Spain/France)        */
+#define REG_DOMAIN_SPAIN       0x31    /* Channel      10-11   Spain                           */
+#define REG_DOMAIN_FRANCE      0x32    /* Channel      10-13   France                          */
+#define REG_DOMAIN_MKK         0x40    /* Channel      14      Japan                           */
+#define REG_DOMAIN_MKK1                0x41    /* Channel      1-14    Japan(MKK1)                     */
+#define REG_DOMAIN_ISRAEL      0x50    /* Channel      3-9     ISRAEL                          */
 
 #define BSS_TYPE_AD_HOC                1
 #define BSS_TYPE_INFRASTRUCTURE 2
@@ -364,13 +364,13 @@ struct tx_desc {
 #define CIPHER_SUITE_CCX      4
 #define CIPHER_SUITE_WEP_128  5
 
-//
-// IFACE MACROS & definitions
-//
-//
+/*
+ * IFACE MACROS & definitions
+ */
 
-// FuncCtrl field:
-//
+/*
+ * FuncCtrl field:
+ */
 #define FUNC_CTRL_TxENABLE             0x10
 #define FUNC_CTRL_RxENABLE             0x20
 #define FUNC_CTRL_INIT_COMPLETE                0x01
@@ -378,48 +378,48 @@ struct tx_desc {
 /* A stub firmware image which reads the MAC address from NVRAM on the card.
    For copyright information and source see the end of this file. */
 static u8 mac_reader[] = {
-       0x06,0x00,0x00,0xea,0x04,0x00,0x00,0xea,0x03,0x00,0x00,0xea,0x02,0x00,0x00,0xea,
-       0x01,0x00,0x00,0xea,0x00,0x00,0x00,0xea,0xff,0xff,0xff,0xea,0xfe,0xff,0xff,0xea,
-       0xd3,0x00,0xa0,0xe3,0x00,0xf0,0x21,0xe1,0x0e,0x04,0xa0,0xe3,0x00,0x10,0xa0,0xe3,
-       0x81,0x11,0xa0,0xe1,0x00,0x10,0x81,0xe3,0x00,0x10,0x80,0xe5,0x1c,0x10,0x90,0xe5,
-       0x10,0x10,0xc1,0xe3,0x1c,0x10,0x80,0xe5,0x01,0x10,0xa0,0xe3,0x08,0x10,0x80,0xe5,
-       0x02,0x03,0xa0,0xe3,0x00,0x10,0xa0,0xe3,0xb0,0x10,0xc0,0xe1,0xb4,0x10,0xc0,0xe1,
-       0xb8,0x10,0xc0,0xe1,0xbc,0x10,0xc0,0xe1,0x56,0xdc,0xa0,0xe3,0x21,0x00,0x00,0xeb,
-       0x0a,0x00,0xa0,0xe3,0x1a,0x00,0x00,0xeb,0x10,0x00,0x00,0xeb,0x07,0x00,0x00,0xeb,
-       0x02,0x03,0xa0,0xe3,0x02,0x14,0xa0,0xe3,0xb4,0x10,0xc0,0xe1,0x4c,0x10,0x9f,0xe5,
-       0xbc,0x10,0xc0,0xe1,0x10,0x10,0xa0,0xe3,0xb8,0x10,0xc0,0xe1,0xfe,0xff,0xff,0xea,
-       0x00,0x40,0x2d,0xe9,0x00,0x20,0xa0,0xe3,0x02,0x3c,0xa0,0xe3,0x00,0x10,0xa0,0xe3,
-       0x28,0x00,0x9f,0xe5,0x37,0x00,0x00,0xeb,0x00,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,
-       0x00,0x40,0x2d,0xe9,0x12,0x2e,0xa0,0xe3,0x06,0x30,0xa0,0xe3,0x00,0x10,0xa0,0xe3,
-       0x02,0x04,0xa0,0xe3,0x2f,0x00,0x00,0xeb,0x00,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,
-       0x00,0x02,0x00,0x02,0x80,0x01,0x90,0xe0,0x01,0x00,0x00,0x0a,0x01,0x00,0x50,0xe2,
-       0xfc,0xff,0xff,0xea,0x1e,0xff,0x2f,0xe1,0x80,0x10,0xa0,0xe3,0xf3,0x06,0xa0,0xe3,
-       0x00,0x10,0x80,0xe5,0x00,0x10,0xa0,0xe3,0x00,0x10,0x80,0xe5,0x01,0x10,0xa0,0xe3,
-       0x04,0x10,0x80,0xe5,0x00,0x10,0x80,0xe5,0x0e,0x34,0xa0,0xe3,0x1c,0x10,0x93,0xe5,
-       0x02,0x1a,0x81,0xe3,0x1c,0x10,0x83,0xe5,0x58,0x11,0x9f,0xe5,0x30,0x10,0x80,0xe5,
-       0x54,0x11,0x9f,0xe5,0x34,0x10,0x80,0xe5,0x38,0x10,0x80,0xe5,0x3c,0x10,0x80,0xe5,
-       0x10,0x10,0x90,0xe5,0x08,0x00,0x90,0xe5,0x1e,0xff,0x2f,0xe1,0xf3,0x16,0xa0,0xe3,
-       0x08,0x00,0x91,0xe5,0x05,0x00,0xa0,0xe3,0x0c,0x00,0x81,0xe5,0x10,0x00,0x91,0xe5,
-       0x02,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0xff,0x00,0xa0,0xe3,0x0c,0x00,0x81,0xe5,
-       0x10,0x00,0x91,0xe5,0x02,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x91,0xe5,
-       0x10,0x00,0x91,0xe5,0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x91,0xe5,
-       0xff,0x00,0x00,0xe2,0x1e,0xff,0x2f,0xe1,0x30,0x40,0x2d,0xe9,0x00,0x50,0xa0,0xe1,
-       0x03,0x40,0xa0,0xe1,0xa2,0x02,0xa0,0xe1,0x08,0x00,0x00,0xe2,0x03,0x00,0x80,0xe2,
-       0xd8,0x10,0x9f,0xe5,0x00,0x00,0xc1,0xe5,0x01,0x20,0xc1,0xe5,0xe2,0xff,0xff,0xeb,
-       0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x1a,0x14,0x00,0xa0,0xe3,0xc4,0xff,0xff,0xeb,
-       0x04,0x20,0xa0,0xe1,0x05,0x10,0xa0,0xe1,0x02,0x00,0xa0,0xe3,0x01,0x00,0x00,0xeb,
-       0x30,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x70,0x40,0x2d,0xe9,0xf3,0x46,0xa0,0xe3,
-       0x00,0x30,0xa0,0xe3,0x00,0x00,0x50,0xe3,0x08,0x00,0x00,0x9a,0x8c,0x50,0x9f,0xe5,
-       0x03,0x60,0xd5,0xe7,0x0c,0x60,0x84,0xe5,0x10,0x60,0x94,0xe5,0x02,0x00,0x16,0xe3,
-       0xfc,0xff,0xff,0x0a,0x01,0x30,0x83,0xe2,0x00,0x00,0x53,0xe1,0xf7,0xff,0xff,0x3a,
-       0xff,0x30,0xa0,0xe3,0x0c,0x30,0x84,0xe5,0x08,0x00,0x94,0xe5,0x10,0x00,0x94,0xe5,
-       0x01,0x00,0x10,0xe3,0xfc,0xff,0xff,0x0a,0x08,0x00,0x94,0xe5,0x00,0x00,0xa0,0xe3,
-       0x00,0x00,0x52,0xe3,0x0b,0x00,0x00,0x9a,0x10,0x50,0x94,0xe5,0x02,0x00,0x15,0xe3,
-       0xfc,0xff,0xff,0x0a,0x0c,0x30,0x84,0xe5,0x10,0x50,0x94,0xe5,0x01,0x00,0x15,0xe3,
-       0xfc,0xff,0xff,0x0a,0x08,0x50,0x94,0xe5,0x01,0x50,0xc1,0xe4,0x01,0x00,0x80,0xe2,
-       0x02,0x00,0x50,0xe1,0xf3,0xff,0xff,0x3a,0xc8,0x00,0xa0,0xe3,0x98,0xff,0xff,0xeb,
-       0x70,0x40,0xbd,0xe8,0x1e,0xff,0x2f,0xe1,0x01,0x0c,0x00,0x02,0x01,0x02,0x00,0x02,
-       0x00,0x01,0x00,0x02
+       0x06, 0x00, 0x00, 0xea, 0x04, 0x00, 0x00, 0xea, 0x03, 0x00, 0x00, 0xea, 0x02, 0x00, 0x00, 0xea,
+       0x01, 0x00, 0x00, 0xea, 0x00, 0x00, 0x00, 0xea, 0xff, 0xff, 0xff, 0xea, 0xfe, 0xff, 0xff, 0xea,
+       0xd3, 0x00, 0xa0, 0xe3, 0x00, 0xf0, 0x21, 0xe1, 0x0e, 0x04, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3,
+       0x81, 0x11, 0xa0, 0xe1, 0x00, 0x10, 0x81, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x1c, 0x10, 0x90, 0xe5,
+       0x10, 0x10, 0xc1, 0xe3, 0x1c, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3, 0x08, 0x10, 0x80, 0xe5,
+       0x02, 0x03, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3, 0xb0, 0x10, 0xc0, 0xe1, 0xb4, 0x10, 0xc0, 0xe1,
+       0xb8, 0x10, 0xc0, 0xe1, 0xbc, 0x10, 0xc0, 0xe1, 0x56, 0xdc, 0xa0, 0xe3, 0x21, 0x00, 0x00, 0xeb,
+       0x0a, 0x00, 0xa0, 0xe3, 0x1a, 0x00, 0x00, 0xeb, 0x10, 0x00, 0x00, 0xeb, 0x07, 0x00, 0x00, 0xeb,
+       0x02, 0x03, 0xa0, 0xe3, 0x02, 0x14, 0xa0, 0xe3, 0xb4, 0x10, 0xc0, 0xe1, 0x4c, 0x10, 0x9f, 0xe5,
+       0xbc, 0x10, 0xc0, 0xe1, 0x10, 0x10, 0xa0, 0xe3, 0xb8, 0x10, 0xc0, 0xe1, 0xfe, 0xff, 0xff, 0xea,
+       0x00, 0x40, 0x2d, 0xe9, 0x00, 0x20, 0xa0, 0xe3, 0x02, 0x3c, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3,
+       0x28, 0x00, 0x9f, 0xe5, 0x37, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1,
+       0x00, 0x40, 0x2d, 0xe9, 0x12, 0x2e, 0xa0, 0xe3, 0x06, 0x30, 0xa0, 0xe3, 0x00, 0x10, 0xa0, 0xe3,
+       0x02, 0x04, 0xa0, 0xe3, 0x2f, 0x00, 0x00, 0xeb, 0x00, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1,
+       0x00, 0x02, 0x00, 0x02, 0x80, 0x01, 0x90, 0xe0, 0x01, 0x00, 0x00, 0x0a, 0x01, 0x00, 0x50, 0xe2,
+       0xfc, 0xff, 0xff, 0xea, 0x1e, 0xff, 0x2f, 0xe1, 0x80, 0x10, 0xa0, 0xe3, 0xf3, 0x06, 0xa0, 0xe3,
+       0x00, 0x10, 0x80, 0xe5, 0x00, 0x10, 0xa0, 0xe3, 0x00, 0x10, 0x80, 0xe5, 0x01, 0x10, 0xa0, 0xe3,
+       0x04, 0x10, 0x80, 0xe5, 0x00, 0x10, 0x80, 0xe5, 0x0e, 0x34, 0xa0, 0xe3, 0x1c, 0x10, 0x93, 0xe5,
+       0x02, 0x1a, 0x81, 0xe3, 0x1c, 0x10, 0x83, 0xe5, 0x58, 0x11, 0x9f, 0xe5, 0x30, 0x10, 0x80, 0xe5,
+       0x54, 0x11, 0x9f, 0xe5, 0x34, 0x10, 0x80, 0xe5, 0x38, 0x10, 0x80, 0xe5, 0x3c, 0x10, 0x80, 0xe5,
+       0x10, 0x10, 0x90, 0xe5, 0x08, 0x00, 0x90, 0xe5, 0x1e, 0xff, 0x2f, 0xe1, 0xf3, 0x16, 0xa0, 0xe3,
+       0x08, 0x00, 0x91, 0xe5, 0x05, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5, 0x10, 0x00, 0x91, 0xe5,
+       0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0xff, 0x00, 0xa0, 0xe3, 0x0c, 0x00, 0x81, 0xe5,
+       0x10, 0x00, 0x91, 0xe5, 0x02, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5,
+       0x10, 0x00, 0x91, 0xe5, 0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x91, 0xe5,
+       0xff, 0x00, 0x00, 0xe2, 0x1e, 0xff, 0x2f, 0xe1, 0x30, 0x40, 0x2d, 0xe9, 0x00, 0x50, 0xa0, 0xe1,
+       0x03, 0x40, 0xa0, 0xe1, 0xa2, 0x02, 0xa0, 0xe1, 0x08, 0x00, 0x00, 0xe2, 0x03, 0x00, 0x80, 0xe2,
+       0xd8, 0x10, 0x9f, 0xe5, 0x00, 0x00, 0xc1, 0xe5, 0x01, 0x20, 0xc1, 0xe5, 0xe2, 0xff, 0xff, 0xeb,
+       0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x1a, 0x14, 0x00, 0xa0, 0xe3, 0xc4, 0xff, 0xff, 0xeb,
+       0x04, 0x20, 0xa0, 0xe1, 0x05, 0x10, 0xa0, 0xe1, 0x02, 0x00, 0xa0, 0xe3, 0x01, 0x00, 0x00, 0xeb,
+       0x30, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x70, 0x40, 0x2d, 0xe9, 0xf3, 0x46, 0xa0, 0xe3,
+       0x00, 0x30, 0xa0, 0xe3, 0x00, 0x00, 0x50, 0xe3, 0x08, 0x00, 0x00, 0x9a, 0x8c, 0x50, 0x9f, 0xe5,
+       0x03, 0x60, 0xd5, 0xe7, 0x0c, 0x60, 0x84, 0xe5, 0x10, 0x60, 0x94, 0xe5, 0x02, 0x00, 0x16, 0xe3,
+       0xfc, 0xff, 0xff, 0x0a, 0x01, 0x30, 0x83, 0xe2, 0x00, 0x00, 0x53, 0xe1, 0xf7, 0xff, 0xff, 0x3a,
+       0xff, 0x30, 0xa0, 0xe3, 0x0c, 0x30, 0x84, 0xe5, 0x08, 0x00, 0x94, 0xe5, 0x10, 0x00, 0x94, 0xe5,
+       0x01, 0x00, 0x10, 0xe3, 0xfc, 0xff, 0xff, 0x0a, 0x08, 0x00, 0x94, 0xe5, 0x00, 0x00, 0xa0, 0xe3,
+       0x00, 0x00, 0x52, 0xe3, 0x0b, 0x00, 0x00, 0x9a, 0x10, 0x50, 0x94, 0xe5, 0x02, 0x00, 0x15, 0xe3,
+       0xfc, 0xff, 0xff, 0x0a, 0x0c, 0x30, 0x84, 0xe5, 0x10, 0x50, 0x94, 0xe5, 0x01, 0x00, 0x15, 0xe3,
+       0xfc, 0xff, 0xff, 0x0a, 0x08, 0x50, 0x94, 0xe5, 0x01, 0x50, 0xc1, 0xe4, 0x01, 0x00, 0x80, 0xe2,
+       0x02, 0x00, 0x50, 0xe1, 0xf3, 0xff, 0xff, 0x3a, 0xc8, 0x00, 0xa0, 0xe3, 0x98, 0xff, 0xff, 0xeb,
+       0x70, 0x40, 0xbd, 0xe8, 0x1e, 0xff, 0x2f, 0xe1, 0x01, 0x0c, 0x00, 0x02, 0x01, 0x02, 0x00, 0x02,
+       0x00, 0x01, 0x00, 0x02
 };
 
 struct atmel_private {
@@ -433,7 +433,7 @@ struct atmel_private {
        struct net_device *dev;
        struct device *sys_dev;
        struct iw_statistics wstats;
-       spinlock_t irqlock, timerlock;  // spinlocks
+       spinlock_t irqlock, timerlock;  /* spinlocks */
        enum { BUS_TYPE_PCCARD, BUS_TYPE_PCI } bus_type;
        enum {
                CARD_TYPE_PARALLEL_FLASH,
@@ -541,7 +541,7 @@ struct atmel_private {
        u8 rx_buf[MAX_WIRELESS_BODY];
 };
 
-static u8 atmel_basic_rates[4] = {0x82,0x84,0x0b,0x16};
+static u8 atmel_basic_rates[4] = {0x82, 0x84, 0x0b, 0x16};
 
 static const struct {
        int reg_domain;
@@ -1283,17 +1283,17 @@ static struct iw_statistics *atmel_get_wireless_stats(struct net_device *dev)
 
 static int atmel_change_mtu(struct net_device *dev, int new_mtu)
 {
-        if ((new_mtu < 68) || (new_mtu > 2312))
-                return -EINVAL;
-        dev->mtu = new_mtu;
-        return 0;
+       if ((new_mtu < 68) || (new_mtu > 2312))
+               return -EINVAL;
+       dev->mtu = new_mtu;
+       return 0;
 }
 
 static int atmel_set_mac_address(struct net_device *dev, void *p)
 {
        struct sockaddr *addr = p;
 
-        memcpy (dev->dev_addr, addr->sa_data, dev->addr_len);
+       memcpy (dev->dev_addr, addr->sa_data, dev->addr_len);
        return atmel_open(dev);
 }
 
@@ -1420,10 +1420,17 @@ static int atmel_proc_output (char *buf, struct atmel_private *priv)
                                     priv->firmware_id);
 
                switch (priv->card_type) {
-               case CARD_TYPE_PARALLEL_FLASH: c = "Parallel flash"; break;
-               case CARD_TYPE_SPI_FLASH: c = "SPI flash\n"; break;
-               case CARD_TYPE_EEPROM: c = "EEPROM"; break;
-               default: c = "<unknown>";
+               case CARD_TYPE_PARALLEL_FLASH:
+                       c = "Parallel flash";
+                       break;
+               case CARD_TYPE_SPI_FLASH:
+                       c = "SPI flash\n";
+                       break;
+               case CARD_TYPE_EEPROM:
+                       c = "EEPROM";
+                       break;
+               default:
+                       c = "<unknown>";
                }
 
                r = "<unknown>";
@@ -1439,16 +1446,33 @@ static int atmel_proc_output (char *buf, struct atmel_private *priv)
                             priv->use_wpa ? "Yes" : "No");
        }
 
-       switch(priv->station_state) {
-       case STATION_STATE_SCANNING: s = "Scanning"; break;
-       case STATION_STATE_JOINNING: s = "Joining"; break;
-       case STATION_STATE_AUTHENTICATING: s = "Authenticating"; break;
-       case STATION_STATE_ASSOCIATING: s = "Associating"; break;
-       case STATION_STATE_READY: s = "Ready"; break;
-       case STATION_STATE_REASSOCIATING: s = "Reassociating"; break;
-       case STATION_STATE_MGMT_ERROR: s = "Management error"; break;
-       case STATION_STATE_DOWN: s = "Down"; break;
-       default: s = "<unknown>";
+       switch (priv->station_state) {
+       case STATION_STATE_SCANNING:
+               s = "Scanning";
+               break;
+       case STATION_STATE_JOINNING:
+               s = "Joining";
+               break;
+       case STATION_STATE_AUTHENTICATING:
+               s = "Authenticating";
+               break;
+       case STATION_STATE_ASSOCIATING:
+               s = "Associating";
+               break;
+       case STATION_STATE_READY:
+               s = "Ready";
+               break;
+       case STATION_STATE_REASSOCIATING:
+               s = "Reassociating";
+               break;
+       case STATION_STATE_MGMT_ERROR:
+               s = "Management error";
+               break;
+       case STATION_STATE_DOWN:
+               s = "Down";
+               break;
+       default:
+               s = "<unknown>";
        }
 
        p += sprintf(p, "Current state:\t\t%s\n", s);
@@ -1458,16 +1482,30 @@ static int atmel_proc_output (char *buf, struct atmel_private *priv)
 static int atmel_read_proc(char *page, char **start, off_t off,
                           int count, int *eof, void *data)
 {
-        struct atmel_private *priv = data;
+       struct atmel_private *priv = data;
        int len = atmel_proc_output (page, priv);
-        if (len <= off+count) *eof = 1;
-        *start = page + off;
-        len -= off;
-        if (len>count) len = count;
-        if (len<0) len = 0;
-        return len;
+       if (len <= off+count)
+               *eof = 1;
+       *start = page + off;
+       len -= off;
+       if (len > count)
+               len = count;
+       if (len < 0)
+               len = 0;
+       return len;
 }
 
+static const struct net_device_ops atmel_netdev_ops = {
+       .ndo_open               = atmel_open,
+       .ndo_stop               = atmel_close,
+       .ndo_change_mtu         = atmel_change_mtu,
+       .ndo_set_mac_address    = atmel_set_mac_address,
+       .ndo_start_xmit         = start_tx,
+       .ndo_do_ioctl           = atmel_ioctl,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
                                   const AtmelFWType fw_type,
                                   struct device *sys_dev,
@@ -1479,11 +1517,11 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
        int rc;
 
        /* Create the network device object. */
-        dev = alloc_etherdev(sizeof(*priv));
-        if (!dev) {
+       dev = alloc_etherdev(sizeof(*priv));
+       if (!dev) {
                printk(KERN_ERR "atmel: Couldn't alloc_etherdev\n");
                return NULL;
-        }
+       }
        if (dev_alloc_name(dev, dev->name) < 0) {
                printk(KERN_ERR "atmel: Couldn't get name!\n");
                goto err_out_free;
@@ -1552,13 +1590,8 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
        priv->management_timer.function = atmel_management_timer;
        priv->management_timer.data = (unsigned long) dev;
 
-       dev->open = atmel_open;
-       dev->stop = atmel_close;
-       dev->change_mtu = atmel_change_mtu;
-       dev->set_mac_address = atmel_set_mac_address;
-       dev->hard_start_xmit = start_tx;
-       dev->wireless_handlers = (struct iw_handler_def *)&atmel_handler_def;
-       dev->do_ioctl = atmel_ioctl;
+       dev->netdev_ops = &atmel_netdev_ops;
+       dev->wireless_handlers = &atmel_handler_def;
        dev->irq = irq;
        dev->base_addr = port;
 
@@ -1577,7 +1610,7 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
        if (register_netdev(dev))
                goto err_out_res;
 
-       if (!probe_atmel_card(dev)){
+       if (!probe_atmel_card(dev)) {
                unregister_netdev(dev);
                goto err_out_res;
        }
@@ -1594,7 +1627,7 @@ struct net_device *init_atmel_card(unsigned short irq, unsigned long port,
        return dev;
 
 err_out_res:
-       release_region( dev->base_addr, 32);
+       release_region(dev->base_addr, 32);
 err_out_irq:
        free_irq(dev->irq, dev);
 err_out_free:
@@ -1632,7 +1665,7 @@ static int atmel_set_essid(struct net_device *dev,
        struct atmel_private *priv = netdev_priv(dev);
 
        /* Check if we asked for `any' */
-       if(dwrq->flags == 0) {
+       if (dwrq->flags == 0) {
                priv->connect_to_any_BSS = 1;
        } else {
                int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
@@ -1768,7 +1801,7 @@ static int atmel_set_encode(struct net_device *dev,
        }
        if (dwrq->flags & IW_ENCODE_RESTRICTED)
                priv->exclude_unencrypted = 1;
-       if(dwrq->flags & IW_ENCODE_OPEN)
+       if (dwrq->flags & IW_ENCODE_OPEN)
                priv->exclude_unencrypted = 0;
 
        return -EINPROGRESS;            /* Call commit handler */
@@ -1797,7 +1830,7 @@ static int atmel_get_encode(struct net_device *dev,
        /* Copy the key to the user buffer */
        dwrq->length = priv->wep_key_len[index];
        if (dwrq->length > 16) {
-               dwrq->length=0;
+               dwrq->length = 0;
        } else {
                memset(extra, 0, 16);
                memcpy(extra, priv->wep_keys[index], dwrq->length);
@@ -2013,11 +2046,20 @@ static int atmel_set_rate(struct net_device *dev,
                } else {
                /* Setting by frequency value */
                        switch (vwrq->value) {
-                       case  1000000: priv->tx_rate = 0; break;
-                       case  2000000: priv->tx_rate = 1; break;
-                       case  5500000: priv->tx_rate = 2; break;
-                       case 11000000: priv->tx_rate = 3; break;
-                       default: return -EINVAL;
+                       case  1000000:
+                               priv->tx_rate = 0;
+                               break;
+                       case  2000000:
+                               priv->tx_rate = 1;
+                               break;
+                       case  5500000:
+                               priv->tx_rate = 2;
+                               break;
+                       case 11000000:
+                               priv->tx_rate = 3;
+                               break;
+                       default:
+                               return -EINVAL;
                        }
                }
        }
@@ -2062,11 +2104,19 @@ static int atmel_get_rate(struct net_device *dev,
                vwrq->value = 11000000;
        } else {
                vwrq->fixed = 1;
-               switch(priv->tx_rate) {
-               case 0: vwrq->value =  1000000; break;
-               case 1: vwrq->value =  2000000; break;
-               case 2: vwrq->value =  5500000; break;
-               case 3: vwrq->value = 11000000; break;
+               switch (priv->tx_rate) {
+               case 0:
+                       vwrq->value =  1000000;
+                       break;
+               case 1:
+                       vwrq->value =  2000000;
+                       break;
+               case 2:
+                       vwrq->value =  5500000;
+                       break;
+               case 3:
+                       vwrq->value = 11000000;
+                       break;
                }
        }
        return 0;
@@ -2576,8 +2626,7 @@ static const struct iw_priv_args atmel_private_args[] = {
        },
 };
 
-static const struct iw_handler_def atmel_handler_def =
-{
+static const struct iw_handler_def atmel_handler_def = {
        .num_standard   = ARRAY_SIZE(atmel_handler),
        .num_private    = ARRAY_SIZE(atmel_private_handler),
        .num_private_args = ARRAY_SIZE(atmel_private_args),
@@ -2834,7 +2883,7 @@ static void send_authentication_request(struct atmel_private *priv, u16 system,
 
        if (priv->wep_is_on && priv->CurrentAuthentTransactionSeqNum != 1)
                /* no WEP for authentication frames with TrSeqNo 1 */
-                header.frame_control |=  cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+               header.frame_control |=  cpu_to_le16(IEEE80211_FCTL_PROTECTED);
 
        auth.alg = cpu_to_le16(system);
 
@@ -2969,7 +3018,7 @@ static void store_bss_info(struct atmel_private *priv,
                if (memcmp(bss, priv->BSSinfo[i].BSSID, 6) == 0)
                        index = i;
 
-        /* If we process a probe and an entry from this BSS exists
+       /* If we process a probe and an entry from this BSS exists
           we will update the BSS entry with the info from this BSS.
           If we process a beacon we will only update RSSI */
 
@@ -2995,7 +3044,7 @@ static void store_bss_info(struct atmel_private *priv,
        if (capability & WLAN_CAPABILITY_IBSS)
                priv->BSSinfo[index].BSStype = IW_MODE_ADHOC;
        else if (capability & WLAN_CAPABILITY_ESS)
-               priv->BSSinfo[index].BSStype =IW_MODE_INFRA;
+               priv->BSSinfo[index].BSStype = IW_MODE_INFRA;
 
        priv->BSSinfo[index].preamble = capability & WLAN_CAPABILITY_SHORT_PREAMBLE ?
                SHORT_PREAMBLE : LONG_PREAMBLE;
@@ -3042,7 +3091,7 @@ static void authenticate(struct atmel_private *priv, u16 frame_len)
                }
 
                if (should_associate) {
-                       if(priv->station_was_associated) {
+                       if (priv->station_was_associated) {
                                atmel_enter_state(priv, STATION_STATE_REASSOCIATING);
                                send_association_request(priv, 1);
                                return;
@@ -3063,8 +3112,8 @@ static void authenticate(struct atmel_private *priv, u16 frame_len)
                        priv->exclude_unencrypted = 1;
                        send_authentication_request(priv, WLAN_AUTH_SHARED_KEY, NULL, 0);
                        return;
-               } else if (   system == WLAN_AUTH_SHARED_KEY
-                          && priv->wep_is_on) {
+               } else if (system == WLAN_AUTH_SHARED_KEY
+                          && priv->wep_is_on) {
                        priv->CurrentAuthentTransactionSeqNum = 0x001;
                        priv->exclude_unencrypted = 0;
                        send_authentication_request(priv, WLAN_AUTH_OPEN, NULL, 0);
@@ -3252,11 +3301,11 @@ static void smooth_rssi(struct atmel_private *priv, u8 rssi)
        u8 max_rssi = 42; /* 502-rmfd-revd max by experiment, default for now */
 
        switch (priv->firmware_type) {
-               case ATMEL_FW_TYPE_502E:
-                       max_rssi = 63; /* 502-rmfd-reve max by experiment */
-                       break;
-               default:
-                       break;
+       case ATMEL_FW_TYPE_502E:
+               max_rssi = 63; /* 502-rmfd-reve max by experiment */
+               break;
+       default:
+               break;
        }
 
        rssi = rssi * 100 / max_rssi;
@@ -3473,8 +3522,7 @@ static void atmel_command_irq(struct atmel_private *priv)
            status == CMD_STATUS_IN_PROGRESS)
                return;
 
-       switch (command){
-
+       switch (command) {
        case CMD_Start:
                if (status == CMD_STATUS_COMPLETE) {
                        priv->station_was_associated = priv->station_is_associated;
@@ -3709,7 +3757,7 @@ static int probe_atmel_card(struct net_device *dev)
 
        if (rc) {
                if (dev->dev_addr[0] == 0xFF) {
-                       u8 default_mac[] = {0x00,0x04, 0x25, 0x00, 0x00, 0x00};
+                       u8 default_mac[] = {0x00, 0x04, 0x25, 0x00, 0x00, 0x00};
                        printk(KERN_ALERT "%s: *** Invalid MAC address. UPGRADE Firmware ****\n", dev->name);
                        memcpy(dev->dev_addr, default_mac, 6);
                }
@@ -3803,7 +3851,7 @@ static void build_wpa_mib(struct atmel_private *priv)
                                } else {
                                        mib.group_key = i;
                                        priv->group_cipher_suite = priv->pairwise_cipher_suite;
-                                       mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 1;
+                                       mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-1] = 1;
                                        mib.cipher_default_key_value[i][MAX_ENCRYPTION_KEY_SIZE-2] = priv->group_cipher_suite;
                                }
                        }
@@ -3913,7 +3961,7 @@ static int reset_atmel_card(struct net_device *dev)
                        len = fw_entry->size;
                }
 
-               if (len <= 0x6000) {
+               if (len <= 0x6000) {
                        atmel_write16(priv->dev, BSR, BSS_IRAM);
                        atmel_copy_to_card(priv->dev, 0, fw, len);
                        atmel_set_gcr(priv->dev, GCR_REMAP);
@@ -3942,7 +3990,7 @@ static int reset_atmel_card(struct net_device *dev)
        priv->use_wpa = (priv->host_info.major_version == 4);
        priv->radio_on_broken = (priv->host_info.major_version == 5);
 
-        /* unmask all irq sources */
+       /* unmask all irq sources */
        atmel_wmem8(priv, atmel_hi(priv, IFACE_INT_MASK_OFFSET), 0xff);
 
        /* int Tx system and enable Tx */
@@ -3975,7 +4023,7 @@ static int reset_atmel_card(struct net_device *dev)
                    CMD_STATUS_REJECTED_RADIO_OFF) {
                        printk(KERN_INFO "%s: cannot turn the radio on.\n",
                               dev->name);
-                        return -EIO;
+                       return -EIO;
                }
        }
 
@@ -3999,8 +4047,7 @@ static int reset_atmel_card(struct net_device *dev)
        else
                build_wep_mib(priv);
 
-       if (old_state == STATION_STATE_READY)
-       {
+       if (old_state == STATION_STATE_READY) {
                union iwreq_data wrqu;
 
                wrqu.data.length = 0;
@@ -4277,24 +4324,24 @@ static void atmel_wmem32(struct atmel_private *priv, u16 pos, u32 data)
        .set NVRAM_LENGTH, 0x0200
        .set MAC_ADDRESS_MIB, SRAM_BASE
        .set MAC_ADDRESS_LENGTH, 6
-        .set MAC_BOOT_FLAG, 0x10
+       .set MAC_BOOT_FLAG, 0x10
        .set MR1, 0
        .set MR2, 4
        .set MR3, 8
        .set MR4, 0xC
 RESET_VECTOR:
-        b RESET_HANDLER
+       b RESET_HANDLER
 UNDEF_VECTOR:
-        b HALT1
+       b HALT1
 SWI_VECTOR:
-        b HALT1
+       b HALT1
 IABORT_VECTOR:
-        b HALT1
+       b HALT1
 DABORT_VECTOR:
 RESERVED_VECTOR:
-        b HALT1
+       b HALT1
 IRQ_VECTOR:
-        b HALT1
+       b HALT1
 FIQ_VECTOR:
        b HALT1
 HALT1: b HALT1
@@ -4306,7 +4353,7 @@ RESET_HANDLER:
        ldr     r0, =SPI_CGEN_BASE
        mov     r1, #0
        mov     r1, r1, lsl #3
-       orr     r1,r1, #0
+       orr     r1, r1, #0
        str     r1, [r0]
        ldr     r1, [r0, #28]
        bic     r1, r1, #16
index b45731012782db3f58d54ccd97c496ff57a92627..beaf18d6e8a7c95f5f41f902de405c242f3254a2 100644 (file)
@@ -550,9 +550,6 @@ struct b43_noise_calculation {
 
 struct b43_stats {
        u8 link_noise;
-       /* Store the last TX/RX times here for updating the leds. */
-       unsigned long last_tx;
-       unsigned long last_rx;
 };
 
 struct b43_key {
index bc2767da46e8ba2c56d80c19f966f2d5dd753e97..45e3d6af69f56e204eefce932e9b801c08f333eb 100644 (file)
@@ -51,8 +51,8 @@ struct b43_debugfs_fops {
 };
 
 static inline
-struct b43_dfs_file * fops_to_dfs_file(struct b43_wldev *dev,
-                                      const struct b43_debugfs_fops *dfops)
+struct b43_dfs_file *fops_to_dfs_file(struct b43_wldev *dev,
+                                     const struct b43_debugfs_fops *dfops)
 {
        void *p;
 
index 6d65a02b7052cdfa0d754a029038dcb66d96c788..0cc804d0a214fcad833c7dcdbd2afd6e7451aee3 100644 (file)
 #include <asm/div64.h>
 
 
+/* Required number of TX DMA slots per TX frame.
+ * This currently is 2, because we put the header and the ieee80211 frame
+ * into separate slots. */
+#define TX_SLOTS_PER_FRAME     2
+
+
 /* 32bit DMA ops. */
 static
 struct b43_dmadesc_generic *op32_idx2desc(struct b43_dmaring *ring,
@@ -74,8 +80,7 @@ static void op32_fill_descriptor(struct b43_dmaring *ring,
        addrext = (u32) (dmaaddr & SSB_DMA_TRANSLATION_MASK)
            >> SSB_DMA_TRANSLATION_SHIFT;
        addr |= ssb_dma_translation(ring->dev->dev);
-       ctl = (bufsize - ring->frameoffset)
-           & B43_DMA32_DCTL_BYTECNT;
+       ctl = bufsize & B43_DMA32_DCTL_BYTECNT;
        if (slot == ring->nr_slots - 1)
                ctl |= B43_DMA32_DCTL_DTABLEEND;
        if (start)
@@ -177,8 +182,7 @@ static void op64_fill_descriptor(struct b43_dmaring *ring,
                ctl0 |= B43_DMA64_DCTL0_FRAMEEND;
        if (irq)
                ctl0 |= B43_DMA64_DCTL0_IRQ;
-       ctl1 |= (bufsize - ring->frameoffset)
-           & B43_DMA64_DCTL1_BYTECNT;
+       ctl1 |= bufsize & B43_DMA64_DCTL1_BYTECNT;
        ctl1 |= (addrext << B43_DMA64_DCTL1_ADDREXT_SHIFT)
            & B43_DMA64_DCTL1_ADDREXT_MASK;
 
@@ -576,12 +580,11 @@ static int setup_rx_descbuffer(struct b43_dmaring *ring,
                        return -ENOMEM;
                dmaaddr = map_descbuffer(ring, skb->data,
                                         ring->rx_buffersize, 0);
-       }
-
-       if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) {
-               b43err(ring->dev->wl, "RX DMA buffer allocation failed\n");
-               dev_kfree_skb_any(skb);
-               return -EIO;
+               if (b43_dma_mapping_error(ring, dmaaddr, ring->rx_buffersize, 0)) {
+                       b43err(ring->dev->wl, "RX DMA buffer allocation failed\n");
+                       dev_kfree_skb_any(skb);
+                       return -EIO;
+               }
        }
 
        meta->skb = skb;
@@ -830,9 +833,6 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                if (ring->index == 0) {
                        ring->rx_buffersize = B43_DMA0_RX_BUFFERSIZE;
                        ring->frameoffset = B43_DMA0_RX_FRAMEOFFSET;
-               } else if (ring->index == 3) {
-                       ring->rx_buffersize = B43_DMA3_RX_BUFFERSIZE;
-                       ring->frameoffset = B43_DMA3_RX_FRAMEOFFSET;
                } else
                        B43_WARN_ON(1);
        }
@@ -842,7 +842,10 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
 #endif
 
        if (for_tx) {
-               ring->txhdr_cache = kcalloc(ring->nr_slots,
+               /* Assumption: B43_TXRING_SLOTS can be divided by TX_SLOTS_PER_FRAME */
+               BUILD_BUG_ON(B43_TXRING_SLOTS % TX_SLOTS_PER_FRAME != 0);
+
+               ring->txhdr_cache = kcalloc(ring->nr_slots / TX_SLOTS_PER_FRAME,
                                            b43_txhdr_size(dev),
                                            GFP_KERNEL);
                if (!ring->txhdr_cache)
@@ -858,7 +861,7 @@ struct b43_dmaring *b43_setup_dmaring(struct b43_wldev *dev,
                                          b43_txhdr_size(dev), 1)) {
                        /* ugh realloc */
                        kfree(ring->txhdr_cache);
-                       ring->txhdr_cache = kcalloc(ring->nr_slots,
+                       ring->txhdr_cache = kcalloc(ring->nr_slots / TX_SLOTS_PER_FRAME,
                                                    b43_txhdr_size(dev),
                                                    GFP_KERNEL | GFP_DMA);
                        if (!ring->txhdr_cache)
@@ -1149,7 +1152,10 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
        u16 cookie;
        size_t hdrsize = b43_txhdr_size(ring->dev);
 
-#define SLOTS_PER_PACKET  2
+       /* Important note: If the number of used DMA slots per TX frame
+        * is changed here, the TX_SLOTS_PER_FRAME definition at the top of
+        * the file has to be updated, too!
+        */
 
        old_top_slot = ring->current_slot;
        old_used_slots = ring->used_slots;
@@ -1159,7 +1165,7 @@ static int dma_tx_fragment(struct b43_dmaring *ring,
        desc = ops->idx2desc(ring, slot, &meta_hdr);
        memset(meta_hdr, 0, sizeof(*meta_hdr));
 
-       header = &(ring->txhdr_cache[slot * hdrsize]);
+       header = &(ring->txhdr_cache[(slot / TX_SLOTS_PER_FRAME) * hdrsize]);
        cookie = generate_cookie(ring, slot);
        err = b43_generate_txhdr(ring->dev, header,
                                 skb->data, skb->len, info, cookie);
@@ -1254,8 +1260,8 @@ static inline int should_inject_overflow(struct b43_dmaring *ring)
 }
 
 /* Static mapping of mac80211's queues (priorities) to b43 DMA rings. */
-static struct b43_dmaring * select_ring_by_priority(struct b43_wldev *dev,
-                                                   u8 queue_prio)
+static struct b43_dmaring *select_ring_by_priority(struct b43_wldev *dev,
+                                                  u8 queue_prio)
 {
        struct b43_dmaring *ring;
 
@@ -1306,17 +1312,19 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
        }
 
        spin_lock_irqsave(&ring->lock, flags);
+
        B43_WARN_ON(!ring->tx);
-       if (unlikely(free_slots(ring) < SLOTS_PER_PACKET)) {
-               b43warn(dev->wl, "DMA queue overflow\n");
-               err = -ENOSPC;
-               goto out_unlock;
-       }
        /* Check if the queue was stopped in mac80211,
         * but we got called nevertheless.
         * That would be a mac80211 bug. */
        B43_WARN_ON(ring->stopped);
 
+       if (unlikely(free_slots(ring) < TX_SLOTS_PER_FRAME)) {
+               b43warn(dev->wl, "DMA queue overflow\n");
+               err = -ENOSPC;
+               goto out_unlock;
+       }
+
        /* Assign the queue number to the ring (if not already done before)
         * so TX status handling can use it. The queue to ring mapping is
         * static, so we don't need to store it per frame. */
@@ -1335,7 +1343,7 @@ int b43_dma_tx(struct b43_wldev *dev, struct sk_buff *skb)
                goto out_unlock;
        }
        ring->nr_tx_packets++;
-       if ((free_slots(ring) < SLOTS_PER_PACKET) ||
+       if ((free_slots(ring) < TX_SLOTS_PER_FRAME) ||
            should_inject_overflow(ring)) {
                /* This TX ring is full. */
                ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));
@@ -1417,9 +1425,8 @@ void b43_dma_handle_txstatus(struct b43_wldev *dev,
                        break;
                slot = next_slot(ring, slot);
        }
-       dev->stats.last_tx = jiffies;
        if (ring->stopped) {
-               B43_WARN_ON(free_slots(ring) < SLOTS_PER_PACKET);
+               B43_WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME);
                ieee80211_wake_queue(dev->wl->hw, ring->queue_prio);
                ring->stopped = 0;
                if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
@@ -1442,8 +1449,8 @@ void b43_dma_get_tx_stats(struct b43_wldev *dev,
                ring = select_ring_by_priority(dev, i);
 
                spin_lock_irqsave(&ring->lock, flags);
-               stats[i].len = ring->used_slots / SLOTS_PER_PACKET;
-               stats[i].limit = ring->nr_slots / SLOTS_PER_PACKET;
+               stats[i].len = ring->used_slots / TX_SLOTS_PER_FRAME;
+               stats[i].limit = ring->nr_slots / TX_SLOTS_PER_FRAME;
                stats[i].count = ring->nr_tx_packets;
                spin_unlock_irqrestore(&ring->lock, flags);
        }
index d1eb5c0848a522edb6a9348366070e4e46980ddd..05dde646d83100986fa08dfddf38977d607c84aa 100644 (file)
@@ -1,14 +1,12 @@
 #ifndef B43_DMA_H_
 #define B43_DMA_H_
 
-#include <linux/list.h>
+#include <linux/ieee80211.h>
 #include <linux/spinlock.h>
-#include <linux/workqueue.h>
-#include <linux/linkage.h>
-#include <asm/atomic.h>
 
 #include "b43.h"
 
+
 /* DMA-Interrupt reasons. */
 #define B43_DMAIRQ_FATALMASK   ((1 << 10) | (1 << 11) | (1 << 12) \
                                         | (1 << 14) | (1 << 15))
@@ -161,14 +159,13 @@ struct b43_dmadesc_generic {
 
 /* Misc DMA constants */
 #define B43_DMA_RINGMEMSIZE            PAGE_SIZE
-#define B43_DMA0_RX_FRAMEOFFSET        30
-#define B43_DMA3_RX_FRAMEOFFSET        0
+#define B43_DMA0_RX_FRAMEOFFSET                30
 
 /* DMA engine tuning knobs */
-#define B43_TXRING_SLOTS               128
+#define B43_TXRING_SLOTS               256
 #define B43_RXRING_SLOTS               64
-#define B43_DMA0_RX_BUFFERSIZE (2304 + 100)
-#define B43_DMA3_RX_BUFFERSIZE 16
+#define B43_DMA0_RX_BUFFERSIZE         IEEE80211_MAX_FRAME_LEN
+
 
 struct sk_buff;
 struct b43_private;
@@ -215,7 +212,7 @@ struct b43_dmaring {
        void *descbase;
        /* Meta data about all descriptors. */
        struct b43_dmadesc_meta *meta;
-       /* Cache of TX headers for each slot.
+       /* Cache of TX headers for each TX frame.
         * This is to avoid an allocation on each TX.
         * This is NULL for an RX ring.
         */
index 6a18a147046519c640f5f622424cfd42d034ea76..22d0fbd83a626a7fc012f23f76b89b634c3ea06e 100644 (file)
@@ -36,8 +36,8 @@
 #include <linux/sched.h>
 
 
-static struct b43_lo_calib * b43_find_lo_calib(struct b43_txpower_lo_control *lo,
-                                              const struct b43_bbatt *bbatt,
+static struct b43_lo_calib *b43_find_lo_calib(struct b43_txpower_lo_control *lo,
+                                             const struct b43_bbatt *bbatt,
                                               const struct b43_rfatt *rfatt)
 {
        struct b43_lo_calib *c;
@@ -138,7 +138,7 @@ static u16 lo_measure_feedthrough(struct b43_wldev *dev,
  * "pad_mix_gain" is the PAD Mixer Gain.
  */
 static u16 lo_txctl_register_table(struct b43_wldev *dev,
-                                  u16 * value, u16 * pad_mix_gain)
+                                  u16 *value, u16 *pad_mix_gain)
 {
        struct b43_phy *phy = &dev->phy;
        u16 reg, v, padmix;
@@ -225,14 +225,12 @@ static void lo_measure_txctl_values(struct b43_wldev *dev)
                                radio_pctl_reg = tmp;
                }
        }
-       b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
-                                     & 0xFFF0) | radio_pctl_reg);
+       b43_radio_maskset(dev, 0x43, 0xFFF0, radio_pctl_reg);
        b43_gphy_set_baseband_attenuation(dev, 2);
 
        reg = lo_txctl_register_table(dev, &mask, NULL);
        mask = ~mask;
-       b43_radio_write16(dev, reg, b43_radio_read16(dev, reg)
-                         & mask);
+       b43_radio_mask(dev, reg, mask);
 
        if (has_tx_magnification(phy)) {
                int i, j;
@@ -242,14 +240,10 @@ static void lo_measure_txctl_values(struct b43_wldev *dev)
 
                for (i = 0; i < ARRAY_SIZE(tx_magn_values); i++) {
                        tx_magn = tx_magn_values[i];
-                       b43_radio_write16(dev, 0x52,
-                                         (b43_radio_read16(dev, 0x52)
-                                          & 0xFF0F) | tx_magn);
+                       b43_radio_maskset(dev, 0x52, 0xFF0F, tx_magn);
                        for (j = 0; j < ARRAY_SIZE(tx_bias_values); j++) {
                                tx_bias = tx_bias_values[j];
-                               b43_radio_write16(dev, 0x52,
-                                                 (b43_radio_read16(dev, 0x52)
-                                                  & 0xFFF0) | tx_bias);
+                               b43_radio_maskset(dev, 0x52, 0xFFF0, tx_bias);
                                feedthrough =
                                    lo_measure_feedthrough(dev, 0, pga,
                                                           trsw_rx);
@@ -269,8 +263,7 @@ static void lo_measure_txctl_values(struct b43_wldev *dev)
        } else {
                lo->tx_magn = 0;
                lo->tx_bias = 0;
-               b43_radio_write16(dev, 0x52, b43_radio_read16(dev, 0x52)
-                                 & 0xFFF0);    /* TX bias == 0 */
+               b43_radio_mask(dev, 0x52, 0xFFF0);      /* TX bias == 0 */
        }
        lo->txctl_measured_time = jiffies;
 }
@@ -406,18 +399,10 @@ static void lo_measure_setup(struct b43_wldev *dev,
                sav->phy_cck_14 = b43_phy_read(dev, B43_PHY_CCK(0x14));
                sav->phy_hpwr_tssictl = b43_phy_read(dev, B43_PHY_HPWR_TSSICTL);
 
-               b43_phy_write(dev, B43_PHY_HPWR_TSSICTL,
-                             b43_phy_read(dev, B43_PHY_HPWR_TSSICTL)
-                             | 0x100);
-               b43_phy_write(dev, B43_PHY_EXTG(0x01),
-                             b43_phy_read(dev, B43_PHY_EXTG(0x01))
-                             | 0x40);
-               b43_phy_write(dev, B43_PHY_DACCTL,
-                             b43_phy_read(dev, B43_PHY_DACCTL)
-                             | 0x40);
-               b43_phy_write(dev, B43_PHY_CCK(0x14),
-                             b43_phy_read(dev, B43_PHY_CCK(0x14))
-                             | 0x200);
+               b43_phy_set(dev, B43_PHY_HPWR_TSSICTL, 0x100);
+               b43_phy_set(dev, B43_PHY_EXTG(0x01), 0x40);
+               b43_phy_set(dev, B43_PHY_DACCTL, 0x40);
+               b43_phy_set(dev, B43_PHY_CCK(0x14), 0x200);
        }
        if (phy->type == B43_PHYTYPE_B &&
            phy->radio_ver == 0x2050 && phy->radio_rev < 6) {
@@ -434,17 +419,10 @@ static void lo_measure_setup(struct b43_wldev *dev,
                sav->phy_cck_3E = b43_phy_read(dev, B43_PHY_CCK(0x3E));
                sav->phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
 
-               b43_phy_write(dev, B43_PHY_CLASSCTL,
-                             b43_phy_read(dev, B43_PHY_CLASSCTL)
-                             & 0xFFFC);
-               b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
-                             & 0x7FFF);
-               b43_phy_write(dev, B43_PHY_ANALOGOVER,
-                             b43_phy_read(dev, B43_PHY_ANALOGOVER)
-                             | 0x0003);
-               b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
-                             b43_phy_read(dev, B43_PHY_ANALOGOVERVAL)
-                             & 0xFFFC);
+               b43_phy_mask(dev, B43_PHY_CLASSCTL, 0xFFFC);
+               b43_phy_mask(dev, B43_PHY_CRS0, 0x7FFF);
+               b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0003);
+               b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFC);
                if (phy->type == B43_PHYTYPE_G) {
                        if ((phy->rev >= 7) &&
                            (sprom->boardflags_lo & B43_BFL_EXTLNA)) {
@@ -558,8 +536,7 @@ static void lo_measure_restore(struct b43_wldev *dev,
        b43_radio_write16(dev, 0x7A, sav->radio_7A);
        if (!has_tx_magnification(phy)) {
                tmp = sav->radio_52;
-               b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
-                                             & 0xFF0F) | tmp);
+               b43_radio_maskset(dev, 0x52, 0xFF0F, tmp);
        }
        b43_write16(dev, 0x3E2, sav->reg_3E2);
        if (phy->type == B43_PHYTYPE_B &&
@@ -754,9 +731,9 @@ static void lo_probe_loctls_statemachine(struct b43_wldev *dev,
 }
 
 static
-struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev,
-                                              const struct b43_bbatt *bbatt,
-                                              const struct b43_rfatt *rfatt)
+struct b43_lo_calib *b43_calibrate_lo_setting(struct b43_wldev *dev,
+                                             const struct b43_bbatt *bbatt,
+                                             const struct b43_rfatt *rfatt)
 {
        struct b43_phy *phy = &dev->phy;
        struct b43_phy_g *gphy = phy->g;
@@ -778,12 +755,8 @@ struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev,
 
        txctl_reg = lo_txctl_register_table(dev, &txctl_value, &pad_mix_gain);
 
-       b43_radio_write16(dev, 0x43,
-                         (b43_radio_read16(dev, 0x43) & 0xFFF0)
-                         | rfatt->att);
-       b43_radio_write16(dev, txctl_reg,
-                         (b43_radio_read16(dev, txctl_reg) & ~txctl_value)
-                         | (rfatt->with_padmix) ? txctl_value : 0);
+       b43_radio_maskset(dev, 0x43, 0xFFF0, rfatt->att);
+       b43_radio_maskset(dev, txctl_reg, ~txctl_value, (rfatt->with_padmix ? txctl_value :0));
 
        max_rx_gain = rfatt->att * 2;
        max_rx_gain += bbatt->att / 2;
@@ -824,9 +797,9 @@ struct b43_lo_calib * b43_calibrate_lo_setting(struct b43_wldev *dev,
 /* Get a calibrated LO setting for the given attenuation values.
  * Might return a NULL pointer under OOM! */
 static
-struct b43_lo_calib * b43_get_calib_lo_settings(struct b43_wldev *dev,
-                                               const struct b43_bbatt *bbatt,
-                                               const struct b43_rfatt *rfatt)
+struct b43_lo_calib *b43_get_calib_lo_settings(struct b43_wldev *dev,
+                                              const struct b43_bbatt *bbatt,
+                                              const struct b43_rfatt *rfatt)
 {
        struct b43_txpower_lo_control *lo = dev->phy.g->lo_control;
        struct b43_lo_calib *c;
index 7116ab6eccfadfc11da321e1541278619020a55a..b72ef3fd315a41833ed1cfb4b863de56443c99e0 100644 (file)
@@ -512,7 +512,7 @@ void b43_shm_write16(struct b43_wldev *dev, u16 routing, u16 offset, u16 value)
 }
 
 /* Read HostFlags */
-u64 b43_hf_read(struct b43_wldev * dev)
+u64 b43_hf_read(struct b43_wldev *dev)
 {
        u64 ret;
 
@@ -600,7 +600,7 @@ void b43_tsf_write(struct b43_wldev *dev, u64 tsf)
 }
 
 static
-void b43_macfilter_set(struct b43_wldev *dev, u16 offset, const u8 * mac)
+void b43_macfilter_set(struct b43_wldev *dev, u16 offset, const u8 *mac)
 {
        static const u8 zero_addr[ETH_ALEN] = { 0 };
        u16 data;
@@ -790,7 +790,7 @@ void b43_dummy_transmission(struct b43_wldev *dev)
 }
 
 static void key_write(struct b43_wldev *dev,
-                     u8 index, u8 algorithm, const u8 * key)
+                     u8 index, u8 algorithm, const u8 *key)
 {
        unsigned int i;
        u32 offset;
@@ -812,7 +812,7 @@ static void key_write(struct b43_wldev *dev,
        }
 }
 
-static void keymac_write(struct b43_wldev *dev, u8 index, const u8 * addr)
+static void keymac_write(struct b43_wldev *dev, u8 index, const u8 *addr)
 {
        u32 addrtmp[2] = { 0, 0, };
        u8 per_sta_keys_start = 8;
@@ -862,7 +862,7 @@ static void keymac_write(struct b43_wldev *dev, u8 index, const u8 * addr)
 
 static void do_key_write(struct b43_wldev *dev,
                         u8 index, u8 algorithm,
-                        const u8 * key, size_t key_len, const u8 * mac_addr)
+                        const u8 *key, size_t key_len, const u8 *mac_addr)
 {
        u8 buf[B43_SEC_KEYSIZE] = { 0, };
        u8 per_sta_keys_start = 8;
@@ -886,8 +886,8 @@ static void do_key_write(struct b43_wldev *dev,
 
 static int b43_key_write(struct b43_wldev *dev,
                         int index, u8 algorithm,
-                        const u8 * key, size_t key_len,
-                        const u8 * mac_addr,
+                        const u8 *key, size_t key_len,
+                        const u8 *mac_addr,
                         struct ieee80211_key_conf *keyconf)
 {
        int i;
@@ -1286,7 +1286,7 @@ static void handle_irq_pmq(struct b43_wldev *dev)
 }
 
 static void b43_write_template_common(struct b43_wldev *dev,
-                                     const u8 * data, u16 size,
+                                     const u8 *data, u16 size,
                                      u16 ram_offset,
                                      u16 shm_size_offset, u8 rate)
 {
@@ -1476,9 +1476,9 @@ static void b43_write_probe_resp_plcp(struct b43_wldev *dev,
  * 2) Patching duration field
  * 3) Stripping TIM
  */
-static const u8 * b43_generate_probe_resp(struct b43_wldev *dev,
-                                         u16 *dest_size,
-                                         struct ieee80211_rate *rate)
+static const u8 *b43_generate_probe_resp(struct b43_wldev *dev,
+                                        u16 *dest_size,
+                                        struct ieee80211_rate *rate)
 {
        const u8 *src_data;
        u8 *dest_data;
@@ -2980,7 +2980,7 @@ static void b43_security_init(struct b43_wldev *dev)
        b43_clear_keys(dev);
 }
 
-static int b43_rng_read(struct hwrng *rng, u32 * data)
+static int b43_rng_read(struct hwrng *rng, u32 *data)
 {
        struct b43_wl *wl = (struct b43_wl *)rng->priv;
        unsigned long flags;
@@ -3311,7 +3311,7 @@ static void b43_put_phy_into_reset(struct b43_wldev *dev)
        msleep(1);
 }
 
-static const char * band_to_string(enum ieee80211_band band)
+static const char *band_to_string(enum ieee80211_band band)
 {
        switch (band) {
        case IEEE80211_BAND_5GHZ:
@@ -4170,11 +4170,21 @@ static int b43_wireless_core_init(struct b43_wldev *dev)
                        hf |= B43_HF_GDCW;
                if (sprom->boardflags_lo & B43_BFL_PACTRL)
                        hf |= B43_HF_OFDMPABOOST;
-       } else if (phy->type == B43_PHYTYPE_B) {
-               hf |= B43_HF_SYMW;
-               if (phy->rev >= 2 && phy->radio_ver == 0x2050)
-                       hf &= ~B43_HF_GDCW;
        }
+       if (phy->radio_ver == 0x2050) {
+               if (phy->radio_rev == 6)
+                       hf |= B43_HF_4318TSSI;
+               if (phy->radio_rev < 6)
+                       hf |= B43_HF_VCORECALC;
+       }
+       if (sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW)
+               hf |= B43_HF_DSCRQ; /* Disable slowclock requests from ucode. */
+#ifdef CONFIG_SSB_DRIVER_PCICORE
+       if ((bus->bustype == SSB_BUSTYPE_PCI) &&
+           (bus->pcicore.dev->id.revision <= 10))
+               hf |= B43_HF_PCISCW; /* PCI slow clock workaround. */
+#endif
+       hf &= ~B43_HF_SKCFPUP;
        b43_hf_write(dev, hf);
 
        b43_set_retry_limits(dev, B43_DEFAULT_SHORT_RETRY_LIMIT,
@@ -4213,7 +4223,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, 1);        /* Enable dynamic PCTL */
+       ssb_bus_powerup(bus, !(sprom->boardflags_lo & B43_BFL_XTAL_NOSLOW));
        b43_upload_card_macaddress(dev);
        b43_security_init(dev);
        if (!dev->suspend_in_progress)
@@ -4397,6 +4407,34 @@ static void b43_op_sta_notify(struct ieee80211_hw *hw,
        B43_WARN_ON(!vif || wl->vif != vif);
 }
 
+static void b43_op_sw_scan_start_notifier(struct ieee80211_hw *hw)
+{
+       struct b43_wl *wl = hw_to_b43_wl(hw);
+       struct b43_wldev *dev;
+
+       mutex_lock(&wl->mutex);
+       dev = wl->current_dev;
+       if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) {
+               /* Disable CFP update during scan on other channels. */
+               b43_hf_write(dev, b43_hf_read(dev) | B43_HF_SKCFPUP);
+       }
+       mutex_unlock(&wl->mutex);
+}
+
+static void b43_op_sw_scan_complete_notifier(struct ieee80211_hw *hw)
+{
+       struct b43_wl *wl = hw_to_b43_wl(hw);
+       struct b43_wldev *dev;
+
+       mutex_lock(&wl->mutex);
+       dev = wl->current_dev;
+       if (dev && (b43_status(dev) >= B43_STAT_INITIALIZED)) {
+               /* Re-enable CFP update. */
+               b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_SKCFPUP);
+       }
+       mutex_unlock(&wl->mutex);
+}
+
 static const struct ieee80211_ops b43_hw_ops = {
        .tx                     = b43_op_tx,
        .conf_tx                = b43_op_conf_tx,
@@ -4415,6 +4453,8 @@ static const struct ieee80211_ops b43_hw_ops = {
        .stop                   = b43_op_stop,
        .set_tim                = b43_op_beacon_set_tim,
        .sta_notify             = b43_op_sta_notify,
+       .sw_scan_start          = b43_op_sw_scan_start_notifier,
+       .sw_scan_complete       = b43_op_sw_scan_complete_notifier,
 };
 
 /* Hard-reset the chip. Do not call this directly.
index 7fe9d1701624b01051518199ca5574c6663f9c24..c836c077d51df3f61aa2438a8e8a14066f7c3c94 100644 (file)
@@ -121,27 +121,18 @@ static void aphy_channel_switch(struct b43_wldev *dev, unsigned int channel)
        b43_radio_write16(dev, 0x0007, (r8 << 4) | r8);
        b43_radio_write16(dev, 0x0020, (r8 << 4) | r8);
        b43_radio_write16(dev, 0x0021, (r8 << 4) | r8);
-       b43_radio_write16(dev, 0x0022, (b43_radio_read16(dev, 0x0022)
-                                       & 0x000F) | (r8 << 4));
+       b43_radio_maskset(dev, 0x0022, 0x000F, (r8 << 4));
        b43_radio_write16(dev, 0x002A, (r8 << 4));
        b43_radio_write16(dev, 0x002B, (r8 << 4));
-       b43_radio_write16(dev, 0x0008, (b43_radio_read16(dev, 0x0008)
-                                       & 0x00F0) | (r8 << 4));
-       b43_radio_write16(dev, 0x0029, (b43_radio_read16(dev, 0x0029)
-                                       & 0xFF0F) | 0x00B0);
+       b43_radio_maskset(dev, 0x0008, 0x00F0, (r8 << 4));
+       b43_radio_maskset(dev, 0x0029, 0xFF0F, 0x00B0);
        b43_radio_write16(dev, 0x0035, 0x00AA);
        b43_radio_write16(dev, 0x0036, 0x0085);
-       b43_radio_write16(dev, 0x003A, (b43_radio_read16(dev, 0x003A)
-                                       & 0xFF20) |
-                         freq_r3A_value(freq));
-       b43_radio_write16(dev, 0x003D,
-                         b43_radio_read16(dev, 0x003D) & 0x00FF);
-       b43_radio_write16(dev, 0x0081, (b43_radio_read16(dev, 0x0081)
-                                       & 0xFF7F) | 0x0080);
-       b43_radio_write16(dev, 0x0035,
-                         b43_radio_read16(dev, 0x0035) & 0xFFEF);
-       b43_radio_write16(dev, 0x0035, (b43_radio_read16(dev, 0x0035)
-                                       & 0xFFEF) | 0x0010);
+       b43_radio_maskset(dev, 0x003A, 0xFF20, freq_r3A_value(freq));
+       b43_radio_mask(dev, 0x003D, 0x00FF);
+       b43_radio_maskset(dev, 0x0081, 0xFF7F, 0x0080);
+       b43_radio_mask(dev, 0x0035, 0xFFEF);
+       b43_radio_maskset(dev, 0x0035, 0xFFEF, 0x0010);
        b43_radio_set_tx_iq(dev);
        //TODO: TSSI2dbm workaround
 //FIXME        b43_phy_xmitpower(dev);
@@ -160,23 +151,20 @@ static void b43_radio_init2060(struct b43_wldev *dev)
        b43_radio_write16(dev, 0x0082, 0x0080);
        b43_radio_write16(dev, 0x0080, 0x0000);
        b43_radio_write16(dev, 0x003F, 0x00DA);
-       b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
-       b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0010);
-       b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
-       b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0020);
+       b43_radio_mask(dev, 0x0005, ~0x0008);
+       b43_radio_mask(dev, 0x0081, ~0x0010);
+       b43_radio_mask(dev, 0x0081, ~0x0020);
+       b43_radio_mask(dev, 0x0081, ~0x0020);
        msleep(1);              /* delay 400usec */
 
-       b43_radio_write16(dev, 0x0081,
-                         (b43_radio_read16(dev, 0x0081) & ~0x0020) | 0x0010);
+       b43_radio_maskset(dev, 0x0081, ~0x0020, 0x0010);
        msleep(1);              /* delay 400usec */
 
-       b43_radio_write16(dev, 0x0005,
-                         (b43_radio_read16(dev, 0x0005) & ~0x0008) | 0x0008);
-       b43_radio_write16(dev, 0x0085, b43_radio_read16(dev, 0x0085) & ~0x0010);
-       b43_radio_write16(dev, 0x0005, b43_radio_read16(dev, 0x0005) & ~0x0008);
-       b43_radio_write16(dev, 0x0081, b43_radio_read16(dev, 0x0081) & ~0x0040);
-       b43_radio_write16(dev, 0x0081,
-                         (b43_radio_read16(dev, 0x0081) & ~0x0040) | 0x0040);
+       b43_radio_maskset(dev, 0x0005, ~0x0008, 0x0008);
+       b43_radio_mask(dev, 0x0085, ~0x0010);
+       b43_radio_mask(dev, 0x0005, ~0x0008);
+       b43_radio_mask(dev, 0x0081, ~0x0040);
+       b43_radio_maskset(dev, 0x0081, ~0x0040, 0x0040);
        b43_radio_write16(dev, 0x0005,
                          (b43_radio_read16(dev, 0x0081) & ~0x0008) | 0x0008);
        b43_phy_write(dev, 0x0063, 0xDDC6);
@@ -224,22 +212,16 @@ static void b43_phy_ww(struct b43_wldev *dev)
        u16 b, curr_s, best_s = 0xFFFF;
        int i;
 
-       b43_phy_write(dev, B43_PHY_CRS0,
-               b43_phy_read(dev, B43_PHY_CRS0) & ~B43_PHY_CRS0_EN);
-       b43_phy_write(dev, B43_PHY_OFDM(0x1B),
-               b43_phy_read(dev, B43_PHY_OFDM(0x1B)) | 0x1000);
-       b43_phy_write(dev, B43_PHY_OFDM(0x82),
-               (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & 0xF0FF) | 0x0300);
-       b43_radio_write16(dev, 0x0009,
-               b43_radio_read16(dev, 0x0009) | 0x0080);
-       b43_radio_write16(dev, 0x0012,
-               (b43_radio_read16(dev, 0x0012) & 0xFFFC) | 0x0002);
+       b43_phy_mask(dev, B43_PHY_CRS0, ~B43_PHY_CRS0_EN);
+       b43_phy_set(dev, B43_PHY_OFDM(0x1B), 0x1000);
+       b43_phy_maskset(dev, B43_PHY_OFDM(0x82), 0xF0FF, 0x0300);
+       b43_radio_set(dev, 0x0009, 0x0080);
+       b43_radio_maskset(dev, 0x0012, 0xFFFC, 0x0002);
        b43_wa_initgains(dev);
        b43_phy_write(dev, B43_PHY_OFDM(0xBA), 0x3ED5);
        b = b43_phy_read(dev, B43_PHY_PWRDOWN);
        b43_phy_write(dev, B43_PHY_PWRDOWN, (b & 0xFFF8) | 0x0005);
-       b43_radio_write16(dev, 0x0004,
-               b43_radio_read16(dev, 0x0004) | 0x0004);
+       b43_radio_set(dev, 0x0004, 0x0004);
        for (i = 0x10; i <= 0x20; i++) {
                b43_radio_write16(dev, 0x0013, i);
                curr_s = b43_phy_read(dev, B43_PHY_OTABLEQ) & 0x00FF;
@@ -252,8 +234,7 @@ static void b43_phy_ww(struct b43_wldev *dev)
                        best_s = curr_s;
        }
        b43_phy_write(dev, B43_PHY_PWRDOWN, b);
-       b43_radio_write16(dev, 0x0004,
-               b43_radio_read16(dev, 0x0004) & 0xFFFB);
+       b43_radio_mask(dev, 0x0004, 0xFFFB);
        b43_radio_write16(dev, 0x0013, best_s);
        b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1_R1, 0, 0xFFEC);
        b43_phy_write(dev, B43_PHY_OFDM(0xB7), 0x1E80);
@@ -261,14 +242,10 @@ static void b43_phy_ww(struct b43_wldev *dev)
        b43_phy_write(dev, B43_PHY_OFDM(0xB5), 0x0EC0);
        b43_phy_write(dev, B43_PHY_OFDM(0xB2), 0x00C0);
        b43_phy_write(dev, B43_PHY_OFDM(0xB9), 0x1FFF);
-       b43_phy_write(dev, B43_PHY_OFDM(0xBB),
-               (b43_phy_read(dev, B43_PHY_OFDM(0xBB)) & 0xF000) | 0x0053);
-       b43_phy_write(dev, B43_PHY_OFDM61,
-               (b43_phy_read(dev, B43_PHY_OFDM61) & 0xFE1F) | 0x0120);
-       b43_phy_write(dev, B43_PHY_OFDM(0x13),
-               (b43_phy_read(dev, B43_PHY_OFDM(0x13)) & 0x0FFF) | 0x3000);
-       b43_phy_write(dev, B43_PHY_OFDM(0x14),
-               (b43_phy_read(dev, B43_PHY_OFDM(0x14)) & 0x0FFF) | 0x3000);
+       b43_phy_maskset(dev, B43_PHY_OFDM(0xBB), 0xF000, 0x0053);
+       b43_phy_maskset(dev, B43_PHY_OFDM61, 0xFE1F, 0x0120);
+       b43_phy_maskset(dev, B43_PHY_OFDM(0x13), 0x0FFF, 0x3000);
+       b43_phy_maskset(dev, B43_PHY_OFDM(0x14), 0x0FFF, 0x3000);
        b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 6, 0x0017);
        for (i = 0; i < 6; i++)
                b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, i, 0x000F);
@@ -276,8 +253,7 @@ static void b43_phy_ww(struct b43_wldev *dev)
        b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0E, 0x0011);
        b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 0x0F, 0x0013);
        b43_phy_write(dev, B43_PHY_OFDM(0x33), 0x5030);
-       b43_phy_write(dev, B43_PHY_CRS0,
-               b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
+       b43_phy_set(dev, B43_PHY_CRS0, B43_PHY_CRS0_EN);
 }
 
 static void hardware_pctl_init_aphy(struct b43_wldev *dev)
@@ -300,26 +276,21 @@ void b43_phy_inita(struct b43_wldev *dev)
 
        if (phy->rev >= 6) {
                if (phy->type == B43_PHYTYPE_A)
-                       b43_phy_write(dev, B43_PHY_OFDM(0x1B),
-                               b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x1000);
+                       b43_phy_mask(dev, B43_PHY_OFDM(0x1B), ~0x1000);
                if (b43_phy_read(dev, B43_PHY_ENCORE) & B43_PHY_ENCORE_EN)
-                       b43_phy_write(dev, B43_PHY_ENCORE,
-                               b43_phy_read(dev, B43_PHY_ENCORE) | 0x0010);
+                       b43_phy_set(dev, B43_PHY_ENCORE, 0x0010);
                else
-                       b43_phy_write(dev, B43_PHY_ENCORE,
-                               b43_phy_read(dev, B43_PHY_ENCORE) & ~0x1010);
+                       b43_phy_mask(dev, B43_PHY_ENCORE, ~0x1010);
        }
 
        b43_wa_all(dev);
 
        if (phy->type == B43_PHYTYPE_A) {
                if (phy->gmode && (phy->rev < 3))
-                       b43_phy_write(dev, 0x0034,
-                               b43_phy_read(dev, 0x0034) | 0x0001);
+                       b43_phy_set(dev, 0x0034, 0x0001);
                b43_phy_rssiagc(dev, 0);
 
-               b43_phy_write(dev, B43_PHY_CRS0,
-                       b43_phy_read(dev, B43_PHY_CRS0) | B43_PHY_CRS0_EN);
+               b43_phy_set(dev, B43_PHY_CRS0, B43_PHY_CRS0_EN);
 
                b43_radio_init2060(dev);
 
@@ -339,9 +310,7 @@ void b43_phy_inita(struct b43_wldev *dev)
 
        if ((phy->type == B43_PHYTYPE_G) &&
            (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)) {
-               b43_phy_write(dev, B43_PHY_OFDM(0x6E),
-                                 (b43_phy_read(dev, B43_PHY_OFDM(0x6E))
-                                  & 0xE000) | 0x3CF);
+               b43_phy_maskset(dev, B43_PHY_OFDM(0x6E), 0xE000, 0x3CF);
        }
 }
 
@@ -520,14 +489,14 @@ static void b43_aphy_op_software_rfkill(struct b43_wldev *dev,
                        return;
                b43_radio_write16(dev, 0x0004, 0x00C0);
                b43_radio_write16(dev, 0x0005, 0x0008);
-               b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) & 0xFFF7);
-               b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) & 0xFFF7);
+               b43_phy_mask(dev, 0x0010, 0xFFF7);
+               b43_phy_mask(dev, 0x0011, 0xFFF7);
                b43_radio_init2060(dev);
        } else {
                b43_radio_write16(dev, 0x0004, 0x00FF);
                b43_radio_write16(dev, 0x0005, 0x00FB);
-               b43_phy_write(dev, 0x0010, b43_phy_read(dev, 0x0010) | 0x0008);
-               b43_phy_write(dev, 0x0011, b43_phy_read(dev, 0x0011) | 0x0008);
+               b43_phy_set(dev, 0x0010, 0x0008);
+               b43_phy_set(dev, 0x0011, 0x0008);
        }
 }
 
index 88bb303ae9d5907524f839b6d59afbbfd67fee0d..e7b98f013b0fa87d571df9af42a1e2e4d48fd1a3 100644 (file)
@@ -204,13 +204,9 @@ void b43_gphy_set_baseband_attenuation(struct b43_wldev *dev,
                                                 & 0xFFF0) |
                            baseband_attenuation);
        } else if (phy->analog > 1) {
-               b43_phy_write(dev, B43_PHY_DACCTL,
-                             (b43_phy_read(dev, B43_PHY_DACCTL)
-                              & 0xFFC3) | (baseband_attenuation << 2));
+               b43_phy_maskset(dev, B43_PHY_DACCTL, 0xFFC3, (baseband_attenuation << 2));
        } else {
-               b43_phy_write(dev, B43_PHY_DACCTL,
-                             (b43_phy_read(dev, B43_PHY_DACCTL)
-                              & 0xFF87) | (baseband_attenuation << 3));
+               b43_phy_maskset(dev, B43_PHY_DACCTL, 0xFF87, (baseband_attenuation << 3));
        }
 }
 
@@ -252,17 +248,13 @@ static void b43_set_txpower_g(struct b43_wldev *dev,
                b43_radio_write16(dev, 0x43,
                                  (rf & 0x000F) | (tx_control & 0x0070));
        } else {
-               b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
-                                             & 0xFFF0) | (rf & 0x000F));
-               b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
-                                             & ~0x0070) | (tx_control &
-                                                           0x0070));
+               b43_radio_maskset(dev, 0x43, 0xFFF0, (rf & 0x000F));
+               b43_radio_maskset(dev, 0x52, ~0x0070, (tx_control & 0x0070));
        }
        if (has_tx_magnification(phy)) {
                b43_radio_write16(dev, 0x52, tx_magn | tx_bias);
        } else {
-               b43_radio_write16(dev, 0x52, (b43_radio_read16(dev, 0x52)
-                                             & 0xFFF0) | (tx_bias & 0x000F));
+               b43_radio_maskset(dev, 0x52, 0xFFF0, (tx_bias & 0x000F));
        }
        b43_lo_g_adjust(dev);
 }
@@ -337,12 +329,9 @@ static void b43_set_all_gains(struct b43_wldev *dev,
 
        if (third != -1) {
                tmp = ((u16) third << 14) | ((u16) third << 6);
-               b43_phy_write(dev, 0x04A0,
-                             (b43_phy_read(dev, 0x04A0) & 0xBFBF) | tmp);
-               b43_phy_write(dev, 0x04A1,
-                             (b43_phy_read(dev, 0x04A1) & 0xBFBF) | tmp);
-               b43_phy_write(dev, 0x04A2,
-                             (b43_phy_read(dev, 0x04A2) & 0xBFBF) | tmp);
+               b43_phy_maskset(dev, 0x04A0, 0xBFBF, tmp);
+               b43_phy_maskset(dev, 0x04A1, 0xBFBF, tmp);
+               b43_phy_maskset(dev, 0x04A2, 0xBFBF, tmp);
        }
        b43_dummy_transmission(dev);
 }
@@ -373,12 +362,9 @@ static void b43_set_original_gains(struct b43_wldev *dev)
        for (i = start; i < end; i++)
                b43_ofdmtab_write16(dev, table, i, i - start);
 
-       b43_phy_write(dev, 0x04A0,
-                     (b43_phy_read(dev, 0x04A0) & 0xBFBF) | 0x4040);
-       b43_phy_write(dev, 0x04A1,
-                     (b43_phy_read(dev, 0x04A1) & 0xBFBF) | 0x4040);
-       b43_phy_write(dev, 0x04A2,
-                     (b43_phy_read(dev, 0x04A2) & 0xBFBF) | 0x4000);
+       b43_phy_maskset(dev, 0x04A0, 0xBFBF, 0x4040);
+       b43_phy_maskset(dev, 0x04A1, 0xBFBF, 0x4040);
+       b43_phy_maskset(dev, 0x04A2, 0xBFBF, 0x4000);
        b43_dummy_transmission(dev);
 }
 
@@ -454,13 +440,11 @@ static void b43_calc_nrssi_offset(struct b43_wldev *dev)
        backup[10] = b43_radio_read16(dev, 0x007A);
        backup[11] = b43_radio_read16(dev, 0x0043);
 
-       b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) & 0x7FFF);
-       b43_phy_write(dev, 0x0001,
-                     (b43_phy_read(dev, 0x0001) & 0x3FFF) | 0x4000);
-       b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C);
-       b43_phy_write(dev, 0x0812,
-                     (b43_phy_read(dev, 0x0812) & 0xFFF3) | 0x0004);
-       b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & ~(0x1 | 0x2));
+       b43_phy_mask(dev, 0x0429, 0x7FFF);
+       b43_phy_maskset(dev, 0x0001, 0x3FFF, 0x4000);
+       b43_phy_set(dev, 0x0811, 0x000C);
+       b43_phy_maskset(dev, 0x0812, 0xFFF3, 0x0004);
+       b43_phy_mask(dev, 0x0802, ~(0x1 | 0x2));
        if (phy->rev >= 6) {
                backup[12] = b43_phy_read(dev, 0x002E);
                backup[13] = b43_phy_read(dev, 0x002F);
@@ -475,13 +459,13 @@ static void b43_calc_nrssi_offset(struct b43_wldev *dev)
                b43_phy_write(dev, 0x002F, 0);
                b43_phy_write(dev, 0x080F, 0);
                b43_phy_write(dev, 0x0810, 0);
-               b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478) | 0x0100);
-               b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801) | 0x0040);
-               b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) | 0x0040);
-               b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014) | 0x0200);
+               b43_phy_set(dev, 0x0478, 0x0100);
+               b43_phy_set(dev, 0x0801, 0x0040);
+               b43_phy_set(dev, 0x0060, 0x0040);
+               b43_phy_set(dev, 0x0014, 0x0200);
        }
-       b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0070);
-       b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0080);
+       b43_radio_set(dev, 0x007A, 0x0070);
+       b43_radio_set(dev, 0x007A, 0x0080);
        udelay(30);
 
        v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
@@ -501,40 +485,31 @@ static void b43_calc_nrssi_offset(struct b43_wldev *dev)
                if (saved == 0xFFFF)
                        saved = 4;
        } else {
-               b43_radio_write16(dev, 0x007A,
-                                 b43_radio_read16(dev, 0x007A) & 0x007F);
+               b43_radio_mask(dev, 0x007A, 0x007F);
                if (phy->rev != 1) {    /* Not in specs, but needed to prevent PPC machine check */
-                       b43_phy_write(dev, 0x0814,
-                                     b43_phy_read(dev, 0x0814) | 0x0001);
-                       b43_phy_write(dev, 0x0815,
-                                     b43_phy_read(dev, 0x0815) & 0xFFFE);
+                       b43_phy_set(dev, 0x0814, 0x0001);
+                       b43_phy_mask(dev, 0x0815, 0xFFFE);
                }
-               b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x000C);
-               b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x000C);
-               b43_phy_write(dev, 0x0811, b43_phy_read(dev, 0x0811) | 0x0030);
-               b43_phy_write(dev, 0x0812, b43_phy_read(dev, 0x0812) | 0x0030);
+               b43_phy_set(dev, 0x0811, 0x000C);
+               b43_phy_set(dev, 0x0812, 0x000C);
+               b43_phy_set(dev, 0x0811, 0x0030);
+               b43_phy_set(dev, 0x0812, 0x0030);
                b43_phy_write(dev, 0x005A, 0x0480);
                b43_phy_write(dev, 0x0059, 0x0810);
                b43_phy_write(dev, 0x0058, 0x000D);
                if (phy->rev == 0) {
                        b43_phy_write(dev, 0x0003, 0x0122);
                } else {
-                       b43_phy_write(dev, 0x000A, b43_phy_read(dev, 0x000A)
-                                     | 0x2000);
+                       b43_phy_set(dev, 0x000A, 0x2000);
                }
                if (phy->rev != 1) {    /* Not in specs, but needed to prevent PPC machine check */
-                       b43_phy_write(dev, 0x0814,
-                                     b43_phy_read(dev, 0x0814) | 0x0004);
-                       b43_phy_write(dev, 0x0815,
-                                     b43_phy_read(dev, 0x0815) & 0xFFFB);
+                       b43_phy_set(dev, 0x0814, 0x0004);
+                       b43_phy_mask(dev, 0x0815, 0xFFFB);
                }
-               b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003) & 0xFF9F)
-                             | 0x0040);
-               b43_radio_write16(dev, 0x007A,
-                                 b43_radio_read16(dev, 0x007A) | 0x000F);
+               b43_phy_maskset(dev, 0x0003, 0xFF9F, 0x0040);
+               b43_radio_set(dev, 0x007A, 0x000F);
                b43_set_all_gains(dev, 3, 0, 1);
-               b43_radio_write16(dev, 0x0043, (b43_radio_read16(dev, 0x0043)
-                                               & 0x00F0) | 0x000F);
+               b43_radio_maskset(dev, 0x0043, 0x00F0, 0x000F);
                udelay(30);
                v47F = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
                if (v47F >= 0x20)
@@ -576,7 +551,7 @@ static void b43_calc_nrssi_offset(struct b43_wldev *dev)
        b43_radio_write16(dev, 0x0043, backup[11]);
        b43_radio_write16(dev, 0x007A, backup[10]);
        b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x1 | 0x2);
-       b43_phy_write(dev, 0x0429, b43_phy_read(dev, 0x0429) | 0x8000);
+       b43_phy_set(dev, 0x0429, 0x8000);
        b43_set_original_gains(dev);
        if (phy->rev >= 6) {
                b43_phy_write(dev, 0x0801, backup[16]);
@@ -604,9 +579,8 @@ static void b43_calc_nrssi_slope(struct b43_wldev *dev)
        if (phy->radio_rev == 8)
                b43_calc_nrssi_offset(dev);
 
-       b43_phy_write(dev, B43_PHY_G_CRS,
-                     b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF);
-       b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
+       b43_phy_mask(dev, B43_PHY_G_CRS, 0x7FFF);
+       b43_phy_mask(dev, 0x0802, 0xFFFC);
        backup[7] = b43_read16(dev, 0x03E2);
        b43_write16(dev, 0x03E2, b43_read16(dev, 0x03E2) | 0x8000);
        backup[0] = b43_radio_read16(dev, 0x007A);
@@ -633,66 +607,44 @@ static void b43_calc_nrssi_slope(struct b43_wldev *dev)
                case 4:
                case 6:
                case 7:
-                       b43_phy_write(dev, 0x0478,
-                                     b43_phy_read(dev, 0x0478)
-                                     | 0x0100);
-                       b43_phy_write(dev, 0x0801,
-                                     b43_phy_read(dev, 0x0801)
-                                     | 0x0040);
+                       b43_phy_set(dev, 0x0478, 0x0100);
+                       b43_phy_set(dev, 0x0801, 0x0040);
                        break;
                case 3:
                case 5:
-                       b43_phy_write(dev, 0x0801,
-                                     b43_phy_read(dev, 0x0801)
-                                     & 0xFFBF);
+                       b43_phy_mask(dev, 0x0801, 0xFFBF);
                        break;
                }
-               b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060)
-                             | 0x0040);
-               b43_phy_write(dev, 0x0014, b43_phy_read(dev, 0x0014)
-                             | 0x0200);
+               b43_phy_set(dev, 0x0060, 0x0040);
+               b43_phy_set(dev, 0x0014, 0x0200);
        }
-       b43_radio_write16(dev, 0x007A,
-                         b43_radio_read16(dev, 0x007A) | 0x0070);
+       b43_radio_set(dev, 0x007A, 0x0070);
        b43_set_all_gains(dev, 0, 8, 0);
-       b43_radio_write16(dev, 0x007A,
-                         b43_radio_read16(dev, 0x007A) & 0x00F7);
+       b43_radio_mask(dev, 0x007A, 0x00F7);
        if (phy->rev >= 2) {
-               b43_phy_write(dev, 0x0811,
-                             (b43_phy_read(dev, 0x0811) & 0xFFCF) |
-                             0x0030);
-               b43_phy_write(dev, 0x0812,
-                             (b43_phy_read(dev, 0x0812) & 0xFFCF) |
-                             0x0010);
+               b43_phy_maskset(dev, 0x0811, 0xFFCF, 0x0030);
+               b43_phy_maskset(dev, 0x0812, 0xFFCF, 0x0010);
        }
-       b43_radio_write16(dev, 0x007A,
-                         b43_radio_read16(dev, 0x007A) | 0x0080);
+       b43_radio_set(dev, 0x007A, 0x0080);
        udelay(20);
 
        nrssi0 = (s16) ((b43_phy_read(dev, 0x047F) >> 8) & 0x003F);
        if (nrssi0 >= 0x0020)
                nrssi0 -= 0x0040;
 
-       b43_radio_write16(dev, 0x007A,
-                         b43_radio_read16(dev, 0x007A) & 0x007F);
+       b43_radio_mask(dev, 0x007A, 0x007F);
        if (phy->rev >= 2) {
-               b43_phy_write(dev, 0x0003, (b43_phy_read(dev, 0x0003)
-                                           & 0xFF9F) | 0x0040);
+               b43_phy_maskset(dev, 0x0003, 0xFF9F, 0x0040);
        }
 
        b43_write16(dev, B43_MMIO_CHANNEL_EXT,
                    b43_read16(dev, B43_MMIO_CHANNEL_EXT)
                    | 0x2000);
-       b43_radio_write16(dev, 0x007A,
-                         b43_radio_read16(dev, 0x007A) | 0x000F);
+       b43_radio_set(dev, 0x007A, 0x000F);
        b43_phy_write(dev, 0x0015, 0xF330);
        if (phy->rev >= 2) {
-               b43_phy_write(dev, 0x0812,
-                             (b43_phy_read(dev, 0x0812) & 0xFFCF) |
-                             0x0020);
-               b43_phy_write(dev, 0x0811,
-                             (b43_phy_read(dev, 0x0811) & 0xFFCF) |
-                             0x0020);
+               b43_phy_maskset(dev, 0x0812, 0xFFCF, 0x0020);
+               b43_phy_maskset(dev, 0x0811, 0xFFCF, 0x0020);
        }
 
        b43_set_all_gains(dev, 3, 0, 1);
@@ -726,10 +678,8 @@ static void b43_calc_nrssi_slope(struct b43_wldev *dev)
                b43_phy_write(dev, B43_PHY_G_LO_CONTROL, backup[13]);
        }
        if (phy->rev >= 2) {
-               b43_phy_write(dev, 0x0812,
-                             b43_phy_read(dev, 0x0812) & 0xFFCF);
-               b43_phy_write(dev, 0x0811,
-                             b43_phy_read(dev, 0x0811) & 0xFFCF);
+               b43_phy_mask(dev, 0x0812, 0xFFCF);
+               b43_phy_mask(dev, 0x0811, 0xFFCF);
        }
 
        b43_radio_write16(dev, 0x007A, backup[0]);
@@ -743,11 +693,9 @@ static void b43_calc_nrssi_slope(struct b43_wldev *dev)
        b43_phy_write(dev, 0x0059, backup[5]);
        b43_phy_write(dev, 0x0058, backup[6]);
        b43_synth_pu_workaround(dev, phy->channel);
-       b43_phy_write(dev, 0x0802,
-                     b43_phy_read(dev, 0x0802) | (0x0001 | 0x0002));
+       b43_phy_set(dev, 0x0802, (0x0001 | 0x0002));
        b43_set_original_gains(dev);
-       b43_phy_write(dev, B43_PHY_G_CRS,
-                     b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000);
+       b43_phy_set(dev, B43_PHY_G_CRS, 0x8000);
        if (phy->rev >= 3) {
                b43_phy_write(dev, 0x0801, backup[14]);
                b43_phy_write(dev, 0x0060, backup[15]);
@@ -774,13 +722,9 @@ static void b43_calc_nrssi_threshold(struct b43_wldev *dev)
                if (tmp16 >= 0x20)
                        tmp16 -= 0x40;
                if (tmp16 < 3) {
-                       b43_phy_write(dev, 0x048A,
-                                     (b43_phy_read(dev, 0x048A)
-                                      & 0xF000) | 0x09EB);
+                       b43_phy_maskset(dev, 0x048A, 0xF000, 0x09EB);
                } else {
-                       b43_phy_write(dev, 0x048A,
-                                     (b43_phy_read(dev, 0x048A)
-                                      & 0xF000) | 0x0AED);
+                       b43_phy_maskset(dev, 0x048A, 0xF000, 0x0AED);
                }
        } else {
                if (gphy->interfmode == B43_INTERFMODE_NONWLAN) {
@@ -823,7 +767,7 @@ static void b43_calc_nrssi_threshold(struct b43_wldev *dev)
  * interference mitigation code.
  * It is save to restore values in random order.
  */
-static void _stack_save(u32 * _stackptr, size_t * stackidx,
+static void _stack_save(u32 *_stackptr, size_t *stackidx,
                        u8 id, u16 offset, u16 value)
 {
        u32 *stackptr = &(_stackptr[*stackidx]);
@@ -837,7 +781,7 @@ static void _stack_save(u32 * _stackptr, size_t * stackidx,
        B43_WARN_ON(*stackidx >= B43_INTERFSTACK_SIZE);
 }
 
-static u16 _stack_restore(u32 * stackptr, u8 id, u16 offset)
+static u16 _stack_restore(u32 *stackptr, u8 id, u16 offset)
 {
        size_t i;
 
@@ -901,11 +845,8 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
        switch (mode) {
        case B43_INTERFMODE_NONWLAN:
                if (phy->rev != 1) {
-                       b43_phy_write(dev, 0x042B,
-                                     b43_phy_read(dev, 0x042B) | 0x0800);
-                       b43_phy_write(dev, B43_PHY_G_CRS,
-                                     b43_phy_read(dev,
-                                                  B43_PHY_G_CRS) & ~0x4000);
+                       b43_phy_set(dev, 0x042B, 0x0800);
+                       b43_phy_mask(dev, B43_PHY_G_CRS, ~0x4000);
                        break;
                }
                radio_stacksave(0x0078);
@@ -924,26 +865,19 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
                phy_stacksave(0x0406);
                b43_phy_write(dev, 0x0406, 0x7E28);
 
-               b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x0800);
-               b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
-                             b43_phy_read(dev,
-                                          B43_PHY_RADIO_BITFIELD) | 0x1000);
+               b43_phy_set(dev, 0x042B, 0x0800);
+               b43_phy_set(dev, B43_PHY_RADIO_BITFIELD, 0x1000);
 
                phy_stacksave(0x04A0);
-               b43_phy_write(dev, 0x04A0,
-                             (b43_phy_read(dev, 0x04A0) & 0xC0C0) | 0x0008);
+               b43_phy_maskset(dev, 0x04A0, 0xC0C0, 0x0008);
                phy_stacksave(0x04A1);
-               b43_phy_write(dev, 0x04A1,
-                             (b43_phy_read(dev, 0x04A1) & 0xC0C0) | 0x0605);
+               b43_phy_maskset(dev, 0x04A1, 0xC0C0, 0x0605);
                phy_stacksave(0x04A2);
-               b43_phy_write(dev, 0x04A2,
-                             (b43_phy_read(dev, 0x04A2) & 0xC0C0) | 0x0204);
+               b43_phy_maskset(dev, 0x04A2, 0xC0C0, 0x0204);
                phy_stacksave(0x04A8);
-               b43_phy_write(dev, 0x04A8,
-                             (b43_phy_read(dev, 0x04A8) & 0xC0C0) | 0x0803);
+               b43_phy_maskset(dev, 0x04A8, 0xC0C0, 0x0803);
                phy_stacksave(0x04AB);
-               b43_phy_write(dev, 0x04AB,
-                             (b43_phy_read(dev, 0x04AB) & 0xC0C0) | 0x0605);
+               b43_phy_maskset(dev, 0x04AB, 0xC0C0, 0x0605);
 
                phy_stacksave(0x04A7);
                b43_phy_write(dev, 0x04A7, 0x0002);
@@ -999,12 +933,8 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
                phy_stacksave(0x042B);
                phy_stacksave(0x048C);
 
-               b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
-                             b43_phy_read(dev, B43_PHY_RADIO_BITFIELD)
-                             & ~0x1000);
-               b43_phy_write(dev, B43_PHY_G_CRS,
-                             (b43_phy_read(dev, B43_PHY_G_CRS)
-                              & 0xFFFC) | 0x0002);
+               b43_phy_mask(dev, B43_PHY_RADIO_BITFIELD, ~0x1000);
+               b43_phy_maskset(dev, B43_PHY_G_CRS, 0xFFFC, 0x0002);
 
                b43_phy_write(dev, 0x0033, 0x0800);
                b43_phy_write(dev, 0x04A3, 0x2027);
@@ -1013,8 +943,7 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
                b43_phy_write(dev, 0x04AA, 0x1CA8);
                b43_phy_write(dev, 0x04AC, 0x287A);
 
-               b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
-                                           & 0xFFC0) | 0x001A);
+               b43_phy_maskset(dev, 0x04A0, 0xFFC0, 0x001A);
                b43_phy_write(dev, 0x04A7, 0x000D);
 
                if (phy->rev < 2) {
@@ -1027,65 +956,41 @@ b43_radio_interference_mitigation_enable(struct b43_wldev *dev, int mode)
                        b43_phy_write(dev, 0x04C1, 0x0059);
                }
 
-               b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
-                                           & 0xC0FF) | 0x1800);
-               b43_phy_write(dev, 0x04A1, (b43_phy_read(dev, 0x04A1)
-                                           & 0xFFC0) | 0x0015);
-               b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
-                                           & 0xCFFF) | 0x1000);
-               b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
-                                           & 0xF0FF) | 0x0A00);
-               b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
-                                           & 0xCFFF) | 0x1000);
-               b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
-                                           & 0xF0FF) | 0x0800);
-               b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
-                                           & 0xFFCF) | 0x0010);
-               b43_phy_write(dev, 0x04AB, (b43_phy_read(dev, 0x04AB)
-                                           & 0xFFF0) | 0x0005);
-               b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
-                                           & 0xFFCF) | 0x0010);
-               b43_phy_write(dev, 0x04A8, (b43_phy_read(dev, 0x04A8)
-                                           & 0xFFF0) | 0x0006);
-               b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
-                                           & 0xF0FF) | 0x0800);
-               b43_phy_write(dev, 0x04A0, (b43_phy_read(dev, 0x04A0)
-                                           & 0xF0FF) | 0x0500);
-               b43_phy_write(dev, 0x04A2, (b43_phy_read(dev, 0x04A2)
-                                           & 0xFFF0) | 0x000B);
+               b43_phy_maskset(dev, 0x04A1, 0xC0FF, 0x1800);
+               b43_phy_maskset(dev, 0x04A1, 0xFFC0, 0x0015);
+               b43_phy_maskset(dev, 0x04A8, 0xCFFF, 0x1000);
+               b43_phy_maskset(dev, 0x04A8, 0xF0FF, 0x0A00);
+               b43_phy_maskset(dev, 0x04AB, 0xCFFF, 0x1000);
+               b43_phy_maskset(dev, 0x04AB, 0xF0FF, 0x0800);
+               b43_phy_maskset(dev, 0x04AB, 0xFFCF, 0x0010);
+               b43_phy_maskset(dev, 0x04AB, 0xFFF0, 0x0005);
+               b43_phy_maskset(dev, 0x04A8, 0xFFCF, 0x0010);
+               b43_phy_maskset(dev, 0x04A8, 0xFFF0, 0x0006);
+               b43_phy_maskset(dev, 0x04A2, 0xF0FF, 0x0800);
+               b43_phy_maskset(dev, 0x04A0, 0xF0FF, 0x0500);
+               b43_phy_maskset(dev, 0x04A2, 0xFFF0, 0x000B);
 
                if (phy->rev >= 3) {
-                       b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A)
-                                     & ~0x8000);
-                       b43_phy_write(dev, 0x0415, (b43_phy_read(dev, 0x0415)
-                                                   & 0x8000) | 0x36D8);
-                       b43_phy_write(dev, 0x0416, (b43_phy_read(dev, 0x0416)
-                                                   & 0x8000) | 0x36D8);
-                       b43_phy_write(dev, 0x0417, (b43_phy_read(dev, 0x0417)
-                                                   & 0xFE00) | 0x016D);
+                       b43_phy_mask(dev, 0x048A, (u16)~0x8000);
+                       b43_phy_maskset(dev, 0x0415, 0x8000, 0x36D8);
+                       b43_phy_maskset(dev, 0x0416, 0x8000, 0x36D8);
+                       b43_phy_maskset(dev, 0x0417, 0xFE00, 0x016D);
                } else {
-                       b43_phy_write(dev, 0x048A, b43_phy_read(dev, 0x048A)
-                                     | 0x1000);
-                       b43_phy_write(dev, 0x048A, (b43_phy_read(dev, 0x048A)
-                                                   & 0x9FFF) | 0x2000);
+                       b43_phy_set(dev, 0x048A, 0x1000);
+                       b43_phy_maskset(dev, 0x048A, 0x9FFF, 0x2000);
                        b43_hf_write(dev, b43_hf_read(dev) | B43_HF_ACIW);
                }
                if (phy->rev >= 2) {
-                       b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B)
-                                     | 0x0800);
+                       b43_phy_set(dev, 0x042B, 0x0800);
                }
-               b43_phy_write(dev, 0x048C, (b43_phy_read(dev, 0x048C)
-                                           & 0xF0FF) | 0x0200);
+               b43_phy_maskset(dev, 0x048C, 0xF0FF, 0x0200);
                if (phy->rev == 2) {
-                       b43_phy_write(dev, 0x04AE, (b43_phy_read(dev, 0x04AE)
-                                                   & 0xFF00) | 0x007F);
-                       b43_phy_write(dev, 0x04AD, (b43_phy_read(dev, 0x04AD)
-                                                   & 0x00FF) | 0x1300);
+                       b43_phy_maskset(dev, 0x04AE, 0xFF00, 0x007F);
+                       b43_phy_maskset(dev, 0x04AD, 0x00FF, 0x1300);
                } else if (phy->rev >= 6) {
                        b43_ofdmtab_write16(dev, 0x1A00, 0x3, 0x007F);
                        b43_ofdmtab_write16(dev, 0x1A00, 0x2, 0x007F);
-                       b43_phy_write(dev, 0x04AD, b43_phy_read(dev, 0x04AD)
-                                     & 0x00FF);
+                       b43_phy_mask(dev, 0x04AD, 0x00FF);
                }
                b43_calc_nrssi_slope(dev);
                break;
@@ -1104,24 +1009,18 @@ b43_radio_interference_mitigation_disable(struct b43_wldev *dev, int mode)
        switch (mode) {
        case B43_INTERFMODE_NONWLAN:
                if (phy->rev != 1) {
-                       b43_phy_write(dev, 0x042B,
-                                     b43_phy_read(dev, 0x042B) & ~0x0800);
-                       b43_phy_write(dev, B43_PHY_G_CRS,
-                                     b43_phy_read(dev,
-                                                  B43_PHY_G_CRS) | 0x4000);
+                       b43_phy_mask(dev, 0x042B, ~0x0800);
+                       b43_phy_set(dev, B43_PHY_G_CRS, 0x4000);
                        break;
                }
                radio_stackrestore(0x0078);
                b43_calc_nrssi_threshold(dev);
                phy_stackrestore(0x0406);
-               b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) & ~0x0800);
+               b43_phy_mask(dev, 0x042B, ~0x0800);
                if (!dev->bad_frames_preempt) {
-                       b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
-                                     b43_phy_read(dev, B43_PHY_RADIO_BITFIELD)
-                                     & ~(1 << 11));
+                       b43_phy_mask(dev, B43_PHY_RADIO_BITFIELD, ~(1 << 11));
                }
-               b43_phy_write(dev, B43_PHY_G_CRS,
-                             b43_phy_read(dev, B43_PHY_G_CRS) | 0x4000);
+               b43_phy_set(dev, B43_PHY_G_CRS, 0x4000);
                phy_stackrestore(0x04A0);
                phy_stackrestore(0x04A1);
                phy_stackrestore(0x04A2);
@@ -1389,17 +1288,10 @@ static u16 b43_radio_init2050(struct b43_wldev *dev)
                sav.phy_crs0 = b43_phy_read(dev, B43_PHY_CRS0);
                sav.phy_classctl = b43_phy_read(dev, B43_PHY_CLASSCTL);
 
-               b43_phy_write(dev, B43_PHY_ANALOGOVER,
-                             b43_phy_read(dev, B43_PHY_ANALOGOVER)
-                             | 0x0003);
-               b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
-                             b43_phy_read(dev, B43_PHY_ANALOGOVERVAL)
-                             & 0xFFFC);
-               b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
-                             & 0x7FFF);
-               b43_phy_write(dev, B43_PHY_CLASSCTL,
-                             b43_phy_read(dev, B43_PHY_CLASSCTL)
-                             & 0xFFFC);
+               b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0003);
+               b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFC);
+               b43_phy_mask(dev, B43_PHY_CRS0, 0x7FFF);
+               b43_phy_mask(dev, B43_PHY_CLASSCTL, 0xFFFC);
                if (has_loopback_gain(phy)) {
                        sav.phy_lo_mask = b43_phy_read(dev, B43_PHY_LO_MASK);
                        sav.phy_lo_ctl = b43_phy_read(dev, B43_PHY_LO_CTL);
@@ -1420,8 +1312,7 @@ static u16 b43_radio_init2050(struct b43_wldev *dev)
        b43_write16(dev, 0x3E2, b43_read16(dev, 0x3E2) | 0x8000);
 
        sav.phy_syncctl = b43_phy_read(dev, B43_PHY_SYNCCTL);
-       b43_phy_write(dev, B43_PHY_SYNCCTL, b43_phy_read(dev, B43_PHY_SYNCCTL)
-                     & 0xFF7F);
+       b43_phy_mask(dev, B43_PHY_SYNCCTL, 0xFF7F);
        sav.reg_3E6 = b43_read16(dev, 0x3E6);
        sav.reg_3F4 = b43_read16(dev, 0x3F4);
 
@@ -1429,9 +1320,7 @@ static u16 b43_radio_init2050(struct b43_wldev *dev)
                b43_write16(dev, 0x03E6, 0x0122);
        } else {
                if (phy->analog >= 2) {
-                       b43_phy_write(dev, B43_PHY_CCK(0x03),
-                                     (b43_phy_read(dev, B43_PHY_CCK(0x03))
-                                      & 0xFFBF) | 0x40);
+                       b43_phy_maskset(dev, B43_PHY_CCK(0x03), 0xFFBF, 0x40);
                }
                b43_write16(dev, B43_MMIO_CHANNEL_EXT,
                            (b43_read16(dev, B43_MMIO_CHANNEL_EXT) | 0x2000));
@@ -1454,14 +1343,12 @@ static u16 b43_radio_init2050(struct b43_wldev *dev)
                                                   LPD(0, 0, 1)));
        }
        b43_phy_write(dev, B43_PHY_PGACTL, 0xBFA0);
-       b43_radio_write16(dev, 0x51, b43_radio_read16(dev, 0x51)
-                         | 0x0004);
+       b43_radio_set(dev, 0x51, 0x0004);
        if (phy->radio_rev == 8) {
                b43_radio_write16(dev, 0x43, 0x1F);
        } else {
                b43_radio_write16(dev, 0x52, 0);
-               b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
-                                             & 0xFFF0) | 0x0009);
+               b43_radio_maskset(dev, 0x43, 0xFFF0, 0x0009);
        }
        b43_phy_write(dev, B43_PHY_CCK(0x58), 0);
 
@@ -1610,8 +1497,7 @@ static void b43_phy_initb5(struct b43_wldev *dev)
        u8 old_channel;
 
        if (phy->analog == 1) {
-               b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A)
-                                 | 0x0050);
+               b43_radio_set(dev, 0x007A, 0x0050);
        }
        if ((bus->boardinfo.vendor != SSB_BOARDVENDOR_BCM) &&
            (bus->boardinfo.type != SSB_BOARD_BU4306)) {
@@ -1621,39 +1507,29 @@ static void b43_phy_initb5(struct b43_wldev *dev)
                        value += 0x202;
                }
        }
-       b43_phy_write(dev, 0x0035, (b43_phy_read(dev, 0x0035) & 0xF0FF)
-                     | 0x0700);
+       b43_phy_maskset(dev, 0x0035, 0xF0FF, 0x0700);
        if (phy->radio_ver == 0x2050)
                b43_phy_write(dev, 0x0038, 0x0667);
 
        if (phy->gmode || phy->rev >= 2) {
                if (phy->radio_ver == 0x2050) {
-                       b43_radio_write16(dev, 0x007A,
-                                         b43_radio_read16(dev, 0x007A)
-                                         | 0x0020);
-                       b43_radio_write16(dev, 0x0051,
-                                         b43_radio_read16(dev, 0x0051)
-                                         | 0x0004);
+                       b43_radio_set(dev, 0x007A, 0x0020);
+                       b43_radio_set(dev, 0x0051, 0x0004);
                }
                b43_write16(dev, B43_MMIO_PHY_RADIO, 0x0000);
 
-               b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100);
-               b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000);
+               b43_phy_set(dev, 0x0802, 0x0100);
+               b43_phy_set(dev, 0x042B, 0x2000);
 
                b43_phy_write(dev, 0x001C, 0x186A);
 
-               b43_phy_write(dev, 0x0013,
-                             (b43_phy_read(dev, 0x0013) & 0x00FF) | 0x1900);
-               b43_phy_write(dev, 0x0035,
-                             (b43_phy_read(dev, 0x0035) & 0xFFC0) | 0x0064);
-               b43_phy_write(dev, 0x005D,
-                             (b43_phy_read(dev, 0x005D) & 0xFF80) | 0x000A);
+               b43_phy_maskset(dev, 0x0013, 0x00FF, 0x1900);
+               b43_phy_maskset(dev, 0x0035, 0xFFC0, 0x0064);
+               b43_phy_maskset(dev, 0x005D, 0xFF80, 0x000A);
        }
 
        if (dev->bad_frames_preempt) {
-               b43_phy_write(dev, B43_PHY_RADIO_BITFIELD,
-                             b43_phy_read(dev,
-                                          B43_PHY_RADIO_BITFIELD) | (1 << 11));
+               b43_phy_set(dev, B43_PHY_RADIO_BITFIELD, (1 << 11));
        }
 
        if (phy->analog == 1) {
@@ -1695,7 +1571,7 @@ static void b43_phy_initb5(struct b43_wldev *dev)
        b43_radio_write16(dev, 0x005B, 0x007B);
        b43_radio_write16(dev, 0x005C, 0x00B0);
 
-       b43_radio_write16(dev, 0x007A, b43_radio_read16(dev, 0x007A) | 0x0007);
+       b43_radio_set(dev, 0x007A, 0x0007);
 
        b43_gphy_channel_switch(dev, old_channel, 0);
 
@@ -1771,12 +1647,10 @@ static void b43_phy_initb6(struct b43_wldev *dev)
                val += 0x0202;
        }
        if (phy->type == B43_PHYTYPE_G) {
-               b43_radio_write16(dev, 0x007A,
-                                 b43_radio_read16(dev, 0x007A) | 0x0020);
-               b43_radio_write16(dev, 0x0051,
-                                 b43_radio_read16(dev, 0x0051) | 0x0004);
-               b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) | 0x0100);
-               b43_phy_write(dev, 0x042B, b43_phy_read(dev, 0x042B) | 0x2000);
+               b43_radio_set(dev, 0x007A, 0x0020);
+               b43_radio_set(dev, 0x0051, 0x0004);
+               b43_phy_set(dev, 0x0802, 0x0100);
+               b43_phy_set(dev, 0x042B, 0x2000);
                b43_phy_write(dev, 0x5B, 0);
                b43_phy_write(dev, 0x5C, 0);
        }
@@ -1801,8 +1675,7 @@ static void b43_phy_initb6(struct b43_wldev *dev)
                b43_radio_write16(dev, 0x5B, 0x7B);
                b43_radio_write16(dev, 0x5C, 0xB0);
        }
-       b43_radio_write16(dev, 0x007A,
-                         (b43_radio_read16(dev, 0x007A) & 0x00F8) | 0x0007);
+       b43_radio_maskset(dev, 0x007A, 0x00F8, 0x0007);
 
        b43_gphy_channel_switch(dev, old_channel, 0);
 
@@ -1814,19 +1687,16 @@ static void b43_phy_initb6(struct b43_wldev *dev)
        b43_phy_write(dev, 0x0038, 0x0668);
        b43_set_txpower_g(dev, &gphy->bbatt, &gphy->rfatt, gphy->tx_control);
        if (phy->radio_rev <= 5) {
-               b43_phy_write(dev, 0x5D, (b43_phy_read(dev, 0x5D)
-                                         & 0xFF80) | 0x0003);
+               b43_phy_maskset(dev, 0x5D, 0xFF80, 0x0003);
        }
        if (phy->radio_rev <= 2)
                b43_radio_write16(dev, 0x005D, 0x000D);
 
        if (phy->analog == 4) {
                b43_write16(dev, 0x3E4, 9);
-               b43_phy_write(dev, 0x61, b43_phy_read(dev, 0x61)
-                             & 0x0FFF);
+               b43_phy_mask(dev, 0x61, 0x0FFF);
        } else {
-               b43_phy_write(dev, 0x0002, (b43_phy_read(dev, 0x0002) & 0xFFC0)
-                             | 0x0004);
+               b43_phy_maskset(dev, 0x0002, 0xFFC0, 0x0004);
        }
        if (phy->type == B43_PHYTYPE_B)
                B43_WARN_ON(1);
@@ -1868,63 +1738,39 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
        backup_radio[1] = b43_radio_read16(dev, 0x43);
        backup_radio[2] = b43_radio_read16(dev, 0x7A);
 
-       b43_phy_write(dev, B43_PHY_CRS0,
-                     b43_phy_read(dev, B43_PHY_CRS0) & 0x3FFF);
-       b43_phy_write(dev, B43_PHY_CCKBBANDCFG,
-                     b43_phy_read(dev, B43_PHY_CCKBBANDCFG) | 0x8000);
-       b43_phy_write(dev, B43_PHY_RFOVER,
-                     b43_phy_read(dev, B43_PHY_RFOVER) | 0x0002);
-       b43_phy_write(dev, B43_PHY_RFOVERVAL,
-                     b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFD);
-       b43_phy_write(dev, B43_PHY_RFOVER,
-                     b43_phy_read(dev, B43_PHY_RFOVER) | 0x0001);
-       b43_phy_write(dev, B43_PHY_RFOVERVAL,
-                     b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xFFFE);
+       b43_phy_mask(dev, B43_PHY_CRS0, 0x3FFF);
+       b43_phy_set(dev, B43_PHY_CCKBBANDCFG, 0x8000);
+       b43_phy_set(dev, B43_PHY_RFOVER, 0x0002);
+       b43_phy_mask(dev, B43_PHY_RFOVERVAL, 0xFFFD);
+       b43_phy_set(dev, B43_PHY_RFOVER, 0x0001);
+       b43_phy_mask(dev, B43_PHY_RFOVERVAL, 0xFFFE);
        if (phy->rev != 1) {    /* Not in specs, but needed to prevent PPC machine check */
-               b43_phy_write(dev, B43_PHY_ANALOGOVER,
-                             b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0001);
-               b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
-                             b43_phy_read(dev,
-                                          B43_PHY_ANALOGOVERVAL) & 0xFFFE);
-               b43_phy_write(dev, B43_PHY_ANALOGOVER,
-                             b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0002);
-               b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
-                             b43_phy_read(dev,
-                                          B43_PHY_ANALOGOVERVAL) & 0xFFFD);
-       }
-       b43_phy_write(dev, B43_PHY_RFOVER,
-                     b43_phy_read(dev, B43_PHY_RFOVER) | 0x000C);
-       b43_phy_write(dev, B43_PHY_RFOVERVAL,
-                     b43_phy_read(dev, B43_PHY_RFOVERVAL) | 0x000C);
-       b43_phy_write(dev, B43_PHY_RFOVER,
-                     b43_phy_read(dev, B43_PHY_RFOVER) | 0x0030);
-       b43_phy_write(dev, B43_PHY_RFOVERVAL,
-                     (b43_phy_read(dev, B43_PHY_RFOVERVAL)
-                      & 0xFFCF) | 0x10);
+               b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0001);
+               b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFE);
+               b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0002);
+               b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFD);
+       }
+       b43_phy_set(dev, B43_PHY_RFOVER, 0x000C);
+       b43_phy_set(dev, B43_PHY_RFOVERVAL, 0x000C);
+       b43_phy_set(dev, B43_PHY_RFOVER, 0x0030);
+       b43_phy_maskset(dev, B43_PHY_RFOVERVAL, 0xFFCF, 0x10);
 
        b43_phy_write(dev, B43_PHY_CCK(0x5A), 0x0780);
        b43_phy_write(dev, B43_PHY_CCK(0x59), 0xC810);
        b43_phy_write(dev, B43_PHY_CCK(0x58), 0x000D);
 
-       b43_phy_write(dev, B43_PHY_CCK(0x0A),
-                     b43_phy_read(dev, B43_PHY_CCK(0x0A)) | 0x2000);
+       b43_phy_set(dev, B43_PHY_CCK(0x0A), 0x2000);
        if (phy->rev != 1) {    /* Not in specs, but needed to prevent PPC machine check */
-               b43_phy_write(dev, B43_PHY_ANALOGOVER,
-                             b43_phy_read(dev, B43_PHY_ANALOGOVER) | 0x0004);
-               b43_phy_write(dev, B43_PHY_ANALOGOVERVAL,
-                             b43_phy_read(dev,
-                                          B43_PHY_ANALOGOVERVAL) & 0xFFFB);
+               b43_phy_set(dev, B43_PHY_ANALOGOVER, 0x0004);
+               b43_phy_mask(dev, B43_PHY_ANALOGOVERVAL, 0xFFFB);
        }
-       b43_phy_write(dev, B43_PHY_CCK(0x03),
-                     (b43_phy_read(dev, B43_PHY_CCK(0x03))
-                      & 0xFF9F) | 0x40);
+       b43_phy_maskset(dev, B43_PHY_CCK(0x03), 0xFF9F, 0x40);
 
        if (phy->radio_rev == 8) {
                b43_radio_write16(dev, 0x43, 0x000F);
        } else {
                b43_radio_write16(dev, 0x52, 0);
-               b43_radio_write16(dev, 0x43, (b43_radio_read16(dev, 0x43)
-                                             & 0xFFF0) | 0x9);
+               b43_radio_maskset(dev, 0x43, 0xFFF0, 0x9);
        }
        b43_gphy_set_baseband_attenuation(dev, 11);
 
@@ -1934,45 +1780,28 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
                b43_phy_write(dev, B43_PHY_LO_MASK, 0x8020);
        b43_phy_write(dev, B43_PHY_LO_CTL, 0);
 
-       b43_phy_write(dev, B43_PHY_CCK(0x2B),
-                     (b43_phy_read(dev, B43_PHY_CCK(0x2B))
-                      & 0xFFC0) | 0x01);
-       b43_phy_write(dev, B43_PHY_CCK(0x2B),
-                     (b43_phy_read(dev, B43_PHY_CCK(0x2B))
-                      & 0xC0FF) | 0x800);
+       b43_phy_maskset(dev, B43_PHY_CCK(0x2B), 0xFFC0, 0x01);
+       b43_phy_maskset(dev, B43_PHY_CCK(0x2B), 0xC0FF, 0x800);
 
-       b43_phy_write(dev, B43_PHY_RFOVER,
-                     b43_phy_read(dev, B43_PHY_RFOVER) | 0x0100);
-       b43_phy_write(dev, B43_PHY_RFOVERVAL,
-                     b43_phy_read(dev, B43_PHY_RFOVERVAL) & 0xCFFF);
+       b43_phy_set(dev, B43_PHY_RFOVER, 0x0100);
+       b43_phy_mask(dev, B43_PHY_RFOVERVAL, 0xCFFF);
 
        if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_EXTLNA) {
                if (phy->rev >= 7) {
-                       b43_phy_write(dev, B43_PHY_RFOVER,
-                                     b43_phy_read(dev, B43_PHY_RFOVER)
-                                     | 0x0800);
-                       b43_phy_write(dev, B43_PHY_RFOVERVAL,
-                                     b43_phy_read(dev, B43_PHY_RFOVERVAL)
-                                     | 0x8000);
+                       b43_phy_set(dev, B43_PHY_RFOVER, 0x0800);
+                       b43_phy_set(dev, B43_PHY_RFOVERVAL, 0x8000);
                }
        }
-       b43_radio_write16(dev, 0x7A, b43_radio_read16(dev, 0x7A)
-                         & 0x00F7);
+       b43_radio_mask(dev, 0x7A, 0x00F7);
 
        j = 0;
        loop_i_max = (phy->radio_rev == 8) ? 15 : 9;
        for (i = 0; i < loop_i_max; i++) {
                for (j = 0; j < 16; j++) {
                        b43_radio_write16(dev, 0x43, i);
-                       b43_phy_write(dev, B43_PHY_RFOVERVAL,
-                                     (b43_phy_read(dev, B43_PHY_RFOVERVAL)
-                                      & 0xF0FF) | (j << 8));
-                       b43_phy_write(dev, B43_PHY_PGACTL,
-                                     (b43_phy_read(dev, B43_PHY_PGACTL)
-                                      & 0x0FFF) | 0xA000);
-                       b43_phy_write(dev, B43_PHY_PGACTL,
-                                     b43_phy_read(dev, B43_PHY_PGACTL)
-                                     | 0xF000);
+                       b43_phy_maskset(dev, B43_PHY_RFOVERVAL, 0xF0FF, (j << 8));
+                       b43_phy_maskset(dev, B43_PHY_PGACTL, 0x0FFF, 0xA000);
+                       b43_phy_set(dev, B43_PHY_PGACTL, 0xF000);
                        udelay(20);
                        if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
                                goto exit_loop1;
@@ -1982,20 +1811,12 @@ static void b43_calc_loopback_gain(struct b43_wldev *dev)
        loop1_outer_done = i;
        loop1_inner_done = j;
        if (j >= 8) {
-               b43_phy_write(dev, B43_PHY_RFOVERVAL,
-                             b43_phy_read(dev, B43_PHY_RFOVERVAL)
-                             | 0x30);
+               b43_phy_set(dev, B43_PHY_RFOVERVAL, 0x30);
                trsw_rx = 0x1B;
                for (j = j - 8; j < 16; j++) {
-                       b43_phy_write(dev, B43_PHY_RFOVERVAL,
-                                     (b43_phy_read(dev, B43_PHY_RFOVERVAL)
-                                      & 0xF0FF) | (j << 8));
-                       b43_phy_write(dev, B43_PHY_PGACTL,
-                                     (b43_phy_read(dev, B43_PHY_PGACTL)
-                                      & 0x0FFF) | 0xA000);
-                       b43_phy_write(dev, B43_PHY_PGACTL,
-                                     b43_phy_read(dev, B43_PHY_PGACTL)
-                                     | 0xF000);
+                       b43_phy_maskset(dev, B43_PHY_RFOVERVAL, 0xF0FF, (j << 8));
+                       b43_phy_maskset(dev, B43_PHY_PGACTL, 0x0FFF, 0xA000);
+                       b43_phy_set(dev, B43_PHY_PGACTL, 0xF000);
                        udelay(20);
                        trsw_rx -= 3;
                        if (b43_phy_read(dev, B43_PHY_LO_LEAKAGE) >= 0xDFC)
@@ -2046,34 +1867,24 @@ static void b43_hardware_pctl_early_init(struct b43_wldev *dev)
                return;
        }
 
-       b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036) & 0xFEFF);
+       b43_phy_mask(dev, 0x0036, 0xFEFF);
        b43_phy_write(dev, 0x002F, 0x0202);
-       b43_phy_write(dev, 0x047C, b43_phy_read(dev, 0x047C) | 0x0002);
-       b43_phy_write(dev, 0x047A, b43_phy_read(dev, 0x047A) | 0xF000);
+       b43_phy_set(dev, 0x047C, 0x0002);
+       b43_phy_set(dev, 0x047A, 0xF000);
        if (phy->radio_ver == 0x2050 && phy->radio_rev == 8) {
-               b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A)
-                                           & 0xFF0F) | 0x0010);
-               b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D)
-                             | 0x8000);
-               b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E)
-                                           & 0xFFC0) | 0x0010);
+               b43_phy_maskset(dev, 0x047A, 0xFF0F, 0x0010);
+               b43_phy_set(dev, 0x005D, 0x8000);
+               b43_phy_maskset(dev, 0x004E, 0xFFC0, 0x0010);
                b43_phy_write(dev, 0x002E, 0xC07F);
-               b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
-                             | 0x0400);
+               b43_phy_set(dev, 0x0036, 0x0400);
        } else {
-               b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
-                             | 0x0200);
-               b43_phy_write(dev, 0x0036, b43_phy_read(dev, 0x0036)
-                             | 0x0400);
-               b43_phy_write(dev, 0x005D, b43_phy_read(dev, 0x005D)
-                             & 0x7FFF);
-               b43_phy_write(dev, 0x004F, b43_phy_read(dev, 0x004F)
-                             & 0xFFFE);
-               b43_phy_write(dev, 0x004E, (b43_phy_read(dev, 0x004E)
-                                           & 0xFFC0) | 0x0010);
+               b43_phy_set(dev, 0x0036, 0x0200);
+               b43_phy_set(dev, 0x0036, 0x0400);
+               b43_phy_mask(dev, 0x005D, 0x7FFF);
+               b43_phy_mask(dev, 0x004F, 0xFFFE);
+               b43_phy_maskset(dev, 0x004E, 0xFFC0, 0x0010);
                b43_phy_write(dev, 0x002E, 0xC07F);
-               b43_phy_write(dev, 0x047A, (b43_phy_read(dev, 0x047A)
-                                           & 0xFF0F) | 0x0010);
+               b43_phy_maskset(dev, 0x047A, 0xFF0F, 0x0010);
        }
 }
 
@@ -2089,22 +1900,17 @@ static void b43_hardware_pctl_init_gphy(struct b43_wldev *dev)
                return;
        }
 
-       b43_phy_write(dev, 0x0036, (b43_phy_read(dev, 0x0036) & 0xFFC0)
-                     | (gphy->tgt_idle_tssi - gphy->cur_idle_tssi));
-       b43_phy_write(dev, 0x0478, (b43_phy_read(dev, 0x0478) & 0xFF00)
-                     | (gphy->tgt_idle_tssi - gphy->cur_idle_tssi));
+       b43_phy_maskset(dev, 0x0036, 0xFFC0, (gphy->tgt_idle_tssi - gphy->cur_idle_tssi));
+       b43_phy_maskset(dev, 0x0478, 0xFF00, (gphy->tgt_idle_tssi - gphy->cur_idle_tssi));
        b43_gphy_tssi_power_lt_init(dev);
        b43_gphy_gain_lt_init(dev);
-       b43_phy_write(dev, 0x0060, b43_phy_read(dev, 0x0060) & 0xFFBF);
+       b43_phy_mask(dev, 0x0060, 0xFFBF);
        b43_phy_write(dev, 0x0014, 0x0000);
 
        B43_WARN_ON(phy->rev < 6);
-       b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478)
-                     | 0x0800);
-       b43_phy_write(dev, 0x0478, b43_phy_read(dev, 0x0478)
-                     & 0xFEFF);
-       b43_phy_write(dev, 0x0801, b43_phy_read(dev, 0x0801)
-                     & 0xFFBF);
+       b43_phy_set(dev, 0x0478, 0x0800);
+       b43_phy_mask(dev, 0x0478, 0xFEFF);
+       b43_phy_mask(dev, 0x0801, 0xFFBF);
 
        b43_gphy_dc_lt_init(dev, 1);
 
@@ -2139,9 +1945,7 @@ static void b43_phy_init_pctl(struct b43_wldev *dev)
        b43_hardware_pctl_early_init(dev);
        if (gphy->cur_idle_tssi == 0) {
                if (phy->radio_ver == 0x2050 && phy->analog == 0) {
-                       b43_radio_write16(dev, 0x0076,
-                                         (b43_radio_read16(dev, 0x0076)
-                                          & 0x00F7) | 0x0084);
+                       b43_radio_maskset(dev, 0x0076, 0x00F7, 0x0084);
                } else {
                        struct b43_rfatt rfatt;
                        struct b43_bbatt bbatt;
@@ -2174,9 +1978,7 @@ static void b43_phy_init_pctl(struct b43_wldev *dev)
                        }
                }
                if (phy->radio_ver == 0x2050 && phy->analog == 0) {
-                       b43_radio_write16(dev, 0x0076,
-                                         b43_radio_read16(dev, 0x0076)
-                                         & 0xFF7B);
+                       b43_radio_mask(dev, 0x0076, 0xFF7B);
                } else {
                        b43_set_txpower_g(dev, &old_bbatt,
                                          &old_rfatt, old_tx_control);
@@ -2220,20 +2022,14 @@ static void b43_phy_initg(struct b43_wldev *dev)
                        b43_phy_write(dev, B43_PHY_OFDM(0xC3), 0x8006);
                }
                if (tmp == 5) {
-                       b43_phy_write(dev, B43_PHY_OFDM(0xCC),
-                                     (b43_phy_read(dev, B43_PHY_OFDM(0xCC))
-                                      & 0x00FF) | 0x1F00);
+                       b43_phy_maskset(dev, B43_PHY_OFDM(0xCC), 0x00FF, 0x1F00);
                }
        }
        if ((phy->rev <= 2 && phy->gmode) || phy->rev >= 2)
                b43_phy_write(dev, B43_PHY_OFDM(0x7E), 0x78);
        if (phy->radio_rev == 8) {
-               b43_phy_write(dev, B43_PHY_EXTG(0x01),
-                             b43_phy_read(dev, B43_PHY_EXTG(0x01))
-                             | 0x80);
-               b43_phy_write(dev, B43_PHY_OFDM(0x3E),
-                             b43_phy_read(dev, B43_PHY_OFDM(0x3E))
-                             | 0x4);
+               b43_phy_set(dev, B43_PHY_EXTG(0x01), 0x80);
+               b43_phy_set(dev, B43_PHY_OFDM(0x3E), 0x4);
        }
        if (has_loopback_gain(phy))
                b43_calc_loopback_gain(dev);
@@ -2251,15 +2047,10 @@ static void b43_phy_initg(struct b43_wldev *dev)
                                  | gphy->lo_control->tx_bias | gphy->
                                  lo_control->tx_magn);
        } else {
-               b43_radio_write16(dev, 0x52,
-                                 (b43_radio_read16(dev, 0x52) & 0xFFF0)
-                                 | gphy->lo_control->tx_bias);
+               b43_radio_maskset(dev, 0x52, 0xFFF0, gphy->lo_control->tx_bias);
        }
        if (phy->rev >= 6) {
-               b43_phy_write(dev, B43_PHY_CCK(0x36),
-                             (b43_phy_read(dev, B43_PHY_CCK(0x36))
-                              & 0x0FFF) | (gphy->lo_control->
-                                           tx_bias << 12));
+               b43_phy_maskset(dev, B43_PHY_CCK(0x36), 0x0FFF, (gphy->lo_control->tx_bias << 12));
        }
        if (dev->dev->bus->sprom.boardflags_lo & B43_BFL_PACTRL)
                b43_phy_write(dev, B43_PHY_CCK(0x2E), 0x8075);
@@ -2298,11 +2089,8 @@ static void b43_phy_initg(struct b43_wldev *dev)
           but OFDM is legal everywhere */
        if ((dev->dev->bus->chip_id == 0x4306
             && dev->dev->bus->chip_package == 2) || 0) {
-               b43_phy_write(dev, B43_PHY_CRS0, b43_phy_read(dev, B43_PHY_CRS0)
-                             & 0xBFFF);
-               b43_phy_write(dev, B43_PHY_OFDM(0xC3),
-                             b43_phy_read(dev, B43_PHY_OFDM(0xC3))
-                             & 0x7FFF);
+               b43_phy_mask(dev, B43_PHY_CRS0, 0xBFFF);
+               b43_phy_mask(dev, B43_PHY_OFDM(0xC3), 0x7FFF);
        }
 }
 
@@ -2504,9 +2292,8 @@ static u8 b43_gphy_aci_scan(struct b43_wldev *dev)
 
        b43_phy_lock(dev);
        b43_radio_lock(dev);
-       b43_phy_write(dev, 0x0802, b43_phy_read(dev, 0x0802) & 0xFFFC);
-       b43_phy_write(dev, B43_PHY_G_CRS,
-                     b43_phy_read(dev, B43_PHY_G_CRS) & 0x7FFF);
+       b43_phy_mask(dev, 0x0802, 0xFFFC);
+       b43_phy_mask(dev, B43_PHY_G_CRS, 0x7FFF);
        b43_set_all_gains(dev, 3, 8, 1);
 
        start = (channel - 5 > 0) ? channel - 5 : 1;
@@ -2517,11 +2304,9 @@ static u8 b43_gphy_aci_scan(struct b43_wldev *dev)
                        ret[i - 1] = b43_gphy_aci_detect(dev, i);
        }
        b43_switch_channel(dev, channel);
-       b43_phy_write(dev, 0x0802,
-                     (b43_phy_read(dev, 0x0802) & 0xFFFC) | 0x0003);
-       b43_phy_write(dev, 0x0403, b43_phy_read(dev, 0x0403) & 0xFFF8);
-       b43_phy_write(dev, B43_PHY_G_CRS,
-                     b43_phy_read(dev, B43_PHY_G_CRS) | 0x8000);
+       b43_phy_maskset(dev, 0x0802, 0xFFFC, 0x0003);
+       b43_phy_mask(dev, 0x0403, 0xFFF8);
+       b43_phy_set(dev, B43_PHY_G_CRS, 0x8000);
        b43_set_original_gains(dev);
        for (i = 0; i < 13; i++) {
                if (!ret[i])
@@ -2565,8 +2350,8 @@ static s8 b43_tssi2dbm_entry(s8 entry[], u8 index,
        return 0;
 }
 
-u8 * b43_generate_dyn_tssi2dbm_tab(struct b43_wldev *dev,
-                                  s16 pab0, s16 pab1, s16 pab2)
+u8 *b43_generate_dyn_tssi2dbm_tab(struct b43_wldev *dev,
+                                 s16 pab0, s16 pab1, s16 pab2)
 {
        unsigned int i;
        u8 *tab;
index 1036bef8c4cc398e0fe72c16e09c4b43f67c45a3..8cd9776752e691407763318599cf1e38660c5f3c 100644 (file)
@@ -55,8 +55,8 @@ static u16 generate_cookie(struct b43_pio_txqueue *q,
 }
 
 static
-struct b43_pio_txqueue * parse_cookie(struct b43_wldev *dev,
-                                     u16 cookie,
+struct b43_pio_txqueue *parse_cookie(struct b43_wldev *dev,
+                                    u16 cookie,
                                      struct b43_pio_txpacket **pack)
 {
        struct b43_pio *pio = &dev->pio;
@@ -134,8 +134,8 @@ static u16 pio_rxqueue_offset(struct b43_wldev *dev)
        return 8;
 }
 
-static struct b43_pio_txqueue * b43_setup_pioqueue_tx(struct b43_wldev *dev,
-                                                     unsigned int index)
+static struct b43_pio_txqueue *b43_setup_pioqueue_tx(struct b43_wldev *dev,
+                                                    unsigned int index)
 {
        struct b43_pio_txqueue *q;
        struct b43_pio_txpacket *p;
@@ -171,8 +171,8 @@ static struct b43_pio_txqueue * b43_setup_pioqueue_tx(struct b43_wldev *dev,
        return q;
 }
 
-static struct b43_pio_rxqueue * b43_setup_pioqueue_rx(struct b43_wldev *dev,
-                                                     unsigned int index)
+static struct b43_pio_rxqueue *b43_setup_pioqueue_rx(struct b43_wldev *dev,
+                                                    unsigned int index)
 {
        struct b43_pio_rxqueue *q;
 
@@ -308,8 +308,8 @@ err_destroy_bk:
 }
 
 /* Static mapping of mac80211's queues (priorities) to b43 PIO queues. */
-static struct b43_pio_txqueue * select_queue_by_priority(struct b43_wldev *dev,
-                                                        u8 queue_prio)
+static struct b43_pio_txqueue *select_queue_by_priority(struct b43_wldev *dev,
+                                                       u8 queue_prio)
 {
        struct b43_pio_txqueue *q;
 
index 713753781f4007eb44ec93090f40c27e452474a1..afad423586931ed618c6ea32445c4df17987b0e2 100644 (file)
@@ -113,7 +113,7 @@ out_unlock:
        return err;
 }
 
-char * b43_rfkill_led_name(struct b43_wldev *dev)
+char *b43_rfkill_led_name(struct b43_wldev *dev)
 {
        struct b43_rfkill *rfk = &(dev->wl->rfkill);
 
index 0c0fb15abb9f0fabfcf89d034fde3e20116f940a..e1e20f69f6d705cf27bbf025d19f0007343cfb35 100644 (file)
@@ -62,8 +62,7 @@ void b43_wa_initgains(struct b43_wldev *dev)
        struct b43_phy *phy = &dev->phy;
 
        b43_phy_write(dev, B43_PHY_LNAHPFCTL, 0x1FF9);
-       b43_phy_write(dev, B43_PHY_LPFGAINCTL,
-               b43_phy_read(dev, B43_PHY_LPFGAINCTL) & 0xFF0F);
+       b43_phy_mask(dev, B43_PHY_LPFGAINCTL, 0xFF0F);
        if (phy->rev <= 2)
                b43_ofdmtab_write16(dev, B43_OFDMTAB_LPFGAIN, 0, 0x1FBF);
        b43_radio_write16(dev, 0x0002, 0x1FBF);
@@ -73,11 +72,9 @@ void b43_wa_initgains(struct b43_wldev *dev)
        b43_phy_write(dev, 0x001D, 0x0F40);
        b43_phy_write(dev, 0x001F, 0x1C00);
        if (phy->rev <= 3)
-               b43_phy_write(dev, 0x002A,
-                       (b43_phy_read(dev, 0x002A) & 0x00FF) | 0x0400);
+               b43_phy_maskset(dev, 0x002A, 0x00FF, 0x0400);
        else if (phy->rev == 5) {
-               b43_phy_write(dev, 0x002A,
-                       (b43_phy_read(dev, 0x002A) & 0x00FF) | 0x1A00);
+               b43_phy_maskset(dev, 0x002A, 0x00FF, 0x1A00);
                b43_phy_write(dev, 0x00CC, 0x2121);
        }
        if (phy->rev >= 3)
@@ -86,7 +83,7 @@ void b43_wa_initgains(struct b43_wldev *dev)
 
 static void b43_wa_divider(struct b43_wldev *dev)
 {
-       b43_phy_write(dev, 0x002B, b43_phy_read(dev, 0x002B) & ~0x0100);
+       b43_phy_mask(dev, 0x002B, ~0x0100);
        b43_phy_write(dev, 0x008E, 0x58C1);
 }
 
@@ -272,8 +269,7 @@ static void b43_wa_2060txlna_gain(struct b43_wldev *dev)
 
 static void b43_wa_lms(struct b43_wldev *dev)
 {
-       b43_phy_write(dev, 0x0055,
-               (b43_phy_read(dev, 0x0055) & 0xFFC0) | 0x0004);
+       b43_phy_maskset(dev, 0x0055, 0xFFC0, 0x0004);
 }
 
 static void b43_wa_mixedsignal(struct b43_wldev *dev)
@@ -318,23 +314,18 @@ static void b43_wa_crs_ed(struct b43_wldev *dev)
        } else if (phy->rev == 2) {
                b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x1861);
                b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0271);
-               b43_phy_write(dev, B43_PHY_ANTDWELL,
-                                 b43_phy_read(dev, B43_PHY_ANTDWELL)
-                                 | 0x0800);
+               b43_phy_set(dev, B43_PHY_ANTDWELL, 0x0800);
        } else {
                b43_phy_write(dev, B43_PHY_CRSTHRES1, 0x0098);
                b43_phy_write(dev, B43_PHY_CRSTHRES2, 0x0070);
                b43_phy_write(dev, B43_PHY_OFDM(0xC9), 0x0080);
-               b43_phy_write(dev, B43_PHY_ANTDWELL,
-                                 b43_phy_read(dev, B43_PHY_ANTDWELL)
-                                 | 0x0800);
+               b43_phy_set(dev, B43_PHY_ANTDWELL, 0x0800);
        }
 }
 
 static void b43_wa_crs_thr(struct b43_wldev *dev)
 {
-       b43_phy_write(dev, B43_PHY_CRS0,
-                       (b43_phy_read(dev, B43_PHY_CRS0) & ~0x03C0) | 0xD000);
+       b43_phy_maskset(dev, B43_PHY_CRS0, ~0x03C0, 0xD000);
 }
 
 static void b43_wa_crs_blank(struct b43_wldev *dev)
@@ -391,72 +382,45 @@ static void b43_wa_altagc(struct b43_wldev *dev)
                b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC1, 3, 25);
        }
 
-       b43_phy_write(dev, B43_PHY_CCKSHIFTBITS_WA,
-               (b43_phy_read(dev, B43_PHY_CCKSHIFTBITS_WA) & ~0xFF00) | 0x5700);
-       b43_phy_write(dev, B43_PHY_OFDM(0x1A),
-               (b43_phy_read(dev, B43_PHY_OFDM(0x1A)) & ~0x007F) | 0x000F);
-       b43_phy_write(dev, B43_PHY_OFDM(0x1A),
-               (b43_phy_read(dev, B43_PHY_OFDM(0x1A)) & ~0x3F80) | 0x2B80);
-       b43_phy_write(dev, B43_PHY_ANTWRSETT,
-               (b43_phy_read(dev, B43_PHY_ANTWRSETT) & 0xF0FF) | 0x0300);
-       b43_radio_write16(dev, 0x7A,
-               b43_radio_read16(dev, 0x7A) | 0x0008);
-       b43_phy_write(dev, B43_PHY_N1P1GAIN,
-               (b43_phy_read(dev, B43_PHY_N1P1GAIN) & ~0x000F) | 0x0008);
-       b43_phy_write(dev, B43_PHY_P1P2GAIN,
-               (b43_phy_read(dev, B43_PHY_P1P2GAIN) & ~0x0F00) | 0x0600);
-       b43_phy_write(dev, B43_PHY_N1N2GAIN,
-               (b43_phy_read(dev, B43_PHY_N1N2GAIN) & ~0x0F00) | 0x0700);
-       b43_phy_write(dev, B43_PHY_N1P1GAIN,
-               (b43_phy_read(dev, B43_PHY_N1P1GAIN) & ~0x0F00) | 0x0100);
+       b43_phy_maskset(dev, B43_PHY_CCKSHIFTBITS_WA, (u16)~0xFF00, 0x5700);
+       b43_phy_maskset(dev, B43_PHY_OFDM(0x1A), ~0x007F, 0x000F);
+       b43_phy_maskset(dev, B43_PHY_OFDM(0x1A), ~0x3F80, 0x2B80);
+       b43_phy_maskset(dev, B43_PHY_ANTWRSETT, 0xF0FF, 0x0300);
+       b43_radio_set(dev, 0x7A, 0x0008);
+       b43_phy_maskset(dev, B43_PHY_N1P1GAIN, ~0x000F, 0x0008);
+       b43_phy_maskset(dev, B43_PHY_P1P2GAIN, ~0x0F00, 0x0600);
+       b43_phy_maskset(dev, B43_PHY_N1N2GAIN, ~0x0F00, 0x0700);
+       b43_phy_maskset(dev, B43_PHY_N1P1GAIN, ~0x0F00, 0x0100);
        if (phy->rev == 1) {
-               b43_phy_write(dev, B43_PHY_N1N2GAIN,
-                                 (b43_phy_read(dev, B43_PHY_N1N2GAIN)
-                                  & ~0x000F) | 0x0007);
+               b43_phy_maskset(dev, B43_PHY_N1N2GAIN, ~0x000F, 0x0007);
        }
-       b43_phy_write(dev, B43_PHY_OFDM(0x88),
-               (b43_phy_read(dev, B43_PHY_OFDM(0x88)) & ~0x00FF) | 0x001C);
-       b43_phy_write(dev, B43_PHY_OFDM(0x88),
-               (b43_phy_read(dev, B43_PHY_OFDM(0x88)) & ~0x3F00) | 0x0200);
-       b43_phy_write(dev, B43_PHY_OFDM(0x96),
-               (b43_phy_read(dev, B43_PHY_OFDM(0x96)) & ~0x00FF) | 0x001C);
-       b43_phy_write(dev, B43_PHY_OFDM(0x89),
-               (b43_phy_read(dev, B43_PHY_OFDM(0x89)) & ~0x00FF) | 0x0020);
-       b43_phy_write(dev, B43_PHY_OFDM(0x89),
-               (b43_phy_read(dev, B43_PHY_OFDM(0x89)) & ~0x3F00) | 0x0200);
-       b43_phy_write(dev, B43_PHY_OFDM(0x82),
-               (b43_phy_read(dev, B43_PHY_OFDM(0x82)) & ~0x00FF) | 0x002E);
-       b43_phy_write(dev, B43_PHY_OFDM(0x96),
-               (b43_phy_read(dev, B43_PHY_OFDM(0x96)) & ~0xFF00) | 0x1A00);
-       b43_phy_write(dev, B43_PHY_OFDM(0x81),
-               (b43_phy_read(dev, B43_PHY_OFDM(0x81)) & ~0x00FF) | 0x0028);
-       b43_phy_write(dev, B43_PHY_OFDM(0x81),
-               (b43_phy_read(dev, B43_PHY_OFDM(0x81)) & ~0xFF00) | 0x2C00);
+       b43_phy_maskset(dev, B43_PHY_OFDM(0x88), ~0x00FF, 0x001C);
+       b43_phy_maskset(dev, B43_PHY_OFDM(0x88), ~0x3F00, 0x0200);
+       b43_phy_maskset(dev, B43_PHY_OFDM(0x96), ~0x00FF, 0x001C);
+       b43_phy_maskset(dev, B43_PHY_OFDM(0x89), ~0x00FF, 0x0020);
+       b43_phy_maskset(dev, B43_PHY_OFDM(0x89), ~0x3F00, 0x0200);
+       b43_phy_maskset(dev, B43_PHY_OFDM(0x82), ~0x00FF, 0x002E);
+       b43_phy_maskset(dev, B43_PHY_OFDM(0x96), (u16)~0xFF00, 0x1A00);
+       b43_phy_maskset(dev, B43_PHY_OFDM(0x81), ~0x00FF, 0x0028);
+       b43_phy_maskset(dev, B43_PHY_OFDM(0x81), (u16)~0xFF00, 0x2C00);
        if (phy->rev == 1) {
                b43_phy_write(dev, B43_PHY_PEAK_COUNT, 0x092B);
-               b43_phy_write(dev, B43_PHY_OFDM(0x1B),
-                       (b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x001E) | 0x0002);
+               b43_phy_maskset(dev, B43_PHY_OFDM(0x1B), ~0x001E, 0x0002);
        } else {
-               b43_phy_write(dev, B43_PHY_OFDM(0x1B),
-                       b43_phy_read(dev, B43_PHY_OFDM(0x1B)) & ~0x001E);
+               b43_phy_mask(dev, B43_PHY_OFDM(0x1B), ~0x001E);
                b43_phy_write(dev, B43_PHY_OFDM(0x1F), 0x287A);
-               b43_phy_write(dev, B43_PHY_LPFGAINCTL,
-                       (b43_phy_read(dev, B43_PHY_LPFGAINCTL) & ~0x000F) | 0x0004);
+               b43_phy_maskset(dev, B43_PHY_LPFGAINCTL, ~0x000F, 0x0004);
                if (phy->rev >= 6) {
                        b43_phy_write(dev, B43_PHY_OFDM(0x22), 0x287A);
-                       b43_phy_write(dev, B43_PHY_LPFGAINCTL,
-                               (b43_phy_read(dev, B43_PHY_LPFGAINCTL) & ~0xF000) | 0x3000);
+                       b43_phy_maskset(dev, B43_PHY_LPFGAINCTL, (u16)~0xF000, 0x3000);
                }
        }
-       b43_phy_write(dev, B43_PHY_DIVSRCHIDX,
-               (b43_phy_read(dev, B43_PHY_DIVSRCHIDX) & 0x8080) | 0x7874);
+       b43_phy_maskset(dev, B43_PHY_DIVSRCHIDX, 0x8080, 0x7874);
        b43_phy_write(dev, B43_PHY_OFDM(0x8E), 0x1C00);
        if (phy->rev == 1) {
-               b43_phy_write(dev, B43_PHY_DIVP1P2GAIN,
-                       (b43_phy_read(dev, B43_PHY_DIVP1P2GAIN) & ~0x0F00) | 0x0600);
+               b43_phy_maskset(dev, B43_PHY_DIVP1P2GAIN, ~0x0F00, 0x0600);
                b43_phy_write(dev, B43_PHY_OFDM(0x8B), 0x005E);
-               b43_phy_write(dev, B43_PHY_ANTWRSETT,
-                       (b43_phy_read(dev, B43_PHY_ANTWRSETT) & ~0x00FF) | 0x001E);
+               b43_phy_maskset(dev, B43_PHY_ANTWRSETT, ~0x00FF, 0x001E);
                b43_phy_write(dev, B43_PHY_OFDM(0x8D), 0x0002);
                b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 0, 0);
                b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3_R1, 1, 7);
@@ -469,10 +433,8 @@ static void b43_wa_altagc(struct b43_wldev *dev)
                b43_ofdmtab_write16(dev, B43_OFDMTAB_AGC3, 3, 28);
        }
        if (phy->rev >= 6) {
-               b43_phy_write(dev, B43_PHY_OFDM(0x26),
-                       b43_phy_read(dev, B43_PHY_OFDM(0x26)) & ~0x0003);
-               b43_phy_write(dev, B43_PHY_OFDM(0x26),
-                       b43_phy_read(dev, B43_PHY_OFDM(0x26)) & ~0x1000);
+               b43_phy_mask(dev, B43_PHY_OFDM(0x26), ~0x0003);
+               b43_phy_mask(dev, B43_PHY_OFDM(0x26), ~0x1000);
        }
        b43_phy_read(dev, B43_PHY_VERSION_OFDM); /* Dummy read */
 }
@@ -538,8 +500,7 @@ static void b43_wa_boards_g(struct b43_wldev *dev)
                        b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 2, 0x0001);
                        if ((bus->sprom.boardflags_lo & B43_BFL_EXTLNA) &&
                            (phy->rev >= 7)) {
-                               b43_phy_write(dev, B43_PHY_EXTG(0x11),
-                                       b43_phy_read(dev, B43_PHY_EXTG(0x11)) & 0xF7FF);
+                               b43_phy_mask(dev, B43_PHY_EXTG(0x11), 0xF7FF);
                                b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0020, 0x0001);
                                b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0021, 0x0001);
                                b43_ofdmtab_write16(dev, B43_OFDMTAB_GAINX, 0x0022, 0x0001);
index eae9b8052658c3c28de328df9016a0bb82917ff8..0f53c7e5e01e99d1377993acb772958cb2f6117e 100644 (file)
@@ -538,8 +538,14 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
        chanstat = le16_to_cpu(rxhdr->channel);
        phytype = chanstat & B43_RX_CHAN_PHYTYPE;
 
-       if (macstat & B43_RX_MAC_FCSERR)
+       if (unlikely(macstat & B43_RX_MAC_FCSERR)) {
                dev->wl->ieee_stats.dot11FCSErrorCount++;
+               status.flag |= RX_FLAG_FAILED_FCS_CRC;
+       }
+       if (unlikely(phystat0 & (B43_RX_PHYST0_PLCPHCF | B43_RX_PHYST0_PLCPFV)))
+               status.flag |= RX_FLAG_FAILED_PLCP_CRC;
+       if (phystat0 & B43_RX_PHYST0_SHORTPRMBL)
+               status.flag |= RX_FLAG_SHORTPRE;
        if (macstat & B43_RX_MAC_DECERR) {
                /* Decryption with the given key failed.
                 * Drop the packet. We also won't be able to decrypt it with
@@ -606,8 +612,12 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
                                                phytype == B43_PHYTYPE_A);
        else
                status.rate_idx = b43_plcp_get_bitrate_idx_cck(plcp);
-       if (unlikely(status.rate_idx == -1))
-               goto drop;
+       if (unlikely(status.rate_idx == -1)) {
+               /* PLCP seems to be corrupted.
+                * Drop the frame, if we are not interested in corrupted frames. */
+               if (!(dev->wl->filter_flags & FIF_PLCPFAIL))
+                       goto drop;
+       }
        status.antenna = !!(phystat0 & B43_RX_PHYST0_ANT);
 
        /*
@@ -661,7 +671,6 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
                goto drop;
        }
 
-       dev->stats.last_rx = jiffies;
        ieee80211_rx_irqsafe(dev->wl->hw, skb, &status);
 
        return;
index 2453deaa3e009e03faab3f92850d012f6f808bbf..ce8721fbc10eec99689fddfde74074ef515f3e26 100644 (file)
@@ -31,7 +31,7 @@ void hostap_dump_rx_header(const char *name,
 void hostap_dump_tx_header(const char *name,
                           const struct hfa384x_tx_frame *tx);
 extern const struct header_ops hostap_80211_ops;
-int hostap_80211_get_hdrlen(u16 fc);
+int hostap_80211_get_hdrlen(__le16 fc);
 struct net_device_stats *hostap_get_stats(struct net_device *dev);
 void hostap_setup_dev(struct net_device *dev, local_info_t *local,
                      int type);
index 3a9474d9a90780b7bbde1b83e2c91f14cd3b27bd..2e9fb0f383fc3bb60f65bd50b53d339f1ee914a2 100644 (file)
@@ -2,7 +2,7 @@
 #define HOSTAP_80211_H
 
 #include <linux/types.h>
-#include <net/ieee80211.h>
+#include <linux/skbuff.h>
 
 struct hostap_ieee80211_mgmt {
        __le16 frame_control;
index 241756318da481c0f038f55b9b395ef4222b9022..3816df96a663e0f544dcf6a53694d8bcf1c33895 100644 (file)
@@ -1,5 +1,6 @@
 #include <linux/etherdevice.h>
 #include <net/lib80211.h>
+#include <linux/if_arp.h>
 
 #include "hostap_80211.h"
 #include "hostap.h"
@@ -17,10 +18,10 @@ static unsigned char bridge_tunnel_header[] =
 void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
                          struct hostap_80211_rx_status *rx_stats)
 {
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
        u16 fc;
 
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
+       hdr = (struct ieee80211_hdr *) skb->data;
 
        printk(KERN_DEBUG "%s: RX signal=%d noise=%d rate=%d len=%d "
               "jiffies=%ld\n",
@@ -30,9 +31,10 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
        if (skb->len < 2)
                return;
 
-       fc = le16_to_cpu(hdr->frame_ctl);
+       fc = le16_to_cpu(hdr->frame_control);
        printk(KERN_DEBUG "   FC=0x%04x (type=%d:%d)%s%s",
-              fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4,
+              fc, (fc & IEEE80211_FCTL_FTYPE) >> 2,
+              (fc & IEEE80211_FCTL_STYPE) >> 4,
               fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
               fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
 
@@ -42,7 +44,7 @@ void hostap_dump_rx_80211(const char *name, struct sk_buff *skb,
        }
 
        printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
-              le16_to_cpu(hdr->seq_ctl));
+              le16_to_cpu(hdr->seq_ctrl));
 
        printk(KERN_DEBUG "   A1=%pM", hdr->addr1);
        printk(" A2=%pM", hdr->addr2);
@@ -63,7 +65,7 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
        int hdrlen, phdrlen, head_need, tail_need;
        u16 fc;
        int prism_header, ret;
-       struct ieee80211_hdr_4addr *fhdr;
+       struct ieee80211_hdr *fhdr;
 
        iface = netdev_priv(dev);
        local = iface->local;
@@ -84,8 +86,8 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
                phdrlen = 0;
        }
 
-       fhdr = (struct ieee80211_hdr_4addr *) skb->data;
-       fc = le16_to_cpu(fhdr->frame_ctl);
+       fhdr = (struct ieee80211_hdr *) skb->data;
+       fc = le16_to_cpu(fhdr->frame_control);
 
        if (type == PRISM2_RX_MGMT && (fc & IEEE80211_FCTL_VERS)) {
                printk(KERN_DEBUG "%s: dropped management frame with header "
@@ -94,7 +96,7 @@ int prism2_rx_80211(struct net_device *dev, struct sk_buff *skb,
                return 0;
        }
 
-       hdrlen = hostap_80211_get_hdrlen(fc);
+       hdrlen = hostap_80211_get_hdrlen(fhdr->frame_control);
 
        /* check if there is enough room for extra data; if not, expand skb
         * buffer to be large enough for the changes */
@@ -205,13 +207,11 @@ hdr->f.status = s; hdr->f.len = l; hdr->f.data = d
 static void monitor_rx(struct net_device *dev, struct sk_buff *skb,
                       struct hostap_80211_rx_status *rx_stats)
 {
-       struct net_device_stats *stats;
        int len;
 
        len = prism2_rx_80211(dev, skb, rx_stats, PRISM2_RX_MONITOR);
-       stats = hostap_get_stats(dev);
-       stats->rx_packets++;
-       stats->rx_bytes += len;
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += len;
 }
 
 
@@ -247,21 +247,21 @@ prism2_frag_cache_find(local_info_t *local, unsigned int seq,
 
 /* Called only as a tasklet (software IRQ) */
 static struct sk_buff *
-prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr_4addr *hdr)
+prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr *hdr)
 {
        struct sk_buff *skb = NULL;
        u16 sc;
        unsigned int frag, seq;
        struct prism2_frag_entry *entry;
 
-       sc = le16_to_cpu(hdr->seq_ctl);
-       frag = WLAN_GET_SEQ_FRAG(sc);
-       seq = WLAN_GET_SEQ_SEQ(sc) >> 4;
+       sc = le16_to_cpu(hdr->seq_ctrl);
+       frag = sc & IEEE80211_SCTL_FRAG;
+       seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
 
        if (frag == 0) {
                /* Reserve enough space to fit maximum frame length */
                skb = dev_alloc_skb(local->dev->mtu +
-                                   sizeof(struct ieee80211_hdr_4addr) +
+                                   sizeof(struct ieee80211_hdr) +
                                    8 /* LLC */ +
                                    2 /* alignment */ +
                                    8 /* WEP */ + ETH_ALEN /* WDS */);
@@ -299,14 +299,14 @@ prism2_frag_cache_get(local_info_t *local, struct ieee80211_hdr_4addr *hdr)
 
 /* Called only as a tasklet (software IRQ) */
 static int prism2_frag_cache_invalidate(local_info_t *local,
-                                       struct ieee80211_hdr_4addr *hdr)
+                                       struct ieee80211_hdr *hdr)
 {
        u16 sc;
        unsigned int seq;
        struct prism2_frag_entry *entry;
 
-       sc = le16_to_cpu(hdr->seq_ctl);
-       seq = WLAN_GET_SEQ_SEQ(sc) >> 4;
+       sc = le16_to_cpu(hdr->seq_ctrl);
+       seq = (sc & IEEE80211_SCTL_SEQ) >> 4;
 
        entry = prism2_frag_cache_find(local, seq, -1, hdr->addr2, hdr->addr1);
 
@@ -472,10 +472,8 @@ hostap_rx_frame_mgmt(local_info_t *local, struct sk_buff *skb,
                     struct hostap_80211_rx_status *rx_stats, u16 type,
                     u16 stype)
 {
-       if (local->iw_mode == IW_MODE_MASTER) {
-               hostap_update_sta_ps(local, (struct ieee80211_hdr_4addr *)
-                                    skb->data);
-       }
+       if (local->iw_mode == IW_MODE_MASTER)
+               hostap_update_sta_ps(local, (struct ieee80211_hdr *) skb->data);
 
        if (local->hostapd && type == IEEE80211_FTYPE_MGMT) {
                if (stype == IEEE80211_STYPE_BEACON &&
@@ -552,8 +550,8 @@ static struct net_device *prism2_rx_get_wds(local_info_t *local,
 
 
 static int
-hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
-                   u16 fc, struct net_device **wds)
+hostap_rx_frame_wds(local_info_t *local, struct ieee80211_hdr *hdr, u16 fc,
+                   struct net_device **wds)
 {
        /* FIX: is this really supposed to accept WDS frames only in Master
         * mode? What about Repeater or Managed with WDS frames? */
@@ -611,14 +609,14 @@ static int hostap_is_eapol_frame(local_info_t *local, struct sk_buff *skb)
 {
        struct net_device *dev = local->dev;
        u16 fc, ethertype;
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
        u8 *pos;
 
        if (skb->len < 24)
                return 0;
 
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
-       fc = le16_to_cpu(hdr->frame_ctl);
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = le16_to_cpu(hdr->frame_control);
 
        /* check that the frame is unicast frame to us */
        if ((fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
@@ -651,14 +649,14 @@ static int
 hostap_rx_frame_decrypt(local_info_t *local, struct sk_buff *skb,
                        struct lib80211_crypt_data *crypt)
 {
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
        int res, hdrlen;
 
        if (crypt == NULL || crypt->ops->decrypt_mpdu == NULL)
                return 0;
 
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
-       hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+       hdr = (struct ieee80211_hdr *) skb->data;
+       hdrlen = hostap_80211_get_hdrlen(hdr->frame_control);
 
        if (local->tkip_countermeasures &&
            strcmp(crypt->ops->name, "TKIP") == 0) {
@@ -689,14 +687,14 @@ static int
 hostap_rx_frame_decrypt_msdu(local_info_t *local, struct sk_buff *skb,
                             int keyidx, struct lib80211_crypt_data *crypt)
 {
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
        int res, hdrlen;
 
        if (crypt == NULL || crypt->ops->decrypt_msdu == NULL)
                return 0;
 
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
-       hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(hdr->frame_ctl));
+       hdr = (struct ieee80211_hdr *) skb->data;
+       hdrlen = hostap_80211_get_hdrlen(hdr->frame_control);
 
        atomic_inc(&crypt->refcnt);
        res = crypt->ops->decrypt_msdu(skb, keyidx, hdrlen, crypt->priv);
@@ -720,11 +718,10 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
 {
        struct hostap_interface *iface;
        local_info_t *local;
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
        size_t hdrlen;
        u16 fc, type, stype, sc;
        struct net_device *wds = NULL;
-       struct net_device_stats *stats;
        unsigned int frag;
        u8 *payload;
        struct sk_buff *skb2 = NULL;
@@ -747,18 +744,17 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
        dev = local->ddev;
        iface = netdev_priv(dev);
 
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
-       stats = hostap_get_stats(dev);
+       hdr = (struct ieee80211_hdr *) skb->data;
 
        if (skb->len < 10)
                goto rx_dropped;
 
-       fc = le16_to_cpu(hdr->frame_ctl);
-       type = WLAN_FC_GET_TYPE(fc);
-       stype = WLAN_FC_GET_STYPE(fc);
-       sc = le16_to_cpu(hdr->seq_ctl);
-       frag = WLAN_GET_SEQ_FRAG(sc);
-       hdrlen = hostap_80211_get_hdrlen(fc);
+       fc = le16_to_cpu(hdr->frame_control);
+       type = fc & IEEE80211_FCTL_FTYPE;
+       stype = fc & IEEE80211_FCTL_STYPE;
+       sc = le16_to_cpu(hdr->seq_ctrl);
+       frag = sc & IEEE80211_SCTL_FRAG;
+       hdrlen = hostap_80211_get_hdrlen(hdr->frame_control);
 
        /* Put this code here so that we avoid duplicating it in all
         * Rx paths. - Jean II */
@@ -866,10 +862,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
 
        if (hostap_rx_frame_wds(local, hdr, fc, &wds))
                goto rx_dropped;
-       if (wds) {
+       if (wds)
                skb->dev = dev = wds;
-               stats = hostap_get_stats(dev);
-       }
 
        if (local->iw_mode == IW_MODE_MASTER && !wds &&
            (fc & (IEEE80211_FCTL_TODS | IEEE80211_FCTL_FROMDS)) ==
@@ -878,7 +872,6 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
            memcmp(hdr->addr2, local->assoc_ap_addr, ETH_ALEN) == 0) {
                /* Frame from BSSID of the AP for which we are a client */
                skb->dev = dev = local->stadev;
-               stats = hostap_get_stats(dev);
                from_assoc_ap = 1;
        }
 
@@ -918,7 +911,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
        if (local->host_decrypt && (fc & IEEE80211_FCTL_PROTECTED) &&
            (keyidx = hostap_rx_frame_decrypt(local, skb, crypt)) < 0)
                goto rx_dropped;
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
+       hdr = (struct ieee80211_hdr *) skb->data;
 
        /* skb: hdr + (possibly fragmented) plaintext payload */
 
@@ -931,7 +924,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
                        printk(KERN_DEBUG "%s: Rx cannot get skb from "
                               "fragment cache (morefrag=%d seq=%u frag=%u)\n",
                               dev->name, (fc & IEEE80211_FCTL_MOREFRAGS) != 0,
-                              WLAN_GET_SEQ_SEQ(sc) >> 4, frag);
+                              (sc & IEEE80211_SCTL_SEQ) >> 4, frag);
                        goto rx_dropped;
                }
 
@@ -972,7 +965,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
                /* this was the last fragment and the frame will be
                 * delivered, so remove skb from fragment cache */
                skb = frag_skb;
-               hdr = (struct ieee80211_hdr_4addr *) skb->data;
+               hdr = (struct ieee80211_hdr *) skb->data;
                prism2_frag_cache_invalidate(local, hdr);
        }
 
@@ -983,7 +976,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
            hostap_rx_frame_decrypt_msdu(local, skb, keyidx, crypt))
                goto rx_dropped;
 
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
+       hdr = (struct ieee80211_hdr *) skb->data;
        if (crypt && !(fc & IEEE80211_FCTL_PROTECTED) && !local->open_wep) {
                if (local->ieee_802_1x &&
                    hostap_is_eapol_frame(local, skb)) {
@@ -1069,8 +1062,8 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
                skb_trim(skb, skb->len - ETH_ALEN);
        }
 
-       stats->rx_packets++;
-       stats->rx_bytes += skb->len;
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += skb->len;
 
        if (local->iw_mode == IW_MODE_MASTER && !wds &&
            local->ap->bridge_packets) {
@@ -1115,7 +1108,7 @@ void hostap_80211_rx(struct net_device *dev, struct sk_buff *skb,
  rx_dropped:
        dev_kfree_skb(skb);
 
-       stats->rx_dropped++;
+       dev->stats.rx_dropped++;
        goto rx_exit;
 }
 
index 078a010f39a0835c765d5e706f7f53600aa8d30a..6693423f63feb3b032681276af06ed5666e89927 100644 (file)
@@ -15,10 +15,10 @@ static unsigned char bridge_tunnel_header[] =
 
 void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
 {
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
        u16 fc;
 
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
+       hdr = (struct ieee80211_hdr *) skb->data;
 
        printk(KERN_DEBUG "%s: TX len=%d jiffies=%ld\n",
               name, skb->len, jiffies);
@@ -26,9 +26,10 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
        if (skb->len < 2)
                return;
 
-       fc = le16_to_cpu(hdr->frame_ctl);
+       fc = le16_to_cpu(hdr->frame_control);
        printk(KERN_DEBUG "   FC=0x%04x (type=%d:%d)%s%s",
-              fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4,
+              fc, (fc & IEEE80211_FCTL_FTYPE) >> 2,
+              (fc & IEEE80211_FCTL_STYPE) >> 4,
               fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
               fc & IEEE80211_FCTL_FROMDS ? " [FromDS]" : "");
 
@@ -38,7 +39,7 @@ void hostap_dump_tx_80211(const char *name, struct sk_buff *skb)
        }
 
        printk(" dur=0x%04x seq=0x%04x\n", le16_to_cpu(hdr->duration_id),
-              le16_to_cpu(hdr->seq_ctl));
+              le16_to_cpu(hdr->seq_ctrl));
 
        printk(KERN_DEBUG "   A1=%pM", hdr->addr1);
        printk(" A2=%pM", hdr->addr2);
@@ -57,7 +58,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct hostap_interface *iface;
        local_info_t *local;
        int need_headroom, need_tailroom = 0;
-       struct ieee80211_hdr_4addr hdr;
+       struct ieee80211_hdr hdr;
        u16 fc, ethertype = 0;
        enum {
                WDS_NO = 0, WDS_OWN_FRAME, WDS_COMPLIANT_FRAME
@@ -201,7 +202,7 @@ int hostap_data_start_xmit(struct sk_buff *skb, struct net_device *dev)
                memcpy(&hdr.addr3, local->bssid, ETH_ALEN);
        }
 
-       hdr.frame_ctl = cpu_to_le16(fc);
+       hdr.frame_control = cpu_to_le16(fc);
 
        skb_pull(skb, skip_header_bytes);
        need_headroom = local->func->need_tx_headroom + hdr_len + encaps_len;
@@ -265,7 +266,7 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct hostap_interface *iface;
        local_info_t *local;
        struct hostap_skb_tx_data *meta;
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
        u16 fc;
 
        iface = netdev_priv(dev);
@@ -287,10 +288,10 @@ int hostap_mgmt_start_xmit(struct sk_buff *skb, struct net_device *dev)
        meta->iface = iface;
 
        if (skb->len >= IEEE80211_DATA_HDR3_LEN + sizeof(rfc1042_header) + 2) {
-               hdr = (struct ieee80211_hdr_4addr *) skb->data;
-               fc = le16_to_cpu(hdr->frame_ctl);
-               if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&
-                   WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_DATA) {
+               hdr = (struct ieee80211_hdr *) skb->data;
+               fc = le16_to_cpu(hdr->frame_control);
+               if (ieee80211_is_data(hdr->frame_control) &&
+                   (fc & IEEE80211_FCTL_STYPE) == IEEE80211_STYPE_DATA) {
                        u8 *pos = &skb->data[IEEE80211_DATA_HDR3_LEN +
                                             sizeof(rfc1042_header)];
                        meta->ethertype = (pos[0] << 8) | pos[1];
@@ -310,8 +311,7 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
 {
        struct hostap_interface *iface;
        local_info_t *local;
-       struct ieee80211_hdr_4addr *hdr;
-       u16 fc;
+       struct ieee80211_hdr *hdr;
        int prefix_len, postfix_len, hdr_len, res;
 
        iface = netdev_priv(skb->dev);
@@ -324,7 +324,7 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
 
        if (local->tkip_countermeasures &&
            strcmp(crypt->ops->name, "TKIP") == 0) {
-               hdr = (struct ieee80211_hdr_4addr *) skb->data;
+               hdr = (struct ieee80211_hdr *) skb->data;
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "%s: TKIP countermeasures: dropped "
                               "TX packet to %pM\n",
@@ -349,9 +349,8 @@ static struct sk_buff * hostap_tx_encrypt(struct sk_buff *skb,
                return NULL;
        }
 
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
-       fc = le16_to_cpu(hdr->frame_ctl);
-       hdr_len = hostap_80211_get_hdrlen(fc);
+       hdr = (struct ieee80211_hdr *) skb->data;
+       hdr_len = hostap_80211_get_hdrlen(hdr->frame_control);
 
        /* Host-based IEEE 802.11 fragmentation for TX is not yet supported, so
         * call both MSDU and MPDU encryption functions from here. */
@@ -384,7 +383,7 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
        ap_tx_ret tx_ret;
        struct hostap_skb_tx_data *meta;
        int no_encrypt = 0;
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
 
        iface = netdev_priv(dev);
        local = iface->local;
@@ -427,14 +426,14 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
        tx_ret = hostap_handle_sta_tx(local, &tx);
        skb = tx.skb;
        meta = (struct hostap_skb_tx_data *) skb->cb;
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
-       fc = le16_to_cpu(hdr->frame_ctl);
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = le16_to_cpu(hdr->frame_control);
        switch (tx_ret) {
        case AP_TX_CONTINUE:
                break;
        case AP_TX_CONTINUE_NOT_AUTHORIZED:
                if (local->ieee_802_1x &&
-                   WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&
+                   ieee80211_is_data(hdr->frame_control) &&
                    meta->ethertype != ETH_P_PAE &&
                    !(meta->flags & HOSTAP_TX_FLAGS_WDS)) {
                        printk(KERN_DEBUG "%s: dropped frame to unauthorized "
@@ -469,10 +468,10 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
                /* remove special version from the frame header */
                fc &= ~IEEE80211_FCTL_VERS;
-               hdr->frame_ctl = cpu_to_le16(fc);
+               hdr->frame_control = cpu_to_le16(fc);
        }
 
-       if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_DATA) {
+       if (!ieee80211_is_data(hdr->frame_control)) {
                no_encrypt = 1;
                tx.crypt = NULL;
        }
@@ -493,9 +492,9 @@ int hostap_master_start_xmit(struct sk_buff *skb, struct net_device *dev)
                /* Add ISWEP flag both for firmware and host based encryption
                 */
                fc |= IEEE80211_FCTL_PROTECTED;
-               hdr->frame_ctl = cpu_to_le16(fc);
+               hdr->frame_control = cpu_to_le16(fc);
        } else if (local->drop_unencrypted &&
-                  WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&
+                  ieee80211_is_data(hdr->frame_control) &&
                   meta->ethertype != ETH_P_PAE) {
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "%s: dropped unencrypted TX data "
index 0a4bf94dddfbd00f92195df9bd9ec5d396b33795..a2a203c90ba3da30dae1d041df49a3b8c683a295 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/proc_fs.h>
 #include <linux/delay.h>
 #include <linux/random.h>
+#include <linux/if_arp.h>
 
 #include "hostap_wlan.h"
 #include "hostap.h"
@@ -588,26 +589,22 @@ void hostap_check_sta_fw_version(struct ap_data *ap, int sta_fw_ver)
 static void hostap_ap_tx_cb(struct sk_buff *skb, int ok, void *data)
 {
        struct ap_data *ap = data;
-       u16 fc;
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
 
        if (!ap->local->hostapd || !ap->local->apdev) {
                dev_kfree_skb(skb);
                return;
        }
 
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
-       fc = le16_to_cpu(hdr->frame_ctl);
-
        /* Pass the TX callback frame to the hostapd; use 802.11 header version
         * 1 to indicate failure (no ACK) and 2 success (frame ACKed) */
 
-       fc &= ~IEEE80211_FCTL_VERS;
-       fc |= ok ? BIT(1) : BIT(0);
-       hdr->frame_ctl = cpu_to_le16(fc);
+       hdr = (struct ieee80211_hdr *) skb->data;
+       hdr->frame_control &= cpu_to_le16(~IEEE80211_FCTL_VERS);
+       hdr->frame_control |= cpu_to_le16(ok ? BIT(1) : BIT(0));
 
        skb->dev = ap->local->apdev;
-       skb_pull(skb, hostap_80211_get_hdrlen(fc));
+       skb_pull(skb, hostap_80211_get_hdrlen(hdr->frame_control));
        skb->pkt_type = PACKET_OTHERHOST;
        skb->protocol = cpu_to_be16(ETH_P_802_2);
        memset(skb->cb, 0, sizeof(skb->cb));
@@ -621,8 +618,8 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data)
 {
        struct ap_data *ap = data;
        struct net_device *dev = ap->local->dev;
-       struct ieee80211_hdr_4addr *hdr;
-       u16 fc, auth_alg, auth_transaction, status;
+       struct ieee80211_hdr *hdr;
+       u16 auth_alg, auth_transaction, status;
        __le16 *pos;
        struct sta_info *sta = NULL;
        char *txt = NULL;
@@ -632,10 +629,8 @@ static void hostap_ap_tx_cb_auth(struct sk_buff *skb, int ok, void *data)
                return;
        }
 
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
-       fc = le16_to_cpu(hdr->frame_ctl);
-       if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT ||
-           WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_AUTH ||
+       hdr = (struct ieee80211_hdr *) skb->data;
+       if (!ieee80211_is_auth(hdr->frame_control) ||
            skb->len < IEEE80211_MGMT_HDR_LEN + 6) {
                printk(KERN_DEBUG "%s: hostap_ap_tx_cb_auth received invalid "
                       "frame\n", dev->name);
@@ -691,7 +686,7 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
 {
        struct ap_data *ap = data;
        struct net_device *dev = ap->local->dev;
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
        u16 fc, status;
        __le16 *pos;
        struct sta_info *sta = NULL;
@@ -702,11 +697,10 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
                return;
        }
 
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
-       fc = le16_to_cpu(hdr->frame_ctl);
-       if (WLAN_FC_GET_TYPE(fc) != IEEE80211_FTYPE_MGMT ||
-           (WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_ASSOC_RESP &&
-            WLAN_FC_GET_STYPE(fc) != IEEE80211_STYPE_REASSOC_RESP) ||
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = le16_to_cpu(hdr->frame_control);
+       if ((!ieee80211_is_assoc_resp(hdr->frame_control) &&
+            !ieee80211_is_reassoc_resp(hdr->frame_control)) ||
            skb->len < IEEE80211_MGMT_HDR_LEN + 4) {
                printk(KERN_DEBUG "%s: hostap_ap_tx_cb_assoc received invalid "
                       "frame\n", dev->name);
@@ -757,12 +751,12 @@ static void hostap_ap_tx_cb_assoc(struct sk_buff *skb, int ok, void *data)
 static void hostap_ap_tx_cb_poll(struct sk_buff *skb, int ok, void *data)
 {
        struct ap_data *ap = data;
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
        struct sta_info *sta;
 
        if (skb->len < 24)
                goto fail;
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
+       hdr = (struct ieee80211_hdr *) skb->data;
        if (ok) {
                spin_lock(&ap->sta_table_lock);
                sta = ap_get_sta(ap, hdr->addr1);
@@ -917,7 +911,7 @@ static void prism2_send_mgmt(struct net_device *dev,
 {
        struct hostap_interface *iface;
        local_info_t *local;
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
        u16 fc;
        struct sk_buff *skb;
        struct hostap_skb_tx_data *meta;
@@ -942,8 +936,8 @@ static void prism2_send_mgmt(struct net_device *dev,
        }
 
        fc = type_subtype;
-       hdrlen = hostap_80211_get_hdrlen(fc);
-       hdr = (struct ieee80211_hdr_4addr *) skb_put(skb, hdrlen);
+       hdrlen = hostap_80211_get_hdrlen(cpu_to_le16(type_subtype));
+       hdr = (struct ieee80211_hdr *) skb_put(skb, hdrlen);
        if (body)
                memcpy(skb_put(skb, body_len), body, body_len);
 
@@ -954,11 +948,11 @@ static void prism2_send_mgmt(struct net_device *dev,
 
 
        memcpy(hdr->addr1, addr, ETH_ALEN); /* DA / RA */
-       if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA) {
+       if (ieee80211_is_data(hdr->frame_control)) {
                fc |= IEEE80211_FCTL_FROMDS;
                memcpy(hdr->addr2, dev->dev_addr, ETH_ALEN); /* BSSID */
                memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* SA */
-       } else if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_CTL) {
+       } else if (ieee80211_is_ctl(hdr->frame_control)) {
                /* control:ACK does not have addr2 or addr3 */
                memset(hdr->addr2, 0, ETH_ALEN);
                memset(hdr->addr3, 0, ETH_ALEN);
@@ -967,7 +961,7 @@ static void prism2_send_mgmt(struct net_device *dev,
                memcpy(hdr->addr3, dev->dev_addr, ETH_ALEN); /* BSSID */
        }
 
-       hdr->frame_ctl = cpu_to_le16(fc);
+       hdr->frame_control = cpu_to_le16(fc);
 
        meta = (struct hostap_skb_tx_data *) skb->cb;
        memset(meta, 0, sizeof(*meta));
@@ -1284,22 +1278,21 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
                          struct hostap_80211_rx_status *rx_stats)
 {
        struct net_device *dev = local->dev;
-       struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        size_t hdrlen;
        struct ap_data *ap = local->ap;
        char body[8 + WLAN_AUTH_CHALLENGE_LEN], *challenge = NULL;
        int len, olen;
        u16 auth_alg, auth_transaction, status_code;
        __le16 *pos;
-       u16 resp = WLAN_STATUS_SUCCESS, fc;
+       u16 resp = WLAN_STATUS_SUCCESS;
        struct sta_info *sta = NULL;
        struct lib80211_crypt_data *crypt;
        char *txt = "";
 
        len = skb->len - IEEE80211_MGMT_HDR_LEN;
 
-       fc = le16_to_cpu(hdr->frame_ctl);
-       hdrlen = hostap_80211_get_hdrlen(fc);
+       hdrlen = hostap_80211_get_hdrlen(hdr->frame_control);
 
        if (len < 6) {
                PDEBUG(DEBUG_AP, "%s: handle_authen - too short payload "
@@ -1435,7 +1428,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
                            challenge == NULL ||
                            memcmp(sta->u.sta.challenge, challenge,
                                   WLAN_AUTH_CHALLENGE_LEN) != 0 ||
-                           !(fc & IEEE80211_FCTL_PROTECTED)) {
+                           !ieee80211_has_protected(hdr->frame_control)) {
                                txt = "challenge response incorrect";
                                resp = WLAN_STATUS_CHALLENGE_FAIL;
                                goto fail;
@@ -1488,7 +1481,7 @@ static void handle_authen(local_info_t *local, struct sk_buff *skb,
                       "trans#=%d stat=%d len=%d fc=%04x) ==> %d (%s)\n",
                       dev->name, hdr->addr2,
                       auth_alg, auth_transaction, status_code, len,
-                      fc, resp, txt);
+                      le16_to_cpu(hdr->frame_control), resp, txt);
        }
 }
 
@@ -1498,7 +1491,7 @@ static void handle_assoc(local_info_t *local, struct sk_buff *skb,
                         struct hostap_80211_rx_status *rx_stats, int reassoc)
 {
        struct net_device *dev = local->dev;
-       struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        char body[12], *p, *lpos;
        int len, left;
        __le16 *pos;
@@ -1707,7 +1700,7 @@ static void handle_deauth(local_info_t *local, struct sk_buff *skb,
                          struct hostap_80211_rx_status *rx_stats)
 {
        struct net_device *dev = local->dev;
-       struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        char *body = (char *) (skb->data + IEEE80211_MGMT_HDR_LEN);
        int len;
        u16 reason_code;
@@ -1749,7 +1742,7 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
                            struct hostap_80211_rx_status *rx_stats)
 {
        struct net_device *dev = local->dev;
-       struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        char *body = skb->data + IEEE80211_MGMT_HDR_LEN;
        int len;
        u16 reason_code;
@@ -1788,7 +1781,7 @@ static void handle_disassoc(local_info_t *local, struct sk_buff *skb,
 
 /* Called only as a scheduled task for pending AP frames. */
 static void ap_handle_data_nullfunc(local_info_t *local,
-                                   struct ieee80211_hdr_4addr *hdr)
+                                   struct ieee80211_hdr *hdr)
 {
        struct net_device *dev = local->dev;
 
@@ -1805,7 +1798,7 @@ static void ap_handle_data_nullfunc(local_info_t *local,
 
 /* Called only as a scheduled task for pending AP frames. */
 static void ap_handle_dropped_data(local_info_t *local,
-                                  struct ieee80211_hdr_4addr *hdr)
+                                  struct ieee80211_hdr *hdr)
 {
        struct net_device *dev = local->dev;
        struct sta_info *sta;
@@ -1863,7 +1856,7 @@ static void pspoll_send_buffered(local_info_t *local, struct sta_info *sta,
 
 /* Called only as a scheduled task for pending AP frames. */
 static void handle_pspoll(local_info_t *local,
-                         struct ieee80211_hdr_4addr *hdr,
+                         struct ieee80211_hdr *hdr,
                          struct hostap_80211_rx_status *rx_stats)
 {
        struct net_device *dev = local->dev;
@@ -1872,8 +1865,7 @@ static void handle_pspoll(local_info_t *local,
        struct sk_buff *skb;
 
        PDEBUG(DEBUG_PS2, "handle_pspoll: BSSID=%pM, TA=%pM PWRMGT=%d\n",
-              hdr->addr1, hdr->addr2,
-              !!(le16_to_cpu(hdr->frame_ctl) & IEEE80211_FCTL_PM));
+              hdr->addr1, hdr->addr2, !!ieee80211_has_pm(hdr->frame_control));
 
        if (memcmp(hdr->addr1, dev->dev_addr, ETH_ALEN)) {
                PDEBUG(DEBUG_AP,
@@ -1984,7 +1976,7 @@ static void handle_wds_oper_queue(struct work_struct *work)
 static void handle_beacon(local_info_t *local, struct sk_buff *skb,
                          struct hostap_80211_rx_status *rx_stats)
 {
-       struct ieee80211_hdr_4addr *hdr = (struct ieee80211_hdr_4addr *) skb->data;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
        char *body = skb->data + IEEE80211_MGMT_HDR_LEN;
        int len, left;
        u16 beacon_int, capability;
@@ -2143,14 +2135,14 @@ static void handle_ap_item(local_info_t *local, struct sk_buff *skb,
        struct net_device *dev = local->dev;
 #endif /* PRISM2_NO_KERNEL_IEEE80211_MGMT */
        u16 fc, type, stype;
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
 
        /* FIX: should give skb->len to handler functions and check that the
         * buffer is long enough */
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
-       fc = le16_to_cpu(hdr->frame_ctl);
-       type = WLAN_FC_GET_TYPE(fc);
-       stype = WLAN_FC_GET_STYPE(fc);
+       hdr = (struct ieee80211_hdr *) skb->data;
+       fc = le16_to_cpu(hdr->frame_control);
+       type = fc & IEEE80211_FCTL_FTYPE;
+       stype = fc & IEEE80211_FCTL_STYPE;
 
 #ifndef PRISM2_NO_KERNEL_IEEE80211_MGMT
        if (!local->hostapd && type == IEEE80211_FTYPE_DATA) {
@@ -2262,8 +2254,7 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb,
 {
        struct hostap_interface *iface;
        local_info_t *local;
-       u16 fc;
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
 
        iface = netdev_priv(dev);
        local = iface->local;
@@ -2271,14 +2262,12 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb,
        if (skb->len < 16)
                goto drop;
 
-       local->stats.rx_packets++;
+       dev->stats.rx_packets++;
 
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
-       fc = le16_to_cpu(hdr->frame_ctl);
+       hdr = (struct ieee80211_hdr *) skb->data;
 
        if (local->ap->ap_policy == AP_OTHER_AP_SKIP_ALL &&
-           WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT &&
-           WLAN_FC_GET_STYPE(fc) == IEEE80211_STYPE_BEACON)
+           ieee80211_is_beacon(hdr->frame_control))
                goto drop;
 
        skb->protocol = cpu_to_be16(ETH_P_HOSTAP);
@@ -2294,7 +2283,7 @@ void hostap_rx(struct net_device *dev, struct sk_buff *skb,
 static void schedule_packet_send(local_info_t *local, struct sta_info *sta)
 {
        struct sk_buff *skb;
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
        struct hostap_80211_rx_status rx_stats;
 
        if (skb_queue_empty(&sta->tx_buf))
@@ -2307,10 +2296,10 @@ static void schedule_packet_send(local_info_t *local, struct sta_info *sta)
                return;
        }
 
-       hdr = (struct ieee80211_hdr_4addr *) skb_put(skb, 16);
+       hdr = (struct ieee80211_hdr *) skb_put(skb, 16);
 
        /* Generate a fake pspoll frame to start packet delivery */
-       hdr->frame_ctl = cpu_to_le16(
+       hdr->frame_control = cpu_to_le16(
                IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL);
        memcpy(hdr->addr1, local->dev->dev_addr, ETH_ALEN);
        memcpy(hdr->addr2, sta->addr, ETH_ALEN);
@@ -2689,7 +2678,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
        struct sta_info *sta = NULL;
        struct sk_buff *skb = tx->skb;
        int set_tim, ret;
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
        struct hostap_skb_tx_data *meta;
 
        meta = (struct hostap_skb_tx_data *) skb->cb;
@@ -2698,7 +2687,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
            meta->iface->type == HOSTAP_INTERFACE_STA)
                goto out;
 
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
+       hdr = (struct ieee80211_hdr *) skb->data;
 
        if (hdr->addr1[0] & 0x01) {
                /* broadcast/multicast frame - no AP related processing */
@@ -2753,7 +2742,7 @@ ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx)
 
        if (meta->flags & HOSTAP_TX_FLAGS_ADD_MOREDATA) {
                /* indicate to STA that more frames follow */
-               hdr->frame_ctl |=
+               hdr->frame_control |=
                        cpu_to_le16(IEEE80211_FCTL_MOREDATA);
        }
 
@@ -2828,10 +2817,10 @@ void hostap_handle_sta_release(void *ptr)
 void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb)
 {
        struct sta_info *sta;
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
        struct hostap_skb_tx_data *meta;
 
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
+       hdr = (struct ieee80211_hdr *) skb->data;
        meta = (struct hostap_skb_tx_data *) skb->cb;
 
        spin_lock(&local->ap->sta_table_lock);
@@ -2898,8 +2887,8 @@ static void hostap_update_sta_ps2(local_info_t *local, struct sta_info *sta,
 
 
 /* Called only as a tasklet (software IRQ). Called for each RX frame to update
- * STA power saving state. pwrmgt is a flag from 802.11 frame_ctl field. */
-int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr_4addr *hdr)
+ * STA power saving state. pwrmgt is a flag from 802.11 frame_control field. */
+int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr)
 {
        struct sta_info *sta;
        u16 fc;
@@ -2913,9 +2902,10 @@ int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr_4addr *hdr)
        if (!sta)
                return -1;
 
-       fc = le16_to_cpu(hdr->frame_ctl);
+       fc = le16_to_cpu(hdr->frame_control);
        hostap_update_sta_ps2(local, sta, fc & IEEE80211_FCTL_PM,
-                             WLAN_FC_GET_TYPE(fc), WLAN_FC_GET_STYPE(fc));
+                             fc & IEEE80211_FCTL_FTYPE,
+                             fc & IEEE80211_FCTL_STYPE);
 
        atomic_dec(&sta->users);
        return 0;
@@ -2932,16 +2922,16 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
        int ret;
        struct sta_info *sta;
        u16 fc, type, stype;
-       struct ieee80211_hdr_4addr *hdr;
+       struct ieee80211_hdr *hdr;
 
        if (local->ap == NULL)
                return AP_RX_CONTINUE;
 
-       hdr = (struct ieee80211_hdr_4addr *) skb->data;
+       hdr = (struct ieee80211_hdr *) skb->data;
 
-       fc = le16_to_cpu(hdr->frame_ctl);
-       type = WLAN_FC_GET_TYPE(fc);
-       stype = WLAN_FC_GET_STYPE(fc);
+       fc = le16_to_cpu(hdr->frame_control);
+       type = fc & IEEE80211_FCTL_FTYPE;
+       stype = fc & IEEE80211_FCTL_STYPE;
 
        spin_lock(&local->ap->sta_table_lock);
        sta = ap_get_sta(local->ap, hdr->addr2);
@@ -3064,7 +3054,7 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
 
 /* Called only as a tasklet (software IRQ) */
 int hostap_handle_sta_crypto(local_info_t *local,
-                            struct ieee80211_hdr_4addr *hdr,
+                            struct ieee80211_hdr *hdr,
                             struct lib80211_crypt_data **crypt,
                             void **sta_ptr)
 {
@@ -3166,7 +3156,7 @@ int hostap_add_sta(struct ap_data *ap, u8 *sta_addr)
 
 /* Called only as a tasklet (software IRQ) */
 int hostap_update_rx_stats(struct ap_data *ap,
-                          struct ieee80211_hdr_4addr *hdr,
+                          struct ieee80211_hdr *hdr,
                           struct hostap_80211_rx_status *rx_stats)
 {
        struct sta_info *sta;
index d36e4b17533615462c9694332764abdc15eba7d3..655ceeba96122467b0e2c459d1ddc9838ba7db3c 100644 (file)
@@ -235,7 +235,7 @@ struct hostap_tx_data {
 ap_tx_ret hostap_handle_sta_tx(local_info_t *local, struct hostap_tx_data *tx);
 void hostap_handle_sta_release(void *ptr);
 void hostap_handle_sta_tx_exc(local_info_t *local, struct sk_buff *skb);
-int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr_4addr *hdr);
+int hostap_update_sta_ps(local_info_t *local, struct ieee80211_hdr *hdr);
 typedef enum {
        AP_RX_CONTINUE, AP_RX_DROP, AP_RX_EXIT, AP_RX_CONTINUE_NOT_AUTHORIZED
 } ap_rx_ret;
@@ -243,13 +243,13 @@ ap_rx_ret hostap_handle_sta_rx(local_info_t *local, struct net_device *dev,
                               struct sk_buff *skb,
                               struct hostap_80211_rx_status *rx_stats,
                               int wds);
-int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr_4addr *hdr,
+int hostap_handle_sta_crypto(local_info_t *local, struct ieee80211_hdr *hdr,
                             struct lib80211_crypt_data **crypt,
                             void **sta_ptr);
 int hostap_is_sta_assoc(struct ap_data *ap, u8 *sta_addr);
 int hostap_is_sta_authorized(struct ap_data *ap, u8 *sta_addr);
 int hostap_add_sta(struct ap_data *ap, u8 *sta_addr);
-int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr_4addr *hdr,
+int hostap_update_rx_stats(struct ap_data *ap, struct ieee80211_hdr *hdr,
                           struct hostap_80211_rx_status *rx_stats);
 void hostap_update_rates(local_info_t *local);
 void hostap_add_wds_links(local_info_t *local);
index 0f27059bbe85a88d20aacc0ec127e63a12fe475f..3dad1cf8f241f3fbbbefa2bbcf4643e257c1d2be 100644 (file)
@@ -46,7 +46,6 @@
 #include <linux/rtnetlink.h>
 #include <linux/wireless.h>
 #include <net/iw_handler.h>
-#include <net/ieee80211.h>
 #include <net/lib80211.h>
 #include <asm/irq.h>
 
@@ -1683,7 +1682,7 @@ static int prism2_get_txfid_idx(local_info_t *local)
 
        PDEBUG(DEBUG_EXTRA2, "prism2_get_txfid_idx: no room in txfid buf: "
               "packet dropped\n");
-       local->stats.tx_dropped++;
+       local->dev->stats.tx_dropped++;
 
        return -1;
 }
@@ -1788,11 +1787,9 @@ static int prism2_transmit(struct net_device *dev, int idx)
                prism2_transmit_cb, (long) idx);
 
        if (res) {
-               struct net_device_stats *stats;
                printk(KERN_DEBUG "%s: prism2_transmit: CMDCODE_TRANSMIT "
                       "failed (res=%d)\n", dev->name, res);
-               stats = hostap_get_stats(dev);
-               stats->tx_dropped++;
+               dev->stats.tx_dropped++;
                netif_wake_queue(dev);
                return -1;
        }
@@ -1840,8 +1837,8 @@ static int prism2_tx_80211(struct sk_buff *skb, struct net_device *dev)
        hdr_len = 24;
        skb_copy_from_linear_data(skb, &txdesc.frame_control, hdr_len);
        fc = le16_to_cpu(txdesc.frame_control);
-       if (WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA &&
-           (fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS) &&
+       if (ieee80211_is_data(txdesc.frame_control) &&
+           ieee80211_has_a4(txdesc.frame_control) &&
            skb->len >= 30) {
                /* Addr4 */
                skb_copy_from_linear_data_offset(skb, hdr_len, txdesc.addr4,
@@ -1940,12 +1937,10 @@ static void prism2_rx(local_info_t *local)
        struct net_device *dev = local->dev;
        int res, rx_pending = 0;
        u16 len, hdr_len, rxfid, status, macport;
-       struct net_device_stats *stats;
        struct hfa384x_rx_frame rxdesc;
        struct sk_buff *skb = NULL;
 
        prism2_callback(local, PRISM2_CALLBACK_RX_START);
-       stats = hostap_get_stats(dev);
 
        rxfid = prism2_read_fid_reg(dev, HFA384X_RXFID_OFF);
 #ifndef final_version
@@ -2032,7 +2027,7 @@ static void prism2_rx(local_info_t *local)
        return;
 
  rx_dropped:
-       stats->rx_dropped++;
+       dev->stats.rx_dropped++;
        if (skb)
                dev_kfree_skb(skb);
        goto rx_exit;
@@ -2082,7 +2077,7 @@ static void hostap_rx_skb(local_info_t *local, struct sk_buff *skb)
        stats.rate = rxdesc->rate;
 
        /* Convert Prism2 RX structure into IEEE 802.11 header */
-       hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(rxdesc->frame_control));
+       hdrlen = hostap_80211_get_hdrlen(rxdesc->frame_control);
        if (hdrlen > rx_hdrlen)
                hdrlen = rx_hdrlen;
 
@@ -2204,7 +2199,7 @@ static void hostap_tx_callback(local_info_t *local,
                return;
        }
 
-       hdrlen = hostap_80211_get_hdrlen(le16_to_cpu(txdesc->frame_control));
+       hdrlen = hostap_80211_get_hdrlen(txdesc->frame_control);
        len = le16_to_cpu(txdesc->data_len);
        skb = dev_alloc_skb(hdrlen + len);
        if (skb == NULL) {
@@ -2315,8 +2310,7 @@ static void hostap_sta_tx_exc_tasklet(unsigned long data)
                if (skb->len >= sizeof(*txdesc)) {
                        /* Convert Prism2 RX structure into IEEE 802.11 header
                         */
-                       u16 fc = le16_to_cpu(txdesc->frame_control);
-                       int hdrlen = hostap_80211_get_hdrlen(fc);
+                       int hdrlen = hostap_80211_get_hdrlen(txdesc->frame_control);
                        memmove(skb_pull(skb, sizeof(*txdesc) - hdrlen),
                                &txdesc->frame_control, hdrlen);
 
@@ -2337,7 +2331,7 @@ static void prism2_txexc(local_info_t *local)
        struct hfa384x_tx_frame txdesc;
 
        show_dump = local->frame_dump & PRISM2_DUMP_TXEXC_HDR;
-       local->stats.tx_errors++;
+       dev->stats.tx_errors++;
 
        res = hostap_tx_compl_read(local, 1, &txdesc, &payload);
        HFA384X_OUTW(HFA384X_EV_TXEXC, HFA384X_EVACK_OFF);
@@ -2394,12 +2388,12 @@ static void prism2_txexc(local_info_t *local)
        PDEBUG(DEBUG_EXTRA, "   retry_count=%d tx_rate=%d fc=0x%04x "
               "(%s%s%s::%d%s%s)\n",
               txdesc.retry_count, txdesc.tx_rate, fc,
-              WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_MGMT ? "Mgmt" : "",
-              WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_CTL ? "Ctrl" : "",
-              WLAN_FC_GET_TYPE(fc) == IEEE80211_FTYPE_DATA ? "Data" : "",
-              WLAN_FC_GET_STYPE(fc) >> 4,
-              fc & IEEE80211_FCTL_TODS ? " ToDS" : "",
-              fc & IEEE80211_FCTL_FROMDS ? " FromDS" : "");
+              ieee80211_is_mgmt(txdesc.frame_control) ? "Mgmt" : "",
+              ieee80211_is_ctl(txdesc.frame_control) ? "Ctrl" : "",
+              ieee80211_is_data(txdesc.frame_control) ? "Data" : "",
+              (fc & IEEE80211_FCTL_STYPE) >> 4,
+              ieee80211_has_tods(txdesc.frame_control) ? " ToDS" : "",
+              ieee80211_has_fromds(txdesc.frame_control) ? " FromDS" : "");
        PDEBUG(DEBUG_EXTRA, "   A1=%pM A2=%pM A3=%pM A4=%pM\n",
               txdesc.addr1, txdesc.addr2,
               txdesc.addr3, txdesc.addr4);
@@ -3228,7 +3222,6 @@ while (0)
 
        hostap_setup_dev(dev, local, HOSTAP_INTERFACE_MASTER);
 
-       dev->hard_start_xmit = hostap_master_start_xmit;
        dev->type = ARPHRD_IEEE80211;
        dev->header_ops = &hostap_80211_ops;
 
index 99b4cf41edf2c59d5d5d2ea2baa5273a21d28d43..6fa14a4e4b53e95c7f870049cf770ec79ac146b6 100644 (file)
@@ -1,5 +1,6 @@
 /* Host AP driver Info Frame processing (part of hostap.o module) */
 
+#include <linux/if_arp.h>
 #include "hostap_wlan.h"
 #include "hostap.h"
 #include "hostap_ap.h"
index 8618b3355eb4ad058a9d4ee931d617f6badb800f..3f2bda881a4f1a40e68b00fc24045c583ae2c0a2 100644 (file)
@@ -2,6 +2,7 @@
 
 #include <linux/types.h>
 #include <linux/ethtool.h>
+#include <linux/if_arp.h>
 #include <net/lib80211.h>
 
 #include "hostap_wlan.h"
index 02a312ca860752ad7c4324570499ee139a771d66..6fe122f18c0dcd68f8de72db16cc3310338aaf2b 100644 (file)
@@ -26,7 +26,6 @@
 #include <linux/etherdevice.h>
 #include <net/net_namespace.h>
 #include <net/iw_handler.h>
-#include <net/ieee80211.h>
 #include <net/lib80211.h>
 #include <asm/uaccess.h>
 
@@ -543,7 +542,8 @@ void hostap_dump_rx_header(const char *name, const struct hfa384x_rx_frame *rx)
        fc = __le16_to_cpu(rx->frame_control);
        printk(KERN_DEBUG "   FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x "
               "data_len=%d%s%s\n",
-              fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4,
+              fc, (fc & IEEE80211_FCTL_FTYPE) >> 2,
+              (fc & IEEE80211_FCTL_STYPE) >> 4,
               __le16_to_cpu(rx->duration_id), __le16_to_cpu(rx->seq_ctrl),
               __le16_to_cpu(rx->data_len),
               fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
@@ -570,7 +570,8 @@ void hostap_dump_tx_header(const char *name, const struct hfa384x_tx_frame *tx)
        fc = __le16_to_cpu(tx->frame_control);
        printk(KERN_DEBUG "   FC=0x%04x (type=%d:%d) dur=0x%04x seq=0x%04x "
               "data_len=%d%s%s\n",
-              fc, WLAN_FC_GET_TYPE(fc) >> 2, WLAN_FC_GET_STYPE(fc) >> 4,
+              fc, (fc & IEEE80211_FCTL_FTYPE) >> 2,
+              (fc & IEEE80211_FCTL_STYPE) >> 4,
               __le16_to_cpu(tx->duration_id), __le16_to_cpu(tx->seq_ctrl),
               __le16_to_cpu(tx->data_len),
               fc & IEEE80211_FCTL_TODS ? " [ToDS]" : "",
@@ -593,37 +594,16 @@ static int hostap_80211_header_parse(const struct sk_buff *skb,
 }
 
 
-int hostap_80211_get_hdrlen(u16 fc)
+int hostap_80211_get_hdrlen(__le16 fc)
 {
-       int hdrlen = 24;
-
-       switch (WLAN_FC_GET_TYPE(fc)) {
-       case IEEE80211_FTYPE_DATA:
-               if ((fc & IEEE80211_FCTL_FROMDS) && (fc & IEEE80211_FCTL_TODS))
-                       hdrlen = 30; /* Addr4 */
-               break;
-       case IEEE80211_FTYPE_CTL:
-               switch (WLAN_FC_GET_STYPE(fc)) {
-               case IEEE80211_STYPE_CTS:
-               case IEEE80211_STYPE_ACK:
-                       hdrlen = 10;
-                       break;
-               default:
-                       hdrlen = 16;
-                       break;
-               }
-               break;
-       }
-
-       return hdrlen;
-}
-
-
-struct net_device_stats *hostap_get_stats(struct net_device *dev)
-{
-       struct hostap_interface *iface;
-       iface = netdev_priv(dev);
-       return &iface->stats;
+       if (ieee80211_is_data(fc) && ieee80211_has_a4 (fc))
+               return 30; /* Addr4 */
+       else if (ieee80211_is_cts(fc) || ieee80211_is_ack(fc))
+               return 10;
+       else if (ieee80211_is_ctl(fc))
+               return 16;
+
+       return 24;
 }
 
 
@@ -835,6 +815,46 @@ const struct header_ops hostap_80211_ops = {
 };
 EXPORT_SYMBOL(hostap_80211_ops);
 
+
+static const struct net_device_ops hostap_netdev_ops = {
+       .ndo_start_xmit         = hostap_data_start_xmit,
+
+       .ndo_open               = prism2_open,
+       .ndo_stop               = prism2_close,
+       .ndo_do_ioctl           = hostap_ioctl,
+       .ndo_set_mac_address    = prism2_set_mac_address,
+       .ndo_set_multicast_list = hostap_set_multicast_list,
+       .ndo_change_mtu         = prism2_change_mtu,
+       .ndo_tx_timeout         = prism2_tx_timeout,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+static const struct net_device_ops hostap_mgmt_netdev_ops = {
+       .ndo_start_xmit         = hostap_mgmt_start_xmit,
+
+       .ndo_open               = prism2_open,
+       .ndo_stop               = prism2_close,
+       .ndo_do_ioctl           = hostap_ioctl,
+       .ndo_set_mac_address    = prism2_set_mac_address,
+       .ndo_set_multicast_list = hostap_set_multicast_list,
+       .ndo_change_mtu         = prism2_change_mtu,
+       .ndo_tx_timeout         = prism2_tx_timeout,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
+static const struct net_device_ops hostap_master_ops = {
+       .ndo_start_xmit         = hostap_master_start_xmit,
+
+       .ndo_open               = prism2_open,
+       .ndo_stop               = prism2_close,
+       .ndo_do_ioctl           = hostap_ioctl,
+       .ndo_set_mac_address    = prism2_set_mac_address,
+       .ndo_set_multicast_list = hostap_set_multicast_list,
+       .ndo_change_mtu         = prism2_change_mtu,
+       .ndo_tx_timeout         = prism2_tx_timeout,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 void hostap_setup_dev(struct net_device *dev, local_info_t *local,
                      int type)
 {
@@ -844,37 +864,31 @@ void hostap_setup_dev(struct net_device *dev, local_info_t *local,
        ether_setup(dev);
 
        /* kernel callbacks */
-       dev->get_stats = hostap_get_stats;
        if (iface) {
                /* Currently, we point to the proper spy_data only on
                 * the main_dev. This could be fixed. Jean II */
                iface->wireless_data.spy_data = &iface->spy_data;
                dev->wireless_data = &iface->wireless_data;
        }
-       dev->wireless_handlers =
-               (struct iw_handler_def *) &hostap_iw_handler_def;
-       dev->do_ioctl = hostap_ioctl;
-       dev->open = prism2_open;
-       dev->stop = prism2_close;
-       dev->set_mac_address = prism2_set_mac_address;
-       dev->set_multicast_list = hostap_set_multicast_list;
-       dev->change_mtu = prism2_change_mtu;
-       dev->tx_timeout = prism2_tx_timeout;
+       dev->wireless_handlers = &hostap_iw_handler_def;
        dev->watchdog_timeo = TX_TIMEOUT;
 
-       if (type == HOSTAP_INTERFACE_AP) {
-               dev->hard_start_xmit = hostap_mgmt_start_xmit;
+       switch(type) {
+       case HOSTAP_INTERFACE_AP:
+               dev->netdev_ops = &hostap_mgmt_netdev_ops;
                dev->type = ARPHRD_IEEE80211;
                dev->header_ops = &hostap_80211_ops;
-       } else {
-               dev->hard_start_xmit = hostap_data_start_xmit;
+               break;
+       case HOSTAP_INTERFACE_MASTER:
+               dev->tx_queue_len = 0;  /* use main radio device queue */
+               dev->netdev_ops = &hostap_master_ops;
+               break;
+       default:
+               dev->netdev_ops = &hostap_netdev_ops;
        }
 
        dev->mtu = local->mtu;
-       if (type != HOSTAP_INTERFACE_MASTER) {
-               /* use main radio device queue */
-               dev->tx_queue_len = 0;
-       }
+
 
        SET_ETHTOOL_OPS(dev, &prism2_ethtool_ops);
 
@@ -1124,7 +1138,6 @@ EXPORT_SYMBOL(hostap_set_auth_algs);
 EXPORT_SYMBOL(hostap_dump_rx_header);
 EXPORT_SYMBOL(hostap_dump_tx_header);
 EXPORT_SYMBOL(hostap_80211_get_hdrlen);
-EXPORT_SYMBOL(hostap_get_stats);
 EXPORT_SYMBOL(hostap_setup_dev);
 EXPORT_SYMBOL(hostap_set_multicast_list_queue);
 EXPORT_SYMBOL(hostap_set_hostapd);
index 4d8d51a353cd3cf02395e7ab6c1eaf4333314303..3d238917af07f32bcd16ffcf8eb75f90f824b120 100644 (file)
@@ -684,7 +684,6 @@ struct local_info {
        u16 channel_mask; /* mask of allowed channels */
        u16 scan_channel_mask; /* mask of channels to be scanned */
        struct comm_tallies_sums comm_tallies;
-       struct net_device_stats stats;
        struct proc_dir_entry *proc;
        int iw_mode; /* operating mode (IW_MODE_*) */
        int pseudo_adhoc; /* 0: IW_MODE_ADHOC is real 802.11 compliant IBSS
index 1d5dc3e9c5fbfb930e60c68ee2515f4cf4f23d49..85cc79995f6f9d853cad49f53e39d6600a70b045 100644 (file)
@@ -186,7 +186,7 @@ config LIBIPW_DEBUG
          % echo 0x00000FFO > /proc/net/ieee80211/debug_level
 
          For a list of values you can assign to debug_level, you
-         can look at the bit mask values in <net/ieee80211.h>
+         can look at the bit mask values in ieee80211.h
 
          If you are not trying to debug or develop the libipw
          component, you most likely want to say N here.
similarity index 90%
rename from include/net/ieee80211.h
rename to drivers/net/wireless/ipw2x00/ieee80211.h
index adb7cf31f781f48cd564df727400f173b8e93d66..70755c1336d573d93f7fafb9aa60aef0fa2143db 100644 (file)
 #define MIN_FRAG_THRESHOLD     256U
 #define        MAX_FRAG_THRESHOLD     2346U
 
-/* Frame control field constants */
-#define IEEE80211_FCTL_VERS            0x0003
-#define IEEE80211_FCTL_FTYPE           0x000c
-#define IEEE80211_FCTL_STYPE           0x00f0
-#define IEEE80211_FCTL_TODS            0x0100
-#define IEEE80211_FCTL_FROMDS          0x0200
-#define IEEE80211_FCTL_MOREFRAGS       0x0400
-#define IEEE80211_FCTL_RETRY           0x0800
-#define IEEE80211_FCTL_PM              0x1000
-#define IEEE80211_FCTL_MOREDATA                0x2000
-#define IEEE80211_FCTL_PROTECTED       0x4000
-#define IEEE80211_FCTL_ORDER           0x8000
-
-#define IEEE80211_FTYPE_MGMT           0x0000
-#define IEEE80211_FTYPE_CTL            0x0004
-#define IEEE80211_FTYPE_DATA           0x0008
-
-/* management */
-#define IEEE80211_STYPE_ASSOC_REQ      0x0000
-#define IEEE80211_STYPE_ASSOC_RESP     0x0010
-#define IEEE80211_STYPE_REASSOC_REQ    0x0020
-#define IEEE80211_STYPE_REASSOC_RESP   0x0030
-#define IEEE80211_STYPE_PROBE_REQ      0x0040
-#define IEEE80211_STYPE_PROBE_RESP     0x0050
-#define IEEE80211_STYPE_BEACON         0x0080
-#define IEEE80211_STYPE_ATIM           0x0090
-#define IEEE80211_STYPE_DISASSOC       0x00A0
-#define IEEE80211_STYPE_AUTH           0x00B0
-#define IEEE80211_STYPE_DEAUTH         0x00C0
-#define IEEE80211_STYPE_ACTION         0x00D0
-
-/* control */
-#define IEEE80211_STYPE_PSPOLL         0x00A0
-#define IEEE80211_STYPE_RTS            0x00B0
-#define IEEE80211_STYPE_CTS            0x00C0
-#define IEEE80211_STYPE_ACK            0x00D0
-#define IEEE80211_STYPE_CFEND          0x00E0
-#define IEEE80211_STYPE_CFENDACK       0x00F0
-
-/* data */
-#define IEEE80211_STYPE_DATA           0x0000
-#define IEEE80211_STYPE_DATA_CFACK     0x0010
-#define IEEE80211_STYPE_DATA_CFPOLL    0x0020
-#define IEEE80211_STYPE_DATA_CFACKPOLL 0x0030
-#define IEEE80211_STYPE_NULLFUNC       0x0040
-#define IEEE80211_STYPE_CFACK          0x0050
-#define IEEE80211_STYPE_CFPOLL         0x0060
-#define IEEE80211_STYPE_CFACKPOLL      0x0070
-#define IEEE80211_STYPE_QOS_DATA        0x0080
-
-#define IEEE80211_SCTL_FRAG            0x000F
-#define IEEE80211_SCTL_SEQ             0xFFF0
-
 /* QOS control */
 #define IEEE80211_QCTL_TID             0x000F
 
 /* debug macros */
 
-#ifdef CONFIG_IEEE80211_DEBUG
+#ifdef CONFIG_LIBIPW_DEBUG
 extern u32 ieee80211_debug_level;
 #define IEEE80211_DEBUG(level, fmt, args...) \
 do { if (ieee80211_debug_level & (level)) \
@@ -128,7 +75,7 @@ static inline bool ieee80211_ratelimit_debug(u32 level)
 {
        return false;
 }
-#endif                         /* CONFIG_IEEE80211_DEBUG */
+#endif                         /* CONFIG_LIBIPW_DEBUG */
 
 /*
  * To use the debug system:
@@ -152,7 +99,7 @@ static inline bool ieee80211_ratelimit_debug(u32 level)
  * you simply need to add your entry to the ieee80211_debug_level array.
  *
  * If you do not see debug_level in /proc/net/ieee80211 then you do not have
- * CONFIG_IEEE80211_DEBUG defined in your kernel configuration
+ * CONFIG_LIBIPW_DEBUG defined in your kernel configuration
  *
  */
 
@@ -217,23 +164,6 @@ struct ieee80211_snap_hdr {
 #define WLAN_GET_SEQ_FRAG(seq) ((seq) & IEEE80211_SCTL_FRAG)
 #define WLAN_GET_SEQ_SEQ(seq)  (((seq) & IEEE80211_SCTL_SEQ) >> 4)
 
-/* Action categories - 802.11h */
-enum ieee80211_actioncategories {
-       WLAN_ACTION_SPECTRUM_MGMT = 0,
-       /* Reserved 1-127  */
-       /* Error    128-255 */
-};
-
-/* Action details - 802.11h */
-enum ieee80211_actiondetails {
-       WLAN_ACTION_CATEGORY_MEASURE_REQUEST = 0,
-       WLAN_ACTION_CATEGORY_MEASURE_REPORT = 1,
-       WLAN_ACTION_CATEGORY_TPC_REQUEST = 2,
-       WLAN_ACTION_CATEGORY_TPC_REPORT = 3,
-       WLAN_ACTION_CATEGORY_CHANNEL_SWITCH = 4,
-       /* 5 - 255 Reserved */
-};
-
 #define IEEE80211_STATMASK_SIGNAL (1<<0)
 #define IEEE80211_STATMASK_RSSI (1<<1)
 #define IEEE80211_STATMASK_NOISE (1<<2)
@@ -411,37 +341,6 @@ Total: 28-2340 bytes
 
 #define BEACON_PROBE_SSID_ID_POSITION 12
 
-/* Management Frame Information Element Types */
-enum ieee80211_mfie {
-       MFIE_TYPE_SSID = 0,
-       MFIE_TYPE_RATES = 1,
-       MFIE_TYPE_FH_SET = 2,
-       MFIE_TYPE_DS_SET = 3,
-       MFIE_TYPE_CF_SET = 4,
-       MFIE_TYPE_TIM = 5,
-       MFIE_TYPE_IBSS_SET = 6,
-       MFIE_TYPE_COUNTRY = 7,
-       MFIE_TYPE_HOP_PARAMS = 8,
-       MFIE_TYPE_HOP_TABLE = 9,
-       MFIE_TYPE_REQUEST = 10,
-       MFIE_TYPE_CHALLENGE = 16,
-       MFIE_TYPE_POWER_CONSTRAINT = 32,
-       MFIE_TYPE_POWER_CAPABILITY = 33,
-       MFIE_TYPE_TPC_REQUEST = 34,
-       MFIE_TYPE_TPC_REPORT = 35,
-       MFIE_TYPE_SUPP_CHANNELS = 36,
-       MFIE_TYPE_CSA = 37,
-       MFIE_TYPE_MEASURE_REQUEST = 38,
-       MFIE_TYPE_MEASURE_REPORT = 39,
-       MFIE_TYPE_QUIET = 40,
-       MFIE_TYPE_IBSS_DFS = 41,
-       MFIE_TYPE_ERP_INFO = 42,
-       MFIE_TYPE_RSN = 48,
-       MFIE_TYPE_RATES_EX = 50,
-       MFIE_TYPE_GENERIC = 221,
-       MFIE_TYPE_QOS_PARAMETER = 222,
-};
-
 struct ieee80211_hdr_1addr {
        __le16 frame_ctl;
        __le16 duration_id;
@@ -887,7 +786,6 @@ struct ieee80211_device {
        struct ieee80211_security sec;
 
        /* Bookkeeping structures */
-       struct net_device_stats stats;
        struct ieee80211_stats ieee_stats;
 
        struct ieee80211_geo geo;
@@ -1118,6 +1016,10 @@ static inline int ieee80211_is_cck_rate(u8 rate)
 /* ieee80211.c */
 extern void free_ieee80211(struct net_device *dev);
 extern struct net_device *alloc_ieee80211(int sizeof_priv);
+extern int ieee80211_change_mtu(struct net_device *dev, int new_mtu);
+
+extern void ieee80211_networks_age(struct ieee80211_device *ieee,
+                                  unsigned long age_secs);
 
 extern int ieee80211_set_encryption(struct ieee80211_device *ieee);
 
index 52b1cf5160f7c1cf40e8ebce5b19a507303d5b8a..115b704875027fc794079b1a3ac856b8c4641ecb 100644 (file)
@@ -1692,7 +1692,13 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
        u32 lock;
        u32 ord_len = sizeof(lock);
 
-       /* Quite if manually disabled. */
+       /* Age scan list entries found before suspend */
+       if (priv->suspend_time) {
+               ieee80211_networks_age(priv->ieee, priv->suspend_time);
+               priv->suspend_time = 0;
+       }
+
+       /* Quiet if manually disabled. */
        if (priv->status & STATUS_RF_KILL_SW) {
                IPW_DEBUG_INFO("%s: Radio is disabled by Manual Disable "
                               "switch\n", priv->net_dev->name);
@@ -2385,13 +2391,14 @@ static void ipw2100_corruption_detected(struct ipw2100_priv *priv, int i)
 #endif
 
        priv->fatal_error = IPW2100_ERR_C3_CORRUPTION;
-       priv->ieee->stats.rx_errors++;
+       priv->net_dev->stats.rx_errors++;
        schedule_reset(priv);
 }
 
 static void isr_rx(struct ipw2100_priv *priv, int i,
                          struct ieee80211_rx_stats *stats)
 {
+       struct net_device *dev = priv->net_dev;
        struct ipw2100_status *status = &priv->status_queue.drv[i];
        struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
 
@@ -2400,14 +2407,14 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
        if (unlikely(status->frame_size > skb_tailroom(packet->skb))) {
                IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
                               "  Dropping.\n",
-                              priv->net_dev->name,
+                              dev->name,
                               status->frame_size, skb_tailroom(packet->skb));
-               priv->ieee->stats.rx_errors++;
+               dev->stats.rx_errors++;
                return;
        }
 
-       if (unlikely(!netif_running(priv->net_dev))) {
-               priv->ieee->stats.rx_errors++;
+       if (unlikely(!netif_running(dev))) {
+               dev->stats.rx_errors++;
                priv->wstats.discard.misc++;
                IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
                return;
@@ -2437,10 +2444,10 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
        if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
 #ifdef IPW2100_RX_DEBUG
                IPW_DEBUG_DROP("%s: Non consumed packet:\n",
-                              priv->net_dev->name);
+                              dev->name);
                printk_buf(IPW_DL_DROP, packet_data, status->frame_size);
 #endif
-               priv->ieee->stats.rx_errors++;
+               dev->stats.rx_errors++;
 
                /* ieee80211_rx failed, so it didn't free the SKB */
                dev_kfree_skb_any(packet->skb);
@@ -2451,7 +2458,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
        if (unlikely(ipw2100_alloc_skb(priv, packet))) {
                printk(KERN_WARNING DRV_NAME ": "
                       "%s: Unable to allocate SKB onto RBD ring - disabling "
-                      "adapter.\n", priv->net_dev->name);
+                      "adapter.\n", dev->name);
                /* TODO: schedule adapter shutdown */
                IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
        }
@@ -2465,6 +2472,7 @@ static void isr_rx(struct ipw2100_priv *priv, int i,
 static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
                   struct ieee80211_rx_stats *stats)
 {
+       struct net_device *dev = priv->net_dev;
        struct ipw2100_status *status = &priv->status_queue.drv[i];
        struct ipw2100_rx_packet *packet = &priv->rx_buffers[i];
 
@@ -2482,15 +2490,15 @@ static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
                                sizeof(struct ipw_rt_hdr))) {
                IPW_DEBUG_INFO("%s: frame_size (%u) > skb_tailroom (%u)!"
                               "  Dropping.\n",
-                              priv->net_dev->name,
+                              dev->name,
                               status->frame_size,
                               skb_tailroom(packet->skb));
-               priv->ieee->stats.rx_errors++;
+               dev->stats.rx_errors++;
                return;
        }
 
-       if (unlikely(!netif_running(priv->net_dev))) {
-               priv->ieee->stats.rx_errors++;
+       if (unlikely(!netif_running(dev))) {
+               dev->stats.rx_errors++;
                priv->wstats.discard.misc++;
                IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
                return;
@@ -2499,7 +2507,7 @@ static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
        if (unlikely(priv->config & CFG_CRC_CHECK &&
                     status->flags & IPW_STATUS_FLAG_CRC_ERROR)) {
                IPW_DEBUG_RX("CRC error in packet.  Dropping.\n");
-               priv->ieee->stats.rx_errors++;
+               dev->stats.rx_errors++;
                return;
        }
 
@@ -2521,7 +2529,7 @@ static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
        skb_put(packet->skb, status->frame_size + sizeof(struct ipw_rt_hdr));
 
        if (!ieee80211_rx(priv->ieee, packet->skb, stats)) {
-               priv->ieee->stats.rx_errors++;
+               dev->stats.rx_errors++;
 
                /* ieee80211_rx failed, so it didn't free the SKB */
                dev_kfree_skb_any(packet->skb);
@@ -2532,7 +2540,7 @@ static void isr_rx_monitor(struct ipw2100_priv *priv, int i,
        if (unlikely(ipw2100_alloc_skb(priv, packet))) {
                IPW_DEBUG_WARNING(
                        "%s: Unable to allocate SKB onto RBD ring - disabling "
-                       "adapter.\n", priv->net_dev->name);
+                       "adapter.\n", dev->name);
                /* TODO: schedule adapter shutdown */
                IPW_DEBUG_INFO("TODO: Shutdown adapter...\n");
        }
@@ -3334,7 +3342,7 @@ static int ipw2100_tx(struct ieee80211_txb *txb, struct net_device *dev,
 
        if (!(priv->status & STATUS_ASSOCIATED)) {
                IPW_DEBUG_INFO("Can not transmit when not connected.\n");
-               priv->ieee->stats.tx_carrier_errors++;
+               priv->net_dev->stats.tx_carrier_errors++;
                netif_stop_queue(dev);
                goto fail_unlock;
        }
@@ -5830,7 +5838,7 @@ static void ipw2100_tx_timeout(struct net_device *dev)
 {
        struct ipw2100_priv *priv = ieee80211_priv(dev);
 
-       priv->ieee->stats.tx_errors++;
+       dev->stats.tx_errors++;
 
 #ifdef CONFIG_IPW2100_MONITOR
        if (priv->ieee->iw_mode == IW_MODE_MONITOR)
@@ -6000,6 +6008,17 @@ static void ipw2100_rf_kill(struct work_struct *work)
 
 static void ipw2100_irq_tasklet(struct ipw2100_priv *priv);
 
+static const struct net_device_ops ipw2100_netdev_ops = {
+       .ndo_open               = ipw2100_open,
+       .ndo_stop               = ipw2100_close,
+       .ndo_start_xmit         = ieee80211_xmit,
+       .ndo_change_mtu         = ieee80211_change_mtu,
+       .ndo_init               = ipw2100_net_init,
+       .ndo_tx_timeout         = ipw2100_tx_timeout,
+       .ndo_set_mac_address    = ipw2100_set_address,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 /* Look into using netdev destructor to shutdown ieee80211? */
 
 static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
@@ -6024,15 +6043,11 @@ static struct net_device *ipw2100_alloc_device(struct pci_dev *pci_dev,
        priv->ieee->perfect_rssi = -20;
        priv->ieee->worst_rssi = -85;
 
-       dev->open = ipw2100_open;
-       dev->stop = ipw2100_close;
-       dev->init = ipw2100_net_init;
+       dev->netdev_ops = &ipw2100_netdev_ops;
        dev->ethtool_ops = &ipw2100_ethtool_ops;
-       dev->tx_timeout = ipw2100_tx_timeout;
        dev->wireless_handlers = &ipw2100_wx_handler_def;
        priv->wireless_data.ieee80211 = priv->ieee;
        dev->wireless_data = &priv->wireless_data;
-       dev->set_mac_address = ipw2100_set_address;
        dev->watchdog_timeo = 3 * HZ;
        dev->irq = 0;
 
@@ -6415,6 +6430,8 @@ static int ipw2100_suspend(struct pci_dev *pci_dev, pm_message_t state)
        pci_disable_device(pci_dev);
        pci_set_power_state(pci_dev, PCI_D3hot);
 
+       priv->suspend_at = get_seconds();
+
        mutex_unlock(&priv->action_mutex);
 
        return 0;
@@ -6458,6 +6475,8 @@ static int ipw2100_resume(struct pci_dev *pci_dev)
         * the queue of needed */
        netif_device_attach(dev);
 
+       priv->suspend_time = get_seconds() - priv->suspend_at;
+
        /* Bring the device back up */
        if (!(priv->status & STATUS_RF_KILL_SW))
                ipw2100_up(priv, 0);
index bbf1ddcafba8f6249f900b51dc8e660f7b043f8b..f183d951cd32754c7812c419303a4ce343ff1e19 100644 (file)
@@ -39,8 +39,6 @@
 #include <linux/wireless.h>
 #include <net/iw_handler.h>    // new driver API
 
-#include <net/ieee80211.h>
-
 #ifdef CONFIG_IPW2100_MONITOR
 #include <net/ieee80211_radiotap.h>
 #endif
@@ -48,6 +46,8 @@
 #include <linux/workqueue.h>
 #include <linux/mutex.h>
 
+#include "ieee80211.h"
+
 struct ipw2100_priv;
 struct ipw2100_tx_packet;
 struct ipw2100_rx_packet;
@@ -591,6 +591,10 @@ struct ipw2100_priv {
 
        int user_requested_scan;
 
+       /* Track time in suspend */
+       unsigned long suspend_at;
+       unsigned long suspend_time;
+
        u32 interrupts;
        int tx_interrupts;
        int rx_interrupts;
index 0420d3d35dd4c15c7ff3194f55fa11c5026ebb66..b3449948a25a92ca8ac3afe17d099530249f0601 100644 (file)
@@ -301,88 +301,102 @@ static inline void ipw_write_reg32(struct ipw_priv *a, u32 b, u32 c)
 }
 
 /* 8-bit direct write (low 4K) */
-#define _ipw_write8(ipw, ofs, val) writeb((val), (ipw)->hw_base + (ofs))
+static inline void _ipw_write8(struct ipw_priv *ipw, unsigned long ofs,
+               u8 val)
+{
+       writeb(val, ipw->hw_base + ofs);
+}
 
 /* 8-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
 #define ipw_write8(ipw, ofs, val) do { \
- IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \
- _ipw_write8(ipw, ofs, val); \
- } while (0)
+       IPW_DEBUG_IO("%s %d: write_direct8(0x%08X, 0x%08X)\n", __FILE__, \
+                       __LINE__, (u32)(ofs), (u32)(val)); \
+       _ipw_write8(ipw, ofs, val); \
+} while (0)
 
 /* 16-bit direct write (low 4K) */
-#define _ipw_write16(ipw, ofs, val) writew((val), (ipw)->hw_base + (ofs))
+static inline void _ipw_write16(struct ipw_priv *ipw, unsigned long ofs,
+               u16 val)
+{
+       writew(val, ipw->hw_base + ofs);
+}
 
 /* 16-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
-#define ipw_write16(ipw, ofs, val) \
- IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \
- _ipw_write16(ipw, ofs, val)
+#define ipw_write16(ipw, ofs, val) do { \
+       IPW_DEBUG_IO("%s %d: write_direct16(0x%08X, 0x%08X)\n", __FILE__, \
+                       __LINE__, (u32)(ofs), (u32)(val)); \
+       _ipw_write16(ipw, ofs, val); \
+} while (0)
 
 /* 32-bit direct write (low 4K) */
-#define _ipw_write32(ipw, ofs, val) writel((val), (ipw)->hw_base + (ofs))
+static inline void _ipw_write32(struct ipw_priv *ipw, unsigned long ofs,
+               u32 val)
+{
+       writel(val, ipw->hw_base + ofs);
+}
 
 /* 32-bit direct write (for low 4K of SRAM/regs), with debug wrapper */
-#define ipw_write32(ipw, ofs, val) \
- IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, __LINE__, (u32)(ofs), (u32)(val)); \
- _ipw_write32(ipw, ofs, val)
+#define ipw_write32(ipw, ofs, val) do { \
+       IPW_DEBUG_IO("%s %d: write_direct32(0x%08X, 0x%08X)\n", __FILE__, \
+                       __LINE__, (u32)(ofs), (u32)(val)); \
+       _ipw_write32(ipw, ofs, val); \
+} while (0)
 
 /* 8-bit direct read (low 4K) */
-#define _ipw_read8(ipw, ofs) readb((ipw)->hw_base + (ofs))
-
-/* 8-bit direct read (low 4K), with debug wrapper */
-static inline u8 __ipw_read8(char *f, u32 l, struct ipw_priv *ipw, u32 ofs)
+static inline u8 _ipw_read8(struct ipw_priv *ipw, unsigned long ofs)
 {
-       IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", f, l, (u32) (ofs));
-       return _ipw_read8(ipw, ofs);
+       return readb(ipw->hw_base + ofs);
 }
 
 /* alias to 8-bit direct read (low 4K of SRAM/regs), with debug wrapper */
-#define ipw_read8(ipw, ofs) __ipw_read8(__FILE__, __LINE__, ipw, ofs)
+#define ipw_read8(ipw, ofs) ({ \
+       IPW_DEBUG_IO("%s %d: read_direct8(0x%08X)\n", __FILE__, __LINE__, \
+                       (u32)(ofs)); \
+       _ipw_read8(ipw, ofs); \
+})
 
 /* 16-bit direct read (low 4K) */
-#define _ipw_read16(ipw, ofs) readw((ipw)->hw_base + (ofs))
-
-/* 16-bit direct read (low 4K), with debug wrapper */
-static inline u16 __ipw_read16(char *f, u32 l, struct ipw_priv *ipw, u32 ofs)
+static inline u16 _ipw_read16(struct ipw_priv *ipw, unsigned long ofs)
 {
-       IPW_DEBUG_IO("%s %d: read_direct16(0x%08X)\n", f, l, (u32) (ofs));
-       return _ipw_read16(ipw, ofs);
+       return readw(ipw->hw_base + ofs);
 }
 
 /* alias to 16-bit direct read (low 4K of SRAM/regs), with debug wrapper */
-#define ipw_read16(ipw, ofs) __ipw_read16(__FILE__, __LINE__, ipw, ofs)
+#define ipw_read16(ipw, ofs) ({ \
+       IPW_DEBUG_IO("%s %d: read_direct16(0x%08X)\n", __FILE__, __LINE__, \
+                       (u32)(ofs)); \
+       _ipw_read16(ipw, ofs); \
+})
 
 /* 32-bit direct read (low 4K) */
-#define _ipw_read32(ipw, ofs) readl((ipw)->hw_base + (ofs))
-
-/* 32-bit direct read (low 4K), with debug wrapper */
-static inline u32 __ipw_read32(char *f, u32 l, struct ipw_priv *ipw, u32 ofs)
+static inline u32 _ipw_read32(struct ipw_priv *ipw, unsigned long ofs)
 {
-       IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", f, l, (u32) (ofs));
-       return _ipw_read32(ipw, ofs);
+       return readl(ipw->hw_base + ofs);
 }
 
 /* alias to 32-bit direct read (low 4K of SRAM/regs), with debug wrapper */
-#define ipw_read32(ipw, ofs) __ipw_read32(__FILE__, __LINE__, ipw, ofs)
+#define ipw_read32(ipw, ofs) ({ \
+       IPW_DEBUG_IO("%s %d: read_direct32(0x%08X)\n", __FILE__, __LINE__, \
+                       (u32)(ofs)); \
+       _ipw_read32(ipw, ofs); \
+})
 
-/* multi-byte read (above 4K), with debug wrapper */
 static void _ipw_read_indirect(struct ipw_priv *, u32, u8 *, int);
-static inline void __ipw_read_indirect(const char *f, int l,
-                                      struct ipw_priv *a, u32 b, u8 * c, int d)
-{
-       IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %d bytes\n", f, l, (u32) (b),
-                    d);
-       _ipw_read_indirect(a, b, c, d);
-}
-
 /* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */
-#define ipw_read_indirect(a, b, c, d) __ipw_read_indirect(__FILE__, __LINE__, a, b, c, d)
+#define ipw_read_indirect(a, b, c, d) ({ \
+       IPW_DEBUG_IO("%s %d: read_indirect(0x%08X) %u bytes\n", __FILE__, \
+                       __LINE__, (u32)(b), (u32)(d)); \
+       _ipw_read_indirect(a, b, c, d); \
+})
 
 /* alias to multi-byte read (SRAM/regs above 4K), with debug wrapper */
 static void _ipw_write_indirect(struct ipw_priv *priv, u32 addr, u8 * data,
                                int num);
-#define ipw_write_indirect(a, b, c, d) \
-       IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %d bytes\n", __FILE__, __LINE__, (u32)(b), d); \
-       _ipw_write_indirect(a, b, c, d)
+#define ipw_write_indirect(a, b, c, d) do { \
+       IPW_DEBUG_IO("%s %d: write_indirect(0x%08X) %u bytes\n", __FILE__, \
+                       __LINE__, (u32)(b), (u32)(d)); \
+       _ipw_write_indirect(a, b, c, d); \
+} while (0)
 
 /* 32-bit indirect write (above 4K) */
 static void _ipw_write_reg32(struct ipw_priv *priv, u32 reg, u32 value)
@@ -7717,22 +7731,23 @@ static void ipw_handle_data_packet(struct ipw_priv *priv,
                                   struct ipw_rx_mem_buffer *rxb,
                                   struct ieee80211_rx_stats *stats)
 {
+       struct net_device *dev = priv->net_dev;
        struct ieee80211_hdr_4addr *hdr;
        struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
 
        /* We received data from the HW, so stop the watchdog */
-       priv->net_dev->trans_start = jiffies;
+       dev->trans_start = jiffies;
 
        /* We only process data packets if the
         * interface is open */
        if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) >
                     skb_tailroom(rxb->skb))) {
-               priv->ieee->stats.rx_errors++;
+               dev->stats.rx_errors++;
                priv->wstats.discard.misc++;
                IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
                return;
        } else if (unlikely(!netif_running(priv->net_dev))) {
-               priv->ieee->stats.rx_dropped++;
+               dev->stats.rx_dropped++;
                priv->wstats.discard.misc++;
                IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
                return;
@@ -7754,7 +7769,7 @@ static void ipw_handle_data_packet(struct ipw_priv *priv,
                ipw_rebuild_decrypted_skb(priv, rxb->skb);
 
        if (!ieee80211_rx(priv->ieee, rxb->skb, stats))
-               priv->ieee->stats.rx_errors++;
+               dev->stats.rx_errors++;
        else {                  /* ieee80211_rx succeeded, so it now owns the SKB */
                rxb->skb = NULL;
                __ipw_led_activity_on(priv);
@@ -7766,6 +7781,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
                                           struct ipw_rx_mem_buffer *rxb,
                                           struct ieee80211_rx_stats *stats)
 {
+       struct net_device *dev = priv->net_dev;
        struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
        struct ipw_rx_frame *frame = &pkt->u.frame;
 
@@ -7783,18 +7799,18 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
        short len = le16_to_cpu(pkt->u.frame.length);
 
        /* We received data from the HW, so stop the watchdog */
-       priv->net_dev->trans_start = jiffies;
+       dev->trans_start = jiffies;
 
        /* We only process data packets if the
         * interface is open */
        if (unlikely((le16_to_cpu(pkt->u.frame.length) + IPW_RX_FRAME_SIZE) >
                     skb_tailroom(rxb->skb))) {
-               priv->ieee->stats.rx_errors++;
+               dev->stats.rx_errors++;
                priv->wstats.discard.misc++;
                IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
                return;
        } else if (unlikely(!netif_running(priv->net_dev))) {
-               priv->ieee->stats.rx_dropped++;
+               dev->stats.rx_dropped++;
                priv->wstats.discard.misc++;
                IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
                return;
@@ -7804,7 +7820,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
         * that now */
        if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) {
                /* FIXME: Should alloc bigger skb instead */
-               priv->ieee->stats.rx_dropped++;
+               dev->stats.rx_dropped++;
                priv->wstats.discard.misc++;
                IPW_DEBUG_DROP("Dropping too large packet in monitor\n");
                return;
@@ -7910,7 +7926,7 @@ static void ipw_handle_data_packet_monitor(struct ipw_priv *priv,
        IPW_DEBUG_RX("Rx packet of %d bytes.\n", rxb->skb->len);
 
        if (!ieee80211_rx(priv->ieee, rxb->skb, stats))
-               priv->ieee->stats.rx_errors++;
+               dev->stats.rx_errors++;
        else {                  /* ieee80211_rx succeeded, so it now owns the SKB */
                rxb->skb = NULL;
                /* no LED during capture */
@@ -7942,6 +7958,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
                                      struct ipw_rx_mem_buffer *rxb,
                                      struct ieee80211_rx_stats *stats)
 {
+       struct net_device *dev = priv->prom_net_dev;
        struct ipw_rx_packet *pkt = (struct ipw_rx_packet *)rxb->skb->data;
        struct ipw_rx_frame *frame = &pkt->u.frame;
        struct ipw_rt_hdr *ipw_rt;
@@ -7964,17 +7981,17 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
                return;
 
        /* We received data from the HW, so stop the watchdog */
-       priv->prom_net_dev->trans_start = jiffies;
+       dev->trans_start = jiffies;
 
        if (unlikely((len + IPW_RX_FRAME_SIZE) > skb_tailroom(rxb->skb))) {
-               priv->prom_priv->ieee->stats.rx_errors++;
+               dev->stats.rx_errors++;
                IPW_DEBUG_DROP("Corruption detected! Oh no!\n");
                return;
        }
 
        /* We only process data packets if the interface is open */
-       if (unlikely(!netif_running(priv->prom_net_dev))) {
-               priv->prom_priv->ieee->stats.rx_dropped++;
+       if (unlikely(!netif_running(dev))) {
+               dev->stats.rx_dropped++;
                IPW_DEBUG_DROP("Dropping packet while interface is not up.\n");
                return;
        }
@@ -7983,7 +8000,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
         * that now */
        if (len > IPW_RX_BUF_SIZE - sizeof(struct ipw_rt_hdr)) {
                /* FIXME: Should alloc bigger skb instead */
-               priv->prom_priv->ieee->stats.rx_dropped++;
+               dev->stats.rx_dropped++;
                IPW_DEBUG_DROP("Dropping too large packet in monitor\n");
                return;
        }
@@ -8115,7 +8132,7 @@ static void ipw_handle_promiscuous_rx(struct ipw_priv *priv,
        IPW_DEBUG_RX("Rx packet of %d bytes.\n", skb->len);
 
        if (!ieee80211_rx(priv->prom_priv->ieee, skb, stats)) {
-               priv->prom_priv->ieee->stats.rx_errors++;
+               dev->stats.rx_errors++;
                dev_kfree_skb_any(skb);
        }
 }
@@ -8399,7 +8416,7 @@ static void ipw_rx(struct ipw_priv *priv)
                                        IPW_DEBUG_DROP
                                            ("Received packet is too small. "
                                             "Dropping.\n");
-                                       priv->ieee->stats.rx_errors++;
+                                       priv->net_dev->stats.rx_errors++;
                                        priv->wstats.discard.misc++;
                                        break;
                                }
@@ -10470,15 +10487,6 @@ static int ipw_net_hard_start_xmit(struct ieee80211_txb *txb,
        return ret;
 }
 
-static struct net_device_stats *ipw_net_get_stats(struct net_device *dev)
-{
-       struct ipw_priv *priv = ieee80211_priv(dev);
-
-       priv->ieee->stats.tx_packets = priv->tx_packets;
-       priv->ieee->stats.rx_packets = priv->rx_packets;
-       return &priv->ieee->stats;
-}
-
 static void ipw_net_set_multicast_list(struct net_device *dev)
 {
 
@@ -11224,6 +11232,12 @@ static int ipw_up(struct ipw_priv *priv)
 {
        int rc, i, j;
 
+       /* Age scan list entries found before suspend */
+       if (priv->suspend_time) {
+               ieee80211_networks_age(priv->ieee, priv->suspend_time);
+               priv->suspend_time = 0;
+       }
+
        if (priv->status & STATUS_EXIT_PENDING)
                return -EIO;
 
@@ -11515,11 +11529,14 @@ static int ipw_prom_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        return -EOPNOTSUPP;
 }
 
-static struct net_device_stats *ipw_prom_get_stats(struct net_device *dev)
-{
-       struct ipw_prom_priv *prom_priv = ieee80211_priv(dev);
-       return &prom_priv->ieee->stats;
-}
+static const struct net_device_ops ipw_prom_netdev_ops = {
+       .ndo_open               = ipw_prom_open,
+       .ndo_stop               = ipw_prom_stop,
+       .ndo_start_xmit         = ipw_prom_hard_start_xmit,
+       .ndo_change_mtu         = ieee80211_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
 
 static int ipw_prom_alloc(struct ipw_priv *priv)
 {
@@ -11540,10 +11557,7 @@ static int ipw_prom_alloc(struct ipw_priv *priv)
        memcpy(priv->prom_net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
 
        priv->prom_net_dev->type = ARPHRD_IEEE80211_RADIOTAP;
-       priv->prom_net_dev->open = ipw_prom_open;
-       priv->prom_net_dev->stop = ipw_prom_stop;
-       priv->prom_net_dev->get_stats = ipw_prom_get_stats;
-       priv->prom_net_dev->hard_start_xmit = ipw_prom_hard_start_xmit;
+       priv->prom_net_dev->netdev_ops = &ipw_prom_netdev_ops;
 
        priv->prom_priv->ieee->iw_mode = IW_MODE_MONITOR;
        SET_NETDEV_DEV(priv->prom_net_dev, &priv->pci_dev->dev);
@@ -11571,6 +11585,17 @@ static void ipw_prom_free(struct ipw_priv *priv)
 
 #endif
 
+static const struct net_device_ops ipw_netdev_ops = {
+       .ndo_init               = ipw_net_init,
+       .ndo_open               = ipw_net_open,
+       .ndo_stop               = ipw_net_stop,
+       .ndo_set_multicast_list = ipw_net_set_multicast_list,
+       .ndo_set_mac_address    = ipw_net_set_mac_address,
+       .ndo_start_xmit         = ieee80211_xmit,
+       .ndo_change_mtu         = ieee80211_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
 
 static int __devinit ipw_pci_probe(struct pci_dev *pdev,
                                   const struct pci_device_id *ent)
@@ -11672,12 +11697,7 @@ static int __devinit ipw_pci_probe(struct pci_dev *pdev,
        priv->ieee->perfect_rssi = -20;
        priv->ieee->worst_rssi = -85;
 
-       net_dev->open = ipw_net_open;
-       net_dev->stop = ipw_net_stop;
-       net_dev->init = ipw_net_init;
-       net_dev->get_stats = ipw_net_get_stats;
-       net_dev->set_multicast_list = ipw_net_set_multicast_list;
-       net_dev->set_mac_address = ipw_net_set_mac_address;
+       net_dev->netdev_ops = &ipw_netdev_ops;
        priv->wireless_data.spy_data = &priv->ieee->spy_data;
        net_dev->wireless_data = &priv->wireless_data;
        net_dev->wireless_handlers = &ipw_wx_handler_def;
@@ -11824,6 +11844,8 @@ static int ipw_pci_suspend(struct pci_dev *pdev, pm_message_t state)
        pci_disable_device(pdev);
        pci_set_power_state(pdev, pci_choose_state(pdev, state));
 
+       priv->suspend_at = get_seconds();
+
        return 0;
 }
 
@@ -11859,6 +11881,8 @@ static int ipw_pci_resume(struct pci_dev *pdev)
         * the queue of needed */
        netif_device_attach(dev);
 
+       priv->suspend_time = get_seconds() - priv->suspend_at;
+
        /* Bring the device back up */
        queue_work(priv->workqueue, &priv->up);
 
index 277b274d4be5d10f6552d5273591895cc138a460..05e8ccf01c5ff907bdfa07dbc937090bd32f29db 100644 (file)
 #include <asm/io.h>
 
 #include <net/lib80211.h>
-#include <net/ieee80211.h>
 #include <net/ieee80211_radiotap.h>
 
 #define DRV_NAME       "ipw2200"
 
 #include <linux/workqueue.h>
 
+#include "ieee80211.h"
+
 /* Authentication  and Association States */
 enum connection_manager_assoc_states {
        CMAS_INIT = 0,
@@ -1346,6 +1347,10 @@ struct ipw_priv {
 
        s8 tx_power;
 
+       /* Track time in suspend */
+       unsigned long suspend_at;
+       unsigned long suspend_time;
+
 #ifdef CONFIG_PM
        u32 pm_state[16];
 #endif
index 960ad13f5e9f41fc724aff31ee842dcaaf4a5e23..9dfbb8760f67833d7a7c0f476fef8e0309715b1e 100644 (file)
@@ -41,7 +41,7 @@
 #include <linux/etherdevice.h>
 #include <asm/uaccess.h>
 
-#include <net/ieee80211.h>
+#include "ieee80211.h"
 
 int ieee80211_is_valid_channel(struct ieee80211_device *ieee, u8 channel)
 {
index a2f5616d5b095a2f80bea548871fbac24f05f751..92a26922e792d73721a2e4ca0ed3c2c3a125fcb5 100644 (file)
@@ -50,7 +50,7 @@
 #include <net/net_namespace.h>
 #include <net/arp.h>
 
-#include <net/ieee80211.h>
+#include "ieee80211.h"
 
 #define DRV_DESCRIPTION "802.11 data/management/control stack"
 #define DRV_NAME        "ieee80211"
@@ -105,6 +105,21 @@ static inline void ieee80211_networks_free(struct ieee80211_device *ieee)
        ieee->networks = NULL;
 }
 
+void ieee80211_networks_age(struct ieee80211_device *ieee,
+                            unsigned long age_secs)
+{
+       struct ieee80211_network *network = NULL;
+       unsigned long flags;
+       unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
+
+       spin_lock_irqsave(&ieee->lock, flags);
+       list_for_each_entry(network, &ieee->network_list, list) {
+               network->last_scanned -= age_jiffies;
+       }
+       spin_unlock_irqrestore(&ieee->lock, flags);
+}
+EXPORT_SYMBOL(ieee80211_networks_age);
+
 static void ieee80211_networks_initialize(struct ieee80211_device *ieee)
 {
        int i;
@@ -116,20 +131,14 @@ static void ieee80211_networks_initialize(struct ieee80211_device *ieee)
                              &ieee->network_free_list);
 }
 
-static int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
+int ieee80211_change_mtu(struct net_device *dev, int new_mtu)
 {
        if ((new_mtu < 68) || (new_mtu > IEEE80211_DATA_LEN))
                return -EINVAL;
        dev->mtu = new_mtu;
        return 0;
 }
-
-static struct net_device_stats *ieee80211_generic_get_stats(
-       struct net_device *dev)
-{
-       struct ieee80211_device *ieee = netdev_priv(dev);
-       return &ieee->stats;
-}
+EXPORT_SYMBOL(ieee80211_change_mtu);
 
 struct net_device *alloc_ieee80211(int sizeof_priv)
 {
@@ -145,12 +154,10 @@ struct net_device *alloc_ieee80211(int sizeof_priv)
                goto failed;
        }
        ieee = netdev_priv(dev);
+#ifdef CONFIG_COMPAT_NET_DEV_OPS
        dev->hard_start_xmit = ieee80211_xmit;
        dev->change_mtu = ieee80211_change_mtu;
-
-       /* Drivers are free to override this if the generic implementation
-        * does not meet their needs. */
-       dev->get_stats = ieee80211_generic_get_stats;
+#endif
 
        ieee->dev = dev;
 
@@ -206,7 +213,7 @@ void free_ieee80211(struct net_device *dev)
        free_netdev(dev);
 }
 
-#ifdef CONFIG_IEEE80211_DEBUG
+#ifdef CONFIG_LIBIPW_DEBUG
 
 static int debug = 0;
 u32 ieee80211_debug_level = 0;
@@ -237,11 +244,11 @@ static int store_debug_level(struct file *file, const char __user * buffer,
 
        return strnlen(buf, len);
 }
-#endif                         /* CONFIG_IEEE80211_DEBUG */
+#endif                         /* CONFIG_LIBIPW_DEBUG */
 
 static int __init ieee80211_init(void)
 {
-#ifdef CONFIG_IEEE80211_DEBUG
+#ifdef CONFIG_LIBIPW_DEBUG
        struct proc_dir_entry *e;
 
        ieee80211_debug_level = debug;
@@ -261,7 +268,7 @@ static int __init ieee80211_init(void)
        e->read_proc = show_debug_level;
        e->write_proc = store_debug_level;
        e->data = NULL;
-#endif                         /* CONFIG_IEEE80211_DEBUG */
+#endif                         /* CONFIG_LIBIPW_DEBUG */
 
        printk(KERN_INFO DRV_NAME ": " DRV_DESCRIPTION ", " DRV_VERSION "\n");
        printk(KERN_INFO DRV_NAME ": " DRV_COPYRIGHT "\n");
@@ -271,20 +278,20 @@ static int __init ieee80211_init(void)
 
 static void __exit ieee80211_exit(void)
 {
-#ifdef CONFIG_IEEE80211_DEBUG
+#ifdef CONFIG_LIBIPW_DEBUG
        if (ieee80211_proc) {
                remove_proc_entry("debug_level", ieee80211_proc);
                remove_proc_entry(DRV_NAME, init_net.proc_net);
                ieee80211_proc = NULL;
        }
-#endif                         /* CONFIG_IEEE80211_DEBUG */
+#endif                         /* CONFIG_LIBIPW_DEBUG */
 }
 
-#ifdef CONFIG_IEEE80211_DEBUG
+#ifdef CONFIG_LIBIPW_DEBUG
 #include <linux/moduleparam.h>
 module_param(debug, int, 0444);
 MODULE_PARM_DESC(debug, "debug output mask");
-#endif                         /* CONFIG_IEEE80211_DEBUG */
+#endif                         /* CONFIG_LIBIPW_DEBUG */
 
 module_exit(ieee80211_exit);
 module_init(ieee80211_init);
index 9c67dfae43200c0e0516abfc794e906be98539b9..dae4b8e4d8e9a3cf9c965e3e6ed0a2661f1c5865 100644 (file)
@@ -33,7 +33,8 @@
 #include <linux/ctype.h>
 
 #include <net/lib80211.h>
-#include <net/ieee80211.h>
+
+#include "ieee80211.h"
 
 static void ieee80211_monitor_rx(struct ieee80211_device *ieee,
                                        struct sk_buff *skb,
@@ -334,7 +335,6 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
        struct ieee80211_hdr_4addr *hdr;
        size_t hdrlen;
        u16 fc, type, stype, sc;
-       struct net_device_stats *stats;
        unsigned int frag;
        u8 *payload;
        u16 ethertype;
@@ -353,8 +353,6 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
        int can_be_decrypted = 0;
 
        hdr = (struct ieee80211_hdr_4addr *)skb->data;
-       stats = &ieee->stats;
-
        if (skb->len < 10) {
                printk(KERN_INFO "%s: SKB length < 10\n", dev->name);
                goto rx_dropped;
@@ -411,8 +409,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
 #endif
 
        if (ieee->iw_mode == IW_MODE_MONITOR) {
-               stats->rx_packets++;
-               stats->rx_bytes += skb->len;
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += skb->len;
                ieee80211_monitor_rx(ieee, skb, rx_stats);
                return 1;
        }
@@ -768,8 +766,8 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
        }
 #endif
 
-       stats->rx_packets++;
-       stats->rx_bytes += skb->len;
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += skb->len;
 
 #ifdef NOT_YET
        if (ieee->iw_mode == IW_MODE_MASTER && !wds && ieee->ap->bridge_packets) {
@@ -811,7 +809,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
                         * in our stats. */
                        IEEE80211_DEBUG_DROP
                            ("RX: netif_rx dropped the packet\n");
-                       stats->rx_dropped++;
+                       dev->stats.rx_dropped++;
                }
        }
 
@@ -823,7 +821,7 @@ int ieee80211_rx(struct ieee80211_device *ieee, struct sk_buff *skb,
        return 1;
 
       rx_dropped:
-       stats->rx_dropped++;
+       dev->stats.rx_dropped++;
 
        /* Returning 0 indicates to caller that we have not handled the SKB--
         * so it is still allocated and can be used again by underlying
@@ -918,7 +916,7 @@ void ieee80211_rx_any(struct ieee80211_device *ieee,
 
 drop_free:
        dev_kfree_skb_irq(skb);
-       ieee->stats.rx_dropped++;
+       ieee->dev->stats.rx_dropped++;
        return;
 }
 
@@ -1079,37 +1077,37 @@ static int ieee80211_parse_qos_info_param_IE(struct ieee80211_info_element
        return rc;
 }
 
-#ifdef CONFIG_IEEE80211_DEBUG
-#define MFIE_STRING(x) case MFIE_TYPE_ ##x: return #x
+#ifdef CONFIG_LIBIPW_DEBUG
+#define MFIE_STRING(x) case WLAN_EID_ ##x: return #x
 
 static const char *get_info_element_string(u16 id)
 {
        switch (id) {
                MFIE_STRING(SSID);
-               MFIE_STRING(RATES);
-               MFIE_STRING(FH_SET);
-               MFIE_STRING(DS_SET);
-               MFIE_STRING(CF_SET);
+               MFIE_STRING(SUPP_RATES);
+               MFIE_STRING(FH_PARAMS);
+               MFIE_STRING(DS_PARAMS);
+               MFIE_STRING(CF_PARAMS);
                MFIE_STRING(TIM);
-               MFIE_STRING(IBSS_SET);
+               MFIE_STRING(IBSS_PARAMS);
                MFIE_STRING(COUNTRY);
-               MFIE_STRING(HOP_PARAMS);
-               MFIE_STRING(HOP_TABLE);
+               MFIE_STRING(HP_PARAMS);
+               MFIE_STRING(HP_TABLE);
                MFIE_STRING(REQUEST);
                MFIE_STRING(CHALLENGE);
-               MFIE_STRING(POWER_CONSTRAINT);
-               MFIE_STRING(POWER_CAPABILITY);
+               MFIE_STRING(PWR_CONSTRAINT);
+               MFIE_STRING(PWR_CAPABILITY);
                MFIE_STRING(TPC_REQUEST);
                MFIE_STRING(TPC_REPORT);
-               MFIE_STRING(SUPP_CHANNELS);
-               MFIE_STRING(CSA);
+               MFIE_STRING(SUPPORTED_CHANNELS);
+               MFIE_STRING(CHANNEL_SWITCH);
                MFIE_STRING(MEASURE_REQUEST);
                MFIE_STRING(MEASURE_REPORT);
                MFIE_STRING(QUIET);
                MFIE_STRING(IBSS_DFS);
                MFIE_STRING(ERP_INFO);
                MFIE_STRING(RSN);
-               MFIE_STRING(RATES_EX);
+               MFIE_STRING(EXT_SUPP_RATES);
                MFIE_STRING(GENERIC);
                MFIE_STRING(QOS_PARAMETER);
        default:
@@ -1124,7 +1122,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
 {
        DECLARE_SSID_BUF(ssid);
        u8 i;
-#ifdef CONFIG_IEEE80211_DEBUG
+#ifdef CONFIG_LIBIPW_DEBUG
        char rates_str[64];
        char *p;
 #endif
@@ -1144,7 +1142,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
                }
 
                switch (info_element->id) {
-               case MFIE_TYPE_SSID:
+               case WLAN_EID_SSID:
                        network->ssid_len = min(info_element->len,
                                                (u8) IW_ESSID_MAX_SIZE);
                        memcpy(network->ssid, info_element->data,
@@ -1153,21 +1151,21 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
                                memset(network->ssid + network->ssid_len, 0,
                                       IW_ESSID_MAX_SIZE - network->ssid_len);
 
-                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_SSID: '%s' len=%d.\n",
+                       IEEE80211_DEBUG_MGMT("WLAN_EID_SSID: '%s' len=%d.\n",
                                             print_ssid(ssid, network->ssid,
                                                        network->ssid_len),
                                             network->ssid_len);
                        break;
 
-               case MFIE_TYPE_RATES:
-#ifdef CONFIG_IEEE80211_DEBUG
+               case WLAN_EID_SUPP_RATES:
+#ifdef CONFIG_LIBIPW_DEBUG
                        p = rates_str;
 #endif
                        network->rates_len = min(info_element->len,
                                                 MAX_RATES_LENGTH);
                        for (i = 0; i < network->rates_len; i++) {
                                network->rates[i] = info_element->data[i];
-#ifdef CONFIG_IEEE80211_DEBUG
+#ifdef CONFIG_LIBIPW_DEBUG
                                p += snprintf(p, sizeof(rates_str) -
                                              (p - rates_str), "%02X ",
                                              network->rates[i]);
@@ -1182,19 +1180,19 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
                                }
                        }
 
-                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES: '%s' (%d)\n",
+                       IEEE80211_DEBUG_MGMT("WLAN_EID_SUPP_RATES: '%s' (%d)\n",
                                             rates_str, network->rates_len);
                        break;
 
-               case MFIE_TYPE_RATES_EX:
-#ifdef CONFIG_IEEE80211_DEBUG
+               case WLAN_EID_EXT_SUPP_RATES:
+#ifdef CONFIG_LIBIPW_DEBUG
                        p = rates_str;
 #endif
                        network->rates_ex_len = min(info_element->len,
                                                    MAX_RATES_EX_LENGTH);
                        for (i = 0; i < network->rates_ex_len; i++) {
                                network->rates_ex[i] = info_element->data[i];
-#ifdef CONFIG_IEEE80211_DEBUG
+#ifdef CONFIG_LIBIPW_DEBUG
                                p += snprintf(p, sizeof(rates_str) -
                                              (p - rates_str), "%02X ",
                                              network->rates[i]);
@@ -1209,49 +1207,49 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
                                }
                        }
 
-                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_RATES_EX: '%s' (%d)\n",
+                       IEEE80211_DEBUG_MGMT("WLAN_EID_EXT_SUPP_RATES: '%s' (%d)\n",
                                             rates_str, network->rates_ex_len);
                        break;
 
-               case MFIE_TYPE_DS_SET:
-                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_DS_SET: %d\n",
+               case WLAN_EID_DS_PARAMS:
+                       IEEE80211_DEBUG_MGMT("WLAN_EID_DS_PARAMS: %d\n",
                                             info_element->data[0]);
                        network->channel = info_element->data[0];
                        break;
 
-               case MFIE_TYPE_FH_SET:
-                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_FH_SET: ignored\n");
+               case WLAN_EID_FH_PARAMS:
+                       IEEE80211_DEBUG_MGMT("WLAN_EID_FH_PARAMS: ignored\n");
                        break;
 
-               case MFIE_TYPE_CF_SET:
-                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_CF_SET: ignored\n");
+               case WLAN_EID_CF_PARAMS:
+                       IEEE80211_DEBUG_MGMT("WLAN_EID_CF_PARAMS: ignored\n");
                        break;
 
-               case MFIE_TYPE_TIM:
+               case WLAN_EID_TIM:
                        network->tim.tim_count = info_element->data[0];
                        network->tim.tim_period = info_element->data[1];
-                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_TIM: partially ignored\n");
+                       IEEE80211_DEBUG_MGMT("WLAN_EID_TIM: partially ignored\n");
                        break;
 
-               case MFIE_TYPE_ERP_INFO:
+               case WLAN_EID_ERP_INFO:
                        network->erp_value = info_element->data[0];
                        network->flags |= NETWORK_HAS_ERP_VALUE;
                        IEEE80211_DEBUG_MGMT("MFIE_TYPE_ERP_SET: %d\n",
                                             network->erp_value);
                        break;
 
-               case MFIE_TYPE_IBSS_SET:
+               case WLAN_EID_IBSS_PARAMS:
                        network->atim_window = info_element->data[0];
-                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_IBSS_SET: %d\n",
+                       IEEE80211_DEBUG_MGMT("WLAN_EID_IBSS_PARAMS: %d\n",
                                             network->atim_window);
                        break;
 
-               case MFIE_TYPE_CHALLENGE:
-                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_CHALLENGE: ignored\n");
+               case WLAN_EID_CHALLENGE:
+                       IEEE80211_DEBUG_MGMT("WLAN_EID_CHALLENGE: ignored\n");
                        break;
 
-               case MFIE_TYPE_GENERIC:
-                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_GENERIC: %d bytes\n",
+               case WLAN_EID_GENERIC:
+                       IEEE80211_DEBUG_MGMT("WLAN_EID_GENERIC: %d bytes\n",
                                             info_element->len);
                        if (!ieee80211_parse_qos_info_param_IE(info_element,
                                                               network))
@@ -1269,8 +1267,8 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
                        }
                        break;
 
-               case MFIE_TYPE_RSN:
-                       IEEE80211_DEBUG_MGMT("MFIE_TYPE_RSN: %d bytes\n",
+               case WLAN_EID_RSN:
+                       IEEE80211_DEBUG_MGMT("WLAN_EID_RSN: %d bytes\n",
                                             info_element->len);
                        network->rsn_ie_len = min(info_element->len + 2,
                                                  MAX_WPA_IE_LEN);
@@ -1278,22 +1276,22 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
                               network->rsn_ie_len);
                        break;
 
-               case MFIE_TYPE_QOS_PARAMETER:
+               case WLAN_EID_QOS_PARAMETER:
                        printk(KERN_ERR
                               "QoS Error need to parse QOS_PARAMETER IE\n");
                        break;
                        /* 802.11h */
-               case MFIE_TYPE_POWER_CONSTRAINT:
+               case WLAN_EID_PWR_CONSTRAINT:
                        network->power_constraint = info_element->data[0];
                        network->flags |= NETWORK_HAS_POWER_CONSTRAINT;
                        break;
 
-               case MFIE_TYPE_CSA:
+               case WLAN_EID_CHANNEL_SWITCH:
                        network->power_constraint = info_element->data[0];
                        network->flags |= NETWORK_HAS_CSA;
                        break;
 
-               case MFIE_TYPE_QUIET:
+               case WLAN_EID_QUIET:
                        network->quiet.count = info_element->data[0];
                        network->quiet.period = info_element->data[1];
                        network->quiet.duration = info_element->data[2];
@@ -1301,7 +1299,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
                        network->flags |= NETWORK_HAS_QUIET;
                        break;
 
-               case MFIE_TYPE_IBSS_DFS:
+               case WLAN_EID_IBSS_DFS:
                        if (network->ibss_dfs)
                                break;
                        network->ibss_dfs = kmemdup(info_element->data,
@@ -1312,7 +1310,7 @@ static int ieee80211_parse_info_param(struct ieee80211_info_element
                        network->flags |= NETWORK_HAS_IBSS_DFS;
                        break;
 
-               case MFIE_TYPE_TPC_REPORT:
+               case WLAN_EID_TPC_REPORT:
                        network->tpc_report.transmit_power =
                            info_element->data[0];
                        network->tpc_report.link_margin = info_element->data[1];
@@ -1561,7 +1559,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device
        };
        struct ieee80211_network *target;
        struct ieee80211_network *oldest = NULL;
-#ifdef CONFIG_IEEE80211_DEBUG
+#ifdef CONFIG_LIBIPW_DEBUG
        struct ieee80211_info_element *info_element = beacon->info_element;
 #endif
        unsigned long flags;
@@ -1615,7 +1613,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device
                        break;
 
                if ((oldest == NULL) ||
-                   (target->last_scanned < oldest->last_scanned))
+                   time_before(target->last_scanned, oldest->last_scanned))
                        oldest = target;
        }
 
@@ -1639,7 +1637,7 @@ static void ieee80211_process_probe_response(struct ieee80211_device
                        list_del(ieee->network_free_list.next);
                }
 
-#ifdef CONFIG_IEEE80211_DEBUG
+#ifdef CONFIG_LIBIPW_DEBUG
                IEEE80211_DEBUG_SCAN("Adding '%s' (%pM) via %s.\n",
                                     print_ssid(ssid, network.ssid,
                                                 network.ssid_len),
index f78f57e8844a9c1eb2d08bbc9b3f4ba6a66b9b94..65a8195b3d90c89fb8c3ace8954827c9a7f5908d 100644 (file)
@@ -41,7 +41,7 @@
 #include <linux/etherdevice.h>
 #include <asm/uaccess.h>
 
-#include <net/ieee80211.h>
+#include "ieee80211.h"
 
 /*
 
@@ -260,7 +260,6 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
        int i, bytes_per_frag, nr_frags, bytes_last_frag, frag_size,
            rts_required;
        unsigned long flags;
-       struct net_device_stats *stats = &ieee->stats;
        int encrypt, host_encrypt, host_encrypt_msdu, host_build_iv;
        __be16 ether_type;
        int bytes, fc, hdr_len;
@@ -306,7 +305,7 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
 
        if (!encrypt && ieee->ieee802_1x &&
            ieee->drop_unencrypted && ether_type != htons(ETH_P_PAE)) {
-               stats->tx_dropped++;
+               dev->stats.tx_dropped++;
                goto success;
        }
 
@@ -526,8 +525,8 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
        if (txb) {
                int ret = (*ieee->hard_start_xmit) (txb, dev, priority);
                if (ret == 0) {
-                       stats->tx_packets++;
-                       stats->tx_bytes += txb->payload_size;
+                       dev->stats.tx_packets++;
+                       dev->stats.tx_bytes += txb->payload_size;
                        return 0;
                }
 
@@ -539,8 +538,9 @@ int ieee80211_xmit(struct sk_buff *skb, struct net_device *dev)
       failed:
        spin_unlock_irqrestore(&ieee->lock, flags);
        netif_stop_queue(dev);
-       stats->tx_errors++;
+       dev->stats.tx_errors++;
        return 1;
 }
+EXPORT_SYMBOL(ieee80211_xmit);
 
 EXPORT_SYMBOL(ieee80211_txb_free);
index 31ea3abfc3277cb672d930007992dd504276186e..3c0812db030a0389c2400f933dc8ff1c069cce4d 100644 (file)
 #include <linux/jiffies.h>
 
 #include <net/lib80211.h>
-#include <net/ieee80211.h>
 #include <linux/wireless.h>
 
+#include "ieee80211.h"
+
 static const char *ieee80211_modes[] = {
        "?", "a", "b", "ab", "g", "ag", "bg", "abg"
 };
 
+static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
+{
+       unsigned long end = jiffies;
+
+       if (end >= start)
+               return jiffies_to_msecs(end - start);
+
+       return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1);
+}
+
 #define MAX_CUSTOM_LEN 64
 static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
                                      char *start, char *stop,
@@ -215,8 +226,8 @@ static char *ieee80211_translate_scan(struct ieee80211_device *ieee,
        iwe.cmd = IWEVCUSTOM;
        p = custom;
        p += snprintf(p, MAX_CUSTOM_LEN - (p - custom),
-                     " Last beacon: %dms ago",
-                     jiffies_to_msecs(jiffies - network->last_scanned));
+                     " Last beacon: %ums ago",
+                     elapsed_jiffies_msecs(network->last_scanned));
        iwe.u.data.length = p - custom;
        if (iwe.u.data.length)
                start = iwe_stream_add_point(info, start, stop, &iwe, custom);
@@ -276,15 +287,15 @@ int ieee80211_wx_get_scan(struct ieee80211_device *ieee,
                    time_after(network->last_scanned + ieee->scan_age, jiffies))
                        ev = ieee80211_translate_scan(ieee, ev, stop, network,
                                                      info);
-               else
+               else {
                        IEEE80211_DEBUG_SCAN("Not showing network '%s ("
-                                            "%pM)' due to age (%dms).\n",
+                                            "%pM)' due to age (%ums).\n",
                                             print_ssid(ssid, network->ssid,
                                                         network->ssid_len),
                                             network->bssid,
-                                            jiffies_to_msecs(jiffies -
-                                                             network->
-                                                             last_scanned));
+                                            elapsed_jiffies_msecs(
+                                                      network->last_scanned));
+               }
        }
 
        spin_unlock_irqrestore(&ieee->lock, flags);
index 7b3bad1796c7f12250057eeb0a9de0a0b7cc1be0..8304f6406a175230173b73c577523b286797c5f0 100644 (file)
@@ -1,27 +1,29 @@
 config IWLWIFI
-       bool "Intel Wireless Wifi"
+       tristate "Intel Wireless Wifi"
        depends on PCI && MAC80211 && WLAN_80211 && EXPERIMENTAL
-       default y
-
-config IWLCORE
-       tristate "Intel Wireless Wifi Core"
-       depends on IWLWIFI
        select LIB80211
+       select FW_LOADER
        select MAC80211_LEDS if IWLWIFI_LEDS
        select LEDS_CLASS if IWLWIFI_LEDS
        select RFKILL if IWLWIFI_RFKILL
 
 config IWLWIFI_LEDS
-       bool "Enable LED support in iwlagn driver"
-       depends on IWLCORE
+       bool "Enable LED support in iwlagn and iwl3945 drivers"
+       depends on IWLWIFI
 
 config IWLWIFI_RFKILL
-       bool "Enable RF kill support in iwlagn driver"
-       depends on IWLCORE
+       bool "Enable RF kill support in iwlagn and iwl3945 drivers"
+       depends on IWLWIFI
+
+config IWLWIFI_SPECTRUM_MEASUREMENT
+       bool "Enable Spectrum Measurement in iwlagn driver"
+       depends on IWLWIFI
+       ---help---
+         This option will enable spectrum measurement for the iwlagn driver.
 
 config IWLWIFI_DEBUG
        bool "Enable full debugging output in iwlagn and iwl3945 drivers"
-       depends on IWLCORE
+       depends on IWLWIFI
        ---help---
          This option will enable debug tracing output for the iwlwifi drivers
 
@@ -45,16 +47,14 @@ config IWLWIFI_DEBUG
          any problems you may encounter.
 
 config IWLWIFI_DEBUGFS
-        bool "Iwlwifi debugfs support"
-        depends on IWLCORE && IWLWIFI_DEBUG && MAC80211_DEBUGFS
+        bool "iwlagn debugfs support"
+        depends on IWLWIFI && IWLWIFI_DEBUG && MAC80211_DEBUGFS
         ---help---
          Enable creation of debugfs files for the iwlwifi drivers.
 
 config IWLAGN
-       tristate "Intel Wireless WiFi Next Gen AGN"
+       tristate "Intel Wireless WiFi Next Gen AGN (iwlagn)"
        depends on IWLWIFI
-       select FW_LOADER
-       select IWLCORE
        ---help---
          Select to build the driver supporting the:
 
@@ -77,19 +77,6 @@ config IWLAGN
          say M here and read <file:Documentation/kbuild/modules.txt>.  The
          module will be called iwlagn.ko.
 
-config IWLAGN_SPECTRUM_MEASUREMENT
-       bool "Enable Spectrum Measurement in iwlagn driver"
-       depends on IWLAGN
-       ---help---
-         This option will enable spectrum measurement for the iwlagn driver.
-
-config IWLAGN_LEDS
-       bool "Enable LEDS features in iwlagn driver"
-       depends on IWLAGN
-       select IWLWIFI_LEDS
-       ---help---
-         This option enables LEDS for the iwlagn drivers
-
 
 config IWL4965
        bool "Intel Wireless WiFi 4965AGN"
@@ -98,19 +85,14 @@ config IWL4965
          This option enables support for Intel Wireless WiFi Link 4965AGN
 
 config IWL5000
-       bool "Intel Wireless WiFi 5000AGN"
+       bool "Intel Wireless WiFi 5000AGN; Intel WiFi Link 1000, 6000, and 6050 Series"
        depends on IWLAGN
        ---help---
          This option enables support for Intel Wireless WiFi Link 5000AGN Family
 
 config IWL3945
-       tristate "Intel PRO/Wireless 3945ABG/BG Network Connection"
+       tristate "Intel PRO/Wireless 3945ABG/BG Network Connection (iwl3945)"
        depends on IWLWIFI
-       select FW_LOADER
-       select LIB80211
-       select MAC80211_LEDS if IWL3945_LEDS
-       select LEDS_CLASS if IWL3945_LEDS
-       select RFKILL if IWLWIFI_RFKILL
        ---help---
          Select to build the driver supporting the:
 
@@ -134,13 +116,7 @@ config IWL3945
          module will be called iwl3945.ko.
 
 config IWL3945_SPECTRUM_MEASUREMENT
-       bool "Enable Spectrum Measurement in iwl3945 drivers"
+       bool "Enable Spectrum Measurement in iwl3945 driver"
        depends on IWL3945
        ---help---
          This option will enable spectrum measurement for the iwl3945 driver.
-
-config IWL3945_LEDS
-       bool "Enable LEDS features in iwl3945 driver"
-       depends on IWL3945
-       ---help---
-         This option enables LEDS for the iwl3945 driver.
index ddc8b31b2608db960327ca24c9a1d8db326bd328..d79d97ad61a56d490811231215ffe8f0144184d6 100644 (file)
@@ -1,11 +1,11 @@
-obj-$(CONFIG_IWLCORE)  += iwlcore.o
+obj-$(CONFIG_IWLWIFI)  += iwlcore.o
 iwlcore-objs           := iwl-core.o iwl-eeprom.o iwl-hcmd.o iwl-power.o
 iwlcore-objs           += iwl-rx.o iwl-tx.o iwl-sta.o iwl-calib.o
 iwlcore-objs           += iwl-scan.o
 iwlcore-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
 iwlcore-$(CONFIG_IWLWIFI_LEDS) += iwl-led.o
 iwlcore-$(CONFIG_IWLWIFI_RFKILL) += iwl-rfkill.o
-iwlcore-$(CONFIG_IWLAGN_SPECTRUM_MEASUREMENT) += iwl-spectrum.o
+iwlcore-$(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) += iwl-spectrum.o
 
 obj-$(CONFIG_IWLAGN)   += iwlagn.o
 iwlagn-objs            := iwl-agn.o iwl-agn-rs.o
@@ -13,10 +13,9 @@ iwlagn-objs          := iwl-agn.o iwl-agn-rs.o
 iwlagn-$(CONFIG_IWL4965) += iwl-4965.o
 iwlagn-$(CONFIG_IWL5000) += iwl-5000.o
 iwlagn-$(CONFIG_IWL5000) += iwl-6000.o
-iwlagn-$(CONFIG_IWL5000) += iwl-100.o
+iwlagn-$(CONFIG_IWL5000) += iwl-1000.o
 
 obj-$(CONFIG_IWL3945)  += iwl3945.o
-iwl3945-objs           := iwl3945-base.o iwl-3945.o iwl-3945-rs.o
-iwl3945-$(CONFIG_IWL3945_LEDS) += iwl-3945-led.o
+iwl3945-objs           := iwl3945-base.o iwl-3945.o iwl-3945-rs.o iwl-3945-led.o
 
 
similarity index 82%
rename from drivers/net/wireless/iwlwifi/iwl-100.c
rename to drivers/net/wireless/iwlwifi/iwl-1000.c
index 11d206abb7100c82621be5bdf0ef204902127427..7da52f1cc1d632cadce52d8f2eecfeb683234414 100644 (file)
 #include "iwl-5000-hw.h"
 
 /* Highest firmware API version supported */
-#define IWL100_UCODE_API_MAX 2
+#define IWL1000_UCODE_API_MAX 2
 
 /* Lowest firmware API version supported */
-#define IWL100_UCODE_API_MIN 1
+#define IWL1000_UCODE_API_MIN 1
 
-#define IWL100_FW_PRE "iwlwifi-100-"
-#define _IWL100_MODULE_FIRMWARE(api) IWL100_FW_PRE #api ".ucode"
-#define IWL100_MODULE_FIRMWARE(api) _IWL100_MODULE_FIRMWARE(api)
+#define IWL1000_FW_PRE "iwlwifi-1000-"
+#define _IWL1000_MODULE_FIRMWARE(api) IWL1000_FW_PRE #api ".ucode"
+#define IWL1000_MODULE_FIRMWARE(api) _IWL1000_MODULE_FIRMWARE(api)
 
-struct iwl_cfg iwl100_bgn_cfg = {
-       .name = "100 Series BGN",
-       .fw_name_pre = IWL100_FW_PRE,
-       .ucode_api_max = IWL100_UCODE_API_MAX,
-       .ucode_api_min = IWL100_UCODE_API_MIN,
+struct iwl_cfg iwl1000_bgn_cfg = {
+       .name = "1000 Series BGN",
+       .fw_name_pre = IWL1000_FW_PRE,
+       .ucode_api_max = IWL1000_UCODE_API_MAX,
+       .ucode_api_min = IWL1000_UCODE_API_MIN,
        .sku = IWL_SKU_G|IWL_SKU_N,
        .ops = &iwl5000_ops,
        .eeprom_size = IWL_5000_EEPROM_IMG_SIZE,
index a973ac13a1d547113b3cb2b4910c08ac518d7b4a..ac22f59be9efdbd3400f87c845c67175141d0391 100644 (file)
@@ -24,6 +24,7 @@
  *
  *****************************************************************************/
 
+#ifdef CONFIG_IWLWIFI_LEDS
 
 #include <linux/kernel.h>
 #include <linux/module.h>
@@ -163,8 +164,8 @@ static int iwl3945_led_associated(struct iwl_priv *priv, int led_id)
 static void iwl3945_led_brightness_set(struct led_classdev *led_cdev,
                                enum led_brightness brightness)
 {
-       struct iwl3945_led *led = container_of(led_cdev,
-                                              struct iwl3945_led, led_dev);
+       struct iwl_led *led = container_of(led_cdev,
+                                              struct iwl_led, led_dev);
        struct iwl_priv *priv = led->priv;
 
        if (test_bit(STATUS_EXIT_PENDING, &priv->status))
@@ -202,7 +203,7 @@ static void iwl3945_led_brightness_set(struct led_classdev *led_cdev,
  * Register led class with the system
  */
 static int iwl3945_led_register_led(struct iwl_priv *priv,
-                                  struct iwl3945_led *led,
+                                  struct iwl_led *led,
                                   enum led_type type, u8 set_led,
                                   char *trigger)
 {
@@ -315,66 +316,66 @@ int iwl3945_led_register(struct iwl_priv *priv)
        priv->allow_blinking = 0;
 
        trigger = ieee80211_get_radio_led_name(priv->hw);
-       snprintf(priv->led39[IWL_LED_TRG_RADIO].name,
-                sizeof(priv->led39[IWL_LED_TRG_RADIO].name), "iwl-%s::radio",
+       snprintf(priv->led[IWL_LED_TRG_RADIO].name,
+                sizeof(priv->led[IWL_LED_TRG_RADIO].name), "iwl-%s::radio",
                 wiphy_name(priv->hw->wiphy));
 
-       priv->led39[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on;
-       priv->led39[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off;
-       priv->led39[IWL_LED_TRG_RADIO].led_pattern = NULL;
+       priv->led[IWL_LED_TRG_RADIO].led_on = iwl3945_led_on;
+       priv->led[IWL_LED_TRG_RADIO].led_off = iwl3945_led_off;
+       priv->led[IWL_LED_TRG_RADIO].led_pattern = NULL;
 
        ret = iwl3945_led_register_led(priv,
-                                  &priv->led39[IWL_LED_TRG_RADIO],
+                                  &priv->led[IWL_LED_TRG_RADIO],
                                   IWL_LED_TRG_RADIO, 1, trigger);
 
        if (ret)
                goto exit_fail;
 
        trigger = ieee80211_get_assoc_led_name(priv->hw);
-       snprintf(priv->led39[IWL_LED_TRG_ASSOC].name,
-                sizeof(priv->led39[IWL_LED_TRG_ASSOC].name), "iwl-%s::assoc",
+       snprintf(priv->led[IWL_LED_TRG_ASSOC].name,
+                sizeof(priv->led[IWL_LED_TRG_ASSOC].name), "iwl-%s::assoc",
                 wiphy_name(priv->hw->wiphy));
 
        ret = iwl3945_led_register_led(priv,
-                                  &priv->led39[IWL_LED_TRG_ASSOC],
+                                  &priv->led[IWL_LED_TRG_ASSOC],
                                   IWL_LED_TRG_ASSOC, 0, trigger);
 
        /* for assoc always turn led on */
-       priv->led39[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on;
-       priv->led39[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on;
-       priv->led39[IWL_LED_TRG_ASSOC].led_pattern = NULL;
+       priv->led[IWL_LED_TRG_ASSOC].led_on = iwl3945_led_on;
+       priv->led[IWL_LED_TRG_ASSOC].led_off = iwl3945_led_on;
+       priv->led[IWL_LED_TRG_ASSOC].led_pattern = NULL;
 
        if (ret)
                goto exit_fail;
 
        trigger = ieee80211_get_rx_led_name(priv->hw);
-       snprintf(priv->led39[IWL_LED_TRG_RX].name,
-                sizeof(priv->led39[IWL_LED_TRG_RX].name), "iwl-%s::RX",
+       snprintf(priv->led[IWL_LED_TRG_RX].name,
+                sizeof(priv->led[IWL_LED_TRG_RX].name), "iwl-%s::RX",
                 wiphy_name(priv->hw->wiphy));
 
        ret = iwl3945_led_register_led(priv,
-                                  &priv->led39[IWL_LED_TRG_RX],
+                                  &priv->led[IWL_LED_TRG_RX],
                                   IWL_LED_TRG_RX, 0, trigger);
 
-       priv->led39[IWL_LED_TRG_RX].led_on = iwl3945_led_associated;
-       priv->led39[IWL_LED_TRG_RX].led_off = iwl3945_led_associated;
-       priv->led39[IWL_LED_TRG_RX].led_pattern = iwl3945_led_pattern;
+       priv->led[IWL_LED_TRG_RX].led_on = iwl3945_led_associated;
+       priv->led[IWL_LED_TRG_RX].led_off = iwl3945_led_associated;
+       priv->led[IWL_LED_TRG_RX].led_pattern = iwl3945_led_pattern;
 
        if (ret)
                goto exit_fail;
 
        trigger = ieee80211_get_tx_led_name(priv->hw);
-       snprintf(priv->led39[IWL_LED_TRG_TX].name,
-                sizeof(priv->led39[IWL_LED_TRG_TX].name), "iwl-%s::TX",
+       snprintf(priv->led[IWL_LED_TRG_TX].name,
+                sizeof(priv->led[IWL_LED_TRG_TX].name), "iwl-%s::TX",
                 wiphy_name(priv->hw->wiphy));
 
        ret = iwl3945_led_register_led(priv,
-                                  &priv->led39[IWL_LED_TRG_TX],
+                                  &priv->led[IWL_LED_TRG_TX],
                                   IWL_LED_TRG_TX, 0, trigger);
 
-       priv->led39[IWL_LED_TRG_TX].led_on = iwl3945_led_associated;
-       priv->led39[IWL_LED_TRG_TX].led_off = iwl3945_led_associated;
-       priv->led39[IWL_LED_TRG_TX].led_pattern = iwl3945_led_pattern;
+       priv->led[IWL_LED_TRG_TX].led_on = iwl3945_led_associated;
+       priv->led[IWL_LED_TRG_TX].led_off = iwl3945_led_associated;
+       priv->led[IWL_LED_TRG_TX].led_pattern = iwl3945_led_pattern;
 
        if (ret)
                goto exit_fail;
@@ -388,7 +389,7 @@ exit_fail:
 
 
 /* unregister led class */
-static void iwl3945_led_unregister_led(struct iwl3945_led *led, u8 set_led)
+static void iwl3945_led_unregister_led(struct iwl_led *led, u8 set_led)
 {
        if (!led->registered)
                return;
@@ -403,9 +404,10 @@ static void iwl3945_led_unregister_led(struct iwl3945_led *led, u8 set_led)
 /* Unregister all led handlers */
 void iwl3945_led_unregister(struct iwl_priv *priv)
 {
-       iwl3945_led_unregister_led(&priv->led39[IWL_LED_TRG_ASSOC], 0);
-       iwl3945_led_unregister_led(&priv->led39[IWL_LED_TRG_RX], 0);
-       iwl3945_led_unregister_led(&priv->led39[IWL_LED_TRG_TX], 0);
-       iwl3945_led_unregister_led(&priv->led39[IWL_LED_TRG_RADIO], 1);
+       iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_ASSOC], 0);
+       iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_RX], 0);
+       iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_TX], 0);
+       iwl3945_led_unregister_led(&priv->led[IWL_LED_TRG_RADIO], 1);
 }
 
+#endif
index 88185a6ccd6aca02677b468ba42e3c1834ed2e8b..3b65642258cabbb2f7b99b2a0802b2aa1c822f93 100644 (file)
 
 struct iwl_priv;
 
-#ifdef CONFIG_IWL3945_LEDS
+#ifdef CONFIG_IWLWIFI_LEDS
 
 #include "iwl-led.h"
 
-struct iwl3945_led {
-       struct iwl_priv *priv;
-       struct led_classdev led_dev;
-       char name[32];
-
-       int (*led_on) (struct iwl_priv *priv, int led_id);
-       int (*led_off) (struct iwl_priv *priv, int led_id);
-       int (*led_pattern) (struct iwl_priv *priv, int led_id,
-                           unsigned int idx);
-
-       enum led_type type;
-       unsigned int registered;
-};
-
 extern int iwl3945_led_register(struct iwl_priv *priv);
 extern void iwl3945_led_unregister(struct iwl_priv *priv);
 extern void iwl3945_led_background(struct iwl_priv *priv);
@@ -55,6 +41,6 @@ extern void iwl3945_led_background(struct iwl_priv *priv);
 static inline int iwl3945_led_register(struct iwl_priv *priv) { return 0; }
 static inline void iwl3945_led_unregister(struct iwl_priv *priv) {}
 static inline void iwl3945_led_background(struct iwl_priv *priv) {}
-#endif /* CONFIG_IWL3945_LEDS */
 
+#endif /* IWLWIFI_LEDS*/
 #endif /* IWL3945_LEDS_H */
index 7db8198c6253752d4b9313ece41b3e148af3c155..f65c308a67148a2294ccb2c7d329ee617c0236a6 100644 (file)
@@ -127,6 +127,7 @@ static struct iwl3945_tpt_entry iwl3945_tpt_table_g[] = {
 #define IWL_RATE_MIN_FAILURE_TH       8
 #define IWL_RATE_MIN_SUCCESS_TH       8
 #define IWL_RATE_DECREASE_TH       1920
+#define IWL_RATE_RETRY_TH           15
 
 static u8 iwl3945_get_rate_index_by_rssi(s32 rssi, enum ieee80211_band band)
 {
@@ -298,37 +299,53 @@ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta,
        }
 
        spin_lock_irqsave(&rs_sta->lock, flags);
-       while (retries--) {
 
-               /* If we have filled up the window then subtract one from the
-                * success counter if the high-bit is counting toward
-                * success */
-               if (window->counter == IWL_RATE_MAX_WINDOW) {
-                       if (window->data & (1ULL << (IWL_RATE_MAX_WINDOW - 1)))
+       /*
+        * Keep track of only the latest 62 tx frame attempts in this rate's
+        * history window; anything older isn't really relevant any more.
+        * If we have filled up the sliding window, drop the oldest attempt;
+        * if the oldest attempt (highest bit in bitmap) shows "success",
+        * subtract "1" from the success counter (this is the main reason
+        * we keep these bitmaps!).
+        * */
+       while (retries > 0) {
+               if (window->counter >= IWL_RATE_MAX_WINDOW) {
+
+                       /* remove earliest */
+                       window->counter = IWL_RATE_MAX_WINDOW - 1;
+
+                       if (window->data & (1ULL << (IWL_RATE_MAX_WINDOW - 1))) {
+                               window->data &= ~(1ULL << (IWL_RATE_MAX_WINDOW - 1));
                                window->success_counter--;
-               } else
-                       window->counter++;
+                       }
+               }
 
-               /* Slide the window to the left one bit */
-               window->data = (window->data << 1);
+               /* Increment frames-attempted counter */
+               window->counter++;
 
-               /* If this packet was a success then set the low bit high */
-               if (success) {
+               /* Shift bitmap by one frame (throw away oldest history),
+                * OR in "1", and increment "success" if this
+                * frame was successful. */
+               window->data <<= 1;
+               if (success > 0) {
                        window->success_counter++;
-                       window->data |= 1;
+                       window->data |= 0x1;
+                       success--;
                }
 
-               /* window->counter can't be 0 -- it is either >0 or
-                * IWL_RATE_MAX_WINDOW */
-               window->success_ratio = 12800 * window->success_counter /
-                   window->counter;
-
-               /* Tag this window as having been updated */
-               window->stamp = jiffies;
-
+               retries--;
        }
 
+       /* Calculate current success ratio, avoid divide-by-0! */
+       if (window->counter > 0)
+               window->success_ratio = 128 * (100 * window->success_counter)
+                                       / window->counter;
+       else
+               window->success_ratio = IWL_INVALID_VALUE;
+
        fail_count = window->counter - window->success_counter;
+
+       /* Calculate average throughput, if we have enough history. */
        if ((fail_count >= IWL_RATE_MIN_FAILURE_TH) ||
            (window->success_counter >= IWL_RATE_MIN_SUCCESS_TH))
                window->average_tpt = ((window->success_ratio *
@@ -336,6 +353,9 @@ static void iwl3945_collect_tx_data(struct iwl3945_rs_sta *rs_sta,
        else
                window->average_tpt = IWL_INVALID_VALUE;
 
+       /* Tag this window as having been updated */
+       window->stamp = jiffies;
+
        spin_unlock_irqrestore(&rs_sta->lock, flags);
 
 }
@@ -468,7 +488,10 @@ static void rs_tx_status(void *priv_rate, struct ieee80211_supported_band *sband
 
        IWL_DEBUG_RATE(priv, "enter\n");
 
-       retries = info->status.rates[0].count;
+       retries = info->status.rates[0].count - 1;
+       /* Sanity Check for retries */
+       if (retries > IWL_RATE_RETRY_TH)
+               retries = IWL_RATE_RETRY_TH;
 
        first_index = sband->bitrates[info->status.rates[0].idx].hw_value;
        if ((first_index < 0) || (first_index >= IWL_RATE_COUNT_3945)) {
@@ -724,7 +747,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
 
        fail_count = window->counter - window->success_counter;
 
-       if (((fail_count <= IWL_RATE_MIN_FAILURE_TH) &&
+       if (((fail_count < IWL_RATE_MIN_FAILURE_TH) &&
             (window->success_counter < IWL_RATE_MIN_SUCCESS_TH))) {
                spin_unlock_irqrestore(&rs_sta->lock, flags);
 
@@ -735,6 +758,9 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
                               window->counter,
                               window->success_counter,
                               rs_sta->expected_tpt ? "not " : "");
+
+          /* Can't calculate this yet; not enough history */
+               window->average_tpt = IWL_INVALID_VALUE;
                goto out;
 
        }
@@ -750,6 +776,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
        if ((max_rate_idx != -1) && (max_rate_idx < high))
                high = IWL_RATE_INVALID;
 
+       /* Collect Measured throughputs of adjacent rates */
        if (low != IWL_RATE_INVALID)
                low_tpt = rs_sta->win[low].average_tpt;
 
@@ -758,24 +785,43 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
 
        spin_unlock_irqrestore(&rs_sta->lock, flags);
 
-       scale_action = 1;
+       scale_action = 0;
 
+       /* Low success ratio , need to drop the rate */
        if ((window->success_ratio < IWL_RATE_DECREASE_TH) || !current_tpt) {
                IWL_DEBUG_RATE(priv, "decrease rate because of low success_ratio\n");
                scale_action = -1;
+
+       /* No throughput measured yet for adjacent rates,
+        * try increase */
        } else if ((low_tpt == IWL_INVALID_VALUE) &&
-                  (high_tpt == IWL_INVALID_VALUE))
-               scale_action = 1;
-       else if ((low_tpt != IWL_INVALID_VALUE) &&
+                  (high_tpt == IWL_INVALID_VALUE)) {
+
+               if (high != IWL_RATE_INVALID && window->success_counter >= IWL_RATE_INCREASE_TH)
+                       scale_action = 1;
+               else if (low != IWL_RATE_INVALID)
+                       scale_action = -1;
+
+       /* Both adjacent throughputs are measured, but neither one has
+        * better throughput; we're using the best rate, don't change
+        * it! */
+       } else if ((low_tpt != IWL_INVALID_VALUE) &&
                 (high_tpt != IWL_INVALID_VALUE) &&
                 (low_tpt < current_tpt) && (high_tpt < current_tpt)) {
+
                IWL_DEBUG_RATE(priv, "No action -- low [%d] & high [%d] < "
                               "current_tpt [%d]\n",
                               low_tpt, high_tpt, current_tpt);
                scale_action = 0;
+
+       /* At least one of the rates has better throughput */
        } else {
                if (high_tpt != IWL_INVALID_VALUE) {
-                       if (high_tpt > current_tpt)
+
+                       /* High rate has better throughput, Increase
+                        * rate */
+                       if (high_tpt > current_tpt &&
+                               window->success_ratio >= IWL_RATE_INCREASE_TH)
                                scale_action = 1;
                        else {
                                IWL_DEBUG_RATE(priv,
@@ -787,29 +833,31 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
                                IWL_DEBUG_RATE(priv,
                                    "decrease rate because of low tpt\n");
                                scale_action = -1;
-                       } else
+                       } else if (window->success_counter >= IWL_RATE_INCREASE_TH) {
+                               /* Lower rate has better
+                                * throughput,decrease rate */
                                scale_action = 1;
+                       }
                }
        }
 
-       if (scale_action == -1) {
-               if (window->success_ratio > IWL_SUCCESS_DOWN_TH)
-                       scale_action = 0;
-       } else if (scale_action == 1) {
-               if (window->success_ratio < IWL_SUCCESS_UP_TH) {
-                       IWL_DEBUG_RATE(priv, "No action -- success_ratio [%d] < "
-                              "SUCCESS UP\n", window->success_ratio);
-                       scale_action = 0;
-               }
-       }
+       /* Sanity check; asked for decrease, but success rate or throughput
+        * has been good at old rate.  Don't change it. */
+       if ((scale_action == -1) && (low != IWL_RATE_INVALID) &&
+                   ((window->success_ratio > IWL_RATE_HIGH_TH) ||
+                    (current_tpt > (100 * rs_sta->expected_tpt[low]))))
+               scale_action = 0;
 
        switch (scale_action) {
        case -1:
+
+               /* Decrese rate */
                if (low != IWL_RATE_INVALID)
                        index = low;
                break;
 
        case 1:
+               /* Increase rate */
                if (high != IWL_RATE_INVALID)
                        index = high;
 
@@ -817,6 +865,7 @@ static void rs_get_rate(void *priv_r, struct ieee80211_sta *sta,
 
        case 0:
        default:
+               /* No change */
                break;
        }
 
@@ -846,11 +895,16 @@ static ssize_t iwl3945_sta_dbgfs_stats_table_read(struct file *file,
                                                  char __user *user_buf,
                                                  size_t count, loff_t *ppos)
 {
-       char buff[1024];
+       char *buff;
        int desc = 0;
        int j;
+       ssize_t ret;
        struct iwl3945_rs_sta *lq_sta = file->private_data;
 
+       buff = kmalloc(1024, GFP_KERNEL);
+       if (!buff)
+               return -ENOMEM;
+
        desc += sprintf(buff + desc, "tx packets=%d last rate index=%d\n"
                        "rate=0x%X flush time %d\n",
                        lq_sta->tx_packets,
@@ -863,7 +917,9 @@ static ssize_t iwl3945_sta_dbgfs_stats_table_read(struct file *file,
                                lq_sta->win[j].success_counter,
                                lq_sta->win[j].success_ratio);
        }
-       return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+       ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+       kfree(buff);
+       return ret;
 }
 
 static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
index d49e48b9b037b7b74f5368639900d7ed24ea922d..ba7e720e73c1638a22b07d01c93a18349e332b37 100644 (file)
@@ -554,7 +554,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
                                   struct ieee80211_rx_status *stats)
 {
        struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
-#ifdef CONFIG_IWL3945_LEDS
+#ifdef CONFIG_IWLWIFI_LEDS
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)IWL_RX_DATA(pkt);
 #endif
        struct iwl3945_rx_frame_hdr *rx_hdr = IWL_RX_HDR(pkt);
@@ -583,7 +583,7 @@ static void iwl3945_pass_packet_to_mac80211(struct iwl_priv *priv,
                                       (struct ieee80211_hdr *)rxb->skb->data,
                                       le32_to_cpu(rx_end->status), stats);
 
-#ifdef CONFIG_IWL3945_LEDS
+#ifdef CONFIG_IWLWIFI_LEDS
        if (ieee80211_is_data(hdr->frame_control))
                priv->rxtxpackets += len;
 #endif
@@ -741,7 +741,8 @@ int iwl3945_hw_txq_attach_buf_to_tfd(struct iwl_priv *priv,
 void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
 {
        struct iwl3945_tfd *tfd_tmp = (struct iwl3945_tfd *)txq->tfds;
-       struct iwl3945_tfd *tfd = &tfd_tmp[txq->q.read_ptr];
+       int index = txq->q.read_ptr;
+       struct iwl3945_tfd *tfd = &tfd_tmp[index];
        struct pci_dev *dev = priv->pci_dev;
        int i;
        int counter;
@@ -759,6 +760,13 @@ void iwl3945_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
                return;
        }
 
+       /* Unmap tx_cmd */
+       if (counter)
+               pci_unmap_single(dev,
+                               pci_unmap_addr(&txq->cmd[index]->meta, mapping),
+                               pci_unmap_len(&txq->cmd[index]->meta, len),
+                               PCI_DMA_TODEVICE);
+
        /* unmap chunks if any */
 
        for (i = 1; i < counter; i++) {
@@ -1073,7 +1081,7 @@ static int iwl3945_apm_init(struct iwl_priv *priv)
        * D0U* --> D0A* state */
        iwl_set_bit(priv, CSR_GP_CNTRL, CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 
-       iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
+       ret = iwl_poll_direct_bit(priv, CSR_GP_CNTRL,
                            CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY, 25000);
        if (ret < 0) {
                IWL_DEBUG_INFO(priv, "Failed to init the card\n");
@@ -2747,6 +2755,7 @@ static struct iwl_lib_ops iwl3945_lib = {
                .query_addr = iwlcore_eeprom_query_addr,
        },
        .send_tx_power  = iwl3945_send_tx_power,
+       .is_valid_rtc_data_addr = iwl3945_hw_valid_rtc_data_addr,
 };
 
 static struct iwl_hcmd_utils_ops iwl3945_hcmd_utils = {
index ab39f4ae8e324985b1861b6151b6de5200c59a45..08c19bea71e35cb0e028e3990b1796756bfc5abf 100644 (file)
@@ -47,7 +47,7 @@
 
 /* Highest firmware API version supported */
 #define IWL5000_UCODE_API_MAX 1
-#define IWL5150_UCODE_API_MAX 1
+#define IWL5150_UCODE_API_MAX 2
 
 /* Lowest firmware API version supported */
 #define IWL5000_UCODE_API_MIN 1
index 04b42c8a77053d101c82d85a5b44dbfeb3fc973d..cab7842a73aaed9cb44bdb536277389ea42e6e1f 100644 (file)
@@ -801,7 +801,10 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
            !(info->flags & IEEE80211_TX_STAT_AMPDU))
                return;
 
-       retries = info->status.rates[0].count - 1;
+       if (info->flags & IEEE80211_TX_STAT_AMPDU)
+               retries = 0;
+       else
+               retries = info->status.rates[0].count - 1;
 
        if (retries > 15)
                retries = 15;
@@ -913,7 +916,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
                        tpt = search_tbl->expected_tpt[rs_index];
                else
                        tpt = 0;
-               if (info->flags & IEEE80211_TX_CTL_AMPDU)
+               if (info->flags & IEEE80211_TX_STAT_AMPDU)
                        rs_collect_tx_data(search_win, rs_index, tpt,
                                           info->status.ampdu_ack_len,
                                           info->status.ampdu_ack_map);
@@ -929,7 +932,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
                        tpt = curr_tbl->expected_tpt[rs_index];
                else
                        tpt = 0;
-               if (info->flags & IEEE80211_TX_CTL_AMPDU)
+               if (info->flags & IEEE80211_TX_STAT_AMPDU)
                        rs_collect_tx_data(window, rs_index, tpt,
                                           info->status.ampdu_ack_len,
                                           info->status.ampdu_ack_map);
@@ -941,7 +944,7 @@ static void rs_tx_status(void *priv_r, struct ieee80211_supported_band *sband,
        /* If not searching for new mode, increment success/failed counter
         * ... these help determine when to start searching again */
        if (lq_sta->stay_in_tbl) {
-               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+               if (info->flags & IEEE80211_TX_STAT_AMPDU) {
                        lq_sta->total_success += info->status.ampdu_ack_map;
                        lq_sta->total_failed +=
                             (info->status.ampdu_ack_len - info->status.ampdu_ack_map);
@@ -1700,6 +1703,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
        u16 high_low;
        s32 sr;
        u8 tid = MAX_TID_COUNT;
+       struct iwl_tid_data *tid_data;
 
        IWL_DEBUG_RATE(priv, "rate scale calculate new rate for skb\n");
 
@@ -1896,7 +1900,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
                if (high != IWL_RATE_INVALID && sr >= IWL_RATE_INCREASE_TH)
                        scale_action = 1;
                else if (low != IWL_RATE_INVALID)
-                       scale_action = -1;
+                       scale_action = 0;
        }
 
        /* Both adjacent throughputs are measured, but neither one has better
@@ -1917,9 +1921,7 @@ static void rs_rate_scale_perform(struct iwl_priv *priv,
                                        sr >= IWL_RATE_INCREASE_TH) {
                                scale_action = 1;
                        } else {
-                               IWL_DEBUG_RATE(priv,
-                                   "decrease rate because of high tpt\n");
-                               scale_action = -1;
+                               scale_action = 0;
                        }
 
                /* Lower adjacent rate's throughput is measured */
@@ -2035,8 +2037,15 @@ lq_update:
                        if ((lq_sta->last_tpt > IWL_AGG_TPT_THREHOLD) &&
                            (lq_sta->tx_agg_tid_en & (1 << tid)) &&
                            (tid != MAX_TID_COUNT)) {
-                               IWL_DEBUG_RATE(priv, "try to aggregate tid %d\n", tid);
-                               rs_tl_turn_on_agg(priv, tid, lq_sta, sta);
+                               tid_data =
+                                  &priv->stations[lq_sta->lq.sta_id].tid[tid];
+                               if (tid_data->agg.state == IWL_AGG_OFF) {
+                                       IWL_DEBUG_RATE(priv,
+                                                      "try to aggregate tid %d\n",
+                                                      tid);
+                                       rs_tl_turn_on_agg(priv, tid,
+                                                         lq_sta, sta);
+                               }
                        }
                        lq_sta->action_counter = 0;
                        rs_set_stay_in_table(priv, 0, lq_sta);
@@ -2464,18 +2473,25 @@ static void rs_dbgfs_set_mcs(struct iwl_lq_sta *lq_sta,
                             u32 *rate_n_flags, int index)
 {
        struct iwl_priv *priv;
+       u8 valid_tx_ant;
+       u8 ant_sel_tx;
 
        priv = lq_sta->drv;
+       valid_tx_ant = priv->hw_params.valid_tx_ant;
        if (lq_sta->dbg_fixed_rate) {
-               if (index < 12) {
+               ant_sel_tx =
+                 ((lq_sta->dbg_fixed_rate & RATE_MCS_ANT_ABC_MSK)
+                 >> RATE_MCS_ANT_POS);
+               if ((valid_tx_ant & ant_sel_tx) == ant_sel_tx) {
                        *rate_n_flags = lq_sta->dbg_fixed_rate;
+                       IWL_DEBUG_RATE(priv, "Fixed rate ON\n");
                } else {
-                       if (lq_sta->band == IEEE80211_BAND_5GHZ)
-                               *rate_n_flags = 0x800D;
-                       else
-                               *rate_n_flags = 0x820A;
+                       lq_sta->dbg_fixed_rate = 0;
+                       IWL_ERR(priv,
+                           "Invalid antenna selection 0x%X, Valid is 0x%X\n",
+                           ant_sel_tx, valid_tx_ant);
+                       IWL_DEBUG_RATE(priv, "Fixed rate OFF\n");
                }
-               IWL_DEBUG_RATE(priv, "Fixed rate ON\n");
        } else {
                IWL_DEBUG_RATE(priv, "Fixed rate OFF\n");
        }
@@ -2520,11 +2536,19 @@ static ssize_t rs_sta_dbgfs_scale_table_write(struct file *file,
 static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
                        char __user *user_buf, size_t count, loff_t *ppos)
 {
-       char buff[1024];
+       char *buff;
        int desc = 0;
        int i = 0;
+       ssize_t ret;
 
        struct iwl_lq_sta *lq_sta = file->private_data;
+       struct iwl_priv *priv;
+       struct iwl_scale_tbl_info *tbl = &(lq_sta->lq_info[lq_sta->active_tbl]);
+
+       priv = lq_sta->drv;
+       buff = kmalloc(1024, GFP_KERNEL);
+       if (!buff)
+               return -ENOMEM;
 
        desc += sprintf(buff+desc, "sta_id %d\n", lq_sta->lq.sta_id);
        desc += sprintf(buff+desc, "failed=%d success=%d rate=0%X\n",
@@ -2532,6 +2556,20 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
                        lq_sta->active_legacy_rate);
        desc += sprintf(buff+desc, "fixed rate 0x%X\n",
                        lq_sta->dbg_fixed_rate);
+       desc += sprintf(buff+desc, "valid_tx_ant %s%s%s\n",
+           (priv->hw_params.valid_tx_ant & ANT_A) ? "ANT_A," : "",
+           (priv->hw_params.valid_tx_ant & ANT_B) ? "ANT_B," : "",
+           (priv->hw_params.valid_tx_ant & ANT_C) ? "ANT_C" : "");
+       desc += sprintf(buff+desc, "lq type %s\n",
+          (is_legacy(tbl->lq_type)) ? "legacy" : "HT");
+       if (is_Ht(tbl->lq_type)) {
+               desc += sprintf(buff+desc, " %s",
+                  (is_siso(tbl->lq_type)) ? "SISO" :
+                  ((is_mimo2(tbl->lq_type)) ? "MIMO2" : "MIMO3"));
+                  desc += sprintf(buff+desc, " %s",
+                  (tbl->is_fat) ? "40MHz" : "20MHz");
+               desc += sprintf(buff+desc, " %s\n", (tbl->is_SGI) ? "SGI" : "");
+       }
        desc += sprintf(buff+desc, "general:"
                "flags=0x%X mimo-d=%d s-ant0x%x d-ant=0x%x\n",
                lq_sta->lq.general_params.flags,
@@ -2557,7 +2595,9 @@ static ssize_t rs_sta_dbgfs_scale_table_read(struct file *file,
                desc += sprintf(buff+desc, " rate[%d] 0x%X\n",
                        i, le32_to_cpu(lq_sta->lq.rs_table[i].rate_n_flags));
 
-       return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+       ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+       kfree(buff);
+       return ret;
 }
 
 static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
@@ -2568,11 +2608,17 @@ static const struct file_operations rs_sta_dbgfs_scale_table_ops = {
 static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
                        char __user *user_buf, size_t count, loff_t *ppos)
 {
-       char buff[1024];
+       char *buff;
        int desc = 0;
        int i, j;
+       ssize_t ret;
 
        struct iwl_lq_sta *lq_sta = file->private_data;
+
+       buff = kmalloc(1024, GFP_KERNEL);
+       if (!buff)
+               return -ENOMEM;
+
        for (i = 0; i < LQ_SIZE; i++) {
                desc += sprintf(buff+desc, "%s type=%d SGI=%d FAT=%d DUP=%d\n"
                                "rate=0x%X\n",
@@ -2590,7 +2636,9 @@ static ssize_t rs_sta_dbgfs_stats_table_read(struct file *file,
                                lq_sta->lq_info[i].win[j].success_ratio);
                }
        }
-       return simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+       ret = simple_read_from_buffer(user_buf, count, ppos, buff, desc);
+       kfree(buff);
+       return ret;
 }
 
 static const struct file_operations rs_sta_dbgfs_stats_table_ops = {
index 345806dd8870b74d1ff792b72be3f797d4af4c07..ab59acc405d9426774f3e3cffad380be8affa542 100644 (file)
@@ -231,7 +231,7 @@ enum {
 #define IWL_RS_GOOD_RATIO              12800   /* 100% */
 #define IWL_RATE_SCALE_SWITCH          10880   /*  85% */
 #define IWL_RATE_HIGH_TH               10880   /*  85% */
-#define IWL_RATE_INCREASE_TH            8960   /*  70% */
+#define IWL_RATE_INCREASE_TH           6400    /*  50% */
 #define IWL_RATE_DECREASE_TH           1920    /*  15% */
 
 /* possible actions when in legacy mode */
index 397577c06c923a33514e6d545744e41b4c8f8330..0db3bc011ac2b76a63696995f10af5279f3bf0db 100644 (file)
@@ -72,7 +72,7 @@
 #define VD
 #endif
 
-#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
 #define VS "s"
 #else
 #define VS
@@ -444,7 +444,7 @@ void iwl_hw_txq_free_tfd(struct iwl_priv *priv, struct iwl_tx_queue *txq)
                pci_unmap_single(dev,
                                pci_unmap_addr(&txq->cmd[index]->meta, mapping),
                                pci_unmap_len(&txq->cmd[index]->meta, len),
-                               PCI_DMA_TODEVICE);
+                               PCI_DMA_BIDIRECTIONAL);
 
        /* Unmap chunks, if any. */
        for (i = 1; i < num_tbs; i++) {
@@ -601,38 +601,6 @@ static void iwl_ht_conf(struct iwl_priv *priv,
        IWL_DEBUG_MAC80211(priv, "leave\n");
 }
 
-/*
- * QoS  support
-*/
-static void iwl_activate_qos(struct iwl_priv *priv, u8 force)
-{
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       priv->qos_data.def_qos_parm.qos_flags = 0;
-
-       if (priv->qos_data.qos_cap.q_AP.queue_request &&
-           !priv->qos_data.qos_cap.q_AP.txop_request)
-               priv->qos_data.def_qos_parm.qos_flags |=
-                       QOS_PARAM_FLG_TXOP_TYPE_MSK;
-       if (priv->qos_data.qos_active)
-               priv->qos_data.def_qos_parm.qos_flags |=
-                       QOS_PARAM_FLG_UPDATE_EDCA_MSK;
-
-       if (priv->current_ht_config.is_ht)
-               priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
-
-       if (force || iwl_is_associated(priv)) {
-               IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
-                               priv->qos_data.qos_active,
-                               priv->qos_data.def_qos_parm.qos_flags);
-
-               iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM,
-                                      sizeof(struct iwl_qosparam_cmd),
-                                      &priv->qos_data.def_qos_parm, NULL);
-       }
-}
-
 #define MAX_UCODE_BEACON_INTERVAL      4096
 
 static u16 iwl_adjust_beacon_interval(u16 beacon_val)
@@ -644,6 +612,9 @@ static u16 iwl_adjust_beacon_interval(u16 beacon_val)
                                        / MAX_UCODE_BEACON_INTERVAL;
        new_val = beacon_val / beacon_factor;
 
+       if (!new_val)
+               new_val = MAX_UCODE_BEACON_INTERVAL;
+
        return new_val;
 }
 
@@ -751,41 +722,6 @@ static void iwl_rx_reply_alive(struct iwl_priv *priv,
                IWL_WARN(priv, "uCode did not respond OK.\n");
 }
 
-static void iwl_rx_reply_error(struct iwl_priv *priv,
-                                  struct iwl_rx_mem_buffer *rxb)
-{
-       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
-
-       IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) "
-               "seq 0x%04X ser 0x%08X\n",
-               le32_to_cpu(pkt->u.err_resp.error_type),
-               get_cmd_string(pkt->u.err_resp.cmd_id),
-               pkt->u.err_resp.cmd_id,
-               le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
-               le32_to_cpu(pkt->u.err_resp.error_info));
-}
-
-static void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
-                                     struct iwl_rx_mem_buffer *rxb)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
-       struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
-       IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
-                    sleep->pm_sleep_mode, sleep->pm_wakeup_src);
-#endif
-}
-
-static void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
-                                            struct iwl_rx_mem_buffer *rxb)
-{
-       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
-       IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
-                       "notification for %s:\n",
-                       le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
-       iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
-}
-
 static void iwl_bg_beacon_update(struct work_struct *work)
 {
        struct iwl_priv *priv =
@@ -1312,64 +1248,6 @@ static void iwl_irq_tasklet(struct iwl_priv *priv)
        spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-static irqreturn_t iwl_isr(int irq, void *data)
-{
-       struct iwl_priv *priv = data;
-       u32 inta, inta_mask;
-       u32 inta_fh;
-       if (!priv)
-               return IRQ_NONE;
-
-       spin_lock(&priv->lock);
-
-       /* Disable (but don't clear!) interrupts here to avoid
-        *    back-to-back ISRs and sporadic interrupts from our NIC.
-        * If we have something to service, the tasklet will re-enable ints.
-        * If we *don't* have something, we'll re-enable before leaving here. */
-       inta_mask = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
-       iwl_write32(priv, CSR_INT_MASK, 0x00000000);
-
-       /* Discover which interrupts are active/pending */
-       inta = iwl_read32(priv, CSR_INT);
-       inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
-
-       /* Ignore interrupt if there's nothing in NIC to service.
-        * This may be due to IRQ shared with another device,
-        * or due to sporadic interrupts thrown from our NIC. */
-       if (!inta && !inta_fh) {
-               IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0, inta_fh == 0\n");
-               goto none;
-       }
-
-       if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
-               /* Hardware disappeared. It might have already raised
-                * an interrupt */
-               IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
-               goto unplugged;
-       }
-
-       IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
-                     inta, inta_mask, inta_fh);
-
-       inta &= ~CSR_INT_BIT_SCD;
-
-       /* iwl_irq_tasklet() will service interrupts and re-enable them */
-       if (likely(inta || inta_fh))
-               tasklet_schedule(&priv->irq_tasklet);
-
- unplugged:
-       spin_unlock(&priv->lock);
-       return IRQ_HANDLED;
-
- none:
-       /* re-enable interrupts here since we don't have anything to service. */
-       /* only Re-enable if diabled by irq */
-       if (test_bit(STATUS_INT_ENABLED, &priv->status))
-               iwl_enable_interrupts(priv);
-       spin_unlock(&priv->lock);
-       return IRQ_NONE;
-}
-
 /******************************************************************************
  *
  * uCode download functions
@@ -2674,71 +2552,6 @@ static void iwl_bss_info_changed(struct ieee80211_hw *hw,
 
 }
 
-static int iwl_mac_hw_scan(struct ieee80211_hw *hw,
-                          struct cfg80211_scan_request *req)
-{
-       unsigned long flags;
-       struct iwl_priv *priv = hw->priv;
-       int ret;
-       u8 *ssid = NULL;
-       size_t ssid_len = 0;
-
-       if (req->n_ssids) {
-               ssid = req->ssids[0].ssid;
-               ssid_len = req->ssids[0].ssid_len;
-       }
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       mutex_lock(&priv->mutex);
-       spin_lock_irqsave(&priv->lock, flags);
-
-       if (!iwl_is_ready_rf(priv)) {
-               ret = -EIO;
-               IWL_DEBUG_MAC80211(priv, "leave - not ready or exit pending\n");
-               goto out_unlock;
-       }
-
-       /* We don't schedule scan within next_scan_jiffies period.
-        * Avoid scanning during possible EAPOL exchange, return
-        * success immediately.
-        */
-       if (priv->next_scan_jiffies &&
-           time_after(priv->next_scan_jiffies, jiffies)) {
-               IWL_DEBUG_SCAN(priv, "scan rejected: within next scan period\n");
-               queue_work(priv->workqueue, &priv->scan_completed);
-               ret = 0;
-               goto out_unlock;
-       }
-
-       /* if we just finished scan ask for delay */
-       if (iwl_is_associated(priv) && priv->last_scan_jiffies &&
-           time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) {
-               IWL_DEBUG_SCAN(priv, "scan rejected: within previous scan period\n");
-               queue_work(priv->workqueue, &priv->scan_completed);
-               ret = 0;
-               goto out_unlock;
-       }
-
-       if (ssid_len) {
-               priv->one_direct_scan = 1;
-               priv->direct_ssid_len = ssid_len;
-               memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
-       } else {
-               priv->one_direct_scan = 0;
-       }
-
-       ret = iwl_scan_initiate(priv);
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-out_unlock:
-       spin_unlock_irqrestore(&priv->lock, flags);
-       mutex_unlock(&priv->mutex);
-
-       return ret;
-}
-
 static void iwl_mac_update_tkip_key(struct ieee80211_hw *hw,
                        struct ieee80211_key_conf *keyconf, const u8 *addr,
                        u32 iv32, u16 *phase1key)
@@ -3370,7 +3183,7 @@ static DEVICE_ATTR(statistics, S_IRUGO, show_statistics, NULL);
 
 static void iwl_setup_deferred_work(struct iwl_priv *priv)
 {
-       priv->workqueue = create_workqueue(DRV_NAME);
+       priv->workqueue = create_singlethread_workqueue(DRV_NAME);
 
        init_waitqueue_head(&priv->wait_command_queue);
 
@@ -3546,7 +3359,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        /* amp init */
        err = priv->cfg->ops->lib->apm_ops.init(priv);
        if (err < 0) {
-               IWL_DEBUG_INFO(priv, "Failed to init APMG\n");
+               IWL_ERR(priv, "Failed to init APMG\n");
                goto out_iounmap;
        }
        /*****************
@@ -3560,7 +3373,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        }
        err = iwl_eeprom_check_version(priv);
        if (err)
-               goto out_iounmap;
+               goto out_free_eeprom;
 
        /* extract MAC Address */
        iwl_eeprom_get_mac(priv, priv->mac_addr);
@@ -3612,7 +3425,7 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        err = sysfs_create_group(&pdev->dev.kobj, &iwl_attribute_group);
        if (err) {
                IWL_ERR(priv, "failed to create sysfs device attributes\n");
-               goto out_uninit_drv;
+               goto out_free_irq;
        }
 
        iwl_setup_deferred_work(priv);
@@ -3656,19 +3469,21 @@ static int iwl_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
        return 0;
 
  out_remove_sysfs:
+       destroy_workqueue(priv->workqueue);
+       priv->workqueue = NULL;
        sysfs_remove_group(&pdev->dev.kobj, &iwl_attribute_group);
+ out_free_irq:
+       free_irq(priv->pci_dev->irq, priv);
  out_disable_msi:
        pci_disable_msi(priv->pci_dev);
-       pci_disable_device(priv->pci_dev);
- out_uninit_drv:
        iwl_uninit_drv(priv);
  out_free_eeprom:
        iwl_eeprom_free(priv);
  out_iounmap:
        pci_iounmap(pdev, priv->hw_base);
  out_pci_release_regions:
-       pci_release_regions(pdev);
        pci_set_drvdata(pdev, NULL);
+       pci_release_regions(pdev);
  out_pci_disable_device:
        pci_disable_device(pdev);
  out_ieee80211_free_hw:
@@ -3828,9 +3643,9 @@ static struct pci_device_id iwl_hw_card_ids[] = {
        {IWL_PCI_DEVICE(0x0087, PCI_ANY_ID, iwl6050_2agn_cfg)},
        {IWL_PCI_DEVICE(0x0088, PCI_ANY_ID, iwl6050_3agn_cfg)},
        {IWL_PCI_DEVICE(0x0089, PCI_ANY_ID, iwl6050_2agn_cfg)},
-/* 100 Series WiFi */
-       {IWL_PCI_DEVICE(0x0083, PCI_ANY_ID, iwl100_bgn_cfg)},
-       {IWL_PCI_DEVICE(0x0084, PCI_ANY_ID, iwl100_bgn_cfg)},
+/* 1000 Series WiFi */
+       {IWL_PCI_DEVICE(0x0083, PCI_ANY_ID, iwl1000_bgn_cfg)},
+       {IWL_PCI_DEVICE(0x0084, PCI_ANY_ID, iwl1000_bgn_cfg)},
 #endif /* CONFIG_IWL5000 */
 
        {0}
index 260bf903cb71ae36e3f2e24cc9c1db0fa5d4738e..085e9cf1cac99f0be0613063adcfd782a05cccf2 100644 (file)
@@ -240,6 +240,39 @@ int iwl_hw_nic_init(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_hw_nic_init);
 
+/*
+ * QoS  support
+*/
+void iwl_activate_qos(struct iwl_priv *priv, u8 force)
+{
+       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
+               return;
+
+       priv->qos_data.def_qos_parm.qos_flags = 0;
+
+       if (priv->qos_data.qos_cap.q_AP.queue_request &&
+           !priv->qos_data.qos_cap.q_AP.txop_request)
+               priv->qos_data.def_qos_parm.qos_flags |=
+                       QOS_PARAM_FLG_TXOP_TYPE_MSK;
+       if (priv->qos_data.qos_active)
+               priv->qos_data.def_qos_parm.qos_flags |=
+                       QOS_PARAM_FLG_UPDATE_EDCA_MSK;
+
+       if (priv->current_ht_config.is_ht)
+               priv->qos_data.def_qos_parm.qos_flags |= QOS_PARAM_FLG_TGN_MSK;
+
+       if (force || iwl_is_associated(priv)) {
+               IWL_DEBUG_QOS(priv, "send QoS cmd with Qos active=%d FLAGS=0x%X\n",
+                               priv->qos_data.qos_active,
+                               priv->qos_data.def_qos_parm.qos_flags);
+
+               iwl_send_cmd_pdu_async(priv, REPLY_QOS_PARAM,
+                                      sizeof(struct iwl_qosparam_cmd),
+                                      &priv->qos_data.def_qos_parm, NULL);
+       }
+}
+EXPORT_SYMBOL(iwl_activate_qos);
+
 void iwl_reset_qos(struct iwl_priv *priv)
 {
        u16 cw_min = 15;
@@ -1386,14 +1419,16 @@ int iwl_set_tx_power(struct iwl_priv *priv, s8 tx_power, bool force)
 {
        int ret = 0;
        if (tx_power < IWL_TX_POWER_TARGET_POWER_MIN) {
-               IWL_WARN(priv, "Requested user TXPOWER %d below limit.\n",
-                           priv->tx_power_user_lmt);
+               IWL_WARN(priv, "Requested user TXPOWER %d below lower limit %d.\n",
+                        tx_power,
+                        IWL_TX_POWER_TARGET_POWER_MIN);
                return -EINVAL;
        }
 
        if (tx_power > IWL_TX_POWER_TARGET_POWER_MAX) {
-               IWL_WARN(priv, "Requested user TXPOWER %d above limit.\n",
-                           priv->tx_power_user_lmt);
+               IWL_WARN(priv, "Requested user TXPOWER %d above upper limit %d.\n",
+                        tx_power,
+                        IWL_TX_POWER_TARGET_POWER_MAX);
                return -EINVAL;
        }
 
@@ -1442,6 +1477,65 @@ void iwl_enable_interrupts(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_enable_interrupts);
 
+irqreturn_t iwl_isr(int irq, void *data)
+{
+       struct iwl_priv *priv = data;
+       u32 inta, inta_mask;
+       u32 inta_fh;
+       if (!priv)
+               return IRQ_NONE;
+
+       spin_lock(&priv->lock);
+
+       /* Disable (but don't clear!) interrupts here to avoid
+        *    back-to-back ISRs and sporadic interrupts from our NIC.
+        * If we have something to service, the tasklet will re-enable ints.
+        * If we *don't* have something, we'll re-enable before leaving here. */
+       inta_mask = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
+       iwl_write32(priv, CSR_INT_MASK, 0x00000000);
+
+       /* Discover which interrupts are active/pending */
+       inta = iwl_read32(priv, CSR_INT);
+       inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
+
+       /* Ignore interrupt if there's nothing in NIC to service.
+        * This may be due to IRQ shared with another device,
+        * or due to sporadic interrupts thrown from our NIC. */
+       if (!inta && !inta_fh) {
+               IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0, inta_fh == 0\n");
+               goto none;
+       }
+
+       if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
+               /* Hardware disappeared. It might have already raised
+                * an interrupt */
+               IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
+               goto unplugged;
+       }
+
+       IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
+                     inta, inta_mask, inta_fh);
+
+       inta &= ~CSR_INT_BIT_SCD;
+
+       /* iwl_irq_tasklet() will service interrupts and re-enable them */
+       if (likely(inta || inta_fh))
+               tasklet_schedule(&priv->irq_tasklet);
+
+ unplugged:
+       spin_unlock(&priv->lock);
+       return IRQ_HANDLED;
+
+ none:
+       /* re-enable interrupts here since we don't have anything to service. */
+       /* only Re-enable if diabled by irq */
+       if (test_bit(STATUS_INT_ENABLED, &priv->status))
+               iwl_enable_interrupts(priv);
+       spin_unlock(&priv->lock);
+       return IRQ_NONE;
+}
+EXPORT_SYMBOL(iwl_isr);
+
 int iwl_send_bt_config(struct iwl_priv *priv)
 {
        struct iwl_bt_cmd bt_cmd = {
@@ -1977,3 +2071,42 @@ void iwl_bg_rf_kill(struct work_struct *work)
        iwl_rfkill_set_hw_state(priv);
 }
 EXPORT_SYMBOL(iwl_bg_rf_kill);
+
+void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
+                          struct iwl_rx_mem_buffer *rxb)
+{
+#ifdef CONFIG_IWLWIFI_DEBUG
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+       struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
+       IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
+                    sleep->pm_sleep_mode, sleep->pm_wakeup_src);
+#endif
+}
+EXPORT_SYMBOL(iwl_rx_pm_sleep_notif);
+
+void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
+                                     struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+       IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
+                       "notification for %s:\n",
+                       le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
+       iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw, le32_to_cpu(pkt->len));
+}
+EXPORT_SYMBOL(iwl_rx_pm_debug_statistics_notif);
+
+void iwl_rx_reply_error(struct iwl_priv *priv,
+                       struct iwl_rx_mem_buffer *rxb)
+{
+       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
+
+       IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) "
+               "seq 0x%04X ser 0x%08X\n",
+               le32_to_cpu(pkt->u.err_resp.error_type),
+               get_cmd_string(pkt->u.err_resp.cmd_id),
+               pkt->u.err_resp.cmd_id,
+               le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
+               le32_to_cpu(pkt->u.err_resp.error_info));
+}
+EXPORT_SYMBOL(iwl_rx_reply_error);
+
index 9d464ec99dd51417e920b2f7c4acd4e57bd9f2a7..27310fec2e43bd5f5498596721b3403b69b0cd35 100644 (file)
@@ -224,6 +224,7 @@ struct ieee80211_hw *iwl_alloc_all(struct iwl_cfg *cfg,
                struct ieee80211_ops *hw_ops);
 void iwl_hw_detect(struct iwl_priv *priv);
 void iwl_reset_qos(struct iwl_priv *priv);
+void iwl_activate_qos(struct iwl_priv *priv, u8 force);
 void iwl_set_rxon_hwcrypto(struct iwl_priv *priv, int hw_decrypt);
 int iwl_check_rxon_cmd(struct iwl_priv *priv);
 int iwl_full_rxon_required(struct iwl_priv *priv);
@@ -249,6 +250,16 @@ int iwl_set_hw_params(struct iwl_priv *priv);
 int iwl_init_drv(struct iwl_priv *priv);
 void iwl_uninit_drv(struct iwl_priv *priv);
 
+/*****************************************************
+ * RX handlers.
+ * **************************************************/
+void iwl_rx_pm_sleep_notif(struct iwl_priv *priv,
+                          struct iwl_rx_mem_buffer *rxb);
+void iwl_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
+                                     struct iwl_rx_mem_buffer *rxb);
+void iwl_rx_reply_error(struct iwl_priv *priv,
+                       struct iwl_rx_mem_buffer *rxb);
+
 /*****************************************************
 * RX
 ******************************************************/
@@ -345,6 +356,7 @@ void iwl_init_scan_params(struct iwl_priv *priv);
 int iwl_scan_cancel(struct iwl_priv *priv);
 int iwl_scan_cancel_timeout(struct iwl_priv *priv, unsigned long ms);
 int iwl_scan_initiate(struct iwl_priv *priv);
+int iwl_mac_hw_scan(struct ieee80211_hw *hw, struct cfg80211_scan_request *req);
 u16 iwl_fill_probe_req(struct iwl_priv *priv, enum ieee80211_band band,
                       struct ieee80211_mgmt *frame, int left);
 void iwl_setup_rx_scan_handlers(struct iwl_priv *priv);
@@ -379,7 +391,7 @@ void iwl_calib_free_results(struct iwl_priv *priv);
 /*******************************************************************************
  * Spectrum Measureemtns in  iwl-spectrum.c
  ******************************************************************************/
-#ifdef CONFIG_IWLAGN_SPECTRUM_MEASUREMENT
+#ifdef CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT
 void iwl_setup_spectrum_handlers(struct iwl_priv *priv);
 #else
 static inline void iwl_setup_spectrum_handlers(struct iwl_priv *priv) {}
@@ -410,6 +422,7 @@ int iwl_send_card_state(struct iwl_priv *priv, u32 flags,
  *****************************************************/
 void iwl_disable_interrupts(struct iwl_priv *priv);
 void iwl_enable_interrupts(struct iwl_priv *priv);
+irqreturn_t iwl_isr(int irq, void *data);
 static inline u16 iwl_pcie_link_ctl(struct iwl_priv *priv)
 {
        int pos;
index 5028c781275b9a3d2f597afe94afaefd1150d057..2f1242447b3b6267b36d4dcc3fcbb808e377e57d 100644 (file)
 #define CSR_HW_REV_TYPE_5350           (0x0000030)
 #define CSR_HW_REV_TYPE_5100           (0x0000050)
 #define CSR_HW_REV_TYPE_5150           (0x0000040)
-#define CSR_HW_REV_TYPE_100            (0x0000060)
+#define CSR_HW_REV_TYPE_1000           (0x0000060)
 #define CSR_HW_REV_TYPE_6x00           (0x0000070)
 #define CSR_HW_REV_TYPE_6x50           (0x0000080)
 #define CSR_HW_REV_TYPE_NONE           (0x00000F0)
index afde713c806f53556a201c577eeae9727dae047a..0baae80228246f9d72c6705c0e1d02339dae8a01 100644 (file)
@@ -62,7 +62,7 @@ extern struct iwl_cfg iwl6000_2agn_cfg;
 extern struct iwl_cfg iwl6000_3agn_cfg;
 extern struct iwl_cfg iwl6050_2agn_cfg;
 extern struct iwl_cfg iwl6050_3agn_cfg;
-extern struct iwl_cfg iwl100_bgn_cfg;
+extern struct iwl_cfg iwl1000_bgn_cfg;
 
 /* shared structures from iwl-5000.c */
 extern struct iwl_mod_params iwl50_mod_params;
@@ -841,7 +841,7 @@ struct iwl_priv {
 
        struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
 
-#if defined(CONFIG_IWLAGN_SPECTRUM_MEASUREMENT) || defined(CONFIG_IWL3945_SPECTRUM_MEASUREMENT)
+#if defined(CONFIG_IWLWIFI_SPECTRUM_MEASUREMENT) || defined(CONFIG_IWL3945_SPECTRUM_MEASUREMENT)
        /* spectrum measurement report caching */
        struct iwl_spectrum_notification measure_report;
        u8 measurement_status;
@@ -922,23 +922,16 @@ struct iwl_priv {
         * 4965's initialize alive response contains some calibration data. */
        struct iwl_init_alive_resp card_alive_init;
        struct iwl_alive_resp card_alive;
-#if defined(CONFIG_IWLWIFI_RFKILL) || defined(CONFIG_IWL3945_RFKILL)
+#if defined(CONFIG_IWLWIFI_RFKILL)
        struct rfkill *rfkill;
 #endif
 
-#if defined(CONFIG_IWLWIFI_LEDS) || defined(CONFIG_IWL3945_LEDS)
+#ifdef CONFIG_IWLWIFI_LEDS
        unsigned long last_blink_time;
        u8 last_blink_rate;
        u8 allow_blinking;
        u64 led_tpt;
-#endif
-
-#ifdef CONFIG_IWLWIFI_LEDS
        struct iwl_led led[IWL_LED_TRG_MAX];
-#endif
-
-#ifdef CONFIG_IWL3945_LEDS
-       struct iwl3945_led led39[IWL_LED_TRG_MAX];
        unsigned int rxtxpackets;
 #endif
        u16 active_rate;
index c7b8e5bb4e427e1d79d0ed229682c887e30780c6..083ea1ffbe87296f8533a2e5ab55d7498d5e4290 100644 (file)
@@ -156,6 +156,7 @@ static inline void __iwl_clear_bit(const char *f, u32 l,
 static inline int _iwl_grab_nic_access(struct iwl_priv *priv)
 {
        int ret;
+       u32 val;
 #ifdef CONFIG_IWLWIFI_DEBUG
        if (atomic_read(&priv->restrict_refcnt))
                return 0;
@@ -167,7 +168,8 @@ static inline int _iwl_grab_nic_access(struct iwl_priv *priv)
                           (CSR_GP_CNTRL_REG_FLAG_MAC_CLOCK_READY |
                            CSR_GP_CNTRL_REG_FLAG_GOING_TO_SLEEP), 15000);
        if (ret < 0) {
-               IWL_ERR(priv, "MAC is in deep sleep!\n");
+               val = _iwl_read32(priv, CSR_GP_CNTRL);
+               IWL_ERR(priv, "MAC is in deep sleep!.  CSR_GP_CNTRL = 0x%08X\n", val);
                return -EIO;
        }
 
index 140fd8fa4855713bed968b01d5162565d632d471..ef9b174c37ff7c0ddd28014eb283a4f2ef53914e 100644 (file)
@@ -30,7 +30,7 @@
 
 struct iwl_priv;
 
-#if defined(CONFIG_IWLWIFI_LEDS) || defined(CONFIG_IWL3945_LEDS)
+#ifdef CONFIG_IWLWIFI_LEDS
 #include <linux/leds.h>
 
 #define IWL_LED_SOLID 11
index 1ec2b20eb37c27f245a850442e1433a524752f74..23644cf884f12d2ddf596ca0a8f690312b01303a 100644 (file)
@@ -440,6 +440,74 @@ int iwl_scan_initiate(struct iwl_priv *priv)
 }
 EXPORT_SYMBOL(iwl_scan_initiate);
 
+#define IWL_DELAY_NEXT_SCAN (HZ*2)
+
+int iwl_mac_hw_scan(struct ieee80211_hw *hw,
+                    struct cfg80211_scan_request *req)
+{
+       unsigned long flags;
+       struct iwl_priv *priv = hw->priv;
+       int ret;
+       u8 *ssid = NULL;
+       size_t ssid_len = 0;
+
+       if (req->n_ssids) {
+               ssid = req->ssids[0].ssid;
+               ssid_len = req->ssids[0].ssid_len;
+       }
+
+       IWL_DEBUG_MAC80211(priv, "enter\n");
+
+       mutex_lock(&priv->mutex);
+       spin_lock_irqsave(&priv->lock, flags);
+
+       if (!iwl_is_ready_rf(priv)) {
+               ret = -EIO;
+               IWL_DEBUG_MAC80211(priv, "leave - not ready or exit pending\n");
+               goto out_unlock;
+       }
+
+       /* We don't schedule scan within next_scan_jiffies period.
+        * Avoid scanning during possible EAPOL exchange, return
+        * success immediately.
+        */
+       if (priv->next_scan_jiffies &&
+           time_after(priv->next_scan_jiffies, jiffies)) {
+               IWL_DEBUG_SCAN(priv, "scan rejected: within next scan period\n");
+               queue_work(priv->workqueue, &priv->scan_completed);
+               ret = 0;
+               goto out_unlock;
+       }
+
+       /* if we just finished scan ask for delay */
+       if (iwl_is_associated(priv) && priv->last_scan_jiffies &&
+           time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN, jiffies)) {
+               IWL_DEBUG_SCAN(priv, "scan rejected: within previous scan period\n");
+               queue_work(priv->workqueue, &priv->scan_completed);
+               ret = 0;
+               goto out_unlock;
+       }
+
+       if (ssid_len) {
+               priv->one_direct_scan = 1;
+               priv->direct_ssid_len =  ssid_len;
+               memcpy(priv->direct_ssid, ssid, priv->direct_ssid_len);
+       } else {
+               priv->one_direct_scan = 0;
+       }
+
+       ret = iwl_scan_initiate(priv);
+
+       IWL_DEBUG_MAC80211(priv, "leave\n");
+
+out_unlock:
+       spin_unlock_irqrestore(&priv->lock, flags);
+       mutex_unlock(&priv->mutex);
+
+       return ret;
+}
+EXPORT_SYMBOL(iwl_mac_hw_scan);
+
 #define IWL_SCAN_CHECK_WATCHDOG (7 * HZ)
 
 void iwl_bg_scan_check(struct work_struct *data)
index 1fae3a6bd8d56f15dc1ec351f081852cc390a3c3..1684490d93c00f474da32cedb27e6cc0b7649350 100644 (file)
@@ -472,6 +472,7 @@ EXPORT_SYMBOL(iwl_remove_station);
 void iwl_clear_stations_table(struct iwl_priv *priv)
 {
        unsigned long flags;
+       int i;
 
        spin_lock_irqsave(&priv->sta_lock, flags);
 
@@ -486,11 +487,17 @@ void iwl_clear_stations_table(struct iwl_priv *priv)
        /* clean ucode key table bit map */
        priv->ucode_key_table = 0;
 
+       /* keep track of static keys */
+       for (i = 0; i < WEP_KEYS_MAX ; i++) {
+               if (priv->wep_keys[i].key_size)
+                       test_and_set_bit(i, &priv->ucode_key_table);
+       }
+
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 }
 EXPORT_SYMBOL(iwl_clear_stations_table);
 
-static int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
+int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
 {
        int i;
 
@@ -500,6 +507,7 @@ static int iwl_get_free_ucode_key_index(struct iwl_priv *priv)
 
        return WEP_INVALID_OFFSET;
 }
+EXPORT_SYMBOL(iwl_get_free_ucode_key_index);
 
 int iwl_send_static_wepkey_cmd(struct iwl_priv *priv, u8 send_if_empty)
 {
index 97f6169007f8f282f75f082f2e03a70507b98db5..59a586b6b56c5f8a40527a4b1f4dad5d68d49ad6 100644 (file)
@@ -54,6 +54,7 @@ void iwl_update_tkip_key(struct iwl_priv *priv,
 int iwl_rxon_add_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
 int iwl_remove_station(struct iwl_priv *priv, const u8 *addr, int is_ap);
 void iwl_clear_stations_table(struct iwl_priv *priv);
+int iwl_get_free_ucode_key_index(struct iwl_priv *priv);
 int iwl_get_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
 int iwl_get_ra_sta_id(struct iwl_priv *priv, struct ieee80211_hdr *hdr);
 int iwl_send_add_sta(struct iwl_priv *priv,
index ae04c2086f70004f3aabb26d8044d5c832c26db7..dff60fb70214938d5acb1b1ed9270a6261c45581 100644 (file)
@@ -819,7 +819,7 @@ int iwl_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
         * within command buffer array. */
        txcmd_phys = pci_map_single(priv->pci_dev,
                                    out_cmd, sizeof(struct iwl_cmd),
-                                   PCI_DMA_TODEVICE);
+                                   PCI_DMA_BIDIRECTIONAL);
        pci_unmap_addr_set(&out_cmd->meta, mapping, txcmd_phys);
        pci_unmap_len_set(&out_cmd->meta, len, sizeof(struct iwl_cmd));
        /* Add buffer containing Tx command and MAC(!) header to TFD's
@@ -968,7 +968,7 @@ int iwl_enqueue_hcmd(struct iwl_priv *priv, struct iwl_host_cmd *cmd)
                        IWL_MAX_SCAN_SIZE : sizeof(struct iwl_cmd);
 
        phys_addr = pci_map_single(priv->pci_dev, out_cmd,
-                                  len, PCI_DMA_TODEVICE);
+                                  len, PCI_DMA_BIDIRECTIONAL);
        pci_unmap_addr_set(&out_cmd->meta, mapping, phys_addr);
        pci_unmap_len_set(&out_cmd->meta, len, len);
        phys_addr += offsetof(struct iwl_cmd, hdr);
@@ -1068,7 +1068,7 @@ static void iwl_hcmd_queue_reclaim(struct iwl_priv *priv, int txq_id,
        pci_unmap_single(priv->pci_dev,
                pci_unmap_addr(&txq->cmd[cmd_idx]->meta, mapping),
                pci_unmap_len(&txq->cmd[cmd_idx]->meta, len),
-               PCI_DMA_TODEVICE);
+               PCI_DMA_BIDIRECTIONAL);
 
        for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx;
             q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
index 0cd8cb96a5ef03d6e319007c90693bf9e4f84388..4465320f27350d2c59b12d48afafacb50e3dfb78 100644 (file)
@@ -328,6 +328,8 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
        struct iwl3945_rxon_cmd *active_rxon = (void *)&priv->active_rxon;
        struct iwl3945_rxon_cmd *staging_rxon = (void *)&priv->staging_rxon;
        int rc = 0;
+       bool new_assoc =
+               !!(priv->staging_rxon.filter_flags & RXON_FILTER_ASSOC_MSK);
 
        if (!iwl_is_alive(priv))
                return -1;
@@ -366,8 +368,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
         * an RXON_ASSOC and the new config wants the associated mask enabled,
         * we must clear the associated from the active configuration
         * before we apply the new config */
-       if (iwl_is_associated(priv) &&
-           (staging_rxon->filter_flags & RXON_FILTER_ASSOC_MSK)) {
+       if (iwl_is_associated(priv) && new_assoc) {
                IWL_DEBUG_INFO(priv, "Toggling associated bit on current RXON\n");
                active_rxon->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
 
@@ -395,8 +396,7 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
                       "* with%s RXON_FILTER_ASSOC_MSK\n"
                       "* channel = %d\n"
                       "* bssid = %pM\n",
-                      ((priv->staging_rxon.filter_flags &
-                        RXON_FILTER_ASSOC_MSK) ? "" : "out"),
+                      (new_assoc ? "" : "out"),
                       le16_to_cpu(staging_rxon->channel),
                       staging_rxon->bssid_addr);
 
@@ -407,6 +407,8 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
        staging_rxon->reserved4 = 0;
        staging_rxon->reserved5 = 0;
 
+       iwl_set_rxon_hwcrypto(priv, !priv->hw_params.sw_crypto);
+
        /* Apply the new configuration */
        rc = iwl_send_cmd_pdu(priv, REPLY_RXON,
                              sizeof(struct iwl3945_rxon_cmd),
@@ -456,25 +458,24 @@ static int iwl3945_commit_rxon(struct iwl_priv *priv)
        return 0;
 }
 
-static int iwl3945_update_sta_key_info(struct iwl_priv *priv,
+static int iwl3945_set_ccmp_dynamic_key_info(struct iwl_priv *priv,
                                   struct ieee80211_key_conf *keyconf,
                                   u8 sta_id)
 {
        unsigned long flags;
        __le16 key_flags = 0;
+       int ret;
+
+       key_flags |= (STA_KEY_FLG_CCMP | STA_KEY_FLG_MAP_KEY_MSK);
+       key_flags |= cpu_to_le16(keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
+
+       if (sta_id == priv->hw_params.bcast_sta_id)
+               key_flags |= STA_KEY_MULTICAST_MSK;
+
+       keyconf->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
+       keyconf->hw_key_idx = keyconf->keyidx;
+       key_flags &= ~STA_KEY_FLG_INVALID;
 
-       switch (keyconf->alg) {
-       case ALG_CCMP:
-               key_flags |= STA_KEY_FLG_CCMP;
-               key_flags |= cpu_to_le16(
-                               keyconf->keyidx << STA_KEY_FLG_KEYID_POS);
-               key_flags &= ~STA_KEY_FLG_INVALID;
-               break;
-       case ALG_TKIP:
-       case ALG_WEP:
-       default:
-               return -EINVAL;
-       }
        spin_lock_irqsave(&priv->sta_lock, flags);
        priv->stations_39[sta_id].keyinfo.alg = keyconf->alg;
        priv->stations_39[sta_id].keyinfo.keylen = keyconf->keylen;
@@ -483,16 +484,43 @@ static int iwl3945_update_sta_key_info(struct iwl_priv *priv,
 
        memcpy(priv->stations_39[sta_id].sta.key.key, keyconf->key,
               keyconf->keylen);
+
+       if ((priv->stations[sta_id].sta.key.key_flags & STA_KEY_FLG_ENCRYPT_MSK)
+                       == STA_KEY_FLG_NO_ENC)
+               priv->stations[sta_id].sta.key.key_offset =
+                                iwl_get_free_ucode_key_index(priv);
+       /* else, we are overriding an existing key => no need to allocated room
+       * in uCode. */
+
+       WARN(priv->stations[sta_id].sta.key.key_offset == WEP_INVALID_OFFSET,
+               "no space for a new key");
+
        priv->stations_39[sta_id].sta.key.key_flags = key_flags;
        priv->stations_39[sta_id].sta.sta.modify_mask = STA_MODIFY_KEY_MASK;
        priv->stations_39[sta_id].sta.mode = STA_CONTROL_MODIFY_MSK;
 
+       IWL_DEBUG_INFO(priv, "hwcrypto: modify ucode station key info\n");
+
+       ret = iwl_send_add_sta(priv,
+               (struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, CMD_ASYNC);
+
        spin_unlock_irqrestore(&priv->sta_lock, flags);
 
-       IWL_DEBUG_INFO(priv, "hwcrypto: modify ucode station key info\n");
-       iwl_send_add_sta(priv,
-               (struct iwl_addsta_cmd *)&priv->stations_39[sta_id].sta, 0);
-       return 0;
+       return ret;
+}
+
+static int iwl3945_set_tkip_dynamic_key_info(struct iwl_priv *priv,
+                                 struct ieee80211_key_conf *keyconf,
+                                 u8 sta_id)
+{
+       return -EOPNOTSUPP;
+}
+
+static int iwl3945_set_wep_dynamic_key_info(struct iwl_priv *priv,
+                                 struct ieee80211_key_conf *keyconf,
+                                 u8 sta_id)
+{
+       return -EOPNOTSUPP;
 }
 
 static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
@@ -514,6 +542,52 @@ static int iwl3945_clear_sta_key_info(struct iwl_priv *priv, u8 sta_id)
        return 0;
 }
 
+static int iwl3945_set_dynamic_key(struct iwl_priv *priv,
+                       struct ieee80211_key_conf *keyconf, u8 sta_id)
+{
+       int ret = 0;
+
+       keyconf->hw_key_idx = HW_KEY_DYNAMIC;
+
+       switch (keyconf->alg) {
+       case ALG_CCMP:
+               ret = iwl3945_set_ccmp_dynamic_key_info(priv, keyconf, sta_id);
+               break;
+       case ALG_TKIP:
+               ret = iwl3945_set_tkip_dynamic_key_info(priv, keyconf, sta_id);
+               break;
+       case ALG_WEP:
+               ret = iwl3945_set_wep_dynamic_key_info(priv, keyconf, sta_id);
+               break;
+       default:
+               IWL_ERR(priv,"Unknown alg: %s alg = %d\n", __func__, keyconf->alg);
+               ret = -EINVAL;
+       }
+
+       IWL_DEBUG_WEP(priv, "Set dynamic key: alg= %d len=%d idx=%d sta=%d ret=%d\n",
+                     keyconf->alg, keyconf->keylen, keyconf->keyidx,
+                     sta_id, ret);
+
+       return ret;
+}
+
+static int iwl3945_remove_static_key(struct iwl_priv *priv)
+{
+       int ret = -EOPNOTSUPP;
+
+       return ret;
+}
+
+static int iwl3945_set_static_key(struct iwl_priv *priv,
+                               struct ieee80211_key_conf *key)
+{
+       if (key->alg == ALG_WEP)
+               return -EOPNOTSUPP;
+
+       IWL_ERR(priv, "Static key invalid: alg %d\n", key->alg);
+       return -EINVAL;
+}
+
 static void iwl3945_clear_free_frames(struct iwl_priv *priv)
 {
        struct list_head *element;
@@ -615,48 +689,6 @@ static void iwl3945_unset_hw_params(struct iwl_priv *priv)
                                    priv->shared_phys);
 }
 
-/*
- * QoS  support
-*/
-static int iwl3945_send_qos_params_command(struct iwl_priv *priv,
-                                      struct iwl_qosparam_cmd *qos)
-{
-
-       return iwl_send_cmd_pdu(priv, REPLY_QOS_PARAM,
-                               sizeof(struct iwl_qosparam_cmd), qos);
-}
-
-static void iwl3945_activate_qos(struct iwl_priv *priv, u8 force)
-{
-       unsigned long flags;
-
-       if (test_bit(STATUS_EXIT_PENDING, &priv->status))
-               return;
-
-       spin_lock_irqsave(&priv->lock, flags);
-       priv->qos_data.def_qos_parm.qos_flags = 0;
-
-       if (priv->qos_data.qos_cap.q_AP.queue_request &&
-           !priv->qos_data.qos_cap.q_AP.txop_request)
-               priv->qos_data.def_qos_parm.qos_flags |=
-                       QOS_PARAM_FLG_TXOP_TYPE_MSK;
-
-       if (priv->qos_data.qos_active)
-               priv->qos_data.def_qos_parm.qos_flags |=
-                       QOS_PARAM_FLG_UPDATE_EDCA_MSK;
-
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       if (force || iwl_is_associated(priv)) {
-               IWL_DEBUG_QOS(priv, "send QoS cmd with QoS active %d \n",
-                             priv->qos_data.qos_active);
-
-               iwl3945_send_qos_params_command(priv,
-                               &(priv->qos_data.def_qos_parm));
-       }
-}
-
-
 #define MAX_UCODE_BEACON_INTERVAL      1024
 #define INTEL_CONN_LISTEN_INTERVAL     cpu_to_le16(0xA)
 
@@ -726,38 +758,6 @@ static void iwl3945_setup_rxon_timing(struct iwl_priv *priv)
                le16_to_cpu(priv->rxon_timing.atim_window));
 }
 
-static int iwl3945_scan_initiate(struct iwl_priv *priv)
-{
-       if (!iwl_is_ready_rf(priv)) {
-               IWL_DEBUG_SCAN(priv, "Aborting scan due to not ready.\n");
-               return -EIO;
-       }
-
-       if (test_bit(STATUS_SCANNING, &priv->status)) {
-               IWL_DEBUG_SCAN(priv, "Scan already in progress.\n");
-               return -EAGAIN;
-       }
-
-       if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
-               IWL_DEBUG_SCAN(priv, "Scan request while abort pending.  "
-                              "Queuing.\n");
-               return -EAGAIN;
-       }
-
-       IWL_DEBUG_INFO(priv, "Starting scan...\n");
-       if (priv->cfg->sku & IWL_SKU_G)
-               priv->scan_bands |= BIT(IEEE80211_BAND_2GHZ);
-       if (priv->cfg->sku & IWL_SKU_A)
-               priv->scan_bands |= BIT(IEEE80211_BAND_5GHZ);
-       set_bit(STATUS_SCANNING, &priv->status);
-       priv->scan_start = jiffies;
-       priv->scan_pass_start = priv->scan_start;
-
-       queue_work(priv->workqueue, &priv->request_scan);
-
-       return 0;
-}
-
 static int iwl3945_set_mode(struct iwl_priv *priv, int mode)
 {
        if (mode == NL80211_IFTYPE_ADHOC) {
@@ -798,11 +798,11 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
                                      struct ieee80211_tx_info *info,
                                      struct iwl_cmd *cmd,
                                      struct sk_buff *skb_frag,
-                                     int last_frag)
+                                     int sta_id)
 {
        struct iwl3945_tx_cmd *tx = (struct iwl3945_tx_cmd *)cmd->cmd.payload;
        struct iwl3945_hw_key *keyinfo =
-           &priv->stations_39[info->control.hw_key->hw_key_idx].keyinfo;
+           &priv->stations_39[sta_id].keyinfo;
 
        switch (keyinfo->alg) {
        case ALG_CCMP:
@@ -812,15 +812,6 @@ static void iwl3945_build_tx_cmd_hwcrypto(struct iwl_priv *priv,
                break;
 
        case ALG_TKIP:
-#if 0
-               tx->sec_ctl = TX_CMD_SEC_TKIP;
-
-               if (last_frag)
-                       memcpy(tx->tkip_mic.byte, skb_frag->tail - 8,
-                              8);
-               else
-                       memset(tx->tkip_mic.byte, 0, 8);
-#endif
                break;
 
        case ALG_WEP:
@@ -899,7 +890,7 @@ static void iwl3945_build_tx_cmd_basic(struct iwl_priv *priv,
                        tx->timeout.pm_frame_timeout = cpu_to_le16(2);
        } else {
                tx->timeout.pm_frame_timeout = 0;
-#ifdef CONFIG_IWL3945_LEDS
+#ifdef CONFIG_IWLWIFI_LEDS
                priv->rxtxpackets += le16_to_cpu(cmd->cmd.tx.len);
 #endif
        }
@@ -1120,7 +1111,7 @@ static int iwl3945_tx_skb(struct iwl_priv *priv, struct sk_buff *skb)
                                                   txcmd_phys, len, 1, 0);
 
        if (info->control.hw_key)
-               iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, 0);
+               iwl3945_build_tx_cmd_hwcrypto(priv, info, out_cmd, skb, sta_id);
 
        /* Set up TFD's 2nd entry to point directly to remainder of skb,
         * if any (802.11 null frames have no payload). */
@@ -1188,56 +1179,6 @@ drop:
        return -1;
 }
 
-static void iwl3945_radio_kill_sw(struct iwl_priv *priv, int disable_radio)
-{
-       unsigned long flags;
-
-       if (!!disable_radio == test_bit(STATUS_RF_KILL_SW, &priv->status))
-               return;
-
-       IWL_DEBUG_RF_KILL(priv, "Manual SW RF KILL set to: RADIO %s\n",
-                         disable_radio ? "OFF" : "ON");
-
-       if (disable_radio) {
-               iwl_scan_cancel(priv);
-               /* FIXME: This is a workaround for AP */
-               if (priv->iw_mode != NL80211_IFTYPE_AP) {
-                       spin_lock_irqsave(&priv->lock, flags);
-                       iwl_write32(priv, CSR_UCODE_DRV_GP1_SET,
-                                   CSR_UCODE_SW_BIT_RFKILL);
-                       spin_unlock_irqrestore(&priv->lock, flags);
-                       iwl_send_card_state(priv, CARD_STATE_CMD_DISABLE, 0);
-                       set_bit(STATUS_RF_KILL_SW, &priv->status);
-               }
-               return;
-       }
-
-       spin_lock_irqsave(&priv->lock, flags);
-       iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
-
-       clear_bit(STATUS_RF_KILL_SW, &priv->status);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       /* wake up ucode */
-       msleep(10);
-
-       spin_lock_irqsave(&priv->lock, flags);
-       iwl_read32(priv, CSR_UCODE_DRV_GP1);
-       if (!iwl_grab_nic_access(priv))
-               iwl_release_nic_access(priv);
-       spin_unlock_irqrestore(&priv->lock, flags);
-
-       if (test_bit(STATUS_RF_KILL_HW, &priv->status)) {
-               IWL_DEBUG_RF_KILL(priv, "Can not turn radio back on - "
-                                 "disabled by HW switch\n");
-               return;
-       }
-
-       if (priv->is_open)
-               queue_work(priv->workqueue, &priv->restart);
-       return;
-}
-
 #ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
 
 #include "iwl-spectrum.h"
@@ -1417,60 +1358,6 @@ static void iwl3945_rx_reply_add_sta(struct iwl_priv *priv,
        return;
 }
 
-static void iwl3945_rx_reply_error(struct iwl_priv *priv,
-                              struct iwl_rx_mem_buffer *rxb)
-{
-       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-
-       IWL_ERR(priv, "Error Reply type 0x%08X cmd %s (0x%02X) "
-               "seq 0x%04X ser 0x%08X\n",
-               le32_to_cpu(pkt->u.err_resp.error_type),
-               get_cmd_string(pkt->u.err_resp.cmd_id),
-               pkt->u.err_resp.cmd_id,
-               le16_to_cpu(pkt->u.err_resp.bad_cmd_seq_num),
-               le32_to_cpu(pkt->u.err_resp.error_info));
-}
-
-static void iwl3945_rx_spectrum_measure_notif(struct iwl_priv *priv,
-                                         struct iwl_rx_mem_buffer *rxb)
-{
-#ifdef CONFIG_IWL3945_SPECTRUM_MEASUREMENT
-       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-       struct iwl_spectrum_notification *report = &(pkt->u.spectrum_notif);
-
-       if (!report->state) {
-               IWL_DEBUG(priv, IWL_DL_11H | IWL_DL_INFO,
-                         "Spectrum Measure Notification: Start\n");
-               return;
-       }
-
-       memcpy(&priv->measure_report, report, sizeof(*report));
-       priv->measurement_status |= MEASUREMENT_READY;
-#endif
-}
-
-static void iwl3945_rx_pm_sleep_notif(struct iwl_priv *priv,
-                                 struct iwl_rx_mem_buffer *rxb)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-       struct iwl_sleep_notification *sleep = &(pkt->u.sleep_notif);
-       IWL_DEBUG_RX(priv, "sleep mode: %d, src: %d\n",
-                    sleep->pm_sleep_mode, sleep->pm_wakeup_src);
-#endif
-}
-
-static void iwl3945_rx_pm_debug_statistics_notif(struct iwl_priv *priv,
-                                            struct iwl_rx_mem_buffer *rxb)
-{
-       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-       IWL_DEBUG_RADIO(priv, "Dumping %d bytes of unhandled "
-                       "notification for %s:\n",
-                       le32_to_cpu(pkt->len), get_cmd_string(pkt->hdr.cmd));
-       iwl_print_hex_dump(priv, IWL_DL_RADIO, pkt->u.raw,
-                          le32_to_cpu(pkt->len));
-}
-
 static void iwl3945_bg_beacon_update(struct work_struct *work)
 {
        struct iwl_priv *priv =
@@ -1518,127 +1405,6 @@ static void iwl3945_rx_beacon_notif(struct iwl_priv *priv,
                queue_work(priv->workqueue, &priv->beacon_update);
 }
 
-/* Service response to REPLY_SCAN_CMD (0x80) */
-static void iwl3945_rx_reply_scan(struct iwl_priv *priv,
-                             struct iwl_rx_mem_buffer *rxb)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-       struct iwl_scanreq_notification *notif =
-           (struct iwl_scanreq_notification *)pkt->u.raw;
-
-       IWL_DEBUG_RX(priv, "Scan request status = 0x%x\n", notif->status);
-#endif
-}
-
-/* Service SCAN_START_NOTIFICATION (0x82) */
-static void iwl3945_rx_scan_start_notif(struct iwl_priv *priv,
-                                   struct iwl_rx_mem_buffer *rxb)
-{
-       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-       struct iwl_scanstart_notification *notif =
-           (struct iwl_scanstart_notification *)pkt->u.raw;
-       priv->scan_start_tsf = le32_to_cpu(notif->tsf_low);
-       IWL_DEBUG_SCAN(priv, "Scan start: "
-                      "%d [802.11%s] "
-                      "(TSF: 0x%08X:%08X) - %d (beacon timer %u)\n",
-                      notif->channel,
-                      notif->band ? "bg" : "a",
-                      notif->tsf_high,
-                      notif->tsf_low, notif->status, notif->beacon_timer);
-}
-
-/* Service SCAN_RESULTS_NOTIFICATION (0x83) */
-static void iwl3945_rx_scan_results_notif(struct iwl_priv *priv,
-                                     struct iwl_rx_mem_buffer *rxb)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-       struct iwl_scanresults_notification *notif =
-           (struct iwl_scanresults_notification *)pkt->u.raw;
-#endif
-
-       IWL_DEBUG_SCAN(priv, "Scan ch.res: "
-                      "%d [802.11%s] "
-                      "(TSF: 0x%08X:%08X) - %d "
-                      "elapsed=%lu usec (%dms since last)\n",
-                      notif->channel,
-                      notif->band ? "bg" : "a",
-                      le32_to_cpu(notif->tsf_high),
-                      le32_to_cpu(notif->tsf_low),
-                      le32_to_cpu(notif->statistics[0]),
-                      le32_to_cpu(notif->tsf_low) - priv->scan_start_tsf,
-                      jiffies_to_msecs(elapsed_jiffies
-                                       (priv->last_scan_jiffies, jiffies)));
-
-       priv->last_scan_jiffies = jiffies;
-       priv->next_scan_jiffies = 0;
-}
-
-/* Service SCAN_COMPLETE_NOTIFICATION (0x84) */
-static void iwl3945_rx_scan_complete_notif(struct iwl_priv *priv,
-                                      struct iwl_rx_mem_buffer *rxb)
-{
-#ifdef CONFIG_IWLWIFI_DEBUG
-       struct iwl_rx_packet *pkt = (void *)rxb->skb->data;
-       struct iwl_scancomplete_notification *scan_notif = (void *)pkt->u.raw;
-#endif
-
-       IWL_DEBUG_SCAN(priv, "Scan complete: %d channels (TSF 0x%08X:%08X) - %d\n",
-                      scan_notif->scanned_channels,
-                      scan_notif->tsf_low,
-                      scan_notif->tsf_high, scan_notif->status);
-
-       /* The HW is no longer scanning */
-       clear_bit(STATUS_SCAN_HW, &priv->status);
-
-       /* The scan completion notification came in, so kill that timer... */
-       cancel_delayed_work(&priv->scan_check);
-
-       IWL_DEBUG_INFO(priv, "Scan pass on %sGHz took %dms\n",
-                      (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ)) ?
-                                                       "2.4" : "5.2",
-                      jiffies_to_msecs(elapsed_jiffies
-                                       (priv->scan_pass_start, jiffies)));
-
-       /* Remove this scanned band from the list of pending
-        * bands to scan, band G precedes A in order of scanning
-        * as seen in iwl3945_bg_request_scan */
-       if (priv->scan_bands & BIT(IEEE80211_BAND_2GHZ))
-               priv->scan_bands &= ~BIT(IEEE80211_BAND_2GHZ);
-       else if (priv->scan_bands &  BIT(IEEE80211_BAND_5GHZ))
-               priv->scan_bands &= ~BIT(IEEE80211_BAND_5GHZ);
-
-       /* If a request to abort was given, or the scan did not succeed
-        * then we reset the scan state machine and terminate,
-        * re-queuing another scan if one has been requested */
-       if (test_bit(STATUS_SCAN_ABORTING, &priv->status)) {
-               IWL_DEBUG_INFO(priv, "Aborted scan completed.\n");
-               clear_bit(STATUS_SCAN_ABORTING, &priv->status);
-       } else {
-               /* If there are more bands on this scan pass reschedule */
-               if (priv->scan_bands > 0)
-                       goto reschedule;
-       }
-
-       priv->last_scan_jiffies = jiffies;
-       priv->next_scan_jiffies = 0;
-       IWL_DEBUG_INFO(priv, "Setting scan to off\n");
-
-       clear_bit(STATUS_SCANNING, &priv->status);
-
-       IWL_DEBUG_INFO(priv, "Scan took %dms\n",
-               jiffies_to_msecs(elapsed_jiffies(priv->scan_start, jiffies)));
-
-       queue_work(priv->workqueue, &priv->scan_completed);
-
-       return;
-
-reschedule:
-       priv->scan_pass_start = jiffies;
-       queue_work(priv->workqueue, &priv->request_scan);
-}
-
 /* Handle notification from uCode that card's power state is changing
  * due to software, hardware, or critical temperature RFKILL */
 static void iwl3945_rx_card_state_notif(struct iwl_priv *priv,
@@ -1690,13 +1456,11 @@ static void iwl3945_setup_rx_handlers(struct iwl_priv *priv)
 {
        priv->rx_handlers[REPLY_ALIVE] = iwl3945_rx_reply_alive;
        priv->rx_handlers[REPLY_ADD_STA] = iwl3945_rx_reply_add_sta;
-       priv->rx_handlers[REPLY_ERROR] = iwl3945_rx_reply_error;
+       priv->rx_handlers[REPLY_ERROR] = iwl_rx_reply_error;
        priv->rx_handlers[CHANNEL_SWITCH_NOTIFICATION] = iwl_rx_csa;
-       priv->rx_handlers[SPECTRUM_MEASURE_NOTIFICATION] =
-           iwl3945_rx_spectrum_measure_notif;
-       priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl3945_rx_pm_sleep_notif;
+       priv->rx_handlers[PM_SLEEP_NOTIFICATION] = iwl_rx_pm_sleep_notif;
        priv->rx_handlers[PM_DEBUG_STATISTIC_NOTIFIC] =
-           iwl3945_rx_pm_debug_statistics_notif;
+           iwl_rx_pm_debug_statistics_notif;
        priv->rx_handlers[BEACON_NOTIFICATION] = iwl3945_rx_beacon_notif;
 
        /*
@@ -1707,97 +1471,14 @@ static void iwl3945_setup_rx_handlers(struct iwl_priv *priv)
        priv->rx_handlers[REPLY_STATISTICS_CMD] = iwl3945_hw_rx_statistics;
        priv->rx_handlers[STATISTICS_NOTIFICATION] = iwl3945_hw_rx_statistics;
 
-       priv->rx_handlers[REPLY_SCAN_CMD] = iwl3945_rx_reply_scan;
-       priv->rx_handlers[SCAN_START_NOTIFICATION] = iwl3945_rx_scan_start_notif;
-       priv->rx_handlers[SCAN_RESULTS_NOTIFICATION] =
-           iwl3945_rx_scan_results_notif;
-       priv->rx_handlers[SCAN_COMPLETE_NOTIFICATION] =
-           iwl3945_rx_scan_complete_notif;
+       iwl_setup_spectrum_handlers(priv);
+       iwl_setup_rx_scan_handlers(priv);
        priv->rx_handlers[CARD_STATE_NOTIFICATION] = iwl3945_rx_card_state_notif;
 
        /* Set up hardware specific Rx handlers */
        iwl3945_hw_rx_handler_setup(priv);
 }
 
-/**
- * iwl3945_cmd_queue_reclaim - Reclaim CMD queue entries
- * When FW advances 'R' index, all entries between old and new 'R' index
- * need to be reclaimed.
- */
-static void iwl3945_cmd_queue_reclaim(struct iwl_priv *priv,
-                                     int txq_id, int index)
-{
-       struct iwl_tx_queue *txq = &priv->txq[txq_id];
-       struct iwl_queue *q = &txq->q;
-       int nfreed = 0;
-
-       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);
-               return;
-       }
-
-       for (index = iwl_queue_inc_wrap(index, q->n_bd); q->read_ptr != index;
-               q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
-               if (nfreed > 1) {
-                       IWL_ERR(priv, "HCMD skipped: index (%d) %d %d\n", index,
-                                       q->write_ptr, q->read_ptr);
-                       queue_work(priv->workqueue, &priv->restart);
-                       break;
-               }
-               nfreed++;
-       }
-}
-
-
-/**
- * iwl3945_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
- * @rxb: Rx buffer to reclaim
- *
- * If an Rx buffer has an async callback associated with it the callback
- * will be executed.  The attached skb (if present) will only be freed
- * if the callback returns 1
- */
-static void iwl3945_tx_cmd_complete(struct iwl_priv *priv,
-                               struct iwl_rx_mem_buffer *rxb)
-{
-       struct iwl_rx_packet *pkt = (struct iwl_rx_packet *)rxb->skb->data;
-       u16 sequence = le16_to_cpu(pkt->hdr.sequence);
-       int txq_id = SEQ_TO_QUEUE(sequence);
-       int index = SEQ_TO_INDEX(sequence);
-       int huge =  !!(pkt->hdr.sequence & SEQ_HUGE_FRAME);
-       int cmd_index;
-       struct iwl_cmd *cmd;
-
-       if (WARN(txq_id != IWL_CMD_QUEUE_NUM,
-                "wrong command queue %d, sequence 0x%X readp=%d writep=%d\n",
-                 txq_id, sequence,
-                 priv->txq[IWL_CMD_QUEUE_NUM].q.read_ptr,
-                 priv->txq[IWL_CMD_QUEUE_NUM].q.write_ptr)) {
-               iwl_print_hex_dump(priv, IWL_DL_INFO , rxb, 32);
-               return;
-       }
-
-       cmd_index = get_cmd_index(&priv->txq[IWL_CMD_QUEUE_NUM].q, index, huge);
-       cmd = priv->txq[IWL_CMD_QUEUE_NUM].cmd[cmd_index];
-
-       /* Input error checking is done when commands are added to queue. */
-       if (cmd->meta.flags & CMD_WANT_SKB) {
-               cmd->meta.source->u.skb = rxb->skb;
-               rxb->skb = NULL;
-       } else if (cmd->meta.u.callback &&
-                  !cmd->meta.u.callback(priv, cmd, rxb->skb))
-               rxb->skb = NULL;
-
-       iwl3945_cmd_queue_reclaim(priv, txq_id, index);
-
-       if (!(cmd->meta.flags & CMD_ASYNC)) {
-               clear_bit(STATUS_HCMD_ACTIVE, &priv->status);
-               wake_up_interruptible(&priv->wait_command_queue);
-       }
-}
-
 /************************** RX-FUNCTIONS ****************************/
 /*
  * Rx theory of operation
@@ -2157,7 +1838,7 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
                         * fire off the (possibly) blocking iwl_send_cmd()
                         * as we reclaim the driver command queue */
                        if (rxb && rxb->skb)
-                               iwl3945_tx_cmd_complete(priv, rxb);
+                               iwl_tx_cmd_complete(priv, rxb);
                        else
                                IWL_WARN(priv, "Claim null rxb?\n");
                }
@@ -2195,14 +1876,6 @@ static void iwl3945_rx_handle(struct iwl_priv *priv)
        iwl3945_rx_queue_restock(priv);
 }
 
-static void iwl3945_enable_interrupts(struct iwl_priv *priv)
-{
-       IWL_DEBUG_ISR(priv, "Enabling interrupts\n");
-       set_bit(STATUS_INT_ENABLED, &priv->status);
-       iwl_write32(priv, CSR_INT_MASK, CSR_INI_SET_MASK);
-}
-
-
 /* call this function to flush any scheduled tasklet */
 static inline void iwl_synchronize_irq(struct iwl_priv *priv)
 {
@@ -2211,21 +1884,6 @@ static inline void iwl_synchronize_irq(struct iwl_priv *priv)
        tasklet_kill(&priv->irq_tasklet);
 }
 
-
-static inline void iwl3945_disable_interrupts(struct iwl_priv *priv)
-{
-       clear_bit(STATUS_INT_ENABLED, &priv->status);
-
-       /* disable interrupts from uCode/NIC to host */
-       iwl_write32(priv, CSR_INT_MASK, 0x00000000);
-
-       /* acknowledge/clear/reset any interrupts still pending
-        * from uCode or flow handler (Rx/Tx DMA) */
-       iwl_write32(priv, CSR_INT, 0xffffffff);
-       iwl_write32(priv, CSR_FH_INT_STATUS, 0xffffffff);
-       IWL_DEBUG_ISR(priv, "Disabled interrupts\n");
-}
-
 static const char *desc_lookup(int i)
 {
        switch (i) {
@@ -2467,7 +2125,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
                IWL_ERR(priv, "Microcode HW error detected.  Restarting.\n");
 
                /* Tell the device to stop sending interrupts */
-               iwl3945_disable_interrupts(priv);
+               iwl_disable_interrupts(priv);
 
                iwl_irq_handle_error(priv);
 
@@ -2547,7 +2205,7 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
        /* Re-enable all interrupts */
        /* only Re-enable if disabled by irq */
        if (test_bit(STATUS_INT_ENABLED, &priv->status))
-               iwl3945_enable_interrupts(priv);
+               iwl_enable_interrupts(priv);
 
 #ifdef CONFIG_IWLWIFI_DEBUG
        if (priv->debug_level & (IWL_DL_ISR)) {
@@ -2561,63 +2219,6 @@ static void iwl3945_irq_tasklet(struct iwl_priv *priv)
        spin_unlock_irqrestore(&priv->lock, flags);
 }
 
-static irqreturn_t iwl3945_isr(int irq, void *data)
-{
-       struct iwl_priv *priv = data;
-       u32 inta, inta_mask;
-       u32 inta_fh;
-       if (!priv)
-               return IRQ_NONE;
-
-       spin_lock(&priv->lock);
-
-       /* Disable (but don't clear!) interrupts here to avoid
-        *    back-to-back ISRs and sporadic interrupts from our NIC.
-        * If we have something to service, the tasklet will re-enable ints.
-        * If we *don't* have something, we'll re-enable before leaving here. */
-       inta_mask = iwl_read32(priv, CSR_INT_MASK);  /* just for debug */
-       iwl_write32(priv, CSR_INT_MASK, 0x00000000);
-
-       /* Discover which interrupts are active/pending */
-       inta = iwl_read32(priv, CSR_INT);
-       inta_fh = iwl_read32(priv, CSR_FH_INT_STATUS);
-
-       /* Ignore interrupt if there's nothing in NIC to service.
-        * This may be due to IRQ shared with another device,
-        * or due to sporadic interrupts thrown from our NIC. */
-       if (!inta && !inta_fh) {
-               IWL_DEBUG_ISR(priv, "Ignore interrupt, inta == 0, inta_fh == 0\n");
-               goto none;
-       }
-
-       if ((inta == 0xFFFFFFFF) || ((inta & 0xFFFFFFF0) == 0xa5a5a5a0)) {
-               /* Hardware disappeared */
-               IWL_WARN(priv, "HARDWARE GONE?? INTA == 0x%08x\n", inta);
-               goto unplugged;
-       }
-
-       IWL_DEBUG_ISR(priv, "ISR inta 0x%08x, enabled 0x%08x, fh 0x%08x\n",
-                     inta, inta_mask, inta_fh);
-
-       inta &= ~CSR_INT_BIT_SCD;
-
-       /* iwl3945_irq_tasklet() will service interrupts and re-enable them */
-       if (likely(inta || inta_fh))
-               tasklet_schedule(&priv->irq_tasklet);
-unplugged:
-       spin_unlock(&priv->lock);
-
-       return IRQ_HANDLED;
-
- none:
-       /* re-enable interrupts here since we don't have anything to service. */
-       /* only Re-enable if disabled by irq */
-       if (test_bit(STATUS_INT_ENABLED, &priv->status))
-               iwl3945_enable_interrupts(priv);
-       spin_unlock(&priv->lock);
-       return IRQ_NONE;
-}
-
 static int iwl3945_get_channels_for_scan(struct iwl_priv *priv,
                                         enum ieee80211_band band,
                                     u8 is_active, u8 n_probes,
@@ -3387,7 +2988,7 @@ static void __iwl3945_down(struct iwl_priv *priv)
 
        /* tell the device to stop sending interrupts */
        spin_lock_irqsave(&priv->lock, flags);
-       iwl3945_disable_interrupts(priv);
+       iwl_disable_interrupts(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
        iwl_synchronize_irq(priv);
 
@@ -3517,7 +3118,7 @@ static int __iwl3945_up(struct iwl_priv *priv)
 
        /* clear (again), then enable host interrupts */
        iwl_write32(priv, CSR_INT, 0xFFFFFFFF);
-       iwl3945_enable_interrupts(priv);
+       iwl_enable_interrupts(priv);
 
        /* really make sure rfkill handshake bits are cleared */
        iwl_write32(priv, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
@@ -3941,7 +3542,7 @@ static void iwl3945_post_associate(struct iwl_priv *priv)
                break;
        }
 
-       iwl3945_activate_qos(priv, 0);
+       iwl_activate_qos(priv, 0);
 
        /* we have just associated, don't start scan too early */
        priv->next_scan_jiffies = jiffies + IWL_DELAY_NEXT_SCAN;
@@ -4172,9 +3773,13 @@ static int iwl3945_mac_config(struct ieee80211_hw *hw, u32 changed)
        }
 #endif
 
-       iwl3945_radio_kill_sw(priv, !conf->radio_enabled);
+       if (conf->radio_enabled && iwl_radio_kill_sw_enable_radio(priv)) {
+               IWL_DEBUG_MAC80211(priv, "leave - RF-KILL - waiting for uCode\n");
+               goto out;
+       }
 
        if (!conf->radio_enabled) {
+               iwl_radio_kill_sw_disable_radio(priv);
                IWL_DEBUG_MAC80211(priv, "leave - radio disabled\n");
                goto out;
        }
@@ -4442,66 +4047,6 @@ static void iwl3945_bss_info_changed(struct ieee80211_hw *hw,
 
 }
 
-static int iwl3945_mac_hw_scan(struct ieee80211_hw *hw,
-                              struct cfg80211_scan_request *req)
-{
-       int rc = 0;
-       unsigned long flags;
-       struct iwl_priv *priv = hw->priv;
-       size_t len = 0;
-       u8 *ssid = NULL;
-       DECLARE_SSID_BUF(ssid_buf);
-
-       IWL_DEBUG_MAC80211(priv, "enter\n");
-
-       if (req->n_ssids) {
-               ssid = req->ssids[0].ssid;
-               len = req->ssids[0].ssid_len;
-       }
-
-       mutex_lock(&priv->mutex);
-       spin_lock_irqsave(&priv->lock, flags);
-
-       if (!iwl_is_ready_rf(priv)) {
-               rc = -EIO;
-               IWL_DEBUG_MAC80211(priv, "leave - not ready or exit pending\n");
-               goto out_unlock;
-       }
-
-       /* we don't schedule scan within next_scan_jiffies period */
-       if (priv->next_scan_jiffies &&
-                       time_after(priv->next_scan_jiffies, jiffies)) {
-               rc = -EAGAIN;
-               goto out_unlock;
-       }
-       /* if we just finished scan ask for delay for a broadcast scan */
-       if ((len == 0) && priv->last_scan_jiffies &&
-           time_after(priv->last_scan_jiffies + IWL_DELAY_NEXT_SCAN,
-                      jiffies)) {
-               rc = -EAGAIN;
-               goto out_unlock;
-       }
-       if (len) {
-               IWL_DEBUG_SCAN(priv, "direct scan for %s [%zd]\n ",
-                              print_ssid(ssid_buf, ssid, len), len);
-
-               priv->one_direct_scan = 1;
-               priv->direct_ssid_len = len;
-               memcpy(priv->direct_ssid, ssid, len);
-       } else
-               priv->one_direct_scan = 0;
-
-       rc = iwl3945_scan_initiate(priv);
-
-       IWL_DEBUG_MAC80211(priv, "leave\n");
-
-out_unlock:
-       spin_unlock_irqrestore(&priv->lock, flags);
-       mutex_unlock(&priv->mutex);
-
-       return rc;
-}
-
 static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                               struct ieee80211_vif *vif,
                               struct ieee80211_sta *sta,
@@ -4509,8 +4054,9 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
 {
        struct iwl_priv *priv = hw->priv;
        const u8 *addr;
-       int ret;
-       u8 sta_id;
+       int ret = 0;
+       u8 sta_id = IWL_INVALID_STATION;
+       u8 static_key;
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
@@ -4520,43 +4066,41 @@ static int iwl3945_mac_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        }
 
        addr = sta ? sta->addr : iwl_bcast_addr;
-       sta_id = iwl3945_hw_find_station(priv, addr);
-       if (sta_id == IWL_INVALID_STATION) {
-               IWL_DEBUG_MAC80211(priv, "leave - %pM not in station map.\n",
-                                  addr);
-               return -EINVAL;
+       static_key = !iwl_is_associated(priv);
+
+       if (!static_key) {
+               sta_id = iwl3945_hw_find_station(priv, addr);
+               if (sta_id == IWL_INVALID_STATION) {
+                       IWL_DEBUG_MAC80211(priv, "leave - %pMnot in station map.\n",
+                                           addr);
+                       return -EINVAL;
+               }
        }
 
        mutex_lock(&priv->mutex);
-
        iwl_scan_cancel_timeout(priv, 100);
+       mutex_unlock(&priv->mutex);
 
        switch (cmd) {
-       case  SET_KEY:
-               ret = iwl3945_update_sta_key_info(priv, key, sta_id);
-               if (!ret) {
-                       iwl_set_rxon_hwcrypto(priv, 1);
-                       iwl3945_commit_rxon(priv);
-                       key->hw_key_idx = sta_id;
-                       IWL_DEBUG_MAC80211(priv,
-                               "set_key success, using hwcrypto\n");
-                       key->flags |= IEEE80211_KEY_FLAG_GENERATE_IV;
-               }
+       case SET_KEY:
+               if (static_key)
+                       ret = iwl3945_set_static_key(priv, key);
+               else
+                       ret = iwl3945_set_dynamic_key(priv, key, sta_id);
+               IWL_DEBUG_MAC80211(priv, "enable hwcrypto key\n");
                break;
        case DISABLE_KEY:
-               ret = iwl3945_clear_sta_key_info(priv, sta_id);
-               if (!ret) {
-                       iwl_set_rxon_hwcrypto(priv, 0);
-                       iwl3945_commit_rxon(priv);
-                       IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n");
-               }
+               if (static_key)
+                       ret = iwl3945_remove_static_key(priv);
+               else
+                       ret = iwl3945_clear_sta_key_info(priv, sta_id);
+               IWL_DEBUG_MAC80211(priv, "disable hwcrypto key\n");
                break;
        default:
                ret = -EINVAL;
        }
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
-       mutex_unlock(&priv->mutex);
 
        return ret;
 }
@@ -4597,9 +4141,9 @@ static int iwl3945_mac_conf_tx(struct ieee80211_hw *hw, u16 queue,
 
        mutex_lock(&priv->mutex);
        if (priv->iw_mode == NL80211_IFTYPE_AP)
-               iwl3945_activate_qos(priv, 1);
+               iwl_activate_qos(priv, 1);
        else if (priv->assoc_id && iwl_is_associated(priv))
-               iwl3945_activate_qos(priv, 0);
+               iwl_activate_qos(priv, 0);
 
        mutex_unlock(&priv->mutex);
 
@@ -4704,6 +4248,7 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
 {
        struct iwl_priv *priv = hw->priv;
        unsigned long flags;
+       __le64 timestamp;
 
        IWL_DEBUG_MAC80211(priv, "enter\n");
 
@@ -4725,6 +4270,8 @@ static int iwl3945_mac_beacon_update(struct ieee80211_hw *hw, struct sk_buff *sk
        priv->ibss_beacon = skb;
 
        priv->assoc_id = 0;
+       timestamp = ((struct ieee80211_mgmt *)skb->data)->u.beacon.timestamp;
+       priv->timestamp = le64_to_cpu(timestamp);
 
        IWL_DEBUG_MAC80211(priv, "leave\n");
        spin_unlock_irqrestore(&priv->lock, flags);
@@ -5201,7 +4748,7 @@ static DEVICE_ATTR(dump_events, S_IWUSR, NULL, dump_event_log);
 
 static void iwl3945_setup_deferred_work(struct iwl_priv *priv)
 {
-       priv->workqueue = create_workqueue(DRV_NAME);
+       priv->workqueue = create_singlethread_workqueue(DRV_NAME);
 
        init_waitqueue_head(&priv->wait_command_queue);
 
@@ -5275,7 +4822,7 @@ static struct ieee80211_ops iwl3945_hw_ops = {
        .conf_tx = iwl3945_mac_conf_tx,
        .reset_tsf = iwl3945_mac_reset_tsf,
        .bss_info_changed = iwl3945_bss_info_changed,
-       .hw_scan = iwl3945_mac_hw_scan
+       .hw_scan = iwl_mac_hw_scan
 };
 
 static int iwl3945_init_drv(struct iwl_priv *priv)
@@ -5340,19 +4887,53 @@ static int iwl3945_init_drv(struct iwl_priv *priv)
        }
        iwl3945_init_hw_rates(priv, priv->ieee_rates);
 
+       return 0;
+
+err_free_channel_map:
+       iwl_free_channel_map(priv);
+err:
+       return ret;
+}
+
+static int iwl3945_setup_mac(struct iwl_priv *priv)
+{
+       int ret;
+       struct ieee80211_hw *hw = priv->hw;
+
+       hw->rate_control_algorithm = "iwl-3945-rs";
+       hw->sta_data_size = sizeof(struct iwl3945_sta_priv);
+
+       /* Tell mac80211 our characteristics */
+       hw->flags = IEEE80211_HW_SIGNAL_DBM |
+                   IEEE80211_HW_NOISE_DBM;
+
+       hw->wiphy->interface_modes =
+               BIT(NL80211_IFTYPE_STATION) |
+               BIT(NL80211_IFTYPE_ADHOC);
+
+       hw->wiphy->custom_regulatory = true;
+
+       /* Default value; 4 EDCA QOS priorities */
+       hw->queues = 4;
+
+       hw->conf.beacon_int = 100;
+
        if (priv->bands[IEEE80211_BAND_2GHZ].n_channels)
                priv->hw->wiphy->bands[IEEE80211_BAND_2GHZ] =
                        &priv->bands[IEEE80211_BAND_2GHZ];
+
        if (priv->bands[IEEE80211_BAND_5GHZ].n_channels)
                priv->hw->wiphy->bands[IEEE80211_BAND_5GHZ] =
                        &priv->bands[IEEE80211_BAND_5GHZ];
 
-       return 0;
+       ret = ieee80211_register_hw(priv->hw);
+       if (ret) {
+               IWL_ERR(priv, "Failed to register hw (error %d)\n", ret);
+               return ret;
+       }
+       priv->mac80211_registered = 1;
 
-err_free_channel_map:
-       iwl_free_channel_map(priv);
-err:
-       return ret;
+       return 0;
 }
 
 static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
@@ -5385,7 +4966,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
                        "invalid queues_num, should be between %d and %d\n",
                        IWL_MIN_NUM_QUEUES, IWL39_MAX_NUM_QUEUES);
                err = -EINVAL;
-               goto out;
+               goto out_ieee80211_free_hw;
        }
 
        /*
@@ -5406,23 +4987,6 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        priv->debug_level = iwl3945_mod_params.debug;
        atomic_set(&priv->restrict_refcnt, 0);
 #endif
-       hw->rate_control_algorithm = "iwl-3945-rs";
-       hw->sta_data_size = sizeof(struct iwl3945_sta_priv);
-
-       /* Tell mac80211 our characteristics */
-       hw->flags = IEEE80211_HW_SIGNAL_DBM |
-                   IEEE80211_HW_NOISE_DBM;
-
-       hw->wiphy->interface_modes =
-               BIT(NL80211_IFTYPE_STATION) |
-               BIT(NL80211_IFTYPE_ADHOC);
-
-       hw->wiphy->custom_regulatory = true;
-
-       hw->wiphy->max_scan_ssids = 1;
-
-       /* 4 EDCA QOS priorities */
-       hw->queues = 4;
 
        /***************************
         * 2. Initializing PCI bus
@@ -5467,7 +5031,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        /* amp init */
        err = priv->cfg->ops->lib->apm_ops.init(priv);
        if (err < 0) {
-               IWL_DEBUG_INFO(priv, "Failed to init APMG\n");
+               IWL_DEBUG_INFO(priv, "Failed to init the card\n");
                goto out_iounmap;
        }
 
@@ -5479,7 +5043,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        err = iwl_eeprom_init(priv);
        if (err) {
                IWL_ERR(priv, "Unable to init EEPROM\n");
-               goto out_remove_sysfs;
+               goto out_iounmap;
        }
        /* MAC Address location in EEPROM same for 3945/4965 */
        eeprom = (struct iwl3945_eeprom *)priv->eeprom;
@@ -5493,7 +5057,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        /* Device-specific setup */
        if (iwl3945_hw_set_hw_params(priv)) {
                IWL_ERR(priv, "failed to set hw settings\n");
-               goto out_iounmap;
+               goto out_eeprom_free;
        }
 
        /***********************
@@ -5503,7 +5067,7 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        err = iwl3945_init_drv(priv);
        if (err) {
                IWL_ERR(priv, "initializing driver failed\n");
-               goto out_free_geos;
+               goto out_unset_hw_params;
        }
 
        IWL_INFO(priv, "Detected Intel Wireless WiFi Link %s\n",
@@ -5526,12 +5090,12 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
         * ********************/
 
        spin_lock_irqsave(&priv->lock, flags);
-       iwl3945_disable_interrupts(priv);
+       iwl_disable_interrupts(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
 
        pci_enable_msi(priv->pci_dev);
 
-       err = request_irq(priv->pci_dev->irq, iwl3945_isr, IRQF_SHARED,
+       err = request_irq(priv->pci_dev->irq, iwl_isr, IRQF_SHARED,
                          DRV_NAME, priv);
        if (err) {
                IWL_ERR(priv, "Error allocating IRQ %d\n", priv->pci_dev->irq);
@@ -5553,19 +5117,18 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
         * 9. Setup and Register mac80211
         * *******************************/
 
-       err = ieee80211_register_hw(priv->hw);
-       if (err) {
-               IWL_ERR(priv, "Failed to register network device: %d\n", err);
-               goto  out_remove_sysfs;
-       }
+       iwl_enable_interrupts(priv);
 
-       priv->hw->conf.beacon_int = 100;
-       priv->mac80211_registered = 1;
+       err = iwl3945_setup_mac(priv);
+       if (err)
+               goto  out_remove_sysfs;
 
        err = iwl_rfkill_init(priv);
        if (err)
                IWL_ERR(priv, "Unable to initialize RFKILL system. "
                                  "Ignoring error: %d\n", err);
+       else
+               iwl_rfkill_set_hw_state(priv);
 
        /* Start monitoring the killswitch */
        queue_delayed_work(priv->workqueue, &priv->rfkill_poll,
@@ -5574,24 +5137,26 @@ static int iwl3945_pci_probe(struct pci_dev *pdev, const struct pci_device_id *e
        return 0;
 
  out_remove_sysfs:
+       destroy_workqueue(priv->workqueue);
+       priv->workqueue = NULL;
        sysfs_remove_group(&pdev->dev.kobj, &iwl3945_attribute_group);
- out_free_geos:
-       iwlcore_free_geos(priv);
-
  out_release_irq:
        free_irq(priv->pci_dev->irq, priv);
-       destroy_workqueue(priv->workqueue);
-       priv->workqueue = NULL;
-       iwl3945_unset_hw_params(priv);
  out_disable_msi:
        pci_disable_msi(priv->pci_dev);
+       iwlcore_free_geos(priv);
+       iwl_free_channel_map(priv);
+ out_unset_hw_params:
+       iwl3945_unset_hw_params(priv);
+ out_eeprom_free:
+       iwl_eeprom_free(priv);
  out_iounmap:
        pci_iounmap(pdev, priv->hw_base);
  out_pci_release_regions:
        pci_release_regions(pdev);
  out_pci_disable_device:
-       pci_disable_device(pdev);
        pci_set_drvdata(pdev, NULL);
+       pci_disable_device(pdev);
  out_ieee80211_free_hw:
        ieee80211_free_hw(priv->hw);
  out:
@@ -5621,7 +5186,7 @@ static void __devexit iwl3945_pci_remove(struct pci_dev *pdev)
         * tasklet for the driver
         */
        spin_lock_irqsave(&priv->lock, flags);
-       iwl3945_disable_interrupts(priv);
+       iwl_disable_interrupts(priv);
        spin_unlock_irqrestore(&priv->lock, flags);
 
        iwl_synchronize_irq(priv);
index 6388b05df4fcdd9f7da04bc5aaaaf79b4852178c..e8dfde39abfc1ccedf841bfb6b5783c730e229f2 100644 (file)
@@ -265,6 +265,7 @@ static inline void lbs_deb_hex(unsigned int grp, const char *prompt, u8 *buf, in
 
 #define        CMD_F_HOSTCMD           (1 << 0)
 #define FW_CAPINFO_WPA         (1 << 0)
+#define FW_CAPINFO_PS                  (1 << 1)
 #define FW_CAPINFO_FIRMWARE_UPGRADE    (1 << 13)
 #define FW_CAPINFO_BOOT2_UPGRADE       (1<<14)
 #define FW_CAPINFO_PERSISTENT_CONFIG   (1<<15)
index dd682c4cfde816929425b3f68417de552e62b0b6..27e81fd97c949c66ad93cb59784be75e7a6342ef 100644 (file)
@@ -109,7 +109,6 @@ struct lbs_private {
        void *card;
        struct net_device *dev;
 
-       struct net_device_stats stats;
        struct net_device *mesh_dev; /* Virtual device */
        struct net_device *rtap_net_dev;
 
index 61d2f50470c8e82f76e031cc82011846689f4723..b118a35ec605dd36dafbb27968dacefec444a62d 100644 (file)
@@ -23,7 +23,7 @@ static const char * mesh_stat_strings[]= {
 static void lbs_ethtool_get_drvinfo(struct net_device *dev,
                                         struct ethtool_drvinfo *info)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        snprintf(info->fw_version, 32, "%u.%u.%u.p%u",
                priv->fwrelease >> 24 & 0xff,
@@ -47,7 +47,7 @@ static int lbs_ethtool_get_eeprom_len(struct net_device *dev)
 static int lbs_ethtool_get_eeprom(struct net_device *dev,
                                   struct ethtool_eeprom *eeprom, u8 * bytes)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        struct cmd_ds_802_11_eeprom_access cmd;
        int ret;
 
@@ -76,7 +76,7 @@ out:
 static void lbs_ethtool_get_stats(struct net_device *dev,
                                  struct ethtool_stats *stats, uint64_t *data)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        struct cmd_ds_mesh_access mesh_access;
        int ret;
 
@@ -113,7 +113,7 @@ static void lbs_ethtool_get_stats(struct net_device *dev,
 
 static int lbs_ethtool_get_sset_count(struct net_device *dev, int sset)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        if (sset == ETH_SS_STATS && dev == priv->mesh_dev)
                return MESH_STATS_NUM;
@@ -143,7 +143,7 @@ static void lbs_ethtool_get_strings(struct net_device *dev,
 static void lbs_ethtool_get_wol(struct net_device *dev,
                                struct ethtool_wolinfo *wol)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        if (priv->wol_criteria == 0xffffffff) {
                /* Interface driver didn't configure wake */
@@ -166,7 +166,7 @@ static void lbs_ethtool_get_wol(struct net_device *dev,
 static int lbs_ethtool_set_wol(struct net_device *dev,
                               struct ethtool_wolinfo *wol)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        uint32_t criteria = 0;
 
        if (priv->wol_criteria == 0xffffffff && wol->wolopts)
index 8f8934a5ba3a9954b255437e0244f2135168abaf..cedeac6322feb8063ebc921e5bd1407a93287f36 100644 (file)
@@ -421,7 +421,7 @@ static struct sk_buff *if_cs_receive_data(struct lbs_private *priv)
        len = if_cs_read16(priv->card, IF_CS_READ_LEN);
        if (len == 0 || len > MRVDRV_ETH_RX_PACKET_BUFFER_SIZE) {
                lbs_pr_err("card data buffer has invalid # of bytes (%d)\n", len);
-               priv->stats.rx_dropped++;
+               priv->dev->stats.rx_dropped++;
                goto dat_err;
        }
 
index 4519d7314f47c37677df87ca51fc4b53bfeac2fe..76f4c653d6419782caf65902ffed19b3a5153f03 100644 (file)
@@ -95,6 +95,8 @@ struct if_sdio_card {
 
        spinlock_t              lock;
        struct if_sdio_packet   *packets;
+
+       struct workqueue_struct *workqueue;
        struct work_struct      packet_worker;
 };
 
@@ -209,6 +211,9 @@ static int if_sdio_handle_event(struct if_sdio_card *card,
                event = sdio_readb(card->func, IF_SDIO_EVENT, &ret);
                if (ret)
                        goto out;
+
+               /* right shift 3 bits to get the event id */
+               event >>= 3;
        } else {
                if (size < 4) {
                        lbs_deb_sdio("event packet too small (%d bytes)\n",
@@ -743,7 +748,7 @@ static int if_sdio_host_to_card(struct lbs_private *priv,
 
        spin_unlock_irqrestore(&card->lock, flags);
 
-       schedule_work(&card->packet_worker);
+       queue_work(card->workqueue, &card->packet_worker);
 
        ret = 0;
 
@@ -833,6 +838,7 @@ static int if_sdio_probe(struct sdio_func *func,
        card->func = func;
        card->model = model;
        spin_lock_init(&card->lock);
+       card->workqueue = create_workqueue("libertas_sdio");
        INIT_WORK(&card->packet_worker, if_sdio_host_to_card_worker);
 
        for (i = 0;i < ARRAY_SIZE(if_sdio_models);i++) {
@@ -921,15 +927,17 @@ static int if_sdio_probe(struct sdio_func *func,
        if (ret)
                goto err_activate_card;
 
+       if (priv->fwcapinfo & FW_CAPINFO_PS)
+               priv->ps_supported = 1;
+
 out:
        lbs_deb_leave_args(LBS_DEB_SDIO, "ret %d", ret);
 
        return ret;
 
 err_activate_card:
-       flush_scheduled_work();
-       free_netdev(priv->dev);
-       kfree(priv);
+       flush_workqueue(card->workqueue);
+       lbs_remove_card(priv);
 reclaim:
        sdio_claim_host(func);
 release_int:
@@ -939,6 +947,7 @@ disable:
 release:
        sdio_release_host(func);
 free:
+       destroy_workqueue(card->workqueue);
        while (card->packets) {
                packet = card->packets;
                card->packets = card->packets->next;
@@ -965,7 +974,8 @@ static void if_sdio_remove(struct sdio_func *func)
        lbs_stop_card(card->priv);
        lbs_remove_card(card->priv);
 
-       flush_scheduled_work();
+       flush_workqueue(card->workqueue);
+       destroy_workqueue(card->workqueue);
 
        sdio_claim_host(func);
        sdio_release_irq(func);
index 2fc637ad85c741b84b94ba1a7f230f30077a4b8a..ea3dc038be76e3c88d89abb9e75328b993501b77 100644 (file)
@@ -59,7 +59,7 @@ static int if_usb_reset_device(struct if_usb_card *cardp);
 static ssize_t if_usb_firmware_set(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        struct if_usb_card *cardp = priv->card;
        char fwname[FIRMWARE_NAME_MAX];
        int ret;
@@ -86,7 +86,7 @@ static DEVICE_ATTR(lbs_flash_fw, 0200, NULL, if_usb_firmware_set);
 static ssize_t if_usb_boot2_set(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        struct if_usb_card *cardp = priv->card;
        char fwname[FIRMWARE_NAME_MAX];
        int ret;
index 8a7eb2778eb680c5f17d5c5ed5b9840745b3825c..8ae935ac32f177ea990c67cb547eb231afa3aeb6 100644 (file)
@@ -222,7 +222,7 @@ u8 lbs_data_rate_to_fw_index(u32 rate)
 static ssize_t lbs_anycast_get(struct device *dev,
                struct device_attribute *attr, char * buf)
 {
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        struct cmd_ds_mesh_access mesh_access;
        int ret;
 
@@ -241,7 +241,7 @@ static ssize_t lbs_anycast_get(struct device *dev,
 static ssize_t lbs_anycast_set(struct device *dev,
                struct device_attribute *attr, const char * buf, size_t count)
 {
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        struct cmd_ds_mesh_access mesh_access;
        uint32_t datum;
        int ret;
@@ -263,7 +263,7 @@ static ssize_t lbs_anycast_set(struct device *dev,
 static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
                struct device_attribute *attr, char *buf)
 {
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        struct cmd_ds_mesh_access mesh_access;
        int ret;
        u32 retry_limit;
@@ -286,7 +286,7 @@ static ssize_t lbs_prb_rsp_limit_get(struct device *dev,
 static ssize_t lbs_prb_rsp_limit_set(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        struct cmd_ds_mesh_access mesh_access;
        int ret;
        unsigned long retry_limit;
@@ -321,7 +321,7 @@ static void lbs_remove_mesh(struct lbs_private *priv);
 static ssize_t lbs_rtap_get(struct device *dev,
                struct device_attribute *attr, char * buf)
 {
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        return snprintf(buf, 5, "0x%X\n", priv->monitormode);
 }
 
@@ -332,7 +332,7 @@ static ssize_t lbs_rtap_set(struct device *dev,
                struct device_attribute *attr, const char * buf, size_t count)
 {
        int monitor_mode;
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
 
        sscanf(buf, "%x", &monitor_mode);
        if (monitor_mode) {
@@ -383,7 +383,7 @@ static DEVICE_ATTR(lbs_rtap, 0644, lbs_rtap_get, lbs_rtap_set );
 static ssize_t lbs_mesh_get(struct device *dev,
                struct device_attribute *attr, char * buf)
 {
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        return snprintf(buf, 5, "0x%X\n", !!priv->mesh_dev);
 }
 
@@ -393,7 +393,7 @@ static ssize_t lbs_mesh_get(struct device *dev,
 static ssize_t lbs_mesh_set(struct device *dev,
                struct device_attribute *attr, const char * buf, size_t count)
 {
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        int enable;
        int ret, action = CMD_ACT_MESH_CONFIG_STOP;
 
@@ -452,7 +452,7 @@ static struct attribute_group lbs_mesh_attr_group = {
  */
 static int lbs_dev_open(struct net_device *dev)
 {
-       struct lbs_private *priv = netdev_priv(dev) ;
+       struct lbs_private *priv = dev->ml_priv;
        int ret = 0;
 
        lbs_deb_enter(LBS_DEB_NET);
@@ -521,7 +521,7 @@ static int lbs_mesh_stop(struct net_device *dev)
  */
 static int lbs_eth_stop(struct net_device *dev)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        lbs_deb_enter(LBS_DEB_NET);
 
@@ -538,7 +538,7 @@ static int lbs_eth_stop(struct net_device *dev)
 
 static void lbs_tx_timeout(struct net_device *dev)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        lbs_deb_enter(LBS_DEB_TX);
 
@@ -582,24 +582,10 @@ void lbs_host_to_card_done(struct lbs_private *priv)
 }
 EXPORT_SYMBOL_GPL(lbs_host_to_card_done);
 
-/**
- *  @brief This function returns the network statistics
- *
- *  @param dev     A pointer to struct lbs_private structure
- *  @return       A pointer to net_device_stats structure
- */
-static struct net_device_stats *lbs_get_stats(struct net_device *dev)
-{
-       struct lbs_private *priv = netdev_priv(dev);
-
-       lbs_deb_enter(LBS_DEB_NET);
-       return &priv->stats;
-}
-
 static int lbs_set_mac_address(struct net_device *dev, void *addr)
 {
        int ret = 0;
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        struct sockaddr *phwaddr = addr;
        struct cmd_ds_802_11_mac_address cmd;
 
@@ -732,7 +718,7 @@ static void lbs_set_mcast_worker(struct work_struct *work)
 
 static void lbs_set_multicast_list(struct net_device *dev)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        schedule_work(&priv->mcast_work);
 }
@@ -748,7 +734,7 @@ static void lbs_set_multicast_list(struct net_device *dev)
 static int lbs_thread(void *data)
 {
        struct net_device *dev = data;
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        wait_queue_t wait;
 
        lbs_deb_enter(LBS_DEB_THREAD);
@@ -1162,6 +1148,17 @@ static void lbs_free_adapter(struct lbs_private *priv)
        lbs_deb_leave(LBS_DEB_MAIN);
 }
 
+static const struct net_device_ops lbs_netdev_ops = {
+       .ndo_open               = lbs_dev_open,
+       .ndo_stop               = lbs_eth_stop,
+       .ndo_start_xmit         = lbs_hard_start_xmit,
+       .ndo_set_mac_address    = lbs_set_mac_address,
+       .ndo_tx_timeout         = lbs_tx_timeout,
+       .ndo_set_multicast_list = lbs_set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 /**
  * @brief This function adds the card. it will probe the
  * card, allocate the lbs_priv and initialize the device.
@@ -1183,6 +1180,7 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
                goto done;
        }
        priv = netdev_priv(dev);
+       dev->ml_priv = priv;
 
        if (lbs_init_adapter(priv)) {
                lbs_pr_err("failed to initialize adapter structure.\n");
@@ -1195,19 +1193,13 @@ struct lbs_private *lbs_add_card(void *card, struct device *dmdev)
        priv->infra_open = 0;
 
        /* Setup the OS Interface to our functions */
-       dev->open = lbs_dev_open;
-       dev->hard_start_xmit = lbs_hard_start_xmit;
-       dev->stop = lbs_eth_stop;
-       dev->set_mac_address = lbs_set_mac_address;
-       dev->tx_timeout = lbs_tx_timeout;
-       dev->get_stats = lbs_get_stats;
+       dev->netdev_ops = &lbs_netdev_ops;
        dev->watchdog_timeo = 5 * HZ;
        dev->ethtool_ops = &lbs_ethtool_ops;
 #ifdef WIRELESS_EXT
-       dev->wireless_handlers = (struct iw_handler_def *)&lbs_handler_def;
+       dev->wireless_handlers = &lbs_handler_def;
 #endif
        dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
-       dev->set_multicast_list = lbs_set_multicast_list;
 
        SET_NETDEV_DEV(dev, dmdev);
 
@@ -1417,6 +1409,14 @@ out:
 EXPORT_SYMBOL_GPL(lbs_stop_card);
 
 
+static const struct net_device_ops mesh_netdev_ops = {
+       .ndo_open               = lbs_dev_open,
+       .ndo_stop               = lbs_mesh_stop,
+       .ndo_start_xmit         = lbs_hard_start_xmit,
+       .ndo_set_mac_address    = lbs_set_mac_address,
+       .ndo_set_multicast_list = lbs_set_multicast_list,
+};
+
 /**
  * @brief This function adds mshX interface
  *
@@ -1439,11 +1439,7 @@ static int lbs_add_mesh(struct lbs_private *priv)
        mesh_dev->ml_priv = priv;
        priv->mesh_dev = mesh_dev;
 
-       mesh_dev->open = lbs_dev_open;
-       mesh_dev->hard_start_xmit = lbs_hard_start_xmit;
-       mesh_dev->stop = lbs_mesh_stop;
-       mesh_dev->get_stats = lbs_get_stats;
-       mesh_dev->set_mac_address = lbs_set_mac_address;
+       mesh_dev->netdev_ops = &mesh_netdev_ops;
        mesh_dev->ethtool_ops = &lbs_ethtool_ops;
        memcpy(mesh_dev->dev_addr, priv->dev->dev_addr,
                        sizeof(priv->dev->dev_addr));
@@ -1454,7 +1450,6 @@ static int lbs_add_mesh(struct lbs_private *priv)
        mesh_dev->wireless_handlers = (struct iw_handler_def *)&mesh_handler_def;
 #endif
        mesh_dev->flags |= IFF_BROADCAST | IFF_MULTICAST;
-       mesh_dev->set_multicast_list = lbs_set_multicast_list;
        /* Register virtual mesh interface */
        ret = register_netdev(mesh_dev);
        if (ret) {
@@ -1647,14 +1642,6 @@ static int lbs_rtap_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        return NETDEV_TX_BUSY;
 }
 
-static struct net_device_stats *lbs_rtap_get_stats(struct net_device *dev)
-{
-       struct lbs_private *priv = dev->ml_priv;
-       lbs_deb_enter(LBS_DEB_NET);
-       return &priv->stats;
-}
-
-
 static void lbs_remove_rtap(struct lbs_private *priv)
 {
        lbs_deb_enter(LBS_DEB_MAIN);
@@ -1667,6 +1654,12 @@ out:
        lbs_deb_leave(LBS_DEB_MAIN);
 }
 
+static const struct net_device_ops rtap_netdev_ops = {
+       .ndo_open = lbs_rtap_open,
+       .ndo_stop = lbs_rtap_stop,
+       .ndo_start_xmit = lbs_rtap_hard_start_xmit,
+};
+
 static int lbs_add_rtap(struct lbs_private *priv)
 {
        int ret = 0;
@@ -1686,10 +1679,7 @@ static int lbs_add_rtap(struct lbs_private *priv)
 
        memcpy(rtap_dev->dev_addr, priv->current_addr, ETH_ALEN);
        rtap_dev->type = ARPHRD_IEEE80211_RADIOTAP;
-       rtap_dev->open = lbs_rtap_open;
-       rtap_dev->stop = lbs_rtap_stop;
-       rtap_dev->get_stats = lbs_rtap_get_stats;
-       rtap_dev->hard_start_xmit = lbs_rtap_hard_start_xmit;
+       rtap_dev->netdev_ops = &rtap_netdev_ops;
        rtap_dev->ml_priv = priv;
        SET_NETDEV_DEV(rtap_dev, priv->dev->dev.parent);
 
index d42b7a5a1b3f32a564579771e19149429348db5b..18fe29faf99b1cb1362a81c5f65fe0e1c47cc46c 100644 (file)
@@ -18,7 +18,7 @@
 static int mesh_get_default_parameters(struct device *dev,
                                       struct mrvl_mesh_defaults *defs)
 {
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        struct cmd_ds_mesh_config cmd;
        int ret;
 
@@ -57,7 +57,7 @@ static ssize_t bootflag_get(struct device *dev,
 static ssize_t bootflag_set(struct device *dev, struct device_attribute *attr,
                            const char *buf, size_t count)
 {
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        struct cmd_ds_mesh_config cmd;
        uint32_t datum;
        int ret;
@@ -100,7 +100,7 @@ static ssize_t boottime_get(struct device *dev,
 static ssize_t boottime_set(struct device *dev,
                struct device_attribute *attr, const char *buf, size_t count)
 {
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        struct cmd_ds_mesh_config cmd;
        uint32_t datum;
        int ret;
@@ -152,7 +152,7 @@ static ssize_t channel_get(struct device *dev,
 static ssize_t channel_set(struct device *dev, struct device_attribute *attr,
                           const char *buf, size_t count)
 {
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        struct cmd_ds_mesh_config cmd;
        uint32_t datum;
        int ret;
@@ -210,7 +210,7 @@ static ssize_t mesh_id_set(struct device *dev, struct device_attribute *attr,
        struct cmd_ds_mesh_config cmd;
        struct mrvl_mesh_defaults defs;
        struct mrvl_meshie *ie;
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        int len;
        int ret;
 
@@ -269,7 +269,7 @@ static ssize_t protocol_id_set(struct device *dev,
        struct cmd_ds_mesh_config cmd;
        struct mrvl_mesh_defaults defs;
        struct mrvl_meshie *ie;
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        uint32_t datum;
        int ret;
 
@@ -323,7 +323,7 @@ static ssize_t metric_id_set(struct device *dev, struct device_attribute *attr,
        struct cmd_ds_mesh_config cmd;
        struct mrvl_mesh_defaults defs;
        struct mrvl_meshie *ie;
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        uint32_t datum;
        int ret;
 
@@ -377,7 +377,7 @@ static ssize_t capability_set(struct device *dev, struct device_attribute *attr,
        struct cmd_ds_mesh_config cmd;
        struct mrvl_mesh_defaults defs;
        struct mrvl_meshie *ie;
-       struct lbs_private *priv = netdev_priv(to_net_dev(dev));
+       struct lbs_private *priv = to_net_dev(dev)->ml_priv;
        uint32_t datum;
        int ret;
 
index 079e6aa874dcc13a4a8b3011c7b44d423438e4fa..4f60948dde9c65d5051ea86b70aefb0da024b7e5 100644 (file)
@@ -168,7 +168,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
 
        if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
                lbs_deb_rx("rx err: frame received with bad length\n");
-               priv->stats.rx_length_errors++;
+               dev->stats.rx_length_errors++;
                ret = 0;
                goto done;
        }
@@ -179,7 +179,7 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
        if (!(p_rx_pd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) {
                lbs_deb_rx("rx err: frame received with bad status\n");
                lbs_pr_alert("rxpd not ok\n");
-               priv->stats.rx_errors++;
+               dev->stats.rx_errors++;
                ret = 0;
                goto done;
        }
@@ -243,8 +243,8 @@ int lbs_process_rxed_packet(struct lbs_private *priv, struct sk_buff *skb)
        lbs_compute_rssi(priv, p_rx_pd);
 
        lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
-       priv->stats.rx_bytes += skb->len;
-       priv->stats.rx_packets++;
+       dev->stats.rx_bytes += skb->len;
+       dev->stats.rx_packets++;
 
        skb->protocol = eth_type_trans(skb, dev);
        if (in_interrupt())
@@ -311,7 +311,7 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
        struct sk_buff *skb)
 {
        int ret = 0;
-
+       struct net_device *dev = priv->dev;
        struct rx80211packethdr *p_rx_pkt;
        struct rxpd *prxpd;
        struct rx_radiotap_hdr radiotap_hdr;
@@ -326,7 +326,7 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
 
        if (skb->len < (ETH_HLEN + 8 + sizeof(struct rxpd))) {
                lbs_deb_rx("rx err: frame received with bad length\n");
-               priv->stats.rx_length_errors++;
+               dev->stats.rx_length_errors++;
                ret = -EINVAL;
                kfree_skb(skb);
                goto done;
@@ -337,7 +337,7 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
         */
        if (!(prxpd->status & cpu_to_le16(MRVDRV_RXPD_STATUS_OK))) {
                //lbs_deb_rx("rx err: frame received with bad status\n");
-               priv->stats.rx_errors++;
+               dev->stats.rx_errors++;
        }
 
        lbs_deb_rx("rx data: skb->len-sizeof(RxPd) = %d-%zd = %zd\n",
@@ -389,8 +389,8 @@ static int process_rxed_802_11_packet(struct lbs_private *priv,
        lbs_compute_rssi(priv, prxpd);
 
        lbs_deb_rx("rx data: size of actual packet %d\n", skb->len);
-       priv->stats.rx_bytes += skb->len;
-       priv->stats.rx_packets++;
+       dev->stats.rx_bytes += skb->len;
+       dev->stats.rx_packets++;
 
        skb->protocol = eth_type_trans(skb, priv->rtap_net_dev);
        netif_rx(skb);
index 00a57ed78afcf3685ce937413b261b376b3c4db8..8124db36aaff4445ddfd6e1564897b56efb95455 100644 (file)
@@ -945,7 +945,7 @@ int lbs_set_scan(struct net_device *dev, struct iw_request_info *info,
                 union iwreq_data *wrqu, char *extra)
 {
        DECLARE_SSID_BUF(ssid);
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        int ret = 0;
 
        lbs_deb_enter(LBS_DEB_WEXT);
@@ -1008,7 +1008,7 @@ int lbs_get_scan(struct net_device *dev, struct iw_request_info *info,
                 struct iw_point *dwrq, char *extra)
 {
 #define SCAN_ITEM_SIZE 128
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        int err = 0;
        char *ev = extra;
        char *stop = ev + dwrq->length;
index dac462641170e6193da4f04cfd44e39222520ba3..f10aa39a6b68e6abe650934ccc4957f653869a98 100644 (file)
@@ -60,7 +60,7 @@ static u32 convert_radiotap_rate_to_mv(u8 rate)
 int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
        unsigned long flags;
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        struct txpd *txpd;
        char *p802x_hdr;
        uint16_t pkt_len;
@@ -82,8 +82,8 @@ int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
                       skb->len, MRVDRV_ETH_TX_PACKET_BUFFER_SIZE);
                /* We'll never manage to send this one; drop it and return 'OK' */
 
-               priv->stats.tx_dropped++;
-               priv->stats.tx_errors++;
+               dev->stats.tx_dropped++;
+               dev->stats.tx_errors++;
                goto free;
        }
 
@@ -146,8 +146,8 @@ int lbs_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        lbs_deb_tx("%s lined up packet\n", __func__);
 
-       priv->stats.tx_packets++;
-       priv->stats.tx_bytes += skb->len;
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
 
        dev->trans_start = jiffies;
 
index c6102e08179e6ba7d9fcc09d7fb8a26da721024b..8bc1907458b1f4dd5ac57ff06dbaeaa8faa3cfc8 100644 (file)
@@ -163,7 +163,7 @@ static int lbs_get_name(struct net_device *dev, struct iw_request_info *info,
 static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
                         struct iw_freq *fwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        struct chan_freq_power *cfp;
 
        lbs_deb_enter(LBS_DEB_WEXT);
@@ -189,7 +189,7 @@ static int lbs_get_freq(struct net_device *dev, struct iw_request_info *info,
 static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info,
                        struct sockaddr *awrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -207,7 +207,7 @@ static int lbs_get_wap(struct net_device *dev, struct iw_request_info *info,
 static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info,
                         struct iw_point *dwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -231,7 +231,7 @@ static int lbs_set_nick(struct net_device *dev, struct iw_request_info *info,
 static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info,
                         struct iw_point *dwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -248,7 +248,7 @@ static int lbs_get_nick(struct net_device *dev, struct iw_request_info *info,
 static int mesh_get_nick(struct net_device *dev, struct iw_request_info *info,
                         struct iw_point *dwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -273,7 +273,7 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
                        struct iw_param *vwrq, char *extra)
 {
        int ret = 0;
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        u32 val = vwrq->value;
 
        lbs_deb_enter(LBS_DEB_WEXT);
@@ -293,7 +293,7 @@ static int lbs_set_rts(struct net_device *dev, struct iw_request_info *info,
 static int lbs_get_rts(struct net_device *dev, struct iw_request_info *info,
                        struct iw_param *vwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        int ret = 0;
        u16 val = 0;
 
@@ -315,7 +315,7 @@ out:
 static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
                         struct iw_param *vwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        int ret = 0;
        u32 val = vwrq->value;
 
@@ -336,7 +336,7 @@ static int lbs_set_frag(struct net_device *dev, struct iw_request_info *info,
 static int lbs_get_frag(struct net_device *dev, struct iw_request_info *info,
                         struct iw_param *vwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        int ret = 0;
        u16 val = 0;
 
@@ -359,7 +359,7 @@ out:
 static int lbs_get_mode(struct net_device *dev,
                         struct iw_request_info *info, u32 * uwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -385,7 +385,7 @@ static int lbs_get_txpow(struct net_device *dev,
                          struct iw_request_info *info,
                          struct iw_param *vwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        s16 curlevel = 0;
        int ret = 0;
 
@@ -418,7 +418,7 @@ out:
 static int lbs_set_retry(struct net_device *dev, struct iw_request_info *info,
                          struct iw_param *vwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        int ret = 0;
        u16 slimit = 0, llimit = 0;
 
@@ -466,7 +466,7 @@ out:
 static int lbs_get_retry(struct net_device *dev, struct iw_request_info *info,
                          struct iw_param *vwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        int ret = 0;
        u16 val = 0;
 
@@ -542,7 +542,7 @@ static int lbs_get_range(struct net_device *dev, struct iw_request_info *info,
                          struct iw_point *dwrq, char *extra)
 {
        int i, j;
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        struct iw_range *range = (struct iw_range *)extra;
        struct chan_freq_power *cfp;
        u8 rates[MAX_RATES + 1];
@@ -708,7 +708,7 @@ out:
 static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
                          struct iw_param *vwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -758,7 +758,7 @@ static int lbs_set_power(struct net_device *dev, struct iw_request_info *info,
 static int lbs_get_power(struct net_device *dev, struct iw_request_info *info,
                          struct iw_param *vwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -781,7 +781,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
                EXCELLENT = 95,
                PERFECT = 100
        };
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        u32 rssi_qual;
        u32 tx_qual;
        u32 quality = 0;
@@ -830,7 +830,7 @@ static struct iw_statistics *lbs_get_wireless_stats(struct net_device *dev)
        quality = rssi_qual;
 
        /* Quality by TX errors */
-       priv->wstats.discard.retries = priv->stats.tx_errors;
+       priv->wstats.discard.retries = dev->stats.tx_errors;
 
        memset(&log, 0, sizeof(log));
        log.hdr.size = cpu_to_le16(sizeof(log));
@@ -886,7 +886,7 @@ static int lbs_set_freq(struct net_device *dev, struct iw_request_info *info,
                  struct iw_freq *fwrq, char *extra)
 {
        int ret = -EINVAL;
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        struct chan_freq_power *cfp;
        struct assoc_request * assoc_req;
 
@@ -943,7 +943,7 @@ static int lbs_mesh_set_freq(struct net_device *dev,
                             struct iw_request_info *info,
                             struct iw_freq *fwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        struct chan_freq_power *cfp;
        int ret = -EINVAL;
 
@@ -994,7 +994,7 @@ out:
 static int lbs_set_rate(struct net_device *dev, struct iw_request_info *info,
                  struct iw_param *vwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        u8 new_rate = 0;
        int ret = -EINVAL;
        u8 rates[MAX_RATES + 1];
@@ -1054,7 +1054,7 @@ out:
 static int lbs_get_rate(struct net_device *dev, struct iw_request_info *info,
                  struct iw_param *vwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -1079,7 +1079,7 @@ static int lbs_set_mode(struct net_device *dev,
                  struct iw_request_info *info, u32 * uwrq, char *extra)
 {
        int ret = 0;
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        struct assoc_request * assoc_req;
 
        lbs_deb_enter(LBS_DEB_WEXT);
@@ -1124,7 +1124,7 @@ static int lbs_get_encode(struct net_device *dev,
                           struct iw_request_info *info,
                           struct iw_point *dwrq, u8 * extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        int index = (dwrq->flags & IW_ENCODE_INDEX) - 1;
 
        lbs_deb_enter(LBS_DEB_WEXT);
@@ -1319,7 +1319,7 @@ static int lbs_set_encode(struct net_device *dev,
                    struct iw_point *dwrq, char *extra)
 {
        int ret = 0;
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        struct assoc_request * assoc_req;
        u16 is_default = 0, index = 0, set_tx_key = 0;
 
@@ -1395,7 +1395,7 @@ static int lbs_get_encodeext(struct net_device *dev,
                              char *extra)
 {
        int ret = -EINVAL;
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
        int index, max_key_len;
 
@@ -1501,7 +1501,7 @@ static int lbs_set_encodeext(struct net_device *dev,
                              char *extra)
 {
        int ret = 0;
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        struct iw_encode_ext *ext = (struct iw_encode_ext *)extra;
        int alg = ext->alg;
        struct assoc_request * assoc_req;
@@ -1639,7 +1639,7 @@ static int lbs_set_genie(struct net_device *dev,
                          struct iw_point *dwrq,
                          char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        int ret = 0;
        struct assoc_request * assoc_req;
 
@@ -1685,7 +1685,7 @@ static int lbs_get_genie(struct net_device *dev,
                          char *extra)
 {
        int ret = 0;
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -1713,7 +1713,7 @@ static int lbs_set_auth(struct net_device *dev,
                         struct iw_param *dwrq,
                         char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        struct assoc_request * assoc_req;
        int ret = 0;
        int updated = 0;
@@ -1816,7 +1816,7 @@ static int lbs_get_auth(struct net_device *dev,
                         char *extra)
 {
        int ret = 0;
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -1857,7 +1857,7 @@ static int lbs_set_txpow(struct net_device *dev, struct iw_request_info *info,
                   struct iw_param *vwrq, char *extra)
 {
        int ret = 0;
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        s16 dbm = (s16) vwrq->value;
 
        lbs_deb_enter(LBS_DEB_WEXT);
@@ -1936,7 +1936,7 @@ out:
 static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info,
                   struct iw_point *dwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -1971,7 +1971,7 @@ static int lbs_get_essid(struct net_device *dev, struct iw_request_info *info,
 static int lbs_set_essid(struct net_device *dev, struct iw_request_info *info,
                   struct iw_point *dwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        int ret = 0;
        u8 ssid[IW_ESSID_MAX_SIZE];
        u8 ssid_len = 0;
@@ -2040,7 +2040,7 @@ static int lbs_mesh_get_essid(struct net_device *dev,
                              struct iw_request_info *info,
                              struct iw_point *dwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
 
        lbs_deb_enter(LBS_DEB_WEXT);
 
@@ -2058,7 +2058,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,
                              struct iw_request_info *info,
                              struct iw_point *dwrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        int ret = 0;
 
        lbs_deb_enter(LBS_DEB_WEXT);
@@ -2102,7 +2102,7 @@ static int lbs_mesh_set_essid(struct net_device *dev,
 static int lbs_set_wap(struct net_device *dev, struct iw_request_info *info,
                 struct sockaddr *awrq, char *extra)
 {
-       struct lbs_private *priv = netdev_priv(dev);
+       struct lbs_private *priv = dev->ml_priv;
        struct assoc_request * assoc_req;
        int ret = 0;
 
index fce49ba061d55cb57166b4935ef9de275f7b25cb..2368b7f825a233f26f3b1406474f836bdb74208d 100644 (file)
@@ -10,7 +10,6 @@
 /*
  * TODO:
  * - IBSS mode simulation (Beacon transmission with competition for "air time")
- * - IEEE 802.11a and 802.11n modes
  * - RX filtering based on filter configuration (data->rx_filter)
  */
 
@@ -31,6 +30,112 @@ static int radios = 2;
 module_param(radios, int, 0444);
 MODULE_PARM_DESC(radios, "Number of simulated radios");
 
+/**
+ * enum hwsim_regtest - the type of regulatory tests we offer
+ *
+ * These are the different values you can use for the regtest
+ * module parameter. This is useful to help test world roaming
+ * and the driver regulatory_hint() call and combinations of these.
+ * If you want to do specific alpha2 regulatory domain tests simply
+ * use the userspace regulatory request as that will be respected as
+ * well without the need of this module parameter. This is designed
+ * only for testing the driver regulatory request, world roaming
+ * and all possible combinations.
+ *
+ * @HWSIM_REGTEST_DISABLED: No regulatory tests are performed,
+ *     this is the default value.
+ * @HWSIM_REGTEST_DRIVER_REG_FOLLOW: Used for testing the driver regulatory
+ *     hint, only one driver regulatory hint will be sent as such the
+ *     secondary radios are expected to follow.
+ * @HWSIM_REGTEST_DRIVER_REG_ALL: Used for testing the driver regulatory
+ *     request with all radios reporting the same regulatory domain.
+ * @HWSIM_REGTEST_DIFF_COUNTRY: Used for testing the drivers calling
+ *     different regulatory domains requests. Expected behaviour is for
+ *     an intersection to occur but each device will still use their
+ *     respective regulatory requested domains. Subsequent radios will
+ *     use the resulting intersection.
+ * @HWSIM_REGTEST_WORLD_ROAM: Used for testing the world roaming. We acomplish
+ *     this by using a custom beacon-capable regulatory domain for the first
+ *     radio. All other device world roam.
+ * @HWSIM_REGTEST_CUSTOM_WORLD: Used for testing the custom world regulatory
+ *     domain requests. All radios will adhere to this custom world regulatory
+ *     domain.
+ * @HWSIM_REGTEST_CUSTOM_WORLD_2: Used for testing 2 custom world regulatory
+ *     domain requests. The first radio will adhere to the first custom world
+ *     regulatory domain, the second one to the second custom world regulatory
+ *     domain. All other devices will world roam.
+ * @HWSIM_REGTEST_STRICT_FOLLOW_: Used for testing strict regulatory domain
+ *     settings, only the first radio will send a regulatory domain request
+ *     and use strict settings. The rest of the radios are expected to follow.
+ * @HWSIM_REGTEST_STRICT_ALL: Used for testing strict regulatory domain
+ *     settings. All radios will adhere to this.
+ * @HWSIM_REGTEST_STRICT_AND_DRIVER_REG: Used for testing strict regulatory
+ *     domain settings, combined with secondary driver regulatory domain
+ *     settings. The first radio will get a strict regulatory domain setting
+ *     using the first driver regulatory request and the second radio will use
+ *     non-strict settings using the second driver regulatory request. All
+ *     other devices should follow the intersection created between the
+ *     first two.
+ * @HWSIM_REGTEST_ALL: Used for testing every possible mix. You will need
+ *     at least 6 radios for a complete test. We will test in this order:
+ *     1 - driver custom world regulatory domain
+ *     2 - second custom world regulatory domain
+ *     3 - first driver regulatory domain request
+ *     4 - second driver regulatory domain request
+ *     5 - strict regulatory domain settings using the third driver regulatory
+ *         domain request
+ *     6 and on - should follow the intersection of the 3rd, 4rth and 5th radio
+ *                regulatory requests.
+ */
+enum hwsim_regtest {
+       HWSIM_REGTEST_DISABLED = 0,
+       HWSIM_REGTEST_DRIVER_REG_FOLLOW = 1,
+       HWSIM_REGTEST_DRIVER_REG_ALL = 2,
+       HWSIM_REGTEST_DIFF_COUNTRY = 3,
+       HWSIM_REGTEST_WORLD_ROAM = 4,
+       HWSIM_REGTEST_CUSTOM_WORLD = 5,
+       HWSIM_REGTEST_CUSTOM_WORLD_2 = 6,
+       HWSIM_REGTEST_STRICT_FOLLOW = 7,
+       HWSIM_REGTEST_STRICT_ALL = 8,
+       HWSIM_REGTEST_STRICT_AND_DRIVER_REG = 9,
+       HWSIM_REGTEST_ALL = 10,
+};
+
+/* Set to one of the HWSIM_REGTEST_* values above */
+static int regtest = HWSIM_REGTEST_DISABLED;
+module_param(regtest, int, 0444);
+MODULE_PARM_DESC(regtest, "The type of regulatory test we want to run");
+
+static const char *hwsim_alpha2s[] = {
+       "FI",
+       "AL",
+       "US",
+       "DE",
+       "JP",
+       "AL",
+};
+
+static const struct ieee80211_regdomain hwsim_world_regdom_custom_01 = {
+       .n_reg_rules = 4,
+       .alpha2 =  "99",
+       .reg_rules = {
+               REG_RULE(2412-10, 2462+10, 40, 0, 20, 0),
+               REG_RULE(2484-10, 2484+10, 40, 0, 20, 0),
+               REG_RULE(5150-10, 5240+10, 40, 0, 30, 0),
+               REG_RULE(5745-10, 5825+10, 40, 0, 30, 0),
+       }
+};
+
+static const struct ieee80211_regdomain hwsim_world_regdom_custom_02 = {
+       .n_reg_rules = 2,
+       .alpha2 =  "99",
+       .reg_rules = {
+               REG_RULE(2412-10, 2462+10, 40, 0, 20, 0),
+               REG_RULE(5725-10, 5850+10, 40, 0, 30,
+                       NL80211_RRF_PASSIVE_SCAN | NL80211_RRF_NO_IBSS),
+       }
+};
+
 struct hwsim_vif_priv {
        u32 magic;
        u8 bssid[ETH_ALEN];
@@ -86,22 +191,65 @@ static struct class *hwsim_class;
 
 static struct net_device *hwsim_mon; /* global monitor netdev */
 
+#define CHAN2G(_freq)  { \
+       .band = IEEE80211_BAND_2GHZ, \
+       .center_freq = (_freq), \
+       .hw_value = (_freq), \
+       .max_power = 20, \
+}
+
+#define CHAN5G(_freq) { \
+       .band = IEEE80211_BAND_5GHZ, \
+       .center_freq = (_freq), \
+       .hw_value = (_freq), \
+       .max_power = 20, \
+}
 
-static const struct ieee80211_channel hwsim_channels[] = {
-       { .center_freq = 2412 },
-       { .center_freq = 2417 },
-       { .center_freq = 2422 },
-       { .center_freq = 2427 },
-       { .center_freq = 2432 },
-       { .center_freq = 2437 },
-       { .center_freq = 2442 },
-       { .center_freq = 2447 },
-       { .center_freq = 2452 },
-       { .center_freq = 2457 },
-       { .center_freq = 2462 },
-       { .center_freq = 2467 },
-       { .center_freq = 2472 },
-       { .center_freq = 2484 },
+static const struct ieee80211_channel hwsim_channels_2ghz[] = {
+       CHAN2G(2412), /* Channel 1 */
+       CHAN2G(2417), /* Channel 2 */
+       CHAN2G(2422), /* Channel 3 */
+       CHAN2G(2427), /* Channel 4 */
+       CHAN2G(2432), /* Channel 5 */
+       CHAN2G(2437), /* Channel 6 */
+       CHAN2G(2442), /* Channel 7 */
+       CHAN2G(2447), /* Channel 8 */
+       CHAN2G(2452), /* Channel 9 */
+       CHAN2G(2457), /* Channel 10 */
+       CHAN2G(2462), /* Channel 11 */
+       CHAN2G(2467), /* Channel 12 */
+       CHAN2G(2472), /* Channel 13 */
+       CHAN2G(2484), /* Channel 14 */
+};
+
+static const struct ieee80211_channel hwsim_channels_5ghz[] = {
+       CHAN5G(5180), /* Channel 36 */
+       CHAN5G(5200), /* Channel 40 */
+       CHAN5G(5220), /* Channel 44 */
+       CHAN5G(5240), /* Channel 48 */
+
+       CHAN5G(5260), /* Channel 52 */
+       CHAN5G(5280), /* Channel 56 */
+       CHAN5G(5300), /* Channel 60 */
+       CHAN5G(5320), /* Channel 64 */
+
+       CHAN5G(5500), /* Channel 100 */
+       CHAN5G(5520), /* Channel 104 */
+       CHAN5G(5540), /* Channel 108 */
+       CHAN5G(5560), /* Channel 112 */
+       CHAN5G(5580), /* Channel 116 */
+       CHAN5G(5600), /* Channel 120 */
+       CHAN5G(5620), /* Channel 124 */
+       CHAN5G(5640), /* Channel 128 */
+       CHAN5G(5660), /* Channel 132 */
+       CHAN5G(5680), /* Channel 136 */
+       CHAN5G(5700), /* Channel 140 */
+
+       CHAN5G(5745), /* Channel 149 */
+       CHAN5G(5765), /* Channel 153 */
+       CHAN5G(5785), /* Channel 157 */
+       CHAN5G(5805), /* Channel 161 */
+       CHAN5G(5825), /* Channel 165 */
 };
 
 static const struct ieee80211_rate hwsim_rates[] = {
@@ -126,8 +274,9 @@ struct mac80211_hwsim_data {
        struct list_head list;
        struct ieee80211_hw *hw;
        struct device *dev;
-       struct ieee80211_supported_band band;
-       struct ieee80211_channel channels[ARRAY_SIZE(hwsim_channels)];
+       struct ieee80211_supported_band bands[2];
+       struct ieee80211_channel channels_2ghz[ARRAY_SIZE(hwsim_channels_2ghz)];
+       struct ieee80211_channel channels_5ghz[ARRAY_SIZE(hwsim_channels_5ghz)];
        struct ieee80211_rate rates[ARRAY_SIZE(hwsim_rates)];
 
        struct ieee80211_channel *channel;
@@ -590,10 +739,16 @@ static struct device_driver mac80211_hwsim_driver = {
        .name = "mac80211_hwsim"
 };
 
+static const struct net_device_ops hwsim_netdev_ops = {
+       .ndo_start_xmit         = hwsim_mon_xmit,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
 
 static void hwsim_mon_setup(struct net_device *dev)
 {
-       dev->hard_start_xmit = hwsim_mon_xmit;
+       dev->netdev_ops = &hwsim_netdev_ops;
        dev->destructor = free_netdev;
        ether_setup(dev);
        dev->tx_queue_len = 0;
@@ -728,6 +883,7 @@ static int __init init_mac80211_hwsim(void)
        u8 addr[ETH_ALEN];
        struct mac80211_hwsim_data *data;
        struct ieee80211_hw *hw;
+       enum ieee80211_band band;
 
        if (radios < 1 || radios > 100)
                return -EINVAL;
@@ -785,25 +941,105 @@ static int __init init_mac80211_hwsim(void)
                hw->vif_data_size = sizeof(struct hwsim_vif_priv);
                hw->sta_data_size = sizeof(struct hwsim_sta_priv);
 
-               memcpy(data->channels, hwsim_channels, sizeof(hwsim_channels));
+               memcpy(data->channels_2ghz, hwsim_channels_2ghz,
+                       sizeof(hwsim_channels_2ghz));
+               memcpy(data->channels_5ghz, hwsim_channels_5ghz,
+                       sizeof(hwsim_channels_5ghz));
                memcpy(data->rates, hwsim_rates, sizeof(hwsim_rates));
-               data->band.channels = data->channels;
-               data->band.n_channels = ARRAY_SIZE(hwsim_channels);
-               data->band.bitrates = data->rates;
-               data->band.n_bitrates = ARRAY_SIZE(hwsim_rates);
-               data->band.ht_cap.ht_supported = true;
-               data->band.ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
-                       IEEE80211_HT_CAP_GRN_FLD |
-                       IEEE80211_HT_CAP_SGI_40 |
-                       IEEE80211_HT_CAP_DSSSCCK40;
-               data->band.ht_cap.ampdu_factor = 0x3;
-               data->band.ht_cap.ampdu_density = 0x6;
-               memset(&data->band.ht_cap.mcs, 0,
-                      sizeof(data->band.ht_cap.mcs));
-               data->band.ht_cap.mcs.rx_mask[0] = 0xff;
-               data->band.ht_cap.mcs.rx_mask[1] = 0xff;
-               data->band.ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
-               hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &data->band;
+
+               for (band = IEEE80211_BAND_2GHZ; band < IEEE80211_NUM_BANDS; band++) {
+                       struct ieee80211_supported_band *sband = &data->bands[band];
+                       switch (band) {
+                       case IEEE80211_BAND_2GHZ:
+                               sband->channels = data->channels_2ghz;
+                               sband->n_channels =
+                                       ARRAY_SIZE(hwsim_channels_2ghz);
+                               break;
+                       case IEEE80211_BAND_5GHZ:
+                               sband->channels = data->channels_5ghz;
+                               sband->n_channels =
+                                       ARRAY_SIZE(hwsim_channels_5ghz);
+                               break;
+                       default:
+                               break;
+                       }
+
+                       sband->bitrates = data->rates;
+                       sband->n_bitrates = ARRAY_SIZE(hwsim_rates);
+
+                       sband->ht_cap.ht_supported = true;
+                       sband->ht_cap.cap = IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+                               IEEE80211_HT_CAP_GRN_FLD |
+                               IEEE80211_HT_CAP_SGI_40 |
+                               IEEE80211_HT_CAP_DSSSCCK40;
+                       sband->ht_cap.ampdu_factor = 0x3;
+                       sband->ht_cap.ampdu_density = 0x6;
+                       memset(&sband->ht_cap.mcs, 0,
+                              sizeof(sband->ht_cap.mcs));
+                       sband->ht_cap.mcs.rx_mask[0] = 0xff;
+                       sband->ht_cap.mcs.rx_mask[1] = 0xff;
+                       sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
+
+                       hw->wiphy->bands[band] = sband;
+               }
+
+               /* Work to be done prior to ieee80211_register_hw() */
+               switch (regtest) {
+               case HWSIM_REGTEST_DISABLED:
+               case HWSIM_REGTEST_DRIVER_REG_FOLLOW:
+               case HWSIM_REGTEST_DRIVER_REG_ALL:
+               case HWSIM_REGTEST_DIFF_COUNTRY:
+                       /*
+                        * Nothing to be done for driver regulatory domain
+                        * hints prior to ieee80211_register_hw()
+                        */
+                       break;
+               case HWSIM_REGTEST_WORLD_ROAM:
+                       if (i == 0) {
+                               hw->wiphy->custom_regulatory = true;
+                               wiphy_apply_custom_regulatory(hw->wiphy,
+                                       &hwsim_world_regdom_custom_01);
+                       }
+                       break;
+               case HWSIM_REGTEST_CUSTOM_WORLD:
+                       hw->wiphy->custom_regulatory = true;
+                       wiphy_apply_custom_regulatory(hw->wiphy,
+                               &hwsim_world_regdom_custom_01);
+                       break;
+               case HWSIM_REGTEST_CUSTOM_WORLD_2:
+                       if (i == 0) {
+                               hw->wiphy->custom_regulatory = true;
+                               wiphy_apply_custom_regulatory(hw->wiphy,
+                                       &hwsim_world_regdom_custom_01);
+                       } else if (i == 1) {
+                               hw->wiphy->custom_regulatory = true;
+                               wiphy_apply_custom_regulatory(hw->wiphy,
+                                       &hwsim_world_regdom_custom_02);
+                       }
+                       break;
+               case HWSIM_REGTEST_STRICT_ALL:
+                       hw->wiphy->strict_regulatory = true;
+                       break;
+               case HWSIM_REGTEST_STRICT_FOLLOW:
+               case HWSIM_REGTEST_STRICT_AND_DRIVER_REG:
+                       if (i == 0)
+                               hw->wiphy->strict_regulatory = true;
+                       break;
+               case HWSIM_REGTEST_ALL:
+                       if (i == 0) {
+                               hw->wiphy->custom_regulatory = true;
+                               wiphy_apply_custom_regulatory(hw->wiphy,
+                                       &hwsim_world_regdom_custom_01);
+                       } else if (i == 1) {
+                               hw->wiphy->custom_regulatory = true;
+                               wiphy_apply_custom_regulatory(hw->wiphy,
+                                       &hwsim_world_regdom_custom_02);
+                       } else if (i == 4)
+                               hw->wiphy->strict_regulatory = true;
+                       break;
+               default:
+                       break;
+               }
 
                err = ieee80211_register_hw(hw);
                if (err < 0) {
@@ -812,6 +1048,52 @@ static int __init init_mac80211_hwsim(void)
                        goto failed_hw;
                }
 
+               /* Work to be done after to ieee80211_register_hw() */
+               switch (regtest) {
+               case HWSIM_REGTEST_WORLD_ROAM:
+               case HWSIM_REGTEST_DISABLED:
+                       break;
+               case HWSIM_REGTEST_DRIVER_REG_FOLLOW:
+                       if (!i)
+                               regulatory_hint(hw->wiphy, hwsim_alpha2s[0]);
+                       break;
+               case HWSIM_REGTEST_DRIVER_REG_ALL:
+               case HWSIM_REGTEST_STRICT_ALL:
+                       regulatory_hint(hw->wiphy, hwsim_alpha2s[0]);
+                       break;
+               case HWSIM_REGTEST_DIFF_COUNTRY:
+                       if (i < ARRAY_SIZE(hwsim_alpha2s))
+                               regulatory_hint(hw->wiphy, hwsim_alpha2s[i]);
+                       break;
+               case HWSIM_REGTEST_CUSTOM_WORLD:
+               case HWSIM_REGTEST_CUSTOM_WORLD_2:
+                       /*
+                        * Nothing to be done for custom world regulatory
+                        * domains after to ieee80211_register_hw
+                        */
+                       break;
+               case HWSIM_REGTEST_STRICT_FOLLOW:
+                       if (i == 0)
+                               regulatory_hint(hw->wiphy, hwsim_alpha2s[0]);
+                       break;
+               case HWSIM_REGTEST_STRICT_AND_DRIVER_REG:
+                       if (i == 0)
+                               regulatory_hint(hw->wiphy, hwsim_alpha2s[0]);
+                       else if (i == 1)
+                               regulatory_hint(hw->wiphy, hwsim_alpha2s[1]);
+                       break;
+               case HWSIM_REGTEST_ALL:
+                       if (i == 2)
+                               regulatory_hint(hw->wiphy, hwsim_alpha2s[0]);
+                       else if (i == 3)
+                               regulatory_hint(hw->wiphy, hwsim_alpha2s[1]);
+                       else if (i == 4)
+                               regulatory_hint(hw->wiphy, hwsim_alpha2s[2]);
+                       break;
+               default:
+                       break;
+               }
+
                printk(KERN_DEBUG "%s: hwaddr %pM registered\n",
                       wiphy_name(hw->wiphy),
                       hw->wiphy->perm_addr);
diff --git a/drivers/net/wireless/mwl8k.c b/drivers/net/wireless/mwl8k.c
new file mode 100644 (file)
index 0000000..57a0268
--- /dev/null
@@ -0,0 +1,3789 @@
+/*
+ * drivers/net/wireless/mwl8k.c driver for Marvell TOPDOG 802.11 Wireless cards
+ *
+ * Copyright (C) 2008 Marvell Semiconductor Inc.
+ *
+ * This file is licensed under the terms of the GNU General Public
+ * License version 2.  This program is licensed "as is" without any
+ * warranty of any kind, whether express or implied.
+ */
+
+#include <linux/init.h>
+#include <linux/module.h>
+#include <linux/kernel.h>
+#include <linux/spinlock.h>
+#include <linux/list.h>
+#include <linux/pci.h>
+#include <linux/delay.h>
+#include <linux/completion.h>
+#include <linux/etherdevice.h>
+#include <net/mac80211.h>
+#include <linux/moduleparam.h>
+#include <linux/firmware.h>
+#include <linux/workqueue.h>
+
+#define MWL8K_DESC     "Marvell TOPDOG(R) 802.11 Wireless Network Driver"
+#define MWL8K_NAME     KBUILD_MODNAME
+#define MWL8K_VERSION  "0.9.1"
+
+MODULE_DESCRIPTION(MWL8K_DESC);
+MODULE_VERSION(MWL8K_VERSION);
+MODULE_AUTHOR("Lennert Buytenhek <buytenh@marvell.com>");
+MODULE_LICENSE("GPL");
+
+static DEFINE_PCI_DEVICE_TABLE(mwl8k_table) = {
+       { PCI_VDEVICE(MARVELL, 0x2a2b), .driver_data = 8687, },
+       { PCI_VDEVICE(MARVELL, 0x2a30), .driver_data = 8687, },
+       { }
+};
+MODULE_DEVICE_TABLE(pci, mwl8k_table);
+
+#define IEEE80211_ADDR_LEN                     ETH_ALEN
+
+/* Register definitions */
+#define MWL8K_HIU_GEN_PTR                      0x00000c10
+#define  MWL8K_MODE_STA                                0x0000005a
+#define  MWL8K_MODE_AP                         0x000000a5
+#define MWL8K_HIU_INT_CODE                     0x00000c14
+#define  MWL8K_FWSTA_READY                     0xf0f1f2f4
+#define  MWL8K_FWAP_READY                      0xf1f2f4a5
+#define  MWL8K_INT_CODE_CMD_FINISHED           0x00000005
+#define MWL8K_HIU_SCRATCH                      0x00000c40
+
+/* Host->device communications */
+#define MWL8K_HIU_H2A_INTERRUPT_EVENTS         0x00000c18
+#define MWL8K_HIU_H2A_INTERRUPT_STATUS         0x00000c1c
+#define MWL8K_HIU_H2A_INTERRUPT_MASK           0x00000c20
+#define MWL8K_HIU_H2A_INTERRUPT_CLEAR_SEL      0x00000c24
+#define MWL8K_HIU_H2A_INTERRUPT_STATUS_MASK    0x00000c28
+#define  MWL8K_H2A_INT_DUMMY                   (1 << 20)
+#define  MWL8K_H2A_INT_RESET                   (1 << 15)
+#define  MWL8K_H2A_INT_PS                      (1 << 2)
+#define  MWL8K_H2A_INT_DOORBELL                        (1 << 1)
+#define  MWL8K_H2A_INT_PPA_READY               (1 << 0)
+
+/* Device->host communications */
+#define MWL8K_HIU_A2H_INTERRUPT_EVENTS         0x00000c2c
+#define MWL8K_HIU_A2H_INTERRUPT_STATUS         0x00000c30
+#define MWL8K_HIU_A2H_INTERRUPT_MASK           0x00000c34
+#define MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL      0x00000c38
+#define MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK    0x00000c3c
+#define  MWL8K_A2H_INT_DUMMY                   (1 << 20)
+#define  MWL8K_A2H_INT_CHNL_SWITCHED           (1 << 11)
+#define  MWL8K_A2H_INT_QUEUE_EMPTY             (1 << 10)
+#define  MWL8K_A2H_INT_RADAR_DETECT            (1 << 7)
+#define  MWL8K_A2H_INT_RADIO_ON                        (1 << 6)
+#define  MWL8K_A2H_INT_RADIO_OFF               (1 << 5)
+#define  MWL8K_A2H_INT_MAC_EVENT               (1 << 3)
+#define  MWL8K_A2H_INT_OPC_DONE                        (1 << 2)
+#define  MWL8K_A2H_INT_RX_READY                        (1 << 1)
+#define  MWL8K_A2H_INT_TX_DONE                 (1 << 0)
+
+#define MWL8K_A2H_EVENTS       (MWL8K_A2H_INT_DUMMY | \
+                                MWL8K_A2H_INT_CHNL_SWITCHED | \
+                                MWL8K_A2H_INT_QUEUE_EMPTY | \
+                                MWL8K_A2H_INT_RADAR_DETECT | \
+                                MWL8K_A2H_INT_RADIO_ON | \
+                                MWL8K_A2H_INT_RADIO_OFF | \
+                                MWL8K_A2H_INT_MAC_EVENT | \
+                                MWL8K_A2H_INT_OPC_DONE | \
+                                MWL8K_A2H_INT_RX_READY | \
+                                MWL8K_A2H_INT_TX_DONE)
+
+/* WME stream classes */
+#define WME_AC_BE      0               /* best effort */
+#define WME_AC_BK      1               /* background */
+#define WME_AC_VI      2               /* video */
+#define WME_AC_VO      3               /* voice */
+
+#define MWL8K_RX_QUEUES                1
+#define MWL8K_TX_QUEUES                4
+
+struct mwl8k_rx_queue {
+       int rx_desc_count;
+
+       /* hw receives here */
+       int rx_head;
+
+       /* refill descs here */
+       int rx_tail;
+
+       struct mwl8k_rx_desc *rx_desc_area;
+       dma_addr_t rx_desc_dma;
+       struct sk_buff **rx_skb;
+};
+
+struct mwl8k_skb {
+       /*
+        * The DMA engine requires a modification to the payload.
+        * If the skbuff is shared/cloned, it needs to be unshared.
+        * This method is used to ensure the stack always gets back
+        * the skbuff it sent for transmission.
+        */
+       struct sk_buff *clone;
+       struct sk_buff *skb;
+};
+
+struct mwl8k_tx_queue {
+       /* hw transmits here */
+       int tx_head;
+
+       /* sw appends here */
+       int tx_tail;
+
+       struct ieee80211_tx_queue_stats tx_stats;
+       struct mwl8k_tx_desc *tx_desc_area;
+       dma_addr_t tx_desc_dma;
+       struct mwl8k_skb *tx_skb;
+};
+
+/* Pointers to the firmware data and meta information about it.  */
+struct mwl8k_firmware {
+       /* Microcode */
+       struct firmware *ucode;
+
+       /* Boot helper code */
+       struct firmware *helper;
+};
+
+struct mwl8k_priv {
+       void __iomem *regs;
+       struct ieee80211_hw *hw;
+
+       struct pci_dev *pdev;
+       u8 name[16];
+       /* firmware access lock */
+       spinlock_t fw_lock;
+
+       /* firmware files and meta data */
+       struct mwl8k_firmware fw;
+       u32 part_num;
+
+       /* lock held over TX and TX reap */
+       spinlock_t tx_lock;
+       u32 int_mask;
+
+       struct ieee80211_vif *vif;
+       struct list_head vif_list;
+
+       struct ieee80211_channel *current_channel;
+
+       /* power management status cookie from firmware */
+       u32 *cookie;
+       dma_addr_t cookie_dma;
+
+       u16 num_mcaddrs;
+       u16 region_code;
+       u8 hw_rev;
+       __le32 fw_rev;
+       u32 wep_enabled;
+
+       /*
+        * Running count of TX packets in flight, to avoid
+        * iterating over the transmit rings each time.
+        */
+       int pending_tx_pkts;
+
+       struct mwl8k_rx_queue rxq[MWL8K_RX_QUEUES];
+       struct mwl8k_tx_queue txq[MWL8K_TX_QUEUES];
+
+       /* PHY parameters */
+       struct ieee80211_supported_band band;
+       struct ieee80211_channel channels[14];
+       struct ieee80211_rate rates[12];
+
+       /* RF preamble: Short, Long or Auto */
+       u8      radio_preamble;
+       u8      radio_state;
+
+       /* WMM MODE 1 for enabled; 0 for disabled */
+       bool wmm_mode;
+
+       /* Set if PHY config is in progress */
+       bool inconfig;
+
+       /* XXX need to convert this to handle multiple interfaces */
+       bool capture_beacon;
+       u8 capture_bssid[IEEE80211_ADDR_LEN];
+       struct sk_buff *beacon_skb;
+
+       /*
+        * This FJ worker has to be global as it is scheduled from the
+        * RX handler.  At this point we don't know which interface it
+        * belongs to until the list of bssids waiting to complete join
+        * is checked.
+        */
+       struct work_struct finalize_join_worker;
+
+       /* Tasklet to reclaim TX descriptors and buffers after tx */
+       struct tasklet_struct tx_reclaim_task;
+
+       /* Work thread to serialize configuration requests */
+       struct workqueue_struct *config_wq;
+       struct completion *hostcmd_wait;
+       struct completion *tx_wait;
+};
+
+/* Per interface specific private data */
+struct mwl8k_vif {
+       struct list_head node;
+
+       /* backpointer to parent config block */
+       struct mwl8k_priv *priv;
+
+       /* BSS config of AP or IBSS from mac80211*/
+       struct ieee80211_bss_conf bss_info;
+
+       /* BSSID of AP or IBSS */
+       u8      bssid[IEEE80211_ADDR_LEN];
+       u8      mac_addr[IEEE80211_ADDR_LEN];
+
+       /*
+        * Subset of supported legacy rates.
+        * Intersection of AP and STA supported rates.
+        */
+       struct ieee80211_rate legacy_rates[12];
+
+       /* number of supported legacy rates */
+       u8      legacy_nrates;
+
+       /* Number of supported MCS rates. Work in progress */
+       u8      mcs_nrates;
+
+        /* Index into station database.Returned by update_sta_db call */
+       u8      peer_id;
+
+       /* Non AMPDU sequence number assigned by driver */
+       u16     seqno;
+
+       /* Note:There is no channel info,
+        * refer to the master channel info in priv
+        */
+};
+
+#define MWL8K_VIF(_vif) (struct mwl8k_vif *)(&((_vif)->drv_priv))
+
+static const struct ieee80211_channel mwl8k_channels[] = {
+       { .center_freq = 2412, .hw_value = 1, },
+       { .center_freq = 2417, .hw_value = 2, },
+       { .center_freq = 2422, .hw_value = 3, },
+       { .center_freq = 2427, .hw_value = 4, },
+       { .center_freq = 2432, .hw_value = 5, },
+       { .center_freq = 2437, .hw_value = 6, },
+       { .center_freq = 2442, .hw_value = 7, },
+       { .center_freq = 2447, .hw_value = 8, },
+       { .center_freq = 2452, .hw_value = 9, },
+       { .center_freq = 2457, .hw_value = 10, },
+       { .center_freq = 2462, .hw_value = 11, },
+};
+
+static const struct ieee80211_rate mwl8k_rates[] = {
+       { .bitrate = 10, .hw_value = 2, },
+       { .bitrate = 20, .hw_value = 4, },
+       { .bitrate = 55, .hw_value = 11, },
+       { .bitrate = 60, .hw_value = 12, },
+       { .bitrate = 90, .hw_value = 18, },
+       { .bitrate = 110, .hw_value = 22, },
+       { .bitrate = 120, .hw_value = 24, },
+       { .bitrate = 180, .hw_value = 36, },
+       { .bitrate = 240, .hw_value = 48, },
+       { .bitrate = 360, .hw_value = 72, },
+       { .bitrate = 480, .hw_value = 96, },
+       { .bitrate = 540, .hw_value = 108, },
+};
+
+/* Radio settings */
+#define MWL8K_RADIO_FORCE              0x2
+#define MWL8K_RADIO_ENABLE             0x1
+#define MWL8K_RADIO_DISABLE            0x0
+#define MWL8K_RADIO_AUTO_PREAMBLE      0x0005
+#define MWL8K_RADIO_SHORT_PREAMBLE     0x0003
+#define MWL8K_RADIO_LONG_PREAMBLE      0x0001
+
+/* WMM */
+#define MWL8K_WMM_ENABLE               1
+#define MWL8K_WMM_DISABLE              0
+
+#define MWL8K_RADIO_DEFAULT_PREAMBLE   MWL8K_RADIO_LONG_PREAMBLE
+
+/* Slot time */
+
+/* Short Slot: 9us slot time */
+#define MWL8K_SHORT_SLOTTIME           1
+
+/* Long slot: 20us slot time */
+#define MWL8K_LONG_SLOTTIME            0
+
+/* Set or get info from Firmware */
+#define MWL8K_CMD_SET                  0x0001
+#define MWL8K_CMD_GET                  0x0000
+
+/* Firmware command codes */
+#define MWL8K_CMD_CODE_DNLD            0x0001
+#define MWL8K_CMD_GET_HW_SPEC          0x0003
+#define MWL8K_CMD_MAC_MULTICAST_ADR    0x0010
+#define MWL8K_CMD_GET_STAT             0x0014
+#define MWL8K_CMD_RADIO_CONTROL                0x001C
+#define MWL8K_CMD_RF_TX_POWER          0x001E
+#define MWL8K_CMD_SET_PRE_SCAN         0x0107
+#define MWL8K_CMD_SET_POST_SCAN                0x0108
+#define MWL8K_CMD_SET_RF_CHANNEL       0x010A
+#define MWL8K_CMD_SET_SLOT             0x0114
+#define MWL8K_CMD_MIMO_CONFIG          0x0125
+#define MWL8K_CMD_ENABLE_SNIFFER       0x0150
+#define MWL8K_CMD_SET_WMM_MODE         0x0123
+#define MWL8K_CMD_SET_EDCA_PARAMS      0x0115
+#define MWL8K_CMD_SET_FINALIZE_JOIN    0x0111
+#define MWL8K_CMD_UPDATE_STADB         0x1123
+#define MWL8K_CMD_SET_RATEADAPT_MODE   0x0203
+#define MWL8K_CMD_SET_LINKADAPT_MODE   0x0129
+#define MWL8K_CMD_SET_AID              0x010d
+#define MWL8K_CMD_SET_RATE             0x0110
+#define MWL8K_CMD_USE_FIXED_RATE       0x0126
+#define MWL8K_CMD_RTS_THRESHOLD                0x0113
+#define MWL8K_CMD_ENCRYPTION           0x1122
+
+static const char *mwl8k_cmd_name(u16 cmd, char *buf, int bufsize)
+{
+#define MWL8K_CMDNAME(x)       case MWL8K_CMD_##x: do {\
+                                       snprintf(buf, bufsize, "%s", #x);\
+                                       return buf;\
+                                       } while (0)
+       switch (cmd & (~0x8000)) {
+               MWL8K_CMDNAME(CODE_DNLD);
+               MWL8K_CMDNAME(GET_HW_SPEC);
+               MWL8K_CMDNAME(MAC_MULTICAST_ADR);
+               MWL8K_CMDNAME(GET_STAT);
+               MWL8K_CMDNAME(RADIO_CONTROL);
+               MWL8K_CMDNAME(RF_TX_POWER);
+               MWL8K_CMDNAME(SET_PRE_SCAN);
+               MWL8K_CMDNAME(SET_POST_SCAN);
+               MWL8K_CMDNAME(SET_RF_CHANNEL);
+               MWL8K_CMDNAME(SET_SLOT);
+               MWL8K_CMDNAME(MIMO_CONFIG);
+               MWL8K_CMDNAME(ENABLE_SNIFFER);
+               MWL8K_CMDNAME(SET_WMM_MODE);
+               MWL8K_CMDNAME(SET_EDCA_PARAMS);
+               MWL8K_CMDNAME(SET_FINALIZE_JOIN);
+               MWL8K_CMDNAME(UPDATE_STADB);
+               MWL8K_CMDNAME(SET_RATEADAPT_MODE);
+               MWL8K_CMDNAME(SET_LINKADAPT_MODE);
+               MWL8K_CMDNAME(SET_AID);
+               MWL8K_CMDNAME(SET_RATE);
+               MWL8K_CMDNAME(USE_FIXED_RATE);
+               MWL8K_CMDNAME(RTS_THRESHOLD);
+               MWL8K_CMDNAME(ENCRYPTION);
+       default:
+               snprintf(buf, bufsize, "0x%x", cmd);
+       }
+#undef MWL8K_CMDNAME
+
+       return buf;
+}
+
+/* Hardware and firmware reset */
+static void mwl8k_hw_reset(struct mwl8k_priv *priv)
+{
+       iowrite32(MWL8K_H2A_INT_RESET,
+               priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
+       iowrite32(MWL8K_H2A_INT_RESET,
+               priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
+       msleep(20);
+}
+
+/* Release fw image */
+static void mwl8k_release_fw(struct firmware **fw)
+{
+       if (*fw == NULL)
+               return;
+       release_firmware(*fw);
+       *fw = NULL;
+}
+
+static void mwl8k_release_firmware(struct mwl8k_priv *priv)
+{
+       mwl8k_release_fw(&priv->fw.ucode);
+       mwl8k_release_fw(&priv->fw.helper);
+}
+
+/* Request fw image */
+static int mwl8k_request_fw(struct mwl8k_priv *priv,
+                               const char *fname, struct firmware **fw)
+{
+       /* release current image */
+       if (*fw != NULL)
+               mwl8k_release_fw(fw);
+
+       return request_firmware((const struct firmware **)fw,
+                                               fname, &priv->pdev->dev);
+}
+
+static int mwl8k_request_firmware(struct mwl8k_priv *priv, u32 part_num)
+{
+       u8 filename[64];
+       int rc;
+
+       priv->part_num = part_num;
+
+       snprintf(filename, sizeof(filename),
+                "mwl8k/helper_%u.fw", priv->part_num);
+
+       rc = mwl8k_request_fw(priv, filename, &priv->fw.helper);
+       if (rc) {
+               printk(KERN_ERR
+                       "%s Error requesting helper firmware file %s\n",
+                       pci_name(priv->pdev), filename);
+               return rc;
+       }
+
+       snprintf(filename, sizeof(filename),
+                "mwl8k/fmimage_%u.fw", priv->part_num);
+
+       rc = mwl8k_request_fw(priv, filename, &priv->fw.ucode);
+       if (rc) {
+               printk(KERN_ERR "%s Error requesting firmware file %s\n",
+                                       pci_name(priv->pdev), filename);
+               mwl8k_release_fw(&priv->fw.helper);
+               return rc;
+       }
+
+       return 0;
+}
+
+struct mwl8k_cmd_pkt {
+       __le16  code;
+       __le16  length;
+       __le16  seq_num;
+       __le16  result;
+       char    payload[0];
+} __attribute__((packed));
+
+/*
+ * Firmware loading.
+ */
+static int
+mwl8k_send_fw_load_cmd(struct mwl8k_priv *priv, void *data, int length)
+{
+       void __iomem *regs = priv->regs;
+       dma_addr_t dma_addr;
+       int rc;
+       int loops;
+
+       dma_addr = pci_map_single(priv->pdev, data, length, PCI_DMA_TODEVICE);
+       if (pci_dma_mapping_error(priv->pdev, dma_addr))
+               return -ENOMEM;
+
+       iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR);
+       iowrite32(0, regs + MWL8K_HIU_INT_CODE);
+       iowrite32(MWL8K_H2A_INT_DOORBELL,
+               regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
+       iowrite32(MWL8K_H2A_INT_DUMMY,
+               regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
+
+       rc = -ETIMEDOUT;
+       loops = 1000;
+       do {
+               u32 int_code;
+
+               int_code = ioread32(regs + MWL8K_HIU_INT_CODE);
+               if (int_code == MWL8K_INT_CODE_CMD_FINISHED) {
+                       iowrite32(0, regs + MWL8K_HIU_INT_CODE);
+                       rc = 0;
+                       break;
+               }
+
+               udelay(1);
+       } while (--loops);
+
+       pci_unmap_single(priv->pdev, dma_addr, length, PCI_DMA_TODEVICE);
+
+       /*
+        * Clear 'command done' interrupt bit.
+        */
+       loops = 1000;
+       do {
+               u32 status;
+
+               status = ioread32(priv->regs +
+                               MWL8K_HIU_A2H_INTERRUPT_STATUS);
+               if (status & MWL8K_A2H_INT_OPC_DONE) {
+                       iowrite32(~MWL8K_A2H_INT_OPC_DONE,
+                               priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
+                       ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
+                       break;
+               }
+
+               udelay(1);
+       } while (--loops);
+
+       return rc;
+}
+
+static int mwl8k_load_fw_image(struct mwl8k_priv *priv,
+                               const u8 *data, size_t length)
+{
+       struct mwl8k_cmd_pkt *cmd;
+       int done;
+       int rc = 0;
+
+       cmd = kmalloc(sizeof(*cmd) + 256, GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->code = cpu_to_le16(MWL8K_CMD_CODE_DNLD);
+       cmd->seq_num = 0;
+       cmd->result = 0;
+
+       done = 0;
+       while (length) {
+               int block_size = length > 256 ? 256 : length;
+
+               memcpy(cmd->payload, data + done, block_size);
+               cmd->length = cpu_to_le16(block_size);
+
+               rc = mwl8k_send_fw_load_cmd(priv, cmd,
+                                               sizeof(*cmd) + block_size);
+               if (rc)
+                       break;
+
+               done += block_size;
+               length -= block_size;
+       }
+
+       if (!rc) {
+               cmd->length = 0;
+               rc = mwl8k_send_fw_load_cmd(priv, cmd, sizeof(*cmd));
+       }
+
+       kfree(cmd);
+
+       return rc;
+}
+
+static int mwl8k_feed_fw_image(struct mwl8k_priv *priv,
+                               const u8 *data, size_t length)
+{
+       unsigned char *buffer;
+       int may_continue, rc = 0;
+       u32 done, prev_block_size;
+
+       buffer = kmalloc(1024, GFP_KERNEL);
+       if (buffer == NULL)
+               return -ENOMEM;
+
+       done = 0;
+       prev_block_size = 0;
+       may_continue = 1000;
+       while (may_continue > 0) {
+               u32 block_size;
+
+               block_size = ioread32(priv->regs + MWL8K_HIU_SCRATCH);
+               if (block_size & 1) {
+                       block_size &= ~1;
+                       may_continue--;
+               } else {
+                       done += prev_block_size;
+                       length -= prev_block_size;
+               }
+
+               if (block_size > 1024 || block_size > length) {
+                       rc = -EOVERFLOW;
+                       break;
+               }
+
+               if (length == 0) {
+                       rc = 0;
+                       break;
+               }
+
+               if (block_size == 0) {
+                       rc = -EPROTO;
+                       may_continue--;
+                       udelay(1);
+                       continue;
+               }
+
+               prev_block_size = block_size;
+               memcpy(buffer, data + done, block_size);
+
+               rc = mwl8k_send_fw_load_cmd(priv, buffer, block_size);
+               if (rc)
+                       break;
+       }
+
+       if (!rc && length != 0)
+               rc = -EREMOTEIO;
+
+       kfree(buffer);
+
+       return rc;
+}
+
+static int mwl8k_load_firmware(struct mwl8k_priv *priv)
+{
+       int loops, rc;
+
+       const u8 *ucode = priv->fw.ucode->data;
+       size_t ucode_len = priv->fw.ucode->size;
+       const u8 *helper = priv->fw.helper->data;
+       size_t helper_len = priv->fw.helper->size;
+
+       if (!memcmp(ucode, "\x01\x00\x00\x00", 4)) {
+               rc = mwl8k_load_fw_image(priv, helper, helper_len);
+               if (rc) {
+                       printk(KERN_ERR "%s: unable to load firmware "
+                               "helper image\n", pci_name(priv->pdev));
+                       return rc;
+               }
+               msleep(1);
+
+               rc = mwl8k_feed_fw_image(priv, ucode, ucode_len);
+       } else {
+               rc = mwl8k_load_fw_image(priv, ucode, ucode_len);
+       }
+
+       if (rc) {
+               printk(KERN_ERR "%s: unable to load firmware data\n",
+                       pci_name(priv->pdev));
+               return rc;
+       }
+
+       iowrite32(MWL8K_MODE_STA, priv->regs + MWL8K_HIU_GEN_PTR);
+       msleep(1);
+
+       loops = 200000;
+       do {
+               if (ioread32(priv->regs + MWL8K_HIU_INT_CODE)
+                                               == MWL8K_FWSTA_READY)
+                       break;
+               udelay(1);
+       } while (--loops);
+
+       return loops ? 0 : -ETIMEDOUT;
+}
+
+
+/*
+ * Defines shared between transmission and reception.
+ */
+/* HT control fields for firmware */
+struct ewc_ht_info {
+       __le16  control1;
+       __le16  control2;
+       __le16  control3;
+} __attribute__((packed));
+
+/* Firmware Station database operations */
+#define MWL8K_STA_DB_ADD_ENTRY         0
+#define MWL8K_STA_DB_MODIFY_ENTRY      1
+#define MWL8K_STA_DB_DEL_ENTRY         2
+#define MWL8K_STA_DB_FLUSH             3
+
+/* Peer Entry flags - used to define the type of the peer node */
+#define MWL8K_PEER_TYPE_ACCESSPOINT    2
+#define MWL8K_PEER_TYPE_ADHOC_STATION  4
+
+#define MWL8K_IEEE_LEGACY_DATA_RATES   12
+#define MWL8K_MCS_BITMAP_SIZE          16
+#define pad_size                       16
+
+struct peer_capability_info {
+       /* Peer type - AP vs. STA.  */
+       __u8    peer_type;
+
+       /* Basic 802.11 capabilities from assoc resp.  */
+       __le16  basic_caps;
+
+       /* Set if peer supports 802.11n high throughput (HT).  */
+       __u8    ht_support;
+
+       /* Valid if HT is supported.  */
+       __le16  ht_caps;
+       __u8    extended_ht_caps;
+       struct ewc_ht_info      ewc_info;
+
+       /* Legacy rate table. Intersection of our rates and peer rates.  */
+       __u8    legacy_rates[MWL8K_IEEE_LEGACY_DATA_RATES];
+
+       /* HT rate table. Intersection of our rates and peer rates.  */
+       __u8    ht_rates[MWL8K_MCS_BITMAP_SIZE];
+       __u8    pad[pad_size];
+
+       /* If set, interoperability mode, no proprietary extensions.  */
+       __u8    interop;
+       __u8    pad2;
+       __u8    station_id;
+       __le16  amsdu_enabled;
+} __attribute__((packed));
+
+/* Inline functions to manipulate QoS field in data descriptor.  */
+static inline u16 mwl8k_qos_setbit_tid(u16 qos, u8 tid)
+{
+       u16 val_mask = 0x000f;
+       u16 qos_mask = ~val_mask;
+
+       /* TID bits 0-3 */
+       return (qos & qos_mask) | (tid & val_mask);
+}
+
+static inline u16 mwl8k_qos_setbit_eosp(u16 qos)
+{
+       u16 val_mask = 1 << 4;
+
+       /* End of Service Period Bit 4 */
+       return qos | val_mask;
+}
+
+static inline u16 mwl8k_qos_setbit_ack(u16 qos, u8 ack_policy)
+{
+       u16 val_mask = 0x3;
+       u8      shift = 5;
+       u16 qos_mask = ~(val_mask << shift);
+
+       /* Ack Policy Bit 5-6 */
+       return (qos & qos_mask) | ((ack_policy & val_mask) << shift);
+}
+
+static inline u16 mwl8k_qos_setbit_amsdu(u16 qos)
+{
+       u16 val_mask = 1 << 7;
+
+       /* AMSDU present Bit 7 */
+       return qos | val_mask;
+}
+
+static inline u16 mwl8k_qos_setbit_qlen(u16 qos, u8 len)
+{
+       u16 val_mask = 0xff;
+       u8      shift = 8;
+       u16 qos_mask = ~(val_mask << shift);
+
+       /* Queue Length Bits 8-15 */
+       return (qos & qos_mask) | ((len & val_mask) << shift);
+}
+
+/* DMA header used by firmware and hardware.  */
+struct mwl8k_dma_data {
+       __le16 fwlen;
+       struct ieee80211_hdr wh;
+} __attribute__((packed));
+
+/* Routines to add/remove DMA header from skb.  */
+static inline int mwl8k_remove_dma_header(struct sk_buff *skb)
+{
+       struct mwl8k_dma_data *tr = (struct mwl8k_dma_data *)(skb->data);
+       void *dst, *src = &tr->wh;
+       __le16 fc = tr->wh.frame_control;
+       int hdrlen = ieee80211_hdrlen(fc);
+       u16 space = sizeof(struct mwl8k_dma_data) - hdrlen;
+
+       dst = (void *)tr + space;
+       if (dst != src) {
+               memmove(dst, src, hdrlen);
+               skb_pull(skb, space);
+       }
+
+       return 0;
+}
+
+static inline struct sk_buff *mwl8k_add_dma_header(struct sk_buff *skb)
+{
+       struct ieee80211_hdr *wh;
+       u32 hdrlen, pktlen;
+       struct mwl8k_dma_data *tr;
+
+       wh = (struct ieee80211_hdr *)skb->data;
+       hdrlen = ieee80211_hdrlen(wh->frame_control);
+       pktlen = skb->len;
+
+       /*
+        * Copy up/down the 802.11 header; the firmware requires
+        * we present a 2-byte payload length followed by a
+        * 4-address header (w/o QoS), followed (optionally) by
+        * any WEP/ExtIV header (but only filled in for CCMP).
+        */
+       if (hdrlen != sizeof(struct mwl8k_dma_data))
+               skb_push(skb, sizeof(struct mwl8k_dma_data) - hdrlen);
+
+       tr = (struct mwl8k_dma_data *)skb->data;
+       if (wh != &tr->wh)
+               memmove(&tr->wh, wh, hdrlen);
+
+       /* Clear addr4 */
+       memset(tr->wh.addr4, 0, IEEE80211_ADDR_LEN);
+
+       /*
+        * Firmware length is the length of the fully formed "802.11
+        * payload".  That is, everything except for the 802.11 header.
+        * This includes all crypto material including the MIC.
+        */
+       tr->fwlen = cpu_to_le16(pktlen - hdrlen);
+
+       return skb;
+}
+
+
+/*
+ * Packet reception.
+ */
+#define MWL8K_RX_CTRL_KEY_INDEX_MASK   0x30
+#define MWL8K_RX_CTRL_OWNED_BY_HOST    0x02
+#define MWL8K_RX_CTRL_AMPDU            0x01
+
+struct mwl8k_rx_desc {
+       __le16 pkt_len;
+       __u8 link_quality;
+       __u8 noise_level;
+       __le32 pkt_phys_addr;
+       __le32 next_rx_desc_phys_addr;
+       __le16 qos_control;
+       __le16 rate_info;
+       __le32 pad0[4];
+       __u8 rssi;
+       __u8 channel;
+       __le16 pad1;
+       __u8 rx_ctrl;
+       __u8 rx_status;
+       __u8 pad2[2];
+} __attribute__((packed));
+
+#define MWL8K_RX_DESCS         256
+#define MWL8K_RX_MAXSZ         3800
+
+static int mwl8k_rxq_init(struct ieee80211_hw *hw, int index)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_rx_queue *rxq = priv->rxq + index;
+       int size;
+       int i;
+
+       rxq->rx_desc_count = 0;
+       rxq->rx_head = 0;
+       rxq->rx_tail = 0;
+
+       size = MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc);
+
+       rxq->rx_desc_area =
+               pci_alloc_consistent(priv->pdev, size, &rxq->rx_desc_dma);
+       if (rxq->rx_desc_area == NULL) {
+               printk(KERN_ERR "%s: failed to alloc RX descriptors\n",
+                      priv->name);
+               return -ENOMEM;
+       }
+       memset(rxq->rx_desc_area, 0, size);
+
+       rxq->rx_skb = kmalloc(MWL8K_RX_DESCS *
+                               sizeof(*rxq->rx_skb), GFP_KERNEL);
+       if (rxq->rx_skb == NULL) {
+               printk(KERN_ERR "%s: failed to alloc RX skbuff list\n",
+                       priv->name);
+               pci_free_consistent(priv->pdev, size,
+                                   rxq->rx_desc_area, rxq->rx_desc_dma);
+               return -ENOMEM;
+       }
+       memset(rxq->rx_skb, 0, MWL8K_RX_DESCS * sizeof(*rxq->rx_skb));
+
+       for (i = 0; i < MWL8K_RX_DESCS; i++) {
+               struct mwl8k_rx_desc *rx_desc;
+               int nexti;
+
+               rx_desc = rxq->rx_desc_area + i;
+               nexti = (i + 1) % MWL8K_RX_DESCS;
+
+               rx_desc->next_rx_desc_phys_addr =
+                       cpu_to_le32(rxq->rx_desc_dma
+                                               + nexti * sizeof(*rx_desc));
+               rx_desc->rx_ctrl =
+                       cpu_to_le32(MWL8K_RX_CTRL_OWNED_BY_HOST);
+       }
+
+       return 0;
+}
+
+static int rxq_refill(struct ieee80211_hw *hw, int index, int limit)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_rx_queue *rxq = priv->rxq + index;
+       int refilled;
+
+       refilled = 0;
+       while (rxq->rx_desc_count < MWL8K_RX_DESCS && limit--) {
+               struct sk_buff *skb;
+               int rx;
+
+               skb = dev_alloc_skb(MWL8K_RX_MAXSZ);
+               if (skb == NULL)
+                       break;
+
+               rxq->rx_desc_count++;
+
+               rx = rxq->rx_tail;
+               rxq->rx_tail = (rx + 1) % MWL8K_RX_DESCS;
+
+               rxq->rx_desc_area[rx].pkt_phys_addr =
+                       cpu_to_le32(pci_map_single(priv->pdev, skb->data,
+                                       MWL8K_RX_MAXSZ, DMA_FROM_DEVICE));
+
+               rxq->rx_desc_area[rx].pkt_len = cpu_to_le16(MWL8K_RX_MAXSZ);
+               rxq->rx_skb[rx] = skb;
+               wmb();
+               rxq->rx_desc_area[rx].rx_ctrl = 0;
+
+               refilled++;
+       }
+
+       return refilled;
+}
+
+/* Must be called only when the card's reception is completely halted */
+static void mwl8k_rxq_deinit(struct ieee80211_hw *hw, int index)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_rx_queue *rxq = priv->rxq + index;
+       int i;
+
+       for (i = 0; i < MWL8K_RX_DESCS; i++) {
+               if (rxq->rx_skb[i] != NULL) {
+                       unsigned long addr;
+
+                       addr = le32_to_cpu(rxq->rx_desc_area[i].pkt_phys_addr);
+                       pci_unmap_single(priv->pdev, addr, MWL8K_RX_MAXSZ,
+                                        PCI_DMA_FROMDEVICE);
+                       kfree_skb(rxq->rx_skb[i]);
+                       rxq->rx_skb[i] = NULL;
+               }
+       }
+
+       kfree(rxq->rx_skb);
+       rxq->rx_skb = NULL;
+
+       pci_free_consistent(priv->pdev,
+                           MWL8K_RX_DESCS * sizeof(struct mwl8k_rx_desc),
+                           rxq->rx_desc_area, rxq->rx_desc_dma);
+       rxq->rx_desc_area = NULL;
+}
+
+
+/*
+ * Scan a list of BSSIDs to process for finalize join.
+ * Allows for extension to process multiple BSSIDs.
+ */
+static inline int
+mwl8k_capture_bssid(struct mwl8k_priv *priv, struct ieee80211_hdr *wh)
+{
+       return priv->capture_beacon &&
+               ieee80211_is_beacon(wh->frame_control) &&
+               !compare_ether_addr(wh->addr3, priv->capture_bssid);
+}
+
+static inline void mwl8k_save_beacon(struct mwl8k_priv *priv,
+                                                       struct sk_buff *skb)
+{
+       priv->capture_beacon = false;
+       memset(priv->capture_bssid, 0, IEEE80211_ADDR_LEN);
+
+       /*
+        * Use GFP_ATOMIC as rxq_process is called from
+        * the primary interrupt handler, memory allocation call
+        * must not sleep.
+        */
+       priv->beacon_skb = skb_copy(skb, GFP_ATOMIC);
+       if (priv->beacon_skb != NULL)
+               queue_work(priv->config_wq,
+                               &priv->finalize_join_worker);
+}
+
+static int rxq_process(struct ieee80211_hw *hw, int index, int limit)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_rx_queue *rxq = priv->rxq + index;
+       int processed;
+
+       processed = 0;
+       while (rxq->rx_desc_count && limit--) {
+               struct mwl8k_rx_desc *rx_desc;
+               struct sk_buff *skb;
+               struct ieee80211_rx_status status;
+               unsigned long addr;
+               struct ieee80211_hdr *wh;
+
+               rx_desc = rxq->rx_desc_area + rxq->rx_head;
+               if (!(rx_desc->rx_ctrl & MWL8K_RX_CTRL_OWNED_BY_HOST))
+                       break;
+               rmb();
+
+               skb = rxq->rx_skb[rxq->rx_head];
+               rxq->rx_skb[rxq->rx_head] = NULL;
+
+               rxq->rx_head = (rxq->rx_head + 1) % MWL8K_RX_DESCS;
+               rxq->rx_desc_count--;
+
+               addr = le32_to_cpu(rx_desc->pkt_phys_addr);
+               pci_unmap_single(priv->pdev, addr,
+                                       MWL8K_RX_MAXSZ, PCI_DMA_FROMDEVICE);
+
+               skb_put(skb, le16_to_cpu(rx_desc->pkt_len));
+               if (mwl8k_remove_dma_header(skb)) {
+                       dev_kfree_skb(skb);
+                       continue;
+               }
+
+               wh = (struct ieee80211_hdr *)skb->data;
+
+               /*
+                * Check for pending join operation. save a copy of
+                * the beacon and schedule a tasklet to send finalize
+                * join command to the firmware.
+                */
+               if (mwl8k_capture_bssid(priv, wh))
+                       mwl8k_save_beacon(priv, skb);
+
+               memset(&status, 0, sizeof(status));
+               status.mactime = 0;
+               status.signal = -rx_desc->rssi;
+               status.noise = -rx_desc->noise_level;
+               status.qual = rx_desc->link_quality;
+               status.antenna = 1;
+               status.rate_idx = 1;
+               status.flag = 0;
+               status.band = IEEE80211_BAND_2GHZ;
+               status.freq = ieee80211_channel_to_frequency(rx_desc->channel);
+               ieee80211_rx_irqsafe(hw, skb, &status);
+
+               processed++;
+       }
+
+       return processed;
+}
+
+
+/*
+ * Packet transmission.
+ */
+
+/* Transmit queue assignment.  */
+enum {
+       MWL8K_WME_AC_BK = 0,            /* background access */
+       MWL8K_WME_AC_BE = 1,            /* best effort access */
+       MWL8K_WME_AC_VI = 2,            /* video access */
+       MWL8K_WME_AC_VO = 3,            /* voice access */
+};
+
+/* Transmit packet ACK policy */
+#define MWL8K_TXD_ACK_POLICY_NORMAL            0
+#define MWL8K_TXD_ACK_POLICY_NONE              1
+#define MWL8K_TXD_ACK_POLICY_NO_EXPLICIT       2
+#define MWL8K_TXD_ACK_POLICY_BLOCKACK          3
+
+#define GET_TXQ(_ac) (\
+               ((_ac) == WME_AC_VO) ? MWL8K_WME_AC_VO : \
+               ((_ac) == WME_AC_VI) ? MWL8K_WME_AC_VI : \
+               ((_ac) == WME_AC_BK) ? MWL8K_WME_AC_BK : \
+               MWL8K_WME_AC_BE)
+
+#define MWL8K_TXD_STATUS_IDLE                  0x00000000
+#define MWL8K_TXD_STATUS_USED                  0x00000001
+#define MWL8K_TXD_STATUS_OK                    0x00000001
+#define MWL8K_TXD_STATUS_OK_RETRY              0x00000002
+#define MWL8K_TXD_STATUS_OK_MORE_RETRY         0x00000004
+#define MWL8K_TXD_STATUS_MULTICAST_TX          0x00000008
+#define MWL8K_TXD_STATUS_BROADCAST_TX          0x00000010
+#define MWL8K_TXD_STATUS_FAILED_LINK_ERROR     0x00000020
+#define MWL8K_TXD_STATUS_FAILED_EXCEED_LIMIT   0x00000040
+#define MWL8K_TXD_STATUS_FAILED_AGING          0x00000080
+#define MWL8K_TXD_STATUS_HOST_CMD              0x40000000
+#define MWL8K_TXD_STATUS_FW_OWNED              0x80000000
+#define  MWL8K_TXD_SOFTSTALE                           0x80
+#define  MWL8K_TXD_SOFTSTALE_MGMT_RETRY                        0x01
+
+struct mwl8k_tx_desc {
+       __le32 status;
+       __u8 data_rate;
+       __u8 tx_priority;
+       __le16 qos_control;
+       __le32 pkt_phys_addr;
+       __le16 pkt_len;
+       __u8 dest_MAC_addr[IEEE80211_ADDR_LEN];
+       __le32 next_tx_desc_phys_addr;
+       __le32 reserved;
+       __le16 rate_info;
+       __u8 peer_id;
+       __u8 tx_frag_cnt;
+} __attribute__((packed));
+
+#define MWL8K_TX_DESCS         128
+
+static int mwl8k_txq_init(struct ieee80211_hw *hw, int index)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_tx_queue *txq = priv->txq + index;
+       int size;
+       int i;
+
+       memset(&txq->tx_stats, 0,
+               sizeof(struct ieee80211_tx_queue_stats));
+       txq->tx_stats.limit = MWL8K_TX_DESCS;
+       txq->tx_head = 0;
+       txq->tx_tail = 0;
+
+       size = MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc);
+
+       txq->tx_desc_area =
+               pci_alloc_consistent(priv->pdev, size, &txq->tx_desc_dma);
+       if (txq->tx_desc_area == NULL) {
+               printk(KERN_ERR "%s: failed to alloc TX descriptors\n",
+                      priv->name);
+               return -ENOMEM;
+       }
+       memset(txq->tx_desc_area, 0, size);
+
+       txq->tx_skb = kmalloc(MWL8K_TX_DESCS * sizeof(*txq->tx_skb),
+                                                               GFP_KERNEL);
+       if (txq->tx_skb == NULL) {
+               printk(KERN_ERR "%s: failed to alloc TX skbuff list\n",
+                      priv->name);
+               pci_free_consistent(priv->pdev, size,
+                                   txq->tx_desc_area, txq->tx_desc_dma);
+               return -ENOMEM;
+       }
+       memset(txq->tx_skb, 0, MWL8K_TX_DESCS * sizeof(*txq->tx_skb));
+
+       for (i = 0; i < MWL8K_TX_DESCS; i++) {
+               struct mwl8k_tx_desc *tx_desc;
+               int nexti;
+
+               tx_desc = txq->tx_desc_area + i;
+               nexti = (i + 1) % MWL8K_TX_DESCS;
+
+               tx_desc->status = 0;
+               tx_desc->next_tx_desc_phys_addr =
+                       cpu_to_le32(txq->tx_desc_dma +
+                                               nexti * sizeof(*tx_desc));
+       }
+
+       return 0;
+}
+
+static inline void mwl8k_tx_start(struct mwl8k_priv *priv)
+{
+       iowrite32(MWL8K_H2A_INT_PPA_READY,
+               priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
+       iowrite32(MWL8K_H2A_INT_DUMMY,
+               priv->regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
+       ioread32(priv->regs + MWL8K_HIU_INT_CODE);
+}
+
+static inline int mwl8k_txq_busy(struct mwl8k_priv *priv)
+{
+       return priv->pending_tx_pkts;
+}
+
+struct mwl8k_txq_info {
+       u32 fw_owned;
+       u32 drv_owned;
+       u32 unused;
+       u32 len;
+       u32 head;
+       u32 tail;
+};
+
+static int mwl8k_scan_tx_ring(struct mwl8k_priv *priv,
+                               struct mwl8k_txq_info txinfo[],
+                               u32 num_queues)
+{
+       int count, desc, status;
+       struct mwl8k_tx_queue *txq;
+       struct mwl8k_tx_desc *tx_desc;
+       int ndescs = 0;
+
+       memset(txinfo, 0, num_queues * sizeof(struct mwl8k_txq_info));
+       spin_lock_bh(&priv->tx_lock);
+       for (count = 0; count < num_queues; count++) {
+               txq = priv->txq + count;
+               txinfo[count].len = txq->tx_stats.len;
+               txinfo[count].head = txq->tx_head;
+               txinfo[count].tail = txq->tx_tail;
+               for (desc = 0; desc < MWL8K_TX_DESCS; desc++) {
+                       tx_desc = txq->tx_desc_area + desc;
+                       status = le32_to_cpu(tx_desc->status);
+
+                       if (status & MWL8K_TXD_STATUS_FW_OWNED)
+                               txinfo[count].fw_owned++;
+                       else
+                               txinfo[count].drv_owned++;
+
+                       if (tx_desc->pkt_len == 0)
+                               txinfo[count].unused++;
+               }
+       }
+       spin_unlock_bh(&priv->tx_lock);
+
+       return ndescs;
+}
+
+static int mwl8k_tx_wait_empty(struct ieee80211_hw *hw, u32 delay_ms)
+{
+       u32 count = 0;
+       unsigned long timeout = 0;
+       struct mwl8k_priv *priv = hw->priv;
+       DECLARE_COMPLETION_ONSTACK(cmd_wait);
+
+       might_sleep();
+
+       if (priv->tx_wait != NULL)
+               printk(KERN_ERR "WARNING Previous TXWaitEmpty instance\n");
+
+       spin_lock_bh(&priv->tx_lock);
+       count = mwl8k_txq_busy(priv);
+       if (count) {
+               priv->tx_wait = &cmd_wait;
+               if (priv->radio_state)
+                       mwl8k_tx_start(priv);
+       }
+       spin_unlock_bh(&priv->tx_lock);
+
+       if (count) {
+               struct mwl8k_txq_info txinfo[4];
+               int index;
+               int newcount;
+
+               timeout = wait_for_completion_timeout(&cmd_wait,
+                                       msecs_to_jiffies(delay_ms));
+               if (timeout)
+                       return 0;
+
+               spin_lock_bh(&priv->tx_lock);
+               priv->tx_wait = NULL;
+               newcount = mwl8k_txq_busy(priv);
+               spin_unlock_bh(&priv->tx_lock);
+
+               printk(KERN_ERR "%s(%u) TIMEDOUT:%ums Pend:%u-->%u\n",
+                      __func__, __LINE__, delay_ms, count, newcount);
+
+               mwl8k_scan_tx_ring(priv, txinfo, 4);
+               for (index = 0 ; index < 4; index++)
+                       printk(KERN_ERR
+                               "TXQ:%u L:%u H:%u T:%u FW:%u DRV:%u U:%u\n",
+                                       index,
+                                       txinfo[index].len,
+                                       txinfo[index].head,
+                                       txinfo[index].tail,
+                                       txinfo[index].fw_owned,
+                                       txinfo[index].drv_owned,
+                                       txinfo[index].unused);
+               return -ETIMEDOUT;
+       }
+
+       return 0;
+}
+
+#define MWL8K_TXD_OK   (MWL8K_TXD_STATUS_OK | \
+                        MWL8K_TXD_STATUS_OK_RETRY | \
+                        MWL8K_TXD_STATUS_OK_MORE_RETRY)
+#define MWL8K_TXD_SUCCESS(stat)                ((stat) & MWL8K_TXD_OK)
+#define MWL8K_TXD_FAIL_RETRY(stat)     \
+       ((stat) & (MWL8K_TXD_STATUS_FAILED_EXCEED_LIMIT))
+
+static void mwl8k_txq_reclaim(struct ieee80211_hw *hw, int index, int force)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_tx_queue *txq = priv->txq + index;
+       int wake = 0;
+
+       while (txq->tx_stats.len > 0) {
+               int tx;
+               int rc;
+               struct mwl8k_tx_desc *tx_desc;
+               unsigned long addr;
+               size_t size;
+               struct sk_buff *skb;
+               struct ieee80211_tx_info *info;
+               u32 status;
+
+               rc = 0;
+               tx = txq->tx_head;
+               tx_desc = txq->tx_desc_area + tx;
+
+               status = le32_to_cpu(tx_desc->status);
+
+               if (status & MWL8K_TXD_STATUS_FW_OWNED) {
+                       if (!force)
+                               break;
+                       tx_desc->status &=
+                               ~cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED);
+               }
+
+               txq->tx_head = (tx + 1) % MWL8K_TX_DESCS;
+               BUG_ON(txq->tx_stats.len == 0);
+               txq->tx_stats.len--;
+               priv->pending_tx_pkts--;
+
+               addr = le32_to_cpu(tx_desc->pkt_phys_addr);
+               size = (u32)(le16_to_cpu(tx_desc->pkt_len));
+               skb = txq->tx_skb[tx].skb;
+               txq->tx_skb[tx].skb = NULL;
+
+               BUG_ON(skb == NULL);
+               pci_unmap_single(priv->pdev, addr, size, PCI_DMA_TODEVICE);
+
+               rc = mwl8k_remove_dma_header(skb);
+
+               /* Mark descriptor as unused */
+               tx_desc->pkt_phys_addr = 0;
+               tx_desc->pkt_len = 0;
+
+               if (txq->tx_skb[tx].clone) {
+                       /* Replace with original skb
+                        * before returning to stack
+                        * as buffer has been cloned
+                        */
+                       dev_kfree_skb(skb);
+                       skb = txq->tx_skb[tx].clone;
+                       txq->tx_skb[tx].clone = NULL;
+               }
+
+               if (rc) {
+                       /* Something has gone wrong here.
+                        * Failed to remove DMA header.
+                        * Print error message and drop packet.
+                        */
+                       printk(KERN_ERR "%s: Error removing DMA header from "
+                                       "tx skb 0x%p.\n", priv->name, skb);
+
+                       dev_kfree_skb(skb);
+                       continue;
+               }
+
+               info = IEEE80211_SKB_CB(skb);
+               ieee80211_tx_info_clear_status(info);
+
+               /* Convert firmware status stuff into tx_status */
+               if (MWL8K_TXD_SUCCESS(status)) {
+                       /* Transmit OK */
+                       info->flags |= IEEE80211_TX_STAT_ACK;
+               }
+
+               ieee80211_tx_status_irqsafe(hw, skb);
+
+               wake = !priv->inconfig && priv->radio_state;
+       }
+
+       if (wake)
+               ieee80211_wake_queue(hw, index);
+}
+
+/* must be called only when the card's transmit is completely halted */
+static void mwl8k_txq_deinit(struct ieee80211_hw *hw, int index)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_tx_queue *txq = priv->txq + index;
+
+       mwl8k_txq_reclaim(hw, index, 1);
+
+       kfree(txq->tx_skb);
+       txq->tx_skb = NULL;
+
+       pci_free_consistent(priv->pdev,
+                           MWL8K_TX_DESCS * sizeof(struct mwl8k_tx_desc),
+                           txq->tx_desc_area, txq->tx_desc_dma);
+       txq->tx_desc_area = NULL;
+}
+
+static int
+mwl8k_txq_xmit(struct ieee80211_hw *hw, int index, struct sk_buff *skb)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       struct ieee80211_tx_info *tx_info;
+       struct ieee80211_hdr *wh;
+       struct mwl8k_tx_queue *txq;
+       struct mwl8k_tx_desc *tx;
+       struct mwl8k_dma_data *tr;
+       struct mwl8k_vif *mwl8k_vif;
+       struct sk_buff *org_skb = skb;
+       dma_addr_t dma;
+       u16 qos = 0;
+       bool qosframe = false, ampduframe = false;
+       bool mcframe = false, eapolframe = false;
+       bool amsduframe = false;
+       __le16 fc;
+
+       txq = priv->txq + index;
+       tx = txq->tx_desc_area + txq->tx_tail;
+
+       BUG_ON(txq->tx_skb[txq->tx_tail].skb != NULL);
+
+       /*
+        * Append HW DMA header to start of packet.  Drop packet if
+        * there is not enough space or a failure to unshare/unclone
+        * the skb.
+        */
+       skb = mwl8k_add_dma_header(skb);
+
+       if (skb == NULL) {
+               printk(KERN_DEBUG "%s: failed to prepend HW DMA "
+                       "header, dropping TX frame.\n", priv->name);
+               dev_kfree_skb(org_skb);
+               return NETDEV_TX_OK;
+       }
+
+       tx_info = IEEE80211_SKB_CB(skb);
+       mwl8k_vif = MWL8K_VIF(tx_info->control.vif);
+       tr = (struct mwl8k_dma_data *)skb->data;
+       wh = &tr->wh;
+       fc = wh->frame_control;
+       qosframe = ieee80211_is_data_qos(fc);
+       mcframe = is_multicast_ether_addr(wh->addr1);
+       ampduframe = !!(tx_info->flags & IEEE80211_TX_CTL_AMPDU);
+
+       if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
+               u16 seqno = mwl8k_vif->seqno;
+               wh->seq_ctrl &= cpu_to_le16(IEEE80211_SCTL_FRAG);
+               wh->seq_ctrl |= cpu_to_le16(seqno << 4);
+               mwl8k_vif->seqno = seqno++ % 4096;
+       }
+
+       if (qosframe)
+               qos = le16_to_cpu(*((__le16 *)ieee80211_get_qos_ctl(wh)));
+
+       dma = pci_map_single(priv->pdev, skb->data,
+                               skb->len, PCI_DMA_TODEVICE);
+
+       if (pci_dma_mapping_error(priv->pdev, dma)) {
+               printk(KERN_DEBUG "%s: failed to dma map skb, "
+                       "dropping TX frame.\n", priv->name);
+
+               if (org_skb != NULL)
+                       dev_kfree_skb(org_skb);
+               if (skb != NULL)
+                       dev_kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       /* Set desc header, cpu bit order.  */
+       tx->status = 0;
+       tx->data_rate = 0;
+       tx->tx_priority = index;
+       tx->qos_control = 0;
+       tx->rate_info = 0;
+       tx->peer_id = mwl8k_vif->peer_id;
+
+       amsduframe = !!(qos & IEEE80211_QOS_CONTROL_A_MSDU_PRESENT);
+
+       /* Setup firmware control bit fields for each frame type.  */
+       if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc)) {
+               tx->data_rate = 0;
+               qos = mwl8k_qos_setbit_eosp(qos);
+               /* Set Queue size to unspecified */
+               qos = mwl8k_qos_setbit_qlen(qos, 0xff);
+       } else if (ieee80211_is_data(fc)) {
+               tx->data_rate = 1;
+               if (mcframe)
+                       tx->status |= MWL8K_TXD_STATUS_MULTICAST_TX;
+
+               /*
+                * Tell firmware to not send EAPOL pkts in an
+                * aggregate.  Verify against mac80211 tx path.  If
+                * stack turns off AMPDU for an EAPOL frame this
+                * check will be removed.
+                */
+               if (eapolframe) {
+                       qos = mwl8k_qos_setbit_ack(qos,
+                               MWL8K_TXD_ACK_POLICY_NORMAL);
+               } else {
+                       /* Send pkt in an aggregate if AMPDU frame.  */
+                       if (ampduframe)
+                               qos = mwl8k_qos_setbit_ack(qos,
+                                       MWL8K_TXD_ACK_POLICY_BLOCKACK);
+                       else
+                               qos = mwl8k_qos_setbit_ack(qos,
+                                       MWL8K_TXD_ACK_POLICY_NORMAL);
+
+                       if (amsduframe)
+                               qos = mwl8k_qos_setbit_amsdu(qos);
+               }
+       }
+
+       /* Convert to little endian */
+       tx->qos_control = cpu_to_le16(qos);
+       tx->status = cpu_to_le32(tx->status);
+       tx->pkt_phys_addr = cpu_to_le32(dma);
+       tx->pkt_len = cpu_to_le16(skb->len);
+
+       txq->tx_skb[txq->tx_tail].skb = skb;
+       txq->tx_skb[txq->tx_tail].clone =
+               skb == org_skb ? NULL : org_skb;
+
+       spin_lock_bh(&priv->tx_lock);
+
+       tx->status = cpu_to_le32(MWL8K_TXD_STATUS_OK |
+                                       MWL8K_TXD_STATUS_FW_OWNED);
+       wmb();
+       txq->tx_stats.len++;
+       priv->pending_tx_pkts++;
+       txq->tx_stats.count++;
+       txq->tx_tail++;
+
+       if (txq->tx_tail == MWL8K_TX_DESCS)
+               txq->tx_tail = 0;
+       if (txq->tx_head == txq->tx_tail)
+               ieee80211_stop_queue(hw, index);
+
+       if (priv->inconfig) {
+               /*
+                * Silently queue packet when we are in the middle of
+                * a config cycle.  Notify firmware only if we are
+                * waiting for TXQs to empty.  If a packet is sent
+                * before .config() is complete, perhaps it is better
+                * to drop the packet, as the channel is being changed
+                * and the packet will end up on the wrong channel.
+                */
+               printk(KERN_ERR "%s(): WARNING TX activity while "
+                       "in config\n", __func__);
+
+               if (priv->tx_wait != NULL)
+                       mwl8k_tx_start(priv);
+       } else
+               mwl8k_tx_start(priv);
+
+       spin_unlock_bh(&priv->tx_lock);
+
+       return NETDEV_TX_OK;
+}
+
+
+/*
+ * Command processing.
+ */
+
+/* Timeout firmware commands after 2000ms */
+#define MWL8K_CMD_TIMEOUT_MS   2000
+
+static int mwl8k_post_cmd(struct ieee80211_hw *hw, struct mwl8k_cmd_pkt *cmd)
+{
+       DECLARE_COMPLETION_ONSTACK(cmd_wait);
+       struct mwl8k_priv *priv = hw->priv;
+       void __iomem *regs = priv->regs;
+       dma_addr_t dma_addr;
+       unsigned int dma_size;
+       int rc;
+       u16 __iomem *result;
+       unsigned long timeout = 0;
+       u8 buf[32];
+
+       cmd->result = 0xFFFF;
+       dma_size = le16_to_cpu(cmd->length);
+       dma_addr = pci_map_single(priv->pdev, cmd, dma_size,
+                                 PCI_DMA_BIDIRECTIONAL);
+       if (pci_dma_mapping_error(priv->pdev, dma_addr))
+               return -ENOMEM;
+
+       if (priv->hostcmd_wait != NULL)
+               printk(KERN_ERR "WARNING host command in progress\n");
+
+       spin_lock_irq(&priv->fw_lock);
+       priv->hostcmd_wait = &cmd_wait;
+       iowrite32(dma_addr, regs + MWL8K_HIU_GEN_PTR);
+       iowrite32(MWL8K_H2A_INT_DOORBELL,
+               regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
+       iowrite32(MWL8K_H2A_INT_DUMMY,
+               regs + MWL8K_HIU_H2A_INTERRUPT_EVENTS);
+       spin_unlock_irq(&priv->fw_lock);
+
+       timeout = wait_for_completion_timeout(&cmd_wait,
+                               msecs_to_jiffies(MWL8K_CMD_TIMEOUT_MS));
+
+       result = &cmd->result;
+       if (!timeout) {
+               spin_lock_irq(&priv->fw_lock);
+               priv->hostcmd_wait = NULL;
+               spin_unlock_irq(&priv->fw_lock);
+               printk(KERN_ERR "%s: Command %s timeout after %u ms\n",
+                      priv->name,
+                      mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
+                      MWL8K_CMD_TIMEOUT_MS);
+               rc = -ETIMEDOUT;
+       } else {
+               rc = *result ? -EINVAL : 0;
+               if (rc)
+                       printk(KERN_ERR "%s: Command %s error 0x%x\n",
+                              priv->name,
+                              mwl8k_cmd_name(cmd->code, buf, sizeof(buf)),
+                              *result);
+       }
+
+       pci_unmap_single(priv->pdev, dma_addr, dma_size,
+                                       PCI_DMA_BIDIRECTIONAL);
+       return rc;
+}
+
+/*
+ * GET_HW_SPEC.
+ */
+struct mwl8k_cmd_get_hw_spec {
+       struct mwl8k_cmd_pkt header;
+       __u8 hw_rev;
+       __u8 host_interface;
+       __le16 num_mcaddrs;
+       __u8 perm_addr[IEEE80211_ADDR_LEN];
+       __le16 region_code;
+       __le32 fw_rev;
+       __le32 ps_cookie;
+       __le32 caps;
+       __u8 mcs_bitmap[16];
+       __le32 rx_queue_ptr;
+       __le32 num_tx_queues;
+       __le32 tx_queue_ptrs[MWL8K_TX_QUEUES];
+       __le32 caps2;
+       __le32 num_tx_desc_per_queue;
+       __le32 total_rx_desc;
+} __attribute__((packed));
+
+static int mwl8k_cmd_get_hw_spec(struct ieee80211_hw *hw)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_cmd_get_hw_spec *cmd;
+       int rc;
+       int i;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_HW_SPEC);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+       memset(cmd->perm_addr, 0xff, sizeof(cmd->perm_addr));
+       cmd->ps_cookie = cpu_to_le32(priv->cookie_dma);
+       cmd->rx_queue_ptr = cpu_to_le32(priv->rxq[0].rx_desc_dma);
+       cmd->num_tx_queues = MWL8K_TX_QUEUES;
+       for (i = 0; i < MWL8K_TX_QUEUES; i++)
+               cmd->tx_queue_ptrs[i] = cpu_to_le32(priv->txq[i].tx_desc_dma);
+       cmd->num_tx_desc_per_queue = MWL8K_TX_DESCS;
+       cmd->total_rx_desc = MWL8K_RX_DESCS;
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+
+       if (!rc) {
+               SET_IEEE80211_PERM_ADDR(hw, cmd->perm_addr);
+               priv->num_mcaddrs = le16_to_cpu(cmd->num_mcaddrs);
+               priv->fw_rev = cmd->fw_rev;
+               priv->hw_rev = cmd->hw_rev;
+               priv->region_code = le16_to_cpu(cmd->region_code);
+       }
+
+       kfree(cmd);
+       return rc;
+}
+
+/*
+ * CMD_MAC_MULTICAST_ADR.
+ */
+struct mwl8k_cmd_mac_multicast_adr {
+       struct mwl8k_cmd_pkt header;
+       __le16 action;
+       __le16 numaddr;
+       __u8 addr[1][IEEE80211_ADDR_LEN];
+};
+
+#define MWL8K_ENABLE_RX_MULTICAST 0x000F
+static int mwl8k_cmd_mac_multicast_adr(struct ieee80211_hw *hw,
+                                       int mc_count,
+                                       struct dev_addr_list *mclist)
+{
+       struct mwl8k_cmd_mac_multicast_adr *cmd;
+       int index = 0;
+       int rc;
+       int size = sizeof(*cmd) + ((mc_count - 1) * IEEE80211_ADDR_LEN);
+       cmd = kzalloc(size, GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_MAC_MULTICAST_ADR);
+       cmd->header.length = cpu_to_le16(size);
+       cmd->action = cpu_to_le16(MWL8K_ENABLE_RX_MULTICAST);
+       cmd->numaddr = cpu_to_le16(mc_count);
+       while ((index < mc_count) && mclist) {
+               if (mclist->da_addrlen != IEEE80211_ADDR_LEN) {
+                       rc = -EINVAL;
+                       goto mwl8k_cmd_mac_multicast_adr_exit;
+               }
+               memcpy(cmd->addr[index], mclist->da_addr, IEEE80211_ADDR_LEN);
+               index++;
+               mclist = mclist->next;
+       }
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+
+mwl8k_cmd_mac_multicast_adr_exit:
+       kfree(cmd);
+       return rc;
+}
+
+/*
+ * CMD_802_11_GET_STAT.
+ */
+struct mwl8k_cmd_802_11_get_stat {
+       struct mwl8k_cmd_pkt header;
+       __le16 action;
+       __le32 stats[64];
+} __attribute__((packed));
+
+#define MWL8K_STAT_ACK_FAILURE 9
+#define MWL8K_STAT_RTS_FAILURE 12
+#define MWL8K_STAT_FCS_ERROR   24
+#define MWL8K_STAT_RTS_SUCCESS 11
+
+static int mwl8k_cmd_802_11_get_stat(struct ieee80211_hw *hw,
+                               struct ieee80211_low_level_stats *stats)
+{
+       struct mwl8k_cmd_802_11_get_stat *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_GET_STAT);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = cpu_to_le16(MWL8K_CMD_GET);
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       if (!rc) {
+               stats->dot11ACKFailureCount =
+                       le32_to_cpu(cmd->stats[MWL8K_STAT_ACK_FAILURE]);
+               stats->dot11RTSFailureCount =
+                       le32_to_cpu(cmd->stats[MWL8K_STAT_RTS_FAILURE]);
+               stats->dot11FCSErrorCount =
+                       le32_to_cpu(cmd->stats[MWL8K_STAT_FCS_ERROR]);
+               stats->dot11RTSSuccessCount =
+                       le32_to_cpu(cmd->stats[MWL8K_STAT_RTS_SUCCESS]);
+       }
+       kfree(cmd);
+
+       return rc;
+}
+
+/*
+ * CMD_802_11_RADIO_CONTROL.
+ */
+struct mwl8k_cmd_802_11_radio_control {
+       struct mwl8k_cmd_pkt header;
+       __le16 action;
+       __le16 control;
+       __le16 radio_on;
+} __attribute__((packed));
+
+static int mwl8k_cmd_802_11_radio_control(struct ieee80211_hw *hw, int enable)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_cmd_802_11_radio_control *cmd;
+       int rc;
+
+       if (((enable & MWL8K_RADIO_ENABLE) == priv->radio_state) &&
+           !(enable & MWL8K_RADIO_FORCE))
+               return 0;
+
+       enable &= MWL8K_RADIO_ENABLE;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_RADIO_CONTROL);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = cpu_to_le16(MWL8K_CMD_SET);
+       cmd->control = cpu_to_le16(priv->radio_preamble);
+       cmd->radio_on = cpu_to_le16(enable ? 0x0001 : 0x0000);
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
+
+       if (!rc)
+               priv->radio_state = enable;
+
+       return rc;
+}
+
+static int
+mwl8k_set_radio_preamble(struct ieee80211_hw *hw, bool short_preamble)
+{
+       struct mwl8k_priv *priv;
+
+       if (hw == NULL || hw->priv == NULL)
+               return -EINVAL;
+       priv = hw->priv;
+
+       priv->radio_preamble = (short_preamble ?
+               MWL8K_RADIO_SHORT_PREAMBLE :
+               MWL8K_RADIO_LONG_PREAMBLE);
+
+       return mwl8k_cmd_802_11_radio_control(hw,
+                       MWL8K_RADIO_ENABLE | MWL8K_RADIO_FORCE);
+}
+
+/*
+ * CMD_802_11_RF_TX_POWER.
+ */
+#define MWL8K_TX_POWER_LEVEL_TOTAL     8
+
+struct mwl8k_cmd_802_11_rf_tx_power {
+       struct mwl8k_cmd_pkt header;
+       __le16 action;
+       __le16 support_level;
+       __le16 current_level;
+       __le16 reserved;
+       __le16 power_level_list[MWL8K_TX_POWER_LEVEL_TOTAL];
+} __attribute__((packed));
+
+static int mwl8k_cmd_802_11_rf_tx_power(struct ieee80211_hw *hw, int dBm)
+{
+       struct mwl8k_cmd_802_11_rf_tx_power *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_RF_TX_POWER);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = cpu_to_le16(MWL8K_CMD_SET);
+       cmd->support_level = cpu_to_le16(dBm);
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+/*
+ * CMD_SET_PRE_SCAN.
+ */
+struct mwl8k_cmd_set_pre_scan {
+       struct mwl8k_cmd_pkt header;
+} __attribute__((packed));
+
+static int mwl8k_cmd_set_pre_scan(struct ieee80211_hw *hw)
+{
+       struct mwl8k_cmd_set_pre_scan *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_PRE_SCAN);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+/*
+ * CMD_SET_POST_SCAN.
+ */
+struct mwl8k_cmd_set_post_scan {
+       struct mwl8k_cmd_pkt header;
+       __le32 isibss;
+       __u8 bssid[IEEE80211_ADDR_LEN];
+} __attribute__((packed));
+
+static int
+mwl8k_cmd_set_post_scan(struct ieee80211_hw *hw, __u8 mac[IEEE80211_ADDR_LEN])
+{
+       struct mwl8k_cmd_set_post_scan *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_POST_SCAN);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->isibss = 0;
+       memcpy(cmd->bssid, mac, IEEE80211_ADDR_LEN);
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+/*
+ * CMD_SET_RF_CHANNEL.
+ */
+struct mwl8k_cmd_set_rf_channel {
+       struct mwl8k_cmd_pkt header;
+       __le16 action;
+       __u8 current_channel;
+       __le32 channel_flags;
+} __attribute__((packed));
+
+static int mwl8k_cmd_set_rf_channel(struct ieee80211_hw *hw,
+                                   struct ieee80211_channel *channel)
+{
+       struct mwl8k_cmd_set_rf_channel *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RF_CHANNEL);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = cpu_to_le16(MWL8K_CMD_SET);
+       cmd->current_channel = channel->hw_value;
+       if (channel->band == IEEE80211_BAND_2GHZ)
+               cmd->channel_flags = cpu_to_le32(0x00000081);
+       else
+               cmd->channel_flags = cpu_to_le32(0x00000000);
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+/*
+ * CMD_SET_SLOT.
+ */
+struct mwl8k_cmd_set_slot {
+       struct mwl8k_cmd_pkt header;
+       __le16 action;
+       __u8 short_slot;
+} __attribute__((packed));
+
+static int mwl8k_cmd_set_slot(struct ieee80211_hw *hw, int slot_time)
+{
+       struct mwl8k_cmd_set_slot *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_SLOT);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = cpu_to_le16(MWL8K_CMD_SET);
+       cmd->short_slot = slot_time == MWL8K_SHORT_SLOTTIME ? 1 : 0;
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+/*
+ * CMD_MIMO_CONFIG.
+ */
+struct mwl8k_cmd_mimo_config {
+       struct mwl8k_cmd_pkt header;
+       __le32 action;
+       __u8 rx_antenna_map;
+       __u8 tx_antenna_map;
+} __attribute__((packed));
+
+static int mwl8k_cmd_mimo_config(struct ieee80211_hw *hw, __u8 rx, __u8 tx)
+{
+       struct mwl8k_cmd_mimo_config *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_MIMO_CONFIG);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = cpu_to_le32((u32)MWL8K_CMD_SET);
+       cmd->rx_antenna_map = rx;
+       cmd->tx_antenna_map = tx;
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+/*
+ * CMD_ENABLE_SNIFFER.
+ */
+struct mwl8k_cmd_enable_sniffer {
+       struct mwl8k_cmd_pkt header;
+       __le32 action;
+} __attribute__((packed));
+
+static int mwl8k_enable_sniffer(struct ieee80211_hw *hw, bool enable)
+{
+       struct mwl8k_cmd_enable_sniffer *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_ENABLE_SNIFFER);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = enable ? cpu_to_le32((u32)MWL8K_CMD_SET) : 0;
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+/*
+ * CMD_SET_RATE_ADAPT_MODE.
+ */
+struct mwl8k_cmd_set_rate_adapt_mode {
+       struct mwl8k_cmd_pkt header;
+       __le16 action;
+       __le16 mode;
+} __attribute__((packed));
+
+static int mwl8k_cmd_setrateadaptmode(struct ieee80211_hw *hw, __u16 mode)
+{
+       struct mwl8k_cmd_set_rate_adapt_mode *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATEADAPT_MODE);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = cpu_to_le16(MWL8K_CMD_SET);
+       cmd->mode = cpu_to_le16(mode);
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+/*
+ * CMD_SET_WMM_MODE.
+ */
+struct mwl8k_cmd_set_wmm {
+       struct mwl8k_cmd_pkt header;
+       __le16 action;
+} __attribute__((packed));
+
+static int mwl8k_set_wmm(struct ieee80211_hw *hw, bool enable)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_cmd_set_wmm *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_WMM_MODE);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = enable ? cpu_to_le16(MWL8K_CMD_SET) : 0;
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
+
+       if (!rc)
+               priv->wmm_mode = enable;
+
+       return rc;
+}
+
+/*
+ * CMD_SET_RTS_THRESHOLD.
+ */
+struct mwl8k_cmd_rts_threshold {
+       struct mwl8k_cmd_pkt header;
+       __le16 action;
+       __le16 threshold;
+} __attribute__((packed));
+
+static int mwl8k_rts_threshold(struct ieee80211_hw *hw,
+                              u16 action, u16 *threshold)
+{
+       struct mwl8k_cmd_rts_threshold *cmd;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_RTS_THRESHOLD);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->action = cpu_to_le16(action);
+       cmd->threshold = cpu_to_le16(*threshold);
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+/*
+ * CMD_SET_EDCA_PARAMS.
+ */
+struct mwl8k_cmd_set_edca_params {
+       struct mwl8k_cmd_pkt header;
+
+       /* See MWL8K_SET_EDCA_XXX below */
+       __le16 action;
+
+       /* TX opportunity in units of 32 us */
+       __le16 txop;
+
+       /* Log exponent of max contention period: 0...15*/
+       __u8 log_cw_max;
+
+       /* Log exponent of min contention period: 0...15 */
+       __u8 log_cw_min;
+
+       /* Adaptive interframe spacing in units of 32us */
+       __u8 aifs;
+
+       /* TX queue to configure */
+       __u8 txq;
+} __attribute__((packed));
+
+#define MWL8K_GET_EDCA_ALL     0
+#define MWL8K_SET_EDCA_CW      0x01
+#define MWL8K_SET_EDCA_TXOP    0x02
+#define MWL8K_SET_EDCA_AIFS    0x04
+
+#define MWL8K_SET_EDCA_ALL     (MWL8K_SET_EDCA_CW | \
+                                MWL8K_SET_EDCA_TXOP | \
+                                MWL8K_SET_EDCA_AIFS)
+
+static int
+mwl8k_set_edca_params(struct ieee80211_hw *hw, __u8 qnum,
+               __u16 cw_min, __u16 cw_max,
+               __u8 aifs, __u16 txop)
+{
+       struct mwl8k_cmd_set_edca_params *cmd;
+       u32 log_cw_min, log_cw_max;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       log_cw_min = ilog2(cw_min+1);
+       log_cw_max = ilog2(cw_max+1);
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_EDCA_PARAMS);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+       cmd->action = cpu_to_le16(MWL8K_SET_EDCA_ALL);
+       cmd->txop = cpu_to_le16(txop);
+       cmd->log_cw_max = (u8)log_cw_max;
+       cmd->log_cw_min = (u8)log_cw_min;
+       cmd->aifs = aifs;
+       cmd->txq = qnum;
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+/*
+ * CMD_FINALIZE_JOIN.
+ */
+
+/* FJ beacon buffer size is compiled into the firmware.  */
+#define MWL8K_FJ_BEACON_MAXLEN 128
+
+struct mwl8k_cmd_finalize_join {
+       struct mwl8k_cmd_pkt header;
+       __le32 sleep_interval;  /* Number of beacon periods to sleep */
+       __u8 beacon_data[MWL8K_FJ_BEACON_MAXLEN];
+} __attribute__((packed));
+
+static int mwl8k_finalize_join(struct ieee80211_hw *hw, void *frame,
+                               __u16 framelen, __u16 dtim)
+{
+       struct mwl8k_cmd_finalize_join *cmd;
+       struct ieee80211_mgmt *payload = frame;
+       u16 hdrlen;
+       u32 payload_len;
+       int rc;
+
+       if (frame == NULL)
+               return -EINVAL;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_FINALIZE_JOIN);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+       if (dtim)
+               cmd->sleep_interval = cpu_to_le32(dtim);
+       else
+               cmd->sleep_interval = cpu_to_le32(1);
+
+       hdrlen = ieee80211_hdrlen(payload->frame_control);
+
+       payload_len = framelen > hdrlen ? framelen - hdrlen : 0;
+
+       /* XXX TBD Might just have to abort and return an error */
+       if (payload_len > MWL8K_FJ_BEACON_MAXLEN)
+               printk(KERN_ERR "%s(): WARNING: Incomplete beacon "
+                       "sent to firmware. Sz=%u MAX=%u\n", __func__,
+                       payload_len, MWL8K_FJ_BEACON_MAXLEN);
+
+       payload_len = payload_len > MWL8K_FJ_BEACON_MAXLEN ?
+                               MWL8K_FJ_BEACON_MAXLEN : payload_len;
+
+       if (payload && payload_len)
+               memcpy(cmd->beacon_data, &payload->u.beacon, payload_len);
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
+       return rc;
+}
+
+/*
+ * CMD_UPDATE_STADB.
+ */
+struct mwl8k_cmd_update_sta_db {
+       struct mwl8k_cmd_pkt header;
+
+       /* See STADB_ACTION_TYPE */
+       __le32  action;
+
+       /* Peer MAC address */
+       __u8    peer_addr[IEEE80211_ADDR_LEN];
+
+       __le32  reserved;
+
+       /* Peer info - valid during add/update.  */
+       struct peer_capability_info     peer_info;
+} __attribute__((packed));
+
+static int mwl8k_cmd_update_sta_db(struct ieee80211_hw *hw,
+               struct ieee80211_vif *vif, __u32 action)
+{
+       struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
+       struct ieee80211_bss_conf *info = &mv_vif->bss_info;
+       struct mwl8k_cmd_update_sta_db *cmd;
+       struct peer_capability_info *peer_info;
+       struct ieee80211_rate *bitrates = mv_vif->legacy_rates;
+       DECLARE_MAC_BUF(mac);
+       int rc;
+       __u8 count, *rates;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_UPDATE_STADB);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+       cmd->action = cpu_to_le32(action);
+       peer_info = &cmd->peer_info;
+       memcpy(cmd->peer_addr, mv_vif->bssid, IEEE80211_ADDR_LEN);
+
+       switch (action) {
+       case MWL8K_STA_DB_ADD_ENTRY:
+       case MWL8K_STA_DB_MODIFY_ENTRY:
+               /* Build peer_info block */
+               peer_info->peer_type = MWL8K_PEER_TYPE_ACCESSPOINT;
+               peer_info->basic_caps = cpu_to_le16(info->assoc_capability);
+               peer_info->interop = 1;
+               peer_info->amsdu_enabled = 0;
+
+               rates = peer_info->legacy_rates;
+               for (count = 0 ; count < mv_vif->legacy_nrates; count++)
+                       rates[count] = bitrates[count].hw_value;
+
+               rc = mwl8k_post_cmd(hw, &cmd->header);
+               if (rc == 0)
+                       mv_vif->peer_id = peer_info->station_id;
+
+               break;
+
+       case MWL8K_STA_DB_DEL_ENTRY:
+       case MWL8K_STA_DB_FLUSH:
+       default:
+               rc = mwl8k_post_cmd(hw, &cmd->header);
+               if (rc == 0)
+                       mv_vif->peer_id = 0;
+               break;
+       }
+       kfree(cmd);
+
+       return rc;
+}
+
+/*
+ * CMD_SET_AID.
+ */
+#define IEEE80211_OPMODE_DISABLED                      0x00
+#define IEEE80211_OPMODE_NON_MEMBER_PROT_MODE          0x01
+#define IEEE80211_OPMODE_ONE_20MHZ_STA_PROT_MODE       0x02
+#define IEEE80211_OPMODE_HTMIXED_PROT_MODE             0x03
+
+#define MWL8K_RATE_INDEX_MAX_ARRAY                     14
+
+#define MWL8K_FRAME_PROT_DISABLED                      0x00
+#define MWL8K_FRAME_PROT_11G                           0x07
+#define MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY             0x02
+#define MWL8K_FRAME_PROT_11N_HT_ALL                    0x06
+#define MWL8K_FRAME_PROT_MASK                          0x07
+
+struct mwl8k_cmd_update_set_aid {
+       struct  mwl8k_cmd_pkt header;
+       __le16  aid;
+
+        /* AP's MAC address (BSSID) */
+       __u8    bssid[IEEE80211_ADDR_LEN];
+       __le16  protection_mode;
+       __u8    supp_rates[MWL8K_RATE_INDEX_MAX_ARRAY];
+} __attribute__((packed));
+
+static int mwl8k_cmd_set_aid(struct ieee80211_hw *hw,
+                                       struct ieee80211_vif *vif)
+{
+       struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
+       struct ieee80211_bss_conf *info = &mv_vif->bss_info;
+       struct mwl8k_cmd_update_set_aid *cmd;
+       struct ieee80211_rate *bitrates = mv_vif->legacy_rates;
+       int count;
+       u16 prot_mode;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_AID);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+       cmd->aid = cpu_to_le16(info->aid);
+
+       memcpy(cmd->bssid, mv_vif->bssid, IEEE80211_ADDR_LEN);
+
+       prot_mode = MWL8K_FRAME_PROT_DISABLED;
+
+       if (info->use_cts_prot) {
+               prot_mode = MWL8K_FRAME_PROT_11G;
+       } else {
+               switch (info->ht.operation_mode &
+                       IEEE80211_HT_OP_MODE_PROTECTION) {
+               case IEEE80211_HT_OP_MODE_PROTECTION_20MHZ:
+                       prot_mode = MWL8K_FRAME_PROT_11N_HT_40MHZ_ONLY;
+                       break;
+               case IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED:
+                       prot_mode = MWL8K_FRAME_PROT_11N_HT_ALL;
+                       break;
+               default:
+                       prot_mode = MWL8K_FRAME_PROT_DISABLED;
+                       break;
+               }
+       }
+
+       cmd->protection_mode = cpu_to_le16(prot_mode);
+
+       for (count = 0; count < mv_vif->legacy_nrates; count++)
+               cmd->supp_rates[count] = bitrates[count].hw_value;
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+/*
+ * CMD_SET_RATE.
+ */
+struct mwl8k_cmd_update_rateset {
+       struct  mwl8k_cmd_pkt header;
+       __u8    legacy_rates[MWL8K_RATE_INDEX_MAX_ARRAY];
+
+       /* Bitmap for supported MCS codes.  */
+       __u8    mcs_set[MWL8K_IEEE_LEGACY_DATA_RATES];
+       __u8    reserved[MWL8K_IEEE_LEGACY_DATA_RATES];
+} __attribute__((packed));
+
+static int mwl8k_update_rateset(struct ieee80211_hw *hw,
+               struct ieee80211_vif *vif)
+{
+       struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
+       struct mwl8k_cmd_update_rateset *cmd;
+       struct ieee80211_rate *bitrates = mv_vif->legacy_rates;
+       int count;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_SET_RATE);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+       for (count = 0; count < mv_vif->legacy_nrates; count++)
+               cmd->legacy_rates[count] = bitrates[count].hw_value;
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+/*
+ * CMD_USE_FIXED_RATE.
+ */
+#define MWL8K_RATE_TABLE_SIZE  8
+#define MWL8K_UCAST_RATE       0
+#define MWL8K_MCAST_RATE       1
+#define MWL8K_BCAST_RATE       2
+
+#define MWL8K_USE_FIXED_RATE   0x0001
+#define MWL8K_USE_AUTO_RATE    0x0002
+
+struct mwl8k_rate_entry {
+       /* Set to 1 if HT rate, 0 if legacy.  */
+       __le32  is_ht_rate;
+
+       /* Set to 1 to use retry_count field.  */
+       __le32  enable_retry;
+
+       /* Specified legacy rate or MCS.  */
+       __le32  rate;
+
+       /* Number of allowed retries.  */
+       __le32  retry_count;
+} __attribute__((packed));
+
+struct mwl8k_rate_table {
+       /* 1 to allow specified rate and below */
+       __le32  allow_rate_drop;
+       __le32  num_rates;
+       struct mwl8k_rate_entry rate_entry[MWL8K_RATE_TABLE_SIZE];
+} __attribute__((packed));
+
+struct mwl8k_cmd_use_fixed_rate {
+       struct  mwl8k_cmd_pkt header;
+       __le32  action;
+       struct mwl8k_rate_table rate_table;
+
+       /* Unicast, Broadcast or Multicast */
+       __le32  rate_type;
+       __le32  reserved1;
+       __le32  reserved2;
+} __attribute__((packed));
+
+static int mwl8k_cmd_use_fixed_rate(struct ieee80211_hw *hw,
+       u32 action, u32 rate_type, struct mwl8k_rate_table *rate_table)
+{
+       struct mwl8k_cmd_use_fixed_rate *cmd;
+       int count;
+       int rc;
+
+       cmd = kzalloc(sizeof(*cmd), GFP_KERNEL);
+       if (cmd == NULL)
+               return -ENOMEM;
+
+       cmd->header.code = cpu_to_le16(MWL8K_CMD_USE_FIXED_RATE);
+       cmd->header.length = cpu_to_le16(sizeof(*cmd));
+
+       cmd->action = cpu_to_le32(action);
+       cmd->rate_type = cpu_to_le32(rate_type);
+
+       if (rate_table != NULL) {
+               /* Copy over each field manually so
+               * that bitflipping can be done
+               */
+               cmd->rate_table.allow_rate_drop =
+                               cpu_to_le32(rate_table->allow_rate_drop);
+               cmd->rate_table.num_rates =
+                               cpu_to_le32(rate_table->num_rates);
+
+               for (count = 0; count < rate_table->num_rates; count++) {
+                       struct mwl8k_rate_entry *dst =
+                               &cmd->rate_table.rate_entry[count];
+                       struct mwl8k_rate_entry *src =
+                               &rate_table->rate_entry[count];
+
+                       dst->is_ht_rate = cpu_to_le32(src->is_ht_rate);
+                       dst->enable_retry = cpu_to_le32(src->enable_retry);
+                       dst->rate = cpu_to_le32(src->rate);
+                       dst->retry_count = cpu_to_le32(src->retry_count);
+               }
+       }
+
+       rc = mwl8k_post_cmd(hw, &cmd->header);
+       kfree(cmd);
+
+       return rc;
+}
+
+
+/*
+ * Interrupt handling.
+ */
+static irqreturn_t mwl8k_interrupt(int irq, void *dev_id)
+{
+       struct ieee80211_hw *hw = dev_id;
+       struct mwl8k_priv *priv = hw->priv;
+       u32 status;
+
+       status = ioread32(priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
+       iowrite32(~status, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
+
+       status &= priv->int_mask;
+       if (!status)
+               return IRQ_NONE;
+
+       if (status & MWL8K_A2H_INT_TX_DONE)
+               tasklet_schedule(&priv->tx_reclaim_task);
+
+       if (status & MWL8K_A2H_INT_RX_READY) {
+               while (rxq_process(hw, 0, 1))
+                       rxq_refill(hw, 0, 1);
+       }
+
+       if (status & MWL8K_A2H_INT_OPC_DONE) {
+               if (priv->hostcmd_wait != NULL) {
+                       complete(priv->hostcmd_wait);
+                       priv->hostcmd_wait = NULL;
+               }
+       }
+
+       if (status & MWL8K_A2H_INT_QUEUE_EMPTY) {
+               if (!priv->inconfig &&
+                       priv->radio_state &&
+                       mwl8k_txq_busy(priv))
+                               mwl8k_tx_start(priv);
+       }
+
+       return IRQ_HANDLED;
+}
+
+
+/*
+ * Core driver operations.
+ */
+static int mwl8k_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       int index = skb_get_queue_mapping(skb);
+       int rc;
+
+       if (priv->current_channel == NULL) {
+               printk(KERN_DEBUG "%s: dropped TX frame since radio "
+                      "disabled\n", priv->name);
+               dev_kfree_skb(skb);
+               return NETDEV_TX_OK;
+       }
+
+       rc = mwl8k_txq_xmit(hw, index, skb);
+
+       return rc;
+}
+
+struct mwl8k_work_struct {
+       /* Initialized by mwl8k_queue_work().  */
+       struct work_struct wt;
+
+       /* Required field passed in to mwl8k_queue_work().  */
+       struct ieee80211_hw *hw;
+
+       /* Required field passed in to mwl8k_queue_work().  */
+       int (*wfunc)(struct work_struct *w);
+
+       /* Initialized by mwl8k_queue_work().  */
+       struct completion *cmd_wait;
+
+       /* Result code.  */
+       int rc;
+
+       /*
+        * Optional field. Refer to explanation of MWL8K_WQ_XXX_XXX
+        * flags for explanation.  Defaults to MWL8K_WQ_DEFAULT_OPTIONS.
+        */
+       u32 options;
+
+       /* Optional field.  Defaults to MWL8K_CONFIG_TIMEOUT_MS.  */
+       unsigned long timeout_ms;
+
+       /* Optional field.  Defaults to MWL8K_WQ_TXWAIT_ATTEMPTS.  */
+       u32 txwait_attempts;
+
+       /* Optional field.  Defaults to MWL8K_TXWAIT_MS.  */
+       u32 tx_timeout_ms;
+       u32 step;
+};
+
+/* Flags controlling behavior of config queue requests */
+
+/* Caller spins while waiting for completion.  */
+#define MWL8K_WQ_SPIN                  0x00000001
+
+/* Wait for TX queues to empty before proceeding with configuration.  */
+#define MWL8K_WQ_TX_WAIT_EMPTY         0x00000002
+
+/* Queue request and return immediately.  */
+#define MWL8K_WQ_POST_REQUEST          0x00000004
+
+/*
+ * Caller sleeps and waits for task complete notification.
+ * Do not use in atomic context.
+ */
+#define MWL8K_WQ_SLEEP                 0x00000008
+
+/* Free work struct when task is done.  */
+#define MWL8K_WQ_FREE_WORKSTRUCT       0x00000010
+
+/*
+ * Config request is queued and returns to caller imediately.  Use
+ * this in atomic context. Work struct is freed by mwl8k_queue_work()
+ * when this flag is set.
+ */
+#define MWL8K_WQ_QUEUE_ONLY    (MWL8K_WQ_POST_REQUEST | \
+                                MWL8K_WQ_FREE_WORKSTRUCT)
+
+/* Default work queue behavior is to sleep and wait for tx completion.  */
+#define MWL8K_WQ_DEFAULT_OPTIONS (MWL8K_WQ_SLEEP | MWL8K_WQ_TX_WAIT_EMPTY)
+
+/*
+ * Default config request timeout.  Add adjustments to make sure the
+ * config thread waits long enough for both tx wait and cmd wait before
+ * timing out.
+ */
+
+/* Time to wait for all TXQs to drain.  TX Doorbell is pressed each time.  */
+#define MWL8K_TXWAIT_TIMEOUT_MS                1000
+
+/* Default number of TX wait attempts.  */
+#define MWL8K_WQ_TXWAIT_ATTEMPTS       4
+
+/* Total time to wait for TXQ to drain.  */
+#define MWL8K_TXWAIT_MS                        (MWL8K_TXWAIT_TIMEOUT_MS * \
+                                               MWL8K_WQ_TXWAIT_ATTEMPTS)
+
+/* Scheduling slop.  */
+#define MWL8K_OS_SCHEDULE_OVERHEAD_MS  200
+
+#define MWL8K_CONFIG_TIMEOUT_MS        (MWL8K_CMD_TIMEOUT_MS + \
+                                MWL8K_TXWAIT_MS + \
+                                MWL8K_OS_SCHEDULE_OVERHEAD_MS)
+
+static void mwl8k_config_thread(struct work_struct *wt)
+{
+       struct mwl8k_work_struct *worker = (struct mwl8k_work_struct *)wt;
+       struct ieee80211_hw *hw = worker->hw;
+       struct mwl8k_priv *priv = hw->priv;
+       int rc = 0;
+
+       spin_lock_irq(&priv->tx_lock);
+       priv->inconfig = true;
+       spin_unlock_irq(&priv->tx_lock);
+
+       ieee80211_stop_queues(hw);
+
+       /*
+        * Wait for host queues to drain before doing PHY
+        * reconfiguration. This avoids interrupting any in-flight
+        * DMA transfers to the hardware.
+        */
+       if (worker->options & MWL8K_WQ_TX_WAIT_EMPTY) {
+               u32 timeout;
+               u32 time_remaining;
+               u32 iter;
+               u32 tx_wait_attempts = worker->txwait_attempts;
+
+               time_remaining = worker->tx_timeout_ms;
+               if (!tx_wait_attempts)
+                       tx_wait_attempts = 1;
+
+               timeout = worker->tx_timeout_ms/tx_wait_attempts;
+               if (!timeout)
+                       timeout = 1;
+
+               iter = tx_wait_attempts;
+               do {
+                       int wait_time;
+
+                       if (time_remaining > timeout) {
+                               time_remaining -= timeout;
+                               wait_time = timeout;
+                       } else
+                               wait_time = time_remaining;
+
+                       if (!wait_time)
+                               wait_time = 1;
+
+                       rc = mwl8k_tx_wait_empty(hw, wait_time);
+                       if (rc)
+                               printk(KERN_ERR "%s() txwait timeout=%ums "
+                                       "Retry:%u/%u\n", __func__, timeout,
+                                       tx_wait_attempts - iter + 1,
+                                       tx_wait_attempts);
+
+               } while (rc && --iter);
+
+               rc = iter ? 0 : -ETIMEDOUT;
+       }
+       if (!rc)
+               rc = worker->wfunc(wt);
+
+       spin_lock_irq(&priv->tx_lock);
+       priv->inconfig = false;
+       if (priv->pending_tx_pkts && priv->radio_state)
+               mwl8k_tx_start(priv);
+       spin_unlock_irq(&priv->tx_lock);
+       ieee80211_wake_queues(hw);
+
+       worker->rc = rc;
+       if (worker->options & MWL8K_WQ_SLEEP)
+               complete(worker->cmd_wait);
+
+       if (worker->options & MWL8K_WQ_FREE_WORKSTRUCT)
+               kfree(wt);
+}
+
+static int mwl8k_queue_work(struct ieee80211_hw *hw,
+                               struct mwl8k_work_struct *worker,
+                               struct workqueue_struct *wqueue,
+                               int (*wfunc)(struct work_struct *w))
+{
+       unsigned long timeout = 0;
+       int rc = 0;
+
+       DECLARE_COMPLETION_ONSTACK(cmd_wait);
+
+       if (!worker->timeout_ms)
+               worker->timeout_ms = MWL8K_CONFIG_TIMEOUT_MS;
+
+       if (!worker->options)
+               worker->options = MWL8K_WQ_DEFAULT_OPTIONS;
+
+       if (!worker->txwait_attempts)
+               worker->txwait_attempts = MWL8K_WQ_TXWAIT_ATTEMPTS;
+
+       if (!worker->tx_timeout_ms)
+               worker->tx_timeout_ms = MWL8K_TXWAIT_MS;
+
+       worker->hw = hw;
+       worker->cmd_wait = &cmd_wait;
+       worker->rc = 1;
+       worker->wfunc = wfunc;
+
+       INIT_WORK(&worker->wt, mwl8k_config_thread);
+       queue_work(wqueue, &worker->wt);
+
+       if (worker->options & MWL8K_WQ_POST_REQUEST) {
+               rc = 0;
+       } else {
+               if (worker->options & MWL8K_WQ_SPIN) {
+                       timeout = worker->timeout_ms;
+                       while (timeout && (worker->rc > 0)) {
+                               mdelay(1);
+                               timeout--;
+                       }
+               } else if (worker->options & MWL8K_WQ_SLEEP)
+                       timeout = wait_for_completion_timeout(&cmd_wait,
+                               msecs_to_jiffies(worker->timeout_ms));
+
+               if (timeout)
+                       rc = worker->rc;
+               else {
+                       cancel_work_sync(&worker->wt);
+                       rc = -ETIMEDOUT;
+               }
+       }
+
+       return rc;
+}
+
+struct mwl8k_start_worker {
+       struct mwl8k_work_struct header;
+};
+
+static int mwl8k_start_wt(struct work_struct *wt)
+{
+       struct mwl8k_start_worker *worker = (struct mwl8k_start_worker *)wt;
+       struct ieee80211_hw *hw = worker->header.hw;
+       struct mwl8k_priv *priv = hw->priv;
+       int rc = 0;
+
+       if (priv->vif != NULL) {
+               rc = -EIO;
+               goto mwl8k_start_exit;
+       }
+
+       /* Turn on radio */
+       if (mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_ENABLE)) {
+               rc = -EIO;
+               goto mwl8k_start_exit;
+       }
+
+       /* Purge TX/RX HW queues */
+       if (mwl8k_cmd_set_pre_scan(hw)) {
+               rc = -EIO;
+               goto mwl8k_start_exit;
+       }
+
+       if (mwl8k_cmd_set_post_scan(hw, "\x00\x00\x00\x00\x00\x00")) {
+               rc = -EIO;
+               goto mwl8k_start_exit;
+       }
+
+       /* Enable firmware rate adaptation */
+       if (mwl8k_cmd_setrateadaptmode(hw, 0)) {
+               rc = -EIO;
+               goto mwl8k_start_exit;
+       }
+
+       /* Disable WMM. WMM gets enabled when stack sends WMM parms */
+       if (mwl8k_set_wmm(hw, MWL8K_WMM_DISABLE)) {
+               rc = -EIO;
+               goto mwl8k_start_exit;
+       }
+
+       /* Disable sniffer mode */
+       if (mwl8k_enable_sniffer(hw, 0))
+               rc = -EIO;
+
+mwl8k_start_exit:
+       return rc;
+}
+
+static int mwl8k_start(struct ieee80211_hw *hw)
+{
+       struct mwl8k_start_worker *worker;
+       struct mwl8k_priv *priv = hw->priv;
+       int rc;
+
+       /* Enable tx reclaim tasklet */
+       tasklet_enable(&priv->tx_reclaim_task);
+
+       rc = request_irq(priv->pdev->irq, &mwl8k_interrupt,
+                        IRQF_SHARED, MWL8K_NAME, hw);
+       if (rc) {
+               printk(KERN_ERR "%s: failed to register IRQ handler\n",
+                      priv->name);
+               rc = -EIO;
+               goto mwl8k_start_disable_tasklet;
+       }
+
+       /* Enable interrupts */
+       iowrite32(priv->int_mask, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
+
+       worker = kzalloc(sizeof(*worker), GFP_KERNEL);
+       if (worker == NULL) {
+               rc = -ENOMEM;
+               goto mwl8k_start_disable_irq;
+       }
+
+       rc = mwl8k_queue_work(hw, &worker->header,
+                             priv->config_wq, mwl8k_start_wt);
+       kfree(worker);
+       if (!rc)
+               return rc;
+
+       if (rc == -ETIMEDOUT)
+               printk(KERN_ERR "%s() timed out\n", __func__);
+
+       rc = -EIO;
+
+mwl8k_start_disable_irq:
+       spin_lock_irq(&priv->tx_lock);
+       iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
+       spin_unlock_irq(&priv->tx_lock);
+       free_irq(priv->pdev->irq, hw);
+
+mwl8k_start_disable_tasklet:
+       tasklet_disable(&priv->tx_reclaim_task);
+
+       return rc;
+}
+
+struct mwl8k_stop_worker {
+       struct mwl8k_work_struct header;
+};
+
+static int mwl8k_stop_wt(struct work_struct *wt)
+{
+       struct mwl8k_stop_worker *worker = (struct mwl8k_stop_worker *)wt;
+       struct ieee80211_hw *hw = worker->header.hw;
+       int rc;
+
+       rc = mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_DISABLE);
+
+       return rc;
+}
+
+static void mwl8k_stop(struct ieee80211_hw *hw)
+{
+       int rc;
+       struct mwl8k_stop_worker *worker;
+       struct mwl8k_priv *priv = hw->priv;
+       int i;
+
+       if (priv->vif != NULL)
+               return;
+
+       ieee80211_stop_queues(hw);
+
+       worker = kzalloc(sizeof(*worker), GFP_KERNEL);
+       if (worker == NULL)
+               return;
+
+       rc = mwl8k_queue_work(hw, &worker->header,
+                             priv->config_wq, mwl8k_stop_wt);
+       kfree(worker);
+       if (rc == -ETIMEDOUT)
+               printk(KERN_ERR "%s() timed out\n", __func__);
+
+       /* Disable interrupts */
+       spin_lock_irq(&priv->tx_lock);
+       iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
+       spin_unlock_irq(&priv->tx_lock);
+       free_irq(priv->pdev->irq, hw);
+
+       /* Stop finalize join worker */
+       cancel_work_sync(&priv->finalize_join_worker);
+       if (priv->beacon_skb != NULL)
+               dev_kfree_skb(priv->beacon_skb);
+
+       /* Stop tx reclaim tasklet */
+       tasklet_disable(&priv->tx_reclaim_task);
+
+       /* Stop config thread */
+       flush_workqueue(priv->config_wq);
+
+       /* Return all skbs to mac80211 */
+       for (i = 0; i < MWL8K_TX_QUEUES; i++)
+               mwl8k_txq_reclaim(hw, i, 1);
+}
+
+static int mwl8k_add_interface(struct ieee80211_hw *hw,
+                               struct ieee80211_if_init_conf *conf)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_vif *mwl8k_vif;
+
+       /*
+        * We only support one active interface at a time.
+        */
+       if (priv->vif != NULL)
+               return -EBUSY;
+
+       /*
+        * We only support managed interfaces for now.
+        */
+       if (conf->type != NL80211_IFTYPE_STATION &&
+           conf->type != NL80211_IFTYPE_MONITOR)
+               return -EINVAL;
+
+       /* Clean out driver private area */
+       mwl8k_vif = MWL8K_VIF(conf->vif);
+       memset(mwl8k_vif, 0, sizeof(*mwl8k_vif));
+
+       /* Save the mac address */
+       memcpy(mwl8k_vif->mac_addr, conf->mac_addr, IEEE80211_ADDR_LEN);
+
+       /* Back pointer to parent config block */
+       mwl8k_vif->priv = priv;
+
+       /* Setup initial PHY parameters */
+       memcpy(mwl8k_vif->legacy_rates ,
+               priv->rates, sizeof(mwl8k_vif->legacy_rates));
+       mwl8k_vif->legacy_nrates = ARRAY_SIZE(priv->rates);
+
+       /* Set Initial sequence number to zero */
+       mwl8k_vif->seqno = 0;
+
+       priv->vif = conf->vif;
+       priv->current_channel = NULL;
+
+       return 0;
+}
+
+static void mwl8k_remove_interface(struct ieee80211_hw *hw,
+                                  struct ieee80211_if_init_conf *conf)
+{
+       struct mwl8k_priv *priv = hw->priv;
+
+       if (priv->vif == NULL)
+               return;
+
+       priv->vif = NULL;
+}
+
+struct mwl8k_config_worker {
+       struct mwl8k_work_struct header;
+       u32 changed;
+};
+
+static int mwl8k_config_wt(struct work_struct *wt)
+{
+       struct mwl8k_config_worker *worker =
+               (struct mwl8k_config_worker *)wt;
+       struct ieee80211_hw *hw = worker->header.hw;
+       struct ieee80211_conf *conf = &hw->conf;
+       struct mwl8k_priv *priv = hw->priv;
+       int rc = 0;
+
+       if (!conf->radio_enabled) {
+               mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_DISABLE);
+               priv->current_channel = NULL;
+               rc = 0;
+               goto mwl8k_config_exit;
+       }
+
+       if (mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_ENABLE)) {
+               rc = -EINVAL;
+               goto mwl8k_config_exit;
+       }
+
+       priv->current_channel = conf->channel;
+
+       if (mwl8k_cmd_set_rf_channel(hw, conf->channel)) {
+               rc = -EINVAL;
+               goto mwl8k_config_exit;
+       }
+
+       if (conf->power_level > 18)
+               conf->power_level = 18;
+       if (mwl8k_cmd_802_11_rf_tx_power(hw, conf->power_level)) {
+               rc = -EINVAL;
+               goto mwl8k_config_exit;
+       }
+
+       if (mwl8k_cmd_mimo_config(hw, 0x7, 0x7))
+               rc = -EINVAL;
+
+mwl8k_config_exit:
+       return rc;
+}
+
+static int mwl8k_config(struct ieee80211_hw *hw, u32 changed)
+{
+       int rc = 0;
+       struct mwl8k_config_worker *worker;
+       struct mwl8k_priv *priv = hw->priv;
+
+       worker = kzalloc(sizeof(*worker), GFP_KERNEL);
+       if (worker == NULL)
+               return -ENOMEM;
+
+       worker->changed = changed;
+       rc = mwl8k_queue_work(hw, &worker->header,
+                             priv->config_wq, mwl8k_config_wt);
+       if (rc == -ETIMEDOUT) {
+               printk(KERN_ERR "%s() timed out.\n", __func__);
+               rc = -EINVAL;
+       }
+
+       kfree(worker);
+
+       /*
+        * mac80211 will crash on anything other than -EINVAL on
+        * error. Looks like wireless extensions which calls mac80211
+        * may be the actual culprit...
+        */
+       return rc ? -EINVAL : 0;
+}
+
+static int mwl8k_config_interface(struct ieee80211_hw *hw,
+                                 struct ieee80211_vif *vif,
+                                 struct ieee80211_if_conf *conf)
+{
+       struct mwl8k_vif *mv_vif = MWL8K_VIF(vif);
+       u32 changed = conf->changed;
+
+       if (changed & IEEE80211_IFCC_BSSID)
+               memcpy(mv_vif->bssid, conf->bssid, IEEE80211_ADDR_LEN);
+
+       return 0;
+}
+
+struct mwl8k_bss_info_changed_worker {
+       struct mwl8k_work_struct header;
+       struct ieee80211_vif *vif;
+       struct ieee80211_bss_conf *info;
+       u32 changed;
+};
+
+static int mwl8k_bss_info_changed_wt(struct work_struct *wt)
+{
+       struct mwl8k_bss_info_changed_worker *worker =
+               (struct mwl8k_bss_info_changed_worker *)wt;
+       struct ieee80211_hw *hw = worker->header.hw;
+       struct ieee80211_vif *vif = worker->vif;
+       struct ieee80211_bss_conf *info = worker->info;
+       u32 changed;
+       int rc;
+
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_vif *mwl8k_vif = MWL8K_VIF(vif);
+
+       changed = worker->changed;
+       priv->capture_beacon = false;
+
+       if (info->assoc) {
+               memcpy(&mwl8k_vif->bss_info, info,
+                       sizeof(struct ieee80211_bss_conf));
+
+               /* Install rates */
+               if (mwl8k_update_rateset(hw, vif))
+                       goto mwl8k_bss_info_changed_exit;
+
+               /* Turn on rate adaptation */
+               if (mwl8k_cmd_use_fixed_rate(hw, MWL8K_USE_AUTO_RATE,
+                       MWL8K_UCAST_RATE, NULL))
+                       goto mwl8k_bss_info_changed_exit;
+
+               /* Set radio preamble */
+               if (mwl8k_set_radio_preamble(hw,
+                               info->use_short_preamble))
+                       goto mwl8k_bss_info_changed_exit;
+
+               /* Set slot time */
+               if (mwl8k_cmd_set_slot(hw, info->use_short_slot ?
+                               MWL8K_SHORT_SLOTTIME : MWL8K_LONG_SLOTTIME))
+                       goto mwl8k_bss_info_changed_exit;
+
+               /* Update peer rate info */
+               if (mwl8k_cmd_update_sta_db(hw, vif,
+                               MWL8K_STA_DB_MODIFY_ENTRY))
+                       goto mwl8k_bss_info_changed_exit;
+
+               /* Set AID */
+               if (mwl8k_cmd_set_aid(hw, vif))
+                       goto mwl8k_bss_info_changed_exit;
+
+               /*
+                * Finalize the join.  Tell rx handler to process
+                * next beacon from our BSSID.
+                */
+               memcpy(priv->capture_bssid,
+                               mwl8k_vif->bssid, IEEE80211_ADDR_LEN);
+               priv->capture_beacon = true;
+       } else {
+               mwl8k_cmd_update_sta_db(hw, vif, MWL8K_STA_DB_DEL_ENTRY);
+               memset(&mwl8k_vif->bss_info, 0,
+                       sizeof(struct ieee80211_bss_conf));
+               memset(mwl8k_vif->bssid, 0, IEEE80211_ADDR_LEN);
+       }
+
+mwl8k_bss_info_changed_exit:
+       rc = 0;
+       return rc;
+}
+
+static void mwl8k_bss_info_changed(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_bss_conf *info,
+                                  u32 changed)
+{
+       struct mwl8k_bss_info_changed_worker *worker;
+       struct mwl8k_priv *priv = hw->priv;
+       int rc;
+
+       if ((changed & BSS_CHANGED_ASSOC) == 0)
+               return;
+
+       worker = kzalloc(sizeof(*worker), GFP_KERNEL);
+       if (worker == NULL)
+               return;
+
+       worker->vif = vif;
+       worker->info = info;
+       worker->changed = changed;
+       rc = mwl8k_queue_work(hw, &worker->header,
+                             priv->config_wq,
+                             mwl8k_bss_info_changed_wt);
+       kfree(worker);
+       if (rc == -ETIMEDOUT)
+               printk(KERN_ERR "%s() timed out\n", __func__);
+}
+
+struct mwl8k_configure_filter_worker {
+       struct mwl8k_work_struct header;
+       unsigned int changed_flags;
+       unsigned int *total_flags;
+       int mc_count;
+       struct dev_addr_list *mclist;
+};
+
+#define MWL8K_SUPPORTED_IF_FLAGS       FIF_BCN_PRBRESP_PROMISC
+
+static int mwl8k_configure_filter_wt(struct work_struct *wt)
+{
+       struct mwl8k_configure_filter_worker *worker =
+               (struct mwl8k_configure_filter_worker *)wt;
+
+       struct ieee80211_hw *hw = worker->header.hw;
+       unsigned int changed_flags = worker->changed_flags;
+       unsigned int *total_flags = worker->total_flags;
+       int mc_count = worker->mc_count;
+       struct dev_addr_list *mclist = worker->mclist;
+
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_vif *mv_vif;
+       int rc = 0;
+
+       if (changed_flags & FIF_BCN_PRBRESP_PROMISC) {
+               if (*total_flags & FIF_BCN_PRBRESP_PROMISC)
+                       rc = mwl8k_cmd_set_pre_scan(hw);
+               else {
+                       mv_vif = MWL8K_VIF(priv->vif);
+                       rc = mwl8k_cmd_set_post_scan(hw, mv_vif->bssid);
+               }
+       }
+
+       if (rc)
+               goto mwl8k_configure_filter_exit;
+       if (mc_count) {
+               mc_count = mc_count < priv->num_mcaddrs ?
+                               mc_count : priv->num_mcaddrs;
+               rc = mwl8k_cmd_mac_multicast_adr(hw, mc_count, mclist);
+               if (rc)
+                       printk(KERN_ERR
+                       "%s()Error setting multicast addresses\n",
+                       __func__);
+       }
+
+mwl8k_configure_filter_exit:
+       return rc;
+}
+
+static void mwl8k_configure_filter(struct ieee80211_hw *hw,
+                                  unsigned int changed_flags,
+                                  unsigned int *total_flags,
+                                  int mc_count,
+                                  struct dev_addr_list *mclist)
+{
+
+       struct mwl8k_configure_filter_worker *worker;
+       struct mwl8k_priv *priv = hw->priv;
+
+       /* Clear unsupported feature flags */
+       *total_flags &= MWL8K_SUPPORTED_IF_FLAGS;
+
+       if (!(changed_flags & MWL8K_SUPPORTED_IF_FLAGS) && !mc_count)
+               return;
+
+       worker = kzalloc(sizeof(*worker), GFP_ATOMIC);
+       if (worker == NULL)
+               return;
+
+       worker->header.options = MWL8K_WQ_QUEUE_ONLY | MWL8K_WQ_TX_WAIT_EMPTY;
+       worker->changed_flags = changed_flags;
+       worker->total_flags = total_flags;
+       worker->mc_count = mc_count;
+       worker->mclist = mclist;
+
+       mwl8k_queue_work(hw, &worker->header, priv->config_wq,
+                        mwl8k_configure_filter_wt);
+}
+
+struct mwl8k_set_rts_threshold_worker {
+       struct mwl8k_work_struct header;
+       u32 value;
+};
+
+static int mwl8k_set_rts_threshold_wt(struct work_struct *wt)
+{
+       struct mwl8k_set_rts_threshold_worker *worker =
+               (struct mwl8k_set_rts_threshold_worker *)wt;
+
+       struct ieee80211_hw *hw = worker->header.hw;
+       u16 threshold = (u16)(worker->value);
+       int rc;
+
+       rc = mwl8k_rts_threshold(hw, MWL8K_CMD_SET, &threshold);
+
+       return rc;
+}
+
+static int mwl8k_set_rts_threshold(struct ieee80211_hw *hw, u32 value)
+{
+       int rc;
+       struct mwl8k_set_rts_threshold_worker *worker;
+       struct mwl8k_priv *priv = hw->priv;
+
+       worker = kzalloc(sizeof(*worker), GFP_KERNEL);
+       if (worker == NULL)
+               return -ENOMEM;
+
+       worker->value = value;
+
+       rc = mwl8k_queue_work(hw, &worker->header,
+                             priv->config_wq,
+                             mwl8k_set_rts_threshold_wt);
+       kfree(worker);
+
+       if (rc == -ETIMEDOUT) {
+               printk(KERN_ERR "%s() timed out\n", __func__);
+               rc = -EINVAL;
+       }
+
+       return rc;
+}
+
+struct mwl8k_conf_tx_worker {
+       struct mwl8k_work_struct header;
+       u16 queue;
+       const struct ieee80211_tx_queue_params *params;
+};
+
+static int mwl8k_conf_tx_wt(struct work_struct *wt)
+{
+       struct mwl8k_conf_tx_worker *worker =
+       (struct mwl8k_conf_tx_worker *)wt;
+
+       struct ieee80211_hw *hw = worker->header.hw;
+       u16 queue = worker->queue;
+       const struct ieee80211_tx_queue_params *params = worker->params;
+
+       struct mwl8k_priv *priv = hw->priv;
+       int rc = 0;
+
+       if (priv->wmm_mode == MWL8K_WMM_DISABLE)
+               if (mwl8k_set_wmm(hw, MWL8K_WMM_ENABLE)) {
+                       rc = -EINVAL;
+                       goto mwl8k_conf_tx_exit;
+       }
+
+       if (mwl8k_set_edca_params(hw, GET_TXQ(queue), params->cw_min,
+               params->cw_max, params->aifs, params->txop))
+                       rc = -EINVAL;
+mwl8k_conf_tx_exit:
+       return rc;
+}
+
+static int mwl8k_conf_tx(struct ieee80211_hw *hw, u16 queue,
+                        const struct ieee80211_tx_queue_params *params)
+{
+       int rc;
+       struct mwl8k_conf_tx_worker *worker;
+       struct mwl8k_priv *priv = hw->priv;
+
+       worker = kzalloc(sizeof(*worker), GFP_KERNEL);
+       if (worker == NULL)
+               return -ENOMEM;
+
+       worker->queue = queue;
+       worker->params = params;
+       rc = mwl8k_queue_work(hw, &worker->header,
+                             priv->config_wq, mwl8k_conf_tx_wt);
+       kfree(worker);
+       if (rc == -ETIMEDOUT) {
+               printk(KERN_ERR "%s() timed out\n", __func__);
+               rc = -EINVAL;
+       }
+       return rc;
+}
+
+static int mwl8k_get_tx_stats(struct ieee80211_hw *hw,
+                             struct ieee80211_tx_queue_stats *stats)
+{
+       struct mwl8k_priv *priv = hw->priv;
+       struct mwl8k_tx_queue *txq;
+       int index;
+
+       spin_lock_bh(&priv->tx_lock);
+       for (index = 0; index < MWL8K_TX_QUEUES; index++) {
+               txq = priv->txq + index;
+               memcpy(&stats[index], &txq->tx_stats,
+                       sizeof(struct ieee80211_tx_queue_stats));
+       }
+       spin_unlock_bh(&priv->tx_lock);
+       return 0;
+}
+
+struct mwl8k_get_stats_worker {
+       struct mwl8k_work_struct header;
+       struct ieee80211_low_level_stats *stats;
+};
+
+static int mwl8k_get_stats_wt(struct work_struct *wt)
+{
+       struct mwl8k_get_stats_worker *worker =
+               (struct mwl8k_get_stats_worker *)wt;
+
+       return mwl8k_cmd_802_11_get_stat(worker->header.hw, worker->stats);
+}
+
+static int mwl8k_get_stats(struct ieee80211_hw *hw,
+                          struct ieee80211_low_level_stats *stats)
+{
+       int rc;
+       struct mwl8k_get_stats_worker *worker;
+       struct mwl8k_priv *priv = hw->priv;
+
+       worker = kzalloc(sizeof(*worker), GFP_KERNEL);
+       if (worker == NULL)
+               return -ENOMEM;
+
+       worker->stats = stats;
+       rc = mwl8k_queue_work(hw, &worker->header,
+                             priv->config_wq, mwl8k_get_stats_wt);
+
+       kfree(worker);
+       if (rc == -ETIMEDOUT) {
+               printk(KERN_ERR "%s() timed out\n", __func__);
+               rc = -EINVAL;
+       }
+
+       return rc;
+}
+
+static const struct ieee80211_ops mwl8k_ops = {
+       .tx                     = mwl8k_tx,
+       .start                  = mwl8k_start,
+       .stop                   = mwl8k_stop,
+       .add_interface          = mwl8k_add_interface,
+       .remove_interface       = mwl8k_remove_interface,
+       .config                 = mwl8k_config,
+       .config_interface       = mwl8k_config_interface,
+       .bss_info_changed       = mwl8k_bss_info_changed,
+       .configure_filter       = mwl8k_configure_filter,
+       .set_rts_threshold      = mwl8k_set_rts_threshold,
+       .conf_tx                = mwl8k_conf_tx,
+       .get_tx_stats           = mwl8k_get_tx_stats,
+       .get_stats              = mwl8k_get_stats,
+};
+
+static void mwl8k_tx_reclaim_handler(unsigned long data)
+{
+       int i;
+       struct ieee80211_hw *hw = (struct ieee80211_hw *) data;
+       struct mwl8k_priv *priv = hw->priv;
+
+       spin_lock_bh(&priv->tx_lock);
+       for (i = 0; i < MWL8K_TX_QUEUES; i++)
+               mwl8k_txq_reclaim(hw, i, 0);
+
+       if (priv->tx_wait != NULL) {
+               int count = mwl8k_txq_busy(priv);
+               if (count == 0) {
+                       complete(priv->tx_wait);
+                       priv->tx_wait = NULL;
+               }
+       }
+       spin_unlock_bh(&priv->tx_lock);
+}
+
+static void mwl8k_finalize_join_worker(struct work_struct *work)
+{
+       struct mwl8k_priv *priv =
+               container_of(work, struct mwl8k_priv, finalize_join_worker);
+       struct sk_buff *skb = priv->beacon_skb;
+       u8 dtim = (MWL8K_VIF(priv->vif))->bss_info.dtim_period;
+
+       mwl8k_finalize_join(priv->hw, skb->data, skb->len, dtim);
+       dev_kfree_skb(skb);
+
+       priv->beacon_skb = NULL;
+}
+
+static int __devinit mwl8k_probe(struct pci_dev *pdev,
+                                const struct pci_device_id *id)
+{
+       struct ieee80211_hw *hw;
+       struct mwl8k_priv *priv;
+       DECLARE_MAC_BUF(mac);
+       int rc;
+       int i;
+       u8 *fw;
+
+       rc = pci_enable_device(pdev);
+       if (rc) {
+               printk(KERN_ERR "%s: Cannot enable new PCI device\n",
+                      MWL8K_NAME);
+               return rc;
+       }
+
+       rc = pci_request_regions(pdev, MWL8K_NAME);
+       if (rc) {
+               printk(KERN_ERR "%s: Cannot obtain PCI resources\n",
+                      MWL8K_NAME);
+               return rc;
+       }
+
+       pci_set_master(pdev);
+
+       hw = ieee80211_alloc_hw(sizeof(*priv), &mwl8k_ops);
+       if (hw == NULL) {
+               printk(KERN_ERR "%s: ieee80211 alloc failed\n", MWL8K_NAME);
+               rc = -ENOMEM;
+               goto err_free_reg;
+       }
+
+       priv = hw->priv;
+       priv->hw = hw;
+       priv->pdev = pdev;
+       priv->hostcmd_wait = NULL;
+       priv->tx_wait = NULL;
+       priv->inconfig = false;
+       priv->wep_enabled = 0;
+       priv->wmm_mode = false;
+       priv->pending_tx_pkts = 0;
+       strncpy(priv->name, MWL8K_NAME, sizeof(priv->name));
+
+       spin_lock_init(&priv->fw_lock);
+
+       SET_IEEE80211_DEV(hw, &pdev->dev);
+       pci_set_drvdata(pdev, hw);
+
+       priv->regs = pci_iomap(pdev, 1, 0x10000);
+       if (priv->regs == NULL) {
+               printk(KERN_ERR "%s: Cannot map device memory\n", priv->name);
+               goto err_iounmap;
+       }
+
+       memcpy(priv->channels, mwl8k_channels, sizeof(mwl8k_channels));
+       priv->band.band = IEEE80211_BAND_2GHZ;
+       priv->band.channels = priv->channels;
+       priv->band.n_channels = ARRAY_SIZE(mwl8k_channels);
+       priv->band.bitrates = priv->rates;
+       priv->band.n_bitrates = ARRAY_SIZE(mwl8k_rates);
+       hw->wiphy->bands[IEEE80211_BAND_2GHZ] = &priv->band;
+
+       BUILD_BUG_ON(sizeof(priv->rates) != sizeof(mwl8k_rates));
+       memcpy(priv->rates, mwl8k_rates, sizeof(mwl8k_rates));
+
+       /*
+        * Extra headroom is the size of the required DMA header
+        * minus the size of the smallest 802.11 frame (CTS frame).
+        */
+       hw->extra_tx_headroom =
+               sizeof(struct mwl8k_dma_data) - sizeof(struct ieee80211_cts);
+
+       hw->channel_change_time = 10;
+
+       hw->queues = MWL8K_TX_QUEUES;
+
+       hw->wiphy->interface_modes =
+               BIT(NL80211_IFTYPE_STATION) | BIT(NL80211_IFTYPE_MONITOR);
+
+       /* Set rssi and noise values to dBm */
+       hw->flags |= (IEEE80211_HW_SIGNAL_DBM | IEEE80211_HW_NOISE_DBM);
+       hw->vif_data_size = sizeof(struct mwl8k_vif);
+       priv->vif = NULL;
+
+       /* Set default radio state and preamble */
+       priv->radio_preamble = MWL8K_RADIO_DEFAULT_PREAMBLE;
+       priv->radio_state = MWL8K_RADIO_DISABLE;
+
+       /* Finalize join worker */
+       INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
+
+       /* TX reclaim tasklet */
+       tasklet_init(&priv->tx_reclaim_task,
+                       mwl8k_tx_reclaim_handler, (unsigned long)hw);
+       tasklet_disable(&priv->tx_reclaim_task);
+
+       /* Config workthread */
+       priv->config_wq = create_singlethread_workqueue("mwl8k_config");
+       if (priv->config_wq == NULL)
+               goto err_iounmap;
+
+       /* Power management cookie */
+       priv->cookie = pci_alloc_consistent(priv->pdev, 4, &priv->cookie_dma);
+       if (priv->cookie == NULL)
+               goto err_iounmap;
+
+       rc = mwl8k_rxq_init(hw, 0);
+       if (rc)
+               goto err_iounmap;
+       rxq_refill(hw, 0, INT_MAX);
+
+       spin_lock_init(&priv->tx_lock);
+
+       for (i = 0; i < MWL8K_TX_QUEUES; i++) {
+               rc = mwl8k_txq_init(hw, i);
+               if (rc)
+                       goto err_free_queues;
+       }
+
+       iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS);
+       priv->int_mask = 0;
+       iowrite32(priv->int_mask, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
+       iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_CLEAR_SEL);
+       iowrite32(0xffffffff, priv->regs + MWL8K_HIU_A2H_INTERRUPT_STATUS_MASK);
+
+       rc = request_irq(priv->pdev->irq, &mwl8k_interrupt,
+                        IRQF_SHARED, MWL8K_NAME, hw);
+       if (rc) {
+               printk(KERN_ERR "%s: failed to register IRQ handler\n",
+                      priv->name);
+               goto err_free_queues;
+       }
+
+       /* Reset firmware and hardware */
+       mwl8k_hw_reset(priv);
+
+       /* Ask userland hotplug daemon for the device firmware */
+       rc = mwl8k_request_firmware(priv, (u32)id->driver_data);
+       if (rc) {
+               printk(KERN_ERR "%s: Firmware files not found\n", priv->name);
+               goto err_free_irq;
+       }
+
+       /* Load firmware into hardware */
+       rc = mwl8k_load_firmware(priv);
+       if (rc) {
+               printk(KERN_ERR "%s: Cannot start firmware\n", priv->name);
+               goto err_stop_firmware;
+       }
+
+       /* Reclaim memory once firmware is successfully loaded */
+       mwl8k_release_firmware(priv);
+
+       /*
+        * Temporarily enable interrupts.  Initial firmware host
+        * commands use interrupts and avoids polling.  Disable
+        * interrupts when done.
+        */
+       priv->int_mask |= MWL8K_A2H_EVENTS;
+
+       iowrite32(priv->int_mask, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
+
+       /* Get config data, mac addrs etc */
+       rc = mwl8k_cmd_get_hw_spec(hw);
+       if (rc) {
+               printk(KERN_ERR "%s: Cannot initialise firmware\n", priv->name);
+               goto err_stop_firmware;
+       }
+
+       /* Turn radio off */
+       rc = mwl8k_cmd_802_11_radio_control(hw, MWL8K_RADIO_DISABLE);
+       if (rc) {
+               printk(KERN_ERR "%s: Cannot disable\n", priv->name);
+               goto err_stop_firmware;
+       }
+
+       /* Disable interrupts */
+       spin_lock_irq(&priv->tx_lock);
+       iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
+       spin_unlock_irq(&priv->tx_lock);
+       free_irq(priv->pdev->irq, hw);
+
+       rc = ieee80211_register_hw(hw);
+       if (rc) {
+               printk(KERN_ERR "%s: Cannot register device\n", priv->name);
+               goto err_stop_firmware;
+       }
+
+       fw = (u8 *)&priv->fw_rev;
+       printk(KERN_INFO "%s: 88W%u %s\n", priv->name, priv->part_num,
+               MWL8K_DESC);
+       printk(KERN_INFO "%s: Driver Ver:%s  Firmware Ver:%u.%u.%u.%u\n",
+               priv->name, MWL8K_VERSION, fw[3], fw[2], fw[1], fw[0]);
+       printk(KERN_INFO "%s: MAC Address: %s\n", priv->name,
+              print_mac(mac, hw->wiphy->perm_addr));
+
+       return 0;
+
+err_stop_firmware:
+       mwl8k_hw_reset(priv);
+       mwl8k_release_firmware(priv);
+
+err_free_irq:
+       spin_lock_irq(&priv->tx_lock);
+       iowrite32(0, priv->regs + MWL8K_HIU_A2H_INTERRUPT_MASK);
+       spin_unlock_irq(&priv->tx_lock);
+       free_irq(priv->pdev->irq, hw);
+
+err_free_queues:
+       for (i = 0; i < MWL8K_TX_QUEUES; i++)
+               mwl8k_txq_deinit(hw, i);
+       mwl8k_rxq_deinit(hw, 0);
+
+err_iounmap:
+       if (priv->cookie != NULL)
+               pci_free_consistent(priv->pdev, 4,
+                               priv->cookie, priv->cookie_dma);
+
+       if (priv->regs != NULL)
+               pci_iounmap(pdev, priv->regs);
+
+       if (priv->config_wq != NULL)
+               destroy_workqueue(priv->config_wq);
+
+       pci_set_drvdata(pdev, NULL);
+       ieee80211_free_hw(hw);
+
+err_free_reg:
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+
+       return rc;
+}
+
+static void __devexit mwl8k_remove(struct pci_dev *pdev)
+{
+       printk(KERN_ERR "===>%s(%u)\n", __func__, __LINE__);
+}
+
+static void __devexit mwl8k_shutdown(struct pci_dev *pdev)
+{
+       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+       struct mwl8k_priv *priv;
+       int i;
+
+       if (hw == NULL)
+               return;
+       priv = hw->priv;
+
+       ieee80211_stop_queues(hw);
+
+       /* Remove tx reclaim tasklet */
+       tasklet_kill(&priv->tx_reclaim_task);
+
+       /* Stop config thread */
+       destroy_workqueue(priv->config_wq);
+
+       /* Stop hardware */
+       mwl8k_hw_reset(priv);
+
+       /* Return all skbs to mac80211 */
+       for (i = 0; i < MWL8K_TX_QUEUES; i++)
+               mwl8k_txq_reclaim(hw, i, 1);
+
+       ieee80211_unregister_hw(hw);
+
+       for (i = 0; i < MWL8K_TX_QUEUES; i++)
+               mwl8k_txq_deinit(hw, i);
+
+       mwl8k_rxq_deinit(hw, 0);
+
+       pci_free_consistent(priv->pdev, 4,
+                               priv->cookie, priv->cookie_dma);
+
+       pci_iounmap(pdev, priv->regs);
+       pci_set_drvdata(pdev, NULL);
+       ieee80211_free_hw(hw);
+       pci_release_regions(pdev);
+       pci_disable_device(pdev);
+}
+
+static struct pci_driver mwl8k_driver = {
+       .name           = MWL8K_NAME,
+       .id_table       = mwl8k_table,
+       .probe          = mwl8k_probe,
+       .remove         = __devexit_p(mwl8k_remove),
+       .shutdown       = __devexit_p(mwl8k_shutdown),
+};
+
+static int __init mwl8k_init(void)
+{
+       return pci_register_driver(&mwl8k_driver);
+}
+
+static void __exit mwl8k_exit(void)
+{
+       pci_unregister_driver(&mwl8k_driver);
+}
+
+module_init(mwl8k_init);
+module_exit(mwl8k_exit);
index 24caec6caf1fc0f98cdbffb1141ee6c57dd123aa..d63c8992f229bf8287f78ed2f790fe93cc5f0421 100644 (file)
@@ -210,10 +210,6 @@ static int netwave_rx( struct net_device *dev);
 static irqreturn_t netwave_interrupt(int irq, void *dev_id);
 static void netwave_watchdog(struct net_device *);
 
-/* Statistics */
-static void update_stats(struct net_device *dev);
-static struct net_device_stats *netwave_get_stats(struct net_device *dev);
-
 /* Wireless extensions */
 static struct iw_statistics* netwave_get_wireless_stats(struct net_device *dev);
 
@@ -275,14 +271,9 @@ typedef struct netwave_private {
     int        lastExec;
     struct timer_list      watchdog;   /* To avoid blocking state */
     struct site_survey     nss;
-    struct net_device_stats stats;
     struct iw_statistics   iw_stats;    /* Wireless stats */
 } netwave_private;
 
-#ifdef NETWAVE_STATS
-static struct net_device_stats *netwave_get_stats(struct net_device *dev);
-#endif
-
 /*
  * The Netwave card is little-endian, so won't work for big endian
  * systems.
@@ -364,6 +355,17 @@ static struct iw_statistics *netwave_get_wireless_stats(struct net_device *dev)
     return &priv->iw_stats;
 }
 
+static const struct net_device_ops netwave_netdev_ops = {
+       .ndo_open               = netwave_open,
+       .ndo_stop               = netwave_close,
+       .ndo_start_xmit         = netwave_start_xmit,
+       .ndo_set_multicast_list = set_multicast_list,
+       .ndo_tx_timeout         = netwave_watchdog,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 /*
  * Function netwave_attach (void)
  *
@@ -412,17 +414,12 @@ static int netwave_probe(struct pcmcia_device *link)
     spin_lock_init(&priv->spinlock);
 
     /* Netwave specific entries in the device structure */
-    dev->hard_start_xmit = &netwave_start_xmit;
-    dev->get_stats  = &netwave_get_stats;
-    dev->set_multicast_list = &set_multicast_list;
+    dev->netdev_ops = &netwave_netdev_ops;
     /* wireless extensions */
-    dev->wireless_handlers = (struct iw_handler_def *)&netwave_handler_def;
+    dev->wireless_handlers = &netwave_handler_def;
 
-    dev->tx_timeout = &netwave_watchdog;
     dev->watchdog_timeo = TX_TIMEOUT;
 
-    dev->open = &netwave_open;
-    dev->stop = &netwave_close;
     link->irq.Instance = dev;
 
     return netwave_pcmcia_config( link);
@@ -988,7 +985,7 @@ static int netwave_hw_xmit(unsigned char* data, int len,
        return 1;
     }
 
-    priv->stats.tx_bytes += len;
+    dev->stats.tx_bytes += len;
 
     DEBUG(3, "Transmitting with SPCQ %x SPU %x LIF %x ISPLQ %x\n",
          readb(ramBase + NETWAVE_EREG_SPCQ),
@@ -1107,11 +1104,11 @@ static irqreturn_t netwave_interrupt(int irq, void* dev_id)
            rser = readb(ramBase + NETWAVE_EREG_RSER);                  
            
            if (rser & 0x04) {
-               ++priv->stats.rx_dropped; 
-               ++priv->stats.rx_crc_errors;
+               ++dev->stats.rx_dropped;
+               ++dev->stats.rx_crc_errors;
            }
            if (rser & 0x02)
-               ++priv->stats.rx_frame_errors;
+               ++dev->stats.rx_frame_errors;
                        
            /* Clear the RxErr bit in RSER. RSER+4 is the
             * write part. Also clear the RxCRC (0x04) and 
@@ -1125,8 +1122,8 @@ static irqreturn_t netwave_interrupt(int irq, void* dev_id)
            wait_WOC(iobase);
            writeb(0x40, ramBase + NETWAVE_EREG_ASCC);
 
-           /* Remember to count up priv->stats on error packets */
-           ++priv->stats.rx_errors;
+           /* Remember to count up dev->stats on error packets */
+           ++dev->stats.rx_errors;
        }
        /* TxDN */
        if (status & 0x20) {
@@ -1140,17 +1137,17 @@ static irqreturn_t netwave_interrupt(int irq, void* dev_id)
                /* Transmitting was okay, clear bits */
                wait_WOC(iobase);
                writeb(0x2f, ramBase + NETWAVE_EREG_TSER + 4);
-               ++priv->stats.tx_packets;
+               ++dev->stats.tx_packets;
            }
                        
            if (txStatus & 0xd0) {
                if (txStatus & 0x80) {
-                   ++priv->stats.collisions; /* Because of /proc/net/dev*/
-                   /* ++priv->stats.tx_aborted_errors; */
+                   ++dev->stats.collisions; /* Because of /proc/net/dev*/
+                   /* ++dev->stats.tx_aborted_errors; */
                    /* printk("Collision. %ld\n", jiffies - dev->trans_start); */
                }
                if (txStatus & 0x40) 
-                   ++priv->stats.tx_carrier_errors;
+                   ++dev->stats.tx_carrier_errors;
                /* 0x80 TxGU Transmit giveup - nine times and no luck
                 * 0x40 TxNOAP No access point. Discarded packet.
                 * 0x10 TxErr Transmit error. Always set when 
@@ -1163,7 +1160,7 @@ static irqreturn_t netwave_interrupt(int irq, void* dev_id)
                /* Clear out TxGU, TxNOAP, TxErr and TxTrys */
                wait_WOC(iobase);
                writeb(0xdf & txStatus, ramBase+NETWAVE_EREG_TSER+4);
-               ++priv->stats.tx_errors;
+               ++dev->stats.tx_errors;
            }
            DEBUG(3, "New status is TSER %x ASR %x\n",
                  readb(ramBase + NETWAVE_EREG_TSER),
@@ -1197,40 +1194,6 @@ static void netwave_watchdog(struct net_device *dev) {
     netif_wake_queue(dev);
 } /* netwave_watchdog */
 
-static struct net_device_stats *netwave_get_stats(struct net_device *dev) {
-    netwave_private *priv = netdev_priv(dev);
-
-    update_stats(dev);
-
-    DEBUG(2, "netwave: SPCQ %x SPU %x LIF %x ISPLQ %x MHS %x rxtx %x"
-         " %x tx %x %x %x %x\n", 
-         readb(priv->ramBase + NETWAVE_EREG_SPCQ),
-         readb(priv->ramBase + NETWAVE_EREG_SPU),
-         readb(priv->ramBase + NETWAVE_EREG_LIF),
-         readb(priv->ramBase + NETWAVE_EREG_ISPLQ),
-         readb(priv->ramBase + NETWAVE_EREG_MHS),
-         readb(priv->ramBase + NETWAVE_EREG_EC + 0xe),
-         readb(priv->ramBase + NETWAVE_EREG_EC + 0xf),
-         readb(priv->ramBase + NETWAVE_EREG_EC + 0x18),
-         readb(priv->ramBase + NETWAVE_EREG_EC + 0x19),
-         readb(priv->ramBase + NETWAVE_EREG_EC + 0x1a),
-         readb(priv->ramBase + NETWAVE_EREG_EC + 0x1b));
-
-    return &priv->stats;
-}
-
-static void update_stats(struct net_device *dev) {
-    //unsigned long flags;
-/*     netwave_private *priv = netdev_priv(dev); */
-
-    //spin_lock_irqsave(&priv->spinlock, flags);
-
-/*    priv->stats.rx_packets = readb(priv->ramBase + 0x18e); 
-    priv->stats.tx_packets = readb(priv->ramBase + 0x18f); */
-
-    //spin_unlock_irqrestore(&priv->spinlock, flags);
-}
-
 static int netwave_rx(struct net_device *dev)
 {
     netwave_private *priv = netdev_priv(dev);
@@ -1274,7 +1237,7 @@ static int netwave_rx(struct net_device *dev)
        if (skb == NULL) {
            DEBUG(1, "netwave_rx: Could not allocate an sk_buff of "
                  "length %d\n", rcvLen);
-           ++priv->stats.rx_dropped; 
+           ++dev->stats.rx_dropped;
            /* Tell the adapter to skip the packet */
            wait_WOC(iobase);
            writeb(NETWAVE_CMD_SRP, ramBase + NETWAVE_EREG_CB + 0);
@@ -1307,8 +1270,8 @@ static int netwave_rx(struct net_device *dev)
        /* Queue packet for network layer */
        netif_rx(skb);
 
-       priv->stats.rx_packets++;
-       priv->stats.rx_bytes += rcvLen;
+       dev->stats.rx_packets++;
+       dev->stats.rx_bytes += rcvLen;
 
        /* Got the packet, tell the adapter to skip it */
        wait_WOC(iobase);
index 7d2292d6ce09fa1a894488fdbabc943beaa541e1..1084b43e04bc62b1c6b9c52eae0047911e1673d9 100644 (file)
@@ -43,6 +43,46 @@ struct orinoco_fw_header {
        char signature[0];      /* FW signature length headersize-20 */
 } __attribute__ ((packed));
 
+/* Check the range of various header entries. Return a pointer to a
+ * description of the problem, or NULL if everything checks out. */
+static const char *validate_fw(const struct orinoco_fw_header *hdr, size_t len)
+{
+       u16 hdrsize;
+
+       if (len < sizeof(*hdr))
+               return "image too small";
+       if (memcmp(hdr->hdr_vers, "HFW", 3) != 0)
+               return "format not recognised";
+
+       hdrsize = le16_to_cpu(hdr->headersize);
+       if (hdrsize > len)
+               return "bad headersize";
+       if ((hdrsize + le32_to_cpu(hdr->block_offset)) > len)
+               return "bad block offset";
+       if ((hdrsize + le32_to_cpu(hdr->pdr_offset)) > len)
+               return "bad PDR offset";
+       if ((hdrsize + le32_to_cpu(hdr->pri_offset)) > len)
+               return "bad PRI offset";
+       if ((hdrsize + le32_to_cpu(hdr->compat_offset)) > len)
+               return "bad compat offset";
+
+       /* TODO: consider adding a checksum or CRC to the firmware format */
+       return NULL;
+}
+
+#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
+static inline const struct firmware *
+orinoco_cached_fw_get(struct orinoco_private *priv, bool primary)
+{
+       if (primary)
+               return priv->cached_pri_fw;
+       else
+               return priv->cached_fw;
+}
+#else
+#define orinoco_cached_fw_get(priv, primary) (NULL)
+#endif
+
 /* Download either STA or AP firmware into the card. */
 static int
 orinoco_dl_firmware(struct orinoco_private *priv,
@@ -56,8 +96,9 @@ orinoco_dl_firmware(struct orinoco_private *priv,
        const struct firmware *fw_entry;
        const struct orinoco_fw_header *hdr;
        const unsigned char *first_block;
-       const unsigned char *end;
+       const void *end;
        const char *firmware;
+       const char *fw_err;
        struct net_device *dev = priv->ndev;
        int err = 0;
 
@@ -79,7 +120,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
        if (err)
                goto free;
 
-       if (!priv->cached_fw) {
+       if (!orinoco_cached_fw_get(priv, false)) {
                err = request_firmware(&fw_entry, firmware, priv->dev);
 
                if (err) {
@@ -89,10 +130,19 @@ orinoco_dl_firmware(struct orinoco_private *priv,
                        goto free;
                }
        } else
-               fw_entry = priv->cached_fw;
+               fw_entry = orinoco_cached_fw_get(priv, false);
 
        hdr = (const struct orinoco_fw_header *) fw_entry->data;
 
+       fw_err = validate_fw(hdr, fw_entry->size);
+       if (fw_err) {
+               printk(KERN_WARNING "%s: Invalid firmware image detected (%s). "
+                      "Aborting download\n",
+                      dev->name, fw_err);
+               err = -EINVAL;
+               goto abort;
+       }
+
        /* Enable aux port to allow programming */
        err = hermesi_program_init(hw, le32_to_cpu(hdr->entry_point));
        printk(KERN_DEBUG "%s: Program init returned %d\n", dev->name, err);
@@ -115,7 +165,8 @@ orinoco_dl_firmware(struct orinoco_private *priv,
                       le16_to_cpu(hdr->headersize) +
                       le32_to_cpu(hdr->pdr_offset));
 
-       err = hermes_apply_pda_with_defaults(hw, first_block, pda);
+       err = hermes_apply_pda_with_defaults(hw, first_block, end, pda,
+                                            &pda[fw->pda_size / sizeof(*pda)]);
        printk(KERN_DEBUG "%s: Apply PDA returned %d\n", dev->name, err);
        if (err)
                goto abort;
@@ -132,7 +183,7 @@ orinoco_dl_firmware(struct orinoco_private *priv,
 
 abort:
        /* If we requested the firmware, release it. */
-       if (!priv->cached_fw)
+       if (!orinoco_cached_fw_get(priv, false))
                release_firmware(fw_entry);
 
 free:
@@ -147,7 +198,7 @@ free:
  */
 static int
 symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
-               const unsigned char *image, const unsigned char *end,
+               const unsigned char *image, const void *end,
                int secondary)
 {
        hermes_t *hw = &priv->hw;
@@ -188,9 +239,10 @@ symbol_dl_image(struct orinoco_private *priv, const struct fw_info *fw,
 
        /* Write the PDA to the adapter */
        if (secondary) {
-               size_t len = hermes_blocks_length(first_block);
+               size_t len = hermes_blocks_length(first_block, end);
                ptr = first_block + len;
-               ret = hermes_apply_pda(hw, ptr, pda);
+               ret = hermes_apply_pda(hw, ptr, end, pda,
+                                      &pda[fw->pda_size / sizeof(*pda)]);
                kfree(pda);
                if (ret)
                        return ret;
@@ -234,20 +286,20 @@ symbol_dl_firmware(struct orinoco_private *priv,
        int ret;
        const struct firmware *fw_entry;
 
-       if (!priv->cached_pri_fw) {
+       if (!orinoco_cached_fw_get(priv, true)) {
                if (request_firmware(&fw_entry, fw->pri_fw, priv->dev) != 0) {
                        printk(KERN_ERR "%s: Cannot find firmware: %s\n",
                               dev->name, fw->pri_fw);
                        return -ENOENT;
                }
        } else
-               fw_entry = priv->cached_pri_fw;
+               fw_entry = orinoco_cached_fw_get(priv, true);
 
        /* Load primary firmware */
        ret = symbol_dl_image(priv, fw, fw_entry->data,
                              fw_entry->data + fw_entry->size, 0);
 
-       if (!priv->cached_pri_fw)
+       if (!orinoco_cached_fw_get(priv, true))
                release_firmware(fw_entry);
        if (ret) {
                printk(KERN_ERR "%s: Primary firmware download failed\n",
@@ -255,19 +307,19 @@ symbol_dl_firmware(struct orinoco_private *priv,
                return ret;
        }
 
-       if (!priv->cached_fw) {
+       if (!orinoco_cached_fw_get(priv, false)) {
                if (request_firmware(&fw_entry, fw->sta_fw, priv->dev) != 0) {
                        printk(KERN_ERR "%s: Cannot find firmware: %s\n",
                               dev->name, fw->sta_fw);
                        return -ENOENT;
                }
        } else
-               fw_entry = priv->cached_fw;
+               fw_entry = orinoco_cached_fw_get(priv, false);
 
        /* Load secondary firmware */
        ret = symbol_dl_image(priv, fw, fw_entry->data,
                              fw_entry->data + fw_entry->size, 1);
-       if (!priv->cached_fw)
+       if (!orinoco_cached_fw_get(priv, false))
                release_firmware(fw_entry);
        if (ret) {
                printk(KERN_ERR "%s: Secondary firmware download failed\n",
@@ -301,9 +353,9 @@ int orinoco_download(struct orinoco_private *priv)
        return err;
 }
 
+#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
 void orinoco_cache_fw(struct orinoco_private *priv, int ap)
 {
-#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
        const struct firmware *fw_entry = NULL;
        const char *pri_fw;
        const char *fw;
@@ -323,12 +375,10 @@ void orinoco_cache_fw(struct orinoco_private *priv, int ap)
                if (request_firmware(&fw_entry, fw, priv->dev) == 0)
                        priv->cached_fw = fw_entry;
        }
-#endif
 }
 
 void orinoco_uncache_fw(struct orinoco_private *priv)
 {
-#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
        if (priv->cached_pri_fw)
                release_firmware(priv->cached_pri_fw);
        if (priv->cached_fw)
@@ -336,5 +386,5 @@ void orinoco_uncache_fw(struct orinoco_private *priv)
 
        priv->cached_pri_fw = NULL;
        priv->cached_fw = NULL;
-#endif
 }
+#endif
index 2290f0845d598f389bb2d732d7f89ce64351f611..89fc26d25b0644a1539c4cc844a56207aa923006 100644 (file)
@@ -10,7 +10,12 @@ struct orinoco_private;
 
 int orinoco_download(struct orinoco_private *priv);
 
+#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
 void orinoco_cache_fw(struct orinoco_private *priv, int ap);
 void orinoco_uncache_fw(struct orinoco_private *priv);
+#else
+#define orinoco_cache_fw(priv, ap) do { } while(0)
+#define orinoco_uncache_fw(priv) do { } while (0)
+#endif
 
 #endif /* _ORINOCO_FW_H_ */
index 5260ceb5cfecae7e98244196e51041daced6c006..a9ba195cdada70963503c6b6bbd0f41ddd4c5905 100644 (file)
 #define BLOCK_END      0xFFFFFFFF      /* Last image block */
 #define TEXT_END       0x1A            /* End of text header */
 
-/*
- * PDA == Production Data Area
- *
- * In principle, the max. size of the PDA is is 4096 words. Currently,
- * however, only about 500 bytes of this area are used.
- *
- * Some USB implementations can't handle sizes in excess of 1016. Note
- * that PDA is not actually used in those USB environments, but may be
- * retrieved by common code.
- */
-#define MAX_PDA_SIZE   1000
-
 /* Limit the amout we try to download in a single shot.
  * Size is in bytes.
  */
@@ -218,13 +206,14 @@ hermes_aux_control(hermes_t *hw, int enabled)
  * Scan PDR for the record with the specified RECORD_ID.
  * If it's not found, return NULL.
  */
-static struct pdr *
-hermes_find_pdr(struct pdr *first_pdr, u32 record_id)
+static const struct pdr *
+hermes_find_pdr(const struct pdr *first_pdr, u32 record_id, const void *end)
 {
-       struct pdr *pdr = first_pdr;
-       void *end = (void *)first_pdr + MAX_PDA_SIZE;
+       const struct pdr *pdr = first_pdr;
 
-       while (((void *)pdr < end) &&
+       end -= sizeof(struct pdr);
+
+       while (((void *) pdr <= end) &&
               (pdr_id(pdr) != PDI_END)) {
                /*
                 * PDR area is currently not terminated by PDI_END.
@@ -244,12 +233,15 @@ hermes_find_pdr(struct pdr *first_pdr, u32 record_id)
 }
 
 /* Scan production data items for a particular entry */
-static struct pdi *
-hermes_find_pdi(struct pdi *first_pdi, u32 record_id)
+static const struct pdi *
+hermes_find_pdi(const struct pdi *first_pdi, u32 record_id, const void *end)
 {
-       struct pdi *pdi = first_pdi;
+       const struct pdi *pdi = first_pdi;
+
+       end -= sizeof(struct pdi);
 
-       while (pdi_id(pdi) != PDI_END) {
+       while (((void *) pdi <= end) &&
+              (pdi_id(pdi) != PDI_END)) {
 
                /* If the record ID matches, we are done */
                if (pdi_id(pdi) == record_id)
@@ -262,12 +254,13 @@ hermes_find_pdi(struct pdi *first_pdi, u32 record_id)
 
 /* Process one Plug Data Item - find corresponding PDR and plug it */
 static int
-hermes_plug_pdi(hermes_t *hw, struct pdr *first_pdr, const struct pdi *pdi)
+hermes_plug_pdi(hermes_t *hw, const struct pdr *first_pdr,
+               const struct pdi *pdi, const void *pdr_end)
 {
-       struct pdr *pdr;
+       const struct pdr *pdr;
 
        /* Find the PDR corresponding to this PDI */
-       pdr = hermes_find_pdr(first_pdr, pdi_id(pdi));
+       pdr = hermes_find_pdr(first_pdr, pdi_id(pdi), pdr_end);
 
        /* No match is found, safe to ignore */
        if (!pdr)
@@ -345,18 +338,22 @@ int hermes_read_pda(hermes_t *hw,
  */
 int hermes_apply_pda(hermes_t *hw,
                     const char *first_pdr,
-                    const __le16 *pda)
+                    const void *pdr_end,
+                    const __le16 *pda,
+                    const void *pda_end)
 {
        int ret;
        const struct pdi *pdi;
-       struct pdr *pdr;
+       const struct pdr *pdr;
 
-       pdr = (struct pdr *) first_pdr;
+       pdr = (const struct pdr *) first_pdr;
+       pda_end -= sizeof(struct pdi);
 
        /* Go through every PDI and plug them into the adapter */
        pdi = (const struct pdi *) (pda + 2);
-       while (pdi_id(pdi) != PDI_END) {
-               ret = hermes_plug_pdi(hw, pdr, pdi);
+       while (((void *) pdi <= pda_end) &&
+              (pdi_id(pdi) != PDI_END)) {
+               ret = hermes_plug_pdi(hw, pdr, pdi, pdr_end);
                if (ret)
                        return ret;
 
@@ -370,15 +367,18 @@ int hermes_apply_pda(hermes_t *hw,
  * including the header data.
  */
 size_t
-hermes_blocks_length(const char *first_block)
+hermes_blocks_length(const char *first_block, const void *end)
 {
        const struct dblock *blk = (const struct dblock *) first_block;
        int total_len = 0;
        int len;
 
+       end -= sizeof(*blk);
+
        /* Skip all blocks to locate Plug Data References
         * (Spectrum CS) */
-       while (dblock_addr(blk) != BLOCK_END) {
+       while (((void *) blk <= end) &&
+              (dblock_addr(blk) != BLOCK_END)) {
                len = dblock_len(blk);
                total_len += sizeof(*blk) + len;
                blk = (struct dblock *) &blk->data[len];
@@ -476,7 +476,7 @@ int hermesi_program_end(hermes_t *hw)
 }
 
 /* Program the data blocks */
-int hermes_program(hermes_t *hw, const char *first_block, const char *end)
+int hermes_program(hermes_t *hw, const char *first_block, const void *end)
 {
        const struct dblock *blk;
        u32 blkaddr;
@@ -488,14 +488,14 @@ int hermes_program(hermes_t *hw, const char *first_block, const char *end)
 
        blk = (const struct dblock *) first_block;
 
-       if ((const char *) blk > (end - sizeof(*blk)))
+       if ((void *) blk > (end - sizeof(*blk)))
                return -EIO;
 
        blkaddr = dblock_addr(blk);
        blklen = dblock_len(blk);
 
        while ((blkaddr != BLOCK_END) &&
-              (((const char *) blk + blklen) <= end)) {
+              (((void *) blk + blklen) <= end)) {
                printk(KERN_DEBUG PFX
                       "Programming block of length %d to address 0x%08x\n",
                       blklen, blkaddr);
@@ -527,7 +527,7 @@ int hermes_program(hermes_t *hw, const char *first_block, const char *end)
 #endif
                blk = (const struct dblock *) &blk->data[blklen];
 
-               if ((const char *) blk > (end - sizeof(*blk)))
+               if ((void *) blk > (end - sizeof(*blk)))
                        return -EIO;
 
                blkaddr = dblock_addr(blk);
@@ -545,9 +545,9 @@ static const struct {                                                       \
        __le16 id;                                                      \
        u8 val[length];                                                 \
 } __attribute__ ((packed)) default_pdr_data_##pid = {                  \
-       cpu_to_le16((sizeof(default_pdr_data_##pid)/            \
+       cpu_to_le16((sizeof(default_pdr_data_##pid)/                    \
                                sizeof(__le16)) - 1),                   \
-       cpu_to_le16(pid),                                       \
+       cpu_to_le16(pid),                                               \
        data                                                            \
 }
 
@@ -616,17 +616,20 @@ DEFINE_DEFAULT_PDR(0x0161, 256,
  */
 int hermes_apply_pda_with_defaults(hermes_t *hw,
                                   const char *first_pdr,
-                                  const __le16 *pda)
+                                  const void *pdr_end,
+                                  const __le16 *pda,
+                                  const void *pda_end)
 {
        const struct pdr *pdr = (const struct pdr *) first_pdr;
-       struct pdi *first_pdi = (struct pdi *) &pda[2];
-       struct pdi *pdi;
-       struct pdi *default_pdi = NULL;
-       struct pdi *outdoor_pdi;
-       void *end = (void *)first_pdr + MAX_PDA_SIZE;
+       const struct pdi *first_pdi = (const struct pdi *) &pda[2];
+       const struct pdi *pdi;
+       const struct pdi *default_pdi = NULL;
+       const struct pdi *outdoor_pdi;
        int record_id;
 
-       while (((void *)pdr < end) &&
+       pdr_end -= sizeof(struct pdr);
+
+       while (((void *) pdr <= pdr_end) &&
               (pdr_id(pdr) != PDI_END)) {
                /*
                 * For spectrum_cs firmwares,
@@ -638,7 +641,7 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
                        break;
                record_id = pdr_id(pdr);
 
-               pdi = hermes_find_pdi(first_pdi, record_id);
+               pdi = hermes_find_pdi(first_pdi, record_id, pda_end);
                if (pdi)
                        printk(KERN_DEBUG PFX "Found record 0x%04x at %p\n",
                               record_id, pdi);
@@ -646,7 +649,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
                switch (record_id) {
                case 0x110: /* Modem REFDAC values */
                case 0x120: /* Modem VGDAC values */
-                       outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1);
+                       outdoor_pdi = hermes_find_pdi(first_pdi, record_id + 1,
+                                                     pda_end);
                        default_pdi = NULL;
                        if (outdoor_pdi) {
                                pdi = outdoor_pdi;
@@ -687,7 +691,8 @@ int hermes_apply_pda_with_defaults(hermes_t *hw,
 
                if (pdi) {
                        /* Lengths of the data in PDI and PDR must match */
-                       if (pdi_len(pdi) == pdr_len(pdr)) {
+                       if ((pdi_len(pdi) == pdr_len(pdr)) &&
+                           ((void *) pdi->data + pdi_len(pdi) < pda_end)) {
                                /* do the actual plugging */
                                hermes_aux_setaddr(hw, pdr_addr(pdr));
                                hermes_write_bytes(hw, HERMES_AUXDATA,
index 6fcb262779991a63451188cc1c4d372b738a5991..583a5bcf917548236d63f6991350d8b760bcfd38 100644 (file)
@@ -29,7 +29,7 @@
 
 int hermesi_program_init(hermes_t *hw, u32 offset);
 int hermesi_program_end(hermes_t *hw);
-int hermes_program(hermes_t *hw, const char *first_block, const char *end);
+int hermes_program(hermes_t *hw, const char *first_block, const void *end);
 
 int hermes_read_pda(hermes_t *hw,
                    __le16 *pda,
@@ -38,11 +38,15 @@ int hermes_read_pda(hermes_t *hw,
                    int use_eeprom);
 int hermes_apply_pda(hermes_t *hw,
                     const char *first_pdr,
-                    const __le16 *pda);
+                    const void *pdr_end,
+                    const __le16 *pda,
+                    const void *pda_end);
 int hermes_apply_pda_with_defaults(hermes_t *hw,
                                   const char *first_pdr,
-                                  const __le16 *pda);
+                                  const void *pdr_end,
+                                  const __le16 *pda,
+                                  const void *pda_end);
 
-size_t hermes_blocks_length(const char *first_block);
+size_t hermes_blocks_length(const char *first_block, const void *end);
 
 #endif /* _HERMES_DLD_H */
index 54dfc4540b82f588037847286eb96723c84b4125..345593c4accbe3c2f007acd9836e66a9ff8375e0 100644 (file)
@@ -2076,8 +2076,20 @@ static int orinoco_pm_notifier(struct notifier_block *notifier,
 
        return NOTIFY_DONE;
 }
+
+static void orinoco_register_pm_notifier(struct orinoco_private *priv)
+{
+       priv->pm_notifier.notifier_call = orinoco_pm_notifier;
+       register_pm_notifier(&priv->pm_notifier);
+}
+
+static void orinoco_unregister_pm_notifier(struct orinoco_private *priv)
+{
+       unregister_pm_notifier(&priv->pm_notifier);
+}
 #else /* !PM_SLEEP || HERMES_CACHE_FW_ON_INIT */
-#define orinoco_pm_notifier NULL
+#define orinoco_register_pm_notifier(priv) do { } while(0)
+#define orinoco_unregister_pm_notifier(priv) do { } while(0)
 #endif
 
 /********************************************************************/
@@ -2568,12 +2580,13 @@ struct net_device
        netif_carrier_off(dev);
        priv->last_linkstatus = 0xffff;
 
+#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
        priv->cached_pri_fw = NULL;
        priv->cached_fw = NULL;
+#endif
 
        /* Register PM notifiers */
-       priv->pm_notifier.notifier_call = orinoco_pm_notifier;
-       register_pm_notifier(&priv->pm_notifier);
+       orinoco_register_pm_notifier(priv);
 
        return dev;
 }
@@ -2598,7 +2611,7 @@ void free_orinocodev(struct net_device *dev)
                kfree(rx_data);
        }
 
-       unregister_pm_notifier(&priv->pm_notifier);
+       orinoco_unregister_pm_notifier(priv);
        orinoco_uncache_fw(priv);
 
        priv->wpa_ie_len = 0;
index f3f94b28ce6df3b57b3f65f48e77aac2163abd22..8e5a72cc297f9c051c7bc3493f42db09884207b0 100644 (file)
@@ -159,9 +159,11 @@ struct orinoco_private {
        unsigned int tkip_cm_active:1;
        unsigned int key_mgmt:3;
 
+#if defined(CONFIG_HERMES_CACHE_FW_ON_INIT) || defined(CONFIG_PM_SLEEP)
        /* Cached in memory firmware to use during ->resume. */
        const struct firmware *cached_pri_fw;
        const struct firmware *cached_fw;
+#endif
 
        struct notifier_block pm_notifier;
 };
index 94c3acd1fcaf41e0058e53e79537b39c3296df5c..2dda5fe418b68fd5ceff3c09dea8a8afb0b3bed8 100644 (file)
  * published by the Free Software Foundation.
  */
 
+#ifdef CONFIG_MAC80211_LEDS
+#include <linux/leds.h>
+#endif /* CONFIG_MAC80211_LEDS */
+
 enum p54_control_frame_types {
        P54_CONTROL_TYPE_SETUP = 0,
        P54_CONTROL_TYPE_SCAN,
@@ -112,6 +116,21 @@ enum fw_state {
        FW_STATE_RESETTING,
 };
 
+#ifdef CONFIG_MAC80211_LEDS
+
+#define P54_LED_MAX_NAME_LEN 31
+
+struct p54_led_dev {
+       struct ieee80211_hw *hw_dev;
+       struct led_classdev led_dev;
+       char name[P54_LED_MAX_NAME_LEN + 1];
+
+       unsigned int index;
+       unsigned int registered;
+};
+
+#endif /* CONFIG_MAC80211_LEDS */
+
 struct p54_common {
        struct ieee80211_hw *hw;
        u32 rx_start;
@@ -157,6 +176,12 @@ struct p54_common {
        struct completion eeprom_comp;
        u8 privacy_caps;
        u8 rx_keycache_size;
+       /* LED management */
+       #ifdef CONFIG_MAC80211_LEDS
+       struct p54_led_dev assoc_led;
+       struct p54_led_dev tx_led;
+       #endif /* CONFIG_MAC80211_LEDS */
+       u16 softled_state;              /* bit field of glowing LEDs */
 };
 
 int p54_rx(struct ieee80211_hw *dev, struct sk_buff *skb);
@@ -165,6 +190,7 @@ int p54_parse_firmware(struct ieee80211_hw *dev, const struct firmware *fw);
 int p54_parse_eeprom(struct ieee80211_hw *dev, void *eeprom, int len);
 int p54_read_eeprom(struct ieee80211_hw *dev);
 struct ieee80211_hw *p54_init_common(size_t priv_data_len);
+int p54_register_common(struct ieee80211_hw *dev, struct device *pdev);
 void p54_free_common(struct ieee80211_hw *dev);
 
 #endif /* P54_H */
index 45c2e7ad3acdfb83e0921ab8428a7aa90de45590..0a989834b70d38fec2bc5cbe1be70190f7f56b23 100644 (file)
@@ -21,6 +21,9 @@
 #include <linux/etherdevice.h>
 
 #include <net/mac80211.h>
+#ifdef CONFIG_MAC80211_LEDS
+#include <linux/leds.h>
+#endif /* CONFIG_MAC80211_LEDS */
 
 #include "p54.h"
 #include "p54common.h"
@@ -735,10 +738,7 @@ static int p54_rx_data(struct ieee80211_hw *dev, struct sk_buff *skb)
                return 0;
 
        if (!(hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_IN_FCS_GOOD))) {
-               if (priv->filter_flags & FIF_FCSFAIL)
-                       rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
-               else
-                       return 0;
+               return 0;
        }
 
        if (hdr->decrypt_status == P54_DECRYPT_OK)
@@ -849,10 +849,11 @@ static struct sk_buff *p54_find_tx_entry(struct ieee80211_hw *dev,
                                           __le32 req_id)
 {
        struct p54_common *priv = dev->priv;
-       struct sk_buff *entry = priv->tx_queue.next;
+       struct sk_buff *entry;
        unsigned long flags;
 
        spin_lock_irqsave(&priv->tx_queue.lock, flags);
+       entry = priv->tx_queue.next;
        while (entry != (struct sk_buff *)&priv->tx_queue) {
                struct p54_hdr *hdr = (struct p54_hdr *) entry->data;
 
@@ -871,7 +872,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
        struct p54_common *priv = dev->priv;
        struct p54_hdr *hdr = (struct p54_hdr *) skb->data;
        struct p54_frame_sent *payload = (struct p54_frame_sent *) hdr->data;
-       struct sk_buff *entry = (struct sk_buff *) priv->tx_queue.next;
+       struct sk_buff *entry;
        u32 addr = le32_to_cpu(hdr->req_id) - priv->headroom;
        struct p54_tx_info *range = NULL;
        u32 freed = 0;
@@ -880,6 +881,7 @@ static void p54_rx_frame_sent(struct ieee80211_hw *dev, struct sk_buff *skb)
        int count, idx;
 
        spin_lock_irqsave(&priv->tx_queue.lock, flags);
+       entry = (struct sk_buff *) priv->tx_queue.next;
        while (entry != (struct sk_buff *)&priv->tx_queue) {
                struct ieee80211_tx_info *info = IEEE80211_SKB_CB(entry);
                struct p54_hdr *entry_hdr;
@@ -1122,7 +1124,7 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
                               struct p54_hdr *data, u32 len)
 {
        struct p54_common *priv = dev->priv;
-       struct sk_buff *entry = priv->tx_queue.next;
+       struct sk_buff *entry;
        struct sk_buff *target_skb = NULL;
        struct ieee80211_tx_info *info;
        struct p54_tx_info *range;
@@ -1160,6 +1162,7 @@ static int p54_assign_address(struct ieee80211_hw *dev, struct sk_buff *skb,
                }
        }
 
+       entry = priv->tx_queue.next;
        while (left--) {
                u32 hole_size;
                info = IEEE80211_SKB_CB(entry);
@@ -1677,7 +1680,7 @@ static int p54_setup_mac(struct ieee80211_hw *dev)
                        mode = P54_FILTER_TYPE_PROMISCUOUS;
                        break;
                default:
-                       mode = P54_FILTER_TYPE_NONE;
+                       mode = P54_FILTER_TYPE_HIBERNATE;
                        break;
                }
 
@@ -1690,7 +1693,7 @@ static int p54_setup_mac(struct ieee80211_hw *dev)
                    (mode != P54_FILTER_TYPE_PROMISCUOUS))
                        mode |= P54_FILTER_TYPE_TRANSPARENT;
        } else
-               mode = P54_FILTER_TYPE_RX_DISABLED;
+               mode = P54_FILTER_TYPE_HIBERNATE;
 
        setup->mac_mode = cpu_to_le16(mode);
        memcpy(setup->mac_addr, priv->mac_addr, ETH_ALEN);
@@ -1868,7 +1871,7 @@ static int p54_scan(struct ieee80211_hw *dev, u16 mode, u16 dwell)
        return -EINVAL;
 }
 
-static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act)
+static int p54_set_leds(struct ieee80211_hw *dev)
 {
        struct p54_common *priv = dev->priv;
        struct sk_buff *skb;
@@ -1879,11 +1882,11 @@ static int p54_set_leds(struct ieee80211_hw *dev, int mode, int link, int act)
        if (!skb)
                return -ENOMEM;
 
-       led = (struct p54_led *)skb_put(skb, sizeof(*led));
-       led->mode = cpu_to_le16(mode);
-       led->led_permanent = cpu_to_le16(link);
-       led->led_temporary = cpu_to_le16(act);
-       led->duration = cpu_to_le16(1000);
+       led = (struct p54_led *) skb_put(skb, sizeof(*led));
+       led->flags = cpu_to_le16(0x0003);
+       led->mask[0] = led->mask[1] = cpu_to_le16(priv->softled_state);
+       led->delay[0] = cpu_to_le16(1);
+       led->delay[1] = cpu_to_le16(0);
        priv->tx(dev, skb);
        return 0;
 }
@@ -2067,6 +2070,9 @@ static int p54_start(struct ieee80211_hw *dev)
 
        queue_delayed_work(dev->workqueue, &priv->work, 0);
 
+       priv->softled_state = 0;
+       err = p54_set_leds(dev);
+
 out:
        mutex_unlock(&priv->conf_mutex);
        return err;
@@ -2079,6 +2085,9 @@ static void p54_stop(struct ieee80211_hw *dev)
 
        mutex_lock(&priv->conf_mutex);
        priv->mode = NL80211_IFTYPE_UNSPECIFIED;
+       priv->softled_state = 0;
+       p54_set_leds(dev);
+
        cancel_delayed_work_sync(&priv->work);
        if (priv->cached_beacon)
                p54_tx_cancel(dev, priv->cached_beacon);
@@ -2116,7 +2125,6 @@ static int p54_add_interface(struct ieee80211_hw *dev,
 
        memcpy(priv->mac_addr, conf->mac_addr, ETH_ALEN);
        p54_setup_mac(dev);
-       p54_set_leds(dev, 1, 0, 0);
        mutex_unlock(&priv->conf_mutex);
        return 0;
 }
@@ -2196,8 +2204,6 @@ static int p54_config_interface(struct ieee80211_hw *dev,
                        goto out;
        }
 
-       ret = p54_set_leds(dev, 1, !is_multicast_ether_addr(priv->bssid), 0);
-
 out:
        mutex_unlock(&priv->conf_mutex);
        return ret;
@@ -2211,9 +2217,7 @@ static void p54_configure_filter(struct ieee80211_hw *dev,
        struct p54_common *priv = dev->priv;
 
        *total_flags &= FIF_PROMISC_IN_BSS |
-                       FIF_OTHER_BSS |
-                       (*total_flags & FIF_PROMISC_IN_BSS) ?
-                               FIF_FCSFAIL : 0;
+                       FIF_OTHER_BSS;
 
        priv->filter_flags = *total_flags;
 
@@ -2416,6 +2420,96 @@ static int p54_set_key(struct ieee80211_hw *dev, enum set_key_cmd cmd,
        return 0;
 }
 
+#ifdef CONFIG_MAC80211_LEDS
+static void p54_led_brightness_set(struct led_classdev *led_dev,
+                                  enum led_brightness brightness)
+{
+       struct p54_led_dev *led = container_of(led_dev, struct p54_led_dev,
+                                              led_dev);
+       struct ieee80211_hw *dev = led->hw_dev;
+       struct p54_common *priv = dev->priv;
+       int err;
+
+       /* Don't toggle the LED, when the device is down. */
+       if (priv->mode == NL80211_IFTYPE_UNSPECIFIED)
+               return ;
+
+       if (brightness != LED_OFF)
+               priv->softled_state |= BIT(led->index);
+       else
+               priv->softled_state &= ~BIT(led->index);
+
+       err = p54_set_leds(dev);
+       if (err && net_ratelimit())
+               printk(KERN_ERR "%s: failed to update %s LED.\n",
+                       wiphy_name(dev->wiphy), led_dev->name);
+}
+
+static int p54_register_led(struct ieee80211_hw *dev,
+                           struct p54_led_dev *led,
+                           unsigned int led_index,
+                           char *name, char *trigger)
+{
+       int err;
+
+       if (led->registered)
+               return -EEXIST;
+
+       snprintf(led->name, sizeof(led->name), "p54-%s::%s",
+                wiphy_name(dev->wiphy), name);
+       led->hw_dev = dev;
+       led->index = led_index;
+       led->led_dev.name = led->name;
+       led->led_dev.default_trigger = trigger;
+       led->led_dev.brightness_set = p54_led_brightness_set;
+
+       err = led_classdev_register(wiphy_dev(dev->wiphy), &led->led_dev);
+       if (err)
+               printk(KERN_ERR "%s: Failed to register %s LED.\n",
+                       wiphy_name(dev->wiphy), name);
+       else
+               led->registered = 1;
+
+       return err;
+}
+
+static int p54_init_leds(struct ieee80211_hw *dev)
+{
+       struct p54_common *priv = dev->priv;
+       int err;
+
+       /*
+        * TODO:
+        * Figure out if the EEPROM contains some hints about the number
+        * of available/programmable LEDs of the device.
+        * But for now, we can assume that we have two programmable LEDs.
+        */
+
+       err = p54_register_led(dev, &priv->assoc_led, 0, "assoc",
+                              ieee80211_get_assoc_led_name(dev));
+       if (err)
+               return err;
+
+       err = p54_register_led(dev, &priv->tx_led, 1, "tx",
+                              ieee80211_get_tx_led_name(dev));
+       if (err)
+               return err;
+
+       err = p54_set_leds(dev);
+       return err;
+}
+
+static void p54_unregister_leds(struct ieee80211_hw *dev)
+{
+       struct p54_common *priv = dev->priv;
+
+       if (priv->tx_led.registered)
+               led_classdev_unregister(&priv->tx_led.led_dev);
+       if (priv->assoc_led.registered)
+               led_classdev_unregister(&priv->assoc_led.led_dev);
+}
+#endif /* CONFIG_MAC80211_LEDS */
+
 static const struct ieee80211_ops p54_ops = {
        .tx                     = p54_tx,
        .start                  = p54_start,
@@ -2449,6 +2543,8 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
        priv->basic_rate_mask = 0x15f;
        skb_queue_head_init(&priv->tx_queue);
        dev->flags = IEEE80211_HW_RX_INCLUDES_FCS |
+                    IEEE80211_HW_SUPPORTS_PS |
+                    IEEE80211_HW_PS_NULLFUNC_STACK |
                     IEEE80211_HW_SIGNAL_DBM |
                     IEEE80211_HW_NOISE_DBM;
 
@@ -2486,12 +2582,37 @@ struct ieee80211_hw *p54_init_common(size_t priv_data_len)
 }
 EXPORT_SYMBOL_GPL(p54_init_common);
 
+int p54_register_common(struct ieee80211_hw *dev, struct device *pdev)
+{
+       int err;
+
+       err = ieee80211_register_hw(dev);
+       if (err) {
+               dev_err(pdev, "Cannot register device (%d).\n", err);
+               return err;
+       }
+
+       #ifdef CONFIG_MAC80211_LEDS
+       err = p54_init_leds(dev);
+       if (err)
+               return err;
+       #endif /* CONFIG_MAC80211_LEDS */
+
+       dev_info(pdev, "is registered as '%s'\n", wiphy_name(dev->wiphy));
+       return 0;
+}
+EXPORT_SYMBOL_GPL(p54_register_common);
+
 void p54_free_common(struct ieee80211_hw *dev)
 {
        struct p54_common *priv = dev->priv;
        kfree(priv->iq_autocal);
        kfree(priv->output_limit);
        kfree(priv->curve_data);
+
+       #ifdef CONFIG_MAC80211_LEDS
+       p54_unregister_leds(dev);
+       #endif /* CONFIG_MAC80211_LEDS */
 }
 EXPORT_SYMBOL_GPL(p54_free_common);
 
index def23b1f49ec4c261b40ca0fac5fde6053e775ca..75ead7a150fc64f63800224cbdd0c024e1baaa86 100644 (file)
@@ -515,10 +515,9 @@ struct p54_scan_tail_rate {
 } __attribute__ ((packed));
 
 struct p54_led {
-       __le16 mode;
-       __le16 led_temporary;
-       __le16 led_permanent;
-       __le16 duration;
+       __le16 flags;
+       __le16 mask[2];
+       __le16 delay[2];
 } __attribute__ ((packed));
 
 struct p54_edcf {
index 3f9a6b04ea95f34a7f1b5e8e57be4c2ead029bfe..e3569a0a952d2b6ca9e951a72c6bb10375da0a45 100644 (file)
@@ -413,8 +413,7 @@ static int p54p_open(struct ieee80211_hw *dev)
        err = request_irq(priv->pdev->irq, &p54p_interrupt,
                          IRQF_SHARED, "p54pci", dev);
        if (err) {
-               printk(KERN_ERR "%s: failed to register IRQ handler\n",
-                      wiphy_name(dev->wiphy));
+               dev_err(&priv->pdev->dev, "failed to register IRQ handler\n");
                return err;
        }
 
@@ -476,30 +475,26 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
 
        err = pci_enable_device(pdev);
        if (err) {
-               printk(KERN_ERR "%s (p54pci): Cannot enable new PCI device\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "Cannot enable new PCI device\n");
                return err;
        }
 
        mem_addr = pci_resource_start(pdev, 0);
        mem_len = pci_resource_len(pdev, 0);
        if (mem_len < sizeof(struct p54p_csr)) {
-               printk(KERN_ERR "%s (p54pci): Too short PCI resources\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "Too short PCI resources\n");
                goto err_disable_dev;
        }
 
        err = pci_request_regions(pdev, "p54pci");
        if (err) {
-               printk(KERN_ERR "%s (p54pci): Cannot obtain PCI resources\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "Cannot obtain PCI resources\n");
                goto err_disable_dev;
        }
 
        if (pci_set_dma_mask(pdev, DMA_32BIT_MASK) ||
            pci_set_consistent_dma_mask(pdev, DMA_32BIT_MASK)) {
-               printk(KERN_ERR "%s (p54pci): No suitable DMA available\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "No suitable DMA available\n");
                goto err_free_reg;
        }
 
@@ -511,8 +506,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
 
        dev = p54_init_common(sizeof(*priv));
        if (!dev) {
-               printk(KERN_ERR "%s (p54pci): ieee80211 alloc failed\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "ieee80211 alloc failed\n");
                err = -ENOMEM;
                goto err_free_reg;
        }
@@ -525,17 +519,15 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
 
        priv->map = ioremap(mem_addr, mem_len);
        if (!priv->map) {
-               printk(KERN_ERR "%s (p54pci): Cannot map device memory\n",
-                      pci_name(pdev));
-               err = -EINVAL;  // TODO: use a better error code?
+               dev_err(&pdev->dev, "Cannot map device memory\n");
+               err = -ENOMEM;
                goto err_free_dev;
        }
 
        priv->ring_control = pci_alloc_consistent(pdev, sizeof(*priv->ring_control),
                                                  &priv->ring_control_dma);
        if (!priv->ring_control) {
-               printk(KERN_ERR "%s (p54pci): Cannot allocate rings\n",
-                      pci_name(pdev));
+               dev_err(&pdev->dev, "Cannot allocate rings\n");
                err = -ENOMEM;
                goto err_iounmap;
        }
@@ -549,8 +541,7 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
        err = request_firmware(&priv->firmware, "isl3886pci",
                               &priv->pdev->dev);
        if (err) {
-               printk(KERN_ERR "%s (p54pci): cannot find firmware "
-                       "(isl3886pci)\n", pci_name(priv->pdev));
+               dev_err(&pdev->dev, "Cannot find firmware (isl3886pci)\n");
                err = request_firmware(&priv->firmware, "isl3886",
                                       &priv->pdev->dev);
                if (err)
@@ -565,12 +556,9 @@ static int __devinit p54p_probe(struct pci_dev *pdev,
        if (err)
                goto err_free_common;
 
-       err = ieee80211_register_hw(dev);
-       if (err) {
-               printk(KERN_ERR "%s (p54pci): Cannot register netdevice\n",
-                      pci_name(pdev));
+       err = p54_register_common(dev, &pdev->dev);
+       if (err)
                goto err_free_common;
-       }
 
        return 0;
 
index 7fde243b3d5d50e2c43c0e1c941590bb23904ee4..2b222aaa6f0ad0226008e2fb04714e78ba76ad45 100644 (file)
@@ -694,15 +694,10 @@ static int __devinit p54spi_probe(struct spi_device *spi)
        if (ret)
                goto err_free_common;
 
-       ret = ieee80211_register_hw(hw);
-       if (ret) {
-               dev_err(&priv->spi->dev, "unable to register "
-                                        "mac80211 hw: %d", ret);
+       ret = p54_register_common(hw, &priv->spi->dev);
+       if (ret)
                goto err_free_common;
-       }
 
-       dev_info(&priv->spi->dev, "device is bound to %s\n",
-                wiphy_name(hw->wiphy));
        return 0;
 
 err_free_common:
index 9539ddcf379ff08cedc0a2b93daf05594a97f425..da6640afc835527a98078c617872e7b63f21f1e4 100644 (file)
@@ -976,11 +976,9 @@ static int __devinit p54u_probe(struct usb_interface *intf,
        if (err)
                goto err_free_dev;
 
-       err = ieee80211_register_hw(dev);
-       if (err) {
-               dev_err(&udev->dev, "(p54usb) Cannot register netdevice\n");
+       err = p54_register_common(dev, &udev->dev);
+       if (err)
                goto err_free_dev;
-       }
 
        return 0;
 
@@ -1024,6 +1022,7 @@ static struct usb_driver p54u_driver = {
        .disconnect = p54u_disconnect,
        .pre_reset = p54u_pre_reset,
        .post_reset = p54u_post_reset,
+       .soft_unbind = 1,
 };
 
 static int __init p54u_init(void)
index 9196825ed1b52539d92aad7bfa7de1db7c88529d..166ed95846017c0463f5ab65a78acc8e5048aa49 100644 (file)
@@ -43,7 +43,6 @@
 
 static int prism54_bring_down(islpci_private *);
 static int islpci_alloc_memory(islpci_private *);
-static struct net_device_stats *islpci_statistics(struct net_device *);
 
 /* Temporary dummy MAC address to use until firmware is loaded.
  * The idea there is that some tools (such as nameif) may query
@@ -614,18 +613,6 @@ islpci_reset(islpci_private *priv, int reload_firmware)
        return rc;
 }
 
-static struct net_device_stats *
-islpci_statistics(struct net_device *ndev)
-{
-       islpci_private *priv = netdev_priv(ndev);
-
-#if VERBOSE > SHOW_ERROR_MESSAGES
-       DEBUG(SHOW_FUNCTION_CALLS, "islpci_statistics\n");
-#endif
-
-       return &priv->statistics;
-}
-
 /******************************************************************************
     Network device configuration functions
 ******************************************************************************/
@@ -804,10 +791,22 @@ static void islpci_ethtool_get_drvinfo(struct net_device *dev,
        strcpy(info->version, DRV_VERSION);
 }
 
-static struct ethtool_ops islpci_ethtool_ops = {
+static const struct ethtool_ops islpci_ethtool_ops = {
        .get_drvinfo = islpci_ethtool_get_drvinfo,
 };
 
+static const struct net_device_ops islpci_netdev_ops = {
+       .ndo_open               = islpci_open,
+       .ndo_stop               = islpci_close,
+       .ndo_do_ioctl           = prism54_ioctl,
+       .ndo_start_xmit         = islpci_eth_transmit,
+       .ndo_tx_timeout         = islpci_eth_tx_timeout,
+       .ndo_set_mac_address    = prism54_set_mac_address,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 struct net_device *
 islpci_setup(struct pci_dev *pdev)
 {
@@ -827,25 +826,16 @@ islpci_setup(struct pci_dev *pdev)
        ndev->irq = pdev->irq;
 
        /* initialize the function pointers */
-       ndev->open = &islpci_open;
-       ndev->stop = &islpci_close;
-       ndev->get_stats = &islpci_statistics;
-       ndev->do_ioctl = &prism54_ioctl;
-       ndev->wireless_handlers =
-           (struct iw_handler_def *) &prism54_handler_def;
+       ndev->netdev_ops = &islpci_netdev_ops;
+       ndev->wireless_handlers = &prism54_handler_def;
        ndev->ethtool_ops = &islpci_ethtool_ops;
 
-       ndev->hard_start_xmit = &islpci_eth_transmit;
        /* ndev->set_multicast_list = &islpci_set_multicast_list; */
        ndev->addr_len = ETH_ALEN;
-       ndev->set_mac_address = &prism54_set_mac_address;
        /* Get a non-zero dummy MAC address for nameif. Jean II */
        memcpy(ndev->dev_addr, dummy_mac, 6);
 
-#ifdef HAVE_TX_TIMEOUT
        ndev->watchdog_timeo = ISLPCI_TX_TIMEOUT;
-       ndev->tx_timeout = &islpci_eth_tx_timeout;
-#endif
 
        /* allocate a private device structure to the network device  */
        priv = netdev_priv(ndev);
index 8e55a5fcffaedaa2e1d181ed6ec65cc62f3b639c..c4d0f19b7cbc2036c67a9e9d4b7326bc1f29f1d8 100644 (file)
@@ -158,9 +158,6 @@ typedef struct {
        dma_addr_t pci_map_tx_address[ISL38XX_CB_TX_QSIZE];
        dma_addr_t pci_map_rx_address[ISL38XX_CB_RX_QSIZE];
 
-       /* driver network interface members */
-       struct net_device_stats statistics;
-
        /* wait for a reset interrupt */
        wait_queue_head_t reset_done;
 
index 88895bd9e495b024847ba2ed221224c79328a454..ef3ef4551b31af3c797b54dcfa4906f5bb722f9b 100644 (file)
@@ -231,8 +231,8 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
 
        /* set the transmission time */
        ndev->trans_start = jiffies;
-       priv->statistics.tx_packets++;
-       priv->statistics.tx_bytes += skb->len;
+       ndev->stats.tx_packets++;
+       ndev->stats.tx_bytes += skb->len;
 
        /* trigger the device */
        islpci_trigger(priv);
@@ -243,7 +243,7 @@ islpci_eth_transmit(struct sk_buff *skb, struct net_device *ndev)
        return 0;
 
       drop_free:
-       priv->statistics.tx_dropped++;
+       ndev->stats.tx_dropped++;
        spin_unlock_irqrestore(&priv->slock, flags);
        dev_kfree_skb(skb);
        return err;
@@ -408,8 +408,8 @@ islpci_eth_receive(islpci_private *priv)
                skb->protocol = eth_type_trans(skb, ndev);
        }
        skb->ip_summed = CHECKSUM_NONE;
-       priv->statistics.rx_packets++;
-       priv->statistics.rx_bytes += size;
+       ndev->stats.rx_packets++;
+       ndev->stats.rx_bytes += size;
 
        /* deliver the skb to the network layer */
 #ifdef ISLPCI_ETH_DEBUG
@@ -497,10 +497,9 @@ void
 islpci_eth_tx_timeout(struct net_device *ndev)
 {
        islpci_private *priv = netdev_priv(ndev);
-       struct net_device_stats *statistics = &priv->statistics;
 
        /* increment the transmit error counter */
-       statistics->tx_errors++;
+       ndev->stats.tx_errors++;
 
        if (!priv->reset_task_pending) {
                printk(KERN_WARNING
index 99ec7d62251813e95caf0c72bac8c1c0439fe3fe..fa90d1d8d82ee08331d416882b9a21f0bbe071af 100644 (file)
@@ -8,7 +8,7 @@
  * Copyright (c) 1998  Corey Thomas (corey@world.std.com)
  *
  * This driver is free software; you can redistribute it and/or modify
- * it under the terms of version 2 only of the GNU General Public License as 
+ * it under the terms of version 2 only of the GNU General Public License as
  * published by the Free Software Foundation.
  *
  * It is distributed in the hope that it will be useful,
@@ -27,7 +27,7 @@
  *
  * Daniele Bellucci <bellucda@tiscali.it> - 07/10/2003
  * - Audit copy_to_user in ioctl(SIOCGIWESSID)
- * 
+ *
 =============================================================================*/
 
 #include <linux/module.h>
@@ -65,8 +65,8 @@
 /* Warning : these stuff will slow down the driver... */
 #define WIRELESS_SPY           /* Enable spying addresses */
 /* Definitions we need for spy */
-typedef struct iw_statistics   iw_stats;
-typedef u_char mac_addr[ETH_ALEN];     /* Hardware address */
+typedef struct iw_statistics iw_stats;
+typedef u_char mac_addr[ETH_ALEN];     /* Hardware address */
 
 #include "rayctl.h"
 #include "ray_cs.h"
@@ -86,7 +86,7 @@ static int ray_debug;
 static int pc_debug = PCMCIA_DEBUG;
 module_param(pc_debug, int, 0);
 /* #define DEBUG(n, args...) if (pc_debug>(n)) printk(KERN_DEBUG args); */
-#define DEBUG(n, args...) if (pc_debug>(n)) printk(args);
+#define DEBUG(n, args...) if (pc_debug > (n)) printk(args);
 #else
 #define DEBUG(n, args...)
 #endif
@@ -108,12 +108,12 @@ static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev);
 static void set_multicast_list(struct net_device *dev);
 static void ray_update_multi_list(struct net_device *dev, int all);
 static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx,
-                unsigned char *data, int len);
-static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, UCHAR msg_type,
-                unsigned char *data);
+                          unsigned char *data, int len);
+static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx,
+                            UCHAR msg_type, unsigned char *data);
 static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len);
-static iw_stats * ray_get_wireless_stats(struct net_device *   dev);
-static const struct iw_handler_def     ray_handler_def;
+static iw_stats *ray_get_wireless_stats(struct net_device *dev);
+static const struct iw_handler_def ray_handler_def;
 
 /***** Prototypes for raylink functions **************************************/
 static int asc_to_int(char a);
@@ -124,7 +124,7 @@ static int get_free_ccs(ray_dev_t *local);
 static int get_free_tx_ccs(ray_dev_t *local);
 static void init_startup_params(ray_dev_t *local);
 static int parse_addr(char *in_str, UCHAR *out);
-static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, UCHAR type);
+static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev, UCHAR type);
 static int ray_init(struct net_device *dev);
 static int interrupt_ecf(ray_dev_t *local, int ccs);
 static void ray_reset(struct net_device *dev);
@@ -132,17 +132,17 @@ static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, i
 static void verify_dl_startup(u_long);
 
 /* Prototypes for interrpt time functions **********************************/
-static irqreturn_t ray_interrupt (int reg, void *dev_id);
+static irqreturn_t ray_interrupt(int reg, void *dev_id);
 static void clear_interrupt(ray_dev_t *local);
-static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, 
-                       unsigned int pkt_addr, int rx_len);
+static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs,
+                             unsigned int pkt_addr, int rx_len);
 static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int len);
 static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs __iomem *prcs);
 static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs);
 static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs,
-                     unsigned int pkt_addr, int rx_len);
-static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned int pkt_addr, 
-             int rx_len);
+                           unsigned int pkt_addr, int rx_len);
+static void rx_data(struct net_device *dev, struct rcs __iomem *prcs,
+                   unsigned int pkt_addr, int rx_len);
 static void associate(ray_dev_t *local);
 
 /* Card command functions */
@@ -219,82 +219,97 @@ module_param(phy_addr, charp, 0);
 module_param(ray_mem_speed, int, 0);
 
 static UCHAR b5_default_startup_parms[] = {
-    0,   0,                         /* Adhoc station */
-   'L','I','N','U','X', 0,  0,  0,  /* 32 char ESSID */
-    0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,
-    1,  0,                          /* Active scan, CA Mode */
-    0,  0,  0,  0,  0,  0,          /* No default MAC addr  */
-    0x7f, 0xff,                     /* Frag threshold */
-    0x00, 0x80,                     /* Hop time 128 Kus*/
-    0x01, 0x00,                     /* Beacon period 256 Kus */
-    0x01, 0x07, 0xa3,               /* DTIM, retries, ack timeout*/
-    0x1d, 0x82, 0x4e,               /* SIFS, DIFS, PIFS */
-    0x7f, 0xff,                     /* RTS threshold */
-    0x04, 0xe2, 0x38, 0xA4,         /* scan_dwell, max_scan_dwell */
-    0x05,                           /* assoc resp timeout thresh */
-    0x08, 0x02, 0x08,               /* adhoc, infra, super cycle max*/
-    0,                              /* Promiscuous mode */
-    0x0c, 0x0bd,                    /* Unique word */
-    0x32,                           /* Slot time */
-    0xff, 0xff,                     /* roam-low snr, low snr count */
-    0x05, 0xff,                     /* Infra, adhoc missed bcn thresh */
-    0x01, 0x0b, 0x4f,               /* USA, hop pattern, hop pat length */
+       0, 0,                   /* Adhoc station */
+       'L', 'I', 'N', 'U', 'X', 0, 0, 0,       /* 32 char ESSID */
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       1, 0,                   /* Active scan, CA Mode */
+       0, 0, 0, 0, 0, 0,       /* No default MAC addr  */
+       0x7f, 0xff,             /* Frag threshold */
+       0x00, 0x80,             /* Hop time 128 Kus */
+       0x01, 0x00,             /* Beacon period 256 Kus */
+       0x01, 0x07, 0xa3,       /* DTIM, retries, ack timeout */
+       0x1d, 0x82, 0x4e,       /* SIFS, DIFS, PIFS */
+       0x7f, 0xff,             /* RTS threshold */
+       0x04, 0xe2, 0x38, 0xA4, /* scan_dwell, max_scan_dwell */
+       0x05,                   /* assoc resp timeout thresh */
+       0x08, 0x02, 0x08,       /* adhoc, infra, super cycle max */
+       0,                      /* Promiscuous mode */
+       0x0c, 0x0bd,            /* Unique word */
+       0x32,                   /* Slot time */
+       0xff, 0xff,             /* roam-low snr, low snr count */
+       0x05, 0xff,             /* Infra, adhoc missed bcn thresh */
+       0x01, 0x0b, 0x4f,       /* USA, hop pattern, hop pat length */
 /* b4 - b5 differences start here */
-    0x00, 0x3f,                     /* CW max */
-    0x00, 0x0f,                     /* CW min */
-    0x04, 0x08,                     /* Noise gain, limit offset */
-    0x28, 0x28,                     /* det rssi, med busy offsets */
-    7,                              /* det sync thresh */
-    0, 2, 2,                        /* test mode, min, max */
-    0,                              /* allow broadcast SSID probe resp */
-    0, 0,                           /* privacy must start, can join */
-    2, 0, 0, 0, 0, 0, 0, 0          /* basic rate set */
+       0x00, 0x3f,             /* CW max */
+       0x00, 0x0f,             /* CW min */
+       0x04, 0x08,             /* Noise gain, limit offset */
+       0x28, 0x28,             /* det rssi, med busy offsets */
+       7,                      /* det sync thresh */
+       0, 2, 2,                /* test mode, min, max */
+       0,                      /* allow broadcast SSID probe resp */
+       0, 0,                   /* privacy must start, can join */
+       2, 0, 0, 0, 0, 0, 0, 0  /* basic rate set */
 };
 
 static UCHAR b4_default_startup_parms[] = {
-    0,   0,                         /* Adhoc station */
-   'L','I','N','U','X', 0,  0,  0,  /* 32 char ESSID */
-    0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,
-    0,  0,  0,  0,  0,  0,  0,  0,
-    1,  0,                          /* Active scan, CA Mode */
-    0,  0,  0,  0,  0,  0,          /* No default MAC addr  */
-    0x7f, 0xff,                     /* Frag threshold */
-    0x02, 0x00,                     /* Hop time */
-    0x00, 0x01,                     /* Beacon period */
-    0x01, 0x07, 0xa3,               /* DTIM, retries, ack timeout*/
-    0x1d, 0x82, 0xce,               /* SIFS, DIFS, PIFS */
-    0x7f, 0xff,                     /* RTS threshold */
-    0xfb, 0x1e, 0xc7, 0x5c,         /* scan_dwell, max_scan_dwell */
-    0x05,                           /* assoc resp timeout thresh */
-    0x04, 0x02, 0x4,                /* adhoc, infra, super cycle max*/
-    0,                              /* Promiscuous mode */
-    0x0c, 0x0bd,                    /* Unique word */
-    0x4e,                           /* Slot time (TBD seems wrong)*/
-    0xff, 0xff,                     /* roam-low snr, low snr count */
-    0x05, 0xff,                     /* Infra, adhoc missed bcn thresh */
-    0x01, 0x0b, 0x4e,               /* USA, hop pattern, hop pat length */
+       0, 0,                   /* Adhoc station */
+       'L', 'I', 'N', 'U', 'X', 0, 0, 0,       /* 32 char ESSID */
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       0, 0, 0, 0, 0, 0, 0, 0,
+       1, 0,                   /* Active scan, CA Mode */
+       0, 0, 0, 0, 0, 0,       /* No default MAC addr  */
+       0x7f, 0xff,             /* Frag threshold */
+       0x02, 0x00,             /* Hop time */
+       0x00, 0x01,             /* Beacon period */
+       0x01, 0x07, 0xa3,       /* DTIM, retries, ack timeout */
+       0x1d, 0x82, 0xce,       /* SIFS, DIFS, PIFS */
+       0x7f, 0xff,             /* RTS threshold */
+       0xfb, 0x1e, 0xc7, 0x5c, /* scan_dwell, max_scan_dwell */
+       0x05,                   /* assoc resp timeout thresh */
+       0x04, 0x02, 0x4,        /* adhoc, infra, super cycle max */
+       0,                      /* Promiscuous mode */
+       0x0c, 0x0bd,            /* Unique word */
+       0x4e,                   /* Slot time (TBD seems wrong) */
+       0xff, 0xff,             /* roam-low snr, low snr count */
+       0x05, 0xff,             /* Infra, adhoc missed bcn thresh */
+       0x01, 0x0b, 0x4e,       /* USA, hop pattern, hop pat length */
 /* b4 - b5 differences start here */
-    0x3f, 0x0f,                     /* CW max, min */
-    0x04, 0x08,                     /* Noise gain, limit offset */
-    0x28, 0x28,                     /* det rssi, med busy offsets */
-    7,                              /* det sync thresh */
-    0, 2, 2                         /* test mode, min, max*/
+       0x3f, 0x0f,             /* CW max, min */
+       0x04, 0x08,             /* Noise gain, limit offset */
+       0x28, 0x28,             /* det rssi, med busy offsets */
+       7,                      /* det sync thresh */
+       0, 2, 2                 /* test mode, min, max */
 };
+
 /*===========================================================================*/
-static unsigned char eth2_llc[] = {0xaa, 0xaa, 3, 0, 0, 0};
+static unsigned char eth2_llc[] = { 0xaa, 0xaa, 3, 0, 0, 0 };
 
 static char hop_pattern_length[] = { 1,
-            USA_HOP_MOD,             EUROPE_HOP_MOD,
-            JAPAN_HOP_MOD,           KOREA_HOP_MOD,
-            SPAIN_HOP_MOD,           FRANCE_HOP_MOD,
-            ISRAEL_HOP_MOD,          AUSTRALIA_HOP_MOD,
-            JAPAN_TEST_HOP_MOD
+       USA_HOP_MOD, EUROPE_HOP_MOD,
+       JAPAN_HOP_MOD, KOREA_HOP_MOD,
+       SPAIN_HOP_MOD, FRANCE_HOP_MOD,
+       ISRAEL_HOP_MOD, AUSTRALIA_HOP_MOD,
+       JAPAN_TEST_HOP_MOD
 };
 
-static char rcsid[] = "Raylink/WebGear wireless LAN - Corey <Thomas corey@world.std.com>";
+static char rcsid[] =
+    "Raylink/WebGear wireless LAN - Corey <Thomas corey@world.std.com>";
+
+static const struct net_device_ops ray_netdev_ops = {
+       .ndo_init               = ray_dev_init,
+       .ndo_open               = ray_open,
+       .ndo_stop               = ray_dev_close,
+       .ndo_start_xmit         = ray_dev_start_xmit,
+       .ndo_set_config         = ray_dev_config,
+       .ndo_get_stats          = ray_get_stats,
+       .ndo_set_multicast_list = set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
 
 /*=============================================================================
     ray_attach() creates an "instance" of the driver, allocating
@@ -306,71 +321,66 @@ static char rcsid[] = "Raylink/WebGear wireless LAN - Corey <Thomas corey@world.
 =============================================================================*/
 static int ray_probe(struct pcmcia_device *p_dev)
 {
-    ray_dev_t *local;
-    struct net_device *dev;
-
-    DEBUG(1, "ray_attach()\n");
-
-    /* Allocate space for private device-specific data */
-    dev = alloc_etherdev(sizeof(ray_dev_t));
-    if (!dev)
-           goto fail_alloc_dev;
-
-    local = netdev_priv(dev);
-    local->finder = p_dev;
-
-    /* The io structure describes IO port mapping. None used here */
-    p_dev->io.NumPorts1 = 0;
-    p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
-    p_dev->io.IOAddrLines = 5;
-
-    /* Interrupt setup. For PCMCIA, driver takes what's given */
-    p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
-    p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
-    p_dev->irq.Handler = &ray_interrupt;
-
-    /* General socket configuration */
-    p_dev->conf.Attributes = CONF_ENABLE_IRQ;
-    p_dev->conf.IntType = INT_MEMORY_AND_IO;
-    p_dev->conf.ConfigIndex = 1;
-
-    p_dev->priv = dev;
-    p_dev->irq.Instance = dev;
-    
-    local->finder = p_dev;
-    local->card_status = CARD_INSERTED;
-    local->authentication_state = UNAUTHENTICATED;
-    local->num_multi = 0;
-    DEBUG(2,"ray_attach p_dev = %p,  dev = %p,  local = %p, intr = %p\n",
-          p_dev,dev,local,&ray_interrupt);
-
-    /* Raylink entries in the device structure */
-    dev->hard_start_xmit = &ray_dev_start_xmit;
-    dev->set_config = &ray_dev_config;
-    dev->get_stats  = &ray_get_stats;
-    SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
-    dev->wireless_handlers = &ray_handler_def;
+       ray_dev_t *local;
+       struct net_device *dev;
+
+       DEBUG(1, "ray_attach()\n");
+
+       /* Allocate space for private device-specific data */
+       dev = alloc_etherdev(sizeof(ray_dev_t));
+       if (!dev)
+               goto fail_alloc_dev;
+
+       local = netdev_priv(dev);
+       local->finder = p_dev;
+
+       /* The io structure describes IO port mapping. None used here */
+       p_dev->io.NumPorts1 = 0;
+       p_dev->io.Attributes1 = IO_DATA_PATH_WIDTH_8;
+       p_dev->io.IOAddrLines = 5;
+
+       /* Interrupt setup. For PCMCIA, driver takes what's given */
+       p_dev->irq.Attributes = IRQ_TYPE_DYNAMIC_SHARING | IRQ_HANDLE_PRESENT;
+       p_dev->irq.IRQInfo1 = IRQ_LEVEL_ID;
+       p_dev->irq.Handler = &ray_interrupt;
+
+       /* General socket configuration */
+       p_dev->conf.Attributes = CONF_ENABLE_IRQ;
+       p_dev->conf.IntType = INT_MEMORY_AND_IO;
+       p_dev->conf.ConfigIndex = 1;
+
+       p_dev->priv = dev;
+       p_dev->irq.Instance = dev;
+
+       local->finder = p_dev;
+       local->card_status = CARD_INSERTED;
+       local->authentication_state = UNAUTHENTICATED;
+       local->num_multi = 0;
+       DEBUG(2, "ray_attach p_dev = %p,  dev = %p,  local = %p, intr = %p\n",
+             p_dev, dev, local, &ray_interrupt);
+
+       /* Raylink entries in the device structure */
+       dev->netdev_ops = &ray_netdev_ops;
+       SET_ETHTOOL_OPS(dev, &netdev_ethtool_ops);
+       dev->wireless_handlers = &ray_handler_def;
 #ifdef WIRELESS_SPY
-    local->wireless_data.spy_data = &local->spy_data;
-    dev->wireless_data = &local->wireless_data;
-#endif /* WIRELESS_SPY */
+       local->wireless_data.spy_data = &local->spy_data;
+       dev->wireless_data = &local->wireless_data;
+#endif /* WIRELESS_SPY */
 
-    dev->set_multicast_list = &set_multicast_list;
 
-    DEBUG(2,"ray_cs ray_attach calling ether_setup.)\n");
-    dev->init = &ray_dev_init;
-    dev->open = &ray_open;
-    dev->stop = &ray_dev_close;
-    netif_stop_queue(dev);
+       DEBUG(2, "ray_cs ray_attach calling ether_setup.)\n");
+       netif_stop_queue(dev);
 
-    init_timer(&local->timer);
+       init_timer(&local->timer);
 
-    this_device = p_dev;
-    return ray_config(p_dev);
+       this_device = p_dev;
+       return ray_config(p_dev);
 
 fail_alloc_dev:
-    return -ENOMEM;
+       return -ENOMEM;
 } /* ray_attach */
+
 /*=============================================================================
     This deletes a driver "instance".  The device is de-registered
     with Card Services.  If it has been released, all local data
@@ -379,25 +389,27 @@ fail_alloc_dev:
 =============================================================================*/
 static void ray_detach(struct pcmcia_device *link)
 {
-    struct net_device *dev;
-    ray_dev_t *local;
+       struct net_device *dev;
+       ray_dev_t *local;
 
-    DEBUG(1, "ray_detach(0x%p)\n", link);
+       DEBUG(1, "ray_detach(0x%p)\n", link);
 
-    this_device = NULL;
-    dev = link->priv;
+       this_device = NULL;
+       dev = link->priv;
 
-    ray_release(link);
+       ray_release(link);
 
-    local = netdev_priv(dev);
-    del_timer(&local->timer);
+       local = netdev_priv(dev);
+       del_timer(&local->timer);
 
-    if (link->priv) {
-       if (link->dev_node) unregister_netdev(dev);
-        free_netdev(dev);
-    }
-    DEBUG(2,"ray_cs ray_detach ending\n");
+       if (link->priv) {
+               if (link->dev_node)
+                       unregister_netdev(dev);
+               free_netdev(dev);
+       }
+       DEBUG(2, "ray_cs ray_detach ending\n");
 } /* ray_detach */
+
 /*=============================================================================
     ray_config() is run after a CARD_INSERTION event
     is received, to configure the PCMCIA socket, and to make the
@@ -408,92 +420,101 @@ do { last_fn = (fn); if ((last_ret = (ret)) != 0) goto cs_failed; } while (0)
 #define MAX_TUPLE_SIZE 128
 static int ray_config(struct pcmcia_device *link)
 {
-    int last_fn = 0, last_ret = 0;
-    int i;
-    win_req_t req;
-    memreq_t mem;
-    struct net_device *dev = (struct net_device *)link->priv;
-    ray_dev_t *local = netdev_priv(dev);
-
-    DEBUG(1, "ray_config(0x%p)\n", link);
-
-    /* Determine card type and firmware version */
-    printk(KERN_INFO "ray_cs Detected: %s%s%s%s\n",
-          link->prod_id[0] ? link->prod_id[0] : " ",
-          link->prod_id[1] ? link->prod_id[1] : " ",
-          link->prod_id[2] ? link->prod_id[2] : " ",
-          link->prod_id[3] ? link->prod_id[3] : " ");
-
-    /* Now allocate an interrupt line.  Note that this does not
-       actually assign a handler to the interrupt.
-    */
-    CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
-    dev->irq = link->irq.AssignedIRQ;
-    
-    /* This actually configures the PCMCIA socket -- setting up
-       the I/O windows and the interrupt mapping.
-    */
-    CS_CHECK(RequestConfiguration, pcmcia_request_configuration(link, &link->conf));
+       int last_fn = 0, last_ret = 0;
+       int i;
+       win_req_t req;
+       memreq_t mem;
+       struct net_device *dev = (struct net_device *)link->priv;
+       ray_dev_t *local = netdev_priv(dev);
+
+       DEBUG(1, "ray_config(0x%p)\n", link);
+
+       /* Determine card type and firmware version */
+       printk(KERN_INFO "ray_cs Detected: %s%s%s%s\n",
+              link->prod_id[0] ? link->prod_id[0] : " ",
+              link->prod_id[1] ? link->prod_id[1] : " ",
+              link->prod_id[2] ? link->prod_id[2] : " ",
+              link->prod_id[3] ? link->prod_id[3] : " ");
+
+       /* Now allocate an interrupt line.  Note that this does not
+          actually assign a handler to the interrupt.
+        */
+       CS_CHECK(RequestIRQ, pcmcia_request_irq(link, &link->irq));
+       dev->irq = link->irq.AssignedIRQ;
+
+       /* This actually configures the PCMCIA socket -- setting up
+          the I/O windows and the interrupt mapping.
+        */
+       CS_CHECK(RequestConfiguration,
+                pcmcia_request_configuration(link, &link->conf));
 
 /*** Set up 32k window for shared memory (transmit and control) ************/
-    req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
-    req.Base = 0;
-    req.Size = 0x8000;
-    req.AccessSpeed = ray_mem_speed;
-    CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win));
-    mem.CardOffset = 0x0000; mem.Page = 0;
-    CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem));
-    local->sram = ioremap(req.Base,req.Size);
+       req.Attributes =
+           WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
+       req.Base = 0;
+       req.Size = 0x8000;
+       req.AccessSpeed = ray_mem_speed;
+       CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &link->win));
+       mem.CardOffset = 0x0000;
+       mem.Page = 0;
+       CS_CHECK(MapMemPage, pcmcia_map_mem_page(link->win, &mem));
+       local->sram = ioremap(req.Base, req.Size);
 
 /*** Set up 16k window for shared memory (receive buffer) ***************/
-    req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
-    req.Base = 0;
-    req.Size = 0x4000;
-    req.AccessSpeed = ray_mem_speed;
-    CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &local->rmem_handle));
-    mem.CardOffset = 0x8000; mem.Page = 0;
-    CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->rmem_handle, &mem));
-    local->rmem = ioremap(req.Base,req.Size);
+       req.Attributes =
+           WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_CM | WIN_ENABLE | WIN_USE_WAIT;
+       req.Base = 0;
+       req.Size = 0x4000;
+       req.AccessSpeed = ray_mem_speed;
+       CS_CHECK(RequestWindow,
+                pcmcia_request_window(&link, &req, &local->rmem_handle));
+       mem.CardOffset = 0x8000;
+       mem.Page = 0;
+       CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->rmem_handle, &mem));
+       local->rmem = ioremap(req.Base, req.Size);
 
 /*** Set up window for attribute memory ***********************************/
-    req.Attributes = WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT;
-    req.Base = 0;
-    req.Size = 0x1000;
-    req.AccessSpeed = ray_mem_speed;
-    CS_CHECK(RequestWindow, pcmcia_request_window(&link, &req, &local->amem_handle));
-    mem.CardOffset = 0x0000; mem.Page = 0;
-    CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->amem_handle, &mem));
-    local->amem = ioremap(req.Base,req.Size);
-
-    DEBUG(3,"ray_config sram=%p\n",local->sram);
-    DEBUG(3,"ray_config rmem=%p\n",local->rmem);
-    DEBUG(3,"ray_config amem=%p\n",local->amem);
-    if (ray_init(dev) < 0) {
-        ray_release(link);
-        return -ENODEV;
-    }
-
-    SET_NETDEV_DEV(dev, &handle_to_dev(link));
-    i = register_netdev(dev);
-    if (i != 0) {
-        printk("ray_config register_netdev() failed\n");
-        ray_release(link);
-        return i;
-    }
-
-    strcpy(local->node.dev_name, dev->name);
-    link->dev_node = &local->node;
-
-    printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %pM\n",
-       dev->name, dev->irq, dev->dev_addr);
-
-    return 0;
+       req.Attributes =
+           WIN_DATA_WIDTH_8 | WIN_MEMORY_TYPE_AM | WIN_ENABLE | WIN_USE_WAIT;
+       req.Base = 0;
+       req.Size = 0x1000;
+       req.AccessSpeed = ray_mem_speed;
+       CS_CHECK(RequestWindow,
+                pcmcia_request_window(&link, &req, &local->amem_handle));
+       mem.CardOffset = 0x0000;
+       mem.Page = 0;
+       CS_CHECK(MapMemPage, pcmcia_map_mem_page(local->amem_handle, &mem));
+       local->amem = ioremap(req.Base, req.Size);
+
+       DEBUG(3, "ray_config sram=%p\n", local->sram);
+       DEBUG(3, "ray_config rmem=%p\n", local->rmem);
+       DEBUG(3, "ray_config amem=%p\n", local->amem);
+       if (ray_init(dev) < 0) {
+               ray_release(link);
+               return -ENODEV;
+       }
+
+       SET_NETDEV_DEV(dev, &handle_to_dev(link));
+       i = register_netdev(dev);
+       if (i != 0) {
+               printk("ray_config register_netdev() failed\n");
+               ray_release(link);
+               return i;
+       }
+
+       strcpy(local->node.dev_name, dev->name);
+       link->dev_node = &local->node;
+
+       printk(KERN_INFO "%s: RayLink, irq %d, hw_addr %pM\n",
+              dev->name, dev->irq, dev->dev_addr);
+
+       return 0;
 
 cs_failed:
-    cs_error(link, last_fn, last_ret);
+       cs_error(link, last_fn, last_ret);
 
-    ray_release(link);
-    return -ENODEV;
+       ray_release(link);
+       return -ENODEV;
 } /* ray_config */
 
 static inline struct ccs __iomem *ccs_base(ray_dev_t *dev)
@@ -516,267 +537,278 @@ static inline struct rcs __iomem *rcs_base(ray_dev_t *dev)
 /*===========================================================================*/
 static int ray_init(struct net_device *dev)
 {
-    int i;
-    UCHAR *p;
-    struct ccs __iomem *pccs;
-    ray_dev_t *local = netdev_priv(dev);
-    struct pcmcia_device *link = local->finder;
-    DEBUG(1, "ray_init(0x%p)\n", dev);
-    if (!(pcmcia_dev_present(link))) {
-        DEBUG(0,"ray_init - device not present\n");
-        return -1;
-    }
-
-    local->net_type = net_type;
-    local->sta_type = TYPE_STA;
-
-    /* Copy the startup results to local memory */
-    memcpy_fromio(&local->startup_res, local->sram + ECF_TO_HOST_BASE,\
-           sizeof(struct startup_res_6));
-
-    /* Check Power up test status and get mac address from card */
-    if (local->startup_res.startup_word != 0x80) {
-    printk(KERN_INFO "ray_init ERROR card status = %2x\n",
-           local->startup_res.startup_word);
-        local->card_status = CARD_INIT_ERROR;
-        return -1;
-    }
-
-    local->fw_ver = local->startup_res.firmware_version[0];
-    local->fw_bld = local->startup_res.firmware_version[1];
-    local->fw_var = local->startup_res.firmware_version[2];
-    DEBUG(1,"ray_init firmware version %d.%d \n",local->fw_ver, local->fw_bld);
-
-    local->tib_length = 0x20;
-    if ((local->fw_ver == 5) && (local->fw_bld >= 30))
-        local->tib_length = local->startup_res.tib_length;
-    DEBUG(2,"ray_init tib_length = 0x%02x\n", local->tib_length);
-    /* Initialize CCS's to buffer free state */
-    pccs = ccs_base(local);
-    for (i=0;  i<NUMBER_OF_CCS;  i++) {
-        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
-    }
-    init_startup_params(local);
-
-    /* copy mac address to startup parameters */
-    if (parse_addr(phy_addr, local->sparm.b4.a_mac_addr))
-    {
-        p = local->sparm.b4.a_mac_addr;
-    }
-    else
-    {
-        memcpy(&local->sparm.b4.a_mac_addr,
-               &local->startup_res.station_addr, ADDRLEN);
-        p = local->sparm.b4.a_mac_addr;
-    }
-
-    clear_interrupt(local); /* Clear any interrupt from the card */
-    local->card_status = CARD_AWAITING_PARAM;
-    DEBUG(2,"ray_init ending\n");
-    return 0;
+       int i;
+       UCHAR *p;
+       struct ccs __iomem *pccs;
+       ray_dev_t *local = netdev_priv(dev);
+       struct pcmcia_device *link = local->finder;
+       DEBUG(1, "ray_init(0x%p)\n", dev);
+       if (!(pcmcia_dev_present(link))) {
+               DEBUG(0, "ray_init - device not present\n");
+               return -1;
+       }
+
+       local->net_type = net_type;
+       local->sta_type = TYPE_STA;
+
+       /* Copy the startup results to local memory */
+       memcpy_fromio(&local->startup_res, local->sram + ECF_TO_HOST_BASE,
+                     sizeof(struct startup_res_6));
+
+       /* Check Power up test status and get mac address from card */
+       if (local->startup_res.startup_word != 0x80) {
+               printk(KERN_INFO "ray_init ERROR card status = %2x\n",
+                      local->startup_res.startup_word);
+               local->card_status = CARD_INIT_ERROR;
+               return -1;
+       }
+
+       local->fw_ver = local->startup_res.firmware_version[0];
+       local->fw_bld = local->startup_res.firmware_version[1];
+       local->fw_var = local->startup_res.firmware_version[2];
+       DEBUG(1, "ray_init firmware version %d.%d \n", local->fw_ver,
+             local->fw_bld);
+
+       local->tib_length = 0x20;
+       if ((local->fw_ver == 5) && (local->fw_bld >= 30))
+               local->tib_length = local->startup_res.tib_length;
+       DEBUG(2, "ray_init tib_length = 0x%02x\n", local->tib_length);
+       /* Initialize CCS's to buffer free state */
+       pccs = ccs_base(local);
+       for (i = 0; i < NUMBER_OF_CCS; i++) {
+               writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+       }
+       init_startup_params(local);
+
+       /* copy mac address to startup parameters */
+       if (parse_addr(phy_addr, local->sparm.b4.a_mac_addr)) {
+               p = local->sparm.b4.a_mac_addr;
+       } else {
+               memcpy(&local->sparm.b4.a_mac_addr,
+                      &local->startup_res.station_addr, ADDRLEN);
+               p = local->sparm.b4.a_mac_addr;
+       }
+
+       clear_interrupt(local); /* Clear any interrupt from the card */
+       local->card_status = CARD_AWAITING_PARAM;
+       DEBUG(2, "ray_init ending\n");
+       return 0;
 } /* ray_init */
+
 /*===========================================================================*/
 /* Download startup parameters to the card and command it to read them       */
 static int dl_startup_params(struct net_device *dev)
 {
-    int ccsindex;
-    ray_dev_t *local = netdev_priv(dev);
-    struct ccs __iomem *pccs;
-    struct pcmcia_device *link = local->finder;
-
-    DEBUG(1,"dl_startup_params entered\n");
-    if (!(pcmcia_dev_present(link))) {
-        DEBUG(2,"ray_cs dl_startup_params - device not present\n");
-        return -1;
-    }
-    
-    /* Copy parameters to host to ECF area */
-    if (local->fw_ver == 0x55) 
-        memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b4,
-               sizeof(struct b4_startup_params));
-    else
-        memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b5,
-               sizeof(struct b5_startup_params));
-
-    
-    /* Fill in the CCS fields for the ECF */
-    if ((ccsindex = get_free_ccs(local)) < 0) return -1;
-    local->dl_param_ccs = ccsindex;
-    pccs = ccs_base(local) + ccsindex;
-    writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd);
-    DEBUG(2,"dl_startup_params start ccsindex = %d\n", local->dl_param_ccs);
-    /* Interrupt the firmware to process the command */
-    if (interrupt_ecf(local, ccsindex)) {
-        printk(KERN_INFO "ray dl_startup_params failed - "
-           "ECF not ready for intr\n");
-        local->card_status = CARD_DL_PARAM_ERROR;
-        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
-        return -2;
-    }
-    local->card_status = CARD_DL_PARAM;
-    /* Start kernel timer to wait for dl startup to complete. */
-    local->timer.expires = jiffies + HZ/2;
-    local->timer.data = (long)local;
-    local->timer.function = &verify_dl_startup;
-    add_timer(&local->timer);
-    DEBUG(2,"ray_cs dl_startup_params started timer for verify_dl_startup\n");
-    return 0;
+       int ccsindex;
+       ray_dev_t *local = netdev_priv(dev);
+       struct ccs __iomem *pccs;
+       struct pcmcia_device *link = local->finder;
+
+       DEBUG(1, "dl_startup_params entered\n");
+       if (!(pcmcia_dev_present(link))) {
+               DEBUG(2, "ray_cs dl_startup_params - device not present\n");
+               return -1;
+       }
+
+       /* Copy parameters to host to ECF area */
+       if (local->fw_ver == 0x55)
+               memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b4,
+                           sizeof(struct b4_startup_params));
+       else
+               memcpy_toio(local->sram + HOST_TO_ECF_BASE, &local->sparm.b5,
+                           sizeof(struct b5_startup_params));
+
+       /* Fill in the CCS fields for the ECF */
+       if ((ccsindex = get_free_ccs(local)) < 0)
+               return -1;
+       local->dl_param_ccs = ccsindex;
+       pccs = ccs_base(local) + ccsindex;
+       writeb(CCS_DOWNLOAD_STARTUP_PARAMS, &pccs->cmd);
+       DEBUG(2, "dl_startup_params start ccsindex = %d\n",
+             local->dl_param_ccs);
+       /* Interrupt the firmware to process the command */
+       if (interrupt_ecf(local, ccsindex)) {
+               printk(KERN_INFO "ray dl_startup_params failed - "
+                      "ECF not ready for intr\n");
+               local->card_status = CARD_DL_PARAM_ERROR;
+               writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+               return -2;
+       }
+       local->card_status = CARD_DL_PARAM;
+       /* Start kernel timer to wait for dl startup to complete. */
+       local->timer.expires = jiffies + HZ / 2;
+       local->timer.data = (long)local;
+       local->timer.function = &verify_dl_startup;
+       add_timer(&local->timer);
+       DEBUG(2,
+             "ray_cs dl_startup_params started timer for verify_dl_startup\n");
+       return 0;
 } /* dl_startup_params */
+
 /*===========================================================================*/
 static void init_startup_params(ray_dev_t *local)
 {
-    int i; 
-
-    if (country > JAPAN_TEST) country = USA;
-    else
-        if (country < USA) country = USA;
-    /* structure for hop time and beacon period is defined here using 
-     * New 802.11D6.1 format.  Card firmware is still using old format
-     * until version 6.
-     *    Before                    After
-     *    a_hop_time ms byte        a_hop_time ms byte
-     *    a_hop_time 2s byte        a_hop_time ls byte
-     *    a_hop_time ls byte        a_beacon_period ms byte
-     *    a_beacon_period           a_beacon_period ls byte
-     *
-     *    a_hop_time = uS           a_hop_time = KuS
-     *    a_beacon_period = hops    a_beacon_period = KuS
-     */                             /* 64ms = 010000 */
-    if (local->fw_ver == 0x55)  {
-        memcpy((UCHAR *)&local->sparm.b4, b4_default_startup_parms, 
-               sizeof(struct b4_startup_params));
-        /* Translate sane kus input values to old build 4/5 format */
-        /* i = hop time in uS truncated to 3 bytes */
-        i = (hop_dwell * 1024) & 0xffffff;
-        local->sparm.b4.a_hop_time[0] = (i >> 16) & 0xff;
-        local->sparm.b4.a_hop_time[1] = (i >> 8) & 0xff;
-        local->sparm.b4.a_beacon_period[0] = 0;
-        local->sparm.b4.a_beacon_period[1] =
-            ((beacon_period/hop_dwell) - 1) & 0xff;
-        local->sparm.b4.a_curr_country_code = country;
-        local->sparm.b4.a_hop_pattern_length = 
-            hop_pattern_length[(int)country] - 1;
-        if (bc)
-        {
-            local->sparm.b4.a_ack_timeout = 0x50;
-            local->sparm.b4.a_sifs = 0x3f;
-        }
-    }
-    else {    /* Version 5 uses real kus values */
-        memcpy((UCHAR *)&local->sparm.b5, b5_default_startup_parms, 
-               sizeof(struct b5_startup_params));
-
-        local->sparm.b5.a_hop_time[0] = (hop_dwell >> 8) & 0xff;
-        local->sparm.b5.a_hop_time[1] = hop_dwell & 0xff;
-        local->sparm.b5.a_beacon_period[0] = (beacon_period >> 8) & 0xff;
-        local->sparm.b5.a_beacon_period[1] = beacon_period & 0xff;
-        if (psm)
-            local->sparm.b5.a_power_mgt_state = 1;
-        local->sparm.b5.a_curr_country_code = country;
-        local->sparm.b5.a_hop_pattern_length = 
-            hop_pattern_length[(int)country];
-    }
-    
-    local->sparm.b4.a_network_type = net_type & 0x01;
-    local->sparm.b4.a_acting_as_ap_status = TYPE_STA;
-
-    if (essid != NULL)
-        strncpy(local->sparm.b4.a_current_ess_id, essid, ESSID_SIZE);
-} /* init_startup_params */ 
+       int i;
+
+       if (country > JAPAN_TEST)
+               country = USA;
+       else if (country < USA)
+               country = USA;
+       /* structure for hop time and beacon period is defined here using
+        * New 802.11D6.1 format.  Card firmware is still using old format
+        * until version 6.
+        *    Before                    After
+        *    a_hop_time ms byte        a_hop_time ms byte
+        *    a_hop_time 2s byte        a_hop_time ls byte
+        *    a_hop_time ls byte        a_beacon_period ms byte
+        *    a_beacon_period           a_beacon_period ls byte
+        *
+        *    a_hop_time = uS           a_hop_time = KuS
+        *    a_beacon_period = hops    a_beacon_period = KuS
+        *//* 64ms = 010000 */
+       if (local->fw_ver == 0x55) {
+               memcpy((UCHAR *) &local->sparm.b4, b4_default_startup_parms,
+                      sizeof(struct b4_startup_params));
+               /* Translate sane kus input values to old build 4/5 format */
+               /* i = hop time in uS truncated to 3 bytes */
+               i = (hop_dwell * 1024) & 0xffffff;
+               local->sparm.b4.a_hop_time[0] = (i >> 16) & 0xff;
+               local->sparm.b4.a_hop_time[1] = (i >> 8) & 0xff;
+               local->sparm.b4.a_beacon_period[0] = 0;
+               local->sparm.b4.a_beacon_period[1] =
+                   ((beacon_period / hop_dwell) - 1) & 0xff;
+               local->sparm.b4.a_curr_country_code = country;
+               local->sparm.b4.a_hop_pattern_length =
+                   hop_pattern_length[(int)country] - 1;
+               if (bc) {
+                       local->sparm.b4.a_ack_timeout = 0x50;
+                       local->sparm.b4.a_sifs = 0x3f;
+               }
+       } else { /* Version 5 uses real kus values */
+               memcpy((UCHAR *) &local->sparm.b5, b5_default_startup_parms,
+                      sizeof(struct b5_startup_params));
+
+               local->sparm.b5.a_hop_time[0] = (hop_dwell >> 8) & 0xff;
+               local->sparm.b5.a_hop_time[1] = hop_dwell & 0xff;
+               local->sparm.b5.a_beacon_period[0] =
+                   (beacon_period >> 8) & 0xff;
+               local->sparm.b5.a_beacon_period[1] = beacon_period & 0xff;
+               if (psm)
+                       local->sparm.b5.a_power_mgt_state = 1;
+               local->sparm.b5.a_curr_country_code = country;
+               local->sparm.b5.a_hop_pattern_length =
+                   hop_pattern_length[(int)country];
+       }
+
+       local->sparm.b4.a_network_type = net_type & 0x01;
+       local->sparm.b4.a_acting_as_ap_status = TYPE_STA;
+
+       if (essid != NULL)
+               strncpy(local->sparm.b4.a_current_ess_id, essid, ESSID_SIZE);
+} /* init_startup_params */
+
 /*===========================================================================*/
 static void verify_dl_startup(u_long data)
 {
-    ray_dev_t *local = (ray_dev_t *)data;
-    struct ccs __iomem *pccs = ccs_base(local) + local->dl_param_ccs;
-    UCHAR status;
-    struct pcmcia_device *link = local->finder;
+       ray_dev_t *local = (ray_dev_t *) data;
+       struct ccs __iomem *pccs = ccs_base(local) + local->dl_param_ccs;
+       UCHAR status;
+       struct pcmcia_device *link = local->finder;
 
-    if (!(pcmcia_dev_present(link))) {
-        DEBUG(2,"ray_cs verify_dl_startup - device not present\n");
-        return;
-    }
+       if (!(pcmcia_dev_present(link))) {
+               DEBUG(2, "ray_cs verify_dl_startup - device not present\n");
+               return;
+       }
 #ifdef PCMCIA_DEBUG
-    if (pc_debug > 2) {
-    int i;
-    printk(KERN_DEBUG "verify_dl_startup parameters sent via ccs %d:\n",
-           local->dl_param_ccs);
-        for (i=0; i<sizeof(struct b5_startup_params); i++) {
-            printk(" %2x", (unsigned int) readb(local->sram + HOST_TO_ECF_BASE + i));
-        }
-    printk("\n");
-    }
+       if (pc_debug > 2) {
+               int i;
+               printk(KERN_DEBUG
+                      "verify_dl_startup parameters sent via ccs %d:\n",
+                      local->dl_param_ccs);
+               for (i = 0; i < sizeof(struct b5_startup_params); i++) {
+                       printk(" %2x",
+                              (unsigned int)readb(local->sram +
+                                                  HOST_TO_ECF_BASE + i));
+               }
+               printk("\n");
+       }
 #endif
 
-    status = readb(&pccs->buffer_status);
-    if (status!= CCS_BUFFER_FREE)
-    {
-        printk(KERN_INFO "Download startup params failed.  Status = %d\n",
-           status);
-        local->card_status = CARD_DL_PARAM_ERROR;
-        return;
-    }
-    if (local->sparm.b4.a_network_type == ADHOC)
-        start_net((u_long)local);
-    else
-        join_net((u_long)local);
-
-    return;
+       status = readb(&pccs->buffer_status);
+       if (status != CCS_BUFFER_FREE) {
+               printk(KERN_INFO
+                      "Download startup params failed.  Status = %d\n",
+                      status);
+               local->card_status = CARD_DL_PARAM_ERROR;
+               return;
+       }
+       if (local->sparm.b4.a_network_type == ADHOC)
+               start_net((u_long) local);
+       else
+               join_net((u_long) local);
+
+       return;
 } /* end verify_dl_startup */
+
 /*===========================================================================*/
 /* Command card to start a network */
 static void start_net(u_long data)
 {
-    ray_dev_t *local = (ray_dev_t *)data;
-    struct ccs __iomem *pccs;
-    int ccsindex;
-    struct pcmcia_device *link = local->finder;
-    if (!(pcmcia_dev_present(link))) {
-        DEBUG(2,"ray_cs start_net - device not present\n");
-        return;
-    }
-    /* Fill in the CCS fields for the ECF */
-    if ((ccsindex = get_free_ccs(local)) < 0) return;
-    pccs = ccs_base(local) + ccsindex;
-    writeb(CCS_START_NETWORK, &pccs->cmd);
-    writeb(0, &pccs->var.start_network.update_param);
-    /* Interrupt the firmware to process the command */
-    if (interrupt_ecf(local, ccsindex)) {
-        DEBUG(1,"ray start net failed - card not ready for intr\n");
-        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
-        return;
-    }
-    local->card_status = CARD_DOING_ACQ;
-    return;
+       ray_dev_t *local = (ray_dev_t *) data;
+       struct ccs __iomem *pccs;
+       int ccsindex;
+       struct pcmcia_device *link = local->finder;
+       if (!(pcmcia_dev_present(link))) {
+               DEBUG(2, "ray_cs start_net - device not present\n");
+               return;
+       }
+       /* Fill in the CCS fields for the ECF */
+       if ((ccsindex = get_free_ccs(local)) < 0)
+               return;
+       pccs = ccs_base(local) + ccsindex;
+       writeb(CCS_START_NETWORK, &pccs->cmd);
+       writeb(0, &pccs->var.start_network.update_param);
+       /* Interrupt the firmware to process the command */
+       if (interrupt_ecf(local, ccsindex)) {
+               DEBUG(1, "ray start net failed - card not ready for intr\n");
+               writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+               return;
+       }
+       local->card_status = CARD_DOING_ACQ;
+       return;
 } /* end start_net */
+
 /*===========================================================================*/
 /* Command card to join a network */
 static void join_net(u_long data)
 {
-    ray_dev_t *local = (ray_dev_t *)data;
-
-    struct ccs __iomem *pccs;
-    int ccsindex;
-    struct pcmcia_device *link = local->finder;
-    
-    if (!(pcmcia_dev_present(link))) {
-        DEBUG(2,"ray_cs join_net - device not present\n");
-        return;
-    }
-    /* Fill in the CCS fields for the ECF */
-    if ((ccsindex = get_free_ccs(local)) < 0) return;
-    pccs = ccs_base(local) + ccsindex;
-    writeb(CCS_JOIN_NETWORK, &pccs->cmd);
-    writeb(0, &pccs->var.join_network.update_param);
-    writeb(0, &pccs->var.join_network.net_initiated);
-    /* Interrupt the firmware to process the command */
-    if (interrupt_ecf(local, ccsindex)) {
-        DEBUG(1,"ray join net failed - card not ready for intr\n");
-        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
-        return;
-    }
-    local->card_status = CARD_DOING_ACQ;
-    return;
+       ray_dev_t *local = (ray_dev_t *) data;
+
+       struct ccs __iomem *pccs;
+       int ccsindex;
+       struct pcmcia_device *link = local->finder;
+
+       if (!(pcmcia_dev_present(link))) {
+               DEBUG(2, "ray_cs join_net - device not present\n");
+               return;
+       }
+       /* Fill in the CCS fields for the ECF */
+       if ((ccsindex = get_free_ccs(local)) < 0)
+               return;
+       pccs = ccs_base(local) + ccsindex;
+       writeb(CCS_JOIN_NETWORK, &pccs->cmd);
+       writeb(0, &pccs->var.join_network.update_param);
+       writeb(0, &pccs->var.join_network.net_initiated);
+       /* Interrupt the firmware to process the command */
+       if (interrupt_ecf(local, ccsindex)) {
+               DEBUG(1, "ray join net failed - card not ready for intr\n");
+               writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+               return;
+       }
+       local->card_status = CARD_DOING_ACQ;
+       return;
 }
+
 /*============================================================================
     After a card is removed, ray_release() will unregister the net
     device, and release the PCMCIA configuration.  If the device is
@@ -784,25 +816,27 @@ static void join_net(u_long data)
 =============================================================================*/
 static void ray_release(struct pcmcia_device *link)
 {
-    struct net_device *dev = link->priv; 
-    ray_dev_t *local = netdev_priv(dev);
-    int i;
-    
-    DEBUG(1, "ray_release(0x%p)\n", link);
-
-    del_timer(&local->timer);
-
-    iounmap(local->sram);
-    iounmap(local->rmem);
-    iounmap(local->amem);
-    /* Do bother checking to see if these succeed or not */
-    i = pcmcia_release_window(local->amem_handle);
-    if ( i != 0 ) DEBUG(0,"ReleaseWindow(local->amem) ret = %x\n",i);
-    i = pcmcia_release_window(local->rmem_handle);
-    if ( i != 0 ) DEBUG(0,"ReleaseWindow(local->rmem) ret = %x\n",i);
-    pcmcia_disable_device(link);
-
-    DEBUG(2,"ray_release ending\n");
+       struct net_device *dev = link->priv;
+       ray_dev_t *local = netdev_priv(dev);
+       int i;
+
+       DEBUG(1, "ray_release(0x%p)\n", link);
+
+       del_timer(&local->timer);
+
+       iounmap(local->sram);
+       iounmap(local->rmem);
+       iounmap(local->amem);
+       /* Do bother checking to see if these succeed or not */
+       i = pcmcia_release_window(local->amem_handle);
+       if (i != 0)
+               DEBUG(0, "ReleaseWindow(local->amem) ret = %x\n", i);
+       i = pcmcia_release_window(local->rmem_handle);
+       if (i != 0)
+               DEBUG(0, "ReleaseWindow(local->rmem) ret = %x\n", i);
+       pcmcia_disable_device(link);
+
+       DEBUG(2, "ray_release ending\n");
 }
 
 static int ray_suspend(struct pcmcia_device *link)
@@ -831,237 +865,243 @@ static int ray_resume(struct pcmcia_device *link)
 static int ray_dev_init(struct net_device *dev)
 {
 #ifdef RAY_IMMEDIATE_INIT
-    int i;
-#endif /* RAY_IMMEDIATE_INIT */
-    ray_dev_t *local = netdev_priv(dev);
-    struct pcmcia_device *link = local->finder;
-
-    DEBUG(1,"ray_dev_init(dev=%p)\n",dev);
-    if (!(pcmcia_dev_present(link))) {
-        DEBUG(2,"ray_dev_init - device not present\n");
-        return -1;
-    }
+       int i;
+#endif /* RAY_IMMEDIATE_INIT */
+       ray_dev_t *local = netdev_priv(dev);
+       struct pcmcia_device *link = local->finder;
+
+       DEBUG(1, "ray_dev_init(dev=%p)\n", dev);
+       if (!(pcmcia_dev_present(link))) {
+               DEBUG(2, "ray_dev_init - device not present\n");
+               return -1;
+       }
 #ifdef RAY_IMMEDIATE_INIT
-    /* Download startup parameters */
-    if ( (i = dl_startup_params(dev)) < 0)
-    {
-        printk(KERN_INFO "ray_dev_init dl_startup_params failed - "
-           "returns 0x%x\n",i);
-        return -1;
-    }
-#else  /* RAY_IMMEDIATE_INIT */
-    /* Postpone the card init so that we can still configure the card,
-     * for example using the Wireless Extensions. The init will happen
-     * in ray_open() - Jean II */
-    DEBUG(1,"ray_dev_init: postponing card init to ray_open() ; Status = %d\n",
-         local->card_status);
-#endif /* RAY_IMMEDIATE_INIT */
-
-    /* copy mac and broadcast addresses to linux device */
-    memcpy(&dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN);
-    memset(dev->broadcast, 0xff, ETH_ALEN);
-
-    DEBUG(2,"ray_dev_init ending\n");
-    return 0;
+       /* Download startup parameters */
+       if ((i = dl_startup_params(dev)) < 0) {
+               printk(KERN_INFO "ray_dev_init dl_startup_params failed - "
+                      "returns 0x%x\n", i);
+               return -1;
+       }
+#else /* RAY_IMMEDIATE_INIT */
+       /* Postpone the card init so that we can still configure the card,
+        * for example using the Wireless Extensions. The init will happen
+        * in ray_open() - Jean II */
+       DEBUG(1,
+             "ray_dev_init: postponing card init to ray_open() ; Status = %d\n",
+             local->card_status);
+#endif /* RAY_IMMEDIATE_INIT */
+
+       /* copy mac and broadcast addresses to linux device */
+       memcpy(&dev->dev_addr, &local->sparm.b4.a_mac_addr, ADDRLEN);
+       memset(dev->broadcast, 0xff, ETH_ALEN);
+
+       DEBUG(2, "ray_dev_init ending\n");
+       return 0;
 }
+
 /*===========================================================================*/
 static int ray_dev_config(struct net_device *dev, struct ifmap *map)
 {
-    ray_dev_t *local = netdev_priv(dev);
-    struct pcmcia_device *link = local->finder;
-    /* Dummy routine to satisfy device structure */
-    DEBUG(1,"ray_dev_config(dev=%p,ifmap=%p)\n",dev,map);
-    if (!(pcmcia_dev_present(link))) {
-        DEBUG(2,"ray_dev_config - device not present\n");
-        return -1;
-    }
+       ray_dev_t *local = netdev_priv(dev);
+       struct pcmcia_device *link = local->finder;
+       /* Dummy routine to satisfy device structure */
+       DEBUG(1, "ray_dev_config(dev=%p,ifmap=%p)\n", dev, map);
+       if (!(pcmcia_dev_present(link))) {
+               DEBUG(2, "ray_dev_config - device not present\n");
+               return -1;
+       }
 
-    return 0;
+       return 0;
 }
+
 /*===========================================================================*/
 static int ray_dev_start_xmit(struct sk_buff *skb, struct net_device *dev)
 {
-    ray_dev_t *local = netdev_priv(dev);
-    struct pcmcia_device *link = local->finder;
-    short length = skb->len;
-
-    if (!(pcmcia_dev_present(link))) {
-        DEBUG(2,"ray_dev_start_xmit - device not present\n");
-        return -1;
-    }
-    DEBUG(3,"ray_dev_start_xmit(skb=%p, dev=%p)\n",skb,dev);
-    if (local->authentication_state == NEED_TO_AUTH) {
-        DEBUG(0,"ray_cs Sending authentication request.\n");
-        if (!build_auth_frame (local, local->auth_id, OPEN_AUTH_REQUEST)) {
-            local->authentication_state = AUTHENTICATED;
-            netif_stop_queue(dev);
-            return 1;
-        }
-    }
-
-    if (length < ETH_ZLEN)
-    {
-       if (skb_padto(skb, ETH_ZLEN))
-               return 0;
-       length = ETH_ZLEN;
-    }
-    switch (ray_hw_xmit( skb->data, length, dev, DATA_TYPE)) {
-        case XMIT_NO_CCS:
-        case XMIT_NEED_AUTH:
-           netif_stop_queue(dev);
-            return 1;
-        case XMIT_NO_INTR:
-        case XMIT_MSG_BAD:
-        case XMIT_OK:
-        default:
-            dev->trans_start = jiffies;
-            dev_kfree_skb(skb);
-            return 0;
-    }
-    return 0;
+       ray_dev_t *local = netdev_priv(dev);
+       struct pcmcia_device *link = local->finder;
+       short length = skb->len;
+
+       if (!(pcmcia_dev_present(link))) {
+               DEBUG(2, "ray_dev_start_xmit - device not present\n");
+               return -1;
+       }
+       DEBUG(3, "ray_dev_start_xmit(skb=%p, dev=%p)\n", skb, dev);
+       if (local->authentication_state == NEED_TO_AUTH) {
+               DEBUG(0, "ray_cs Sending authentication request.\n");
+               if (!build_auth_frame(local, local->auth_id, OPEN_AUTH_REQUEST)) {
+                       local->authentication_state = AUTHENTICATED;
+                       netif_stop_queue(dev);
+                       return 1;
+               }
+       }
+
+       if (length < ETH_ZLEN) {
+               if (skb_padto(skb, ETH_ZLEN))
+                       return 0;
+               length = ETH_ZLEN;
+       }
+       switch (ray_hw_xmit(skb->data, length, dev, DATA_TYPE)) {
+       case XMIT_NO_CCS:
+       case XMIT_NEED_AUTH:
+               netif_stop_queue(dev);
+               return 1;
+       case XMIT_NO_INTR:
+       case XMIT_MSG_BAD:
+       case XMIT_OK:
+       default:
+               dev->trans_start = jiffies;
+               dev_kfree_skb(skb);
+               return 0;
+       }
+       return 0;
 } /* ray_dev_start_xmit */
+
 /*===========================================================================*/
-static int ray_hw_xmit(unsigned char* data, int len, struct net_device* dev, 
-                UCHAR msg_type)
-{
-    ray_dev_t *local = netdev_priv(dev);
-    struct ccs __iomem *pccs;
-    int ccsindex;
-    int offset;
-    struct tx_msg __iomem *ptx; /* Address of xmit buffer in PC space */
-    short int addr;     /* Address of xmit buffer in card space */
-    
-    DEBUG(3,"ray_hw_xmit(data=%p, len=%d, dev=%p)\n",data,len,dev);
-    if (len + TX_HEADER_LENGTH > TX_BUF_SIZE)
-    {
-        printk(KERN_INFO "ray_hw_xmit packet too large: %d bytes\n",len);
-        return XMIT_MSG_BAD;
-    }
+static int ray_hw_xmit(unsigned char *data, int len, struct net_device *dev,
+                      UCHAR msg_type)
+{
+       ray_dev_t *local = netdev_priv(dev);
+       struct ccs __iomem *pccs;
+       int ccsindex;
+       int offset;
+       struct tx_msg __iomem *ptx;     /* Address of xmit buffer in PC space */
+       short int addr;         /* Address of xmit buffer in card space */
+
+       DEBUG(3, "ray_hw_xmit(data=%p, len=%d, dev=%p)\n", data, len, dev);
+       if (len + TX_HEADER_LENGTH > TX_BUF_SIZE) {
+               printk(KERN_INFO "ray_hw_xmit packet too large: %d bytes\n",
+                      len);
+               return XMIT_MSG_BAD;
+       }
        switch (ccsindex = get_free_tx_ccs(local)) {
        case ECCSBUSY:
-               DEBUG(2,"ray_hw_xmit tx_ccs table busy\n");
+               DEBUG(2, "ray_hw_xmit tx_ccs table busy\n");
        case ECCSFULL:
-        DEBUG(2,"ray_hw_xmit No free tx ccs\n");
+               DEBUG(2, "ray_hw_xmit No free tx ccs\n");
        case ECARDGONE:
-       netif_stop_queue(dev);
-        return XMIT_NO_CCS;
+               netif_stop_queue(dev);
+               return XMIT_NO_CCS;
        default:
                break;
        }
-    addr = TX_BUF_BASE + (ccsindex << 11);
-
-    if (msg_type == DATA_TYPE) {
-        local->stats.tx_bytes += len;
-        local->stats.tx_packets++;
-    }
-
-    ptx = local->sram + addr;
-
-    ray_build_header(local, ptx, msg_type, data);
-    if (translate) {
-        offset = translate_frame(local, ptx, data, len);
-    }
-    else { /* Encapsulate frame */
-        /* TBD TIB length will move address of ptx->var */
-        memcpy_toio(&ptx->var, data, len);
-        offset = 0;
-    }
-
-    /* fill in the CCS */
-    pccs = ccs_base(local) + ccsindex;
-    len += TX_HEADER_LENGTH + offset;
-    writeb(CCS_TX_REQUEST, &pccs->cmd);
-    writeb(addr >> 8, &pccs->var.tx_request.tx_data_ptr[0]);
-    writeb(local->tib_length, &pccs->var.tx_request.tx_data_ptr[1]);
-    writeb(len >> 8, &pccs->var.tx_request.tx_data_length[0]);
-    writeb(len & 0xff, &pccs->var.tx_request.tx_data_length[1]);
+       addr = TX_BUF_BASE + (ccsindex << 11);
+
+       if (msg_type == DATA_TYPE) {
+               local->stats.tx_bytes += len;
+               local->stats.tx_packets++;
+       }
+
+       ptx = local->sram + addr;
+
+       ray_build_header(local, ptx, msg_type, data);
+       if (translate) {
+               offset = translate_frame(local, ptx, data, len);
+       } else { /* Encapsulate frame */
+               /* TBD TIB length will move address of ptx->var */
+               memcpy_toio(&ptx->var, data, len);
+               offset = 0;
+       }
+
+       /* fill in the CCS */
+       pccs = ccs_base(local) + ccsindex;
+       len += TX_HEADER_LENGTH + offset;
+       writeb(CCS_TX_REQUEST, &pccs->cmd);
+       writeb(addr >> 8, &pccs->var.tx_request.tx_data_ptr[0]);
+       writeb(local->tib_length, &pccs->var.tx_request.tx_data_ptr[1]);
+       writeb(len >> 8, &pccs->var.tx_request.tx_data_length[0]);
+       writeb(len & 0xff, &pccs->var.tx_request.tx_data_length[1]);
 /* TBD still need psm_cam? */
-    writeb(PSM_CAM, &pccs->var.tx_request.pow_sav_mode);
-    writeb(local->net_default_tx_rate, &pccs->var.tx_request.tx_rate);
-    writeb(0, &pccs->var.tx_request.antenna);
-    DEBUG(3,"ray_hw_xmit default_tx_rate = 0x%x\n",\
-          local->net_default_tx_rate);
-
-    /* Interrupt the firmware to process the command */
-    if (interrupt_ecf(local, ccsindex)) {
-        DEBUG(2,"ray_hw_xmit failed - ECF not ready for intr\n");
+       writeb(PSM_CAM, &pccs->var.tx_request.pow_sav_mode);
+       writeb(local->net_default_tx_rate, &pccs->var.tx_request.tx_rate);
+       writeb(0, &pccs->var.tx_request.antenna);
+       DEBUG(3, "ray_hw_xmit default_tx_rate = 0x%x\n",
+             local->net_default_tx_rate);
+
+       /* Interrupt the firmware to process the command */
+       if (interrupt_ecf(local, ccsindex)) {
+               DEBUG(2, "ray_hw_xmit failed - ECF not ready for intr\n");
 /* TBD very inefficient to copy packet to buffer, and then not
    send it, but the alternative is to queue the messages and that
    won't be done for a while.  Maybe set tbusy until a CCS is free?
 */
-        writeb(CCS_BUFFER_FREE, &pccs->buffer_status);
-        return XMIT_NO_INTR;
-    }
-    return XMIT_OK;
+               writeb(CCS_BUFFER_FREE, &pccs->buffer_status);
+               return XMIT_NO_INTR;
+       }
+       return XMIT_OK;
 } /* end ray_hw_xmit */
+
 /*===========================================================================*/
-static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx, unsigned char *data,
-                    int len)
-{
-    __be16 proto = ((struct ethhdr *)data)->h_proto;
-    if (ntohs(proto) >= 1536) { /* DIX II ethernet frame */
-        DEBUG(3,"ray_cs translate_frame DIX II\n");
-        /* Copy LLC header to card buffer */
-        memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc));
-        memcpy_toio( ((void __iomem *)&ptx->var) + sizeof(eth2_llc), (UCHAR *)&proto, 2);
-        if (proto == htons(ETH_P_AARP) || proto == htons(ETH_P_IPX)) {
-            /* This is the selective translation table, only 2 entries */
-            writeb(0xf8, &((struct snaphdr_t __iomem *)ptx->var)->org[3]);
-        }
-        /* Copy body of ethernet packet without ethernet header */
-        memcpy_toio((void __iomem *)&ptx->var + sizeof(struct snaphdr_t), \
-                    data + ETH_HLEN,  len - ETH_HLEN);
-        return (int) sizeof(struct snaphdr_t) - ETH_HLEN;
-    }
-    else { /* already  802 type, and proto is length */
-        DEBUG(3,"ray_cs translate_frame 802\n");
-        if (proto == htons(0xffff)) { /* evil netware IPX 802.3 without LLC */
-        DEBUG(3,"ray_cs translate_frame evil IPX\n");
-            memcpy_toio(&ptx->var, data + ETH_HLEN,  len - ETH_HLEN);
-            return 0 - ETH_HLEN;
-        }
-        memcpy_toio(&ptx->var, data + ETH_HLEN,  len - ETH_HLEN);
-        return 0 - ETH_HLEN;
-    }
-    /* TBD do other frame types */
+static int translate_frame(ray_dev_t *local, struct tx_msg __iomem *ptx,
+                          unsigned char *data, int len)
+{
+       __be16 proto = ((struct ethhdr *)data)->h_proto;
+       if (ntohs(proto) >= 1536) { /* DIX II ethernet frame */
+               DEBUG(3, "ray_cs translate_frame DIX II\n");
+               /* Copy LLC header to card buffer */
+               memcpy_toio(&ptx->var, eth2_llc, sizeof(eth2_llc));
+               memcpy_toio(((void __iomem *)&ptx->var) + sizeof(eth2_llc),
+                           (UCHAR *) &proto, 2);
+               if (proto == htons(ETH_P_AARP) || proto == htons(ETH_P_IPX)) {
+                       /* This is the selective translation table, only 2 entries */
+                       writeb(0xf8,
+                              &((struct snaphdr_t __iomem *)ptx->var)->org[3]);
+               }
+               /* Copy body of ethernet packet without ethernet header */
+               memcpy_toio((void __iomem *)&ptx->var +
+                           sizeof(struct snaphdr_t), data + ETH_HLEN,
+                           len - ETH_HLEN);
+               return (int)sizeof(struct snaphdr_t) - ETH_HLEN;
+       } else { /* already  802 type, and proto is length */
+               DEBUG(3, "ray_cs translate_frame 802\n");
+               if (proto == htons(0xffff)) { /* evil netware IPX 802.3 without LLC */
+                       DEBUG(3, "ray_cs translate_frame evil IPX\n");
+                       memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN);
+                       return 0 - ETH_HLEN;
+               }
+               memcpy_toio(&ptx->var, data + ETH_HLEN, len - ETH_HLEN);
+               return 0 - ETH_HLEN;
+       }
+       /* TBD do other frame types */
 } /* end translate_frame */
+
 /*===========================================================================*/
-static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx, UCHAR msg_type,
-                unsigned char *data)
+static void ray_build_header(ray_dev_t *local, struct tx_msg __iomem *ptx,
+                            UCHAR msg_type, unsigned char *data)
 {
-    writeb(PROTOCOL_VER | msg_type, &ptx->mac.frame_ctl_1);
+       writeb(PROTOCOL_VER | msg_type, &ptx->mac.frame_ctl_1);
 /*** IEEE 802.11 Address field assignments *************
-                TODS FROMDS   addr_1     addr_2          addr_3   addr_4
-Adhoc           0    0        dest       src (terminal)  BSSID    N/A
-AP to Terminal  0    1        dest       AP(BSSID)       source   N/A
-Terminal to AP  1    0        AP(BSSID)  src (terminal)  dest     N/A
-AP to AP        1    1        dest AP    src AP          dest     source      
+               TODS    FROMDS  addr_1          addr_2          addr_3  addr_4
+Adhoc          0       0       dest            src (terminal)  BSSID   N/A
+AP to Terminal 0       1       dest            AP(BSSID)       source  N/A
+Terminal to AP 1       0       AP(BSSID)       src (terminal)  dest    N/A
+AP to AP       1       1       dest AP         src AP          dest    source
 *******************************************************/
-    if (local->net_type == ADHOC) {   
-        writeb(0, &ptx->mac.frame_ctl_2);
-        memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest, 2 * ADDRLEN);
-        memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN);
-    }
-    else /* infrastructure */
-    {
-        if (local->sparm.b4.a_acting_as_ap_status)
-        {
-            writeb(FC2_FROM_DS, &ptx->mac.frame_ctl_2);
-            memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest, ADDRLEN);
-            memcpy_toio(ptx->mac.addr_2, local->bss_id, 6);
-            memcpy_toio(ptx->mac.addr_3, ((struct ethhdr *)data)->h_source, ADDRLEN);
-        }
-        else /* Terminal */
-        {
-            writeb(FC2_TO_DS, &ptx->mac.frame_ctl_2);
-            memcpy_toio(ptx->mac.addr_1, local->bss_id, ADDRLEN);
-            memcpy_toio(ptx->mac.addr_2, ((struct ethhdr *)data)->h_source, ADDRLEN);
-            memcpy_toio(ptx->mac.addr_3, ((struct ethhdr *)data)->h_dest, ADDRLEN);
-        }
-    }
+       if (local->net_type == ADHOC) {
+               writeb(0, &ptx->mac.frame_ctl_2);
+               memcpy_toio(ptx->mac.addr_1, ((struct ethhdr *)data)->h_dest,
+                           2 * ADDRLEN);
+               memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN);
+       } else { /* infrastructure */
+
+               if (local->sparm.b4.a_acting_as_ap_status) {
+                       writeb(FC2_FROM_DS, &ptx->mac.frame_ctl_2);
+                       memcpy_toio(ptx->mac.addr_1,
+                                   ((struct ethhdr *)data)->h_dest, ADDRLEN);
+                       memcpy_toio(ptx->mac.addr_2, local->bss_id, 6);
+                       memcpy_toio(ptx->mac.addr_3,
+                                   ((struct ethhdr *)data)->h_source, ADDRLEN);
+               } else { /* Terminal */
+
+                       writeb(FC2_TO_DS, &ptx->mac.frame_ctl_2);
+                       memcpy_toio(ptx->mac.addr_1, local->bss_id, ADDRLEN);
+                       memcpy_toio(ptx->mac.addr_2,
+                                   ((struct ethhdr *)data)->h_source, ADDRLEN);
+                       memcpy_toio(ptx->mac.addr_3,
+                                   ((struct ethhdr *)data)->h_dest, ADDRLEN);
+               }
+       }
 } /* end encapsulate_frame */
 
-
 /*===========================================================================*/
 
 static void netdev_get_drvinfo(struct net_device *dev,
@@ -1071,7 +1111,7 @@ static void netdev_get_drvinfo(struct net_device *dev,
 }
 
 static const struct ethtool_ops netdev_ethtool_ops = {
-       .get_drvinfo            = netdev_get_drvinfo,
+       .get_drvinfo = netdev_get_drvinfo,
 };
 
 /*====================================================================*/
@@ -1081,9 +1121,7 @@ static const struct ethtool_ops netdev_ethtool_ops = {
  * Wireless Handler : get protocol name
  */
 static int ray_get_name(struct net_device *dev,
-                       struct iw_request_info *info,
-                       char *cwrq,
-                       char *extra)
+                       struct iw_request_info *info, char *cwrq, char *extra)
 {
        strcpy(cwrq, "IEEE 802.11-FH");
        return 0;
@@ -1095,14 +1133,13 @@ static int ray_get_name(struct net_device *dev,
  */
 static int ray_set_freq(struct net_device *dev,
                        struct iw_request_info *info,
-                       struct iw_freq *fwrq,
-                       char *extra)
+                       struct iw_freq *fwrq, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
-       int err = -EINPROGRESS;         /* Call commit handler */
+       int err = -EINPROGRESS; /* Call commit handler */
 
        /* Reject if card is already initialised */
-       if(local->card_status != CARD_AWAITING_PARAM)
+       if (local->card_status != CARD_AWAITING_PARAM)
                return -EBUSY;
 
        /* Setting by channel number */
@@ -1113,15 +1150,14 @@ static int ray_set_freq(struct net_device *dev,
 
        return err;
 }
+
 /*------------------------------------------------------------------*/
 /*
  * Wireless Handler : get frequency
  */
 static int ray_get_freq(struct net_device *dev,
                        struct iw_request_info *info,
-                       struct iw_freq *fwrq,
-                       char *extra)
+                       struct iw_freq *fwrq, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
@@ -1136,22 +1172,21 @@ static int ray_get_freq(struct net_device *dev,
  */
 static int ray_set_essid(struct net_device *dev,
                         struct iw_request_info *info,
-                        struct iw_point *dwrq,
-                        char *extra)
+                        struct iw_point *dwrq, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
        /* Reject if card is already initialised */
-       if(local->card_status != CARD_AWAITING_PARAM)
+       if (local->card_status != CARD_AWAITING_PARAM)
                return -EBUSY;
 
        /* Check if we asked for `any' */
-       if(dwrq->flags == 0) {
+       if (dwrq->flags == 0) {
                /* Corey : can you do that ? */
                return -EOPNOTSUPP;
        } else {
                /* Check the size of the string */
-               if(dwrq->length > IW_ESSID_MAX_SIZE) {
+               if (dwrq->length > IW_ESSID_MAX_SIZE) {
                        return -E2BIG;
                }
 
@@ -1160,7 +1195,7 @@ static int ray_set_essid(struct net_device *dev,
                memcpy(local->sparm.b5.a_current_ess_id, extra, dwrq->length);
        }
 
-       return -EINPROGRESS;            /* Call commit handler */
+       return -EINPROGRESS;    /* Call commit handler */
 }
 
 /*------------------------------------------------------------------*/
@@ -1169,8 +1204,7 @@ static int ray_set_essid(struct net_device *dev,
  */
 static int ray_get_essid(struct net_device *dev,
                         struct iw_request_info *info,
-                        struct iw_point *dwrq,
-                        char *extra)
+                        struct iw_point *dwrq, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
@@ -1179,7 +1213,7 @@ static int ray_get_essid(struct net_device *dev,
 
        /* Push it out ! */
        dwrq->length = strlen(extra);
-       dwrq->flags = 1; /* active */
+       dwrq->flags = 1;        /* active */
 
        return 0;
 }
@@ -1189,9 +1223,8 @@ static int ray_get_essid(struct net_device *dev,
  * Wireless Handler : get AP address
  */
 static int ray_get_wap(struct net_device *dev,
-                       struct iw_request_info *info,
-                       struct sockaddr *awrq,
-                       char *extra)
+                      struct iw_request_info *info,
+                      struct sockaddr *awrq, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
@@ -1207,25 +1240,24 @@ static int ray_get_wap(struct net_device *dev,
  */
 static int ray_set_rate(struct net_device *dev,
                        struct iw_request_info *info,
-                       struct iw_param *vwrq,
-                       char *extra)
+                       struct iw_param *vwrq, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
        /* Reject if card is already initialised */
-       if(local->card_status != CARD_AWAITING_PARAM)
+       if (local->card_status != CARD_AWAITING_PARAM)
                return -EBUSY;
 
        /* Check if rate is in range */
-       if((vwrq->value != 1000000) && (vwrq->value != 2000000))
+       if ((vwrq->value != 1000000) && (vwrq->value != 2000000))
                return -EINVAL;
 
        /* Hack for 1.5 Mb/s instead of 2 Mb/s */
-       if((local->fw_ver == 0x55) &&           /* Please check */
-          (vwrq->value == 2000000))
+       if ((local->fw_ver == 0x55) &&  /* Please check */
+           (vwrq->value == 2000000))
                local->net_default_tx_rate = 3;
        else
-               local->net_default_tx_rate = vwrq->value/500000;
+               local->net_default_tx_rate = vwrq->value / 500000;
 
        return 0;
 }
@@ -1236,16 +1268,15 @@ static int ray_set_rate(struct net_device *dev,
  */
 static int ray_get_rate(struct net_device *dev,
                        struct iw_request_info *info,
-                       struct iw_param *vwrq,
-                       char *extra)
+                       struct iw_param *vwrq, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
-       if(local->net_default_tx_rate == 3)
-               vwrq->value = 2000000;          /* Hum... */
+       if (local->net_default_tx_rate == 3)
+               vwrq->value = 2000000;  /* Hum... */
        else
                vwrq->value = local->net_default_tx_rate * 500000;
-       vwrq->fixed = 0;                /* We are in auto mode */
+       vwrq->fixed = 0;        /* We are in auto mode */
 
        return 0;
 }
@@ -1256,43 +1287,40 @@ static int ray_get_rate(struct net_device *dev,
  */
 static int ray_set_rts(struct net_device *dev,
                       struct iw_request_info *info,
-                      struct iw_param *vwrq,
-                      char *extra)
+                      struct iw_param *vwrq, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
        int rthr = vwrq->value;
 
        /* Reject if card is already initialised */
-       if(local->card_status != CARD_AWAITING_PARAM)
+       if (local->card_status != CARD_AWAITING_PARAM)
                return -EBUSY;
 
        /* if(wrq->u.rts.fixed == 0) we should complain */
-       if(vwrq->disabled)
+       if (vwrq->disabled)
                rthr = 32767;
        else {
-               if((rthr < 0) || (rthr > 2347)) /* What's the max packet size ??? */
+               if ((rthr < 0) || (rthr > 2347))   /* What's the max packet size ??? */
                        return -EINVAL;
        }
        local->sparm.b5.a_rts_threshold[0] = (rthr >> 8) & 0xFF;
        local->sparm.b5.a_rts_threshold[1] = rthr & 0xFF;
 
-       return -EINPROGRESS;            /* Call commit handler */
+       return -EINPROGRESS;    /* Call commit handler */
 }
 
-
 /*------------------------------------------------------------------*/
 /*
  * Wireless Handler : get RTS threshold
  */
 static int ray_get_rts(struct net_device *dev,
                       struct iw_request_info *info,
-                      struct iw_param *vwrq,
-                      char *extra)
+                      struct iw_param *vwrq, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
        vwrq->value = (local->sparm.b5.a_rts_threshold[0] << 8)
-               + local->sparm.b5.a_rts_threshold[1];
+           + local->sparm.b5.a_rts_threshold[1];
        vwrq->disabled = (vwrq->value == 32767);
        vwrq->fixed = 1;
 
@@ -1305,27 +1333,26 @@ static int ray_get_rts(struct net_device *dev,
  */
 static int ray_set_frag(struct net_device *dev,
                        struct iw_request_info *info,
-                       struct iw_param *vwrq,
-                       char *extra)
+                       struct iw_param *vwrq, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
        int fthr = vwrq->value;
 
        /* Reject if card is already initialised */
-       if(local->card_status != CARD_AWAITING_PARAM)
+       if (local->card_status != CARD_AWAITING_PARAM)
                return -EBUSY;
 
        /* if(wrq->u.frag.fixed == 0) should complain */
-       if(vwrq->disabled)
+       if (vwrq->disabled)
                fthr = 32767;
        else {
-               if((fthr < 256) || (fthr > 2347)) /* To check out ! */
+               if ((fthr < 256) || (fthr > 2347))      /* To check out ! */
                        return -EINVAL;
        }
        local->sparm.b5.a_frag_threshold[0] = (fthr >> 8) & 0xFF;
        local->sparm.b5.a_frag_threshold[1] = fthr & 0xFF;
 
-       return -EINPROGRESS;            /* Call commit handler */
+       return -EINPROGRESS;    /* Call commit handler */
 }
 
 /*------------------------------------------------------------------*/
@@ -1334,13 +1361,12 @@ static int ray_set_frag(struct net_device *dev,
  */
 static int ray_get_frag(struct net_device *dev,
                        struct iw_request_info *info,
-                       struct iw_param *vwrq,
-                       char *extra)
+                       struct iw_param *vwrq, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
        vwrq->value = (local->sparm.b5.a_frag_threshold[0] << 8)
-               + local->sparm.b5.a_frag_threshold[1];
+           + local->sparm.b5.a_frag_threshold[1];
        vwrq->disabled = (vwrq->value == 32767);
        vwrq->fixed = 1;
 
@@ -1352,23 +1378,20 @@ static int ray_get_frag(struct net_device *dev,
  * Wireless Handler : set Mode of Operation
  */
 static int ray_set_mode(struct net_device *dev,
-                       struct iw_request_info *info,
-                       __u32 *uwrq,
-                       char *extra)
+                       struct iw_request_info *info, __u32 *uwrq, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
-       int err = -EINPROGRESS;         /* Call commit handler */
+       int err = -EINPROGRESS; /* Call commit handler */
        char card_mode = 1;
 
        /* Reject if card is already initialised */
-       if(local->card_status != CARD_AWAITING_PARAM)
+       if (local->card_status != CARD_AWAITING_PARAM)
                return -EBUSY;
 
-       switch (*uwrq)
-       {
+       switch (*uwrq) {
        case IW_MODE_ADHOC:
                card_mode = 0;
-               // Fall through
+               /* Fall through */
        case IW_MODE_INFRA:
                local->sparm.b5.a_network_type = card_mode;
                break;
@@ -1384,13 +1407,11 @@ static int ray_set_mode(struct net_device *dev,
  * Wireless Handler : get Mode of Operation
  */
 static int ray_get_mode(struct net_device *dev,
-                       struct iw_request_info *info,
-                       __u32 *uwrq,
-                       char *extra)
+                       struct iw_request_info *info, __u32 *uwrq, char *extra)
 {
        ray_dev_t *local = netdev_priv(dev);
 
-       if(local->sparm.b5.a_network_type)
+       if (local->sparm.b5.a_network_type)
                *uwrq = IW_MODE_INFRA;
        else
                *uwrq = IW_MODE_ADHOC;
@@ -1404,12 +1425,11 @@ static int ray_get_mode(struct net_device *dev,
  */
 static int ray_get_range(struct net_device *dev,
                         struct iw_request_info *info,
-                        struct iw_point *dwrq,
-                        char *extra)
+                        struct iw_point *dwrq, char *extra)
 {
-       struct iw_range *range = (struct iw_range *) extra;
+       struct iw_range *range = (struct iw_range *)extra;
 
-       memset((char *) range, 0, sizeof(struct iw_range));
+       memset((char *)range, 0, sizeof(struct iw_range));
 
        /* Set the length (very important for backward compatibility) */
        dwrq->length = sizeof(struct iw_range);
@@ -1420,7 +1440,7 @@ static int ray_get_range(struct net_device *dev,
 
        /* Set information in the range struct */
        range->throughput = 1.1 * 1000 * 1000;  /* Put the right number here */
-       range->num_channels = hop_pattern_length[(int)country]; 
+       range->num_channels = hop_pattern_length[(int)country];
        range->num_frequency = 0;
        range->max_qual.qual = 0;
        range->max_qual.level = 255;    /* What's the correct value ? */
@@ -1437,8 +1457,7 @@ static int ray_get_range(struct net_device *dev,
  */
 static int ray_set_framing(struct net_device *dev,
                           struct iw_request_info *info,
-                          union iwreq_data *wrqu,
-                          char *extra)
+                          union iwreq_data *wrqu, char *extra)
 {
        translate = *(extra);   /* Set framing mode */
 
@@ -1451,8 +1470,7 @@ static int ray_set_framing(struct net_device *dev,
  */
 static int ray_get_framing(struct net_device *dev,
                           struct iw_request_info *info,
-                          union iwreq_data *wrqu,
-                          char *extra)
+                          union iwreq_data *wrqu, char *extra)
 {
        *(extra) = translate;
 
@@ -1465,8 +1483,7 @@ static int ray_get_framing(struct net_device *dev,
  */
 static int ray_get_country(struct net_device *dev,
                           struct iw_request_info *info,
-                          union iwreq_data *wrqu,
-                          char *extra)
+                          union iwreq_data *wrqu, char *extra)
 {
        *(extra) = country;
 
@@ -1477,11 +1494,10 @@ static int ray_get_country(struct net_device *dev,
 /*
  * Commit handler : called after a bunch of SET operations
  */
-static int ray_commit(struct net_device *dev,
-                     struct iw_request_info *info,     /* NULL */
-                     void *zwrq,                       /* NULL */
-                     char *extra)                      /* NULL */
-{
+static int ray_commit(struct net_device *dev, struct iw_request_info *info,    /* NULL */
+                     void *zwrq,       /* NULL */
+                     char *extra)
+{ /* NULL */
        return 0;
 }
 
@@ -1489,33 +1505,34 @@ static int ray_commit(struct net_device *dev,
 /*
  * Stats handler : return Wireless Stats
  */
-static iw_stats * ray_get_wireless_stats(struct net_device *   dev)
+static iw_stats *ray_get_wireless_stats(struct net_device *dev)
 {
-  ray_dev_t *  local = netdev_priv(dev);
-  struct pcmcia_device *link = local->finder;
-  struct status __iomem *p = local->sram + STATUS_BASE;
+       ray_dev_t *local = netdev_priv(dev);
+       struct pcmcia_device *link = local->finder;
+       struct status __iomem *p = local->sram + STATUS_BASE;
 
-  if(local == (ray_dev_t *) NULL)
-    return (iw_stats *) NULL;
+       if (local == (ray_dev_t *) NULL)
+               return (iw_stats *) NULL;
 
-  local->wstats.status = local->card_status;
+       local->wstats.status = local->card_status;
 #ifdef WIRELESS_SPY
-  if((local->spy_data.spy_number > 0) && (local->sparm.b5.a_network_type == 0))
-    {
-      /* Get it from the first node in spy list */
-      local->wstats.qual.qual = local->spy_data.spy_stat[0].qual;
-      local->wstats.qual.level = local->spy_data.spy_stat[0].level;
-      local->wstats.qual.noise = local->spy_data.spy_stat[0].noise;
-      local->wstats.qual.updated = local->spy_data.spy_stat[0].updated;
-    }
+       if ((local->spy_data.spy_number > 0)
+           && (local->sparm.b5.a_network_type == 0)) {
+               /* Get it from the first node in spy list */
+               local->wstats.qual.qual = local->spy_data.spy_stat[0].qual;
+               local->wstats.qual.level = local->spy_data.spy_stat[0].level;
+               local->wstats.qual.noise = local->spy_data.spy_stat[0].noise;
+               local->wstats.qual.updated =
+                   local->spy_data.spy_stat[0].updated;
+       }
 #endif /* WIRELESS_SPY */
 
-  if(pcmcia_dev_present(link)) {
-    local->wstats.qual.noise = readb(&p->rxnoise);
-    local->wstats.qual.updated |= 4;
-  }
+       if (pcmcia_dev_present(link)) {
+               local->wstats.qual.noise = readb(&p->rxnoise);
+               local->wstats.qual.updated |= 4;
+       }
 
-  return &local->wstats;
+       return &local->wstats;
 } /* end ray_get_wireless_stats */
 
 /*------------------------------------------------------------------*/
@@ -1523,1159 +1540,1264 @@ static iw_stats * ray_get_wireless_stats(struct net_device *        dev)
  * Structures to export the Wireless Handlers
  */
 
-static const iw_handler        ray_handler[] = {
-       [SIOCSIWCOMMIT-SIOCIWFIRST] = (iw_handler) ray_commit,
-       [SIOCGIWNAME  -SIOCIWFIRST] = (iw_handler) ray_get_name,
-       [SIOCSIWFREQ  -SIOCIWFIRST] = (iw_handler) ray_set_freq,
-       [SIOCGIWFREQ  -SIOCIWFIRST] = (iw_handler) ray_get_freq,
-       [SIOCSIWMODE  -SIOCIWFIRST] = (iw_handler) ray_set_mode,
-       [SIOCGIWMODE  -SIOCIWFIRST] = (iw_handler) ray_get_mode,
-       [SIOCGIWRANGE -SIOCIWFIRST] = (iw_handler) ray_get_range,
+static const iw_handler ray_handler[] = {
+       [SIOCSIWCOMMIT - SIOCIWFIRST] = (iw_handler) ray_commit,
+       [SIOCGIWNAME SIOCIWFIRST] = (iw_handler) ray_get_name,
+       [SIOCSIWFREQ SIOCIWFIRST] = (iw_handler) ray_set_freq,
+       [SIOCGIWFREQ SIOCIWFIRST] = (iw_handler) ray_get_freq,
+       [SIOCSIWMODE SIOCIWFIRST] = (iw_handler) ray_set_mode,
+       [SIOCGIWMODE SIOCIWFIRST] = (iw_handler) ray_get_mode,
+       [SIOCGIWRANGE - SIOCIWFIRST] = (iw_handler) ray_get_range,
 #ifdef WIRELESS_SPY
-       [SIOCSIWSPY   -SIOCIWFIRST] = (iw_handler) iw_handler_set_spy,
-       [SIOCGIWSPY   -SIOCIWFIRST] = (iw_handler) iw_handler_get_spy,
-       [SIOCSIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_set_thrspy,
-       [SIOCGIWTHRSPY-SIOCIWFIRST] = (iw_handler) iw_handler_get_thrspy,
-#endif /* WIRELESS_SPY */
-       [SIOCGIWAP    -SIOCIWFIRST] = (iw_handler) ray_get_wap,
-       [SIOCSIWESSID -SIOCIWFIRST] = (iw_handler) ray_set_essid,
-       [SIOCGIWESSID -SIOCIWFIRST] = (iw_handler) ray_get_essid,
-       [SIOCSIWRATE  -SIOCIWFIRST] = (iw_handler) ray_set_rate,
-       [SIOCGIWRATE  -SIOCIWFIRST] = (iw_handler) ray_get_rate,
-       [SIOCSIWRTS   -SIOCIWFIRST] = (iw_handler) ray_set_rts,
-       [SIOCGIWRTS   -SIOCIWFIRST] = (iw_handler) ray_get_rts,
-       [SIOCSIWFRAG  -SIOCIWFIRST] = (iw_handler) ray_set_frag,
-       [SIOCGIWFRAG  -SIOCIWFIRST] = (iw_handler) ray_get_frag,
+       [SIOCSIWSPY SIOCIWFIRST] = (iw_handler) iw_handler_set_spy,
+       [SIOCGIWSPY SIOCIWFIRST] = (iw_handler) iw_handler_get_spy,
+       [SIOCSIWTHRSPY - SIOCIWFIRST] = (iw_handler) iw_handler_set_thrspy,
+       [SIOCGIWTHRSPY - SIOCIWFIRST] = (iw_handler) iw_handler_get_thrspy,
+#endif /* WIRELESS_SPY */
+       [SIOCGIWAP SIOCIWFIRST] = (iw_handler) ray_get_wap,
+       [SIOCSIWESSID - SIOCIWFIRST] = (iw_handler) ray_set_essid,
+       [SIOCGIWESSID - SIOCIWFIRST] = (iw_handler) ray_get_essid,
+       [SIOCSIWRATE SIOCIWFIRST] = (iw_handler) ray_set_rate,
+       [SIOCGIWRATE SIOCIWFIRST] = (iw_handler) ray_get_rate,
+       [SIOCSIWRTS SIOCIWFIRST] = (iw_handler) ray_set_rts,
+       [SIOCGIWRTS SIOCIWFIRST] = (iw_handler) ray_get_rts,
+       [SIOCSIWFRAG SIOCIWFIRST] = (iw_handler) ray_set_frag,
+       [SIOCGIWFRAG SIOCIWFIRST] = (iw_handler) ray_get_frag,
 };
 
-#define SIOCSIPFRAMING SIOCIWFIRSTPRIV         /* Set framing mode */
+#define SIOCSIPFRAMING SIOCIWFIRSTPRIV /* Set framing mode */
 #define SIOCGIPFRAMING SIOCIWFIRSTPRIV + 1     /* Get framing mode */
 #define SIOCGIPCOUNTRY SIOCIWFIRSTPRIV + 3     /* Get country code */
 
-static const iw_handler        ray_private_handler[] = {
+static const iw_handler ray_private_handler[] = {
        [0] = (iw_handler) ray_set_framing,
        [1] = (iw_handler) ray_get_framing,
        [3] = (iw_handler) ray_get_country,
 };
 
-static const struct iw_priv_args       ray_private_args[] = {
+static const struct iw_priv_args ray_private_args[] = {
 /* cmd,                set_args,       get_args,       name */
-{ SIOCSIPFRAMING, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0, "set_framing" },
-{ SIOCGIPFRAMING, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_framing" },
-{ SIOCGIPCOUNTRY, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, "get_country" },
+       {SIOCSIPFRAMING, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1, 0,
+        "set_framing"},
+       {SIOCGIPFRAMING, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+        "get_framing"},
+       {SIOCGIPCOUNTRY, 0, IW_PRIV_TYPE_BYTE | IW_PRIV_SIZE_FIXED | 1,
+        "get_country"},
 };
 
-static const struct iw_handler_def     ray_handler_def =
-{
-       .num_standard   = ARRAY_SIZE(ray_handler),
-       .num_private    = ARRAY_SIZE(ray_private_handler),
+static const struct iw_handler_def ray_handler_def = {
+       .num_standard = ARRAY_SIZE(ray_handler),
+       .num_private = ARRAY_SIZE(ray_private_handler),
        .num_private_args = ARRAY_SIZE(ray_private_args),
-       .standard       = ray_handler,
-       .private        = ray_private_handler,
-       .private_args   = ray_private_args,
+       .standard = ray_handler,
+       .private = ray_private_handler,
+       .private_args = ray_private_args,
        .get_wireless_stats = ray_get_wireless_stats,
 };
 
 /*===========================================================================*/
 static int ray_open(struct net_device *dev)
 {
-    ray_dev_t *local = netdev_priv(dev);
-    struct pcmcia_device *link;
-    link = local->finder;
-    
-    DEBUG(1, "ray_open('%s')\n", dev->name);
+       ray_dev_t *local = netdev_priv(dev);
+       struct pcmcia_device *link;
+       link = local->finder;
 
-    if (link->open == 0)
-           local->num_multi = 0;
-    link->open++;
+       DEBUG(1, "ray_open('%s')\n", dev->name);
 
-    /* If the card is not started, time to start it ! - Jean II */
-    if(local->card_status == CARD_AWAITING_PARAM) {
-       int i;
+       if (link->open == 0)
+               local->num_multi = 0;
+       link->open++;
 
-       DEBUG(1,"ray_open: doing init now !\n");
+       /* If the card is not started, time to start it ! - Jean II */
+       if (local->card_status == CARD_AWAITING_PARAM) {
+               int i;
 
-       /* Download startup parameters */
-       if ( (i = dl_startup_params(dev)) < 0)
-         {
-           printk(KERN_INFO "ray_dev_init dl_startup_params failed - "
-                  "returns 0x%x\n",i);
-           return -1;
-         }
-     }
-
-    if (sniffer) netif_stop_queue(dev);
-    else         netif_start_queue(dev);
-
-    DEBUG(2,"ray_open ending\n");
-    return 0;
+               DEBUG(1, "ray_open: doing init now !\n");
+
+               /* Download startup parameters */
+               if ((i = dl_startup_params(dev)) < 0) {
+                       printk(KERN_INFO
+                              "ray_dev_init dl_startup_params failed - "
+                              "returns 0x%x\n", i);
+                       return -1;
+               }
+       }
+
+       if (sniffer)
+               netif_stop_queue(dev);
+       else
+               netif_start_queue(dev);
+
+       DEBUG(2, "ray_open ending\n");
+       return 0;
 } /* end ray_open */
+
 /*===========================================================================*/
 static int ray_dev_close(struct net_device *dev)
 {
-    ray_dev_t *local = netdev_priv(dev);
-    struct pcmcia_device *link;
-    link = local->finder;
+       ray_dev_t *local = netdev_priv(dev);
+       struct pcmcia_device *link;
+       link = local->finder;
 
-    DEBUG(1, "ray_dev_close('%s')\n", dev->name);
+       DEBUG(1, "ray_dev_close('%s')\n", dev->name);
 
-    link->open--;
-    netif_stop_queue(dev);
+       link->open--;
+       netif_stop_queue(dev);
 
-    /* In here, we should stop the hardware (stop card from beeing active)
-     * and set local->card_status to CARD_AWAITING_PARAM, so that while the
-     * card is closed we can chage its configuration.
-     * Probably also need a COR reset to get sane state - Jean II */
+       /* In here, we should stop the hardware (stop card from beeing active)
+        * and set local->card_status to CARD_AWAITING_PARAM, so that while the
+        * card is closed we can chage its configuration.
+        * Probably also need a COR reset to get sane state - Jean II */
 
-    return 0;
+       return 0;
 } /* end ray_dev_close */
+
 /*===========================================================================*/
-static void ray_reset(struct net_device *dev) {
-    DEBUG(1,"ray_reset entered\n");
-    return;
+static void ray_reset(struct net_device *dev)
+{
+       DEBUG(1, "ray_reset entered\n");
+       return;
 }
+
 /*===========================================================================*/
 /* Cause a firmware interrupt if it is ready for one                         */
 /* Return nonzero if not ready                                               */
 static int interrupt_ecf(ray_dev_t *local, int ccs)
 {
-    int i = 50;
-    struct pcmcia_device *link = local->finder;
-
-    if (!(pcmcia_dev_present(link))) {
-        DEBUG(2,"ray_cs interrupt_ecf - device not present\n");
-        return -1;
-    }
-    DEBUG(2,"interrupt_ecf(local=%p, ccs = 0x%x\n",local,ccs);
-
-    while ( i && 
-            (readb(local->amem + CIS_OFFSET + ECF_INTR_OFFSET) & ECF_INTR_SET))
-        i--;
-    if (i == 0) {
-        DEBUG(2,"ray_cs interrupt_ecf card not ready for interrupt\n");
-        return -1;
-    }
+       int i = 50;
+       struct pcmcia_device *link = local->finder;
+
+       if (!(pcmcia_dev_present(link))) {
+               DEBUG(2, "ray_cs interrupt_ecf - device not present\n");
+               return -1;
+       }
+       DEBUG(2, "interrupt_ecf(local=%p, ccs = 0x%x\n", local, ccs);
+
+       while (i &&
+              (readb(local->amem + CIS_OFFSET + ECF_INTR_OFFSET) &
+               ECF_INTR_SET))
+               i--;
+       if (i == 0) {
+               DEBUG(2, "ray_cs interrupt_ecf card not ready for interrupt\n");
+               return -1;
+       }
        /* Fill the mailbox, then kick the card */
-    writeb(ccs, local->sram + SCB_BASE);
-    writeb(ECF_INTR_SET, local->amem + CIS_OFFSET + ECF_INTR_OFFSET);
-    return 0;
+       writeb(ccs, local->sram + SCB_BASE);
+       writeb(ECF_INTR_SET, local->amem + CIS_OFFSET + ECF_INTR_OFFSET);
+       return 0;
 } /* interrupt_ecf */
+
 /*===========================================================================*/
 /* Get next free transmit CCS                                                */
 /* Return - index of current tx ccs                                          */
 static int get_free_tx_ccs(ray_dev_t *local)
 {
-    int i;
-    struct ccs __iomem *pccs = ccs_base(local);
-    struct pcmcia_device *link = local->finder;
+       int i;
+       struct ccs __iomem *pccs = ccs_base(local);
+       struct pcmcia_device *link = local->finder;
 
-    if (!(pcmcia_dev_present(link))) {
-        DEBUG(2,"ray_cs get_free_tx_ccs - device not present\n");
-        return ECARDGONE;
-    }
+       if (!(pcmcia_dev_present(link))) {
+               DEBUG(2, "ray_cs get_free_tx_ccs - device not present\n");
+               return ECARDGONE;
+       }
 
-    if (test_and_set_bit(0,&local->tx_ccs_lock)) {
-        DEBUG(1,"ray_cs tx_ccs_lock busy\n");
-        return ECCSBUSY;
-    } 
+       if (test_and_set_bit(0, &local->tx_ccs_lock)) {
+               DEBUG(1, "ray_cs tx_ccs_lock busy\n");
+               return ECCSBUSY;
+       }
 
-    for (i=0; i < NUMBER_OF_TX_CCS; i++) {
-        if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) {
-            writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status);
-            writeb(CCS_END_LIST, &(pccs+i)->link);
+       for (i = 0; i < NUMBER_OF_TX_CCS; i++) {
+               if (readb(&(pccs + i)->buffer_status) == CCS_BUFFER_FREE) {
+                       writeb(CCS_BUFFER_BUSY, &(pccs + i)->buffer_status);
+                       writeb(CCS_END_LIST, &(pccs + i)->link);
                        local->tx_ccs_lock = 0;
-            return i;
-        }
-    }
+                       return i;
+               }
+       }
        local->tx_ccs_lock = 0;
-    DEBUG(2,"ray_cs ERROR no free tx CCS for raylink card\n");
-    return ECCSFULL;
+       DEBUG(2, "ray_cs ERROR no free tx CCS for raylink card\n");
+       return ECCSFULL;
 } /* get_free_tx_ccs */
+
 /*===========================================================================*/
 /* Get next free CCS                                                         */
 /* Return - index of current ccs                                             */
 static int get_free_ccs(ray_dev_t *local)
 {
-    int i;
-    struct ccs __iomem *pccs = ccs_base(local);
-    struct pcmcia_device *link = local->finder;
-
-    if (!(pcmcia_dev_present(link))) {
-        DEBUG(2,"ray_cs get_free_ccs - device not present\n");
-        return ECARDGONE;
-    }
-    if (test_and_set_bit(0,&local->ccs_lock)) {
-        DEBUG(1,"ray_cs ccs_lock busy\n");
-        return ECCSBUSY;
-    } 
-
-    for (i = NUMBER_OF_TX_CCS; i < NUMBER_OF_CCS; i++) {
-        if (readb(&(pccs+i)->buffer_status) == CCS_BUFFER_FREE) {
-            writeb(CCS_BUFFER_BUSY, &(pccs+i)->buffer_status);
-            writeb(CCS_END_LIST, &(pccs+i)->link);
+       int i;
+       struct ccs __iomem *pccs = ccs_base(local);
+       struct pcmcia_device *link = local->finder;
+
+       if (!(pcmcia_dev_present(link))) {
+               DEBUG(2, "ray_cs get_free_ccs - device not present\n");
+               return ECARDGONE;
+       }
+       if (test_and_set_bit(0, &local->ccs_lock)) {
+               DEBUG(1, "ray_cs ccs_lock busy\n");
+               return ECCSBUSY;
+       }
+
+       for (i = NUMBER_OF_TX_CCS; i < NUMBER_OF_CCS; i++) {
+               if (readb(&(pccs + i)->buffer_status) == CCS_BUFFER_FREE) {
+                       writeb(CCS_BUFFER_BUSY, &(pccs + i)->buffer_status);
+                       writeb(CCS_END_LIST, &(pccs + i)->link);
                        local->ccs_lock = 0;
-            return i;
-        }
-    }
+                       return i;
+               }
+       }
        local->ccs_lock = 0;
-    DEBUG(1,"ray_cs ERROR no free CCS for raylink card\n");
-    return ECCSFULL;
+       DEBUG(1, "ray_cs ERROR no free CCS for raylink card\n");
+       return ECCSFULL;
 } /* get_free_ccs */
+
 /*===========================================================================*/
 static void authenticate_timeout(u_long data)
 {
-    ray_dev_t *local = (ray_dev_t *)data;
-    del_timer(&local->timer);
-    printk(KERN_INFO "ray_cs Authentication with access point failed"
-       " - timeout\n");
-    join_net((u_long)local);
+       ray_dev_t *local = (ray_dev_t *) data;
+       del_timer(&local->timer);
+       printk(KERN_INFO "ray_cs Authentication with access point failed"
+              " - timeout\n");
+       join_net((u_long) local);
 }
+
 /*===========================================================================*/
 static int asc_to_int(char a)
 {
-    if (a < '0') return -1;
-    if (a <= '9') return (a - '0');
-    if (a < 'A') return -1;
-    if (a <= 'F') return (10 + a - 'A');
-    if (a < 'a') return -1;
-    if (a <= 'f') return (10 + a - 'a');
-    return -1;
+       if (a < '0')
+               return -1;
+       if (a <= '9')
+               return (a - '0');
+       if (a < 'A')
+               return -1;
+       if (a <= 'F')
+               return (10 + a - 'A');
+       if (a < 'a')
+               return -1;
+       if (a <= 'f')
+               return (10 + a - 'a');
+       return -1;
 }
+
 /*===========================================================================*/
 static int parse_addr(char *in_str, UCHAR *out)
 {
-    int len;
-    int i,j,k;
-    int status;
-    
-    if (in_str == NULL) return 0;
-    if ((len = strlen(in_str)) < 2) return 0;
-    memset(out, 0, ADDRLEN);
-
-    status = 1;
-    j = len - 1;
-    if (j > 12) j = 12;
-    i = 5;
-    
-    while (j > 0)
-    {
-        if ((k = asc_to_int(in_str[j--])) != -1) out[i] = k;
-        else return 0;
-
-        if (j == 0) break;
-        if ((k = asc_to_int(in_str[j--])) != -1) out[i] += k << 4;
-        else return 0;
-        if (!i--) break;
-    }
-    return status;
+       int len;
+       int i, j, k;
+       int status;
+
+       if (in_str == NULL)
+               return 0;
+       if ((len = strlen(in_str)) < 2)
+               return 0;
+       memset(out, 0, ADDRLEN);
+
+       status = 1;
+       j = len - 1;
+       if (j > 12)
+               j = 12;
+       i = 5;
+
+       while (j > 0) {
+               if ((k = asc_to_int(in_str[j--])) != -1)
+                       out[i] = k;
+               else
+                       return 0;
+
+               if (j == 0)
+                       break;
+               if ((k = asc_to_int(in_str[j--])) != -1)
+                       out[i] += k << 4;
+               else
+                       return 0;
+               if (!i--)
+                       break;
+       }
+       return status;
 }
+
 /*===========================================================================*/
 static struct net_device_stats *ray_get_stats(struct net_device *dev)
 {
-    ray_dev_t *local = netdev_priv(dev);
-    struct pcmcia_device *link = local->finder;
-    struct status __iomem *p = local->sram + STATUS_BASE;
-    if (!(pcmcia_dev_present(link))) {
-        DEBUG(2,"ray_cs net_device_stats - device not present\n");
-        return &local->stats;
-    }
-    if (readb(&p->mrx_overflow_for_host))
-    {
-        local->stats.rx_over_errors += swab16(readw(&p->mrx_overflow));
-        writeb(0,&p->mrx_overflow);
-        writeb(0,&p->mrx_overflow_for_host);
-    }
-    if (readb(&p->mrx_checksum_error_for_host))
-    {
-        local->stats.rx_crc_errors += swab16(readw(&p->mrx_checksum_error));
-        writeb(0,&p->mrx_checksum_error);
-        writeb(0,&p->mrx_checksum_error_for_host);
-    }
-    if (readb(&p->rx_hec_error_for_host))
-    {
-        local->stats.rx_frame_errors += swab16(readw(&p->rx_hec_error));
-        writeb(0,&p->rx_hec_error);
-        writeb(0,&p->rx_hec_error_for_host);
-    }
-    return &local->stats;
+       ray_dev_t *local = netdev_priv(dev);
+       struct pcmcia_device *link = local->finder;
+       struct status __iomem *p = local->sram + STATUS_BASE;
+       if (!(pcmcia_dev_present(link))) {
+               DEBUG(2, "ray_cs net_device_stats - device not present\n");
+               return &local->stats;
+       }
+       if (readb(&p->mrx_overflow_for_host)) {
+               local->stats.rx_over_errors += swab16(readw(&p->mrx_overflow));
+               writeb(0, &p->mrx_overflow);
+               writeb(0, &p->mrx_overflow_for_host);
+       }
+       if (readb(&p->mrx_checksum_error_for_host)) {
+               local->stats.rx_crc_errors +=
+                   swab16(readw(&p->mrx_checksum_error));
+               writeb(0, &p->mrx_checksum_error);
+               writeb(0, &p->mrx_checksum_error_for_host);
+       }
+       if (readb(&p->rx_hec_error_for_host)) {
+               local->stats.rx_frame_errors += swab16(readw(&p->rx_hec_error));
+               writeb(0, &p->rx_hec_error);
+               writeb(0, &p->rx_hec_error_for_host);
+       }
+       return &local->stats;
 }
+
 /*===========================================================================*/
-static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value, int len)
-{
-    ray_dev_t *local = netdev_priv(dev);
-    struct pcmcia_device *link = local->finder;
-    int ccsindex;
-    int i;
-    struct ccs __iomem *pccs;
-
-    if (!(pcmcia_dev_present(link))) {
-        DEBUG(2,"ray_update_parm - device not present\n");
-        return;
-    }
-
-    if ((ccsindex = get_free_ccs(local)) < 0)
-    {
-        DEBUG(0,"ray_update_parm - No free ccs\n");
-        return;
-    }
-    pccs = ccs_base(local) + ccsindex;
-    writeb(CCS_UPDATE_PARAMS, &pccs->cmd);
-    writeb(objid, &pccs->var.update_param.object_id);
-    writeb(1, &pccs->var.update_param.number_objects);
-    writeb(0, &pccs->var.update_param.failure_cause);
-    for (i=0; i<len; i++) {
-        writeb(value[i], local->sram + HOST_TO_ECF_BASE);
-    }
-    /* Interrupt the firmware to process the command */
-    if (interrupt_ecf(local, ccsindex)) {
-        DEBUG(0,"ray_cs associate failed - ECF not ready for intr\n");
-        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
-    }
+static void ray_update_parm(struct net_device *dev, UCHAR objid, UCHAR *value,
+                           int len)
+{
+       ray_dev_t *local = netdev_priv(dev);
+       struct pcmcia_device *link = local->finder;
+       int ccsindex;
+       int i;
+       struct ccs __iomem *pccs;
+
+       if (!(pcmcia_dev_present(link))) {
+               DEBUG(2, "ray_update_parm - device not present\n");
+               return;
+       }
+
+       if ((ccsindex = get_free_ccs(local)) < 0) {
+               DEBUG(0, "ray_update_parm - No free ccs\n");
+               return;
+       }
+       pccs = ccs_base(local) + ccsindex;
+       writeb(CCS_UPDATE_PARAMS, &pccs->cmd);
+       writeb(objid, &pccs->var.update_param.object_id);
+       writeb(1, &pccs->var.update_param.number_objects);
+       writeb(0, &pccs->var.update_param.failure_cause);
+       for (i = 0; i < len; i++) {
+               writeb(value[i], local->sram + HOST_TO_ECF_BASE);
+       }
+       /* Interrupt the firmware to process the command */
+       if (interrupt_ecf(local, ccsindex)) {
+               DEBUG(0, "ray_cs associate failed - ECF not ready for intr\n");
+               writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+       }
 }
+
 /*===========================================================================*/
 static void ray_update_multi_list(struct net_device *dev, int all)
 {
-    struct dev_mc_list *dmi, **dmip;
-    int ccsindex;
-    struct ccs __iomem *pccs;
-    int i = 0;
-    ray_dev_t *local = netdev_priv(dev);
-    struct pcmcia_device *link = local->finder;
-    void __iomem *p = local->sram + HOST_TO_ECF_BASE;
-
-    if (!(pcmcia_dev_present(link))) {
-        DEBUG(2,"ray_update_multi_list - device not present\n");
-        return;
-    }
-    else 
-        DEBUG(2,"ray_update_multi_list(%p)\n",dev);
-    if ((ccsindex = get_free_ccs(local)) < 0)
-    {
-        DEBUG(1,"ray_update_multi - No free ccs\n");
-        return;
-    }
-    pccs = ccs_base(local) + ccsindex;
-    writeb(CCS_UPDATE_MULTICAST_LIST, &pccs->cmd);
-
-    if (all) {
-        writeb(0xff, &pccs->var);
-        local->num_multi = 0xff;
-    }
-    else {
-        /* Copy the kernel's list of MC addresses to card */
-        for (dmip=&dev->mc_list; (dmi=*dmip)!=NULL; dmip=&dmi->next) {
-            memcpy_toio(p, dmi->dmi_addr, ETH_ALEN);
-            DEBUG(1,"ray_update_multi add addr %02x%02x%02x%02x%02x%02x\n",dmi->dmi_addr[0],dmi->dmi_addr[1],dmi->dmi_addr[2],dmi->dmi_addr[3],dmi->dmi_addr[4],dmi->dmi_addr[5]);
-            p += ETH_ALEN;
-            i++;
-        }
-        if (i > 256/ADDRLEN) i = 256/ADDRLEN;
-        writeb((UCHAR)i, &pccs->var);
-        DEBUG(1,"ray_cs update_multi %d addresses in list\n", i);
-        /* Interrupt the firmware to process the command */
-        local->num_multi = i;
-    }
-    if (interrupt_ecf(local, ccsindex)) {
-        DEBUG(1,"ray_cs update_multi failed - ECF not ready for intr\n");
-        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
-    }
+       struct dev_mc_list *dmi, **dmip;
+       int ccsindex;
+       struct ccs __iomem *pccs;
+       int i = 0;
+       ray_dev_t *local = netdev_priv(dev);
+       struct pcmcia_device *link = local->finder;
+       void __iomem *p = local->sram + HOST_TO_ECF_BASE;
+
+       if (!(pcmcia_dev_present(link))) {
+               DEBUG(2, "ray_update_multi_list - device not present\n");
+               return;
+       } else
+               DEBUG(2, "ray_update_multi_list(%p)\n", dev);
+       if ((ccsindex = get_free_ccs(local)) < 0) {
+               DEBUG(1, "ray_update_multi - No free ccs\n");
+               return;
+       }
+       pccs = ccs_base(local) + ccsindex;
+       writeb(CCS_UPDATE_MULTICAST_LIST, &pccs->cmd);
+
+       if (all) {
+               writeb(0xff, &pccs->var);
+               local->num_multi = 0xff;
+       } else {
+               /* Copy the kernel's list of MC addresses to card */
+               for (dmip = &dev->mc_list; (dmi = *dmip) != NULL;
+                    dmip = &dmi->next) {
+                       memcpy_toio(p, dmi->dmi_addr, ETH_ALEN);
+                       DEBUG(1,
+                             "ray_update_multi add addr %02x%02x%02x%02x%02x%02x\n",
+                             dmi->dmi_addr[0], dmi->dmi_addr[1],
+                             dmi->dmi_addr[2], dmi->dmi_addr[3],
+                             dmi->dmi_addr[4], dmi->dmi_addr[5]);
+                       p += ETH_ALEN;
+                       i++;
+               }
+               if (i > 256 / ADDRLEN)
+                       i = 256 / ADDRLEN;
+               writeb((UCHAR) i, &pccs->var);
+               DEBUG(1, "ray_cs update_multi %d addresses in list\n", i);
+               /* Interrupt the firmware to process the command */
+               local->num_multi = i;
+       }
+       if (interrupt_ecf(local, ccsindex)) {
+               DEBUG(1,
+                     "ray_cs update_multi failed - ECF not ready for intr\n");
+               writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+       }
 } /* end ray_update_multi_list */
+
 /*===========================================================================*/
 static void set_multicast_list(struct net_device *dev)
 {
-    ray_dev_t *local = netdev_priv(dev);
-    UCHAR promisc;
-
-    DEBUG(2,"ray_cs set_multicast_list(%p)\n",dev);
-
-    if (dev->flags & IFF_PROMISC)
-    {
-        if (local->sparm.b5.a_promiscuous_mode == 0) {
-            DEBUG(1,"ray_cs set_multicast_list promisc on\n");
-            local->sparm.b5.a_promiscuous_mode = 1;
-            promisc = 1;
-            ray_update_parm(dev,  OBJID_promiscuous_mode, \
-                            &promisc, sizeof(promisc));
-        }
-    }
-    else {
-        if (local->sparm.b5.a_promiscuous_mode == 1) {
-            DEBUG(1,"ray_cs set_multicast_list promisc off\n");
-            local->sparm.b5.a_promiscuous_mode = 0;
-            promisc = 0;
-            ray_update_parm(dev,  OBJID_promiscuous_mode, \
-                            &promisc, sizeof(promisc));
-        }
-    }
-
-    if (dev->flags & IFF_ALLMULTI) ray_update_multi_list(dev, 1);
-    else
-    {
-        if (local->num_multi != dev->mc_count) ray_update_multi_list(dev, 0);
-    }
+       ray_dev_t *local = netdev_priv(dev);
+       UCHAR promisc;
+
+       DEBUG(2, "ray_cs set_multicast_list(%p)\n", dev);
+
+       if (dev->flags & IFF_PROMISC) {
+               if (local->sparm.b5.a_promiscuous_mode == 0) {
+                       DEBUG(1, "ray_cs set_multicast_list promisc on\n");
+                       local->sparm.b5.a_promiscuous_mode = 1;
+                       promisc = 1;
+                       ray_update_parm(dev, OBJID_promiscuous_mode,
+                                       &promisc, sizeof(promisc));
+               }
+       } else {
+               if (local->sparm.b5.a_promiscuous_mode == 1) {
+                       DEBUG(1, "ray_cs set_multicast_list promisc off\n");
+                       local->sparm.b5.a_promiscuous_mode = 0;
+                       promisc = 0;
+                       ray_update_parm(dev, OBJID_promiscuous_mode,
+                                       &promisc, sizeof(promisc));
+               }
+       }
+
+       if (dev->flags & IFF_ALLMULTI)
+               ray_update_multi_list(dev, 1);
+       else {
+               if (local->num_multi != dev->mc_count)
+                       ray_update_multi_list(dev, 0);
+       }
 } /* end set_multicast_list */
+
 /*=============================================================================
  * All routines below here are run at interrupt time.
 =============================================================================*/
 static irqreturn_t ray_interrupt(int irq, void *dev_id)
 {
-    struct net_device *dev = (struct net_device *)dev_id;
-    struct pcmcia_device *link;
-    ray_dev_t *local;
-    struct ccs __iomem *pccs;
-    struct rcs __iomem *prcs;
-    UCHAR rcsindex;
-    UCHAR tmp;
-    UCHAR cmd;
-    UCHAR status;
-
-    if (dev == NULL) /* Note that we want interrupts with dev->start == 0 */
-       return IRQ_NONE;
-
-    DEBUG(4,"ray_cs: interrupt for *dev=%p\n",dev);
-
-    local = netdev_priv(dev);
-    link = (struct pcmcia_device *)local->finder;
-    if (!pcmcia_dev_present(link)) {
-        DEBUG(2,"ray_cs interrupt from device not present or suspended.\n");
-        return IRQ_NONE;
-    }
-    rcsindex = readb(&((struct scb __iomem *)(local->sram))->rcs_index);
-
-    if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS))
-    {
-        DEBUG(1,"ray_cs interrupt bad rcsindex = 0x%x\n",rcsindex);
-        clear_interrupt(local);
-        return IRQ_HANDLED;
-    }
-    if (rcsindex < NUMBER_OF_CCS) /* If it's a returned CCS */
-    {
-        pccs = ccs_base(local) + rcsindex;
-        cmd = readb(&pccs->cmd);
-        status = readb(&pccs->buffer_status);
-        switch (cmd)
-        {
-        case CCS_DOWNLOAD_STARTUP_PARAMS: /* Happens in firmware someday */
-            del_timer(&local->timer);
-            if (status == CCS_COMMAND_COMPLETE) {
-                DEBUG(1,"ray_cs interrupt download_startup_parameters OK\n");
-            }
-            else {
-                DEBUG(1,"ray_cs interrupt download_startup_parameters fail\n");
-            }
-            break;
-        case CCS_UPDATE_PARAMS:
-            DEBUG(1,"ray_cs interrupt update params done\n");
-            if (status != CCS_COMMAND_COMPLETE) {
-                tmp = readb(&pccs->var.update_param.failure_cause);
-            DEBUG(0,"ray_cs interrupt update params failed - reason %d\n",tmp);
-            }
-            break;
-        case CCS_REPORT_PARAMS:
-            DEBUG(1,"ray_cs interrupt report params done\n");
-            break;
-        case CCS_UPDATE_MULTICAST_LIST: /* Note that this CCS isn't returned */
-            DEBUG(1,"ray_cs interrupt CCS Update Multicast List done\n");
-            break;
-        case CCS_UPDATE_POWER_SAVINGS_MODE:
-            DEBUG(1,"ray_cs interrupt update power save mode done\n");
-            break;
-        case CCS_START_NETWORK:
-        case CCS_JOIN_NETWORK:
-            if (status == CCS_COMMAND_COMPLETE) {
-                if (readb(&pccs->var.start_network.net_initiated) == 1) {
-                    DEBUG(0,"ray_cs interrupt network \"%s\" started\n",\
-                          local->sparm.b4.a_current_ess_id);
-                }
-                else {
-                    DEBUG(0,"ray_cs interrupt network \"%s\" joined\n",\
-                          local->sparm.b4.a_current_ess_id);
-                }
-                memcpy_fromio(&local->bss_id,pccs->var.start_network.bssid,ADDRLEN);
-
-                if (local->fw_ver == 0x55) local->net_default_tx_rate = 3;
-                else local->net_default_tx_rate = 
-                         readb(&pccs->var.start_network.net_default_tx_rate);
-                local->encryption = readb(&pccs->var.start_network.encryption);
-                if (!sniffer && (local->net_type == INFRA)
-                    && !(local->sparm.b4.a_acting_as_ap_status)) {
-                    authenticate(local);
-                }
-                local->card_status = CARD_ACQ_COMPLETE;
-            }
-            else {
-                local->card_status = CARD_ACQ_FAILED;
-
-                del_timer(&local->timer);
-                local->timer.expires = jiffies + HZ*5;
-                local->timer.data = (long)local;
-                if (status == CCS_START_NETWORK) {
-                    DEBUG(0,"ray_cs interrupt network \"%s\" start failed\n",\
-                          local->sparm.b4.a_current_ess_id);
-                    local->timer.function = &start_net;
-                }
-                else {
-                    DEBUG(0,"ray_cs interrupt network \"%s\" join failed\n",\
-                          local->sparm.b4.a_current_ess_id);
-                    local->timer.function = &join_net;
-                }
-                add_timer(&local->timer);
-            }
-            break;
-        case CCS_START_ASSOCIATION:
-            if (status == CCS_COMMAND_COMPLETE) {
-                local->card_status = CARD_ASSOC_COMPLETE;
-                DEBUG(0,"ray_cs association successful\n");
-            }
-            else
-            {
-                DEBUG(0,"ray_cs association failed,\n");
-                local->card_status = CARD_ASSOC_FAILED;
-                join_net((u_long)local);
-            }
-            break;
-        case CCS_TX_REQUEST:
-            if (status == CCS_COMMAND_COMPLETE) {
-                DEBUG(3,"ray_cs interrupt tx request complete\n");
-            }
-            else {
-                DEBUG(1,"ray_cs interrupt tx request failed\n");
-            }
-            if (!sniffer) netif_start_queue(dev);
-            netif_wake_queue(dev);
-            break;
-        case CCS_TEST_MEMORY:
-            DEBUG(1,"ray_cs interrupt mem test done\n");
-            break;
-        case CCS_SHUTDOWN:
-            DEBUG(1,"ray_cs interrupt Unexpected CCS returned - Shutdown\n");
-            break;
-        case CCS_DUMP_MEMORY:
-            DEBUG(1,"ray_cs interrupt dump memory done\n");
-            break;
-        case CCS_START_TIMER:
-            DEBUG(2,"ray_cs interrupt DING - raylink timer expired\n");
-            break;
-        default:
-            DEBUG(1,"ray_cs interrupt Unexpected CCS 0x%x returned 0x%x\n",\
-                  rcsindex, cmd);
-        }
-        writeb(CCS_BUFFER_FREE, &pccs->buffer_status);
-    }
-    else /* It's an RCS */
-    {
-        prcs = rcs_base(local) + rcsindex;
-    
-        switch (readb(&prcs->interrupt_id))
-        {
-        case PROCESS_RX_PACKET:
-            ray_rx(dev, local, prcs);
-            break;
-        case REJOIN_NET_COMPLETE:
-            DEBUG(1,"ray_cs interrupt rejoin net complete\n");
-            local->card_status = CARD_ACQ_COMPLETE;
-            /* do we need to clear tx buffers CCS's? */
-            if (local->sparm.b4.a_network_type == ADHOC) {
-                if (!sniffer) netif_start_queue(dev);
-            }
-            else {
-                memcpy_fromio(&local->bss_id, prcs->var.rejoin_net_complete.bssid, ADDRLEN);
-                DEBUG(1,"ray_cs new BSSID = %02x%02x%02x%02x%02x%02x\n",\
-                      local->bss_id[0], local->bss_id[1], local->bss_id[2],\
-                      local->bss_id[3], local->bss_id[4], local->bss_id[5]);
-                if (!sniffer) authenticate(local);
-            }
-            break;
-        case ROAMING_INITIATED:
-            DEBUG(1,"ray_cs interrupt roaming initiated\n"); 
-            netif_stop_queue(dev);
-            local->card_status = CARD_DOING_ACQ;
-            break;
-        case JAPAN_CALL_SIGN_RXD:
-            DEBUG(1,"ray_cs interrupt japan call sign rx\n");
-            break;
-        default:
-            DEBUG(1,"ray_cs Unexpected interrupt for RCS 0x%x cmd = 0x%x\n",\
-                  rcsindex, (unsigned int) readb(&prcs->interrupt_id));
-            break;
-        }
-        writeb(CCS_BUFFER_FREE, &prcs->buffer_status);
-    }
-    clear_interrupt(local);
-    return IRQ_HANDLED;
+       struct net_device *dev = (struct net_device *)dev_id;
+       struct pcmcia_device *link;
+       ray_dev_t *local;
+       struct ccs __iomem *pccs;
+       struct rcs __iomem *prcs;
+       UCHAR rcsindex;
+       UCHAR tmp;
+       UCHAR cmd;
+       UCHAR status;
+
+       if (dev == NULL)        /* Note that we want interrupts with dev->start == 0 */
+               return IRQ_NONE;
+
+       DEBUG(4, "ray_cs: interrupt for *dev=%p\n", dev);
+
+       local = netdev_priv(dev);
+       link = (struct pcmcia_device *)local->finder;
+       if (!pcmcia_dev_present(link)) {
+               DEBUG(2,
+                     "ray_cs interrupt from device not present or suspended.\n");
+               return IRQ_NONE;
+       }
+       rcsindex = readb(&((struct scb __iomem *)(local->sram))->rcs_index);
+
+       if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) {
+               DEBUG(1, "ray_cs interrupt bad rcsindex = 0x%x\n", rcsindex);
+               clear_interrupt(local);
+               return IRQ_HANDLED;
+       }
+       if (rcsindex < NUMBER_OF_CCS) { /* If it's a returned CCS */
+               pccs = ccs_base(local) + rcsindex;
+               cmd = readb(&pccs->cmd);
+               status = readb(&pccs->buffer_status);
+               switch (cmd) {
+               case CCS_DOWNLOAD_STARTUP_PARAMS:       /* Happens in firmware someday */
+                       del_timer(&local->timer);
+                       if (status == CCS_COMMAND_COMPLETE) {
+                               DEBUG(1,
+                                     "ray_cs interrupt download_startup_parameters OK\n");
+                       } else {
+                               DEBUG(1,
+                                     "ray_cs interrupt download_startup_parameters fail\n");
+                       }
+                       break;
+               case CCS_UPDATE_PARAMS:
+                       DEBUG(1, "ray_cs interrupt update params done\n");
+                       if (status != CCS_COMMAND_COMPLETE) {
+                               tmp =
+                                   readb(&pccs->var.update_param.
+                                         failure_cause);
+                               DEBUG(0,
+                                     "ray_cs interrupt update params failed - reason %d\n",
+                                     tmp);
+                       }
+                       break;
+               case CCS_REPORT_PARAMS:
+                       DEBUG(1, "ray_cs interrupt report params done\n");
+                       break;
+               case CCS_UPDATE_MULTICAST_LIST: /* Note that this CCS isn't returned */
+                       DEBUG(1,
+                             "ray_cs interrupt CCS Update Multicast List done\n");
+                       break;
+               case CCS_UPDATE_POWER_SAVINGS_MODE:
+                       DEBUG(1,
+                             "ray_cs interrupt update power save mode done\n");
+                       break;
+               case CCS_START_NETWORK:
+               case CCS_JOIN_NETWORK:
+                       if (status == CCS_COMMAND_COMPLETE) {
+                               if (readb
+                                   (&pccs->var.start_network.net_initiated) ==
+                                   1) {
+                                       DEBUG(0,
+                                             "ray_cs interrupt network \"%s\" started\n",
+                                             local->sparm.b4.a_current_ess_id);
+                               } else {
+                                       DEBUG(0,
+                                             "ray_cs interrupt network \"%s\" joined\n",
+                                             local->sparm.b4.a_current_ess_id);
+                               }
+                               memcpy_fromio(&local->bss_id,
+                                             pccs->var.start_network.bssid,
+                                             ADDRLEN);
+
+                               if (local->fw_ver == 0x55)
+                                       local->net_default_tx_rate = 3;
+                               else
+                                       local->net_default_tx_rate =
+                                           readb(&pccs->var.start_network.
+                                                 net_default_tx_rate);
+                               local->encryption =
+                                   readb(&pccs->var.start_network.encryption);
+                               if (!sniffer && (local->net_type == INFRA)
+                                   && !(local->sparm.b4.a_acting_as_ap_status)) {
+                                       authenticate(local);
+                               }
+                               local->card_status = CARD_ACQ_COMPLETE;
+                       } else {
+                               local->card_status = CARD_ACQ_FAILED;
+
+                               del_timer(&local->timer);
+                               local->timer.expires = jiffies + HZ * 5;
+                               local->timer.data = (long)local;
+                               if (status == CCS_START_NETWORK) {
+                                       DEBUG(0,
+                                             "ray_cs interrupt network \"%s\" start failed\n",
+                                             local->sparm.b4.a_current_ess_id);
+                                       local->timer.function = &start_net;
+                               } else {
+                                       DEBUG(0,
+                                             "ray_cs interrupt network \"%s\" join failed\n",
+                                             local->sparm.b4.a_current_ess_id);
+                                       local->timer.function = &join_net;
+                               }
+                               add_timer(&local->timer);
+                       }
+                       break;
+               case CCS_START_ASSOCIATION:
+                       if (status == CCS_COMMAND_COMPLETE) {
+                               local->card_status = CARD_ASSOC_COMPLETE;
+                               DEBUG(0, "ray_cs association successful\n");
+                       } else {
+                               DEBUG(0, "ray_cs association failed,\n");
+                               local->card_status = CARD_ASSOC_FAILED;
+                               join_net((u_long) local);
+                       }
+                       break;
+               case CCS_TX_REQUEST:
+                       if (status == CCS_COMMAND_COMPLETE) {
+                               DEBUG(3,
+                                     "ray_cs interrupt tx request complete\n");
+                       } else {
+                               DEBUG(1,
+                                     "ray_cs interrupt tx request failed\n");
+                       }
+                       if (!sniffer)
+                               netif_start_queue(dev);
+                       netif_wake_queue(dev);
+                       break;
+               case CCS_TEST_MEMORY:
+                       DEBUG(1, "ray_cs interrupt mem test done\n");
+                       break;
+               case CCS_SHUTDOWN:
+                       DEBUG(1,
+                             "ray_cs interrupt Unexpected CCS returned - Shutdown\n");
+                       break;
+               case CCS_DUMP_MEMORY:
+                       DEBUG(1, "ray_cs interrupt dump memory done\n");
+                       break;
+               case CCS_START_TIMER:
+                       DEBUG(2,
+                             "ray_cs interrupt DING - raylink timer expired\n");
+                       break;
+               default:
+                       DEBUG(1,
+                             "ray_cs interrupt Unexpected CCS 0x%x returned 0x%x\n",
+                             rcsindex, cmd);
+               }
+               writeb(CCS_BUFFER_FREE, &pccs->buffer_status);
+       } else { /* It's an RCS */
+
+               prcs = rcs_base(local) + rcsindex;
+
+               switch (readb(&prcs->interrupt_id)) {
+               case PROCESS_RX_PACKET:
+                       ray_rx(dev, local, prcs);
+                       break;
+               case REJOIN_NET_COMPLETE:
+                       DEBUG(1, "ray_cs interrupt rejoin net complete\n");
+                       local->card_status = CARD_ACQ_COMPLETE;
+                       /* do we need to clear tx buffers CCS's? */
+                       if (local->sparm.b4.a_network_type == ADHOC) {
+                               if (!sniffer)
+                                       netif_start_queue(dev);
+                       } else {
+                               memcpy_fromio(&local->bss_id,
+                                             prcs->var.rejoin_net_complete.
+                                             bssid, ADDRLEN);
+                               DEBUG(1,
+                                     "ray_cs new BSSID = %02x%02x%02x%02x%02x%02x\n",
+                                     local->bss_id[0], local->bss_id[1],
+                                     local->bss_id[2], local->bss_id[3],
+                                     local->bss_id[4], local->bss_id[5]);
+                               if (!sniffer)
+                                       authenticate(local);
+                       }
+                       break;
+               case ROAMING_INITIATED:
+                       DEBUG(1, "ray_cs interrupt roaming initiated\n");
+                       netif_stop_queue(dev);
+                       local->card_status = CARD_DOING_ACQ;
+                       break;
+               case JAPAN_CALL_SIGN_RXD:
+                       DEBUG(1, "ray_cs interrupt japan call sign rx\n");
+                       break;
+               default:
+                       DEBUG(1,
+                             "ray_cs Unexpected interrupt for RCS 0x%x cmd = 0x%x\n",
+                             rcsindex,
+                             (unsigned int)readb(&prcs->interrupt_id));
+                       break;
+               }
+               writeb(CCS_BUFFER_FREE, &prcs->buffer_status);
+       }
+       clear_interrupt(local);
+       return IRQ_HANDLED;
 } /* ray_interrupt */
+
 /*===========================================================================*/
-static void ray_rx(struct net_device *dev, ray_dev_t *local, struct rcs __iomem *prcs)
-{
-    int rx_len;
-    unsigned int pkt_addr;
-    void __iomem *pmsg;
-    DEBUG(4,"ray_rx process rx packet\n");
-
-    /* Calculate address of packet within Rx buffer */
-    pkt_addr = ((readb(&prcs->var.rx_packet.rx_data_ptr[0]) << 8)
-                + readb(&prcs->var.rx_packet.rx_data_ptr[1])) & RX_BUFF_END;
-    /* Length of first packet fragment */
-    rx_len = (readb(&prcs->var.rx_packet.rx_data_length[0]) << 8)
-        + readb(&prcs->var.rx_packet.rx_data_length[1]);
-
-    local->last_rsl = readb(&prcs->var.rx_packet.rx_sig_lev);
-    pmsg = local->rmem + pkt_addr;
-    switch(readb(pmsg))
-    {
-    case DATA_TYPE:
-        DEBUG(4,"ray_rx data type\n");
-        rx_data(dev, prcs, pkt_addr, rx_len);
-        break;
-    case AUTHENTIC_TYPE:
-        DEBUG(4,"ray_rx authentic type\n");
-        if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len);
-        else rx_authenticate(local, prcs, pkt_addr, rx_len);
-        break;
-    case DEAUTHENTIC_TYPE:
-        DEBUG(4,"ray_rx deauth type\n");
-        if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len);
-        else rx_deauthenticate(local, prcs, pkt_addr, rx_len);
-        break;
-    case NULL_MSG_TYPE:
-        DEBUG(3,"ray_cs rx NULL msg\n");
-        break;
-    case BEACON_TYPE:
-        DEBUG(4,"ray_rx beacon type\n");
-        if (sniffer) rx_data(dev, prcs, pkt_addr, rx_len);
-
-        copy_from_rx_buff(local, (UCHAR *)&local->last_bcn, pkt_addr, 
-                          rx_len < sizeof(struct beacon_rx) ? 
-                          rx_len : sizeof(struct beacon_rx));
-
-       local->beacon_rxed = 1;
-        /* Get the statistics so the card counters never overflow */
-        ray_get_stats(dev);
-            break;
-    default:
-        DEBUG(0,"ray_cs unknown pkt type %2x\n", (unsigned int) readb(pmsg));
-        break;
-    }
+static void ray_rx(struct net_device *dev, ray_dev_t *local,
+                  struct rcs __iomem *prcs)
+{
+       int rx_len;
+       unsigned int pkt_addr;
+       void __iomem *pmsg;
+       DEBUG(4, "ray_rx process rx packet\n");
+
+       /* Calculate address of packet within Rx buffer */
+       pkt_addr = ((readb(&prcs->var.rx_packet.rx_data_ptr[0]) << 8)
+                   + readb(&prcs->var.rx_packet.rx_data_ptr[1])) & RX_BUFF_END;
+       /* Length of first packet fragment */
+       rx_len = (readb(&prcs->var.rx_packet.rx_data_length[0]) << 8)
+           + readb(&prcs->var.rx_packet.rx_data_length[1]);
+
+       local->last_rsl = readb(&prcs->var.rx_packet.rx_sig_lev);
+       pmsg = local->rmem + pkt_addr;
+       switch (readb(pmsg)) {
+       case DATA_TYPE:
+               DEBUG(4, "ray_rx data type\n");
+               rx_data(dev, prcs, pkt_addr, rx_len);
+               break;
+       case AUTHENTIC_TYPE:
+               DEBUG(4, "ray_rx authentic type\n");
+               if (sniffer)
+                       rx_data(dev, prcs, pkt_addr, rx_len);
+               else
+                       rx_authenticate(local, prcs, pkt_addr, rx_len);
+               break;
+       case DEAUTHENTIC_TYPE:
+               DEBUG(4, "ray_rx deauth type\n");
+               if (sniffer)
+                       rx_data(dev, prcs, pkt_addr, rx_len);
+               else
+                       rx_deauthenticate(local, prcs, pkt_addr, rx_len);
+               break;
+       case NULL_MSG_TYPE:
+               DEBUG(3, "ray_cs rx NULL msg\n");
+               break;
+       case BEACON_TYPE:
+               DEBUG(4, "ray_rx beacon type\n");
+               if (sniffer)
+                       rx_data(dev, prcs, pkt_addr, rx_len);
+
+               copy_from_rx_buff(local, (UCHAR *) &local->last_bcn, pkt_addr,
+                                 rx_len < sizeof(struct beacon_rx) ?
+                                 rx_len : sizeof(struct beacon_rx));
+
+               local->beacon_rxed = 1;
+               /* Get the statistics so the card counters never overflow */
+               ray_get_stats(dev);
+               break;
+       default:
+               DEBUG(0, "ray_cs unknown pkt type %2x\n",
+                     (unsigned int)readb(pmsg));
+               break;
+       }
 
 } /* end ray_rx */
+
 /*===========================================================================*/
-static void rx_data(struct net_device *dev, struct rcs __iomem *prcs, unsigned int pkt_addr, 
-             int rx_len)
-{
-    struct sk_buff *skb = NULL;
-    struct rcs __iomem *prcslink = prcs;
-    ray_dev_t *local = netdev_priv(dev);
-    UCHAR *rx_ptr;
-    int total_len;
-    int tmp;
+static void rx_data(struct net_device *dev, struct rcs __iomem *prcs,
+                   unsigned int pkt_addr, int rx_len)
+{
+       struct sk_buff *skb = NULL;
+       struct rcs __iomem *prcslink = prcs;
+       ray_dev_t *local = netdev_priv(dev);
+       UCHAR *rx_ptr;
+       int total_len;
+       int tmp;
 #ifdef WIRELESS_SPY
-    int siglev = local->last_rsl;
-    u_char linksrcaddr[ETH_ALEN];      /* Other end of the wireless link */
+       int siglev = local->last_rsl;
+       u_char linksrcaddr[ETH_ALEN];   /* Other end of the wireless link */
 #endif
 
-    if (!sniffer) {
-        if (translate) {
+       if (!sniffer) {
+               if (translate) {
 /* TBD length needs fixing for translated header */
-            if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
-                rx_len > (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + FCS_LEN)) 
-            {
-                DEBUG(0,"ray_cs invalid packet length %d received \n",rx_len);
-                return;
-            }
-        }
-        else /* encapsulated ethernet */ {
-            if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
-                rx_len > (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN + FCS_LEN))
-            {
-                DEBUG(0,"ray_cs invalid packet length %d received \n",rx_len);
-                return;
-            }
-        }
-    }
-    DEBUG(4,"ray_cs rx_data packet\n");
-    /* If fragmented packet, verify sizes of fragments add up */
-    if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) {
-        DEBUG(1,"ray_cs rx'ed fragment\n");
-        tmp = (readb(&prcs->var.rx_packet.totalpacketlength[0]) << 8)
-            +  readb(&prcs->var.rx_packet.totalpacketlength[1]);
-        total_len = tmp;
-        prcslink = prcs;
-        do {
-            tmp -= (readb(&prcslink->var.rx_packet.rx_data_length[0]) << 8)
-                +   readb(&prcslink->var.rx_packet.rx_data_length[1]);
-            if (readb(&prcslink->var.rx_packet.next_frag_rcs_index) == 0xFF
-                || tmp < 0) break;
-            prcslink = rcs_base(local)
-                + readb(&prcslink->link_field);
-        } while (1);
-
-        if (tmp < 0)
-        {
-            DEBUG(0,"ray_cs rx_data fragment lengths don't add up\n");
-            local->stats.rx_dropped++; 
-            release_frag_chain(local, prcs);
-            return;
-        }
-    }
-    else { /* Single unfragmented packet */
-        total_len = rx_len;
-    }
-
-    skb = dev_alloc_skb( total_len+5 );
-    if (skb == NULL)
-    {
-        DEBUG(0,"ray_cs rx_data could not allocate skb\n");
-        local->stats.rx_dropped++; 
-        if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF)
-            release_frag_chain(local, prcs);
-        return;
-    }
-    skb_reserve( skb, 2);   /* Align IP on 16 byte (TBD check this)*/
-
-    DEBUG(4,"ray_cs rx_data total_len = %x, rx_len = %x\n",total_len,rx_len);
+                       if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
+                           rx_len >
+                           (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
+                            FCS_LEN)) {
+                               DEBUG(0,
+                                     "ray_cs invalid packet length %d received \n",
+                                     rx_len);
+                               return;
+                       }
+               } else { /* encapsulated ethernet */
+
+                       if (rx_len < (ETH_HLEN + RX_MAC_HEADER_LENGTH) ||
+                           rx_len >
+                           (dev->mtu + RX_MAC_HEADER_LENGTH + ETH_HLEN +
+                            FCS_LEN)) {
+                               DEBUG(0,
+                                     "ray_cs invalid packet length %d received \n",
+                                     rx_len);
+                               return;
+                       }
+               }
+       }
+       DEBUG(4, "ray_cs rx_data packet\n");
+       /* If fragmented packet, verify sizes of fragments add up */
+       if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) {
+               DEBUG(1, "ray_cs rx'ed fragment\n");
+               tmp = (readb(&prcs->var.rx_packet.totalpacketlength[0]) << 8)
+                   + readb(&prcs->var.rx_packet.totalpacketlength[1]);
+               total_len = tmp;
+               prcslink = prcs;
+               do {
+                       tmp -=
+                           (readb(&prcslink->var.rx_packet.rx_data_length[0])
+                            << 8)
+                           + readb(&prcslink->var.rx_packet.rx_data_length[1]);
+                       if (readb(&prcslink->var.rx_packet.next_frag_rcs_index)
+                           == 0xFF || tmp < 0)
+                               break;
+                       prcslink = rcs_base(local)
+                           + readb(&prcslink->link_field);
+               } while (1);
+
+               if (tmp < 0) {
+                       DEBUG(0,
+                             "ray_cs rx_data fragment lengths don't add up\n");
+                       local->stats.rx_dropped++;
+                       release_frag_chain(local, prcs);
+                       return;
+               }
+       } else { /* Single unfragmented packet */
+               total_len = rx_len;
+       }
+
+       skb = dev_alloc_skb(total_len + 5);
+       if (skb == NULL) {
+               DEBUG(0, "ray_cs rx_data could not allocate skb\n");
+               local->stats.rx_dropped++;
+               if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF)
+                       release_frag_chain(local, prcs);
+               return;
+       }
+       skb_reserve(skb, 2);    /* Align IP on 16 byte (TBD check this) */
+
+       DEBUG(4, "ray_cs rx_data total_len = %x, rx_len = %x\n", total_len,
+             rx_len);
 
 /************************/
-    /* Reserve enough room for the whole damn packet. */
-    rx_ptr = skb_put( skb, total_len);
-    /* Copy the whole packet to sk_buff */
-    rx_ptr += copy_from_rx_buff(local, rx_ptr, pkt_addr & RX_BUFF_END, rx_len);
-    /* Get source address */
+       /* Reserve enough room for the whole damn packet. */
+       rx_ptr = skb_put(skb, total_len);
+       /* Copy the whole packet to sk_buff */
+       rx_ptr +=
+           copy_from_rx_buff(local, rx_ptr, pkt_addr & RX_BUFF_END, rx_len);
+       /* Get source address */
 #ifdef WIRELESS_SPY
-    skb_copy_from_linear_data_offset(skb, offsetof(struct mac_header, addr_2),
-                                    linksrcaddr, ETH_ALEN);
+       skb_copy_from_linear_data_offset(skb,
+                                        offsetof(struct mac_header, addr_2),
+                                        linksrcaddr, ETH_ALEN);
 #endif
-    /* Now, deal with encapsulation/translation/sniffer */
-    if (!sniffer) {
-        if (!translate) { 
-            /* Encapsulated ethernet, so just lop off 802.11 MAC header */
+       /* Now, deal with encapsulation/translation/sniffer */
+       if (!sniffer) {
+               if (!translate) {
+                       /* Encapsulated ethernet, so just lop off 802.11 MAC header */
 /* TBD reserve            skb_reserve( skb, RX_MAC_HEADER_LENGTH); */
-            skb_pull( skb, RX_MAC_HEADER_LENGTH);
-        }
-        else {
-            /* Do translation */
-            untranslate(local, skb, total_len);
-        }
-    }
-    else 
-    {  /* sniffer mode, so just pass whole packet */  };
+                       skb_pull(skb, RX_MAC_HEADER_LENGTH);
+               } else {
+                       /* Do translation */
+                       untranslate(local, skb, total_len);
+               }
+       } else { /* sniffer mode, so just pass whole packet */
+       };
 
 /************************/
-    /* Now pick up the rest of the fragments if any */
-    tmp = 17; 
-    if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) {
-        prcslink = prcs;
-        DEBUG(1,"ray_cs rx_data in fragment loop\n");
-        do {
-            prcslink = rcs_base(local)
-                + readb(&prcslink->var.rx_packet.next_frag_rcs_index);
-            rx_len = (( readb(&prcslink->var.rx_packet.rx_data_length[0]) << 8)
-                      + readb(&prcslink->var.rx_packet.rx_data_length[1]))
-                & RX_BUFF_END;
-            pkt_addr = (( readb(&prcslink->var.rx_packet.rx_data_ptr[0]) << 8)
-                        + readb(&prcslink->var.rx_packet.rx_data_ptr[1]))
-                & RX_BUFF_END;
-
-            rx_ptr += copy_from_rx_buff(local, rx_ptr, pkt_addr, rx_len);
-
-        } while (tmp-- && 
-                 readb(&prcslink->var.rx_packet.next_frag_rcs_index) != 0xFF);
-        release_frag_chain(local, prcs);
-    }
-
-    skb->protocol = eth_type_trans(skb,dev);
-    netif_rx(skb);
-    local->stats.rx_packets++;
-    local->stats.rx_bytes += total_len;
-
-    /* Gather signal strength per address */
+       /* Now pick up the rest of the fragments if any */
+       tmp = 17;
+       if (readb(&prcs->var.rx_packet.next_frag_rcs_index) != 0xFF) {
+               prcslink = prcs;
+               DEBUG(1, "ray_cs rx_data in fragment loop\n");
+               do {
+                       prcslink = rcs_base(local)
+                           +
+                           readb(&prcslink->var.rx_packet.next_frag_rcs_index);
+                       rx_len =
+                           ((readb(&prcslink->var.rx_packet.rx_data_length[0])
+                             << 8)
+                            +
+                            readb(&prcslink->var.rx_packet.rx_data_length[1]))
+                           & RX_BUFF_END;
+                       pkt_addr =
+                           ((readb(&prcslink->var.rx_packet.rx_data_ptr[0]) <<
+                             8)
+                            + readb(&prcslink->var.rx_packet.rx_data_ptr[1]))
+                           & RX_BUFF_END;
+
+                       rx_ptr +=
+                           copy_from_rx_buff(local, rx_ptr, pkt_addr, rx_len);
+
+               } while (tmp-- &&
+                        readb(&prcslink->var.rx_packet.next_frag_rcs_index) !=
+                        0xFF);
+               release_frag_chain(local, prcs);
+       }
+
+       skb->protocol = eth_type_trans(skb, dev);
+       netif_rx(skb);
+       local->stats.rx_packets++;
+       local->stats.rx_bytes += total_len;
+
+       /* Gather signal strength per address */
 #ifdef WIRELESS_SPY
-    /* For the Access Point or the node having started the ad-hoc net
-     * note : ad-hoc work only in some specific configurations, but we
-     * kludge in ray_get_wireless_stats... */
-    if(!memcmp(linksrcaddr, local->bss_id, ETH_ALEN))
-      {
-       /* Update statistics */
-       /*local->wstats.qual.qual = none ? */
-       local->wstats.qual.level = siglev;
-       /*local->wstats.qual.noise = none ? */
-       local->wstats.qual.updated = 0x2;
-      }
-    /* Now, update the spy stuff */
-    {
-       struct iw_quality wstats;
-       wstats.level = siglev;
-       /* wstats.noise = none ? */
-       /* wstats.qual = none ? */
-       wstats.updated = 0x2;
-       /* Update spy records */
-       wireless_spy_update(dev, linksrcaddr, &wstats);
-    }
-#endif /* WIRELESS_SPY */
+       /* For the Access Point or the node having started the ad-hoc net
+        * note : ad-hoc work only in some specific configurations, but we
+        * kludge in ray_get_wireless_stats... */
+       if (!memcmp(linksrcaddr, local->bss_id, ETH_ALEN)) {
+               /* Update statistics */
+               /*local->wstats.qual.qual = none ? */
+               local->wstats.qual.level = siglev;
+               /*local->wstats.qual.noise = none ? */
+               local->wstats.qual.updated = 0x2;
+       }
+       /* Now, update the spy stuff */
+       {
+               struct iw_quality wstats;
+               wstats.level = siglev;
+               /* wstats.noise = none ? */
+               /* wstats.qual = none ? */
+               wstats.updated = 0x2;
+               /* Update spy records */
+               wireless_spy_update(dev, linksrcaddr, &wstats);
+       }
+#endif /* WIRELESS_SPY */
 } /* end rx_data */
+
 /*===========================================================================*/
 static void untranslate(ray_dev_t *local, struct sk_buff *skb, int len)
 {
-    snaphdr_t *psnap = (snaphdr_t *)(skb->data + RX_MAC_HEADER_LENGTH);
-    struct ieee80211_hdr *pmac = (struct ieee80211_hdr *)skb->data;
-    __be16 type = *(__be16 *)psnap->ethertype;
-    int delta;
-    struct ethhdr *peth;
-    UCHAR srcaddr[ADDRLEN];
-    UCHAR destaddr[ADDRLEN];
-    static UCHAR org_bridge[3] = {0, 0, 0xf8};
-    static UCHAR org_1042[3] = {0, 0, 0};
+       snaphdr_t *psnap = (snaphdr_t *) (skb->data + RX_MAC_HEADER_LENGTH);
+       struct ieee80211_hdr *pmac = (struct ieee80211_hdr *)skb->data;
+       __be16 type = *(__be16 *) psnap->ethertype;
+       int delta;
+       struct ethhdr *peth;
+       UCHAR srcaddr[ADDRLEN];
+       UCHAR destaddr[ADDRLEN];
+       static UCHAR org_bridge[3] = { 0, 0, 0xf8 };
+       static UCHAR org_1042[3] = { 0, 0, 0 };
 
-    memcpy(destaddr, ieee80211_get_DA(pmac), ADDRLEN);
-    memcpy(srcaddr, ieee80211_get_SA(pmac), ADDRLEN);
+       memcpy(destaddr, ieee80211_get_DA(pmac), ADDRLEN);
+       memcpy(srcaddr, ieee80211_get_SA(pmac), ADDRLEN);
 
 #ifdef PCMCIA_DEBUG
-    if (pc_debug > 3) {
-    int i;
-    printk(KERN_DEBUG "skb->data before untranslate");
-    for (i=0;i<64;i++) 
-        printk("%02x ",skb->data[i]);
-    printk("\n" KERN_DEBUG "type = %08x, xsap = %02x%02x%02x, org = %02x02x02x\n",
-           ntohs(type),
-          psnap->dsap, psnap->ssap, psnap->ctrl,
-          psnap->org[0], psnap->org[1], psnap->org[2]);
-    printk(KERN_DEBUG "untranslate skb->data = %p\n",skb->data);
-    }
+       if (pc_debug > 3) {
+               int i;
+               printk(KERN_DEBUG "skb->data before untranslate");
+               for (i = 0; i < 64; i++)
+                       printk("%02x ", skb->data[i]);
+               printk("\n" KERN_DEBUG
+                      "type = %08x, xsap = %02x%02x%02x, org = %02x02x02x\n",
+                      ntohs(type), psnap->dsap, psnap->ssap, psnap->ctrl,
+                      psnap->org[0], psnap->org[1], psnap->org[2]);
+               printk(KERN_DEBUG "untranslate skb->data = %p\n", skb->data);
+       }
 #endif
 
-    if (psnap->dsap != 0xaa || psnap->ssap != 0xaa || psnap->ctrl != 3) {
-        /* not a snap type so leave it alone */
-        DEBUG(3,"ray_cs untranslate NOT SNAP %02x %02x %02x\n",
-               psnap->dsap, psnap->ssap, psnap->ctrl);
-
-        delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
-        peth = (struct ethhdr *)(skb->data + delta);
-        peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH);
-    }
-    else { /* Its a SNAP */
-        if (memcmp(psnap->org, org_bridge, 3) == 0) { /* EtherII and nuke the LLC  */
-        DEBUG(3,"ray_cs untranslate Bridge encap\n");
-            delta = RX_MAC_HEADER_LENGTH 
-                + sizeof(struct snaphdr_t) - ETH_HLEN;
-            peth = (struct ethhdr *)(skb->data + delta);
-            peth->h_proto = type;
-       } else if (memcmp(psnap->org, org_1042, 3) == 0) {
-                switch (ntohs(type)) {
-                case ETH_P_IPX:
-                case ETH_P_AARP:
-                    DEBUG(3,"ray_cs untranslate RFC IPX/AARP\n");
-                    delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
-                    peth = (struct ethhdr *)(skb->data + delta);
-                    peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH);
-                    break;
-                default:
-                    DEBUG(3,"ray_cs untranslate RFC default\n");
-                    delta = RX_MAC_HEADER_LENGTH + 
-                        sizeof(struct snaphdr_t) - ETH_HLEN;
-                    peth = (struct ethhdr *)(skb->data + delta);
-                    peth->h_proto = type;
-                    break;
-                }
-       } else {
-                printk("ray_cs untranslate very confused by packet\n");
-                delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
-                peth = (struct ethhdr *)(skb->data + delta);
-                peth->h_proto = type;
+       if (psnap->dsap != 0xaa || psnap->ssap != 0xaa || psnap->ctrl != 3) {
+               /* not a snap type so leave it alone */
+               DEBUG(3, "ray_cs untranslate NOT SNAP %02x %02x %02x\n",
+                     psnap->dsap, psnap->ssap, psnap->ctrl);
+
+               delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
+               peth = (struct ethhdr *)(skb->data + delta);
+               peth->h_proto = htons(len - RX_MAC_HEADER_LENGTH);
+       } else { /* Its a SNAP */
+               if (memcmp(psnap->org, org_bridge, 3) == 0) {
+               /* EtherII and nuke the LLC */
+                       DEBUG(3, "ray_cs untranslate Bridge encap\n");
+                       delta = RX_MAC_HEADER_LENGTH
+                           + sizeof(struct snaphdr_t) - ETH_HLEN;
+                       peth = (struct ethhdr *)(skb->data + delta);
+                       peth->h_proto = type;
+               } else if (memcmp(psnap->org, org_1042, 3) == 0) {
+                       switch (ntohs(type)) {
+                       case ETH_P_IPX:
+                       case ETH_P_AARP:
+                               DEBUG(3, "ray_cs untranslate RFC IPX/AARP\n");
+                               delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
+                               peth = (struct ethhdr *)(skb->data + delta);
+                               peth->h_proto =
+                                   htons(len - RX_MAC_HEADER_LENGTH);
+                               break;
+                       default:
+                               DEBUG(3, "ray_cs untranslate RFC default\n");
+                               delta = RX_MAC_HEADER_LENGTH +
+                                   sizeof(struct snaphdr_t) - ETH_HLEN;
+                               peth = (struct ethhdr *)(skb->data + delta);
+                               peth->h_proto = type;
+                               break;
+                       }
+               } else {
+                       printk("ray_cs untranslate very confused by packet\n");
+                       delta = RX_MAC_HEADER_LENGTH - ETH_HLEN;
+                       peth = (struct ethhdr *)(skb->data + delta);
+                       peth->h_proto = type;
+               }
        }
-    }
 /* TBD reserve  skb_reserve(skb, delta); */
-    skb_pull(skb, delta);
-    DEBUG(3,"untranslate after skb_pull(%d), skb->data = %p\n",delta,skb->data);
-    memcpy(peth->h_dest, destaddr, ADDRLEN);
-    memcpy(peth->h_source, srcaddr, ADDRLEN);
+       skb_pull(skb, delta);
+       DEBUG(3, "untranslate after skb_pull(%d), skb->data = %p\n", delta,
+             skb->data);
+       memcpy(peth->h_dest, destaddr, ADDRLEN);
+       memcpy(peth->h_source, srcaddr, ADDRLEN);
 #ifdef PCMCIA_DEBUG
-    if (pc_debug > 3) {
-    int i;
-    printk(KERN_DEBUG "skb->data after untranslate:");
-    for (i=0;i<64;i++)
-        printk("%02x ",skb->data[i]);
-    printk("\n");
-    }
+       if (pc_debug > 3) {
+               int i;
+               printk(KERN_DEBUG "skb->data after untranslate:");
+               for (i = 0; i < 64; i++)
+                       printk("%02x ", skb->data[i]);
+               printk("\n");
+       }
 #endif
 } /* end untranslate */
+
 /*===========================================================================*/
 /* Copy data from circular receive buffer to PC memory.
  * dest     = destination address in PC memory
  * pkt_addr = source address in receive buffer
  * len      = length of packet to copy
  */
-static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr, int length)
-{
-    int wrap_bytes = (pkt_addr + length) - (RX_BUFF_END + 1);
-    if (wrap_bytes <= 0)
-    {
-        memcpy_fromio(dest,local->rmem + pkt_addr,length);
-    }
-    else /* Packet wrapped in circular buffer */
-    {
-        memcpy_fromio(dest,local->rmem+pkt_addr,length - wrap_bytes);
-        memcpy_fromio(dest + length - wrap_bytes, local->rmem, wrap_bytes);
-    }
-    return length;
+static int copy_from_rx_buff(ray_dev_t *local, UCHAR *dest, int pkt_addr,
+                            int length)
+{
+       int wrap_bytes = (pkt_addr + length) - (RX_BUFF_END + 1);
+       if (wrap_bytes <= 0) {
+               memcpy_fromio(dest, local->rmem + pkt_addr, length);
+       } else { /* Packet wrapped in circular buffer */
+
+               memcpy_fromio(dest, local->rmem + pkt_addr,
+                             length - wrap_bytes);
+               memcpy_fromio(dest + length - wrap_bytes, local->rmem,
+                             wrap_bytes);
+       }
+       return length;
 }
+
 /*===========================================================================*/
-static void release_frag_chain(ray_dev_t *local, struct rcs __iomem * prcs)
-{
-    struct rcs __iomem *prcslink = prcs;
-    int tmp = 17;
-    unsigned rcsindex = readb(&prcs->var.rx_packet.next_frag_rcs_index);
-
-    while (tmp--) {
-        writeb(CCS_BUFFER_FREE, &prcslink->buffer_status);
-        if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) {
-            DEBUG(1,"ray_cs interrupt bad rcsindex = 0x%x\n",rcsindex);
-            break;      
-        }   
-        prcslink = rcs_base(local) + rcsindex;
-        rcsindex = readb(&prcslink->var.rx_packet.next_frag_rcs_index);
-    }
-    writeb(CCS_BUFFER_FREE, &prcslink->buffer_status);
+static void release_frag_chain(ray_dev_t *local, struct rcs __iomem *prcs)
+{
+       struct rcs __iomem *prcslink = prcs;
+       int tmp = 17;
+       unsigned rcsindex = readb(&prcs->var.rx_packet.next_frag_rcs_index);
+
+       while (tmp--) {
+               writeb(CCS_BUFFER_FREE, &prcslink->buffer_status);
+               if (rcsindex >= (NUMBER_OF_CCS + NUMBER_OF_RCS)) {
+                       DEBUG(1, "ray_cs interrupt bad rcsindex = 0x%x\n",
+                             rcsindex);
+                       break;
+               }
+               prcslink = rcs_base(local) + rcsindex;
+               rcsindex = readb(&prcslink->var.rx_packet.next_frag_rcs_index);
+       }
+       writeb(CCS_BUFFER_FREE, &prcslink->buffer_status);
 }
+
 /*===========================================================================*/
 static void authenticate(ray_dev_t *local)
 {
-    struct pcmcia_device *link = local->finder;
-    DEBUG(0,"ray_cs Starting authentication.\n");
-    if (!(pcmcia_dev_present(link))) {
-        DEBUG(2,"ray_cs authenticate - device not present\n");
-        return;
-    }
-
-    del_timer(&local->timer);
-    if (build_auth_frame(local, local->bss_id, OPEN_AUTH_REQUEST)) {
-        local->timer.function = &join_net;
-    }
-    else {
-        local->timer.function = &authenticate_timeout;
-    }
-    local->timer.expires = jiffies + HZ*2;
-    local->timer.data = (long)local;
-    add_timer(&local->timer);
-    local->authentication_state = AWAITING_RESPONSE;
+       struct pcmcia_device *link = local->finder;
+       DEBUG(0, "ray_cs Starting authentication.\n");
+       if (!(pcmcia_dev_present(link))) {
+               DEBUG(2, "ray_cs authenticate - device not present\n");
+               return;
+       }
+
+       del_timer(&local->timer);
+       if (build_auth_frame(local, local->bss_id, OPEN_AUTH_REQUEST)) {
+               local->timer.function = &join_net;
+       } else {
+               local->timer.function = &authenticate_timeout;
+       }
+       local->timer.expires = jiffies + HZ * 2;
+       local->timer.data = (long)local;
+       add_timer(&local->timer);
+       local->authentication_state = AWAITING_RESPONSE;
 } /* end authenticate */
+
 /*===========================================================================*/
 static void rx_authenticate(ray_dev_t *local, struct rcs __iomem *prcs,
-                     unsigned int pkt_addr, int rx_len)
-{
-    UCHAR buff[256];
-    struct rx_msg *msg = (struct rx_msg *)buff;
-    
-    del_timer(&local->timer);
-
-    copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff);
-    /* if we are trying to get authenticated */
-    if (local->sparm.b4.a_network_type == ADHOC) {
-        DEBUG(1,"ray_cs rx_auth var= %02x %02x %02x %02x %02x %02x\n", msg->var[0],msg->var[1],msg->var[2],msg->var[3],msg->var[4],msg->var[5]);
-        if (msg->var[2] == 1) {
-                    DEBUG(0,"ray_cs Sending authentication response.\n");
-                    if (!build_auth_frame (local, msg->mac.addr_2, OPEN_AUTH_RESPONSE)) {
-                        local->authentication_state = NEED_TO_AUTH;
-                        memcpy(local->auth_id, msg->mac.addr_2, ADDRLEN);
-                    }
-        }
-    }
-    else /* Infrastructure network */
-    {
-        if (local->authentication_state == AWAITING_RESPONSE) {
-            /* Verify authentication sequence #2 and success */
-            if (msg->var[2] == 2) {
-                if ((msg->var[3] | msg->var[4]) == 0) {
-                    DEBUG(1,"Authentication successful\n");
-                    local->card_status = CARD_AUTH_COMPLETE;
-                    associate(local);
-                    local->authentication_state = AUTHENTICATED;
-                }
-                else {
-                    DEBUG(0,"Authentication refused\n");
-                    local->card_status = CARD_AUTH_REFUSED;
-                    join_net((u_long)local);
-                    local->authentication_state = UNAUTHENTICATED;
-                }
-            }
-        }
-    }
+                           unsigned int pkt_addr, int rx_len)
+{
+       UCHAR buff[256];
+       struct rx_msg *msg = (struct rx_msg *)buff;
+
+       del_timer(&local->timer);
+
+       copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff);
+       /* if we are trying to get authenticated */
+       if (local->sparm.b4.a_network_type == ADHOC) {
+               DEBUG(1, "ray_cs rx_auth var= %02x %02x %02x %02x %02x %02x\n",
+                     msg->var[0], msg->var[1], msg->var[2], msg->var[3],
+                     msg->var[4], msg->var[5]);
+               if (msg->var[2] == 1) {
+                       DEBUG(0, "ray_cs Sending authentication response.\n");
+                       if (!build_auth_frame
+                           (local, msg->mac.addr_2, OPEN_AUTH_RESPONSE)) {
+                               local->authentication_state = NEED_TO_AUTH;
+                               memcpy(local->auth_id, msg->mac.addr_2,
+                                      ADDRLEN);
+                       }
+               }
+       } else { /* Infrastructure network */
+
+               if (local->authentication_state == AWAITING_RESPONSE) {
+                       /* Verify authentication sequence #2 and success */
+                       if (msg->var[2] == 2) {
+                               if ((msg->var[3] | msg->var[4]) == 0) {
+                                       DEBUG(1, "Authentication successful\n");
+                                       local->card_status = CARD_AUTH_COMPLETE;
+                                       associate(local);
+                                       local->authentication_state =
+                                           AUTHENTICATED;
+                               } else {
+                                       DEBUG(0, "Authentication refused\n");
+                                       local->card_status = CARD_AUTH_REFUSED;
+                                       join_net((u_long) local);
+                                       local->authentication_state =
+                                           UNAUTHENTICATED;
+                               }
+                       }
+               }
+       }
 
 } /* end rx_authenticate */
+
 /*===========================================================================*/
 static void associate(ray_dev_t *local)
 {
-    struct ccs __iomem *pccs;
-    struct pcmcia_device *link = local->finder;
-    struct net_device *dev = link->priv;
-    int ccsindex;
-    if (!(pcmcia_dev_present(link))) {
-        DEBUG(2,"ray_cs associate - device not present\n");
-        return;
-    }
-    /* If no tx buffers available, return*/
-    if ((ccsindex = get_free_ccs(local)) < 0)
-    {
+       struct ccs __iomem *pccs;
+       struct pcmcia_device *link = local->finder;
+       struct net_device *dev = link->priv;
+       int ccsindex;
+       if (!(pcmcia_dev_present(link))) {
+               DEBUG(2, "ray_cs associate - device not present\n");
+               return;
+       }
+       /* If no tx buffers available, return */
+       if ((ccsindex = get_free_ccs(local)) < 0) {
 /* TBD should never be here but... what if we are? */
-        DEBUG(1,"ray_cs associate - No free ccs\n");
-        return;
-    }
-    DEBUG(1,"ray_cs Starting association with access point\n");
-    pccs = ccs_base(local) + ccsindex;
-    /* fill in the CCS */
-    writeb(CCS_START_ASSOCIATION, &pccs->cmd);
-    /* Interrupt the firmware to process the command */
-    if (interrupt_ecf(local, ccsindex)) {
-        DEBUG(1,"ray_cs associate failed - ECF not ready for intr\n");
-        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
-
-        del_timer(&local->timer);
-        local->timer.expires = jiffies + HZ*2;
-        local->timer.data = (long)local;
-        local->timer.function = &join_net;
-        add_timer(&local->timer);
-        local->card_status = CARD_ASSOC_FAILED;
-        return;
-    }
-    if (!sniffer) netif_start_queue(dev);
+               DEBUG(1, "ray_cs associate - No free ccs\n");
+               return;
+       }
+       DEBUG(1, "ray_cs Starting association with access point\n");
+       pccs = ccs_base(local) + ccsindex;
+       /* fill in the CCS */
+       writeb(CCS_START_ASSOCIATION, &pccs->cmd);
+       /* Interrupt the firmware to process the command */
+       if (interrupt_ecf(local, ccsindex)) {
+               DEBUG(1, "ray_cs associate failed - ECF not ready for intr\n");
+               writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+
+               del_timer(&local->timer);
+               local->timer.expires = jiffies + HZ * 2;
+               local->timer.data = (long)local;
+               local->timer.function = &join_net;
+               add_timer(&local->timer);
+               local->card_status = CARD_ASSOC_FAILED;
+               return;
+       }
+       if (!sniffer)
+               netif_start_queue(dev);
 
 } /* end associate */
+
 /*===========================================================================*/
-static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs, 
-                       unsigned int pkt_addr, int rx_len)
+static void rx_deauthenticate(ray_dev_t *local, struct rcs __iomem *prcs,
+                             unsigned int pkt_addr, int rx_len)
 {
 /*  UCHAR buff[256];
     struct rx_msg *msg = (struct rx_msg *)buff;
 */
-    DEBUG(0,"Deauthentication frame received\n");
-    local->authentication_state = UNAUTHENTICATED;
-    /* Need to reauthenticate or rejoin depending on reason code */
+       DEBUG(0, "Deauthentication frame received\n");
+       local->authentication_state = UNAUTHENTICATED;
+       /* Need to reauthenticate or rejoin depending on reason code */
 /*  copy_from_rx_buff(local, buff, pkt_addr, rx_len & 0xff);
  */
 }
+
 /*===========================================================================*/
 static void clear_interrupt(ray_dev_t *local)
 {
-    writeb(0, local->amem + CIS_OFFSET + HCS_INTR_OFFSET);
+       writeb(0, local->amem + CIS_OFFSET + HCS_INTR_OFFSET);
 }
+
 /*===========================================================================*/
 #ifdef CONFIG_PROC_FS
 #define MAXDATA (PAGE_SIZE - 80)
 
 static char *card_status[] = {
-    "Card inserted - uninitialized",     /* 0 */
-    "Card not downloaded",               /* 1 */
-    "Waiting for download parameters",   /* 2 */
-    "Card doing acquisition",            /* 3 */
-    "Acquisition complete",              /* 4 */
-    "Authentication complete",           /* 5 */
-    "Association complete",              /* 6 */
-    "???", "???", "???", "???",          /* 7 8 9 10 undefined */
-    "Card init error",                   /* 11 */
-    "Download parameters error",         /* 12 */
-    "???",                               /* 13 */
-    "Acquisition failed",                /* 14 */
-    "Authentication refused",            /* 15 */
-    "Association failed"                 /* 16 */
+       "Card inserted - uninitialized",        /* 0 */
+       "Card not downloaded",                  /* 1 */
+       "Waiting for download parameters",      /* 2 */
+       "Card doing acquisition",               /* 3 */
+       "Acquisition complete",                 /* 4 */
+       "Authentication complete",              /* 5 */
+       "Association complete",                 /* 6 */
+       "???", "???", "???", "???",             /* 7 8 9 10 undefined */
+       "Card init error",                      /* 11 */
+       "Download parameters error",            /* 12 */
+       "???",                                  /* 13 */
+       "Acquisition failed",                   /* 14 */
+       "Authentication refused",               /* 15 */
+       "Association failed"                    /* 16 */
 };
 
-static char *nettype[] = {"Adhoc", "Infra "};
-static char *framing[] = {"Encapsulation", "Translation"}
+static char *nettype[] = { "Adhoc", "Infra " };
+static char *framing[] = { "Encapsulation", "Translation" }
+
 ;
 /*===========================================================================*/
 static int ray_cs_proc_show(struct seq_file *m, void *v)
 {
 /* Print current values which are not available via other means
- * eg ifconfig 
+ * eg ifconfig
  */
-    int i;
-    struct pcmcia_device *link;
-    struct net_device *dev;
-    ray_dev_t *local;
-    UCHAR *p;
-    struct freq_hop_element *pfh;
-    UCHAR c[33];
-
-    link = this_device;
-    if (!link)
-       return 0;
-    dev = (struct net_device *)link->priv;
-    if (!dev)
-       return 0;
-    local = netdev_priv(dev);
-    if (!local)
-       return 0;
-
-    seq_puts(m, "Raylink Wireless LAN driver status\n");
-    seq_printf(m, "%s\n", rcsid);
-    /* build 4 does not report version, and field is 0x55 after memtest */
-    seq_puts(m, "Firmware version     = ");
-    if (local->fw_ver == 0x55)
-        seq_puts(m, "4 - Use dump_cis for more details\n");
-    else
-        seq_printf(m, "%2d.%02d.%02d\n",
-                   local->fw_ver, local->fw_bld, local->fw_var);
-
-    for (i=0; i<32; i++) c[i] = local->sparm.b5.a_current_ess_id[i];
-    c[32] = 0;
-    seq_printf(m, "%s network ESSID = \"%s\"\n",
-                   nettype[local->sparm.b5.a_network_type], c);
-
-    p = local->bss_id;
-    seq_printf(m, "BSSID                = %pM\n", p);
-
-    seq_printf(m, "Country code         = %d\n",
-                   local->sparm.b5.a_curr_country_code);
-
-    i = local->card_status;
-    if (i < 0) i = 10;
-    if (i > 16) i = 10;
-    seq_printf(m, "Card status          = %s\n", card_status[i]);
-
-    seq_printf(m, "Framing mode         = %s\n",framing[translate]);
-
-    seq_printf(m, "Last pkt signal lvl  = %d\n", local->last_rsl);
-
-    if (local->beacon_rxed) {
-       /* Pull some fields out of last beacon received */
-       seq_printf(m, "Beacon Interval      = %d Kus\n",
-                      local->last_bcn.beacon_intvl[0]
-                      + 256 * local->last_bcn.beacon_intvl[1]);
-    
-    p = local->last_bcn.elements;
-    if (p[0] == C_ESSID_ELEMENT_ID) p += p[1] + 2;
-    else {
-        seq_printf(m, "Parse beacon failed at essid element id = %d\n",p[0]);
-        return 0;
-    }
-
-    if (p[0] == C_SUPPORTED_RATES_ELEMENT_ID) {
-        seq_puts(m, "Supported rate codes = ");
-        for (i=2; i<p[1] + 2; i++) 
-            seq_printf(m, "0x%02x ", p[i]);
-        seq_putc(m, '\n');
-        p += p[1] + 2;
-    }
-    else {
-        seq_puts(m, "Parse beacon failed at rates element\n");
-        return 0;
-    }
-
-       if (p[0] == C_FH_PARAM_SET_ELEMENT_ID) {
-           pfh = (struct freq_hop_element *)p;
-           seq_printf(m, "Hop dwell            = %d Kus\n",
-                          pfh->dwell_time[0] + 256 * pfh->dwell_time[1]);
-           seq_printf(m, "Hop set              = %d \n", pfh->hop_set);
-           seq_printf(m, "Hop pattern          = %d \n", pfh->hop_pattern);
-           seq_printf(m, "Hop index            = %d \n", pfh->hop_index);
-           p += p[1] + 2;
-       }
-       else {
-           seq_puts(m, "Parse beacon failed at FH param element\n");
-           return 0;
+       int i;
+       struct pcmcia_device *link;
+       struct net_device *dev;
+       ray_dev_t *local;
+       UCHAR *p;
+       struct freq_hop_element *pfh;
+       UCHAR c[33];
+
+       link = this_device;
+       if (!link)
+               return 0;
+       dev = (struct net_device *)link->priv;
+       if (!dev)
+               return 0;
+       local = netdev_priv(dev);
+       if (!local)
+               return 0;
+
+       seq_puts(m, "Raylink Wireless LAN driver status\n");
+       seq_printf(m, "%s\n", rcsid);
+       /* build 4 does not report version, and field is 0x55 after memtest */
+       seq_puts(m, "Firmware version     = ");
+       if (local->fw_ver == 0x55)
+               seq_puts(m, "4 - Use dump_cis for more details\n");
+       else
+               seq_printf(m, "%2d.%02d.%02d\n",
+                          local->fw_ver, local->fw_bld, local->fw_var);
+
+       for (i = 0; i < 32; i++)
+               c[i] = local->sparm.b5.a_current_ess_id[i];
+       c[32] = 0;
+       seq_printf(m, "%s network ESSID = \"%s\"\n",
+                  nettype[local->sparm.b5.a_network_type], c);
+
+       p = local->bss_id;
+       seq_printf(m, "BSSID                = %pM\n", p);
+
+       seq_printf(m, "Country code         = %d\n",
+                  local->sparm.b5.a_curr_country_code);
+
+       i = local->card_status;
+       if (i < 0)
+               i = 10;
+       if (i > 16)
+               i = 10;
+       seq_printf(m, "Card status          = %s\n", card_status[i]);
+
+       seq_printf(m, "Framing mode         = %s\n", framing[translate]);
+
+       seq_printf(m, "Last pkt signal lvl  = %d\n", local->last_rsl);
+
+       if (local->beacon_rxed) {
+               /* Pull some fields out of last beacon received */
+               seq_printf(m, "Beacon Interval      = %d Kus\n",
+                          local->last_bcn.beacon_intvl[0]
+                          + 256 * local->last_bcn.beacon_intvl[1]);
+
+               p = local->last_bcn.elements;
+               if (p[0] == C_ESSID_ELEMENT_ID)
+                       p += p[1] + 2;
+               else {
+                       seq_printf(m,
+                                  "Parse beacon failed at essid element id = %d\n",
+                                  p[0]);
+                       return 0;
+               }
+
+               if (p[0] == C_SUPPORTED_RATES_ELEMENT_ID) {
+                       seq_puts(m, "Supported rate codes = ");
+                       for (i = 2; i < p[1] + 2; i++)
+                               seq_printf(m, "0x%02x ", p[i]);
+                       seq_putc(m, '\n');
+                       p += p[1] + 2;
+               } else {
+                       seq_puts(m, "Parse beacon failed at rates element\n");
+                       return 0;
+               }
+
+               if (p[0] == C_FH_PARAM_SET_ELEMENT_ID) {
+                       pfh = (struct freq_hop_element *)p;
+                       seq_printf(m, "Hop dwell            = %d Kus\n",
+                                  pfh->dwell_time[0] +
+                                  256 * pfh->dwell_time[1]);
+                       seq_printf(m, "Hop set              = %d \n",
+                                  pfh->hop_set);
+                       seq_printf(m, "Hop pattern          = %d \n",
+                                  pfh->hop_pattern);
+                       seq_printf(m, "Hop index            = %d \n",
+                                  pfh->hop_index);
+                       p += p[1] + 2;
+               } else {
+                       seq_puts(m,
+                                "Parse beacon failed at FH param element\n");
+                       return 0;
+               }
+       } else {
+               seq_puts(m, "No beacons received\n");
        }
-    } else {
-       seq_puts(m, "No beacons received\n");
-    }
-    return 0;
+       return 0;
 }
 
 static int ray_cs_proc_open(struct inode *inode, struct file *file)
@@ -2684,74 +2806,77 @@ static int ray_cs_proc_open(struct inode *inode, struct file *file)
 }
 
 static const struct file_operations ray_cs_proc_fops = {
-       .owner          = THIS_MODULE,
-       .open           = ray_cs_proc_open,
-       .read           = seq_read,
-       .llseek         = seq_lseek,
-       .release        = single_release,
+       .owner = THIS_MODULE,
+       .open = ray_cs_proc_open,
+       .read = seq_read,
+       .llseek = seq_lseek,
+       .release = single_release,
 };
 #endif
 /*===========================================================================*/
 static int build_auth_frame(ray_dev_t *local, UCHAR *dest, int auth_type)
 {
-    int addr;
-    struct ccs __iomem *pccs;
-    struct tx_msg __iomem *ptx;
-    int ccsindex;
-
-    /* If no tx buffers available, return */
-    if ((ccsindex = get_free_tx_ccs(local)) < 0)
-    {
-        DEBUG(1,"ray_cs send authenticate - No free tx ccs\n");
-        return -1;
-    }
-
-    pccs = ccs_base(local) + ccsindex;
-
-    /* Address in card space */
-    addr = TX_BUF_BASE + (ccsindex << 11);
-    /* fill in the CCS */
-    writeb(CCS_TX_REQUEST, &pccs->cmd);
-    writeb(addr >> 8, pccs->var.tx_request.tx_data_ptr);
-    writeb(0x20, pccs->var.tx_request.tx_data_ptr + 1);
-    writeb(TX_AUTHENTICATE_LENGTH_MSB, pccs->var.tx_request.tx_data_length);
-    writeb(TX_AUTHENTICATE_LENGTH_LSB,pccs->var.tx_request.tx_data_length + 1);
-    writeb(0, &pccs->var.tx_request.pow_sav_mode);
-
-    ptx = local->sram + addr;
-    /* fill in the mac header */
-    writeb(PROTOCOL_VER | AUTHENTIC_TYPE, &ptx->mac.frame_ctl_1);
-    writeb(0, &ptx->mac.frame_ctl_2);
-
-    memcpy_toio(ptx->mac.addr_1, dest, ADDRLEN);
-    memcpy_toio(ptx->mac.addr_2, local->sparm.b4.a_mac_addr, ADDRLEN);
-    memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN);
-
-    /* Fill in msg body with protocol 00 00, sequence 01 00 ,status 00 00 */
-    memset_io(ptx->var, 0, 6);
-    writeb(auth_type & 0xff, ptx->var + 2);
-
-    /* Interrupt the firmware to process the command */
-    if (interrupt_ecf(local, ccsindex)) {
-        DEBUG(1,"ray_cs send authentication request failed - ECF not ready for intr\n");
-        writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
-        return -1;
-    }
-    return 0;
+       int addr;
+       struct ccs __iomem *pccs;
+       struct tx_msg __iomem *ptx;
+       int ccsindex;
+
+       /* If no tx buffers available, return */
+       if ((ccsindex = get_free_tx_ccs(local)) < 0) {
+               DEBUG(1, "ray_cs send authenticate - No free tx ccs\n");
+               return -1;
+       }
+
+       pccs = ccs_base(local) + ccsindex;
+
+       /* Address in card space */
+       addr = TX_BUF_BASE + (ccsindex << 11);
+       /* fill in the CCS */
+       writeb(CCS_TX_REQUEST, &pccs->cmd);
+       writeb(addr >> 8, pccs->var.tx_request.tx_data_ptr);
+       writeb(0x20, pccs->var.tx_request.tx_data_ptr + 1);
+       writeb(TX_AUTHENTICATE_LENGTH_MSB, pccs->var.tx_request.tx_data_length);
+       writeb(TX_AUTHENTICATE_LENGTH_LSB,
+              pccs->var.tx_request.tx_data_length + 1);
+       writeb(0, &pccs->var.tx_request.pow_sav_mode);
+
+       ptx = local->sram + addr;
+       /* fill in the mac header */
+       writeb(PROTOCOL_VER | AUTHENTIC_TYPE, &ptx->mac.frame_ctl_1);
+       writeb(0, &ptx->mac.frame_ctl_2);
+
+       memcpy_toio(ptx->mac.addr_1, dest, ADDRLEN);
+       memcpy_toio(ptx->mac.addr_2, local->sparm.b4.a_mac_addr, ADDRLEN);
+       memcpy_toio(ptx->mac.addr_3, local->bss_id, ADDRLEN);
+
+       /* Fill in msg body with protocol 00 00, sequence 01 00 ,status 00 00 */
+       memset_io(ptx->var, 0, 6);
+       writeb(auth_type & 0xff, ptx->var + 2);
+
+       /* Interrupt the firmware to process the command */
+       if (interrupt_ecf(local, ccsindex)) {
+               DEBUG(1,
+                     "ray_cs send authentication request failed - ECF not ready for intr\n");
+               writeb(CCS_BUFFER_FREE, &(pccs++)->buffer_status);
+               return -1;
+       }
+       return 0;
 } /* End build_auth_frame */
 
 /*===========================================================================*/
 #ifdef CONFIG_PROC_FS
 static void raycs_write(const char *name, write_proc_t *w, void *data)
 {
-       struct proc_dir_entry * entry = create_proc_entry(name, S_IFREG | S_IWUSR, NULL);
+       struct proc_dir_entry *entry =
+           create_proc_entry(name, S_IFREG | S_IWUSR, NULL);
        if (entry) {
                entry->write_proc = w;
                entry->data = data;
        }
 }
 
-static int write_essid(struct file *file, const char __user *buffer, unsigned long count, void *data)
+static int write_essid(struct file *file, const char __user *buffer,
+                      unsigned long count, void *data)
 {
        static char proc_essid[33];
        int len = count;
@@ -2765,7 +2890,8 @@ static int write_essid(struct file *file, const char __user *buffer, unsigned lo
        return count;
 }
 
-static int write_int(struct file *file, const char __user *buffer, unsigned long count, void *data)
+static int write_int(struct file *file, const char __user *buffer,
+                    unsigned long count, void *data)
 {
        static char proc_number[10];
        char *p;
@@ -2785,7 +2911,7 @@ static int write_int(struct file *file, const char __user *buffer, unsigned long
                unsigned int c = *p - '0';
                if (c > 9)
                        return -EINVAL;
-               nr = nr*10 + c;
+               nr = nr * 10 + c;
                p++;
        } while (--len);
        *(int *)data = nr;
@@ -2797,55 +2923,58 @@ static struct pcmcia_device_id ray_ids[] = {
        PCMCIA_DEVICE_MANF_CARD(0x01a6, 0x0000),
        PCMCIA_DEVICE_NULL,
 };
+
 MODULE_DEVICE_TABLE(pcmcia, ray_ids);
 
 static struct pcmcia_driver ray_driver = {
-       .owner          = THIS_MODULE,
-       .drv            = {
-               .name   = "ray_cs",
-       },
-       .probe          = ray_probe,
-       .remove         = ray_detach,
-       .id_table       = ray_ids,
-       .suspend        = ray_suspend,
-       .resume         = ray_resume,
+       .owner = THIS_MODULE,
+       .drv = {
+               .name = "ray_cs",
+               },
+       .probe = ray_probe,
+       .remove = ray_detach,
+       .id_table = ray_ids,
+       .suspend = ray_suspend,
+       .resume = ray_resume,
 };
 
 static int __init init_ray_cs(void)
 {
-    int rc;
-    
-    DEBUG(1, "%s\n", rcsid);
-    rc = pcmcia_register_driver(&ray_driver);
-    DEBUG(1, "raylink init_module register_pcmcia_driver returns 0x%x\n",rc);
+       int rc;
+
+       DEBUG(1, "%s\n", rcsid);
+       rc = pcmcia_register_driver(&ray_driver);
+       DEBUG(1, "raylink init_module register_pcmcia_driver returns 0x%x\n",
+             rc);
 
 #ifdef CONFIG_PROC_FS
-    proc_mkdir("driver/ray_cs", NULL);
+       proc_mkdir("driver/ray_cs", NULL);
 
-    proc_create("driver/ray_cs/ray_cs", 0, NULL, &ray_cs_proc_fops);
-    raycs_write("driver/ray_cs/essid", write_essid, NULL);
-    raycs_write("driver/ray_cs/net_type", write_int, &net_type);
-    raycs_write("driver/ray_cs/translate", write_int, &translate);
+       proc_create("driver/ray_cs/ray_cs", 0, NULL, &ray_cs_proc_fops);
+       raycs_write("driver/ray_cs/essid", write_essid, NULL);
+       raycs_write("driver/ray_cs/net_type", write_int, &net_type);
+       raycs_write("driver/ray_cs/translate", write_int, &translate);
 #endif
-    if (translate != 0) translate = 1;
-    return 0;
+       if (translate != 0)
+               translate = 1;
+       return 0;
 } /* init_ray_cs */
 
 /*===========================================================================*/
 
 static void __exit exit_ray_cs(void)
 {
-    DEBUG(0, "ray_cs: cleanup_module\n");
+       DEBUG(0, "ray_cs: cleanup_module\n");
 
 #ifdef CONFIG_PROC_FS
-    remove_proc_entry("driver/ray_cs/ray_cs", NULL);
-    remove_proc_entry("driver/ray_cs/essid", NULL);
-    remove_proc_entry("driver/ray_cs/net_type", NULL);
-    remove_proc_entry("driver/ray_cs/translate", NULL);
-    remove_proc_entry("driver/ray_cs", NULL);
+       remove_proc_entry("driver/ray_cs/ray_cs", NULL);
+       remove_proc_entry("driver/ray_cs/essid", NULL);
+       remove_proc_entry("driver/ray_cs/net_type", NULL);
+       remove_proc_entry("driver/ray_cs/translate", NULL);
+       remove_proc_entry("driver/ray_cs", NULL);
 #endif
 
-    pcmcia_unregister_driver(&ray_driver);
+       pcmcia_unregister_driver(&ray_driver);
 } /* exit_ray_cs */
 
 module_init(init_ray_cs);
index b0848259b45553ab7d8aa132f6e51ef874b7858b..0f08773328c6b8f182936fbb9dc2e95f58401226 100644 (file)
@@ -114,9 +114,6 @@ static void rt2400pci_rf_write(struct rt2x00_dev *rt2x00dev,
 {
        u32 reg;
 
-       if (!word)
-               return;
-
        mutex_lock(&rt2x00dev->csr_mutex);
 
        /*
index 72ac31c3cb759db0672024cdbfec2248ceaa9db4..ec3b004ddc3c8a05637a2d65c77c32831f5612f1 100644 (file)
@@ -48,8 +48,8 @@
 #define EEPROM_SIZE                    0x0100
 #define BBP_BASE                       0x0000
 #define BBP_SIZE                       0x0020
-#define RF_BASE                                0x0000
-#define RF_SIZE                                0x0010
+#define RF_BASE                                0x0004
+#define RF_SIZE                                0x000c
 
 /*
  * Number of TX queues.
index eb82860c54f9e49a068c58af7c3cd22394c138d6..276a8232aaa084583a5b4b97897c4a8207b25f7b 100644 (file)
@@ -114,9 +114,6 @@ static void rt2500pci_rf_write(struct rt2x00_dev *rt2x00dev,
 {
        u32 reg;
 
-       if (!word)
-               return;
-
        mutex_lock(&rt2x00dev->csr_mutex);
 
        /*
index 17a0c9c8c18468e7592ed341ef9296e46db7711b..ce2f065c74868927a4935d9249683e5c5fd3ff1b 100644 (file)
@@ -59,8 +59,8 @@
 #define EEPROM_SIZE                    0x0200
 #define BBP_BASE                       0x0000
 #define BBP_SIZE                       0x0040
-#define RF_BASE                                0x0000
-#define RF_SIZE                                0x0014
+#define RF_BASE                                0x0004
+#define RF_SIZE                                0x0010
 
 /*
  * Number of TX queues.
index 270691ac23618295eca217ff1561b78b5e89bc5d..9e630e70fc976d9d6da06c42ab80bf6970a81778 100644 (file)
@@ -204,9 +204,6 @@ static void rt2500usb_rf_write(struct rt2x00_dev *rt2x00dev,
 {
        u16 reg;
 
-       if (!word)
-               return;
-
        mutex_lock(&rt2x00dev->csr_mutex);
 
        /*
@@ -2007,6 +2004,8 @@ static struct usb_device_id rt2500usb_device_table[] = {
        { USB_DEVICE(0x13b1, 0x000d), USB_DEVICE_DATA(&rt2500usb_ops) },
        { USB_DEVICE(0x13b1, 0x0011), USB_DEVICE_DATA(&rt2500usb_ops) },
        { USB_DEVICE(0x13b1, 0x001a), USB_DEVICE_DATA(&rt2500usb_ops) },
+       /* CNet */
+       { USB_DEVICE(0x1371, 0x9022), USB_DEVICE_DATA(&rt2500usb_ops) },
        /* Conceptronic */
        { USB_DEVICE(0x14b2, 0x3c02), USB_DEVICE_DATA(&rt2500usb_ops) },
        /* D-LINK */
@@ -2031,14 +2030,20 @@ static struct usb_device_id rt2500usb_device_table[] = {
        { USB_DEVICE(0x148f, 0x2570), USB_DEVICE_DATA(&rt2500usb_ops) },
        { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt2500usb_ops) },
        { USB_DEVICE(0x148f, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) },
+       /* Sagem */
+       { USB_DEVICE(0x079b, 0x004b), USB_DEVICE_DATA(&rt2500usb_ops) },
        /* Siemens */
        { USB_DEVICE(0x0681, 0x3c06), USB_DEVICE_DATA(&rt2500usb_ops) },
        /* SMC */
        { USB_DEVICE(0x0707, 0xee13), USB_DEVICE_DATA(&rt2500usb_ops) },
        /* Spairon */
        { USB_DEVICE(0x114b, 0x0110), USB_DEVICE_DATA(&rt2500usb_ops) },
+       /* SURECOM */
+       { USB_DEVICE(0x0769, 0x11f3), USB_DEVICE_DATA(&rt2500usb_ops) },
        /* Trust */
        { USB_DEVICE(0x0eb0, 0x9020), USB_DEVICE_DATA(&rt2500usb_ops) },
+       /* VTech */
+       { USB_DEVICE(0x0f88, 0x3012), USB_DEVICE_DATA(&rt2500usb_ops) },
        /* Zinwell */
        { USB_DEVICE(0x5a57, 0x0260), USB_DEVICE_DATA(&rt2500usb_ops) },
        { 0, }
index afce0e0322c3e5a74438c742ee319b683bccb7d5..5bc46fe72179302d38cb79cd767674aff0924037 100644 (file)
@@ -59,8 +59,8 @@
 #define EEPROM_SIZE                    0x006a
 #define BBP_BASE                       0x0000
 #define BBP_SIZE                       0x0060
-#define RF_BASE                                0x0000
-#define RF_SIZE                                0x0014
+#define RF_BASE                                0x0004
+#define RF_SIZE                                0x0010
 
 /*
  * Number of TX queues.
index dcdce7f746b5eb5db8d83abba464cd8e2de90f7b..07d378ef0b46297995d016b039af2452e2646bea 100644 (file)
@@ -435,11 +435,12 @@ static ssize_t rt2x00debug_read_##__name(struct file *file,       \
        if (index >= debug->__name.word_count)                  \
                return -EINVAL;                                 \
                                                                \
+       index += (debug->__name.word_base /                     \
+                 debug->__name.word_size);                     \
+                                                               \
        if (debug->__name.flags & RT2X00DEBUGFS_OFFSET)         \
                index *= debug->__name.word_size;               \
                                                                \
-       index += debug->__name.word_base;                       \
-                                                               \
        debug->__name.read(intf->rt2x00dev, index, &value);     \
                                                                \
        size = sprintf(line, __format, value);                  \
@@ -476,11 +477,12 @@ static ssize_t rt2x00debug_write_##__name(struct file *file,      \
        size = strlen(line);                                    \
        value = simple_strtoul(line, NULL, 0);                  \
                                                                \
+       index += (debug->__name.word_base /                     \
+                 debug->__name.word_size);                     \
+                                                               \
        if (debug->__name.flags & RT2X00DEBUGFS_OFFSET)         \
                index *= debug->__name.word_size;               \
                                                                \
-       index += debug->__name.word_base;                       \
-                                                               \
        debug->__name.write(intf->rt2x00dev, index, value);     \
                                                                \
        *offset += size;                                        \
@@ -545,9 +547,9 @@ static struct dentry *rt2x00debug_create_file_driver(const char *name,
                return NULL;
 
        blob->data = data;
-       data += sprintf(data, "driver: %s\n", intf->rt2x00dev->ops->name);
-       data += sprintf(data, "version: %s\n", DRV_VERSION);
-       data += sprintf(data, "compiled: %s %s\n", __DATE__, __TIME__);
+       data += sprintf(data, "driver:\t%s\n", intf->rt2x00dev->ops->name);
+       data += sprintf(data, "version:\t%s\n", DRV_VERSION);
+       data += sprintf(data, "compiled:\t%s %s\n", __DATE__, __TIME__);
        blob->size = strlen(blob->data);
 
        return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob);
@@ -568,14 +570,27 @@ static struct dentry *rt2x00debug_create_file_chipset(const char *name,
                return NULL;
 
        blob->data = data;
-       data += sprintf(data, "rt chip: %04x\n", intf->rt2x00dev->chip.rt);
-       data += sprintf(data, "rf chip: %04x\n", intf->rt2x00dev->chip.rf);
-       data += sprintf(data, "revision:%08x\n", intf->rt2x00dev->chip.rev);
+       data += sprintf(data, "rt chip:\t%04x\n", intf->rt2x00dev->chip.rt);
+       data += sprintf(data, "rf chip:\t%04x\n", intf->rt2x00dev->chip.rf);
+       data += sprintf(data, "revision:\t%08x\n", intf->rt2x00dev->chip.rev);
        data += sprintf(data, "\n");
-       data += sprintf(data, "csr length: %d\n", debug->csr.word_count);
-       data += sprintf(data, "eeprom length: %d\n", debug->eeprom.word_count);
-       data += sprintf(data, "bbp length: %d\n", debug->bbp.word_count);
-       data += sprintf(data, "rf length: %d\n", debug->rf.word_count);
+       data += sprintf(data, "register\tbase\twords\twordsize\n");
+       data += sprintf(data, "csr\t%d\t%d\t%d\n",
+                       debug->csr.word_base,
+                       debug->csr.word_count,
+                       debug->csr.word_size);
+       data += sprintf(data, "eeprom\t%d\t%d\t%d\n",
+                       debug->eeprom.word_base,
+                       debug->eeprom.word_count,
+                       debug->eeprom.word_size);
+       data += sprintf(data, "bbp\t%d\t%d\t%d\n",
+                       debug->bbp.word_base,
+                       debug->bbp.word_count,
+                       debug->bbp.word_size);
+       data += sprintf(data, "rf\t%d\t%d\t%d\n",
+                       debug->rf.word_base,
+                       debug->rf.word_count,
+                       debug->rf.word_size);
        blob->size = strlen(blob->data);
 
        return debugfs_create_blob(name, S_IRUSR, intf->driver_folder, blob);
index 9223a6d1f1d036cb96a5bed62f010a5dee273c62..7eb5cd7e5f32424ea97474b57e009374a212da29 100644 (file)
@@ -302,11 +302,6 @@ static void rt2x00link_precalculate_signal(struct rt2x00_dev *rt2x00dev)
            PERCENTAGE(qual->rx_success, qual->rx_failed + qual->rx_success);
        link->tx_percentage =
            PERCENTAGE(qual->tx_success, qual->tx_failed + qual->tx_success);
-
-       qual->rx_success = 0;
-       qual->rx_failed = 0;
-       qual->tx_success = 0;
-       qual->tx_failed = 0;
 }
 
 int rt2x00link_calculate_signal(struct rt2x00_dev *rt2x00dev, int rssi)
@@ -392,6 +387,16 @@ void rt2x00link_reset_tuner(struct rt2x00_dev *rt2x00dev, bool antenna)
                rt2x00link_antenna_reset(rt2x00dev);
 }
 
+void rt2x00link_reset_qual(struct rt2x00_dev *rt2x00dev)
+{
+       struct link_qual *qual = &rt2x00dev->link.qual;
+
+       qual->rx_success = 0;
+       qual->rx_failed = 0;
+       qual->tx_success = 0;
+       qual->tx_failed = 0;
+}
+
 static void rt2x00link_tuner(struct work_struct *work)
 {
        struct rt2x00_dev *rt2x00dev =
@@ -447,6 +452,11 @@ static void rt2x00link_tuner(struct work_struct *work)
         */
        rt2x00lib_antenna_diversity(rt2x00dev);
 
+       /*
+        * Reset the quality counters which recounted during each period.
+        */
+       rt2x00link_reset_qual(rt2x00dev);
+
        /*
         * Increase tuner counter, and reschedule the next link tuner run.
         */
index 0be147f364e718271539b4f17adf03291a25d37a..2ca8b7a9722c96f8dfd6b7ad0689d1738d143145 100644 (file)
@@ -123,9 +123,6 @@ static void rt61pci_rf_write(struct rt2x00_dev *rt2x00dev,
 {
        u32 reg;
 
-       if (!word)
-               return;
-
        mutex_lock(&rt2x00dev->csr_mutex);
 
        /*
index 2f97fee7a8de84b4cbae8231452ac7220a8a5f44..41e8959919f6dd897dc49133ab51027e9f0192f6 100644 (file)
@@ -50,8 +50,8 @@
 #define EEPROM_SIZE                    0x0100
 #define BBP_BASE                       0x0000
 #define BBP_SIZE                       0x0080
-#define RF_BASE                                0x0000
-#define RF_SIZE                                0x0014
+#define RF_BASE                                0x0004
+#define RF_SIZE                                0x0010
 
 /*
  * Number of TX queues.
index 6521dac7ec4a45fa4b271ee389cf0ca81ca2bc0a..24fdfdfee3df4efd28c8a09cd60f8b5c4aa6af2e 100644 (file)
@@ -122,9 +122,6 @@ static void rt73usb_rf_write(struct rt2x00_dev *rt2x00dev,
 {
        u32 reg;
 
-       if (!word)
-               return;
-
        mutex_lock(&rt2x00dev->csr_mutex);
 
        /*
@@ -2241,13 +2238,6 @@ static int rt73usb_conf_tx(struct ieee80211_hw *hw, u16 queue_idx,
        return 0;
 }
 
-#if 0
-/*
- * Mac80211 demands get_tsf must be atomic.
- * This is not possible for rt73usb since all register access
- * functions require sleeping. Untill mac80211 no longer needs
- * get_tsf to be atomic, this function should be disabled.
- */
 static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
 {
        struct rt2x00_dev *rt2x00dev = hw->priv;
@@ -2261,9 +2251,6 @@ static u64 rt73usb_get_tsf(struct ieee80211_hw *hw)
 
        return tsf;
 }
-#else
-#define rt73usb_get_tsf        NULL
-#endif
 
 static const struct ieee80211_ops rt73usb_mac80211_ops = {
        .tx                     = rt2x00mac_tx,
@@ -2354,7 +2341,18 @@ static const struct rt2x00_ops rt73usb_ops = {
  */
 static struct usb_device_id rt73usb_device_table[] = {
        /* AboCom */
+       { USB_DEVICE(0x07b8, 0xb21b), USB_DEVICE_DATA(&rt73usb_ops) },
+       { USB_DEVICE(0x07b8, 0xb21c), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x07b8, 0xb21d), USB_DEVICE_DATA(&rt73usb_ops) },
+       { USB_DEVICE(0x07b8, 0xb21e), USB_DEVICE_DATA(&rt73usb_ops) },
+       { USB_DEVICE(0x07b8, 0xb21f), USB_DEVICE_DATA(&rt73usb_ops) },
+       /* AL */
+       { USB_DEVICE(0x14b2, 0x3c10), USB_DEVICE_DATA(&rt73usb_ops) },
+       /* Amigo */
+       { USB_DEVICE(0x148f, 0x9021), USB_DEVICE_DATA(&rt73usb_ops) },
+       { USB_DEVICE(0x0eb0, 0x9021), USB_DEVICE_DATA(&rt73usb_ops) },
+       /* AMIT  */
+       { USB_DEVICE(0x18c5, 0x0002), USB_DEVICE_DATA(&rt73usb_ops) },
        /* Askey */
        { USB_DEVICE(0x1690, 0x0722), USB_DEVICE_DATA(&rt73usb_ops) },
        /* ASUS */
@@ -2367,6 +2365,7 @@ static struct usb_device_id rt73usb_device_table[] = {
        { USB_DEVICE(0x050d, 0x905c), USB_DEVICE_DATA(&rt73usb_ops) },
        /* Billionton */
        { USB_DEVICE(0x1631, 0xc019), USB_DEVICE_DATA(&rt73usb_ops) },
+       { USB_DEVICE(0x08dd, 0x0120), USB_DEVICE_DATA(&rt73usb_ops) },
        /* Buffalo */
        { USB_DEVICE(0x0411, 0x00d8), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x0411, 0x00f4), USB_DEVICE_DATA(&rt73usb_ops) },
@@ -2382,6 +2381,11 @@ static struct usb_device_id rt73usb_device_table[] = {
        { USB_DEVICE(0x07d1, 0x3c04), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x07d1, 0x3c06), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x07d1, 0x3c07), USB_DEVICE_DATA(&rt73usb_ops) },
+       /* Edimax */
+       { USB_DEVICE(0x7392, 0x7318), USB_DEVICE_DATA(&rt73usb_ops) },
+       { USB_DEVICE(0x7392, 0x7618), USB_DEVICE_DATA(&rt73usb_ops) },
+       /* EnGenius */
+       { USB_DEVICE(0x1740, 0x3701), USB_DEVICE_DATA(&rt73usb_ops) },
        /* Gemtek */
        { USB_DEVICE(0x15a9, 0x0004), USB_DEVICE_DATA(&rt73usb_ops) },
        /* Gigabyte */
@@ -2402,22 +2406,34 @@ static struct usb_device_id rt73usb_device_table[] = {
        { USB_DEVICE(0x0db0, 0xa861), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x0db0, 0xa874), USB_DEVICE_DATA(&rt73usb_ops) },
        /* Ralink */
+       { USB_DEVICE(0x04bb, 0x093d), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x148f, 0x2573), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x148f, 0x2671), USB_DEVICE_DATA(&rt73usb_ops) },
        /* Qcom */
        { USB_DEVICE(0x18e8, 0x6196), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x18e8, 0x6229), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x18e8, 0x6238), USB_DEVICE_DATA(&rt73usb_ops) },
+       /* Samsung */
+       { USB_DEVICE(0x04e8, 0x4471), USB_DEVICE_DATA(&rt73usb_ops) },
        /* Senao */
        { USB_DEVICE(0x1740, 0x7100), USB_DEVICE_DATA(&rt73usb_ops) },
        /* Sitecom */
-       { USB_DEVICE(0x0df6, 0x9712), USB_DEVICE_DATA(&rt73usb_ops) },
+       { USB_DEVICE(0x0df6, 0x0024), USB_DEVICE_DATA(&rt73usb_ops) },
+       { USB_DEVICE(0x0df6, 0x0027), USB_DEVICE_DATA(&rt73usb_ops) },
+       { USB_DEVICE(0x0df6, 0x002f), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x0df6, 0x90ac), USB_DEVICE_DATA(&rt73usb_ops) },
+       { USB_DEVICE(0x0df6, 0x9712), USB_DEVICE_DATA(&rt73usb_ops) },
        /* Surecom */
        { USB_DEVICE(0x0769, 0x31f3), USB_DEVICE_DATA(&rt73usb_ops) },
+       /* Philips */
+       { USB_DEVICE(0x0471, 0x200a), USB_DEVICE_DATA(&rt73usb_ops) },
        /* Planex */
        { USB_DEVICE(0x2019, 0xab01), USB_DEVICE_DATA(&rt73usb_ops) },
        { USB_DEVICE(0x2019, 0xab50), USB_DEVICE_DATA(&rt73usb_ops) },
+       /* Zcom */
+       { USB_DEVICE(0x0cde, 0x001c), USB_DEVICE_DATA(&rt73usb_ops) },
+       /* ZyXEL */
+       { USB_DEVICE(0x0586, 0x3415), USB_DEVICE_DATA(&rt73usb_ops) },
        { 0, }
 };
 
index 834b28ce6cde569b8c93f7140b2a27e9ef7127d5..c8016f65b4bd2c6d52e5a740b2bdc7a039a4c846 100644 (file)
@@ -50,8 +50,8 @@
 #define EEPROM_SIZE                    0x0100
 #define BBP_BASE                       0x0000
 #define BBP_SIZE                       0x0080
-#define RF_BASE                                0x0000
-#define RF_SIZE                                0x0014
+#define RF_BASE                                0x0004
+#define RF_SIZE                                0x0010
 
 /*
  * Number of TX queues.
index 82bd47e7c617795045a6d3f0b9d9c4590b2d7a53..fd81884b9c7d8b583ed2c63e1e26efa0aca51dea 100644 (file)
@@ -48,6 +48,10 @@ static struct usb_device_id rtl8187_table[] __devinitdata = {
        {USB_DEVICE(0x0bda, 0x8189), .driver_info = DEVICE_RTL8187B},
        {USB_DEVICE(0x0bda, 0x8197), .driver_info = DEVICE_RTL8187B},
        {USB_DEVICE(0x0bda, 0x8198), .driver_info = DEVICE_RTL8187B},
+       /* Surecom */
+       {USB_DEVICE(0x0769, 0x11F2), .driver_info = DEVICE_RTL8187},
+       /* Logitech */
+       {USB_DEVICE(0x0789, 0x010C), .driver_info = DEVICE_RTL8187},
        /* Netgear */
        {USB_DEVICE(0x0846, 0x6100), .driver_info = DEVICE_RTL8187},
        {USB_DEVICE(0x0846, 0x6a00), .driver_info = DEVICE_RTL8187},
@@ -57,8 +61,16 @@ static struct usb_device_id rtl8187_table[] __devinitdata = {
        /* Sitecom */
        {USB_DEVICE(0x0df6, 0x000d), .driver_info = DEVICE_RTL8187},
        {USB_DEVICE(0x0df6, 0x0028), .driver_info = DEVICE_RTL8187B},
+       /* Sphairon Access Systems GmbH */
+       {USB_DEVICE(0x114B, 0x0150), .driver_info = DEVICE_RTL8187},
+       /* Dick Smith Electronics */
+       {USB_DEVICE(0x1371, 0x9401), .driver_info = DEVICE_RTL8187},
        /* Abocom */
        {USB_DEVICE(0x13d1, 0xabe6), .driver_info = DEVICE_RTL8187},
+       /* Qcom */
+       {USB_DEVICE(0x18E8, 0x6232), .driver_info = DEVICE_RTL8187},
+       /* AirLive */
+       {USB_DEVICE(0x1b75, 0x8187), .driver_info = DEVICE_RTL8187},
        {}
 };
 
index 39f525efdc8d90af46b572e60b749386d9f31919..f9520463269074eee8fb724ddc75b002de86103e 100644 (file)
@@ -2477,6 +2477,16 @@ static const struct header_ops strip_header_ops = {
        .rebuild = strip_rebuild_header,
 };
 
+
+static const struct net_device_ops strip_netdev_ops = {
+       .ndo_open       = strip_open_low,
+       .ndo_stop       = strip_close_low,
+       .ndo_start_xmit = strip_xmit,
+       .ndo_set_mac_address = strip_set_mac_address,
+       .ndo_get_stats  = strip_get_stats,
+       .ndo_change_mtu = strip_change_mtu,
+};
+
 /*
  * This routine is called by DDI when the
  * (dynamically assigned) device is registered
@@ -2503,18 +2513,8 @@ static void strip_dev_setup(struct net_device *dev)
        dev->dev_addr[0] = 0;
        dev->addr_len = sizeof(MetricomAddress);
 
-       /*
-        * Pointers to interface service routines.
-        */
-
-       dev->open = strip_open_low;
-       dev->stop = strip_close_low;
-       dev->hard_start_xmit = strip_xmit;
-       dev->header_ops = &strip_header_ops;
-
-       dev->set_mac_address = strip_set_mac_address;
-       dev->get_stats = strip_get_stats;
-       dev->change_mtu = strip_change_mtu;
+       dev->header_ops = &strip_header_ops,
+       dev->netdev_ops = &strip_netdev_ops;
 }
 
 /*
index 688bdea8f13a8cc1b74c025e7bdd4acb40528699..b728541f2fb538c116367fb0241e1247b0859d64 100644 (file)
@@ -4281,8 +4281,7 @@ int __init init_module(void)
 
 
        /* Loop on all possible base addresses. */
-       i = -1;
-       while ((io[++i] != 0) && (i < ARRAY_SIZE(io))) {
+       for (i = 0; i < ARRAY_SIZE(io) && io[i] != 0; i++) {
                struct net_device *dev = alloc_etherdev(sizeof(net_local));
                if (!dev)
                        break;
index de717f8ffd61061a5caccfa92cb62d70403b1087..e55b33961aeb8c7d030642027c3075536a979f5d 100644 (file)
@@ -838,9 +838,8 @@ wv_82593_cmd(struct net_device *    dev,
     }
   while(((status & SR3_EXEC_STATE_MASK) != SR3_EXEC_IDLE) && (spin-- > 0));
 
-  /* If the interrupt hasn't be posted */
-  if(spin <= 0)
-    {
+  /* If the interrupt hasn't been posted */
+  if (spin < 0) {
 #ifdef DEBUG_INTERRUPT_ERROR
       printk(KERN_INFO "wv_82593_cmd: %s timeout (previous command), status 0x%02x\n",
             str, status);
@@ -1353,21 +1352,6 @@ wv_init_info(struct net_device * dev)
  * or wireless extensions
  */
 
-/*------------------------------------------------------------------*/
-/*
- * Get the current ethernet statistics. This may be called with the
- * card open or closed.
- * Used when the user read /proc/net/dev
- */
-static en_stats        *
-wavelan_get_stats(struct net_device *  dev)
-{
-#ifdef DEBUG_IOCTL_TRACE
-  printk(KERN_DEBUG "%s: <>wavelan_get_stats()\n", dev->name);
-#endif
-
-  return(&((net_local *)netdev_priv(dev))->stats);
-}
 
 /*------------------------------------------------------------------*/
 /*
@@ -2818,7 +2802,7 @@ wv_packet_read(struct net_device *                dev,
       printk(KERN_INFO "%s: wv_packet_read(): could not alloc_skb(%d, GFP_ATOMIC)\n",
             dev->name, sksize);
 #endif
-      lp->stats.rx_dropped++;
+      dev->stats.rx_dropped++;
       /*
        * Not only do we want to return here, but we also need to drop the
        * packet on the floor to clear the interrupt.
@@ -2878,8 +2862,8 @@ wv_packet_read(struct net_device *                dev,
   netif_rx(skb);
 
   /* Keep stats up to date */
-  lp->stats.rx_packets++;
-  lp->stats.rx_bytes += sksize;
+  dev->stats.rx_packets++;
+  dev->stats.rx_bytes += sksize;
 
 #ifdef DEBUG_RX_TRACE
   printk(KERN_DEBUG "%s: <-wv_packet_read()\n", dev->name);
@@ -2981,13 +2965,13 @@ wv_packet_rcv(struct net_device *       dev)
       /* Check status */
       if((status & RX_RCV_OK) != RX_RCV_OK)
        {
-         lp->stats.rx_errors++;
+         dev->stats.rx_errors++;
          if(status & RX_NO_SFD)
-           lp->stats.rx_frame_errors++;
+           dev->stats.rx_frame_errors++;
          if(status & RX_CRC_ERR)
-           lp->stats.rx_crc_errors++;
+           dev->stats.rx_crc_errors++;
          if(status & RX_OVRRUN)
-           lp->stats.rx_over_errors++;
+           dev->stats.rx_over_errors++;
 
 #ifdef DEBUG_RX_FAIL
          printk(KERN_DEBUG "%s: wv_packet_rcv(): packet not received ok, status = 0x%x\n",
@@ -3074,7 +3058,7 @@ wv_packet_write(struct net_device *       dev,
   dev->trans_start = jiffies;
 
   /* Keep stats up to date */
-  lp->stats.tx_bytes += length;
+  dev->stats.tx_bytes += length;
 
   spin_unlock_irqrestore(&lp->spinlock, flags);
 
@@ -4107,7 +4091,7 @@ wavelan_interrupt(int             irq,
              printk(KERN_INFO "%s: wv_interrupt(): receive buffer overflow\n",
                     dev->name);
 #endif
-             lp->stats.rx_over_errors++;
+             dev->stats.rx_over_errors++;
              lp->overrunning = 1;
            }
 
@@ -4156,7 +4140,7 @@ wavelan_interrupt(int             irq,
          /* Check for possible errors */
          if((tx_status & TX_OK) != TX_OK)
            {
-             lp->stats.tx_errors++;
+             dev->stats.tx_errors++;
 
              if(tx_status & TX_FRTL)
                {
@@ -4171,14 +4155,14 @@ wavelan_interrupt(int           irq,
                  printk(KERN_DEBUG "%s: wv_interrupt(): DMA underrun\n",
                         dev->name);
 #endif
-                 lp->stats.tx_aborted_errors++;
+                 dev->stats.tx_aborted_errors++;
                }
              if(tx_status & TX_LOST_CTS)
                {
 #ifdef DEBUG_TX_FAIL
                  printk(KERN_DEBUG "%s: wv_interrupt(): no CTS\n", dev->name);
 #endif
-                 lp->stats.tx_carrier_errors++;
+                 dev->stats.tx_carrier_errors++;
                }
              if(tx_status & TX_LOST_CRS)
                {
@@ -4186,14 +4170,14 @@ wavelan_interrupt(int           irq,
                  printk(KERN_DEBUG "%s: wv_interrupt(): no carrier\n",
                         dev->name);
 #endif
-                 lp->stats.tx_carrier_errors++;
+                 dev->stats.tx_carrier_errors++;
                }
              if(tx_status & TX_HRT_BEAT)
                {
 #ifdef DEBUG_TX_FAIL
                  printk(KERN_DEBUG "%s: wv_interrupt(): heart beat\n", dev->name);
 #endif
-                 lp->stats.tx_heartbeat_errors++;
+                 dev->stats.tx_heartbeat_errors++;
                }
              if(tx_status & TX_DEFER)
                {
@@ -4217,14 +4201,14 @@ wavelan_interrupt(int           irq,
 #endif
                      if(!(tx_status & TX_NCOL_MASK))
                        {
-                         lp->stats.collisions += 0x10;
+                         dev->stats.collisions += 0x10;
                        }
                    }
                }
            }   /* if(!(tx_status & TX_OK)) */
 
-         lp->stats.collisions += (tx_status & TX_NCOL_MASK);
-         lp->stats.tx_packets++;
+         dev->stats.collisions += (tx_status & TX_NCOL_MASK);
+         dev->stats.tx_packets++;
 
          netif_wake_queue(dev);
          outb(CR0_INT_ACK | OP0_NOP, LCCR(base));      /* Acknowledge the interrupt */
@@ -4452,6 +4436,19 @@ wavelan_close(struct net_device *        dev)
   return 0;
 }
 
+static const struct net_device_ops wavelan_netdev_ops = {
+       .ndo_open               = wavelan_open,
+       .ndo_stop               = wavelan_close,
+       .ndo_start_xmit         = wavelan_packet_xmit,
+       .ndo_set_multicast_list = wavelan_set_multicast_list,
+#ifdef SET_MAC_ADDRESS
+       .ndo_set_mac_address    = wavelan_set_mac_address,
+#endif
+       .ndo_tx_timeout         = wavelan_watchdog,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 /*------------------------------------------------------------------*/
 /*
  * wavelan_attach() creates an "instance" of the driver, allocating
@@ -4512,17 +4509,7 @@ wavelan_probe(struct pcmcia_device *p_dev)
   lp->dev = dev;
 
   /* wavelan NET3 callbacks */
-  dev->open = &wavelan_open;
-  dev->stop = &wavelan_close;
-  dev->hard_start_xmit = &wavelan_packet_xmit;
-  dev->get_stats = &wavelan_get_stats;
-  dev->set_multicast_list = &wavelan_set_multicast_list;
-#ifdef SET_MAC_ADDRESS
-  dev->set_mac_address = &wavelan_set_mac_address;
-#endif /* SET_MAC_ADDRESS */
-
-  /* Set the watchdog timer */
-  dev->tx_timeout      = &wavelan_watchdog;
+  dev->netdev_ops = &wavelan_netdev_ops;
   dev->watchdog_timeo  = WATCHDOG_JIFFIES;
   SET_ETHTOOL_OPS(dev, &ops);
 
index 628192d7248f4d0c527240361da331736f83baad..706fd3007d21550c135226c8a83ac77599f521f8 100644 (file)
@@ -576,7 +576,6 @@ struct wavepoint_table
 /****************************** TYPES ******************************/
 
 /* Shortcuts */
-typedef struct net_device_stats        en_stats;
 typedef struct iw_statistics   iw_stats;
 typedef struct iw_quality      iw_qual;
 typedef struct iw_freq         iw_freq;
@@ -592,8 +591,6 @@ typedef u_char              mac_addr[WAVELAN_ADDR_SIZE];    /* Hardware address */
  * For each network interface, Linux keep data in two structure. "device"
  * keep the generic data (same format for everybody) and "net_local" keep
  * the additional specific data.
- * Note that some of this specific data is in fact generic (en_stats, for
- * example).
  */
 struct net_local
 {
@@ -601,7 +598,6 @@ struct net_local
   struct net_device *  dev;            /* Reverse link... */
   spinlock_t   spinlock;       /* Serialize access to the hardware (SMP) */
   struct pcmcia_device *       link;           /* pcmcia structure */
-  en_stats     stats;          /* Ethernet interface statistics */
   int          nresets;        /* Number of hw resets */
   u_char       configured;     /* If it is configured */
   u_char       reconfig_82593; /* Need to reconfigure the controller */
@@ -694,8 +690,6 @@ static void
 static void
        wv_init_info(struct net_device *);      /* display startup info */
 /* ------------------- IOCTL, STATS & RECONFIG ------------------- */
-static en_stats        *
-       wavelan_get_stats(struct net_device *); /* Give stats /proc/net/dev */
 static iw_stats *
        wavelan_get_wireless_stats(struct net_device *);
 /* ----------------------- PACKET RECEPTION ----------------------- */
index 59bb3a55ab48c82838da43c1545d9863560bf572..8bce1a550a2296218131dfce28128224f14e678d 100644 (file)
@@ -606,7 +606,7 @@ struct wl3501_card {
        u8                              reg_domain;
        u8                              version[2];
        struct wl3501_scan_confirm      bss_set[20];
-       struct net_device_stats         stats;
+
        struct iw_statistics            wstats;
        struct iw_spy_data              spy_data;
        struct iw_public_data           wireless_data;
index c8d5c34e8ddffb6943120423040e2d669a85cce7..1f64d6033ab534509052854ea48845f202b52f06 100644 (file)
@@ -1000,7 +1000,7 @@ static inline void wl3501_md_ind_interrupt(struct net_device *dev,
        if (!skb) {
                printk(KERN_WARNING "%s: Can't alloc a sk_buff of size %d.\n",
                       dev->name, pkt_len);
-               this->stats.rx_dropped++;
+               dev->stats.rx_dropped++;
        } else {
                skb->dev = dev;
                skb_reserve(skb, 2); /* IP headers on 16 bytes boundaries */
@@ -1008,8 +1008,8 @@ static inline void wl3501_md_ind_interrupt(struct net_device *dev,
                wl3501_receive(this, skb->data, pkt_len);
                skb_put(skb, pkt_len);
                skb->protocol   = eth_type_trans(skb, dev);
-               this->stats.rx_packets++;
-               this->stats.rx_bytes += skb->len;
+               dev->stats.rx_packets++;
+               dev->stats.rx_bytes += skb->len;
                netif_rx(skb);
        }
 }
@@ -1311,7 +1311,7 @@ out:
 static void wl3501_tx_timeout(struct net_device *dev)
 {
        struct wl3501_card *this = netdev_priv(dev);
-       struct net_device_stats *stats = &this->stats;
+       struct net_device_stats *stats = &dev->stats;
        unsigned long flags;
        int rc;
 
@@ -1346,11 +1346,11 @@ static int wl3501_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        if (enabled)
                wl3501_unblock_interrupt(this);
        if (rc) {
-               ++this->stats.tx_dropped;
+               ++dev->stats.tx_dropped;
                netif_stop_queue(dev);
        } else {
-               ++this->stats.tx_packets;
-               this->stats.tx_bytes += skb->len;
+               ++dev->stats.tx_packets;
+               dev->stats.tx_bytes += skb->len;
                kfree_skb(skb);
 
                if (this->tx_buffer_cnt < 2)
@@ -1400,13 +1400,6 @@ fail:
        goto out;
 }
 
-static struct net_device_stats *wl3501_get_stats(struct net_device *dev)
-{
-       struct wl3501_card *this = netdev_priv(dev);
-
-       return &this->stats;
-}
-
 static struct iw_statistics *wl3501_get_wireless_stats(struct net_device *dev)
 {
        struct wl3501_card *this = netdev_priv(dev);
@@ -1890,6 +1883,16 @@ static const struct iw_handler_def wl3501_handler_def = {
        .get_wireless_stats = wl3501_get_wireless_stats,
 };
 
+static const struct net_device_ops wl3501_netdev_ops = {
+       .ndo_open               = wl3501_open,
+       .ndo_stop               = wl3501_close,
+       .ndo_start_xmit         = wl3501_hard_start_xmit,
+       .ndo_tx_timeout         = wl3501_tx_timeout,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 /**
  * wl3501_attach - creates an "instance" of the driver
  *
@@ -1922,17 +1925,16 @@ static int wl3501_probe(struct pcmcia_device *p_dev)
        dev = alloc_etherdev(sizeof(struct wl3501_card));
        if (!dev)
                goto out_link;
-       dev->open               = wl3501_open;
-       dev->stop               = wl3501_close;
-       dev->hard_start_xmit    = wl3501_hard_start_xmit;
-       dev->tx_timeout         = wl3501_tx_timeout;
+
+
+       dev->netdev_ops         = &wl3501_netdev_ops;
        dev->watchdog_timeo     = 5 * HZ;
-       dev->get_stats          = wl3501_get_stats;
+
        this = netdev_priv(dev);
        this->wireless_data.spy_data = &this->spy_data;
        this->p_dev = p_dev;
        dev->wireless_data      = &this->wireless_data;
-       dev->wireless_handlers  = (struct iw_handler_def *)&wl3501_handler_def;
+       dev->wireless_handlers  = &wl3501_handler_def;
        SET_ETHTOOL_OPS(dev, &ops);
        netif_stop_queue(dev);
        p_dev->priv = p_dev->irq.Instance = dev;
index 6226ac2357f82a308c6efa7d42daab08d4122a91..9b244c96b221bbc3c96006112681d1157e4d42d6 100644 (file)
@@ -328,8 +328,8 @@ static void zd1201_usbrx(struct urb *urb)
                        memcpy(skb_put(skb, 2), &data[datalen-24], 2);
                        memcpy(skb_put(skb, len), data, len);
                        skb->protocol = eth_type_trans(skb, zd->dev);
-                       zd->stats.rx_packets++;
-                       zd->stats.rx_bytes += skb->len;
+                       zd->dev->stats.rx_packets++;
+                       zd->dev->stats.rx_bytes += skb->len;
                        netif_rx(skb);
                        goto resubmit;
                }
@@ -384,8 +384,8 @@ static void zd1201_usbrx(struct urb *urb)
                        memcpy(skb_put(skb, len), data+8, len);
                }
                skb->protocol = eth_type_trans(skb, zd->dev);
-               zd->stats.rx_packets++;
-               zd->stats.rx_bytes += skb->len;
+               zd->dev->stats.rx_packets++;
+               zd->dev->stats.rx_bytes += skb->len;
                netif_rx(skb);
        }
 resubmit:
@@ -787,7 +787,7 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct urb *urb = zd->tx_urb;
 
        if (!zd->mac_enabled || zd->monitor) {
-               zd->stats.tx_dropped++;
+               dev->stats.tx_dropped++;
                kfree_skb(skb);
                return 0;
        }
@@ -817,12 +817,12 @@ static int zd1201_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
 
        err = usb_submit_urb(zd->tx_urb, GFP_ATOMIC);
        if (err) {
-               zd->stats.tx_errors++;
+               dev->stats.tx_errors++;
                netif_start_queue(dev);
                return err;
        }
-       zd->stats.tx_packets++;
-       zd->stats.tx_bytes += skb->len;
+       dev->stats.tx_packets++;
+       dev->stats.tx_bytes += skb->len;
        dev->trans_start = jiffies;
        kfree_skb(skb);
 
@@ -838,7 +838,7 @@ static void zd1201_tx_timeout(struct net_device *dev)
        dev_warn(&zd->usb->dev, "%s: TX timeout, shooting down urb\n",
            dev->name);
        usb_unlink_urb(zd->tx_urb);
-       zd->stats.tx_errors++;
+       dev->stats.tx_errors++;
        /* Restart the timeout to quiet the watchdog: */
        dev->trans_start = jiffies;
 }
@@ -861,13 +861,6 @@ static int zd1201_set_mac_address(struct net_device *dev, void *p)
        return zd1201_mac_reset(zd);
 }
 
-static struct net_device_stats *zd1201_get_stats(struct net_device *dev)
-{
-       struct zd1201 *zd = netdev_priv(dev);
-
-       return &zd->stats;
-}
-
 static struct iw_statistics *zd1201_get_wireless_stats(struct net_device *dev)
 {
        struct zd1201 *zd = netdev_priv(dev);
@@ -1724,6 +1717,18 @@ static const struct iw_handler_def zd1201_iw_handlers = {
        .get_wireless_stats     = zd1201_get_wireless_stats,
 };
 
+static const struct net_device_ops zd1201_netdev_ops = {
+       .ndo_open               = zd1201_net_open,
+       .ndo_stop               = zd1201_net_stop,
+       .ndo_start_xmit         = zd1201_hard_start_xmit,
+       .ndo_tx_timeout         = zd1201_tx_timeout,
+       .ndo_set_multicast_list = zd1201_set_multicast,
+       .ndo_set_mac_address    = zd1201_set_mac_address,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_set_mac_address    = eth_mac_addr,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 static int zd1201_probe(struct usb_interface *interface,
                        const struct usb_device_id *id)
 {
@@ -1776,16 +1781,9 @@ static int zd1201_probe(struct usb_interface *interface,
        if (err)
                goto err_start;
 
-       dev->open = zd1201_net_open;
-       dev->stop = zd1201_net_stop;
-       dev->get_stats = zd1201_get_stats;
-       dev->wireless_handlers =
-           (struct iw_handler_def *)&zd1201_iw_handlers;
-       dev->hard_start_xmit = zd1201_hard_start_xmit;
+       dev->netdev_ops = &zd1201_netdev_ops;
+       dev->wireless_handlers = &zd1201_iw_handlers;
        dev->watchdog_timeo = ZD1201_TX_TIMEOUT;
-       dev->tx_timeout = zd1201_tx_timeout;
-       dev->set_multicast_list = zd1201_set_multicast;
-       dev->set_mac_address = zd1201_set_mac_address;
        strcpy(dev->name, "wlan%d");
 
        err = zd1201_getconfig(zd, ZD1201_RID_CNFOWNMACADDR, 
index 235f0ee34b24d56d45282ea6e6eacb186594f87e..dd7ea1f35bef83d00d0fa18c91f6947ab02b1ab8 100644 (file)
@@ -26,7 +26,6 @@ struct zd1201 {
        struct usb_device       *usb;
        int                     removed;
        struct net_device       *dev;
-       struct net_device_stats stats;
        struct iw_statistics    iwstats;
 
        int                     endp_in;
index f1519143f8a65e80fca00501be81e5fd456cec73..2c813d87092c0b1c60846f12af4433bd6a03da68 100644 (file)
@@ -1616,3 +1616,24 @@ int zd_chip_set_multicast_hash(struct zd_chip *chip,
 
        return zd_iowrite32a(chip, ioreqs, ARRAY_SIZE(ioreqs));
 }
+
+u64 zd_chip_get_tsf(struct zd_chip *chip)
+{
+       int r;
+       static const zd_addr_t aw_pt_bi_addr[] =
+               { CR_TSF_LOW_PART, CR_TSF_HIGH_PART };
+       u32 values[2];
+       u64 tsf;
+
+       mutex_lock(&chip->mutex);
+       r = zd_ioread32v_locked(chip, values, (const zd_addr_t *)aw_pt_bi_addr,
+                               ARRAY_SIZE(aw_pt_bi_addr));
+       mutex_unlock(&chip->mutex);
+       if (r)
+               return 0;
+
+       tsf = values[1];
+       tsf = (tsf << 32) | values[0];
+
+       return tsf;
+}
index f8c061a9b6ecd2f181b938ee7f14a5deaa45956b..ee42751d5cb02039e3b226e97556288fa625b243 100644 (file)
@@ -950,4 +950,6 @@ static inline void zd_mc_add_addr(struct zd_mc_hash *hash, u8 *addr)
 int zd_chip_set_multicast_hash(struct zd_chip *chip,
                               struct zd_mc_hash *hash);
 
+u64 zd_chip_get_tsf(struct zd_chip *chip);
+
 #endif /* _ZD_CHIP_H */
index 7579af27edbd6e6d639ac2644267fb9333299b4f..c3a51266de209c7ad6c47e559f54612ee5dc6d2e 100644 (file)
@@ -170,10 +170,10 @@ int zd_mac_init_hw(struct ieee80211_hw *hw)
                goto disable_int;
 
        r = zd_reg2alpha2(mac->regdomain, alpha2);
-       if (!r)
-               regulatory_hint(hw->wiphy, alpha2);
+       if (r)
+               goto disable_int;
 
-       r = 0;
+       r = regulatory_hint(hw->wiphy, alpha2);
 disable_int:
        zd_chip_disable_int(chip);
 out:
@@ -575,13 +575,17 @@ static int zd_op_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
 
        r = fill_ctrlset(mac, skb);
        if (r)
-               return r;
+               goto fail;
 
        info->rate_driver_data[0] = hw;
 
        r = zd_usb_tx(&mac->chip.usb, skb);
        if (r)
-               return r;
+               goto fail;
+       return 0;
+
+fail:
+       dev_kfree_skb(skb);
        return 0;
 }
 
@@ -935,6 +939,12 @@ static void zd_op_bss_info_changed(struct ieee80211_hw *hw,
        }
 }
 
+static u64 zd_op_get_tsf(struct ieee80211_hw *hw)
+{
+       struct zd_mac *mac = zd_hw_mac(hw);
+       return zd_chip_get_tsf(&mac->chip);
+}
+
 static const struct ieee80211_ops zd_ops = {
        .tx                     = zd_op_tx,
        .start                  = zd_op_start,
@@ -945,6 +955,7 @@ static const struct ieee80211_ops zd_ops = {
        .config_interface       = zd_op_config_interface,
        .configure_filter       = zd_op_configure_filter,
        .bss_info_changed       = zd_op_bss_info_changed,
+       .get_tsf                = zd_op_get_tsf,
 };
 
 struct ieee80211_hw *zd_mac_alloc_hw(struct usb_interface *intf)
index 2f1645dcb8c81e3a8bbd91a792f97f2619135a79..7477ffdcddb45923e0b74cda2fbd8a876c84c94d 100644 (file)
@@ -107,9 +107,9 @@ static int gx_fix;
 #include <asm/io.h>
 
 /* These identify the driver base version and may not be removed. */
-static char version[] __devinitdata =
-KERN_INFO DRV_NAME ".c:v1.05  1/09/2001  Written by Donald Becker <becker@scyld.com>\n"
-KERN_INFO "  (unofficial 2.4.x port, " DRV_VERSION ", " DRV_RELDATE ")\n";
+static const char version[] __devinitconst =
+  KERN_INFO DRV_NAME ".c:v1.05  1/09/2001  Written by Donald Becker <becker@scyld.com>\n"
+  KERN_INFO "  (unofficial 2.4.x port, " DRV_VERSION ", " DRV_RELDATE ")\n";
 
 MODULE_AUTHOR("Donald Becker <becker@scyld.com>");
 MODULE_DESCRIPTION("Packet Engines Yellowfin G-NIC Gigabit Ethernet driver");
index ad4cdd25613771f60857d4900a77d15f81c454a5..0b28fccec03f4a43ff09811a90db88b5b22bd8a4 100644 (file)
@@ -84,7 +84,7 @@ parport_atari_frob_control(struct parport *p, unsigned char mask,
 static unsigned char
 parport_atari_read_status(struct parport *p)
 {
-       return ((mfp.par_dt_reg & 1 ? 0 : PARPORT_STATUS_BUSY) |
+       return ((st_mfp.par_dt_reg & 1 ? 0 : PARPORT_STATUS_BUSY) |
                PARPORT_STATUS_SELECT | PARPORT_STATUS_ERROR);
 }
 
@@ -193,9 +193,9 @@ static int __init parport_atari_init(void)
                sound_ym.wd_data = sound_ym.rd_data_reg_sel | (1 << 5);
                local_irq_restore(flags);
                /* MFP port I0 as input. */
-               mfp.data_dir &= ~1;
+               st_mfp.data_dir &= ~1;
                /* MFP port I0 interrupt on high->low edge. */
-               mfp.active_edge &= ~1;
+               st_mfp.active_edge &= ~1;
                p = parport_register_port((unsigned long)&sound_ym.wd_data,
                                          IRQ_MFP_BUSY, PARPORT_DMA_NONE,
                                          &parport_atari_ops);
index f5a662a50acb12edea158dc114002cf1be33a418..26c536b51c5acd80d5f4915bb4980a666bed06b5 100644 (file)
@@ -330,6 +330,14 @@ parse_dmar_table(void)
        entry_header = (struct acpi_dmar_header *)(dmar + 1);
        while (((unsigned long)entry_header) <
                        (((unsigned long)dmar) + dmar_tbl->length)) {
+               /* Avoid looping forever on bad ACPI tables */
+               if (entry_header->length == 0) {
+                       printk(KERN_WARNING PREFIX
+                               "Invalid 0-length structure\n");
+                       ret = -EINVAL;
+                       break;
+               }
+
                dmar_table_print_dmar_entry(entry_header);
 
                switch (entry_header->type) {
@@ -491,7 +499,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
        int map_size;
        u32 ver;
        static int iommu_allocated = 0;
-       int agaw;
+       int agaw = 0;
 
        iommu = kzalloc(sizeof(*iommu), GFP_KERNEL);
        if (!iommu)
@@ -507,6 +515,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
        iommu->cap = dmar_readq(iommu->reg + DMAR_CAP_REG);
        iommu->ecap = dmar_readq(iommu->reg + DMAR_ECAP_REG);
 
+#ifdef CONFIG_DMAR
        agaw = iommu_calculate_agaw(iommu);
        if (agaw < 0) {
                printk(KERN_ERR
@@ -514,6 +523,7 @@ int alloc_iommu(struct dmar_drhd_unit *drhd)
                        iommu->seq_id);
                goto error;
        }
+#endif
        iommu->agaw = agaw;
 
        /* the registers might be more than one page */
@@ -571,19 +581,49 @@ static inline void reclaim_free_desc(struct q_inval *qi)
        }
 }
 
+static int qi_check_fault(struct intel_iommu *iommu, int index)
+{
+       u32 fault;
+       int head;
+       struct q_inval *qi = iommu->qi;
+       int wait_index = (index + 1) % QI_LENGTH;
+
+       fault = readl(iommu->reg + DMAR_FSTS_REG);
+
+       /*
+        * If IQE happens, the head points to the descriptor associated
+        * with the error. No new descriptors are fetched until the IQE
+        * is cleared.
+        */
+       if (fault & DMA_FSTS_IQE) {
+               head = readl(iommu->reg + DMAR_IQH_REG);
+               if ((head >> 4) == index) {
+                       memcpy(&qi->desc[index], &qi->desc[wait_index],
+                                       sizeof(struct qi_desc));
+                       __iommu_flush_cache(iommu, &qi->desc[index],
+                                       sizeof(struct qi_desc));
+                       writel(DMA_FSTS_IQE, iommu->reg + DMAR_FSTS_REG);
+                       return -EINVAL;
+               }
+       }
+
+       return 0;
+}
+
 /*
  * Submit the queued invalidation descriptor to the remapping
  * hardware unit and wait for its completion.
  */
-void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
+int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
 {
+       int rc = 0;
        struct q_inval *qi = iommu->qi;
        struct qi_desc *hw, wait_desc;
        int wait_index, index;
        unsigned long flags;
 
        if (!qi)
-               return;
+               return 0;
 
        hw = qi->desc;
 
@@ -601,7 +641,8 @@ void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
 
        hw[index] = *desc;
 
-       wait_desc.low = QI_IWD_STATUS_DATA(2) | QI_IWD_STATUS_WRITE | QI_IWD_TYPE;
+       wait_desc.low = QI_IWD_STATUS_DATA(QI_DONE) |
+                       QI_IWD_STATUS_WRITE | QI_IWD_TYPE;
        wait_desc.high = virt_to_phys(&qi->desc_status[wait_index]);
 
        hw[wait_index] = wait_desc;
@@ -612,13 +653,11 @@ void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
        qi->free_head = (qi->free_head + 2) % QI_LENGTH;
        qi->free_cnt -= 2;
 
-       spin_lock(&iommu->register_lock);
        /*
         * update the HW tail register indicating the presence of
         * new descriptors.
         */
        writel(qi->free_head << 4, iommu->reg + DMAR_IQT_REG);
-       spin_unlock(&iommu->register_lock);
 
        while (qi->desc_status[wait_index] != QI_DONE) {
                /*
@@ -628,15 +667,21 @@ void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu)
                 * a deadlock where the interrupt context can wait indefinitely
                 * for free slots in the queue.
                 */
+               rc = qi_check_fault(iommu, index);
+               if (rc)
+                       goto out;
+
                spin_unlock(&qi->q_lock);
                cpu_relax();
                spin_lock(&qi->q_lock);
        }
-
-       qi->desc_status[index] = QI_DONE;
+out:
+       qi->desc_status[index] = qi->desc_status[wait_index] = QI_DONE;
 
        reclaim_free_desc(qi);
        spin_unlock_irqrestore(&qi->q_lock, flags);
+
+       return rc;
 }
 
 /*
@@ -649,13 +694,13 @@ void qi_global_iec(struct intel_iommu *iommu)
        desc.low = QI_IEC_TYPE;
        desc.high = 0;
 
+       /* should never fail */
        qi_submit_sync(&desc, iommu);
 }
 
 int qi_flush_context(struct intel_iommu *iommu, u16 did, u16 sid, u8 fm,
                     u64 type, int non_present_entry_flush)
 {
-
        struct qi_desc desc;
 
        if (non_present_entry_flush) {
@@ -669,10 +714,7 @@ int qi_flush_context(struct intel_iommu *iommu, u16 did, u16 sid, u8 fm,
                        | QI_CC_GRAN(type) | QI_CC_TYPE;
        desc.high = 0;
 
-       qi_submit_sync(&desc, iommu);
-
-       return 0;
-
+       return qi_submit_sync(&desc, iommu);
 }
 
 int qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr,
@@ -702,10 +744,7 @@ int qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr,
        desc.high = QI_IOTLB_ADDR(addr) | QI_IOTLB_IH(ih)
                | QI_IOTLB_AM(size_order);
 
-       qi_submit_sync(&desc, iommu);
-
-       return 0;
-
+       return qi_submit_sync(&desc, iommu);
 }
 
 /*
index db85284ffb621a98d93252f8c6d6069aa43fb006..39ae37589fda7f6106d845148d1175b4a927b1df 100644 (file)
@@ -111,6 +111,7 @@ struct controller {
        int cmd_busy;
        unsigned int no_cmd_complete:1;
        unsigned int link_active_reporting:1;
+       unsigned int notification_enabled:1;
 };
 
 #define INT_BUTTON_IGNORE              0
@@ -170,6 +171,7 @@ extern int pciehp_configure_device(struct slot *p_slot);
 extern int pciehp_unconfigure_device(struct slot *p_slot);
 extern void pciehp_queue_pushbutton_work(struct work_struct *work);
 struct controller *pcie_init(struct pcie_device *dev);
+int pcie_init_notification(struct controller *ctrl);
 int pciehp_enable_slot(struct slot *p_slot);
 int pciehp_disable_slot(struct slot *p_slot);
 int pcie_enable_notification(struct controller *ctrl);
index c2485542f54356f01c016e83c082e96e3866b62c..681e3912b821a4dce3f5ee11844b73cf6e8b316d 100644 (file)
@@ -434,6 +434,13 @@ static int pciehp_probe(struct pcie_device *dev, const struct pcie_port_service_
                goto err_out_release_ctlr;
        }
 
+       /* Enable events after we have setup the data structures */
+       rc = pcie_init_notification(ctrl);
+       if (rc) {
+               ctrl_err(ctrl, "Notification initialization failed\n");
+               goto err_out_release_ctlr;
+       }
+
        /* Check if slot is occupied */
        t_slot = pciehp_find_slot(ctrl, ctrl->slot_device_offset);
        t_slot->hpc_ops->get_adapter_status(t_slot, &value);
index 71a8012886b0f0705dcd6cfb27827720ce006cf4..7a16c6897bb92698abc8edfb9af1d909f235453d 100644 (file)
@@ -934,7 +934,7 @@ static void pcie_disable_notification(struct controller *ctrl)
                ctrl_warn(ctrl, "Cannot disable software notification\n");
 }
 
-static int pcie_init_notification(struct controller *ctrl)
+int pcie_init_notification(struct controller *ctrl)
 {
        if (pciehp_request_irq(ctrl))
                return -1;
@@ -942,13 +942,17 @@ static int pcie_init_notification(struct controller *ctrl)
                pciehp_free_irq(ctrl);
                return -1;
        }
+       ctrl->notification_enabled = 1;
        return 0;
 }
 
 static void pcie_shutdown_notification(struct controller *ctrl)
 {
-       pcie_disable_notification(ctrl);
-       pciehp_free_irq(ctrl);
+       if (ctrl->notification_enabled) {
+               pcie_disable_notification(ctrl);
+               pciehp_free_irq(ctrl);
+               ctrl->notification_enabled = 0;
+       }
 }
 
 static int pcie_init_slot(struct controller *ctrl)
@@ -1110,13 +1114,8 @@ struct controller *pcie_init(struct pcie_device *dev)
        if (pcie_init_slot(ctrl))
                goto abort_ctrl;
 
-       if (pcie_init_notification(ctrl))
-               goto abort_slot;
-
        return ctrl;
 
-abort_slot:
-       pcie_cleanup_slot(ctrl);
 abort_ctrl:
        kfree(ctrl);
 abort:
index f4b7c79023ffe7d05589dd93526531ea3dc3708f..f3f686581a9026685dc3e6c994b00e88ed88486c 100644 (file)
@@ -61,6 +61,8 @@
 /* global iommu list, set NULL for ignored DMAR units */
 static struct intel_iommu **g_iommus;
 
+static int rwbf_quirk;
+
 /*
  * 0: Present
  * 1-11: Reserved
@@ -785,7 +787,7 @@ static void iommu_flush_write_buffer(struct intel_iommu *iommu)
        u32 val;
        unsigned long flag;
 
-       if (!cap_rwbf(iommu->cap))
+       if (!rwbf_quirk && !cap_rwbf(iommu->cap))
                return;
        val = iommu->gcmd | DMA_GCMD_WBF;
 
@@ -3137,3 +3139,15 @@ static struct iommu_ops intel_iommu_ops = {
        .unmap          = intel_iommu_unmap_range,
        .iova_to_phys   = intel_iommu_iova_to_phys,
 };
+
+static void __devinit quirk_iommu_rwbf(struct pci_dev *dev)
+{
+       /*
+        * Mobile 4 Series Chipset neglects to set RWBF capability,
+        * but needs it:
+        */
+       printk(KERN_INFO "DMAR: Forcing write-buffer flush capability\n");
+       rwbf_quirk = 1;
+}
+
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_INTEL, 0x2a40, quirk_iommu_rwbf);
index f78371b2252976efb8ab86c7eaf87a7240949ea5..45effc5726c0f63a55862c85eaa6d9cb4a38c706 100644 (file)
@@ -207,7 +207,7 @@ int alloc_irte(struct intel_iommu *iommu, int irq, u16 count)
        return index;
 }
 
-static void qi_flush_iec(struct intel_iommu *iommu, int index, int mask)
+static int qi_flush_iec(struct intel_iommu *iommu, int index, int mask)
 {
        struct qi_desc desc;
 
@@ -215,7 +215,7 @@ static void qi_flush_iec(struct intel_iommu *iommu, int index, int mask)
                   | QI_IEC_SELECTIVE;
        desc.high = 0;
 
-       qi_submit_sync(&desc, iommu);
+       return qi_submit_sync(&desc, iommu);
 }
 
 int map_irq_to_irte_handle(int irq, u16 *sub_handle)
@@ -283,6 +283,7 @@ int clear_irte_irq(int irq, struct intel_iommu *iommu, u16 index)
 
 int modify_irte(int irq, struct irte *irte_modified)
 {
+       int rc;
        int index;
        struct irte *irte;
        struct intel_iommu *iommu;
@@ -303,14 +304,15 @@ int modify_irte(int irq, struct irte *irte_modified)
        set_64bit((unsigned long *)irte, irte_modified->low | (1 << 1));
        __iommu_flush_cache(iommu, irte, sizeof(*irte));
 
-       qi_flush_iec(iommu, index, 0);
-
+       rc = qi_flush_iec(iommu, index, 0);
        spin_unlock(&irq_2_ir_lock);
-       return 0;
+
+       return rc;
 }
 
 int flush_irte(int irq)
 {
+       int rc;
        int index;
        struct intel_iommu *iommu;
        struct irq_2_iommu *irq_iommu;
@@ -326,10 +328,10 @@ int flush_irte(int irq)
 
        index = irq_iommu->irte_index + irq_iommu->sub_handle;
 
-       qi_flush_iec(iommu, index, irq_iommu->irte_mask);
+       rc = qi_flush_iec(iommu, index, irq_iommu->irte_mask);
        spin_unlock(&irq_2_ir_lock);
 
-       return 0;
+       return rc;
 }
 
 struct intel_iommu *map_ioapic_to_ir(int apic)
@@ -355,6 +357,7 @@ struct intel_iommu *map_dev_to_ir(struct pci_dev *dev)
 
 int free_irte(int irq)
 {
+       int rc = 0;
        int index, i;
        struct irte *irte;
        struct intel_iommu *iommu;
@@ -375,7 +378,7 @@ int free_irte(int irq)
        if (!irq_iommu->sub_handle) {
                for (i = 0; i < (1 << irq_iommu->irte_mask); i++)
                        set_64bit((unsigned long *)irte, 0);
-               qi_flush_iec(iommu, index, irq_iommu->irte_mask);
+               rc = qi_flush_iec(iommu, index, irq_iommu->irte_mask);
        }
 
        irq_iommu->iommu = NULL;
@@ -385,7 +388,7 @@ int free_irte(int irq)
 
        spin_unlock(&irq_2_ir_lock);
 
-       return 0;
+       return rc;
 }
 
 static void iommu_set_intr_remapping(struct intel_iommu *iommu, int mode)
index 44f15ff70c1d4f5f6c135d68367cbfb57b31783e..baba2eb5367df54bcc947333beda7e56332f3785 100644 (file)
@@ -103,14 +103,12 @@ static void msix_set_enable(struct pci_dev *dev, int enable)
        }
 }
 
-/*
- * Essentially, this is ((1 << (1 << x)) - 1), but without the
- * undefinedness of a << 32.
- */
 static inline __attribute_const__ u32 msi_mask(unsigned x)
 {
-       static const u32 mask[] = { 1, 2, 4, 0xf, 0xff, 0xffff, 0xffffffff };
-       return mask[x];
+       /* Don't shift by >= width of type */
+       if (x >= 5)
+               return 0xffffffff;
+       return (1 << (1 << x)) - 1;
 }
 
 static void msix_flush_writes(struct irq_desc *desc)
index e3efe6b19ee79210e2885f03b1d21995e2125abb..6d6120007af4ed01d5fdc39331bff59349b1ed00 100644 (file)
@@ -1540,16 +1540,21 @@ void pci_release_region(struct pci_dev *pdev, int bar)
 }
 
 /**
- *     pci_request_region - Reserved PCI I/O and memory resource
+ *     __pci_request_region - Reserved PCI I/O and memory resource
  *     @pdev: PCI device whose resources are to be reserved
  *     @bar: BAR to be reserved
  *     @res_name: Name to be associated with resource.
+ *     @exclusive: whether the region access is exclusive or not
  *
  *     Mark the PCI region associated with PCI device @pdev BR @bar as
  *     being reserved by owner @res_name.  Do not access any
  *     address inside the PCI regions unless this call returns
  *     successfully.
  *
+ *     If @exclusive is set, then the region is marked so that userspace
+ *     is explicitly not allowed to map the resource via /dev/mem or
+ *     sysfs MMIO access.
+ *
  *     Returns 0 on success, or %EBUSY on error.  A warning
  *     message is also printed on failure.
  */
@@ -1588,12 +1593,12 @@ err_out:
 }
 
 /**
- *     pci_request_region - Reserved PCI I/O and memory resource
+ *     pci_request_region - Reserve PCI I/O and memory resource
  *     @pdev: PCI device whose resources are to be reserved
  *     @bar: BAR to be reserved
- *     @res_name: Name to be associated with resource.
+ *     @res_name: Name to be associated with resource
  *
- *     Mark the PCI region associated with PCI device @pdev BR @bar as
+ *     Mark the PCI region associated with PCI device @pdev BAR @bar as
  *     being reserved by owner @res_name.  Do not access any
  *     address inside the PCI regions unless this call returns
  *     successfully.
index 26ddf78ac30049ddb3fd0203828519689dfc886b..07c0aa5275e6edf33ab1914761d6acb3113f1741 100644 (file)
@@ -16,21 +16,21 @@ extern int pci_mmap_fits(struct pci_dev *pdev, int resno,
 #endif
 
 /**
- * Firmware PM callbacks
+ * struct pci_platform_pm_ops - Firmware PM callbacks
  *
- * @is_manageable - returns 'true' if given device is power manageable by the
- *                  platform firmware
+ * @is_manageable: returns 'true' if given device is power manageable by the
+ *                 platform firmware
  *
- * @set_state - invokes the platform firmware to set the device's power state
+ * @set_state: invokes the platform firmware to set the device's power state
  *
- * @choose_state - returns PCI power state of given device preferred by the
- *                 platform; to be used during system-wide transitions from a
- *                 sleeping state to the working state and vice versa
+ * @choose_state: returns PCI power state of given device preferred by the
+ *                platform; to be used during system-wide transitions from a
+ *                sleeping state to the working state and vice versa
  *
- * @can_wakeup - returns 'true' if given device is capable of waking up the
- *               system from a sleeping state
+ * @can_wakeup: returns 'true' if given device is capable of waking up the
+ *              system from a sleeping state
  *
- * @sleep_wake - enables/disables the system wake up capability of given device
+ * @sleep_wake: enables/disables the system wake up capability of given device
  *
  * If given platform is generally capable of power managing PCI devices, all of
  * these callbacks are mandatory.
index aac7006949f15c9eb52b56968a4dca6ef812e3c2..d0c9736858689f62f19dc6fd85572dacc3c2d3ec 100644 (file)
@@ -108,6 +108,34 @@ int pci_cleanup_aer_correct_error_status(struct pci_dev *dev)
 }
 #endif  /*  0  */
 
+
+static void set_device_error_reporting(struct pci_dev *dev, void *data)
+{
+       bool enable = *((bool *)data);
+
+       if (dev->pcie_type != PCIE_RC_PORT &&
+           dev->pcie_type != PCIE_SW_UPSTREAM_PORT &&
+           dev->pcie_type != PCIE_SW_DOWNSTREAM_PORT)
+               return;
+
+       if (enable)
+               pci_enable_pcie_error_reporting(dev);
+       else
+               pci_disable_pcie_error_reporting(dev);
+}
+
+/**
+ * set_downstream_devices_error_reporting - enable/disable the error reporting  bits on the root port and its downstream ports.
+ * @dev: pointer to root port's pci_dev data structure
+ * @enable: true = enable error reporting, false = disable error reporting.
+ */
+static void set_downstream_devices_error_reporting(struct pci_dev *dev,
+                                                  bool enable)
+{
+       set_device_error_reporting(dev, &enable);
+       pci_walk_bus(dev->subordinate, set_device_error_reporting, &enable);
+}
+
 static int find_device_iter(struct device *device, void *data)
 {
        struct pci_dev *dev;
@@ -525,15 +553,11 @@ void aer_enable_rootport(struct aer_rpc *rpc)
        pci_read_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, &reg32);
        pci_write_config_dword(pdev, aer_pos + PCI_ERR_UNCOR_STATUS, reg32);
 
-       /* Enable Root Port device reporting error itself */
-       pci_read_config_word(pdev, pos+PCI_EXP_DEVCTL, &reg16);
-       reg16 = reg16 |
-               PCI_EXP_DEVCTL_CERE |
-               PCI_EXP_DEVCTL_NFERE |
-               PCI_EXP_DEVCTL_FERE |
-               PCI_EXP_DEVCTL_URRE;
-       pci_write_config_word(pdev, pos+PCI_EXP_DEVCTL,
-               reg16);
+       /*
+        * Enable error reporting for the root port device and downstream port
+        * devices.
+        */
+       set_downstream_devices_error_reporting(pdev, true);
 
        /* Enable Root Port's interrupt in response to error messages */
        pci_write_config_dword(pdev,
@@ -553,6 +577,12 @@ static void disable_root_aer(struct aer_rpc *rpc)
        u32 reg32;
        int pos;
 
+       /*
+        * Disable error reporting for the root port device and downstream port
+        * devices.
+        */
+       set_downstream_devices_error_reporting(pdev, false);
+
        pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_ERR);
        /* Disable Root's interrupt in response to error messages */
        pci_write_config_dword(pdev, pos + PCI_ERR_ROOT_COMMAND, 0);
index f9b874eaeb9f80daea9f7eff884574cf7f749008..248b4db915526e5819c7050737f4467456aeda9f 100644 (file)
@@ -97,8 +97,6 @@ static int __devinit pcie_portdrv_probe (struct pci_dev *dev,
 
        pcie_portdrv_save_config(dev);
 
-       pci_enable_pcie_error_reporting(dev);
-
        return 0;
 }
 
index baad093aafe3c75088c6a1f19d28d826dd5a63de..f20d55368edb7edfb5d0a6bc9ef1a8746da6b8cb 100644 (file)
@@ -1584,6 +1584,7 @@ DECLARE_PCI_FIXUP_RESUME(PCI_VENDOR_ID_SERVERWORKS,   PCI_DEVICE_ID_SERVERWORKS_
  */
 #define AMD_813X_MISC                  0x40
 #define AMD_813X_NOIOAMODE             (1<<0)
+#define AMD_813X_REV_B2                        0x13
 
 static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev)
 {
@@ -1591,6 +1592,8 @@ static void quirk_disable_amd_813x_boot_interrupt(struct pci_dev *dev)
 
        if (noioapicquirk)
                return;
+       if (dev->revision == AMD_813X_REV_B2)
+               return;
 
        pci_read_config_dword(dev, AMD_813X_MISC, &pci_config_dword);
        pci_config_dword &= ~AMD_813X_NOIOAMODE;
@@ -1981,7 +1984,6 @@ static void __devinit quirk_msi_ht_cap(struct pci_dev *dev)
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT2000_PCIE,
                        quirk_msi_ht_cap);
 
-
 /* The nVidia CK804 chipset may have 2 HT MSI mappings.
  * MSI are supported if the MSI capability set in any of these mappings.
  */
@@ -2032,6 +2034,9 @@ DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_SERVERWORKS,
                         PCI_DEVICE_ID_SERVERWORKS_HT1000_PXB,
                         ht_enable_msi_mapping);
 
+DECLARE_PCI_FIXUP_HEADER(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_8132_BRIDGE,
+                        ht_enable_msi_mapping);
+
 /* The P5N32-SLI Premium motherboard from Asus has a problem with msi
  * for the MCP55 NIC. It is not yet determined whether the msi problem
  * also affects other devices. As for now, turn off msi for this device.
@@ -2048,10 +2053,100 @@ DECLARE_PCI_FIXUP_EARLY(PCI_VENDOR_ID_NVIDIA,
                        PCI_DEVICE_ID_NVIDIA_NVENET_15,
                        nvenet_msi_disable);
 
-static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
+static void __devinit nv_ht_enable_msi_mapping(struct pci_dev *dev)
 {
        struct pci_dev *host_bridge;
+       int pos;
+       int i, dev_no;
+       int found = 0;
+
+       dev_no = dev->devfn >> 3;
+       for (i = dev_no; i >= 0; i--) {
+               host_bridge = pci_get_slot(dev->bus, PCI_DEVFN(i, 0));
+               if (!host_bridge)
+                       continue;
+
+               pos = pci_find_ht_capability(host_bridge, HT_CAPTYPE_SLAVE);
+               if (pos != 0) {
+                       found = 1;
+                       break;
+               }
+               pci_dev_put(host_bridge);
+       }
+
+       if (!found)
+               return;
+
+       /* root did that ! */
+       if (msi_ht_cap_enabled(host_bridge))
+               goto out;
+
+       ht_enable_msi_mapping(dev);
+
+out:
+       pci_dev_put(host_bridge);
+}
+
+static void __devinit ht_disable_msi_mapping(struct pci_dev *dev)
+{
+       int pos, ttl = 48;
+
+       pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
+       while (pos && ttl--) {
+               u8 flags;
+
+               if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
+                                        &flags) == 0) {
+                       dev_info(&dev->dev, "Enabling HT MSI Mapping\n");
+
+                       pci_write_config_byte(dev, pos + HT_MSI_FLAGS,
+                                             flags & ~HT_MSI_FLAGS_ENABLE);
+               }
+               pos = pci_find_next_ht_capability(dev, pos,
+                                                 HT_CAPTYPE_MSI_MAPPING);
+       }
+}
+
+static int __devinit ht_check_msi_mapping(struct pci_dev *dev)
+{
        int pos, ttl = 48;
+       int found = 0;
+
+       /* check if there is HT MSI cap or enabled on this device */
+       pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
+       while (pos && ttl--) {
+               u8 flags;
+
+               if (found < 1)
+                       found = 1;
+               if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
+                                        &flags) == 0) {
+                       if (flags & HT_MSI_FLAGS_ENABLE) {
+                               if (found < 2) {
+                                       found = 2;
+                                       break;
+                               }
+                       }
+               }
+               pos = pci_find_next_ht_capability(dev, pos,
+                                                 HT_CAPTYPE_MSI_MAPPING);
+       }
+
+       return found;
+}
+
+static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
+{
+       struct pci_dev *host_bridge;
+       int pos;
+       int found;
+
+       /* check if there is HT MSI cap or enabled on this device */
+       found = ht_check_msi_mapping(dev);
+
+       /* no HT MSI CAP */
+       if (found == 0)
+               return;
 
        /*
         * HT MSI mapping should be disabled on devices that are below
@@ -2067,24 +2162,19 @@ static void __devinit nv_msi_ht_cap_quirk(struct pci_dev *dev)
        pos = pci_find_ht_capability(host_bridge, HT_CAPTYPE_SLAVE);
        if (pos != 0) {
                /* Host bridge is to HT */
-               ht_enable_msi_mapping(dev);
+               if (found == 1) {
+                       /* it is not enabled, try to enable it */
+                       nv_ht_enable_msi_mapping(dev);
+               }
                return;
        }
 
-       /* Host bridge is not to HT, disable HT MSI mapping on this device */
-       pos = pci_find_ht_capability(dev, HT_CAPTYPE_MSI_MAPPING);
-       while (pos && ttl--) {
-               u8 flags;
+       /* HT MSI is not enabled */
+       if (found == 1)
+               return;
 
-               if (pci_read_config_byte(dev, pos + HT_MSI_FLAGS,
-                                        &flags) == 0) {
-                       dev_info(&dev->dev, "Disabling HT MSI mapping");
-                       pci_write_config_byte(dev, pos + HT_MSI_FLAGS,
-                                             flags & ~HT_MSI_FLAGS_ENABLE);
-               }
-               pos = pci_find_next_ht_capability(dev, pos,
-                                                 HT_CAPTYPE_MSI_MAPPING);
-       }
+       /* Host bridge is not to HT, disable HT MSI mapping on this device */
+       ht_disable_msi_mapping(dev);
 }
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_NVIDIA, PCI_ANY_ID, nv_msi_ht_cap_quirk);
 DECLARE_PCI_FIXUP_FINAL(PCI_VENDOR_ID_AL, PCI_ANY_ID, nv_msi_ht_cap_quirk);
index 29cbe47f219f8c39f2b3f66490a272f339b1f9d5..36864a935d687bb732f9c09b45f2c647d6dca54c 100644 (file)
@@ -55,6 +55,7 @@ void pci_disable_rom(struct pci_dev *pdev)
 
 /**
  * pci_get_rom_size - obtain the actual size of the ROM image
+ * @pdev: target PCI device
  * @rom: kernel virtual pointer to image of ROM
  * @size: size of PCI window
  *  return: size of actual ROM image
index 94363115a42a69502d8ddd3f029984fd62aa07b6..b3866ad502273bc23545305745863e800336b87a 100644 (file)
@@ -62,6 +62,7 @@ config DELL_LAPTOP
        depends on EXPERIMENTAL
        depends on BACKLIGHT_CLASS_DEVICE
        depends on RFKILL
+       depends on POWER_SUPPLY
        default n
        ---help---
        This driver adds support for rfkill and backlight control to Dell
@@ -301,6 +302,7 @@ config INTEL_MENLOW
 config EEEPC_LAPTOP
        tristate "Eee PC Hotkey Driver (EXPERIMENTAL)"
        depends on ACPI
+       depends on INPUT
        depends on EXPERIMENTAL
        select BACKLIGHT_CLASS_DEVICE
        select HWMON
index 65dc41540c62bdbe72bd0a68f88c042a7f06fd12..45940f31fe9e57642b08bbdb4aa8dc45d8d5d798 100644 (file)
@@ -166,6 +166,7 @@ struct fujitsu_hotkey_t {
        struct platform_device *pf_device;
        struct kfifo *fifo;
        spinlock_t fifo_lock;
+       int rfkill_supported;
        int rfkill_state;
        int logolamp_registered;
        int kblamps_registered;
@@ -526,7 +527,7 @@ static ssize_t
 show_lid_state(struct device *dev,
                        struct device_attribute *attr, char *buf)
 {
-       if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD)
+       if (!(fujitsu_hotkey->rfkill_supported & 0x100))
                return sprintf(buf, "unknown\n");
        if (fujitsu_hotkey->rfkill_state & 0x100)
                return sprintf(buf, "open\n");
@@ -538,7 +539,7 @@ static ssize_t
 show_dock_state(struct device *dev,
                        struct device_attribute *attr, char *buf)
 {
-       if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD)
+       if (!(fujitsu_hotkey->rfkill_supported & 0x200))
                return sprintf(buf, "unknown\n");
        if (fujitsu_hotkey->rfkill_state & 0x200)
                return sprintf(buf, "docked\n");
@@ -550,7 +551,7 @@ static ssize_t
 show_radios_state(struct device *dev,
                        struct device_attribute *attr, char *buf)
 {
-       if (fujitsu_hotkey->rfkill_state == UNSUPPORTED_CMD)
+       if (!(fujitsu_hotkey->rfkill_supported & 0x20))
                return sprintf(buf, "unknown\n");
        if (fujitsu_hotkey->rfkill_state & 0x20)
                return sprintf(buf, "on\n");
@@ -928,8 +929,17 @@ static int acpi_fujitsu_hotkey_add(struct acpi_device *device)
                ; /* No action, result is discarded */
        vdbg_printk(FUJLAPTOP_DBG_INFO, "Discarded %i ringbuffer entries\n", i);
 
-       fujitsu_hotkey->rfkill_state =
-               call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
+       fujitsu_hotkey->rfkill_supported =
+               call_fext_func(FUNC_RFKILL, 0x0, 0x0, 0x0);
+
+       /* Make sure our bitmask of supported functions is cleared if the
+          RFKILL function block is not implemented, like on the S7020. */
+       if (fujitsu_hotkey->rfkill_supported == UNSUPPORTED_CMD)
+               fujitsu_hotkey->rfkill_supported = 0;
+
+       if (fujitsu_hotkey->rfkill_supported)
+               fujitsu_hotkey->rfkill_state =
+                       call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
 
        /* Suspect this is a keymap of the application panel, print it */
        printk(KERN_INFO "fujitsu-laptop: BTNI: [0x%x]\n",
@@ -1005,8 +1015,9 @@ static void acpi_fujitsu_hotkey_notify(acpi_handle handle, u32 event,
 
        input = fujitsu_hotkey->input;
 
-       fujitsu_hotkey->rfkill_state =
-               call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
+       if (fujitsu_hotkey->rfkill_supported)
+               fujitsu_hotkey->rfkill_state =
+                       call_fext_func(FUNC_RFKILL, 0x4, 0x0, 0x0);
 
        switch (event) {
        case ACPI_FUJITSU_NOTIFY_CODE1:
index 1fd8f2193ed853b143cdd25d1792224c91f4f1b9..4377e93a43d7f97b7087ed5164967743337fc8a5 100644 (file)
@@ -280,8 +280,11 @@ sclp_dispatch_evbufs(struct sccb_header *sccb)
        rc = 0;
        for (offset = sizeof(struct sccb_header); offset < sccb->length;
             offset += evbuf->length) {
-               /* Search for event handler */
                evbuf = (struct evbuf_header *) ((addr_t) sccb + offset);
+               /* Check for malformed hardware response */
+               if (evbuf->length == 0)
+                       break;
+               /* Search for event handler */
                reg = NULL;
                list_for_each(l, &sclp_reg_list) {
                        reg = list_entry(l, struct sclp_register, list);
index 506390496416ea1163d12919042a6f0d0d34df34..77ab6e34a100b758bc3047888e78f1962a90146d 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/memory.h>
 #include <asm/chpid.h>
 #include <asm/sclp.h>
+#include <asm/setup.h>
 
 #include "sclp.h"
 
@@ -474,6 +475,10 @@ static void __init add_memory_merged(u16 rn)
                goto skip_add;
        if (start + size > VMEM_MAX_PHYS)
                size = VMEM_MAX_PHYS - start;
+       if (memory_end_set && (start >= memory_end))
+               goto skip_add;
+       if (memory_end_set && (start + size > memory_end))
+               size = memory_end - start;
        add_memory(0, start, size);
 skip_add:
        first_rn = rn;
index fde6e4c634e71878c79e4ae771781fc968663467..a7cf550b9cca0ba030f7b58a8c81ccc2ef954e41 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/list.h>
 #include <linux/netdevice.h>
 #include <linux/scatterlist.h>
+#include <linux/skbuff.h>
 #include <scsi/libiscsi_tcp.h>
 
 /* from cxgb3 LLD */
@@ -113,6 +114,26 @@ struct cxgb3i_endpoint {
        struct cxgb3i_conn *cconn;
 };
 
+/**
+ * struct cxgb3i_task_data - private iscsi task data
+ *
+ * @nr_frags:  # of coalesced page frags (from scsi sgl)
+ * @frags:     coalesced page frags (from scsi sgl)
+ * @skb:       tx pdu skb
+ * @offset:    data offset for the next pdu
+ * @count:     max. possible pdu payload
+ * @sgoffset:  offset to the first sg entry for a given offset
+ */
+#define MAX_PDU_FRAGS  ((ULP2_MAX_PDU_PAYLOAD + 512 - 1) / 512)
+struct cxgb3i_task_data {
+       unsigned short nr_frags;
+       skb_frag_t frags[MAX_PDU_FRAGS];
+       struct sk_buff *skb;
+       unsigned int offset;
+       unsigned int count;
+       unsigned int sgoffset;
+};
+
 int cxgb3i_iscsi_init(void);
 void cxgb3i_iscsi_cleanup(void);
 
index 08f3a09d92330863fa692263ecd556b0185285d3..a83d36e4926fc64b646e3d828f1a0d878304a66b 100644 (file)
@@ -639,10 +639,11 @@ static int ddp_init(struct t3cdev *tdev)
        write_unlock(&cxgb3i_ddp_rwlock);
 
        ddp_log_info("nppods %u (0x%x ~ 0x%x), bits %u, mask 0x%x,0x%x "
-                       "pkt %u,%u.\n",
+                       "pkt %u/%u, %u/%u.\n",
                        ppmax, ddp->llimit, ddp->ulimit, ddp->idx_bits,
                        ddp->idx_mask, ddp->rsvd_tag_mask,
-                       ddp->max_txsz, ddp->max_rxsz);
+                       ddp->max_txsz, uinfo.max_txsz,
+                       ddp->max_rxsz, uinfo.max_rxsz);
        return 0;
 
 free_ddp_map:
@@ -654,8 +655,8 @@ free_ddp_map:
  * cxgb3i_adapter_ddp_init - initialize the adapter's ddp resource
  * @tdev: t3cdev adapter
  * @tformat: tag format
- * @txsz: max tx pkt size, filled in by this func.
- * @rxsz: max rx pkt size, filled in by this func.
+ * @txsz: max tx pdu payload size, filled in by this func.
+ * @rxsz: max rx pdu payload size, filled in by this func.
  * initialize the ddp pagepod manager for a given adapter if needed and
  * setup the tag format for a given iscsi entity
  */
@@ -685,10 +686,12 @@ int cxgb3i_adapter_ddp_init(struct t3cdev *tdev,
                      tformat->sw_bits, tformat->rsvd_bits,
                      tformat->rsvd_shift, tformat->rsvd_mask);
 
-       *txsz = ddp->max_txsz;
-       *rxsz = ddp->max_rxsz;
-       ddp_log_info("ddp max pkt size: %u, %u.\n",
-                    ddp->max_txsz, ddp->max_rxsz);
+       *txsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,
+                       ddp->max_txsz - ISCSI_PDU_NONPAYLOAD_LEN);
+       *rxsz = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,
+                       ddp->max_rxsz - ISCSI_PDU_NONPAYLOAD_LEN);
+       ddp_log_info("max payload size: %u/%u, %u/%u.\n",
+                    *txsz, ddp->max_txsz, *rxsz, ddp->max_rxsz);
        return 0;
 }
 EXPORT_SYMBOL_GPL(cxgb3i_adapter_ddp_init);
index f675807cc48f1391413023eedd707727fbe64cea..3faae7831c838a97693e6f91d4fe77460c9f7b5b 100644 (file)
@@ -87,8 +87,9 @@ struct cxgb3i_ddp_info {
        struct sk_buff **gl_skb;
 };
 
+#define ISCSI_PDU_NONPAYLOAD_LEN       312 /* bhs(48) + ahs(256) + digest(8) */
 #define ULP2_MAX_PKT_SIZE      16224
-#define ULP2_MAX_PDU_PAYLOAD   (ULP2_MAX_PKT_SIZE - ISCSI_PDU_NONPAYLOAD_MAX)
+#define ULP2_MAX_PDU_PAYLOAD   (ULP2_MAX_PKT_SIZE - ISCSI_PDU_NONPAYLOAD_LEN)
 #define PPOD_PAGES_MAX         4
 #define PPOD_PAGES_SHIFT       2       /* 4 pages per pod */
 
index 091ecb4d9f3d8c8febaed68af246c69b2e486768..1ce9f244e46c53d9725cb9d953b0b8169e1470fe 100644 (file)
@@ -12,8 +12,8 @@
 #include "cxgb3i.h"
 
 #define DRV_MODULE_NAME         "cxgb3i"
-#define DRV_MODULE_VERSION     "1.0.0"
-#define DRV_MODULE_RELDATE     "Jun. 1, 2008"
+#define DRV_MODULE_VERSION     "1.0.1"
+#define DRV_MODULE_RELDATE     "Jan. 2009"
 
 static char version[] =
        "Chelsio S3xx iSCSI Driver " DRV_MODULE_NAME
index d83464b9b3f9c66c23fc9dd379626287e835cfdb..fa2a44f37b361e657a6d37bb452c90b6e461200c 100644 (file)
@@ -364,7 +364,8 @@ cxgb3i_session_create(struct iscsi_endpoint *ep, u16 cmds_max, u16 qdepth,
 
        cls_session = iscsi_session_setup(&cxgb3i_iscsi_transport, shost,
                                          cmds_max,
-                                         sizeof(struct iscsi_tcp_task),
+                                         sizeof(struct iscsi_tcp_task) +
+                                         sizeof(struct cxgb3i_task_data),
                                          initial_cmdsn, ISCSI_MAX_TARGET);
        if (!cls_session)
                return NULL;
@@ -402,17 +403,15 @@ static inline int cxgb3i_conn_max_xmit_dlength(struct iscsi_conn *conn)
 {
        struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
        struct cxgb3i_conn *cconn = tcp_conn->dd_data;
-       unsigned int max = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,
-                                cconn->hba->snic->tx_max_size -
-                                ISCSI_PDU_NONPAYLOAD_MAX);
+       unsigned int max = max(512 * MAX_SKB_FRAGS, SKB_TX_HEADROOM);
 
+       max = min(cconn->hba->snic->tx_max_size, max);
        if (conn->max_xmit_dlength)
-               conn->max_xmit_dlength = min_t(unsigned int,
-                                               conn->max_xmit_dlength, max);
+               conn->max_xmit_dlength = min(conn->max_xmit_dlength, max);
        else
                conn->max_xmit_dlength = max;
        align_pdu_size(conn->max_xmit_dlength);
-       cxgb3i_log_info("conn 0x%p, max xmit %u.\n",
+       cxgb3i_api_debug("conn 0x%p, max xmit %u.\n",
                         conn, conn->max_xmit_dlength);
        return 0;
 }
@@ -427,9 +426,7 @@ static inline int cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn)
 {
        struct iscsi_tcp_conn *tcp_conn = conn->dd_data;
        struct cxgb3i_conn *cconn = tcp_conn->dd_data;
-       unsigned int max = min_t(unsigned int, ULP2_MAX_PDU_PAYLOAD,
-                                cconn->hba->snic->rx_max_size -
-                                ISCSI_PDU_NONPAYLOAD_MAX);
+       unsigned int max = cconn->hba->snic->rx_max_size;
 
        align_pdu_size(max);
        if (conn->max_recv_dlength) {
@@ -439,8 +436,7 @@ static inline int cxgb3i_conn_max_recv_dlength(struct iscsi_conn *conn)
                                         conn->max_recv_dlength, max);
                        return -EINVAL;
                }
-               conn->max_recv_dlength = min_t(unsigned int,
-                                               conn->max_recv_dlength, max);
+               conn->max_recv_dlength = min(conn->max_recv_dlength, max);
                align_pdu_size(conn->max_recv_dlength);
        } else
                conn->max_recv_dlength = max;
@@ -844,7 +840,7 @@ static struct scsi_host_template cxgb3i_host_template = {
        .proc_name              = "cxgb3i",
        .queuecommand           = iscsi_queuecommand,
        .change_queue_depth     = iscsi_change_queue_depth,
-       .can_queue              = 128 * (ISCSI_DEF_XMIT_CMDS_MAX - 1),
+       .can_queue              = CXGB3I_SCSI_QDEPTH_DFLT - 1,
        .sg_tablesize           = SG_ALL,
        .max_sectors            = 0xFFFF,
        .cmd_per_lun            = ISCSI_DEF_CMD_PER_LUN,
index a865f1fefe8bfebbcbc2af1a391238acb840849d..de3b3b614cca7a92fff8e395be632d3a3eb6b2db 100644 (file)
 #include "cxgb3i_ddp.h"
 
 #ifdef __DEBUG_C3CN_CONN__
-#define c3cn_conn_debug         cxgb3i_log_info
+#define c3cn_conn_debug                cxgb3i_log_debug
 #else
 #define c3cn_conn_debug(fmt...)
 #endif
 
 #ifdef __DEBUG_C3CN_TX__
-#define c3cn_tx_debug         cxgb3i_log_debug
+#define c3cn_tx_debug          cxgb3i_log_debug
 #else
 #define c3cn_tx_debug(fmt...)
 #endif
 
 #ifdef __DEBUG_C3CN_RX__
-#define c3cn_rx_debug         cxgb3i_log_debug
+#define c3cn_rx_debug          cxgb3i_log_debug
 #else
 #define c3cn_rx_debug(fmt...)
 #endif
@@ -47,9 +47,9 @@ static int cxgb3_rcv_win = 256 * 1024;
 module_param(cxgb3_rcv_win, int, 0644);
 MODULE_PARM_DESC(cxgb3_rcv_win, "TCP receive window in bytes (default=256KB)");
 
-static int cxgb3_snd_win = 64 * 1024;
+static int cxgb3_snd_win = 128 * 1024;
 module_param(cxgb3_snd_win, int, 0644);
-MODULE_PARM_DESC(cxgb3_snd_win, "TCP send window in bytes (default=64KB)");
+MODULE_PARM_DESC(cxgb3_snd_win, "TCP send window in bytes (default=128KB)");
 
 static int cxgb3_rx_credit_thres = 10 * 1024;
 module_param(cxgb3_rx_credit_thres, int, 0644);
@@ -301,8 +301,8 @@ static void act_open_req_arp_failure(struct t3cdev *dev, struct sk_buff *skb)
 static void skb_entail(struct s3_conn *c3cn, struct sk_buff *skb,
                       int flags)
 {
-       CXGB3_SKB_CB(skb)->seq = c3cn->write_seq;
-       CXGB3_SKB_CB(skb)->flags = flags;
+       skb_tcp_seq(skb) = c3cn->write_seq;
+       skb_flags(skb) = flags;
        __skb_queue_tail(&c3cn->write_queue, skb);
 }
 
@@ -457,12 +457,9 @@ static unsigned int wrlen __read_mostly;
  * The number of WRs needed for an skb depends on the number of fragments
  * in the skb and whether it has any payload in its main body.  This maps the
  * length of the gather list represented by an skb into the # of necessary WRs.
- *
- * The max. length of an skb is controlled by the max pdu size which is ~16K.
- * Also, assume the min. fragment length is the sector size (512), then add
- * extra fragment counts for iscsi bhs and payload padding.
+ * The extra two fragments are for iscsi bhs and payload padding.
  */
-#define SKB_WR_LIST_SIZE       (16384/512 + 3)
+#define SKB_WR_LIST_SIZE       (MAX_SKB_FRAGS + 2)
 static unsigned int skb_wrs[SKB_WR_LIST_SIZE] __read_mostly;
 
 static void s3_init_wr_tab(unsigned int wr_len)
@@ -485,7 +482,7 @@ static void s3_init_wr_tab(unsigned int wr_len)
 
 static inline void reset_wr_list(struct s3_conn *c3cn)
 {
-       c3cn->wr_pending_head = NULL;
+       c3cn->wr_pending_head = c3cn->wr_pending_tail = NULL;
 }
 
 /*
@@ -496,7 +493,7 @@ static inline void reset_wr_list(struct s3_conn *c3cn)
 static inline void enqueue_wr(struct s3_conn *c3cn,
                              struct sk_buff *skb)
 {
-       skb_wr_data(skb) = NULL;
+       skb_tx_wr_next(skb) = NULL;
 
        /*
         * We want to take an extra reference since both us and the driver
@@ -509,10 +506,22 @@ static inline void enqueue_wr(struct s3_conn *c3cn,
        if (!c3cn->wr_pending_head)
                c3cn->wr_pending_head = skb;
        else
-               skb_wr_data(skb) = skb;
+               skb_tx_wr_next(c3cn->wr_pending_tail) = skb;
        c3cn->wr_pending_tail = skb;
 }
 
+static int count_pending_wrs(struct s3_conn *c3cn)
+{
+       int n = 0;
+       const struct sk_buff *skb = c3cn->wr_pending_head;
+
+       while (skb) {
+               n += skb->csum;
+               skb = skb_tx_wr_next(skb);
+       }
+       return n;
+}
+
 static inline struct sk_buff *peek_wr(const struct s3_conn *c3cn)
 {
        return c3cn->wr_pending_head;
@@ -529,8 +538,8 @@ static inline struct sk_buff *dequeue_wr(struct s3_conn *c3cn)
 
        if (likely(skb)) {
                /* Don't bother clearing the tail */
-               c3cn->wr_pending_head = skb_wr_data(skb);
-               skb_wr_data(skb) = NULL;
+               c3cn->wr_pending_head = skb_tx_wr_next(skb);
+               skb_tx_wr_next(skb) = NULL;
        }
        return skb;
 }
@@ -543,13 +552,14 @@ static void purge_wr_queue(struct s3_conn *c3cn)
 }
 
 static inline void make_tx_data_wr(struct s3_conn *c3cn, struct sk_buff *skb,
-                                  int len)
+                                  int len, int req_completion)
 {
        struct tx_data_wr *req;
 
        skb_reset_transport_header(skb);
        req = (struct tx_data_wr *)__skb_push(skb, sizeof(*req));
-       req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA));
+       req->wr_hi = htonl(V_WR_OP(FW_WROPCODE_OFLD_TX_DATA) |
+                       (req_completion ? F_WR_COMPL : 0));
        req->wr_lo = htonl(V_WR_TID(c3cn->tid));
        req->sndseq = htonl(c3cn->snd_nxt);
        /* len includes the length of any HW ULP additions */
@@ -592,7 +602,7 @@ static int c3cn_push_tx_frames(struct s3_conn *c3cn, int req_completion)
 
        if (unlikely(c3cn->state == C3CN_STATE_CONNECTING ||
                     c3cn->state == C3CN_STATE_CLOSE_WAIT_1 ||
-                    c3cn->state == C3CN_STATE_ABORTING)) {
+                    c3cn->state >= C3CN_STATE_ABORTING)) {
                c3cn_tx_debug("c3cn 0x%p, in closing state %u.\n",
                              c3cn, c3cn->state);
                return 0;
@@ -615,7 +625,7 @@ static int c3cn_push_tx_frames(struct s3_conn *c3cn, int req_completion)
                if (c3cn->wr_avail < wrs_needed) {
                        c3cn_tx_debug("c3cn 0x%p, skb len %u/%u, frag %u, "
                                      "wr %d < %u.\n",
-                                     c3cn, skb->len, skb->datalen, frags,
+                                     c3cn, skb->len, skb->data_len, frags,
                                      wrs_needed, c3cn->wr_avail);
                        break;
                }
@@ -627,20 +637,24 @@ static int c3cn_push_tx_frames(struct s3_conn *c3cn, int req_completion)
                c3cn->wr_unacked += wrs_needed;
                enqueue_wr(c3cn, skb);
 
-               if (likely(CXGB3_SKB_CB(skb)->flags & C3CB_FLAG_NEED_HDR)) {
-                       len += ulp_extra_len(skb);
-                       make_tx_data_wr(c3cn, skb, len);
-                       c3cn->snd_nxt += len;
-                       if ((req_completion
-                            && c3cn->wr_unacked == wrs_needed)
-                           || (CXGB3_SKB_CB(skb)->flags & C3CB_FLAG_COMPL)
-                           || c3cn->wr_unacked >= c3cn->wr_max / 2) {
-                               struct work_request_hdr *wr = cplhdr(skb);
+               c3cn_tx_debug("c3cn 0x%p, enqueue, skb len %u/%u, frag %u, "
+                               "wr %d, left %u, unack %u.\n",
+                               c3cn, skb->len, skb->data_len, frags,
+                               wrs_needed, c3cn->wr_avail, c3cn->wr_unacked);
+
 
-                               wr->wr_hi |= htonl(F_WR_COMPL);
+               if (likely(skb_flags(skb) & C3CB_FLAG_NEED_HDR)) {
+                       if ((req_completion &&
+                               c3cn->wr_unacked == wrs_needed) ||
+                           (skb_flags(skb) & C3CB_FLAG_COMPL) ||
+                           c3cn->wr_unacked >= c3cn->wr_max / 2) {
+                               req_completion = 1;
                                c3cn->wr_unacked = 0;
                        }
-                       CXGB3_SKB_CB(skb)->flags &= ~C3CB_FLAG_NEED_HDR;
+                       len += ulp_extra_len(skb);
+                       make_tx_data_wr(c3cn, skb, len, req_completion);
+                       c3cn->snd_nxt += len;
+                       skb_flags(skb) &= ~C3CB_FLAG_NEED_HDR;
                }
 
                total_size += skb->truesize;
@@ -735,8 +749,11 @@ static void process_act_establish(struct s3_conn *c3cn, struct sk_buff *skb)
        if (unlikely(c3cn_flag(c3cn, C3CN_ACTIVE_CLOSE_NEEDED)))
                /* upper layer has requested closing */
                send_abort_req(c3cn);
-       else if (c3cn_push_tx_frames(c3cn, 1))
+       else {
+               if (skb_queue_len(&c3cn->write_queue))
+                       c3cn_push_tx_frames(c3cn, 1);
                cxgb3i_conn_tx_open(c3cn);
+       }
 }
 
 static int do_act_establish(struct t3cdev *cdev, struct sk_buff *skb,
@@ -1082,8 +1099,8 @@ static void process_rx_iscsi_hdr(struct s3_conn *c3cn, struct sk_buff *skb)
                return;
        }
 
-       CXGB3_SKB_CB(skb)->seq = ntohl(hdr_cpl->seq);
-       CXGB3_SKB_CB(skb)->flags = 0;
+       skb_tcp_seq(skb) = ntohl(hdr_cpl->seq);
+       skb_flags(skb) = 0;
 
        skb_reset_transport_header(skb);
        __skb_pull(skb, sizeof(struct cpl_iscsi_hdr));
@@ -1103,12 +1120,12 @@ static void process_rx_iscsi_hdr(struct s3_conn *c3cn, struct sk_buff *skb)
                goto abort_conn;
 
        skb_ulp_mode(skb) = ULP2_FLAG_DATA_READY;
-       skb_ulp_pdulen(skb) = ntohs(ddp_cpl.len);
-       skb_ulp_ddigest(skb) = ntohl(ddp_cpl.ulp_crc);
+       skb_rx_pdulen(skb) = ntohs(ddp_cpl.len);
+       skb_rx_ddigest(skb) = ntohl(ddp_cpl.ulp_crc);
        status = ntohl(ddp_cpl.ddp_status);
 
        c3cn_rx_debug("rx skb 0x%p, len %u, pdulen %u, ddp status 0x%x.\n",
-                     skb, skb->len, skb_ulp_pdulen(skb), status);
+                     skb, skb->len, skb_rx_pdulen(skb), status);
 
        if (status & (1 << RX_DDP_STATUS_HCRC_SHIFT))
                skb_ulp_mode(skb) |= ULP2_FLAG_HCRC_ERROR;
@@ -1126,7 +1143,7 @@ static void process_rx_iscsi_hdr(struct s3_conn *c3cn, struct sk_buff *skb)
        } else if (status & (1 << RX_DDP_STATUS_DDP_SHIFT))
                skb_ulp_mode(skb) |= ULP2_FLAG_DATA_DDPED;
 
-       c3cn->rcv_nxt = ntohl(ddp_cpl.seq) + skb_ulp_pdulen(skb);
+       c3cn->rcv_nxt = ntohl(ddp_cpl.seq) + skb_rx_pdulen(skb);
        __pskb_trim(skb, len);
        __skb_queue_tail(&c3cn->receive_queue, skb);
        cxgb3i_conn_pdu_ready(c3cn);
@@ -1151,12 +1168,27 @@ static int do_iscsi_hdr(struct t3cdev *t3dev, struct sk_buff *skb, void *ctx)
  * Process an acknowledgment of WR completion.  Advance snd_una and send the
  * next batch of work requests from the write queue.
  */
+static void check_wr_invariants(struct s3_conn *c3cn)
+{
+       int pending = count_pending_wrs(c3cn);
+
+       if (unlikely(c3cn->wr_avail + pending != c3cn->wr_max))
+               cxgb3i_log_error("TID %u: credit imbalance: avail %u, "
+                               "pending %u, total should be %u\n",
+                               c3cn->tid, c3cn->wr_avail, pending,
+                               c3cn->wr_max);
+}
+
 static void process_wr_ack(struct s3_conn *c3cn, struct sk_buff *skb)
 {
        struct cpl_wr_ack *hdr = cplhdr(skb);
        unsigned int credits = ntohs(hdr->credits);
        u32 snd_una = ntohl(hdr->snd_una);
 
+       c3cn_tx_debug("%u WR credits, avail %u, unack %u, TID %u, state %u.\n",
+                       credits, c3cn->wr_avail, c3cn->wr_unacked,
+                       c3cn->tid, c3cn->state);
+
        c3cn->wr_avail += credits;
        if (c3cn->wr_unacked > c3cn->wr_max - c3cn->wr_avail)
                c3cn->wr_unacked = c3cn->wr_max - c3cn->wr_avail;
@@ -1171,6 +1203,17 @@ static void process_wr_ack(struct s3_conn *c3cn, struct sk_buff *skb)
                        break;
                }
                if (unlikely(credits < p->csum)) {
+                       struct tx_data_wr *w = cplhdr(p);
+                       cxgb3i_log_error("TID %u got %u WR credits need %u, "
+                                        "len %u, main body %u, frags %u, "
+                                        "seq # %u, ACK una %u, ACK nxt %u, "
+                                        "WR_AVAIL %u, WRs pending %u\n",
+                                        c3cn->tid, credits, p->csum, p->len,
+                                        p->len - p->data_len,
+                                        skb_shinfo(p)->nr_frags,
+                                        ntohl(w->sndseq), snd_una,
+                                        ntohl(hdr->snd_nxt), c3cn->wr_avail,
+                                        count_pending_wrs(c3cn) - credits);
                        p->csum -= credits;
                        break;
                } else {
@@ -1180,15 +1223,24 @@ static void process_wr_ack(struct s3_conn *c3cn, struct sk_buff *skb)
                }
        }
 
-       if (unlikely(before(snd_una, c3cn->snd_una)))
+       check_wr_invariants(c3cn);
+
+       if (unlikely(before(snd_una, c3cn->snd_una))) {
+               cxgb3i_log_error("TID %u, unexpected sequence # %u in WR_ACK "
+                                "snd_una %u\n",
+                                c3cn->tid, snd_una, c3cn->snd_una);
                goto out_free;
+       }
 
        if (c3cn->snd_una != snd_una) {
                c3cn->snd_una = snd_una;
                dst_confirm(c3cn->dst_cache);
        }
 
-       if (skb_queue_len(&c3cn->write_queue) && c3cn_push_tx_frames(c3cn, 0))
+       if (skb_queue_len(&c3cn->write_queue)) {
+               if (c3cn_push_tx_frames(c3cn, 0))
+                       cxgb3i_conn_tx_open(c3cn);
+       } else
                cxgb3i_conn_tx_open(c3cn);
 out_free:
        __kfree_skb(skb);
@@ -1452,7 +1504,7 @@ static void init_offload_conn(struct s3_conn *c3cn,
                              struct dst_entry *dst)
 {
        BUG_ON(c3cn->cdev != cdev);
-       c3cn->wr_max = c3cn->wr_avail = T3C_DATA(cdev)->max_wrs;
+       c3cn->wr_max = c3cn->wr_avail = T3C_DATA(cdev)->max_wrs - 1;
        c3cn->wr_unacked = 0;
        c3cn->mss_idx = select_mss(c3cn, dst_mtu(dst));
 
@@ -1671,9 +1723,17 @@ int cxgb3i_c3cn_send_pdus(struct s3_conn *c3cn, struct sk_buff *skb)
                goto out_err;
        }
 
-       err = -EPIPE;
        if (c3cn->err) {
                c3cn_tx_debug("c3cn 0x%p, err %d.\n", c3cn, c3cn->err);
+               err = -EPIPE;
+               goto out_err;
+       }
+
+       if (c3cn->write_seq - c3cn->snd_una >= cxgb3_snd_win) {
+               c3cn_tx_debug("c3cn 0x%p, snd %u - %u > %u.\n",
+                               c3cn, c3cn->write_seq, c3cn->snd_una,
+                               cxgb3_snd_win);
+               err = -EAGAIN;
                goto out_err;
        }
 
index d23156907ffdce1b8bb58dee792e2ee7204b4f8a..6344b9eb2589cfe42c8e33ff5606e5ae0e6b53f4 100644 (file)
@@ -178,25 +178,33 @@ void cxgb3i_c3cn_release(struct s3_conn *);
  * @flag:      see C3CB_FLAG_* below
  * @ulp_mode:  ULP mode/submode of sk_buff
  * @seq:       tcp sequence number
- * @ddigest:   pdu data digest
- * @pdulen:    recovered pdu length
- * @wr_data:   scratch area for tx wr
  */
+struct cxgb3_skb_rx_cb {
+       __u32 ddigest;                  /* data digest */
+       __u32 pdulen;                   /* recovered pdu length */
+};
+
+struct cxgb3_skb_tx_cb {
+       struct sk_buff *wr_next;        /* next wr */
+};
+
 struct cxgb3_skb_cb {
        __u8 flags;
        __u8 ulp_mode;
        __u32 seq;
-       __u32 ddigest;
-       __u32 pdulen;
-       struct sk_buff *wr_data;
+       union {
+               struct cxgb3_skb_rx_cb rx;
+               struct cxgb3_skb_tx_cb tx;
+       };
 };
 
 #define CXGB3_SKB_CB(skb)      ((struct cxgb3_skb_cb *)&((skb)->cb[0]))
-
+#define skb_flags(skb)         (CXGB3_SKB_CB(skb)->flags)
 #define skb_ulp_mode(skb)      (CXGB3_SKB_CB(skb)->ulp_mode)
-#define skb_ulp_ddigest(skb)   (CXGB3_SKB_CB(skb)->ddigest)
-#define skb_ulp_pdulen(skb)    (CXGB3_SKB_CB(skb)->pdulen)
-#define skb_wr_data(skb)       (CXGB3_SKB_CB(skb)->wr_data)
+#define skb_tcp_seq(skb)       (CXGB3_SKB_CB(skb)->seq)
+#define skb_rx_ddigest(skb)    (CXGB3_SKB_CB(skb)->rx.ddigest)
+#define skb_rx_pdulen(skb)     (CXGB3_SKB_CB(skb)->rx.pdulen)
+#define skb_tx_wr_next(skb)    (CXGB3_SKB_CB(skb)->tx.wr_next)
 
 enum c3cb_flags {
        C3CB_FLAG_NEED_HDR = 1 << 0,    /* packet needs a TX_DATA_WR header */
@@ -217,6 +225,7 @@ struct sge_opaque_hdr {
 /* for TX: a skb must have a headroom of at least TX_HEADER_LEN bytes */
 #define TX_HEADER_LEN \
                (sizeof(struct tx_data_wr) + sizeof(struct sge_opaque_hdr))
+#define SKB_TX_HEADROOM                SKB_MAX_HEAD(TX_HEADER_LEN)
 
 /*
  * get and set private ip for iscsi traffic
index ce7ce8c6094c549e44079079557ebb2d1f49791b..17115c230d6582ca8d8522166f774a999727ed3f 100644 (file)
 #define cxgb3i_tx_debug(fmt...)
 #endif
 
+/* always allocate rooms for AHS */
+#define SKB_TX_PDU_HEADER_LEN  \
+       (sizeof(struct iscsi_hdr) + ISCSI_MAX_AHS_SIZE)
+static unsigned int skb_extra_headroom;
 static struct page *pad_page;
 
 /*
@@ -146,12 +150,13 @@ static inline void tx_skb_setmode(struct sk_buff *skb, int hcrc, int dcrc)
 
 void cxgb3i_conn_cleanup_task(struct iscsi_task *task)
 {
-       struct iscsi_tcp_task *tcp_task = task->dd_data;
+       struct cxgb3i_task_data *tdata = task->dd_data +
+                                       sizeof(struct iscsi_tcp_task);
 
        /* never reached the xmit task callout */
-       if (tcp_task->dd_data)
-               kfree_skb(tcp_task->dd_data);
-       tcp_task->dd_data = NULL;
+       if (tdata->skb)
+               __kfree_skb(tdata->skb);
+       memset(tdata, 0, sizeof(struct cxgb3i_task_data));
 
        /* MNC - Do we need a check in case this is called but
         * cxgb3i_conn_alloc_pdu has never been called on the task */
@@ -159,28 +164,102 @@ void cxgb3i_conn_cleanup_task(struct iscsi_task *task)
        iscsi_tcp_cleanup_task(task);
 }
 
-/*
- * We do not support ahs yet
- */
+static int sgl_seek_offset(struct scatterlist *sgl, unsigned int sgcnt,
+                               unsigned int offset, unsigned int *off,
+                               struct scatterlist **sgp)
+{
+       int i;
+       struct scatterlist *sg;
+
+       for_each_sg(sgl, sg, sgcnt, i) {
+               if (offset < sg->length) {
+                       *off = offset;
+                       *sgp = sg;
+                       return 0;
+               }
+               offset -= sg->length;
+       }
+       return -EFAULT;
+}
+
+static int sgl_read_to_frags(struct scatterlist *sg, unsigned int sgoffset,
+                               unsigned int dlen, skb_frag_t *frags,
+                               int frag_max)
+{
+       unsigned int datalen = dlen;
+       unsigned int sglen = sg->length - sgoffset;
+       struct page *page = sg_page(sg);
+       int i;
+
+       i = 0;
+       do {
+               unsigned int copy;
+
+               if (!sglen) {
+                       sg = sg_next(sg);
+                       if (!sg) {
+                               cxgb3i_log_error("%s, sg NULL, len %u/%u.\n",
+                                                __func__, datalen, dlen);
+                               return -EINVAL;
+                       }
+                       sgoffset = 0;
+                       sglen = sg->length;
+                       page = sg_page(sg);
+
+               }
+               copy = min(datalen, sglen);
+               if (i && page == frags[i - 1].page &&
+                   sgoffset + sg->offset ==
+                       frags[i - 1].page_offset + frags[i - 1].size) {
+                       frags[i - 1].size += copy;
+               } else {
+                       if (i >= frag_max) {
+                               cxgb3i_log_error("%s, too many pages %u, "
+                                                "dlen %u.\n", __func__,
+                                                frag_max, dlen);
+                               return -EINVAL;
+                       }
+
+                       frags[i].page = page;
+                       frags[i].page_offset = sg->offset + sgoffset;
+                       frags[i].size = copy;
+                       i++;
+               }
+               datalen -= copy;
+               sgoffset += copy;
+               sglen -= copy;
+       } while (datalen);
+
+       return i;
+}
+
 int cxgb3i_conn_alloc_pdu(struct iscsi_task *task, u8 opcode)
 {
+       struct iscsi_conn *conn = task->conn;
        struct iscsi_tcp_task *tcp_task = task->dd_data;
-       struct sk_buff *skb;
+       struct cxgb3i_task_data *tdata = task->dd_data + sizeof(*tcp_task);
+       struct scsi_cmnd *sc = task->sc;
+       int headroom = SKB_TX_PDU_HEADER_LEN;
 
+       tcp_task->dd_data = tdata;
        task->hdr = NULL;
-       /* always allocate rooms for AHS */
-       skb = alloc_skb(sizeof(struct iscsi_hdr) + ISCSI_MAX_AHS_SIZE +
-                       TX_HEADER_LEN,  GFP_ATOMIC);
-       if (!skb)
+
+       /* write command, need to send data pdus */
+       if (skb_extra_headroom && (opcode == ISCSI_OP_SCSI_DATA_OUT ||
+           (opcode == ISCSI_OP_SCSI_CMD &&
+           (scsi_bidi_cmnd(sc) || sc->sc_data_direction == DMA_TO_DEVICE))))
+               headroom += min(skb_extra_headroom, conn->max_xmit_dlength);
+
+       tdata->skb = alloc_skb(TX_HEADER_LEN + headroom, GFP_ATOMIC);
+       if (!tdata->skb)
                return -ENOMEM;
+       skb_reserve(tdata->skb, TX_HEADER_LEN);
 
        cxgb3i_tx_debug("task 0x%p, opcode 0x%x, skb 0x%p.\n",
-                       task, opcode, skb);
+                       task, opcode, tdata->skb);
 
-       tcp_task->dd_data = skb;
-       skb_reserve(skb, TX_HEADER_LEN);
-       task->hdr = (struct iscsi_hdr *)skb->data;
-       task->hdr_max = sizeof(struct iscsi_hdr);
+       task->hdr = (struct iscsi_hdr *)tdata->skb->data;
+       task->hdr_max = SKB_TX_PDU_HEADER_LEN;
 
        /* data_out uses scsi_cmd's itt */
        if (opcode != ISCSI_OP_SCSI_DATA_OUT)
@@ -192,13 +271,13 @@ int cxgb3i_conn_alloc_pdu(struct iscsi_task *task, u8 opcode)
 int cxgb3i_conn_init_pdu(struct iscsi_task *task, unsigned int offset,
                              unsigned int count)
 {
-       struct iscsi_tcp_task *tcp_task = task->dd_data;
-       struct sk_buff *skb = tcp_task->dd_data;
        struct iscsi_conn *conn = task->conn;
-       struct page *pg;
+       struct iscsi_tcp_task *tcp_task = task->dd_data;
+       struct cxgb3i_task_data *tdata = tcp_task->dd_data;
+       struct sk_buff *skb = tdata->skb;
        unsigned int datalen = count;
        int i, padlen = iscsi_padding(count);
-       skb_frag_t *frag;
+       struct page *pg;
 
        cxgb3i_tx_debug("task 0x%p,0x%p, offset %u, count %u, skb 0x%p.\n",
                        task, task->sc, offset, count, skb);
@@ -209,90 +288,94 @@ int cxgb3i_conn_init_pdu(struct iscsi_task *task, unsigned int offset,
                return 0;
 
        if (task->sc) {
-               struct scatterlist *sg;
-               struct scsi_data_buffer *sdb;
-               unsigned int sgoffset = offset;
-               struct page *sgpg;
-               unsigned int sglen;
-
-               sdb = scsi_out(task->sc);
-               sg = sdb->table.sgl;
-
-               for_each_sg(sdb->table.sgl, sg, sdb->table.nents, i) {
-                       cxgb3i_tx_debug("sg %d, page 0x%p, len %u offset %u\n",
-                                       i, sg_page(sg), sg->length, sg->offset);
-
-                       if (sgoffset < sg->length)
-                               break;
-                       sgoffset -= sg->length;
+               struct scsi_data_buffer *sdb = scsi_out(task->sc);
+               struct scatterlist *sg = NULL;
+               int err;
+
+               tdata->offset = offset;
+               tdata->count = count;
+               err = sgl_seek_offset(sdb->table.sgl, sdb->table.nents,
+                                       tdata->offset, &tdata->sgoffset, &sg);
+               if (err < 0) {
+                       cxgb3i_log_warn("tpdu, sgl %u, bad offset %u/%u.\n",
+                                       sdb->table.nents, tdata->offset,
+                                       sdb->length);
+                       return err;
                }
-               sgpg = sg_page(sg);
-               sglen = sg->length - sgoffset;
-
-               do {
-                       int j = skb_shinfo(skb)->nr_frags;
-                       unsigned int copy;
-
-                       if (!sglen) {
-                               sg = sg_next(sg);
-                               sgpg = sg_page(sg);
-                               sgoffset = 0;
-                               sglen = sg->length;
-                               ++i;
+               err = sgl_read_to_frags(sg, tdata->sgoffset, tdata->count,
+                                       tdata->frags, MAX_PDU_FRAGS);
+               if (err < 0) {
+                       cxgb3i_log_warn("tpdu, sgl %u, bad offset %u + %u.\n",
+                                       sdb->table.nents, tdata->offset,
+                                       tdata->count);
+                       return err;
+               }
+               tdata->nr_frags = err;
+
+               if (tdata->nr_frags > MAX_SKB_FRAGS ||
+                   (padlen && tdata->nr_frags == MAX_SKB_FRAGS)) {
+                       char *dst = skb->data + task->hdr_len;
+                       skb_frag_t *frag = tdata->frags;
+
+                       /* data fits in the skb's headroom */
+                       for (i = 0; i < tdata->nr_frags; i++, frag++) {
+                               char *src = kmap_atomic(frag->page,
+                                                       KM_SOFTIRQ0);
+
+                               memcpy(dst, src+frag->page_offset, frag->size);
+                               dst += frag->size;
+                               kunmap_atomic(src, KM_SOFTIRQ0);
                        }
-                       copy = min(sglen, datalen);
-                       if (j && skb_can_coalesce(skb, j, sgpg,
-                                                 sg->offset + sgoffset)) {
-                               skb_shinfo(skb)->frags[j - 1].size += copy;
-                       } else {
-                               get_page(sgpg);
-                               skb_fill_page_desc(skb, j, sgpg,
-                                                  sg->offset + sgoffset, copy);
+                       if (padlen) {
+                               memset(dst, 0, padlen);
+                               padlen = 0;
                        }
-                       sgoffset += copy;
-                       sglen -= copy;
-                       datalen -= copy;
-               } while (datalen);
+                       skb_put(skb, count + padlen);
+               } else {
+                       /* data fit into frag_list */
+                       for (i = 0; i < tdata->nr_frags; i++)
+                               get_page(tdata->frags[i].page);
+
+                       memcpy(skb_shinfo(skb)->frags, tdata->frags,
+                               sizeof(skb_frag_t) * tdata->nr_frags);
+                       skb_shinfo(skb)->nr_frags = tdata->nr_frags;
+                       skb->len += count;
+                       skb->data_len += count;
+                       skb->truesize += count;
+               }
+
        } else {
                pg = virt_to_page(task->data);
 
-               while (datalen) {
-                       i = skb_shinfo(skb)->nr_frags;
-                       frag = &skb_shinfo(skb)->frags[i];
-
-                       get_page(pg);
-                       frag->page = pg;
-                       frag->page_offset = 0;
-                       frag->size = min((unsigned int)PAGE_SIZE, datalen);
-
-                       skb_shinfo(skb)->nr_frags++;
-                       datalen -= frag->size;
-                       pg++;
-               }
+               get_page(pg);
+               skb_fill_page_desc(skb, 0, pg, offset_in_page(task->data),
+                                       count);
+               skb->len += count;
+               skb->data_len += count;
+               skb->truesize += count;
        }
 
        if (padlen) {
                i = skb_shinfo(skb)->nr_frags;
-               frag = &skb_shinfo(skb)->frags[i];
-               frag->page = pad_page;
-               frag->page_offset = 0;
-               frag->size = padlen;
-               skb_shinfo(skb)->nr_frags++;
+               get_page(pad_page);
+               skb_fill_page_desc(skb, skb_shinfo(skb)->nr_frags, pad_page, 0,
+                                padlen);
+
+               skb->data_len += padlen;
+               skb->truesize += padlen;
+               skb->len += padlen;
        }
 
-       datalen = count + padlen;
-       skb->data_len += datalen;
-       skb->truesize += datalen;
-       skb->len += datalen;
        return 0;
 }
 
 int cxgb3i_conn_xmit_pdu(struct iscsi_task *task)
 {
-       struct iscsi_tcp_task *tcp_task = task->dd_data;
-       struct sk_buff *skb = tcp_task->dd_data;
        struct iscsi_tcp_conn *tcp_conn = task->conn->dd_data;
        struct cxgb3i_conn *cconn = tcp_conn->dd_data;
+       struct iscsi_tcp_task *tcp_task = task->dd_data;
+       struct cxgb3i_task_data *tdata = tcp_task->dd_data;
+       struct sk_buff *skb = tdata->skb;
        unsigned int datalen;
        int err;
 
@@ -300,13 +383,14 @@ int cxgb3i_conn_xmit_pdu(struct iscsi_task *task)
                return 0;
 
        datalen = skb->data_len;
-       tcp_task->dd_data = NULL;
+       tdata->skb = NULL;
        err = cxgb3i_c3cn_send_pdus(cconn->cep->c3cn, skb);
-       cxgb3i_tx_debug("task 0x%p, skb 0x%p, len %u/%u, rv %d.\n",
-                       task, skb, skb->len, skb->data_len, err);
        if (err > 0) {
                int pdulen = err;
 
+       cxgb3i_tx_debug("task 0x%p, skb 0x%p, len %u/%u, rv %d.\n",
+                       task, skb, skb->len, skb->data_len, err);
+
                if (task->conn->hdrdgst_en)
                        pdulen += ISCSI_DIGEST_SIZE;
                if (datalen && task->conn->datadgst_en)
@@ -325,12 +409,14 @@ int cxgb3i_conn_xmit_pdu(struct iscsi_task *task)
                return err;
        }
        /* reset skb to send when we are called again */
-       tcp_task->dd_data = skb;
+       tdata->skb = skb;
        return -EAGAIN;
 }
 
 int cxgb3i_pdu_init(void)
 {
+       if (SKB_TX_HEADROOM > (512 * MAX_SKB_FRAGS))
+               skb_extra_headroom = SKB_TX_HEADROOM;
        pad_page = alloc_page(GFP_KERNEL);
        if (!pad_page)
                return -ENOMEM;
@@ -366,7 +452,9 @@ void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn)
        skb = skb_peek(&c3cn->receive_queue);
        while (!err && skb) {
                __skb_unlink(skb, &c3cn->receive_queue);
-               read += skb_ulp_pdulen(skb);
+               read += skb_rx_pdulen(skb);
+               cxgb3i_rx_debug("conn 0x%p, cn 0x%p, rx skb 0x%p, pdulen %u.\n",
+                               conn, c3cn, skb, skb_rx_pdulen(skb));
                err = cxgb3i_conn_read_pdu_skb(conn, skb);
                __kfree_skb(skb);
                skb = skb_peek(&c3cn->receive_queue);
@@ -377,6 +465,11 @@ void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn)
                cxgb3i_c3cn_rx_credits(c3cn, read);
        }
        conn->rxdata_octets += read;
+
+       if (err) {
+               cxgb3i_log_info("conn 0x%p rx failed err %d.\n", conn, err);
+               iscsi_conn_failure(conn, ISCSI_ERR_CONN_FAILED);
+       }
 }
 
 void cxgb3i_conn_tx_open(struct s3_conn *c3cn)
index a3f685cc236299521aa54e4e8207b974875b3aee..0770b23d90da1a704019e6d538a8aae2640f21d4 100644 (file)
@@ -53,7 +53,7 @@ struct cpl_rx_data_ddp_norss {
 #define ULP2_FLAG_DCRC_ERROR           0x20
 #define ULP2_FLAG_PAD_ERROR            0x40
 
-void cxgb3i_conn_closing(struct s3_conn *);
+void cxgb3i_conn_closing(struct s3_conn *c3cn);
 void cxgb3i_conn_pdu_ready(struct s3_conn *c3cn);
 void cxgb3i_conn_tx_open(struct s3_conn *c3cn);
 #endif
index a48e4990fe12fc79f06d649faa5dac4887f0a65e..34be88d7afa53da88fc2910ede911bfe9b758550 100644 (file)
@@ -1251,6 +1251,7 @@ static struct pci_device_id hptiop_id_table[] = {
        { PCI_VDEVICE(TTI, 0x3530), (kernel_ulong_t)&hptiop_itl_ops },
        { PCI_VDEVICE(TTI, 0x3560), (kernel_ulong_t)&hptiop_itl_ops },
        { PCI_VDEVICE(TTI, 0x4322), (kernel_ulong_t)&hptiop_itl_ops },
+       { PCI_VDEVICE(TTI, 0x4321), (kernel_ulong_t)&hptiop_itl_ops },
        { PCI_VDEVICE(TTI, 0x4210), (kernel_ulong_t)&hptiop_itl_ops },
        { PCI_VDEVICE(TTI, 0x4211), (kernel_ulong_t)&hptiop_itl_ops },
        { PCI_VDEVICE(TTI, 0x4310), (kernel_ulong_t)&hptiop_itl_ops },
index a1a511bdec8cb87961023da3bbf487de6d9a580e..ed1e728763a2192c14acfe1322ef227ddc01f129 100644 (file)
@@ -1573,9 +1573,6 @@ static int ibmvfc_queuecommand(struct scsi_cmnd *cmnd,
        vfc_cmd->resp_len = sizeof(vfc_cmd->rsp);
        vfc_cmd->cancel_key = (unsigned long)cmnd->device->hostdata;
        vfc_cmd->tgt_scsi_id = rport->port_id;
-       if ((rport->supported_classes & FC_COS_CLASS3) &&
-           (fc_host_supported_classes(vhost->host) & FC_COS_CLASS3))
-               vfc_cmd->flags = IBMVFC_CLASS_3_ERR;
        vfc_cmd->iu.xfer_len = scsi_bufflen(cmnd);
        int_to_scsilun(cmnd->device->lun, &vfc_cmd->iu.lun);
        memcpy(vfc_cmd->iu.cdb, cmnd->cmnd, cmnd->cmd_len);
@@ -3266,6 +3263,7 @@ static int ibmvfc_alloc_target(struct ibmvfc_host *vhost, u64 scsi_id)
                return -ENOMEM;
        }
 
+       memset(tgt, 0, sizeof(*tgt));
        tgt->scsi_id = scsi_id;
        tgt->new_scsi_id = scsi_id;
        tgt->vhost = vhost;
@@ -3576,9 +3574,18 @@ static void ibmvfc_log_ae(struct ibmvfc_host *vhost, int events)
 static void ibmvfc_tgt_add_rport(struct ibmvfc_target *tgt)
 {
        struct ibmvfc_host *vhost = tgt->vhost;
-       struct fc_rport *rport;
+       struct fc_rport *rport = tgt->rport;
        unsigned long flags;
 
+       if (rport) {
+               tgt_dbg(tgt, "Setting rport roles\n");
+               fc_remote_port_rolechg(rport, tgt->ids.roles);
+               spin_lock_irqsave(vhost->host->host_lock, flags);
+               ibmvfc_set_tgt_action(tgt, IBMVFC_TGT_ACTION_NONE);
+               spin_unlock_irqrestore(vhost->host->host_lock, flags);
+               return;
+       }
+
        tgt_dbg(tgt, "Adding rport\n");
        rport = fc_remote_port_add(vhost->host, 0, &tgt->ids);
        spin_lock_irqsave(vhost->host->host_lock, flags);
index 87dafd0f8d4416b48e27bf08b3673d391a670abe..b21e071b986214875074ea35748e775a4ec51469 100644 (file)
@@ -32,7 +32,7 @@
 #define IBMVFC_DRIVER_VERSION          "1.0.4"
 #define IBMVFC_DRIVER_DATE             "(November 14, 2008)"
 
-#define IBMVFC_DEFAULT_TIMEOUT 15
+#define IBMVFC_DEFAULT_TIMEOUT 60
 #define IBMVFC_INIT_TIMEOUT            120
 #define IBMVFC_MAX_REQUESTS_DEFAULT    100
 
index 74d07d137daeb75b038071f6fe9a279b927243e1..c9aa7611e40824142534d21aa46fc4461936ba33 100644 (file)
@@ -432,6 +432,7 @@ static int map_sg_data(struct scsi_cmnd *cmd,
                                sdev_printk(KERN_ERR, cmd->device,
                                            "Can't allocate memory "
                                            "for indirect table\n");
+                       scsi_dma_unmap(cmd);
                        return 0;
                }
        }
index 257c24115de9108132d955ab5e488cf0b6c37c3e..809d32d95c76e6457a33469c8a43bf7246ef44e0 100644 (file)
@@ -1998,6 +1998,8 @@ int iscsi_host_add(struct Scsi_Host *shost, struct device *pdev)
        if (!shost->can_queue)
                shost->can_queue = ISCSI_DEF_XMIT_CMDS_MAX;
 
+       if (!shost->transportt->eh_timed_out)
+               shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
        return scsi_add_host(shost, pdev);
 }
 EXPORT_SYMBOL_GPL(iscsi_host_add);
@@ -2020,7 +2022,6 @@ struct Scsi_Host *iscsi_host_alloc(struct scsi_host_template *sht,
        shost = scsi_host_alloc(sht, sizeof(struct iscsi_host) + dd_data_size);
        if (!shost)
                return NULL;
-       shost->transportt->eh_timed_out = iscsi_eh_cmd_timed_out;
 
        if (qdepth > ISCSI_MAX_CMD_PER_LUN || qdepth < 1) {
                if (qdepth != 0)
index a8f30bdaff69a2e1203297a5bbbb7caa823cf550..a7302480bc4a7fb3605f6317631de89e5a9303d4 100644 (file)
@@ -5258,6 +5258,7 @@ lpfc_send_els_event(struct lpfc_vport *vport,
                        sizeof(struct lpfc_name));
                break;
        default:
+               kfree(els_data);
                return;
        }
        memcpy(els_data->wwpn, &ndlp->nlp_portname, sizeof(struct lpfc_name));
index 33a3c13fd8936b717fb3cec81258a76e88478094..f4c57227ec185cf2a6357ebc24bccf674e7e36cf 100644 (file)
@@ -1265,13 +1265,6 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
            test_bit(FCPORT_UPDATE_NEEDED, &vha->dpc_flags))
                msleep(1000);
 
-       if (ha->mqenable) {
-               if (qla25xx_delete_queues(vha, 0) != QLA_SUCCESS)
-                       qla_printk(KERN_WARNING, ha,
-                               "Queue delete failed.\n");
-               vha->req_ques[0] = ha->req_q_map[0]->id;
-       }
-
        qla24xx_disable_vp(vha);
 
        fc_remove_host(vha->host);
@@ -1293,6 +1286,12 @@ qla24xx_vport_delete(struct fc_vport *fc_vport)
                    vha->host_no, vha->vp_idx, vha));
         }
 
+       if (ha->mqenable) {
+               if (qla25xx_delete_queues(vha, 0) != QLA_SUCCESS)
+                       qla_printk(KERN_WARNING, ha,
+                               "Queue delete failed.\n");
+       }
+
        scsi_host_put(vha->host);
        qla_printk(KERN_INFO, ha, "vport %d deleted\n", id);
        return 0;
index 023ee77fb027beddfacc5005d2372f0f3a3d584e..e0c5bb54b258a492e9ceb641cada66b07d4785f8 100644 (file)
@@ -2135,6 +2135,7 @@ struct qla_msix_entry {
 /* Work events.  */
 enum qla_work_type {
        QLA_EVT_AEN,
+       QLA_EVT_IDC_ACK,
 };
 
 
@@ -2149,6 +2150,10 @@ struct qla_work_evt {
                        enum fc_host_event_code code;
                        u32 data;
                } aen;
+               struct {
+#define QLA_IDC_ACK_REGS       7
+                       uint16_t mb[QLA_IDC_ACK_REGS];
+               } idc_ack;
        } u;
 };
 
index d78d35e681ab3413f5b3835d1671709ca76e8753..d6ea69df7c5cf584ae21ab4c210c05a0873f1422 100644 (file)
@@ -72,7 +72,7 @@ static char *qla2x00_model_name[QLA_MODEL_NAMES*2] = {
        "QLA2462",      "Sun PCI-X 2.0 to 4Gb FC, Dual Channel",        /* 0x141 */
        "QLE2460",      "Sun PCI-Express to 2Gb FC, Single Channel",    /* 0x142 */
        "QLE2462",      "Sun PCI-Express to 4Gb FC, Single Channel",    /* 0x143 */
-       "QEM2462"       "Server I/O Module 4Gb FC, Dual Channel",       /* 0x144 */
+       "QEM2462",      "Server I/O Module 4Gb FC, Dual Channel",       /* 0x144 */
        "QLE2440",      "PCI-Express to 4Gb FC, Single Channel",        /* 0x145 */
        "QLE2464",      "PCI-Express to 4Gb FC, Quad Channel",          /* 0x146 */
        "QLA2440",      "PCI-X 2.0 to 4Gb FC, Single Channel",          /* 0x147 */
index 7abb045a0410e4eed6624af160188bff170ec797..ffff4255408784ffe24c1a2753a9654950e5ca6d 100644 (file)
@@ -1402,6 +1402,8 @@ struct access_chip_rsp_84xx {
 #define MBA_IDC_NOTIFY         0x8101
 #define MBA_IDC_TIME_EXT       0x8102
 
+#define MBC_IDC_ACK            0x101
+
 struct nvram_81xx {
        /* NVRAM header. */
        uint8_t id[4];
index a336b4bc81a7e50b5d1407ba249c0c5944615a6f..6de283f8f111d0a2a30056594e02b6e410add6f1 100644 (file)
@@ -72,6 +72,7 @@ extern int qla2x00_loop_reset(scsi_qla_host_t *);
 extern void qla2x00_abort_all_cmds(scsi_qla_host_t *, int);
 extern int qla2x00_post_aen_work(struct scsi_qla_host *, enum
     fc_host_event_code, u32);
+extern int qla2x00_post_idc_ack_work(struct scsi_qla_host *, uint16_t *);
 
 extern void qla2x00_abort_fcport_cmds(fc_port_t *);
 extern struct scsi_qla_host *qla2x00_create_host(struct scsi_host_template *,
@@ -266,6 +267,8 @@ qla2x00_set_idma_speed(scsi_qla_host_t *, uint16_t, uint16_t, uint16_t *);
 
 extern int qla84xx_verify_chip(struct scsi_qla_host *, uint16_t *);
 
+extern int qla81xx_idc_ack(scsi_qla_host_t *, uint16_t *);
+
 /*
  * Global Function Prototypes in qla_isr.c source file.
  */
@@ -376,10 +379,8 @@ extern int qla2x00_dfs_remove(scsi_qla_host_t *);
 
 /* Globa function prototypes for multi-q */
 extern int qla25xx_request_irq(struct rsp_que *);
-extern int qla25xx_init_req_que(struct scsi_qla_host *, struct req_que *,
-       uint8_t);
-extern int qla25xx_init_rsp_que(struct scsi_qla_host *, struct rsp_que *,
-       uint8_t);
+extern int qla25xx_init_req_que(struct scsi_qla_host *, struct req_que *);
+extern int qla25xx_init_rsp_que(struct scsi_qla_host *, struct rsp_que *);
 extern int qla25xx_create_req_que(struct qla_hw_data *, uint16_t, uint8_t,
        uint16_t, uint8_t, uint8_t);
 extern int qla25xx_create_rsp_que(struct qla_hw_data *, uint16_t, uint8_t,
index f6368a1d3021e1e4e2f2c569d5742683cab61d47..986501759ad4910fa6b93c7db75d355001c47ad8 100644 (file)
@@ -1226,9 +1226,8 @@ qla24xx_config_rings(struct scsi_qla_host *vha)
                        icb->firmware_options_2 |=
                                __constant_cpu_to_le32(BIT_18);
 
-               icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_22);
+               icb->firmware_options_2 &= __constant_cpu_to_le32(~BIT_22);
                icb->firmware_options_2 |= __constant_cpu_to_le32(BIT_23);
-               ha->rsp_q_map[0]->options = icb->firmware_options_2;
 
                WRT_REG_DWORD(&reg->isp25mq.req_q_in, 0);
                WRT_REG_DWORD(&reg->isp25mq.req_q_out, 0);
@@ -3493,7 +3492,7 @@ qla25xx_init_queues(struct qla_hw_data *ha)
                rsp = ha->rsp_q_map[i];
                if (rsp) {
                        rsp->options &= ~BIT_0;
-                       ret = qla25xx_init_rsp_que(base_vha, rsp, rsp->options);
+                       ret = qla25xx_init_rsp_que(base_vha, rsp);
                        if (ret != QLA_SUCCESS)
                                DEBUG2_17(printk(KERN_WARNING
                                        "%s Rsp que:%d init failed\n", __func__,
@@ -3507,7 +3506,7 @@ qla25xx_init_queues(struct qla_hw_data *ha)
                if (req) {
                /* Clear outstanding commands array. */
                        req->options &= ~BIT_0;
-                       ret = qla25xx_init_req_que(base_vha, req, req->options);
+                       ret = qla25xx_init_req_que(base_vha, req);
                        if (ret != QLA_SUCCESS)
                                DEBUG2_17(printk(KERN_WARNING
                                        "%s Req que:%d init failed\n", __func__,
index e28ad81baf1e09d84edcbfef99e1ce945c2264b3..f250e5b7897cf7387f14579d50dd9462c2b0dc28 100644 (file)
@@ -266,6 +266,40 @@ qla2x00_mbx_completion(scsi_qla_host_t *vha, uint16_t mb0)
        }
 }
 
+static void
+qla81xx_idc_event(scsi_qla_host_t *vha, uint16_t aen, uint16_t descr)
+{
+       static char *event[] =
+               { "Complete", "Request Notification", "Time Extension" };
+       int rval;
+       struct device_reg_24xx __iomem *reg24 = &vha->hw->iobase->isp24;
+       uint16_t __iomem *wptr;
+       uint16_t cnt, timeout, mb[QLA_IDC_ACK_REGS];
+
+       /* Seed data -- mailbox1 -> mailbox7. */
+       wptr = (uint16_t __iomem *)&reg24->mailbox1;
+       for (cnt = 0; cnt < QLA_IDC_ACK_REGS; cnt++, wptr++)
+               mb[cnt] = RD_REG_WORD(wptr);
+
+       DEBUG2(printk("scsi(%ld): Inter-Driver Commucation %s -- "
+           "%04x %04x %04x %04x %04x %04x %04x.\n", vha->host_no,
+           event[aen & 0xff],
+           mb[0], mb[1], mb[2], mb[3], mb[4], mb[5], mb[6]));
+
+       /* Acknowledgement needed? [Notify && non-zero timeout]. */
+       timeout = (descr >> 8) & 0xf;
+       if (aen != MBA_IDC_NOTIFY || !timeout)
+               return;
+
+       DEBUG2(printk("scsi(%ld): Inter-Driver Commucation %s -- "
+           "ACK timeout=%d.\n", vha->host_no, event[aen & 0xff], timeout));
+
+       rval = qla2x00_post_idc_ack_work(vha, mb);
+       if (rval != QLA_SUCCESS)
+               qla_printk(KERN_WARNING, vha->hw,
+                   "IDC failed to post ACK.\n");
+}
+
 /**
  * qla2x00_async_event() - Process aynchronous events.
  * @ha: SCSI driver HA context
@@ -714,21 +748,9 @@ skip_rio:
                    "%04x %04x %04x\n", vha->host_no, mb[1], mb[2], mb[3]));
                break;
        case MBA_IDC_COMPLETE:
-               DEBUG2(printk("scsi(%ld): Inter-Driver Commucation "
-                   "Complete -- %04x %04x %04x\n", vha->host_no, mb[1], mb[2],
-                   mb[3]));
-               break;
        case MBA_IDC_NOTIFY:
-               DEBUG2(printk("scsi(%ld): Inter-Driver Commucation "
-                   "Request Notification -- %04x %04x %04x\n", vha->host_no,
-                   mb[1], mb[2], mb[3]));
-               /**** Mailbox registers 4 - 7 valid!!! */
-               break;
        case MBA_IDC_TIME_EXT:
-               DEBUG2(printk("scsi(%ld): Inter-Driver Commucation "
-                   "Time Extension -- %04x %04x %04x\n", vha->host_no, mb[1],
-                   mb[2], mb[3]));
-               /**** Mailbox registers 4 - 7 valid!!! */
+               qla81xx_idc_event(vha, mb[0], mb[1]);
                break;
        }
 
@@ -1707,7 +1729,6 @@ qla25xx_msix_rsp_q(int irq, void *dev_id)
        struct qla_hw_data *ha;
        struct rsp_que *rsp;
        struct device_reg_24xx __iomem *reg;
-       uint16_t msix_disabled_hccr = 0;
 
        rsp = (struct rsp_que *) dev_id;
        if (!rsp) {
@@ -1720,17 +1741,8 @@ qla25xx_msix_rsp_q(int irq, void *dev_id)
 
        spin_lock_irq(&ha->hardware_lock);
 
-       msix_disabled_hccr = rsp->options;
-       if (!rsp->id)
-               msix_disabled_hccr &= __constant_cpu_to_le32(BIT_22);
-       else
-               msix_disabled_hccr &= __constant_cpu_to_le32(BIT_6);
-
        qla24xx_process_response_queue(rsp);
 
-       if (!msix_disabled_hccr)
-               WRT_REG_DWORD(&reg->hccr, HCCRX_CLR_RISC_INT);
-
        spin_unlock_irq(&ha->hardware_lock);
 
        return IRQ_HANDLED;
index f94ffbb98e95f2a53918888ed76ebf235b3aa5cc..4c7504cb3990490830e89c85edeea9df7bf004db 100644 (file)
@@ -3090,8 +3090,7 @@ verify_done:
 }
 
 int
-qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req,
-       uint8_t options)
+qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req)
 {
        int rval;
        unsigned long flags;
@@ -3101,7 +3100,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req,
        struct qla_hw_data *ha = vha->hw;
 
        mcp->mb[0] = MBC_INITIALIZE_MULTIQ;
-       mcp->mb[1] = options;
+       mcp->mb[1] = req->options;
        mcp->mb[2] = MSW(LSD(req->dma));
        mcp->mb[3] = LSW(LSD(req->dma));
        mcp->mb[6] = MSW(MSD(req->dma));
@@ -3128,7 +3127,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req,
        mcp->tov = 60;
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       if (!(options & BIT_0)) {
+       if (!(req->options & BIT_0)) {
                WRT_REG_DWORD(&reg->req_q_in, 0);
                WRT_REG_DWORD(&reg->req_q_out, 0);
        }
@@ -3142,8 +3141,7 @@ qla25xx_init_req_que(struct scsi_qla_host *vha, struct req_que *req,
 }
 
 int
-qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp,
-       uint8_t options)
+qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
 {
        int rval;
        unsigned long flags;
@@ -3153,7 +3151,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp,
        struct qla_hw_data *ha = vha->hw;
 
        mcp->mb[0] = MBC_INITIALIZE_MULTIQ;
-       mcp->mb[1] = options;
+       mcp->mb[1] = rsp->options;
        mcp->mb[2] = MSW(LSD(rsp->dma));
        mcp->mb[3] = LSW(LSD(rsp->dma));
        mcp->mb[6] = MSW(MSD(rsp->dma));
@@ -3178,7 +3176,7 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp,
        mcp->tov = 60;
 
        spin_lock_irqsave(&ha->hardware_lock, flags);
-       if (!(options & BIT_0)) {
+       if (!(rsp->options & BIT_0)) {
                WRT_REG_DWORD(&reg->rsp_q_out, 0);
                WRT_REG_DWORD(&reg->rsp_q_in, 0);
        }
@@ -3193,3 +3191,29 @@ qla25xx_init_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp,
        return rval;
 }
 
+int
+qla81xx_idc_ack(scsi_qla_host_t *vha, uint16_t *mb)
+{
+       int rval;
+       mbx_cmd_t mc;
+       mbx_cmd_t *mcp = &mc;
+
+       DEBUG11(printk("%s(%ld): entered.\n", __func__, vha->host_no));
+
+       mcp->mb[0] = MBC_IDC_ACK;
+       memcpy(&mcp->mb[1], mb, QLA_IDC_ACK_REGS * sizeof(uint16_t));
+       mcp->out_mb = MBX_7|MBX_6|MBX_5|MBX_4|MBX_3|MBX_2|MBX_1|MBX_0;
+       mcp->in_mb = MBX_0;
+       mcp->tov = MBX_TOV_SECONDS;
+       mcp->flags = 0;
+       rval = qla2x00_mailbox_command(vha, mcp);
+
+       if (rval != QLA_SUCCESS) {
+               DEBUG2_3_11(printk("%s(%ld): failed=%x (%x).\n", __func__,
+                   vha->host_no, rval, mcp->mb[0]));
+       } else {
+               DEBUG11(printk("%s(%ld): done.\n", __func__, vha->host_no));
+       }
+
+       return rval;
+}
index f53179c46423adb449c2480aa205bcd2b868c17a..3f23932210c4231a38c7c8ccd9ccd77a85951e91 100644 (file)
@@ -396,7 +396,7 @@ qla24xx_create_vhost(struct fc_vport *fc_vport)
 
        qla2x00_start_timer(vha, qla2x00_timer, WATCH_INTERVAL);
 
-       memset(vha->req_ques, 0, sizeof(vha->req_ques) * QLA_MAX_HOST_QUES);
+       memset(vha->req_ques, 0, sizeof(vha->req_ques));
        vha->req_ques[0] = ha->req_q_map[0]->id;
        host->can_queue = ha->req_q_map[0]->length + 128;
        host->this_id = 255;
@@ -471,7 +471,7 @@ qla25xx_delete_req_que(struct scsi_qla_host *vha, struct req_que *req)
 
        if (req) {
                req->options |= BIT_0;
-               ret = qla25xx_init_req_que(vha, req, req->options);
+               ret = qla25xx_init_req_que(vha, req);
        }
        if (ret == QLA_SUCCESS)
                qla25xx_free_req_que(vha, req);
@@ -486,7 +486,7 @@ qla25xx_delete_rsp_que(struct scsi_qla_host *vha, struct rsp_que *rsp)
 
        if (rsp) {
                rsp->options |= BIT_0;
-               ret = qla25xx_init_rsp_que(vha, rsp, rsp->options);
+               ret = qla25xx_init_rsp_que(vha, rsp);
        }
        if (ret == QLA_SUCCESS)
                qla25xx_free_rsp_que(vha, rsp);
@@ -502,7 +502,7 @@ int qla25xx_update_req_que(struct scsi_qla_host *vha, uint8_t que, uint8_t qos)
 
        req->options |= BIT_3;
        req->qos = qos;
-       ret = qla25xx_init_req_que(vha, req, req->options);
+       ret = qla25xx_init_req_que(vha, req);
        if (ret != QLA_SUCCESS)
                DEBUG2_17(printk(KERN_WARNING "%s failed\n", __func__));
        /* restore options bit */
@@ -632,7 +632,7 @@ qla25xx_create_req_que(struct qla_hw_data *ha, uint16_t options,
        req->max_q_depth = ha->req_q_map[0]->max_q_depth;
        mutex_unlock(&ha->vport_lock);
 
-       ret = qla25xx_init_req_que(base_vha, req, options);
+       ret = qla25xx_init_req_que(base_vha, req);
        if (ret != QLA_SUCCESS) {
                qla_printk(KERN_WARNING, ha, "%s failed\n", __func__);
                mutex_lock(&ha->vport_lock);
@@ -710,7 +710,7 @@ qla25xx_create_rsp_que(struct qla_hw_data *ha, uint16_t options,
        if (ret)
                goto que_failed;
 
-       ret = qla25xx_init_rsp_que(base_vha, rsp, options);
+       ret = qla25xx_init_rsp_que(base_vha, rsp);
        if (ret != QLA_SUCCESS) {
                qla_printk(KERN_WARNING, ha, "%s failed\n", __func__);
                mutex_lock(&ha->vport_lock);
index c11f872d3e105776f76b9fe566f24289bb87d331..2f5f72531e23108acde73b9174d22af9e584e83c 100644 (file)
@@ -2522,6 +2522,19 @@ qla2x00_post_aen_work(struct scsi_qla_host *vha, enum fc_host_event_code code,
        return qla2x00_post_work(vha, e, 1);
 }
 
+int
+qla2x00_post_idc_ack_work(struct scsi_qla_host *vha, uint16_t *mb)
+{
+       struct qla_work_evt *e;
+
+       e = qla2x00_alloc_work(vha, QLA_EVT_IDC_ACK, 1);
+       if (!e)
+               return QLA_FUNCTION_FAILED;
+
+       memcpy(e->u.idc_ack.mb, mb, QLA_IDC_ACK_REGS * sizeof(uint16_t));
+       return qla2x00_post_work(vha, e, 1);
+}
+
 static void
 qla2x00_do_work(struct scsi_qla_host *vha)
 {
@@ -2539,6 +2552,9 @@ qla2x00_do_work(struct scsi_qla_host *vha)
                        fc_host_post_event(vha->host, fc_get_event_number(),
                            e->u.aen.code, e->u.aen.data);
                        break;
+               case QLA_EVT_IDC_ACK:
+                       qla81xx_idc_ack(vha, e->u.idc_ack.mb);
+                       break;
                }
                if (e->flags & QLA_EVT_FLAG_FREE)
                        kfree(e);
index 9c3b694c049dad0695a4d99d59de28d3a57493ce..284827926effc096155dd3e755a2348fb03631d6 100644 (file)
@@ -684,7 +684,7 @@ qla2xxx_get_flt_info(scsi_qla_host_t *vha, uint32_t flt_addr)
                    "end=0x%x size=0x%x.\n", le32_to_cpu(region->code), start,
                    le32_to_cpu(region->end) >> 2, le32_to_cpu(region->size)));
 
-               switch (le32_to_cpu(region->code)) {
+               switch (le32_to_cpu(region->code) & 0xff) {
                case FLT_REG_FW:
                        ha->flt_region_fw = start;
                        break;
index cfa4c11a4797abf8a8a2e9b7ee1669ca6d3705ac..79f7053da99b47bec9478f5454d01dcf20685403 100644 (file)
@@ -7,7 +7,7 @@
 /*
  * Driver version
  */
-#define QLA2XXX_VERSION      "8.03.00-k2"
+#define QLA2XXX_VERSION      "8.03.00-k3"
 
 #define QLA_DRIVER_MAJOR_VER   8
 #define QLA_DRIVER_MINOR_VER   3
index 940dc32ff0dc731523c0e02849e3772950260ef0..b82ffd90632e256ca0ce5c7d478dae715f3e8318 100644 (file)
@@ -1040,12 +1040,11 @@ void scsi_io_completion(struct scsi_cmnd *cmd, unsigned int good_bytes)
                                action = ACTION_FAIL;
                        break;
                case ABORTED_COMMAND:
+                       action = ACTION_FAIL;
                        if (sshdr.asc == 0x10) { /* DIF */
                                description = "Target Data Integrity Failure";
-                               action = ACTION_FAIL;
                                error = -EILSEQ;
-                       } else
-                               action = ACTION_RETRY;
+                       }
                        break;
                case NOT_READY:
                        /* If the device is in the process of becoming
index 66505bb794100320f03aa43344be94284c22dcfd..8f4de20c9deb061266b41f18866931523e93241a 100644 (file)
@@ -317,6 +317,7 @@ static struct scsi_device *scsi_alloc_sdev(struct scsi_target *starget,
        return sdev;
 
 out_device_destroy:
+       scsi_device_set_state(sdev, SDEV_DEL);
        transport_destroy_device(&sdev->sdev_gendev);
        put_device(&sdev->sdev_gendev);
 out:
index d57566b8be0ad9f095a0ef0525b5c265b61e8b2c..55310dbc10a669f6b9cbf3bb5627d9bf8badc171 100644 (file)
@@ -107,6 +107,7 @@ static void scsi_disk_release(struct device *cdev);
 static void sd_print_sense_hdr(struct scsi_disk *, struct scsi_sense_hdr *);
 static void sd_print_result(struct scsi_disk *, int);
 
+static DEFINE_SPINLOCK(sd_index_lock);
 static DEFINE_IDA(sd_index_ida);
 
 /* This semaphore is used to mediate the 0->1 reference get in the
@@ -1914,7 +1915,9 @@ static int sd_probe(struct device *dev)
                if (!ida_pre_get(&sd_index_ida, GFP_KERNEL))
                        goto out_put;
 
+               spin_lock(&sd_index_lock);
                error = ida_get_new(&sd_index_ida, &index);
+               spin_unlock(&sd_index_lock);
        } while (error == -EAGAIN);
 
        if (error)
@@ -1936,7 +1939,9 @@ static int sd_probe(struct device *dev)
        return 0;
 
  out_free_index:
+       spin_lock(&sd_index_lock);
        ida_remove(&sd_index_ida, index);
+       spin_unlock(&sd_index_lock);
  out_put:
        put_disk(gd);
  out_free:
@@ -1986,7 +1991,9 @@ static void scsi_disk_release(struct device *dev)
        struct scsi_disk *sdkp = to_scsi_disk(dev);
        struct gendisk *disk = sdkp->disk;
        
+       spin_lock(&sd_index_lock);
        ida_remove(&sd_index_ida, sdkp->index);
+       spin_unlock(&sd_index_lock);
 
        disk->private_data = NULL;
        put_disk(disk);
index 8f0bd3f7a59fdbc9b8c50ab69904d388b4ce24c5..516925d8b570c3fab05d5d1b0a6b729e0ebce395 100644 (file)
@@ -1078,7 +1078,7 @@ sg_ioctl(struct inode *inode, struct file *filp,
        case BLKTRACESETUP:
                return blk_trace_setup(sdp->device->request_queue,
                                       sdp->disk->disk_name,
-                                      sdp->device->sdev_gendev.devt,
+                                      MKDEV(SCSI_GENERIC_MAJOR, sdp->index),
                                       (char *)arg);
        case BLKTRACESTART:
                return blk_trace_startstop(sdp->device->request_queue, 1);
index 0d934bfbdd9b2ded293260968927a7de5e776f88..b4b39811b44544cc76a4c71e00c5c02567a765c2 100644 (file)
@@ -2083,6 +2083,20 @@ static int serial8250_startup(struct uart_port *port)
 
        serial8250_set_mctrl(&up->port, up->port.mctrl);
 
+       /* Serial over Lan (SoL) hack:
+          Intel 8257x Gigabit ethernet chips have a
+          16550 emulation, to be used for Serial Over Lan.
+          Those chips take a longer time than a normal
+          serial device to signalize that a transmission
+          data was queued. Due to that, the above test generally
+          fails. One solution would be to delay the reading of
+          iir. However, this is not reliable, since the timeout
+          is variable. So, let's just don't test if we receive
+          TX irq. This way, we'll never enable UART_BUG_TXEN.
+        */
+       if (up->port.flags & UPF_NO_TXEN_TEST)
+               goto dont_test_tx_en;
+
        /*
         * Do a quick test to see if we receive an
         * interrupt when we enable the TX irq.
@@ -2102,6 +2116,7 @@ static int serial8250_startup(struct uart_port *port)
                up->bugs &= ~UART_BUG_TXEN;
        }
 
+dont_test_tx_en:
        spin_unlock_irqrestore(&up->port.lock, flags);
 
        /*
index 536d8e510f66da655b9106ac7eb2e0719edce2b3..533f82025adf218e6fffbfd1730f94839924be21 100644 (file)
@@ -798,6 +798,21 @@ pci_default_setup(struct serial_private *priv,
        return setup_port(priv, port, bar, offset, board->reg_shift);
 }
 
+static int skip_tx_en_setup(struct serial_private *priv,
+                       const struct pciserial_board *board,
+                       struct uart_port *port, int idx)
+{
+       port->flags |= UPF_NO_TXEN_TEST;
+       printk(KERN_DEBUG "serial8250: skipping TxEn test for device "
+                         "[%04x:%04x] subsystem [%04x:%04x]\n",
+                         priv->dev->vendor,
+                         priv->dev->device,
+                         priv->dev->subsystem_vendor,
+                         priv->dev->subsystem_device);
+
+       return pci_default_setup(priv, board, port, idx);
+}
+
 /* This should be in linux/pci_ids.h */
 #define PCI_VENDOR_ID_SBSMODULARIO     0x124B
 #define PCI_SUBVENDOR_ID_SBSMODULARIO  0x124B
@@ -864,6 +879,27 @@ static struct pci_serial_quirk pci_serial_quirks[] __refdata = {
                .init           = pci_inteli960ni_init,
                .setup          = pci_default_setup,
        },
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_8257X_SOL,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = skip_tx_en_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_82573L_SOL,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = skip_tx_en_setup,
+       },
+       {
+               .vendor         = PCI_VENDOR_ID_INTEL,
+               .device         = PCI_DEVICE_ID_INTEL_82573E_SOL,
+               .subvendor      = PCI_ANY_ID,
+               .subdevice      = PCI_ANY_ID,
+               .setup          = skip_tx_en_setup,
+       },
        /*
         * ITE
         */
index 89362d733d6230331c6bead3c8bbce3ef9d28563..8f58f7ff0dd7db29af5c749dbeda386b8c6c10b9 100644 (file)
@@ -877,6 +877,10 @@ static int atmel_startup(struct uart_port *port)
                }
        }
 
+       /* Save current CSR for comparison in atmel_tasklet_func() */
+       atmel_port->irq_status_prev = UART_GET_CSR(port);
+       atmel_port->irq_status = atmel_port->irq_status_prev;
+
        /*
         * Finally, enable the serial port
         */
index 92187e28608aeb6cb03c0a090a38db5d186bd090..ac79cbe4c2cf40e2e5512a4607d517c120784757 100644 (file)
@@ -84,6 +84,8 @@ static int jsm_probe_one(struct pci_dev *pdev, const struct pci_device_id *ent)
        brd->pci_dev = pdev;
        if (pdev->device == PCIE_DEVICE_ID_NEO_4_IBM)
                brd->maxports = 4;
+       else if (pdev->device == PCI_DEVICE_ID_DIGI_NEO_8)
+               brd->maxports = 8;
        else
                brd->maxports = 2;
 
@@ -212,6 +214,7 @@ static struct pci_device_id jsm_pci_tbl[] = {
        { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45), 0, 0, 2 },
        { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_NEO_2RJ45PRI), 0, 0, 3 },
        { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCIE_DEVICE_ID_NEO_4_IBM), 0, 0, 4 },
+       { PCI_DEVICE(PCI_VENDOR_ID_DIGI, PCI_DEVICE_ID_DIGI_NEO_8), 0, 0, 5 },
        { 0, }
 };
 MODULE_DEVICE_TABLE(pci, jsm_pci_tbl);
index 3599828b976600848d644d51c42db442d808a708..022e89ffec1da4bc8da86bf6ba8471634f4fdaad 100644 (file)
 # define SCSPTR3       0xffed0024      /* 16 bit SCIF */
 # define SCSPTR4       0xffee0024      /* 16 bit SCIF */
 # define SCSPTR5       0xffef0024      /* 16 bit SCIF */
-# define SCIF_OPER     0x0001          /* Overrun error bit */
+# define SCIF_ORER     0x0001          /* Overrun error bit */
 # define SCSCR_INIT(port)      0x3a    /* TIE=0,RIE=0,TE=1,RE=1,REIE=1 */
 #elif defined(CONFIG_CPU_SUBTYPE_SH7201) || \
       defined(CONFIG_CPU_SUBTYPE_SH7203) || \
index 49698cabc30ddba88a6a6b02cb6ab3dd07da0fac..f5ed9721aabb33c24c9a75c79d58df19e595450f 100644 (file)
@@ -114,7 +114,7 @@ static inline void setmosi(const struct spi_device *spi, int is_on)
 
 static inline int getmiso(const struct spi_device *spi)
 {
-       return gpio_get_value(SPI_MISO_GPIO);
+       return !!gpio_get_value(SPI_MISO_GPIO);
 }
 
 #undef pdata
index c958ac16423ce68232ebf7069629cde645cb9736..40ea4176224761d5db83cdb81cadfe723e814243 100644 (file)
@@ -564,6 +564,7 @@ static int sprom_extract(struct ssb_bus *bus, struct ssb_sprom *out,
 static int ssb_pci_sprom_get(struct ssb_bus *bus,
                             struct ssb_sprom *sprom)
 {
+       const struct ssb_sprom *fallback;
        int err = -ENOMEM;
        u16 *buf;
 
@@ -583,12 +584,23 @@ static int ssb_pci_sprom_get(struct ssb_bus *bus,
                bus->sprom_size = SSB_SPROMSIZE_WORDS_R4;
                sprom_do_read(bus, buf);
                err = sprom_check_crc(buf, bus->sprom_size);
-               if (err)
+               if (err) {
+                       /* All CRC attempts failed.
+                        * Maybe there is no SPROM on the device?
+                        * If we have a fallback, use that. */
+                       fallback = ssb_get_fallback_sprom();
+                       if (fallback) {
+                               memcpy(sprom, fallback, sizeof(*sprom));
+                               err = 0;
+                               goto out_free;
+                       }
                        ssb_printk(KERN_WARNING PFX "WARNING: Invalid"
                                   " SPROM CRC (corrupt SPROM)\n");
+               }
        }
        err = sprom_extract(bus, sprom, buf, bus->sprom_size);
 
+out_free:
        kfree(buf);
 out:
        return err;
index 3668edb39315a1c6db8cae6c07198b133ffcb65b..8943015a3eef2b45794c7b5f250d53c33d24cc76 100644 (file)
@@ -14,6 +14,9 @@
 #include "ssb_private.h"
 
 
+static const struct ssb_sprom *fallback_sprom;
+
+
 static int sprom2hex(const u16 *sprom, char *buf, size_t buf_len,
                     size_t sprom_size_words)
 {
@@ -131,3 +134,36 @@ out:
                return res;
        return err ? err : count;
 }
+
+/**
+ * ssb_arch_set_fallback_sprom - Set a fallback SPROM for use if no SPROM is found.
+ *
+ * @sprom: The SPROM data structure to register.
+ *
+ * With this function the architecture implementation may register a fallback
+ * SPROM data structure. The fallback is only used for PCI based SSB devices,
+ * where no valid SPROM can be found in the shadow registers.
+ *
+ * This function is useful for weird architectures that have a half-assed SSB device
+ * hardwired to their PCI bus.
+ *
+ * Note that it does only work with PCI attached SSB devices. PCMCIA devices currently
+ * don't use this fallback.
+ * Architectures must provide the SPROM for native SSB devices anyway,
+ * so the fallback also isn't used for native devices.
+ *
+ * This function is available for architecture code, only. So it is not exported.
+ */
+int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom)
+{
+       if (fallback_sprom)
+               return -EEXIST;
+       fallback_sprom = sprom;
+
+       return 0;
+}
+
+const struct ssb_sprom *ssb_get_fallback_sprom(void)
+{
+       return fallback_sprom;
+}
index ebc32d8fe15f990475131ecb4cdda6f873fd2487..57fa482abb94ebf15c1ed977ba4700d57372b0c5 100644 (file)
@@ -131,6 +131,7 @@ ssize_t ssb_attr_sprom_store(struct ssb_bus *bus,
                             const char *buf, size_t count,
                             int (*sprom_check_crc)(const u16 *sprom, size_t size),
                             int (*sprom_write)(struct ssb_bus *bus, const u16 *sprom));
+extern const struct ssb_sprom *ssb_get_fallback_sprom(void);
 
 
 /* core.c */
index ab69c1bf36a8205fd80a2abb46cd7c16e1d9d5be..c2747bc88c6fbe42861857cca5dd6190e5559a28 100644 (file)
@@ -2164,19 +2164,20 @@ static void __exit panel_cleanup_module(void)
        if (scan_timer.function != NULL)
                del_timer(&scan_timer);
 
-       if (keypad_enabled)
-               misc_deregister(&keypad_dev);
+       if (pprt != NULL) {
+               if (keypad_enabled)
+                       misc_deregister(&keypad_dev);
+
+               if (lcd_enabled) {
+                       panel_lcd_print("\x0cLCD driver " PANEL_VERSION
+                                       "\nunloaded.\x1b[Lc\x1b[Lb\x1b[L-");
+                       misc_deregister(&lcd_dev);
+               }
 
-       if (lcd_enabled) {
-               panel_lcd_print("\x0cLCD driver " PANEL_VERSION
-                               "\nunloaded.\x1b[Lc\x1b[Lb\x1b[L-");
-               misc_deregister(&lcd_dev);
+               /* TODO: free all input signals */
+               parport_release(pprt);
+               parport_unregister_device(pprt);
        }
-
-       /* TODO: free all input signals */
-
-       parport_release(pprt);
-       parport_unregister_device(pprt);
        parport_unregister_driver(&panel_driver);
 }
 
index 79c225acd1ad7b9904668c40586d8f0e6c7ee0fd..f636296b54bc7fd7d809755682ecf844e0aa5f2e 100644 (file)
@@ -1,5 +1,6 @@
 config RTL8187SE
        tristate "RealTek RTL8187SE Wireless LAN NIC driver"
        depends on PCI
+       depends on WIRELESS_EXT && COMPAT_NET_DEV_OPS
        default N
        ---help---
index af64cfbe16dbbb056e6dde50b50f2f1e7e022544..7370296225e19b78942d076cf84fca84e6a0ffb9 100644 (file)
@@ -234,20 +234,21 @@ out:
 void ieee80211_crypto_deinit(void)
 {
        struct list_head *ptr, *n;
+       struct ieee80211_crypto_alg *alg = NULL;
 
        if (hcrypt == NULL)
                return;
 
-       for (ptr = hcrypt->algs.next, n = ptr->next; ptr != &hcrypt->algs;
-            ptr = n, n = ptr->next) {
-               struct ieee80211_crypto_alg *alg =
-                       (struct ieee80211_crypto_alg *) ptr;
-               list_del(ptr);
-               printk(KERN_DEBUG "ieee80211_crypt: unregistered algorithm "
-                      "'%s' (deinit)\n", alg->ops->name);
-               kfree(alg);
+       list_for_each_safe(ptr, n, &hcrypt->algs) {
+               alg = list_entry(ptr, struct ieee80211_crypto_alg, list);
+               if (alg) {
+                       list_del(ptr);
+                       printk(KERN_DEBUG
+                              "ieee80211_crypt: unregistered algorithm '%s' (deinit)\n",
+                              alg->ops->name);
+                       kfree(alg);
+               }
        }
-
        kfree(hcrypt);
 }
 
index 94534955e38b52eae91fe8f732d2a0f56cedd928..66de5cc8ddf119a85d4b66c4829bfe4c97422b90 100644 (file)
@@ -6161,10 +6161,10 @@ static void __exit rtl8180_pci_module_exit(void)
 {
        pci_unregister_driver (&rtl8180_pci_driver);
        rtl8180_proc_module_remove();
-       ieee80211_crypto_deinit();
        ieee80211_crypto_tkip_exit();
        ieee80211_crypto_ccmp_exit();
        ieee80211_crypto_wep_exit();
+       ieee80211_crypto_deinit();
        DMESG("Exiting");
 }
 
index b003f9a7e1518b58f62ec83787a529652481a1f9..f716b2e92b654a55f848aecd370c0736861f201f 100644 (file)
@@ -319,16 +319,18 @@ static int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id
        struct usb_device *udev = interface_to_usbdev(intf);
        struct wbsoft_priv *priv;
        struct ieee80211_hw *dev;
-       int err;
+       int nr, err;
 
        usb_get_dev(udev);
 
        // 20060630.2 Check the device if it already be opened
-       err = usb_control_msg(udev, usb_rcvctrlpipe( udev, 0 ),
-                             0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN,
-                             0x0, 0x400, &ltmp, 4, HZ*100 );
-       if (err)
+       nr = usb_control_msg(udev, usb_rcvctrlpipe( udev, 0 ),
+                            0x01, USB_TYPE_VENDOR|USB_RECIP_DEVICE|USB_DIR_IN,
+                            0x0, 0x400, &ltmp, 4, HZ*100 );
+       if (nr < 0) {
+               err = nr;
                goto error;
+       }
 
        ltmp = cpu_to_le32(ltmp);
        if (ltmp) {  // Is already initialized?
@@ -337,8 +339,10 @@ static int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id
        }
 
        dev = ieee80211_alloc_hw(sizeof(*priv), &wbsoft_ops);
-       if (!dev)
+       if (!dev) {
+               err = -ENOMEM;
                goto error;
+       }
 
        priv = dev->priv;
 
@@ -369,9 +373,11 @@ static int wb35_probe(struct usb_interface *intf, const struct usb_device_id *id
        }
 
        dev->extra_tx_headroom = 12;    /* FIXME */
-       dev->flags = 0;
+       dev->flags = IEEE80211_HW_SIGNAL_UNSPEC;
+       dev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION);
 
        dev->channel_change_time = 1000;
+       dev->max_signal = 100;
        dev->queues = 1;
 
        dev->wiphy->bands[IEEE80211_BAND_2GHZ] = &wbsoft_band_2GHz;
index 326dd7f65ee9aaf0b846d09c80c9d6d2b260b0d8..b3d5a23ab56fbf5c3832aa76d69e27caf15a9ff4 100644 (file)
@@ -1376,6 +1376,15 @@ static struct usb_device_id acm_ids[] = {
        { USB_DEVICE(0x0572, 0x1324), /* Conexant USB MODEM RD02-D400 */
        .driver_info = NO_UNION_NORMAL, /* has no union descriptor */
        },
+       { USB_DEVICE(0x22b8, 0x6425), /* Motorola MOTOMAGX phones */
+       },
+       { USB_DEVICE(0x0572, 0x1329), /* Hummingbird huc56s (Conexant) */
+       .driver_info = NO_UNION_NORMAL, /* union descriptor misplaced on
+                                          data interface instead of
+                                          communications interface.
+                                          Maybe we should define a new
+                                          quirk for this. */
+       },
 
        /* control interfaces with various AT-command sets */
        { USB_INTERFACE_INFO(USB_CLASS_COMM, USB_CDC_SUBCLASS_ACM,
index c54fc40458b171aa863eec63aa4821a45287d4e2..a4301dc02d275c1f28c77cde42183d1a2d435792 100644 (file)
@@ -297,19 +297,6 @@ int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t message)
 }
 EXPORT_SYMBOL_GPL(usb_hcd_pci_suspend);
 
-/**
- * usb_hcd_pci_resume_early - resume a PCI-based HCD before IRQs are enabled
- * @dev: USB Host Controller being resumed
- *
- * Store this function in the HCD's struct pci_driver as .resume_early.
- */
-int usb_hcd_pci_resume_early(struct pci_dev *dev)
-{
-       pci_restore_state(dev);
-       return 0;
-}
-EXPORT_SYMBOL_GPL(usb_hcd_pci_resume_early);
-
 /**
  * usb_hcd_pci_resume - power management resume of a PCI-based HCD
  * @dev: USB Host Controller being resumed
@@ -333,6 +320,8 @@ int usb_hcd_pci_resume(struct pci_dev *dev)
        }
 #endif
 
+       pci_restore_state(dev);
+
        hcd = pci_get_drvdata(dev);
        if (hcd->state != HC_STATE_SUSPENDED) {
                dev_dbg(hcd->self.controller,
index 5b94a56bec2356d7945ec4d56bca543d0c229a26..f750eb1ab595e926aecba81a9579f8674eae76fa 100644 (file)
@@ -257,7 +257,6 @@ extern void usb_hcd_pci_remove(struct pci_dev *dev);
 
 #ifdef CONFIG_PM
 extern int usb_hcd_pci_suspend(struct pci_dev *dev, pm_message_t msg);
-extern int usb_hcd_pci_resume_early(struct pci_dev *dev);
 extern int usb_hcd_pci_resume(struct pci_dev *dev);
 #endif /* CONFIG_PM */
 
index 31fb204f44c6a020467f952b5ed855132ba0dff7..49e7f56e0d7f72ea14800a3caf719538897234e3 100644 (file)
@@ -653,7 +653,7 @@ int usb_get_descriptor(struct usb_device *dev, unsigned char type,
                if (result <= 0 && result != -ETIMEDOUT)
                        continue;
                if (result > 1 && ((u8 *)buf)[1] != type) {
-                       result = -EPROTO;
+                       result = -ENODATA;
                        continue;
                }
                break;
@@ -696,8 +696,13 @@ static int usb_get_string(struct usb_device *dev, unsigned short langid,
                        USB_REQ_GET_DESCRIPTOR, USB_DIR_IN,
                        (USB_DT_STRING << 8) + index, langid, buf, size,
                        USB_CTRL_GET_TIMEOUT);
-               if (!(result == 0 || result == -EPIPE))
-                       break;
+               if (result == 0 || result == -EPIPE)
+                       continue;
+               if (result > 1 && ((u8 *) buf)[1] != USB_DT_STRING) {
+                       result = -ENODATA;
+                       continue;
+               }
+               break;
        }
        return result;
 }
index 3219d137340a31009893184301b801068fe7e62a..e55fef52a5dc5797c02121e0d7482d528a66144f 100644 (file)
@@ -191,6 +191,7 @@ config USB_GADGET_OMAP
        boolean "OMAP USB Device Controller"
        depends on ARCH_OMAP
        select ISP1301_OMAP if MACH_OMAP_H2 || MACH_OMAP_H3 || MACH_OMAP_H4_OTG
+       select USB_OTG_UTILS if ARCH_OMAP
        help
           Many Texas Instruments OMAP processors have flexible full
           speed USB device controllers, with support for up to 30
index 80c2e7e9622f63507c16b4ec2682709936423f45..38aa896cc5db36317c8e4b7e03a1dc4734bb5c1c 100644 (file)
@@ -366,9 +366,9 @@ obex_bind(struct usb_configuration *c, struct usb_function *f)
                f->hs_descriptors = usb_copy_descriptors(hs_function);
 
                obex->hs.obex_in = usb_find_endpoint(hs_function,
-                               f->descriptors, &obex_hs_ep_in_desc);
+                               f->hs_descriptors, &obex_hs_ep_in_desc);
                obex->hs.obex_out = usb_find_endpoint(hs_function,
-                               f->descriptors, &obex_hs_ep_out_desc);
+                               f->hs_descriptors, &obex_hs_ep_out_desc);
        }
 
        /* Avoid letting this gadget enumerate until the userspace
index b10fa31cc9157a8f60a538ac8da42946f366efdc..1ab9dac7e12df8eec07e5ed278e48ca90cdd3bc5 100644 (file)
@@ -3879,7 +3879,11 @@ static int __init check_parameters(struct fsg_dev *fsg)
        mod_data.protocol_type = USB_SC_SCSI;
        mod_data.protocol_name = "Transparent SCSI";
 
-       if (gadget_is_sh(fsg->gadget))
+       /* Some peripheral controllers are known not to be able to
+        * halt bulk endpoints correctly.  If one of them is present,
+        * disable stalls.
+        */
+       if (gadget_is_sh(fsg->gadget) || gadget_is_at91(fsg->gadget))
                mod_data.can_stall = 0;
 
        if (mod_data.release == 0xffff) {       // Parameter wasn't set
index f3c6703cffda3c700399f8352f2ed5bf76530b6f..d8d9a52a44b34e5a517c3a8dd923478e3b88b198 100644 (file)
@@ -404,7 +404,10 @@ static void struct_ep_qh_setup(struct fsl_udc *udc, unsigned char ep_num,
        }
        if (zlt)
                tmp |= EP_QUEUE_HEAD_ZLT_SEL;
+
        p_QH->max_pkt_length = cpu_to_le32(tmp);
+       p_QH->next_dtd_ptr = 1;
+       p_QH->size_ioc_int_sts = 0;
 
        return;
 }
index 9b36205c5759d3d1f8cf11b8edeba1958d1371e1..0ce4e2819847c13fb7548fcf910923495d4588ba 100644 (file)
@@ -904,8 +904,8 @@ static void pxa25x_ep_fifo_flush(struct usb_ep *_ep)
 
        /* most IN status is the same, but ISO can't stall */
        *ep->reg_udccs = UDCCS_BI_TPC|UDCCS_BI_FTF|UDCCS_BI_TUR
-               | (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC)
-                       ? 0 : UDCCS_BI_SST;
+               | (ep->bmAttributes == USB_ENDPOINT_XFER_ISOC
+                       ? 0 : UDCCS_BI_SST);
 }
 
 
index d2860a823680065859ee105872732f65445f94b1..2b4660e08c4db367af0e6c5159855b675616eb9a 100644 (file)
@@ -170,7 +170,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
        int                     i, count;
        rndis_query_cmplt_type  *resp;
        struct net_device       *net;
-       struct net_device_stats *stats;
+       const struct net_device_stats   *stats;
 
        if (!r) return -ENOMEM;
        resp = (rndis_query_cmplt_type *) r->buf;
@@ -193,10 +193,7 @@ gen_ndis_query_resp (int configNr, u32 OID, u8 *buf, unsigned buf_len,
        resp->InformationBufferOffset = cpu_to_le32 (16);
 
        net = rndis_per_dev_params[configNr].dev;
-       if (net->get_stats)
-               stats = net->get_stats(net);
-       else
-               stats = NULL;
+       stats = dev_get_stats(net);
 
        switch (OID) {
 
index 4725d15d096f559fc833d0e0f6323bcff4aa7631..e551bb38852be35eefeb532a23c260ecff6109ff 100644 (file)
@@ -485,6 +485,7 @@ static int ehci_init(struct usb_hcd *hcd)
         * periodic_size can shrink by USBCMD update if hcc_params allows.
         */
        ehci->periodic_size = DEFAULT_I_TDPS;
+       INIT_LIST_HEAD(&ehci->cached_itd_list);
        if ((retval = ehci_mem_init(ehci, GFP_KERNEL)) < 0)
                return retval;
 
@@ -497,6 +498,7 @@ static int ehci_init(struct usb_hcd *hcd)
 
        ehci->reclaim = NULL;
        ehci->next_uframe = -1;
+       ehci->clock_frame = -1;
 
        /*
         * dedicate a qh for the async ring head, since we couldn't unlink
index 0431397836f65e859f1a2b1829f418fa3697f65d..10d52919abbb1513feefe95ecaa5c5aa518a7443 100644 (file)
@@ -128,6 +128,7 @@ static inline void qh_put (struct ehci_qh *qh)
 
 static void ehci_mem_cleanup (struct ehci_hcd *ehci)
 {
+       free_cached_itd_list(ehci);
        if (ehci->async)
                qh_put (ehci->async);
        ehci->async = NULL;
index bb21fb0a4969d0bc793f22c091c5053b973ddeac..abb9a7706ec7c370dd0835db9d04b0e3f1abc6b8 100644 (file)
@@ -432,7 +432,6 @@ static struct pci_driver ehci_pci_driver = {
 
 #ifdef CONFIG_PM
        .suspend =      usb_hcd_pci_suspend,
-       .resume_early = usb_hcd_pci_resume_early,
        .resume =       usb_hcd_pci_resume,
 #endif
        .shutdown =     usb_hcd_pci_shutdown,
index a081ee65bde6d933f3f2000c67028d461ece27c7..07bcb931021b48a9b00ffeac887288448c7d696e 100644 (file)
@@ -1004,7 +1004,8 @@ iso_stream_put(struct ehci_hcd *ehci, struct ehci_iso_stream *stream)
 
                is_in = (stream->bEndpointAddress & USB_DIR_IN) ? 0x10 : 0;
                stream->bEndpointAddress &= 0x0f;
-               stream->ep->hcpriv = NULL;
+               if (stream->ep)
+                       stream->ep->hcpriv = NULL;
 
                if (stream->rescheduled) {
                        ehci_info (ehci, "ep%d%s-iso rescheduled "
@@ -1653,14 +1654,28 @@ itd_complete (
                        (stream->bEndpointAddress & USB_DIR_IN) ? "in" : "out");
        }
        iso_stream_put (ehci, stream);
-       /* OK to recycle this ITD now that its completion callback ran. */
+
 done:
        usb_put_urb(urb);
        itd->urb = NULL;
-       itd->stream = NULL;
-       list_move(&itd->itd_list, &stream->free_list);
-       iso_stream_put(ehci, stream);
-
+       if (ehci->clock_frame != itd->frame || itd->index[7] != -1) {
+               /* OK to recycle this ITD now. */
+               itd->stream = NULL;
+               list_move(&itd->itd_list, &stream->free_list);
+               iso_stream_put(ehci, stream);
+       } else {
+               /* HW might remember this ITD, so we can't recycle it yet.
+                * Move it to a safe place until a new frame starts.
+                */
+               list_move(&itd->itd_list, &ehci->cached_itd_list);
+               if (stream->refcount == 2) {
+                       /* If iso_stream_put() were called here, stream
+                        * would be freed.  Instead, just prevent reuse.
+                        */
+                       stream->ep->hcpriv = NULL;
+                       stream->ep = NULL;
+               }
+       }
        return retval;
 }
 
@@ -2101,6 +2116,20 @@ done:
 
 /*-------------------------------------------------------------------------*/
 
+static void free_cached_itd_list(struct ehci_hcd *ehci)
+{
+       struct ehci_itd *itd, *n;
+
+       list_for_each_entry_safe(itd, n, &ehci->cached_itd_list, itd_list) {
+               struct ehci_iso_stream  *stream = itd->stream;
+               itd->stream = NULL;
+               list_move(&itd->itd_list, &stream->free_list);
+               iso_stream_put(ehci, stream);
+       }
+}
+
+/*-------------------------------------------------------------------------*/
+
 static void
 scan_periodic (struct ehci_hcd *ehci)
 {
@@ -2115,10 +2144,17 @@ scan_periodic (struct ehci_hcd *ehci)
         * Touches as few pages as possible:  cache-friendly.
         */
        now_uframe = ehci->next_uframe;
-       if (HC_IS_RUNNING (ehci_to_hcd(ehci)->state))
+       if (HC_IS_RUNNING(ehci_to_hcd(ehci)->state)) {
                clock = ehci_readl(ehci, &ehci->regs->frame_index);
-       else
+               clock_frame = (clock >> 3) % ehci->periodic_size;
+       } else  {
                clock = now_uframe + mod - 1;
+               clock_frame = -1;
+       }
+       if (ehci->clock_frame != clock_frame) {
+               free_cached_itd_list(ehci);
+               ehci->clock_frame = clock_frame;
+       }
        clock %= mod;
        clock_frame = clock >> 3;
 
@@ -2277,6 +2313,10 @@ restart:
                        /* rescan the rest of this frame, then ... */
                        clock = now;
                        clock_frame = clock >> 3;
+                       if (ehci->clock_frame != clock_frame) {
+                               free_cached_itd_list(ehci);
+                               ehci->clock_frame = clock_frame;
+                       }
                } else {
                        now_uframe++;
                        now_uframe %= mod;
index fb7054ccf4fce90c516397f9923e6195c149768e..262b00c9b334286583d8fb84d394bac07a86a304 100644 (file)
@@ -87,6 +87,10 @@ struct ehci_hcd {                    /* one per controller */
        int                     next_uframe;    /* scan periodic, start here */
        unsigned                periodic_sched; /* periodic activity count */
 
+       /* list of itds completed while clock_frame was still active */
+       struct list_head        cached_itd_list;
+       unsigned                clock_frame;
+
        /* per root hub port */
        unsigned long           reset_done [EHCI_MAX_ROOT_PORTS];
 
@@ -220,6 +224,8 @@ timer_action (struct ehci_hcd *ehci, enum ehci_timer_action action)
        }
 }
 
+static void free_cached_itd_list(struct ehci_hcd *ehci);
+
 /*-------------------------------------------------------------------------*/
 
 #include <linux/usb/ehci_def.h>
index 5d625c3fd4232b163699ac5975bfe6da08d639a7..f9961b4c0da3e5065f054aa7dc34a619e00b8187 100644 (file)
@@ -487,7 +487,6 @@ static struct pci_driver ohci_pci_driver = {
 
 #ifdef CONFIG_PM
        .suspend =      usb_hcd_pci_suspend,
-       .resume_early = usb_hcd_pci_resume_early,
        .resume =       usb_hcd_pci_resume,
 #endif
 
index 944f7e0ca4df1327eeb7025f706677741f462ae0..cf5e4cf7ea425828ca099af27dc6d2639ded8f9a 100644 (file)
@@ -942,7 +942,6 @@ static struct pci_driver uhci_pci_driver = {
 
 #ifdef CONFIG_PM
        .suspend =      usb_hcd_pci_suspend,
-       .resume_early = usb_hcd_pci_resume_early,
        .resume =       usb_hcd_pci_resume,
 #endif /* PM */
 };
index 2291c5f5af5152b3aadcf029f48fcc73dd05fba6..958751ccea432cd3f41bda0dbd55828f5d15efd4 100644 (file)
@@ -227,13 +227,13 @@ void scan_async_work(struct work_struct *work)
         * Now that the ASL is updated, complete the removal of any
         * removed qsets.
         */
-       spin_lock(&whc->lock);
+       spin_lock_irq(&whc->lock);
 
        list_for_each_entry_safe(qset, t, &whc->async_removed_list, list_node) {
                qset_remove_complete(whc, qset);
        }
 
-       spin_unlock(&whc->lock);
+       spin_unlock_irq(&whc->lock);
 }
 
 /**
index 7dc85a0bee7c2f563c3c89f8e7d5aa9229ffd4df..df8b85f07092e3c398a410fff318f9b9b772ba7c 100644 (file)
@@ -255,13 +255,13 @@ void scan_periodic_work(struct work_struct *work)
         * Now that the PZL is updated, complete the removal of any
         * removed qsets.
         */
-       spin_lock(&whc->lock);
+       spin_lock_irq(&whc->lock);
 
        list_for_each_entry_safe(qset, t, &whc->periodic_removed_list, list_node) {
                qset_remove_complete(whc, qset);
        }
 
-       spin_unlock(&whc->lock);
+       spin_unlock_irq(&whc->lock);
 }
 
 /**
index 5a8fd5d57a11a9e303969f623157e01030d3c569..2dc7606f319c1e0e857e6c70a0178e0f477a5d6c 100644 (file)
@@ -377,18 +377,8 @@ int __init musb_platform_init(struct musb *musb)
        u32             revision;
 
        musb->mregs += DAVINCI_BASE_OFFSET;
-#if 0
-       /* REVISIT there's something odd about clocking, this
-        * didn't appear do the job ...
-        */
-       musb->clock = clk_get(pDevice, "usb");
-       if (IS_ERR(musb->clock))
-               return PTR_ERR(musb->clock);
 
-       status = clk_enable(musb->clock);
-       if (status < 0)
-               return -ENODEV;
-#endif
+       clk_enable(musb->clock);
 
        /* returns zero if e.g. not clocked */
        revision = musb_readl(tibase, DAVINCI_USB_VERSION_REG);
@@ -453,5 +443,8 @@ int musb_platform_exit(struct musb *musb)
        }
 
        phy_off();
+
+       clk_disable(musb->clock);
+
        return 0;
 }
index 2cc34fa05b7391813cb386342849b15bab714bc5..af77e46590065fd5b8890bd819ac20d0cc912b82 100644 (file)
 
 
 unsigned musb_debug;
-module_param(musb_debug, uint, S_IRUGO | S_IWUSR);
+module_param_named(debug, musb_debug, uint, S_IRUGO | S_IWUSR);
 MODULE_PARM_DESC(debug, "Debug message level. Default = 0");
 
 #define DRIVER_AUTHOR "Mentor Graphics, Texas Instruments, Nokia"
@@ -767,6 +767,7 @@ static irqreturn_t musb_stage2_irq(struct musb *musb, u8 int_usb,
 #ifdef CONFIG_USB_MUSB_HDRC_HCD
                case OTG_STATE_A_HOST:
                case OTG_STATE_A_SUSPEND:
+                       usb_hcd_resume_root_hub(musb_to_hcd(musb));
                        musb_root_disconnect(musb);
                        if (musb->a_wait_bcon != 0)
                                musb_platform_try_idle(musb, jiffies
@@ -1815,7 +1816,7 @@ static void musb_free(struct musb *musb)
 #ifdef CONFIG_SYSFS
        device_remove_file(musb->controller, &dev_attr_mode);
        device_remove_file(musb->controller, &dev_attr_vbus);
-#ifdef CONFIG_USB_MUSB_OTG
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
        device_remove_file(musb->controller, &dev_attr_srp);
 #endif
 #endif
@@ -2063,7 +2064,7 @@ fail2:
 #ifdef CONFIG_SYSFS
        device_remove_file(musb->controller, &dev_attr_mode);
        device_remove_file(musb->controller, &dev_attr_vbus);
-#ifdef CONFIG_USB_MUSB_OTG
+#ifdef CONFIG_USB_GADGET_MUSB_HDRC
        device_remove_file(musb->controller, &dev_attr_srp);
 #endif
 #endif
@@ -2243,10 +2244,10 @@ static int __init musb_init(void)
        return platform_driver_probe(&musb_driver, musb_probe);
 }
 
-/* make us init after usbcore and before usb
- * gadget and host-side drivers start to register
+/* make us init after usbcore and i2c (transceivers, regulators, etc)
+ * and before usb gadget and host-side drivers start to register
  */
-subsys_initcall(musb_init);
+fs_initcall(musb_init);
 
 static void __exit musb_cleanup(void)
 {
index 4ea305387981655db2aca1858fe4c5fe6b9011a2..c7ebd0867fcca9281ecf25abc130c91389444240 100644 (file)
@@ -575,7 +575,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
        struct usb_request      *request = &req->request;
        struct musb_ep          *musb_ep = &musb->endpoints[epnum].ep_out;
        void __iomem            *epio = musb->endpoints[epnum].regs;
-       u16                     fifo_count = 0;
+       unsigned                fifo_count = 0;
        u16                     len = musb_ep->packet_sz;
 
        csr = musb_readw(epio, MUSB_RXCSR);
@@ -687,7 +687,7 @@ static void rxstate(struct musb *musb, struct musb_request *req)
                                        len, fifo_count,
                                        musb_ep->packet_sz);
 
-                       fifo_count = min(len, fifo_count);
+                       fifo_count = min_t(unsigned, len, fifo_count);
 
 #ifdef CONFIG_USB_TUSB_OMAP_DMA
                        if (tusb_dma_omap() && musb_ep->dma) {
index a035ceccf95019c09082139be0727bf395a7a311..6dbbd0786a6a0955877dca888f107b641d50eec0 100644 (file)
@@ -335,16 +335,11 @@ musb_save_toggle(struct musb_hw_ep *ep, int is_in, struct urb *urb)
 static struct musb_qh *
 musb_giveback(struct musb_qh *qh, struct urb *urb, int status)
 {
-       int                     is_in;
        struct musb_hw_ep       *ep = qh->hw_ep;
        struct musb             *musb = ep->musb;
+       int                     is_in = usb_pipein(urb->pipe);
        int                     ready = qh->is_ready;
 
-       if (ep->is_shared_fifo)
-               is_in = 1;
-       else
-               is_in = usb_pipein(urb->pipe);
-
        /* save toggle eagerly, for paranoia */
        switch (qh->type) {
        case USB_ENDPOINT_XFER_BULK:
@@ -432,7 +427,7 @@ musb_advance_schedule(struct musb *musb, struct urb *urb,
        else
                qh = musb_giveback(qh, urb, urb->status);
 
-       if (qh && qh->is_ready && !list_empty(&qh->hep->urb_list)) {
+       if (qh != NULL && qh->is_ready) {
                DBG(4, "... next ep%d %cX urb %p\n",
                                hw_ep->epnum, is_in ? 'R' : 'T',
                                next_urb(qh));
@@ -942,8 +937,8 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb)
        switch (musb->ep0_stage) {
        case MUSB_EP0_IN:
                fifo_dest = urb->transfer_buffer + urb->actual_length;
-               fifo_count = min(len, ((u16) (urb->transfer_buffer_length
-                                       - urb->actual_length)));
+               fifo_count = min_t(size_t, len, urb->transfer_buffer_length -
+                                  urb->actual_length);
                if (fifo_count < len)
                        urb->status = -EOVERFLOW;
 
@@ -976,10 +971,9 @@ static bool musb_h_ep0_continue(struct musb *musb, u16 len, struct urb *urb)
                }
                /* FALLTHROUGH */
        case MUSB_EP0_OUT:
-               fifo_count = min(qh->maxpacket, ((u16)
-                               (urb->transfer_buffer_length
-                               - urb->actual_length)));
-
+               fifo_count = min_t(size_t, qh->maxpacket,
+                                  urb->transfer_buffer_length -
+                                  urb->actual_length);
                if (fifo_count) {
                        fifo_dest = (u8 *) (urb->transfer_buffer
                                        + urb->actual_length);
@@ -1161,7 +1155,8 @@ void musb_host_tx(struct musb *musb, u8 epnum)
        struct urb              *urb;
        struct musb_hw_ep       *hw_ep = musb->endpoints + epnum;
        void __iomem            *epio = hw_ep->regs;
-       struct musb_qh          *qh = hw_ep->out_qh;
+       struct musb_qh          *qh = hw_ep->is_shared_fifo ? hw_ep->in_qh
+                                                           : hw_ep->out_qh;
        u32                     status = 0;
        void __iomem            *mbase = musb->mregs;
        struct dma_channel      *dma;
@@ -1308,7 +1303,8 @@ void musb_host_tx(struct musb *musb, u8 epnum)
                 * packets before updating TXCSR ... other docs disagree ...
                 */
                /* PIO:  start next packet in this URB */
-               wLength = min(qh->maxpacket, (u16) wLength);
+               if (wLength > qh->maxpacket)
+                       wLength = qh->maxpacket;
                musb_write_fifo(hw_ep, wLength, buf);
                qh->segsize = wLength;
 
@@ -1867,19 +1863,21 @@ static int musb_urb_enqueue(
        }
        qh->type_reg = type_reg;
 
-       /* precompute rxinterval/txinterval register */
-       interval = min((u8)16, epd->bInterval); /* log encoding */
+       /* Precompute RXINTERVAL/TXINTERVAL register */
        switch (qh->type) {
        case USB_ENDPOINT_XFER_INT:
-               /* fullspeed uses linear encoding */
-               if (USB_SPEED_FULL == urb->dev->speed) {
-                       interval = epd->bInterval;
-                       if (!interval)
-                               interval = 1;
+               /*
+                * Full/low speeds use the  linear encoding,
+                * high speed uses the logarithmic encoding.
+                */
+               if (urb->dev->speed <= USB_SPEED_FULL) {
+                       interval = max_t(u8, epd->bInterval, 1);
+                       break;
                }
                /* FALLTHROUGH */
        case USB_ENDPOINT_XFER_ISOC:
-               /* iso always uses log encoding */
+               /* ISO always uses logarithmic encoding */
+               interval = min_t(u8, epd->bInterval, 16);
                break;
        default:
                /* REVISIT we actually want to use NAK limits, hinting to the
@@ -2037,9 +2035,9 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                goto done;
 
        /* Any URB not actively programmed into endpoint hardware can be
-        * immediately given back.  Such an URB must be at the head of its
+        * immediately given back; that's any URB not at the head of an
         * endpoint queue, unless someday we get real DMA queues.  And even
-        * then, it might not be known to the hardware...
+        * if it's at the head, it might not be known to the hardware...
         *
         * Otherwise abort current transfer, pending dma, etc.; urb->status
         * has already been updated.  This is a synchronous abort; it'd be
@@ -2078,6 +2076,15 @@ static int musb_urb_dequeue(struct usb_hcd *hcd, struct urb *urb, int status)
                qh->is_ready = 0;
                __musb_giveback(musb, urb, 0);
                qh->is_ready = ready;
+
+               /* If nothing else (usually musb_giveback) is using it
+                * and its URB list has emptied, recycle this qh.
+                */
+               if (ready && list_empty(&qh->hep->urb_list)) {
+                       qh->hep->hcpriv = NULL;
+                       list_del(&qh->ring);
+                       kfree(qh);
+               }
        } else
                ret = musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
 done:
@@ -2093,15 +2100,16 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
        unsigned long           flags;
        struct musb             *musb = hcd_to_musb(hcd);
        u8                      is_in = epnum & USB_DIR_IN;
-       struct musb_qh          *qh = hep->hcpriv;
-       struct urb              *urb, *tmp;
+       struct musb_qh          *qh;
+       struct urb              *urb;
        struct list_head        *sched;
 
-       if (!qh)
-               return;
-
        spin_lock_irqsave(&musb->lock, flags);
 
+       qh = hep->hcpriv;
+       if (qh == NULL)
+               goto exit;
+
        switch (qh->type) {
        case USB_ENDPOINT_XFER_CONTROL:
                sched = &musb->control;
@@ -2135,13 +2143,28 @@ musb_h_disable(struct usb_hcd *hcd, struct usb_host_endpoint *hep)
 
                /* cleanup */
                musb_cleanup_urb(urb, qh, urb->pipe & USB_DIR_IN);
-       } else
-               urb = NULL;
 
-       /* then just nuke all the others */
-       list_for_each_entry_safe_from(urb, tmp, &hep->urb_list, urb_list)
-               musb_giveback(qh, urb, -ESHUTDOWN);
+               /* Then nuke all the others ... and advance the
+                * queue on hw_ep (e.g. bulk ring) when we're done.
+                */
+               while (!list_empty(&hep->urb_list)) {
+                       urb = next_urb(qh);
+                       urb->status = -ESHUTDOWN;
+                       musb_advance_schedule(musb, urb, qh->hw_ep, is_in);
+               }
+       } else {
+               /* Just empty the queue; the hardware is busy with
+                * other transfers, and since !qh->is_ready nothing
+                * will activate any of these as it advances.
+                */
+               while (!list_empty(&hep->urb_list))
+                       __musb_giveback(musb, next_urb(qh), -ESHUTDOWN);
 
+               hep->hcpriv = NULL;
+               list_del(&qh->ring);
+               kfree(qh);
+       }
+exit:
        spin_unlock_irqrestore(&musb->lock, flags);
 }
 
index bfd0b68ceccd52942b864a79dfccdbe28735f5a5..b7c132bded7f43bf5fc6b69e7852d8e87dbabbf1 100644 (file)
@@ -294,7 +294,11 @@ static int  option_send_setup(struct tty_struct *tty, struct usb_serial_port *po
 
 /* Ericsson products */
 #define ERICSSON_VENDOR_ID                     0x0bdb
-#define ERICSSON_PRODUCT_F3507G                        0x1900
+#define ERICSSON_PRODUCT_F3507G_1              0x1900
+#define ERICSSON_PRODUCT_F3507G_2              0x1902
+
+#define BENQ_VENDOR_ID                         0x04a5
+#define BENQ_PRODUCT_H10                       0x4068
 
 static struct usb_device_id option_ids[] = {
        { USB_DEVICE(OPTION_VENDOR_ID, OPTION_PRODUCT_COLT) },
@@ -509,7 +513,10 @@ static struct usb_device_id option_ids[] = {
        { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF626) },
        { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_MF628) },
        { USB_DEVICE(ZTE_VENDOR_ID, ZTE_PRODUCT_CDMA_TECH) },
-       { USB_DEVICE(ERICSSON_VENDOR_ID, ERICSSON_PRODUCT_F3507G) },
+       { USB_DEVICE(ERICSSON_VENDOR_ID, ERICSSON_PRODUCT_F3507G_1) },
+       { USB_DEVICE(ERICSSON_VENDOR_ID, ERICSSON_PRODUCT_F3507G_2) },
+       { USB_DEVICE(BENQ_VENDOR_ID, BENQ_PRODUCT_H10) },
+       { USB_DEVICE(0x1da5, 0x4515) }, /* BenQ H20 */
        { } /* Terminating entry */
 };
 MODULE_DEVICE_TABLE(usb, option_ids);
index 50dc33a6065bd01b61bac0b26da138eabd015c68..6f59c8e510ea433be6f623890d97bab675d97b77 100644 (file)
@@ -907,13 +907,13 @@ UNUSUAL_DEV(  0x05e3, 0x0701, 0x0000, 0xffff,
                "Genesys Logic",
                "USB to IDE Optical",
                US_SC_DEVICE, US_PR_DEVICE, NULL,
-               US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 ),
+               US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 | US_FL_IGNORE_RESIDUE ),
 
 UNUSUAL_DEV(  0x05e3, 0x0702, 0x0000, 0xffff,
                "Genesys Logic",
                "USB to IDE Disk",
                US_SC_DEVICE, US_PR_DEVICE, NULL,
-               US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 ),
+               US_FL_GO_SLOW | US_FL_MAX_SECTORS_64 | US_FL_IGNORE_RESIDUE ),
 
 /* Reported by Ben Efros <ben@pc-doctor.com> */
 UNUSUAL_DEV(  0x05e3, 0x0723, 0x9451, 0x9451,
index bf0af660df8a07e7b922871a8da860dff77accea..fb19803060cf6c35727c9f287f5668bf670ed969 100644 (file)
@@ -1054,10 +1054,7 @@ config FB_RIVA_BACKLIGHT
 
 config FB_I810
        tristate "Intel 810/815 support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && PCI && X86_32
-       select AGP
-       select AGP_INTEL
-       select FB
+       depends on EXPERIMENTAL && FB && PCI && X86_32 && AGP_INTEL
        select FB_MODE_HELPERS
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
@@ -1120,10 +1117,7 @@ config FB_CARILLO_RANCH
 
 config FB_INTEL
        tristate "Intel 830M/845G/852GM/855GM/865G/915G/945G/945GM/965G/965GM support (EXPERIMENTAL)"
-       depends on EXPERIMENTAL && PCI && X86
-       select FB
-       select AGP
-       select AGP_INTEL
+       depends on EXPERIMENTAL && FB && PCI && X86 && AGP_INTEL
        select FB_MODE_HELPERS
        select FB_CFB_FILLRECT
        select FB_CFB_COPYAREA
index 8058572a74283303f178d03d0e97e64632c85099..018850c116c646edbeadf5cc6e4fc828e3901eff 100644 (file)
@@ -841,7 +841,7 @@ static int tt_detect(void)
                tt_dmasnd.ctrl = DMASND_CTRL_OFF;
                udelay(20);             /* wait a while for things to settle down */
        }
-       mono_moni = (mfp.par_dt_reg & 0x80) == 0;
+       mono_moni = (st_mfp.par_dt_reg & 0x80) == 0;
 
        tt_get_par(&par);
        tt_encode_var(&atafb_predefined[0], &par);
@@ -2035,7 +2035,7 @@ static int stste_detect(void)
                tt_dmasnd.ctrl = DMASND_CTRL_OFF;
                udelay(20);             /* wait a while for things to settle down */
        }
-       mono_moni = (mfp.par_dt_reg & 0x80) == 0;
+       mono_moni = (st_mfp.par_dt_reg & 0x80) == 0;
 
        stste_get_par(&par);
        stste_encode_var(&atafb_predefined[0], &par);
@@ -2086,20 +2086,20 @@ static void st_ovsc_switch(void)
                return;
        local_irq_save(flags);
 
-       mfp.tim_ct_b = 0x10;
-       mfp.active_edge |= 8;
-       mfp.tim_ct_b = 0;
-       mfp.tim_dt_b = 0xf0;
-       mfp.tim_ct_b = 8;
-       while (mfp.tim_dt_b > 1)        /* TOS does it this way, don't ask why */
+       st_mfp.tim_ct_b = 0x10;
+       st_mfp.active_edge |= 8;
+       st_mfp.tim_ct_b = 0;
+       st_mfp.tim_dt_b = 0xf0;
+       st_mfp.tim_ct_b = 8;
+       while (st_mfp.tim_dt_b > 1)     /* TOS does it this way, don't ask why */
                ;
-       new = mfp.tim_dt_b;
+       new = st_mfp.tim_dt_b;
        do {
                udelay(LINE_DELAY);
                old = new;
-               new = mfp.tim_dt_b;
+               new = st_mfp.tim_dt_b;
        } while (old != new);
-       mfp.tim_ct_b = 0x10;
+       st_mfp.tim_ct_b = 0x10;
        udelay(SYNC_DELAY);
 
        if (atari_switches & ATARI_SWITCH_OVSC_IKBD)
index e6e299feb51bd5151eba736e03309d89da1d29ae..2181ce4d7ebd4c75009683c2f50bb0d1eebcd034 100644 (file)
@@ -2365,7 +2365,6 @@ static void fbcon_aty128_bmove(struct display *p, int sy, int sx, int dy, int dx
 static void aty128_set_suspend(struct aty128fb_par *par, int suspend)
 {
        u32     pmgt;
-       u16     pwr_command;
        struct pci_dev *pdev = par->pdev;
 
        if (!par->pm_reg)
index 48ff701d3a72b9cd1d5a6cb7b345a89e9678e50d..2552b9f325ee9b4c33eea202329e23e47b544c3e 100644 (file)
@@ -2230,7 +2230,7 @@ static int __devexit pxafb_remove(struct platform_device *dev)
 
 static struct platform_driver pxafb_driver = {
        .probe          = pxafb_probe,
-       .remove         = pxafb_remove,
+       .remove         = __devexit_p(pxafb_remove),
        .suspend        = pxafb_suspend,
        .resume         = pxafb_resume,
        .driver         = {
index 8d0b1fb1e52edb6eeb57f98887e399d8a4c4b7af..1f51366417b9370b064488427eb5353234b117e1 100644 (file)
@@ -16,6 +16,12 @@ config W1_SLAVE_SMEM
          Say Y here if you want to connect 1-wire
          simple 64bit memory rom(ds2401/ds2411/ds1990*) to your wire.
 
+config W1_SLAVE_DS2431
+       tristate "1kb EEPROM family support (DS2431)"
+       help
+         Say Y here if you want to use a 1-wire
+         1kb EEPROM family device (DS2431)
+
 config W1_SLAVE_DS2433
        tristate "4kb EEPROM family support (DS2433)"
        help
index 990f400b6d22dc82563a382f6c0b7defd09820a6..f1f51f19b129115790996cb7349c1e53b1a9db8c 100644 (file)
@@ -4,6 +4,7 @@
 
 obj-$(CONFIG_W1_SLAVE_THERM)   += w1_therm.o
 obj-$(CONFIG_W1_SLAVE_SMEM)    += w1_smem.o
+obj-$(CONFIG_W1_SLAVE_DS2431)  += w1_ds2431.o
 obj-$(CONFIG_W1_SLAVE_DS2433)  += w1_ds2433.o
 obj-$(CONFIG_W1_SLAVE_DS2760)  += w1_ds2760.o
 obj-$(CONFIG_W1_SLAVE_BQ27000) += w1_bq27000.o
index 858c16a544c21bc4517c50b853c394e8004373be..1394471488228d2f747475256a3236103a7973f4 100644 (file)
@@ -156,6 +156,9 @@ out_up:
  */
 static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data)
 {
+#ifdef CONFIG_W1_SLAVE_DS2433_CRC
+       struct w1_f23_data *f23 = sl->family_data;
+#endif
        u8 wrbuf[4];
        u8 rdbuf[W1_PAGE_SIZE + 3];
        u8 es = (addr + len - 1) & 0x1f;
@@ -196,7 +199,9 @@ static int w1_f23_write(struct w1_slave *sl, int addr, int len, const u8 *data)
 
        /* Reset the bus to wake up the EEPROM (this may not be needed) */
        w1_reset_bus(sl->master);
-
+#ifdef CONFIG_W1_SLAVE_DS2433_CRC
+       f23->validcrc &= ~(1 << (addr >> W1_PAGE_BITS));
+#endif
        return 0;
 }
 
index 09a3d5522b43d9a2b6d00f3612f6c88c516068ae..325c10ff6a2cd2dc616228bead8fc5c8cdb7f034 100644 (file)
@@ -406,7 +406,7 @@ config ITCO_WDT
        ---help---
          Hardware driver for the intel TCO timer based watchdog devices.
          These drivers are included in the Intel 82801 I/O Controller
-         Hub family (from ICH0 up to ICH8) and in the Intel 6300ESB
+         Hub family (from ICH0 up to ICH10) and in the Intel 63xxESB
          controller hub.
 
          The TCO (Total Cost of Ownership) timer is a watchdog timer
index 5531691f46eaf51746db11cd23acc61dbde095ed..e35d545892325b15f1b26427bf5475728e8a8504 100644 (file)
@@ -107,10 +107,10 @@ static int at91_wdt_close(struct inode *inode, struct file *file)
 static int at91_wdt_settimeout(int new_time)
 {
        /*
-        * All counting occurs at SLOW_CLOCK / 128 = 0.256 Hz
+        * All counting occurs at SLOW_CLOCK / 128 = 256 Hz
         *
         * Since WDV is a 16-bit counter, the maximum period is
-        * 65536 / 0.256 = 256 seconds.
+        * 65536 / 256 = 256 seconds.
         */
        if ((new_time <= 0) || (new_time > WDT_MAX_TIME))
                return -EINVAL;
index b1da287f90ecc24bc5395234a5d71198f0fb630a..a56ac84381b1d3ad3a879cee04bfd657fe907565 100644 (file)
@@ -18,6 +18,7 @@
 #include <linux/errno.h>
 #include <linux/fs.h>
 #include <linux/init.h>
+#include <linux/io.h>
 #include <linux/kernel.h>
 #include <linux/miscdevice.h>
 #include <linux/module.h>
index 2474ebca88f6d816837765b667bdf7e9e4ea087f..d8264ad0be41f91f8ac9cfcc8ce79faff8d0f48d 100644 (file)
@@ -1,7 +1,7 @@
 /*
  *     intel TCO vendor specific watchdog driver support
  *
- *     (c) Copyright 2006-2008 Wim Van Sebroeck <wim@iguana.be>.
+ *     (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>.
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
@@ -19,7 +19,7 @@
 
 /* Module and version information */
 #define DRV_NAME       "iTCO_vendor_support"
-#define DRV_VERSION    "1.02"
+#define DRV_VERSION    "1.03"
 #define PFX            DRV_NAME ": "
 
 /* Includes */
@@ -77,6 +77,26 @@ MODULE_PARM_DESC(vendorsupport, "iTCO vendor specific support mode, default=0 (n
  *         20.6 seconds.
  */
 
+static void supermicro_old_pre_start(unsigned long acpibase)
+{
+       unsigned long val32;
+
+       /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
+       val32 = inl(SMI_EN);
+       val32 &= 0xffffdfff;    /* Turn off SMI clearing watchdog */
+       outl(val32, SMI_EN);    /* Needed to activate watchdog */
+}
+
+static void supermicro_old_pre_stop(unsigned long acpibase)
+{
+       unsigned long val32;
+
+       /* Bit 13: TCO_EN -> 1 = Enables the TCO logic to generate SMI# */
+       val32 = inl(SMI_EN);
+       val32 |= 0x00002000;    /* Turn on SMI clearing watchdog */
+       outl(val32, SMI_EN);    /* Needed to deactivate watchdog */
+}
+
 static void supermicro_old_pre_keepalive(unsigned long acpibase)
 {
        /* Reload TCO Timer (done in iTCO_wdt_keepalive) + */
@@ -228,14 +248,18 @@ static void supermicro_new_pre_set_heartbeat(unsigned int heartbeat)
 void iTCO_vendor_pre_start(unsigned long acpibase,
                           unsigned int heartbeat)
 {
-       if (vendorsupport == SUPERMICRO_NEW_BOARD)
+       if (vendorsupport == SUPERMICRO_OLD_BOARD)
+               supermicro_old_pre_start(acpibase);
+       else if (vendorsupport == SUPERMICRO_NEW_BOARD)
                supermicro_new_pre_start(heartbeat);
 }
 EXPORT_SYMBOL(iTCO_vendor_pre_start);
 
 void iTCO_vendor_pre_stop(unsigned long acpibase)
 {
-       if (vendorsupport == SUPERMICRO_NEW_BOARD)
+       if (vendorsupport == SUPERMICRO_OLD_BOARD)
+               supermicro_old_pre_stop(acpibase);
+       else if (vendorsupport == SUPERMICRO_NEW_BOARD)
                supermicro_new_pre_stop();
 }
 EXPORT_SYMBOL(iTCO_vendor_pre_stop);
index 5b395a4ddfdfec67dbd4324acbc521258977a855..352334947ea30ba0726bdb214915494d9122ddbe 100644 (file)
@@ -1,7 +1,7 @@
 /*
- *     intel TCO Watchdog Driver (Used in i82801 and i6300ESB chipsets)
+ *     intel TCO Watchdog Driver (Used in i82801 and i63xxESB chipsets)
  *
- *     (c) Copyright 2006-2008 Wim Van Sebroeck <wim@iguana.be>.
+ *     (c) Copyright 2006-2009 Wim Van Sebroeck <wim@iguana.be>.
  *
  *     This program is free software; you can redistribute it and/or
  *     modify it under the terms of the GNU General Public License
@@ -63,7 +63,7 @@
 
 /* Module and version information */
 #define DRV_NAME       "iTCO_wdt"
-#define DRV_VERSION    "1.04"
+#define DRV_VERSION    "1.05"
 #define PFX            DRV_NAME ": "
 
 /* Includes */
@@ -236,16 +236,16 @@ MODULE_DEVICE_TABLE(pci, iTCO_wdt_pci_tbl);
 
 /* Address definitions for the TCO */
 /* TCO base address */
-#define        TCOBASE         iTCO_wdt_private.ACPIBASE + 0x60
+#define TCOBASE                iTCO_wdt_private.ACPIBASE + 0x60
 /* SMI Control and Enable Register */
-#define        SMI_EN          iTCO_wdt_private.ACPIBASE + 0x30
+#define SMI_EN         iTCO_wdt_private.ACPIBASE + 0x30
 
 #define TCO_RLD                TCOBASE + 0x00  /* TCO Timer Reload and Curr. Value */
 #define TCOv1_TMR      TCOBASE + 0x01  /* TCOv1 Timer Initial Value    */
-#define        TCO_DAT_IN      TCOBASE + 0x02  /* TCO Data In Register         */
-#define        TCO_DAT_OUT     TCOBASE + 0x03  /* TCO Data Out Register        */
-#define        TCO1_STS        TCOBASE + 0x04  /* TCO1 Status Register         */
-#define        TCO2_STS        TCOBASE + 0x06  /* TCO2 Status Register         */
+#define TCO_DAT_IN     TCOBASE + 0x02  /* TCO Data In Register         */
+#define TCO_DAT_OUT    TCOBASE + 0x03  /* TCO Data Out Register        */
+#define TCO1_STS       TCOBASE + 0x04  /* TCO1 Status Register         */
+#define TCO2_STS       TCOBASE + 0x06  /* TCO2 Status Register         */
 #define TCO1_CNT       TCOBASE + 0x08  /* TCO1 Control Register        */
 #define TCO2_CNT       TCOBASE + 0x0a  /* TCO2 Control Register        */
 #define TCOv2_TMR      TCOBASE + 0x12  /* TCOv2 Timer Initial Value    */
@@ -338,7 +338,6 @@ static int iTCO_wdt_unset_NO_REBOOT_bit(void)
 static int iTCO_wdt_start(void)
 {
        unsigned int val;
-       unsigned long val32;
 
        spin_lock(&iTCO_wdt_private.io_lock);
 
@@ -351,11 +350,6 @@ static int iTCO_wdt_start(void)
                return -EIO;
        }
 
-       /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
-       val32 = inl(SMI_EN);
-       val32 &= 0xffffdfff;    /* Turn off SMI clearing watchdog */
-       outl(val32, SMI_EN);
-
        /* Force the timer to its reload value by writing to the TCO_RLD
           register */
        if (iTCO_wdt_private.iTCO_version == 2)
@@ -378,7 +372,6 @@ static int iTCO_wdt_start(void)
 static int iTCO_wdt_stop(void)
 {
        unsigned int val;
-       unsigned long val32;
 
        spin_lock(&iTCO_wdt_private.io_lock);
 
@@ -390,11 +383,6 @@ static int iTCO_wdt_stop(void)
        outw(val, TCO1_CNT);
        val = inw(TCO1_CNT);
 
-       /* Bit 13: TCO_EN -> 1 = Enables the TCO logic to generate SMI# */
-       val32 = inl(SMI_EN);
-       val32 |= 0x00002000;
-       outl(val32, SMI_EN);
-
        /* Set the NO_REBOOT bit to prevent later reboots, just for sure */
        iTCO_wdt_set_NO_REBOOT_bit();
 
@@ -649,6 +637,7 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
        int ret;
        u32 base_address;
        unsigned long RCBA;
+       unsigned long val32;
 
        /*
         *      Find the ACPI/PM base I/O address which is the base
@@ -695,6 +684,10 @@ static int __devinit iTCO_wdt_init(struct pci_dev *pdev,
                ret = -EIO;
                goto out;
        }
+       /* Bit 13: TCO_EN -> 0 = Disables TCO logic generating an SMI# */
+       val32 = inl(SMI_EN);
+       val32 &= 0xffffdfff;    /* Turn off SMI clearing watchdog */
+       outl(val32, SMI_EN);
 
        /* The TCO I/O registers reside in a 32-byte range pointed to
           by the TCOBASE value */
index 9b91617b9582d320b67ce6c1984663d48659e03d..56892a142ee273eef1112ea212792556ecfc806b 100644 (file)
@@ -45,6 +45,13 @@ static int xen_suspend(void *data)
                       err);
                return err;
        }
+       err = sysdev_suspend(PMSG_SUSPEND);
+       if (err) {
+               printk(KERN_ERR "xen_suspend: sysdev_suspend failed: %d\n",
+                       err);
+               device_power_up(PMSG_RESUME);
+               return err;
+       }
 
        xen_mm_pin_all();
        gnttab_suspend();
@@ -61,6 +68,7 @@ static int xen_suspend(void *data)
        gnttab_resume();
        xen_mm_unpin_all();
 
+       sysdev_resume();
        device_power_up(PMSG_RESUME);
 
        if (!*cancelled) {
diff --git a/firmware/3com/typhoon.bin.ihex b/firmware/3com/typhoon.bin.ihex
new file mode 100644 (file)
index 0000000..d7a83be
--- /dev/null
@@ -0,0 +1,2819 @@
+:10000000545950484F4F4E000200000009000000B4
+:100010000000FFFFCB99B1D44CB8D04B3202D4EEE4
+:10002000737E0B139BC0AEF440010000E8FC00009F
+:100030000000FFFF390000EA050000EA040000EAC2
+:10004000030000EA020000EA010000EA320200EACE
+:10005000C51400EA07002DE90E00A0E100100FE131
+:10006000D0209FE512FF2FE1FEFFFFEA010080E0B4
+:10007000042081E4010050E1FCFFFF1A0EF0A0E132
+:1000800000A0A0E10EB0A0E10000A0E3A8109FE551
+:10009000000081E5A4109FE5000081E50116A0E3C2
+:1000A000000091E5010080E3000081E5D700A0E3B6
+:1000B00000F021E188D09FE5DB00A0E300F021E122
+:1000C0007CD09FE5D200A0E300F021E174D09FE551
+:1000D000D100A0E300F021E16CD09FE59B1400EB80
+:1000E000D300A0E300F021E160D09FE560009FE530
+:1000F00060109FE560209FE5DBFFFFEB5C009FE564
+:100100005C109FE50020A0E3D7FFFFEB54009FE5C4
+:1001100054109FE5D4FFFFEB0A00A0E10BF0A0E133
+:10012000D310A0E301F021E1D4FFFFEB3CA09FE559
+:100130001AFF2FE1C6FFFFEA1521FFFF0C00100098
+:100140001C0010003C380080FC370080FC3F008021
+:100150007C340080800F000080300080ADDEADDE9A
+:10016000B0BB000024AB20404829000028050080D7
+:10017000BDBA214000000000FFFF000000000000A9
+:1001800000000000FFFF00000000000058570000C2
+:10019000864B00006001FFFFB0B5071C124D002424
+:1001A000286800281ED0381C104904F07BFD2968FF
+:1001B000C0460860002815D038010D4940181923A1
+:1001C000DB01C018416B80290CD2013141632868E2
+:1001D000C169C0462960390741600462C762B0BC8A
+:1001E00008BC1847201CFAE7E8170080EE0500005D
+:1001F000A01C008002490A68C046C26108607047BE
+:10020000E81700807047000070470000704700004A
+:1002100000000FE10010A0E1C01081E301F021E136
+:100220001EFF2FE100F021E11EFF2FE100000FE192
+:10023000C00080E300F021E11EFF2FE100000FE18C
+:10024000C000C0E300F021E11EFF2FE100000FE13C
+:10025000400080E300F021E11EFF2FE100000FE1EC
+:10026000800010E3800080E300F021E10000001234
+:100270001EFF2FE1000050E300000FE18000C013DB
+:1002800000F021E11EFF2FE100000FE18000C0E33C
+:1002900000F021E11EFF2FE1910000E01EFF2FE1A1
+:1002A000012080E0010080E01EFF2FE180B5084FB3
+:1002B000642804D3642038630020C04303E038631B
+:1002C000044905F001FB7863B86380BC08BC18479B
+:1002D000680E00808813000080B4104B00221F6B52
+:1002E000642F03D209680968490802D2101C80BC37
+:1002F0007047191CDB6B4F6BBB4205D24068000492
+:10030000000C1818C863F1E74168054B19434160B8
+:100310000448C16B0131C1630220E8E7680E008028
+:10032000000000800C2B008090B5071C154C0020AD
+:10033000216B64290BD2B96E490808D3216CA26BDA
+:10034000914207D2FA1D3932528B8918216490BC30
+:1003500008BC1847786A396BC0464862386B02F0AF
+:100360002DFE381C02F0E8FA0120BB231B01E11826
+:10037000C87305490A6C12180A6404498A6D121878
+:100380008A65E4E7680E00800C2B0080A42A0080B8
+:1003900080B40A48C06D02231840094A0021002891
+:1003A00003D0D163116480BC7047064807687B1C8A
+:1003B00003600A2FF7D30160F3E70000A42A00804E
+:1003C000680E0080E001008070470204120C000CEF
+:1003D00010180A04120C090C51180818010C05D049
+:1003E0000104090C000C0818010CF9D10004000CE0
+:1003F000704780B40022002918D04F087B1E002FC0
+:1004000006D00788BA1802301F1C013B002FF8D114
+:10041000490803D300880006000E8218100C05D08E
+:100420001004000C110C4218100CF9D11004000C2F
+:1004300080BC704780B58389C789FB18078AFB1881
+:10044000478AFB18407A0002C718380C05D03804D8
+:10045000000C3B0CC718380CF9D1081C111CFFF715
+:10046000C8FF011C381CFFF7B0FF80BC08BC184750
+:1004700090B5022382681A400027002A0FD00A4A4A
+:100480009369013393610A688B689A1800681C1895
+:1004900057810969101CFFF7ACFFC0436081381C0D
+:1004A00090BC08BC184700000C2B008090B50423BA
+:1004B00082681A400027002A11D04A6852090ED3D8
+:1004C000094A136A01331362CB6802689C1801233E
+:1004D0009B07083A1A43126800F02EF82082381C55
+:1004E00090BC08BC184700000C2B008090B58023FE
+:1004F00082681A400024002A15D04A68920912D353
+:100500000B4AD3690133D361CB6802689F1801237A
+:100510009B07083A1A43126800F00EF8002800D131
+:100520000448C046F880201C90BC08BC1847000056
+:100530000C2B0080FFFF0000B0B5141C051C0F1C25
+:100540003869B96841183868FFF753FFC0430104A0
+:10055000090C201CFFF739FF041CB86879694018A2
+:10056000696888420CD22A681218091A101C00F017
+:1005700005F9C0430104090C201CFFF726FF041CE9
+:10058000E0430004000CB0BC08BC184780B5071C51
+:10059000B86BC0081AD3B86AF96B4018796C00F0D0
+:1005A000EDF8C0430104090C0A4807D02023B969BB
+:1005B0001943B961016B0131016307E0FF23013386
+:1005C000B9691943B961416A01314162002080BCB7
+:1005D00008BC18470C2B008080B5071CB86B41097C
+:1005E0001CD3C0081AD3F81D3930007B062815D15A
+:1005F000381C00F053F8011C0A4807D04023B969A1
+:100600001943B961816B0131816307E001239B02CA
+:10061000B9691943B961C16A0131C162002080BC66
+:1006200008BC18470C2B0080B0B5071CB86B8109BB
+:100630002CD3C0082AD3F81D3930007B112825D1CE
+:10064000B86A396C401801239B07063018430068CC
+:1006500005042D0C0F4C11D0381C00F01FF8002899
+:100660000CD0A84202D10C4B984207D08023B86925
+:100670001843B861606B0130606307E001235B02DF
+:10068000B8691843B861A06A0130A0620020B0BC0C
+:1006900008BC18470C2B0080FFFF0000F0B5FFB02E
+:1006A00099B0041CE06B616C091803AA8518A36A51
+:1006B00000208A080132979207D082009F5803AE2B
+:1006C000B750979A01308242F7D8606A01239B079E
+:1006D000043018430068C046029002AF3F8803A868
+:1006E000FFF787FEC0430104090C381CFFF76DFEBD
+:1006F000071CE06BA16C4018616A01239B0708315D
+:1007000019430968C046019101A90988013188424D
+:100710000CD2A26A1218091A101C00F02FF8C0435C
+:100720000104090C381CFFF750FE071CA889E98951
+:100730000818298A0818698A0818697A09020818A5
+:10074000A16C626C891A0A04120C1102120A11437C
+:100750000904090C0918080C05D00804000C090C40
+:100760004118080CF9D1381CFFF72FFEC0430004D4
+:10077000000C7FB019B0F0BC08BC1847B0B4002220
+:1007800000292ED083079B0FDC0047180425EF1BA0
+:10079000BF07BF0FFF008008800059180331890888
+:1007A0004D1E02C8E140A1406B1E002D09D00C0473
+:1007B000240CA218090C8A1802C81C1C013B002C2E
+:1007C000F5D1B940081CF8400104090C8918000C47
+:1007D0004218100C05D01004000C110C4218100C1B
+:1007E000F9D11004000CB0BC7047000090B4002098
+:1007F0000127114942001218D20053189C680123A6
+:100800009B0723431B681B031B0B8A581203120B05
+:1008100093420CD101300428ECD30848C06A01038C
+:10082000090B0748006F0003000B814202D0381CFF
+:1008300090BC70470020FBE7A803008000401440F4
+:10084000680E008098B4144AC04600928300134892
+:10085000C05807033F0B1248C0580203120B11483F
+:10086000C0580003000B104CE45801239B0723439E
+:100870001B689B00CC000121984201D1081C09E0B3
+:10088000984203D9101ADA1B801800E0181A844223
+:10089000F4D3002098BC704755555555200400806E
+:1008A00028040080080400801804008080B4130429
+:1008B00000D0013A80000B1C13490F58C0463B6022
+:1008C0000B58C0465A600A580832104B1B589A42BF
+:1008D00001D30F4A12580F4B1F5801239B073B436C
+:1008E0001B689B0017033F0B9F4206D10A48C16853
+:1008F0000131C160012080BC7047084B1B58C046C5
+:100900001A600A500020F6E70804008028040080DE
+:100910002004008018040080A08220401004008081
+:10092000FF5F2DE948FEFFEB01B6A0E301B18BE2CA
+:10093000028AA0E3017AA0E301A9A0E30156A0E3A3
+:10094000C8609FE5C8909FE514409BE5000054E314
+:100950002C00000A030A14E31100000A0C0096E5BB
+:10096000000050E32100000A010A14E30500000A18
+:100970001C0096E5010AC0E31C0086E51C0085E525
+:10098000147085E5060000EA020A14E30400000A78
+:100990001C0096E5020AC0E31C0086E51C0085E504
+:1009A000148085E5010914E30400000A1C0096E5A3
+:1009B0000109C0E31C0086E51C0085E514A085E55F
+:1009C000020014E34000001B010014E35400001B6C
+:1009D000020B14E36700001B010B14E32000001B53
+:1009E000180099E5010080E2180089E5D5FFFFEACB
+:1009F0001C0096E5010AC0E31C0086E51C0085E5A5
+:100A0000147085E5E1FFFFEAFF5FBDE804F05EE2F8
+:100A1000680E00800883204010101FE5143091E517
+:100A20000020C3E1142081E50116A0E30C2081E53C
+:100A30000B12A0E3000081E518109FE5B024D1E17E
+:100A4000012082E2B024C1E13C2091E5000082E176
+:100A50003C0081E51EFF2FE1A0822040FFFFFFEA5E
+:100A6000FEFFFFEA010BA0E30116A0E3140081E5FD
+:100A7000001A81E1242091E570001FE500000000CC
+:100A8000242080E5281091E500000000281080E572
+:100A90002C2090E5012082E22C2080E53F0001E23D
+:100AA0003F0050E31EFF2F1118009FE5001090E556
+:100AB000011081E2001080E50218A0E30B02A0E320
+:100AC000001080E51EFF2FE1300400800106A0E346
+:100AD000010180E2001090E5010811E30B10A0E392
+:100AE000021981E20500001A002090E54228B0E1D9
+:100AF0000500001A000090E5020C10E30200000A55
+:100B00000607A0E34C1180E5030000EA0C009FE516
+:100B100000000000401080E5FFFFFFEAFEFFFFEA53
+:100B2000000000800106A0E3010180E2001090E5D2
+:100B3000010811E30C10A0E3021981E20500001A7C
+:100B4000002090E54228B0E10500001A000090E581
+:100B5000020C10E30200000A0607A0E34C1180E536
+:100B6000030000EA4C001FE500000000401080E593
+:100B7000FFFFFFEAFEFFFFEA021BA0E30106A0E37E
+:100B8000141080E51EFF2FE180211FE5143092E54F
+:100B900000000000003080E51C0092E5000000002D
+:100BA000000081E50010A0E3141082E50106A0E337
+:100BB0001C1082E50C1080E51C1092E5000000007E
+:100BC0001C1080E51EFF2FE1C0211FE50000000082
+:100BD0001C1082E50116A0E3140082E50C0081E5FB
+:100BE0001C0092E5000000001C0081E51EFF2FE1C3
+:100BF00080B50F1C381C00F017F8002802D0381CF4
+:100C000000F092F8002080BC08BC184780B50F1C8B
+:100C1000381C00F009F8002802D0381C00F084F8D5
+:100C2000002080BC08BC1847F0B407683A78D207A7
+:100C3000D20F0024002A03D0FF220132426000E0DC
+:100C400044603A7B7B7B1B021A43812A08D1012333
+:100C50005B0242681A4342600422BF18826000E0CF
+:100C600084603A7B7B7B1B021A43082A06D1062349
+:100C700041681943416081680E313CE0C123DB00CB
+:100C80009A4203D14168244B19433EE0234B9A42D8
+:100C900004D101231B034168194336E01302120AF1
+:100CA0001206120E1A431204120C2E3A1C4B9A42D0
+:100CB0002DD80125426815434560BA7BFB7B1B029A
+:100CC0001A43184B9A4222D1FB1D093344CB9B0790
+:100CD000DB0EDA405B4220339E401643032E18D1D0
+:100CE000397D7B7D1B021943082907D10421294343
+:100CF000416081681631816001210AE0C123DB0077
+:100D0000994204D1012189032943416000E08460B4
+:100D10000021081CF0BC70470240000081800000E8
+:100D2000AE050000AAAA000080B44268D1083FD3F3
+:100D300001688368591802398F783F073F0F052FE4
+:100D400003D1DA1D0D32C26005E0BF00DB19C360BC
+:100D500008231A4342608A781207120F9200026138
+:100D60000A794B791B021A431302120A1206120E59
+:100D70001A431204120C4261CA7A062A03D11023C4
+:100D800042681A4310E0112A03D1202342681A4313
+:100D90000AE0332A03D1402342681A4304E0322A8E
+:100DA00003D1802342681A434260C97AC046017663
+:100DB00080BC70470A78C04602604B781B021A4319
+:100DC00002608B781B041A430260C978090611433C
+:100DD0000160704780B5071C4868800926D3B86A4F
+:100DE000C968401801239B070230184300680004BB
+:100DF000000C11239B02984218D1786A396BC046C7
+:100E00004862386B02F0DAF8381C01F095FD0120D9
+:100E10000749C046C87307494A6C12184A64064914
+:100E20008A6D12188A6580BC08BC18470020FAE752
+:100E3000181A00800C2B0080A42A0080810719D08A
+:100E40008008800001239B07011D18430068194397
+:100E500009680202120E1206000AFF231B04184042
+:100E600010430A0A1206120E104309021B0A194007
+:100E70000843704701239B071843006801060202DC
+:100E8000FF231B041A401143020A1B0A1A40114394
+:100E9000000E0843EDE70000F0B50423816B194014
+:100EA0000022002946D0C71D3937397B332901D0AC
+:100EB00032293FD1016BC0464A65C41D2D34CD1D7A
+:100EC0002D3500229300E658C046EE500132072A25
+:100ED000F8D3826AC0464A63826AC0468A627A8BC5
+:100EE000CB1D39335A83406AC046486212480127F5
+:100EF0004268002A10D1C268002A13D14269002A30
+:100F00000DD10161C160016A022902D3203007714D
+:100F10000CE000F013F809E0C268002A02D1016178
+:100F2000C16003E00269C04651650161381CF0BC34
+:100F300008BC1847101CFAE76C06008080B51E49F3
+:100F40000022CB68002B34D0C81DF9308362CB68F7
+:100F50009B6AC046C362CF697B00DF197F02174BD3
+:100F6000FF18FF37653783630763CB1DFF335A33A1
+:100F70001A72CB69002B01D0CA6101E00123CB6159
+:100F80000F1CC968496A098901314163F81DFF30A6
+:100F90003A30426002828260C260381C00F0CEFAB1
+:100FA000386A01303862381C00F00AF880BC08BC8E
+:100FB0001847101CFAE700006C060080ACAB20401C
+:100FC000F0B5071CF91DF931886AC21D2D320123C5
+:100FD0009B0708321A43C86A12681204120C801860
+:100FE0008279C3791B021A431302120A1206120EE7
+:100FF0001A431204120C02389204920C0026254D5A
+:10100000EC1DFF343A34002A04D0208A01239B02CD
+:1010100018432BE001239B07C21D0D321A431268AF
+:1010200012041230184300680004000C1043031C23
+:10103000F81DFF304A308278C86B191C02F002F8A4
+:10104000002804DA208AFF23013318430EE0F91D3B
+:10105000FF313A3108600104090C381C00F01CF81B
+:10106000002814D1208A01235B0218432082218AA0
+:10107000381C00F0A2FBE86801239B07543018439A
+:101080000068C046E860301CF0BC08BC184701206E
+:10109000FAE700006C060080F8B5071CFC1DF93467
+:1010A000A06BA66AC51D0D353848C06A4B0059189B
+:1010B0004901421801208007104300680004000C19
+:1010C000009001239B07D01D053018430068381C91
+:1010D000291C00F0C2FAA888410701D0002051E085
+:1010E00029890918606B8142F8D86989EA888918CA
+:1010F0008142F3D80098012825D1E06AF16B4018AD
+:10110000716CFA1DCD3201F033F9FA1DFF323A321B
+:10111000E06A51694018C31D0333002081005E5806
+:10112000C919FF3101314E6101300428F6D3E06A5C
+:1011300051694018C11D0531002000224300CA52E8
+:1011400001300628FAD3291C114A0020FFF7AEFB14
+:1011500001225204606B02430120216BFFF7A6FBC2
+:1011600001225204606B02430020E16AFFF79EFBFC
+:10117000A16B084A0120FFF799FB03200649C046EE
+:1011800048620120F8BC08BC184700004C2A0080C7
+:101190005400030014000F006C070080F0B58DB000
+:1011A0000020B54AD51DF935686201200005B34914
+:1011B000C0460860A86AC41D2D34B148C06AD71D56
+:1011C000FF373A3739684B00591849014018012355
+:1011D0009B07C11D05311943096808301843006891
+:1011E000C0460990FF231B021840000A0A900A9883
+:1011F000A44E012859D1286BA2688018A24A2169FF
+:101200000904090C01F026F9286B79694018C11D01
+:10121000053100208200984BD318FF3301335B69FE
+:10122000C0468B5001300428F4D30020311C8200CA
+:10123000561801239B0733431B6804AEB35001309B
+:101240000328F4D300200890904942008B5AB25AE8
+:10125000934213D08E48C1890131C181B8680028FA
+:1012600003D1388A1023184371E0388A4023184389
+:101270006DE000F011F901F067FFF5E0013006289C
+:10128000E3D3089800280CD1B868411CB960002845
+:1012900003D1388A0123184302E0388A0423184313
+:1012A000388278680130786062E00A9802285FD15D
+:1012B0000998400C73D301239B07E01D01301843AC
+:1012C0000068E11D0D311943096840180C3800040D
+:1012D000000C00218A006B4BD61801239B07334377
+:1012E0001B6804AEB35001310329F3D30021831EE0
+:1012F0000C93684A166BC0460B968A000C9B9B1891
+:101300000B9E9E1901239B0733431B686E46B35007
+:1013100001310429F1D369468B1C07930021089100
+:1013200004AE4A00079B9B5AB25A934211D05848C8
+:10133000C1890131C181F868411CF960002803D1DD
+:10134000388A2023184302E0388A802318433882E1
+:101350008FE701310629E4D3089900290DD1F968F6
+:101360004A1CFA60002904D1398A0223194303E098
+:101370000CE0398A082319433982296B08180123A4
+:101380009B07013818430068C046207601239B075D
+:10139000E01D1130184300680106090E00E019E055
+:1013A00035482A6BC046EA6204294FD10121C61D87
+:1013B000FF365A3631720A9902291ED10999090E4F
+:1013C00049061AD1E11D0531194309680906090EBC
+:1013D00008391AE001239B07E01D0130184300681B
+:1013E000E11D0D311943096840180004000CF9682B
+:1013F0004A1CFA600029BCD1B6E701239B07E11D16
+:101400000531194309680906090EA160E86AC0465A
+:101410002060201CFFF788FC207E332801D0322872
+:1014200011D10121144CC046F960B960201C00F0B4
+:1014300085F8286BA96AC0468862201CFFF7C0FDAA
+:10144000002811D10EE00020307211E0332901D0C4
+:1014500032290DD1071C00F071F8381CFFF7B0FDE0
+:10146000002801D101F070FE0DB0F0BC08BC184797
+:1014700000F012F8F6E700006C060080000000B0F3
+:101480004C2A0080ACAB20404007008082070080DF
+:101490000C2B00806C070080F0B5254841680131B5
+:1014A0004160244FF91DF9310024886AFA68C0466A
+:1014B00094610422FB68C046DA601022FB68C046D3
+:1014C0009A61FA1DFF325A32137A1B4A002B0BD055
+:1014D000158A2E0A360233232B409B001E43CC2351
+:1014E0002B409B0833431382128AFB68C046DA8381
+:1014F0004A6BFB68C046DA810A6BC0468262C462EE
+:10150000C31D39334A6BC0465A83042302681A4309
+:101510000260886A01F032FAF86801239B075430B0
+:1015200018430068C046F860F0BC08BC18470000CB
+:101530000C2B00806C060080AC07008080B5C11DBC
+:10154000F9318A6A01239B07D11D45311943096886
+:101550000B061B0E0127C11DFF314A31332B05D16C
+:101560008B70011C101C00F00FF806E0322B08D124
+:101570008B70011C101C00F03CF8381C80BC08BCAF
+:10158000184700208870F9E790B4CA1DF932332754
+:10159000CC1DFF344A34D36AC046A770FF314131B5
+:1015A000076CC0464F61FB18391C9F1E01239B0727
+:1015B000FC1C23431B681B061B0E9B001B041B0CFF
+:1015C000C9180831016401239B07B91C1943096834
+:1015D00034300176F81D0130184300680004B91D4D
+:1015E0001943D06309680904090C0843D06390BC0F
+:1015F0007047B0B5CA1DF932C51D2D353220CF1D3B
+:10160000FF374A37D36AC046B870CC1DFF343A342E
+:10161000E868C04660611030E8606069C018871EE5
+:1016200001239B07381D184300680004B91C1943A7
+:10163000D06309680904090C0843D063F81D03301E
+:10164000FFF7FCFB2062F81D0730FFF7F7FB606235
+:1016500000202876B0BC08BC1847F7B581B00198C7
+:10166000C71DF937B86A01239B07D41D05342343EE
+:101670001C68FF23FE3323407F6B3F043B430B601A
+:1016800034301C1C80232340019FFF374137002B3F
+:101690003CD00C23009300239D00AE1836696D18D2
+:1016A0006E610133052BF7D300239D00AE18766AD7
+:1016B0006D18AE620133052BF7D3019BFF33513315
+:1016C0009B78332B0ED101239B07C51D01352B437E
+:1016D0001B68C0464B8101239B07C51D0D352B435D
+:1016E0001B6816E07B69C0464B8101239B07C51D23
+:1016F0000D352B431B687D695D1B01239B07C61DB0
+:10170000013633431B68EB180C3B02E000230093C7
+:101710004B81CB80630949D301239B07C41D05344A
+:1017200023431B68C0460B8101239B07C41D0D3456
+:1017300023431B680C891B1B009C1C1B01239B075C
+:1017400008301843006820188880386A040EFF2388
+:101750001B0403401B0A1C43FF231B0203401B0204
+:10176000234300061843C860786A070EFF231B0452
+:1017700003401B0A1F43FF231B0203401B023B4382
+:10178000000618430861D06BC046C863906BC04622
+:101790000864506CC0464864106CC0468864D06CC5
+:1017A000C046C864906CC046086502E000230B8107
+:1017B0008B8004B0F0BC08BC184700B50F4A938971
+:1017C00001339381C21DF9320423906AC046C3607D
+:1017D00010238361CB0A01D318238361C183516B2A
+:1017E000C046C181516BC21D393251830423016847
+:1017F0001943016001F0C2F808BC18470C2B0080A7
+:10180000B0B51B4C206A02281BD20020E71D1937F7
+:101810003871E168E01DF930002915D0426A002ACC
+:1018200012D101250AE0FFF789FB002809D1206ABF
+:10183000022800D33D71E068002802D038790028E2
+:10184000F1D0B0BC08BC1847406A0028F9D1002983
+:10185000F7D16069002804D00648006803F0A8FCAE
+:10186000EFE760680028ECD000F05AF8E9E70000E4
+:101870006C06008034040080B0B5071C2023B868D3
+:1018800018400124002500280BD1386A002803D114
+:10189000281CB0BC08BC18471F48016E0131016606
+:1018A00003E04868C423184003D1386A00F00CFCF8
+:1018B0002FE0381C00F01CFC381C00F07BFAB868E4
+:1018C000C00802D3386A00F0D1FBB868396AC04654
+:1018D0008860386AC046C56010484168002911D147
+:1018E000C168002909D14169002906D1396AC04679
+:1018F0008160416000F014F80BE0396AC0468160F5
+:10190000416006E0396A8268C046D160396AC046E3
+:101910008160201CBDE70000A42A00806C060080C6
+:1019200090B50B4C6768002F0FD0381C00F012F8F0
+:1019300000280AD16068C068C0466060381C00F0AA
+:10194000C3FB002090BC08BC18470120FAE7000048
+:101950006C060080F0B5071CFE1D4936307840004B
+:10196000C019858B334C344B9D423CD0381C211C14
+:101970002A1C00F01DF93148806A5821694340183B
+:1019800001239B07184300680004000C2C4D01281C
+:101990001AD13078C019C11D1931087A3A688018F7
+:1019A000097BEA1D213200F0E3FC3078C0192030B9
+:1019B000007939684018C11D05310020002342001C
+:1019C0008B5201300628FAD3A08841070BD1218918
+:1019D000091878680004000C814204D86189E28803
+:1019E0008918814203D90020F0BC08BC1847211C8B
+:1019F000144A0020FEF75AFF01225204786802437D
+:101A000001203968FEF752FF012252047868024330
+:101A100000203968FEF74AFF0B490C4A0120FEF707
+:101A200045FF0120E91D193148710221EA1DF932F3
+:101A30005162D9E728AC2040FFFF00004C2A00800B
+:101A40006C0600805400030014AC20401400070012
+:101A5000F0B583B000214F48C21DF9325162012117
+:101A6000C9044D4AC0461160C11D19314979002988
+:101A700004D14A48006803F09BFB87E0454847686B
+:101A8000FC1D493421784800C019808B444A926A71
+:101A900058235843151801239B07EA1D05321A43A2
+:101AA000126808352B431D68FF231B022B401B0ABD
+:101AB0003C4D012B24D1C819C11D1931087A3A684F
+:101AC0008018394A097B00F0C5FC2078C019203005
+:101AD0000079396841180020820053199B6E6E46C8
+:101AE000B35001300328F7D3CA1D053269460020E0
+:101AF0004300CD5AC046D55201300628F8D32DE018
+:101B0000022B2BD1110A29D300218A0053199B6E75
+:101B10006E46B35001310329F7D321784900C91922
+:101B2000098F3A688B186A4600214D00565BC04603
+:101B30005E5301310629F8D319498A6A13181A6DC0
+:101B4000009D5540194AD66875401D65896A081878
+:101B5000416D029B59409269514041652078411E78
+:101B6000217000280DD0381CFFF7F4FE00280DD19D
+:101B7000084A5068C068C0465060381C00F0A4FA9B
+:101B800002E0381C00F073FA01F0DEFA03B0F0BC9A
+:101B900008BC18476C060080000000B038040080C4
+:101BA0004C2A0080ACAB2040940600800883204083
+:101BB000F0B582B0694B9F6A58235A43BA18C31DC7
+:101BC00049331F7801239B07D41D013423431D682B
+:101BD00043681C0401239B07D61D053633431B684D
+:101BE0001C4342231C430C60FF2636022E40012377
+:101BF0005B029E4274D16B0C2BD3C31920331B792B
+:101C0000C0464B817B001B181B8F4C891B1BCB8054
+:101C10000024A6000196B318DE1D093601239B0798
+:101C200033431B68019E761873610134052CF0D391
+:101C30000024A6000096B318DE1D1D3601239B0765
+:101C400033431B68009E7618B3620134052CF0D331
+:101C500006E000234B81CB8040239C430C60231C77
+:101C60006B0E4AD3C31920331B7910330B817B00D1
+:101C70001B181B8F0F89DB1B8B8001239B07D41D37
+:101C8000353423431B68C046CB6301239B07D41D17
+:101C9000313423431B68C0460B64AB0E21D20123B1
+:101CA0009B07D41D3D3423431B68C0464B6401236E
+:101CB0009B07D41D393423431B68C0468B64012322
+:101CC0009B07D41D453423431B68C046CB640123C6
+:101CD0009B07D41D413423431B68C0460B6500E0BD
+:101CE0000FE0FB1F013B1B041B0C0768FF18036977
+:101CF000081C391C00F034F82CE000230B818B8089
+:101D000028E000238B800B81C31920331B7AC04647
+:101D10004B817B001818008EC046C88000208700C9
+:101D2000BB18DC1D093401239B0723431B687F1864
+:101D30007B6101300528F2D300208700BB18DC1D31
+:101D40001D3401239B0723431B687F18BB620130AE
+:101D50000528F2D302B0F0BC08BC18474C2A00801A
+:101D600080B41F1C3B0C18D2176D114BC046DF60AE
+:101D7000526DC0461A61C7601A69C0460261D868D0
+:101D8000C0460880D868000C48801869C046888022
+:101D90001869000CC88080BC70474A8812040B8800
+:101DA0001A43C2608A88C988090411430161F2E7B5
+:101DB0002C070080F1B588B000220898006A089BC3
+:101DC0009968490A02D30127FF0300E00027038B2B
+:101DD000002B19D0A349896A1C1C58236343C918D6
+:101DE00001239B075839194309680904090C022982
+:101DF00002D108231F4307E0418B002902D00C23A6
+:101E00001F4301E004231F43838A002B18D0954908
+:101E1000896A1C1C58236343C91801239B0758393E
+:101E2000194309680904090C022901D10F4307E08D
+:101E3000C18A002902D003231F4301E001231F436D
+:101E4000C11D393107914B890C891C192404240CBC
+:101E5000089D2D68C0460195C9887D081AD31A1CB3
+:101E6000C31D19331A72079A9289C0461A73079ACA
+:101E70001289C04602860487828A013A828301223F
+:101E80001971089B1B685B185B789B001B041B0C7B
+:101E900008335918BB0847D3079B5B8985180695FB
+:101EA00020352B72079B9B89C0462B73079B1B8990
+:101EB0002E1C55002D1805952B86002A01D0C38AAB
+:101EC00000E0838A013B059DC046AB833171654BC1
+:101ED0009D6A059B9E8B58237343EB18DD1D0135CE
+:101EE00001239B072B431D682B0E5B0601D1083194
+:101EF00000E0103181235B021D409D4203D1E31FAE
+:101F0000053B1C04240C059BC0461C87089B1B68D2
+:101F10001B19103B9B7B069D40352B702B780233A1
+:101F2000E31A1C04240C0132BB089B076DD08318F4
+:101F3000203304931972019B5D1801239B072B43E7
+:101F40001B681B071B0F9B00049EC0463373009544
+:101F50002B781B071B0F9B00049DC0462B73009D15
+:101F6000EB78AD781B021D432B022D0A2D062D0E9A
+:101F70002B4355002D182B86049BC0465972049B99
+:101F80001B7B2E1C049DC0466B73338EC04673862C
+:101F9000009D2B781B071B0F9B001B041B0C591863
+:101FA00004253D400ED03487038B013BB383131CC3
+:101FB0001B1820331971019B5B185B789B00591823
+:101FC000083101323B0937D3002D01D0438B00E0AB
+:101FD000038B55002D18013BAB83831803932033EB
+:101FE0001971204B9D6A53001B1802939E8B582336
+:101FF0007343EB18DD1D013501239B072B431D683F
+:102000002B0E5B0602D1083101E015E0103181236F
+:102010005B021D409D4203D1E31F053B1C04240CC1
+:10202000029BC0461C87089B1B681B19103B9B7BAF
+:10203000039C403423700132079BC046D980511E57
+:10204000C31D493319700761042A06D2064953009B
+:102050001B1899830132042AF9D309B0F0BC08BCDB
+:10206000184700004C2A0080FFFF0000704780B531
+:102070008CB0071C12480168013101603868C04605
+:1020800000907868C0460190B868C04602900D483C
+:102090004168C968C0464160381C00F04FF8B86814
+:1020A000400906D31023029818430290684602F0B4
+:1020B000E1FF684602F09AFE0CB080BC08BC1847ED
+:1020C0000C2B00806C06008000B58CB00168C04607
+:1020D00000914168054B1943019100F02FF86846C3
+:1020E00002F084FE0CB008BC18470000000000A0FD
+:1020F000026A0368C04613604068C04650604032C0
+:102100004868C0469080C868C046D0804869C046CC
+:1021100010818868C0465081087EC0469073086967
+:10212000C0469081704704490868002800D1704774
+:10213000C268C0460A60FAE76C06008002490A6875
+:10214000C046C260086070476C060080B0B40022D0
+:10215000124F7C7F01347C770323FC1D19343862D5
+:10216000796223720E4C25686B0C05D223681B0C18
+:1021700010D12468A30A0DD301230A4FC046FB6285
+:10218000094F0A4BC046DF6099605860101C186008
+:102190000132FBE7101C38640132FBE700000080CD
+:1021A00000001040C000180002810000400118002B
+:1021B000F0B5474F3868474E474D07235B02EC1890
+:1021C00000281DD1206B013020634449C0460860BF
+:1021D00043484169002913D0C11D6931097B002999
+:1021E0000ED001239B07016D19430968C046816128
+:1021F000C269914204D0F16C0131F16401F050FEEA
+:102200003868012817D137484169002913D0C11D0A
+:102210006931097B00290ED001239B07016D194309
+:102220000968C0468161C269914204D0F16C0131F4
+:10223000F16401F035FE386802282FD1BB231B0161
+:10224000EE18707B002803D00020707300F04AFD68
+:10225000307B002802D0786802F0AAFF1B23DB0144
+:10226000E818C08B04260640E06AB04214D0F86833
+:102270000130F860192811D31B48017B00290DD1CA
+:10228000FF3041304078002808D1B86802F090FF54
+:102290000020F860E66201E00020F860386803285A
+:1022A0000BD1EC1D7934E06B800802D3022002F0E0
+:1022B00007FC0223E06B9843E06338680130386024
+:1022C000032801D900203860F0BC08BC1847000082
+:1022D0003C040080A0822040680E0080400118006D
+:1022E000642D0080E42C008028050080B0B41D48D7
+:1022F000848A1D4A138AC11D093101279C4203D1DA
+:10230000438A548AA34210D00B78002B0DD04B780F
+:10231000002B0AD0448B938A9C4204DC134BC046AA
+:102320005F60978201E001339382C38B5C1CC4839E
+:10233000848BA3420EDB848A058B0023AC4205DA32
+:10234000448AC58AAC4201DA4B7000E04F70438288
+:102350008382C383418AC0465182808AC0461082EC
+:10236000B0BC7047E80E00803C04008040011800BB
+:10237000F7B591B06B46841E129914291AD9002022
+:1023800081006758C046575001300006000E1028E3
+:10239000F6D3002105208700D6594F1C3D062D0E8F
+:1023A0000F1CBF00DE51291C01300006000E102852
+:1023B000F1D309E0002081006358C046535001303A
+:1023C0000006000E0628F6D30020E070207260722E
+:1023D000A072207360731299142937D969468E1C34
+:1023E00091780907090F890014390D062D16002769
+:1023F000002D1BDDF01910A900F03DF800280ED0CB
+:10240000002010A90978002909DD0022391872542A
+:1024100001300006000E10A909788842F6DB10A8EA
+:102420000078381807063F0EAF42E3DB6846E21D2E
+:102430000D320021AB085F1C08D08B00C458C04689
+:10244000D45001310906090E8F42F6D814B0F0BC01
+:1024500008BC184790B4871E002089084B1C08D080
+:1024600081005458C0467C5001300006000E834263
+:10247000F6D890BC704780B40278D206D20E002302
+:102480000127012A01DC0F7011E04078C046087076
+:10249000142A04D10848017A0131017207E0022AA6
+:1024A00005D0052A03D0062A01D0152A02D1181C0E
+:1024B00080BC7047381CFBE7E082204000B50F4825
+:1024C00001231B06416999431A094161D16000212A
+:1024D000A12252039161191C094AC04611601B23B5
+:1024E000DB01C0188069002803D002F061FE08BC3F
+:1024F00018470448418801314180F8E7680E0080A0
+:10250000000000B0E082204070470000F0B586B0C7
+:10251000954AD068D71D7937012809D13889002814
+:1025200006D1D06F022301689943016014203881DD
+:102530008E4C616A8E48C36B5918C163A06A192317
+:10254000DB01D418A062216A0903090B814205D17D
+:10255000012040048749C0460860F3E0BB8A581C4C
+:10256000B8823D8B01200021AB4204DBD31D8933AF
+:102570005870B982F98333239B01D31805935B69A3
+:102580000F2B73D200217C4FC0463961216A8A68C3
+:102590001204120C4B681E0C3604FD1F093D002E60
+:1025A00005D13B2A03D30123DB029A4201D9A87348
+:1025B000C8E001239B07083119430968C04603910D
+:1025C00003A9098801310904090C798249090531F7
+:1025D0000906090E694EC04602966948436AC0461C
+:1025E0000193836AC0460093C21D113280690003C3
+:1025F000000B9268B3071A431268904201D1012080
+:102600000DE0904205D9009B181A019BD21A82183E
+:1026100000E0121A01200901914200D30020012894
+:1026200065D151492069002862D005994869013077
+:1026300048610220216AC046086000F0A7FC786368
+:10264000BE604949226AA36BD318666BB34200D9B6
+:10265000226BC046BA62BA6A0C32FA620022FA6190
+:1026600003AA5288D20903D3012200E07BE000E0F4
+:1026700000227A607A68C0460260788A414E6028FB
+:1026800004DCB083788AC046F08308E06020B08321
+:10269000798AF86A4218636B9A4203D8F183002260
+:1026A0003A6305E0216BC0463963616B081AF08319
+:1026B0002D49786B4268C046BA608268C046FA60AD
+:1026C0000269C0467A614069C046B8612E4BC8189D
+:1026D000049000F037F9049800F088F800F0F6FA5A
+:1026E000788AF18B884204D1F96A081804E038E04E
+:1026F00032E03A6B1018401A810702D0800880003F
+:102700000430616B091AA26B914200D2206BC04663
+:102710002062E87B002808D00022EA730599486906
+:1027200001384861786B00F073FA1848806A8006B7
+:10273000800E01280AD1206A0003000B0B4CA16A0D
+:10274000884203D006B0F0BC08BC18470120400402
+:102750000849C046086006E0E068002801D000F0A3
+:10276000B5FA0120A873EDE7680E00800040144020
+:10277000A42A0080000000B0281A00805555555545
+:10278000A8030080681A0080C40B000000001040FD
+:1027900080B5071C786A4089FF210131014010484B
+:1027A00002D1816C01318164796A4989490B02D275
+:1027B000416C013141640B48416A01314162786AE0
+:1027C000396BC0464862386B00F0F8FB381C00F0EB
+:1027D000B3F801200449C046C87380BC08BC184740
+:1027E000A42A0080A0822040181A0080F8B5071C97
+:1027F0000022F91D61310D1C786AC04600904089A5
+:10280000030C01D2400A03D2381CFFF7C1FF67E076
+:102810003548C06B00091FD3087840081CD200203F
+:102820004300CC5A314E9E1933239B01F3181B8869
+:102830009C420ED0B869396BC0468861F868396B24
+:10284000C046C860381C00F027F9381C00F074F846
+:1028500046E001300328E3DB022043005C18E488F3
+:10286000224E9E1933239B01F3181B889C4203D1EF
+:1028700001230138D842F0DC0123D842C4D01B4EDA
+:102880000B231B02F0184069002824D07D630098B8
+:102890004089000C1FD200242D239B01F018C06B2F
+:1028A000351C002817D0FE1D2D36A20052192D23ED
+:1028B0009B01D218D26B381C311C02F07BFC012822
+:1028C0000ED00134A00040192D239B01C018C06B0D
+:1028D0000028EAD101E0012A02D0381C00F008F8F3
+:1028E000F8BC08BC18470000E81A0080680E008099
+:1028F00080B5071CB869396BC0468861F868396BC8
+:10290000C046C860786A4089010C0ED2400A0CD3D8
+:102910003868400802D3381C02F00CFC381C00F068
+:10292000BBF8381C00F008F802E0381CFFF730FF55
+:10293000012080BC08BC18470121006B406AC046DA
+:1029400001607047B0B4C11D3931098B8908090491
+:10295000090C846AC21D6132002000290CDD870049
+:102960003D1901239B072B431B68C046D3510130FF
+:102970000004000C8842F2DBB0BC7047F0B5A0B098
+:1029800001239B07C11D213119430968C0460B91E2
+:10299000C11D533119431F91096801AFFA1D393226
+:1029A0001E9217AB59803A4901239B070A6A1343C9
+:1029B000CC1D113489690903090B2269E568C046F9
+:1029C0001D95FC1D3934648B640905342406240EDE
+:1029D0001C94561A1B961C9C2E4AC0460092012637
+:1029E0001D9D1A68914201D1321C0BE0914203D91E
+:1029F000521B1B9EB51800E0551A01222401AC425F
+:102A000000D30022012AE6D1910701430968C0469C
+:102A100039609307011D19430968C0467960C11DDB
+:102A2000013119430968C046B9601F9909681E9AA7
+:102A3000C0465183C11D1D3119430968C046386322
+:102A40007962C11D113119430968C046B961C11DC0
+:102A5000053119430968C046F960C11D1731194392
+:102A60000968C046F9830E3018430068C046F881F3
+:102A70003868400802D3381C02F05CFB381C00F0B8
+:102A80000BF8381CFFF758FF20B0F0BC08BC184703
+:102A9000A803008055555555F8B5071CF81D393069
+:102AA000418B394A914200DD4283428BC0460092FD
+:102AB00001203A1D06CABB6A02F00EFF334AC04627
+:102AC0000092334E306A334CE16D4118386BC31DB0
+:102AD00005330120726A02F0FBFEE06D183000251C
+:102AE000B16A814201D8E56500E0E0652F239B01D2
+:102AF000201CE16DE41822689200274BC0469950D3
+:102B00002648C16B4A0805D349084900C163012022
+:102B100001F0D6FF224A1F48C11D89310B78002BD6
+:102B200002D04978002900D11E4AC0460092206890
+:102B30008000194BC31805CEC11D1131012002F0D0
+:102B4000C7FE1448216801312160172900D3256090
+:102B5000396BC0460D65796A3A6BC04651623323C2
+:102B60009B01C0188168002903D1396BC046816080
+:102B700004E0396BC268C0461165396BC046C1605C
+:102B8000F8BC08BC18470000EA0500001800140251
+:102B90007C290080680E008044822040E80E00807E
+:102BA0000400000204000003F0B5114EFF250135BA
+:102BB000104FC0463560786901387861BC68002CD8
+:102BC00010D0206DC046B860201C00F021F8201CF9
+:102BD00000F004FA0848806A000C0007E9D1F0BC54
+:102BE00008BC18470548C1790131C171F7E70000F9
+:102BF000000000B0281B008000001040A082204090
+:102C0000012080030149C04608607047000000B001
+:102C100090B5071C3868C00809D31D48016A0139FE
+:102C2000016220300079002801D0FEF7E9FD012380
+:102C30009B07F81D1D3018430068164C616A8142DD
+:102C400021D1011C194309680904090C01291AD171
+:102C500000F022F86062606A216A884205D0012192
+:102C60008907014309680904F2D051218903626A86
+:102C7000236B9A4202D1606BA26B801A0438C86041
+:102C800090BC08BC18470020796AC0460860F7E786
+:102C90006C060080E81A008001239B07C11D0131EA
+:102CA000194309680904090C08180D30810702D07E
+:102CB00080088000043004498A6B12184B6B9A42DA
+:102CC00000D9086B70470000E81A008000B504487E
+:102CD000C068102801D300F005F808BC18470000B0
+:102CE000E81A008088B50C4F3879002811D10B49BB
+:102CF000102002F0F5FD00280BD001203871084AA1
+:102D0000C046009207484268074B0168002002F065
+:102D1000DFFD88BC08BC1847F81A0080F52CFFFFBF
+:102D2000100035027C2900804480204090B50120AD
+:102D300040021049C04608600F4F1021F81D3D3079
+:102D400002F04CFC1923DB01FC18E068002801D0DC
+:102D500000F014F80020C9231B01F9180871E0687D
+:102D6000102804D30120BB231B01F918487390BC21
+:102D700008BC1847000000B0680E0080F8B537485E
+:102D80001923DB01C118C968354D102900D910215C
+:102D900069623248C16C006E814207D9081A07097E
+:102DA0000024686AB84212D2071C10E081422AD27D
+:102DB0002C4A526B101A0709686AB84205D90C09E7
+:102DC0003919884203D2C41B01E00024071C3E19B4
+:102DD0003001254902F084FD00283DD02348002C15
+:102DE0001AD11E493A016F62096E8C181D4D6B6B2A
+:102DF000A34200D8E41A1E4B1A430092EA6A511803
+:102E00002A6B031C20E01B48016B01310163002089
+:102E10006862F8BC08BC1847104924013F01112220
+:102E200052053A436E6200920E4DEA6A096E5118DD
+:102E3000031C061C00202A6B02F04AFD0C4A2243A8
+:102E40000092BB19E96A2A6B002002F041FD034899
+:102E5000C046046600F010F80120DAE7680E008032
+:102E6000281B00807C2900805D2EFFFF44802040CD
+:102E700000003602A08220400448016E044A8030DF
+:102E8000D1600223C16B1943C1637047680E008093
+:102E900090EE2040F0B584B0012080021C49C0466D
+:102EA000086000271B4E33239B01F518686A002831
+:102EB0001DD9194C6846102102F090FB684600F0BD
+:102EC00033F8002804D015494869013048610AE008
+:102ED0001349607B01306073887901308871114833
+:102EE000006802F065F9686A0137B842E2D8BB238E
+:102EF0001B01F018817B002903D000218173FFF7AB
+:102F000005FBFFF7E3FE04B0F0BC08BC1847000067
+:102F1000000000B0680E0080B0822040088320408E
+:102F2000A08220405804008090B4174F1923DB0181
+:102F3000F9180022CB68002B23D0013BCB60332350
+:102F40009B01FF18BB691C6DC046BC610468C0468C
+:102F50005C604468C0469C608468C0461C61C06870
+:102F6000C04658611A650869421C0A61002803D0EE
+:102F7000386AC046036500E0FB613B62181C90BCE8
+:102F80007047101CFBE70000680E00800A4A3323DC
+:102F90009B01D118C8691923DB01D2181369002BD2
+:102FA00006D0013B1361CA69126DC046CA61704701
+:102FB00000211161FBE70000680E0080064A1169DC
+:102FC0004B1C13614032002901D0D16900E000217F
+:102FD0000165D06170470000E81A0080064AD16898
+:102FE0004B1CD3604032002901D0916900E00021E0
+:102FF0000165906170470000E81A008090B40021DC
+:103000000F4A9789926A4B001B189B8A002B12D09B
+:10301000BB4210DC1C1C58236343D318DC1F493C03
+:1030200001239B0723431B681B061B0E032B02D0A7
+:10303000002090BC704701310429E4D30120F8E757
+:103040004C2A0080F7B586B03D4A071CD1698F40F5
+:10305000031C146AE3405F40079E8E407740CF40D8
+:103060009469C0460594031CA34000251469C0461A
+:103070000494002C5DD91C1C324E26439469E64012
+:10308000331C0396536AC0460293D26AC04601922B
+:10309000BB00029AD258131C059CE340039CA34238
+:1030A0003ED18A40CA40141C63001B195B01019A7F
+:1030B000D21801239B07D61D013633431B681B061C
+:1030C0001B0E032B2CD101239B07D61D51363343F6
+:1030D0001B68079E1E40009601239B07D61D49369C
+:1030E00033431B6883421BD101239B07D61D4D36FA
+:1030F00033431B68009EB34212D101239B071A433E
+:1031000012681204120C089B322B04D1022A07D138
+:10311000200400140FE0089B332B01D1012AF7D0C3
+:10312000049A0137974200D30027049A0135AA4236
+:10313000AED80020C04309B0F0BC08BC184700005E
+:103140004C2A008000000080F0B5274D68690028F7
+:1031500006D02648006802F02BF8F0BC08BC1847DF
+:10316000234C0026A068234F002816D00FE0286AC1
+:10317000022802D3012038710FE0A660FDF7DEFEC1
+:103180000028EAD1286A022801D301203871E868B2
+:10319000002802D038790028E9D0686800281BD0C0
+:1031A0000120A060FEF7BCFB0028D6D1686800288B
+:1031B000F6D111E00028D0D1286A022802D30120DC
+:1031C0003871CAE7A660FDF7B9FE0028C5D1286AA4
+:1031D000022801D301203871E8680028BDD0387971
+:1031E0000028E7D0B9E700006C0600805C0400808E
+:1031F0004C2A00808C060080704700007047000059
+:103200007047000090B540201D49C046086001F09D
+:103210009DFC03231B07416819400C0F6101091B2A
+:103220008900184A8F1801213980816AC046796562
+:10323000416AC0467967B96CFA6C8918B964002193
+:10324000F964BA6B3B6DD218BA633965426A2032B1
+:103250005171796D7A6FD26DC0461160FCF7CAFF6B
+:103260002001094940181923DB01C018416B0139BD
+:103270004163786F01F0C6FB90BC08BC18470000A2
+:10328000000000B05C2B0080A01C0080F0B5402046
+:103290001249C046086001F059FC071C406803232E
+:1032A0001B071840060F7001801B80000C49441852
+:1032B000B86AC0466065786AC0466067806F051D61
+:1032C000E563B969281C02F089F9381C211C321CFD
+:1032D0002B1C00F020F8F0BC08BC1847000000B020
+:1032E0005C2B0080F0B54B6F9B6F1F1DCF63056893
+:1032F00000238469A40808D09C002E59C0463E5182
+:103300008469A40801339C42F6D83B1C00F003F802
+:10331000F0BC08BC1847FFB581B0041C1D1C0F1C75
+:103320004648016901310161F91D5131BD650091C6
+:10333000201CFDF75DFCF86D400936D2B86D067BA8
+:10334000437B1B021E431721490201730B0A43737F
+:103350000099201CFDF74CFCB86DC0460673330A7B
+:103360004373F86D400920D260680104090C03988A
+:1033700001F0CCFC6068324B18436060201C01F007
+:1033800035FD00257D60BD603D647D64201CFCF73B
+:1033900031FF38884023184338807D622948C04671
+:1033A000B862381C00F0A0FB44E0206801239B07B2
+:1033B000083818430068C046786460680204120C3C
+:1033C000786E0126C11D0D318A4202D23A64081C72
+:1033D0000EE041198989F023194009098900401834
+:1033E000F860F96161680904090C814216D23964F8
+:1033F00063681904090C401A033080088200A06138
+:10340000206809189B186360C31F053B381C00F037
+:10341000B6FA7E80201C00F0BFFB0BE0B968081AEA
+:1034200000257862BD62381C00F03CFC201C391C71
+:1034300000F064F805B0F0BC08BC18470C2B008005
+:1034400000000080010000C0F0B5041C0F1C386CA7
+:10345000F96B0D18216841180020A269002A0BD9C8
+:103460008200561801239B0733431B68C046AB50AC
+:10347000A26901308242F3D8786EF96B0918898904
+:10348000F0231940090989004018F860F9612068A3
+:1034900001239B07083818430168786CFCF795FFF7
+:1034A000786460680104090CF868814219D23964B3
+:1034B00063681904090C401A033080088200A06177
+:1034C000206809189B186360C31F053B381C00F077
+:1034D00056FA01207880201C00F05EFBF0BC08BC8E
+:1034E0001847B968081A78620020B862381C00F0E2
+:1034F000D9FB201C391C00F001F8EFE7F0B584B0CF
+:10350000041C0F1C8E4841690131416103200007F2
+:1035100061680840060F0A04120C20681118FB6845
+:10352000D21A7B689D1AC31F053B381C2A1C00F069
+:1035300026FA00207880201C00F02EFB60684019DD
+:103540000104090C6060301C01F0E0FB7D4E0B2390
+:103550001B02F0180069002819D000252D239B01BB
+:10356000F018C068002812D0AA0092192D239B01E0
+:10357000D218D268201C391C01F01CFE0135A800AD
+:1035800080192D239B01C018C0680028ECD1F86B6E
+:10359000011F8A1CFA63FA687D6C00F0BBF9C04316
+:1035A0000104090C281CFCF710FF0390F96B3A6E1C
+:1035B0008E182068121801927A6E8D1811180291D7
+:1035C000C81D0930E060B1880802090A0906090E21
+:1035D00008430004000C78616868010EFF221204A1
+:1035E0000240120A1143FF2212020240120211434A
+:1035F000000608433861A88909231B021840B861F6
+:10360000A8899843A881A8890299C046888100208A
+:103610007080B080708168602882B96E301CFCF7C1
+:10362000E8FE3886FA69301C291CFCF703FF78860F
+:103630003D8E788E0399FCF7C8FE00906068000408
+:10364000000C396E411A0904090C7A6E821A1304AF
+:103650001B0C1A021B0A1A431604360CBA68824263
+:1036600001D2002000E0101AB86008020912090611
+:10367000090E08430104090C0198C0464180281C2A
+:10368000FCF7A3FE051C0098311CFCF79EFE061CEF
+:1036900078690004000C0102000A08430104090CC7
+:1036A0000198C0468180281CFCF78FFE79690131A2
+:1036B000C0437961019AC04650813869010EFF22EA
+:1036C00012040240120A1143FF22120202401202A7
+:1036D000114300060143301CFCF777FE39697A6814
+:1036E00089183961B968002909D102998989BA69AB
+:1036F0001143029AC0469181B969FCF766FE2082A7
+:1037000000206082F86D410816D3800A0AD36068F1
+:1037100010380104090C0802090A08432168C04650
+:10372000088209E060680C380104090C0802090AE3
+:1037300008432168C046888104B0F0BC08BC184723
+:103740000C2B0080680E0080F1B584B06E4D2869A6
+:10375000012204998A409043286104984301181A71
+:103760008000161C69494418E06BC0460090A068B0
+:10377000002801D1002626E06548416901314161F8
+:103780000498FCF709FD071C03D128693043286120
+:10379000B5E0A0686568A84200D2051CA16CA942EA
+:1037A00016D2401A626A101A00266062A660A662EB
+:1037B00020884823184320800D1C09D1381CFCF7B1
+:1037C00019FD032060806660201C00F08DF996E0F2
+:1037D000E16838680918C31F053B201C02392A1C00
+:1037E00000F0CDF8381C00F0D7F9E0684619786889
+:1037F000304378600498311C01F088FA216E0098FB
+:1038000008180190701A0004000C616E711A0A0405
+:10381000120C1102120A11430904090C029101024F
+:10382000000A08430104090C0198C0464180208E1B
+:10383000FCF7CBFD061C608E0299FCF7C6FD0390D9
+:1038400060690104090C0802090A08430104090C13
+:103850000198C0468180301CFCF7B7FD61690131D9
+:10386000C04361610199C0464881606E0099461865
+:103870002069010EFF2212040240120A1143FF22A6
+:1038800012020240120211430006014371600398C4
+:10389000FCF79BFD216949192161A168491BA160C1
+:1038A00006D1B189A2691143B181A169FCF78DFDEF
+:1038B0003882616E386809180E31F960E268009943
+:1038C000043800F04CF802207882E06D410816D3ED
+:1038D000800A0AD3786810380104090C0802090A22
+:1038E00008433968C046C88109E078680C3801048B
+:1038F000090C0802090A08433968C046488105B026
+:10390000F0BC08BC18470000D02C00805C2B008065
+:103910000C2B0080F7B5031C0F1C00201C6826042C
+:10392000311C1D1DFCF751FD40C7029AD11C8908AE
+:1039300001394A1E029200290DD0210C10CD22041B
+:103940000A43111C161CFCF740FD40C702994A1E91
+:1039500002920029F1D103B0F0BC08BC18478008DE
+:10396000800089088900033293085A1E002B05D075
+:1039700008C908C0131C013A002BF9D17047FFB5E4
+:1039800086B0171C00260698806CC01B0699C0469E
+:1039900088640120C0050699896BC046019106998B
+:1039A0004C6B67E02168C04602916168C046039194
+:1039B000A168C046049102A94988B94208D202AD63
+:1039C0006D8802A949887F1A002102AB598019E04D
+:1039D00002A94988C91B02AB59803D1C002701215F
+:1039E0004906079B9A07920F0DD0EB06DB0E08D015
+:1039F0001E2B08D31E2B02D1032A04D101E0022A78
+:103A000001D301260021294301430A1C0091002013
+:103A10000399049A079B01F05BFF079949190791E5
+:103A2000002E0AD01D4AC04600921D48016D426D0D
+:103A30000020079B01F04CFF002602A840880028C8
+:103A40000CD00398401903900298C0462060039858
+:103A5000C04660600498C046A06003E00198013849
+:103A6000019010340698C046446301980699C046F8
+:103A700088630020002F02D00199002992D1094AC1
+:103A8000C04600920648016D426D0020099B01F07E
+:103A90001FFF0AB0F0BC08BC18470000010000027C
+:103AA0007C2900800400530290B50C1C071C386868
+:103AB00001239B07083818430168388AFCF785FC06
+:103AC000C043F968C0460880788A3968081A3860A7
+:103AD000381C01F08BF9381CFCF78CFB201CFFF71D
+:103AE00033FE90BC08BC184780B501888A0921D3F1
+:103AF000CA091FD28A081DD3002101804180476F67
+:103B0000406DFA1D19325171FA6DC04610603A6E5F
+:103B1000C04610600C48C0468163C16B490849002B
+:103B2000C163012000F0CCFF381C00F06BFF80BCAB
+:103B300008BC184780231943018001884909F6D23F
+:103B400000F0B0F8F3E70000E80E0080F0B5071CC5
+:103B5000101C0D1C00245E1E002B19D00168C046ED
+:103B6000396041880C194168C04679608168C04657
+:103B7000B960C168C046F96010301037E96A814207
+:103B800002D8281C00F0ECFF311C013E0029E5D1D1
+:103B9000201CF0BC08BC18470021C16105490A6817
+:103BA000002A01D1086002E04A68C046D06148603E
+:103BB00070470000D02C008003490868002802D01C
+:103BC000C269C0460A607047D02C0080002181671E
+:103BD00005498A68002A01D1886002E0CA68C046A7
+:103BE0009067C86070470000D02C00800349886847
+:103BF000002802D0826FC0468A607047D02C0080B7
+:103C000000B580201349C0460860FFF7D5FF0028A3
+:103C10001BD003231B07416819400A0F5101891A61
+:103C200089000D4BC9184B88002B04D1111CFFF7DC
+:103C30003BFF08BC1847012B02D1FFF705FCF8E752
+:103C4000022BF6D1FFF74EFBF3E70448016D01317B
+:103C50000165EEE7000000B05C2B0080A0822040F0
+:103C600000B520200D49C0460860FFF7BFFF0028BF
+:103C70000ED0018820231943018001881023994325
+:103C800001800188090A01D3FFF72EFF08BC1847FD
+:103C90000348016D01310165F8E70000000000B044
+:103CA000A082204098B5071C2248C04600902248B8
+:103CB000C31D4133416D826D806C0003000B9C6815
+:103CC00001239B0723431B68984200D10CE09842D4
+:103CD00003D9101A591A411800E0191A01201029A5
+:103CE00000D8002000281FD0786AF96AC046086012
+:103CF000B86AF96AC0464860104AC0460092FB6A3A
+:103D00000F48426D0320396A01F0E2FD3888102324
+:103D1000184338803888402398433880381CFFF790
+:103D200055FF98BC08BC1847388840231843388092
+:103D3000F7E7000055555555A8030080080011020B
+:103D40007C290080B0B540202C49C046086000F0B6
+:103D5000FDFE071C406803231B071840050F680180
+:103D6000401B8000264944182088022318432080E5
+:103D70002088410834D3400840002080A06CE16CCA
+:103D80004018A0640020E064A16B226D8918A16333
+:103D90002065B86AC046606503231B077868184031
+:103DA000786061683631942904D8382318437860E4
+:103DB000382003E09423184378609420B861396870
+:103DC00078680204120C201CCB1F053BFFF7D7FDBF
+:103DD00002206080381CFFF7DFFEB0BC08BC18472B
+:103DE000381CFCF707FA2801064940181923DB01A3
+:103DF000C018416B01394163EFE70000000000B0DB
+:103E00005C2B0080A01C008090B500270F4C0DE0BB
+:103E1000426B013A4263002A05DC026BC0464263F2
+:103E2000C06A01F0C6F901370B2F07D2380100191B
+:103E300033239B01C018816A0029E9D10120400683
+:103E40000349C046086090BC08BC1847680E008053
+:103E5000000000B01048C1680131C1600F49C86856
+:103E6000012817D1C81D79300289002A12D0013AE1
+:103E700002810289002A0DD14289002A08D1C96F26
+:103E800002230A681A430A6004210181012100E02B
+:103E9000002141817047000008832040680E0080A7
+:103EA000B0B5071C0123F81D693003731E48C21DFD
+:103EB0007932548A611C5182D58A0021AC4204DBDC
+:103EC000C41D893463705182D18301239B073A6DED
+:103ED0001A431268C046BA61FB699A4206D1F86C6F
+:103EE0001249C0460860B0BC08BC184779614169F6
+:103EF000FA6C9143416101200005C16038690228D4
+:103F0000F1D0B869F969411A01D5786D4118381CAA
+:103F100000F00EF8F9690918F961786D8142E2D371
+:103F2000081AF861DFE70000680E0080000000B0AA
+:103F3000F8B5041C0F1CFF2321339F4201D9FF2732
+:103F40002137E16E381C01F0CBFC2D4D002813D138
+:103F5000E01D4930017A012319430172294AC04604
+:103F600000922948016D426D00202B1C01F0B0FC2D
+:103F70000020F8BC08BC18472069013020612349A3
+:103F8000C81DB930026B92005118C0310F61016B2E
+:103F900001318907890F0163206BC219616D8A4263
+:103FA00003D8232212053A4305E0091A7E1A07D1E5
+:103FB000232212050A430092616E0918A26E10E0D6
+:103FC000112252050A430092616E09180020A26E68
+:103FD0002B1C01F07DFC2322120532430092616EFE
+:103FE000A26E00202B1C01F073FC206BC01900098D
+:103FF0000001616D814200D8401A2063381CB8E787
+:104000004480204004001B027C290080680E008050
+:1040100080B50120C0030D49C04608600C49C81D89
+:104020004930027A0027002A03D00772081CFFF7E4
+:1040300037FF0849C81D4930027A002A03D00772A9
+:10404000081CFFF72DFF80BC08BC1847000000B01B
+:10405000642D0080E42C008090B5071C10201849C6
+:10406000C0460860F8680130F8601648C41DB934CD
+:10407000616B89000918C03109697A689200D21908
+:104080005164616B89000818C0300169786880004C
+:10409000C019C06B01F0A2FA01237868584078601B
+:1040A000606B01308007800F6063F81D1930407924
+:1040B000002802D1381C00F007F890BC08BC184753
+:1040C000000000B0680E008090B5071C3948C06839
+:1040D000002805D0B86AC068800901D3022000E03A
+:1040E000786FFCF759F8041C06D10120F91D19312D
+:1040F000087190BC08BC1847F86C2F49C04608608E
+:10410000BA6A381C211C00F059F86762002803D1F4
+:10411000201C00F00BFDECE7F96D0968091809098E
+:1041200009017A6D8A4200D8891AA162B9688900AA
+:10413000C9194A6C002A07D04A6C121A4A648008CE
+:104140008000B96A0818B8623868B96A8000C01976
+:10415000426B91420ED300214164B86A39688900EC
+:10416000C919496B401AB862B9688900C919C96B85
+:104170004018B862B8688100C919496C0029B8D1E3
+:10418000B96AFA6B9142B4D03A6C9142B1D0012332
+:104190005840B8608000C019C06BC046B862F8686B
+:1041A000002801D00138F86038690028A1D0013812
+:1041B00038619EE768190080000000B0F7B590B044
+:1041C000041C0D1C00200590029000220192F94869
+:1041D000C06AC046A861A06881000919496BC04641
+:1041E0002060E162129AD068C046A860129A5178A5
+:1041F000C0460C91F048C0460390D71D0937E06ACD
+:10420000C11B0909E31D19330C9AC0460F93EB4BF0
+:10421000C0460E93914201D3B84221D8E1680229E9
+:104220001ED201200F99C04648710020039901F069
+:1042300057FB002803D10E9BD86B0130D8630120B7
+:10424000800600276860AF61DD4AC0460092DD4805
+:10425000016D426DDC4B002001F03AFB381C5CE341
+:10426000B84203D8201C00F07BFC071CD748C0686C
+:10427000002864D038784007400F032860D10598A3
+:1042800001300006000E05903878F023184058D110
+:10429000E06AC01B00090C99884202D2E06802283B
+:1042A00005D3CB49886800F083FF061C06D1039B29
+:1042B000281C391C221C00F08BFC16E12E62F868C9
+:1042C00000280DD0B889002803D0C149C96800F082
+:1042D00070FFF889002803D0BD49C96800F069FF64
+:1042E0007A68C0467261B968C046B161301CB8498D
+:1042F000096800F05EFF002817D1301CB4494968F6
+:1043000000F057FF1037E06AB84203D8201C00F0D5
+:1043100027FC071C6868AF4B184368600020A86141
+:10432000AC23A8689843A860B0E0A869A82801D287
+:10433000A820A8611037E06AB8426CD89CE0A5E0DC
+:10434000A4E0102868D103231B0768681840010FF8
+:104350004801401A8000A04A821801927888420BD6
+:1043600031D3820B2FD39D48C04603900220019A7F
+:10437000C046108078880005000D019AC046506044
+:10438000B868019AC04690607868019AC046106289
+:104390000020019AC0469064019AC046906388024A
+:1043A0008F494018019AC0465063019A50683630D0
+:1043B000942801D8382000E09420A8611037E06AE2
+:1043C000B84228D858E07A88920B03D38548C04673
+:1043D000039023E0012212030240834B1DD003937C
+:1043E0000005000D019AC0465060B868019AC046A9
+:1043F00090607868019AC04610620020019AC04619
+:104400009064019AC0469063880275494018019AE9
+:10441000C046506302E033E02AE0039301200F9985
+:10442000C0464871129A50780599431A0B93103779
+:10443000E06AB84203D8201C00F092FB071C019AE6
+:10444000506B916B090140180B9B211C3A1CFFF724
+:104450007DFB019AC046D064019A0B9BC046136550
+:1044600001235B066868184368600020A8610DE0BE
+:104470001037E06AB84203D8201C00F071FB071C1B
+:1044800038784007400F032800D1F8E6A86903995F
+:1044900001F026FA00282AD1381C211C00F079FBF3
+:1044A000A868800904D3301C4949496800F081FE9E
+:1044B0004149002001F014FA002804D10E9BD86B6A
+:1044C0000130D86311E001200F99C0464871800681
+:1044D00000276860AF613A4AC04600923948016DD2
+:1044E000426D394B002001F0F3F9002015E20598E8
+:1044F0000C99081A0004000C0C900B900C980028E2
+:1045000003D001200F99C04648712868C046049026
+:1045100000260020089000220A920C9801380D9085
+:10452000A3E078888A1B1204120C904205DD0792E2
+:10453000801A0004000C089000E0079008980028FA
+:1045400007D10D980A9A904207DD079830188842E3
+:1045500003D80120400506901CE01120400506907C
+:10456000A8688C23184002D12048C0460690B107A5
+:10457000890F0FD00798C006C00E08D01E2809DB8F
+:104580001E2802D1032905D101E0022902D301200E
+:104590000290DEE70A9A002A04D10123DB0506987F
+:1045A00018430690079806990843021C0090049847
+:1045B00083191DE0E80E00800149FFFF280F0080ED
+:1045C000040012027C290080448020406819008089
+:1045D00060040080000000805C2B00805532FFFFEB
+:1045E000AC5E21400D3DFFFFCD31FFFF00003202E8
+:1045F00000203A1D06CA01F06BF907983618029898
+:10460000002816D0A8688C23184004D109235B0425
+:104610000698184306900698C24A024300920498EE
+:104620008319C148016D426D002001F051F900204D
+:104630000290089800280BD10B9B013B0B9310377D
+:10464000E06AB8420CD8201C00F08AFA071C07E088
+:104650007868079A801878607888079A801A788036
+:104660000A9A501C0204120C0A920C980A9A82426E
+:1046700003DAA969B14200D953E7A869B0426BD106
+:10468000A868010969D2089A002A56D00C990A9A9A
+:104690008A423EDBB107890F0CD0089AD206D20EAF
+:1046A0000BD01E2A06DB1E2A02D1032905D001E009
+:1046B000022902D20299002921D0089AC04600920C
+:1046C0000498831900203A1D06CA01F001F90898E0
+:1046D0003618A8688C23184002D00120400600E05C
+:1046E0009248012202430092049883198E48016D7A
+:1046F000426D002001F0ECF80020029015E08C23C0
+:10470000184002D00120400600E08848089A024381
+:1047100000E0089AC04600920498831900203A1DD0
+:1047200006CA01F0D5F8089836181037E06AB84282
+:1047300003D8201C00F014FA071C6868800E6BD2A6
+:104740000A98C04609900C9988425CDA0D9809993C
+:10475000884203D07A881EE05FE05EE0788801221C
+:1047600052060243A9688C23194002D109235B0435
+:104770001A43B107890F0ED0C306DB0E08D01E2BDB
+:1047800009DB1E2B02D1032905D101E0022902D346
+:1047900001210291021C0998002802D10123DB05A6
+:1047A0001A4300920498831900203A1D06CA01F0AA
+:1047B0008FF87888861910370298002814D0A868D6
+:1047C0008C23184002D00120400600E05748012207
+:1047D00002430092049883195348016D426D0020F2
+:1047E00001F076F800200290E06AB84203D8201C5D
+:1047F00000F0B6F9071C099801300004000C09907C
+:104800000C998842A2DB686830430104090C686097
+:10481000E86A00F07BFA28E027E0A868000914D3D2
+:104820006868800E15D2019A002A12D0019A506B46
+:104830000B9B211C3A1CFFF789F9019AC046906432
+:10484000019A0B9BC046936303E0E86A311C00F0B9
+:104850005DFA686830436860A869B04205D9000411
+:10486000000C801B00F0EEF9AE61A8688C231840A4
+:104870000BD02F4AC04600920498C31F053B2A481C
+:10488000016D426D002001F023F801239B07206D8C
+:1048900018430068C046A061E169814212D02269D4
+:1048A000022A0FD2411A01D5606D4118201CFFF772
+:1048B0003FFBE1694018E061616D884224D3401AF2
+:1048C000E06121E081421FD1206902281CD2012031
+:1048D000606118484169E26C0A4342618169E36C96
+:1048E0009943816101210905CA608069C046086158
+:1048F0008B02206D18430068C046A061E1698142C7
+:1049000002D0201CFFF7CCFA281C00F00FF90C98FD
+:104910000599401800011030686113B0F0BC08BC64
+:1049200018470000010000027C29008000001202EC
+:1049300004005202680E0080F0B540202D49C046A8
+:10494000086000F003F9071C8169446AA06F00F059
+:1049500045FE0020E11D193148717968C90E09D35F
+:10496000F86A000124494018244BC0180168013935
+:10497000016036E0E16D0968226EC0461160204E8C
+:10498000F51D79350123E96B1943E963B96AE26DD5
+:10499000C0461160B96A226EC04611606169002983
+:1049A00004D1A96B0131A963082907D3A8630120A9
+:1049B00000F086F8E86B40084000E8637868810EF4
+:1049C0000FD20B231B02F118C968002906D000087A
+:1049D00004D2201C391C00F043F802E0381C00F01F
+:1049E00005FA381CFBF706FC201C00F00BF8F0BCA5
+:1049F00008BC1847000000B0A01C0080B40C0000E8
+:104A0000680E008080B5071CF81D19300179002957
+:104A100004D000210171381CFFF756FBF86802280A
+:104A20000DD0B8688000C219506C002811D0B86A47
+:104A3000417809011031526B101A884205D3381C95
+:104A4000FFF742FB80BC08BC1847381CFFF728FA68
+:104A5000F8E778688000C019C06BC046B862F1E71B
+:104A6000B0B587B00F1C806FC04600900024134D76
+:104A70000B231B02E8188069002817D06946A200A2
+:104A800052190B231B02D2189269381C00F092FBBA
+:104A9000002809D10134A00040190B231B02C018C3
+:104AA00080690028EAD101E0012802D0381C00F01A
+:104AB0009DF907B0B0BC08BC18470000680E008024
+:104AC000B8B5C207D20F164C164901D0082208E02B
+:104AD000820805D30C22A4180B68DF1D153703E0EC
+:104AE0001C220B68DF1D09370F4B1D78002D13D0DA
+:104AF0005B78002B10D001235B061A43002801D1FC
+:104B00005B081A4300924A680120391C231C00F0FC
+:104B1000DFFEB8BC08BC184703231B061A43F1E7A5
+:104B200090EE20407C290080F80E00800021C161B9
+:104B300005498A68002A01D1886002E0CA68C04637
+:104B4000D061C86070470000280F00800349886862
+:104B5000002802D0C269C0468A607047280F0080D2
+:104B6000011C0123886858408860CA68013ACA60FD
+:104B70000A69013A80000A614218D06B536BC04643
+:104B8000CB620B689B005918496C536CC91851646F
+:104B900070478A6892005218D36B834217D1D01D98
+:104BA0003D300A6892005218526C03689A1A0260EB
+:104BB0000123886858408860CA680132CA600A695F
+:104BC0000132800040180A61406BC046C8627047DD
+:104BD000B8B5041C1D1C171C081C391CFFF7D9FF95
+:104BE0000020291C00F07CFE0120F91D19314871BC
+:104BF000800660600020A061064AC0460092064818
+:104C0000016D426D054B002000F062FEB8BC08BC8F
+:104C100018470000040012027C29008044802040D4
+:104C200006490A681018086001235B02984203D9FC
+:104C300003490A7901320A7170470000E42D0080AF
+:104C4000A08220408008800006490A681018086089
+:104C500001235B02984203D903490A7901320A71A0
+:104C600070470000E42D0080A082204003308008BF
+:104C7000800006490A681018086001235B02984208
+:104C800003D903490A7901320A717047E42D008083
+:104C9000A0822040024841790131417170470000F3
+:104CA000A082204090B48200174B9A588B0702D004
+:104CB00089080B1D01E08908CB1C1169D768124CCB
+:104CC000800020584068B94203D1814219D9116847
+:104CD00017E00024B94209D9814212D91168781A23
+:104CE00000D50330801098420BD807E0814205D8E8
+:104CF000781A00D503308010984202D8201C90BC4E
+:104D00007047C81D0530FAE77004008080B5800048
+:104D10000F4A1758880702D08808043001E0880835
+:104D2000033039697A68914209D93968C0463961D6
+:104D3000F9687A68914202D93968C046F960810001
+:104D4000386900F0D1FD386180BC08BC184700000C
+:104D50007004008090B50321090701400C0F010485
+:104D6000090C012292070240A3001C4FFF5889073B
+:104D7000890F0004000C8008002900D00130002AAF
+:104D800001D0023000E00330F9687A68914202D91C
+:104D90003968C046F9608100F86800F0A5FDF86048
+:104DA0000F480069002805D00120A04002D0201C37
+:104DB000FEF7CAFC0B49C81D193003790022002BED
+:104DC00005D10949C81D19300379002B03D00271A0
+:104DD000081CFFF779F990BC08BC184770040080E4
+:104DE000D02C0080642D0080E42C0080B0B52B49CD
+:104DF0000979002903D14168294B19434160816831
+:104E0000490802D30921090401E00D2109040CC855
+:104E1000083819438768BB0A03D343685B0800D38B
+:104E20000131406803231B071840070FF8001D4C91
+:104E300000192368C01850300079012810D160682B
+:104E400001280DD0101C00F071F838010019192349
+:104E5000DB01C018416B01394163B0BC08BC184785
+:104E6000380100191923DB01C018036B5D1C0563B1
+:104E7000BD022D19DB00EB1880331963DA62816BF8
+:104E8000013181630121B940226811432160016B26
+:104E90008029E2D300210163DFE70000280F0080B2
+:104EA00000000080A01C0080F0B51F4E7068002834
+:104EB00036D10024B168481CC9008919B060326835
+:104EC000891860310D7B082800D3B460280180194F
+:104ED0001923DB01C018876B002F21D0C16A4B1C3E
+:104EE000AA029219C90051188031C362CA6A096BBB
+:104EF000013F8763802B00D3C462002F06D10127B6
+:104F0000AF403B1CDB4337683B403360436B013BA6
+:104F10004363101C371C00F009F878680028C9D0DA
+:104F2000F0BC08BC18470000A01C0080F0B5CD0FF5
+:104F3000ED07012400272E4B2E4A002D1DD0D86AE4
+:104F40000130D862101C5269002A12D00269531C29
+:104F50009200121803619161416901314161026956
+:104F60000F2A00D307610F2900D34460F0BC08BCAE
+:104F70001847081CFFF7EEFEF8E715696E1CAD0038
+:104F8000AD181661A96155690135556116690F2E75
+:104F900000D317610F2D00D354608C02A40A164F62
+:104FA0003A6FFD68F91D7931012D0CD1DB6D5B087D
+:104FB00009D30B89002B06D1FD6F033B2E683340CC
+:104FC0002B6014230B8110608007800A20430304A8
+:104FD00000D001385060096A0832914200D8074A6F
+:104FE000000D02D35120800382613A67BEE70000C2
+:104FF000A42A0080A01C0080680E008024A7204006
+:10500000B0B5002804D10120C0051649C04608608B
+:10501000154C00256769002F16D0E068411C800000
+:105020000019E1608069013FFFF794FEE0680F28F6
+:1050300000D3E560E068800000198069000801D3B2
+:10504000002FEAD1676103E00848016D0131016575
+:1050500065602068002801D0FFF726FFB0BC08BCBF
+:1050600018470000000000B0A01C0080A082204073
+:1050700000207047B0B41023826813400021002B39
+:1050800015D00C4B1A401201812414430268156894
+:10509000131D80CB1B68043A026020C280C208C284
+:1050A0001460426801239B0704321A434260081CC3
+:1050B000B0BC704700F0FF0FF0B48268530934D3DE
+:1050C0001B4B1A4012018126164303681D681F1DE1
+:1050D00010CF3F68043B036020C310C380C31E6031
+:1050E00043681F1D01239B073B434360CB6B181F85
+:1050F000C86380CB80C01C681F1D031D0460381C62
+:105100003F68C0461F601F1D43681C04240C812398
+:1051100023433B604068000C000410437860086E35
+:1051200004300866486E043048660020F0BC7047C2
+:1051300000F0FF0F80B4816A01239B07CA1D05326E
+:105140001A431268CF1D01373B431B68C046CB6032
+:1051500001239B070F1D3B431B68C0468B60012347
+:105160009B070B431B680CC10262016BC0460A62BD
+:105170000423816919438161026BC0469161816A90
+:1051800004318162026BC0469162C11D39314A8B84
+:10519000043A4A83498B026B40325183C1890439F6
+:1051A000C181C168006BC046C160002080BC7047EF
+:1051B00000470847104718472047284730473847D7
+:1051C00030402DE90CC09DE50C48A0E12448B0E139
+:1051D0001E00000A01C04CE21840A0E364519FE5A4
+:1051E000945020E0005090E5144090E5003085E5B3
+:1051F00004C085E5081085E50C2085E5101090E5D4
+:10520000105085E2010055E10C509055040055E125
+:105210000500000A041090E5005080E5005081E58B
+:105220000000A0E33040BDE81EFF2FE1003093E511
+:10523000082090E5013183E3023683E3030055E162
+:10524000143080E5F2FFFF1A0100A0E3F4FFFFEA4B
+:1052500001061CE3F1FFFF0AEC109FE502C6CCE358
+:10526000542091E5E4309FE5501091E5D9FFFFEA25
+:10527000F0472DE920C09DE50C68A0E12668B0E16B
+:105280002500000A1840A0E3B8509FE5940000E014
+:10529000050080E0084090E5048090E50070A0E300
+:1052A0001FC0A0E302C48CE3005090E5109090E58D
+:1052B00014A090E5003085E504C085E5081085E57B
+:1052C0000C2085E5105085E2090055E10C50905501
+:1052D0000A0055E11500000A037017E2201081E270
+:1052E000203083E20A00000A006096E2017087E243
+:1052F0000900000A206046E2200056E3ECFFFFCAE6
+:105300000070A0E301C046E202C48CE30060A0E3A9
+:10531000E7FFFFEA005088E5F2FFFFEA0010A0E394
+:10532000005080E50100A0E1F047BDE81EFF2FE13D
+:1053300000A094E50A0055E114A080E5E5FFFF1AFE
+:105340000110A0E3F5FFFFEAA80300807C2900809C
+:105350000080204068829FE50B92A0E364A29FE555
+:1053600058B09AE50EF0A0E154B09AE51EFF2FE187
+:105370003F402DE900004FE11F0000E2120050E322
+:105380005400000A00000FE18000C0E300F021E1BA
+:105390000450A0E3004099E5090000EA020014E38C
+:1053A0005300001B800014E35900001B200014E38D
+:1053B0005900001B020714E35900001B010614E307
+:1053C0005900001B080014E34500001B020514E30C
+:1053D0004A00001B020814E34B00001BE50E14E317
+:1053E0000700000A042098E50C1098E5043052E20A
+:1053F0003C30A0B3043088E5020091E70FE0A0E163
+:1054000010FF2FE1015055E20300000A004099E52A
+:105410000C009AE5000014E11BFF2F1108009AE52B
+:10542000000014E10B00000A010C14E398019F1521
+:105430000FE0A01110FF2F11020414E38C019F153F
+:105440000FE0A01110FF2F11010914E380019F1537
+:105450000FE0A01110FF2F1104009AE5000014E1E5
+:105460001600000A54E08FE2040014E340009A158D
+:1054700010FF2F11020A14E344009A1510FF2F1198
+:10548000020914E348009A1510FF2F11010214E3DA
+:105490004C009A1510FF2F11010414E350009A15C7
+:1054A00010FF2F11010A14E32100001B020014E376
+:1054B0000E00001B10009AE5000014E11C00001B08
+:1054C000004099E50450A0E3004094E21BFF2F1137
+:1054D0003F40BDE804F05EE2C00080E300F061E11F
+:1054E000FAFFFFEA18009AE51C109AE511FF2FE178
+:1054F00054B09AE51C109AE514009AE511FF2FE1CB
+:1055000020109AE50000A0E311FF2FE124109AE596
+:1055100011FF2FE128109AE511FF2FE12C109AE5D9
+:1055200011FF2FE130109AE511FF2FE134109AE5B9
+:1055300011FF2FE1FEFFFFEA38E09AE53C109AE503
+:1055400018009AE511FF2FE138E09AE53C109AE542
+:1055500014009AE511FF2FE164209FE5003092E5E9
+:10556000003053E00A0000BA003082E50C0092E5FA
+:10557000083092E5001091E20300000A031080E772
+:10558000043053E23C30A0B3083082E50100A0E3D0
+:105590001EFF2FE13C109FE5000091E5010080E235
+:1055A000000081E50000A0E3F8FFFFEA10009FE59E
+:1055B000081090E5041051E23C10A0B3081080E5FB
+:1055C0001EFF2FE1E42D0080CC040080712BFFFF33
+:1055D000D13DFFFFC92BFFFFA0822040C91C8908D5
+:1055E00089000123854A5B07184313685B18136021
+:1055F000001F81A35B1A18470420A0E50420A0E542
+:105600000420A0E50420A0E50420A0E50420A0E5F6
+:105610000420A0E50420A0E50420A0E50420A0E5E6
+:105620000420A0E50420A0E50420A0E50420A0E5D6
+:105630000420A0E50420A0E50420A0E50420A0E5C6
+:105640000420A0E50420A0E50420A0E50420A0E5B6
+:105650000420A0E50420A0E50420A0E50420A0E5A6
+:105660000420A0E50420A0E50420A0E50420A0E596
+:105670000420A0E50420A0E50420A0E50420A0E586
+:105680000420A0E50420A0E50420A0E50420A0E576
+:105690000420A0E50420A0E50420A0E50420A0E566
+:1056A0000420A0E50420A0E50420A0E50420A0E556
+:1056B0000420A0E50420A0E50420A0E50420A0E546
+:1056C0000420A0E50420A0E50420A0E50420A0E536
+:1056D0000420A0E50420A0E50420A0E50420A0E526
+:1056E0000420A0E50420A0E50420A0E50420A0E516
+:1056F0000420A0E50420A0E50420A0E50420A0E506
+:105700000420A0E50420A0E50420A0E50420A0E5F5
+:105710000420A0E50420A0E50420A0E50420A0E5E5
+:105720000420A0E50420A0E50420A0E50420A0E5D5
+:105730000420A0E50420A0E50420A0E50420A0E5C5
+:105740000420A0E50420A0E50420A0E50420A0E5B5
+:105750000420A0E50420A0E50420A0E50420A0E5A5
+:105760000420A0E50420A0E50420A0E50420A0E595
+:105770000420A0E50420A0E50420A0E50420A0E585
+:105780000420A0E50420A0E50420A0E50420A0E575
+:105790000420A0E50420A0E50420A0E50420A0E565
+:1057A0000420A0E50420A0E50420A0E50420A0E555
+:1057B0000420A0E50420A0E50420A0E50420A0E545
+:1057C0000420A0E50420A0E50420A0E50420A0E535
+:1057D0000420A0E50420A0E50420A0E50420A0E525
+:1057E0000420A0E50420A0E50420A0E50420A0E515
+:1057F0000420A0E50420A0E51EFF2FE1E42D008099
+:1058000098009FE598109FE5012040E094309FE5C7
+:10581000000091E5030050E10300001A041081E24A
+:10582000042052E20000000AF8FFFFEA78009FE53A
+:10583000002080E574009FE574109FE5012040E0A2
+:1058400060309FE5000091E5030050E10300001A7D
+:10585000041081E2042052E20000000AF8FFFFEA8F
+:1058600050009FE5002080E54C009FE54C109FE52F
+:10587000012040E02C309FE5000091E5030050E15D
+:105880000300001A041081E2042052E20000000A22
+:10589000F8FFFFEA28009FE5002080E51EFF2FE1CA
+:1058A0007C34008080300080ADDEADDEC00400803E
+:1058B000FC37008080340080C4040080FC3F0080FE
+:1058C00040380080C80400807847000071EAFFEA91
+:1058D0007847000039FEFFEA7847000063FEFFEAE0
+:1058E000784700001BFFFFEA784700006BEAFFEAF9
+:1058F00000000000FFFF00000000008028040000FE
+:10590000F83D00000001008000FF000000000000E2
+:10591000B90BFFFF00000000D50BFFFF03FF06548B
+:10592000030000007504FFFF00000000A105FFFF59
+:1059300004FF075403000000B504FFFF000000004F
+:10594000F105FFFF05FF0554030000003904FFFFC8
+:10595000000000005505FFFF01FF040003000000E8
+:105960004118FFFF00000000610EFFFF02FF020868
+:1059700000000000A102FFFF00000000F102FFFF95
+:10598000FFFF0144030000000000000000000000D1
+:105990009D0DFFFF0600FF00000000003D50FFFFCF
+:1059A0008150FFFF00000000FFFFFF00000000002B
+:1059B000000000000000000000000000FFFFFF00EA
+:1059C00000000000000000000000000000000000D7
+:1059D000FFFFFF00000000000000000000000000CA
+:1059E00000000000000000000000000048050080EA
+:1059F000117521401B7521403175214049752140A9
+:105A000055752140637521407D752140A975214060
+:105A10006D762140C5762140D3762140DD76214048
+:105A2000E776214099772140A7772140B57721403B
+:105A3000617821405F7C2140E97C2140897D2140C3
+:105A4000BD7E2140C97E2140297F21408D7F21409C
+:105A5000B97F2140DD7F21401D80214045802140CC
+:105A60008D8021409D802140C5802140D5802140EE
+:105A70001D8121405B812140B18121401182214063
+:105A80001B8221401F8221408D822140D9822140EA
+:105A9000318321406D832140D183214009842140FD
+:105AA0001984214051842140618421407584214022
+:105AB0009D842140A7842140B18421401585214047
+:105AC0004585214051852140C5852140CF85214014
+:105AD000D9852140E3852140ED852140F78521408E
+:105AE000018621400B8621401586214001892140F5
+:105AF0001F86214029862140338621403D86214052
+:105B0000658621406F862140D1862140DB86214079
+:105B1000E5862140EF862140F98621409D74214091
+:105B20000387214069872140B5872140F9872140BB
+:105B3000098821409D742140558821405988214081
+:105B40005D882140B5882140DD882140E9882140D9
+:105B5000ED882140F1882140F5882140F9882140D5
+:105B6000FD8821402D852140898521409D7421405B
+:105B70009D7421400D8921409D742140E174214094
+:105B80009D7421409D7421409D7421409D7421404D
+:105B90009D7421409D7421406B782140F57B21400C
+:105BA000317C2140000000000000000000000000E7
+:105BB000000000005C0118405801184024A3204058
+:105BC00024A7204000000000000000006C011840E5
+:105BD000680118402483204024A3204000000000D6
+:105BE000000000007C01184078011840000000000F
+:105BF0000000000000000000000000008C011840C0
+:105C00008801184024A9204024AB20400000000057
+:105C10000000000000000000080012001800120040
+:105C20000C0012001C00120024A82040A4A8204050
+:105C3000A4A8204024A9204000000000D1A82140B1
+:105C40002DAA21400000000089702140C9A12140F7
+:105C50000000000000000000010000000000000043
+:105C600057892140D1A82140C52FFFFF0521FFFF03
+:105C7000EF20FFFF59A72140342E0080482E0080DE
+:105C80005C2E008030333A31313A31310030372FD9
+:105C900032332F3031003030303031353639004337
+:105CA0006F707972696768742028632920323030F8
+:105CB000312033436F6D20436F72706F726174696E
+:105CC0006F6E0A00081000030000000000000000D2
+:105CD000000000008C53FFFF27F07DFD0001000253
+:105CE000DA0E820001406404642D0080E42C008000
+:105CF000693EFFFFC94FFFFFD524FFFFC93BFFFFF0
+:105D0000293CFFFF191AFFFF6511FFFFCC53FFFF6E
+:105D10002140FFFF8970214049722140D93FFFFF98
+:105D2000219A21408524FFFF6453FFFF8C53FFFF1E
+:105D300000000000FFFF0000803000800000000035
+:105D4000FFFF000000002040B05000007B0E00006C
+:105D5000006E21400000000000000000ED8921409D
+:105D60008B892140A58C2140058D2140CD8D21407E
+:105D70008B8B2140A98E2140158F2140698B2140BA
+:105D80000000000000000000000000000000000013
+:105D90000000000000000000000000000000000003
+:105DA0000000000059BD2140C1BD21402DBE214051
+:105DB00000200A4A0B231B02D1182D239B01D31864
+:105DC0008861D860D8638032C86008614861D06259
+:105DD0000348C0464860886070470000680E008035
+:105DE000FE030000F0B584B00C1C051C00230093DA
+:105DF000FFF7DEFF68490B231B02CF1878682840A5
+:105E00000022F8603A61BA6822407A610C1C4109AC
+:105E100003D2510901D2800A02D3604800F0C2F8CF
+:105E20000120F968490903D27969490900D20020A3
+:105E30000006000E03F0D4FAF868002870D00023A2
+:105E400002930193544A01231843F8600020D51DA2
+:105E500079350395012400214F4DFA68224039D04D
+:105E60008A00521892004E4B9B5C1E1C834204D049
+:105E70004B4BD3185B7883422CD1494BD218D37843
+:105E8000039DED6AAB4202D9039DC046EB625368A5
+:105E90005B0801D30123009386420AD19568029BD7
+:105EA0005E1C02969B003C4E9E190B231B02F318AE
+:105EB0009D61537883420DD1D268019B5D1C019591
+:105EC0009B00354D5D192D239B01EB18DA603A6973
+:105ED00001323A61640001310B29BDD30130092838
+:105EE000B8D30020029B99002B4A89180B231B0270
+:105EF000C9188861019B990089182D239B01C91835
+:105F0000C860009B002B0CD1810089180B231B0259
+:105F1000C918CB69C0468B6101300B28F4D308E067
+:105F200007E0039DE86A302803D23020039DC04675
+:105F3000E862194A786900282AD000210123184311
+:105F40007861002001240022134E7B69234010D089
+:105F500093009B189B00124D5B199D78854208D1D8
+:105F60001D690B1C9B009E192D239B01F318DD63FB
+:105F70000131640001320B2AE6D301300928E1D354
+:105F800000208900044A89182D239B01C918C86381
+:105F900004B0F0BC08BC1847680E00803053FFFF07
+:105FA0000001008000470847104718477847C0465F
+:105FB00018C09FE51CFF2FE17847C04610C09FE541
+:105FC0001CFF2FE17847C04608C09FE51CFF2FE16A
+:105FD0003852FFFF8851FFFFD5B02140F0B50420B3
+:105FE0001A49012508601A4FBB231B01F8180573D5
+:105FF0001848416B2C0500207A6E174B8A421DD041
+:10600000197B002917D1D91DFF313A3149781E1C5F
+:10601000002910D1B06010207060104A1049FFF7BD
+:10602000C3FF002807D035730423B8691843B8614B
+:10603000206100F017F8F0BC08BC1847187304235F
+:10604000B8699843B8612061F5E70000000000B02E
+:10605000680E008000011840280500802055FFFFD1
+:106060007D712140F8B5154F396C1548406E0C1AFA
+:10607000144E7168144DA14206D8144A0A43009286
+:10608000B96B0918FA6B11E01122520522430092F4
+:10609000B96B09180020FA6B2B1CFFF78DFF706895
+:1060A000001B0A4A02430092B96BFA6B00202B1CBA
+:1060B000FFF782FFF8BC08BC184700007C2900806D
+:1060C000680E0080280500804480204000003702D0
+:1060D000F0B52B4FB8687968C0192030294AFFF70E
+:1060E00063FF0120C0022849C0460860B968381C17
+:1060F000264D0024264EEF1D7937002931D1316815
+:106100000A78120A03D20473F0BC08BC1847497815
+:1061100000290CD1051C406800F03EF9306800F001
+:1061200067F8002826D12C73FFF758FF22E00901F9
+:10613000071C4160081C174A1749FFF735FF002864
+:1061400007D13C730423A86998439904A8610861A6
+:10615000DAE7102000F020F91020B860FFF782FF86
+:10616000D2E7051C406800F017F9306800F040F8ED
+:106170000028D8D00223F86B1843F863C4E7000066
+:1061800028050080A555FFFF000000B0680E0080C4
+:10619000E40100802055FFFF7D71214090B5012072
+:1061A00040031049002708600F4CE01DFF303A30D3
+:1061B0004770E06980000019006900F0D7F8E069D5
+:1061C000002801D0E76101E00120E06107480223D7
+:1061D000C16B1943C1632773FFF700FF90BC08BC74
+:1061E00018470000000000B028050080E80E00807D
+:1061F00080B584B0071C78886D2803DB381C00F05C
+:10620000F7F817E080000D490958381CFFF7CBFE5E
+:1062100000280FD13978C9090CD36946381C00F021
+:10622000CFF86846002100F00BF8002801D10120CA
+:1062300000E0002004B080BC08BC1847E8010080E2
+:10624000F0B582B0021C414BDD1DFF353A352F7889
+:10625000002F01D0002700E001272F702F78FB00CE
+:10626000DB195B013A4FDC1940780001C71D093783
+:1062700000208300D658C046E65001300428F8D3E9
+:1062800000290FD00022BB08019383420BD9131CB5
+:106290009B00CB588600A351019B01300132834201
+:1062A000F5D800E010272B48026D806E2A49824203
+:1062B00003D8821ACB6C9A1A00E0121ABA4205D897
+:1062C0002648816B01318163012037E0C319CA6C14
+:1062D000934208D8224A3A4300920A1C496C091892
+:1062E000926C231C12E0161A00961B49496C09187F
+:1062F0001948826C0320231CFFF75EFEB81B184A66
+:1063000002430092A3191448826C416C0320FFF7EA
+:1063100053FE01200D49C04668708A6992005218E8
+:1063200017618A69002A02D000278F6100E0886126
+:106330000C480223C16B1943C163002001270A499D
+:10634000C0464F7302B0F0BC08BC18472805008057
+:1063500050BA2040680E00807C290080A082204036
+:1063600000001902E80E0080181A008007498A6EA2
+:106370001018074AD26C13041B0C834200D8801AF1
+:106380008866886E0349C04648617047680E008081
+:106390007C29008090EE204006494A6E1018064A7B
+:1063A000126C824200D8801A4866486E0349C04683
+:1063B00008617047680E00807C29008090EE2040C4
+:1063C00005220A608288C0468A8000224A7040887E
+:1063D000C0464880CA808A60CA6070470522026051
+:1063E0000022828042704180C2808260C260704719
+:1063F00080B584B0071C0E48416B0131416369468A
+:10640000381CFFF7DDFF3868C0460090452000AB20
+:1064100018700127DF8068460021FFF711FF002870
+:1064200001D1381C00E0002004B080BC08BC184733
+:10643000A082204000B584B0C188094AC04691813D
+:106440006946FFF7BDFF0120400201AB5880684656
+:106450000021FFF7F5FE012004B008BC184700003A
+:10646000E80E008000B5FFF7C3FF08BC1847012005
+:106470000349C0460871A121490388600020704784
+:10648000280F008000200449C0460871FF21A12286
+:106490005203013191607047280F00800220A12132
+:1064A000490388600020704701204002A121490370
+:1064B000886000207047C088C006C00EA121490333
+:1064C00048610249C046C86300207047E81A00804E
+:1064D00080B584B008490F6B6946FFF771FFF80675
+:1064E000C00E01AB588068460021FFF7A9FE0120CD
+:1064F00004B080BC08BC18478000144080B585B04B
+:10650000071C6946381CFFF75BFFF88804A903F0F5
+:10651000C9FF01AB588001A8408800280FD001A80E
+:1065200040888008033880080130043B5870049884
+:106530000168C04602914068C046039005E000A88B
+:1065400000784023184300AB18700498C11D013136
+:106550006846FFF775FE012005B080BC08BC1847EF
+:1065600090B584B0144F397B002920D1F91DFF313B
+:106570003A31497800291AD110490522009208229F
+:1065800000AB5A809880062000AB58700024DC8055
+:106590000868C04602904868C046039001203873DE
+:1065A00068460831FFF74CFE002800D03C7304B069
+:1065B00090BC08BC1847000028050080A42A008071
+:1065C00090B584B0071C6946381CFFF7F9FEBA681D
+:1065D0000D4C0E48002A05D10D49FFF7E4FC0028B8
+:1065E0000CDA05E0B9880B4BFFF7DFFC002805DA71
+:1065F00001AB5C8068460021FFF722FE002004B05A
+:1066000090BC08BC18470000FFFF00000D76214039
+:10661000C1BD214059BD214000B5C08803F02EFF07
+:10662000002008BC184700B5FFF7E2FE08BC184779
+:1066300000B5FFF7DDFE08BC184700B5011C0220BD
+:1066400000F002F808BC1847B0B5C6B0071C081C1B
+:106650006946FFF7B5FE2148FFF7A4FC041C204A59
+:106660000021381CFFF7A0FC002827D004A91D4AF0
+:10667000381CFFF799FC04A80023012F06D10CAAAF
+:1066800002320021136001311029FBD30168042973
+:1066900004D9890803398908013100E0191C00ABCD
+:1066A000597006A90978C046D9800068C046029092
+:1066B0000798C0460390043308AD02E0452000ABC4
+:1066C00018700949201CFFF76EFC6846291CFFF76B
+:1066D000B7FD012046B0B0BC08BC18472402FFFF3C
+:1066E00059B121409DAF21403C02FFFF00B5011C84
+:1066F000022000F010F808BC184700B5011C01206A
+:10670000FFF7A2FF08BC184700B5011C012000F0EC
+:1067100002F808BC1847F0B5C7B0041C0F1C381CA1
+:1067200001A9FFF74DFE2148FFF73CFC0090787867
+:106730000001BA680430FC2A25D8FF2309339842A7
+:1067400021D8192C1FD8FD88F868C0460590F91D7E
+:10675000093106AB00207E78002E0DDD40C940C314
+:1067600040C940C340C940C340C940C301300004D0
+:10677000000C7E788642F1DC201C05A92B1CFFF75B
+:1067800021FC002805D001A800784023184301AB64
+:10679000187007490098FFF706FC002101A8FFF7D1
+:1067A0004FFD012047B0F0BC08BC18472402FFFF92
+:1067B0003C02FFFF00B5FFF71BFE08BC1847F0B511
+:1067C000C6B0071CFC88254D6868013069466860C2
+:1067D000381CFFF7F5FD102C08D300A800784023E3
+:1067E000184300AB18700220D88017E07878820038
+:1067F000FB1D09330020B968002A15D940CB0F1CB6
+:106800000131BE420DD000AA127840231A4300ABDA
+:106810001A700422DA800290039104336846002142
+:1068200015E001309042E9D300AB5C7002946968D6
+:10683000C0460391A20000201033002A05D90F1C86
+:1068400080C3013001319042F9D3684604A9FFF7B3
+:10685000F7FC012046B0F0BC08BC18479C03008040
+:1068600090B4234800680121420900D30021002789
+:106870003A1C430B00D2022211431E4A2024D36843
+:10688000012B2ED1800A00D200240C43201C1B2394
+:10689000DB01D118898B090B00D204273843D16F53
+:1068A0000968090A07D2D11D793109680968090AFE
+:1068B00001D308231843E3231B01D1188979032945
+:1068C00002D1FF23013318430B49096A10224B0AF6
+:1068D00000D2002210438907890F8901084390BC28
+:1068E0007047400C00D200240C43201CECE7000051
+:1068F00000001040680E0080C0001840F0B53A4C0F
+:10690000201C04F007FA3948E3231B01C718B979A2
+:10691000374EC51D7935062962D202A35B5C5B0048
+:106920009F44001C030E1E374E550120B8710020F5
+:10693000B060FFF795FF0523984300F06FF80CE077
+:10694000FFF78EFFC00806D3B068411CB1600A286B
+:1069500003D9042000E00220B8716422201C2BE03F
+:10696000061CC06F80230168194301600320B871C1
+:10697000201C204A002104F099F9F06F04230168DB
+:10698000994301602868016819430160F0BC08BCA4
+:1069900018470521B971296804230A689A430A60D7
+:1069A000C06F016819430160FFF75AFF08231843BD
+:1069B00000F034F8201C104A002104F077F9E5E7D4
+:1069C000FFF74EFF0423184300F028F8DEE700200D
+:1069D000296860230A689A430A60FFF7E3FAD5E75B
+:1069E0000620B871D2E70000A9792140680E008026
+:1069F0009C030080307500001027000000B50020C7
+:106A00000449C046887104480122002104F04EF96F
+:106A100008BC1847981C0080A979214090B5071C34
+:106A200031480068790803D31023011C994301E021
+:106A3000102101432D4CE268012A05D12279002A58
+:106A400002D001239B021943814202D0012000059C
+:106A50000160E068012820D11B23DB01E018808B56
+:106A6000F90804D30123DB02011C994301E0012151
+:106A7000C902814202D0002002F01AFB380907D374
+:106A8000E06F8023016899430160E018006800E02E
+:106A9000E06F80230168194301601548016A780995
+:106AA00003D3FF200130084303E0FF23081C013318
+:106AB000984380088000BA099207920F10438842D9
+:106AC00002D00C49C0460862E168012908D1790A60
+:106AD00006D3FF2304331840032801D1FFF78EFFAC
+:106AE00090BC08BC1847000000001040680E0080F1
+:106AF000C0001840C000180080B5FFF7B1FE800943
+:106B00001BD20F48E3231B01C1184A79002A14D174
+:106B100001224A7100278030006860230168994390
+:106B20000160084806E0022002F08CFC072002F019
+:106B30005BFC381CFFF736FAF5E780BC08BC184749
+:106B4000680E0080F401FFFF00B584B06946FFF7CE
+:106B500037FCFFF785FE01AB588008480068C04647
+:106B600002900748006AC046039068460021FFF77C
+:106B700067FB012004B008BC18470000000010406B
+:106B8000C000184080B584B0071C6946381CFFF768
+:106B900017FCF888FFF742FFFFF762FE01AB588051
+:106BA00068460021FFF74CFB012004B080BC08BC04
+:106BB0001847B0B5C6B0C7886946FFF701FC012485
+:106BC0001A4B9F420AD900A800784023184300AB13
+:106BD00018700220D8806846002120E01448FFF792
+:106BE000E1F9051C134A381C04A9FFF7DDF9124925
+:106BF000281CFFF7D8F9012F06D10CA9002000228C
+:106C00000A6001301028FBD3102000AB58700498A4
+:106C1000C04602900598C0460390684606A9FFF753
+:106C20000FFB201C46B0B0BC08BC1847FF01000099
+:106C30002402FFFF9DAF21403C02FFFFF0B5C6B02C
+:106C4000071C6946381CFFF7BBFBFC8878780125D8
+:106C5000102801D1192C09D900A800784023184325
+:106C600000AB18700220D880043327E0B868C04613
+:106C70000490F868C046059006AAFB1D0933002160
+:106C8000787800280DDD002040CB40C201300004A0
+:106C9000000C0428F8DB481C0104090C78788842B1
+:106CA000F1DC0B48FFF77EF9071C0A4A201C04A9F7
+:106CB000FFF77AF90849381CFFF775F96846002193
+:106CC000FFF7BEFA281C46B0F0BC08BC184700000D
+:106CD0002402FFFFC5AF21403C02FFFFF0B584B0A6
+:106CE000041C0027E688A26847490879002808D0D4
+:106CF000002E01D0012E01D1012701E0042E00D188
+:106D0000032601254148052E66D202A39B5D5B0048
+:106D10009F44001C0306080C10000580002303E0BC
+:106D2000058005E000230380438006E00023038004
+:106D3000458002E0FF2301330380CB1D79339E8918
+:106D400001235B029E4202DBD207D20F00E0012248
+:106D50006D235B01C9188988FF23E133994301231F
+:106D600019430688FF339E420DD1FF20E1300843CE
+:106D7000002A04D101239B029843011C20E0012139
+:106D8000890201431CE0012E0AD14088012804D168
+:106D900060231943002A13D00CE0202319430FE08D
+:106DA000002E0DD14088012808D1FF2381331943DB
+:106DB000002A05D001239B02194301E080231943D7
+:106DC000042002F075F909214902002002F070F94F
+:106DD000002F02D1002012E0FFE76946201CFFF7D8
+:106DE000EFFA00A800784023184300AB1870022087
+:106DF000D880684600210433FFF722FA281C04B02B
+:106E0000F0BC08BC18470000680E0080881C008099
+:106E1000C0885121890308620020704780B5164F51
+:106E2000F868012807D137239B01F818408A802190
+:106E300001431B2007E06D235B01F818808B0121C3
+:106E400049030143102002F033F9012071235B0153
+:106E5000F918088048801B23DB01F818808B012378
+:106E60001B039843412109020143002002F020F94D
+:106E7000002080BC08BC1847680E008080B5174F02
+:106E8000F868012808D137239B01F818408A80232D
+:106E90009843011C1B2008E06D235B01F818808BD0
+:106EA00001235B039843011C102002F001F9FF202D
+:106EB00071235B01F918013008801B23DB01F818EE
+:106EC000808B41231B029843092149020143002082
+:106ED00002F0EEF8002080BC08BC1847680E008065
+:106EE00080B584B00849CF6A6946FFF769FAB805EA
+:106EF000800D01AB588068460021FFF7A1F9012001
+:106F000004B080BC08BC184740001440C0889F23D0
+:106F100018400549C96A1B235B011940084303490E
+:106F2000C046C86200207047400014404000140072
+:106F300080B584B00D490F6A012F01D1FF0307E02E
+:106F4000022F01D13F0303E0002F01D10127FF02EF
+:106F50006946FFF735FA01AB5F8068460021FFF70D
+:106F60006FF9012004B080BC08BC18470020144011
+:106F7000C288A1204003002101235B039A4201D172
+:106F8000022204E00123DB039A4202D101220262C1
+:106F900000E00162081C704790B584B0071C02F045
+:106FA0009FF86946041C381CFFF70AFA01AB5C80A5
+:106FB000094FF86DC046029068460021FFF740F97E
+:106FC000F86DC007C00F0549C046C862012004B073
+:106FD00090BC08BC18470000A42A0080681C0080F0
+:106FE000C0880249C04648610020704780001400F4
+:106FF00000B584B06946FFF7E3F90648C06801AB05
+:10700000588068460021FFF71BF9012004B008BC36
+:107010001847000080001440C0880249C046C8607C
+:10702000002070478000140080B584B069468768EE
+:10703000FFF7C6F9202F07D278000C4940181B2310
+:10704000DB01C018808B06E000A8007840231843BD
+:1070500000AB1870022001AB588068460021FFF792
+:10706000EFF8012004B080BC08BC1847680E00800F
+:1070700000B584B0C1888268202A04D2101C02F0B6
+:1070800017F8002010E06946FFF79AF900A8007889
+:107090004023184300AB18700220D88068460021B6
+:1070A0000433FFF7CDF8012004B008BC184790B5B1
+:1070B00084B0C7886946FFF783F91048FEF772FF6E
+:1070C0000220391C02F0F2FF002806D00220391CF1
+:1070D00002F036FF01AB588002E0452000AB18708B
+:1070E0000749201CFEF75FFF68460021FFF7A8F85C
+:1070F000012004B090BC08BC184700002402FFFF28
+:107100003C02FFFFB0B584B0C78869468468FFF7CA
+:1071100057F91048FEF746FF0F4A0220391CFEF7C8
+:1071200043FF002806D00D4B0220391C221CFEF71D
+:107130003CFF02E0452000AB18700949281CFEF70F
+:1071400032FF68460021FFF77BF8012004B0B0BC95
+:1071500008BC18472402FFFF59B1214059B0214013
+:107160003C02FFFF00B5FFF743F908BC18470020B9
+:10717000704780B4C288194BA1214903002A03D16A
+:10718000186B1023984304E0012A04D1186B1023D4
+:10719000184348611FE0022A1DD1C2688768002099
+:1071A0003B1CC340DB07DB0F9B0203430B61013039
+:1071B0000004000C2028F3DB0020131CC340DB0775
+:1071C000DB0F9B02C71D19373B430B6101300004E5
+:1071D000000C2028F1DB002080BC704780001440A8
+:1071E00080B4C28881681002120A10430204120C93
+:1071F0000C48C04602600C4BC0461A800A0C1702AD
+:1072000012123A431204120C42605A800904090C0B
+:107210000A02090A11430904090C816099800020BF
+:1072200080BC704740001400281B0080B0B584B0BB
+:1072300013490A681204120C1302121213434A680B
+:107240001204120C1F1C1302121213438968090442
+:10725000090C0A02091211430C04240C69461D1C76
+:10726000FFF7AEF801AB5F80280420430290684628
+:107270000021FEF7E5FF012004B0B0BC08BC1847B0
+:1072800040001440C18882680802090A08430004CB
+:10729000000C0A49C046C860100C030200121843D3
+:1072A0000004000C08611004000C0202000A1043E4
+:1072B0000004000C486100207047000040001400EA
+:1072C00090B584B0164BD9680904090C0A0209125A
+:1072D00011431A691204120C170212123A435B6925
+:1072E0001B041B0C1F021B123B431F043F0C0523F6
+:1072F0000093848801AB1C800024043B5C704088B0
+:1073000000AB5880D980100438430290039468463B
+:107310000021FEF795FF012004B090BC08BC18477F
+:107320004000144000B584B00B498A6A05210091E1
+:10733000818801AB19800021043B5970408800AB63
+:107340005880DA80029103916846FEF779FF0120A8
+:1073500004B008BC18470000C0001440C0880249AF
+:10736000C046886200207047C000140000B584B099
+:107370000B490A6A05210091818801AB198000211F
+:10738000043B5970408800AB5880DA800291039129
+:107390006846FEF755FF012004B008BC18470000FE
+:1073A000C0001440C0880249C046086200207047EF
+:1073B000C000140000B5C0880249FEF7F4FD0020AB
+:1073C00008BC18477502FFFF00B584B06946FEF798
+:1073D000F7FF0648006B01AB588068460021FEF7B6
+:1073E0002FFF012004B008BC18470000680E008081
+:1073F00000B5FEF7FDFF08BC184700B5FEF7F8FF23
+:1074000008BC184700B5FEF7F3FF08BC184780B565
+:10741000071C1048FEF7C6FD01204002A1214903C8
+:10742000886000210C48C04601710C480268520C6B
+:1074300005D20268120C06D10068800A03D30848FE
+:10744000C046C76002E00748C0460764081C80BC0D
+:1074500008BC1847D5942140280F00800000104038
+:10746000400118000000008000B501200349C0461B
+:1074700008721220FFF7CBFF08BC1847881C008059
+:1074800000B501200349C04648721520FFF7BFFF31
+:1074900008BC1847881C008000B501F0F9FF0120E6
+:1074A00008BC184780B584B0071CF88802F0FEF8C5
+:1074B00000280CD16946381CFEF782FF064801AB54
+:1074C000588068460021FEF7BBFE012000E0002046
+:1074D00004B080BC08BC1847FFFF000080B584B032
+:1074E0006946FEF76DFF012701AB5F80094881897E
+:1074F0000904C2891143029181880904C0880843A4
+:10750000039068460021FEF79BFE381C04B080BC47
+:1075100008BC18474C2A008000B5FEF769FF08BC7C
+:10752000184700B5FEF764FF08BC184700B5FEF722
+:107530005FFF08BC184700B5FEF75AFF08BC1847A4
+:1075400000B5FEF755FF08BC184700B5FEF750FF21
+:1075500008BC184700B5FEF74BFF08BC184700B53C
+:10756000FEF746FF08BC184700B5FEF741FF08BC10
+:10757000184700B5FEF73CFF08BC184700B5FEF7FA
+:1075800037FF08BC184700B5FEF732FF08BC1847A4
+:1075900000B58CB008A9FEF713FF694608A802F0F1
+:1075A000A9FF022008AB5870694608A8FEF748FEFC
+:1075B00001200CB008BC184700B5FEF719FF08BC45
+:1075C000184790B584B0071C6946381CFEF7F8FED2
+:1075D000FA8812490124C81D8930002A0FD004708E
+:1075E0004470B868000C8031C882B868C04608830F
+:1075F000F868000C4883F868C046888302E00021E0
+:1076000001704170064801AB588068460021FEF7C2
+:1076100017FE201C04B090BC08BC1847680E008000
+:10762000FFFF000000B5FEF7E3FE08BC184700B5F9
+:10763000FEF7DEFE08BC184700B5FEF7D9FE08BC11
+:10764000184700B5FEF7D4FE08BC184700B5FEF792
+:10765000CFFE08BC184790B584B0071C6946381C9B
+:10766000FEF7AEFEF8880324E40404430323DB049E
+:107670009C4202D30F4B9C4206D90F4801AB588065
+:1076800068460021FEF7DCFD0120800720430068EA
+:10769000002100AB5970FA88C046DA80029003914D
+:1076A00068460433FEF7CCFD012004B090BC08BC52
+:1076B00018470000E0001800FFFF000080B584B00C
+:1076C000071C6946381CFEF77BFEF8880323DB04A1
+:1076D0001843984202D30A4B984208D9094801AB93
+:1076E000588068460021FEF7ABFD012003E0B96831
+:1076F000C0460160002004B080BC08BC18470000F0
+:10770000E0001800FFFF000080B586B002A9FEF778
+:1077100057FE012702AB5F700020D8800A484168FD
+:10772000C04604918168C0460591C168C046009179
+:107730004069C0460190694602A8FEF781FD381CE9
+:1077400006B080BC08BC18476819008000B5C16845
+:107750008068FEF747FB002008BC184700207047F0
+:1077600090B584B0041C0F1C68465021FEF736FE0D
+:1077700001AB5C80029768460021FEF761FD04B012
+:1077800090BC08BC184780B584B0071C68465121DE
+:10779000FEF724FE01AB5F8068460021FEF750FD36
+:1077A00004B080BC08BC1847002070470020704718
+:1077B00090B584B0002712490968124A126B102351
+:1077C0001A400124002A00D001278A0C03D33A046E
+:1077D000120C02271743C90C03D33904090C0427E0
+:1077E0000F436946FEF7ECFD01AB5F806846002160
+:1077F000FEF726FD201C04B090BC08BC1847000012
+:1078000000001040C000184000B584B06946FEF783
+:10781000D7FD0648C06D01AB588068460021FEF7D1
+:107820000FFD012004B008BC18470000A42A008006
+:1078300000B5FEF7DDFD08BC184770470020704713
+:1078400000207047002070470020704700207047DC
+:107850000020704700B5FEF7CBFD08BC18470000BC
+:1078600080B585B001A9FEF7ABFD002001AB5870D3
+:107870000C49C9680127012902D10397049701E047
+:1078800003970490684601F033FD02AB0098C046B0
+:107890005880002101A8FEF7D3FC381C05B080BC3D
+:1078A00008BC1847680E0080704704490020002279
+:1078B0000A70013001316828FAD37047A082204055
+:1078C0000022884203D3401A01328842FBD2101CA6
+:1078D0007047884202D3401A8842FCD2704790B465
+:1078E000011CFF27042927DA0020144A43001B1833
+:1078F000DB00D458630C1AD24B005918C9005758F2
+:1079000043001B18DB00D75089189A184F68C046EF
+:1079100057608B68C04693600B69C04613614B6922
+:10792000C0465361C968C046D16090BC7047013001
+:107930000006000E0428D9DB381CF6E740AB2040D7
+:10794000F7B5C4B0041C0020469A112111406ED036
+:1079500000277900C919C900574A5158490C03D268
+:1079600001300006000E04E0791C0F063F0E042FC4
+:10797000EFDB00285BD0002600220092402300218C
+:10798000002002AA00F088FA04A9002082008A5888
+:107990001206120EA24203D1721C1606360E04E025
+:1079A00001300006000E1028F0DB002E3DD0042C24
+:1079B0003ED1800008584001800D00220092102323
+:1079C000002102AA00F068FA0021019102A805999D
+:1079D000490C890529D0C1680A06120E459B9A42B6
+:1079E00011D1C0684001860D002200920C230021B5
+:1079F000301C02AA00F050FA0199029D481C0106B1
+:107A0000090E01910EE04801860D0022009210231C
+:107A10000021301C02AA00F03FFA02A80599490C87
+:107A20008905D8D1019900290FD1FF203DE040E020
+:107A3000800008584001860D002200920C2300218E
+:107A4000301C02AA00F028FA029D01200004469A88
+:107A500010437900C919C900174AC0465050301C5C
+:107A60008E1870601020042C00D00C20041CB06014
+:107A700000202021469A1140202900D0281C306186
+:107A80002819FF21FF3008300931FFF719FF4301A2
+:107A90001818C000001B706100205021469A114048
+:107AA000502900D1281CF060381C47B0F0BC08BC3D
+:107AB0001847FF20F9E7000040AB204080B40023C6
+:107AC0000022002906D9875C7B401B061B0E013271
+:107AD0008A42F8D3D8430006000E80BC7047F0B548
+:107AE000C6B0042807DA41000918C9004591414A87
+:107AF00051584B0C02D20020C04376E001235B04B6
+:107B0000194043001818C0003A4A1418002961D0DF
+:107B1000002102912069A168451830D0FF21681E1C
+:107B20000931FFF7CDFE616840180190019881424C
+:107B300002D1A668AF1B09E00026FF21281C0931ED
+:107B4000FFF7C7FE071C01D1FF270937002200926B
+:107B50000198311C03AA3B1C00F09EF903A8391CB4
+:107B6000FFF7ACFFC043029948400106090E02919D
+:107B7000ED1BA068A84200D10025002DCED80299A7
+:107B8000CF43002200920C230021606803AA00F07A
+:107B900083F92069C04603900598000A000239065F
+:107BA000090E08430590FF231B02984305900C2102
+:107BB00003A8FFF783FFFF231B02059999430006E3
+:107BC000000E0002084305900C230021606803AA00
+:107BD00000F0CAF900204599064AC0465050C143FA
+:107BE0006160A160E1602161616146B0F0BC08BCE8
+:107BF0001847000040AB2040B0B44C42002900DBE5
+:107C00000C1C0027FF43042821DA124D43001818EA
+:107C1000C0004019012A05D0022A09D0032A16D132
+:107C200001690BE0002912DB02698A420FD305E0EB
+:107C3000002907DAC168A14209D3091BC160C068E5
+:107C4000B0BC7047C168091902699142F6D9381C65
+:107C5000F6E7000040AB2040F0B584B0171C0D1CC7
+:107C60000021029142001218D2002C498B581B06A9
+:107C70001B0E01930023DB43042802DA019840081D
+:107C800001D2181C46E05418E068C21921698A42E2
+:107C900000D90F1A002F3CD9A068E1684018FF21D5
+:107CA0000931FFF70DFE61684618A068E1684018C9
+:107CB000FF210931FFF70DFEC219FF2109318A4268
+:107CC00014D9019AC04600920B1A0393011C301C70
+:107CD0002A1C00F0E1F8E068039BC018E060039BF9
+:107CE0005D19FF1A02981818029010E0019AC04618
+:107CF0000092011C301C2A1C3B1C00F0CDF8E068EF
+:107D0000C019ED19E0600298C01902900027002FF9
+:107D1000C2D8029804B0F0BC08BC184740AB204061
+:107D2000F0B583B0171C0D1C002101914200121800
+:107D3000D200029230498A581206120E0024E443FF
+:107D4000042801DA500901D2201C51E0029A54188B
+:107D5000E068C2196069824201D92269871A002F3E
+:107D600045D9254EA068E1684018FF210931FFF789
+:107D7000A7FD616840180090A068E1684018FF21E5
+:107D80000931FFF7A6FD029AB15801235B0419439C
+:107D9000B150C119FF220932914213D9131A011CA3
+:107DA00000982A1C1E1C00F0DFF8E0688019751985
+:107DB000E0602169884200D92061BF1B019830181A
+:107DC000019012E0011C009E301C2A1C3B1C00F09C
+:107DD000CBF8E068C019ED19E0602169884200D94C
+:107DE00020610198C01901900027002FB9D801988F
+:107DF00003B0F0BC08BC184740AB2040B0B5C3B0DE
+:107E00000C1C0027FA43042806DA41000918C900AF
+:107E1000144845586B0C04D2101C43B0B0BC08BCCD
+:107E2000184762091BD300220092081840680C23EF
+:107E3000002101AA00F030F8112C0DD0122C0DD029
+:107E4000132C05D0142C0AD103980004070E06E069
+:107E5000039807063F0E02E0019F00E0029F381CD6
+:107E6000DBE7000040AB20400349002000220A5419
+:107E700001306028FBD3704740AB204000B502F0D2
+:107E80006FFA572002F0CCF902F040F9000AFBD358
+:107E900002F04EFA08BC1847F0B582B0079D141CDA
+:107EA0001F1C304AD26F202316689E431660331C75
+:107EB000FF2201322A4040020843050A061C000C3A
+:107EC0000190002A20D002F04BFA532002F0A8F9CA
+:107ED0000198C046009002F0A3F9281C02F0A0F916
+:107EE000301C02F09DF902F023FAFFF7C7FF02F001
+:107EF00037FA542002F094F9009802F091F9281C06
+:107F000002F08EF9301C14E002F02AFA522002F03E
+:107F100087F9019802F084F9281C02F081F9301CDD
+:107F200002F07EF9002002F07BF9002002F078F9DF
+:107F3000002002F075F9002002F072F9002F05D937
+:107F400002F0E4F820700134013FF9D102F0F0F9B9
+:107F5000044AD06F202301681943016002B0F0BCCD
+:107F600008BC1847680E0080F0B582B0141C1F1CB6
+:107F700042020A43151C012854D02C49C86F202303
+:107F800002689A430260C86F402301681943016088
+:107F900002F0E6F9532002F043F9280C061C02F027
+:107FA0003FF9280A0190009002F03AF9281C02F0EB
+:107FB00037F902F0BDF9FFF761FF02F0D1F9842033
+:107FC00002F02EF9301C02F02BF9009802F028F98B
+:107FD000281C02F025F9002F05D92078013402F081
+:107FE0001FF9013FF9D102F0A3F902F0B9F983209A
+:107FF00002F016F9301C02F013F9019802F010F9A2
+:10800000281C02F00DF902F093F9FFF737FF07493A
+:10801000C86F402302689A430260C86F202301683A
+:108020001943016002B0F0BC08BC1847680E00801C
+:108030007047000080B501F08FF8064FC046F86029
+:1080400001F0F2F8788001F0B1F8387180BC08BC1A
+:1080500018470000680E008000B501F005F90249DC
+:10806000C046088008BC1847680E00800B48C168ED
+:10807000012911D1C16F02230A681A430A60C16F36
+:1080800080230A681A430A60C118086882230268BC
+:108090001A4302600020088170470000680E0080CB
+:1080A000F0B44A49CA1D9D32002000278300D750F2
+:1080B00001301728FAD3464C00208200A750013027
+:1080C0002028FAD3434A00208300D75001302028CB
+:1080D000FAD3A76197614F658F653F4DC0462F600A
+:1080E0006F60AF60AF61EF602F616F610020C10012
+:1080F00009184901354BC9188600CB1DF933344C9A
+:108100003419E36311235B01CB1863630D239B01D7
+:10811000CB18B418E36323235B01C91861630130F2
+:108120000228E4DB2948C11DF931294CC046A1626F
+:10813000616B0D239B01E162C1189162516BC046D6
+:10814000D1620821E1642549C046216524490B69B3
+:10815000C0466365C31D4D33E36525668B68C04625
+:108160006366CB68C046A3661E4BC046E3662767BE
+:108170000B23DB01C318A36767670126E31D69337F
+:108180006661E7611F730223D364174BC046136512
+:10819000CB69C0465365C31D5133D3652B1D136690
+:1081A0004B69C04653668969C04691660F49C0460F
+:1081B000D16616670F23DB01C01890675667D76139
+:1081C000D01D693056610773F0BC7047680E00809F
+:1081D000E42C0080642D008090EE204030011800D7
+:1081E0007C2900800055FFFF380118001055FFFF63
+:1081F00090B400211E4ABB231B01D718F973192321
+:10820000DB01D0180124CD231B01D318C1611C70E0
+:1082100033239B01D3189960B97359612F239B01B4
+:10822000D3181960134B5127BF0303633B60846964
+:10823000E4184463043C7C600124E40284630E4C33
+:10824000C046BC60046BC04644628469E4180B4BB2
+:10825000E318FB60036BC0468362436AC046036257
+:10826000C16351649164D165D16690BC70470000D0
+:10827000680E008000002040FC070000FCF7FFFFB4
+:1082800090B400221B49C9231B01C81802710120A8
+:10829000BB231B01CB1858731748031C0027DC1D98
+:1082A000C1341C65231C01373F2FF8D31A651923ED
+:1082B000DB01CF1833239B01CB183A619861402032
+:1082C000F860DA611A62CA640A660C48C046C26085
+:1082D0000B48006BC006C00EF8630A480168C04630
+:1082E00019804168C04659808068C046988090BC1B
+:1082F00070470000680E008090BC204090EE204047
+:10830000800014404000144000200A49C046087311
+:10831000CB1DFF333A338861C8611870064AC046E6
+:1083200010655066906608705870BB231B01D11809
+:108330000873704728050080680E0080F0B42F494C
+:108340002F4AC046116101239B02C81850612D4875
+:10835000C0461062DB00C3185362002313635363EB
+:10836000294A2A4FD41DFF34FA3414C7083F3B6111
+:108370001C1F7C61264FC0463960B8617961F86284
+:108380003B637B64BA64FA65224FFE1DF936224DC9
+:10839000EC1D793426625126B6033761246AC04643
+:1083A00074612F671D4D09277F04EC1D75347C60B7
+:1083B0003D601B4CC0463C61E61D75367E61194F21
+:1083C000C0467C603D600F1C0021FF2401341D1C51
+:1083D0008B00FD500131A142FAD3011C002001277E
+:1083E000FF028300CD500130B842FAD30020810053
+:1083F000555001308028FAD3F0BC704724A32040A8
+:10840000400118002483204024A920408001180046
+:10841000A803008024A72040680E008024A82040E4
+:10842000A4A8204008040080B8B52C48FDF7BAFD88
+:1084300001202B490A68520C06D20A68120C02D19C
+:108440000A68920A00D200200406240E254AD71D8D
+:108450000D37002300209D0078510133042BFAD3FF
+:1084600001273F055061F860D061F8610023DB43CC
+:1084700093613B6113623B6200271B4B8D68C046D2
+:1084800000958D69C0460095002C0BD0DD6BC04671
+:1084900000959D6BC04600955D6BC04600951D6BB9
+:1084A000C04600950137402FE8D300276C460123D2
+:1084B0005B071C4301E0206001370D682B0902D2E5
+:1084C000802FF8D301E0802F03D308494B6E01338E
+:1084D0004B66D062B8BC08BC18470000F401FFFF2F
+:1084E00000001040680E008000011840A08220406B
+:1084F00090B400210E4F0F4A00204C01641AA400D2
+:10850000A318586098601864586410535880CC00C1
+:10851000E4199867DC6201310329EED30649C046AD
+:10852000086048608860C860086190BC70470000BF
+:10853000AC6621405C2B0080D02C00806421054873
+:10854000C04601630021C943416381630021C163C7
+:1085500001647047680E008080B4012040020A491F
+:10856000C04608603C20486088600848C046C86033
+:108570000020074A8700CB68C046DA510130102836
+:10858000F8D380BC70470000E42D0080F42D0080FB
+:108590005D4CFFFF1249134867239B01CA1806C0B0
+:1085A0000838114BCA18C160826001610F49104838
+:1085B000A7239B01CA1806C008380E4BCA18C16011
+:1085C000826001610C480D4967239B01C21805C1F7
+:1085D0000839054BC218C8608A60086170470000FE
+:1085E000AC1E2140482E0080FC1F0000ACEE204055
+:1085F000342E0080FC2F0000AC3E21405C2E008019
+:1086000090B40021404C00200A0112191923DB010B
+:10861000D218D06210635063906301310329F3D301
+:108620003A49C04608634863886320600121E31D1E
+:108630005933606019711872987198725971587233
+:10864000D871D872E21D4932117319709073987005
+:1086500051735970D073D8701171117290719072FA
+:1086600050715072D071D07218730222E71D6937B1
+:108670003A709973BA7058737870D873F87039710A
+:108680003A72B971B97278717A72F971F972397393
+:10869000E31D79331A70B973997078735A70F9734E
+:1086A000D9701A711A7299719A7258715A72D97175
+:1086B000DA721973E71D89373A709973B970587374
+:1086C0007A70D973F97039713A72B971B972787177
+:1086D0007A72F971F9723A73E31D99331A70B973AA
+:1086E0009A7078735A70F973DA7019711A729971F5
+:1086F000997258715A72D971D9722061E0606061C3
+:10870000A06090BC70470000A01C0080E8190080A9
+:10871000812000020149C04688627047C0001400F1
+:1087200009490A4BC818043BC91808600021C21D3A
+:108730002932C261101C01310829F8D3C11F29391F
+:108740000020C86170470000680E008084090000A6
+:1087500006480749C0460880488000208880C880B5
+:1087600088600449C046486188617047FFFF000087
+:108770004C2A00806C06008000210648C21D193278
+:10878000C1600161C16101621171FF30013041625C
+:10879000704700006C06008009480A4BC04618600C
+:1087A0000021C21D4D32C260101C01311429F8D3C2
+:1087B000C11F4D390020C8605860986070470000A4
+:1087C000D80700806C06008000B50B490B48FDF708
+:1087D000EAFB0B48006A0123DB0398430949C046C2
+:1087E00008620948C168012904D1C06F802301686B
+:1087F0001943016008BC1847C1BD2140759821404C
+:10880000C0001840C0001800680E008000B50F4876
+:10881000C168012904D1C06F8023016899430160B8
+:108820000B4B0C480C4A0021FDF7BFFB0B48418D58
+:10883000013141850021C1850948006A0123DB031C
+:1088400018430849C046086208BC1847680E0080F3
+:1088500059BD214075982140B80B000000000080F0
+:10886000C0001840C0001800F0B51B4C1026E0688E
+:10887000012808D16088002805D12079002802D17C
+:108880001920A06700E0A667002007235B02E51817
+:10889000C143E86169625908A1277F0379600F210C
+:1088A0007960E11DB93108710120B8604002B860FB
+:1088B00000F04CFA00F0F0FA0420B860072078616C
+:1088C0007E601B23DB01E018C08B04231840E862A4
+:1088D000F0BC08BC18470000680E008090B4021C71
+:1088E0000020FF2301339A4208D0012900D1012042
+:1088F000002A01D10223184390BC70471B4AD76855
+:108900001A4B19791C1C37239B01E318012F0DD139
+:108910005788002F0AD100290AD1598B0A0900D3A0
+:1089200002204909E8D301231843E5E7002903D0D1
+:10893000988A8007800FDFE76D235B01D1188A8852
+:10894000FF27013717400A49C98803D04B0A01D3D2
+:108950000320D1E7130A03D30B0A01D30220CBE78C
+:10896000D209C9D3C909C7D30120C5E7680E008061
+:10897000081C0080F0B5C1B0012000075249C04674
+:10898000086052484269400DA1214903486050489F
+:10899000C06A504B1843002103031B0B4E4C276F3A
+:1089A0003D032D0BE71D7937AB421CD0E31D793316
+:1089B0001B6AC046409301239B0703431B68CC00FE
+:1089C0006E46335101239B07061D33431B686C44DD
+:1089D000636008300131409B834200D83F48030365
+:1089E0001B0BAB42E7D1002001231B0313403C4C7F
+:1089F00003D0636A0133636209E0130B03D3236A74
+:108A00000133236203E0374B5C6D01345C65002960
+:108A100009D0031CDC00231C6B445C680130230D6F
+:108A200001D28842F5D1304C25686B0C05D2236801
+:108A30001B0C08D12468A30A05D320242B4BC04665
+:108A40005C6200245C62254B234C5126B6032367ED
+:108A500033613D6AC04675610225A12676037560C3
+:108A60000125B560E61DB9363571884221D0251C37
+:108A7000C3006C46E4582E6F6B4434605B682C6F07
+:108A8000C04663602B6F08332B673C6AA34202D356
+:108A9000124BC0462B67031CDB006B445C68013043
+:108AA000230D04D35124A4032B6FC046A361884235
+:108AB000DED1100B03D30E490120FDF774FA41B04B
+:108AC000F0BC08BC18470000000000B000011440D2
+:108AD0000040144000002040680E008024A7204081
+:108AE000A42A0080A082204000001040C00018008E
+:108AF000C94FFFFFF0B40021002307220624474F8F
+:108B0000C0463C613A610133202BF9D304253D6115
+:108B100005233B613C613A613C613A613D613B61E7
+:108B20003F4DAB6FDE0802231E40042333433B61FD
+:108B3000052333433B61AB6F9E0802231E40042391
+:108B400033433B61052333433B61AB6F5E08022334
+:108B50001E40042333433B61052333433B6102231F
+:108B6000AE6F1E40042333433B61052333433B6117
+:108B7000AB6F5D0002231D4004232B433B610523A3
+:108B80002B433B61C50802231D4004232B433B615B
+:108B900005232B433B61850802231D4004232B43FF
+:108BA0003B6105232B433B61450802231D40042301
+:108BB0002B433B6105232B433B61022505400423E6
+:108BC0002B433B6105232B433B61400002231840AC
+:108BD000042303433B6105231843386100253D61AD
+:108BE00001233B613D613B6100203D610D4B1B69F1
+:108BF00049001E1C02233340194301233B6101300D
+:108C00001028F2D302203861032038613C613A61B8
+:108C10003C613A6138614808F0BC7047800014003C
+:108C2000680E008080001440F0B40024072306275B
+:108C3000444AC046176113610134202CF9D304263D
+:108C4000166105241461176107231361166114610D
+:108C5000176113613C4B9B6FDD0802231D402B1CE9
+:108C60003343136125431561374B9B6F9D080223E6
+:108C70001D402B1C3343136125431561324B9B6F01
+:108C80005D0802231D402B1C3343136125431561EE
+:108C90002D4B9D6F02231D402B1C33431361254335
+:108CA0001561294B9B6F5D0002231D402B1C334334
+:108CB000136125431561C50802231D402B1C334356
+:108CC000136125431561850802231D402B1C334386
+:108CD000136125431561450802231D402B1C3343B6
+:108CE000136125431561022505402B1C3343136195
+:108CF00025431561400002231840031C33431361D0
+:108D000020431061176107231361166114614C0041
+:108D100000200F21251CCD4002231D4004232B439E
+:108D2000136105232B431361013001391028F1D35E
+:108D30001761072313611761136103201061F0BCF1
+:108D40007047000080001400680E0080F0B54F4DA1
+:108D5000082102202A1CFDF727F94D4C71235B01E5
+:108D6000E71838801A2102202A1CFDF71DF97880A7
+:108D7000207900280BD000203880E068012810D12D
+:108D80004448006801239B02184399020860E06888
+:108D9000012806D16088002803D1F9211220FFF7AD
+:108DA00043FF0121C9030020FFF73EFF00257D2678
+:108DB000F60000E001350020FFF79CFE000C01D317
+:108DC000B542F7D3002505E0032109030020FFF792
+:108DD0002BFF01350020FFF78DFE400B01D2B5427D
+:108DE000F2D30420FFF786FEFF23E13398430121ED
+:108DF00001433888FF230133984203D12F235B01BD
+:108E0000194316E0012809D17888012803D12323CA
+:108E10005B0119430DE0202319430AE0002808D123
+:108E20007888012803D10B23DB01194301E080235B
+:108E300019430420FFF7F8FE092149020020FFF73B
+:108E4000F3FEE06800280CD100211B20FFF7ECFEA8
+:108E50001A20FFF74FFE0121C90301431A20FFF733
+:108E6000E3FE002703E0082F01D30F2F08D9381C99
+:108E7000FFF740FE790009191B23DB01C91888831D
+:108E80000137202FEFD3F0BC08BC1847EDAF2140CD
+:108E9000680E00800000104081B013480168C04691
+:108EA00000914168C04600918168C0460091C16848
+:108EB000C04600910169C04600914169C0460091D9
+:108EC0008169C0460091C169C0460091016AC046EF
+:108ED0000091416AC0460091816AC0460091C06A13
+:108EE000C046009001B0704700081440F0B583B050
+:108EF000684D1B23DB01EF18F88B0422024002921D
+:108F000071235B01E8180188C04601914088C04682
+:108F10000090002403E0082C01D30F2C08D9201C5A
+:108F2000FFF7E8FD610049191B23DB01C91888839D
+:108F30000134202CEFD3584CE069002815D0574E4F
+:108F40002025013D5349E06930400BD068004018AE
+:108F500037239B01C018818B281CFFF765FEE06951
+:108F6000B043E0617608002DEBD10120FFF7C2FD90
+:108F70004849C046F883F88BC20825D3CA68012A3D
+:108F800013D10A79002A1FD1498800291CD10199DF
+:108F9000434A002905D0012916D1518BC90813D2A3
+:108FA0000FE0518B09090FD20BE00A79002A0BD18F
+:108FB0006D235B01C9188A88C988114049090907CE
+:108FC00002D104239843F883F88B04210140029ACC
+:108FD0001FD0B98B4A0B27D3800925D3FF230198D3
+:108FE0000133984220D000250098012800D10502C5
+:108FF0000198002802D101235B031D43A94213D02D
+:109000000020291CFFF710FEBD830020C0436062D2
+:109010000AE0B88B400B07D2092149020020FFF774
+:1090200003FE09204002B883F88BC0082DD31D48E9
+:10903000C76A01980099FFF751FCC207D20F1A497D
+:1090400003D00423CD6D2B4303E00423CD6D9D435A
+:109050002B1CCB65830803D30223CD6D2B4303E088
+:109060000223CD6D9D432B1CCB65616A81420CD0E0
+:1090700060620E48002A03D0FF212131394303E00A
+:10908000FF2321339F43391CC16203B0F0BC08BCED
+:1090900018470000680E0080681C008000000080F7
+:1090A000281C008040001440A42A008040001400C6
+:1090B00090B4012220280FD243000F1C07495C18EE
+:1090C00037239B01E3189F83824007235B02C91863
+:1090D000101CCA691043C86190BC7047680E0080BC
+:1090E0000B4840690B49C98B04220A400A4906D043
+:1090F0000123DB0298430123CA6D1A4305E00123D3
+:10910000DB021843CA6D52085200CA65704700005E
+:1091100080001440E81B0080A42A008000B584B0C1
+:10912000FFF7DEFF011C05200090002001AB188036
+:10913000043B58701B2200AB5A80D9800549C96D89
+:10914000C0460291039068460021FDF779F804B00B
+:1091500008BC1847A42A00800F480168490C05D2B2
+:109160000168090C06D10068800A03D30B48006827
+:10917000000C01E00A48806C0004000C094B984286
+:1091800005D00233984202D0074B984201D101200A
+:1091900070470020FCE7000000001040000018406D
+:1091A00000000080049900000799000090B4012499
+:1091B000211C18480268520C06D20268120C02D117
+:1091C0000068800A00D200210906090E124F134AD6
+:1091D00002D03868000C00E0906C0004000C104BCA
+:1091E000984208D00233984205D00E4B984202D0E4
+:1091F000023B98420CD1002902D0F86A000C00E032
+:10920000D06C400A00D200242006000E90BC7047AB
+:109210000020FBE700001040000018400000008024
+:1092200004990000079900000C480168490C05D218
+:109230000168090C05D10068800A02D308488068DB
+:1092400001E00848406C0004000C0021032803D012
+:10925000400801D301207047081CFCE700001040C3
+:109260000000184000000080F0B501271A4C256866
+:10927000FFF772FF031C194A022101261848012B2F
+:109280001BD1CB041E605523036000234360066896
+:10929000552E1BD1AA26066043600368AA2B15D160
+:1092A0000923036005230F4FC0463B6003230E4F85
+:1092B000C0463B601160076808E008232360042370
+:1092C0000A4FC0463B60116006602768C0462560B3
+:1092D000381CF0BC08BC18470000204000002440A7
+:1092E0000000224000002A400000264000002840E4
+:1092F00080B5071CFFF730FF012805D11948006829
+:109300001949496B084022E018480168490C05D208
+:109310000168090C06D10068800A03D3144800686C
+:10932000000C01E01348806C0004000C124BC018C4
+:1093300008280BD201A31B5C5B009F4405030703B5
+:1093400007070503032002E0012000E000200121BF
+:109350003860800700D100210806000E80BC08BCE0
+:1093600018470000346E21400000114000001040FA
+:109370000000184000000080FE66FFFFF0B582B0DC
+:10938000071C01200190FFF7E7FE012813D1382FB9
+:1093900001D0A82F07D10026F643341CA82F02D1F4
+:1093A000301C0096351C1120000406624462856260
+:1093B0000099C046C16200210848C0460160382FAC
+:1093C00001D0A82F05D101210160A82F01D10321CF
+:1093D0000160019802B0F0BC08BC1847346E21400F
+:1093E000704700007047000090B5071C124C2168C0
+:1093F000124881420BD00023211CE21DC13200E043
+:1094000008C19142FCD32060C820A0806772380157
+:1094100000F018F827720A48C046E060092F00DB08
+:109420000027E019017D01310175E0880130E080FD
+:10943000012090BC08BC184700000080EEFFC0D09F
+:109440000810000380B4084AD11D89310B7A202B03
+:1094500001D300230B72071C087A431C0B7280187F
+:109460009030477280BC704700000080074901229D
+:109470001204086802400120002A06D10A68120C72
+:1094800002D10968890A00D200207047000010400C
+:1094900090B5071C094C381C211CFCF791FF381CA7
+:1094A00000F00EF80123D84201D1000CE080002129
+:1094B000201CFCF7C5FE90BC08BC1847C4662140C0
+:1094C000F8B5071C797A76480023764C01295DD1DE
+:1094D000A288C0460092A1898A4274DAFA7A002AE8
+:1094E00015D07A6C002A12D08A4210D8009A511CEA
+:1094F000A180A188C0464181786C6B4EC046F08047
+:10950000A06A5823796C59434018C11A28E0228870
+:1095100001321204120C22808A4200DB23800022D6
+:10952000002969DD5F4CA46A5E4B1D8858236B439C
+:10953000E318DE1D013601239B0733431B681B061E
+:1095400015D15849009A01328A808A88C0464281E2
+:1095500008880130544EC046F080582068432118D6
+:10956000381C00F039FBF0880004001495E04D4BE6
+:1095700001352D042D0C1D808D4201DB00251D8041
+:109580000132120412149142CEDC81E0E188E289BA
+:10959000914218DAF97A00292FD0796C4904490CE4
+:1095A00079642AD0E289914227D8E1880131E180AB
+:1095B000E188C04681810123DB03786C18433A4E71
+:1095C000C046F08000E063E0E06A796C4B00591817
+:1095D00049014018C11F5939381C00F00FFBE06ADF
+:1095E000796C4A0052185201801801390904090C9B
+:1095F000603800F089FBB6E74AE061880131090470
+:10960000090C6180E289914200DB63800021002A1D
+:109610003EDD244CE46A234B5D886B005B195B01E3
+:10962000E318DE1D013601239B0733431B681B062D
+:1096300020D11C4EF1880131F180F188C046818132
+:1096400070880123DB03013018431749C046C880E6
+:109650006800401940012118381C00F0CFFA7188C9
+:109660004A0052185201F06A801800F04DFB0E4972
+:10967000C88879E70B4B01352D042D0C5D80954290
+:1096800001DB00255D800131090409148A42C2DC36
+:109690000189013101810020C043F8BC08BC184792
+:1096A0004C2B00804C2A0080C4662140F0B4061C7C
+:1096B0000123DB0333400124444F0020444A454D3D
+:1096C000D11D3931002B41D0E303F31A73D0EE8959
+:1096D0009E4271D3EE88002E6DD0ED6A5E1E73003F
+:1096E0009B195B01ED18AE683606360E032E02D0CC
+:1096F000CE890136CE814035AD8BAD00354E766AD0
+:10970000C0467051558901355581324EF26AD218E2
+:109710009060F26AD2189063F26AD218D063F26A4B
+:10972000D2181064F26AD2185064F26AD2189064A7
+:10973000F26AD218D064F0880138F080F088C04610
+:1097400088812449002839D14F8037E0002E38D94C
+:10975000AB89B34230D3AB88002B2CD05389013373
+:1097600053812A1CAD6A5823013E7343ED18AE683D
+:109770003606360E032E02D0CE890136CE81A86081
+:10978000956AED18A863956AED18E863956AED1877
+:109790002864956AED186864956AED18A864956A5E
+:1097A000EB18D8649088013890809088C046488132
+:1097B000002803D101E004E003E01780201CF0BC86
+:1097C0007047CA890132CA81F9E70000FFFF000033
+:1097D0000C2B00804C2A008000B50021416010490C
+:1097E0004A68002A10D1CA68002A04D0CA1D19325A
+:1097F0001279002A08D04A69002A0BD18861486191
+:1098000000F010F808BC18474A69002A02D18861A4
+:109810004861F7E78A69C04650608861F2E7000056
+:109820006C060080B0B52A48406900284CD0082258
+:10983000C1680A400027274BD91DB931002A11D031
+:109840000422254CC0460C61244CC0464C62244C7A
+:10985000C0468C62234CC046CC62234CC0460C638D
+:109860004F6312E00522214CC0460C61204CC046DB
+:109870004C62204CC0468C621F4CC046CC621F4CD0
+:10988000C0460C631E4CC0464C634024CC824F83C0
+:109890001C4F0021002A0CD98C0005196D6A7D40EF
+:1098A000E418FF340134656201319142F4D3102988
+:1098B00007D28A00D218FF320132576201311029D3
+:1098C000F7D3114900F022F8B0BC08BC18470000DB
+:1098D0006C060080ACAB20402801400001234567A6
+:1098E00089ABCDEFFEDCBA987654321020014000EF
+:1098F00067452301EFCDAB8998BADCFE1032547670
+:10990000C3D2E1F03636363630802040B0B50F1C79
+:10991000154DE91DC931154C231C154A0020FCF7D3
+:1099200044FBE91DFF311E31231C0D1C114A01208F
+:10993000FCF73BFB291C231C0E4A0020FCF735FBDF
+:10994000391C231C0C4A0120FCF72FFB00210B487B
+:10995000C21D193251710121FF3001304162081CD2
+:10996000B0BC08BC18470000ACAB20407508FFFF36
+:109970002800030040000200140007006C0600806D
+:10998000F0B5374A506901239B0708301843006837
+:109990000106090E334B012949D11F68191C324BAE
+:1099A0009F4204D1FFF73EFFF0BC08BC18470023DC
+:1099B0009F00CC595569EF193C610133052BF7D352
+:1099C000000A0002022318435369C0469860506998
+:1099D0000823C2681340254FFA1DB932002B02D06C
+:1099E0000423234C01E00523224CC046146140248B
+:1099F000D48200245483204C0022002B0CD99500E3
+:109A00004619766A6640ED19FF3501356E620132FE
+:109A10009A42F4D3102A07D29300DB19FF330133A3
+:109A20005C620132102AF7D3FFF770FFBCE7002118
+:109A30008F00DC595569EF197C6201310529F7D394
+:109A4000000A0002032318435169C0468860506928
+:109A50004068C04650610948FCF7A4FAA4E700003A
+:109A60006C0600803080204067452301ACAB20406D
+:109A700028014000200140005C5C5C5C1131FFFF6C
+:109A8000F0B5071C3B483C4C08212060A180002019
+:109A90002081E18060813948C046E0603848C04696
+:109AA00020613848C04660613748C046A0613748E9
+:109AB000C046E0613648C04620623648C046606213
+:109AC0003548C046A0623548C046E0623448C046CA
+:109AD00020633448C04660633348C046A0633348BF
+:109AE000C046E0633248C04620643248C0466064E5
+:109AF0003148C046A0643148C046E0643048C046A2
+:109B000020653049C868020489694A40E31D7933F9
+:109B10000904C943C0434840E11DB931DA63086014
+:109B2000294D211C2B1C294A0020FCF73EFA284A0B
+:109B3000E11DB53101202B1C0E1CFCF736FA244A1E
+:109B40000020311C2B1CFCF730FAE11D4D312B1C81
+:109B5000204A0120FCF729FAE01D5D300168002948
+:109B6000FCD0606DC0463865206EC0467865F0BC9C
+:109B700008BC1847800008008CB92040818148BD8E
+:109B80007956238C930C82951D0E12CF9B3BC0E916
+:109B9000E6557C8299F67802D1D72573728C331002
+:109BA000F703F1426C9B4AA7828E23A990B1828E63
+:109BB000DC3FFB2900622245882BF1851261D173BD
+:109BC0006EB11116088320407508FFFF5400030092
+:109BD000080002001400030080B50F1C391C00F0BF
+:109BE00033F8381CFFF74CFF03480189013101812C
+:109BF00080BC08BC184700000C2B008090B5041CEA
+:109C00000F1C201C391C00F01FF8E068010EFF2219
+:109C100012040240120A1143FF22120202401202F1
+:109C200011430006084338652069C04678656069BD
+:109C3000C046B865034801890131018190BC08BC68
+:109C4000184700000C2B008090B5002293001F18CD
+:109C5000BF695B185F620132052AF7D3077AFB08F8
+:109C600003D30023920052181362076BC0468F6320
+:109C7000C76AC046CF63876BC0460F64476BC04658
+:109C80004F64076CC0468F64C26BC046CA64C2880A
+:109C9000C0460A80827A1206037A1B041A43C388DC
+:109CA0001B021A43437ADB071A438A60171C837A24
+:109CB0005A0805D314221C1CA30802D2152200E066
+:109CC0000022007A430810D3C00802D38820104332
+:109CD00001E0802010433A0A120201231A43C860AF
+:109CE0008A60081CFFF778FD05E0380A00020323AC
+:109CF00018438860CA60034801890131018190BC22
+:109D000008BC18470C2B0080F0B4026D144C151CD5
+:109D1000E769BD40131C266AF3405D402E1C456D6B
+:109D2000BD406E402B1C351CFD402F1CBB00656ADE
+:109D3000EB58002B08D0236901379F4200D300273E
+:109D4000BE00AE59002EF7D1A469A2401143054BC5
+:109D50001943BA00A95040308783F0BC7047000017
+:109D60004C2A00800000008080B4002200230029DB
+:109D700005D907787A40013001338B42F9D3D043BB
+:109D80000006000E80BC7047F0B5071C0024FF26BB
+:109D90000936201C00F09AF800F0B8F9051C00F014
+:109DA000C7FA3D70281C01370134B442F1D3F0BC2E
+:109DB00008BC184780B500F093F800F0A7F9071C1D
+:109DC00000F0B6FA380AF6D380BC08BC1847F3B5E1
+:109DD00082B002984102532000F064F800F0A8FA23
+:109DE000FFF7E8FF0024002001902E2000900025BE
+:109DF00000270298012804D10098844201D300264C
+:109E000009E00198411C019100F060F800F07EF932
+:109E1000061C00F08DFAF800864035430134013706
+:109E2000042FE6D3039920C10391FF2309339C42F9
+:109E3000DDD304B0F0BC08BC1847F0B5041C0F1CFF
+:109E4000012C2AD01648C06F4023016819430160D5
+:109E5000002620CFB100842000F024F8281C00F058
+:109E6000DFF9280A00F0DCF9280C00F0D9F9280EF7
+:109E700000F0D6F900F05CFA0136422EE9D3610217
+:109E8000832000F00FF800F053FAFFF793FF044827
+:109E9000C06F4023016899430160F0BC08BC1847BB
+:109EA000680E008090B5041C0F1C00F059FA201CAD
+:109EB00000F0B6F9380C00F0B3F9380A00F0B0F948
+:109EC000381C00F0ADF990BC08BC184700B5011C67
+:109ED0005420FFF7E7FF002000F0A2F908BC184764
+:109EE00000B500F03DFA572000F09AF908BC184779
+:109EF00090B5084FFA6F202314689C431460231C0C
+:109F0000FFF765FFF86F202301681943016090BCDB
+:109F100008BC1847680E008090B5084FFA6F2023E0
+:109F200014689C431460231CFFF787FFF86F2023FD
+:109F300001681943016090BC08BC1847680E008096
+:109F4000F0B5041C0F1C184EF06F202301689943D4
+:109F5000016061025320FFF7A5FF00F0E9F9FFF768
+:109F600029FFF81D0530012C03D1222F01D3002732
+:109F70000FE0441CFFF7AAFF00F0C8F8071C00F030
+:109F8000D7F9201CFFF7A2FF00F0C0F8051C00F075
+:109F9000CFF9F06F2023016819430160280238438C
+:109FA000F0BC08BC18470000680E0080F0B5C2B0D5
+:109FB000141C0D1C071C012F2FD07902194EF06FB5
+:109FC000202302689A4302605320FFF76BFF00F0E2
+:109FD000AFF9FFF7EFFE6846FFF7D6FE6A46E81DC9
+:109FE00005301454210A68444170684600990C30C9
+:109FF000FFF7BAFE02AB18700020587068460C21BB
+:10A00000FFF7B2FE02AB58706946381CFFF715FF28
+:10A01000F06F202301681943016042B0F0BC08BC16
+:10A0200018470000680E0080FFB5C2B0071C012F62
+:10A0300001D1012036E06B460020C44310C301303B
+:10A040004228FBD368460C30031C0024002A0AD99E
+:10A050000E88C04606700E883612467002300231F5
+:10A0600002349442F4D30092181C111CFFF77CFEBA
+:10A07000041C0020019002AB1C7058709D70684653
+:10A080000C21FFF771FE02AB5870459B1D062D0E8B
+:10A09000AC4203D16946381CFFF73EFF0120AC42B9
+:10A0A00000D1002046B0F0BC08BC1847B0B5C2B023
+:10A0B0000F1C4102144CE06F202302689A43026097
+:10A0C0005320FFF7EFFE00F033F9FFF773FE684609
+:10A0D000FFF75AFEE06F20230168194302AD0160CB
+:10A0E0006D78002402AB5C7068460C21FFF73CFEE3
+:10A0F000A84202D10098874201D3201C00E0012031
+:10A1000042B0B0BC08BC1847680E0080FC466047EF
+:10A110000000A0E3B4229FE5B4329FE50110A0E364
+:10A12000001082E5001082E50010A0E3001082E537
+:10A13000001082E5001093E5810380E10110A0E3A7
+:10A14000001082E5001082E50010A0E3001082E517
+:10A15000001082E5001093E5010380E10110A0E307
+:10A16000001082E5001082E50010A0E3001082E5F7
+:10A17000001082E5001093E5810280E10110A0E368
+:10A18000001082E5001082E50010A0E3001082E5D7
+:10A19000001082E5001093E5010280E10110A0E3C8
+:10A1A000001082E5001082E50010A0E3001082E5B7
+:10A1B000001082E5001093E5810180E10110A0E329
+:10A1C000001082E5001082E50010A0E3001082E597
+:10A1D000001082E5001093E5010180E10110A0E389
+:10A1E000001082E5001082E50010A0E3001082E577
+:10A1F000001082E5001093E5810080E10110A0E3EA
+:10A20000001082E5001082E50010A0E3001082E556
+:10A21000001082E5001093E5010080E11EFF2FE1B0
+:10A22000FC466047A4219FE5A8319FE5A013A0E16B
+:10A23000001083E50110A0E3001082E5001082E524
+:10A240000010A0E3001082E5001082E52013A0E1D9
+:10A25000001083E50110A0E3001082E5001082E504
+:10A260000010A0E3001082E5001082E5A012A0E13A
+:10A27000001083E50110A0E3001082E5001082E5E4
+:10A280000010A0E3001082E5001082E52012A0E19A
+:10A29000001083E50110A0E3001082E5001082E5C4
+:10A2A0000010A0E3001082E5001082E5A011A0E1FB
+:10A2B000001083E50110A0E3001082E5001082E5A4
+:10A2C0000010A0E3001082E5001082E52011A0E15B
+:10A2D000001083E50110A0E3001082E5001082E584
+:10A2E0000010A0E3001082E5001082E5A010A0E1BC
+:10A2F000001083E50110A0E3001082E5001082E564
+:10A300000010A0E3001082E5001082E50010A0E13B
+:10A31000001083E50110A0E3001082E5001082E543
+:10A320000010A0E3001082E5001082E51EFF2FE17F
+:10A33000FC466047A0309FE50110A0E3001083E5D4
+:10A34000001083E5001083E5001083E5001083E52D
+:10A35000001083E5001083E5001083E51EFF2FE168
+:10A36000FC46604770309FE50010A0E3001083E5D5
+:10A37000001083E5001083E5001083E5001083E5FD
+:10A38000001083E5001083E5001083E51EFF2FE138
+:10A39000FC46604734209FE53C309FE50010A0E379
+:10A3A000001082E5001082E50110A0E3001083E5B3
+:10A3B000001083E5001083E5001083E5001083E5BD
+:10A3C000001083E5001083E5001083E51EFF2FE1F8
+:10A3D000F80018400401184000011840FC00184023
+:10A3E00080B500F00CF80027381C00F047F8781C06
+:10A3F00007043F0C0C2FF7DD80BC08BC18471D4834
+:10A4000002681D498B69D218026002668A6A436835
+:10A410009B184360934202D2826801328260C26814
+:10A420000B6AD218C2604269CB68D2184261C26915
+:10A430008B68D218C26102690B69D2180261826905
+:10A440000B68D2188261026BCB69D21802634A6A28
+:10A45000436B9B184363934202D2826B0132826347
+:10A46000C26B4B69D218C263026CC96A511801648D
+:10A4700070470000A42A00800008144088B569468F
+:10A4800000F017F881080AD00020002907D900221F
+:10A490008300009FC046FA5001308842F8D388BC40
+:10A4A00008BC184700B500F004F80004000C08BC14
+:10A4B0001847002200280AD001280AD002280CD010
+:10A4C000032802D107481C220860101C7047064868
+:10A4D00004E0064850220860F7E705486822086053
+:10A4E000F3E7000008832040A42A00800C2B0080A2
+:10A4F000A082204080B40322C280154AC0468260F8
+:10A50000144A12880132C2600020134A135CC0460C
+:10A510000B70013001310828F8D320220A70013174
+:10A5200000200E4B1F5CC0460F700130013108281F
+:10A53000F8D30A7001310020094A135CC0460B7041
+:10A54000013001310828F8D30020087080BC704722
+:10A5500008100003680E00807C04008085040080E1
+:10A560008E04008000B501230A48C11D89314B705B
+:10A5700000220A7064218030C182018343837D21DF
+:10A58000C9008183C28304480122002100F08EFBB0
+:10A5900008BC1847680E0080B522FFFF00B5FFF722
+:10A5A000E1FF13480222002100F080FB0123D84282
+:10A5B0000AD11048C11D3931CA880132CA80817957
+:10A5C00001318171FDF770F90B48C068012805D190
+:10A5D0000A487D22D200002100F068FB0848FBF702
+:10A5E000E1FC08482822002100F060FB08BC184765
+:10A5F0007921FFFFA0822040680E0080A57B2140CA
+:10A60000952CFFFF5903FFFF00B510200F49C046EE
+:10A6100008600F4A0F486421FBF7C6FC0E48012270
+:10A62000120401680A400821002A05D10268120CB0
+:10A6300007D10068800A04D30848C046C16008BC3E
+:10A6400018470748C0460164F9E70000000000B061
+:10A65000A555FFFF7C290080000010404001180034
+:10A6600000000080F8B527480122120401680A4062
+:10A670000721002A05D10268120C06D10068800A61
+:10A6800003D32148C046C16002E02048C0460164AF
+:10A690001F48FBF787FC1F48C16BFF29FCD1816B6A
+:10A6A000426B161C0F1C1C4C102360691843606120
+:10A6B000A16999431D04A161E860A069C0462861B1
+:10A6C000164A17496420FBF76FFC164AC0460092F1
+:10A6D000154B0020391C321CFBF76EFC1348C16877
+:10A6E0000829FCD11248FBF75DFC102360699843F0
+:10A6F0006061E8600120E3231B01E118C871F8BC28
+:10A7000008BC1847000010404001180000000080FD
+:10A710000402FFFF00011840680E00802055FFFF73
+:10A72000B5B621406400300244802040400118400A
+:10A73000F401FFFF00B5FDF701FF0648FBF732FC0F
+:10A74000FDF7D6FEFEF704F8FEF716F8FEF724F83C
+:10A7500008BC18479103FFFF90B5FDF76BFC344F21
+:10A760000024F968F81D793001290FD13149C0461C
+:10A77000F9673149C04601603049C0460C604C6001
+:10A780008C60CC600C614C618C6104E0F91D7D3102
+:10A79000F96712C008380068602301681943016036
+:10A7A000F86F2023016819430160F86F40230168A6
+:10A7B0009943016000F054F8FDF74EFC00F05EF99B
+:10A7C000FDF773F8FFF70CFEFDF72EFEFDF7B6FD63
+:10A7D000FDF7C2FEFDF754FDFDF70AFDFDF794FD00
+:10A7E00000F01AFAFDF79CFFFDF70AFFFDF7D2FE15
+:10A7F000FDF73CFCFBF7DCFAFFF79CFF71235B01E4
+:10A80000F8180472447207235B02F8180463F868AE
+:10A81000012802D1A820FEF7B1FD0948C0464462D4
+:10A8200000F018FA0748FBF7BDFB90BC08BC1847BE
+:10A83000680E008000011140040111400001110068
+:10A84000C0001800158F214000B50448FBF7AAFB93
+:10A85000FDF75EFFFDF724FC08BC18471599214061
+:10A86000FA210348C046416240214162704700001E
+:10A87000C000180007484169074B194341618269CC
+:10A880009A43826101221205D1608069C04610613D
+:10A8900070470000680E0080FEAF9A1000B50248B5
+:10A8A000FBF780FB08BC1847C857FFFFF0B5244CE6
+:10A8B00001210904206801400920224E224D00296F
+:10A8C00005D12168090C04D12168890A01D3F060FF
+:10A8D00000E028641D48FBF765FB1D4F1D49886992
+:10A8E00001308861387A002802D1787A00281FD098
+:10A8F0001948FBF757FB1948FBF754FB0028FAD11E
+:10A90000387A002802D01648FBF74CFB01210904D5
+:10A91000206801401420002905D12168090C04D1C8
+:10A920002168890A01D3F06001E02864FFE7FEE7AF
+:10A93000FFF765FD0B48FBF735FBFFF7AFFFCDE7F2
+:10A940000000104040011800000000800402FFFFDA
+:10A95000881C008008832040F401FFFFB507FFFF3B
+:10A960000000FFFF999F21400020074A01210905AF
+:10A970005061C860D061C8610323DB04034A012130
+:10A98000D1635860FCE70000680E0080C00018002A
+:10A9900080B5C0B0012200210A20FCF7D1FF071CBE
+:10A9A000FF2F28D06946FF22381C0132FDF754F9E9
+:10A9B000FF23013398421BD10D98000918D3381C8E
+:10A9C000FDF78DF80E4901221204086802400D4877
+:10A9D00005D10A68120C06D10968890A03D30A490D
+:10A9E000C046C86002E00949C0460864FFF7BCFFE2
+:10A9F000381CFDF774F840B080BC08BC1847000054
+:10AA00000000104007800000400118000000008096
+:10AA100000B5174901221204086802400620002AE6
+:10AA200005D10A68120C06D10968890A03D31149B5
+:10AA3000C046C86002E01049C04608640320FEF723
+:10AA4000D3FCFBF70DFF01231843FBF7E7FFFFF7EC
+:10AA500083FEFFF79DFFFFF705FEFFF7F5FEFFF70B
+:10AA600009FFFFF79BFDFFF721FF08BC1847000017
+:10AA7000000010404001180000000080F0B4464A79
+:10AA80000121C903454D1923DB01EC18A161288878
+:10AA90004004434BC018871A0420AF60414EC046A3
+:10AAA000B0610820C8234343BB4221D941003D4E39
+:10AAB000C0463161B66920239B1B3A4EC046F36104
+:10AAC000103B33628B00FF1A4008814217D3B82332
+:10AAD0004343BB4208D9411E324BC0469981D981BC
+:10AAE0004000023858610AE001308142EFD206E0AE
+:10AAF0002C4EB3690133B36140008842D2D92A4950
+:10AB00000020A3699B0807D0284B8700CB51A76979
+:10AB1000BF0801308742F8D82249C0468A628C8932
+:10AB200058206043871800200022002C0ADD58239B
+:10AB300043438C6AE31801300004000C9A608B894F
+:10AB40008342F4DCCF62CC89600000194001C71950
+:10AB50000020002C0BDD43001B185B01CC6AE318BE
+:10AB600001300004000C9A60CB898342F3DC4F6211
+:10AB700000200B69002B07D987004B6AC046DA51C9
+:10AB80000B6901308342F7D8496A800008180438FD
+:10AB90002861F0BC70470000B0BE2140680E008004
+:10ABA000000020404C2A00800000204000ADDE0064
+:10ABB0000A4801231B06416999431A094161D16082
+:10ABC0000021A122520391611B23DB01C018816186
+:10ABD000012000065905086070470000680E0080DB
+:10ABE00080B4021C0B481B23DB01C3189A610123AC
+:10ABF0001B0642691A43426187699F4301231B0573
+:10AC00008761DA608069C0461861A12040038161D4
+:10AC100080BC7047680E008080B5FFF7C9FF002038
+:10AC200000F020F800200949002203015F183323B7
+:10AC30009B01FB189A6201300B28F6D304480122CD
+:10AC4000002100F033F880BC08BC1847680E008073
+:10AC50001D3EFFFF00B5024800F004F808BC18478D
+:10AC6000A861000080B4012212050F4BA121490305
+:10AC700000280ED0C861181C59695301194341615D
+:10AC800087699F438761D1608069C046106180BC3D
+:10AC90007047181C5F6901235B069F434761D760BB
+:10ACA0000020C861F3E70000680E0080B0B4071C04
+:10ACB0000020174C03011D1933239B01EB189D6ADB
+:10ACC000BD4205D11D6B954202D1DB6A8B421CD07F
+:10ACD00001300B28EED3002003011D1933239B0103
+:10ACE000EB189B6A002B09D103011C1933239B012C
+:10ACF000E3181A63D9625A639F6202E001300B289D
+:10AD0000EAD30B2801D10020C043B0BC704700003B
+:10AD1000680E008090B4011C00220120164F01E053
+:10AD2000002A07D10301DC1933239B01E3189B6937
+:10AD30008B4211D10201D21933239B01D218936A9D
+:10AD4000C0469361D36AC046D361136BC046136299
+:10AD5000536BC0465362012201300B28E0D3074BEE
+:10AD6000002A02D19A688A4203D10021996090BCDE
+:10AD700070470020C043FAE7680E0080E81B00809F
+:10AD80000B2817DA0C4901235B068A691343012259
+:10AD900012058B6113610001401833239B01C01819
+:10ADA000036BC0464363530188699843886110610F
+:10ADB000012070470020FCE7680E008090B4084A2C
+:10ADC000D0690021074FD369834202D9FC1A2018A9
+:10ADD00000E0C01A0918181CB942F4D990BC704799
+:10ADE00000201440A861000090B5071C0024002F2B
+:10ADF00004D3FFF7E3FF0134BC42FAD990BC08BC8E
+:04AE000018470000EF
+:00000001FF
+/* ver 03.001.008 */
+/*
+ * Copyright 1999-2004 3Com Corporation.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms of the 3c990img.h
+ * microcode software are permitted provided that the following conditions
+ * are met:
+ * 1. Redistribution of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistribution in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of 3Com may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY 3COM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * USER ACKNOWLEDGES AND AGREES THAT PURCHASE OR USE OF THE 3c990img.h
+ * MICROCODE SOFTWARE WILL NOT CREATE OR GIVE GROUNDS FOR A LICENSE BY
+ * IMPLICATION, ESTOPPEL, OR OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS
+ * (PATENT, COPYRIGHT, TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT)
+ * EMBODIED IN ANY OTHER 3COM HARDWARE OR SOFTWARE EITHER SOLELY OR IN
+ * COMBINATION WITH THE 3c990img.h MICROCODE SOFTWARE
+ */
index 466106fa214639bb8a32e6b5c2ade0bb7525f4d2..c6af61b4e51e4448272a88cdee6daac956fa2a51 100644 (file)
@@ -35,7 +35,7 @@ fw-shipped-$(CONFIG_CASSINI) += sun/cassini.bin
 fw-shipped-$(CONFIG_COMPUTONE) += intelliport2.bin
 fw-shipped-$(CONFIG_CHELSIO_T3) += cxgb3/t3b_psram-1.1.0.bin \
                                   cxgb3/t3c_psram-1.1.0.bin \
-                                  cxgb3/t3fw-7.0.0.bin
+                                  cxgb3/t3fw-7.1.0.bin
 fw-shipped-$(CONFIG_DVB_TTUSB_BUDGET) += ttusb-budget/dspbootcode.bin
 fw-shipped-$(CONFIG_E100) += e100/d101m_ucode.bin e100/d101s_ucode.bin \
                             e100/d102e_ucode.bin
@@ -49,8 +49,10 @@ fw-shipped-$(CONFIG_SND_SB16_CSP) += sb16/mulaw_main.csp sb16/alaw_main.csp \
                                     sb16/ima_adpcm_capture.csp
 fw-shipped-$(CONFIG_SND_YMFPCI) += yamaha/ds1_ctrl.fw yamaha/ds1_dsp.fw \
                                   yamaha/ds1e_ctrl.fw
+fw-shipped-$(CONFIG_TEHUTI) += tehuti/bdx.bin
 fw-shipped-$(CONFIG_TIGON3) += tigon/tg3.bin tigon/tg3_tso.bin \
                               tigon/tg3_tso5.bin
+fw-shipped-$(CONFIG_TYPHOON) += 3com/typhoon.bin
 fw-shipped-$(CONFIG_USB_DABUSB) += dabusb/firmware.fw dabusb/bitstream.bin
 fw-shipped-$(CONFIG_USB_EMI26) += emi26/loader.fw emi26/firmware.fw \
                                  emi26/bitstream.fw
index 524113f9bea32e23c42d02b1ac3ea18297c6b93c..00b6e3c0905d09aa41d5670cdcd4e0ae4bba1362 100644 (file)
@@ -368,7 +368,7 @@ Driver: cxgb3 - Chelsio Terminator 3 1G/10G Ethernet adapter
 
 File: cxgb3/t3b_psram-1.1.0.bin.ihex
 File: cxgb3/t3c_psram-1.1.0.bin.ihex
-file: cxgb3/t3fw-7.0.0.bin.ihex
+file: cxgb3/t3fw-7.1.0.bin.ihex
 
 License: GPLv2 or OpenIB.org BSD license, no source visible
 
@@ -435,3 +435,61 @@ Found in hex form in kernel source, with the following notice:
  ARISING OUT OF THE USE OR INABILITY TO USE THE PROGRAM.
 
 --------------------------------------------------------------------------
+
+Driver: TEHUTI - Tehuti Networks 10G Ethernet
+
+File: tehuti/bdx.bin
+
+Licence:
+
+ Copyright (C) 2007 Tehuti Networks Ltd.
+
+ Permission is hereby granted for the distribution of this firmware data
+ in hexadecimal or equivalent format, provided this copyright notice is
+ accompanying it.
+
+Found in hex form in kernel source.
+
+--------------------------------------------------------------------------
+
+Driver: TYPHOON - 3cr990 series Typhoon
+
+File: 3com/typhoon.bin
+
+Licence:
+/*
+ * Copyright 1999-2004 3Com Corporation.  All Rights Reserved.
+ *
+ * Redistribution and use in source and binary forms of the 3c990img.h
+ * microcode software are permitted provided that the following conditions
+ * are met:
+ * 1. Redistribution of source code must retain the above copyright
+ *    notice, this list of conditions and the following disclaimer.
+ * 2. Redistribution in binary form must reproduce the above copyright
+ *    notice, this list of conditions and the following disclaimer in the
+ *    documentation and/or other materials provided with the distribution.
+ * 3. The name of 3Com may not be used to endorse or promote products
+ *    derived from this software without specific prior written permission
+ *
+ * THIS SOFTWARE IS PROVIDED BY 3COM ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ *
+ * USER ACKNOWLEDGES AND AGREES THAT PURCHASE OR USE OF THE 3c990img.h
+ * MICROCODE SOFTWARE WILL NOT CREATE OR GIVE GROUNDS FOR A LICENSE BY
+ * IMPLICATION, ESTOPPEL, OR OTHERWISE IN ANY INTELLECTUAL PROPERTY RIGHTS
+ * (PATENT, COPYRIGHT, TRADE SECRET, MASK WORK, OR OTHER PROPRIETARY RIGHT)
+ * EMBODIED IN ANY OTHER 3COM HARDWARE OR SOFTWARE EITHER SOLELY OR IN
+ * COMBINATION WITH THE 3c990img.h MICROCODE SOFTWARE
+ */
+
+Found in hex form in kernel source.
+
+--------------------------------------------------------------------------
diff --git a/firmware/cxgb3/t3fw-7.0.0.bin.ihex b/firmware/cxgb3/t3fw-7.0.0.bin.ihex
deleted file mode 100644 (file)
index e661179..0000000
+++ /dev/null
@@ -1,1881 +0,0 @@
-:1000000060007400200380002003700000001000D6
-:1000100000002000E100028400070000E1000288E7
-:1000200000010000E0000000E00000A0010000006E
-:1000300044444440E3000183200200002001E0002A
-:100040002001FF101FFFD0001FFFC000E300043C91
-:1000500002000000200069541FFFC5802000699C39
-:100060001FFFC584200069DC1FFFC58820006A507F
-:100070001FFFC58C200003C0C00000E43100EA313E
-:1000800000A13100A03103020002ED306E2A05000C
-:10009000ED3100020002160012FFDBC03014FFDA5F
-:1000A000D30FD30FD30F03431F244C107249F0D347
-:1000B0000FD30FD30F12FFD5230A00240A00D30F4A
-:1000C000D30FD30F03431F244C107249F0D30FD327
-:1000D0000FD30F14FFCE03421F14FFCB03421F1296
-:1000E000FFCCC0302D37302D37342D37382D373CED
-:1000F000233D017233ED00020012FFC4C0302F37E0
-:10010000002F37102F37202F3730233D017233ED6A
-:1001100000020012FFBEC0302737002737102737F4
-:1001200020273730233D017233ED03020012FFB95F
-:1001300013FFBA0C0200932012FFB913FFB90C028F
-:1001400000932012FFB8C0319320822012FFB71312
-:10015000FFB7932012FFB715FFB316FFB6C030D715
-:100160002005660160001B00000000000000000088
-:10017000043605000200D30FD30F7531140747145E
-:1001800005330C0704437631E60436057539ED0076
-:10019000020012FFA715FFA3C030D72060000600A1
-:1001A00007471405330C070443043E057539F00373
-:1001B000020012FFA1C03014FFA1D30FD30FD30F41
-:1001C0009340B4447249F2D30FD30FD30F14FF9B63
-:1001D000834014FF9B834012FF9B230A0014FF9A65
-:1001E000D30FD30FD30F9340B4447249F2D30FD33C
-:1001F0000FD30F14FF95834012FF95CA20832084EC
-:10020000218522BC22743B108650B4559630B433FD
-:100210007433F463FFE6000000653FE0655FDD12C4
-:10022000FF7CC03028374028374428374828374CCF
-:10023000233D017233ED03020000020012FF7AC079
-:1002400032032E0503020012FF7813FF819320C0B2
-:1002500011014931004831010200C00014FF7E0441
-:10026000D23115FF7D945014FF7D04D33115FF7CEE
-:10027000945014FF7C04D43115FF7C24560014FFE5
-:100280007B04D53115FF7B24560010FF7A03000054
-:10029000000000000000000000000000000000005E
-:1002A000000000000000000000000000000000004E
-:1002B000000000000000000000000000000000003E
-:1002C000000000000000000000000000000000002E
-:1002D000000000000000000000000000000000001E
-:1002E000000000000000000000000000000000000E
-:1002F00000000000000000000000000000000000FE
-:1003000000000000000000000000000000000000ED
-:1003100000000000000000000000000000000000DD
-:1003200000000000000000000000000000000000CD
-:1003300000000000000000000000000000000000BD
-:1003400000000000000000000000000000000000AD
-:10035000000000000000000000000000000000009D
-:10036000000000000000000000000000000000008D
-:10037000000000000000000000000000000000007D
-:10038000000000000000000000000000000000006D
-:10039000000000000000000000000000000000005D
-:1003A000000000000000000000000000000000004D
-:1003B000000000000000000000000000000000003D
-:1003C000000000000000000000000000000000002D
-:1003D000000000000000000000000000000000001D
-:1003E000000000000000000000000000000000000D
-:1003F00000000000000000000000000000000000FD
-:1004000000000000000000000000000000000000EC
-:1004100000000000000000000000000000000000DC
-:1004200063FFFC000000000000000000000000006E
-:100430000000000000000000000000001FFC0000A1
-:100440001FFC0000E30005C81FFC00001FFC0000AB
-:10045000E30005C81FFC00001FFC0000E30005C806
-:100460001FFFC0001FFFC000E30005C81FFFC00042
-:100470001FFFC018E30005C81FFFC0181FFFC018EA
-:10048000E30005E01FFFC0181FFFC288E30005E07E
-:100490001FFFC2881FFFC288E30008501FFFC290E1
-:1004A0001FFFC57CE3000850200000002000016A07
-:1004B000E3000B3C2000018020000180E3000CA839
-:1004C0002000020020000203E3000CA82000021C10
-:1004D00020000220E3000CAC2000022020000226B5
-:1004E000E3000CB02000023C20000240E3000CB806
-:1004F0002000024020000249E3000CBC2000024C16
-:1005000020000250E3000CC82000025020000259D5
-:10051000E3000CCC2000025C20000260E3000CD859
-:100520002000026020000269E3000CDC2000026C65
-:1005300020000270E3000CE8200002702000027925
-:10054000E3000CEC2000028C2000028CE3000CF88D
-:100550002000029020000293E3000CF8200002AC7F
-:10056000200002B0E3000CFC200002D0200002F2C8
-:10057000E3000D00200003B0200003B0E3000D24D1
-:10058000200003B0200003B0E3000D24200003B0DE
-:10059000200003B0E3000D24200003B0200003B0CE
-:1005A000E3000D24200003B020006B74E3000D2451
-:1005B00020006B7420006B74E30074E800000000FE
-:1005C00000000000000000001FFC00001FFC0000F5
-:1005D0001FFFC5801FFFC67020006B7820006B785E
-:1005E000DEFFFE000000080CDEADBEEF1FFFC29074
-:1005F0001FFCFE001FFFC0841FFFC5C030000000AD
-:10060000003FFFFF8040000010000000080FFFFFC8
-:100610001FFFC25D000FFFFF804FFFFF8000000043
-:1006200000000880B000000560500000600000007D
-:1006300040000011350000004100000010000001E2
-:1006400020000000000010007FFFFFFF40000000BE
-:1006500005000000800000190400000000000800F0
-:1006600010000005806000007000000020000009FC
-:10067000001FF8008000001EA0000000F80000002D
-:100680000800000007FFFFFF1800000001008001C4
-:10069000420000001FFFC20D1FFFC0CC0001008000
-:1006A000604000001A0000000C0000000000300054
-:1006B000600008008000001C000100008000001A9B
-:1006C00080000018FC0000008000000100004000D5
-:1006D000800004000300000050000003FFFFBFFF84
-:1006E00000000FFF1FFFC390FFFFF000000016D0B7
-:1006F0000000FFF7A50000001FFFC4A01FFFC451AA
-:100700000001000800000B20202FFF801FFFC445C0
-:1007100000002C00FFFEFFF800FFFFFF1FFFC56871
-:1007200000002000FFFFDFFF0000FFEF01001100CD
-:100730001FFFC4611FFFC3C21FFFC4101FFFC5906E
-:10074000FFFFEFFF0000FFFB1FFFBE90FFFFF7FF63
-:100750001FFFC0540000FFFD0001FBD01FFFC5B00C
-:100760001FFFC6601FFFC591E0FFFE000000800074
-:100770001FFFC52C1FFFC5B41FFFC0581FFFC4D0EB
-:100780001FFCFFD800010081E100060000002710D7
-:100790001FFCFE301FFCFE70E10002001FFFC52899
-:1007A0001FFFC5400003D0901FFFC5542B5063802E
-:1007B0002B5079802B5090802B50A6801FFFC4595E
-:1007C0000100110F202FFE0020300080202FFF009D
-:1007D0000000FFFF0001FFF82B50B2002B50B208C1
-:1007E000000100102B50B1802B50B2802B50BA006A
-:1007F000000100112B50BD282B50BC802B50BDA0F8
-:1008000020300000DFFFFE005000000200C00000AA
-:1008100002000000FFFFF7F41FFFC05C000FF800AC
-:1008200004400000001000000C4000001C400000CC
-:10083000E00000A01FFFC5301FFD00081FFFC544DA
-:100840001FFFC5581FFFC56CE1000690E10006ECD4
-:100850000100000000000000000000000000000097
-:100860002010004020100040201000402014008084
-:10087000200C0000200C0000200C00002010004084
-:10088000201400802014008020140080201800C054
-:10089000201C0100201C0100201C01002020014020
-:1008A000201800C0201800C0201800C0201C010023
-:1008B000201800C0201800C0201800C0201C010013
-:1008C000202001402020014020200140202009401C
-:1008D00020200940202009402020094020240980B0
-:1008E000FFFFFFFFFFFFFFFFFFFFFFFF0000000014
-:1008F00000000000000000000000000000000000F8
-:100900002000525420005124200052542000525400
-:1009100020005060200050602000506020004E9465
-:1009200020004E9420004E8C20004DFC20004CA056
-:1009300020004A88200048880000000000000000D5
-:1009400020005224200050F02000519420005194A7
-:1009500020004F3820004F3820004F3820004F38FB
-:1009600020004F3820004E8420004F3820004BC418
-:1009700020004A3C20004838000000000000000031
-:1009800020000B702000384C200004C02000442CB4
-:1009900020000B6820003F40200003F0200043ECC3
-:1009A0002000481420003C5020003B6C200037C839
-:1009B00020003654200033CC20002EF8200039CC03
-:1009C00020002B5C200027942000648C2000232032
-:1009D0002000200420001FB820001CA4200017B015
-:1009E000200014F020000D8C20000BB4200010BC5F
-:1009F000200012A02000413020003C0420000B7891
-:100A0000200004C000000000000000000000000002
-:100A100000000000000000000000000000000000D6
-:100A200000000000000000000000000000000000C6
-:100A300000000000000000000000000000000000B6
-:100A400000000000000000000000000000000000A6
-:100A50000000000000000000000000000000000096
-:100A60000000000000000000000000000000000086
-:100A70000000000000000000000000000000000076
-:100A8000000000003264000000000000326400003A
-:100A90006400640064006400640064006400640036
-:100AA0000000000000000000000000000000000046
-:100AB0000000000000000000000000000000000036
-:100AC0000000000000000000000000000000000026
-:100AD0000000000000000000000000000000000016
-:100AE00000000000000000000000100000000000F6
-:100AF00000000000000000000000000000000000F6
-:100B000000001000000000000000000000000000D5
-:100B100000000000004323800000000000000000EF
-:100B200000000000000000000000000000000000C5
-:100B3000000000000000000000000000005C9401C4
-:100B40005D94025E94035F94004300000000000087
-:100B50000000000000000000000000000000000095
-:100B60000000000000000000000000000000000085
-:100B7000000000000000000000000000005C900188
-:100B80005D90025E90035F90005300000000000043
-:100B90000000000000000000000000000000000055
-:100BA0000000000000000000000000000000000045
-:100BB000000000000000000000000000009C940005
-:100BC0001D90019D94029E94039F9404089405092E
-:100BD00094060A94070B94004300000000000000F4
-:100BE0000000000000000000000000000000000005
-:100BF000000000000000000000000000009C9001C8
-:100C00009D90029E90071D90039F90047890057917
-:100C100090067A90077B90005300000000000000CF
-:100C200000000000000000000000000000000000C4
-:100C300000000000000000000000000000DC940044
-:100C40001D9001DD9402DE9403DF940404940505F5
-:100C5000940606940707940808940909940A0A94CC
-:100C60000B0B940043000000000000000000000097
-:100C700000000000000000000000000000DC900107
-:100C8000DD9002DE900B1D9003DF9004B49005B55B
-:100C90009006B69007B79008B89009B9900ABA9034
-:100CA0000BBB90005300000063FFFC002000693084
-:100CB00010FFFF0A000000002000695400D231102C
-:100CC000FFFE0A00000000002000699C00D33110E4
-:100CD000FFFE0A0000000000200069DC00D4311093
-:100CE000FFFE0A000000000020006A5000D531100D
-:100CF000FFFE0A000000000063FFFC00E00000A00F
-:100D000012FFF78220028257C82163FFFC12FFF313
-:100D100003E83004EE3005C030932094219522631F
-:100D2000FFFC00001FFFD000000400201FFFC58053
-:100D30001FFFC670200A0011FFFB13FFFB03E63103
-:100D400001020016FFFA17FFFAD30F776B069060C7
-:100D5000B4667763F85415265419D90F140063FF4D
-:100D6000F90000006C1004C020D10F006C1006C008
-:100D7000C71AEF060D4911D830D7201BEF05BC224A
-:100D80008572AB76837105450B957209330C23761A
-:100D900001723B05233D08237601A39D19EEFE7DDC
-:100DA0006326C021C0E0032E380E0E42C8EE29A6ED
-:100DB0007E6D4A0500808800308C8271D10FC0F0B2
-:100DC000082F387FC0EA63FFE49210037F0CABFF6B
-:100DD0000F3D12DB802EDC100E4E36C021C05003BA
-:100DE0002538221200050542CB5029A67E6DEA0562
-:100DF00000B08800308CBC76C050A8F3C081068556
-:100E000038050542CA5129A67E0D480CD30F6D8ABC
-:100E10000500308800208C8271D10F00C061C05065
-:100E200008653875C0C663FFC0C0B0038B387BC08F
-:100E3000D763FFD16C101216EED82A221E2E221D67
-:100E4000C0D07AE11B2CA000D7A028CCE96481484F
-:100E500029CCE8649341C1B97BC12569CC1B6000F2
-:100E6000222CD000D7D028CCE964815429CCE86466
-:100E700093BAC1B97BC10968CC09C020D10F000069
-:100E8000002D25028C32C0900C6F5065F586292408
-:100E900067090847658582B44927200C18EEC00C05
-:100EA0007F11A8FF28F286DB707893026005541941
-:100EB000EEBC09790A2992A36890082822000988C3
-:100EC0000C65853F29F28564953929161A655563A5
-:100ED0007AE104DBA0600001C0B022161B8DB412C1
-:100EE000EEB10D881482240D0D47A82218EEAF092B
-:100EF000DD10082202929018EEAD12EEAE08C80185
-:100F00000D88020242021DEEAA92910D880298926B
-:100F100022B0232DB02204281006DD100242120850
-:100F2000DD0228B0210722100C88100288020D88EB
-:100F30000212EEA18D3302DD0182340D88029893F6
-:100F400092B992948DB582399D9588B68D389896D0
-:100F500088B792999D989897C0D028F28512EE97FD
-:100F600008480BA2722D24CF28F68522121B655447
-:100F7000DE7AE104DBA0600001C0B064BEFB2CB0EF
-:100F80000728B000DA2006880A28824CC0D10B80DE
-:100F900000DBA065AFE763FEE02EA0032B2067D93E
-:100FA000E0D4E065B1AB8B320BFC5064C4B218EEF8
-:100FB000848F2A08B80108FF0C64F2CDC09260014A
-:100FC0008A2AD003292067D4A06594C98B320BFCF0
-:100FD0005064C48C1FEE7B8E2A0FBF017FE9DC8C2E
-:100FE000330CE8506484B4C0B00CA5118F592B1693
-:100FF000128A578E582A1611DBE0AAFA7FAB01B18C
-:10100000EB75CE599E1F8937951CAF98981D798B2B
-:101010000825160C29EC0129160F9A168A1D851F22
-:101020002A16192A0A007BE30A7BE9052B12067FA0
-:10103000BB01C0A165A4698B35C0A0C08078E30462
-:1010400064E3B5C0A165A458891C2916170C4A543D
-:101050002A1616BCAA2A16186000AF0000008837AE
-:10106000893628161429161508F80C09E90C2916D2
-:1010700013981E78FB07281213B088281613891EB0
-:101080009A189F172A1213C0F02916197BE30C7BBC
-:10109000E9078E172B12087EBB01C0F165F406C06C
-:1010A000B02F121988352E12129819281211AAEE93
-:1010B000AF8F78FB022EEC019F138F199F12C0F0A7
-:1010C0007BE30C7EB9078913281202798B01C0F1EA
-:1010D00065F3D22516172912150C4F54C0E12F16AF
-:1010E00016BCFF2F161800F10400EE1A2F1214B0D0
-:1010F000EE0EF8130988010FEE012F1219A8AAAEFF
-:10110000FE7FEB01B1AAD5A02E16192B1219DA50C9
-:101110002C12185818D3C0D0C0902E121907480AA4
-:101120002C1218DAB08F34C0B1AAFF00C1042A1201
-:10113000162F86162C121700BB1AB0BB0EBE019ECE
-:10114000C90BFB1305BB019BC82A7410292467290E
-:1011500070038E75B19F2F7403B0EE0E4E0C65EDCB
-:10116000182820672D25026583132A221E29221D97
-:101170007A9104DBA0600001C0B064BCFC2CB00715
-:1011800028B000DA2006880A28824CC0D10B8000E3
-:10119000DBA065AFE763FCE189AAB199659094890A
-:1011A000341BEE0899AA88331FEE0208485428A47D
-:1011B0002C8E2A8C320FEE020BCB017EB9640C4BC5
-:1011C000516FB25E8B3375B6592CA0130BEE510ED6
-:1011D000CE010E0E410C0C417EC9472FA012B0FF6C
-:1011E00065F2DD8E378CA88B368FA97CB3077BC95F
-:1011F000027EFB01C0D1CED98835DDB00E8E0878D5
-:10120000EB01B1BD89A7DAC00F9B0879BB022ACCDC
-:1012100001DCB0C0B07DA3077AD9027CEB01C0B17C
-:1012200064B163C091292467C020D10F008BDAB16B
-:10123000BB64B0C02C20672D250265C2281DEDDCE3
-:101240008C321FEDE10DCD010FDD0C65D1C10C4FCE
-:10125000516FF2026001B8C0902924670908476500
-:10126000820F7AE104DBA0600001C0B064BC0A2CEC
-:10127000B00728B000DA2006880A28824CC0D10BBB
-:101280008000DBA065AFE763FBEF8C330CE95064B3
-:1012900092090CEF11AFAF2F16178EF885F7DBE030
-:1012A0008FF9251610A5F57F5B022BEC010CA850D9
-:1012B0006580DD8837DAE0AF8929160A789B022A33
-:1012C000EC019514891AD5A02916192A0A007BE386
-:1012D0000A7BE9052B12047FBB01C0A165A1C18B6C
-:1012E00035C0A0C08078E30464E104C0A164AD5CB3
-:1012F0006001AD00008E3419EDB39EDA8C331BED26
-:10130000AC0C4C542CD42C8A2A8C320BAA0209C95E
-:10131000010A990C659F0B0C4F516EF20263FF029C
-:101320008B330BA850648EFA29D0130BEA510A9A1A
-:10133000010A0A410909410A990C659EE52BD01260
-:10134000B0BB65B188C0A08E378CD82B32062FD2A7
-:10135000097CB3077BC9027EFB01C0A165AEC388CF
-:1013600035D3B0AE8E78EB01B1B389D7DAC0AF9B7D
-:1013700079BB01B1CADCB0C0B073A3077A39027C73
-:10138000EB01C0B165BE9BC090292467C020D10F7E
-:10139000008A3688372A16152816140AEA0C08F827
-:1013A0000C981B78FB01B0AA9F158F1B2F16192FC5
-:1013B0000A007BE30A7BE905281205785B01C0F18E
-:1013C00065F0E2AADE8B352F1219291210C050AF3A
-:1013D0009F79FB01B1EE9F11C0F075E30A7E5905BC
-:1013E00028120178BB01C0F164FCEA6000B700007C
-:1013F0007FB30263FEF663FEF17FB30263FC4563D5
-:10140000FC4000006450A4DA205815C8C020D10F59
-:10141000C09163FE43C09163FA73DA20DB70C0D1E0
-:101420002E0A80C09A2924682C70075814B8D2A0BC
-:10143000D10F000019ED6603480B9810088B0209C4
-:1014400029087983022B8DF829121A63FA8B000080
-:101450002A2C74DB40580E442E221D2A221E63FBC8
-:101460000FC09163FCE5022A0258024C0AA2020650
-:101470000000022A025802490AA202060000DB709C
-:10148000DA20C0D12E0A80C0CE2C24682C700758D8
-:10149000149FC020D10FD9A063FCB600C09463FC98
-:1014A000AAC09663FCA5C09663FCA0002A2C74DB3E
-:1014B00030DC405BFE2EC2D02DA4002B200C63FF3D
-:1014C000458F358EA77FEB0263FEBB63FD548935E4
-:1014D00088D7798B0263FEAE63FD47006C1004C0B1
-:1014E00020D10F006C1004C020D10F006C10042B11
-:1014F000221E28221DC0A0C0942924062A25027B72
-:101500008901DBA0C9B913ED24DA2028B0002CB082
-:101510000703880A28824CC0D10B8000DBA065AF8E
-:10152000E7C020D10F0000006C100602260229201F
-:1015300006C0E0689805289CF96581202A61021799
-:10154000ED170A0A4C65A0F02B729E1AED136FB8C6
-:10155000026000F42AA22668A0098B60D30F0ABBA0
-:101560000C65B0E42A729D64A0DE2B600C0CBC11EB
-:1015700007CC082DC2866FD9026000D71DED090D7A
-:10158000BD0A2DD2A368D0078F600DFF0C65F0C394
-:1015900022C285C0F06420BB1DED0E68434D18EDDE
-:1015A0000D8C6B08CC029C208A6008AA110DAA023F
-:1015B0009A21896A9924883298252C610408CC11D3
-:1015C0009C271CECFE0CBA11A7AA29A285ACBC2F43
-:1015D000C4CF299C2829A685C85A2A6C74DB405898
-:1015E0000DE2D2A0D10FD2E0D10F0000289CF96407
-:1015F00080912C60668931B1CC0C0C472C64666FED
-:10160000C669709E661AECF48C30896B0C8C400BAA
-:10161000CC100C99020A9902992088600888110D53
-:10162000880298218C339C238A329A22896A9924D1
-:101630008834982563FF820000CC57DA60DB30DC09
-:10164000405814A7C020D10F00DA60C0B658153733
-:1016500063FFE500DA6058153563FFDC00DA20DB54
-:1016600030DC40DD505815B7D2A0D10F9E102B6151
-:10167000045813C81DECD78E102B600CC0F02F64DB
-:101680006663FF80296123C08879830263FF752E1A
-:1016900016002C60662B61042CCC010C0C472C64CA
-:1016A000665813BC1DECCB8E102B600CC0F02F6461
-:1016B0006663FF506C1004C0B7C0A116ECC815ECEF
-:1016C000BAD720D840B822C040053502967195702F
-:1016D00002A438040442C94B1AECAD19ECAE29A699
-:1016E0007EC140D30F6D4A0500808800208C220AFD
-:1016F00088A272D10FC05008A53875B0E363FFD738
-:101700006C100893149412292006655270C07168F9
-:1017100098052A9CF965A28016ECA12921028A1459
-:1017200009094C6590C78AA00A6A512AACFD65A0D8
-:10173000BCCC5FDB30DA208C12581469C0519A148B
-:10174000C7BF9BA98E142EE20968E0602F629E1D20
-:10175000EC926FF8026000812DD22668D0052F220E
-:10176000007DF9752C629DC79064C06D9C118A1430
-:101770002B200C2AA0200CBD11A6DD0A4F14BFA8F7
-:1017800009880129D286AF88288C09798B551FECEE
-:10179000840FBF0A2FF2A368F0052822007F894337
-:1017A00029D285D49065907760003D00002B200CF5
-:1017B0001FEC7C0CBD11A6DD29D2860FBF0A6E96E8
-:1017C000102FF2A368F00488207F890529D285654F
-:1017D0009155DA205814D5600013DA20C0B6581499
-:1017E000D3600009C09063FFB9DA205814D089147F
-:1017F000899109FE506551CC8C128D14DA20DBD012
-:101800008DD09E100D6D515813419A1464A1F0C7EC
-:101810005F8FA195A9C0510F0F479F1263FEFB0078
-:10182000C091C0F12820062C2066288CF9A7CC0C8A
-:101830000C472C24666FC6088D148DD170DE01C054
-:1018400090DD90648141C9D28A112B210458135133
-:101850008A14C0B02B24668EA92AA020C1701CEC6B
-:101860005B0E281415EC508E148556AC2C9C132E50
-:10187000EC28A855DDE07CE3022DEDF8D3D00A7703
-:1018800036DA40DB50DC305BFF8BD4A02E200CB46A
-:1018900055290A88C0C01BEC490CEF11A6FF28F29D
-:1018A00085ABEE2CE4CFA98828F685290A80881319
-:1018B000A933DD3089147833022D3DF8289020D3E8
-:1018C000D007880CC170080847289420087736652F
-:1018D0007FAE891413EC438990C0D477973D18EC00
-:1018E00041C1BA2721048514099C4006CC118653B6
-:1018F00004771185520C77020B7702C0C098A09D27
-:10190000A18D2B9CA597A496A795A603DD029DA269
-:101910002BF2852CE4CF2BBC202BF6852A2C748B44
-:1019200012580D11D2A0D10F28203DC0E07C87773E
-:101930002E24670E0A4765A07318EC2B8F201CEC31
-:10194000198E148CC48EE408FF1108FF020E8E1449
-:10195000AECC1EEC269F910ECC029C90C0801EEC5B
-:10196000242C21021AEC162FD285AABAB8FF2FD642
-:10197000850ECC0228A4CF2C2502C020D10F8714BD
-:10198000877007074763FD86282123C099798B025A
-:1019900063FEB2DDF063FEAD00DA20DB308C12DDD9
-:1019A000505814E8D2A0D10FC0E163FF828B148C91
-:1019B00012DD50C0AA2E0A802A2468DA2058135358
-:1019C000D2A0D10F007096552B629E6EB8531DEBBE
-:1019D000F22DD22668D0048E207DE9452A629DCB67
-:1019E000AF2B21042C20665812EBC090292466826C
-:1019F0001418EC008F2108FF019F21C020D10F0097
-:101A00008B10C9B88CA00C6C51CCCC8E241FEBEE83
-:101A10008DE19E140FDD029DE18810658FA9C02025
-:101A2000D10FDA20C0B6581441C020D10F000000F9
-:101A30006C1006C0D02A2102941175A70E89347F3C
-:101A400097098B357FBF042D2502DAD00A0C4C652F
-:101A5000C17B16EBD21FEBD028629EC0EA78E3026E
-:101A600060018129F2266890078A2009AA0C65A1E5
-:101A7000732A629DDEA064A1702B200CC0700CBC88
-:101A80001106CC0829C286280A0C79830260014C11
-:101A900019EBC409B90A2992A3689007882009881C
-:101AA0000C65813824C2851CEBC664412F8931093D
-:101AB0008B140CBB016FB11D2C20669E10B1CC0C99
-:101AC0000C472C24666EC60260013409FE5065E1A5
-:101AD0002E8A102AAC188934C0E47F973617EBC7DA
-:101AE000C0821BEBC58C359E419B408B2098459D49
-:101AF0004418EBC307BB029B420C07400F771198B9
-:101B0000439747D7E07FC70B2C2102284A0008CC17
-:101B1000022C25027E97048B362B25227D97048C80
-:101B2000372C25217C973A0AAB022C0A01C0800A87
-:101B3000C8382A3C200808426480821CEB9419EBC8
-:101B40009529C67E00A08800B08C00A08800B08CCB
-:101B500000A08800B08C28629D2DF4A2288C182843
-:101B6000669D89307797351FEB9F8C338832047BD5
-:101B70000B2A2104B47704AA119EB19FB08F2B9D2C
-:101B8000B598B69CB718EB96099C4006CC110CAAE8
-:101B90000208FF029FB2C1CC0CAA029AB4C9772AEC
-:101BA000200C1BEB860CA911A699289285ABAA2DB7
-:101BB000A4CF08780B289685CF58C020D10FC087B6
-:101BC000C0900AC93879880263FF7863FF6CCC57EC
-:101BD000DA20DB308C11581342C020D10FDA2058A4
-:101BE00013D363FFE8C0A063FE89DA20C0B65813A0
-:101BF000CF63FFD92A2C748B11580C5BD2A0D10F64
-:101C00008A102B21045812631FEB64C0D02D246668
-:101C100063FEBD006C1006D62019EB5F1EEB612839
-:101C2000610217EB5E08084C65805F8A300A6A51D2
-:101C300069A3572B729E6EB83F2A922668A0048C27
-:101C4000607AC9342A729D2C4CFECAAB2B600CB64C
-:101C50004F0CBD11A7DD28D2860EBE0A78FB269C4C
-:101C6000112EE2A32C160068E0052F62007EF91504
-:101C700022D285CF2560000D00DA60C0B65813ABC4
-:101C8000C85A60010F00DA605813A8655106DC409D
-:101C9000DB308D30DA600D6D5158121CD3A064A07A
-:101CA000F384A1C05104044763FF6D00C0B02C60F1
-:101CB000668931B1CC0C0C472C64666FC6027096F5
-:101CC0000A2B6104581233C0B02B64666550B42AE5
-:101CD0003C10C0E7DC20C0D1C0F002DF380F0F425B
-:101CE00064F09019EB2A18EB2B28967E8D106DDA94
-:101CF0000500A08800C08CC0A089301DEB3A779702
-:101D00005388328C108F3302CE0BC02492E12261B3
-:101D1000049DE00422118D6B9BE59FE798E61FEB85
-:101D2000300998400688110822020FDD02C18D9DFE
-:101D3000E208220292E4B4C22E600C1FEB200CE8F1
-:101D400011A7882C8285AFEE0C220B2BE4CF2286C4
-:101D500085D2A0D10F28600CD2A08C1119EB180CE1
-:101D60008D11A7DD2ED285A9882B84CF0ECC0B2C0C
-:101D7000D685D10FC0F00ADF387FE80263FF6C63BD
-:101D8000FF6000002A6C74C0B2DC20DD40581211E4
-:101D9000C0B063FF63C020D10F0000006C10042CA2
-:101DA000221D2A221EC049D320293006243468C0AF
-:101DB000407AC105DDA060000200C0D06E9738C037
-:101DC0008F2E0A802B3014C0962934060EBB022EAB
-:101DD00031022B34147E8004243502DE407AC10E99
-:101DE000C8ABDBD0DA302C0A00580A792E31020E4B
-:101DF0000F4CC8FEC020D10F6895F82831020808A2
-:101E00004C658FEF1AEAE61CEAE42BA29EC09A7B8F
-:101E10009B462BC22668B0048D307BD93B29A29DFE
-:101E2000C0E3CB9394901BEAF72D31049B9608DD19
-:101E3000110EDD029D979D9124C4A212EAF32F3169
-:101E40000228A29DC0E52E3406288C3028A69D02CB
-:101E5000FF022F3502C020D10FDA30C0B65813333D
-:101E6000C020D10F6C10062A2006941168A80528FE
-:101E7000ACF965824F29210209094C659206CC5FB5
-:101E8000DB30DA208C11581296C051D3A0C7AF9A1C
-:101E90003AC0E019EAC31DEAC91AEAC28F3A16EA43
-:101EA000BFB1FB64B1352C629E6FC8026001E927A7
-:101EB000DC33277226687007882007880C6581D874
-:101EC00024629DC0766441D02B200C0CBC11A6CCA2
-:101ED00028C286C09E7893026001C819EAB109B988
-:101EE0000A2992A39410689007882009880C6581BC
-:101EF000B224C2856441AC292006299CF96491DF93
-:101F00002C20668931B1CC0C0C472C24666EC6029D
-:101F100060019809F8506581921AEAA38C3619EA93
-:101F2000A10C881489940C0C4709CC10A8990A9923
-:101F30000218EAB62A210499409841882A19EAB47D
-:101F40000C8802098802984228302C2C3013293042
-:101F50001204CC100699100C88109F4408A8020C9B
-:101F6000990209880298438F379F458C389C46898F
-:101F700039C0F1994719EAA788359F4B98480888D6
-:101F800014098802984A8F3018EA9777F732C0749C
-:101F900089328C33984C974D0F9740882B2E4611E1
-:101FA0000677112C461329461204AC1119EA8D0745
-:101FB000CC02C179098802984E07CC022C4610C089
-:101FC0007AADBC0CBA11A6AA29A2852EC4CF097974
-:101FD0000B29A6856550FCC020D10F002B200C0CCE
-:101FE000BC1106CC082FC28609B90A6FF90260013C
-:101FF0001E2992A36890082F220009FF0C65F10F9B
-:102000002FC28564F10928203D082840648084841B
-:102010003504841464407C85A57453778436048425
-:102020001464406F74536C293013C08C798864C079
-:10203000902924670908476580DD882089A48435B4
-:102040001AEA6B048414A4940A440294F014EA6615
-:1020500008881104880298F1843698F3048414A443
-:10206000990A990299F21AEA6229210224C285ADDD
-:10207000B82E84CF244C1024C6850A990229250243
-:10208000C020D10F00CC57DA20DB308C115812144D
-:10209000C020D10FC09163FF97DA20C0B65812A3B9
-:1020A00063FFE100DA205812A163FFD88A102B21C8
-:1020B000045811381DEA422B200CC0E02E24668FF4
-:1020C0003A63FE5400DA20DB30DC40DD5058131D4B
-:1020D000D2A0D10F2A2C748B11580B23D2A0D10F70
-:1020E000292123C08879830263FE2D2A12002C2027
-:1020F000662B21042CCC010C0C472C24665811258E
-:102100001DEA2F2B200CC0E02E24668F3A63FE08B8
-:10211000DA2058128663FF6CDA205BFF20D2A0D150
-:102120000F0000006C100A9516C061C1B0D9402A9A
-:10213000203DC0400BAA010A64382A200629160750
-:1021400068A8052CACF965C33B1DEA16C8442F12DC
-:102150000664F29B2621021EEA12961406064C65BE
-:1021600062DE15EA0E6440CF8A352930039A150ADB
-:10217000990C6490C22C200C8B159C120CCC11A5D0
-:10218000CC9C132CC286B4BB7CB3026002CE8F12EF
-:102190000EFE0A2EE2A368E0082622000E660C65F9
-:1021A00062BA88132882856482B2891564905EDAE7
-:1021B00080D9308C201EEA0C1FEA0D1DE9FA8B1520
-:1021C0008DD4D4B07FB718B88A293C10853608C69C
-:1021D000110E66029681058514A5D50F55029580CE
-:1021E0000418146D8927889608CB110888140EBB33
-:1021F00002A8D8299C200F88029BA198A088929BB6
-:10220000A3088814A8D80F880298A22AAC10C0D0BE
-:102210008A151FE9EA8E1219E9F68B1388142CB27D
-:1022200085098802AFEE0CAA0B2DE4CF2AB68528CB
-:102230002502C020D10F000026529E18E9D76F68F2
-:102240000260020D2882266880098920D30F089930
-:102250000C6591FD2A529DC0FD9A1164A1F32B20BB
-:102260000CC1CA0CB8110588082D82860EBE0A7DE5
-:10227000C30260020A2EE2A368E0082622000E666E
-:102280000C6561FB288285DE806482072920069820
-:1022900010299CF96492042C20668831B1CC0C0C76
-:1022A000472C24666EC6026001BD08FD5065D1B79B
-:1022B00017E9DA1CE9BD19E9C42A21048B2D28305D
-:1022C000102D211D0C88100BDB090A8802098802D9
-:1022D0000CBB0264415589109B909791989284356C
-:1022E000D9E064406FD730DB40D8307F4715273CBA
-:1022F00010BCE92632168C3996E69CE78A37283CD2
-:10230000042AE6080B131464304A2A821686799A46
-:102310009696978C778A7D9C982B82172C7C209A96
-:102320009A2A9C189B99867BB03B298C086DB92111
-:102330008BC996A52692162AAC18B8999BA196A08F
-:102340008BC786CD9BA22B921596A49BA386CB2CE4
-:10235000CC2026A605C0346B4420043B0C0448095D
-:102360000E880A7FB705C0909988BC88C0900B1A68
-:10237000126DAA069988998B288C181CE9A81BE96C
-:10238000A816E99DB1DD2A211C23E6130D0D4F2669
-:10239000E6122D251DC06087207DA907C0D0280A20
-:1023A0000028251D26E6172CE6162BE61505D81164
-:1023B0001AE99328E6180A7A022AE614292006293F
-:1023C0009CF96491062A200CC0901BE97C0CAD118D
-:1023D000A5DD2CD285ABAAC0B029A4CF0CFC0B2C58
-:1023E000D685DA208C172D120658110DD2A0D10FE8
-:1023F0008A356FA546D8308BD56DA90C8A860A8A96
-:1024000014CBA77AB335288C10C080282467080B1A
-:102410004765B11CDA20DB308C17581131D3A0C0CE
-:10242000C1C0D02DA4039C1663FD280086366461CC
-:102430001689109B909791989263FEA1C08163FFCB
-:10244000C98A16CCA7DA20DB308C17581125C0209A
-:10245000D10FDA20C0B65811B563FFE400DA208B43
-:10246000125811B263FFD9009F189E198A112B21AF
-:10247000045810488E198F18C0B02B246663FE2FA5
-:10248000C08063FE01DA20DB308C17DD5058122D3E
-:10249000D2A0D10FDA205811A563FFA42D2123C0AB
-:1024A000C87DC30263FE089F188A112B21042C20CB
-:1024B000669819B1CC0C0C472C24665810368E192E
-:1024C0008F18C0D02D246663FDE50000262123B0BF
-:1024D0006606064F262523656EEA28206A7F870553
-:1024E0000829416490FDC0D01BE93F19E94E262020
-:1024F0000723E61BB166097A022BE61A28200A2D6B
-:10250000E61D2AE61E09880228E61C8826060647DC
-:1025100028E6208B2826E53E2BE6212D24072C20BB
-:10252000062A20642CCCFD64C09DB4FF63FE950098
-:1025300000DB30DA208D16C0CE2E0A802C24688C69
-:1025400017581072D2A0D10F8E102632161FE9151F
-:102550000626148FF62BE61297E127E61328E614D9
-:10256000A6FF0CFF029FE0C1F62EEC4826ECC064EB
-:102570006D6B8435C080644DDBD9E0DC30DBE0DDA1
-:1025800030B18814E92986C98AC8279DFF2CCC1050
-:10259000299C102A76322A76300464011AE9242410
-:1025A0007631AA442476332AD21617E9219AB6073F
-:1025B000660196B784C3BCBB94B58435B4DD74831F
-:1025C000BF2D211D63FD8D0064AF5E1DE8F62C203C
-:1025D000168DD20ACC0C00D10400CC1AACBC9C29BC
-:1025E00063FF46002B21046EB8222C2066B8CC0C69
-:1025F0000C472C2466C9C49F189E198A11580FE5F0
-:102600008E198F18C0348720C0D02D2466C068264C
-:10261000240663FED00000006C1008292006289CC8
-:10262000F86582C3292102C0AA09094C6590E62BEE
-:10263000200C16E8DA0CBC11A6CC2EC286C1D27EC4
-:10264000D30260028E19E8D609B90A2992A32A1684
-:10265000026890078A2009AA0C65A27729C28564BE
-:1026600092712B629E1AE8CC6FB80260026E2AA2A9
-:102670002629160168A0082B22000ABB0C65B25C53
-:1026800029629DC18C6492542A21200A806099108D
-:102690002C203CC7EF000F3E010B3EB1BD0FDB39D4
-:1026A0000BBB098F260DBD112DDC1C0D0D410EDD60
-:1026B000038E27B1DD0D0D410FEE0C0DBB0B2BBCB6
-:1026C0001C0BB7027EC71C2C21257BCB162D1AFCB8
-:1026D0000CBA0C0DA16000093E01073EB1780987D4
-:1026E000390B770A77EB026002062B212328212180
-:1026F000B1BB0B0B4F2B25237B8B29B0BD2D252385
-:10270000C855DA20DB30580FF0292102CC96C0E8FA
-:102710000E9E022E2502CC57DA20DB30DC4058100A
-:1027200070C020D10F2C20668931B1CC0C0C472C05
-:1027300024666EC6026001CF09FD5065D1C92F0A1B
-:10274000012830112922146480112A221B090C440B
-:1027500000C10400FB1A0BAA022A261B2D3010C050
-:10276000A0C0E088301BE88F94139514240A01253B
-:10277000203C2BB022088C14778704C0F10BFA3868
-:10278000C0F2C0840858010F5F010F4E3805354074
-:1027900007EE10C0F0084F3808FF100FEE0228DCDB
-:1027A000FEC0F0084F38842B0BA8100AFF102A2116
-:1027B000200F88020E880208440218E89E8F110834
-:1027C00044022821250A2A140828140488110A889A
-:1027D000022A210494F08E2004D41008EE1104EE95
-:1027E00002C04A04EE029EF1842A08AE110EDE02F7
-:1027F00094F40A54110E44020555100C1E4094F72F
-:1028000007EE100E5502085502C08195F68433C0BC
-:102810005094F3B1948E3295F898F99EF2C080C12D
-:10282000EC24261498FB9EF599FA853895FC843A99
-:1028300094FD8E3B9EFE883998FF853525F61084E1
-:1028400036851424F6118E3784132EF612C0E064F8
-:10285000B04989307797442B301088338C111FE8AA
-:10286000618D322FC614C0F42FC6158F2B2EC619BA
-:102870002DC61A28C61B04AD1109984006881108F8
-:10288000DD020DBB0218E856C1D00DBB0208FF02E5
-:102890002FC6162BC618280A0E2816022B200C88C5
-:1028A000121CE8460CB911A6992A9285ACBB2EB42D
-:1028B000CF0A880B289685C9718B268A2907BB0801
-:1028C0002B26060BAA0C0A0A482A2525655048C063
-:1028D00020D10F00DA2058109563FE3900DA20C0AD
-:1028E000B658109263FE2E00689738C020D10F00B2
-:1028F00000DA20DB7058104FC0C0C0D10ADA390AA4
-:10290000DC3865CDE463FE0D8A102B2104580F21BD
-:10291000C0E02E246663FE25DB402A2C7458091281
-:10292000D2A0D10FDA20580F2663FCF76C1004C038
-:1029300020D10F006C1004270A801CE83F1DE83FDF
-:102940001AE8170C2911AA992A2CFC2B92850DAA9A
-:10295000029CB19AB0C05113E83C28928516E83821
-:1029600014E839A62604240AB888289685234691B7
-:10297000A76625649FD10F006C100AD6302830104E
-:10298000292006288CF964829768980B2A9CF9659F
-:10299000A1B2022A02580F0A89371BE802C89164C3
-:1029A000520E2A21020A0C4C65C2558D3019E7FBE4
-:1029B00074D7052E212365E29A2F929E1AE7F76FAE
-:1029C000F8026002502AA22668A0082C22000ACC35
-:1029D0000C65C2412A929D64A23B9A151FE7F18DB6
-:1029E00067C1E6C8DD2B620618E7EF64B0052880F2
-:1029F000217B8B432B200C18E7E90CBC11A8CC29B8
-:102A0000C28679EB460FBE0A2EE2A368E0052F22AC
-:102A1000007EF9372CC2859C1864C22F2B212F878A
-:102A2000660B7B360B790C6F9D266ED2462C203DB3
-:102A30007BC740CE5560001E2A200CC1B28C2058A6
-:102A4000106F9A1864A2418D6763FFCFC0C063FF07
-:102A5000C5D7B063FFD300C0E06000022E60030E54
-:102A6000DB0C6EB20EDC700CEA11AA6A2AAC20589C
-:102A70000198D7A0DA20DB70C1C82D21205810158D
-:102A80008C268B279A160CBB0C7AB3348F1889636B
-:102A900099F3886298F28E659EF82D60108A189DD1
-:102AA0001768D729C0D09DA92C22182B22139CABC4
-:102AB0009BAA97A58E667E7302600097CF58600030
-:102AC0001FDA208B16580FDB65A13563FFBDC0816F
-:102AD000C0908F18C0A29AF999FB98FA97F563FFF6
-:102AE000D2DB30DA20DC40580F7EC051D6A0C0C007
-:102AF0002BA0102CA4039B172C1208022A02066B91
-:102B000002DF702D60038E179D149E100CDD11C026
-:102B1000E0AD6D2DDC205801178C148B16ACAC2C5D
-:102B200064038A268929ABAA0A990C9A2688660921
-:102B3000094829252507880C98662F2218A7FF2FFA
-:102B4000261863FE96DA20DB30DC40DD5058107D1D
-:102B5000D2A0D10FC0302C20668961B1CC0C0C47BB
-:102B60002C24666EC6026000CEC03009FD5065D0D0
-:102B7000C68E6764E069647066DB608C18DF70DAAB
-:102B8000202D60038E170CDD119E10AD6D2DDC2005
-:102B90001EE7A75800F8232618DA208B16DC402FF2
-:102BA0002213DD50B1FF2F2613580F1DD2A0D10FD5
-:102BB0000028203D084840658DE76F953EDA308D4E
-:102BC000B56D990C8CA80C8C14CACF7CD32D2AAC73
-:102BD00010C090292467090D4764DDC560008E0090
-:102BE0002C1208066B022D6C20077F028E17DA204C
-:102BF0009E101EE78E58007C63FF9A00C09163FF11
-:102C0000D1655080DA20DB60DC40580F35C020C031
-:102C1000F02FA403D10FDA20C0B6580FC463FFE031
-:102C2000006F950263FD70DA20DB30DC40DD50C4BC
-:102C3000E0580EB6D2A0D10F8A152B2104580E559C
-:102C4000232466286010981763FF2500DA20580FA8
-:102C5000B763FFACC858DB30DA20580E9B2A21023C
-:102C600065AF9DC09409A90229250263FF92DB305C
-:102C7000DC40DD50C0A32E0A802A2468DA20580EDA
-:102C8000A3D2A0D10FC020D10FDA202B200C580FD7
-:102C9000C063FF6C6C1004282006C062288CF865A5
-:102CA0008125C050C7DF2B221BC0E12A206B2921C0
-:102CB0002300A104B099292523B1AA00EC1A0BC462
-:102CC000010A0A442A246B04E4390DCC030CBB012D
-:102CD0002B261B64406929200C1BE7300C9A110B32
-:102CE000AA082FA2861BE72E6FF9026000B60B9B85
-:102CF0000A2BB2A368B0082C22000BCC0C65C0A430
-:102D00002BA2851CE75264B09B882B2F21040C88D2
-:102D10000298B08420C08508441108440294B1840C
-:102D20002A08FF1194B48E349FB79EB5C0401DE7AA
-:102D3000232EA2850D9D082EEC282EA68525D4CF06
-:102D400029210209094C68941A689820C9402A214F
-:102D50000265A00B2A221E2B221D7AB10265A079E2
-:102D6000C020D10F2C212365CFDE6000082E212149
-:102D70002D21237EDBD52B221E2F221D2525027B14
-:102D8000F901C0B064BFC413E7042CB00728B00039
-:102D9000DA2003880A28824CC0D10B8000DBA065B2
-:102DA000AFE763FFA62A2C74C0B02C0A02580D8D21
-:102DB0001CE7289CA08B2008BB1106BB029BA189A5
-:102DC0003499A263FF790000262468DA20DB30DC26
-:102DD00040DD50580FDCD2A0D10FDA202B200C5848
-:102DE0000F53C020D10F00006C1006073D14C080A7
-:102DF000DC30DB40DA20C047C02123BC3003283858
-:102E00000808427740022DDC016481571EE6E01974
-:102E1000E6E129E67E6DDA0500508800308CC0E0DE
-:102E2000C02025A03C14E6DFB6D38FC0C0D00F87EA
-:102E3000142440220F8940941077F704C081048243
-:102E400038C0F10B2810C044C02204540104FD38DE
-:102E500002520102FE3808DD10821C07EE100E6ED1
-:102E6000020EDD02242CFEC0E004FE380AEE100E35
-:102E700088020D88028DAB1EE6CF08D8020E8802AC
-:102E800098B0C0E80428100E5E0184A025A1250892
-:102E90004411084402052514045511043402C0816C
-:102EA0000E8E3994B18FAA84109FB475660A26A13C
-:102EB0001FC0F206261460000726A120C0F20626D5
-:102EC000140565020F770107873905E610077810AA
-:102ED00008660206550295B625A1040AE6110858AF
-:102EE0001108280208660296B7C0606440566490D4
-:102EF00053067E11C0F489C288C30B340B964598E3
-:102F000047994618E6B79F410459110E99021FE6EA
-:102F1000B5020E4708D8029F4098420E9902B43875
-:102F2000C1E00E990299442FA00C0CF91114E6A3EC
-:102F30001EE69BA4FFAE992E928526F4CF0E880B39
-:102F4000289685D10F2BA00C0CBE111CE69C1FE609
-:102F500093ACBBAFEE2DE28526B4CF0D3D0B2DE635
-:102F600085D10F00C08005283878480263FEA5632C
-:102F7000FE9900006C1006C0B0C0A6C0C06570F01D
-:102F80008830C0300887140888406580D3C0E0C00E
-:102F900091C0D4C08225203C0B3F109712831CC0E7
-:102FA000700858010D5D01089738C0800B983807EC
-:102FB0007710048810086802087702C0800D9838DE
-:102FC0002D3CFE0888100D9E388D2B0AEE1008EE61
-:102FD0000207EE020CB8100FDD02053B400EDD02C9
-:102FE0009D408920043D100899110D99022D21045E
-:102FF00009A90208DD119941872A05B9100D3D0282
-:103000000ABB110DBB0208770297442821258712BD
-:10301000082814048811071E4007EE100E99027547
-:10302000660926211F0626146000060026212006B8
-:1030300026140868029B47098802984629200CD26A
-:10304000C0C0800C9E111BE65D1FE654AB99AFEE2D
-:103050002DE2852894CF0DAD0B2DE685D10F000014
-:10306000001FE6502FF022C03065FF20C03163FF03
-:103070001BDD408E51CAE00E7836981008770CB2EE
-:10308000AAB1BB8F502DDC1098D99FD889538F528D
-:10309000991199DB9FDA7E830AB1CC255C10C9783F
-:1030A00063FFCF0088108D1108E70C9751AD8DD7C5
-:1030B000F078DB01B1F79D5397528830C030088714
-:1030C00014088840648EC565BFA163FF93000000AB
-:1030D0006C1004D720B03A8820C0308221CAA17475
-:1030E0002B1F2972046D080FC981C9928575B133F0
-:1030F000A2527A3B0C742B0963FFE90000649FEB3A
-:10310000D10FD240D10F00006C1008D630C070959E
-:1031100015DA408E3914E6239A1464E0026451F8FB
-:103120002920062A9CF865A25B2A21020A0B4C651D
-:10313000B21B2C320015E61974C7052D212365D367
-:10314000202E529E1AE6156FE8026002172AA22668
-:1031500068A0082B22000ABB0C65B2082E529D1DE8
-:10316000E61064E1FF8B3864B2299E16C8BC8D69F5
-:103170001EE60D64D0052EE0217BEB492E200C18B5
-:10318000E6070CEF11A8FF29F286C186798B4A1752
-:10319000E60407E70A2772A3687004882077893954
-:1031A00025F28564529E27212E07B73607B90C6F8A
-:1031B0009D01D7B089696E924228203D7B873C8A69
-:1031C00015CDAF600018C1B28C202A200C580E8B90
-:1031D000D5A064A2A88B6863FFCBC05063FFC3C0B7
-:1031E000E06000022E60030E9B0C6EB20EDC700CD1
-:1031F000EA11AA6A2AAC285BFFB6D7A0DA20DB70F6
-:10320000C1C42D211F580E338C268B27D4A00CBB94
-:103210000C7AB3258A63C0909A5388629958985261
-:103220008F659F598E679E5B8D6697559D5A8B68FB
-:103230007B7B748B15CEB360000DDA20DB40580D1C
-:10324000FD65A10963FFCC00DA20DB308C14580D3A
-:10325000A4D6A0C0C0C0D19D152CA403DA20DB6089
-:10326000DF70DC50C0E02560039E101EE5E60C5DBB
-:1032700011AD6D2DDC285BFF3F8E66A5A88F6728FA
-:103280006403AF7F77FB01B1EE9E669F678D268C4E
-:1032900029A4DD0DCC0C9D268B680C0C482C252513
-:1032A00007BB0C9B6863FEC32C20668961B1CC0C04
-:1032B0000C472C24666EC6026000B409FD5065D030
-:1032C000AECBBB8E69CBE7DB60DC50DF70DA201E53
-:1032D000E5E12D6003C08098100CDD11AD6D2DDC93
-:1032E000285BFF248B15C84F8A268929A4AA9A2611
-:1032F0000A990C09094829252565B13BC020D10F41
-:10330000DB602D6C28DF70DA20C0C01EE5D29C1077
-:10331000DC505BFEB563FFCB002D203D0D4D4065BD
-:10332000DDFD6FE522DA308F456DE90C8EAA0E8E39
-:1033300014C9E37EF3112AAC10C090292467090F49
-:103340004764FDDB60014100C09163FFED0088151B
-:1033500065814CDA20DB608C14580D61C020C09070
-:1033600029A403D10FDA20C0B6580DF063FFDE00A8
-:103370008A162B2104580C87C0A02A24668B686308
-:10338000FF3E0000002B9CF965B0C5DA20580C8C7C
-:1033900063FD95002B200C0CBA11A5AA2FA286C1A3
-:1033A000C27FC3026000FC0DB90A2992A36890078E
-:1033B0008C2009CC0C65C0EB26A2856460E52C202E
-:1033C000668931B1CC0C0C472C24666FC60270960E
-:1033D0000ADAE02B2104580C6F272466893077978E
-:1033E0004B18E57F1DE5808A328B33C0F42C210415
-:1033F000099E4006EE1104CC110ECC029F61C1E083
-:103400000ECC029D608F2B9A669B679C6497650823
-:10341000FF029F622F200C18E5690CFE11A5EE2D0E
-:10342000E285A8FF27F4CF2DDC202DE6858F1565DA
-:10343000F091C020D10F00002A2C748B1458064A3A
-:10344000D2A0D10F00DA20DBE0580DB863FEFE00F9
-:1034500000DA20DB308C148D15580E3AD2A0D10F33
-:1034600000008815C888DA20DB30580C972A210222
-:1034700065AEDAC09409A90229250263FECFDA20DD
-:103480002B200C580DC363FEC4272468DA20DB30E0
-:103490002C12042D12052E0A80580C9C63FC80000F
-:1034A000C020D10FDA20580DA18A15CDA1DA200352
-:1034B0003B022C1204580D0A27A403C020D10F0090
-:1034C000C020D10F2A2C748B14580627D2A0D10FFC
-:1034D0006C100E282102941008084C65835E1FE5CD
-:1034E0002F29F29E6F98026003621DE52B29D226D8
-:1034F0006890082A220009AA0C65A3502CF29D644A
-:10350000C34A2B200C0CB611AF66286286C1EC783A
-:10351000E30260034219E52209B90A2992A36890DF
-:10352000078A2009AA0C65A32E246285644328C05B
-:10353000E12A3109C07027246689359A12992A88B0
-:10354000369913982B89379814992C88389915082F
-:1035500058149816982D89392A25042E251D2925B9
-:103560001C283028C09228243C2A30290808479873
-:10357000170989012A243D2A311599180A09410998
-:10358000A90C299CEC29251F7E87192D2A000DA046
-:103590006000083E010A3EB1AD08DA390EAA110AF0
-:1035A000990C29251F27211F18E52C078160010888
-:1035B0003E000D3EB18A0DA8392D9CFC2D2520C161
-:1035C0009009883608DD1C08771C893D8A3C2E2628
-:1035D000132E26142E26152E246B2925222A25216A
-:1035E000282014C0A027252E2D252F0808432D2183
-:1035F0001C282414C07027252427252527252C279F
-:10360000261827261B2724672724682932112725F7
-:103610002399196ED2156D080AB1AA00A10400E918
-:103620001A7D9B0563FFEE00000089191DE4FDC0B3
-:10363000E0C0729B1D8813951B9F1F9C1E961C1C2F
-:10364000E50826203DC0F006054008DB14076601AA
-:103650000D8810C071057E38067F3885120BFF106B
-:1036600016E4E60AEE1096400FEE020D5511B0AFCB
-:1036700009FF110FEE021FE4F90855020FEE02C018
-:10368000F49F418A209F4996489C4B9B4E9D439EA8
-:10369000468D161EE4DA8B15C7CF9C4D9C4C9C457D
-:1036A0009C440BD8140EAE020DBB109E4A9E4208DD
-:1036B0005502954F0D181415E4CD0D88110588029B
-:1036C000984718E4E885262E46122E461A2E4622E2
-:1036D0002646102646182646202F46112F46192F1B
-:1036E00046212846242846262C46142C461595119A
-:1036F0008C1718E4DD0505488F1805551109064893
-:1037000028461389140E66110655020F7F390C3EA8
-:103710004002EE1017E4D60D99110C26400F6611E9
-:103720000B99020C0C408B1D01CC1006FF022746A2
-:103730001B294616C07029311616E4CD0ECC0205A1
-:10374000FF021EE49C15E4CB2F461726461CC0F052
-:10375000861C2F461D2F461F2F46272546230ECC9D
-:1037600002851B2C461E1EE4C41CE48E8F1F8CC7D2
-:103770002E4625ADCC28200629246A2431179C2DFD
-:103780002425238C1ECC81272407C0D77F97188E31
-:10379000110928419E2964808E644098C098094987
-:1037A000362D240660000B00644075C09809493628
-:1037B0002D240601C4042D0AA02E210428628508A8
-:1037C000EE11AD88286685863F843E2D321006486E
-:1037D0001898C300C40406461818E47804C45300BB
-:1037E000661106DD02A8B82784CF9DC409064E964F
-:1037F000C51DE4A305A61106440216E4A09DC0065B
-:10380000440294C2C04304EE029EC114E46326F253
-:103810009D2744A2266C1826F69D655042C020D1F3
-:103820000FC09063FF890000654F70C098C0E82EFC
-:10383000240663FF7D2D2406C09063FF75CC57DA04
-:1038400020DB308C10580C26C020D10F00DA20C0AD
-:10385000B6580CB663FFE500DA20580CB463FFDC01
-:103860002A2C748B10580540D2A0D10F6C1006285A
-:1038700020068A336F8202600161C05013E4472939
-:10388000210216E446699204252502D9502C201500
-:103890009A2814E4448F2627200B0AFE0C0477098B
-:1038A0002B711C64E1398E428D436FBC0260016F45
-:1038B00000E104B0C800881A08A80808D8029827B0
-:1038C0002B200668B32ECE972B221E2C221D011111
-:1038D000027BC901C0B064B0172CB00728B000DA71
-:1038E0002003880A28824CC0D10B8000DBA065AF82
-:1038F000E7C020D10F2D206464DFCA8B29C0F10BF3
-:10390000AB0C66BFC02B200C0CBC11A6CC28C28609
-:103910002E0A0878EB611EE4220EBE0A2EE2A3688E
-:10392000E0052822007E894F29C2851EE42E64907E
-:10393000461FE43C9E90C084989128200A95930FDE
-:10394000880298928E200FEE029E942F20078826E0
-:103950002F950A98969A972E200625240768E34308
-:103960002921021AE4162DC285AABA2DDC202DC603
-:103970008525A4CF63FF4E002B2065CBBDC0C22C94
-:103980002465C9F605E4310002002E62821FE41EA0
-:103990002D41020FEE022E66820DE43129210263D1
-:1039A000FF23000064DFB889422820160091040D2F
-:1039B000880C00881AA8A8982963FFA38C202D32B0
-:1039C00021B1CC9CD02B32212A3223B4BB2B3621FF
-:1039D0007BA9A92D32222D362163FFA0C020D10F53
-:1039E0009F27252415ACB828751C2B2006C0C12E96
-:1039F000BCFE64E0AB68B7772DBCFD65DEC72D204B
-:103A000064C0F064D0868E290EAE0C66E089C0F1E9
-:103A100028205A288CFE08CF3865FEE863FF58003E
-:103A200000E0049310C0810AF30C038339C78F08A8
-:103A3000D80308A80108F80C080819A83303C80C13
-:103A4000A8B828751C030B472B24158310CBB7008F
-:103A5000E104B0BC00CC1AACAC0CDC029C27659E27
-:103A60005EC0B20B990209094F29250263FE50007E
-:103A70002D206A0D2D4165DF7EDA20C0B0580C7212
-:103A800064AF18C0F163FEEF9F2763FFD02E221FA3
-:103A900065EE3263FF79000028221F658E2763FFE1
-:103AA0006E252406252502C09063FE196C1006655C
-:103AB00071332B4C18C0C7293C18C0A1C08009A87D
-:103AC000380808426481101CE3B11AE3B22AC67EAA
-:103AD0002A5CFDD30F6DAA0500B08800908C884049
-:103AE000C0A00889471FE3DB090B47084C50080DAD
-:103AF0005304DD10B4CC04CC100D5D029D310CBB21
-:103B0000029B3088438E2098350FEE029E328D2620
-:103B1000D850A6DD9D268E40C0900E5E5064E09782
-:103B20001CE3C11EE3B0038B0BC0F49FB19EB02D0C
-:103B3000200A99B30CDD029DB28F200CFF029FB4C6
-:103B40008E262D20079EB68C282DB50A9CB72924D9
-:103B5000072F20062B206469F339CBB61DE392238F
-:103B600020168DD20B330C00D10400331AA3C3B43A
-:103B70008D932922200C13E3911FE3880C2E11AFA3
-:103B8000EEA3222924CF2FE285D2A00FDD0B2DE654
-:103B900085D10F00B48C2E200C0CEB111FE3881D77
-:103BA000E37FAFEEADBB22B28529E4CF02C20B2288
-:103BB000B685D2A0D10F00002E200C0CEB111FE314
-:103BC0007F1CE376AFEEACBB22B28529E4CF028244
-:103BD0000B22B685D2A0D10FC0D00BAD387DC80264
-:103BE00063FEEC63FEE08E40272C747BEE12DA70ED
-:103BF000C0B32C3C18DD50580A77C090884063FE53
-:103C0000E3066E02022A02033B02DC40DD5058004C
-:103C1000049A10DB50DA70580454881063FEF600E2
-:103C20006C10082E3C18C0A092161FE3688C40AFA1
-:103C30002F0C8C47C02304CB0BDDB07FB3022DBD0E
-:103C4000F8D9D0C0B075C30260008D9F146D084FC5
-:103C50008D900D6D36ADAA0D660C0EB70B0EBF0A1A
-:103C60009DF0B877B89FD8F000808800708C9711CD
-:103C700087909810971568B12AB22277D32D889132
-:103C8000C0D0CB8F9890279C10007088971200F0BE
-:103C90008C9F139D916460A0C08108BB0375CB38D5
-:103CA00063FFA900B1222EEC1863FFCE85920D7739
-:103CB0000C86939790A6D67D6B01B15595929693FD
-:103CC0008942600017B3CC299C188814DD90789342
-:103CD000022D9DF8D9D063FFBB8942DA9085160C7E
-:103CE0000D472D44021BE36792319B3086437A9146
-:103CF000261BE3581EE36589500E660196350B9925
-:103D000002993288420A880C98428756A7A797568C
-:103D10008F44AFAF9F44D10F1BE34F895096350BB3
-:103D20009902993288420A880C98428756A7A79729
-:103D3000568F44AFAF9F44D10F894263FF9E00006E
-:103D40006C10061FE3529310D6308830C091086380
-:103D5000510808470598389811282102293CFD0888
-:103D6000084C6581576591542A62030A2B5065B14E
-:103D70007E0A68142E0AFF7CA60A2C205ACCC42D79
-:103D80000A022D245A78E0026002088A288926183F
-:103D9000E3400A990C6592032E200B1CE33F08EECA
-:103DA0000B2EED012DE0322EE03308DD110EDD0289
-:103DB0001EE339AFDD0EDD010DCC372D200C8960FF
-:103DC000C1E07B96231AE2F78B622AA0219C127B2A
-:103DD000A316DAD0C1B00B4B37B4BB8C20580B877D
-:103DE0008C12DBA0CEAB6001BF0E4E371BE2EC0C99
-:103DF000DA11ABAA28A286B8EE78EB351EE2E90EFE
-:103E0000DE0A2EE2A368E00488207E89242BA285A6
-:103E100064B0A28762DE700C79369B1388268D27EA
-:103E2000097A0C08DD0C6FAD0E77D3107E7B6960CC
-:103E3000001FC0B063FFD800D79063FFEB9C12DA7D
-:103E400020DB70580AFC8B138C1265A06F8E627E8B
-:103E50007B469C129B13CC5FDA208B10044C0258DB
-:103E60000AA0D6A08B13250A01DE70DA20DC60DD03
-:103E7000405BFF6B8C12D9A02D200CC0E01BE2C769
-:103E800017E2CF0CDA11A7D7ABAA2BA2852E74CFDD
-:103E90000B990B29A68563FF24DA20DC60DD40DE68
-:103EA000708911282007DF50A9882824075BFEFFAE
-:103EB000D2A0D10F0000DBD0DA20580B1C6550F3E4
-:103EC0002A20140A3A4065A0EEDB60DC40DD30DADF
-:103ED0002058098E1FE2EED6A064A0D784A183A04B
-:103EE0000404470305479511036351C05163FE68FD
-:103EF0002C200628CCFD6480A868C704C093292420
-:103F000006C0C18E6419E2A79E269E299E2889922A
-:103F10009E2700910400CC1A009004B0C88D65085B
-:103F2000EE01AECC0D0E5E01EE11AECCB0CC2E0A81
-:103F3000FE0C0C190ECC36C0E20C0C470ECC372C04
-:103F40002416C0B02B24072C20061BE29F0A0E4526
-:103F50000D084228240B2E240AB48929240C7DB88C
-:103F60005A2920160A5D52B09E0EDD362D24642B90
-:103F7000CCFD65BDFB0D0C4764CDF51DE28A88289C
-:103F80008DD20C9B0C00D10400BB1AAB889829631E
-:103F9000FDDE00001CE2B963FE2000001CE2AF63FE
-:103FA000FE188D6563FFA20000DA202B200C580A52
-:103FB000F8645F0BC020D10FC020D10FC093C0E3C5
-:103FC0002E241663FF9D00006C1004C06017E2727F
-:103FD0001DE275C3812931012A300829240A78A1FC
-:103FE00008C3B27BA172D260D10FC0C16550512607
-:103FF00025022AD0202F200B290AFB2B20142E204B
-:104000001526241509BB010DFF0928F11C2B2414CA
-:10401000A8EE2EF51C64A0B52B221E28221D01112E
-:10402000027B8901DB6064B0172CB00728B000DA8E
-:104030002007880A28824CC0D10B8000DBA065AF26
-:10404000E7DB30DC40DD50DA205800D829210209B6
-:104050000B4CCAB2D2A0D10F00CC5A2C30087BC175
-:10406000372ED02064E02D022A02033B02DC40DD23
-:10407000505800CED2A0D10F2B2014B0BB2B24144B
-:104080000B0F4164F0827CB7CAC0C10C9C022C2586
-:1040900002D2A0D10FC020D10F2E200669E2C12F7D
-:1040A00021020F0F4C69F1B82624062625022B2287
-:1040B0001E28221D2A200B2920150DAA092CA11C1F
-:1040C000262415AC9929A51C7B814A600049B0BB08
-:1040D0002B24140B0D41CBD67CB7022C25022B22AE
-:1040E0001E2E221D7BE9022B0A0064B0172CB0079C
-:1040F00028B000DA2007880A28824CC0D10B800043
-:10410000DBA065AFE7C020D10F262406D2A0D10FD7
-:1041100026240663FFC7DB601DE22364BF422CB088
-:104120000728B000DA2007880A28824CC0D10B800B
-:1041300000DBA065AFE71DE21B63FF246C100428C1
-:104140002006C0646F8564CA5B2920147D9726DA37
-:1041500020DB30DC40055D02580019292102090AE4
-:104160004CC8A3C020D10F00C0B10B9B022B25026D
-:10417000C020D10F0000022A02033B022C0A015882
-:1041800000C9C9AADA20DB30DC405809D529A011C2
-:10419000D3A07E97082C0AFD0C9C012CA411C051C1
-:1041A0002D201406DD022D241463FFA2DA20DB305B
-:1041B000DC40DD50C0E0580955D2A0D10F0000000E
-:1041C0006C100616E1F61CE1F665513BC0E117E103
-:1041D000F22821028B2008084C65807C29320009D6
-:1041E00069516993732A629E6EA8482A722668A054
-:1041F000027AB93F2A629DB44FCBA72B200C0CBD8D
-:104200001106DD0828D28678FB150CBF0A2FF2A311
-:1042100068F00488207F89072DD285D30F65D06090
-:104220002A210419E21ED30F7A9B1DDA2058085365
-:10423000600025002C21041BE2197CBB14DA20C08D
-:10424000B658084EC9546000EFDA20580A386000AA
-:104250000700DA20C0B6580A356550DCDC40DB3098
-:104260008D30DA200D6D515808A9D3A064A0C91C67
-:10427000E1CCC05184A18EA00404470E0E4763FF19
-:104280004F2B2104C08C8931C070DF7009F95009AF
-:104290008F386EB8172C2066AECC0C0C472C2466D9
-:1042A0007CFB099D105808BB8D1027246694D11EF5
-:1042B000E1D2B8DC9ED0655056C0D7B83AC0B1C084
-:1042C000F00CBF380F0F42CBF119E1B018E1B22862
-:1042D000967EB04BD30F6DBA0500A08800C08C2C21
-:1042E000200CC0201DE1B60CCF11A6FF2EF285AD2B
-:1042F000CC27C4CF0E4E0B2EF685D10FC0800AB846
-:104300003878D0CD63FFC1008E300E0E4763FEBDFE
-:104310002A2C742B0A01044D025808AE2F200C12CF
-:10432000E1A70CF911A699289285A2FF27F4CFD214
-:10433000A008480B289685D10FC020D10F0000009F
-:104340006C1004C060CB55DB30DC40055D02022AF6
-:10435000025BFF9B29210209084CC882D2A0D10F21
-:104360002B2014B0BB2B24140B0C41CBC57DB7EB19
-:10437000C0C10C9C022C2502D2A0D10F0000022A41
-:1043800002033B02066C02C0D0C7F72E201428316E
-:104390000126250228240A0FEE012E241458010CB0
-:1043A00063FFA300262406D2A0D10F006C100628BC
-:1043B0002102D62008084C6580992B200C12E17749
-:1043C0000CB811A2882A8286B5497A9302600093BC
-:1043D00019E17409B90A2992A36890082A620009B0
-:1043E000AA0C65A07E2882851CE17F6480759C8074
-:1043F000B887B14B9B819B10655072C0A7D97028BC
-:104400000A01C0D0078D380D0D42CBDB1FE1601EC5
-:10441000E1612EF67ED830D30F6D4A05008088000A
-:10442000908CC0802F30082F740029600C1AE16333
-:104430000C9D11A2DD2CD285C020AA992294CF0C0C
-:10444000BC0B2CD685D280D10FC0E0038E387EA065
-:10445000C363FFB7CC582A6C74DB30DC405807E1EB
-:10446000C020D10FDA605809B163FFE70000DD40DA
-:1044700085102A6C74C0B0DC705808562F30082F95
-:10448000740028600CC0F00C8B11A2BB29B28512FD
-:10449000E14B09590BA2822F24CF29B685D2A0D196
-:1044A0000F0000006C1004292014282006B199295F
-:1044B0002414688124C0AF2C0A012B21022C24066D
-:1044C0007BA004C0D02D2502022A02033B02044C2B
-:1044D00002C0D05800BFD2A0D10FC020D10F000021
-:1044E0006C1004293101C2B429240A2A3011C28374
-:1044F00078A16C7BA1696450472C2006C0686FC509
-:1045000062CA572D20147CD722DA20DB30DC40DD54
-:10451000505BFFA6292102090E4CC8E2C020D10F32
-:10452000C0F10F9F022F2502C020D10FDA20DB300F
-:10453000C0C05BFFDC28201406880228241463FF17
-:10454000C72920151BE1182A200BC0C09C240BAAE8
-:10455000092BA11C2C2415AB9929A51C63FF9900DC
-:10456000C020D10FDA20DB30DC40DD50C0E058083D
-:1045700067D2A0D10F0000006C1004CB5513E113DB
-:1045800025221F0D461106550CA32326221E252683
-:104590001F06440B24261E734B1DC852D240D10F58
-:1045A000280A80C04024261FA82828261E28261D49
-:1045B000D240D10FC020D10F244DF824261E63FF16
-:1045C000D80000006C1004282006D6206E850260FA
-:1045D00000DE17E0F21DE0F919E0F2C0C1C0202AA8
-:1045E0008CFC64A1322B6102B44E0B0B4C65B0A85D
-:1045F0002B600C2A62000CB8110788082F828609EC
-:10460000B90A7FE30260009F2992A368900509AA76
-:104610000C65A09328828564808DB8891BE0F7948F
-:10462000819B8065514DC0B7B838C0A1C0E009AECC
-:10463000380E0E4264E0481AE0D51FE0D62FA67E61
-:10464000B04A6DAA0500808800908CC0A02E600C36
-:104650000CE811A7882F8285ADEE0F4F0B2F8685B2
-:104660002B600622E4CF68B12A296015C0B2C99A2E
-:10467000D2A02D61022B64060CDD022D6502D10F44
-:10468000C0E008AE387EB0B763FFAB00226406D24C
-:10469000A0D10F00D2A0D10F00CC57DA60DB30DC04
-:1046A0004058088FC020D10FDA6058092063FFE816
-:1046B0000028221E29221D789902280A00C176C1ED
-:1046C000C1C1D21BE0C2C124AB6B6480437891406E
-:1046D0002A80000CAF0C64F0AE0DAE0C64E0A802B2
-:1046E000AF0C64F0A207AE0C64E09C2FACE864F061
-:1046F000962EACE764E0902FACE664F08A2A80073F
-:1047000008A80B088A027B83022A8DF8D8A065AF1F
-:10471000BBC09060007300002B600C0CB811A78820
-:104720002E82866EE87909BA0A2AA2A368A0048EAE
-:10473000607AE96B2A828564A0651FE0AAC0E32E37
-:1047400064069EA19FA01FE0D62E600A92A30FEEE2
-:10475000029EA28E600FEE029EA42F60147AFF4785
-:1047600022A4172F8285ADBE22E4CF2FFC182F86FE
-:104770008563FE702A6C74C0B1DC90DD40580795EB
-:104780001DE08FC0C163FEC4D9A0DA60DB30DC401D
-:10479000DD50C2F0C1E009FE395807DCD2A0D10FCC
-:1047A000DA605808E263FEF02CA4172982850DBE5A
-:1047B0000822E4CF299C1829868564500C2A6C7441
-:1047C000044B02580169D2A0D10FC020D10F0000C4
-:1047D0006C10062B221E28221D93107B8901C0B06D
-:1047E000C0C9C03BC1F20406401DE078C0E2C074FD
-:1047F0000747010E4E01AD2D9E11C0402E0A1464D4
-:10480000B06E6D084428221D7B81652AB0007EA110
-:104810003B7FA1477B51207CA14968A91768AA1456
-:1048200073A111C09F79A10CC18B78A107C1AE29DA
-:104830000A1E29B4007CA12B2AB0070BAB0BDAB0FF
-:104840007DB3022ABDF8DBA0CAA563FFB428B0106F
-:1048500089116987BB649FB863FFDC00647FB46320
-:10486000FFD50000646FD0C041C1AE2AB40063FF21
-:10487000C62B2102CEBE2A221D2B221E7AB12A8CE3
-:10488000107CB1217AB901C0B0C9B913E043DA2074
-:1048900028B0002CB00703880A28824CC0D10B80B6
-:1048A00000DBA065AFE7D240D10F8910659FD463CC
-:1048B000FFF300006C1008C0706451718F30292123
-:1048C000020F0F4716E036090C4C65C08F8D300D76
-:1048D0006E5168E30260008428629E1AE02F6E88A1
-:1048E000522AA22668A0048B207AB9472A629DB07A
-:1048F0004ECBAF9A102B200C9E110CBC11A6CC29CC
-:10490000C286B748798B4117E02607B70A2772A3FA
-:1049100068700488207789302CC2859C12D7C065C6
-:10492000C0622C21041AE05D7CAB22DA2058069389
-:10493000600029002E21041DE0597EDB18DA20C01A
-:10494000B658068EC958600156C0C063FFCCDA2045
-:10495000580876600006DA20C0B658087465513FE2
-:10496000DC40DB308D30DA200D6D515806E8D3A0E5
-:1049700064A12CC05129210284A18FA00404470FF7
-:104980000F4763FF412B2104C08C8931C0A009F976
-:1049900050098A386EB81E2C2066AFCC0C0C472C00
-:1049A00024667CAB109E142A12005806FA8E14C09E
-:1049B000D02D24668D30C0921BE010C1F87FD60C3C
-:1049C00087129B702976012F7408277C106550B7D9
-:1049D000B83AC0D7DC70C051C080075838080842C8
-:1049E0006480791DDFEA19DFEB29D67E6A420AD39B
-:1049F0000F6DE90500A08800C08CC0A08830C0926F
-:104A00007F863807E80B2F84089B809981B4E82CB7
-:104A1000200CC0901DDFEA0CC311A633223285ADF5
-:104A2000CC02820B29C4CF223685D2A0D10F8A3086
-:104A3000C0F17EAE3229210263FE88002C200C8E4C
-:104A400011C0B01DDFDE0CCF11A6FF22F285ADCC68
-:104A50002BC4CF02EE0B2EF685D2A0D10FC0800A58
-:104A6000583878D08663FF7A9F13DB30DA20C0C1D4
-:104A7000DD705BFF572921028F132A9CFE65AE4330
-:104A8000272502C09063FE3B9E142A2C74C0B1DC23
-:104A900070DD405806D08E141BDFD8C1F863FF5B71
-:104AA000C020D10F6C100628210216DFBC08084C6C
-:104AB00065821529629E6F980260021C19DFB72972
-:104AC00092266890078A2009AA0C65A20B27629D8E
-:104AD000C0CC6472032B21048E31C0A0DDA00EFE79
-:104AE000500ECD386EB8112C20662CCC010C0C4722
-:104AF0002C24667CDB026001EAC0C12930081BDF80
-:104B0000A96490972F0AFFC0D3B09E64E0FD68921D
-:104B10000E6450832A2C74DB40580093D2A0D10F2E
-:104B20002B200C2721040CBC11A6CC29C286280AF4
-:104B3000087983026001B919DF9A09B90A2992A399
-:104B40006890082E220009EE0C65E1A42EC285644F
-:104B5000E19E26200713DFA36E7B0260019A17DF18
-:104B60009A1FDFA319DFD0C0D228200A93E09DE16D
-:104B7000A9690F880298E22F90802A9480B1FF07DC
-:104B8000FF029FE31EDF8E2FC285AEBE0FDF0B2F0D
-:104B9000C6852AE4CF655F7BC020D10F2F30102956
-:104BA00030112E301300993200ED3264F0EE2A30CD
-:104BB000141FDFBD00AA3278EF050F9E092DE47F98
-:104BC0001EDFBB66A0050F98092A8480B4A718DFF2
-:104BD000B8C76F009104AE9EDDE000AF1A00C31AA3
-:104BE0006EE1052DB2000DED0C1EDFB208D81C06DB
-:104BF0003303AE882A848B2EB02E27848C03EE01DB
-:104C00000FEE022EB42E58018F63FF0429310829BC
-:104C100025042830142E3109B0886480A32E240A7C
-:104C2000C0812E30162CB4232E240BB4EF2F240C6D
-:104C30008C378B36292504DEB0DFC00F8F390E8EFE
-:104C4000390FEE0264EEC9089F1101C4048D380CBF
-:104C5000B81800C4040CBE1800EE110EDD02C0E34B
-:104C60000EFF021EDF879F719E701EDF848F2098CB
-:104C7000739D7405FF110BCD53C18098750FDD0234
-:104C80000EDD029D722A24661EDF442F629D2AE4F7
-:104C9000A22FFC182F669D63FE760000002F3012B5
-:104CA0001BDF8600FA3278FF050B980B2A847F669B
-:104CB000D0050B9A0B2DA4802A301100AA3263FF75
-:104CC000442F240A9E2B63FF56CC57DA20DB30DCBE
-:104CD00040580703C020D10F00DA20C0B658079310
-:104CE00063FFE500DA7058062BC0A02A246663FE35
-:104CF00007DA2058078E63FFCFB16928200A862083
-:104D0000090947991129240798107F812693E027E4
-:104D1000E50A9AE388109DE119DF628D11096F029F
-:104D20009FE42DE416098802C0D398E22A24076381
-:104D3000FE5100001FDF2B08691188118D2B93E0B5
-:104D4000098802C09F98E50FDD020478119DE2C03A
-:104D5000F49FE1C0D409880298E463FFCE0000000C
-:104D60006C1004C020D10F006C100485210D381187
-:104D700014DF088622A42408660C962205330B93C0
-:104D800021743B13C862D230D10FC030BC299921A5
-:104D900099209322D230D10F233DF8932163FFE372
-:104DA0006C100AD620941817DEFDD930B83898193F
-:104DB0009914655252C0E1D2E02E61021DDEFA0E56
-:104DC0000E4C65E1638F308E190F6F512FFCFD651E
-:104DD000F1568EE129D0230E8F5077E66B8F181E87
-:104DE000DF37B0FF0FF4110F1F146590CE18DF34BA
-:104DF0008C60A8CCC0B119DEE828600B09CC0B0D83
-:104E0000880929811C28811A2A0A0009880C08BAF5
-:104E1000381BDF2A0CA90A2992947B9B0260008C24
-:104E20002B600C94160CBD11A7DD29D286B84879E9
-:104E300083026000D219DEDA09B80A2882A3981723
-:104E40006880026000A36000A51ADF1E84180AEEC5
-:104E500001CA981BDED18C192BB0008CC06EB31325
-:104E60001DDECE0C1C520DCC0B2DC295C0A17EDBDD
-:104E7000AE6000380C0C5360000900000018DF1011
-:104E80008C60A8CCC0B119DEC428600B09CC0B0D16
-:104E9000880929811C28811A2A0A0009880C08BA65
-:104EA000380CA90A2992947E930263FF72DA60C0DB
-:104EB000BA58071E64507460026600001ADEB78C90
-:104EC000192AA0008CC06EA31A18DEB30C1C52085D
-:104ED000CC0B18DEFA2BC295C0A178B30263FF3F5A
-:104EE00063FFC9000C0C5363FF0989607899182986
-:104EF000D285C9922B729E1DDEA86EB8242DD226B3
-:104F0000991369D00C60000EDA6058070860001829
-:104F1000000088607D890A9A1A29729D9C12991551
-:104F2000CF94DA60C0B65807016551F48D148C181F
-:104F3000DBD08DD0DA600D6D51580574D3A09A1472
-:104F400064A1DD82A085A1B8AF9F190505470202C3
-:104F5000479518C05163FE602B6104C08C8931C035
-:104F6000A009F950098A386EB81F2C6066A2CC0CD3
-:104F70000C472C64667CAB119F119E1B8A1558054B
-:104F8000858E1B8F11C0A02A64669F1164F0E18991
-:104F9000138819DEF06DE9172F810300908DAEFEA6
-:104FA0000080889F9200908C008088B89900908C37
-:104FB00065514E8A10851A8B301FDE8A881229604F
-:104FC0000708580A2C82942D61040ECC0C2C869470
-:104FD0006FDB3C1CDEB4AC9C29C0800B5D50A299F9
-:104FE00009094729C48065D0DA2E600CC0D01FDEC5
-:104FF000730CE811A788228285AFEE02420B2DE4E4
-:10500000CF228685D2A0D10F8E300E0E4763FDA62B
-:10501000A29C0C0C472C64077AB6CD8B602E600ADC
-:10502000280AFF08E80C64810E18DE9D831682139F
-:10503000B33902330B2C34162D350AC02392319F1D
-:1050400030C020923308B20208E80292349832C08D
-:10505000802B600C286407D2A01CDE580CBE11A760
-:10506000EE2DE285ACBB28B4CF0D9D0B2DE685D18E
-:105070000F8B1888138D30B88C0D8F470D4950B4A5
-:10508000990499100D0D5F04DD1009FF029F800D3A
-:10509000BB029B8165508D851AB83AC0F1C0800C67
-:1050A000F83808084264806B1BDE3919DE3A29B6ED
-:1050B0007E8D18B0DD6DDA0500A08800C08CC0A020
-:1050C00063FEF3001DDE4B28600A82138B16C0E0DE
-:1050D0002EC48002B20B0D8802B2BB99239F20C060
-:1050E000D298229D2122600C0C2D11A7DD28D2859B
-:1050F00008BB0B18DE322BD685A8222E24CFD2A0D7
-:10510000D10F9E1B851A2A6C748B185BFF178E1BA0
-:1051100063FEA300C087C0900AF93879809263FFCC
-:1051200086C020D10F9E1B2A6C74C0B18D18580503
-:10513000298E1B851A63FE7E886B8213891608BE32
-:10514000110ECE0202920B9E25B4991EDE259F20E1
-:105150000E88029822C0EF04D8110E88029824C04D
-:10516000E49E21C080D2A02B600C2864071CDE13B3
-:105170000CBE11A7EE2DE285ACBB28B4CF0D9D0B64
-:105180002DE685D10F0000006C1004C020D10F0067
-:105190006C10048633C071C030600001B13300313F
-:1051A0000400741A0462017460F1D10F6C100402DF
-:1051B0002A02033B025BFFF61DDDFB1BDE43C79F9C
-:1051C00088B009A903098A019AB02BD10279801B02
-:1051D0001CDDF3C0E00EE4310002002AC2821DDEB5
-:1051E0003B0DAA022AC6820BE431D10FC1F00FBFDA
-:1051F000020F0F4F2FD5020FE431D10F6C100412A4
-:10520000DDE91ADDE6C0C00CE43100020029A2820B
-:1052100018DE311BDE2F2621020B990108660129B9
-:10522000A68226250206E43114DE2C15DE27236A29
-:10523000902326128550242611252613222C40D196
-:105240000F0000006C100816DE252B0A642C1AB41F
-:1052500017DDD51DDDD118DE220F2E110D2A11B25A
-:10526000E90EEE11A8A80E9911ADAAA799A7EE9E76
-:10527000169911ACAA9A152C80FF2A80FE288D0160
-:1052800029800108AA112880000CAA0208881109A7
-:10529000880208AA1CB88828160058085D297116CB
-:1052A0009A122916038A158B122AA0800BAA288B22
-:1052B00010580857D4708C168B1315DE0A0BAB28C8
-:1052C000235C419B142BC6282C308072C9158C148A
-:1052D0002A50C02B3A200CAA2858084DC0D10ADD0C
-:1052E000372D4540B444B255B2337639DAB2778FB0
-:1052F000118E168815B4EEB18898159E167FE9A414
-:10530000D10F00006C1004C021D10F006C1006C03A
-:10531000701ADDA21EDDAD1DDDB31CDDB51BDD9EEB
-:1053200013DDE1220A0818DD9F14DDEF28802E240A
-:1053300040002816006D2A70A349289080C0F164AF
-:1053400080598510004104C06100661A06550105A8
-:10535000F5390C56110A66082F62966EF74D0B5FF1
-:105360000A2FF22468F00812DDD102420872F93BDC
-:105370002362950C4202CB349232C0F29D309F31B1
-:105380000E8F029F33236295AB522F0A002F948019
-:105390002F24A0233C1023669513DDC2B17712DDC4
-:1053A000D2B144040442242400D10F00D10FD10F04
-:1053B0006C10041ADD792AA00058021B5BFFD3028F
-:1053C0002A02033B025BFFCF1BDD77C0C429B10279
-:1053D000C8AC0C9C020C0C4F2CB5020CE431D10F64
-:1053E0001EDD6FC08008E4310002002DE2821FDD67
-:1053F000800FDD022DE68209E431D10F6C10041517
-:10540000DD6716DD68C02002E4310002002452820C
-:10541000226102734F0602E431C020D10F18DDB4BF
-:1054200019DDB308280109490129568228650208B7
-:10543000E43113DDA9226C7023661DD10F0000003A
-:105440006C1004292006289CF96480A02A9CFD6524
-:10545000A0968A288D262F0A087AD9042B221FC8E5
-:10546000BD2C206464C0812E22090EAE0C66E0784B
-:105470002B200C1EDD4A0CBC11AECC28C28619DDD7
-:105480004878F3026000A909B90A2992A368900834
-:105490002E220009EE0C65E09729C2851FDD5264BB
-:1054A000908E9F90C0E41FDD5F9E9128200AC0E08F
-:1054B0009E930F8802989288200F880298942F203C
-:1054C000079A979D962F950A2E24072820062920B3
-:1054D0006468832F28C28512DD39288C20A2B22E61
-:1054E00024CF28C685C020D10FC020D10F2A206A22
-:1054F0000A2A4165AF55DA20C0B05805D364AFE839
-:10550000C021D10F649FCC1FDD272D20168FF209FB
-:10551000DD0C00F10400DD1AADAD9D2928C2851215
-:10552000DD27288C20A2B22E24CF28C685C020D10A
-:105530000FC021D10F0000006C1004260A001BDDF3
-:105540006D15DD1828206517DD15288CFE64809404
-:105550000C4D11ADBD2CD2F52BD2F42A51027CB1E9
-:10556000422A5102B4BB2ED2F72BD6F47BE9052B8D
-:10557000D2F62BD6F47CB92B29D2F629D6F529D62A
-:10558000F406E4310002002F7282C79F004104C07C
-:105590008100881A09880308FF012F76820AE43106
-:1055A000600000002624652BD2F48E5A2CD2F5B070
-:1055B000EE9E5A7BCB1629D2F62FD2F70CB80C09E7
-:1055C000FF0C08FF0C0F2F14C8F960002F0BCD0C37
-:1055D0000D2D14CED6C0E20EAE020E0E4F2E550289
-:1055E0000EE431D10FDB30DA205BFF951BDD426426
-:1055F000AF5D2A51020C4D11ADBD63FFA906E43128
-:105600000002002E72821FDD000FEE022E76820A4B
-:10561000E431D10F6C100416DCE115DCE2C030037C
-:10562000E43100020024628274472118DD33875A76
-:10563000084801286682CD7319DD310C2A11AA9918
-:105640002292832992847291038220CC292B5102C9
-:105650000BE431C020D10F001FDD2A2E51020FEEC6
-:10566000012E55020EE431B02DB17C9C5A225C60B3
-:1056700008DD112D5619D10F6C100A1ADCC71DDC7C
-:10568000C923A00019DD206F33791CDD07C0281560
-:10569000DD1F1EDD1D2B1C10D4B083E0005086954D
-:1056A0001000408A94186D2A4F0F35110C340924CC
-:1056B00040800A560A2862940D55092F51400F4424
-:1056C000110B440A08970C0F77368F400F7736225C
-:1056D000514107FF0C9F40A8772F62952766940FD2
-:1056E000980C0288368741078836B13308770CAFAB
-:1056F0008F2F66959741030342B13808084298E01E
-:10570000D10F00001CDD0314DD03BFC52442B564C6
-:105710003055C091C0D016DD000488432BC000C0B6
-:10572000406D393E00410400971A7780162FA295EC
-:105730008E50AFEE2EED2006EE369E502DA69560D3
-:10574000001A000077B00983509D5023A695600091
-:105750000223A295223D2006223622A695B144B40A
-:1057600055B8AA28C400D10F04884328C400D10F1B
-:105770006C100415DCEA13DCEAC04004E4310002DA
-:10578000008850CB815BFFBC1CDCE70C2D11ADCC3D
-:105790002BC2822AC28394507BAB142EC28429C2AE
-:1057A000850ABD0C0E990C0D990C09291460000591
-:1057B0000BA90C092914993015DC7B2A51020AE443
-:1057C000312A2CFC5800492B32001EDC742BBCFF04
-:1057D0002B3600CCB5C8A3D2A0D10F00D2A004E4D0
-:1057E000310002002DE2822C51022FBAFF0FDD01A1
-:1057F0002DE6820CE431D10F6C1004D10F000000B3
-:105800006C1004C020D10F006C100413DCC7C0D191
-:1058100003230923318DC0A06F34026000891BDC93
-:1058200061C7CF18DCC00C2911A988268283258284
-:105830008219DC5A7651442752002E8285255C0459
-:1058400025868275E9052582842586827659542627
-:105850008284D5602686822686830AE4310002008F
-:105860002392822FB10200210400D41A0C440304B5
-:1058700033012396820FE43160000200D7A07659ED
-:10588000220AE4310002002E928200210428B10293
-:1058900000DF1A0CFF030FEE012E968208E431D2CE
-:1058A00070D10F00D270D10FC020D10F6C1004DB6B
-:1058B00030862015DC39280A00282502DA2028B095
-:1058C000002CB00705880A28824C2D0A010B8000A5
-:1058D000DBA065AFE61ADC320A4A0A29A2A3C7BFD9
-:1058E000769101D10F2BA6A3D10F00006C1004C03C
-:1058F000D1C7CF1BDC2CC0A018DC280C2911A9882B
-:105900008785858419DC2677517986508E87B45532
-:10591000958475E9038586958477596C8F869F8574
-:105920009F840AE431000200239282B42E00E10435
-:105930002FB10200D41A0C44030433012396820FC2
-:10594000E4310AE43100020023928200D41A0C44AC
-:10595000030433012396820FE431D260D10F00009B
-:105960000AE431000200239282B42800810422B1AB
-:105970000200D41A0C440304330123968202E4315A
-:10598000D2A0D10FD6A07751D6D260D10F0000009F
-:105990006C1004270A801CDC281DDC281ADC000C93
-:1059A0002911AA992A2CFC2B92850DAA029CB19A46
-:1059B000B0C05113DC2528928516DC2114DC22A608
-:1059C0002604240AB888289685234691A76625646C
-:1059D0009FD10F006C100419DC550C2A11A9A9895C
-:1059E00090C484798B761BDC45ABAC2AC2832CC275
-:1059F000847AC1688AA02BBC30D3A064A05E0B2B34
-:105A00000A2CB2A319DC0F68C0071DDC49D30F7D37
-:105A1000C94AA929299D0129901F68913270A603BE
-:105A2000D3A0CA9E689210C7AF2AB6A32A2CFC5BEB
-:105A3000FFAFD230D10F000013DBEF03A3018C3195
-:105A40001DDBE00C8C140DCC012CB6A363FFDC0035
-:105A5000C020D10FDA205BFFCEC020D10FC020D1F3
-:105A60000F0000006C1004DB30C0D019DBCBDA2053
-:105A700028300022300708481209880A28824CDCA6
-:105A8000200B80001BDBC60C4A11ABAA29A284099B
-:105A9000290B29A684D10F006C1004C04118DBBF6C
-:105AA00017DBC10C2611A727277030A86625628650
-:105AB000007104A35500441A75414822628415DB25
-:105AC000E202320BC922882117DBBE088414074486
-:105AD00001754905C834C020D10FD10F1DDC15C098
-:105AE000B28E201FDBAD0E0E43AFEC0FEE0A2BC4BF
-:105AF000A02DE624C0202A62840809470A990B29B0
-:105B00006684D10FC020D10F6C1004DB30C0D018D8
-:105B1000DBA2DA2025300022300708580A28824C00
-:105B2000DC200B80008931709E121BDB9C0C4A111B
-:105B3000ABAA29A28409290B29A684D10F09C9522D
-:105B400068532600910418DB97C0A12F811200AA88
-:105B50001A0AFF022F85121EDB910C4D11AEDD2CAF
-:105B6000D2840C2C0B2CD684D10FC0811FDB8EB8B5
-:105B70009A0A0A4700A1042EF11200881A08EE02C0
-:105B80002EF5121DDB860C4C11ADCC2BC2840B2BD9
-:105B90000B2BC684D10F00006C1004DB30C0D01971
-:105BA000DB7EDA2028300022300709880A28824C60
-:105BB000DC200B80001CDB790C4B11ACBB2AB284BF
-:105BC0000A2A0B2AB684D10F6C1004C04118DB736B
-:105BD00016DB750C2711A626266030A872252286B2
-:105BE000006104A35500441A754108222284023240
-:105BF0000BD10F00C020D10F6C100415DBCE024971
-:105C000014295611245212C0730208430F88110040
-:105C1000810400361AC78F00771A087703074401FA
-:105C2000064402245612D10F6C1006C0B06E230237
-:105C30006000A264209D851013DBAA16DBBEC04065
-:105C4000A6BA2BA2AE0B194164905E68915568927A
-:105C50004A6893372930FF2830FE2AA2AA08881103
-:105C60000A0A4D2AACF20988027589442B3D0129A4
-:105C7000B0002BB0010899110B99027A9932B83310
-:105C80002B2A00B1447249B7600048007FBF051558
-:105C9000DBAA63FFBE253AE863FFB800253AE86354
-:105CA000FFB10000250A6463FFA9C05A63FFA40086
-:105CB00000705F082534FF058C142C34FE70AF0B88
-:105CC0000A8D142E3D012AE4012DE400DA405BFD2B
-:105CD0005D63FFA9D10FD10F6C10041ADB3219DB01
-:105CE0002F1CDB961BDB97C080C07160000D00008D
-:105CF0000022A430B1AA299C107B915F269286795C
-:105D0000C215C0206E62E96D080AB12200210400AC
-:105D1000741A764BDB63FFEE2292850D6311032527
-:105D200014645FCFD650032D436DD9039820B4225D
-:105D30000644146D4922982098219822982398248B
-:105D400098259826982798289829982A982B982C4F
-:105D5000982D982E982F222C4063FF971EDB10273A
-:105D6000E68027E681D10F006C1004C062C04112AA
-:105D7000DB0D13DB7423322D1ADB0819DB6E2AA02E
-:105D8000002992AE6EA30260009128ACFE090D407E
-:105D90002C1AC2C2BD0DCB392B25166480895BFF3E
-:105DA000A215DB691ADB142B3AE80A3A0158059868
-:105DB0002B21160ABB28D3A02B56005805AF8B50B9
-:105DC0000ABB082A0A005805AE15DB602D21022CFB
-:105DD0003AE80C3C2804DD022D25029C505805A60B
-:105DE0008B50AABBC0A15805A61CDB592D21020C63
-:105DF0003C2806DD0213DB572D25029C3058059EFA
-:105E00008B30AABBC0A258059E2A2102C0B40BAA9F
-:105E1000020A0A4F2A25025805B2D10F242423C3AF
-:105E2000CC2C251663FF760018DB4F1CDB4B19DBEF
-:105E30004C1BDB4A17DB1F85202E0AFD1FDB4B2D79
-:105E4000202E24F47A24F47E24F4820EDD0124F43E
-:105E5000862E0AF707552806DD02C0750EDD0105FE
-:105E60000506AB5BA959C0E8AC5C24C4AB0EDD02EF
-:105E700027C4AC2E0ADFA85527B4EC0EDD0124B4EC
-:105E8000EBC2E027942C0EDD0224942B2E0A800D09
-:105E90000D4627546C24546B0EDD022D242E63FE18
-:105EA000FC0000006C1004C3A0C0B35BFF53C04AE9
-:105EB00012DB21C380282616242617C3A1C0B35B9A
-:105EC000FF4EC03CC3A12A261619DAB6299020231A
-:105ED000261764908F2A0A322B0A015BFF47C3A260
-:105EE0002B0A015BFF45C3B22B2616232617C2AF30
-:105EF000C0B15BFF41C2FF2F2616C0EE2E2617C28F
-:105F0000D22D2616C0C82C26172426112A2212C7E5
-:105F1000B30BAA01C0B40BAA022A2612290AA1298E
-:105F20002616C182282617C0B32B26112E22121F37
-:105F3000DACA0FEE022E2612C3D62D26162A0AA280
-:105F4000C1C32C26175BFF2C2C0AA22C2616C1B528
-:105F50002B2617C2AB2A2616C09729261718DB0353
-:105F6000282610D10FC3A2C0B35BFF2363FF6E00CE
-:105F70006C10041CDACE1BDABB18DAFD17DAFE1639
-:105F8000DAFE15DAFEC0E0C0D414DACA1FDA8622BF
-:105F90000A082FF2006D2A36DAC0D9C07C5B020FE6
-:105FA000C90C1CDAC30C9C28A8C3A6C22A36802AB6
-:105FB0002584A4C2A7CC2D248C2B248A2B24872EA5
-:105FC000248BB1BB2E369F2C369E2C369DB1AC1C3B
-:105FD000DAA51BDAEBC0286D2A33DAC0D9C07C5BA6
-:105FE000020FC90C1CDAB30C9C28A8C3A6C22A361F
-:105FF000802B2584A4C2B1BBA7CC2D248C2E248B4E
-:106000002A248A2E369F2C369E2C369DB1ACC07920
-:1060100019DAA31BDADE13DADB1ADADB18DADD149D
-:10602000DAA416DADC04F42812DADC04660C0405BF
-:1060300006A252A858AA5AA3539B3029A500278428
-:106040008AC091C0A52A848C29848B17DAD518DAE6
-:10605000D3A75726361D26361E2E361F16DAD21324
-:10606000DAD2A65504330C2826C82E75002D54AC60
-:106070002E54AB2E54AA2326E62326E52E26E7D15E
-:106080000F0000006C100613DAAF17DAAA24723D75
-:106090002232937F2F0B6D08052832937F8F026386
-:1060A000FFF3C0C4C0B01EDA3FC061D940096939EE
-:1060B00029E4206E4401D6B0C328DFB026E42206CE
-:1060C0002F392FE421C0501FDAB919DAAA16DAAB3A
-:1060D00018DA7994102A72458DE017DAA59D111D02
-:1060E000DAB46DA94BD450255C037A5B18DE507589
-:1060F0006B052E12010E5E0C12DA6E02E2280111FF
-:1061000002AF2222D681D54013DA6A746B052512BC
-:106110000105450C035328B145A83EA932A73322F7
-:10612000369D22369E2436802B369F2BE48B2CE422
-:106130008C14DA8424424DC030041414C84C6D0809
-:1061400006B133041414C84263FFF20016DA13C414
-:1061500040C1580031041ADA13C0B193A200BB1A2F
-:10616000B0BB9BA318DA7829824D23824E28825334
-:106170007A871C2C64008C106FC4481EDA0A043D18
-:106180000C2DE51C2FE11D2DE51A2FE51BD10F006D
-:10619000C07212DA6882207E27DB03034F27640077
-:1061A0008810C0616F8430C0A00319140A54391AD2
-:1061B000D9FD04990C29A51C29A51D29A51A29A5D5
-:1061C0001BD10F001CD9F8053B0C2BC51C2DC11D84
-:1061D0002BC51A2DC51BD10F065439031E1404EE0E
-:1061E0000C2EA51C2EA51D2EA51A2EA51BD10F0009
-:1061F0006C10081AD9EC14DA4F13DA52C72FC050BA
-:1062000016DA6C2566A82566A92566AA2566AB223E
-:1062100036292B424519DA13D8101CDA66C0D49DF2
-:10622000119C100080890B990C99A02816025BFF25
-:10623000952A32E31FD9DC0A5A149AF42932E4B1C0
-:10624000990959140A990C99F52832E508581498B7
-:10625000F62E32CD0E5E142EF6075BFF455BFF1166
-:1062600022463B1CD9D02AC102C1B00BAA021BDABC
-:106270002A0A0A4F2AC5022B463A5804995BFEBAED
-:106280005BFE95C0B0861317D9C525362DC74EC005
-:10629000309414C05014D9CA60004300007F9F0F8F
-:1062A000B155091914659FF4C0500AA9027FA7EFE0
-:1062B00018D9BADA5008580A28822C2B0A000B8009
-:1062C00000005104D2A0C091C7AF00991A0A9903E7
-:1062D000291604CE33642063D3202B2007D6508C9C
-:1062E000142A72827CA85C18D9AC08580A28822C1F
-:1062F000DA500B8000D2A0643FDA8A310A8A140493
-:10630000AA01C82A2B22010B8B1404BB017AB940C5
-:10631000DDA06EA1081DD9A32DD2000DAD0CDB3080
-:10632000DC601AD9E318D99C0ADA2808680A1DDA51
-:106330001F28823CADAA0B8000652F9BD320C0B0E4
-:1063400063FF9B00CA5CB1550050040A091963FF42
-:106350004BDCB06EB1091CD9938CC0D30F0CBC0CB4
-:106360001DD9D41EDA120DCD28AEDD1EDA112DE6B0
-:106370008163FF9B7FA7CE63FF6C00006C10041B42
-:10638000D98727221EC08008E4310002002AB28289
-:1063900019D985003104C06100661A2991020A6A80
-:1063A000022AB68209E43115D9DF0C3811A8532826
-:1063B00032822432842A8CFC7841102921022A3628
-:1063C0008297A0096902292502D10F002B21022CF6
-:1063D00032850B6B022CCCFC2C368297C02B25020D
-:1063E000D10F00006C1006C0C71BD9681AD96A0DFE
-:1063F0004E11D72088208522D98005450B02820CBA
-:106400009572222CF4C8346F2E026000AB1FD96045
-:10641000A9E2AF7D72D334C93DC0212F0A00092FF4
-:10642000380F0F42C9F92AB67E6D4A050030880040
-:10643000908C22720002E20872D1749270D280D1E4
-:106440000FC05003253875C0DF63FFD9097D0CAF3D
-:10645000DD0DEE0C64304ED2300D3F1296112F162A
-:10646000002FFC100F4F36260A01250A0009653857
-:106470000505426450712AB67E6DFA050020880039
-:10648000908CC050A3D28910237C0C09440C290A9B
-:106490000103953805054264505A2AB67E6D4A05B7
-:1064A00000208800308CD280A7EABCAA9A70D10F55
-:1064B000D280BC7B9B70D10F00023F14C1D0D23080
-:1064C0000FDD0C0D4D36298D08C0F1250A0009F5A8
-:1064D00038050542CA582AB67E6DDA0500208800C4
-:1064E000908C897063FF2500C061C05003653875CA
-:1064F000C08663FF80C0D0029D387DC09F63FF9936
-:10650000C05003F53875C0D063FFCA006C1004D6C4
-:106510002068520F695324DA20DB30DC405800F049
-:10652000D2A0D10FDA20DB30DC405800ED9A2424D1
-:10653000240EC02122640FC020D10F00B83BB04C04
-:106540002A2C7489242D200E2E200FA4DDB1EE2ECE
-:10655000240FB0DD2D240E2890072D9003A488B0C1
-:1065600088B1DD2D94032894075BFF9E69511DC0FF
-:10657000E082242A600F18D9902A240329600E8F04
-:106580002029240708FF029F209E64D10FC020D13C
-:106590000F0000006C1004942319D988C0B3083A86
-:1065A000110BAA02992019D8FD9A2128929D16D87C
-:1065B000FAC0502564A2288C1828969DD10F00009F
-:1065C0006C1004282066C038232406B78828246667
-:1065D000D10F00006C1006035A0C0D36110D5C1122
-:1065E000D8208B2282210CBB0C06550F9B820232D5
-:1065F0000B928113D8E7D920A38F6450531CD8E3A2
-:10660000C0D71BD8E4A256C0E1290A0004E9380922
-:10661000094276F34A044302C99E2BC67E6DAA0541
-:1066200000208800308C8981A95909FA0C64A0796E
-:1066300099818A82C8ADD290D10FC06002E63876C7
-:10664000D0DA63FFD4C020BC89998199809282D12D
-:106650000F7F2304292DF8998165BFD963FFE500D9
-:10666000028F0CA3FF0F3312931003AA0CD340CB5D
-:106670009E2BC67E86106D6A0500208800308CBC7B
-:1066800082290A0004F308240A010349380909424F
-:10669000CA982BC67E6DAA0500208800308C0F5941
-:1066A0000CA989BC99998163FF87BC89998163FF93
-:1066B00080C06002E63876D0BA63FFB4C07002478B
-:1066C0003877D0D063FFCA006C100414D8C0C15210
-:1066D000A424C93E28221D738119292102CD932AA1
-:1066E000300075A912DA20DB302C3007C0D25801F7
-:1066F000C4653FDFD10F00002B300703BB0BDAB0BE
-:1067000074B3022ABDF8D3A063FFC6006C1004293D
-:106710002006C0706E9741292102C08F2A2014C024
-:10672000B62B240606AA022A241479800227250201
-:106730002A221E2C221D7AC10EC8ABDA20DB302C97
-:106740000A00033D025BF8226450752D21020D0DF5
-:106750004CC9D3C020D10F00002E9CFB64E0822FD7
-:1067600021020F0F4C65F0911AD88D1CD88B29A2ED
-:106770009EC08A798B5D2BC22668B0048D207BD9A0
-:106780005229A29DC0F364904A97901DD89E2E2155
-:10679000049D9608EE110FEE029E979E9127C4A2CB
-:1067A00018D89A2F21022BA29DC0E52E24062BBCBF
-:1067B0003008FF022BA69D2F2502C020D10F00001C
-:1067C000002F300068F938DA20DB30DC4058004414
-:1067D00063FF7700022A022B0A065800D4220A001F
-:1067E000D10F655010283000688924022A02033B2B
-:1067F00002DC4058003BC020D10FD270D10F000006
-:106800002A2C74033B02044C025BFEF663FF3B0040
-:10681000DB30DC402A2C745BFEF3C020D10F00007B
-:106820006C1004C83F89268829A399992609880CE9
-:10683000080848282525CC52C020D10FDB402A2C3F
-:10684000745BF949D2A0D10F6C1004D820D73082E4
-:10685000220D451105220C928264207407420B130D
-:10686000D84CD420A383732302242DF8858074513F
-:106870004CBC82C0906D081600408800708C77393F
-:1068800003D720C0918680743901D42074610263DB
-:10689000FFE2CA98C097C0411BD8CAC0A00B8B0C9E
-:1068A0000B4A380A0A42C9AA1DD8391CD83A2CD634
-:1068B0007EC140D30F6D4A0500208800308C978040
-:1068C000D270D10FBC8FC0E00F4E387E90E263FFD4
-:1068D000D6BC8292819280C0209282D10F000000AB
-:1068E0006C1006C0D71CD8291BD82B0D4911D720F6
-:1068F0002A221F28221D0A4A0BD28007860C2A76DC
-:106900001F266C80C8346F6E026000D02F0A801A78
-:10691000D82FA29EAA7A7EA33FC93FC0E1C05002F1
-:10692000E538050542CA552BC67EDB20D30F6D4ADC
-:106930000500308800B08C2E721DAE9E0EA50C6432
-:10694000508AD2802E761DC091298403D10FC05069
-:1069500003E53875D0D363FFCD15D81C027E0CA596
-:10696000EE643055DA300E351296129511255C1012
-:10697000054536C0619510C0500265380505426472
-:1069800050892BC67E8510D30F6D5A0500A0880054
-:10699000208CC0A1A3E2C05023FA8003730C03A58E
-:1069A00038AF730505426450722BC67E85110545CC
-:1069B0000C6D5A0500208800308CD280C0A10E9B3F
-:1069C0000CAB7BAFBB2B761D2A8403D10FD280C0CA
-:1069D000C1AF7D2D761D2C8403D10F0000063F141E
-:1069E000C1E0D2300FEE0C0E4E362A8D08C0F125D4
-:1069F0000A000AF538050542CA5C2BC67E6DEA0519
-:106A000000208800A08C22721D63FEFFC061C05070
-:106A100003653875D80263FF6B63FF65C05002A53C
-:106A20003875D08763FF8100C06003F63876D0CC1C
-:106A300063FFC6006C10042A201529201614D7D92C
-:106A40000A990CCB9D2E200B04ED092BD11C09BCFF
-:106A500036ACAA0CBB0C2BD51C0A0A472A2415CB32
-:106A6000A18B438F288942B0A800910400881AA8FE
-:106A7000FF0FBB029B278F260FB80C783B1AC02054
-:106A8000D10F0000292102C0A20A9902292502C0C3
-:106A900021D10F008B2763FFDC2BD11C0CAA0C0A21
-:106AA0000A472A2415ACBB2BD51CC9AE8B438C28B6
-:106AB0008F42B0AD00F10400DD1AADCC0CBB029BDF
-:106AC00027DA20B7EB580019C021D10F9F2763FFA9
-:106AD000EF0000006C100428203C64304705306053
-:106AE00000073E01053EB156076539054928C77FB5
-:106AF000A933030641076603B166060641A6337E45
-:106B0000871E222125291AFC732B1502380C0981B6
-:106B10006000063E01023EB12406423903220AD13A
-:106B20000FD230D10FC05163FFC000006C10041DA4
-:106B3000D79B27221EC08008E4310002002CD2829D
-:106B40001BD799003104C06100661A2BB1020C6C8E
-:106B5000022CD6820BE43119D81B0C3A11AA9328C7
-:106B600032829780253282243284B455253682754C
-:106B7000410A292102096902292502D10F2A21028D
-:106B80002B32830A6A022B36822A2502D10F00009B
-:106B90006C10041DD78219D78C27221EC08009775C
-:106BA0000208E4310002002CD2821BD77E0031049F
-:106BB000C06100661A2BB1020C6C022CD6820BE469
-:106BC0003119D8000C3A11AA9328328297802532C5
-:106BD00082243284B45525368275410B2A21020A5B
-:106BE0006A022A2502D10F002B21022C32830B6B63
-:106BF000022C36822B2502D10F0000006C10041BE2
-:106C0000D7670C2A11ABAA29A286B438798B221B2C
-:106C1000D76419D78B0B2B0A2BB2A309290868B0AC
-:106C20000274B90D299D0129901F6E920822A28538
-:106C3000D10FC020D10FC892C020D10FDA205BEF56
-:106C40003DC020D10F0000006C100414D75428421E
-:106C50009E19D7516F88026000B929922668900763
-:106C60008A2009AA0C65A0AB2A429DC0DC64A0A3BF
-:106C70002B200C19D74B0CBC11A4CC2EC28609B901
-:106C80000A7ED3026000992992A36890078D20099B
-:106C9000DD0C65D08B25C2856450852D2104C03064
-:106CA0006ED80D2C2066B8CC0C0C472C246665C021
-:106CB0007A1AD7521CD75B1DD7481ED74FC084986D
-:106CC000519E5089209D569D54935793559C530A2D
-:106CD00099021CD7BD1AD76499528F26995A985990
-:106CE0009E58935E9C5D935C9A5B0F0D4805DD1189
-:106CF0009D5FC0D81ED7320CB911A499289285AED9
-:106D0000BE23E4CF288C402896859F292D2406C0D9
-:106D100020D10F00CA32DA20C0B65BFF84C72FD162
-:106D20000FC939DA205BFF81C72FD10FDBD05BFEA3
-:106D3000192324662B200C63FF76C72FD10FC72F92
-:106D4000D10F00006C1004C85B29200668941C68F1
-:106D50009607C020D10FC020D10FDA20DB30DC40F5
-:106D6000DD502E0A005BFE69D2A0D10F2E200C1838
-:106D7000D70B0CEF11A8FF29F286C088798B751A02
-:106D8000D7080AEA0A2AA2A368A0048B207AB96469
-:106D900023F28564305E1CD7122A0A802D206829D0
-:106DA00020672821040B991104881109880208DD45
-:106DB00002C094284A1008DD0218D70A9931983089
-:106DC0008B2B9A379D340CBB029B32C0C09C359CE8
-:106DD000362A2C74DB40C0D318D6F929F285A8EEE8
-:106DE000299C2029F6852CE4CF2D2406DD405BFD6F
-:106DF000F9D2A0D10FDA20DBE05BFF4CC020D10F2D
-:106E00006C100AD6302A2006941028ACF86583FF4F
-:106E10002B2122270A022A2124CC572AAC010A0A54
-:106E20004F2A25247ABB026003F72C21022A200C6A
-:106E30000C0C4C65C38E2E22158D32C0F10EDD0C6C
-:106E400065D40488381ED6D56483E18F37C0C8C0A6
-:106E5000960FC9399914B49B9B110D99119913C9B7
-:106E6000FB19D6D02990217F93138B148C205BFFC4
-:106E7000631ED6CADDA064A41C8F676000298C1134
-:106E80000CAD11AEDD28D2860AAB0278CB621AD6E1
-:106E9000C40ABA0A2AA2A368A0052C22007AC95003
-:106EA0002AD285DDA064A3D729212E09F9362A200C
-:106EB0003C09F80C6F8D3ED7F0CB7F28211F08705E
-:106EC00060010B3E00043EB1BC04CB39C74F0BBB85
-:106ED0000A07BB0A0B0C4104CC03B1CC0C0C41AC2F
-:106EE000BBD4B0C0C27CA04C2A21257BAB4660003D
-:106EF0002CC0A063FFACD79063FFBD00C092C74F0A
-:106F00002C7C140C0B4104BB03B1BB0B0B41AB74C9
-:106F1000244C1479A01E2A212574AB18ACBB241A6A
-:106F2000FC0ABC0C04C16000093E01043EB14809E2
-:106F300084390B440A8926882709880C74831DC06C
-:106F40008098D88C649CD98B668A659BDB9ADA978B
-:106F5000D57F730260013ACE5E600016009D15DA9F
-:106F600020DB405BFEB48D151ED68D65A2568F6763
-:106F700063FFCB9D15DA20DB308C105BFE598D153D
-:106F80001ED687C051D6A08FA7C0C08A6897DD9A49
-:106F9000DC8869896A98DE99DF8B6A8A69AB7B77BE
-:106FA000BB022AAC019B6A9A698860C0A0088B1456
-:106FB000778701C0A1C09028203C9417951893169C
-:106FC000C050C031C044048401043938089910C04D
-:106FD00042048401043538083840832B0BA4100781
-:106FE00055102A211F0955020544020B19400A2A8F
-:106FF000140799100585100433020A881114D6F37A
-:10700000095502292104043302089911098802C094
-:107010009209880229212593D00929140499110A7B
-:1070200099020955028A20891408AA110A99021A9C
-:10703000D66F14D6E70A990299D1832A95D698D7A4
-:10704000851804330293D4841783168A658D66AA43
-:10705000CAAD7D77DB01B1AA07FF0C9A659D6688F2
-:10706000268C29A48808CC0C98260C0C482C2525A5
-:107070009F672A200CC0C01BD6510CA911AE99AB3A
-:10708000AB2892852CB4CF8B13AB8828968563FDF3
-:10709000CD00C091C0F0C0B2C0C4886023203C982D
-:1070A000120C3C010B3A010888140B88010A9F3826
-:1070B00007FF10089839C0A00C9A3807881008AA52
-:1070C000100AFF02C0A80A33010393392A210429B8
-:1070D0002125053C1008CC020A331108AA11092900
-:1070E0001403AA020499110BAA022B211F83140B6B
-:1070F0002B140B99020C99028B201CD63C08BB1157
-:1071000003BB020CBB02832A8C2B647084886897B3
-:10711000DD98DC8769886A97DE98DF8812C070770F
-:107120008701C0719BD199D60B78109AD717D6A931
-:1071300008F80208C80207880217D6A598D00737B2
-:107140000297D428200C295CFE2B2124C0F01AD6EB
-:107150001B0C8D11AEDD2CD285AA882F84CF8F1306
-:10716000B0BBAFCC2CD6852A22152B2524B1AA2A58
-:1071700026156490DCC84F8C268B29A4CC9C260C49
-:10718000BB0C0B0B482B25256550E8C020D10F0008
-:107190000000C0709BD199D69AD7881293D4778774
-:1071A0000E18D600921A288022C021082738821A89
-:1071B00018D68A0B731003F30203C3020833029339
-:1071C000D063FF7E00CC57DA20DB608C105BFDC4FF
-:1071D000292102689806689403C020D10F2B221E33
-:1071E000C09028221D2925027B8901C0B064BFE818
-:1071F00013D5EA2CB00728B000DA2003880A2882C9
-:107200004CC0D10B8000DBA065AFE763FFCA000074
-:1072100068A775DA20DB30DC40DD505BFECAD2A007
-:10722000D10FC1FDC19D29252C600003002F252C05
-:107230002F2467272468DA20DB308C10DD502E0ADB
-:10724000805BFD32D2A0D10FC1F8C1A82A252C63E2
-:10725000FFDDC84F8C268B29A4CC9C260CBB0C0BC5
-:107260000B482B25252A2C74DB602C12005BFD7645
-:10727000D2A0D10F2A2C748B105BF6BBD2A0D10FF9
-:10728000DA205BFE2A63FF3C00DA20C0B15BFE6EB1
-:1072900065AF3163FB79DA202B200C5BFE3D63FF89
-:1072A0002300000012D64E8220028257C82163FFBD
-:1072B000FC12D64A03E83004EE3005B13093209436
-:1072C00021952263FFFC000010D6469100920193A5
-:1072D00002940311D61D821001EA30A21101F0318F
-:1072E000C04004E41600020011D63F8210234A0079
-:1072F000032202921011D609C021921004E43184B5
-:107300000383028201810000D230012300000000CB
-:1073100010D636910092019302940311D60C82107C
-:1073200001EA30A21101F131C04004E4160002006C
-:1073300011D62D821013D5B4032202921004E43129
-:10734000840383028201810000D3300133000000F6
-:1073500010D6279100810165104981026510448192
-:1073600003CF1F92019302940311D5FA821001EA10
-:1073700030A21101F231C04004E41600020011D61F
-:1073800019821013D59B032202921004E431840366
-:1073900083028201C010910391029101810000D407
-:1073A0003001430012D5CAC030283740283744285E
-:1073B000374828374C233D017233ED03020063FF49
-:1073C000FC00000010D60B9100920193029403116F
-:1073D000D6098210921011D5BC831003220292109C
-:1073E00011D60612D5CD9210C04004E4160002005A
-:1073F00011D5FD821013D5B5032202921004E43199
-:10740000840383028201810000D530015300000013
-:107410006C10026E322FD620056F04043F04745B9B
-:107420002A05440C00410400331A220A006D490D5C
-:1074300073630403660CB1220F22110313147363E8
-:1074400002222C01D10FC83BD10F000073630CC086
-:1074500021D10F000000000044495630C020D10F58
-:107460006C10020040046B4C07032318020219D170
-:107470000F020319C020D10F6C100202EA30D10FA5
-:107480006C1002CC2503F03160000F006F22050361
-:10749000F1316000056F230503F231000200D10FC6
-:1074A0006C1002CC2502F030D10F00006F220402D4
-:1074B000F130D10F6F230402F230D10FC020D10F71
-:1074C0006C1002220A20230A006D280E283740285B
-:1074D000374428374828374C233D01030200D10F99
-:1074E0006C100202E431D10F0A004368656C7369C5
-:1074F0006F2046572044454255473D30202842756D
-:10750000696C7420547565204175672031322030D4
-:10751000393A34333A303420504454203230303801
-:10752000206F6E2066656C69782E6173696364658F
-:107530007369676E6572732E636F6D3A2F686F6D36
-:10754000652F66656C69782F772F66775F362E30EA
-:10755000292C2056657273696F6E20543378782019
-:107560003030372E30302E3030202D203130303733
-:0C7570003030303010070000CC44A0D6B2
-:00000001FF
diff --git a/firmware/cxgb3/t3fw-7.1.0.bin.ihex b/firmware/cxgb3/t3fw-7.1.0.bin.ihex
new file mode 100644 (file)
index 0000000..1042f75
--- /dev/null
@@ -0,0 +1,1885 @@
+:1000000060007400200380002003700000001000D6
+:1000100000002000E100028400070000E1000288E7
+:1000200000010000E0000000E00000A0010000006E
+:1000300044444440E3000183200200002001E0002A
+:100040002001FF101FFFD0001FFFC000E300043C91
+:1000500002000000200069881FFFC290200069D0C4
+:100060001FFFC29420006A101FFFC29820006A84FC
+:100070001FFFC29C200003C0C00000E43100EA3131
+:1000800000A13100A03103020002ED306E2A05000C
+:10009000ED3100020002160012FFDBC03014FFDA5F
+:1000A000D30FD30FD30F03431F244C107249F0D347
+:1000B0000FD30FD30F12FFD5230A00240A00D30F4A
+:1000C000D30FD30F03431F244C107249F0D30FD327
+:1000D0000FD30F14FFCE03421F14FFCB03421F1296
+:1000E000FFCCC0302D37302D37342D37382D373CED
+:1000F000233D017233ED00020012FFC4C0302F37E0
+:10010000002F37102F37202F3730233D017233ED6A
+:1001100000020012FFBEC0302737002737102737F4
+:1001200020273730233D017233ED03020012FFB95F
+:1001300013FFBA0C0200932012FFB913FFB90C028F
+:1001400000932012FFB8C0319320822012FFB71312
+:10015000FFB7932012FFB715FFB316FFB6C030D715
+:100160002005660160001B00000000000000000088
+:10017000043605000200D30FD30F05330C6E3B1479
+:100180000747140704437631E604360505330C6F40
+:100190003BED00020012FFA615FFA3230A00D720A3
+:1001A000070443043E0505330C0747146F3BF00377
+:1001B000020012FFA1C03014FFA1D30FD30FD30F41
+:1001C0009340B4447249F2D30FD30FD30F14FF9B63
+:1001D000834014FF9B834012FF9B230A0014FF9A65
+:1001E000D30FD30FD30F9340B4447249F2D30FD33C
+:1001F0000FD30F14FF95834012FF95C92F832084DE
+:10020000218522BC22743B0F8650B4559630B433FE
+:100210007433F463FFE60000653FE1655FDE12FFC3
+:100220007C230A0028374028374428374828374C91
+:10023000233D017233ED03020000020012FF7AC079
+:1002400032032E0503020012FF7813FF819320C0B2
+:1002500011014931004831010200C00014FF7E0441
+:10026000D23115FF7D945014FF7D04D33115FF7CEE
+:10027000945014FF7C04D43115FF7C24560014FFE5
+:100280007B04D53115FF7B24560010FF7A03000054
+:10029000000000000000000000000000000000005E
+:1002A000000000000000000000000000000000004E
+:1002B000000000000000000000000000000000003E
+:1002C000000000000000000000000000000000002E
+:1002D000000000000000000000000000000000001E
+:1002E000000000000000000000000000000000000E
+:1002F00000000000000000000000000000000000FE
+:1003000000000000000000000000000000000000ED
+:1003100000000000000000000000000000000000DD
+:1003200000000000000000000000000000000000CD
+:1003300000000000000000000000000000000000BD
+:1003400000000000000000000000000000000000AD
+:10035000000000000000000000000000000000009D
+:10036000000000000000000000000000000000008D
+:10037000000000000000000000000000000000007D
+:10038000000000000000000000000000000000006D
+:10039000000000000000000000000000000000005D
+:1003A000000000000000000000000000000000004D
+:1003B000000000000000000000000000000000003D
+:1003C000000000000000000000000000000000002D
+:1003D000000000000000000000000000000000001D
+:1003E000000000000000000000000000000000000D
+:1003F00000000000000000000000000000000000FD
+:1004000000000000000000000000000000000000EC
+:1004100000000000000000000000000000000000DC
+:1004200063FFFC000000000000000000000000006E
+:100430000000000000000000000000001FFC0000A1
+:100440001FFC0000E30005C81FFC00001FFC0000AB
+:10045000E30005C81FFC00001FFC0000E30005C806
+:100460001FFFC0001FFFC000E30005C81FFFC00042
+:100470001FFFC018E30005C81FFFC0181FFFC018EA
+:10048000E30005E01FFFC0181FFFC28CE30005E07A
+:100490001FFFC28C1FFFC28CE30008541FFFC290D5
+:1004A0001FFFC58CE3000854200000002000016AF3
+:1004B000E3000B502000018020000180E3000CBC11
+:1004C0002000020020000203E3000CBC2000021CFC
+:1004D00020000220E3000CC02000022020000226A1
+:1004E000E3000CC42000023C20000240E3000CCCDE
+:1004F0002000024020000249E3000CD02000024C02
+:1005000020000250E3000CDC2000025020000259C1
+:10051000E3000CE02000025C20000260E3000CEC31
+:100520002000026020000269E3000CF02000026C51
+:1005300020000270E3000CFC200002702000027911
+:10054000E3000D002000028C2000028CE3000D0C63
+:100550002000029020000293E3000D0C200002AC6A
+:10056000200002B0E3000D10200002D0200002F2B3
+:10057000E3000D14200003B0200003B0E3000D38A9
+:10058000200003B0200003B0E3000D38200003B0CA
+:10059000200003B0E3000D38200003B0200003B0BA
+:1005A000E3000D38200003B020006BA8E3000D38F5
+:1005B00020006BA820006BA8E3007530000000004D
+:1005C00000000000000000001FFC00001FFC0000F5
+:1005D0001FFFC5901FFFC67020006BA820006BA8EE
+:1005E000DEFFFE000000080CDEADBEEF1FFFC2A064
+:1005F0001FFCFE001FFFC0941FFFC5C0300000009D
+:10060000003FFFFF8040000010000000080FFFFFC8
+:100610001FFFC26D000FFFFF804FFFFF8000000033
+:1006200000000880B000000560500000600000007D
+:1006300040000011350000004100000010000001E2
+:1006400020000000000010007FFFFFFF40000000BE
+:1006500005000000800000190400000000000800F0
+:1006600010000005806000007000000020000009FC
+:10067000001FF8008000001EA0000000F80000002D
+:1006800007FFFFFF080000001800000001008001C4
+:10069000420000001FFFC21D1FFFC0DC00010080E0
+:1006A000604000001A0000000C0000000000300054
+:1006B000600008008000001C000100008000001A9B
+:1006C00080000018FC0000008000000100004000D5
+:1006D000030000008000040050000003FFFFBFFF84
+:1006E0001FFFC3D400000FFFFFFFF000000016D073
+:1006F0000000FFF7A50000001FFFC4B01FFFC4618A
+:100700000001000800000B20202FFF801FFFC455B0
+:1007100000002C00FFFEFFF800FFFFFF1FFFC57861
+:1007200000002000FFFFDFFF0000FFEF01001100CD
+:100730001FFFC3D21FFFC590FFFFEFFF0000FFFBAD
+:100740001FFFC6301FFFBEA0FFFFF7FF1FFFC064E3
+:100750000000FFFD1FFFC6200001FBD01FFFC5B03A
+:100760001FFFC6601FFFC591E0FFFE001FFFC5A071
+:10077000000080001FFFC53C1FFFC5B41FFFC068FD
+:100780001FFFC4D01FFCFFD800010081E10006005C
+:10079000000027101FFCFE301FFCFE70E10002006D
+:1007A0001FFFC5381FFFC5500003D0901FFFC56451
+:1007B0002B5063802B5079802B5090802B50A6803B
+:1007C0001FFFC4690100110F202FFE0020300080A0
+:1007D000202FFF000000FFFF0001FFF82B50B200A8
+:1007E0002B50B208000100102B50B1802B50B2806A
+:1007F0002B50BA00000100112B50BD282B50BC809B
+:100800002B50BDA020300000DFFFFE005000000292
+:1008100000C0000002000000FFFFF7F41FFFC06CE3
+:10082000000FF80004400000001000000C40000021
+:100830001C400000E00000A01FFFC5401FFD000895
+:100840001FFFC5541FFFC5681FFFC57CE100069050
+:10085000E10006EC000000000000000000000000C5
+:100860000000000001000000000000000000000087
+:100870000000000020100040201000402010004028
+:1008800020140080200C0000200C0000200C000030
+:1008900020100040201400802014008020140080CC
+:1008A000201800C0201C0100201C0100201C010099
+:1008B00020200140201800C0201800C0201800C0CF
+:1008C000201C0100201800C0201800C0201800C003
+:1008D000201C010020200140202001402020014058
+:1008E00020200940202009402020094020200940E4
+:1008F00020240980FFFFFFFFFFFFFFFFFFFFFFFF37
+:1009000000000000000000000000000000000000E7
+:1009100000000000200052FC200051CC200052FCBE
+:10092000200052FC200051082000510820005108EE
+:1009300020004F4820004F4820004F4020004EAC80
+:1009400020004D5420004B342000490800000000D6
+:1009500000000000200052CC200051982000523CA2
+:100960002000523C20004FF020004FF020004FF0BC
+:1009700020004FF020004FF020004F3820004FF0B3
+:1009800020004C7420004AE4200048B4000000001D
+:100990000000000020000BE0200038BC200004C054
+:1009A000200044A820000BD820003FB4200003F012
+:1009B000200044682000489020003CC420003BE018
+:1009C00020003838200036C42000343420002F9412
+:1009D00020003A3C20002BF4200028282000653419
+:1009E000200023B4200020942000204020001D2C53
+:1009F000200018402000157020000DEC20000C2471
+:100A00002000113420001320200041AC20003C784D
+:100A100020000BE8200004C00000000000000000DF
+:100A200000000000000000000000000000000000C6
+:100A300000000000000000000000000000000000B6
+:100A400000000000000000000000000000000000A6
+:100A50000000000000000000000000000000000096
+:100A60000000000000000000000000000000000086
+:100A70000000000000000000000000000000000076
+:100A80000000000000000000000000000000000066
+:100A900000000000000000003264000000000000C0
+:100AA0003264000064006400640064006400640058
+:100AB000640064000000000000000000000000006E
+:100AC0000000000000000000000000000000000026
+:100AD0000000000000000000000000000000000016
+:100AE0000000000000000000000000000000000006
+:100AF00000000000000000000000000000001000E6
+:100B000000000000000000000000000000000000E5
+:100B100000000000000010000000000000000000C5
+:100B200000000000000000000043238000000000DF
+:100B300000000000000000000000000000000000B5
+:100B400000000000000000000000000000000000A5
+:100B5000005C94015D94025E94035F940043000086
+:100B60000000000000000000000000000000000085
+:100B70000000000000000000000000000000000075
+:100B80000000000000000000000000000000000065
+:100B9000005C90015D90025E90035F900053000046
+:100BA0000000000000000000000000000000000045
+:100BB0000000000000000000000000000000000035
+:100BC0000000000000000000000000000000000025
+:100BD000009C94001D90019D94029E94039F940498
+:100BE0000894050994060A94070B9400430000003A
+:100BF00000000000000000000000000000000000F5
+:100C000000000000000000000000000000000000E4
+:100C1000009C90019D90029E90071D90039F900460
+:100C20007890057990067A90077B90005300000039
+:100C300000000000000000000000000000000000B4
+:100C400000000000000000000000000000000000A4
+:100C500000DC94001D9001DD9402DE9403DF940417
+:100C60000494050594060694070794080894090956
+:100C7000940A0A940B0B940043000000000000004B
+:100C80000000000000000000000000000000000064
+:100C900000DC9001DD9002DE900B1D9003DF9004DC
+:100CA000B49005B59006B69007B79008B89009B90A
+:100CB000900ABA900BBB90005300000063FFFC0049
+:100CC0002000696410FFFF0A00000000200069880E
+:100CD00000D23110FFFE0A0000000000200069D0A1
+:100CE00000D33110FFFE0A000000000020006A104F
+:100CF00000D43110FFFE0A000000000020006A84CA
+:100D000000D53110FFFE0A000000000063FFFC0068
+:100D1000E00000A012FFF78220028257C82163FF83
+:100D2000FC12FFF303E83004EE3005C0309320944A
+:100D300021952263FFFC00001FFFD000000400206B
+:100D40001FFFC5901FFFC670200A0011FFFB13FF95
+:100D5000FB03E63101020016FFFA17FFFAD30F7703
+:100D60006B069060B4667763F85415505419E60F1B
+:100D7000140063FFF90000006C1004C020D10F00C4
+:100D80006C1004C0C71AEF06D830BC2BD720857270
+:100D90000D4211837105450B957202330C237601C8
+:100DA0007B3B04233D089371A32D12EEFE19EEFE4A
+:100DB000A2767D632C2E0A00088202280A01038E87
+:100DC000380E0E42C8EE29A67E6D4A050020880026
+:100DD000308C8271D10FC0F0028F387FC0EA63FF80
+:100DE000E400C0F1C050037E0CA2EE0E3D1208825A
+:100DF0000203F538050542CB5729A67E2FDC100FDC
+:100E00004F366DFA0500208800308CBC75C0300864
+:100E1000E208280A01058338030342C93E29A67E59
+:100E20000D480CD30F6D8A0500208800B08C8271AC
+:100E3000D10FC05008F53875C0C163FFBBC0600258
+:100E4000863876C0DA63FFD46C101216EED8C1F87B
+:100E5000C1E72B221E2C221DC0D07BC12F292006CA
+:100E6000D7B0299CFACC57282070288CFF282470F2
+:100E700064915C2AB0000EA80C6481670FA90C6411
+:100E800092B3C1E97EA13969AC2F600036292006F2
+:100E9000D7D0299CFACC57282070288CFF282470A2
+:100EA0006491352AD0000EA80C6481640FA90C64EB
+:100EB000931BC1E97EA10968AC09C020D10F0000D5
+:100EC000002D25028A32C0900A6F5065F5AD2924A5
+:100ED000670908476585A92F200C18EEB50CFE118F
+:100EE000A8EE28E286B44978930260057A19EEB13B
+:100EF00009F90A2992A3689007882009880C65855A
+:100F00006627E28564756065558E7BC104D9B06043
+:100F10000001C0908B941CEEA80B88148CC40B0BA2
+:100F200047A8CC18EEA609BB1008CC029C7018EE9E
+:100F3000A41CEEA508A8010B88020C4C021BEEA114
+:100F40009C710B880298722C90232B902204C8105D
+:100F500006BB100C4C1208BB0228902107CC100CC9
+:100F600088100C88020B88021CEE998B330CBB0195
+:100F70008C340B880298739C999C748B958C399B4C
+:100F80007588968B38987688979C799B7898771C8B
+:100F9000EE9028E2850CFC082DC4CF08480B28E60B
+:100FA0008565550B2B221E2D221D7BD9022B0A0095
+:100FB00064BF062CB00728B000DA2006880A288211
+:100FC0004CC0D10B8000DBA065AFE763FEEB0000F7
+:100FD000292070659E9C6004E42A207065AEC36081
+:100FE00004DB00002EB0032C2067D4E065C1058A25
+:100FF000328C330AFF500C4554BC5564F4E619EEAC
+:1010000075882A09A90109880C64821BC0926000B6
+:10101000DD2ED0032A2067D4E065A0D88A328B3336
+:101020000AFC500B4554BC5564C4B919EE6A882AB1
+:1010300009A9017989D50BEA5064A4DD0CEE11C031
+:10104000F02F16132E16168AE78CE82A16128EE950
+:10105000DFC0AAEA7EAB01B1CF0BA85065834288FE
+:1010600037DBC0AE89991E789B022BCC012B161B57
+:1010700029120E2B0A0029161A7FC3077FC9027E88
+:10108000AB01C0B165B4988B352F0A002A0A007AEB
+:10109000C30564C3C72F0A0165F4842B12162B16EF
+:1010A00019005104C0C100CC1A2CCCFF2C16170C0F
+:1010B000FC132C16182B121A2A121BDC505818FA83
+:1010C000C0D0C0902E5CF42C12172812182F121BBF
+:1010D0002A121A08FF010CAA018834074C0AAB8BAC
+:1010E0002812192BC6162F86082A86092E74102955
+:1010F00024672E70038975B1EA2A7403B0990949EF
+:101100000C659DB52B20672D250265B3F42B221E9F
+:101110002C221D7BC901C0B064BD9E2CB00728B035
+:1011200000DA2006880A28824CC0D10B8000DBA0A0
+:1011300065AFE763FD8389BAB19965909788341CE0
+:10114000EE2698BA8F331EEE1F0F4F542FB42C8DFE
+:101150002A8A320EDD020CAC017DC9660A49516F44
+:1011600092608A3375A65B2CB0130AED510DCD0148
+:101170000D0D410C0C417DC9492EB012B0EE65E356
+:10118000C2C0D08E378CB88A368FB97CA3077AC993
+:10119000027EFB01C0D1CED988350AAD020E8E0881
+:1011A00078EB022DAC0189B7DAC0AF9B79BB01B1F6
+:1011B000CADCB0C0B07DA3077AD9027CEB01C0B114
+:1011C00064B15DC091292467C020D10F00008ADA84
+:1011D000B1AA64A0BC2E20672D250265E30B1FED8C
+:1011E000F98A3218EDFE0FAF0108FF0C65F2860A8E
+:1011F00048516F820260027DC090292467090A4726
+:1012000065A2F27BC901C0B064BCAE2CB00728B0A7
+:1012100000DA2006880A28824CC0D10B8000DBA0AF
+:1012200065AFE763FC9300000CE9506492EB0CEFB0
+:1012300011C080281611AFBF2F16198EF88BF7DA60
+:10124000E08FF92B1610ABFB7FBB01B1EA0CA85065
+:101250006580D68837DCE0AF89991C789B022CEC3E
+:10126000012C161B29120C2C0A0029161A7AE307E6
+:101270007AE9027FBB01C0C165C2A48B352C0A008C
+:101280002A0A007AE30564E1CA2C0A0164CE1160DF
+:10129000028D88341BEDD198DA8F331EEDCA0F4FC3
+:1012A000542FD42C8C2A8A320ECC020BAB010CBBEF
+:1012B0000C65BF0E0A49516E920263FF058A330A1C
+:1012C000AB5064BEFD2CD0130AEE510ECE010E0EB3
+:1012D000410C0C410ECC0C65CEE82FD012B0FF654E
+:1012E000F26EC0B08E378CD88A362FD2097CA30715
+:1012F0007AC9027EFB01C0B165BEC78835DBA0AEEE
+:101300008E78EB01B1AB89D7DAC0AF9D79DB01B143
+:10131000CAC0C07BA3077AB9027DEB01C0C165CE0C
+:10132000A1C090292467C020D10F88378C3698142B
+:101330000CE90C29161408F80C981D78FB072812E4
+:1013400014B088281614891D9F159B16C0F02B1207
+:101350001429161A2B161B8B147AE30B7AE90688CC
+:10136000158E1678EB01C0F165F1B929121A2F120A
+:10137000118A352E121B9A1AAFEE2F1210C0A0AF91
+:101380009F79FB01B1EE9F11881AC0F098107AE3A3
+:101390000A7EA9052A12017A8B01C0F164F08160EE
+:1013A000018289368B3799170BE80C981F09C90CF5
+:1013B00029161578EB07281215B088281615D9C0FC
+:1013C0009A199E188A1F2E12152A161A2E161BDA23
+:1013D000C0C0E08C177F930B7FA90688188F1978FF
+:1013E000FB01C0E165E13D29121A2F12138A352E47
+:1013F000121B9A1BAFEE2F1212C0A0AF9F79FB01F8
+:10140000B1EE9F13881BC0F098127AE30A7EA905FB
+:101410002A12037A8B01C0F165F1092E12162E16DD
+:10142000192A121B005104C0E100EE1AB0EE2E166C
+:10143000170EFF132F16180FCC01ACAA2F121A0E7D
+:10144000BC01ACFC7FCB01B1AA2A161B2C161A6377
+:10145000FC6200007FB30263FE3163FE2B7EB302A9
+:1014600063FC3463FC2E00006450C0DA20DBF058CB
+:1014700015DEC020D10FC09163FD7E00C09163FADC
+:101480004CDA20DB70C0D12E0A80C09A2924682C47
+:1014900070075814CED2A0D10F034C0B18ED51DBBE
+:1014A000C0A82878C3022BCDF8D9B063FA65000034
+:1014B0002A2C74DB40580E5063FAE80000002D25FA
+:1014C000027BC901C0B064B0172CB00728B000DAA5
+:1014D0002006880A28824CC0D10B8000DBA065AFB3
+:1014E000E7C020D10FC09163FC04022A02580250C9
+:1014F0000AA202060000022A0258024D0AA20206AF
+:101500000000DB70DA20C0D12E0A80C09E2924683A
+:101510002C70075814AEC020D10FC09463FBCF00CD
+:10152000C09663FBC9C09663FBC400002A2C74DB21
+:1015300030DC405BFE13DBA0C2A02AB4002F200CDD
+:1015400063FF27008D358CB77DCB0263FDD263FC32
+:10155000718F358ED77FEB0263FDC563FC6400009D
+:101560006C1004C020D10F006C1004C020D10F00FB
+:101570006C10042B221E28221DC0A0C09429240612
+:101580002A25027B8901DBA0C9B913ED08DA2028DE
+:10159000B0002CB00703880A28824CC0D10B800011
+:1015A000DBA065AFE7C020D10F0000006C1004295C
+:1015B00020062A2102689805289CF965811A0A0AE2
+:1015C0004C65A0F016ECFB2B629E1AECF86FB8028B
+:1015D0006000F12AA22668A0078B200ABB0C65B028
+:1015E000E32A629D64A0DD2B200C0CBC11A6CC2D3F
+:1015F000C2866FD9026000D71DECEF0DBD0A2DD257
+:10160000A368D0078E200DEE0C65E0C327C285C00D
+:10161000E06470BB1DECF468434D1CECF38A2B0CAA
+:10162000AA029A7089200899110D99029971882A45
+:1016300098748F329F75282104088811987718ECC8
+:10164000E40CBF11A6FF2DF285A8B82E84CF2DDCA7
+:10165000282DF685C85A2A2C74DB40580DE7D2A0F5
+:10166000D10FC020D10F00002C9CF964C08D2C201C
+:10167000668931B1CC0C0C472C24666FC669709E0C
+:101680006618ECDA89308F2B0989400B991009FF15
+:101690000208FF029F708C2008CC110DCC029C71B7
+:1016A0008A339A7389329972882A98748F349F7515
+:1016B00063FF820000CC57DA20DB30DC405814B8DE
+:1016C000C020D10F00DA20C0B658154763FFE500EF
+:1016D000DA2058154563FFDC00DA20DB30DC40DD22
+:1016E000505815C7D2A0D10F2B21045813DA1DEC86
+:1016F000BD2B200CC0E02E246663FF842F2123C065
+:10170000C87FC30263FF792C20662B2104B1CC0C67
+:101710000C472C24665813CF1DECB32B200CC0E0D3
+:101720002E246663FF5A00006C1004C0B7C0A116D7
+:10173000ECB015ECA2D720D840B822C04005350245
+:101740009671957002A438040442C94B1AEC95199D
+:10175000EC9629A67EC140D30F6D4A050080880013
+:10176000208C220A88A272D10FC05008A53875B00B
+:10177000E363FFD76C100893149412292006655276
+:1017800088C0716898052A9CF965A29816EC892989
+:1017900021028A1409094C6590C78AA00A6A512A55
+:1017A000ACFD65A0BCCC5FDB30DA208C1258147C19
+:1017B000C0519A14C7BF9BA98E142EE20968E0603D
+:1017C0002F629E1DEC7A6FF8026000812DD2266890
+:1017D000D0052F22007DF9752C629DC79064C06DE5
+:1017E0009C118A142B200C2AA0200CBD11A6DD0A06
+:1017F0004F14BFA809880129D286AF88288C09799F
+:101800008B551FEC6C0FBF0A2FF2A368F00528223E
+:10181000007F894329D285D49065907760003D0090
+:10182000002B200C1FEC640CBD11A6DD29D2860F05
+:10183000BF0A6E96102FF2A368F00488207F8905F6
+:1018400029D285659165DA205814E7600013DA2003
+:10185000C0B65814E5600009C09063FFB9DA20589B
+:1018600014E28914899109FE506551E48C128D149B
+:10187000DA20DBD08DD09E100D6D515813549A1480
+:1018800064A208C75F8FA195A9C0510F0F479F128F
+:1018900063FEFB00C091C0F12820062C2066288C36
+:1018A000F9A7CC0C0C472C24666FC6088D148DD17B
+:1018B00070DE01C090DD90648159C9D32A12012BDA
+:1018C00021045813648A14C0B02B24668EA92AA060
+:1018D000200E28141CEC438D1415EC37C1700A77C8
+:1018E0003685562DDC28AC2C9C13DED0A8557CD335
+:1018F000022EDDF8D3E0DA40055B02DC305BFF8AC4
+:10190000D4A028200CB455C0D02B0A882F0A800CF4
+:101910008C11A6CC29C285AF3FAB9929C6851CEC9A
+:101920002CDEF0AC882D84CF28120329120478F322
+:10193000022EFDF8289020D3E007880CC17008081B
+:1019400047289420087736657FAB891413EC2A89E1
+:1019500090C0F47797491BEC28C1CA28210485144C
+:10196000099E4006EE11875304881185520E8802A5
+:101970000C88029BA09FA18F2B9DA598A497A7954B
+:10198000A603FF029FA22C200C1EEC11AECE0CCCA5
+:101990001106CC082BC2852DE4CF2BBC202BC6858D
+:1019A0002A2C748B12580D14D2A0D10F28203DC0C0
+:1019B000E07C877F2E24670E0A4765A07B1AEC0F18
+:1019C00088201EEBFD8F148EE48FF40888110A889E
+:1019D000020F8F14AFEE1FEC0A98910FEE029E904B
+:1019E0001EEC09C0801AEBFA2CD285AABAB8CC2812
+:1019F000A4CF2CD6852C21022F20700ECC02B1FF53
+:101A00002F24702C2502C020D10F87148770070760
+:101A10004763FD6E282123C099798B0263FE9ADD0E
+:101A2000F063FE9500DA20DB308C12DD505814F4A0
+:101A3000D2A0D10FC0E163FF7A8B148C12DD50C0AD
+:101A4000AA2E0A802A2468DA20581360D2A0D10F67
+:101A5000007096552B629E6EB8531DEBD42DD22686
+:101A600068D0048E207DE9452A629DCBAF2B2104EE
+:101A70002C20665812F8C090292466821418EBE2D4
+:101A80008F2108FF019F21C020D10F008B10C9B802
+:101A90008CA00C6C51CCCC8E241FEBD08DE19E140D
+:101AA0000FDD029DE18810658FA9C020D10FDA20DB
+:101AB000C0B658144DC020D10F0000006C1006298C
+:101AC0002102C0D07597102A32047FA70A8B357F78
+:101AD000BF052D25020DD902090C4C65C18216EBFC
+:101AE000B41EEBB228629EC0FA78F3026001882926
+:101AF000E2266890078A2009AA0C65A17A2A629DCD
+:101B0000DFA064A1772B200C0CBC11A6CC29C286C7
+:101B1000C08C79830260015719EBA709B90A299291
+:101B2000A3689007882009880C65814327C2851C1B
+:101B3000EBA964713A8931098B140CBB016FB11D9B
+:101B40002C20669F10B1CC0C0C472C24666EC6026C
+:101B500060014009FF5065F13A8A102AAC188934B7
+:101B6000C0C47F973C18EBAA1BEBA98F359C719BD7
+:101B7000708B209D7408BB029B72C08298751BEB12
+:101B8000A50F08409B730F881198777FF70B2F21C3
+:101B900002284A0008FF022F2502C0B4600004009A
+:101BA0000000C0B07E97048F362F25227D970488D1
+:101BB000372825217C9736C0F1C0900AF9382F3C90
+:101BC0002009094264908619EB7618EB7728967EF7
+:101BD00000F08800A08C00F08800A08C00F0880045
+:101BE000A08C2A629D2DE4A22AAC182A669D893019
+:101BF0007797388F338A3218EB8007BE0B2C21047D
+:101C0000B4BB04CC1198E0C08498E1882B9DE59A80
+:101C1000E69FE71AEB78099F4006FF110FCC020AF6
+:101C2000880298E2C1FC0FCC022CE604C9B82C2033
+:101C30000C1EEB670CCA11AECC06AA0829A2852D92
+:101C4000C4CF09B90B29A685CF5CC020D10FC081B4
+:101C5000C0900F8938C08779880263FF7263FF667E
+:101C600000CC57DA20DB30DC4058134DC020D10FB8
+:101C7000DA205813DD63FFE8C0A063FE82DA20C0DB
+:101C8000B65813D963FFD900DB402A2C74580C5A7C
+:101C9000D2A0D10F8A102B210458126E1EEB44C023
+:101CA000D02D246663FEB1006C1006D62019EB3FE0
+:101CB0001EEB4128610217EB3E08084C65805F8AE5
+:101CC000300A6A5169A3572B729E6EB83F2A92263A
+:101CD00068A0048C607AC9342A729D2C4CFECAAB71
+:101CE0002B600CB64F0CBD11A7DD28D2860EBE0AA4
+:101CF00078FB269C112EE2A32C160068E0052F62CB
+:101D0000007EF91522D285CF2560000D00DA60C073
+:101D1000B65813B5C85A60010F00DA605813B2659F
+:101D20005106DC40DB308D30DA600D6D51581227E2
+:101D3000D3A064A0F384A1C05104044763FF6D00E5
+:101D4000C0B02C60668931B1CC0C0C472C64666F36
+:101D5000C60270960A2B610458123EC0B02B64660E
+:101D60006550B42A3C10C0E7DC20C0D1C0F002DFCF
+:101D7000380F0F4264F09019EB0A18EB0B28967E8F
+:101D80008D106DDA0500A08800C08CC0A089301DC0
+:101D9000EB1A77975388328C108F3302CE0BC02406
+:101DA00092E12261049DE00422118D6B9BE59FE787
+:101DB00098E61FEB100998400688110822020FDDF3
+:101DC00002C18D9DE208220292E4B4C22E600C1F73
+:101DD000EB000CE811A7882C8285AFEE0C220B2BB0
+:101DE000E4CF228685D2A0D10F28600CD2A08C111E
+:101DF00019EAF80C8D11A988A7DD2ED2852B84CF86
+:101E00000ECC0B2CD685D10FC0F00ADF387FE8024C
+:101E100063FF6C63FF6000002A6C74C0B2DC20DDDD
+:101E20004058121CC0B063FF63C020D10F000000F7
+:101E30006C10042C221D2A221EC049D320293006F2
+:101E4000243468C0407AC105DDA060000200C0D023
+:101E50006E9738C08F2E0A802B3014C09629340616
+:101E60000EBB022E31022B34147E8004243502DE98
+:101E7000407AC10EC8ABDBD0DA302C0A00580A76A3
+:101E80002E31020E0F4CC8FEC020D10F6895F828E5
+:101E9000310208084C658FEF1AEAC61CEAC42BA26F
+:101EA0009EC09A7B9B462BC22668B0048D307BD99E
+:101EB0003B29A29DC0E3CB9394901BEAD72D31041C
+:101EC0009B9608DD110EDD029D979D9112EAD4C00C
+:101ED000E524C4A22E34062F310228A29D02FF025F
+:101EE000288C3028A69D2F3502C020D10FDA30C0B3
+:101EF000B658133DC020D10F6C10062920066898F3
+:101F000005289CF965825D29210209094C6592101A
+:101F1000CD51DB30DA20044C025812A1C051D3A0BD
+:101F2000C7AF2A360AC0E019EAA31DEAA91FEAA230
+:101F30008A3A16EA9FB1AC64C13528629E6F880266
+:101F40006001F129DC332992266890078B2009BBB8
+:101F50000C65B1E027629DC08E6471D82B200C0CFB
+:101F6000BC11A6CC29C2867983026001D219EA91FC
+:101F700009B90A2992A397106890082822000988B5
+:101F80000C6581BB27C2856471B5292006299CF99F
+:101F90006491EC2C20668931B1CC0C0C472C246662
+:101FA0006EC6026001A109F85065819B883689F4EC
+:101FB000088C14AC991CEA810C99022C21049970AC
+:101FC00019EA980808479971892A0988100899021E
+:101FD00018EA95089902997228301329301204885A
+:101FE0001006991008990228302C9A740C88100851
+:101FF000C802098802987389379975883898768A53
+:1020000039C0819A771AEA888935987B9978098945
+:10201000140A9902997A8A30893277A73618EA76B3
+:102020008F33987CC084987D882B2E761129761268
+:102030002F761319EA700A9F4006FF1104CA11098E
+:1020400088020FAA02987EC1F90FAA022A7610C050
+:10205000AA600001C0A6ADBF0CBC11A6CC29C285E8
+:102060002EF4CF09A90B29C685655107C020D10FD1
+:102070002B200C0CBC1106CC0828C28609B90A6FAB
+:10208000890260012E2992A36890082A220009AAD9
+:102090000C65A11F2AC28564A11928203D0828408B
+:1020A00064808C843504841464408485F574537F83
+:1020B0008436048414644077745374293013C08CBC
+:1020C00079886CC0902924670908476580ED8820CD
+:1020D00089F484351FEA4B048414A4940F440294B9
+:1020E000A014EA4608881104880298A1843698A3AF
+:1020F000048414A4990F990299A219EA42ADB42854
+:10210000C2852E44CF288C1028C6852821022F2076
+:1021100070098802B2FF2F2470282502C020D10F39
+:1021200000CC57DA20DB30DC4058121DC020D10F24
+:10213000C09163FF8FDA20C0B65812AB63FFE10095
+:10214000DA205812A963FFD88A102B2104581141B4
+:102150001DEA201FEA192B200CC0E02E24668A3AC3
+:1021600063FE480000DA20DB30DC40DD50581324E9
+:10217000D2A0D10F2A2C74DB40580B1FD2A0D10F54
+:10218000292123C08879830263FE202A12002C2093
+:10219000662B21042CCC010C0C472C246658112DE5
+:1021A0001DEA0C1FEA052B200CC0E02E24668A3A9B
+:1021B00063FDF800DA2058128C63FF64DA205BFFBD
+:1021C0001CD2A0D10F0000006C10089515C061C191
+:1021D000B0D9402A203DC0400BAA010A64382A2009
+:1021E0000629160668A8052CACF965C33B1DE9F263
+:1021F0006440052F120564F29C2621021EE9EE06BA
+:10220000064C6562E315E9EA6440D98A3529300352
+:102210009A140A990C6490CC2C200C8B149C110CF1
+:10222000CC11A5CC9C122CC286B4BB7CB30260023C
+:10223000D38F110EFE0A2EE2A368E0098620D30F89
+:102240000E660C6562BE88122882856482B6891487
+:1022500064905EDA80D9308C201EE9E81FE9E91D20
+:10226000E9D68B148DD4D4B07FB718B88A293C1026
+:10227000853608C6110E66029681058514A5D50F10
+:10228000550295800418146D8927889608CB11088B
+:1022900088140EBB02A8D8299C200F88029BA19805
+:1022A000A088929BA3088814A8D80F880298A22A15
+:1022B000AC1019E9D4C0C08F141EE9C586128D1167
+:1022C000286285AEDD08FF0B2CD4CF2821022F66B3
+:1022D000858B352A2070098802ABAA2825022A247A
+:1022E00070C020D10F29529E18E9B16F9802600288
+:1022F0000828822668800829220008990C6591F92F
+:102300002A529DC1CA9A1364A1EF2B200C262006E5
+:102310000CB811A5882D82860EBE0A7DC30260020C
+:10232000022EE2A368E0082F22000EFF0C65F1F3F5
+:10233000288285DE806481FF9810266CF96461FF35
+:102340002C20668831B1CC0C0C472C24666EC6025A
+:102350006001BC08FD5065D1B617E9B419E9981AB7
+:10236000E99F2C21048B2D2830102F211D0C881063
+:102370000BFB090C88020A880209BB0264415289DE
+:1023800010C04D9B90979198928D35D9E064D06C98
+:10239000D730DBD0D8307FD713273C10BCE92632AA
+:1023A000168C3996E69CE78A37B4389AE80B1314F2
+:1023B0006430492A821686799A9696978C778A7D18
+:1023C0009C982B82172C7C209A9A2A9C189B998681
+:1023D0007BB03BB8896DB9218BC996A52692162A88
+:1023E000AC18B8999BA196A08BC786CD9BA22B92C7
+:1023F0001596A49BA386CB2CCC2026A605C0346BB7
+:10240000D4200D3B0C0DD8090E880A7FB705C0906B
+:102410009988BC88C0900B1A126DAA069988998B6E
+:10242000288C18C0D01BE9831CE98216E978B1FF1B
+:102430002A211C23E6130F0F4F26E6122F251D7F9E
+:10244000A906C0F0C08028251D05F6111AE9718F74
+:10245000202BE6152CE6162DE61726E6180AFA02BA
+:102460002AE614292006299CF96490FF29200C8D66
+:1024700015C0801AE9570C9C11AA99A5CCDA202B1B
+:10248000C2852894CF0B4B0B2BC685C0B08C165839
+:102490001114D2A0D10F8A356FA548D8308BD56DD5
+:1024A000A90C8A860A8A14CBA97AB337288C10C063
+:1024B00080282467080B4765B112DA20DB302C1224
+:1024C00006581137D3A0C0C1C0D02DA4039C1563FA
+:1024D000FD26863664610C8910C04D9B90979198BB
+:1024E0009263FEA4C08163FFC78A15CCA7DA20DB04
+:1024F000308C1658112BC020D10FDA20C0B65811DD
+:10250000BA63FFE400DA208B115811B763FFD900DA
+:102510009E178A132B210458104F8E17C0B02B24FE
+:102520006663FE34C08063FE09DA20DB308C16DD82
+:1025300050581233D2A0D10FDA205811AB63FFA844
+:102540002D2123C0C87DC30263FE0D8A132B2104F5
+:102550002C20669817B1CC0C0C472C246658103DE3
+:102560008E17C0D02D246663FDEE0000262123B017
+:102570006606064F262523656EF128206A7F8705AB
+:102580000829416490A5C0D01BE91C19E92B26201D
+:102590000723E61BB16609FA022BE61A28200A2D4A
+:1025A000E61D2AE61E09880228E61C88260606473C
+:1025B00028E6202B220826E53E2BE6212D24072C99
+:1025C00020062A206468C347B44463FE9EDB30DAE9
+:1025D000208D15C0CE2E0A802C24688C1658107BB6
+:1025E000D2A0D10F8E102A321616E8F30A2A1486CA
+:1025F000662BE61297E127E61328E614AA66096619
+:102600000296E02EEC4869ED50C14663FD7A000069
+:1026100064AFB419E8E928201689920A880C009161
+:102620000400881AA8B8982963FF9C002B21046E27
+:10263000B81E2C2066B8CC0C0C472C2466C9C09E52
+:10264000178A135810048E17C0348F20C0D02D2441
+:1026500066C06826240663FF2C008D35C08064D0D8
+:102660004AD9E0DC30DBE0DF301AE8F4B188B4FFAF
+:1026700017E8F486C9249DFF8DC82CCC102D463058
+:102680000767012D46320A66011DE8EE264631AD88
+:102690006D2D463326F21597B796B684C3BCBB940E
+:1026A000B58D35299C107D83C22F211DC14663FD48
+:1026B0004B0000006C1006292006289CF86582C398
+:1026C0002921022B200C09094C6590E116E8B90C70
+:1026D000BA11A6AA2DA2862C0A127DC3026002900E
+:1026E00019E8B509B90A2992A36890078C2009CC8A
+:1026F0000C65C27C29A2856492762D629E1AE8AB95
+:102700006FD8026002722AA22629160168A0082B3F
+:1027100022000ABB0C65B26029629DC18C6492588C
+:102720002A21200A806099102C203CC7EF000F3E20
+:10273000010B3EB1BD0FDB390BBB098F260DBD115F
+:102740002DDC1C0D0D410EDD038E27B1DD0D0D417D
+:102750000FEE0C0DBB0B2BBC1C0BB7027EC71C2C49
+:1027600021257BCB162D1AFC0CBA0C0DA16000099B
+:102770003E01073EB1780987390B770A77EB026093
+:10278000020A2C2123282121B1CC0C0C4F2C25230B
+:102790007C8B29B0CD2D2523C855DA20DB30580F8E
+:1027A000FA292102CC96C0E80E9E022E2502CC57B3
+:1027B000DA20DB30DC4058107AC020D10F2C2066A4
+:1027C0008931B1CC0C0C472C24666EC6026001D353
+:1027D00009FD5065D1CD2F0A012E30112922146434
+:1027E000E01128221B090C4400C10400FA1A0A88CF
+:1027F0000228261B2E3010C0A0C0B088301CE86E06
+:1028000094129513C04125203C2CC022088D1477CA
+:1028100087052F0A010CFA38C0F2C0840858010F4E
+:102820005F010F4B3805354007BB10C0F0084F382B
+:1028300008FF100FBB0228ECFEC0F0084F38842BB5
+:102840000BA8100AFF102A21200F88020B8802080B
+:10285000440218E87D8F110844022821250A2A1411
+:102860000828140488110A88022A210494F08B2075
+:1028700004E41008BB1104BB02C04A04BB029BF174
+:10288000842A08AB110BEB0294F40A54110B440296
+:102890000555100D1B4094F707BB100B550208554A
+:1028A00002C08195F68433C05094F3B1948B329575
+:1028B000F898F99BF2C080C1BC24261498FB9BF5C4
+:1028C00099FA853895FC843A94FD8B3B9BFE8839B8
+:1028D00098FF853525F6108436851324F6118B373D
+:1028E00084122BF612C0B064C08189307797468D70
+:1028F0003288332E30108F111CE840099940069918
+:10290000112CF614C0C42CF6158C2B2DF61A28F6B3
+:102910001B2BF61904A81109880208EE0219E835E4
+:10292000C18008EE0209C90229F6162EF618C09ECB
+:10293000600004000000C09A2F200C18E8250CFE4F
+:1029400011A8FFA6EE2DE2852BF4CF0D9D0B2DE6F1
+:1029500085C87F8A268929A7AA9A260A990C090977
+:102960004829252565504CC020D10F00C09A63FF2F
+:10297000C6DA2058109D63FE34DA20C0B658109A8B
+:1029800063FE2A00689738C020D10F0000DA20DBF0
+:1029900070581057C0B0C0C10ACA390ACB3865BDDB
+:1029A000E063FE098A102B2104580F2AC0B02B24A3
+:1029B0006663FE21DB402A2C7458090FD2A0D10F88
+:1029C000DA20580F2F63FCF76C1004C020D10F00E1
+:1029D0006C1004290A801EE81D1FE81D1CE7F50C79
+:1029E0002B11ACBB2C2CFC2DB2850FCC029ED19CA4
+:1029F000D0C051C07013E81914E81818E8162AB2AC
+:102A000085A82804240A234691A986B8AA2AB6854F
+:102A1000A98827849F25649FD10F00006C100AD6D7
+:102A200030283010292006288CF964829B68980B86
+:102A30002A9CF965A1B2022A02580F1189371BE7B7
+:102A4000DEC89164520E2A21020A0C4C65C2588DD0
+:102A50003019E7D774D7052E212365E29E2F929E69
+:102A60001AE7D36FF8026002532AA22668A0082C46
+:102A700022000ACC0C65C2442A929D64A23E9A159B
+:102A80001FE7CD8D67C1E664D00E2B620618E7CA3A
+:102A900064B0052880217B8B422B200C18E7C50CE5
+:102AA000BC11A8CC29C28679EB450FBE0A2EE2A341
+:102AB00068E0048F207EF9372CC2859C1864C233ED
+:102AC0002B212F87660B7B360B790C6F9D266ED2E0
+:102AD000462C203D7BC740CE5560001E2A200CC1ED
+:102AE000B28C205810759A1864A2458D6763FFCF89
+:102AF000C0C063FFC5D7B063FFD300C0E060000271
+:102B00002E60030EDB0C6EB20EDC700CEA11AA6AAA
+:102B10002AAC20580199D7A0DA20DB70C1C82D213A
+:102B20002058101B8C268B279A160CBB0C7AB334BA
+:102B30008F18896399F3886298F28E659EF82D60EC
+:102B4000108A189D1768D729C0D09DA92C22182B50
+:102B500022139CAB9BAA97A58E667E73026000979A
+:102B6000CF5860001FDA208B16580FE165A138633B
+:102B7000FFBDC081C0908F18C0A29AF999FB98FA46
+:102B800097F563FFD2DB30DA20DC40580F85C05167
+:102B9000D6A0C0C02BA0102CA4039B172C12080297
+:102BA0002A02066B02DF702D60038E179D149E10A3
+:102BB0000CDD11C0E0AD6D2DDC205801188C148B9C
+:102BC00016ACAC2C64038A268929ABAA0A990C9A04
+:102BD00026886609094829252507880C98662F222A
+:102BE00018A7FF2F261863FE96DA20DB30DC40DDC5
+:102BF00050581083D2A0D10FC0302C20668961B10B
+:102C0000CC0C0C472C24666EC6026000D2C0300982
+:102C1000FD5065D0CA8E6764E069647066DB608CC5
+:102C200018DF70DA202D60038E170CDD119E10ADB9
+:102C30006D2DDC201EE7845800F9232618DA208B3E
+:102C400016DC402F2213DD50B1FF2F2613580F241E
+:102C5000D2A0D10F0028203D084840658DE76F9530
+:102C60003EDA308DB56D990C8CA80C8C14CACF7CD3
+:102C7000D32D2AAC10C090292467090D4764DDC507
+:102C8000600092002C1208066B022D6C20077F0258
+:102C90008E17DA209E101EE76B58007D63FF9A00A6
+:102CA000C09163FFD1000000655081DA20DB60DC59
+:102CB00040580F3BC020C0F02FA403D10FDA20C032
+:102CC000B6580FC963FFE000006F950263FD6CDA30
+:102CD00020DB30DC40DD50C4E0580EBCD2A0D10F68
+:102CE0008A152B2104580E5B232466286010981740
+:102CF00063FF2100DA20580FBC63FFABC858DB30FC
+:102D0000DA20580EA12A210265AF9CC09409A902BD
+:102D100029250263FF91DB30DC40DD50C0A32E0A81
+:102D2000802A2468DA20580EA9D2A0D10FC020D161
+:102D30000FDA202B200C580FC563FF6B6C10042892
+:102D40002006C062288CF8658125C050C7DF2B2281
+:102D50001BC0E12A206B29212300A104B099292559
+:102D600023B1AA00EC1A0BC4010A0A442A246B04FA
+:102D7000E4390DCC030CBB012B261B6440692920D0
+:102D80000C1BE70B0C9A110BAA082FA2861BE70954
+:102D90006FF9026000B60B9B0A2BB2A368B0082C37
+:102DA00022000BCC0C65C0A42BA2851DE72D64B0BE
+:102DB0009B8C2B2421040DCC029CB08820C0C5081C
+:102DC00088110C880298B1882A08441198B48F346D
+:102DD00094B79FB5C0401EE6FE2DA2850E9E082525
+:102DE000E4CF2DDC282DA68529210209094C689401
+:102DF0001A689820C9402A210265A00B2A221E2B9E
+:102E0000221D7AB10265A079C020D10F2C21236543
+:102E1000CFDE6000082E21212D21237EDBD52B2241
+:102E20001E2F221D2525027BF901C0B064BFC413EB
+:102E3000E6DF2CB00728B000DA2003880A28824C8D
+:102E4000C0D10B8000DBA065AFE763FFA62A2C741E
+:102E5000C0B02C0A02580D951CE7039CA08B2008DB
+:102E6000BB1106BB029BA1893499A263FF790000C4
+:102E7000262468DA20DB30DC40DD50580FE1D2A098
+:102E8000D10FDA202B200C580F58C020D10F000092
+:102E90006C1006073D14C080DC30DB40DA20C047F0
+:102EA000C02123BC30032838080842774001B1DD37
+:102EB00064815A1EE6BB19E6BC29E67ED30F6DDAA3
+:102EC0000500508800308CC0E0C02025A03C14E6EE
+:102ED000BAB6D38FC0C0D00F87142440220F8940C8
+:102EE000941077F704C081048238C0F10B2810C019
+:102EF00044C02204540104FD3802520102FE380885
+:102F0000DD10821C07EE100E6E020EDD02242CFE78
+:102F1000C0E004FE380AEE100E88020D88028DAB68
+:102F20001EE6AA08D8020E880298B0C0E80428104D
+:102F30000E5E0184A025A125084411084402052540
+:102F400014045511043402C0810E8E3994B18FAA35
+:102F500084109FB475660C26A11FC0F2062614606B
+:102F60000009000026A120C0F20626140565020F04
+:102F7000770107873905E6100778100866020655BD
+:102F80000295B625A1040AE611085811082802087E
+:102F9000660296B7C060644056649053067E11C0C6
+:102FA000F489C288C30B340B96459847994618E6B6
+:102FB000919F410459110E99021FE68F020E470896
+:102FC000D80298420E99029F40C1E00E990299449E
+:102FD0002FA00CB4380CF91114E67E1EE675A4FF80
+:102FE000AE992E928526F4CF0E880B289685D10FA8
+:102FF0002BA00C1FE66F1CE6760CBE11ACBBAFEE2F
+:103000002DE28526B4CF0D3D0B2DE685D10FC08076
+:1030100005283878480263FEA263FE966C1006C04D
+:10302000C06570F18830C030088714778712C0B04F
+:10303000C0A619E661299022C030CC97C03160004B
+:1030400003C0B0C0A6C0E0C091C0D4C08225203C5F
+:103050000B3F109712831CC0700858010D5D0108CA
+:103060009738C0800B9838077710048810086802DA
+:10307000087702C0800D98382D3CFE0888100D9E00
+:10308000388D2B0AEE1008EE0207EE020CB8100F76
+:10309000DD02053B400EDD029D408920043D100805
+:1030A00099110D99022D210409A90208DD119941F8
+:1030B000872A05B9100D3D020ABB110DBB02087726
+:1030C0000297442821258712082814048811071E16
+:1030D0004007EE100E990275660926211F06261478
+:1030E000600006002621200626140868029B470976
+:1030F0008802984629200CD2C0C0800C9E111BE685
+:10310000341FE62BAB99AFEE2DE2852894CF0DADA1
+:103110000B2DE685D10FDD40C0A6C0B08E51CAE0B0
+:10312000B2AAB1BB2DDC108F500E783698100877FC
+:103130000C9FD898D989538F52991199DB9FDA7EC9
+:103140008309B1CC255C10C97763FFCF88108D113E
+:1031500008E70C9751AD8DD7F078DB01B1F79D539F
+:1031600097528830C030088714088840648ED5652F
+:10317000BEC963FEBC0000006C1004D720B03A88C2
+:1031800020C0308221CAA0742B1E2972046D080F42
+:10319000C980C9918575B133A2527A3B0B742B0853
+:1031A00063FFE900649FECD10FD240D10F00000013
+:1031B0006C1008D630C0709515DA408E3914E5FED3
+:1031C0009A1464E0026451FC2920062A9CF865A246
+:1031D0005F2A21020A0B4C65B21F2C320015E5F460
+:1031E00074C7052D212365D3242E529E1AE5F06F56
+:1031F000E80260021B2AA22668A0082B22000ABB54
+:103200000C65B20C2E529D1DE5EB64E2038B386415
+:10321000B22D9E16C8BC8D691EE5E864D0052EE06F
+:10322000217BEB492E200C18E5E20CEF11A8FF29B9
+:10323000F286C186798B4A17E5DF07E70A2772A372
+:10324000687004882077893925F2856452A2272185
+:103250002E07B73607B90C6F9D01D7B089696E92FA
+:103260004228203D7B873C8A15CDAF600018C1B253
+:103270008C202A200C580E90D5A064A2AC8B6863D9
+:10328000FFCBC05063FFC3C0E06000022E60030E9E
+:103290009B0C6EB20EDC700CEA11AA6A2AAC285B99
+:1032A000FFB6D7A0DA20DB70C1C42D211F580E381D
+:1032B0008C268B27D4A00CBB0C7AB3258A63C090D4
+:1032C0009A538862995898528F659F598E679E5B72
+:1032D0008D6697559D5A8B687B7B748B15CEB3603A
+:1032E000000DDA20DB40580E0265A10D63FFCC0013
+:1032F000DA20DB308C14580DAAD6A0C0C0C0D19DF6
+:10330000152CA403DA20DB60DF70DC50C0E0256000
+:10331000039E101EE5C10C5D11AD6D2DDC285BFF19
+:103320003F8E66A5A88F67286403AF7F77FB01B146
+:10333000EE9E669F678D268C29A4DD0DCC0C9D2604
+:103340008B680C0C482C252507BB0C9B6863FEC3BF
+:103350002C20668961B1CC0C0C472C24666EC60209
+:103360006000B809FD5065D0B2CBBF8E69CBEBDBF6
+:1033700060DC50DF70DA201EE5BC2D6003C0809851
+:10338000100CDD11AD6D2DDC285BFF248B15C942BF
+:103390008A2629220904AA082A26060A990C09095C
+:1033A0004829252565B13CC020D10F00DB602D6C7C
+:1033B00028DF70DA20C0C01EE5AC9C10DC505BFE3C
+:1033C000B463FFC7002D203D0D4D4065DDF96FE56D
+:1033D00022DA308F456DE90C8EAA0E8E14C9E37E79
+:1033E000F3112AAC10C090292467090F4764FDD758
+:1033F00060014100C09163FFED00881565814CDAE2
+:1034000020DB608C14580D66C020C09029A403D125
+:103410000FDA20C0B6580DF463FFDE008A162B21A8
+:1034200004580C8CC0A02A24668B6863FF3A000005
+:10343000002B9CF965B0C5DA20580C9163FD910012
+:103440002B200C0CBA11A5AA2FA286C1C27FC302E1
+:103450006000FC0DB90A2992A36890078C2009CC62
+:103460000C65C0EB26A2856460E52C20668931B12D
+:10347000CC0C0C472C24666FC60270960ADAE02B3F
+:103480002104580C74272466893077974B18E55926
+:103490001DE55A8A328B33C0F42C2104099E400664
+:1034A000EE1104CC110ECC029F61C1E00ECC029D46
+:1034B000608F2B9A669B679C64976508FF029F62EA
+:1034C0002F200C18E5430CFE11A5EE2DE285A8FF78
+:1034D00027F4CF2DDC202DE6858F1565F091C020D7
+:1034E000D10F00002A2C748B14580643D2A0D10FA0
+:1034F00000DA20DBE0580DBC63FEFE0000DA20DBC2
+:10350000308C148D15580E3ED2A0D10F00008815B6
+:10351000C888DA20DB30580C9C2A210265AEDAC05C
+:103520009409A90229250263FECFDA202B200C582A
+:103530000DC763FEC4272468DA20DB302C12042D6B
+:1035400012052E0A80580CA163FC7C00C020D10F0C
+:10355000DA20580DA58A15CDA1DA20033B022C12E2
+:1035600004580D0F27A403C020D10F00C020D10F95
+:103570002A2C748B14580620D2A0D10F6C100C2862
+:103580002102941008084C6583621FE50929F29E08
+:103590006F98026003661DE50529D2266890082A07
+:1035A000220009AA0C65A3542CF29D64C34E2B2063
+:1035B0000C0CB611AF66286286C1EC78E30260039A
+:1035C0004619E4FC09B90A2992A36890078A2009E0
+:1035D000AA0C65A33224628564432CC0E12A310918
+:1035E000C07027246689359A11992A8836991298CD
+:1035F0002B89379813992C883899140858149815E2
+:10360000982D89392A25042E251D29251C28302886
+:10361000C09228243C2A30290808479816098901B5
+:103620002A243D2A311599170A094109A90C299C18
+:10363000EC29251F7E87192D2A000DA06000083E69
+:10364000010A3EB1AD08DA390EAA110A990C2925F2
+:103650001F2A211F18E5060A8160C1D0941A951B04
+:1036600001083E00053EB184054839843C259CFC98
+:103670000D883629201408AA1C8D3D2726182E26D1
+:10368000132E26142E261527261B2E246B2724677F
+:1036900027246808581C0909432924142932112AAF
+:1036A000252E28252F27252427252527252C2725A6
+:1036B000232525202425212D2522841A2D211C8512
+:1036C0001B6FD202600209C0A099186D080AB1AA46
+:1036D00000A10400E91A7D9B0263FFEE8918C080F7
+:1036E000C0E1C070C0D29B1D951B961C9C1E16E4A9
+:1036F000D12C203D15E4E00C0B400DCC010BE7383C
+:103700001DE4C30A77100CE8380B8810C0C49C4134
+:103710000877029D40B0A80988118B209C499D48DC
+:10372000954B9643087702861418E4D115E4B9083E
+:10373000770205BB029B4A9B429746881287110875
+:10374000DA149A4E0D88100D77110877021AE4AC3E
+:1037500006D8140D6610087702974FC78F984D98BA
+:103760004C9845871598440715140D55110A5502B4
+:10377000954715E4C18A262D46102D46182D462062
+:103780002C46112C46192C46212B46122B461A2862
+:1037900046142846152B46228816254624254626FB
+:1037A0008B170A0C48090D4885130EDD1105CC1145
+:1037B0000839400BEB390299101EE4B00DCC020D14
+:1037C0005511082D400655022E461316E47B0FDDD9
+:1037D00011254616080840851B0188100DBB02867E
+:1037E000671DE4A70988020CBB0219E4771CE4A555
+:1037F0002B46172D461BA7661BE4A4C0702C461C45
+:103800000988028C1E28461E2B4623C0908B1D293A
+:10381000461D29461F18E49D29462728462529319B
+:10382000162E200629246A243117962D2425238656
+:103830001CCCE1272407C0D7090E4064E0829A29F6
+:1038400009284164809164409B2D2406C098094951
+:1038500036280AA024628501C404A844282104242F
+:1038600066850888118E3F8A3E2D32100EA41800FE
+:10387000C4040EAE1800EE110ACA530EDD02C0E3F6
+:103880000E880298C11EE48209084E9EC08E2094C4
+:10389000C398C59DC418E44E1DE47F05EE110EAA21
+:1038A000020DAA02A8B82784CF9AC21EE44024F2CF
+:1038B0009D27E4A2244C1824F69D655052C020D1C7
+:1038C0000F2D2406C0A0C09809493604A93863FF0B
+:1038D0007FC0A063FE070000654F6DC098C0A82A96
+:1038E000240663FF6B2D2406C09063FF63CC57DA78
+:1038F00020DB308C10580C2AC020D10F00DA20C0F9
+:10390000B6580CB963FFE500DA20580CB763FFDC4A
+:103910002A2C748B10580538D2A0D10F6C100628B1
+:1039200020068A336F8202600161C05013E42029AF
+:10393000210216E41F699204252502D9502C201576
+:103940009A2814E41D8F2627200B0AFE0C04770901
+:103950002B711C64E1398E428D436FBC0260016F94
+:1039600000E104B0C800881A08A80808D8029827FF
+:103970002B200668B32ECE972B221E2C221D011160
+:10398000027BC901C0B064B0172CB00728B000DAC0
+:103990002003880A28824CC0D10B8000DBA065AFD1
+:1039A000E7C020D10F2D206464DFCA8B29C0F10B42
+:1039B000AB0C66BFC02B200C0CBC11A6CC28C28659
+:1039C0002E0A0878EB611EE3FB0EBE0A2EE2A36806
+:1039D000E0052822007E894F29C2851EE4076490F5
+:1039E000461FE4159E90C084989128200A95930F55
+:1039F000880298928E200FEE029E942F2007882630
+:103A00002F950A98969A972E200625240768E34357
+:103A10002921022AC2851DE3EE2AAC20ADBD25D4A2
+:103A2000CF2AC68563FF4E002E2065CBEDC08228CD
+:103A30002465C9F605E4310002002A62821BE3F71F
+:103A40002941020BAA022A668209E4312921026374
+:103A5000FF23000064DFB88F422E201600F1040D12
+:103A6000EE0C00EE1AAEAE9E2963FFA38A202B3225
+:103A700021B1AA9AB0293221283223B499293621BA
+:103A80007989A92B32222B362163FFA0C020D10FC8
+:103A90009F27252415ACB828751C2B2006C0C12EE5
+:103AA000BCFE64E0AB68B7772DBCFD65DEC72D209A
+:103AB00064C0F064D0868E290EAE0C66E089C0F139
+:103AC00028205A288CFE08CF3865FEE863FF58008E
+:103AD00000E0049310C0810AF30C038339C78F08F8
+:103AE000D80308A80108F80C080819A83303C80C63
+:103AF000A8B828751C030B472B24158310CBB700DF
+:103B0000E104B0BC00CC1AACAC0CDC029C27659E76
+:103B10005EC0B20B990209094F29250263FE5000CD
+:103B20002D206A0D2D4165DF7EDA20C0B0580C755E
+:103B300064AF18C0F163FEEF9F2763FFD02E221FF2
+:103B400065EE3263FF79000028221F658E2763FF30
+:103B50006E252406252502C09063FE196C100665AB
+:103B600071332B4C18C0C7293C18C0A1C08009A8CC
+:103B7000380808426481101CE38A1AE38B2AC67E47
+:103B80002A5CFDD30F6DAA0500B08800908C894097
+:103B9000C0A00988471FE3B4080B47094C50090D22
+:103BA0005304DD10B4CC04CC100D5D029D310CBB70
+:103BB000029B3088438E2098350FEE029E328D2670
+:103BC000D850A6DD9D268E40C0900E5E5064E097D2
+:103BD0001CE39A1EE389038B0BC0F49FB19EB02DAA
+:103BE000200A99B30CDD029DB28F200CFF029FB416
+:103BF0008E262D20079EB68C282DB50A9CB7292429
+:103C0000072F20062B206469F339CBB61DE36B2305
+:103C100020168DD20B330C00D10400331AB48DA3BF
+:103C2000C3932922200C13E36A1FE3610C2E11AF0A
+:103C3000EEA3222924CF2FE285D2A00FDD0B2DE6A3
+:103C400085D10F002E200CB48C0CEB111FE3611DED
+:103C5000E358AFEEADBB22B28529E4CF02C20B22FE
+:103C6000B685D2A0D10F00002E200C1CE3511FE31B
+:103C7000580CEB11AFEEACBB22B28529E4CF028227
+:103C80000B22B685D2A0D10FC0D00BAD387DC802B3
+:103C900063FEEC63FEE08E40272C747BEE12DA703C
+:103CA000C0B32C3C18DD50580A7B8940C08063FEAD
+:103CB000E3DE60DA20DB30DC40DD505800059A108E
+:103CC000DB50077A0258044C881063FEF8000000AD
+:103CD0006C100692121EE3428C40AE2D0C8C472EC7
+:103CE0003C1804CA0BD9A07DA30229ADF875C30204
+:103CF000600084C0B0C023C0A09D106D0844B89F70
+:103D00000EB80A8D900EB70BB8770D6D36ADAA9D23
+:103D1000800D660CD8F000808800708C879068B1A8
+:103D200024B22277D3278891C0D0CB879890279C44
+:103D30001000708800F08C9D91CB6FC08108BB0390
+:103D400075CB3663FFB4B1222EEC1863FFD4859295
+:103D50000D770C86939790A6D67D6B01B1559693FF
+:103D60009592600016B3CC2D9C188810D9D078D3CA
+:103D7000C729DDF863FFC100C0238A421BE3470067
+:103D8000CD322D44029B3092318942854379A10581
+:103D90001EE3430E550187121BE334897095350BE2
+:103DA0009902993288420A880C98428676A6A6968D
+:103DB000768F44AFAF9F44D10F0000006C10089382
+:103DC00011D6308830C091086351080847059838EB
+:103DD0009812282102293CFD08084C6581656591EF
+:103DE000628A630A2B5065B18B0A6F142E0AFF7C1E
+:103DF000A60A2C205ACCC42D0A022D245A7FE00298
+:103E0000600215892888261FE32609880C65820F21
+:103E10002E200B0FEE0B2DE0FE2EE0FF08DD110E25
+:103E2000DD021EE320AEDD1EE3201CE3200EDD01DB
+:103E30000DCC37C180084837B88DB4889810896098
+:103E40001AE2DE7B96218B622AA0219C147BA317A9
+:103E50009D132A200C8B108C20580B978C148D13DB
+:103E6000DBA0CEAC6001C4002E200C1BE2D10CEA1A
+:103E7000110BAA082BA2861FE2CF7BDB3B0FEF0AB8
+:103E80002FF2A368F0052822007F892C2BA28564DD
+:103E9000B0AA87628826DE700C7936097A0C6FAD7D
+:103EA0001C8F279B1508FF0C77F3197E7B729D13DF
+:103EB0009C149B15CF56600025C0B063FFD0D790EF
+:103EC00063FFDD00009D139C14DA20DB70580B08A3
+:103ED0008B158C148D1365A06A8E6263FFCC00DA9B
+:103EE000208B11DC40580AAED6A08B15C051DE7075
+:103EF000DA20DC60DD405BFF768D138C14D9A02EB8
+:103F0000200C1BE2AB1FE2B20CEA11AFEFC0E0AB3A
+:103F1000AA2BA2852EF4CF0B990B29A68563FF1D32
+:103F200000DA20DC60DD40DE708912282007DF50D7
+:103F3000A9882824075BFF09D2A0D10F00DBE0DAB3
+:103F400020580B296550EF2A20140A3A4065A0EB4F
+:103F5000DB60DC40DD30022A0258099CD6A064A058
+:103F6000D584A183A0040447030547951203635138
+:103F7000C05163FE5C2C2006D30F28CCFD6480A5C5
+:103F800068C704C0932924062C2006C0B18D641F85
+:103F9000E28A9D279D289D298FF29D2600F104002D
+:103FA000BB1A00F004B0BE0EDD01C0F0ADBB8D65E4
+:103FB0002F24070D0E5E01EE11AEBB2E0AFEB0BB24
+:103FC0000B0B190EBB36C0E20B0B470EBB372B2475
+:103FD0001618E2820A09450D0B422B240B29240AEC
+:103FE000B4BE2E240C7D88572920162FCCFDB09D01
+:103FF0000A5C520DCC362C246465FDEC0C0C476435
+:10400000CDE618E26D8E2888820C9F0C008104009A
+:10401000FF1AAFEE9E2963FDCF1CE29C63FE1300E6
+:104020001CE29363FE0C8D6563FFA500DA202B2054
+:104030000C580B06645F0FC020D10F00C020D10FB9
+:10404000C093292416C09363FFA000006C1004C025
+:104050006017E2561DE259C3812931012A3008292F
+:10406000240A78A108C3B27BA172D260D10FC0C16B
+:104070006550512625022AD0202F200B290AFB2B20
+:1040800020142E201526241509BB010DFF0928F147
+:104090001C2B2414A8EE2EF51C64A0B52B221E2880
+:1040A000221D0111027B8901DB6064B0172CB0076F
+:1040B00028B000DA2007880A28824CC0D10B800083
+:1040C000DBA065AFE7DB30DC40DD50DA205800D8FC
+:1040D000292102090B4CCAB2D2A0D10F00CC5A2C14
+:1040E00030087BC1372ED02064E02D022A02033B2A
+:1040F00002DC40DD505800CED2A0D10F2B2014B0EE
+:10410000BB2B24140B0F4164F0827CB7CAC0C10CD6
+:104110009C022C2502D2A0D10FC020D10F2E200648
+:1041200069E2C12F21020F0F4C69F1B8262406263F
+:1041300025022B221E28221D2A200B2920150DAA1C
+:10414000092CA11C262415AC9929A51C7B814A6049
+:104150000049B0BB2B24140B0D41CBD67CB7022CED
+:1041600025022B221E2E221D7BE9022B0A0064B0A1
+:10417000172CB00728B000DA2007880A28824CC024
+:10418000D10B8000DBA065AFE7C020D10F2624064D
+:10419000D2A0D10F26240663FFC7DB601DE20764AF
+:1041A000BF422CB00728B000DA2007880A28824CCA
+:1041B000C0D10B8000DBA065AFE71DE1FF63FF24EA
+:1041C0006C1004282006C0646F8564CA5B29201423
+:1041D0007D9726DA20DB30DC40055D025800192986
+:1041E0002102090A4CC8A3C020D10F00C0B10B9B0B
+:1041F000022B2502C020D10F0000022A02033B023D
+:104200002C0A015800CAC9AADA20DB30DC40580960
+:10421000E429A011D3A07E97082C0AFD0C9C012C48
+:10422000A411C0512D201406DD022D241463FFA219
+:10423000DA20DB30DC40DD50C0E0580964D2A0D188
+:104240000F0000006C100616E1DA1CE1DA65513B44
+:10425000C0E117E1D62821028B2008084C65807B3D
+:104260002932000969516993722A629E6EA8482A10
+:10427000722668A0027AB93F2A629DB44FCBA72B61
+:10428000200C0CBD1106DD0828D28678FB150CBF6A
+:104290000A2FF2A368F00488207F89072DD285D3E6
+:1042A0000F65D0602A210419E202D30F7A9B1DDA30
+:1042B00020580864600024002C21041BE1FD7CBB15
+:1042C00013DA20C0B658085FC9536000EFDA2058EF
+:1042D0000A46600006DA20C0B6580A436550DDDCA5
+:1042E00040DB308D30DA200D6D515808B8D3A06412
+:1042F000A0CA1CE1B0C05184A18EA00404470E0ED8
+:104300004763FF50002B2104C08C8931C070DF70DF
+:1043100009F950098F386EB8172C2066AECC0C0CFA
+:10432000472C24667CFB099D105808CA8D10272451
+:104330006694D11EE1B6B8DC9ED0655056C0D7B8A1
+:104340003AC0B1C0F00CBF380F0F42CBF119E19465
+:1043500018E19628967EB04BD30F6DBA0500A08861
+:1043600000C08C2C200CC0201DE19A0CCF11A6FFA0
+:104370002EF285ADCC27C4CF0E4E0B2EF685D10F75
+:10438000C0800AB83878D0CD63FFC1008E300E0EE1
+:104390004763FEBD2A2C742B0A01044D025808BD48
+:1043A0002F200C12E18B0CF911A699A2FF27F4CF54
+:1043B000289285D2A008480B289685D10FC020D11D
+:1043C0000F0000006C1004C060CB55DB30DC4005F2
+:1043D0005D02022A025BFF9B29210209084CC88268
+:1043E000D2A0D10F2B2014B0BB2B24140B0C41CB2B
+:1043F000C57DB7EBC0C10C9C022C2502D2A0D10F09
+:104400000000022A02033B02066C02C0D0C7F72E4E
+:10441000201428310126250228240A0FEE012E241B
+:104420001458010D63FFA300262406D2A0D10F006B
+:104430006C1006282102D62008084C65809D2B2090
+:104440000C12E15B0CB811A2882A8286B5497A93D6
+:104450000260009719E15809B90A2992A3689008E7
+:104460002A620009AA0C65A0822882851CE1636487
+:1044700080799C80B887B14B9B819B10655074C03C
+:10448000A7D970280A01C0D0078D380D0D42CBDEA8
+:104490001FE1441EE1452EF67ED830D30F6D4A054C
+:1044A00000808800908C2E3008C0A000EE322E7460
+:1044B0000028600C19E1470C8D11A2DDA988C020ED
+:1044C0002CD2852284CFD2A00CBC0B2CD685D10F48
+:1044D000C0F0038F387FA0C063FFB400CC582A6CB3
+:1044E00074DB30DC405807F1C020D10FDA60580986
+:1044F000BE63FFE7DD402A6C74C0B0DC705808650D
+:104500002E30088B1000EE322E740028600C19E15A
+:10451000300C8D11A2DDA988C0202CD2852284CF39
+:10452000D2A00CBC0B2CD685D10F00006C10042936
+:104530002014282006B199292414688124C0AF2CA6
+:104540000A012B21022C24067BA004C0D02D2502B9
+:10455000022A02033B02044C02C0D05800BFD2A082
+:10456000D10FC020D10F00006C1004293101C2B45A
+:1045700029240A2A3011C28378A16C7BA169645076
+:10458000472C2006C0686FC562CA572D20147CD7FF
+:1045900022DA20DB30DC40DD505BFFA52921020957
+:1045A0000E4CC8E2C020D10FC0F10F9F022F250290
+:1045B000C020D10FDA20DB30C0C05BFFDC28201424
+:1045C00006880228241463FFC72920151BE0FB2A54
+:1045D000200BC0C09C240BAA092BA11C2C2415ABBA
+:1045E0009929A51C63FF9900C020D10FDA20DB3088
+:1045F000DC40DD50C0E0580875D2A0D10F000000AB
+:104600006C1004CB5513E0F625221F0D46110655FC
+:104610000CA32326221E25261F06440B24261E73C8
+:104620004B1DC852D240D10F280A80C04024261FFB
+:10463000A82828261E28261DD240D10FC020D10F21
+:10464000244DF824261E63FFD80000006C100428B7
+:104650002006D6206E85026000DE17E0D51DE0DC66
+:1046600019E0D5C0C1C0202A8CFC64A1322B6102A4
+:10467000B44E0B0B4C65B0A82B600C2A62000CB832
+:10468000110788082F828609B90A7FE30260009F1C
+:104690002992A368900509AA0C65A09328828564D5
+:1046A000808DB8891BE0DA94819B8065514DC0B73D
+:1046B000B838C0A1C0E009AE380E0E4264E0481A16
+:1046C000E0B81FE0B92FA67EB04A6DAA0500808829
+:1046D00000908CC0A02E600C0CE811A7882F82855A
+:1046E000ADEE0F4F0B2F86852B600622E4CF68B10D
+:1046F0002A296015C0B2C99AD2A02D61022B640686
+:104700000CDD022D6502D10FC0E008AE387EB0B7D7
+:1047100063FFAB00226406D2A0D10F00D2A0D10F5C
+:1047200000CC57DA60DB30DC4058089DC020D10F48
+:10473000DA6058092D63FFE80028221E29221D781F
+:104740009902280A00C176C1C1C1D21BE0A5C124CB
+:10475000AB6B6480437891402A80000CAF0C64F00E
+:10476000AE0DAE0C64E0A802AF0C64F0A207AE0C74
+:1047700064E09C2FACE864F0962EACE764E0902FE8
+:10478000ACE664F08A2A800708A80B088A027B83BB
+:10479000022A8DF8D8A065AFBBC0906000730000FE
+:1047A0002B600C0CB811A7882E82866EE87909BAA6
+:1047B0000A2AA2A368A0048E607AE96B2A82856423
+:1047C000A0651FE08DC0E32E64069EA19FA01FE0A0
+:1047D000B92E600A92A30FEE029EA28E600FEE0227
+:1047E0009EA42F60147AFF4722A417ADBE2F8285A6
+:1047F00022E4CF2FFC182F868563FE702A6C74C0CC
+:10480000B1DC90DD405807A31DE072C0C163FEC457
+:10481000D9A0DA60DB30DC40DD50C2F0C1E009FE37
+:10482000395807EAD2A0D10FDA605808EF63FEF0DA
+:104830002CA4170DBE0829828522E4CF299C1829B3
+:10484000868564500C2A6C74044B0258016BD2A00C
+:10485000D10FC020D10F00006C10062B221E282281
+:104860001D93107B8901C0B0C0C9C03BC1F20406D2
+:10487000401DE05BC0E2C0740747010E4E01AD2D44
+:104880009E11C0402E0A1464B06E6D084428221D8B
+:104890007B81652AB0007EA13B7FA1477B51207CB4
+:1048A000A14968A91768AA1473A111C09F79A10C26
+:1048B000C18B78A107C1AE290A1E29B4007CA12BA7
+:1048C0002AB0070BAB0BDAB07DB3022ABDF8DBA030
+:1048D000CAA563FFB428B01089116987BB649FB86B
+:1048E00063FFDC00647FB463FFD50000646FD0C059
+:1048F00041C1AE2AB40063FFC62B2102CEBE2A22DC
+:104900001D2B221E7AB12A8C107CB1217AB901C0EC
+:10491000B0C9B913E026DA2028B0002CB00703880C
+:104920000A28824CC0D10B8000DBA065AFE7D240E3
+:10493000D10F8910659FD463FFF300006C1008C08D
+:10494000D0C8598C302921020C0C4760000C8E30E5
+:104950000E1E5065E19E292102C0C116E015090B0B
+:104960004C65B0908A300A6E5168E3026000852F72
+:10497000629E1BE00E6EF8532BB22668B0052E2205
+:10498000007BE94727629DB748CB7F97102B200C0F
+:10499000B04E0CBF11A6FF29F2869E12798B4117EB
+:1049A000E00507B70A2772A368700488207789306A
+:1049B00029F285DF90D7906590652A210419E03CA3
+:1049C0007A9B22DA2058069F600029002C21041BC4
+:1049D000E0387CBB18DA20C0B658069AC958600186
+:1049E0004CC09063FFCCDA2058087F600006DA20C4
+:1049F000C0B658087D655135DC40DB308D30DA209B
+:104A00000D6D515806F2C0D0D3A064A12029210217
+:104A1000C05184A18CA00404470C0C4763FF3E00E6
+:104A2000C09C8831DBD008F850089B3828210498B6
+:104A3000116E8823282066AC8C0C0C472C24667CD5
+:104A4000BB159F139E148A108B115807028E148F6A
+:104A500013C0D02D24668A30C092C1C81BDFEC7F02
+:104A6000A6099BF099F12CF40827FC106550A4B816
+:104A70003ADF70C051C08007583808084264806728
+:104A800018DFC819DFC929867E6A420AD30F6DE98B
+:104A90000500A08800F08CC0A08930B4E37F962880
+:104AA000C0F207E90B2C94089B909F912F200C12C9
+:104AB000DFC80CF811A688298285A2FF2DF4CFD279
+:104AC000A009330B238685D10F22200C891218DF11
+:104AD000C00C2B11A6BBA8222D24CF2CB285D2A0AE
+:104AE0000C990B29B685D10FC087C0900A59387927
+:104AF000809663FF8ADB30DA20C0C1C0D05BFF56EE
+:104B0000292102C0D02A9CFE65AE4D2D2502C09001
+:104B100063FE45009E142A2C74C0B1DC70DD405841
+:104B200006DD8E14C0D01BDFB9C1C863FF6AC02088
+:104B3000D10F00006C100628210216DF9D08084CDA
+:104B400065821929629E6F980260022019DF9829F8
+:104B500092266890078A2009AA0C65A20F27629DF9
+:104B6000C0CC6472072B21048E31C0A0DDA00EFEE4
+:104B7000500ECD386EB8102C2066B1CC0C0C472CE2
+:104B800024667CDB026001EFC0C12930081BDF8A8C
+:104B900064909C2F0AFFC0D3B09E64E10268921318
+:104BA0006450882A2C74044B025800930AA202060F
+:104BB000000000002B200C2721040CBC11A6CC29DE
+:104BC000C286280A087983026001B919DF7A09B917
+:104BD0000A2992A36890082E220009EE0C65E1A430
+:104BE0002EC28564E19E26200713DF836E7B026060
+:104BF000019A17DF7A1FDF8319DFB0C0D228200A9D
+:104C000093E09DE1A9690F880298E22F90802A9491
+:104C100080B1FF07FF029FE32EC2851FDF6D0EDE0E
+:104C20000BAFBF2AF4CF2EC685655F76C020D10FAB
+:104C30002830102930112E301300993200ED3264E3
+:104C400080EE2A30141FDF9D00AA3278EF050F9EF8
+:104C5000092DE47F1EDF9B66A0050F98092A84803A
+:104C6000B4A718DF98C76F009104AE9EDDE000AFD7
+:104C70001A00C31A6EE1052DB2000DED0C1EDF9275
+:104C800008D81C063303AE882A848B2EB02E2784C6
+:104C90008C03EE010FEE022EB42E58018F63FEFF3F
+:104CA0002931082925042830142E3109B088648060
+:104CB000A32E240AC0812E30162CB4232E240BB42C
+:104CC000EF2F240C8C378B36292504DEB0DFC00C87
+:104CD0008F390B8E390FEE0264EEC4089F1101C4A8
+:104CE000048D380CB81800C4040CBE1800EE110E68
+:104CF000DD02C0E30EFF021EDF669F719E701EDFA5
+:104D0000658F2098739D7405FF110BCD53C180985A
+:104D1000750FDD020EDD029D721EDF242A24662F30
+:104D2000629D2AE4A22FFC182F669D63FE7100008D
+:104D3000002F30121BDF6600FA3278FF050B980B4C
+:104D40002A847F66D0050B9A0B2DA4802A3011008F
+:104D5000AA3263FF442F240A9E2B63FF56CC57DAF6
+:104D600020DB30DC4058070EC020D10F00DA20C015
+:104D7000B658079D63FFE500DA70580636C0A02AD2
+:104D8000246663FE02DA2058079863FFCFB16928D2
+:104D9000200A8620090947991129240798107F8144
+:104DA0002693E027E50A9AE388109DE119DF428DFA
+:104DB00011096F029FE42DE416098802C0D398E21E
+:104DC0002A240763FE5100001DDF0B0868118F11B4
+:104DD000892B93E008FF02C08F9FE50D990299E2AD
+:104DE000047F11C0D49DE108FF029FE463FFD0005F
+:104DF0006C1004C020D10F006C100485210D3811F7
+:104E000014DEE98622A42408660C962205330B934F
+:104E100021743B13C862D230D10FC030BC29992114
+:104E200099209322D230D10F233DF8932163FFE3E1
+:104E30006C100AD620941817DEDED930B8389819CD
+:104E40009914655252C0E1D2E02E61021DDEDB0EE4
+:104E50000E4C65E1628F308E190F6F512FFCFD658E
+:104E6000F1558EE129D0230E8F5077E66B8F181EF7
+:104E7000DF18B0FF0FF4110F1F146590CE18DF1567
+:104E80008C60A8CCC0B119DEC928600B09CC0B0D11
+:104E9000880929811C28811A2A0A0009880C08BA65
+:104EA000381BDF0B0CA90A2992947B9B0260008CB3
+:104EB0002B600C94160CBD11A7DD29D286B8487959
+:104EC00083026000D219DEBB09B80A2882A39817B2
+:104ED0006880026000A36000A51ADEFF84180AEE55
+:104EE00001CA981BDEB28C192BB0008CC06EB313B4
+:104EF0001DDEAF0C1C520DCC0B2DC295C0A17EDB6C
+:104F0000AE6000380C0C5360000900000018DEF1A0
+:104F10008C60A8CCC0B119DEA528600B09CC0B0DA4
+:104F2000880929811C28811A2A0A0009880C08BAD4
+:104F3000380CA90A2992947E930263FF72DA60C04A
+:104F4000BA58072964507360026600001ADE988C14
+:104F5000192AA0008CC06EA31A18DE940C1C5208EB
+:104F6000CC0B18DEDB2BC295C0A178B30263FF3FE8
+:104F700063FFC9000C0C5363FF09896078991829F5
+:104F8000D285C9922B729E1DDE896EB8232DD22642
+:104F9000991369D00B60000DDA6058071360001791
+:104FA0000088607D890A9A1A29729D9C129915CFF2
+:104FB00095DA60C0B658070C6551F58D148C18DB76
+:104FC000D08DD0066A020D6D51580580D3A09A1479
+:104FD00064A1DD82A085A1B8AF9F19050547020233
+:104FE000479518C05163FE602B6104C08C8931C0A5
+:104FF000A009F950098A386EB81F2C6066A2CC0C43
+:105000000C472C64667CAB119F119E1B8A155805BA
+:10501000918E1B8F11C0A02A64669F1164F0E12954
+:1050200012032812096DF9172F810300908DAEFE2F
+:105030000080889F9200908C008088B89900908CA6
+:1050400065514E8A10851A8B301FDE6B88122960DD
+:105050000708580A2C82942D61040ECC0C2C8694DF
+:105060006FDB3C1CDE95AC9C29C0800B5D50A29987
+:1050700009094729C48065D0DA2E600CC0D01FDE34
+:10508000540CE811AFEEA7882282852DE4CF0242AE
+:105090000B228685D2A0D10F8E300E0E4763FDA65F
+:1050A000A29C0C0C472C64077AB6CD8B602E600A4C
+:1050B000280AFF08E80C64810E18DE7E831682132E
+:1050C000B33902330B2C34162D350AC02392319F8D
+:1050D00030C020923308B20208E80292349832C0FD
+:1050E000802864072B600CD2A01CDE390CBE11A7EF
+:1050F000EE2DE285ACBB28B4CF0D9D0B2DE685D1FE
+:105100000F8B1888138D30B88C0D8F470D4950B414
+:10511000990499100D0D5F04DD1009FF029F800DA9
+:10512000BB029B8165508D851AB83AC0F1C0800CD6
+:10513000F83808084264806B1BDE1A19DE1B29B69A
+:105140007E8D18B0DD6DDA0500A08800C08CC0A08F
+:1051500063FEF30082138B161DDE2B28600AC0E06D
+:105160002EC4800D880202B20B99239F20C0D298D2
+:10517000229D2122600CB2BB0C2D11A7DD28D28507
+:1051800008BB0B18DE132BD685A8222E24CFD2A065
+:10519000D10F9E1B851A2A6C748B185BFF178E1B10
+:1051A00063FEA300C087C0900AF93879809263FF3C
+:1051B00086C020D10F9E1B2A6C74C0B18D18580573
+:1051C000358E1B851A63FE7E886B8213891608BE96
+:1051D000110ECE0202920B9E25B4991EDE069F2070
+:1051E0000E88029822C0EF04D8110E88029824C0BD
+:1051F000E49E21C080D2A02B600C2864071CDDF443
+:105200000CBE11A7EE2DE285ACBB28B4CF0D9D0BD3
+:105210002DE685D10F0000006C1004C020D10F00D6
+:105220006C10048633C071C030600001B1330031AE
+:105230000400741A0462017460F1D10F6C1004024E
+:105240002A02033B025BFFF61CDDDC1BDE24C79F4A
+:1052500088B009A903098A019AB079801EC0F00FAD
+:10526000E4311DDDD30002002BD2821EDE1D2AC1D7
+:10527000020EBB022BD6820AE431D10F28C102C133
+:105280009009880208084F28C50208E431D10F00B0
+:105290006C1004C0C00CE43112DDC81ADDC5000278
+:1052A0000029A28218DE111BDE0F2621020B9901B4
+:1052B00008660129A68226250206E43114DE0C15B3
+:1052C000DE07236A902326128550242611252613F3
+:1052D000222C40D10F0000006C1008D6102B0A645D
+:1052E000291AB41ADDB20D23111CDDB30F2511B834
+:1052F0001898130E551118DDFEAC55A838AA332C9A
+:1053000080FF2A80FEA933288D0129800108AA1177
+:105310002880000CAA0208881109880208AA1C2803
+:105320008C0828160458084C14DDA40AA70224414E
+:10533000162A30802B120407AA28580847B1338B4D
+:1053400013B4559A6004AC28B4662C56277B69E0E8
+:1053500016DDDB9412C050C0D017DD979D15D370B9
+:10536000D4102F60802E60829F169E178816728937
+:105370001A8D128C402A607F0DCC282B3A200CAA63
+:1053800028580835C0B10ABE372E35408F1772F93C
+:105390001A8D128C402A60810DCC282B3A200CAA41
+:1053A0002858082DC0B10ABE372E3542B233B44456
+:1053B000B1556952B6B466C0508F15B877D370B284
+:1053C000FF9F156EF899D10F6C1004C021D10F000A
+:1053D0006C1004270A001CDD761FDD871EDD8A1D88
+:1053E000DD731ADDB51BDDC3C02824B0006D2A753E
+:1053F000AA48288080C09164806100410415DD6E58
+:10540000C03125502E00361A0655010595390C5627
+:10541000110C66082962966E974D0D590A2992243F
+:1054200068900812DDA702420872993B2362951228
+:10543000DD6BCB349F300282020E4402C092993160
+:1054400094329233AD52246295C090244C1024665D
+:105450009524B0002924A0AA42292480B177B14420
+:1054600004044224B400D10FD10FD10F6C10041AE0
+:10547000DD4F2AA00058021C5BFFD5022A02033B25
+:10548000025BFFD11BDD4DC9A12CB102C0D40DCCF4
+:10549000020C0C4F2CB5020CE431D10FC0A00AE471
+:1054A0003118DD430002002F828219DD562EB10231
+:1054B00009FF022F86820EE431D10F006C1004C068
+:1054C0002002E43114DD3D16DD3A00020022628242
+:1054D000234102732F0603E431C020D10F19DD8769
+:1054E0001ADD862841020A2A010988012A668228D3
+:1054F000450208E43115DD7D12DD8225461DD10F00
+:105500006C1004292006289CF96480A02A9CFD6563
+:10551000A0968A288D262F0A087AD9042B221FC824
+:10552000BD2C206464C0812E22090EAE0C66E0788A
+:105530002B200C1EDD1F0CBC11AECC28C28619DD41
+:105540001D78F3026000AD09B90A2992A36890089A
+:105550002E220009EE0C65E09B29C2851FDD276421
+:1055600090929F90C0E41FDD349E9128200AC0E0F5
+:105570009E930F8802989288200F880298942F207B
+:10558000079A979D962F950A2E24072820062920F2
+:105590006468833328C28512DD0E288C20A2B22EC7
+:1055A00024CF28C685C020D10FC020D10F2A206A61
+:1055B0000111020A2A4165AF52DA20C0B05805D164
+:1055C00064AFE5C021D10F00649FC81FDCFB2D2014
+:1055D000168FF209DD0C00F10400DD1AADAD9D2936
+:1055E00012DCFC28C285A2B22E24CF288C2028C62B
+:1055F00085C020D10FC021D10F0000006C100426FF
+:105600000A001BDD4015DCEC28206517DCE9288C3E
+:10561000FE6480940C4D110DBD082CD2F52BD2F4F4
+:105620002ED2F77CB13DB4BB2BD6F47BE9052BD24F
+:10563000F62BD6F47CB92C2AD2F62AD6F52AD6F443
+:1056400006E4310002002872822AFAFF0041042990
+:105650000A012F510200991A0A9903098801287634
+:10566000820FE4312624652BD2F48E5A2CD2F5B069
+:10567000EE9E5A7BCB1629D2F62FD2F70CB80C0926
+:10568000FF0C08FF0C0F2F14C8F96000320BCA0C76
+:105690000A2A14CEA92B5102C0C20CBB020B0B4F1D
+:1056A0002B55020BE431D10F00DB30DA205BFF9485
+:1056B0001BDD1564AF5D0C4D11ADBD63FFA800008F
+:1056C00006E4310002002F728218DCD42E51020849
+:1056D000FF022F76820EE431D10F00006C1004C05F
+:1056E0003003E43116DCB315DCB40002002462821E
+:1056F00074472118DD05875A084801286682CD7352
+:1057000019DD030C2A11AA9922928329928472919D
+:10571000038220CC292B51020BE431C020D10F0091
+:105720001FDCFC2E51020FEE012E55020EE431B0AB
+:105730002DB17C9C5A12DCF708DD112D5619D10FC2
+:105740006C10061BDC9A1EDC9C22B0001ADCF36F86
+:1057500023721DDCDAC04818DCF21FDCF0DC10D547
+:10576000C083F000808600508A6D4A4F0F35110DBE
+:1057700034092440800B560A296294B1330E55092E
+:105780002251400F44110C440A874009A80C02889A
+:105790003622514107883608770CA89929669497D4
+:1057A00040296295874109A80C0288360788360887
+:1057B000770CA8992966959741030342B1380808E8
+:1057C0004298F0D10F1CDCD713DCD827B00023326D
+:1057D000B5647057C091C0D016DCD615DCD4C0407B
+:1057E0002AC00003884328C4006D793C004104B1FD
+:1057F0004400971A7780148E502FB2952DB695AF2E
+:10580000EE2EED2006EE369E5060001877A009833C
+:10581000509D5023B69560000223B295223D20068C
+:10582000223622B695B455B8BBD10F000388432861
+:10583000C400D10F6C1004C04004E43115DCBE007C
+:105840000200885013DCBDCB815BFFBD1CDCBC0CAF
+:105850002D11ADCC2BC2822AC28394507BAB142E67
+:10586000C28429C2850ABD0C0E990C0D990C092918
+:10587000146000050BA90C092914993015DC4F2A76
+:1058800051020AE4312A2CFC58004B2B32000AA2A8
+:10589000022BBCFF9B30CCB6C8A4D2A0D10F000015
+:1058A00004E4311EDC430002002DE2822FBAFF2CFB
+:1058B00051020FDD012DE6820CE431D10F00000012
+:1058C0006C1004D10F0000006C1004C020D10F0038
+:1058D0006C100413DC9BC0D103230923318DC0A0BD
+:1058E0006F340260008D19DC321BDC3317DC940C42
+:1058F0002811A8772672832572822CFAFF765147E9
+:1059000088502E7285255C0425768275E9052572FE
+:10591000842576827659292E72842E76822E76837D
+:105920000AE4310002002392820021042FB1020018
+:10593000D61A0C66030633012396820FE4312672D1
+:105940008325728260000200D8A07659220AE431D1
+:1059500000020023928200210400D21A2FB1020C0F
+:1059600022030232012296820FE431D280D10F004D
+:10597000D280D10FC020D10F6C1004DB30862015EF
+:10598000DC0B280A00282502DA2028B0002CB007FA
+:1059900005880A28824C2D0A010B8000DBA065AF28
+:1059A000E61ADC040A4A0A29A2A3C7BF769101D1EC
+:1059B0000F2BA6A3D10F00006C1004C0D1C7CF1BC2
+:1059C000DBFE19DBFB17DBF90C2811A87786758540
+:1059D00074C0A076516288508E77B455957475E97D
+:1059E00003857695747659278F769F759F740AE4A0
+:1059F00031000200239282B42E2FB10200E1040094
+:105A0000D61A0C66030633012396820FE43186759D
+:105A100083747639280AE4310002002E9282B4227F
+:105A200000210424B10200DF1A0CFF030FEE012E47
+:105A3000968204E431D280D10FD8A07651D6D2809C
+:105A4000D10F00006C1004290A801EDC001FDC004E
+:105A50001CDBD80C2B11ACBB2C2CFC2DB2850FCC35
+:105A6000029ED19CD0C051C07013DBFC14DBFB182C
+:105A7000DBF92AB285A82804240A234691A986B80E
+:105A8000AA2AB685A98827849F25649FD10F000084
+:105A90006C100419DC2C0C2A11A9A98990C48479F2
+:105AA0008B761BDC1AABAC2AC2832CC2847AC16809
+:105AB0008AA02BBC30D3A064A05E0B2B0A2CB2A30F
+:105AC00019DBE568C0071DDC20D30F7DC94AA92971
+:105AD000299D0129901F68913270A603D3A0CA9E08
+:105AE000689210C7AF2AB6A32A2CFC5BFFB3D23052
+:105AF000D10F000013DBC503A3018C311DDBB60CF5
+:105B00008C140DCC012CB6A363FFDC00C020D10F98
+:105B1000DA205BFFCCC020D10FC020D10F000000E5
+:105B20006C1004DB30C0D019DBA1DA202830002251
+:105B3000300708481209880A28824CDC200B8000B4
+:105B40001BDB9C0C4A11ABAA29A28409290B29A6AC
+:105B500084D10F006C1004C04118DB9517DB970C43
+:105B60002611A727277030A866256286007104A336
+:105B70005500441A75414822628415DBB802320B85
+:105B8000C922882117DB940884140744017549054C
+:105B9000C834C020D10FD10F0809471DDBEBC0B2BC
+:105BA0008E201FDB820E0E43AFEC2BC4A00FEE0A3B
+:105BB0002DE6242A6284C0200A990B296684D10F1D
+:105BC000C020D10F6C1004DB30C0D018DB78DA2095
+:105BD00025300022300708580A28824CDC200B8030
+:105BE000008931709E121BDB720C4A11ABAA29A2EC
+:105BF0008409290B29A684D10F09C95268532600AC
+:105C0000910418DB6DC0A12F811200AA1A0AFF02AD
+:105C10002F85121EDB670C4D11AEDD2CD2840C2CAF
+:105C20000B2CD684D10FC0811FDB64B89A0A0A47B7
+:105C30002EF11200A10400881A08EE022EF5121DA2
+:105C4000DB5C0C4C11ADCC2BC2840B2B0B2BC68414
+:105C5000D10F00006C1004DB30C0D019DB54DA2007
+:105C600028300022300709880A28824CDC200B806B
+:105C7000001CDB4F0C4B11ACBB2AB2840A2A0B2A46
+:105C8000B684D10F6C1004C04118DB4916DB4B0CF5
+:105C90002711A626266030A872252286006104A35B
+:105CA0005500441A75410822228402320BD10F009C
+:105CB000C020D10F6C100415DBA502491429561120
+:105CC0002452120208430F8811C073008104003669
+:105CD0001A008104C78F00771A087703074401066A
+:105CE0004402245612D10F006C10066E230260008D
+:105CF000AC6420A7C0A0851013DB7E16DB94C040E7
+:105D0000A6AA2BA2AE0B194164906668915D6892B9
+:105D10005268933C2AA2AA283C7F288C7F0A0A4D0D
+:105D20002980012880002AACF208881109880275B0
+:105D300089462B3D0129B0002BB0010899110B9920
+:105D4000027A9934B8332A2A00B1447249B160000A
+:105D50004A7FBF0715DB7F63FFB90000253AE86380
+:105D6000FFB10000253AE863FFA90000250A64633B
+:105D7000FFA1C05A63FF9C0000705F082534FF0537
+:105D80008C142C34FE70AF0B0A8D142E3D012AE4C6
+:105D9000012DE400DA405BFD5063FFA7D10FD10F66
+:105DA0006C10041ADB0519DB021CDB6A1BDB6BC001
+:105DB00080C07160000D00000022A430B1AA299CAF
+:105DC000107B915F26928679C2156E6262C0206D4B
+:105DD000080AB12200210400741A764BDB63FFEE3F
+:105DE0002292850D6311032514645FCFD650032DD5
+:105DF000436DD9039820B4220644146D492298209B
+:105E000098219822982398249825982698279828AE
+:105E10009829982A982B982C982D982E982F222CD8
+:105E20004063FF971EDAE327E68027E681D10F0063
+:105E3000C02063FF830000006C1004C062C04112E8
+:105E4000DADE1ADADA13DB452AA00023322D19DB59
+:105E50003F2BACFE2992AE6EA30260008E090E406D
+:105E60002D1AC2C2CD0EDC392C251664B0895BFF19
+:105E70009E15DB3B1ADAE52B3AE80A3A015805761B
+:105E80002B21160ABB28D3A02B560058058D8B500A
+:105E90000ABB082A0A0058058C15DB322D21022C7A
+:105EA0003AE80C3C2804DD022D25029C505805845C
+:105EB0008B50AABBC0A15805841CDB2B2D21020CE2
+:105EC0003C2806DD0213DB292D25029C3058057C79
+:105ED0008B30AABBC0A258057C2A2102C0B40BAAF1
+:105EE000020A0A4F2A2502580590D10F242423C301
+:105EF000CC2C251663FF760018DB211CDB1D19DB7B
+:105F00001E1BDB1C17DAF085202E0AFD1FDB1D2D62
+:105F1000202E24F47A24F47E24F4820EDD0124F46D
+:105F2000862E0AF707552806DD02C0750EDD01052D
+:105F30000506AB5BA959C0E8AC5C24C4AB0EDD021E
+:105F400027C4AC2E0ADFA85527B4EC0EDD0124B41B
+:105F5000EBC2E027942C0EDD0224942B2E0A800D38
+:105F60000D4627546C24546B0EDD022D242E63FE47
+:105F7000FC0000006C10042A0A302B0A035BFF4D62
+:105F800012DAF3C390292616C3A1C0B3C08A28260B
+:105F9000175BFF48C03CC3B12B26161ADA872AA02C
+:105FA0002023261764A079C3A2C0B15BFF42C3A21D
+:105FB000C0B15BFF40C3C22C2616C2AFC0B12326BE
+:105FC000175BFF3CC28F282616C0FE2F2617C2E2A1
+:105FD0002E26162A0AA1C0B1C0D82D26175BFF3580
+:105FE0002A0AA12A2616C3A6C0B3C1922926175B86
+:105FF000FF31C3C62C2616C1B32A0AA22B2617C00E
+:10600000B35BFF2C290AA2292616C185282617C2B0
+:10601000FB2F2616C0E72E26171DDADA2D2610D103
+:106020000FC3A2C0B35BFF2363FF82006C10041C8C
+:10603000DAA41BDA9118DAD417DAD516DAD515DA1C
+:10604000D5C0E0C0D414DAA01FDA5CC0288FF06D90
+:106050002A36DAC0D9C07C5B020FC90C1CDA9A0C54
+:106060009C28A8C3A6C22A36802A2584A4C2A7CC0D
+:106070002D248C2B248A2B24872E248BB1BB2E36E7
+:106080009F2C369E2C369DB1AC1CDA7B1BDAC3C02C
+:10609000286D2A33DAC0D9C07C5B020FC90C1CDA28
+:1060A000890C9C28A8C3A6C22A36802B2584A4C2AA
+:1060B000B1BBA7CC2D248C2E248B2A248A2E369F6C
+:1060C0002C369E2C369DB1ACC07919DA791BDAB525
+:1060D00013DAB31ADAB318DAB414DA7A16DAB404C3
+:1060E000F42812DAB304660C040506A252A858AAD2
+:1060F0005AA3539B3029A50027848AC091C0A52AA2
+:10610000848C29848B17DAAC18DAABA75726361D96
+:1061100026361E2E361F16DAA913DAA9A655043321
+:106120000C2826C82E75002D54AC2E54AB2E54AA24
+:106130002326E62326E52E26E7D10F006C10061352
+:10614000DA8717DA8224723D2232937F2F0B6D0893
+:10615000052832937F8F0263FFF3C0C4C0B01ADA00
+:1061600016C051D94004593929A4206E44020BB5F8
+:1061700002C3281EDA11DDB025E422052D392DE4F5
+:1061800021C0501EDA9019DA8018DA8016DA821DE2
+:10619000DA8E94102A724517DA4C6DA94BD450B39D
+:1061A000557A5B17DF50756B071FDA038FF00F5FAF
+:1061B0000C12DA4402F228AE2222D681D54013DA3C
+:1061C00041746B0715D9FD855005450C035328B163
+:1061D00045A73FA832A93322369D22369E24368019
+:1061E0002B369F2BF48B2CF48C14DA5C24424DC09C
+:1061F00030041414C84C6D0806B133041414C8429A
+:1062000063FFF20015D9EAC4400031041AD9EBC08B
+:10621000D193A200DD1AC138B0DD9DA318DA502B4E
+:10622000824D29824E29A51C2882537A871E2C5420
+:10623000008E106FE45D12D9E02F211D23211C2F49
+:10624000251B04330C23251C23251AD10FC06218EB
+:10625000DA3F88807E87D989102654006F94191BF5
+:10626000D9D62AB11C0A1A1404AA0C2AB51C2AB5BC
+:106270001D2AB51A2AB51BD10F1BD9CF2AB11C0A6A
+:106280001A1403AA0C2AB51C2AB51D2AB51A2AB558
+:106290001BD10F001CD9C92BC11D2DC11C2BC51B27
+:1062A00003DD0C2DC51C2DC51AD10F006C1006196D
+:1062B000D9C214DA2612DA2915DA44C73FC0E02E13
+:1062C00056A82E56A92E56AA2E56AB23262918D9E3
+:1062D000EADB101CDA3EC0D42A42452D16019C1080
+:1062E00000B0890A880C2896005BFF942B22E318E3
+:1062F000D9B20B5B149B842A22E48B84B1AA0A5A7C
+:10630000140BAA0C9A852922E509591499862F2283
+:10631000CD0F5F149F875BFF455BFF1623463BC194
+:10632000B01DD9A51CDA032AD1022C463A0BAA02C9
+:106330000A0A4F2AD50258047C5BFEBF5BFE98C058
+:1063400050C0B016D99B14D9A317DA12C0C0C73EEB
+:1063500093122C262DC0306000430000007F9F0F59
+:10636000B155091914659FF4C0500AA9027FA7EF1F
+:1063700018D98FDA5008580A28822C2B0A000B8073
+:1063800000005104D2A0C091C7AF00991A0A990326
+:106390009912CE33642067D3202B200795138C12DB
+:1063A0002A62827CA85F18D98108580A28822CDAD0
+:1063B000500B8000D2A0643FDA8A310A8A1404AA02
+:1063C00001C8298B210B8B1404BB017BA945DDA0DF
+:1063D0007A7B081DD9792DD2000DAD0CDB3019D98F
+:1063E000731AD9B82812030ADA28088C021DD9F5C5
+:1063F00009880A28823C0DAA080B8000652F97D3D4
+:1064000020C0B063FF97CB53B1550050040A09195F
+:1064100063FF4900DAB07B7B071AD9678AA00ABA02
+:106420000C1BD9A88C310BAB280C8A141CD9E6ACF8
+:10643000BB1CD9E504AA012BC68163FF907FA7C7C7
+:1064400063FF62006C100427221EC08008E4311B29
+:10645000D9580002002AB28219D958003104C0610B
+:1064600000661A2991020A6A022AB68209E43115E5
+:10647000D9B30C3811A8532832822432842A8CFCD8
+:106480007841102921022A368297A009690229251C
+:1064900002D10F002B21022C32850B6B022CCCFC7D
+:1064A0002C368297C02B2502D10F00006C1004C03F
+:1064B000E71DD93B1CD93D0D4911D7208B228A20DD
+:1064C0000B4B0BD2A007A80C9B72288CF4C8346F1E
+:1064D0008E026000A21FD933A298AF7B78B334C973
+:1064E0003DC081C0F0028F380F0F42C9FA2CD67E12
+:1064F000D5206D4A0500308800508C8870089808B7
+:1065000078B16CD2A09870D10FC0F0038F387FE0C3
+:10651000DE63FFD8027B0CAFBB0B990C643046D80E
+:1065200030C0F1C05002F5380505426450792CD6D0
+:106530007E0B36122F6C100F4F366DFA05008088D7
+:1065400000208C06440CC081250A0003B208237C7D
+:106550000C0385380505426450592CD67E6D4A05DA
+:1065600000208800308CD2A0A798BC889870D10FEA
+:10657000D2A0BC799970D10FD2302BAD08C0F1C038
+:10658000500BF538050542CB552CD67E083F14C17B
+:10659000600F660C064636D30F6D6A050020880032
+:1065A000B08C827063FF2D00C05003F53875E08019
+:1065B00063FF7A00C06002863876E0A063FF9A002D
+:1065C000C05003F53875E0C363FFBD006C1004D6FE
+:1065D0002068520F695324DA20DB30DC405800F089
+:1065E000D2A0D10FDA20DB30DC405800ED9A242411
+:1065F000240EC02122640FC020D10F00B83BB04C44
+:106600002A2C7489242D200E2E200FA4DDB1EE2E0D
+:10661000240FB0DD2D240E2890072D9003A488B000
+:1066200088B1DD2D94032894075BFFA069511DC03C
+:10663000E082242A600F18D9662A240329600E8F6D
+:106640002029240708FF029F209E64D10FC020D17B
+:106650000F0000006C1004942319D95EC0B3083AEF
+:10666000110BAA02992019D8D29A2116D8D0C0505D
+:1066700028929D2564A2288C1828969DD10F000091
+:106680006C1004282066C038232406B788282466A6
+:10669000D10F00006C1006035A0C0D36110D5C1161
+:1066A000D8208B2282210CBB0C06550F9B82023214
+:1066B0000B928113D8BCD920A38F6450531CD8B837
+:1066C000C0D71BD8B9A256C0E1290A0004E938098D
+:1066D000094276F34A044302C99E2BC67E6DAA0581
+:1066E00000208800308C8981A95909FA0C64A079AE
+:1066F00099818A82C8ADD290D10FC06002E6387607
+:10670000D0DA63FFD4C020BC89998199809282D16C
+:106710000F7F2304292DF8998165BFD963FFE50018
+:10672000028F0CA3FF0F3312931003AA0CD340CB9C
+:106730009E2BC67E86106D6A0500208800308CBCBA
+:1067400082290A0004F308240A010349380909428E
+:10675000CA982BC67E6DAA0500208800308C0F5980
+:106760000CA989BC99998163FF87BC89998163FFD2
+:1067700080C06002E63876D0BA63FFB4C0700247CA
+:106780003877D0D063FFCA006C100414D895C1527A
+:10679000A424CA3028221D73811B292102CD952AE9
+:1067A000300075A912DA20033B022C30072D0A02B3
+:1067B0005801C2653FDDD10F2B300703BB0BDAB0A8
+:1067C00074B3022ABDF8D3A063FFC6006C1004297D
+:1067D0002006C0706E9741292102C08F2A2014C064
+:1067E000B62B240606AA022A241479800227250241
+:1067F0002A221E2C221D7AC10EC8ABDA20DB302CD7
+:106800000A00033D025BF8146450752D21020D0D42
+:106810004CC9D3C020D10F00002E9CFB64E0822F16
+:1068200021020F0F4C65F0911AD8621CD86029A282
+:106830009EC08A798B5D2BC22668B0048D207BD9DF
+:106840005229A29DC0F364904A97901DD8732E21BF
+:10685000049D9608EE110FEE029E979E9118D86F38
+:10686000C0E527C4A22E24062BA29D2F21022BBCFB
+:106870003008FF022F25022BA69DC020D10F00005B
+:10688000002F300068F938DA20DB30DC4058004453
+:1068900063FF7700022A022B0A065800D3220A005F
+:1068A000D10F655010283000688924022A02033B6A
+:1068B00002DC4058003BC020D10FD270D10F000045
+:1068C0002A2C74033B02044C025BFEF863FF3B007E
+:1068D000DB30DC402A2C745BFEF5C020D10F0000B9
+:1068E0006C1004C83F89268829A399992609880C29
+:1068F000080848282525CC52C020D10FDB402A2C7F
+:10690000745BF93DD2A0D10F6C1004D820D730822F
+:10691000220D451105220C928264207407420B134C
+:10692000D821D420A383732302242DF885807451A9
+:106930004CBC82C0906D081600408800708C77397E
+:1069400003D720C0918680743901D420746102631A
+:10695000FFE2CA98C097C0411BD8A0C0A00B8B0C07
+:106960000B4A380A0A42C9AA1DD80E1CD80F2CD6C9
+:106970007EC140D30F6D4A0500208800308C97807F
+:10698000D270D10FBC8FC0E00F4E387E90E263FF13
+:10699000D6BC8292819280C0209282D10F000000EA
+:1069A0006C1006C0D71CD7FE1BD8000D4911D7208C
+:1069B0002E221F28221D0E4E0BD280078A0C2E7607
+:1069C0001F2AAC80C8346FAE026000CB2F0A801A39
+:1069D000D804A29EAA7A7EA33FC93FC0E1C050025C
+:1069E000E538050542CA552BC67EDB20D30F6D4A1C
+:1069F0000500308800B08C2E721DAE9E0EA50C6472
+:106A00005086D2802E761DC091298403D10FC050AC
+:106A100003E53875D0D363FFCD15D7F1027E0CA501
+:106A2000EE643051C0A1250A0002A538033A0205E0
+:106A300005426450922BC67E0E35129510255C10CF
+:106A4000054536D30F6D5A0500A08800208CC0A1E3
+:106A5000A3E2C05023FA8003730C03A538AF73057B
+:106A600005426450722BC67E851005450C6D5A0593
+:106A700000208800308CD280C0A10E9B0CAB7BAF75
+:106A8000BB2B761D2A8403D10FD280C0C1AF7D2DD0
+:106A9000761D2C8403D10F00D2302E8D08C0F1C09A
+:106AA000500EF538050542CB592BC67E0A3F14C15E
+:106AB000600F660C064636D30F6D6A05002088000D
+:106AC000E08C22721D63FF03C061C05003653875FE
+:106AD000D80263FF6263FF5CC05002A53875D0879F
+:106AE00063FF8100C06003F63876D0BF63FFB90052
+:106AF0006C10042A201529201614D7AF0A990CCB44
+:106B00009D2E200B04ED092BD11C8F2809BC36AC1F
+:106B1000AA0CBB0C2BD51C0A0A472A2415CAAF8B1A
+:106B2000438942B0A800910400881AA8FF0FBB0255
+:106B30009B278F260FB80C783B1AC020D10F00007E
+:106B4000292102C0A20A9902292502C021D10F00E1
+:106B50008B2763FFDC2BD11C0CAA0C0A0A472A24C2
+:106B600015ACBB2BD51CC9AE8B438C288F42B0AD66
+:106B700000F10400DD1AADCC0CBB029B27DA20B774
+:106B8000EB580019C021D10F9F2763FFEF000000D1
+:106B90006C100428203C64304705306000073E013B
+:106BA000053EB156076539054928C77FA933030655
+:106BB00041076603B166060641A6337E871E222181
+:106BC00025291AFC732B1502380C09816000063E3A
+:106BD00001023EB12406423903220AD10FD230D13C
+:106BE0000FC05163FFC000006C100427221EC0803C
+:106BF00008E4311DD76F0002002CD2821BD76F0032
+:106C00003104C06100661A2BB1020C6C022CD682D2
+:106C10000BE43119D7F20C3A11AA932832829780EB
+:106C2000253282243284B45525368275410A2921C1
+:106C300002096902292502D10F2A21022B32830A77
+:106C40006A022B36822A2502D10F00006C1004192B
+:106C5000D76327221EC08009770208E4311DD7546C
+:106C60000002002CD2821BD754003104C0610066A0
+:106C70001A2BB1020C6C022CD6820BE43119D7D737
+:106C80000C3A11AA932832829780253282243284CA
+:106C9000B45525368275410B2A21020A6A022A253B
+:106CA00002D10F002B21022C32830B6B022C368277
+:106CB0002B2502D10F0000006C10041BD73D0C2ABD
+:106CC00011ABAA29A286B438798B221BD73A19D7DF
+:106CD000610B2B0A2BB2A309290868B00274B90D05
+:106CE000299D0129901F6E920822A285D10FC020F4
+:106CF000D10FC892C020D10FDA205BEF35C020D170
+:106D00000F0000006C100414D72A28429E19D727C0
+:106D10006F88026000BA2992266890078A2009AA23
+:106D20000C65A0AC2A429DC0DC64A0A42B200C19E9
+:106D3000D7210CBC11A4CC2EC28609B90A7ED3027D
+:106D400060009A2992A36890078D2009DD0C65D018
+:106D50008C25C2856450862D2104C0306ED80D2C40
+:106D60002066B8CC0C0C472C246665C07B1CD79CD5
+:106D700018D7281AD71E19D72F1DD724C0E49E5123
+:106D80009D508F209357935599539A569A5408FFC4
+:106D9000021AD73A9F5288269F5A9E599D58935E51
+:106DA0009C5D935C9A5B080848058811985FC0D881
+:106DB0001FD7080CB911A499289285AFBF23F4CF2F
+:106DC000288C402896858E262D24069E29C020D109
+:106DD0000FCA33DA20C0B65BFF84C72FD10FC93A80
+:106DE000DA205BFF81C72FD10FDBD05BFE1A232493
+:106DF000662B200C63FF7500C72FD10FC72FD10F53
+:106E00006C1004C85B29200668941C689607C02093
+:106E1000D10FC020D10FDA20DB30DC40DD502E0A4C
+:106E2000005BFE6AD2A0D10F2E200C18D6E10CEF29
+:106E300011A8FF29F286C088798B751AD6DE0AEA76
+:106E40000A2AA2A368A0048B207AB96423F285647D
+:106E5000305E1CD6E82A0A802D2068292067282168
+:106E6000040B991104881109880208DD02C09428D6
+:106E70004A1008DD0218D6E0993198308B2B9A37EA
+:106E80009D340CBB029B32C0C09C359C362A2C74AE
+:106E9000DB40C0D318D6CF29F285A8EE299C202C40
+:106EA000E4CF29F6852D2406DD405BFDFAD2A0D182
+:106EB0000FDA20DBE05BFF4CC020D10F6C100AD64C
+:106EC000302A2006941128ACF86583872B2122C034
+:106ED000F22A21246550082AAC010A0A4F2A2524E7
+:106EE0007ABB0260037F2C21020C0C4C65C3192E67
+:106EF00022158D32C0910EDD0C65D39088381ED6D8
+:106F0000AC64836B8C37C0B8C0960CB9399914B493
+:106F10009A9A120D991199138F6718D6A7C9FB2851
+:106F200080217F83168B142C22002A200C5BFF62A9
+:106F3000D4A064A3A88F6760002800002B200C89D0
+:106F4000120CBA11AEAA2CA2861DD69A7C9B3E0DBD
+:106F5000BD0A2DD2A368D00488207D893024A28563
+:106F600064436427212E07F73607F90C6F9D01D77C
+:106F7000F0DA20DB70C1C42D211F5BFF0589268854
+:106F800027DDA009880C7A8B179A10600006C04094
+:106F900063FFCC0000DA208B105BFED58D1065A25C
+:106FA00067C0E09E488C649C498B658A669B4A9AC0
+:106FB0004B97458F677F7302600120CD529D10DA99
+:106FC00020DB302C12015BFE768D10C051D6A08FD5
+:106FD000A7C0C08A68974D9A4C8869896A984E996B
+:106FE0004F8E6A8A69AE7E77EB01B1AA9E6A9A6972
+:106FF0008B60C0A00B8E1477B701C0A1C091C08474
+:1070000093159D179516C0D025203CC03008580117
+:10701000089338C082083310085B010535400B9D8A
+:107020003807DD100BAB100E19402A211F079910ED
+:1070300003DD020DBB020553100933020A55112965
+:1070400021250A2A140929140499110A99020933DD
+:10705000028A2B2921040BAA021BD6E208991109E6
+:1070600055020855020BAA029A40892088140899F3
+:107070001109880219D6631DD6DC09880298418B54
+:107080002A9346954783150DBB0285168D179B44A1
+:107090008A658966AACAA97C77CB01B1AA07FB0CCD
+:1070A0009C669A6588268E29AD87972607EE0C0E7A
+:1070B0000E482E25259B672B200C87131ED63D0CD2
+:1070C000B911AE99289285A78828968517D641C010
+:1070D00090A7BB29B4CF871863FE3C008C60C0E04A
+:1070E000C091C0F0C034C0B82A210428203C08AAAE
+:1070F000110B8B01038301039F380B9B39C03208AE
+:10710000FF10038801089E380C881407EE100FEE5C
+:107110000203880108983905BF1029211F0ABB11F5
+:1071200007881008FF020BAA0218D6350929140394
+:10713000AA022B212583200B2B1404BB1108331129
+:107140000FBB020B99028B148F2A0B3302083302F8
+:107150008B2B6470868868974D984C8769886A93F2
+:10716000419946974E984FC07077C701C0719A47B2
+:1071700018D69E0B7C100CEC0208F802984418D626
+:107180009B0CBC0208CC029C402A200C295CFEC04F
+:10719000801FD6071CD60F0CAE112B2124ACAAAF32
+:1071A000EEB0BB8F132CE28528A4CFAFCC2CE685A4
+:1071B0002A22152B2524B1AA2A26156490DBC9D2D0
+:1071C0008F262E22090DFF082F26060FEE0C0E0E1D
+:1071D000482E25256550E4C020D10F00C070934192
+:1071E0009F4499469A4777C70A1CD5F32CC022C002
+:1071F000810C87381CD67F0B781008E80208B8028B
+:107200000C8802984063FF8000CC57DA20DB608C4A
+:10721000115BFDE3292102689806689403C020D120
+:107220000F2B221EC0A029221D2A25027B9901C0F6
+:10723000B064BFE813D5DE2CB00728B000DA200315
+:10724000880A28824CC0D10B8000DBA065AFE763C1
+:10725000FFCA000068A779DA20DB30DC40DD505B34
+:10726000FEE8D2A0D10FC16DC19D29252C6000047C
+:1072700029252CD6902624672F2468DA20DB308C31
+:1072800011DD502E0A805BFD51D2A0D10FC168C123
+:10729000A82A252C63FFDD000000C8DF8C268B297F
+:1072A000ADCC9C260CBB0C0B0B482B25252A2C7433
+:1072B000DB602C12015BFD94D2A0D10F2A2C748BC1
+:1072C000115BF6CDD2A0D10FDA205BFE4763FF3809
+:1072D00000DA20C0B15BFE8B65AF2D63FBEDDA20D9
+:1072E0002B200C5BFE5A63FF1F00000012D6428267
+:1072F00020028257C82163FFFC12D63E03E8300407
+:10730000EE3005B13093209421952263FFFC0000FC
+:1073100010D63A910092019302940311D611821073
+:1073200001EA30A21101F031C04004E4160002006D
+:1073300011D6338210234A00032202921011D5FD88
+:10734000C021921004E43184038302820181000091
+:10735000D23001230000000010D62A910092019340
+:1073600002940311D600821001EA30A21101F1311A
+:10737000C04004E41600020011D621821013D5A7E4
+:10738000032202921004E43184038302820181000B
+:1073900000D330013300000010D61B91008101653D
+:1073A000104981026510448103CF1F92019302941A
+:1073B0000311D5EE821001EA30A21101F231C04072
+:1073C00004E41600020011D60D821013D58E03229C
+:1073D00002921004E431840383028201C0109103FD
+:1073E00091029101810000D43001430012D5BDC04B
+:1073F0003028374028374428374828374C233D0168
+:107400007233ED03020063FFFC00000010D5FF9112
+:107410000092019302940311D5FD8210921011D5B0
+:10742000AF8310032202921011D5FA12D5C1921027
+:10743000C04004E41600020011D5F1821013D5A853
+:10744000032202921004E43184038302820181004A
+:1074500000D53001530000006C10026E322FD62090
+:10746000056F04043F04745B2A05440C00410400CA
+:10747000331A220A006D490D73630403660CB122AE
+:107480000F2211031314736302222C01D10FC83B86
+:10749000D10F000073630CC021D10F000000000069
+:1074A00044495630C020D10F6C10020040046B4C90
+:1074B00007032318020219D10F020319C020D10FAC
+:1074C0006C100202EA30D10F6C1002CC2503F031AF
+:1074D00060000F006F220503F1316000056F230586
+:1074E00003F231000200D10F6C1002CC2502F03003
+:1074F000D10F00006F220402F130D10F6F2304027C
+:10750000F230D10FC020D10F6C1002220A20230AC2
+:10751000006D280E28374028374428374828374C34
+:10752000233D01030200D10F6C100202E431D10FA0
+:107530000A0000004368656C73696F204657204459
+:10754000454255473D3020284275696C7420576587
+:1075500064204F63742020382031353A35303A3575
+:1075600030205044542032303038206F6E20636C0D
+:10757000656F70617472613A2F686F6D652F666513
+:107580006C69782F772F66775F372E30292C20563D
+:10759000657273696F6E2054337878203030372EDF
+:1075A00030312E3030202D203130303730313030F6
+:0875B000100701006F4EF8BB4B
+:00000001FF
diff --git a/firmware/tehuti/bdx.bin.ihex b/firmware/tehuti/bdx.bin.ihex
new file mode 100644 (file)
index 0000000..b029e4c
--- /dev/null
@@ -0,0 +1,2678 @@
+:1000000002000F00008071402D000000000000C0C1
+:1000100002000F00018071002D000000000080C070
+:1000200002000F00028071002D000000000000C1DE
+:1000300002000F00038071002D000000000080C14D
+:1000400002000F00048071002D000000000000C2BB
+:1000500002000F00058071002D000000000080C22A
+:1000600002000F00068071002D000000000000C398
+:1000700002000F00078071002D000000000080C307
+:1000800002000F00088071002D000000000000C475
+:1000900002000F00098071002D000000000080C4E4
+:1000A00002000F000A8071002D000000000000C552
+:1000B00002000F000B8071002D000000000080C5C1
+:1000C00002000F000C8071002D000000000000C62F
+:1000D00002000F000D8071002D000000000080C69E
+:1000E00002000F000E8071002D000000000000C70C
+:1000F00002000F000F8071002D000000000080C77B
+:1001000002000F00108071002D000000000000C8E8
+:1001100002000F00118071002D000000000080C857
+:1001200002000F00128071002D000000000000C9C5
+:1001300002000F00138071002D000000000080C934
+:1001400002000F00148071002D000000000000CAA2
+:1001500002000F00158071002D000000000080CA11
+:1001600002000F00168071002D000000000000CB7F
+:1001700002000F00178071002D000000000080CBEE
+:1001800002000F00188071002D000000000000CC5C
+:1001900002000F00198071002D000000000080CCCB
+:1001A00002000F001A8071002D000000000000CD39
+:1001B00002000F001B8071002D000000000080CDA8
+:1001C00002000F001C8071002D000000000000CE16
+:1001D00002000F001D8071002D000000000080CE85
+:1001E00002000F001E8071002D000000000000CFF3
+:1001F00002000F001F8071002D000000000080CF62
+:1002000002000F00208071002D000000000000D0CF
+:1002100002000F00218071002D000000000080D03E
+:1002200002000F00228071002D000000000000D1AC
+:1002300002000F00238071002D000000000080D11B
+:1002400002000F00248071002D000000000000D289
+:1002500002000F00258071002D000000000080D2F8
+:1002600002000F00268071002D000000000000D366
+:1002700002000F00278071002D000000000080D3D5
+:1002800002000F00288071002D000000000000D443
+:1002900002000F00298071002D000000000080D4B2
+:1002A00002000F002A8071002D000000000000D520
+:1002B00002000F002B8071002D000000000080D58F
+:1002C00002000F002C8071002D000000000000D6FD
+:1002D00002000F002D8071002D000000000080D66C
+:1002E00002000F002E8071002D000000000000D7DA
+:1002F00002000F002F8071002D000000000080D749
+:1003000002000F00308071002D000000000000D8B6
+:1003100002000F00318071002D000000000080D825
+:1003200002000F00328071002D000000000000D993
+:1003300002000F00338071002D000000000080D902
+:1003400002000F00348071002D000000000000DA70
+:1003500002000F00358071002D000000000080DADF
+:1003600002000F00368071002D000000000000DB4D
+:1003700002000F00378071002D000000000080DBBC
+:1003800002000F00388071007B000000008060DDFB
+:1003900002000F00398071002D000000000000DD18
+:1003A00002000F003A8071002D000000000080DB89
+:1003B00002000F003B8071002D000000000000DDF6
+:1003C00002000F003C8071002D000000000000DDE5
+:1003D00002000F003D8071000000000000000000DE
+:1003E00002000F003E8071000000000000000000CD
+:1003F00002000F003F8071000000000000000000BC
+:1004000002000F00408071000000000000000000AA
+:1004100002000F0041807100000000000000000099
+:1004200002000F0042807100000000000000000088
+:1004300002000F0043807100000000000000000077
+:1004400002000F0044807100000000000000000066
+:1004500002000F0045807100000000000000000055
+:1004600002000F0046807100000000000000000044
+:1004700002000F0047807100000000000000000033
+:1004800002000F0048807100000000000000000022
+:1004900002000F0049807100000000000000000011
+:1004A00002000F004A807100000000000000000000
+:1004B00002000F004B8071000000000000000000EF
+:1004C00002000F004C8071000000000000000000DE
+:1004D00002000F004D8071000000000000000000CD
+:1004E00002000F004E8071000000000000000000BC
+:1004F00002000F004F8071000000000000000000AB
+:1005000002000F0050807100000000000000000099
+:1005100002000F0051807100000000000000000088
+:1005200002000F0052807100000000000000000077
+:1005300002000F0053807100000000000000000066
+:1005400002000F0054807100000000000000000055
+:1005500002000F0055807100000000000000000044
+:1005600002000F0056807100000000000000000033
+:1005700002000F0057807100000000000000000022
+:1005800002000F0058807100000000000000000011
+:1005900002000F0059807100000000000000000000
+:1005A00002000F005A8071000000000000000000EF
+:1005B00002000F005B8071000000000000000000DE
+:1005C00002000F005C8071000000000000000000CD
+:1005D00002000F005D8071000000000000000000BC
+:1005E00002000F005E8071000000000000000000AB
+:1005F00002000F005F80710000000000000000009A
+:1006000002000F0060807100000000000000000088
+:1006100002000F0061807100000000000000000077
+:1006200002000F0062807100000000000000000066
+:1006300002000F0063807100000000000000000055
+:1006400002000F00648071002D000000000000DB3C
+:1006500002000F00658071003F000000040100DD12
+:1006600002000F00668071003F000000010018DDED
+:1006700002000F0067807100690000007A3D00DD14
+:1006800002000F00688071003F000000040800DDD8
+:1006900002000F0069807100690000007A3D00DDF2
+:1006A00002000F006A8071003F000000043000DD8E
+:1006B00002000F006B8071003F000000010018DD98
+:1006C00002000F006C807100690000007A3D00DDBF
+:1006D00002000F006D8071003F000000040000DD8B
+:1006E00002000F006E807100690000007A3D00DD9D
+:1006F00002000F006F8071003F000000043D00DD2C
+:1007000002000F00708071003F000000010018DD42
+:1007100002000F0071807100690000007A3D00DD69
+:1007200002000F00728071003F000000040700DD2E
+:1007300002000F0073807100690000007A3D00DD47
+:1007400002000F00748071003F000000842800DD6B
+:1007500002000F00758071003F000000010018DDED
+:1007600002000F0076807100690000007A3D00DD14
+:1007700002000F00778071003F000000043700DDA9
+:1007800002000F0078807100690000007A3D00DDF2
+:1007900002000F00798071003F000000042900DD95
+:1007A00002000F007A8071003F000000010018DD98
+:1007B00002000F007B807100690000007A3D00DDBF
+:1007C00002000F007C8071003F00000004AA04DDDD
+:1007D00002000F007D807100690000007A3D00DD9D
+:1007E00002000F007E8071003F000000042800DD41
+:1007F00002000F007F8071003F000000010018DD43
+:1008000002000F0080807100690000007A3D00DD69
+:1008100002000F00818071003F000000043100DD04
+:1008200002000F0082807100690000007A3D00DD47
+:1008300002000F00838071003F000000842B00DD68
+:1008400002000F00848071003F000000010018DDED
+:1008500002000F0085807100690000007A3D00DD14
+:1008600002000F00868071003F00000004E401DDFB
+:1008700002000F0087807100690000007A3D00DDF2
+:1008800002000F00888071003F000000840080D7C4
+:1008900002000F00898071003F000000010098D71E
+:1008A00002000F008A80710059000000EF3780D7E6
+:1008B00002000F008B8071003D0000006F0080F788
+:1008C00002000F008C8071003D0000006F0080F777
+:1008D00002000F008D8071003D0000006F0080F766
+:1008E00002000F008E8071002D0000007F02D6D71D
+:1008F00002000F008F807100180000008100FF17B8
+:1009000002000F00908071003D0000006F0080F732
+:1009100002000F00918071003D0000006F0080F721
+:1009200002000F00928071002D000000B800D8D79F
+:1009300002000F0093807100180000008100EB1787
+:1009400002000F00948071003F000000042900DDC8
+:1009500002000F00958071003F000000010018DDCB
+:1009600002000F0096807100690000007A3D00DDF2
+:1009700002000F00978071003F00000084AA04DD90
+:1009800002000F0098807100690000007A3D00DDD0
+:1009900002000F00998071003F000000042B00DD71
+:1009A00002000F009A8071003F000000010018DD76
+:1009B00002000F009B807100690000007A3D00DD9D
+:1009C00002000F009C8071003F000000040000DD69
+:1009D00002000F009D807100690000007A3D00DD7B
+:1009E00002000F009E8071003F000000842900DD9E
+:1009F00002000F009F8071003F000000010018DD21
+:100A000002000F00A0807100690000007A3D00DD47
+:100A100002000F00A18071003F000000040000DD13
+:100A200002000F00A2807100690000007A3D00DD25
+:100A300002000F00A38071003F000000042A00DDC7
+:100A400002000F00A48071003F000000010018DDCB
+:100A500002000F00A5807100690000007A3D00DDF2
+:100A600002000F00A68071003F000000849100DDAD
+:100A700002000F00A7807100690000007A3D00DDD0
+:100A800002000F00A88071003F000000841980D68A
+:100A900002000F00A98071003F000000010080D615
+:100AA00002000F00AA80710035000000ED0080D622
+:100AB00002000F00AB807100180000008100FF37BA
+:100AC00002000F00AC8071003F000000042B00DD2D
+:100AD00002000F00AD8071003F000000010018DD32
+:100AE00002000F00AE807100690000007A3D00DD59
+:100AF00002000F00AF8071003F000000040000DD25
+:100B000002000F00B0807100690000007A3D00DD36
+:100B100002000F00B18071003F000000842A00DD58
+:100B200002000F00B28071003F000000010018DDDC
+:100B300002000F00B3807100690000007A3D00DD03
+:100B400002000F00B48071003F000000040000DDCF
+:100B500002000F00B5807100690000007A3D00DDE1
+:100B600002000F00B68071003F000000840C80D6A8
+:100B700002000F00B78071003F000000010080D626
+:100B800002000F00B880710035000000ED0080D633
+:100B900002000F00B9807100180000008100FF37CB
+:100BA00002000F00BA8071003F000000842A00DDBF
+:100BB00002000F00BB8071003F000000010018DD43
+:100BC00002000F00BC807100690000007A3D00DD6A
+:100BD00002000F00BD8071003F000000040000DD36
+:100BE00002000F00BE807100690000007A3D00DD48
+:100BF00002000F00BF8071003F000000840F80D60C
+:100C000002000F00C08071003F000000010080D68C
+:100C100002000F00C180710035000000ED0080D699
+:100C200002000F00C2807100180000008100FF3731
+:100C300002000F00C38071003F000000042A00DDA5
+:100C400002000F00C48071003F000000010018DDA9
+:100C500002000F00C5807100690000007A3D00DDD0
+:100C600002000F00C68071003F000000841100DD0B
+:100C700002000F00C7807100690000007A3D00DDAE
+:100C800002000F00C88071003F000000842800DDD2
+:100C900002000F00C98071003F000000010018DD54
+:100CA00002000F00CA807100690000007A3D00DD7B
+:100CB00002000F00CB8071003F000000843700DD90
+:100CC00002000F00CC807100690000007A3D00DD59
+:100CD00002000F00CD8071002D000000000080D3C5
+:100CE00002000F00CE8071003F000000803700D26C
+:100CF00002000F00CF8071003F000000040480D18B
+:100D000002000F00D08071003F000000010084D17C
+:100D100002000F00D180710069000000763B00DD09
+:100D200002000F00D280710069000000763B00DDF8
+:100D300002000F00D380710069000000763B00DDE7
+:100D400002000F00D48071003F00000084FF7FD1BB
+:100D500002000F00D58071003F00000081FF7FD1AD
+:100D600002000F00D680710069000000763B00DDB4
+:100D700002000F00D780710069000000763B00DDA3
+:100D800002000F00D880710069000000763B00DD92
+:100D900002000F00D980710069000000763B00DD81
+:100DA00002000F00DA80710069000000763B00DD70
+:100DB00002000F00DB80710069000000763B00DD5F
+:100DC00002000F00DC8071003F000000840780D625
+:100DD00002000F00DD8071003F000000010080D69E
+:100DE00002000F00DE80710035000000ED0080D6AB
+:100DF00002000F00DF807100180000008100FF3743
+:100E000002000F00E080710049000000633B00DD3C
+:100E100002000F00E180710059000000763B00DD08
+:100E200002000F00E28071003D0000006F0080F7BB
+:100E300002000F00E38071003D0000006F0080F7AA
+:100E400002000F00E48071003D0000006F0080F799
+:100E500002000F00E58071002D0000007F0206DD1A
+:100E600002000F00E6807100180000007A3D7F1D2F
+:100E700002000F00E780710045000000393100DDFD
+:100E800002000F00E8807100940000003B310B006D
+:100E900002000F00E9807100940000003D3109005C
+:100EA00002000F00EA807100940000003F3107004B
+:100EB00002000F00EB80710094000000763B0500FB
+:100EC00002000F00EC807100090000007A3DEDC1C6
+:100ED00002000F00ED8071003F00000080B700D2DB
+:100EE00002000F00EE8071003F000000842800DD4A
+:100EF00002000F00EF8071003F000000010018DDCC
+:100F000002000F00F080710069000000643200DD13
+:100F100002000F00F1807100690000007A3D00DDE1
+:100F200002000F00F28071003F000000840780D6AD
+:100F300002000F00F38071003F000000010080D626
+:100F400002000F00F480710035000000ED0080D633
+:100F500002000F00F5807100180000008100FF37CB
+:100F600002000F00F680710049000000633B00DDC5
+:100F700002000F00F780710059000000763B00DD91
+:100F800002000F00F88071003D0000006F0080F744
+:100F900002000F00F98071003D0000006F0080F733
+:100FA00002000F00FA8071003D0000006F0080F722
+:100FB00002000F00FB8071002D0000007F0206DDA3
+:100FC00002000F00FC807100180000007A3D7F1DB8
+:100FD00002000F00FD807100450000003A3100DD85
+:100FE00002000F00FE80710018000000763B2D1DEE
+:100FF00002000F00FF807100450000003C3100DD61
+:1010000002000F000081710018000000763B131DE4
+:1010100002000F0001817100450000003E3100DD3B
+:1010200002000F000281710018000000763B1B1DBA
+:1010300002000F00038171003F000000043000DD5A
+:1010400002000F00048171003F000000010018DD64
+:1010500002000F0005817100690000007A3D00DD8B
+:1010600002000F00068171003F000000040100DD56
+:1010700002000F0007817100690000007A3D00DD69
+:1010800002000F0008817100090000007A3D2DC5A3
+:1010900002000F000981710029000000640001D2E4
+:1010A00002000F000A8171003F000000842800DD6B
+:1010B00002000F000B8171003F000000010018DDED
+:1010C00002000F000C81710069000000643200DD35
+:1010D00002000F000D817100690000007A3D00DD03
+:1010E00002000F000E817100090000007A3D29C244
+:1010F00002000F000F81710029000000640000D27F
+:1011000002000F00108171003F000000842800DD04
+:1011100002000F00118171003F000000010018DD86
+:1011200002000F001281710069000000643200DDCE
+:1011300002000F0013817100690000007A3D00DD9C
+:1011400002000F001481710049000000633B00DDC4
+:1011500002000F001581710059000000763B00DD90
+:1011600002000F00168171003D0000006F0080F743
+:1011700002000F00178171003D0000006F0080F732
+:1011800002000F00188171003D0000006F0080F721
+:1011900002000F00198171002D0000007F0206DDA2
+:1011A00002000F001A817100180000007A3D7F1DB7
+:1011B00002000F001B817100450000003A3100DD84
+:1011C00002000F001C81710018000000763B0F1D0B
+:1011D00002000F001D8171003F000000043000DD9F
+:1011E00002000F001E8171003F000000010018DDA9
+:1011F00002000F001F817100690000007A3D00DDD0
+:1012000002000F00208171003F000000040100DD9A
+:1012100002000F0021817100690000007A3D00DDAD
+:1012200002000F0022817100090000007A3D2DC5E7
+:1012300002000F00238171002D000000820008D100
+:1012400002000F0024817100080000007A3DC323D2
+:1012500002000F0025817100490000000A3B00D602
+:1012600002000F00268171003F000000040000D33F
+:1012700002000F00278171003F000000010004D32D
+:1012800002000F00288171002F000000854081D6E8
+:1012900002000F00298171003F00000084FFFFD48D
+:1012A00002000F002A8171003F000000810780D4F6
+:1012B00002000F002B8171003F00000084FFFFD16E
+:1012C00002000F002C8171003F000000010080D15E
+:1012D00002000F002D81710049000000663600DD1C
+:1012E00002000F002E81710069000000763B00DDD6
+:1012F00002000F002F81710069000000763B00DDC5
+:1013000002000F003081710069000000763B00DDB3
+:1013100002000F003181710069000000693B00DDAF
+:1013200002000F003281710069000000763B00DD91
+:1013300002000F003381710069000000763B00DD80
+:1013400002000F003481710069000000763B00DD6F
+:1013500002000F003581710069000000693B00DD6B
+:1013600002000F0036817100610000006C0400F67D
+:1013700002000F003781710035000000ED0080D6BB
+:1013800002000F00388171001800000081006B3DE1
+:1013900002000F0039817100490000008B0500D662
+:1013A00002000F003A8171002F000000060181D673
+:1013B00002000F003B8171002D000000000000D2F0
+:1013C00002000F003C81710021000000E40000D207
+:1013D00002000F003D8171003D0000006F0080F7AA
+:1013E00002000F003E8171002D0000007F0106DD2C
+:1013F00002000F003F817100180000007A3D7F1D40
+:1014000002000F0040817100490000006C3600D8D6
+:1014100002000F004181710069000000E73300D82D
+:1014200002000F004281710069000000E73300D81C
+:1014300002000F004381710069000000EF3700D8FF
+:1014400002000F0044817100310000006C0100D6E1
+:1014500002000F00458171002D000000000000D146
+:1014600002000F004681710049000000E4337AD188
+:1014700002000F00478171002F000000620171D14E
+:1014800002000F00488171002F000000620161D14D
+:1014900002000F004981710049000000E33340D190
+:1014A00002000F004A8171003D0000006F0080F7CC
+:1014B00002000F004B8171002D0000007F0106DD4E
+:1014C00002000F004C817100180000007A3D7F1D62
+:1014D00002000F004D817100490000006C3600D8F9
+:1014E00002000F004E81710069000000E73300D850
+:1014F00002000F004F81710069000000623100D8C6
+:1015000002000F005081710069000000EF3700D821
+:1015100002000F0051817100310000006C0100D603
+:1015200002000F00528171003D0000006F0080F743
+:1015300002000F00538171002D0000007F0106DDC5
+:1015400002000F0054817100180000007A3D7F1DD9
+:1015500002000F0055817100490000006C3600D870
+:1015600002000F005681710069000000E73300D8C7
+:1015700002000F005781710069000000E73300D8B6
+:1015800002000F005881710069000000EF3700D899
+:1015900002000F0059817100310000006C0100D67B
+:1015A00002000F005A8171002D000000000000D1E0
+:1015B00002000F005B8171002D000000E4076CD178
+:1015C00002000F005C81710049000000E33340D14C
+:1015D00002000F005D8171003D0000006F0080F788
+:1015E00002000F005E8171002D0000007F0106DD0A
+:1015F00002000F005F817100180000007A3D7F1D1E
+:1016000002000F0060817100490000006C3600D8B4
+:1016100002000F006181710069000000E73300D80B
+:1016200002000F006281710069000000623100D881
+:1016300002000F006381710069000000EF3700D8DD
+:1016400002000F0064817100310000006C0100D6BF
+:1016500002000F00658171003D0000006F0080F7FF
+:1016600002000F00668171002D0000007F0106DD81
+:1016700002000F0067817100180000007A3D7F1D95
+:1016800002000F0068817100490000006C3600D82C
+:1016900002000F006981710069000000E73300D883
+:1016A00002000F006A81710069000000E73300D872
+:1016B00002000F006B81710069000000EF3700D855
+:1016C00002000F006C817100310000006C0100D637
+:1016D00002000F006D8171002D000000000000D19C
+:1016E00002000F006E81710049000000E43378D1E0
+:1016F00002000F006F8171002F000000620171D1A4
+:1017000002000F00708171002F000000620161D1A2
+:1017100002000F007181710049000000E33340D1E5
+:1017200002000F00728171003D0000006F0080F721
+:1017300002000F00738171002D0000007F0106DDA3
+:1017400002000F0074817100180000007A3D7F1DB7
+:1017500002000F0075817100490000006C3600D84E
+:1017600002000F007681710069000000E73300D8A5
+:1017700002000F007781710069000000623100D81B
+:1017800002000F007881710069000000EF3700D877
+:1017900002000F0079817100310000006C0100D659
+:1017A00002000F007A8171003D0000006F0080F799
+:1017B00002000F007B8171002D0000007F0106DD1B
+:1017C00002000F007C817100180000007A3D7F1D2F
+:1017D00002000F007D817100490000006C3600D8C6
+:1017E00002000F007E81710069000000E73300D81D
+:1017F00002000F007F81710069000000E73300D80C
+:1018000002000F008081710069000000EF3700D8EE
+:1018100002000F0081817100310000006C0100D6D0
+:1018200002000F00828171002D000000000000D135
+:1018300002000F00838171002D000000E40768D1D1
+:1018400002000F008481710049000000E33340D1A1
+:1018500002000F00858171003D0000006F0080F7DD
+:1018600002000F00868171002D0000007F0106DD5F
+:1018700002000F0087817100180000007A3D7F1D73
+:1018800002000F0088817100490000006C3600D80A
+:1018900002000F008981710069000000E73300D861
+:1018A00002000F008A81710069000000623100D8D7
+:1018B00002000F008B81710069000000EF3700D833
+:1018C00002000F008C817100310000006C0100D615
+:1018D00002000F008D81710035000000ED0080D600
+:1018E00002000F008E817100080000008100792243
+:1018F00002000F008F817100490000000C0600D625
+:1019000002000F00908171002F000000060181D6B7
+:1019100002000F00918171003F000000020080D49E
+:1019200002000F00928171003F000000840080D40B
+:1019300002000F00938171003F000000020100D5FA
+:1019400002000F00948171003F000000840100D567
+:1019500002000F00958171003F000000020280D557
+:1019600002000F00968171003F000000040280D544
+:1019700002000F00978171003D0000006F0080F7AA
+:1019800002000F00988171002D0000007F0106DD2C
+:1019900002000F0099817100180000007A3D7F1D40
+:1019A00002000F009A817100490000006C3600D8D7
+:1019B00002000F009B81710069000000E93400D82B
+:1019C00002000F009C817100690000006A3500D898
+:1019D00002000F009D81710069000000EF3700D800
+:1019E00002000F009E817100310000006C0100D6E2
+:1019F00002000F009F81710041000000EB3480D491
+:101A000002000F00A0817100410000006B3500D57D
+:101A100002000F00A181710035000000ED0080D6AA
+:101A200002000F00A2817100180000008100EB3756
+:101A300002000F00A3817100490000000D3B00D699
+:101A400002000F00A481710049000000073B80D60E
+:101A500002000F00A58171002D000000000000D1E0
+:101A600002000F00A681710049000000663600DD0B
+:101A700002000F00A781710069000000763B00DDC5
+:101A800002000F00A881710069000000763B00DDB4
+:101A900002000F00A981710069000000763B00DDA3
+:101AA00002000F00AA81710069000000763B00DD92
+:101AB00002000F00AB81710069000000763B00DD81
+:101AC00002000F00AC81710069000000763B00DD70
+:101AD00002000F00AD81710069000000763B00DD5F
+:101AE00002000F00AE81710069000000763B00DD4E
+:101AF00002000F00AF817100610000006C0400F66D
+:101B000002000F00B081710035000000ED0080D6AA
+:101B100002000F00B1817100180000008100EB3756
+:101B200002000F00B2817100490000000E3B00D698
+:101B300002000F00B381710049000000083B80D60D
+:101B400002000F00B481710049000000093B80D5FC
+:101B500002000F00B58171003D0000006F0080F7AA
+:101B600002000F00B68171002D0000007F0106DD2C
+:101B700002000F00B7817100180000007A3D7F1D40
+:101B800002000F00B8817100490000006C3600D8D7
+:101B900002000F00B981710069000000EB3500D828
+:101BA00002000F00BA81710069000000E73300D81D
+:101BB00002000F00BB81710069000000EF3700D800
+:101BC00002000F00BC81710041000000EC0700D64C
+:101BD00002000F00BD817100410000006B0880D53C
+:101BE00002000F00BE81710035000000ED0080D6BC
+:101BF00002000F00BF817100180000008100ED3766
+:101C000002000F00C08171003F00000080FFFFD480
+:101C100002000F00C18171003F000000040002D5E6
+:101C200002000F00C28171003F000000010018D5C2
+:101C300002000F00C3817100490000006A3B00DD13
+:101C400002000F00C481710069000000693B00DDE3
+:101C500002000F00C581710069000000693B00DDD2
+:101C600002000F00C681710021000000EA0000D5CB
+:101C700002000F00C7817100490000006A3B0EDDC1
+:101C800002000F00C8817100350000007A0004D105
+:101C900002000F00C9817100180000008100F537B3
+:101CA00002000F00CA8171003F00000080FFFFD4D6
+:101CB00002000F00CB8171003F000000040004D53A
+:101CC00002000F00CC8171003F000000010018D518
+:101CD00002000F00CD81710069000000693B00DD4A
+:101CE00002000F00CE81710069000000693B00DD39
+:101CF00002000F00CF817100490000006A3B00DD47
+:101D000002000F00D081710051000000EA0000F5D0
+:101D100002000F00D18171003D0000006F0080F7CC
+:101D200002000F00D28171003D0000006F0080F7BB
+:101D300002000F00D3817100490000006A3B0EDDF4
+:101D400002000F00D4817100350000007A8004D1B8
+:101D500002000F00D5817100180000008100F537E6
+:101D600002000F00D68171003F000000047F7FC792
+:101D700002000F00D78171003F000000017F7FC784
+:101D800002000F00D88171003F000000004080D6A3
+:101D900002000F00D98171003F00000000C003D194
+:101DA00002000F00DA81710025000000E20020DE51
+:101DB00002000F00DB817100490000004E2780DE29
+:101DC00002000F00DC8171003D0000006F0080F711
+:101DD00002000F00DD8171003D0000006F0080F700
+:101DE00002000F00DE81710035000000E20000D12A
+:101DF00002000F00DF81710035000000ED0080D689
+:101E000002000F00E0817100180000008100F5372A
+:101E100002000F00E18171003F000000043000DD8E
+:101E200002000F00E28171003F000000010018DD98
+:101E300002000F00E3817100690000003A1D00DD1F
+:101E400002000F00E4817100690000007A3D00DDAE
+:101E500002000F00E58171007D00000013A760C73C
+:101E600002000F00E681710031000000410080C0D7
+:101E700002000F00E781710031000000480000C43B
+:101E800002000F00E881710031000000450080C2AF
+:101E900002000F00E9817100000000000000000056
+:101EA00002000F00EA817100000000000000000045
+:101EB00002000F00EB817100000000000000000034
+:101EC00002000F00EC817100000000000000000023
+:101ED00002000F00ED817100000000000000000012
+:101EE00002000F00EE817100000000000000000001
+:101EF00002000F00EF8171000000000000000000F0
+:101F000002000F00F08171000000000000000000DE
+:101F100002000F00F18171000000000000000000CD
+:101F200002000F00F28171000000000000000000BC
+:101F300002000F00F38171000000000000000000AB
+:101F400002000F00F48171002D000000000000DB92
+:101F500002000F00F58171003F000000043000DD39
+:101F600002000F00F68171003F000000010018DD43
+:101F700002000F00F7817100690000007A3D00DD6A
+:101F800002000F00F88171003F000000040000DD36
+:101F900002000F00F9817100690000007A3D00DD48
+:101FA00002000F00FA8171002D000000000080D3B4
+:101FB00002000F00FB8171003F000000040400DDFF
+:101FC00002000F00FC8171003F000000010018DDDD
+:101FD00002000F00FD81710069000000140A00DD9D
+:101FE00002000F00FE817100690000007A3D00DDF3
+:101FF00002000F00FF81710049000000943304D1FA
+:1020000002000F00008271003F000000840400DD28
+:1020100002000F00018271003F000000010018DD86
+:1020200002000F000282710069000000623100DDD1
+:1020300002000F0003827100690000007A3D00DD9C
+:1020400002000F00048271003F000000040500DD63
+:1020500002000F00058271003F000000010018DD42
+:1020600002000F000682710069000000950A00DD81
+:1020700002000F0007827100690000007A3D00DD58
+:1020800002000F000882710049000000953304D15E
+:1020900002000F00098271003F000000840500DD8E
+:1020A00002000F000A8271003F000000010018DDED
+:1020B00002000F000B82710069000000623100DD38
+:1020C00002000F000C827100690000007A3D00DD03
+:1020D00002000F000D8271003F000000040600DDC9
+:1020E00002000F000E8271003F000000010018DDA9
+:1020F00002000F000F827100690000007A3D00DDD0
+:1021000002000F00108271003F000000840000DD1B
+:1021100002000F0011827100690000007A3D00DDAD
+:1021200002000F00128271003F000000040000DD79
+:1021300002000F00138271003F000000010018DD53
+:1021400002000F001482710069000000160B00DD10
+:1021500002000F0015827100690000007A3D00DD69
+:1021600002000F00168271003F000000041000DD25
+:1021700002000F00178271003F000000010018DD0F
+:1021800002000F0018827100690000007A3D00DD36
+:1021900002000F00198271003F000000040000DD02
+:1021A00002000F001A827100690000007A3D00DD14
+:1021B00002000F001B8271003F000000841000DD50
+:1021C00002000F001C8271003F000000010018DDBA
+:1021D00002000F001D827100690000007A3D00DDE1
+:1021E00002000F001E8271003F000000048001DD2C
+:1021F00002000F001F827100690000007A3D00DDBF
+:1022000002000F00208271003F000000041100DD79
+:1022100002000F00218271003F000000010018DD64
+:1022200002000F0022827100690000007A3D00DD8B
+:1022300002000F00238271003F000000040000DD57
+:1022400002000F0024827100690000007A3D00DD69
+:1022500002000F00258271003F000000841100DDA4
+:1022600002000F00268271003F000000010018DD0F
+:1022700002000F0027827100690000007A3D00DD36
+:1022800002000F00288271003F000000040016DDEC
+:1022900002000F0029827100690000007A3D00DD14
+:1022A00002000F002A8271003F000000041200DDCE
+:1022B00002000F002B8271003F000000010018DDBA
+:1022C00002000F002C827100690000007A3D00DDE1
+:1022D00002000F002D8271003F000000040000DDAD
+:1022E00002000F002E827100690000007A3D00DDBF
+:1022F00002000F002F8271003F000000841200DDF9
+:1023000002000F00308271003F000000010018DD64
+:1023100002000F0031827100690000007A3D00DD8B
+:1023200002000F00328271003F000000040000DD57
+:1023300002000F0033827100690000007A3D00DD69
+:1023400002000F00348271003F000000041300DD22
+:1023500002000F00358271003F000000010018DD0F
+:1023600002000F0036827100690000007A3D00DD36
+:1023700002000F00378271003F000000040000DD02
+:1023800002000F0038827100690000007A3D00DD14
+:1023900002000F00398271003F000000841300DD4D
+:1023A00002000F003A8271003F000000010018DDBA
+:1023B00002000F003B827100690000007A3D00DDE1
+:1023C00002000F003C8271003F000000040005DDA8
+:1023D00002000F003D827100690000007A3D00DDBF
+:1023E00002000F003E8271003F000000042000DD6B
+:1023F00002000F003F8271003F000000010018DD65
+:1024000002000F0040827100690000007A3D00DD8B
+:1024100002000F00418271003F000000040000DD57
+:1024200002000F0042827100690000007A3D00DD69
+:1024300002000F00438271003F000000842000DD95
+:1024400002000F00448271003F000000010018DD0F
+:1024500002000F0045827100690000007A3D00DD36
+:1024600002000F00468271003F000000049001DD71
+:1024700002000F0047827100690000007A3D00DD14
+:1024800002000F00488271003F000000042100DDBF
+:1024900002000F00498271003F000000010018DDBA
+:1024A00002000F004A827100690000007A3D00DDE1
+:1024B00002000F004B8271003F000000840000DD2D
+:1024C00002000F004C827100690000007A3D00DDBF
+:1024D00002000F004D8271003F000000842100DDEA
+:1024E00002000F004E8271003F000000010018DD65
+:1024F00002000F004F827100690000007A3D00DD8C
+:1025000002000F00508271003F000000040000DD57
+:1025100002000F0051827100690000007A3D00DD69
+:1025200002000F00528271003F000000042200DD13
+:1025300002000F00538271003F000000010018DD0F
+:1025400002000F0054827100690000007A3D00DD36
+:1025500002000F00558271003F000000840200DD80
+:1025600002000F0056827100690000007A3D00DD14
+:1025700002000F00578271003F000000842200DD3E
+:1025800002000F00588271003F000000010018DDBA
+:1025900002000F0059827100690000007A3D00DDE1
+:1025A00002000F005A8271003F000000040000DDAD
+:1025B00002000F005B827100690000007A3D00DDBF
+:1025C00002000F005C8271003F000000042300DD68
+:1025D00002000F005D8271003F000000010018DD65
+:1025E00002000F005E827100690000007A3D00DD8C
+:1025F00002000F005F8271003F000000040000DD58
+:1026000002000F0060827100690000007A3D00DD69
+:1026100002000F00618271003F000000041800DD1D
+:1026200002000F00628271003F000000010018DD0F
+:1026300002000F006382710069000000970B00DD4B
+:1026400002000F0064827100690000007A3D00DD25
+:1026500002000F006582710049000000973304D129
+:1026600002000F00668271003F000000841800DD48
+:1026700002000F00678271003F000000010018DDBA
+:1026800002000F006882710069000000623100DD05
+:1026900002000F0069827100690000007A3D00DDD0
+:1026A00002000F006A8271003F000000041900DD83
+:1026B00002000F006B8271003F000000010018DD76
+:1026C00002000F006C82710069000000180C00DD30
+:1026D00002000F006D827100690000007A3D00DD8C
+:1026E00002000F006E82710049000000983304D18F
+:1026F00002000F006F8271003F000000841900DDAE
+:1027000002000F00708271003F000000010018DD20
+:1027100002000F007182710069000000623100DD6B
+:1027200002000F0072827100690000007A3D00DD36
+:1027300002000F00738271003F000000041A00DDE8
+:1027400002000F00748271003F000000010018DDDC
+:1027500002000F0075827100690000007A3D00DD03
+:1027600002000F00768271003F000000040000DDCF
+:1027700002000F0077827100690000007A3D00DDE1
+:1027800002000F00788271003F000000841A00DD13
+:1027900002000F00798271003F000000010018DD87
+:1027A00002000F007A82710069000000160B00DD44
+:1027B00002000F007B827100690000007A3D00DD9D
+:1027C00002000F007C8271003F000000041C00DD4D
+:1027D00002000F007D8271003F000000010018DD43
+:1027E00002000F007E82710069000000990C00DD7C
+:1027F00002000F007F827100690000007A3D00DD59
+:1028000002000F00808271003F000000841C00DD88
+:1028100002000F00818271003F000000010018DDFE
+:1028200002000F0082827100690000001A0D00DDB5
+:1028300002000F0083827100690000007A3D00DD14
+:1028400002000F00848271003F000000041D00DDC3
+:1028500002000F00858271003F000000010018DDBA
+:1028600002000F0086827100690000009B0D00DDF0
+:1028700002000F0087827100690000007A3D00DDD0
+:1028800002000F0088827100490000009B3304D1D0
+:1028900002000F00898271003F000000841D00DDEE
+:1028A00002000F008A8271003F000000010018DD65
+:1028B00002000F008B82710069000000623100DDB0
+:1028C00002000F008C827100690000007A3D00DD7B
+:1028D00002000F008D8271003F000000041E00DD29
+:1028E00002000F008E8271003F000000010018DD21
+:1028F00002000F008F827100690000001C0E00DDD5
+:1029000002000F0090827100690000007A3D00DD36
+:1029100002000F00918271003F000000040100DD01
+:1029200002000F00928271003F000000010018DDDC
+:1029300002000F0093827100690000007A3D00DD03
+:1029400002000F00948271003F000000040F00DDC0
+:1029500002000F0095827100690000007A3D00DDE1
+:1029600002000F00968271007D00000013A760C76F
+:1029700002000F009782710031000000410080C00A
+:1029800002000F009882710031000000480000C46E
+:1029900002000F009982710031000000450080C2E2
+:1029A00002000F009A827100310000006D0080D695
+:1029B0000F000F0064007000000000000000000025
+:1029C00000000000400000000001000000040000C2
+:1029D000640000005400000000000000002400001B
+:1029E0000028000000040000802800008001000092
+:1029F00003000000000000000000000000000000D4
+:102A0000510000007D01000008000000510000009E
+:102A10005D00000000000000090000000050000000
+:102A200000000000000000000F000F00F401700023
+:102A30000000000000000000000000004000000056
+:102A400000010000000400006400000054000000C9
+:102A50000000000000240000002800000004000026
+:102A6000802800008001000003000000000000003A
+:102A70000000000000000000510000007D01000087
+:102A800008000000510000005D0000000000000090
+:102A900009000000005000000000000000000000DD
+:102AA00002000F00000070000100000000000000A4
+:102AB00002000F0000007000010000000000000094
+:102AC00002000F00008071002500000002000EDDF2
+:102AD00002000F000180710004000000763BD1016C
+:102AE00002000F00028071002500000082000EDD50
+:102AF00002000F000380710004000000763B890291
+:102B000002000F00048071002500000002010EDDAC
+:102B100002000F000580710004000000763B850272
+:102B200002000F00068071002500000082010EDD0A
+:102B300002000F000780710004000000763BFD03D7
+:102B400002000F000880710009000000763B81CF71
+:102B500002000F000980710000000000000000006A
+:102B600002000F000A807100000000000000000059
+:102B700002000F000B807100000000000000000048
+:102B800002000F000C807100000000000000000037
+:102B900002000F000D807100000000000000000026
+:102BA00002000F000E807100000000000000000015
+:102BB00002000F000F807100000000000000000004
+:102BC00002000F00108071000000000000000000F3
+:102BD00002000F00118071000000000000000000E2
+:102BE00002000F00128071000000000000000000D1
+:102BF00002000F00138071000000000000000000C0
+:102C000002000F00148071000000000000000000AE
+:102C100002000F001580710000000000000000009D
+:102C200002000F001680710000000000000000008C
+:102C300002000F001780710000000000000000007B
+:102C400002000F001880710000000000000000006A
+:102C500002000F0019807100000000000000000059
+:102C600002000F001A807100000000000000000048
+:102C700002000F001B807100000000000000000037
+:102C800002000F001C807100000000000000000026
+:102C900002000F001D807100000000000000000015
+:102CA00002000F001E807100000000000000000004
+:102CB00002000F001F8071000000000000000000F3
+:102CC00002000F00208071000000000000000000E2
+:102CD00002000F00218071000000000000000000D1
+:102CE00002000F00228071000000000000000000C0
+:102CF00002000F00238071000000000000000000AF
+:102D000002000F002480710000000000000000009D
+:102D100002000F002580710000000000000000008C
+:102D200002000F002680710000000000000000007B
+:102D300002000F002780710000000000000000006A
+:102D400002000F002880710049000000003B00C015
+:102D500002000F002980710049000000023B80C082
+:102D600002000F002A80710049000000033B00C1EF
+:102D700002000F002B80710049000000043B80C15D
+:102D800002000F002C80710029000000760060DF37
+:102D900002000F002D807100490000007D3B44DFE0
+:102DA00002000F002E80710079000000769060FD17
+:102DB00002000F002F8071003D0000006F0080F7BF
+:102DC00002000F00308071003D0000006F0080F7AE
+:102DD00002000F00318071003D0000006F0080F79D
+:102DE00002000F00328071003D0000006F0080F78C
+:102DF00002000F003380710000000000000000009E
+:102E000002000F003480710000000000000000008C
+:102E100002000F003580710000000000000000007B
+:102E200002000F003680710000000000000000006A
+:102E300002000F0037807100000000000000000059
+:102E400002000F0038807100000000000000000048
+:102E500002000F0039807100000000000000000037
+:102E600002000F003A807100000000000000000026
+:102E700002000F003B807100000000000000000015
+:102E800002000F003C807100000000000000000004
+:102E900002000F003D8071000000000000000000F3
+:102EA00002000F003E8071000000000000000000E2
+:102EB00002000F003F8071000000000000000000D1
+:102EC00002000F00408071000000000000000000C0
+:102ED00002000F00418071000000000000000000AF
+:102EE00002000F004280710000000000000000009E
+:102EF00002000F004380710000000000000000008D
+:102F000002000F004480710000000000000000007B
+:102F100002000F004580710000000000000000006A
+:102F200002000F0046807100000000000000000059
+:102F300002000F0047807100000000000000000048
+:102F400002000F0048807100000000000000000037
+:102F500002000F0049807100000000000000000026
+:102F600002000F004A807100000000000000000015
+:102F700002000F004B807100000000000000000004
+:102F800002000F004C8071000000000000000000F3
+:102F900002000F004D8071000000000000000000E2
+:102FA00002000F004E8071000000000000000000D1
+:102FB00002000F004F8071000000000000000000C0
+:102FC00002000F00508071000000000000000000AF
+:102FD00002000F005180710000000000000000009E
+:102FE00002000F005280710000000000000000008D
+:102FF00002000F005380710000000000000000007C
+:1030000002000F005480710000000000000000006A
+:1030100002000F0055807100000000000000000059
+:1030200002000F0056807100000000000000000048
+:1030300002000F0057807100000000000000000037
+:1030400002000F0058807100000000000000000026
+:1030500002000F0059807100000000000000000015
+:1030600002000F005A807100000000000000000004
+:1030700002000F005B8071000000000000000000F3
+:1030800002000F005C8071000000000000000000E2
+:1030900002000F005D8071000000000000000000D1
+:1030A00002000F005E8071000000000000000000C0
+:1030B00002000F005F8071000000000000000000AF
+:1030C00002000F00608071003F000000030000DF7D
+:1030D00002000F00618071002D000000810FE0DD13
+:1030E00002000F00628071003F000000830280DD5B
+:1030F00002000F00638071002D000000800104DDDC
+:1031000002000F00648071007D000000800015FD4A
+:1031100002000F00658071007A000000763B2010ED
+:1031200002000F00668071007A000000767B20307C
+:1031300002000F006780710021000000600024D0B1
+:1031400002000F00688071003F000000040100DDF4
+:1031500002000F00698071003F000000810240DD25
+:1031600002000F006A8071007900000003BB31DDAE
+:1031700002000F006B8071007900000004FB31DD5C
+:1031800002000F006C8071007900000076BB31DD19
+:1031900002000F006D8071007900000076FB31DDC8
+:1031A00002000F006E80710079000000010121FD16
+:1031B00002000F006F8071007D00000081402BFD38
+:1031C00002000F0070807100400000000230003DDE
+:1031D00002000F007180710048000000023B001DDA
+:1031E00002000F007280710079000000767B21DD03
+:1031F00002000F00738071002D0000007F0504DDC8
+:1032000002000F007480710018000000763B7F3DC3
+:1032100002000F00758071003D0000006F0080F714
+:1032200002000F00768071003D0000006F0080F703
+:1032300002000F00778071003D0000006F0080F7F2
+:1032400002000F007880710021000000761F37E334
+:1032500002000F007980710049000000793B00DD19
+:1032600002000F007A8071007900000076BB21DD3A
+:1032700002000F007B80710049000000793B00DDF7
+:1032800002000F007C8071007900000076BB21DD18
+:1032900002000F007D80710049000000793B00DDD5
+:1032A00002000F007E8071007900000076BB21DDF6
+:1032B00002000F007F80710079000000769060FDB1
+:1032C00002000F00808071007900000076FB21DD94
+:1032D00002000F00818071003F000000830000DFCA
+:1032E00002000F00828071003D0000006F0080F737
+:1032F00002000F0083807100000000000000000049
+:1033000002000F0084807100000000000000000037
+:1033100002000F0085807100000000000000000026
+:1033200002000F0086807100000000000000000015
+:1033300002000F0087807100000000000000000004
+:1033400002000F00888071000000000000000000F3
+:1033500002000F00898071000000000000000000E2
+:1033600002000F008A8071000000000000000000D1
+:1033700002000F008B8071000000000000000000C0
+:1033800002000F008C8071000000000000000000AF
+:1033900002000F008D80710000000000000000009E
+:1033A00002000F008E80710000000000000000008D
+:1033B00002000F008F80710000000000000000007C
+:1033C00002000F009080710000000000000000006B
+:1033D00002000F009180710000000000000000005A
+:1033E00002000F0092807100000000000000000049
+:1033F00002000F0093807100000000000000000038
+:1034000002000F0094807100000000000000000026
+:1034100002000F0095807100000000000000000015
+:1034200002000F0096807100000000000000000004
+:1034300002000F00978071000000000000000000F3
+:1034400002000F00988071000000000000000000E2
+:1034500002000F00998071000000000000000000D1
+:1034600002000F009A8071000000000000000000C0
+:1034700002000F009B8071000000000000000000AF
+:1034800002000F009C80710000000000000000009E
+:1034900002000F009D80710000000000000000008D
+:1034A00002000F009E80710000000000000000007C
+:1034B00002000F009F80710000000000000000006B
+:1034C00002000F00A08071002D000000030808D04A
+:1034D00002000F00A18071000800000076FBB521FA
+:1034E00002000F00A280710079000000810001DD60
+:1034F00002000F00A380710079000000028101DD4D
+:1035000002000F00A48071007D000000838001FD97
+:1035100002000F00A580710079000000763B90D07A
+:1035200002000F00A6807100490000007A3B58D0CD
+:1035300002000F00A780710049000000003B04D288
+:1035400002000F00A88071003D000000030040DD74
+:1035500002000F00A9807100240000006402003204
+:1035600002000F00AA8071003D00000003F87FDD1B
+:1035700002000F00AB807100290000007A0120D00A
+:1035800002000F00AC807100490000000E3BA4D087
+:1035900002000F00AD8071002D000000FF4204DD2D
+:1035A00002000F00AE80710018000000763B7F3DE6
+:1035B00002000F00AF8071002D000000820006DDC8
+:1035C00002000F00B080710038000000E001003000
+:1035D00002000F00B180710039000000600100D0CE
+:1035E00002000F00B2807100790000007C3BB1D175
+:1035F00002000F00B38071002D000000E30FE0DD3A
+:1036000002000F00B480710049000000E43080D057
+:1036100002000F00B5807100790000007C7B31DD75
+:1036200002000F00B6807100790000007C3B31DDA4
+:1036300002000F00B78071007D000000824037FD5E
+:1036400002000F00B880710008000000763B7D0189
+:1036500002000F00B98071003D0000006F0080F78C
+:1036600002000F00BA8071003D0000006F0080F77B
+:1036700002000F00BB80710049000000870300DDDD
+:1036800002000F00BC80710079000000080431DDE9
+:1036900002000F00BD807100790000007A7D31DDED
+:1036A00002000F00BE807100490000007C3B00D387
+:1036B00002000F00BF807100790000007CBB81D345
+:1036C00002000F00C08071007F0000007CB201D1B9
+:1036D00002000F00C18071004800000064320051F8
+:1036E00002000F00C28071003D000000030040DDB9
+:1036F00002000F00C38071000800000062319501D4
+:1037000002000F00C480710021000000660600D393
+:1037100002000F00C580710020000000E700805308
+:1037200002000F00C68071003F000000000800DDAD
+:1037300002000F00C78071007900000066B301DD50
+:1037400002000F00C880710079000000E7B301DDBE
+:1037500002000F00C980710075000000628601F14F
+:1037600002000F00CA8071007500000064B101D230
+:1037700002000F00CB80710078000000767B001DF6
+:1037800002000F00CC80710025000000E30100DD85
+:1037900002000F00CD807100080000006231B1010D
+:1037A00002000F00CE8071003D0000006F0080F726
+:1037B00002000F00CF8071003D0000006F0080F715
+:1037C00002000F00D08071003D0000006F0080F704
+:1037D00002000F00D180710021000000639F37E3D9
+:1037E00002000F00D2807100490000007C3B00D332
+:1037F00002000F00D3807100790000007CBB81D3F0
+:1038000002000F00D48071007F0000007CB201D163
+:1038100002000F00D58071004800000064320051A2
+:1038200002000F00D68071007500000064B101D263
+:1038300002000F00D780710078000000767B001D29
+:1038400002000F00D88071003F000000040000DD7E
+:1038500002000F00D98071007900000081C001DDF5
+:1038600002000F00DA80710079000000769060FDA0
+:1038700002000F00DB8071002D000000030808DD4E
+:1038800002000F00DC8071007800000081C0013D63
+:1038900002000F00DD8071003D0000006F0080F726
+:1038A00002000F00DE807100000000000000000038
+:1038B00002000F00DF807100000000000000000027
+:1038C00002000F00E0807100000000000000000016
+:1038D00002000F00E1807100000000000000000005
+:1038E00002000F00E28071000000000000000000F4
+:1038F00002000F00E38071000000000000000000E3
+:1039000002000F00E48071000000000000000000D1
+:1039100002000F00E58071000000000000000000C0
+:1039200002000F00E68071000000000000000000AF
+:1039300002000F00E780710000000000000000009E
+:1039400002000F00E880710049000000033B8ED1A7
+:1039500002000F00E98071002F000000E30081D118
+:1039600002000F00EA8071003F000000031880D1C0
+:1039700002000F00EB80710049000000033B04D1FE
+:1039800002000F00EC8071003F000000030280DDA8
+:1039900002000F00ED80710049000000023B04D2DC
+:1039A00002000F00EE80710049000000003B84D24D
+:1039B00002000F00EF80710025000000E20000DD32
+:1039C00002000F00F08071009400000062411300BB
+:1039D00002000F00F18071009400000062430B00B0
+:1039E00002000F00F280710094000000E248150010
+:1039F00002000F00F38071009400000062491B0078
+:103A000002000F00F48071009400000076402F0047
+:103A100002000F00F5807100090000007A3D81CF9F
+:103A200002000F00F68071001D000000E5802BFDF4
+:103A300002000F00F78071003000000063808331C6
+:103A400002000F00F88071003000000063808211D6
+:103A500002000F00F98071001D000000E58025FDC7
+:103A600002000F00FA807100300000006300833113
+:103A700002000F00FB807100300000006300821123
+:103A800002000F00FC8071002F000000E30081D1D4
+:103A900002000F00FD8071001D000000E58009FD9F
+:103AA00002000F00FE8071003000000063D38331FC
+:103AB00002000F00FF8071003000000063D283110C
+:103AC00002000F00008171002F000000E30081D18F
+:103AD00002000F00018171003F000000840180D6C8
+:103AE00002000F00028171003F000000010080D63B
+:103AF00002000F000381710035000000ED0080D648
+:103B000002000F0004817100180000008100FF37DF
+:103B100002000F000581710025000000640200D240
+:103B200002000F0006817100180000007AFD777D09
+:103B300002000F000781710049000000633B20DE96
+:103B400002000F000881710049000000793B80DE0F
+:103B500002000F000981710021000000E30080D104
+:103B600002000F000A817100090000007A3D81CF38
+:103B700002000F000B81710049000000E33100DDFD
+:103B800002000F000C81710069000000783B0EDD1F
+:103B900002000F000D81710061000000763B00DD26
+:103BA00002000F000E8171003F000000840100DD63
+:103BB00002000F000F8171003F000000010000DDD6
+:103BC00002000F001081710035000000FA0000DDD6
+:103BD00002000F001181710018000000763B7F3B4E
+:103BE00002000F00128171003D0000006F0080F79D
+:103BF00002000F00138171003D0000006F0080F78C
+:103C000002000F00148171003D0000006F0080F77A
+:103C100002000F001581710021000000E30080D137
+:103C200002000F001681710069000000793B04DD7D
+:103C300002000F001781710061000000E30080F1B5
+:103C400002000F00188171003F000000840180D63F
+:103C500002000F00198171003F000000010080D6B2
+:103C600002000F001A81710035000000ED0080D6BF
+:103C700002000F001B817100180000008100FF3757
+:103C800002000F001C81710025000000640200D2B8
+:103C900002000F001D8171009800000076BB5D607E
+:103CA00002000F001E817100090000007A3D81CFE3
+:103CB00002000F001F8171000000000000000000E2
+:103CC00002000F00208171000000000000000000D1
+:103CD00002000F00218171000000000000000000C0
+:103CE00002000F00228171000000000000000000AF
+:103CF00002000F002381710000000000000000009E
+:103D000002000F002481710000000000000000008C
+:103D100002000F002581710000000000000000007B
+:103D200002000F002681710000000000000000006A
+:103D300002000F0027817100000000000000000059
+:103D400002000F0028817100000000000000000048
+:103D500002000F0029817100000000000000000037
+:103D600002000F002A817100000000000000000026
+:103D700002000F002B817100000000000000000015
+:103D800002000F002C817100000000000000000004
+:103D900002000F002D8171000000000000000000F3
+:103DA00002000F002E8171000000000000000000E2
+:103DB00002000F002F8171000000000000000000D1
+:103DC00002000F00308171000000000000000000C0
+:103DD00002000F00318171000000000000000000AF
+:103DE00002000F003281710000000000000000009E
+:103DF00002000F003381710000000000000000008D
+:103E000002000F003481710000000000000000007B
+:103E100002000F003581710000000000000000006A
+:103E200002000F0036817100000000000000000059
+:103E300002000F0037817100000000000000000048
+:103E400002000F0038817100000000000000000037
+:103E500002000F0039817100000000000000000026
+:103E600002000F003A817100000000000000000015
+:103E700002000F003B817100000000000000000004
+:103E800002000F003C8171000000000000000000F3
+:103E900002000F003D8171000000000000000000E2
+:103EA00002000F003E8171000000000000000000D1
+:103EB00002000F003F8171000000000000000000C0
+:103EC00002000F004081710049000000013B08D44E
+:103ED00002000F0041817100090000007A3D8BC291
+:103EE00002000F00428171003F000000800300D4F7
+:103EF00002000F0043817100090000007A3D8BC26F
+:103F000002000F004481710049000000033B0ED401
+:103F100002000F00458171003F000000000042D602
+:103F200002000F00468171002F000000804081D206
+:103F300002000F00478171002D000000650384D24C
+:103F400002000F00488171003F000000800080D611
+:103F500002000F00498171003F000000040004DDF1
+:103F600002000F004A8171003F000000010018DDCF
+:103F700002000F004B817100690000006D3B00DD05
+:103F800002000F004C817100690000006D3B00DDF4
+:103F900002000F004D8171003100000065D203D393
+:103FA00002000F004E81710049000000663B40DEB8
+:103FB00002000F004F8171003F000000840180D695
+:103FC00002000F00508171003F000000010080D608
+:103FD00002000F005181710035000000ED0080D615
+:103FE00002000F0052817100180000008100FF37AD
+:103FF00002000F0053817100490000007E3B80D514
+:1040000002000F005481710021000000E60040DE34
+:1040100002000F00558171003F000000840180D62E
+:1040200002000F00568171003F000000010080D6A1
+:1040300002000F005781710035000000ED0080D6AE
+:1040400002000F0058817100180000008100FF3746
+:1040500002000F0059817100490000007E3B00D52D
+:1040600002000F005A81710079000000763B01DDEB
+:1040700002000F005B8171002D0000007F4004DD15
+:1040800002000F005C81710018000000763B7F3D4C
+:1040900002000F005D8171007900000076BB01DD38
+:1040A00002000F005E81710075000000E88001FDD4
+:1040B00002000F005F81710094000000684115004C
+:1040C00002000F006081710094000000E8442500A8
+:1040D00002000F006181710094000000E84123009C
+:1040E00002000F0062817100940000006845170013
+:1040F00002000F0063817100940000006842150007
+:1041000002000F006481710094000000E842270063
+:1041100002000F00658171009400000068432D00CB
+:1041200002000F00668171009400000068442D00B9
+:1041300002000F006781710094000000E843330023
+:1041400002000F006881710004000000763B9703B5
+:1041500002000F00698171000D00000065C10DE3D0
+:1041600002000F006A817100300000007600033207
+:1041700002000F006B817100300000007600021217
+:1041800002000F006C8171003F000000000080D42D
+:1041900002000F006D8171003F000000008080D19F
+:1041A00002000F006E8171000D00000065C13FE349
+:1041B00002000F006F817100300000007660043251
+:1041C00002000F0070817100300000007640041280
+:1041D00002000F00718171003F000000008082D456
+:1041E00002000F00728171003F000000008080D14A
+:1041F00002000F00738171000D00000065C13FE3F4
+:1042000002000F007481710030000000762004323B
+:1042100002000F007581710030000000760004126A
+:1042200002000F00768171003F000000000082D480
+:1042300002000F00778171000D00000065C163E38B
+:1042400002000F00788171003000000076200332F8
+:1042500002000F0079817100300000007600031227
+:1042600002000F007A8171003F000000000083D43B
+:1042700002000F007B81710049000000763B80D274
+:1042800002000F007C8171000D00000065C10DE38C
+:1042900002000F007D817100300000007680033243
+:1042A00002000F007E817100300000007680021253
+:1042B00002000F007F8171003F000000000081D4E8
+:1042C00002000F00808171003F000000000002D654
+:1042D00002000F00818171003F000000000081D1C9
+:1042E00002000F00828171000D00000065C13FE3F4
+:1042F00002000F008381710030000000762004323C
+:1043000002000F008481710030000000760004126A
+:1043100002000F00858171003F000000000082D480
+:1043200002000F008681710041000000EB3480D450
+:1043300002000F0087817100790000006ABB01DD77
+:1043400002000F00888171007900000076BB01DD5A
+:1043500002000F00898171003F000000031800D2A5
+:1043600002000F008A8171003F000000000081D12F
+:1043700002000F008B81710075000000638001FD59
+:1043800002000F008C81710098000000643B69807E
+:1043900002000F008D81710051000000E40000F266
+:1043A00002000F008E8171003F000000840180D662
+:1043B00002000F008F8171003F000000010080D6D5
+:1043C00002000F009081710035000000ED0080D6E2
+:1043D00002000F0091817100180000008100FF377A
+:1043E00002000F00928171002D0000007F4004DD6B
+:1043F00002000F009381710018000000763B7F3DA2
+:1044000002000F009481710049000000383BC0D3C6
+:1044100002000F009581710049000000643B00DD3F
+:1044200002000F009681710051000000E40000F2CC
+:1044300002000F00978171003F000000840180D6C8
+:1044400002000F00988171003F000000010080D63B
+:1044500002000F009981710035000000ED0080D648
+:1044600002000F009A817100180000008100FF37E0
+:1044700002000F009B81710049000000383BA0D36F
+:1044800002000F009C8171001900000076BB61DD05
+:1044900002000F009D81710049000000673B00DDB4
+:1044A00002000F009E81710075000000638281F19F
+:1044B00002000F009F81710041000000EB3480D4A6
+:1044C00002000F00A0817100790000006ABB01DDCD
+:1044D00002000F00A18171007900000076BB01DDB0
+:1044E00002000F00A28171003F000000031800D2FB
+:1044F00002000F00A38171003F000000008080D106
+:1045000002000F00A481710075000000638001FDAE
+:1045100002000F00A581710098000000643B378005
+:1045200002000F00A681710051000000E40000F2BB
+:1045300002000F00A78171003F000000840180D6B7
+:1045400002000F00A88171003F000000010080D62A
+:1045500002000F00A981710035000000ED0080D637
+:1045600002000F00AA817100180000008100FF37CF
+:1045700002000F00AB8171002D0000007F4004DDC0
+:1045800002000F00AC81710018000000763B7F3DF7
+:1045900002000F00AD81710049000000383B80D35C
+:1045A00002000F00AE8171001900000076BB6FDDC4
+:1045B00002000F00AF81710049000000673B00DD81
+:1045C00002000F00B081710075000000638281F16C
+:1045D00002000F00B181710041000000EB3480D473
+:1045E00002000F00B2817100790000006ABB01DD9A
+:1045F00002000F00B38171007900000063BB01DD90
+:1046000002000F00B481710075000000638001FD9D
+:1046100002000F00B581710098000000643B178014
+:1046200002000F00B681710049000000643B40DECB
+:1046300002000F00B78171003F000000840180D6A6
+:1046400002000F00B88171003F000000010080D619
+:1046500002000F00B981710035000000ED0080D626
+:1046600002000F00BA817100180000008100FF37BE
+:1046700002000F00BB8171002D0000007F4004DDAF
+:1046800002000F00BC81710018000000763B7F3DE6
+:1046900002000F00BD81710021000000E40000D283
+:1046A00002000F00BE817100190000007E7BEFD375
+:1046B00002000F00BF81710075000000638281F16C
+:1046C00002000F00C08171003F000000000080D692
+:1046D00002000F00C18171003F000000040004DDF2
+:1046E00002000F00C28171003F000000010018DDD0
+:1046F00002000F00C3817100690000006D3B00DD06
+:1047000002000F00C4817100690000006D3B00DDF4
+:1047100002000F00C58171003F000000000000DDB5
+:1047200002000F00C68171002D000000800154DDE1
+:1047300002000F00C7817100790000007680E0F36D
+:1047400002000F00C8817100490000007A3600D6CF
+:1047500002000F00C98171007900000076FB01DDC5
+:1047600002000F00CA8171003D0000006F0080F759
+:1047700002000F00CB81710049000000033B00DD07
+:1047800002000F00CC81710059000000763B00FD53
+:1047900002000F00CD8171003F000000031C80DD8E
+:1047A00002000F00CE8171003D0000006F0080F715
+:1047B00002000F00CF8171003D0000006F0080F704
+:1047C00002000F00D08171003D0000006F0080F7F3
+:1047D00002000F00D18171002D0000007F0206DD74
+:1047E00002000F00D2817100180000007A3D7F1D89
+:1047F00002000F00D3817100310000006B8883D468
+:1048000002000F00D4817100790000006ABB01DD55
+:1048100002000F00D581710079000000769081F1CF
+:1048200002000F00D681710075000000638001FD59
+:1048300002000F00D78171009800000076BB538002
+:1048400002000F00D881710019000000797B7FDD24
+:1048500002000F00D981710075000000638281F1B0
+:1048600002000F00DA81710000000000000000006B
+:1048700002000F00DB81710000000000000000005A
+:1048800002000F00DC817100000000000000000049
+:1048900002000F00DD817100000000000000000038
+:1048A00002000F00DE817100000000000000000027
+:1048B00002000F00DF817100000000000000000016
+:1048C00002000F00E0817100000000000000000005
+:1048D00002000F00E18171000000000000000000F4
+:1048E00002000F00E28171000000000000000000E3
+:1048F00002000F00E38171000000000000000000D2
+:1049000002000F00E48171000000000000000000C0
+:1049100002000F00E58171000000000000000000AF
+:1049200002000F00E681710000000000000000009E
+:1049300002000F00E781710000000000000000008D
+:1049400002000F00E881710000000000000000007C
+:1049500002000F00E981710000000000000000006B
+:1049600002000F00EA81710000000000000000005A
+:1049700002000F00EB817100000000000000000049
+:1049800002000F00EC817100000000000000000038
+:1049900002000F00ED817100000000000000000027
+:1049A00002000F00EE817100000000000000000016
+:1049B00002000F00EF817100000000000000000005
+:1049C00002000F00F08171000000000000000000F4
+:1049D00002000F00F18171000000000000000000E3
+:1049E00002000F00F28171000000000000000000D2
+:1049F00002000F00F38171000000000000000000C1
+:104A000002000F00F48171000000000000000000AF
+:104A100002000F00F581710000000000000000009E
+:104A200002000F00F681710000000000000000008D
+:104A300002000F00F781710000000000000000007C
+:104A400002000F00F881710000000000000000006B
+:104A500002000F00F981710000000000000000005A
+:104A600002000F00FA817100000000000000000049
+:104A700002000F00FB817100000000000000000038
+:104A800002000F00FC817100000000000000000027
+:104A900002000F00FD817100000000000000000016
+:104AA00002000F00FE8171003F000000030280DD64
+:104AB00002000F00FF81710049000000023B84D119
+:104AC00002000F000082710049000000033B00DD7E
+:104AD00002000F0001827100690000007A3B00DDD6
+:104AE00002000F000282710049000000793B00DDE6
+:104AF00002000F000382710065000000630280F174
+:104B000002000F000482710018000000763B7D7DDA
+:104B100002000F0005827100090000007A3D81CF7C
+:104B200002000F000682710000000000000000007B
+:104B300002000F000782710000000000000000006A
+:104B400002000F0008827100000000000000000059
+:104B500002000F0009827100000000000000000048
+:104B600002000F000A827100000000000000000037
+:104B700002000F000B827100000000000000000026
+:104B800002000F000C827100000000000000000015
+:104B900002000F000D827100000000000000000004
+:104BA00002000F000E8271000000000000000000F3
+:104BB00002000F000F8271000000000000000000E2
+:104BC00002000F00108271000000000000000000D1
+:104BD00002000F00118271000000000000000000C0
+:104BE00002000F00128271000000000000000000AF
+:104BF00002000F001382710000000000000000009E
+:104C000002000F001482710000000000000000008C
+:104C100002000F001582710000000000000000007B
+:104C200002000F001682710000000000000000006A
+:104C300002000F0017827100000000000000000059
+:104C400002000F0018827100000000000000000048
+:104C500002000F0019827100000000000000000037
+:104C600002000F001A827100000000000000000026
+:104C700002000F001B827100000000000000000015
+:104C800002000F001C827100000000000000000004
+:104C900002000F001D8271000000000000000000F3
+:104CA00002000F001E8271000000000000000000E2
+:104CB00002000F001F8271000000000000000000D1
+:104CC00002000F00208271000000000000000000C0
+:104CD00002000F00218271000000000000000000AF
+:104CE00002000F002282710000000000000000009E
+:104CF00002000F002382710000000000000000008D
+:104D000002000F002482710000000000000000007B
+:104D100002000F002582710000000000000000006A
+:104D200002000F0026827100000000000000000059
+:104D300002000F0027827100000000000000000048
+:104D400002000F0028827100000000000000000037
+:104D500002000F0029827100000000000000000026
+:104D600002000F002A827100000000000000000015
+:104D700002000F002B827100000000000000000004
+:104D800002000F002C8271000000000000000000F3
+:104D900002000F002D8271000000000000000000E2
+:104DA00002000F002E8271000000000000000000D1
+:104DB00002000F002F8271000000000000000000C0
+:104DC00002000F00308271000000000000000000AF
+:104DD00002000F003182710000000000000000009E
+:104DE00002000F003282710000000000000000008D
+:104DF00002000F003382710000000000000000007C
+:104E000002000F003482710000000000000000006A
+:104E100002000F0035827100000000000000000059
+:104E200002000F0036827100000000000000000048
+:104E300002000F0037827100000000000000000037
+:104E400002000F0038827100000000000000000026
+:104E500002000F0039827100000000000000000015
+:104E600002000F003A827100000000000000000004
+:104E700002000F003B8271000000000000000000F3
+:104E800002000F003C8271000000000000000000E2
+:104E900002000F003D8271000000000000000000D1
+:104EA00002000F003E8271000000000000000000C0
+:104EB00002000F003F8271000000000000000000AF
+:104EC00002000F004082710000000000000000009E
+:104ED00002000F004182710000000000000000008D
+:104EE00002000F004282710000000000000000007C
+:104EF00002000F004382710000000000000000006B
+:104F000002000F0044827100000000000000000059
+:104F100002000F0045827100000000000000000048
+:104F200002000F0046827100000000000000000037
+:104F300002000F0047827100000000000000000026
+:104F400002000F0048827100000000000000000015
+:104F500002000F0049827100000000000000000004
+:104F600002000F004A8271000000000000000000F3
+:104F700002000F004B8271000000000000000000E2
+:104F800002000F004C8271000000000000000000D1
+:104F900002000F004D8271000000000000000000C0
+:104FA00002000F004E8271000000000000000000AF
+:104FB00002000F004F82710000000000000000009E
+:104FC00002000F005082710000000000000000008D
+:104FD00002000F005182710000000000000000007C
+:104FE00002000F005282710000000000000000006B
+:104FF00002000F005382710000000000000000005A
+:1050000002000F0054827100000000000000000048
+:1050100002000F0055827100000000000000000037
+:1050200002000F0056827100000000000000000026
+:1050300002000F0057827100000000000000000015
+:1050400002000F0058827100000000000000000004
+:1050500002000F00598271000000000000000000F3
+:1050600002000F005A8271000000000000000000E2
+:1050700002000F005B8271000000000000000000D1
+:1050800002000F005C8271000000000000000000C0
+:1050900002000F005D8271000000000000000000AF
+:1050A00002000F005E82710000000000000000009E
+:1050B00002000F005F82710000000000000000008D
+:1050C00002000F006082710000000000000000007C
+:1050D00002000F006182710000000000000000006B
+:1050E00002000F006282710000000000000000005A
+:1050F00002000F0063827100000000000000000049
+:1051000002000F0064827100000000000000000037
+:1051100002000F0065827100000000000000000026
+:1051200002000F0066827100000000000000000015
+:1051300002000F0067827100000000000000000004
+:1051400002000F00688271000000000000000000F3
+:1051500002000F00698271000000000000000000E2
+:1051600002000F006A8271000000000000000000D1
+:1051700002000F006B8271000000000000000000C0
+:1051800002000F006C8271000000000000000000AF
+:1051900002000F006D82710000000000000000009E
+:1051A00002000F006E82710000000000000000008D
+:1051B00002000F006F82710000000000000000007C
+:1051C00002000F007082710000000000000000006B
+:1051D00002000F007182710000000000000000005A
+:1051E00002000F0072827100000000000000000049
+:1051F00002000F0073827100000000000000000038
+:1052000002000F0074827100000000000000000026
+:1052100002000F0075827100000000000000000015
+:1052200002000F0076827100000000000000000004
+:1052300002000F00778271000000000000000000F3
+:1052400002000F00788271000000000000000000E2
+:1052500002000F00798271000000000000000000D1
+:1052600002000F007A8271000000000000000000C0
+:1052700002000F007B8271000000000000000000AF
+:1052800002000F007C82710000000000000000009E
+:1052900002000F007D82710000000000000000008D
+:1052A00002000F007E82710000000000000000007C
+:1052B00002000F007F82710000000000000000006B
+:1052C00002000F008082710000000000000000005A
+:1052D00002000F0081827100000000000000000049
+:1052E00002000F0082827100000000000000000038
+:1052F00002000F0083827100000000000000000027
+:1053000002000F0084827100000000000000000015
+:1053100002000F0085827100000000000000000004
+:1053200002000F00868271000000000000000000F3
+:1053300002000F00878271000000000000000000E2
+:1053400002000F00888271000000000000000000D1
+:1053500002000F00898271000000000000000000C0
+:1053600002000F008A8271000000000000000000AF
+:1053700002000F008B82710000000000000000009E
+:1053800002000F008C82710000000000000000008D
+:1053900002000F008D82710000000000000000007C
+:1053A00002000F008E82710000000000000000006B
+:1053B00002000F008F82710000000000000000005A
+:1053C00002000F0090827100000000000000000049
+:1053D00002000F0091827100000000000000000038
+:1053E00002000F0092827100000000000000000027
+:1053F00002000F0093827100000000000000000016
+:1054000002000F0094827100000000000000000004
+:1054100002000F00958271000000000000000000F3
+:1054200002000F00968271000000000000000000E2
+:1054300002000F00978271000000000000000000D1
+:1054400002000F00988271000000000000000000C0
+:1054500002000F00998271000000000000000000AF
+:1054600002000F009A82710000000000000000009E
+:1054700002000F009B82710000000000000000008D
+:1054800002000F009C82710000000000000000007C
+:1054900002000F009D82710000000000000000006B
+:1054A00002000F009E82710000000000000000005A
+:1054B00002000F009F827100000000000000000049
+:1054C00002000F00A0827100000000000000000038
+:1054D00002000F00A1827100000000000000000027
+:1054E00002000F00A2827100000000000000000016
+:1054F00002000F00A3827100000000000000000005
+:1055000002000F00A48271000000000000000000F3
+:1055100002000F00A58271000000000000000000E2
+:1055200002000F00A68271000000000000000000D1
+:1055300002000F00A78271000000000000000000C0
+:1055400002000F00A88271000000000000000000AF
+:1055500002000F00A982710000000000000000009E
+:1055600002000F00AA82710000000000000000008D
+:1055700002000F00AB82710000000000000000007C
+:1055800002000F00AC82710000000000000000006B
+:1055900002000F00AD82710000000000000000005A
+:1055A00002000F00AE827100000000000000000049
+:1055B00002000F00AF827100000000000000000038
+:1055C00002000F00B0827100000000000000000027
+:1055D00002000F00B1827100000000000000000016
+:1055E00002000F00B2827100000000000000000005
+:1055F00002000F00B38271000000000000000000F4
+:1056000002000F00B48271000000000000000000E2
+:1056100002000F00B58271000000000000000000D1
+:1056200002000F00B68271000000000000000000C0
+:1056300002000F00B78271000000000000000000AF
+:1056400002000F00B882710000000000000000009E
+:1056500002000F00B982710000000000000000008D
+:1056600002000F00BA82710000000000000000007C
+:1056700002000F00BB82710000000000000000006B
+:1056800002000F00BC82710000000000000000005A
+:1056900002000F00BD827100000000000000000049
+:1056A00002000F00BE827100000000000000000038
+:1056B00002000F00BF827100000000000000000027
+:1056C00002000F00C0827100000000000000000016
+:1056D00002000F00C1827100000000000000000005
+:1056E00002000F00C28271000000000000000000F4
+:1056F00002000F00C38271000000000000000000E3
+:1057000002000F00C48271000000000000000000D1
+:1057100002000F00C58271000000000000000000C0
+:1057200002000F00C68271000000000000000000AF
+:1057300002000F00C782710000000000000000009E
+:1057400002000F00C882710000000000000000008D
+:1057500002000F00C982710000000000000000007C
+:1057600002000F00CA82710000000000000000006B
+:1057700002000F00CB82710000000000000000005A
+:1057800002000F00CC827100000000000000000049
+:1057900002000F00CD827100000000000000000038
+:1057A00002000F00CE827100000000000000000027
+:1057B00002000F00CF827100000000000000000016
+:1057C00002000F00D0827100000000000000000005
+:1057D00002000F00D18271000000000000000000F4
+:1057E00002000F00D28271000000000000000000E3
+:1057F00002000F00D38271000000000000000000D2
+:1058000002000F00D48271000000000000000000C0
+:1058100002000F00D58271000000000000000000AF
+:1058200002000F00D682710000000000000000009E
+:1058300002000F00D782710000000000000000008D
+:1058400002000F00D882710000000000000000007C
+:1058500002000F00D982710000000000000000006B
+:1058600002000F00DA82710000000000000000005A
+:1058700002000F00DB827100000000000000000049
+:1058800002000F00DC827100000000000000000038
+:1058900002000F00DD827100000000000000000027
+:1058A00002000F00DE827100000000000000000016
+:1058B00002000F00DF827100000000000000000005
+:1058C00002000F00E08271000000000000000000F4
+:1058D00002000F00E18271000000000000000000E3
+:1058E00002000F00E28271000000000000000000D2
+:1058F00002000F00E38271000000000000000000C1
+:1059000002000F00E48271000000000000000000AF
+:1059100002000F00E582710000000000000000009E
+:1059200002000F00E682710000000000000000008D
+:1059300002000F00E782710000000000000000007C
+:1059400002000F00E882710000000000000000006B
+:1059500002000F00E982710000000000000000005A
+:1059600002000F00EA827100000000000000000049
+:1059700002000F00EB827100000000000000000038
+:1059800002000F00EC827100000000000000000027
+:1059900002000F00ED827100000000000000000016
+:1059A00002000F00EE827100000000000000000005
+:1059B00002000F00EF8271000000000000000000F4
+:1059C00002000F00F08271000000000000000000E3
+:1059D00002000F00F18271000000000000000000D2
+:1059E00002000F00F28271000000000000000000C1
+:1059F00002000F00F38271000000000000000000B0
+:105A000002000F00F482710000000000000000009E
+:105A100002000F00F582710000000000000000008D
+:105A200002000F00F682710000000000000000007C
+:105A300002000F00F782710000000000000000006B
+:105A400002000F00F882710000000000000000005A
+:105A500002000F00F9827100000000000000000049
+:105A600002000F00FA827100000000000000000038
+:105A700002000F00FB827100000000000000000027
+:105A800002000F00FC827100000000000000000016
+:105A900002000F00FD827100000000000000000005
+:105AA00002000F00FE8271000000000000000000F4
+:105AB00002000F00FF8271000000000000000000E3
+:105AC00002000F00008371000000000000000000D1
+:105AD00002000F00018371000000000000000000C0
+:105AE00002000F00028371000000000000000000AF
+:105AF00002000F000383710000000000000000009E
+:105B000002000F000483710000000000000000008C
+:105B100002000F000583710000000000000000007B
+:105B200002000F000683710000000000000000006A
+:105B300002000F0007837100000000000000000059
+:105B400002000F0008837100000000000000000048
+:105B500002000F0009837100000000000000000037
+:105B600002000F000A837100000000000000000026
+:105B700002000F000B837100000000000000000015
+:105B800002000F000C837100000000000000000004
+:105B900002000F000D8371000000000000000000F3
+:105BA00002000F000E8371000000000000000000E2
+:105BB00002000F000F8371000000000000000000D1
+:105BC00002000F00108371000000000000000000C0
+:105BD00002000F00118371000000000000000000AF
+:105BE00002000F001283710000000000000000009E
+:105BF00002000F001383710000000000000000008D
+:105C000002000F001483710000000000000000007B
+:105C100002000F001583710000000000000000006A
+:105C200002000F0016837100000000000000000059
+:105C300002000F0017837100000000000000000048
+:105C400002000F0018837100000000000000000037
+:105C500002000F0019837100000000000000000026
+:105C600002000F001A837100000000000000000015
+:105C700002000F001B837100000000000000000004
+:105C800002000F001C8371000000000000000000F3
+:105C900002000F001D8371000000000000000000E2
+:105CA00002000F001E8371000000000000000000D1
+:105CB00002000F001F8371000000000000000000C0
+:105CC00002000F00208371000000000000000000AF
+:105CD00002000F002183710000000000000000009E
+:105CE00002000F002283710000000000000000008D
+:105CF00002000F002383710000000000000000007C
+:105D000002000F002483710000000000000000006A
+:105D100002000F0025837100000000000000000059
+:105D200002000F0026837100000000000000000048
+:105D300002000F0027837100000000000000000037
+:105D400002000F0028837100000000000000000026
+:105D500002000F0029837100000000000000000015
+:105D600002000F002A837100000000000000000004
+:105D700002000F002B8371000000000000000000F3
+:105D800002000F002C8371000000000000000000E2
+:105D900002000F002D8371000000000000000000D1
+:105DA00002000F002E8371000000000000000000C0
+:105DB00002000F002F8371000000000000000000AF
+:105DC00002000F003083710000000000000000009E
+:105DD00002000F003183710000000000000000008D
+:105DE00002000F003283710000000000000000007C
+:105DF00002000F003383710000000000000000006B
+:105E000002000F0034837100000000000000000059
+:105E100002000F0035837100000000000000000048
+:105E200002000F0036837100000000000000000037
+:105E300002000F0037837100000000000000000026
+:105E400002000F0038837100000000000000000015
+:105E500002000F0039837100000000000000000004
+:105E600002000F003A8371000000000000000000F3
+:105E700002000F003B8371000000000000000000E2
+:105E800002000F003C8371000000000000000000D1
+:105E900002000F003D8371000000000000000000C0
+:105EA00002000F003E8371000000000000000000AF
+:105EB00002000F003F83710000000000000000009E
+:105EC00002000F004083710000000000000000008D
+:105ED00002000F004183710000000000000000007C
+:105EE00002000F004283710000000000000000006B
+:105EF00002000F004383710000000000000000005A
+:105F000002000F0044837100000000000000000048
+:105F100002000F0045837100000000000000000037
+:105F200002000F0046837100000000000000000026
+:105F300002000F0047837100000000000000000015
+:105F400002000F0048837100000000000000000004
+:105F500002000F00498371000000000000000000F3
+:105F600002000F004A8371000000000000000000E2
+:105F700002000F004B8371000000000000000000D1
+:105F800002000F004C8371000000000000000000C0
+:105F900002000F004D8371000000000000000000AF
+:105FA00002000F004E83710000000000000000009E
+:105FB00002000F004F83710000000000000000008D
+:105FC00002000F005083710000000000000000007C
+:105FD00002000F005183710000000000000000006B
+:105FE00002000F005283710000000000000000005A
+:105FF00002000F0053837100000000000000000049
+:1060000002000F0054837100000000000000000037
+:1060100002000F0055837100000000000000000026
+:1060200002000F0056837100000000000000000015
+:1060300002000F0057837100000000000000000004
+:1060400002000F00588371000000000000000000F3
+:1060500002000F00598371000000000000000000E2
+:1060600002000F005A8371000000000000000000D1
+:1060700002000F005B8371000000000000000000C0
+:1060800002000F005C8371000000000000000000AF
+:1060900002000F005D83710000000000000000009E
+:1060A00002000F005E83710000000000000000008D
+:1060B00002000F005F83710000000000000000007C
+:1060C00002000F006083710000000000000000006B
+:1060D00002000F006183710000000000000000005A
+:1060E00002000F0062837100000000000000000049
+:1060F00002000F0063837100000000000000000038
+:1061000002000F0064837100000000000000000026
+:1061100002000F0065837100000000000000000015
+:1061200002000F0066837100000000000000000004
+:1061300002000F00678371000000000000000000F3
+:1061400002000F00688371000000000000000000E2
+:1061500002000F00698371000000000000000000D1
+:1061600002000F006A8371000000000000000000C0
+:1061700002000F006B8371000000000000000000AF
+:1061800002000F006C83710000000000000000009E
+:1061900002000F006D83710000000000000000008D
+:1061A00002000F006E83710000000000000000007C
+:1061B00002000F006F83710000000000000000006B
+:1061C00002000F007083710000000000000000005A
+:1061D00002000F0071837100000000000000000049
+:1061E00002000F0072837100000000000000000038
+:1061F00002000F0073837100000000000000000027
+:1062000002000F0074837100000000000000000015
+:1062100002000F0075837100000000000000000004
+:1062200002000F00768371000000000000000000F3
+:1062300002000F00778371000000000000000000E2
+:1062400002000F00788371000000000000000000D1
+:1062500002000F00798371000000000000000000C0
+:1062600002000F007A8371000000000000000000AF
+:1062700002000F007B83710000000000000000009E
+:1062800002000F007C83710000000000000000008D
+:1062900002000F007D83710000000000000000007C
+:1062A00002000F007E83710000000000000000006B
+:1062B00002000F007F83710000000000000000005A
+:1062C00002000F0080837100000000000000000049
+:1062D00002000F0081837100000000000000000038
+:1062E00002000F0082837100000000000000000027
+:1062F00002000F0083837100000000000000000016
+:1063000002000F0084837100000000000000000004
+:1063100002000F00858371000000000000000000F3
+:1063200002000F00868371000000000000000000E2
+:1063300002000F00878371000000000000000000D1
+:1063400002000F00888371000000000000000000C0
+:1063500002000F00898371000000000000000000AF
+:1063600002000F008A83710000000000000000009E
+:1063700002000F008B83710000000000000000008D
+:1063800002000F008C83710000000000000000007C
+:1063900002000F008D83710000000000000000006B
+:1063A00002000F008E83710000000000000000005A
+:1063B00002000F008F837100000000000000000049
+:1063C00002000F0090837100000000000000000038
+:1063D00002000F0091837100000000000000000027
+:1063E00002000F0092837100000000000000000016
+:1063F00002000F0093837100000000000000000005
+:1064000002000F00948371000000000000000000F3
+:1064100002000F00958371000000000000000000E2
+:1064200002000F00968371000000000000000000D1
+:1064300002000F00978371000000000000000000C0
+:1064400002000F00988371000000000000000000AF
+:1064500002000F009983710000000000000000009E
+:1064600002000F009A83710000000000000000008D
+:1064700002000F009B83710000000000000000007C
+:1064800002000F009C83710000000000000000006B
+:1064900002000F009D83710000000000000000005A
+:1064A00002000F009E837100000000000000000049
+:1064B00002000F009F837100000000000000000038
+:1064C00002000F00A0837100000000000000000027
+:1064D00002000F00A1837100000000000000000016
+:1064E00002000F00A2837100000000000000000005
+:1064F00002000F00A38371000000000000000000F4
+:1065000002000F00A48371000000000000000000E2
+:1065100002000F00A58371000000000000000000D1
+:1065200002000F00A68371000000000000000000C0
+:1065300002000F00A78371000000000000000000AF
+:1065400002000F00A883710000000000000000009E
+:1065500002000F00A983710000000000000000008D
+:1065600002000F00AA83710000000000000000007C
+:1065700002000F00AB83710000000000000000006B
+:1065800002000F00AC83710000000000000000005A
+:1065900002000F00AD837100000000000000000049
+:1065A00002000F00AE837100000000000000000038
+:1065B00002000F00AF837100000000000000000027
+:1065C00002000F00B0837100000000000000000016
+:1065D00002000F00B1837100000000000000000005
+:1065E00002000F00B28371000000000000000000F4
+:1065F00002000F00B38371000000000000000000E3
+:1066000002000F00B48371000000000000000000D1
+:1066100002000F00B58371000000000000000000C0
+:1066200002000F00B68371000000000000000000AF
+:1066300002000F00B783710000000000000000009E
+:1066400002000F00B883710000000000000000008D
+:1066500002000F00B983710000000000000000007C
+:1066600002000F00BA83710000000000000000006B
+:1066700002000F00BB83710000000000000000005A
+:1066800002000F00BC837100000000000000000049
+:1066900002000F00BD837100000000000000000038
+:1066A00002000F00BE837100000000000000000027
+:1066B00002000F00BF837100000000000000000016
+:1066C00002000F00C0837100000000000000000005
+:1066D00002000F00C18371000000000000000000F4
+:1066E00002000F00C28371000000000000000000E3
+:1066F00002000F00C38371000000000000000000D2
+:1067000002000F00C48371000000000000000000C0
+:1067100002000F00C58371000000000000000000AF
+:1067200002000F00C683710000000000000000009E
+:1067300002000F00C783710000000000000000008D
+:1067400002000F00C883710000000000000000007C
+:1067500002000F00C983710000000000000000006B
+:1067600002000F00CA83710000000000000000005A
+:1067700002000F00CB837100000000000000000049
+:1067800002000F00CC837100000000000000000038
+:1067900002000F00CD837100000000000000000027
+:1067A00002000F00CE837100000000000000000016
+:1067B00002000F00CF837100000000000000000005
+:1067C00002000F00D08371000000000000000000F4
+:1067D00002000F00D18371000000000000000000E3
+:1067E00002000F00D28371000000000000000000D2
+:1067F00002000F00D38371000000000000000000C1
+:1068000002000F00D48371000000000000000000AF
+:1068100002000F00D583710000000000000000009E
+:1068200002000F00D683710000000000000000008D
+:1068300002000F00D783710000000000000000007C
+:1068400002000F00D883710000000000000000006B
+:1068500002000F00D983710000000000000000005A
+:1068600002000F00DA837100000000000000000049
+:1068700002000F00DB837100000000000000000038
+:1068800002000F00DC837100000000000000000027
+:1068900002000F00DD837100000000000000000016
+:1068A00002000F00DE837100000000000000000005
+:1068B00002000F00DF8371000000000000000000F4
+:1068C00002000F00E08371000000000000000000E3
+:1068D00002000F00E18371000000000000000000D2
+:1068E00002000F00E28371000000000000000000C1
+:1068F00002000F00E38371000000000000000000B0
+:1069000002000F00E483710000000000000000009E
+:1069100002000F00E583710000000000000000008D
+:1069200002000F00E683710000000000000000007C
+:1069300002000F00E783710000000000000000006B
+:1069400002000F00E883710000000000000000005A
+:1069500002000F00E9837100000000000000000049
+:1069600002000F00EA837100000000000000000038
+:1069700002000F00EB837100000000000000000027
+:1069800002000F00EC837100000000000000000016
+:1069900002000F00ED837100000000000000000005
+:1069A00002000F00EE8371000000000000000000F4
+:1069B00002000F00EF8371000000000000000000E3
+:1069C00002000F00F08371000000000000000000D2
+:1069D00002000F00F18371000000000000000000C1
+:1069E00002000F00F28371000000000000000000B0
+:1069F00002000F00F383710000000000000000009F
+:106A000002000F00F483710000000000000000008D
+:106A100002000F00F583710000000000000000007C
+:106A200002000F00F683710000000000000000006B
+:106A300002000F00F783710000000000000000005A
+:106A400002000F00F8837100000000000000000049
+:106A500002000F00F9837100000000000000000038
+:106A600002000F00FA837100000000000000000027
+:106A700002000F00FB837100000000000000000016
+:106A800002000F00FC837100000000000000000005
+:106A900002000F00FD8371000000000000000000F4
+:106AA00002000F00FE8371000000000000000000E3
+:106AB00002000F00FF8371000000000000000000D2
+:106AC00002000F00008471000000000000000000C0
+:106AD00002000F00018471000000000000000000AF
+:106AE00002000F000284710000000000000000009E
+:106AF00002000F000384710000000000000000008D
+:106B000002000F000484710000000000000000007B
+:106B100002000F000584710000000000000000006A
+:106B200002000F0006847100000000000000000059
+:106B300002000F0007847100000000000000000048
+:106B400002000F0008847100000000000000000037
+:106B500002000F0009847100000000000000000026
+:106B600002000F000A847100000000000000000015
+:106B700002000F000B847100000000000000000004
+:106B800002000F000C8471000000000000000000F3
+:106B900002000F000D8471000000000000000000E2
+:106BA00002000F000E8471000000000000000000D1
+:106BB00002000F000F8471000000000000000000C0
+:106BC00002000F00108471000000000000000000AF
+:106BD00002000F001184710000000000000000009E
+:106BE00002000F001284710000000000000000008D
+:106BF00002000F001384710000000000000000007C
+:106C000002000F001484710000000000000000006A
+:106C100002000F0015847100000000000000000059
+:106C200002000F0016847100000000000000000048
+:106C300002000F0017847100000000000000000037
+:106C400002000F0018847100000000000000000026
+:106C500002000F0019847100000000000000000015
+:106C600002000F001A847100000000000000000004
+:106C700002000F001B8471000000000000000000F3
+:106C800002000F001C8471000000000000000000E2
+:106C900002000F001D8471000000000000000000D1
+:106CA00002000F001E8471000000000000000000C0
+:106CB00002000F001F8471000000000000000000AF
+:106CC00002000F002084710000000000000000009E
+:106CD00002000F002184710000000000000000008D
+:106CE00002000F002284710000000000000000007C
+:106CF00002000F002384710000000000000000006B
+:106D000002000F0024847100000000000000000059
+:106D100002000F0025847100000000000000000048
+:106D200002000F0026847100000000000000000037
+:106D300002000F0027847100000000000000000026
+:106D400002000F0028847100000000000000000015
+:106D500002000F0029847100000000000000000004
+:106D600002000F002A8471000000000000000000F3
+:106D700002000F002B8471000000000000000000E2
+:106D800002000F002C8471000000000000000000D1
+:106D900002000F002D8471000000000000000000C0
+:106DA00002000F002E8471000000000000000000AF
+:106DB00002000F002F84710000000000000000009E
+:106DC00002000F003084710000000000000000008D
+:106DD00002000F003184710000000000000000007C
+:106DE00002000F003284710000000000000000006B
+:106DF00002000F003384710000000000000000005A
+:106E000002000F0034847100000000000000000048
+:106E100002000F0035847100000000000000000037
+:106E200002000F0036847100000000000000000026
+:106E300002000F0037847100000000000000000015
+:106E400002000F0038847100000000000000000004
+:106E500002000F00398471000000000000000000F3
+:106E600002000F003A8471000000000000000000E2
+:106E700002000F003B8471000000000000000000D1
+:106E800002000F003C8471000000000000000000C0
+:106E900002000F003D8471000000000000000000AF
+:106EA00002000F003E84710000000000000000009E
+:106EB00002000F003F84710000000000000000008D
+:106EC00002000F004084710000000000000000007C
+:106ED00002000F004184710000000000000000006B
+:106EE00002000F004284710000000000000000005A
+:106EF00002000F0043847100000000000000000049
+:106F000002000F0044847100000000000000000037
+:106F100002000F0045847100000000000000000026
+:106F200002000F0046847100000000000000000015
+:106F300002000F0047847100000000000000000004
+:106F400002000F00488471000000000000000000F3
+:106F500002000F00498471000000000000000000E2
+:106F600002000F004A8471000000000000000000D1
+:106F700002000F004B8471000000000000000000C0
+:106F800002000F004C8471000000000000000000AF
+:106F900002000F004D84710000000000000000009E
+:106FA00002000F004E84710000000000000000008D
+:106FB00002000F004F84710000000000000000007C
+:106FC00002000F005084710000000000000000006B
+:106FD00002000F005184710000000000000000005A
+:106FE00002000F0052847100000000000000000049
+:106FF00002000F0053847100000000000000000038
+:1070000002000F0054847100000000000000000026
+:1070100002000F0055847100000000000000000015
+:1070200002000F0056847100000000000000000004
+:1070300002000F00578471000000000000000000F3
+:1070400002000F00588471000000000000000000E2
+:1070500002000F00598471000000000000000000D1
+:1070600002000F005A8471000000000000000000C0
+:1070700002000F005B8471000000000000000000AF
+:1070800002000F005C84710000000000000000009E
+:1070900002000F005D84710000000000000000008D
+:1070A00002000F005E84710000000000000000007C
+:1070B00002000F005F84710000000000000000006B
+:1070C00002000F006084710000000000000000005A
+:1070D00002000F0061847100000000000000000049
+:1070E00002000F0062847100000000000000000038
+:1070F00002000F0063847100000000000000000027
+:1071000002000F0064847100000000000000000015
+:1071100002000F0065847100000000000000000004
+:1071200002000F00668471000000000000000000F3
+:1071300002000F00678471000000000000000000E2
+:1071400002000F00688471000000000000000000D1
+:1071500002000F00698471000000000000000000C0
+:1071600002000F006A8471000000000000000000AF
+:1071700002000F006B84710000000000000000009E
+:1071800002000F006C84710000000000000000008D
+:1071900002000F006D84710000000000000000007C
+:1071A00002000F006E84710000000000000000006B
+:1071B00002000F006F84710000000000000000005A
+:1071C00002000F0070847100000000000000000049
+:1071D00002000F0071847100000000000000000038
+:1071E00002000F0072847100000000000000000027
+:1071F00002000F0073847100000000000000000016
+:1072000002000F0074847100000000000000000004
+:1072100002000F00758471000000000000000000F3
+:1072200002000F00768471000000000000000000E2
+:1072300002000F00778471000000000000000000D1
+:1072400002000F00788471000000000000000000C0
+:1072500002000F00798471000000000000000000AF
+:1072600002000F007A84710000000000000000009E
+:1072700002000F007B84710000000000000000008D
+:1072800002000F007C84710000000000000000007C
+:1072900002000F007D84710000000000000000006B
+:1072A00002000F007E84710000000000000000005A
+:1072B00002000F007F847100000000000000000049
+:1072C00002000F0080847100000000000000000038
+:1072D00002000F0081847100000000000000000027
+:1072E00002000F0082847100000000000000000016
+:1072F00002000F0083847100000000000000000005
+:1073000002000F00848471000000000000000000F3
+:1073100002000F00858471000000000000000000E2
+:1073200002000F00868471000000000000000000D1
+:1073300002000F00878471000000000000000000C0
+:1073400002000F00888471000000000000000000AF
+:1073500002000F008984710000000000000000009E
+:1073600002000F008A84710000000000000000008D
+:1073700002000F008B84710000000000000000007C
+:1073800002000F008C84710000000000000000006B
+:1073900002000F008D84710000000000000000005A
+:1073A00002000F008E847100000000000000000049
+:1073B00002000F008F847100000000000000000038
+:1073C00002000F0090847100000000000000000027
+:1073D00002000F0091847100000000000000000016
+:1073E00002000F0092847100000000000000000005
+:1073F00002000F00938471000000000000000000F4
+:1074000002000F00948471000000000000000000E2
+:1074100002000F00958471000000000000000000D1
+:1074200002000F00968471000000000000000000C0
+:1074300002000F00978471000000000000000000AF
+:1074400002000F009884710000000000000000009E
+:1074500002000F009984710000000000000000008D
+:1074600002000F009A84710000000000000000007C
+:1074700002000F009B84710000000000000000006B
+:1074800002000F009C84710000000000000000005A
+:1074900002000F009D847100000000000000000049
+:1074A00002000F009E847100000000000000000038
+:1074B00002000F009F847100000000000000000027
+:1074C00002000F00A0847100000000000000000016
+:1074D00002000F00A1847100000000000000000005
+:1074E00002000F00A28471000000000000000000F4
+:1074F00002000F00A38471000000000000000000E3
+:1075000002000F00A48471000000000000000000D1
+:1075100002000F00A58471000000000000000000C0
+:1075200002000F00A68471000000000000000000AF
+:1075300002000F00A784710000000000000000009E
+:1075400002000F00A884710000000000000000008D
+:1075500002000F00A984710000000000000000007C
+:1075600002000F00AA84710000000000000000006B
+:1075700002000F00AB84710000000000000000005A
+:1075800002000F00AC847100000000000000000049
+:1075900002000F00AD847100000000000000000038
+:1075A00002000F00AE847100000000000000000027
+:1075B00002000F00AF847100000000000000000016
+:1075C00002000F00B0847100000000000000000005
+:1075D00002000F00B18471000000000000000000F4
+:1075E00002000F00B28471000000000000000000E3
+:1075F00002000F00B38471000000000000000000D2
+:1076000002000F00B48471000000000000000000C0
+:1076100002000F00B58471000000000000000000AF
+:1076200002000F00B684710000000000000000009E
+:1076300002000F00B784710000000000000000008D
+:1076400002000F00B884710000000000000000007C
+:1076500002000F00B984710000000000000000006B
+:1076600002000F00BA84710000000000000000005A
+:1076700002000F00BB847100000000000000000049
+:1076800002000F00BC847100000000000000000038
+:1076900002000F00BD847100000000000000000027
+:1076A00002000F00BE847100000000000000000016
+:1076B00002000F00BF847100000000000000000005
+:1076C00002000F00C08471000000000000000000F4
+:1076D00002000F00C18471000000000000000000E3
+:1076E00002000F00C28471000000000000000000D2
+:1076F00002000F00C38471000000000000000000C1
+:1077000002000F00C48471000000000000000000AF
+:1077100002000F00C584710000000000000000009E
+:1077200002000F00C684710000000000000000008D
+:1077300002000F00C784710000000000000000007C
+:1077400002000F00C884710000000000000000006B
+:1077500002000F00C984710000000000000000005A
+:1077600002000F00CA847100000000000000000049
+:1077700002000F00CB847100000000000000000038
+:1077800002000F00CC847100000000000000000027
+:1077900002000F00CD847100000000000000000016
+:1077A00002000F00CE847100000000000000000005
+:1077B00002000F00CF8471000000000000000000F4
+:1077C00002000F00D08471000000000000000000E3
+:1077D00002000F00D18471000000000000000000D2
+:1077E00002000F00D28471000000000000000000C1
+:1077F00002000F00D38471000000000000000000B0
+:1078000002000F00D484710000000000000000009E
+:1078100002000F00D584710000000000000000008D
+:1078200002000F00D684710000000000000000007C
+:1078300002000F00D784710000000000000000006B
+:1078400002000F00D884710000000000000000005A
+:1078500002000F00D9847100000000000000000049
+:1078600002000F00DA847100000000000000000038
+:1078700002000F00DB847100000000000000000027
+:1078800002000F00DC847100000000000000000016
+:1078900002000F00DD847100000000000000000005
+:1078A00002000F00DE8471000000000000000000F4
+:1078B00002000F00DF8471000000000000000000E3
+:1078C00002000F00E08471000000000000000000D2
+:1078D00002000F00E18471000000000000000000C1
+:1078E00002000F00E28471000000000000000000B0
+:1078F00002000F00E384710000000000000000009F
+:1079000002000F00E484710000000000000000008D
+:1079100002000F00E584710000000000000000007C
+:1079200002000F00E684710000000000000000006B
+:1079300002000F00E784710000000000000000005A
+:1079400002000F00E8847100000000000000000049
+:1079500002000F00E9847100000000000000000038
+:1079600002000F00EA847100000000000000000027
+:1079700002000F00EB847100000000000000000016
+:1079800002000F00EC847100000000000000000005
+:1079900002000F00ED8471000000000000000000F4
+:1079A00002000F00EE8471000000000000000000E3
+:1079B00002000F00EF8471000000000000000000D2
+:1079C00002000F00F08471000000000000000000C1
+:1079D00002000F00F18471000000000000000000B0
+:1079E00002000F00F284710000000000000000009F
+:1079F00002000F00F384710000000000000000008E
+:107A000002000F00F484710000000000000000007C
+:107A100002000F00F584710000000000000000006B
+:107A200002000F00F684710000000000000000005A
+:107A300002000F00F7847100000000000000000049
+:107A400002000F00F8847100000000000000000038
+:107A500002000F00F9847100000000000000000027
+:107A600002000F00FA847100000000000000000016
+:107A700002000F00FB847100000000000000000005
+:107A800002000F00FC8471000000000000000000F4
+:107A900002000F00FD8471000000000000000000E3
+:107AA00002000F00FE8471000000000000000000D2
+:107AB00002000F00FF8471000000000000000000C1
+:107AC00002000F00008571000000000000000000AF
+:107AD00002000F000185710000000000000000009E
+:107AE00002000F000285710000000000000000008D
+:107AF00002000F000385710000000000000000007C
+:107B000002000F000485710000000000000000006A
+:107B100002000F0005857100000000000000000059
+:107B200002000F0006857100000000000000000048
+:107B300002000F0007857100000000000000000037
+:107B400002000F0008857100000000000000000026
+:107B500002000F0009857100000000000000000015
+:107B600002000F000A857100000000000000000004
+:107B700002000F000B8571000000000000000000F3
+:107B800002000F000C8571000000000000000000E2
+:107B900002000F000D8571000000000000000000D1
+:107BA00002000F000E8571000000000000000000C0
+:107BB00002000F000F8571000000000000000000AF
+:107BC00002000F001085710000000000000000009E
+:107BD00002000F001185710000000000000000008D
+:107BE00002000F001285710000000000000000007C
+:107BF00002000F001385710000000000000000006B
+:107C000002000F0014857100000000000000000059
+:107C100002000F0015857100000000000000000048
+:107C200002000F0016857100000000000000000037
+:107C300002000F0017857100000000000000000026
+:107C400002000F0018857100000000000000000015
+:107C500002000F0019857100000000000000000004
+:107C600002000F001A8571000000000000000000F3
+:107C700002000F001B8571000000000000000000E2
+:107C800002000F001C8571000000000000000000D1
+:107C900002000F001D8571000000000000000000C0
+:107CA00002000F001E8571000000000000000000AF
+:107CB00002000F001F85710000000000000000009E
+:107CC00002000F002085710000000000000000008D
+:107CD00002000F002185710000000000000000007C
+:107CE00002000F002285710000000000000000006B
+:107CF00002000F002385710000000000000000005A
+:107D000002000F0024857100000000000000000048
+:107D100002000F0025857100000000000000000037
+:107D200002000F0026857100000000000000000026
+:107D300002000F0027857100000000000000000015
+:107D400002000F0028857100000000000000000004
+:107D500002000F00298571000000000000000000F3
+:107D600002000F002A8571000000000000000000E2
+:107D700002000F002B8571000000000000000000D1
+:107D800002000F002C8571000000000000000000C0
+:107D900002000F002D8571000000000000000000AF
+:107DA00002000F002E85710000000000000000009E
+:107DB00002000F002F85710000000000000000008D
+:107DC00002000F003085710000000000000000007C
+:107DD00002000F003185710000000000000000006B
+:107DE00002000F003285710000000000000000005A
+:107DF00002000F0033857100000000000000000049
+:107E000002000F0034857100000000000000000037
+:107E100002000F0035857100000000000000000026
+:107E200002000F0036857100000000000000000015
+:107E300002000F0037857100000000000000000004
+:107E400002000F00388571000000000000000000F3
+:107E500002000F00398571000000000000000000E2
+:107E600002000F003A8571000000000000000000D1
+:107E700002000F003B8571000000000000000000C0
+:107E800002000F003C8571000000000000000000AF
+:107E900002000F003D85710000000000000000009E
+:107EA00002000F003E85710000000000000000008D
+:107EB00002000F003F85710000000000000000007C
+:107EC00002000F004085710000000000000000006B
+:107ED00002000F004185710000000000000000005A
+:107EE00002000F0042857100000000000000000049
+:107EF00002000F0043857100000000000000000038
+:107F000002000F0044857100000000000000000026
+:107F100002000F0045857100000000000000000015
+:107F200002000F0046857100000000000000000004
+:107F300002000F00478571000000000000000000F3
+:107F400002000F00488571000000000000000000E2
+:107F500002000F00498571000000000000000000D1
+:107F600002000F004A8571000000000000000000C0
+:107F700002000F004B8571000000000000000000AF
+:107F800002000F004C85710000000000000000009E
+:107F900002000F004D85710000000000000000008D
+:107FA00002000F004E85710000000000000000007C
+:107FB00002000F004F85710000000000000000006B
+:107FC00002000F005085710000000000000000005A
+:107FD00002000F0051857100000000000000000049
+:107FE00002000F0052857100000000000000000038
+:107FF00002000F0053857100000000000000000027
+:1080000002000F0054857100000000000000000015
+:1080100002000F0055857100000000000000000004
+:1080200002000F00568571000000000000000000F3
+:1080300002000F00578571000000000000000000E2
+:1080400002000F00588571000000000000000000D1
+:1080500002000F00598571000000000000000000C0
+:1080600002000F005A8571000000000000000000AF
+:1080700002000F005B85710000000000000000009E
+:1080800002000F005C85710000000000000000008D
+:1080900002000F005D85710000000000000000007C
+:1080A00002000F005E85710000000000000000006B
+:1080B00002000F005F85710000000000000000005A
+:1080C00002000F0060857100000000000000000049
+:1080D00002000F0061857100000000000000000038
+:1080E00002000F0062857100000000000000000027
+:1080F00002000F0063857100000000000000000016
+:1081000002000F0064857100000000000000000004
+:1081100002000F00658571000000000000000000F3
+:1081200002000F00668571000000000000000000E2
+:1081300002000F00678571000000000000000000D1
+:1081400002000F00688571000000000000000000C0
+:1081500002000F00698571000000000000000000AF
+:1081600002000F006A85710000000000000000009E
+:1081700002000F006B85710000000000000000008D
+:1081800002000F006C85710000000000000000007C
+:1081900002000F006D85710000000000000000006B
+:1081A00002000F006E85710000000000000000005A
+:1081B00002000F006F857100000000000000000049
+:1081C00002000F0070857100000000000000000038
+:1081D00002000F0071857100000000000000000027
+:1081E00002000F0072857100000000000000000016
+:1081F00002000F0073857100000000000000000005
+:1082000002000F00748571000000000000000000F3
+:1082100002000F00758571000000000000000000E2
+:1082200002000F00768571000000000000000000D1
+:1082300002000F00778571000000000000000000C0
+:1082400002000F00788571000000000000000000AF
+:1082500002000F007985710000000000000000009E
+:1082600002000F007A85710000000000000000008D
+:1082700002000F007B85710000000000000000007C
+:1082800002000F007C85710000000000000000006B
+:1082900002000F007D85710000000000000000005A
+:1082A00002000F007E857100000000000000000049
+:1082B00002000F007F857100000000000000000038
+:1082C00002000F0080857100000000000000000027
+:1082D00002000F0081857100000000000000000016
+:1082E00002000F0082857100000000000000000005
+:1082F00002000F00838571000000000000000000F4
+:1083000002000F00848571000000000000000000E2
+:1083100002000F00858571000000000000000000D1
+:1083200002000F00868571000000000000000000C0
+:1083300002000F00878571000000000000000000AF
+:1083400002000F008885710000000000000000009E
+:1083500002000F008985710000000000000000008D
+:1083600002000F008A85710000000000000000007C
+:1083700002000F008B85710000000000000000006B
+:1083800002000F008C85710000000000000000005A
+:1083900002000F008D857100000000000000000049
+:1083A00002000F008E857100000000000000000038
+:1083B00002000F008F857100000000000000000027
+:1083C00002000F0090857100000000000000000016
+:1083D00002000F0091857100000000000000000005
+:1083E00002000F00928571000000000000000000F4
+:1083F00002000F00938571000000000000000000E3
+:1084000002000F00948571000000000000000000D1
+:1084100002000F00958571000000000000000000C0
+:1084200002000F00968571000000000000000000AF
+:1084300002000F009785710000000000000000009E
+:1084400002000F009885710000000000000000008D
+:1084500002000F009985710000000000000000007C
+:1084600002000F009A85710000000000000000006B
+:1084700002000F009B85710000000000000000005A
+:1084800002000F009C857100000000000000000049
+:1084900002000F009D857100000000000000000038
+:1084A00002000F009E857100000000000000000027
+:1084B00002000F009F857100000000000000000016
+:1084C00002000F00A0857100000000000000000005
+:1084D00002000F00A18571000000000000000000F4
+:1084E00002000F00A28571000000000000000000E3
+:1084F00002000F00A38571000000000000000000D2
+:1085000002000F00A48571000000000000000000C0
+:1085100002000F00A58571000000000000000000AF
+:1085200002000F00A685710000000000000000009E
+:1085300002000F00A785710000000000000000008D
+:1085400002000F00A885710000000000000000007C
+:1085500002000F00A985710000000000000000006B
+:1085600002000F00AA85710000000000000000005A
+:1085700002000F00AB857100000000000000000049
+:1085800002000F00AC857100000000000000000038
+:1085900002000F00AD857100000000000000000027
+:1085A00002000F00AE857100000000000000000016
+:1085B00002000F00AF857100000000000000000005
+:1085C00002000F00B08571000000000000000000F4
+:1085D00002000F00B18571000000000000000000E3
+:1085E00002000F00B28571000000000000000000D2
+:1085F00002000F00B38571000000000000000000C1
+:1086000002000F00B48571000000000000000000AF
+:1086100002000F00B585710000000000000000009E
+:1086200002000F00B685710000000000000000008D
+:1086300002000F00B785710000000000000000007C
+:1086400002000F00B885710000000000000000006B
+:1086500002000F00B985710000000000000000005A
+:1086600002000F00BA857100000000000000000049
+:1086700002000F00BB857100000000000000000038
+:1086800002000F00BC857100000000000000000027
+:1086900002000F00BD857100000000000000000016
+:1086A00002000F00BE857100000000000000000005
+:1086B00002000F00BF8571000000000000000000F4
+:1086C00002000F00C08571000000000000000000E3
+:1086D00002000F00C18571000000000000000000D2
+:1086E00002000F00C28571000000000000000000C1
+:1086F00002000F00C38571000000000000000000B0
+:1087000002000F00C485710000000000000000009E
+:1087100002000F00C585710000000000000000008D
+:1087200002000F00C685710000000000000000007C
+:1087300002000F00C785710000000000000000006B
+:1087400002000F00C885710000000000000000005A
+:1087500002000F00C9857100000000000000000049
+:1087600002000F00CA857100000000000000000038
+:1087700002000F00CB857100000000000000000027
+:1087800002000F00CC857100000000000000000016
+:1087900002000F00CD857100000000000000000005
+:1087A00002000F00CE8571000000000000000000F4
+:1087B00002000F00CF8571000000000000000000E3
+:1087C00002000F00D08571000000000000000000D2
+:1087D00002000F00D18571000000000000000000C1
+:1087E00002000F00D28571000000000000000000B0
+:1087F00002000F00D385710000000000000000009F
+:1088000002000F00D485710000000000000000008D
+:1088100002000F00D585710000000000000000007C
+:1088200002000F00D685710000000000000000006B
+:1088300002000F00D785710000000000000000005A
+:1088400002000F00D8857100000000000000000049
+:1088500002000F00D9857100000000000000000038
+:1088600002000F00DA857100000000000000000027
+:1088700002000F00DB857100000000000000000016
+:1088800002000F00DC857100000000000000000005
+:1088900002000F00DD8571000000000000000000F4
+:1088A00002000F00DE8571000000000000000000E3
+:1088B00002000F00DF8571000000000000000000D2
+:1088C00002000F00E08571000000000000000000C1
+:1088D00002000F00E18571000000000000000000B0
+:1088E00002000F00E285710000000000000000009F
+:1088F00002000F00E385710000000000000000008E
+:1089000002000F00E485710000000000000000007C
+:1089100002000F00E585710000000000000000006B
+:1089200002000F00E685710000000000000000005A
+:1089300002000F00E7857100000000000000000049
+:1089400002000F00E8857100000000000000000038
+:1089500002000F00E9857100000000000000000027
+:1089600002000F00EA857100000000000000000016
+:1089700002000F00EB857100000000000000000005
+:1089800002000F00EC8571000000000000000000F4
+:1089900002000F00ED8571000000000000000000E3
+:1089A00002000F00EE8571000000000000000000D2
+:1089B00002000F00EF8571000000000000000000C1
+:1089C00002000F00F08571000000000000000000B0
+:1089D00002000F00F185710000000000000000009F
+:1089E00002000F00F285710000000000000000008E
+:1089F00002000F00F385710000000000000000007D
+:108A000002000F00F485710000000000000000006B
+:108A100002000F00F585710000000000000000005A
+:108A200002000F00F6857100000000000000000049
+:108A300002000F00F7857100000000000000000038
+:108A400002000F00F8857100000000000000000027
+:108A500002000F00F9857100000000000000000016
+:108A600002000F00FA857100000000000000000005
+:108A700002000F00FB8571000000000000000000F4
+:108A800002000F00FC8571000000000000000000E3
+:108A900002000F00FD8571000000000000000000D2
+:108AA00002000F00FE8571000000000000000000C1
+:108AB00002000F00FF8571000000000000000000B0
+:108AC00002000F000086710000000000000000009E
+:108AD00002000F000186710000000000000000008D
+:108AE00002000F000286710000000000000000007C
+:108AF00002000F000386710000000000000000006B
+:108B000002000F0004867100000000000000000059
+:108B100002000F0005867100000000000000000048
+:108B200002000F0006867100000000000000000037
+:108B300002000F0007867100000000000000000026
+:108B400002000F0008867100000000000000000015
+:108B500002000F0009867100000000000000000004
+:108B600002000F000A8671000000000000000000F3
+:108B700002000F000B8671000000000000000000E2
+:108B800002000F000C8671000000000000000000D1
+:108B900002000F000D8671000000000000000000C0
+:108BA00002000F000E8671000000000000000000AF
+:108BB00002000F000F86710000000000000000009E
+:108BC00002000F001086710000000000000000008D
+:108BD00002000F001186710000000000000000007C
+:108BE00002000F001286710000000000000000006B
+:108BF00002000F001386710000000000000000005A
+:108C000002000F0014867100000000000000000048
+:108C100002000F0015867100000000000000000037
+:108C200002000F0016867100000000000000000026
+:108C300002000F0017867100000000000000000015
+:108C400002000F0018867100000000000000000004
+:108C500002000F00198671000000000000000000F3
+:108C600002000F001A8671000000000000000000E2
+:108C700002000F001B8671000000000000000000D1
+:108C800002000F001C8671000000000000000000C0
+:108C900002000F001D8671000000000000000000AF
+:108CA00002000F001E86710000000000000000009E
+:108CB00002000F001F86710000000000000000008D
+:108CC00002000F002086710000000000000000007C
+:108CD00002000F002186710000000000000000006B
+:108CE00002000F002286710000000000000000005A
+:108CF00002000F0023867100000000000000000049
+:108D000002000F0024867100000000000000000037
+:108D100002000F0025867100000000000000000026
+:108D200002000F0026867100000000000000000015
+:108D300002000F0027867100000000000000000004
+:108D400002000F00288671000000000000000000F3
+:108D500002000F00298671000000000000000000E2
+:108D600002000F002A8671000000000000000000D1
+:108D700002000F002B8671000000000000000000C0
+:108D800002000F002C8671000000000000000000AF
+:108D900002000F002D86710000000000000000009E
+:108DA00002000F002E86710000000000000000008D
+:108DB00002000F002F86710000000000000000007C
+:108DC00002000F003086710000000000000000006B
+:108DD00002000F003186710000000000000000005A
+:108DE00002000F0032867100000000000000000049
+:108DF00002000F0033867100000000000000000038
+:108E000002000F0034867100000000000000000026
+:108E100002000F0035867100000000000000000015
+:108E200002000F0036867100000000000000000004
+:108E300002000F00378671000000000000000000F3
+:108E400002000F00388671000000000000000000E2
+:108E500002000F00398671000000000000000000D1
+:108E600002000F003A8671000000000000000000C0
+:108E700002000F003B8671000000000000000000AF
+:108E800002000F003C86710000000000000000009E
+:108E900002000F003D86710000000000000000008D
+:108EA00002000F003E86710000000000000000007C
+:108EB00002000F003F86710000000000000000006B
+:108EC00002000F004086710000000000000000005A
+:108ED00002000F0041867100000000000000000049
+:108EE00002000F0042867100000000000000000038
+:108EF00002000F0043867100000000000000000027
+:108F000002000F0044867100000000000000000015
+:108F100002000F0045867100000000000000000004
+:108F200002000F00468671000000000000000000F3
+:108F300002000F00478671000000000000000000E2
+:108F400002000F00488671000000000000000000D1
+:108F500002000F00498671000000000000000000C0
+:108F600002000F004A8671000000000000000000AF
+:108F700002000F004B86710000000000000000009E
+:108F800002000F004C86710000000000000000008D
+:108F900002000F004D86710000000000000000007C
+:108FA00002000F004E86710000000000000000006B
+:108FB00002000F004F86710000000000000000005A
+:108FC00002000F0050867100000000000000000049
+:108FD00002000F0051867100000000000000000038
+:108FE00002000F0052867100000000000000000027
+:108FF00002000F0053867100000000000000000016
+:1090000002000F0054867100000000000000000004
+:1090100002000F00558671000000000000000000F3
+:1090200002000F00568671000000000000000000E2
+:1090300002000F00578671000000000000000000D1
+:1090400002000F00588671000000000000000000C0
+:1090500002000F00598671000000000000000000AF
+:1090600002000F005A86710000000000000000009E
+:1090700002000F005B86710000000000000000008D
+:1090800002000F005C86710000000000000000007C
+:1090900002000F005D86710000000000000000006B
+:1090A00002000F005E86710000000000000000005A
+:1090B00002000F005F867100000000000000000049
+:1090C00002000F0060867100000000000000000038
+:1090D00002000F0061867100000000000000000027
+:1090E00002000F0062867100000000000000000016
+:1090F00002000F0063867100000000000000000005
+:1091000002000F00648671000000000000000000F3
+:1091100002000F00658671000000000000000000E2
+:1091200002000F00668671000000000000000000D1
+:1091300002000F00678671000000000000000000C0
+:1091400002000F00688671000000000000000000AF
+:1091500002000F006986710000000000000000009E
+:1091600002000F006A86710000000000000000008D
+:1091700002000F006B86710000000000000000007C
+:1091800002000F006C86710000000000000000006B
+:1091900002000F006D86710000000000000000005A
+:1091A00002000F006E867100000000000000000049
+:1091B00002000F006F867100000000000000000038
+:1091C00002000F0070867100000000000000000027
+:1091D00002000F0071867100000000000000000016
+:1091E00002000F0072867100000000000000000005
+:1091F00002000F00738671000000000000000000F4
+:1092000002000F00748671000000000000000000E2
+:1092100002000F00758671000000000000000000D1
+:1092200002000F00768671000000000000000000C0
+:1092300002000F00778671000000000000000000AF
+:1092400002000F007886710000000000000000009E
+:1092500002000F007986710000000000000000008D
+:1092600002000F007A86710000000000000000007C
+:1092700002000F007B86710000000000000000006B
+:1092800002000F007C86710000000000000000005A
+:1092900002000F007D867100000000000000000049
+:1092A00002000F007E867100000000000000000038
+:1092B00002000F007F867100000000000000000027
+:1092C00002000F0080867100000000000000000016
+:1092D00002000F0081867100000000000000000005
+:1092E00002000F00828671000000000000000000F4
+:1092F00002000F00838671000000000000000000E3
+:1093000002000F00848671000000000000000000D1
+:1093100002000F00858671000000000000000000C0
+:1093200002000F00868671000000000000000000AF
+:1093300002000F008786710000000000000000009E
+:1093400002000F008886710000000000000000008D
+:1093500002000F008986710000000000000000007C
+:1093600002000F008A86710000000000000000006B
+:1093700002000F008B86710000000000000000005A
+:1093800002000F008C867100000000000000000049
+:1093900002000F008D867100000000000000000038
+:1093A00002000F008E867100000000000000000027
+:1093B00002000F008F867100000000000000000016
+:1093C00002000F0090867100000000000000000005
+:1093D00002000F00918671000000000000000000F4
+:1093E00002000F00928671000000000000000000E3
+:1093F00002000F00938671000000000000000000D2
+:1094000002000F00948671000000000000000000C0
+:1094100002000F00958671000000000000000000AF
+:1094200002000F009686710000000000000000009E
+:1094300002000F009786710000000000000000008D
+:1094400002000F009886710000000000000000007C
+:1094500002000F009986710000000000000000006B
+:1094600002000F009A86710000000000000000005A
+:1094700002000F009B867100000000000000000049
+:1094800002000F009C867100000000000000000038
+:1094900002000F009D867100000000000000000027
+:1094A00002000F009E867100000000000000000016
+:1094B00002000F009F867100000000000000000005
+:1094C00002000F00A08671000000000000000000F4
+:1094D00002000F00A18671000000000000000000E3
+:1094E00002000F00A28671000000000000000000D2
+:1094F00002000F00A38671000000000000000000C1
+:1095000002000F00A48671000000000000000000AF
+:1095100002000F00A586710000000000000000009E
+:1095200002000F00A686710000000000000000008D
+:1095300002000F00A786710000000000000000007C
+:1095400002000F00A886710000000000000000006B
+:1095500002000F00A986710000000000000000005A
+:1095600002000F00AA867100000000000000000049
+:1095700002000F00AB867100000000000000000038
+:1095800002000F00AC867100000000000000000027
+:1095900002000F00AD867100000000000000000016
+:1095A00002000F00AE867100000000000000000005
+:1095B00002000F00AF8671000000000000000000F4
+:1095C00002000F00B08671000000000000000000E3
+:1095D00002000F00B18671000000000000000000D2
+:1095E00002000F00B28671000000000000000000C1
+:1095F00002000F00B38671000000000000000000B0
+:1096000002000F00B486710000000000000000009E
+:1096100002000F00B586710000000000000000008D
+:1096200002000F00B686710000000000000000007C
+:1096300002000F00B786710000000000000000006B
+:1096400002000F00B886710000000000000000005A
+:1096500002000F00B9867100000000000000000049
+:1096600002000F00BA867100000000000000000038
+:1096700002000F00BB867100000000000000000027
+:1096800002000F00BC867100000000000000000016
+:1096900002000F00BD867100000000000000000005
+:1096A00002000F00BE8671000000000000000000F4
+:1096B00002000F00BF8671000000000000000000E3
+:1096C00002000F00C08671000000000000000000D2
+:1096D00002000F00C18671000000000000000000C1
+:1096E00002000F00C28671000000000000000000B0
+:1096F00002000F00C386710000000000000000009F
+:1097000002000F00C486710000000000000000008D
+:1097100002000F00C586710000000000000000007C
+:1097200002000F00C686710000000000000000006B
+:1097300002000F00C786710000000000000000005A
+:1097400002000F00C8867100000000000000000049
+:1097500002000F00C9867100000000000000000038
+:1097600002000F00CA867100000000000000000027
+:1097700002000F00CB867100000000000000000016
+:1097800002000F00CC867100000000000000000005
+:1097900002000F00CD8671000000000000000000F4
+:1097A00002000F00CE8671000000000000000000E3
+:1097B00002000F00CF8671000000000000000000D2
+:1097C00002000F00D08671000000000000000000C1
+:1097D00002000F00D18671000000000000000000B0
+:1097E00002000F00D286710000000000000000009F
+:1097F00002000F00D386710000000000000000008E
+:1098000002000F00D486710000000000000000007C
+:1098100002000F00D586710000000000000000006B
+:1098200002000F00D686710000000000000000005A
+:1098300002000F00D7867100000000000000000049
+:1098400002000F00D8867100000000000000000038
+:1098500002000F00D9867100000000000000000027
+:1098600002000F00DA867100000000000000000016
+:1098700002000F00DB867100000000000000000005
+:1098800002000F00DC8671000000000000000000F4
+:1098900002000F00DD8671000000000000000000E3
+:1098A00002000F00DE8671000000000000000000D2
+:1098B00002000F00DF8671000000000000000000C1
+:1098C00002000F00E08671000000000000000000B0
+:1098D00002000F00E186710000000000000000009F
+:1098E00002000F00E286710000000000000000008E
+:1098F00002000F00E386710000000000000000007D
+:1099000002000F00E486710000000000000000006B
+:1099100002000F00E586710000000000000000005A
+:1099200002000F00E6867100000000000000000049
+:1099300002000F00E7867100000000000000000038
+:1099400002000F00E8867100000000000000000027
+:1099500002000F00E9867100000000000000000016
+:1099600002000F00EA867100000000000000000005
+:1099700002000F00EB8671000000000000000000F4
+:1099800002000F00EC8671000000000000000000E3
+:1099900002000F00ED8671000000000000000000D2
+:1099A00002000F00EE8671000000000000000000C1
+:1099B00002000F00EF8671000000000000000000B0
+:1099C00002000F00F086710000000000000000009F
+:1099D00002000F00F186710000000000000000008E
+:1099E00002000F00F286710000000000000000007D
+:1099F00002000F00F386710000000000000000006C
+:109A000002000F00F486710000000000000000005A
+:109A100002000F00F5867100000000000000000049
+:109A200002000F00F6867100000000000000000038
+:109A300002000F00F7867100000000000000000027
+:109A400002000F00F8867100000000000000000016
+:109A500002000F00F9867100000000000000000005
+:109A600002000F00FA8671000000000000000000F4
+:109A700002000F00FB8671000000000000000000E3
+:109A800002000F00FC8671000000000000000000D2
+:109A900002000F00FD8671000000000000000000C1
+:109AA00002000F00FE8671000000000000000000B0
+:109AB00002000F00FF86710000000000000000009F
+:109AC00002000F000087710000000000000000008D
+:109AD00002000F000187710000000000000000007C
+:109AE00002000F000287710000000000000000006B
+:109AF00002000F000387710000000000000000005A
+:109B000002000F0004877100000000000000000048
+:109B100002000F0005877100000000000000000037
+:109B200002000F0006877100000000000000000026
+:109B300002000F0007877100000000000000000015
+:109B400002000F0008877100000000000000000004
+:109B500002000F00098771000000000000000000F3
+:109B600002000F000A8771000000000000000000E2
+:109B700002000F000B8771000000000000000000D1
+:109B800002000F000C8771000000000000000000C0
+:109B900002000F000D8771000000000000000000AF
+:109BA00002000F000E87710000000000000000009E
+:109BB00002000F000F87710000000000000000008D
+:109BC00002000F001087710000000000000000007C
+:109BD00002000F001187710000000000000000006B
+:109BE00002000F001287710000000000000000005A
+:109BF00002000F0013877100000000000000000049
+:109C000002000F0014877100000000000000000037
+:109C100002000F0015877100000000000000000026
+:109C200002000F0016877100000000000000000015
+:109C300002000F0017877100000000000000000004
+:109C400002000F00188771000000000000000000F3
+:109C500002000F00198771000000000000000000E2
+:109C600002000F001A8771000000000000000000D1
+:109C700002000F001B8771000000000000000000C0
+:109C800002000F001C8771000000000000000000AF
+:109C900002000F001D87710000000000000000009E
+:109CA00002000F001E87710000000000000000008D
+:109CB00002000F001F87710000000000000000007C
+:109CC00002000F002087710000000000000000006B
+:109CD00002000F002187710000000000000000005A
+:109CE00002000F0022877100000000000000000049
+:109CF00002000F0023877100000000000000000038
+:109D000002000F0024877100000000000000000026
+:109D100002000F0025877100000000000000000015
+:109D200002000F0026877100000000000000000004
+:109D300002000F00278771000000000000000000F3
+:109D400002000F00288771000000000000000000E2
+:109D500002000F00298771000000000000000000D1
+:109D600002000F002A8771000000000000000000C0
+:109D700002000F002B8771000000000000000000AF
+:109D800002000F002C87710000000000000000009E
+:109D900002000F002D87710000000000000000008D
+:109DA00002000F002E87710000000000000000007C
+:109DB00002000F002F87710000000000000000006B
+:109DC00002000F003087710000000000000000005A
+:109DD00002000F0031877100000000000000000049
+:109DE00002000F0032877100000000000000000038
+:109DF00002000F0033877100000000000000000027
+:109E000002000F0034877100000000000000000015
+:109E100002000F0035877100000000000000000004
+:109E200002000F00368771000000000000000000F3
+:109E300002000F00378771000000000000000000E2
+:109E400002000F00388771000000000000000000D1
+:109E500002000F00398771000000000000000000C0
+:109E600002000F003A8771000000000000000000AF
+:109E700002000F003B87710000000000000000009E
+:109E800002000F003C87710000000000000000008D
+:109E900002000F003D87710000000000000000007C
+:109EA00002000F003E87710000000000000000006B
+:109EB00002000F003F87710000000000000000005A
+:109EC00002000F0040877100000000000000000049
+:109ED00002000F0041877100000000000000000038
+:109EE00002000F0042877100000000000000000027
+:109EF00002000F0043877100000000000000000016
+:109F000002000F0044877100000000000000000004
+:109F100002000F00458771000000000000000000F3
+:109F200002000F00468771000000000000000000E2
+:109F300002000F00478771000000000000000000D1
+:109F400002000F00488771000000000000000000C0
+:109F500002000F00498771000000000000000000AF
+:109F600002000F004A87710000000000000000009E
+:109F700002000F004B87710000000000000000008D
+:109F800002000F004C87710000000000000000007C
+:109F900002000F004D87710000000000000000006B
+:109FA00002000F004E87710000000000000000005A
+:109FB00002000F004F877100000000000000000049
+:109FC00002000F0050877100000000000000000038
+:109FD00002000F0051877100000000000000000027
+:109FE00002000F0052877100000000000000000016
+:109FF00002000F0053877100000000000000000005
+:10A0000002000F00548771000000000000000000F3
+:10A0100002000F00558771000000000000000000E2
+:10A0200002000F00568771000000000000000000D1
+:10A0300002000F00578771000000000000000000C0
+:10A0400002000F00588771000000000000000000AF
+:10A0500002000F005987710000000000000000009E
+:10A0600002000F005A87710000000000000000008D
+:10A0700002000F005B87710000000000000000007C
+:10A0800002000F005C87710000000000000000006B
+:10A0900002000F005D87710000000000000000005A
+:10A0A00002000F005E877100000000000000000049
+:10A0B00002000F005F877100000000000000000038
+:10A0C00002000F0060877100000000000000000027
+:10A0D00002000F0061877100000000000000000016
+:10A0E00002000F0062877100000000000000000005
+:10A0F00002000F00638771000000000000000000F4
+:10A1000002000F00648771000000000000000000E2
+:10A1100002000F00658771000000000000000000D1
+:10A1200002000F00668771000000000000000000C0
+:10A1300002000F00678771000000000000000000AF
+:10A1400002000F006887710000000000000000009E
+:10A1500002000F006987710000000000000000008D
+:10A1600002000F006A87710000000000000000007C
+:10A1700002000F006B87710000000000000000006B
+:10A1800002000F006C87710000000000000000005A
+:10A1900002000F006D877100000000000000000049
+:10A1A00002000F006E877100000000000000000038
+:10A1B00002000F006F877100000000000000000027
+:10A1C00002000F0070877100000000000000000016
+:10A1D00002000F0071877100000000000000000005
+:10A1E00002000F00728771000000000000000000F4
+:10A1F00002000F00738771000000000000000000E3
+:10A2000002000F00748771000000000000000000D1
+:10A2100002000F00758771000000000000000000C0
+:10A2200002000F00768771000000000000000000AF
+:10A2300002000F007787710000000000000000009E
+:10A2400002000F007887710000000000000000008D
+:10A2500002000F007987710000000000000000007C
+:10A2600002000F007A87710000000000000000006B
+:10A2700002000F007B87710000000000000000005A
+:10A2800002000F007C877100000000000000000049
+:10A2900002000F007D877100000000000000000038
+:10A2A00002000F007E877100000000000000000027
+:10A2B00002000F007F877100000000000000000016
+:10A2C00002000F0080877100000000000000000005
+:10A2D00002000F00818771000000000000000000F4
+:10A2E00002000F00828771000000000000000000E3
+:10A2F00002000F00838771000000000000000000D2
+:10A3000002000F00848771000000000000000000C0
+:10A3100002000F00858771000000000000000000AF
+:10A3200002000F008687710000000000000000009E
+:10A3300002000F008787710000000000000000008D
+:10A3400002000F008887710000000000000000007C
+:10A3500002000F008987710000000000000000006B
+:10A3600002000F008A87710000000000000000005A
+:10A3700002000F008B877100000000000000000049
+:10A3800002000F008C877100000000000000000038
+:10A3900002000F008D877100000000000000000027
+:10A3A00002000F008E877100000000000000000016
+:10A3B00002000F008F877100000000000000000005
+:10A3C00002000F00908771000000000000000000F4
+:10A3D00002000F00918771000000000000000000E3
+:10A3E00002000F00928771000000000000000000D2
+:10A3F00002000F00938771000000000000000000C1
+:10A4000002000F00948771000000000000000000AF
+:10A4100002000F009587710000000000000000009E
+:10A4200002000F009687710000000000000000008D
+:10A4300002000F009787710000000000000000007C
+:10A4400002000F009887710000000000000000006B
+:10A4500002000F009987710000000000000000005A
+:10A4600002000F009A877100000000000000000049
+:10A4700002000F009B877100000000000000000038
+:10A4800002000F009C877100000000000000000027
+:10A4900002000F009D877100000000000000000016
+:10A4A00002000F009E877100000000000000000005
+:10A4B00002000F009F8771000000000000000000F4
+:10A4C00002000F00A08771000000000000000000E3
+:10A4D00002000F00A18771000000000000000000D2
+:10A4E00002000F00A28771000000000000000000C1
+:10A4F00002000F00A38771000000000000000000B0
+:10A5000002000F00A487710000000000000000009E
+:10A5100002000F00A587710000000000000000008D
+:10A5200002000F00A687710000000000000000007C
+:10A5300002000F00A787710000000000000000006B
+:10A5400002000F00A887710000000000000000005A
+:10A5500002000F00A9877100000000000000000049
+:10A5600002000F00AA877100000000000000000038
+:10A5700002000F00AB877100000000000000000027
+:10A5800002000F00AC877100000000000000000016
+:10A5900002000F00AD877100000000000000000005
+:10A5A00002000F00AE8771000000000000000000F4
+:10A5B00002000F00AF8771000000000000000000E3
+:10A5C00002000F00B08771000000000000000000D2
+:10A5D00002000F00B18771000000000000000000C1
+:10A5E00002000F00B28771000000000000000000B0
+:10A5F00002000F00B387710000000000000000009F
+:10A6000002000F00B487710000000000000000008D
+:10A6100002000F00B587710000000000000000007C
+:10A6200002000F00B687710000000000000000006B
+:10A6300002000F00B787710000000000000000005A
+:10A6400002000F00B8877100000000000000000049
+:10A6500002000F00B9877100000000000000000038
+:10A6600002000F00BA877100000000000000000027
+:10A6700002000F00BB877100000000000000000016
+:10A6800002000F00BC877100000000000000000005
+:10A6900002000F00BD8771000000000000000000F4
+:10A6A00002000F00BE8771000000000000000000E3
+:10A6B00002000F00BF8771000000000000000000D2
+:10A6C00002000F00C087710079000000769060FDE5
+:10A6D00002000F00C18771003D0000006F0080F78D
+:10A6E00002000F00C28771003D0000006F0080F77C
+:10A6F00002000F00C38771003D0000006F0080F76B
+:10A7000002000F00C48771803D0000006F0080F7D9
+:00000001FF
+/* Loading Firmware */
+/* INT_MEM Ver */
+ * Tehuti Networks(R) Network Driver
+ * Copyright (C) 2007 Tehuti Networks Ltd. All rights reserved
index 38bc735c67ad2ebfe79a4d64d35e6ad01117c8d6..dc20db348679d9f300f68af931b4e9b3a0019752 100644 (file)
@@ -69,10 +69,12 @@ obj-$(CONFIG_DLM)           += dlm/
 # Do not add any filesystems before this line
 obj-$(CONFIG_REISERFS_FS)      += reiserfs/
 obj-$(CONFIG_EXT3_FS)          += ext3/ # Before ext2 so root fs can be ext3
-obj-$(CONFIG_EXT4_FS)          += ext4/ # Before ext2 so root fs can be ext4
+obj-$(CONFIG_EXT2_FS)          += ext2/
+# We place ext4 after ext2 so plain ext2 root fs's are mounted using ext2
+# unless explicitly requested by rootfstype
+obj-$(CONFIG_EXT4_FS)          += ext4/
 obj-$(CONFIG_JBD)              += jbd/
 obj-$(CONFIG_JBD2)             += jbd2/
-obj-$(CONFIG_EXT2_FS)          += ext2/
 obj-$(CONFIG_CRAMFS)           += cramfs/
 obj-$(CONFIG_SQUASHFS)         += squashfs/
 obj-y                          += ramfs/
index 062299acbccddc2d8f808d6cb85722cdd9ef6d09..124b95c4d58286649d8d0f982edd9074af18ac82 100644 (file)
--- a/fs/bio.c
+++ b/fs/bio.c
@@ -302,9 +302,10 @@ void bio_init(struct bio *bio)
 struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
 {
        struct bio *bio = NULL;
+       void *uninitialized_var(p);
 
        if (bs) {
-               void *p = mempool_alloc(bs->bio_pool, gfp_mask);
+               p = mempool_alloc(bs->bio_pool, gfp_mask);
 
                if (p)
                        bio = p + bs->front_pad;
@@ -329,7 +330,7 @@ struct bio *bio_alloc_bioset(gfp_t gfp_mask, int nr_iovecs, struct bio_set *bs)
                        }
                        if (unlikely(!bvl)) {
                                if (bs)
-                                       mempool_free(bio, bs->bio_pool);
+                                       mempool_free(p, bs->bio_pool);
                                else
                                        kfree(bio);
                                bio = NULL;
index a8c9693b75ac42e939edaede65a29a31244d66c8..72677ce2b74fc87b1ff6a277906492389085f687 100644 (file)
@@ -66,6 +66,9 @@ struct btrfs_inode {
         */
        struct list_head delalloc_inodes;
 
+       /* the space_info for where this inode's data allocations are done */
+       struct btrfs_space_info *space_info;
+
        /* full 64 bit generation number, struct vfs_inode doesn't have a big
         * enough field for this.
         */
@@ -94,6 +97,11 @@ struct btrfs_inode {
         */
        u64 delalloc_bytes;
 
+       /* total number of bytes that may be used for this inode for
+        * delalloc
+        */
+       u64 reserved_bytes;
+
        /*
         * the size of the file stored in the metadata on disk.  data=ordered
         * means the in-memory i_size might be larger than the size on disk
index 35443cc4b9a976607f41866d68c202855c1bf16b..42491d728e9950f9c1f6f1cc4741e2997690f05f 100644 (file)
@@ -38,19 +38,12 @@ static int balance_node_right(struct btrfs_trans_handle *trans,
 static int del_ptr(struct btrfs_trans_handle *trans, struct btrfs_root *root,
                   struct btrfs_path *path, int level, int slot);
 
-inline void btrfs_init_path(struct btrfs_path *p)
-{
-       memset(p, 0, sizeof(*p));
-}
-
 struct btrfs_path *btrfs_alloc_path(void)
 {
        struct btrfs_path *path;
-       path = kmem_cache_alloc(btrfs_path_cachep, GFP_NOFS);
-       if (path) {
-               btrfs_init_path(path);
+       path = kmem_cache_zalloc(btrfs_path_cachep, GFP_NOFS);
+       if (path)
                path->reada = 1;
-       }
        return path;
 }
 
@@ -69,14 +62,38 @@ noinline void btrfs_set_path_blocking(struct btrfs_path *p)
 
 /*
  * reset all the locked nodes in the patch to spinning locks.
+ *
+ * held is used to keep lockdep happy, when lockdep is enabled
+ * we set held to a blocking lock before we go around and
+ * retake all the spinlocks in the path.  You can safely use NULL
+ * for held
  */
-noinline void btrfs_clear_path_blocking(struct btrfs_path *p)
+noinline void btrfs_clear_path_blocking(struct btrfs_path *p,
+                                       struct extent_buffer *held)
 {
        int i;
-       for (i = 0; i < BTRFS_MAX_LEVEL; i++) {
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       /* lockdep really cares that we take all of these spinlocks
+        * in the right order.  If any of the locks in the path are not
+        * currently blocking, it is going to complain.  So, make really
+        * really sure by forcing the path to blocking before we clear
+        * the path blocking.
+        */
+       if (held)
+               btrfs_set_lock_blocking(held);
+       btrfs_set_path_blocking(p);
+#endif
+
+       for (i = BTRFS_MAX_LEVEL - 1; i >= 0; i--) {
                if (p->nodes[i] && p->locks[i])
                        btrfs_clear_lock_blocking(p->nodes[i]);
        }
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+       if (held)
+               btrfs_clear_lock_blocking(held);
+#endif
 }
 
 /* this also releases the path */
@@ -286,7 +303,7 @@ static noinline int __btrfs_cow_block(struct btrfs_trans_handle *trans,
                                                  trans->transid, level, &ins);
                BUG_ON(ret);
                cow = btrfs_init_new_buffer(trans, root, prealloc_dest,
-                                           buf->len);
+                                           buf->len, level);
        } else {
                cow = btrfs_alloc_free_block(trans, root, buf->len,
                                             parent_start,
@@ -917,9 +934,9 @@ static noinline int balance_level(struct btrfs_trans_handle *trans,
 
                /* promote the child to a root */
                child = read_node_slot(root, mid, 0);
+               BUG_ON(!child);
                btrfs_tree_lock(child);
                btrfs_set_lock_blocking(child);
-               BUG_ON(!child);
                ret = btrfs_cow_block(trans, root, child, mid, 0, &child, 0);
                BUG_ON(ret);
 
@@ -1566,7 +1583,7 @@ cow_done:
                if (!p->skip_locking)
                        p->locks[level] = 1;
 
-               btrfs_clear_path_blocking(p);
+               btrfs_clear_path_blocking(p, NULL);
 
                /*
                 * we have a lock on b and as long as we aren't changing
@@ -1605,7 +1622,7 @@ cow_done:
 
                                btrfs_set_path_blocking(p);
                                sret = split_node(trans, root, p, level);
-                               btrfs_clear_path_blocking(p);
+                               btrfs_clear_path_blocking(p, NULL);
 
                                BUG_ON(sret > 0);
                                if (sret) {
@@ -1625,7 +1642,7 @@ cow_done:
 
                                btrfs_set_path_blocking(p);
                                sret = balance_level(trans, root, p, level);
-                               btrfs_clear_path_blocking(p);
+                               btrfs_clear_path_blocking(p, NULL);
 
                                if (sret) {
                                        ret = sret;
@@ -1688,13 +1705,13 @@ cow_done:
                        if (!p->skip_locking) {
                                int lret;
 
-                               btrfs_clear_path_blocking(p);
+                               btrfs_clear_path_blocking(p, NULL);
                                lret = btrfs_try_spin_lock(b);
 
                                if (!lret) {
                                        btrfs_set_path_blocking(p);
                                        btrfs_tree_lock(b);
-                                       btrfs_clear_path_blocking(p);
+                                       btrfs_clear_path_blocking(p, b);
                                }
                        }
                } else {
@@ -1706,7 +1723,7 @@ cow_done:
                                btrfs_set_path_blocking(p);
                                sret = split_leaf(trans, root, key,
                                                      p, ins_len, ret == 0);
-                               btrfs_clear_path_blocking(p);
+                               btrfs_clear_path_blocking(p, NULL);
 
                                BUG_ON(sret > 0);
                                if (sret) {
@@ -3926,7 +3943,6 @@ find_next_key:
                                btrfs_release_path(root, path);
                                goto again;
                        } else {
-                               btrfs_clear_path_blocking(path);
                                goto out;
                        }
                }
@@ -3946,7 +3962,7 @@ find_next_key:
                path->locks[level - 1] = 1;
                path->nodes[level - 1] = cur;
                unlock_up(path, level, 1);
-               btrfs_clear_path_blocking(path);
+               btrfs_clear_path_blocking(path, NULL);
        }
 out:
        if (ret == 0)
index 531db112c8bd5e003bde909c4adfb8c74a8b4e64..82491ba8fa40a451d0396f7f0b13c7a625414548 100644 (file)
@@ -43,11 +43,7 @@ struct btrfs_ordered_sum;
 
 #define BTRFS_ACL_NOT_CACHED    ((void *)-1)
 
-#ifdef CONFIG_LOCKDEP
-# define BTRFS_MAX_LEVEL 7
-#else
-# define BTRFS_MAX_LEVEL 8
-#endif
+#define BTRFS_MAX_LEVEL 8
 
 /* holds pointers to all of the tree roots */
 #define BTRFS_ROOT_TREE_OBJECTID 1ULL
@@ -600,13 +596,27 @@ struct btrfs_block_group_item {
 
 struct btrfs_space_info {
        u64 flags;
-       u64 total_bytes;
-       u64 bytes_used;
-       u64 bytes_pinned;
-       u64 bytes_reserved;
-       u64 bytes_readonly;
-       int full;
-       int force_alloc;
+
+       u64 total_bytes;        /* total bytes in the space */
+       u64 bytes_used;         /* total bytes used on disk */
+       u64 bytes_pinned;       /* total bytes pinned, will be freed when the
+                                  transaction finishes */
+       u64 bytes_reserved;     /* total bytes the allocator has reserved for
+                                  current allocations */
+       u64 bytes_readonly;     /* total bytes that are read only */
+
+       /* delalloc accounting */
+       u64 bytes_delalloc;     /* number of bytes reserved for allocation,
+                                  this space is not necessarily reserved yet
+                                  by the allocator */
+       u64 bytes_may_use;      /* number of bytes that may be used for
+                                  delalloc */
+
+       int full;               /* indicates that we cannot allocate any more
+                                  chunks for this space */
+       int force_alloc;        /* set if we need to force a chunk alloc for
+                                  this space */
+
        struct list_head list;
 
        /* for block groups in our same type */
@@ -1715,7 +1725,8 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
                                             u64 empty_size);
 struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
                                            struct btrfs_root *root,
-                                           u64 bytenr, u32 blocksize);
+                                           u64 bytenr, u32 blocksize,
+                                           int level);
 int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
                       struct btrfs_root *root,
                       u64 num_bytes, u64 parent, u64 min_bytes,
@@ -1785,6 +1796,16 @@ int btrfs_add_dead_reloc_root(struct btrfs_root *root);
 int btrfs_cleanup_reloc_trees(struct btrfs_root *root);
 int btrfs_reloc_clone_csums(struct inode *inode, u64 file_pos, u64 len);
 u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags);
+void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *ionde);
+int btrfs_check_metadata_free_space(struct btrfs_root *root);
+int btrfs_check_data_free_space(struct btrfs_root *root, struct inode *inode,
+                               u64 bytes);
+void btrfs_free_reserved_data_space(struct btrfs_root *root,
+                                   struct inode *inode, u64 bytes);
+void btrfs_delalloc_reserve_space(struct btrfs_root *root, struct inode *inode,
+                                u64 bytes);
+void btrfs_delalloc_free_space(struct btrfs_root *root, struct inode *inode,
+                             u64 bytes);
 /* ctree.c */
 int btrfs_previous_item(struct btrfs_root *root,
                        struct btrfs_path *path, u64 min_objectid,
@@ -1834,9 +1855,7 @@ int btrfs_realloc_node(struct btrfs_trans_handle *trans,
 void btrfs_release_path(struct btrfs_root *root, struct btrfs_path *p);
 struct btrfs_path *btrfs_alloc_path(void);
 void btrfs_free_path(struct btrfs_path *p);
-void btrfs_init_path(struct btrfs_path *p);
 void btrfs_set_path_blocking(struct btrfs_path *p);
-void btrfs_clear_path_blocking(struct btrfs_path *p);
 void btrfs_unlock_up_safe(struct btrfs_path *p, int level);
 
 int btrfs_del_items(struct btrfs_trans_handle *trans, struct btrfs_root *root,
@@ -2032,8 +2051,6 @@ int btrfs_merge_bio_hook(struct page *page, unsigned long offset,
 unsigned long btrfs_force_ra(struct address_space *mapping,
                              struct file_ra_state *ra, struct file *file,
                              pgoff_t offset, pgoff_t last_index);
-int btrfs_check_free_space(struct btrfs_root *root, u64 num_required,
-                          int for_del);
 int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page);
 int btrfs_readpage(struct file *file, struct page *page);
 void btrfs_delete_inode(struct inode *inode);
index 5aebddd711934817e6f2993375bc1031e3330e63..adda739a0215345b99476435ad35f703174b1d26 100644 (file)
@@ -75,6 +75,40 @@ struct async_submit_bio {
        struct btrfs_work work;
 };
 
+/* These are used to set the lockdep class on the extent buffer locks.
+ * The class is set by the readpage_end_io_hook after the buffer has
+ * passed csum validation but before the pages are unlocked.
+ *
+ * The lockdep class is also set by btrfs_init_new_buffer on freshly
+ * allocated blocks.
+ *
+ * The class is based on the level in the tree block, which allows lockdep
+ * to know that lower nodes nest inside the locks of higher nodes.
+ *
+ * We also add a check to make sure the highest level of the tree is
+ * the same as our lockdep setup here.  If BTRFS_MAX_LEVEL changes, this
+ * code needs update as well.
+ */
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+# if BTRFS_MAX_LEVEL != 8
+#  error
+# endif
+static struct lock_class_key btrfs_eb_class[BTRFS_MAX_LEVEL + 1];
+static const char *btrfs_eb_name[BTRFS_MAX_LEVEL + 1] = {
+       /* leaf */
+       "btrfs-extent-00",
+       "btrfs-extent-01",
+       "btrfs-extent-02",
+       "btrfs-extent-03",
+       "btrfs-extent-04",
+       "btrfs-extent-05",
+       "btrfs-extent-06",
+       "btrfs-extent-07",
+       /* highest possible level */
+       "btrfs-extent-08",
+};
+#endif
+
 /*
  * extents on the btree inode are pretty simple, there's one extent
  * that covers the entire device
@@ -347,6 +381,15 @@ static int check_tree_block_fsid(struct btrfs_root *root,
        return ret;
 }
 
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+void btrfs_set_buffer_lockdep_class(struct extent_buffer *eb, int level)
+{
+       lockdep_set_class_and_name(&eb->lock,
+                          &btrfs_eb_class[level],
+                          btrfs_eb_name[level]);
+}
+#endif
+
 static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
                               struct extent_state *state)
 {
@@ -392,6 +435,8 @@ static int btree_readpage_end_io_hook(struct page *page, u64 start, u64 end,
        }
        found_level = btrfs_header_level(eb);
 
+       btrfs_set_buffer_lockdep_class(eb, found_level);
+
        ret = csum_tree_block(root, eb, 1);
        if (ret)
                ret = -EIO;
@@ -1777,7 +1822,6 @@ struct btrfs_root *open_ctree(struct super_block *sb,
        ret = find_and_setup_root(tree_root, fs_info,
                                  BTRFS_DEV_TREE_OBJECTID, dev_root);
        dev_root->track_dirty = 1;
-
        if (ret)
                goto fail_extent_root;
 
index 494a56eb298614d6f443b37ff375e94f06f44b92..95029db227be5767d17eeab2a11cb36b63709849 100644 (file)
@@ -101,4 +101,14 @@ int btrfs_init_log_root_tree(struct btrfs_trans_handle *trans,
 int btrfs_add_log_tree(struct btrfs_trans_handle *trans,
                       struct btrfs_root *root);
 int btree_lock_page_hook(struct page *page);
+
+
+#ifdef CONFIG_DEBUG_LOCK_ALLOC
+void btrfs_set_buffer_lockdep_class(struct extent_buffer *eb, int level);
+#else
+static inline void btrfs_set_buffer_lockdep_class(struct extent_buffer *eb,
+                                                int level)
+{
+}
+#endif
 #endif
index 7527523c2d2d851ce1200424dce799814ac5a1fa..6b5966aacf447bfd14fbd2a2a1ef3be8b1280c29 100644 (file)
@@ -60,6 +60,10 @@ static int update_block_group(struct btrfs_trans_handle *trans,
                              u64 bytenr, u64 num_bytes, int alloc,
                              int mark_free);
 
+static int do_chunk_alloc(struct btrfs_trans_handle *trans,
+                         struct btrfs_root *extent_root, u64 alloc_bytes,
+                         u64 flags, int force);
+
 static int block_group_bits(struct btrfs_block_group_cache *cache, u64 bits)
 {
        return (cache->flags & bits) == bits;
@@ -1323,8 +1327,25 @@ int btrfs_inc_extent_ref(struct btrfs_trans_handle *trans,
 int btrfs_extent_post_op(struct btrfs_trans_handle *trans,
                         struct btrfs_root *root)
 {
-       finish_current_insert(trans, root->fs_info->extent_root, 1);
-       del_pending_extents(trans, root->fs_info->extent_root, 1);
+       u64 start;
+       u64 end;
+       int ret;
+
+       while(1) {
+               finish_current_insert(trans, root->fs_info->extent_root, 1);
+               del_pending_extents(trans, root->fs_info->extent_root, 1);
+
+               /* is there more work to do? */
+               ret = find_first_extent_bit(&root->fs_info->pending_del,
+                                           0, &start, &end, EXTENT_WRITEBACK);
+               if (!ret)
+                       continue;
+               ret = find_first_extent_bit(&root->fs_info->extent_ins,
+                                           0, &start, &end, EXTENT_WRITEBACK);
+               if (!ret)
+                       continue;
+               break;
+       }
        return 0;
 }
 
@@ -1892,6 +1913,7 @@ static int update_space_info(struct btrfs_fs_info *info, u64 flags,
        found->bytes_pinned = 0;
        found->bytes_reserved = 0;
        found->bytes_readonly = 0;
+       found->bytes_delalloc = 0;
        found->full = 0;
        found->force_alloc = 0;
        *space_info = found;
@@ -1955,6 +1977,233 @@ u64 btrfs_reduce_alloc_profile(struct btrfs_root *root, u64 flags)
        return flags;
 }
 
+static u64 btrfs_get_alloc_profile(struct btrfs_root *root, u64 data)
+{
+       struct btrfs_fs_info *info = root->fs_info;
+       u64 alloc_profile;
+
+       if (data) {
+               alloc_profile = info->avail_data_alloc_bits &
+                       info->data_alloc_profile;
+               data = BTRFS_BLOCK_GROUP_DATA | alloc_profile;
+       } else if (root == root->fs_info->chunk_root) {
+               alloc_profile = info->avail_system_alloc_bits &
+                       info->system_alloc_profile;
+               data = BTRFS_BLOCK_GROUP_SYSTEM | alloc_profile;
+       } else {
+               alloc_profile = info->avail_metadata_alloc_bits &
+                       info->metadata_alloc_profile;
+               data = BTRFS_BLOCK_GROUP_METADATA | alloc_profile;
+       }
+
+       return btrfs_reduce_alloc_profile(root, data);
+}
+
+void btrfs_set_inode_space_info(struct btrfs_root *root, struct inode *inode)
+{
+       u64 alloc_target;
+
+       alloc_target = btrfs_get_alloc_profile(root, 1);
+       BTRFS_I(inode)->space_info = __find_space_info(root->fs_info,
+                                                      alloc_target);
+}
+
+/*
+ * for now this just makes sure we have at least 5% of our metadata space free
+ * for use.
+ */
+int btrfs_check_metadata_free_space(struct btrfs_root *root)
+{
+       struct btrfs_fs_info *info = root->fs_info;
+       struct btrfs_space_info *meta_sinfo;
+       u64 alloc_target, thresh;
+       int committed = 0, ret;
+
+       /* get the space info for where the metadata will live */
+       alloc_target = btrfs_get_alloc_profile(root, 0);
+       meta_sinfo = __find_space_info(info, alloc_target);
+
+again:
+       spin_lock(&meta_sinfo->lock);
+       if (!meta_sinfo->full)
+               thresh = meta_sinfo->total_bytes * 80;
+       else
+               thresh = meta_sinfo->total_bytes * 95;
+
+       do_div(thresh, 100);
+
+       if (meta_sinfo->bytes_used + meta_sinfo->bytes_reserved +
+           meta_sinfo->bytes_pinned + meta_sinfo->bytes_readonly > thresh) {
+               struct btrfs_trans_handle *trans;
+               if (!meta_sinfo->full) {
+                       meta_sinfo->force_alloc = 1;
+                       spin_unlock(&meta_sinfo->lock);
+
+                       trans = btrfs_start_transaction(root, 1);
+                       if (!trans)
+                               return -ENOMEM;
+
+                       ret = do_chunk_alloc(trans, root->fs_info->extent_root,
+                                            2 * 1024 * 1024, alloc_target, 0);
+                       btrfs_end_transaction(trans, root);
+                       goto again;
+               }
+               spin_unlock(&meta_sinfo->lock);
+
+               if (!committed) {
+                       committed = 1;
+                       trans = btrfs_join_transaction(root, 1);
+                       if (!trans)
+                               return -ENOMEM;
+                       ret = btrfs_commit_transaction(trans, root);
+                       if (ret)
+                               return ret;
+                       goto again;
+               }
+               return -ENOSPC;
+       }
+       spin_unlock(&meta_sinfo->lock);
+
+       return 0;
+}
+
+/*
+ * This will check the space that the inode allocates from to make sure we have
+ * enough space for bytes.
+ */
+int btrfs_check_data_free_space(struct btrfs_root *root, struct inode *inode,
+                               u64 bytes)
+{
+       struct btrfs_space_info *data_sinfo;
+       int ret = 0, committed = 0;
+
+       /* make sure bytes are sectorsize aligned */
+       bytes = (bytes + root->sectorsize - 1) & ~((u64)root->sectorsize - 1);
+
+       data_sinfo = BTRFS_I(inode)->space_info;
+again:
+       /* make sure we have enough space to handle the data first */
+       spin_lock(&data_sinfo->lock);
+       if (data_sinfo->total_bytes - data_sinfo->bytes_used -
+           data_sinfo->bytes_delalloc - data_sinfo->bytes_reserved -
+           data_sinfo->bytes_pinned - data_sinfo->bytes_readonly -
+           data_sinfo->bytes_may_use < bytes) {
+               struct btrfs_trans_handle *trans;
+
+               /*
+                * if we don't have enough free bytes in this space then we need
+                * to alloc a new chunk.
+                */
+               if (!data_sinfo->full) {
+                       u64 alloc_target;
+
+                       data_sinfo->force_alloc = 1;
+                       spin_unlock(&data_sinfo->lock);
+
+                       alloc_target = btrfs_get_alloc_profile(root, 1);
+                       trans = btrfs_start_transaction(root, 1);
+                       if (!trans)
+                               return -ENOMEM;
+
+                       ret = do_chunk_alloc(trans, root->fs_info->extent_root,
+                                            bytes + 2 * 1024 * 1024,
+                                            alloc_target, 0);
+                       btrfs_end_transaction(trans, root);
+                       if (ret)
+                               return ret;
+                       goto again;
+               }
+               spin_unlock(&data_sinfo->lock);
+
+               /* commit the current transaction and try again */
+               if (!committed) {
+                       committed = 1;
+                       trans = btrfs_join_transaction(root, 1);
+                       if (!trans)
+                               return -ENOMEM;
+                       ret = btrfs_commit_transaction(trans, root);
+                       if (ret)
+                               return ret;
+                       goto again;
+               }
+
+               printk(KERN_ERR "no space left, need %llu, %llu delalloc bytes"
+                      ", %llu bytes_used, %llu bytes_reserved, "
+                      "%llu bytes_pinned, %llu bytes_readonly, %llu may use"
+                      "%llu total\n", bytes, data_sinfo->bytes_delalloc,
+                      data_sinfo->bytes_used, data_sinfo->bytes_reserved,
+                      data_sinfo->bytes_pinned, data_sinfo->bytes_readonly,
+                      data_sinfo->bytes_may_use, data_sinfo->total_bytes);
+               return -ENOSPC;
+       }
+       data_sinfo->bytes_may_use += bytes;
+       BTRFS_I(inode)->reserved_bytes += bytes;
+       spin_unlock(&data_sinfo->lock);
+
+       return btrfs_check_metadata_free_space(root);
+}
+
+/*
+ * if there was an error for whatever reason after calling
+ * btrfs_check_data_free_space, call this so we can cleanup the counters.
+ */
+void btrfs_free_reserved_data_space(struct btrfs_root *root,
+                                   struct inode *inode, u64 bytes)
+{
+       struct btrfs_space_info *data_sinfo;
+
+       /* make sure bytes are sectorsize aligned */
+       bytes = (bytes + root->sectorsize - 1) & ~((u64)root->sectorsize - 1);
+
+       data_sinfo = BTRFS_I(inode)->space_info;
+       spin_lock(&data_sinfo->lock);
+       data_sinfo->bytes_may_use -= bytes;
+       BTRFS_I(inode)->reserved_bytes -= bytes;
+       spin_unlock(&data_sinfo->lock);
+}
+
+/* called when we are adding a delalloc extent to the inode's io_tree */
+void btrfs_delalloc_reserve_space(struct btrfs_root *root, struct inode *inode,
+                                 u64 bytes)
+{
+       struct btrfs_space_info *data_sinfo;
+
+       /* get the space info for where this inode will be storing its data */
+       data_sinfo = BTRFS_I(inode)->space_info;
+
+       /* make sure we have enough space to handle the data first */
+       spin_lock(&data_sinfo->lock);
+       data_sinfo->bytes_delalloc += bytes;
+
+       /*
+        * we are adding a delalloc extent without calling
+        * btrfs_check_data_free_space first.  This happens on a weird
+        * writepage condition, but shouldn't hurt our accounting
+        */
+       if (unlikely(bytes > BTRFS_I(inode)->reserved_bytes)) {
+               data_sinfo->bytes_may_use -= BTRFS_I(inode)->reserved_bytes;
+               BTRFS_I(inode)->reserved_bytes = 0;
+       } else {
+               data_sinfo->bytes_may_use -= bytes;
+               BTRFS_I(inode)->reserved_bytes -= bytes;
+       }
+
+       spin_unlock(&data_sinfo->lock);
+}
+
+/* called when we are clearing an delalloc extent from the inode's io_tree */
+void btrfs_delalloc_free_space(struct btrfs_root *root, struct inode *inode,
+                             u64 bytes)
+{
+       struct btrfs_space_info *info;
+
+       info = BTRFS_I(inode)->space_info;
+
+       spin_lock(&info->lock);
+       info->bytes_delalloc -= bytes;
+       spin_unlock(&info->lock);
+}
+
 static int do_chunk_alloc(struct btrfs_trans_handle *trans,
                          struct btrfs_root *extent_root, u64 alloc_bytes,
                          u64 flags, int force)
@@ -2211,13 +2460,12 @@ static int finish_current_insert(struct btrfs_trans_handle *trans,
        u64 end;
        u64 priv;
        u64 search = 0;
-       u64 skipped = 0;
        struct btrfs_fs_info *info = extent_root->fs_info;
        struct btrfs_path *path;
        struct pending_extent_op *extent_op, *tmp;
        struct list_head insert_list, update_list;
        int ret;
-       int num_inserts = 0, max_inserts;
+       int num_inserts = 0, max_inserts, restart = 0;
 
        path = btrfs_alloc_path();
        INIT_LIST_HEAD(&insert_list);
@@ -2233,19 +2481,19 @@ again:
                ret = find_first_extent_bit(&info->extent_ins, search, &start,
                                            &end, EXTENT_WRITEBACK);
                if (ret) {
-                       if (skipped && all && !num_inserts &&
+                       if (restart && !num_inserts &&
                            list_empty(&update_list)) {
-                               skipped = 0;
+                               restart = 0;
                                search = 0;
                                continue;
                        }
-                       mutex_unlock(&info->extent_ins_mutex);
                        break;
                }
 
                ret = try_lock_extent(&info->extent_ins, start, end, GFP_NOFS);
                if (!ret) {
-                       skipped = 1;
+                       if (all)
+                               restart = 1;
                        search = end + 1;
                        if (need_resched()) {
                                mutex_unlock(&info->extent_ins_mutex);
@@ -2264,7 +2512,7 @@ again:
                        list_add_tail(&extent_op->list, &insert_list);
                        search = end + 1;
                        if (num_inserts == max_inserts) {
-                               mutex_unlock(&info->extent_ins_mutex);
+                               restart = 1;
                                break;
                        }
                } else if (extent_op->type == PENDING_BACKREF_UPDATE) {
@@ -2280,7 +2528,6 @@ again:
         * somebody marked this thing for deletion then just unlock it and be
         * done, the free_extents will handle it
         */
-       mutex_lock(&info->extent_ins_mutex);
        list_for_each_entry_safe(extent_op, tmp, &update_list, list) {
                clear_extent_bits(&info->extent_ins, extent_op->bytenr,
                                  extent_op->bytenr + extent_op->num_bytes - 1,
@@ -2302,6 +2549,10 @@ again:
        if (!list_empty(&update_list)) {
                ret = update_backrefs(trans, extent_root, path, &update_list);
                BUG_ON(ret);
+
+               /* we may have COW'ed new blocks, so lets start over */
+               if (all)
+                       restart = 1;
        }
 
        /*
@@ -2309,9 +2560,9 @@ again:
         * need to make sure everything is cleaned then reset everything and
         * go back to the beginning
         */
-       if (!num_inserts && all && skipped) {
+       if (!num_inserts && restart) {
                search = 0;
-               skipped = 0;
+               restart = 0;
                INIT_LIST_HEAD(&update_list);
                INIT_LIST_HEAD(&insert_list);
                goto again;
@@ -2368,27 +2619,19 @@ again:
        BUG_ON(ret);
 
        /*
-        * if we broke out of the loop in order to insert stuff because we hit
-        * the maximum number of inserts at a time we can handle, then loop
-        * back and pick up where we left off
+        * if restart is set for whatever reason we need to go back and start
+        * searching through the pending list again.
+        *
+        * We just inserted some extents, which could have resulted in new
+        * blocks being allocated, which would result in new blocks needing
+        * updates, so if all is set we _must_ restart to get the updated
+        * blocks.
         */
-       if (num_inserts == max_inserts) {
-               INIT_LIST_HEAD(&insert_list);
-               INIT_LIST_HEAD(&update_list);
-               num_inserts = 0;
-               goto again;
-       }
-
-       /*
-        * again, if we need to make absolutely sure there are no more pending
-        * extent operations left and we know that we skipped some, go back to
-        * the beginning and do it all again
-        */
-       if (all && skipped) {
+       if (restart || all) {
                INIT_LIST_HEAD(&insert_list);
                INIT_LIST_HEAD(&update_list);
                search = 0;
-               skipped = 0;
+               restart = 0;
                num_inserts = 0;
                goto again;
        }
@@ -2709,6 +2952,8 @@ again:
                goto again;
        }
 
+       if (!err)
+               finish_current_insert(trans, extent_root, 0);
        return err;
 }
 
@@ -2859,7 +3104,8 @@ static noinline int find_free_extent(struct btrfs_trans_handle *trans,
 
        if (data & BTRFS_BLOCK_GROUP_METADATA) {
                last_ptr = &root->fs_info->last_alloc;
-               empty_cluster = 64 * 1024;
+               if (!btrfs_test_opt(root, SSD))
+                       empty_cluster = 64 * 1024;
        }
 
        if ((data & BTRFS_BLOCK_GROUP_DATA) && btrfs_test_opt(root, SSD))
@@ -3091,6 +3337,10 @@ static void dump_space_info(struct btrfs_space_info *info, u64 bytes)
               (unsigned long long)(info->total_bytes - info->bytes_used -
                                    info->bytes_pinned - info->bytes_reserved),
               (info->full) ? "" : "not ");
+       printk(KERN_INFO "space_info total=%llu, pinned=%llu, delalloc=%llu,"
+              " may_use=%llu, used=%llu\n", info->total_bytes,
+              info->bytes_pinned, info->bytes_delalloc, info->bytes_may_use,
+              info->bytes_used);
 
        down_read(&info->groups_sem);
        list_for_each_entry(cache, &info->block_groups, list) {
@@ -3117,24 +3367,10 @@ static int __btrfs_reserve_extent(struct btrfs_trans_handle *trans,
 {
        int ret;
        u64 search_start = 0;
-       u64 alloc_profile;
        struct btrfs_fs_info *info = root->fs_info;
 
-       if (data) {
-               alloc_profile = info->avail_data_alloc_bits &
-                       info->data_alloc_profile;
-               data = BTRFS_BLOCK_GROUP_DATA | alloc_profile;
-       } else if (root == root->fs_info->chunk_root) {
-               alloc_profile = info->avail_system_alloc_bits &
-                       info->system_alloc_profile;
-               data = BTRFS_BLOCK_GROUP_SYSTEM | alloc_profile;
-       } else {
-               alloc_profile = info->avail_metadata_alloc_bits &
-                       info->metadata_alloc_profile;
-               data = BTRFS_BLOCK_GROUP_METADATA | alloc_profile;
-       }
+       data = btrfs_get_alloc_profile(root, data);
 again:
-       data = btrfs_reduce_alloc_profile(root, data);
        /*
         * the only place that sets empty_size is btrfs_realloc_node, which
         * is not called recursively on allocations
@@ -3402,7 +3638,8 @@ int btrfs_alloc_extent(struct btrfs_trans_handle *trans,
 
 struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
                                            struct btrfs_root *root,
-                                           u64 bytenr, u32 blocksize)
+                                           u64 bytenr, u32 blocksize,
+                                           int level)
 {
        struct extent_buffer *buf;
 
@@ -3410,6 +3647,7 @@ struct extent_buffer *btrfs_init_new_buffer(struct btrfs_trans_handle *trans,
        if (!buf)
                return ERR_PTR(-ENOMEM);
        btrfs_set_header_generation(buf, trans->transid);
+       btrfs_set_buffer_lockdep_class(buf, level);
        btrfs_tree_lock(buf);
        clean_tree_block(trans, root, buf);
 
@@ -3453,7 +3691,8 @@ struct extent_buffer *btrfs_alloc_free_block(struct btrfs_trans_handle *trans,
                return ERR_PTR(ret);
        }
 
-       buf = btrfs_init_new_buffer(trans, root, ins.objectid, blocksize);
+       buf = btrfs_init_new_buffer(trans, root, ins.objectid,
+                                   blocksize, level);
        return buf;
 }
 
@@ -5641,7 +5880,9 @@ static noinline int relocate_one_extent(struct btrfs_root *extent_root,
                        prev_block = block_start;
                }
 
+               mutex_lock(&extent_root->fs_info->trans_mutex);
                btrfs_record_root_in_trans(found_root);
+               mutex_unlock(&extent_root->fs_info->trans_mutex);
                if (ref_path->owner_objectid >= BTRFS_FIRST_FREE_OBJECTID) {
                        /*
                         * try to update data extent references while
index 37d43b516b79bdb7cb64dd153a06a805be59dd94..ebe6b29e60698156250708766c70bb74b903bfb6 100644 (file)
@@ -415,8 +415,6 @@ static int split_state(struct extent_io_tree *tree, struct extent_state *orig,
 
        node = tree_insert(&tree->state, prealloc->end, &prealloc->rb_node);
        if (node) {
-               struct extent_state *found;
-               found = rb_entry(node, struct extent_state, rb_node);
                free_extent_state(prealloc);
                return -EEXIST;
        }
index 3e8023efaff7581568f8d9a4f131a01c37f76d3b..dc78954861b333d75e831e27c6bbe7760f6e1de9 100644 (file)
@@ -1091,19 +1091,24 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
                WARN_ON(num_pages > nrptrs);
                memset(pages, 0, sizeof(struct page *) * nrptrs);
 
-               ret = btrfs_check_free_space(root, write_bytes, 0);
+               ret = btrfs_check_data_free_space(root, inode, write_bytes);
                if (ret)
                        goto out;
 
                ret = prepare_pages(root, file, pages, num_pages,
                                    pos, first_index, last_index,
                                    write_bytes);
-               if (ret)
+               if (ret) {
+                       btrfs_free_reserved_data_space(root, inode,
+                                                      write_bytes);
                        goto out;
+               }
 
                ret = btrfs_copy_from_user(pos, num_pages,
                                           write_bytes, pages, buf);
                if (ret) {
+                       btrfs_free_reserved_data_space(root, inode,
+                                                      write_bytes);
                        btrfs_drop_pages(pages, num_pages);
                        goto out;
                }
@@ -1111,8 +1116,11 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
                ret = dirty_and_release_pages(NULL, root, file, pages,
                                              num_pages, pos, write_bytes);
                btrfs_drop_pages(pages, num_pages);
-               if (ret)
+               if (ret) {
+                       btrfs_free_reserved_data_space(root, inode,
+                                                      write_bytes);
                        goto out;
+               }
 
                if (will_write) {
                        btrfs_fdatawrite_range(inode->i_mapping, pos,
@@ -1136,6 +1144,8 @@ static ssize_t btrfs_file_write(struct file *file, const char __user *buf,
        }
 out:
        mutex_unlock(&inode->i_mutex);
+       if (ret)
+               err = ret;
 
 out_nolock:
        kfree(pages);
@@ -1222,7 +1232,7 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
        /*
         * ok we haven't committed the transaction yet, lets do a commit
         */
-       if (file->private_data)
+       if (file && file->private_data)
                btrfs_ioctl_trans_end(file);
 
        trans = btrfs_start_transaction(root, 1);
@@ -1231,7 +1241,7 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
                goto out;
        }
 
-       ret = btrfs_log_dentry_safe(trans, root, file->f_dentry);
+       ret = btrfs_log_dentry_safe(trans, root, dentry);
        if (ret < 0)
                goto out;
 
@@ -1245,7 +1255,7 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
         * file again, but that will end up using the synchronization
         * inside btrfs_sync_log to keep things safe.
         */
-       mutex_unlock(&file->f_dentry->d_inode->i_mutex);
+       mutex_unlock(&dentry->d_inode->i_mutex);
 
        if (ret > 0) {
                ret = btrfs_commit_transaction(trans, root);
@@ -1253,7 +1263,7 @@ int btrfs_sync_file(struct file *file, struct dentry *dentry, int datasync)
                btrfs_sync_log(trans, root);
                ret = btrfs_end_transaction(trans, root);
        }
-       mutex_lock(&file->f_dentry->d_inode->i_mutex);
+       mutex_lock(&dentry->d_inode->i_mutex);
 out:
        return ret > 0 ? EIO : ret;
 }
index 2aa79873eb46a46baa00503d6682de1861db7c45..cc7334d833c9d27f4a139b6b96232e959f1458a5 100644 (file)
@@ -84,7 +84,6 @@ int btrfs_find_free_objectid(struct btrfs_trans_handle *trans,
        search_key.type = 0;
        search_key.offset = 0;
 
-       btrfs_init_path(path);
        start_found = 0;
        ret = btrfs_search_slot(trans, root, &search_key, path, 0, 0);
        if (ret < 0)
index 8f0706210a478cc8866b3dd280b2860e75089757..7d4f948bc22a5b5c811b93b385ff36d5b49e8977 100644 (file)
@@ -101,34 +101,6 @@ static int btrfs_init_inode_security(struct inode *inode,  struct inode *dir)
        return err;
 }
 
-/*
- * a very lame attempt at stopping writes when the FS is 85% full.  There
- * are countless ways this is incorrect, but it is better than nothing.
- */
-int btrfs_check_free_space(struct btrfs_root *root, u64 num_required,
-                          int for_del)
-{
-       u64 total;
-       u64 used;
-       u64 thresh;
-       int ret = 0;
-
-       spin_lock(&root->fs_info->delalloc_lock);
-       total = btrfs_super_total_bytes(&root->fs_info->super_copy);
-       used = btrfs_super_bytes_used(&root->fs_info->super_copy);
-       if (for_del)
-               thresh = total * 90;
-       else
-               thresh = total * 85;
-
-       do_div(thresh, 100);
-
-       if (used + root->fs_info->delalloc_bytes + num_required > thresh)
-               ret = -ENOSPC;
-       spin_unlock(&root->fs_info->delalloc_lock);
-       return ret;
-}
-
 /*
  * this does all the hard work for inserting an inline extent into
  * the btree.  The caller should have done a btrfs_drop_extents so that
@@ -1190,6 +1162,7 @@ static int btrfs_set_bit_hook(struct inode *inode, u64 start, u64 end,
         */
        if (!(old & EXTENT_DELALLOC) && (bits & EXTENT_DELALLOC)) {
                struct btrfs_root *root = BTRFS_I(inode)->root;
+               btrfs_delalloc_reserve_space(root, inode, end - start + 1);
                spin_lock(&root->fs_info->delalloc_lock);
                BTRFS_I(inode)->delalloc_bytes += end - start + 1;
                root->fs_info->delalloc_bytes += end - start + 1;
@@ -1223,9 +1196,12 @@ static int btrfs_clear_bit_hook(struct inode *inode, u64 start, u64 end,
                               (unsigned long long)end - start + 1,
                               (unsigned long long)
                               root->fs_info->delalloc_bytes);
+                       btrfs_delalloc_free_space(root, inode, (u64)-1);
                        root->fs_info->delalloc_bytes = 0;
                        BTRFS_I(inode)->delalloc_bytes = 0;
                } else {
+                       btrfs_delalloc_free_space(root, inode,
+                                                 end - start + 1);
                        root->fs_info->delalloc_bytes -= end - start + 1;
                        BTRFS_I(inode)->delalloc_bytes -= end - start + 1;
                }
@@ -2245,10 +2221,6 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
 
        root = BTRFS_I(dir)->root;
 
-       ret = btrfs_check_free_space(root, 1, 1);
-       if (ret)
-               goto fail;
-
        trans = btrfs_start_transaction(root, 1);
 
        btrfs_set_trans_block_group(trans, dir);
@@ -2261,7 +2233,6 @@ static int btrfs_unlink(struct inode *dir, struct dentry *dentry)
        nr = trans->blocks_used;
 
        btrfs_end_transaction_throttle(trans, root);
-fail:
        btrfs_btree_balance_dirty(root, nr);
        return ret;
 }
@@ -2284,10 +2255,6 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
                return -ENOTEMPTY;
        }
 
-       ret = btrfs_check_free_space(root, 1, 1);
-       if (ret)
-               goto fail;
-
        trans = btrfs_start_transaction(root, 1);
        btrfs_set_trans_block_group(trans, dir);
 
@@ -2304,7 +2271,6 @@ static int btrfs_rmdir(struct inode *dir, struct dentry *dentry)
 fail_trans:
        nr = trans->blocks_used;
        ret = btrfs_end_transaction_throttle(trans, root);
-fail:
        btrfs_btree_balance_dirty(root, nr);
 
        if (ret && !err)
@@ -2531,8 +2497,6 @@ noinline int btrfs_truncate_inode_items(struct btrfs_trans_handle *trans,
        key.offset = (u64)-1;
        key.type = (u8)-1;
 
-       btrfs_init_path(path);
-
 search_again:
        ret = btrfs_search_slot(trans, root, &key, path, -1, 1);
        if (ret < 0)
@@ -2820,7 +2784,7 @@ int btrfs_cont_expand(struct inode *inode, loff_t size)
        if (size <= hole_start)
                return 0;
 
-       err = btrfs_check_free_space(root, 1, 0);
+       err = btrfs_check_metadata_free_space(root);
        if (err)
                return err;
 
@@ -3016,6 +2980,7 @@ static noinline void init_btrfs_i(struct inode *inode)
        bi->last_trans = 0;
        bi->logged_trans = 0;
        bi->delalloc_bytes = 0;
+       bi->reserved_bytes = 0;
        bi->disk_i_size = 0;
        bi->flags = 0;
        bi->index_cnt = (u64)-1;
@@ -3037,6 +3002,7 @@ static int btrfs_init_locked_inode(struct inode *inode, void *p)
        inode->i_ino = args->ino;
        init_btrfs_i(inode);
        BTRFS_I(inode)->root = args->root;
+       btrfs_set_inode_space_info(args->root, inode);
        return 0;
 }
 
@@ -3457,6 +3423,7 @@ static struct inode *btrfs_new_inode(struct btrfs_trans_handle *trans,
        BTRFS_I(inode)->index_cnt = 2;
        BTRFS_I(inode)->root = root;
        BTRFS_I(inode)->generation = trans->transid;
+       btrfs_set_inode_space_info(root, inode);
 
        if (mode & S_IFDIR)
                owner = 0;
@@ -3604,7 +3571,7 @@ static int btrfs_mknod(struct inode *dir, struct dentry *dentry,
        if (!new_valid_dev(rdev))
                return -EINVAL;
 
-       err = btrfs_check_free_space(root, 1, 0);
+       err = btrfs_check_metadata_free_space(root);
        if (err)
                goto fail;
 
@@ -3667,7 +3634,7 @@ static int btrfs_create(struct inode *dir, struct dentry *dentry,
        u64 objectid;
        u64 index = 0;
 
-       err = btrfs_check_free_space(root, 1, 0);
+       err = btrfs_check_metadata_free_space(root);
        if (err)
                goto fail;
        trans = btrfs_start_transaction(root, 1);
@@ -3735,7 +3702,7 @@ static int btrfs_link(struct dentry *old_dentry, struct inode *dir,
                return -ENOENT;
 
        btrfs_inc_nlink(inode);
-       err = btrfs_check_free_space(root, 1, 0);
+       err = btrfs_check_metadata_free_space(root);
        if (err)
                goto fail;
        err = btrfs_set_inode_index(dir, &index);
@@ -3781,7 +3748,7 @@ static int btrfs_mkdir(struct inode *dir, struct dentry *dentry, int mode)
        u64 index = 0;
        unsigned long nr = 1;
 
-       err = btrfs_check_free_space(root, 1, 0);
+       err = btrfs_check_metadata_free_space(root);
        if (err)
                goto out_unlock;
 
@@ -4263,7 +4230,7 @@ static int btrfs_releasepage(struct page *page, gfp_t gfp_flags)
 {
        if (PageWriteback(page) || PageDirty(page))
                return 0;
-       return __btrfs_releasepage(page, gfp_flags);
+       return __btrfs_releasepage(page, gfp_flags & GFP_NOFS);
 }
 
 static void btrfs_invalidatepage(struct page *page, unsigned long offset)
@@ -4338,7 +4305,7 @@ int btrfs_page_mkwrite(struct vm_area_struct *vma, struct page *page)
        u64 page_start;
        u64 page_end;
 
-       ret = btrfs_check_free_space(root, PAGE_CACHE_SIZE, 0);
+       ret = btrfs_check_data_free_space(root, inode, PAGE_CACHE_SIZE);
        if (ret)
                goto out;
 
@@ -4351,6 +4318,7 @@ again:
 
        if ((page->mapping != inode->i_mapping) ||
            (page_start >= size)) {
+               btrfs_free_reserved_data_space(root, inode, PAGE_CACHE_SIZE);
                /* page got truncated out from underneath us */
                goto out_unlock;
        }
@@ -4633,7 +4601,7 @@ static int btrfs_rename(struct inode *old_dir, struct dentry *old_dentry,
        if (old_inode->i_ino == BTRFS_FIRST_FREE_OBJECTID)
                return -EXDEV;
 
-       ret = btrfs_check_free_space(root, 1, 0);
+       ret = btrfs_check_metadata_free_space(root);
        if (ret)
                goto out_unlock;
 
@@ -4751,7 +4719,7 @@ static int btrfs_symlink(struct inode *dir, struct dentry *dentry,
        if (name_len > BTRFS_MAX_INLINE_DATA_SIZE(root))
                return -ENAMETOOLONG;
 
-       err = btrfs_check_free_space(root, 1, 0);
+       err = btrfs_check_metadata_free_space(root);
        if (err)
                goto out_fail;
 
index 988fdc8b49ebb92b7ad7d5d9163f3fc23e866d16..bca729fc80c83e07a3847b2b7bb6e73123d6c30f 100644 (file)
@@ -70,7 +70,7 @@ static noinline int create_subvol(struct btrfs_root *root,
        u64 index = 0;
        unsigned long nr = 1;
 
-       ret = btrfs_check_free_space(root, 1, 0);
+       ret = btrfs_check_metadata_free_space(root);
        if (ret)
                goto fail_commit;
 
@@ -203,7 +203,7 @@ static int create_snapshot(struct btrfs_root *root, struct dentry *dentry,
        if (!root->ref_cows)
                return -EINVAL;
 
-       ret = btrfs_check_free_space(root, 1, 0);
+       ret = btrfs_check_metadata_free_space(root);
        if (ret)
                goto fail_unlock;
 
@@ -374,7 +374,7 @@ static int btrfs_defrag_file(struct file *file)
        unsigned long i;
        int ret;
 
-       ret = btrfs_check_free_space(root, inode->i_size, 0);
+       ret = btrfs_check_data_free_space(root, inode, inode->i_size);
        if (ret)
                return -ENOSPC;
 
index 9ebe9385129be7a32c3394a9d20ab13ff119fcb9..85506c4a3af7406c248b575149863ccdb8eb88f0 100644 (file)
 #include "extent_io.h"
 #include "locking.h"
 
-/*
- * btrfs_header_level() isn't free, so don't call it when lockdep isn't
- * on
- */
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
-static inline void spin_nested(struct extent_buffer *eb)
-{
-       spin_lock_nested(&eb->lock, BTRFS_MAX_LEVEL - btrfs_header_level(eb));
-}
-#else
 static inline void spin_nested(struct extent_buffer *eb)
 {
        spin_lock(&eb->lock);
 }
-#endif
 
 /*
  * Setting a lock to blocking will drop the spinlock and set the
index f3fd7e2cbc383aaefd42be70a02f80c759b6979b..19a4daf03ccb6d7d8730d4d8c9602a24dc0c370b 100644 (file)
@@ -379,7 +379,6 @@ int btrfs_sync_fs(struct super_block *sb, int wait)
        btrfs_start_delalloc_inodes(root);
        btrfs_wait_ordered_extents(root, 0);
 
-       btrfs_clean_old_snapshots(root);
        trans = btrfs_start_transaction(root, 1);
        ret = btrfs_commit_transaction(trans, root);
        sb->s_dirt = 0;
@@ -511,6 +510,10 @@ static int btrfs_remount(struct super_block *sb, int *flags, char *data)
        struct btrfs_root *root = btrfs_sb(sb);
        int ret;
 
+       ret = btrfs_parse_options(root, data);
+       if (ret)
+               return -EINVAL;
+
        if ((*flags & MS_RDONLY) == (sb->s_flags & MS_RDONLY))
                return 0;
 
index 919172de5c9aa9ce64630f593f74a7942e8292fd..4112d53d4f4dad195636c6ffa93deaded831af6e 100644 (file)
@@ -688,7 +688,9 @@ static noinline int drop_dirty_roots(struct btrfs_root *tree_root,
                num_bytes -= btrfs_root_used(&dirty->root->root_item);
                bytes_used = btrfs_root_used(&root->root_item);
                if (num_bytes) {
+                       mutex_lock(&root->fs_info->trans_mutex);
                        btrfs_record_root_in_trans(root);
+                       mutex_unlock(&root->fs_info->trans_mutex);
                        btrfs_set_root_used(&root->root_item,
                                            bytes_used - num_bytes);
                }
index 20794290256b4f977f14a5ea95810781edc7bbad..9c462fbd60fac14ad17f192afb08c37794295d36 100644 (file)
@@ -2832,7 +2832,9 @@ again:
                BUG_ON(!wc.replay_dest);
 
                wc.replay_dest->log_root = log;
+               mutex_lock(&fs_info->trans_mutex);
                btrfs_record_root_in_trans(wc.replay_dest);
+               mutex_unlock(&fs_info->trans_mutex);
                ret = walk_log_tree(trans, log, &wc);
                BUG_ON(ret);
 
index bcd14ebccae16e751e67a73cf79c2dfbbf0db465..1316139bf9e8209750ba671edd042df4976307ab 100644 (file)
@@ -2894,10 +2894,6 @@ static int read_one_chunk(struct btrfs_root *root, struct btrfs_key *key,
                free_extent_map(em);
        }
 
-       map = kzalloc(sizeof(*map), GFP_NOFS);
-       if (!map)
-               return -ENOMEM;
-
        em = alloc_extent_map(GFP_NOFS);
        if (!em)
                return -ENOMEM;
@@ -3106,6 +3102,8 @@ int btrfs_read_sys_array(struct btrfs_root *root)
        if (!sb)
                return -ENOMEM;
        btrfs_set_buffer_uptodate(sb);
+       btrfs_set_buffer_lockdep_class(sb, 0);
+
        write_extent_buffer(sb, super_copy, 0, BTRFS_SUPER_INFO_SIZE);
        array_size = btrfs_super_sys_array_size(super_copy);
 
index 665d446b25bc034241ef54c3c6b1d239c0ccf0f9..9f697419ed8e34ec041c92d8f6794c8b4b06ab33 100644 (file)
@@ -777,6 +777,7 @@ static int __set_page_dirty(struct page *page,
                        __inc_zone_page_state(page, NR_FILE_DIRTY);
                        __inc_bdi_stat(mapping->backing_dev_info,
                                        BDI_RECLAIMABLE);
+                       task_dirty_inc(current);
                        task_io_account_write(PAGE_CACHE_SIZE);
                }
                radix_tree_tag_set(&mapping->page_tree,
@@ -3108,7 +3109,7 @@ int sync_dirty_buffer(struct buffer_head *bh)
        if (test_clear_buffer_dirty(bh)) {
                get_bh(bh);
                bh->b_end_io = end_buffer_write_sync;
-               ret = submit_bh(WRITE_SYNC, bh);
+               ret = submit_bh(WRITE, bh);
                wait_on_buffer(bh);
                if (buffer_eopnotsupp(bh)) {
                        clear_buffer_eopnotsupp(bh);
index 73ac7ebd1dfcc253db5a40d9aa91379764dbebdb..851388fafc7302dbae9d5b5f7f33da5101eed4cd 100644 (file)
@@ -1,3 +1,13 @@
+Version 1.57
+------------
+Improve support for multiple security contexts to the same server. We
+used to use the same "vcnumber" for all connections which could cause
+the server to treat subsequent connections, especially those that
+are authenticated as guest, as reconnections, invalidating the earlier
+user's smb session.  This fix allows cifs to mount multiple times to the
+same server with different userids without risking invalidating earlier
+established security contexts.
+
 Version 1.56
 ------------
 Add "forcemandatorylock" mount option to allow user to use mandatory
@@ -7,7 +17,10 @@ specified and user does not have access to query information about the
 top of the share.  Fix problem in 2.6.28 resolving DFS paths to
 Samba servers (worked to Windows).  Fix rmdir so that pending search
 (readdir) requests do not get invalid results which include the now
-removed directory.
+removed directory.  Fix oops in cifs_dfs_ref.c when prefixpath is not reachable
+when using DFS.  Add better file create support to servers which support
+the CIFS POSIX protocol extensions (this adds support for new flags
+on create, and improves semantics for write of locked ranges).
 
 Version 1.55
 ------------
index 7ac481841f8726a272068a730235d0cd322bc799..2b1d28a9ee287b6b998c034c403c240b101c682e 100644 (file)
@@ -100,5 +100,5 @@ extern long cifs_ioctl(struct file *filep, unsigned int cmd, unsigned long arg);
 extern const struct export_operations cifs_export_ops;
 #endif /* EXPERIMENTAL */
 
-#define CIFS_VERSION   "1.56"
+#define CIFS_VERSION   "1.57"
 #endif                         /* _CIFSFS_H */
index 94c1ca0ec9539ef1ee08ff9983e291b2c21e7449..e004f6db5fc87904e21d6ebc4eb0cb56ccc15d29 100644 (file)
@@ -164,9 +164,12 @@ struct TCP_Server_Info {
        /* multiplexed reads or writes */
        unsigned int maxBuf;    /* maxBuf specifies the maximum */
        /* message size the server can send or receive for non-raw SMBs */
-       unsigned int maxRw;     /* maxRw specifies the maximum */
+       unsigned int max_rw;    /* maxRw specifies the maximum */
        /* message size the server can send or receive for */
        /* SMB_COM_WRITE_RAW or SMB_COM_READ_RAW. */
+       unsigned int max_vcs;   /* maximum number of smb sessions, at least
+                                  those that can be specified uniquely with
+                                  vcnumbers */
        char sessid[4];         /* unique token id for this session */
        /* (returned on Negotiate */
        int capabilities; /* allow selective disabling of caps by smb sess */
@@ -210,6 +213,7 @@ struct cifsSesInfo {
        unsigned overrideSecFlg;  /* if non-zero override global sec flags */
        __u16 ipc_tid;          /* special tid for connection to IPC share */
        __u16 flags;
+       __u16 vcnum;
        char *serverOS;         /* name of operating system underlying server */
        char *serverNOS;        /* name of network operating system of server */
        char *serverDomain;     /* security realm of server */
index 382ba62988094b58ec396ae7872a104ff7a66104..083dfc57c7a3e53adf54f32e9af4c56a8c2eeb9f 100644 (file)
@@ -42,6 +42,7 @@ extern void _FreeXid(unsigned int);
 #define GetXid() (int)_GetXid(); cFYI(1,("CIFS VFS: in %s as Xid: %d with uid: %d",__func__, xid,current_fsuid()));
 #define FreeXid(curr_xid) {_FreeXid(curr_xid); cFYI(1,("CIFS VFS: leaving %s (xid = %d) rc = %d",__func__,curr_xid,(int)rc));}
 extern char *build_path_from_dentry(struct dentry *);
+extern char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb);
 extern char *build_wildcard_path_from_dentry(struct dentry *direntry);
 /* extern void renew_parental_timestamps(struct dentry *direntry);*/
 extern int SendReceive(const unsigned int /* xid */ , struct cifsSesInfo *,
@@ -91,6 +92,9 @@ extern u64 cifs_UnixTimeToNT(struct timespec);
 extern __le64 cnvrtDosCifsTm(__u16 date, __u16 time);
 extern struct timespec cnvrtDosUnixTm(__u16 date, __u16 time);
 
+extern void posix_fill_in_inode(struct inode *tmp_inode,
+                               FILE_UNIX_BASIC_INFO *pData, int isNewInode);
+extern struct inode *cifs_new_inode(struct super_block *sb, __u64 *inum);
 extern int cifs_get_inode_info(struct inode **pinode,
                        const unsigned char *search_path,
                        FILE_ALL_INFO *pfile_info,
index 552642a507c4be6744e32a0738c07d27bd89a635..939e2f76b9596203ab68276a59aad6fd8c36981e 100644 (file)
@@ -528,14 +528,15 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
                server->maxReq = le16_to_cpu(rsp->MaxMpxCount);
                server->maxBuf = min((__u32)le16_to_cpu(rsp->MaxBufSize),
                                (__u32)CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
+               server->max_vcs = le16_to_cpu(rsp->MaxNumberVcs);
                GETU32(server->sessid) = le32_to_cpu(rsp->SessionKey);
                /* even though we do not use raw we might as well set this
                accurately, in case we ever find a need for it */
                if ((le16_to_cpu(rsp->RawMode) & RAW_ENABLE) == RAW_ENABLE) {
-                       server->maxRw = 0xFF00;
+                       server->max_rw = 0xFF00;
                        server->capabilities = CAP_MPX_MODE | CAP_RAW_MODE;
                } else {
-                       server->maxRw = 0;/* we do not need to use raw anyway */
+                       server->max_rw = 0;/* do not need to use raw anyway */
                        server->capabilities = CAP_MPX_MODE;
                }
                tmp = (__s16)le16_to_cpu(rsp->ServerTimeZone);
@@ -638,7 +639,7 @@ CIFSSMBNegotiate(unsigned int xid, struct cifsSesInfo *ses)
        /* probably no need to store and check maxvcs */
        server->maxBuf = min(le32_to_cpu(pSMBr->MaxBufferSize),
                        (__u32) CIFSMaxBufSize + MAX_CIFS_HDR_SIZE);
-       server->maxRw = le32_to_cpu(pSMBr->MaxRawSize);
+       server->max_rw = le32_to_cpu(pSMBr->MaxRawSize);
        cFYI(DBG2, ("Max buf = %d", ses->server->maxBuf));
        GETU32(ses->server->sessid) = le32_to_cpu(pSMBr->SessionKey);
        server->capabilities = le32_to_cpu(pSMBr->Capabilities);
index 2209be94305132f375b1082193bdcf7280c312d8..da0f4ffa06132f725570a79f7e0b5fb0b65d1eb6 100644 (file)
@@ -23,7 +23,6 @@
 #include <linux/string.h>
 #include <linux/list.h>
 #include <linux/wait.h>
-#include <linux/ipv6.h>
 #include <linux/pagemap.h>
 #include <linux/ctype.h>
 #include <linux/utsname.h>
@@ -35,6 +34,7 @@
 #include <linux/freezer.h>
 #include <asm/uaccess.h>
 #include <asm/processor.h>
+#include <net/ipv6.h>
 #include "cifspdu.h"
 #include "cifsglob.h"
 #include "cifsproto.h"
@@ -1379,8 +1379,8 @@ cifs_find_tcp_session(struct sockaddr_storage *addr)
                     server->addr.sockAddr.sin_addr.s_addr))
                        continue;
                else if (addr->ss_family == AF_INET6 &&
-                        memcmp(&server->addr.sockAddr6.sin6_addr,
-                               &addr6->sin6_addr, sizeof(addr6->sin6_addr)))
+                        !ipv6_addr_equal(&server->addr.sockAddr6.sin6_addr,
+                                         &addr6->sin6_addr))
                        continue;
 
                ++server->srv_count;
@@ -2180,6 +2180,33 @@ static void setup_cifs_sb(struct smb_vol *pvolume_info,
                           "mount option supported"));
 }
 
+static int
+is_path_accessible(int xid, struct cifsTconInfo *tcon,
+                  struct cifs_sb_info *cifs_sb, const char *full_path)
+{
+       int rc;
+       __u64 inode_num;
+       FILE_ALL_INFO *pfile_info;
+
+       rc = CIFSGetSrvInodeNumber(xid, tcon, full_path, &inode_num,
+                                  cifs_sb->local_nls,
+                                  cifs_sb->mnt_cifs_flags &
+                                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+       if (rc != -EOPNOTSUPP)
+               return rc;
+
+       pfile_info = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
+       if (pfile_info == NULL)
+               return -ENOMEM;
+
+       rc = CIFSSMBQPathInfo(xid, tcon, full_path, pfile_info,
+                             0 /* not legacy */, cifs_sb->local_nls,
+                             cifs_sb->mnt_cifs_flags &
+                               CIFS_MOUNT_MAP_SPECIAL_CHR);
+       kfree(pfile_info);
+       return rc;
+}
+
 int
 cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
           char *mount_data, const char *devname)
@@ -2190,6 +2217,7 @@ cifs_mount(struct super_block *sb, struct cifs_sb_info *cifs_sb,
        struct cifsSesInfo *pSesInfo = NULL;
        struct cifsTconInfo *tcon = NULL;
        struct TCP_Server_Info *srvTcp = NULL;
+       char   *full_path;
 
        xid = GetXid();
 
@@ -2426,6 +2454,23 @@ mount_fail_check:
                cifs_sb->rsize = min(cifs_sb->rsize,
                               (tcon->ses->server->maxBuf - MAX_CIFS_HDR_SIZE));
 
+       if (!rc && cifs_sb->prepathlen) {
+               /* build_path_to_root works only when we have a valid tcon */
+               full_path = cifs_build_path_to_root(cifs_sb);
+               if (full_path == NULL) {
+                       rc = -ENOMEM;
+                       goto mount_fail_check;
+               }
+               rc = is_path_accessible(xid, tcon, cifs_sb, full_path);
+               if (rc) {
+                       cERROR(1, ("Path %s in not accessible: %d",
+                                               full_path, rc));
+                       kfree(full_path);
+                       goto mount_fail_check;
+               }
+               kfree(full_path);
+       }
+
        /* volume_info->password is freed above when existing session found
        (in which case it is not needed anymore) but when new sesion is created
        the password ptr is put in the new session structure (in which case the
index 964aad03c5ad82d914ad504a8453f09f149d5c67..89fb728326523f6f3367a7343e057350341f423a 100644 (file)
@@ -3,7 +3,7 @@
  *
  *   vfs operations that deal with dentries
  *
- *   Copyright (C) International Business Machines  Corp., 2002,2008
+ *   Copyright (C) International Business Machines  Corp., 2002,2009
  *   Author(s): Steve French (sfrench@us.ibm.com)
  *
  *   This library is free software; you can redistribute it and/or modify
@@ -129,6 +129,78 @@ cifs_bp_rename_retry:
        return full_path;
 }
 
+static int cifs_posix_open(char *full_path, struct inode **pinode,
+                   struct super_block *sb, int mode, int oflags,
+                   int *poplock, __u16 *pnetfid, int xid)
+{
+       int rc;
+       __u32 oplock;
+       FILE_UNIX_BASIC_INFO *presp_data;
+       __u32 posix_flags = 0;
+       struct cifs_sb_info *cifs_sb = CIFS_SB(sb);
+
+       cFYI(1, ("posix open %s", full_path));
+
+       presp_data = kzalloc(sizeof(FILE_UNIX_BASIC_INFO), GFP_KERNEL);
+       if (presp_data == NULL)
+               return -ENOMEM;
+
+/* So far cifs posix extensions can only map the following flags.
+   There are other valid fmode oflags such as FMODE_LSEEK, FMODE_PREAD, but
+   so far we do not seem to need them, and we can treat them as local only */
+       if ((oflags & (FMODE_READ | FMODE_WRITE)) ==
+               (FMODE_READ | FMODE_WRITE))
+               posix_flags = SMB_O_RDWR;
+       else if (oflags & FMODE_READ)
+               posix_flags = SMB_O_RDONLY;
+       else if (oflags & FMODE_WRITE)
+               posix_flags = SMB_O_WRONLY;
+       if (oflags & O_CREAT)
+               posix_flags |= SMB_O_CREAT;
+       if (oflags & O_EXCL)
+               posix_flags |= SMB_O_EXCL;
+       if (oflags & O_TRUNC)
+               posix_flags |= SMB_O_TRUNC;
+       if (oflags & O_APPEND)
+               posix_flags |= SMB_O_APPEND;
+       if (oflags & O_SYNC)
+               posix_flags |= SMB_O_SYNC;
+       if (oflags & O_DIRECTORY)
+               posix_flags |= SMB_O_DIRECTORY;
+       if (oflags & O_NOFOLLOW)
+               posix_flags |= SMB_O_NOFOLLOW;
+       if (oflags & O_DIRECT)
+               posix_flags |= SMB_O_DIRECT;
+
+
+       rc = CIFSPOSIXCreate(xid, cifs_sb->tcon, posix_flags, mode,
+                       pnetfid, presp_data, &oplock, full_path,
+                       cifs_sb->local_nls, cifs_sb->mnt_cifs_flags &
+                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
+       if (rc)
+               goto posix_open_ret;
+
+       if (presp_data->Type == cpu_to_le32(-1))
+               goto posix_open_ret; /* open ok, caller does qpathinfo */
+
+       /* get new inode and set it up */
+       if (!pinode)
+               goto posix_open_ret; /* caller does not need info */
+
+       *pinode = cifs_new_inode(sb, &presp_data->UniqueId);
+
+       /* We do not need to close the file if new_inode fails since
+          the caller will retry qpathinfo as long as inode is null */
+       if (*pinode == NULL)
+               goto posix_open_ret;
+
+       posix_fill_in_inode(*pinode, presp_data, 1);
+
+posix_open_ret:
+       kfree(presp_data);
+       return rc;
+}
+
 static void setup_cifs_dentry(struct cifsTconInfo *tcon,
                              struct dentry *direntry,
                              struct inode *newinode)
@@ -150,7 +222,14 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
        int xid;
        int create_options = CREATE_NOT_DIR;
        int oplock = 0;
-       /* BB below access is too much for the mknod to request */
+       int oflags;
+       /*
+        * BB below access is probably too much for mknod to request
+        *    but we have to do query and setpathinfo so requesting
+        *    less could fail (unless we want to request getatr and setatr
+        *    permissions (only).  At least for POSIX we do not have to
+        *    request so much.
+        */
        int desiredAccess = GENERIC_READ | GENERIC_WRITE;
        __u16 fileHandle;
        struct cifs_sb_info *cifs_sb;
@@ -174,13 +253,43 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
        }
 
        mode &= ~current->fs->umask;
+       if (oplockEnabled)
+               oplock = REQ_OPLOCK;
 
-       if (nd && (nd->flags & LOOKUP_OPEN)) {
-               int oflags = nd->intent.open.flags;
+       if (nd && (nd->flags & LOOKUP_OPEN))
+               oflags = nd->intent.open.flags;
+       else
+               oflags = FMODE_READ;
+
+       if (tcon->unix_ext && (tcon->ses->capabilities & CAP_UNIX) &&
+           (CIFS_UNIX_POSIX_PATH_OPS_CAP &
+                       le64_to_cpu(tcon->fsUnixInfo.Capability))) {
+               rc = cifs_posix_open(full_path, &newinode, inode->i_sb,
+                                    mode, oflags, &oplock, &fileHandle, xid);
+               /* EIO could indicate that (posix open) operation is not
+                  supported, despite what server claimed in capability
+                  negotation.  EREMOTE indicates DFS junction, which is not
+                  handled in posix open */
+
+               if ((rc == 0) && (newinode == NULL))
+                       goto cifs_create_get_file_info; /* query inode info */
+               else if (rc == 0) /* success, no need to query */
+                       goto cifs_create_set_dentry;
+               else if ((rc != -EIO) && (rc != -EREMOTE) &&
+                        (rc != -EOPNOTSUPP)) /* path not found or net err */
+                       goto cifs_create_out;
+               /* else fallthrough to retry, using older open call, this is
+                  case where server does not support this SMB level, and
+                  falsely claims capability (also get here for DFS case
+                  which should be rare for path not covered on files) */
+       }
 
+       if (nd && (nd->flags & LOOKUP_OPEN)) {
+               /* if the file is going to stay open, then we
+                  need to set the desired access properly */
                desiredAccess = 0;
                if (oflags & FMODE_READ)
-                       desiredAccess |= GENERIC_READ;
+                       desiredAccess |= GENERIC_READ; /* is this too little? */
                if (oflags & FMODE_WRITE) {
                        desiredAccess |= GENERIC_WRITE;
                        if (!(oflags & FMODE_READ))
@@ -199,8 +308,6 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
 
        /* BB add processing to set equivalent of mode - e.g. via CreateX with
           ACLs */
-       if (oplockEnabled)
-               oplock = REQ_OPLOCK;
 
        buf = kmalloc(sizeof(FILE_ALL_INFO), GFP_KERNEL);
        if (buf == NULL) {
@@ -233,116 +340,112 @@ cifs_create(struct inode *inode, struct dentry *direntry, int mode,
        }
        if (rc) {
                cFYI(1, ("cifs_create returned 0x%x", rc));
-       } else {
-               /* If Open reported that we actually created a file
-               then we now have to set the mode if possible */
-               if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
-                       struct cifs_unix_set_info_args args = {
+               goto cifs_create_out;
+       }
+
+       /* If Open reported that we actually created a file
+          then we now have to set the mode if possible */
+       if ((tcon->unix_ext) && (oplock & CIFS_CREATE_ACTION)) {
+               struct cifs_unix_set_info_args args = {
                                .mode   = mode,
                                .ctime  = NO_CHANGE_64,
                                .atime  = NO_CHANGE_64,
                                .mtime  = NO_CHANGE_64,
                                .device = 0,
-                       };
+               };
 
-                       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
-                               args.uid = (__u64) current_fsuid();
-                               if (inode->i_mode & S_ISGID)
-                                       args.gid = (__u64) inode->i_gid;
-                               else
-                                       args.gid = (__u64) current_fsgid();
-                       } else {
-                               args.uid = NO_CHANGE_64;
-                               args.gid = NO_CHANGE_64;
-                       }
-                       CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
-                               cifs_sb->local_nls,
-                               cifs_sb->mnt_cifs_flags &
-                                       CIFS_MOUNT_MAP_SPECIAL_CHR);
+               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID) {
+                       args.uid = (__u64) current_fsuid();
+                       if (inode->i_mode & S_ISGID)
+                               args.gid = (__u64) inode->i_gid;
+                       else
+                               args.gid = (__u64) current_fsgid();
                } else {
-                       /* BB implement mode setting via Windows security
-                          descriptors e.g. */
-                       /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
-
-                       /* Could set r/o dos attribute if mode & 0222 == 0 */
+                       args.uid = NO_CHANGE_64;
+                       args.gid = NO_CHANGE_64;
                }
+               CIFSSMBUnixSetInfo(xid, tcon, full_path, &args,
+                       cifs_sb->local_nls,
+                       cifs_sb->mnt_cifs_flags & CIFS_MOUNT_MAP_SPECIAL_CHR);
+       } else {
+               /* BB implement mode setting via Windows security
+                  descriptors e.g. */
+               /* CIFSSMBWinSetPerms(xid,tcon,path,mode,-1,-1,nls);*/
 
-               /* server might mask mode so we have to query for it */
-               if (tcon->unix_ext)
-                       rc = cifs_get_inode_info_unix(&newinode, full_path,
-                                                inode->i_sb, xid);
-               else {
-                       rc = cifs_get_inode_info(&newinode, full_path,
-                                                buf, inode->i_sb, xid,
-                                                &fileHandle);
-                       if (newinode) {
-                               if (cifs_sb->mnt_cifs_flags &
-                                   CIFS_MOUNT_DYNPERM)
-                                       newinode->i_mode = mode;
-                               if ((oplock & CIFS_CREATE_ACTION) &&
-                                   (cifs_sb->mnt_cifs_flags &
-                                    CIFS_MOUNT_SET_UID)) {
-                                       newinode->i_uid = current_fsuid();
-                                       if (inode->i_mode & S_ISGID)
-                                               newinode->i_gid =
-                                                       inode->i_gid;
-                                       else
-                                               newinode->i_gid =
-                                                       current_fsgid();
-                               }
+               /* Could set r/o dos attribute if mode & 0222 == 0 */
+       }
+
+cifs_create_get_file_info:
+       /* server might mask mode so we have to query for it */
+       if (tcon->unix_ext)
+               rc = cifs_get_inode_info_unix(&newinode, full_path,
+                                             inode->i_sb, xid);
+       else {
+               rc = cifs_get_inode_info(&newinode, full_path, buf,
+                                        inode->i_sb, xid, &fileHandle);
+               if (newinode) {
+                       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_DYNPERM)
+                               newinode->i_mode = mode;
+                       if ((oplock & CIFS_CREATE_ACTION) &&
+                           (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SET_UID)) {
+                               newinode->i_uid = current_fsuid();
+                               if (inode->i_mode & S_ISGID)
+                                       newinode->i_gid = inode->i_gid;
+                               else
+                                       newinode->i_gid = current_fsgid();
                        }
                }
+       }
 
-               if (rc != 0) {
-                       cFYI(1, ("Create worked, get_inode_info failed rc = %d",
-                                rc));
-               } else
-                       setup_cifs_dentry(tcon, direntry, newinode);
-
-               if ((nd == NULL /* nfsd case - nfs srv does not set nd */) ||
-                       (!(nd->flags & LOOKUP_OPEN))) {
-                       /* mknod case - do not leave file open */
-                       CIFSSMBClose(xid, tcon, fileHandle);
-               } else if (newinode) {
-                       struct cifsFileInfo *pCifsFile =
-                          kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
-
-                       if (pCifsFile == NULL)
-                               goto cifs_create_out;
-                       pCifsFile->netfid = fileHandle;
-                       pCifsFile->pid = current->tgid;
-                       pCifsFile->pInode = newinode;
-                       pCifsFile->invalidHandle = false;
-                       pCifsFile->closePend     = false;
-                       init_MUTEX(&pCifsFile->fh_sem);
-                       mutex_init(&pCifsFile->lock_mutex);
-                       INIT_LIST_HEAD(&pCifsFile->llist);
-                       atomic_set(&pCifsFile->wrtPending, 0);
-
-                       /* set the following in open now
+cifs_create_set_dentry:
+       if (rc == 0)
+               setup_cifs_dentry(tcon, direntry, newinode);
+       else
+               cFYI(1, ("Create worked, get_inode_info failed rc = %d", rc));
+
+       /* nfsd case - nfs srv does not set nd */
+       if ((nd == NULL) || (!(nd->flags & LOOKUP_OPEN))) {
+               /* mknod case - do not leave file open */
+               CIFSSMBClose(xid, tcon, fileHandle);
+       } else if (newinode) {
+               struct cifsFileInfo *pCifsFile =
+                       kzalloc(sizeof(struct cifsFileInfo), GFP_KERNEL);
+
+               if (pCifsFile == NULL)
+                       goto cifs_create_out;
+               pCifsFile->netfid = fileHandle;
+               pCifsFile->pid = current->tgid;
+               pCifsFile->pInode = newinode;
+               pCifsFile->invalidHandle = false;
+               pCifsFile->closePend     = false;
+               init_MUTEX(&pCifsFile->fh_sem);
+               mutex_init(&pCifsFile->lock_mutex);
+               INIT_LIST_HEAD(&pCifsFile->llist);
+               atomic_set(&pCifsFile->wrtPending, 0);
+
+               /* set the following in open now
                                pCifsFile->pfile = file; */
-                       write_lock(&GlobalSMBSeslock);
-                       list_add(&pCifsFile->tlist, &tcon->openFileList);
-                       pCifsInode = CIFS_I(newinode);
-                       if (pCifsInode) {
-                               /* if readable file instance put first in list*/
-                               if (write_only) {
-                                       list_add_tail(&pCifsFile->flist,
-                                               &pCifsInode->openFileList);
-                               } else {
-                                       list_add(&pCifsFile->flist,
-                                               &pCifsInode->openFileList);
-                               }
-                               if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
-                                       pCifsInode->clientCanCacheAll = true;
-                                       pCifsInode->clientCanCacheRead = true;
-                                       cFYI(1, ("Exclusive Oplock inode %p",
-                                               newinode));
-                               } else if ((oplock & 0xF) == OPLOCK_READ)
-                                       pCifsInode->clientCanCacheRead = true;
+               write_lock(&GlobalSMBSeslock);
+               list_add(&pCifsFile->tlist, &tcon->openFileList);
+               pCifsInode = CIFS_I(newinode);
+               if (pCifsInode) {
+                       /* if readable file instance put first in list*/
+                       if (write_only) {
+                               list_add_tail(&pCifsFile->flist,
+                                             &pCifsInode->openFileList);
+                       } else {
+                               list_add(&pCifsFile->flist,
+                                        &pCifsInode->openFileList);
                        }
-                       write_unlock(&GlobalSMBSeslock);
+                       if ((oplock & 0xF) == OPLOCK_EXCLUSIVE) {
+                               pCifsInode->clientCanCacheAll = true;
+                               pCifsInode->clientCanCacheRead = true;
+                               cFYI(1, ("Exclusive Oplock inode %p",
+                                       newinode));
+                       } else if ((oplock & 0xF) == OPLOCK_READ)
+                               pCifsInode->clientCanCacheRead = true;
                }
+               write_unlock(&GlobalSMBSeslock);
        }
 cifs_create_out:
        kfree(buf);
index bcf7b518466413023097ba69b7a5cb8cb4c4a449..4690a360c85587ed85a76db68ab4c5afed4f998e 100644 (file)
@@ -199,6 +199,49 @@ static void fill_fake_finddataunix(FILE_UNIX_BASIC_INFO *pfnd_dat,
        pfnd_dat->Gid = cpu_to_le64(pinode->i_gid);
 }
 
+/**
+ * cifs_new inode - create new inode, initialize, and hash it
+ * @sb - pointer to superblock
+ * @inum - if valid pointer and serverino is enabled, replace i_ino with val
+ *
+ * Create a new inode, initialize it for CIFS and hash it. Returns the new
+ * inode or NULL if one couldn't be allocated.
+ *
+ * If the share isn't mounted with "serverino" or inum is a NULL pointer then
+ * we'll just use the inode number assigned by new_inode(). Note that this can
+ * mean i_ino collisions since the i_ino assigned by new_inode is not
+ * guaranteed to be unique.
+ */
+struct inode *
+cifs_new_inode(struct super_block *sb, __u64 *inum)
+{
+       struct inode *inode;
+
+       inode = new_inode(sb);
+       if (inode == NULL)
+               return NULL;
+
+       /*
+        * BB: Is i_ino == 0 legal? Here, we assume that it is. If it isn't we
+        *     stop passing inum as ptr. Are there sanity checks we can use to
+        *     ensure that the server is really filling in that field? Also,
+        *     if serverino is disabled, perhaps we should be using iunique()?
+        */
+       if (inum && (CIFS_SB(sb)->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM))
+               inode->i_ino = (unsigned long) *inum;
+
+       /*
+        * must set this here instead of cifs_alloc_inode since VFS will
+        * clobber i_flags
+        */
+       if (sb->s_flags & MS_NOATIME)
+               inode->i_flags |= S_NOATIME | S_NOCMTIME;
+
+       insert_inode_hash(inode);
+
+       return inode;
+}
+
 int cifs_get_inode_info_unix(struct inode **pinode,
        const unsigned char *full_path, struct super_block *sb, int xid)
 {
@@ -233,22 +276,11 @@ int cifs_get_inode_info_unix(struct inode **pinode,
 
        /* get new inode */
        if (*pinode == NULL) {
-               *pinode = new_inode(sb);
+               *pinode = cifs_new_inode(sb, &find_data.UniqueId);
                if (*pinode == NULL) {
                        rc = -ENOMEM;
                        goto cgiiu_exit;
                }
-               /* Is an i_ino of zero legal? */
-               /* note ino incremented to unique num in new_inode */
-               /* Are there sanity checks we can use to ensure that
-                  the server is really filling in that field? */
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
-                       (*pinode)->i_ino = (unsigned long)find_data.UniqueId;
-
-               if (sb->s_flags & MS_NOATIME)
-                       (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
-
-               insert_inode_hash(*pinode);
        }
 
        inode = *pinode;
@@ -465,11 +497,9 @@ int cifs_get_inode_info(struct inode **pinode,
 
        /* get new inode */
        if (*pinode == NULL) {
-               *pinode = new_inode(sb);
-               if (*pinode == NULL) {
-                       rc = -ENOMEM;
-                       goto cgii_exit;
-               }
+               __u64 inode_num;
+               __u64 *pinum = &inode_num;
+
                /* Is an i_ino of zero legal? Can we use that to check
                   if the server supports returning inode numbers?  Are
                   there other sanity checks we can use to ensure that
@@ -486,22 +516,26 @@ int cifs_get_inode_info(struct inode **pinode,
 
                if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
                        int rc1 = 0;
-                       __u64 inode_num;
 
                        rc1 = CIFSGetSrvInodeNumber(xid, pTcon,
-                                       full_path, &inode_num,
+                                       full_path, pinum,
                                        cifs_sb->local_nls,
                                        cifs_sb->mnt_cifs_flags &
                                                CIFS_MOUNT_MAP_SPECIAL_CHR);
                        if (rc1) {
                                cFYI(1, ("GetSrvInodeNum rc %d", rc1));
+                               pinum = NULL;
                                /* BB EOPNOSUPP disable SERVER_INUM? */
-                       } else /* do we need cast or hash to ino? */
-                               (*pinode)->i_ino = inode_num;
-               } /* else ino incremented to unique num in new_inode*/
-               if (sb->s_flags & MS_NOATIME)
-                       (*pinode)->i_flags |= S_NOATIME | S_NOCMTIME;
-               insert_inode_hash(*pinode);
+                       }
+               } else {
+                       pinum = NULL;
+               }
+
+               *pinode = cifs_new_inode(sb, pinum);
+               if (*pinode == NULL) {
+                       rc = -ENOMEM;
+                       goto cgii_exit;
+               }
        }
        inode = *pinode;
        cifsInfo = CIFS_I(inode);
@@ -621,7 +655,7 @@ static const struct inode_operations cifs_ipc_inode_ops = {
        .lookup = cifs_lookup,
 };
 
-static char *build_path_to_root(struct cifs_sb_info *cifs_sb)
+char *cifs_build_path_to_root(struct cifs_sb_info *cifs_sb)
 {
        int pplen = cifs_sb->prepathlen;
        int dfsplen;
@@ -678,7 +712,7 @@ struct inode *cifs_iget(struct super_block *sb, unsigned long ino)
                return inode;
 
        cifs_sb = CIFS_SB(inode->i_sb);
-       full_path = build_path_to_root(cifs_sb);
+       full_path = cifs_build_path_to_root(cifs_sb);
        if (full_path == NULL)
                return ERR_PTR(-ENOMEM);
 
@@ -1017,7 +1051,7 @@ out_reval:
        return rc;
 }
 
-static void posix_fill_in_inode(struct inode *tmp_inode,
+void posix_fill_in_inode(struct inode *tmp_inode,
        FILE_UNIX_BASIC_INFO *pData, int isNewInode)
 {
        struct cifsInodeInfo *cifsInfo = CIFS_I(tmp_inode);
@@ -1114,24 +1148,14 @@ int cifs_mkdir(struct inode *inode, struct dentry *direntry, int mode)
                        else
                                direntry->d_op = &cifs_dentry_ops;
 
-                       newinode = new_inode(inode->i_sb);
+                       newinode = cifs_new_inode(inode->i_sb,
+                                                 &pInfo->UniqueId);
                        if (newinode == NULL) {
                                kfree(pInfo);
                                goto mkdir_get_info;
                        }
 
-                       /* Is an i_ino of zero legal? */
-                       /* Are there sanity checks we can use to ensure that
-                          the server is really filling in that field? */
-                       if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM) {
-                               newinode->i_ino =
-                                       (unsigned long)pInfo->UniqueId;
-                       } /* note ino incremented to unique num in new_inode */
-                       if (inode->i_sb->s_flags & MS_NOATIME)
-                               newinode->i_flags |= S_NOATIME | S_NOCMTIME;
                        newinode->i_nlink = 2;
-
-                       insert_inode_hash(newinode);
                        d_instantiate(direntry, newinode);
 
                        /* we already checked in POSIXCreate whether
index 9f51f9bf0292f4a67aee9ca82aae2f6d3b6cc5d0..c2c01ff4c32c1b21965ebf814ee83a93318c7a31 100644 (file)
@@ -56,35 +56,34 @@ static inline void dump_cifs_file_struct(struct file *file, char *label)
 }
 #endif /* DEBUG2 */
 
-/* Returns one if new inode created (which therefore needs to be hashed) */
+/* Returns 1 if new inode created, 2 if both dentry and inode were */
 /* Might check in the future if inode number changed so we can rehash inode */
-static int construct_dentry(struct qstr *qstring, struct file *file,
-       struct inode **ptmp_inode, struct dentry **pnew_dentry)
+static int
+construct_dentry(struct qstr *qstring, struct file *file,
+                struct inode **ptmp_inode, struct dentry **pnew_dentry,
+                __u64 *inum)
 {
-       struct dentry *tmp_dentry;
-       struct cifs_sb_info *cifs_sb;
-       struct cifsTconInfo *pTcon;
+       struct dentry *tmp_dentry = NULL;
+       struct super_block *sb = file->f_path.dentry->d_sb;
        int rc = 0;
 
        cFYI(1, ("For %s", qstring->name));
-       cifs_sb = CIFS_SB(file->f_path.dentry->d_sb);
-       pTcon = cifs_sb->tcon;
 
        qstring->hash = full_name_hash(qstring->name, qstring->len);
        tmp_dentry = d_lookup(file->f_path.dentry, qstring);
        if (tmp_dentry) {
+               /* BB: overwrite old name? i.e. tmp_dentry->d_name and
+                * tmp_dentry->d_name.len??
+                */
                cFYI(0, ("existing dentry with inode 0x%p",
                         tmp_dentry->d_inode));
                *ptmp_inode = tmp_dentry->d_inode;
-/* BB overwrite old name? i.e. tmp_dentry->d_name and tmp_dentry->d_name.len??*/
                if (*ptmp_inode == NULL) {
-                       *ptmp_inode = new_inode(file->f_path.dentry->d_sb);
+                       *ptmp_inode = cifs_new_inode(sb, inum);
                        if (*ptmp_inode == NULL)
                                return rc;
                        rc = 1;
                }
-               if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
-                       (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
        } else {
                tmp_dentry = d_alloc(file->f_path.dentry, qstring);
                if (tmp_dentry == NULL) {
@@ -93,15 +92,14 @@ static int construct_dentry(struct qstr *qstring, struct file *file,
                        return rc;
                }
 
-               *ptmp_inode = new_inode(file->f_path.dentry->d_sb);
-               if (pTcon->nocase)
+               if (CIFS_SB(sb)->tcon->nocase)
                        tmp_dentry->d_op = &cifs_ci_dentry_ops;
                else
                        tmp_dentry->d_op = &cifs_dentry_ops;
+
+               *ptmp_inode = cifs_new_inode(sb, inum);
                if (*ptmp_inode == NULL)
                        return rc;
-               if (file->f_path.dentry->d_sb->s_flags & MS_NOATIME)
-                       (*ptmp_inode)->i_flags |= S_NOATIME | S_NOCMTIME;
                rc = 2;
        }
 
@@ -822,7 +820,7 @@ static int find_cifs_entry(const int xid, struct cifsTconInfo *pTcon,
 /* inode num, inode type and filename returned */
 static int cifs_get_name_from_search_buf(struct qstr *pqst,
        char *current_entry, __u16 level, unsigned int unicode,
-       struct cifs_sb_info *cifs_sb, int max_len, ino_t *pinum)
+       struct cifs_sb_info *cifs_sb, int max_len, __u64 *pinum)
 {
        int rc = 0;
        unsigned int len = 0;
@@ -842,9 +840,7 @@ static int cifs_get_name_from_search_buf(struct qstr *pqst,
                        len = strnlen(filename, PATH_MAX);
                }
 
-               /* BB fixme - hash low and high 32 bits if not 64 bit arch BB */
-               if (cifs_sb->mnt_cifs_flags & CIFS_MOUNT_SERVER_INUM)
-                       *pinum = pFindData->UniqueId;
+               *pinum = pFindData->UniqueId;
        } else if (level == SMB_FIND_FILE_DIRECTORY_INFO) {
                FILE_DIRECTORY_INFO *pFindData =
                        (FILE_DIRECTORY_INFO *)current_entry;
@@ -907,7 +903,7 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
        struct qstr qstring;
        struct cifsFileInfo *pCifsF;
        unsigned int obj_type;
-       ino_t  inum;
+       __u64  inum;
        struct cifs_sb_info *cifs_sb;
        struct inode *tmp_inode;
        struct dentry *tmp_dentry;
@@ -940,20 +936,18 @@ static int cifs_filldir(char *pfindEntry, struct file *file,
        if (rc)
                return rc;
 
-       rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry);
+       /* only these two infolevels return valid inode numbers */
+       if (pCifsF->srch_inf.info_level == SMB_FIND_FILE_UNIX ||
+           pCifsF->srch_inf.info_level == SMB_FIND_FILE_ID_FULL_DIR_INFO)
+               rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry,
+                                       &inum);
+       else
+               rc = construct_dentry(&qstring, file, &tmp_inode, &tmp_dentry,
+                                       NULL);
+
        if ((tmp_inode == NULL) || (tmp_dentry == NULL))
                return -ENOMEM;
 
-       if (rc) {
-               /* inode created, we need to hash it with right inode number */
-               if (inum != 0) {
-                       /* BB fixme - hash the 2 32 quantities bits together if
-                        *  necessary BB */
-                       tmp_inode->i_ino = inum;
-               }
-               insert_inode_hash(tmp_inode);
-       }
-
        /* we pass in rc below, indicating whether it is a new inode,
           so we can figure out whether to invalidate the inode cached
           data if the file has changed */
index 5f22de7b79a900fe9bbd79e68f9823da136d132e..5c68b4282be917bc48ba04e77b0af2120952d50a 100644 (file)
 extern void SMBNTencrypt(unsigned char *passwd, unsigned char *c8,
                         unsigned char *p24);
 
+/* Checks if this is the first smb session to be reconnected after
+   the socket has been reestablished (so we know whether to use vc 0).
+   Called while holding the cifs_tcp_ses_lock, so do not block */
+static bool is_first_ses_reconnect(struct cifsSesInfo *ses)
+{
+       struct list_head *tmp;
+       struct cifsSesInfo *tmp_ses;
+
+       list_for_each(tmp, &ses->server->smb_ses_list) {
+               tmp_ses = list_entry(tmp, struct cifsSesInfo,
+                                    smb_ses_list);
+               if (tmp_ses->need_reconnect == false)
+                       return false;
+       }
+       /* could not find a session that was already connected,
+          this must be the first one we are reconnecting */
+       return true;
+}
+
+/*
+ *     vc number 0 is treated specially by some servers, and should be the
+ *      first one we request.  After that we can use vcnumbers up to maxvcs,
+ *     one for each smb session (some Windows versions set maxvcs incorrectly
+ *     so maxvc=1 can be ignored).  If we have too many vcs, we can reuse
+ *     any vc but zero (some servers reset the connection on vcnum zero)
+ *
+ */
+static __le16 get_next_vcnum(struct cifsSesInfo *ses)
+{
+       __u16 vcnum = 0;
+       struct list_head *tmp;
+       struct cifsSesInfo *tmp_ses;
+       __u16 max_vcs = ses->server->max_vcs;
+       __u16 i;
+       int free_vc_found = 0;
+
+       /* Quoting the MS-SMB specification: "Windows-based SMB servers set this
+       field to one but do not enforce this limit, which allows an SMB client
+       to establish more virtual circuits than allowed by this value ... but
+       other server implementations can enforce this limit." */
+       if (max_vcs < 2)
+               max_vcs = 0xFFFF;
+
+       write_lock(&cifs_tcp_ses_lock);
+       if ((ses->need_reconnect) && is_first_ses_reconnect(ses))
+                       goto get_vc_num_exit;  /* vcnum will be zero */
+       for (i = ses->server->srv_count - 1; i < max_vcs; i++) {
+               if (i == 0) /* this is the only connection, use vc 0 */
+                       break;
+
+               free_vc_found = 1;
+
+               list_for_each(tmp, &ses->server->smb_ses_list) {
+                       tmp_ses = list_entry(tmp, struct cifsSesInfo,
+                                            smb_ses_list);
+                       if (tmp_ses->vcnum == i) {
+                               free_vc_found = 0;
+                               break; /* found duplicate, try next vcnum */
+                       }
+               }
+               if (free_vc_found)
+                       break; /* we found a vcnumber that will work - use it */
+       }
+
+       if (i == 0)
+               vcnum = 0; /* for most common case, ie if one smb session, use
+                             vc zero.  Also for case when no free vcnum, zero
+                             is safest to send (some clients only send zero) */
+       else if (free_vc_found == 0)
+               vcnum = 1;  /* we can not reuse vc=0 safely, since some servers
+                               reset all uids on that, but 1 is ok. */
+       else
+               vcnum = i;
+       ses->vcnum = vcnum;
+get_vc_num_exit:
+       write_unlock(&cifs_tcp_ses_lock);
+
+       return le16_to_cpu(vcnum);
+}
+
 static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
 {
        __u32 capabilities = 0;
 
        /* init fields common to all four types of SessSetup */
-       /* note that header is initialized to zero in header_assemble */
+       /* Note that offsets for first seven fields in req struct are same  */
+       /*      in CIFS Specs so does not matter which of 3 forms of struct */
+       /*      that we use in next few lines                               */
+       /* Note that header is initialized to zero in header_assemble */
        pSMB->req.AndXCommand = 0xFF;
        pSMB->req.MaxBufferSize = cpu_to_le16(ses->server->maxBuf);
        pSMB->req.MaxMpxCount = cpu_to_le16(ses->server->maxReq);
+       pSMB->req.VcNumber = get_next_vcnum(ses);
 
        /* Now no need to set SMBFLG_CASELESS or obsolete CANONICAL PATH */
 
@@ -71,7 +155,6 @@ static __u32 cifs_ssetup_hdr(struct cifsSesInfo *ses, SESSION_SETUP_ANDX *pSMB)
        if (ses->capabilities & CAP_UNIX)
                capabilities |= CAP_UNIX;
 
-       /* BB check whether to init vcnum BB */
        return capabilities;
 }
 
@@ -228,7 +311,7 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft,
 
        kfree(ses->serverOS);
        /* UTF-8 string will not grow more than four times as big as UCS-16 */
-       ses->serverOS = kzalloc(4 * len, GFP_KERNEL);
+       ses->serverOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL);
        if (ses->serverOS != NULL)
                cifs_strfromUCS_le(ses->serverOS, (__le16 *)data, len, nls_cp);
        data += 2 * (len + 1);
@@ -241,7 +324,7 @@ static int decode_unicode_ssetup(char **pbcc_area, int bleft,
                return rc;
 
        kfree(ses->serverNOS);
-       ses->serverNOS = kzalloc(4 * len, GFP_KERNEL); /* BB this is wrong length FIXME BB */
+       ses->serverNOS = kzalloc((4 * len) + 2 /* trailing null */, GFP_KERNEL);
        if (ses->serverNOS != NULL) {
                cifs_strfromUCS_le(ses->serverNOS, (__le16 *)data, len,
                                   nls_cp);
index 763fe69ef3519a01be16cae0c9e6e0bd6af9119a..ff786687e93b7289e74f0587c170ca5a2f1006c0 100644 (file)
@@ -1918,6 +1918,9 @@ COMPATIBLE_IOCTL(FIONREAD)  /* This is also TIOCINQ */
 /* 0x00 */
 COMPATIBLE_IOCTL(FIBMAP)
 COMPATIBLE_IOCTL(FIGETBSZ)
+/* 'X' - originally XFS but some now in the VFS */
+COMPATIBLE_IOCTL(FIFREEZE)
+COMPATIBLE_IOCTL(FITHAW)
 /* RAID */
 COMPATIBLE_IOCTL(RAID_VERSION)
 COMPATIBLE_IOCTL(GET_ARRAY_INFO)
@@ -1943,6 +1946,8 @@ ULONG_IOCTL(SET_BITMAP_FILE)
 /* Big K */
 COMPATIBLE_IOCTL(PIO_FONT)
 COMPATIBLE_IOCTL(GIO_FONT)
+COMPATIBLE_IOCTL(PIO_CMAP)
+COMPATIBLE_IOCTL(GIO_CMAP)
 ULONG_IOCTL(KDSIGACCEPT)
 COMPATIBLE_IOCTL(KDGETKEYCODE)
 COMPATIBLE_IOCTL(KDSETKEYCODE)
index 937df0fb0da5aefbb1a69b94c6a06afbe1747439..07e2d4a44bda3204c083a6e38ef79fe9b144d958 100644 (file)
@@ -1180,7 +1180,7 @@ struct dentry *d_obtain_alias(struct inode *inode)
        iput(inode);
        return res;
 }
-EXPORT_SYMBOL_GPL(d_obtain_alias);
+EXPORT_SYMBOL(d_obtain_alias);
 
 /**
  * d_splice_alias - splice a disconnected dentry into the tree if one exists
index 9a50b8052dcfab2865d34aebf54b459ec81e54b7..de9459b4cb943205c4bb40b442a486c657855f5e 100644 (file)
@@ -609,7 +609,9 @@ int ext4_claim_free_blocks(struct ext4_sb_info *sbi,
  */
 int ext4_should_retry_alloc(struct super_block *sb, int *retries)
 {
-       if (!ext4_has_free_blocks(EXT4_SB(sb), 1) || (*retries)++ > 3)
+       if (!ext4_has_free_blocks(EXT4_SB(sb), 1) ||
+           (*retries)++ > 3 ||
+           !EXT4_SB(sb)->s_journal)
                return 0;
 
        jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id);
index aafc9eba1c25c8aace126bafc56e70d058695621..b0c87dce66a32e56b40b5248a0019c380818ae5b 100644 (file)
@@ -868,7 +868,7 @@ static inline unsigned ext4_rec_len_from_disk(__le16 dlen)
 {
        unsigned len = le16_to_cpu(dlen);
 
-       if (len == EXT4_MAX_REC_LEN)
+       if (len == EXT4_MAX_REC_LEN || len == 0)
                return 1 << 16;
        return len;
 }
index 4fb86a0061d033db005eb485d92263ede5120664..f18a919be70becf286c74364345a464e4d6e75e6 100644 (file)
@@ -715,6 +715,13 @@ struct inode *ext4_new_inode(handle_t *handle, struct inode *dir, int mode)
 
        if (sbi->s_log_groups_per_flex) {
                ret2 = find_group_flex(sb, dir, &group);
+               if (ret2 == -1) {
+                       ret2 = find_group_other(sb, dir, &group);
+                       if (ret2 == 0 && printk_ratelimit())
+                               printk(KERN_NOTICE "ext4: find_group_flex "
+                                      "failed, fallback succeeded dir %lu\n",
+                                      dir->i_ino);
+               }
                goto got_group;
        }
 
index 03ba20be132997140e4dcae313dadb865149427e..c7fed5b1874532ca17d1c1a2724f19096bda6c7e 100644 (file)
 static inline int ext4_begin_ordered_truncate(struct inode *inode,
                                              loff_t new_size)
 {
-       return jbd2_journal_begin_ordered_truncate(&EXT4_I(inode)->jinode,
-                                                  new_size);
+       return jbd2_journal_begin_ordered_truncate(
+                                       EXT4_SB(inode->i_sb)->s_journal,
+                                       &EXT4_I(inode)->jinode,
+                                       new_size);
 }
 
 static void ext4_invalidatepage(struct page *page, unsigned long offset);
@@ -1366,6 +1368,10 @@ retry:
                goto out;
        }
 
+       /* We cannot recurse into the filesystem as the transaction is already
+        * started */
+       flags |= AOP_FLAG_NOFS;
+
        page = grab_cache_page_write_begin(mapping, index, flags);
        if (!page) {
                ext4_journal_stop(handle);
@@ -1375,7 +1381,7 @@ retry:
        *pagep = page;
 
        ret = block_write_begin(file, mapping, pos, len, flags, pagep, fsdata,
-                                                       ext4_get_block);
+                               ext4_get_block);
 
        if (!ret && ext4_should_journal_data(inode)) {
                ret = walk_page_buffers(handle, page_buffers(page),
@@ -2437,6 +2443,7 @@ static int ext4_da_writepages(struct address_space *mapping,
        int no_nrwrite_index_update;
        int pages_written = 0;
        long pages_skipped;
+       int range_cyclic, cycled = 1, io_done = 0;
        int needed_blocks, ret = 0, nr_to_writebump = 0;
        struct ext4_sb_info *sbi = EXT4_SB(mapping->host->i_sb);
 
@@ -2488,9 +2495,15 @@ static int ext4_da_writepages(struct address_space *mapping,
        if (wbc->range_start == 0 && wbc->range_end == LLONG_MAX)
                range_whole = 1;
 
-       if (wbc->range_cyclic)
+       range_cyclic = wbc->range_cyclic;
+       if (wbc->range_cyclic) {
                index = mapping->writeback_index;
-       else
+               if (index)
+                       cycled = 0;
+               wbc->range_start = index << PAGE_CACHE_SHIFT;
+               wbc->range_end  = LLONG_MAX;
+               wbc->range_cyclic = 0;
+       } else
                index = wbc->range_start >> PAGE_CACHE_SHIFT;
 
        mpd.wbc = wbc;
@@ -2504,6 +2517,7 @@ static int ext4_da_writepages(struct address_space *mapping,
        wbc->no_nrwrite_index_update = 1;
        pages_skipped = wbc->pages_skipped;
 
+retry:
        while (!ret && wbc->nr_to_write > 0) {
 
                /*
@@ -2530,7 +2544,7 @@ static int ext4_da_writepages(struct address_space *mapping,
 
                ext4_journal_stop(handle);
 
-               if (mpd.retval == -ENOSPC) {
+               if ((mpd.retval == -ENOSPC) && sbi->s_journal) {
                        /* commit the transaction which would
                         * free blocks released in the transaction
                         * and try again
@@ -2546,6 +2560,7 @@ static int ext4_da_writepages(struct address_space *mapping,
                        pages_written += mpd.pages_written;
                        wbc->pages_skipped = pages_skipped;
                        ret = 0;
+                       io_done = 1;
                } else if (wbc->nr_to_write)
                        /*
                         * There is no more writeout needed
@@ -2554,6 +2569,13 @@ static int ext4_da_writepages(struct address_space *mapping,
                         */
                        break;
        }
+       if (!io_done && !cycled) {
+               cycled = 1;
+               index = 0;
+               wbc->range_start = index << PAGE_CACHE_SHIFT;
+               wbc->range_end  = mapping->writeback_index - 1;
+               goto retry;
+       }
        if (pages_skipped != wbc->pages_skipped)
                printk(KERN_EMERG "This should not happen leaving %s "
                                "with nr_to_write = %ld ret = %d\n",
@@ -2561,6 +2583,7 @@ static int ext4_da_writepages(struct address_space *mapping,
 
        /* Update index */
        index += pages_written;
+       wbc->range_cyclic = range_cyclic;
        if (wbc->range_cyclic || (range_whole && wbc->nr_to_write > 0))
                /*
                 * set the writeback_index so that range_cyclic
@@ -2648,6 +2671,9 @@ retry:
                ret = PTR_ERR(handle);
                goto out;
        }
+       /* We cannot recurse into the filesystem as the transaction is already
+        * started */
+       flags |= AOP_FLAG_NOFS;
 
        page = grab_cache_page_write_begin(mapping, index, flags);
        if (!page) {
index deba54f6cbed2af2d504224d2910829951e98d1c..4415beeb0b620c46611348c7092fa75c42cf2337 100644 (file)
@@ -3693,6 +3693,8 @@ ext4_mb_new_inode_pa(struct ext4_allocation_context *ac)
        pa->pa_free = pa->pa_len;
        atomic_set(&pa->pa_count, 1);
        spin_lock_init(&pa->pa_lock);
+       INIT_LIST_HEAD(&pa->pa_inode_list);
+       INIT_LIST_HEAD(&pa->pa_group_list);
        pa->pa_deleted = 0;
        pa->pa_linear = 0;
 
@@ -3755,6 +3757,7 @@ ext4_mb_new_group_pa(struct ext4_allocation_context *ac)
        atomic_set(&pa->pa_count, 1);
        spin_lock_init(&pa->pa_lock);
        INIT_LIST_HEAD(&pa->pa_inode_list);
+       INIT_LIST_HEAD(&pa->pa_group_list);
        pa->pa_deleted = 0;
        pa->pa_linear = 1;
 
@@ -4476,23 +4479,26 @@ static int ext4_mb_release_context(struct ext4_allocation_context *ac)
                        pa->pa_free -= ac->ac_b_ex.fe_len;
                        pa->pa_len -= ac->ac_b_ex.fe_len;
                        spin_unlock(&pa->pa_lock);
-                       /*
-                        * We want to add the pa to the right bucket.
-                        * Remove it from the list and while adding
-                        * make sure the list to which we are adding
-                        * doesn't grow big.
-                        */
-                       if (likely(pa->pa_free)) {
-                               spin_lock(pa->pa_obj_lock);
-                               list_del_rcu(&pa->pa_inode_list);
-                               spin_unlock(pa->pa_obj_lock);
-                               ext4_mb_add_n_trim(ac);
-                       }
                }
-               ext4_mb_put_pa(ac, ac->ac_sb, pa);
        }
        if (ac->alloc_semp)
                up_read(ac->alloc_semp);
+       if (pa) {
+               /*
+                * We want to add the pa to the right bucket.
+                * Remove it from the list and while adding
+                * make sure the list to which we are adding
+                * doesn't grow big.  We need to release
+                * alloc_semp before calling ext4_mb_add_n_trim()
+                */
+               if (pa->pa_linear && likely(pa->pa_free)) {
+                       spin_lock(pa->pa_obj_lock);
+                       list_del_rcu(&pa->pa_inode_list);
+                       spin_unlock(pa->pa_obj_lock);
+                       ext4_mb_add_n_trim(ac);
+               }
+               ext4_mb_put_pa(ac, ac->ac_sb, pa);
+       }
        if (ac->ac_bitmap_page)
                page_cache_release(ac->ac_bitmap_page);
        if (ac->ac_buddy_page)
index 734abca25e359bc4b21f3e8b67674cc9c320698a..fe64d9f79852f1dc22764cfa00f261c84858107b 100644 (file)
@@ -481,7 +481,7 @@ int ext4_ext_migrate(struct inode *inode)
                                        + 1);
        if (IS_ERR(handle)) {
                retval = PTR_ERR(handle);
-               goto err_out;
+               return retval;
        }
        tmp_inode = ext4_new_inode(handle,
                                inode->i_sb->s_root->d_inode,
@@ -489,8 +489,7 @@ int ext4_ext_migrate(struct inode *inode)
        if (IS_ERR(tmp_inode)) {
                retval = -ENOMEM;
                ext4_journal_stop(handle);
-               tmp_inode = NULL;
-               goto err_out;
+               return retval;
        }
        i_size_write(tmp_inode, i_size_read(inode));
        /*
@@ -618,8 +617,7 @@ err_out:
 
        ext4_journal_stop(handle);
 
-       if (tmp_inode)
-               iput(tmp_inode);
+       iput(tmp_inode);
 
        return retval;
 }
index e5f06a5f045ee72ed825748d760485ec8739240f..39d1993cfa1370c3718dffd95231660f3dc606b4 100644 (file)
@@ -3046,14 +3046,17 @@ static void ext4_write_super(struct super_block *sb)
 static int ext4_sync_fs(struct super_block *sb, int wait)
 {
        int ret = 0;
+       tid_t target;
 
        trace_mark(ext4_sync_fs, "dev %s wait %d", sb->s_id, wait);
        sb->s_dirt = 0;
        if (EXT4_SB(sb)->s_journal) {
-               if (wait)
-                       ret = ext4_force_commit(sb);
-               else
-                       jbd2_journal_start_commit(EXT4_SB(sb)->s_journal, NULL);
+               if (jbd2_journal_start_commit(EXT4_SB(sb)->s_journal,
+                                             &target)) {
+                       if (wait)
+                               jbd2_log_wait_commit(EXT4_SB(sb)->s_journal,
+                                                    target);
+               }
        } else {
                ext4_commit_super(sb, EXT4_SB(sb)->s_es, wait);
        }
@@ -3088,7 +3091,6 @@ static int ext4_freeze(struct super_block *sb)
 
                /* Journal blocked and flushed, clear needs_recovery flag. */
                EXT4_CLEAR_INCOMPAT_FEATURE(sb, EXT4_FEATURE_INCOMPAT_RECOVER);
-               ext4_commit_super(sb, EXT4_SB(sb)->s_es, 1);
                error = ext4_commit_super(sb, EXT4_SB(sb)->s_es, 1);
                if (error)
                        goto out;
index eb343008eded0fd86851417f60717650dda96857..58144102bf253b2244fee8fe44ce1a7c02cfbc79 100644 (file)
@@ -450,7 +450,7 @@ int __jbd2_log_space_left(journal_t *journal)
 }
 
 /*
- * Called under j_state_lock.  Returns true if a transaction was started.
+ * Called under j_state_lock.  Returns true if a transaction commit was started.
  */
 int __jbd2_log_start_commit(journal_t *journal, tid_t target)
 {
@@ -518,7 +518,8 @@ int jbd2_journal_force_commit_nested(journal_t *journal)
 
 /*
  * Start a commit of the current running transaction (if any).  Returns true
- * if a transaction was started, and fills its tid in at *ptid
+ * if a transaction is going to be committed (or is currently already
+ * committing), and fills its tid in at *ptid
  */
 int jbd2_journal_start_commit(journal_t *journal, tid_t *ptid)
 {
@@ -528,15 +529,19 @@ int jbd2_journal_start_commit(journal_t *journal, tid_t *ptid)
        if (journal->j_running_transaction) {
                tid_t tid = journal->j_running_transaction->t_tid;
 
-               ret = __jbd2_log_start_commit(journal, tid);
-               if (ret && ptid)
+               __jbd2_log_start_commit(journal, tid);
+               /* There's a running transaction and we've just made sure
+                * it's commit has been scheduled. */
+               if (ptid)
                        *ptid = tid;
-       } else if (journal->j_committing_transaction && ptid) {
+               ret = 1;
+       } else if (journal->j_committing_transaction) {
                /*
                 * If ext3_write_super() recently started a commit, then we
                 * have to wait for completion of that transaction
                 */
-               *ptid = journal->j_committing_transaction->t_tid;
+               if (ptid)
+                       *ptid = journal->j_committing_transaction->t_tid;
                ret = 1;
        }
        spin_unlock(&journal->j_state_lock);
index 46b4e347ed7d9f3949df7b2b475bda7d7f2b8fef..28ce21d8598e11f16182a973d31d7e8bef83c145 100644 (file)
@@ -2129,26 +2129,46 @@ done:
 }
 
 /*
- * This function must be called when inode is journaled in ordered mode
- * before truncation happens. It starts writeout of truncated part in
- * case it is in the committing transaction so that we stand to ordered
- * mode consistency guarantees.
+ * File truncate and transaction commit interact with each other in a
+ * non-trivial way.  If a transaction writing data block A is
+ * committing, we cannot discard the data by truncate until we have
+ * written them.  Otherwise if we crashed after the transaction with
+ * write has committed but before the transaction with truncate has
+ * committed, we could see stale data in block A.  This function is a
+ * helper to solve this problem.  It starts writeout of the truncated
+ * part in case it is in the committing transaction.
+ *
+ * Filesystem code must call this function when inode is journaled in
+ * ordered mode before truncation happens and after the inode has been
+ * placed on orphan list with the new inode size. The second condition
+ * avoids the race that someone writes new data and we start
+ * committing the transaction after this function has been called but
+ * before a transaction for truncate is started (and furthermore it
+ * allows us to optimize the case where the addition to orphan list
+ * happens in the same transaction as write --- we don't have to write
+ * any data in such case).
  */
-int jbd2_journal_begin_ordered_truncate(struct jbd2_inode *inode,
+int jbd2_journal_begin_ordered_truncate(journal_t *journal,
+                                       struct jbd2_inode *jinode,
                                        loff_t new_size)
 {
-       journal_t *journal;
-       transaction_t *commit_trans;
+       transaction_t *inode_trans, *commit_trans;
        int ret = 0;
 
-       if (!inode->i_transaction && !inode->i_next_transaction)
+       /* This is a quick check to avoid locking if not necessary */
+       if (!jinode->i_transaction)
                goto out;
-       journal = inode->i_transaction->t_journal;
+       /* Locks are here just to force reading of recent values, it is
+        * enough that the transaction was not committing before we started
+        * a transaction adding the inode to orphan list */
        spin_lock(&journal->j_state_lock);
        commit_trans = journal->j_committing_transaction;
        spin_unlock(&journal->j_state_lock);
-       if (inode->i_transaction == commit_trans) {
-               ret = filemap_fdatawrite_range(inode->i_vfs_inode->i_mapping,
+       spin_lock(&journal->j_list_lock);
+       inode_trans = jinode->i_transaction;
+       spin_unlock(&journal->j_list_lock);
+       if (inode_trans == commit_trans) {
+               ret = filemap_fdatawrite_range(jinode->i_vfs_inode->i_mapping,
                        new_size, LLONG_MAX);
                if (ret)
                        jbd2_journal_abort(journal, ret);
index 3cceef4ad2b7df413e98b8171cadf074de83ad2d..e9580104b6ba477894b60c6bb3e69839c5677d2f 100644 (file)
@@ -95,13 +95,17 @@ static int jffs2_garbage_collect_thread(void *_c)
                        spin_unlock(&c->erase_completion_lock);
                        
 
-               /* This thread is purely an optimisation. But if it runs when
-                  other things could be running, it actually makes things a
-                  lot worse. Use yield() and put it at the back of the runqueue
-                  every time. Especially during boot, pulling an inode in
-                  with read_inode() is much preferable to having the GC thread
-                  get there first. */
-               yield();
+               /* Problem - immediately after bootup, the GCD spends a lot
+                * of time in places like jffs2_kill_fragtree(); so much so
+                * that userspace processes (like gdm and X) are starved
+                * despite plenty of cond_resched()s and renicing.  Yield()
+                * doesn't help, either (presumably because userspace and GCD
+                * are generally competing for a higher latency resource -
+                * disk).
+                * This forces the GCD to slow the hell down.   Pulling an
+                * inode in with read_inode() is much preferable to having
+                * the GC thread get there first. */
+               schedule_timeout_interruptible(msecs_to_jiffies(50));
 
                /* Put_super will send a SIGKILL and then wait on the sem.
                 */
index 6ca08ad887c09211bf98ab57cb1ec8578bd5d632..1fc1e92356eeb8f2a5c115082edf0109bb37a6db 100644 (file)
@@ -220,7 +220,7 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
                                struct jffs2_tmp_dnode_info *tn)
 {
        uint32_t fn_end = tn->fn->ofs + tn->fn->size;
-       struct jffs2_tmp_dnode_info *this;
+       struct jffs2_tmp_dnode_info *this, *ptn;
 
        dbg_readinode("insert fragment %#04x-%#04x, ver %u at %08x\n", tn->fn->ofs, fn_end, tn->version, ref_offset(tn->fn->raw));
 
@@ -251,11 +251,18 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
        if (this) {
                /* If the node is coincident with another at a lower address,
                   back up until the other node is found. It may be relevant */
-               while (this->overlapped)
-                       this = tn_prev(this);
-
-               /* First node should never be marked overlapped */
-               BUG_ON(!this);
+               while (this->overlapped) {
+                       ptn = tn_prev(this);
+                       if (!ptn) {
+                               /*
+                                * We killed a node which set the overlapped
+                                * flags during the scan. Fix it up.
+                                */
+                               this->overlapped = 0;
+                               break;
+                       }
+                       this = ptn;
+               }
                dbg_readinode("'this' found %#04x-%#04x (%s)\n", this->fn->ofs, this->fn->ofs + this->fn->size, this->fn ? "data" : "hole");
        }
 
@@ -360,7 +367,17 @@ static int jffs2_add_tn_to_tree(struct jffs2_sb_info *c,
                        }
                        if (!this->overlapped)
                                break;
-                       this = tn_prev(this);
+
+                       ptn = tn_prev(this);
+                       if (!ptn) {
+                               /*
+                                * We killed a node which set the overlapped
+                                * flags during the scan. Fix it up.
+                                */
+                               this->overlapped = 0;
+                               break;
+                       }
+                       this = ptn;
                }
        }
 
@@ -456,8 +473,15 @@ static int jffs2_build_inode_fragtree(struct jffs2_sb_info *c,
                eat_last(&rii->tn_root, &last->rb);
                ver_insert(&ver_root, last);
 
-               if (unlikely(last->overlapped))
-                       continue;
+               if (unlikely(last->overlapped)) {
+                       if (pen)
+                               continue;
+                       /*
+                        * We killed a node which set the overlapped
+                        * flags during the scan. Fix it up.
+                        */
+                       last->overlapped = 0;
+               }
 
                /* Now we have a bunch of nodes in reverse version
                   order, in the tree at ver_root. Most of the time,
index 228d8c4bfd18a1925fd57ac3880e2e47031470d2..06f8e63f6cb1dc929e0ad9c0627320066db57cb1 100644 (file)
@@ -614,9 +614,11 @@ static inline void __mntput(struct vfsmount *mnt)
         */
        for_each_possible_cpu(cpu) {
                struct mnt_writer *cpu_writer = &per_cpu(mnt_writers, cpu);
-               if (cpu_writer->mnt != mnt)
-                       continue;
                spin_lock(&cpu_writer->lock);
+               if (cpu_writer->mnt != mnt) {
+                       spin_unlock(&cpu_writer->lock);
+                       continue;
+               }
                atomic_add(cpu_writer->count, &mnt->__mnt_writers);
                cpu_writer->count = 0;
                /*
index dae3f28f30d4779ee69cc8780d8424818b0fbfa4..331f2e88e284e44e373cbda23ab41a024c01c6b1 100644 (file)
@@ -156,7 +156,7 @@ static int inotify_handle_get_wd(struct inotify_handle *ih,
        int ret;
 
        do {
-               if (unlikely(!idr_pre_get(&ih->idr, GFP_KERNEL)))
+               if (unlikely(!idr_pre_get(&ih->idr, GFP_NOFS)))
                        return -ENOSPC;
                ret = idr_get_new_above(&ih->idr, watch, ih->last_wd+1, &watch->wd);
        } while (ret == -EAGAIN);
index 60fe74035db5745fb541bdcc6983d3bb442e17ce..3a9e5deed74d5ec6900b3b531328ab21fb682a49 100644 (file)
@@ -4796,6 +4796,29 @@ out:
        return ret;
 }
 
+static int ocfs2_replace_extent_rec(struct inode *inode,
+                                   handle_t *handle,
+                                   struct ocfs2_path *path,
+                                   struct ocfs2_extent_list *el,
+                                   int split_index,
+                                   struct ocfs2_extent_rec *split_rec)
+{
+       int ret;
+
+       ret = ocfs2_path_bh_journal_access(handle, inode, path,
+                                          path_num_items(path) - 1);
+       if (ret) {
+               mlog_errno(ret);
+               goto out;
+       }
+
+       el->l_recs[split_index] = *split_rec;
+
+       ocfs2_journal_dirty(handle, path_leaf_bh(path));
+out:
+       return ret;
+}
+
 /*
  * Mark part or all of the extent record at split_index in the leaf
  * pointed to by path as written. This removes the unwritten
@@ -4885,7 +4908,9 @@ static int __ocfs2_mark_extent_written(struct inode *inode,
 
        if (ctxt.c_contig_type == CONTIG_NONE) {
                if (ctxt.c_split_covers_rec)
-                       el->l_recs[split_index] = *split_rec;
+                       ret = ocfs2_replace_extent_rec(inode, handle,
+                                                      path, el,
+                                                      split_index, split_rec);
                else
                        ret = ocfs2_split_and_insert(inode, handle, path, et,
                                                     &last_eb_bh, split_index,
index 54e182a27caf81a86b96fb9cc133b5776346e028..0a2813947853dfd68372506b9fb43de894c3d577 100644 (file)
@@ -1849,12 +1849,12 @@ int dlm_assert_master_handler(struct o2net_msg *msg, u32 len, void *data,
                if (!mle) {
                        if (res->owner != DLM_LOCK_RES_OWNER_UNKNOWN &&
                            res->owner != assert->node_idx) {
-                               mlog(ML_ERROR, "assert_master from "
-                                         "%u, but current owner is "
-                                         "%u! (%.*s)\n",
-                                      assert->node_idx, res->owner,
-                                      namelen, name);
-                               goto kill;
+                               mlog(ML_ERROR, "DIE! Mastery assert from %u, "
+                                    "but current owner is %u! (%.*s)\n",
+                                    assert->node_idx, res->owner, namelen,
+                                    name);
+                               __dlm_print_one_lock_resource(res);
+                               BUG();
                        }
                } else if (mle->type != DLM_MLE_MIGRATION) {
                        if (res->owner != DLM_LOCK_RES_OWNER_UNKNOWN) {
index d1295203029fd927131e626c44f97def0433a918..4060bb328bc8a08c22bbd77c59835d757ebdcda5 100644 (file)
@@ -181,8 +181,7 @@ static int dlm_purge_lockres(struct dlm_ctxt *dlm,
 
                spin_lock(&res->spinlock);
                /* This ensures that clear refmap is sent after the set */
-               __dlm_wait_on_lockres_flags(res, (DLM_LOCK_RES_SETREF_INPROG |
-                                                 DLM_LOCK_RES_MIGRATING));
+               __dlm_wait_on_lockres_flags(res, DLM_LOCK_RES_SETREF_INPROG);
                spin_unlock(&res->spinlock);
 
                /* clear our bit from the master's refmap, ignore errors */
index 86ca085ef3246b8066d7f9f976b0866e7e63e168..fcf879ed69308e9518d0504428d3afbe13ee9f8f 100644 (file)
@@ -117,11 +117,11 @@ static enum dlm_status dlmunlock_common(struct dlm_ctxt *dlm,
        else
                BUG_ON(res->owner == dlm->node_num);
 
-       spin_lock(&dlm->spinlock);
+       spin_lock(&dlm->ast_lock);
        /* We want to be sure that we're not freeing a lock
         * that still has AST's pending... */
        in_use = !list_empty(&lock->ast_list);
-       spin_unlock(&dlm->spinlock);
+       spin_unlock(&dlm->ast_lock);
        if (in_use) {
               mlog(ML_ERROR, "lockres %.*s: Someone is calling dlmunlock "
                    "while waiting for an ast!", res->lockname.len,
index 206a2370876a8c82f4c6ad04f101a7d801be6e5b..7219a86d34ccc3102b360e10c298ed50fda903a7 100644 (file)
@@ -320,9 +320,14 @@ static void ocfs2_schedule_blocked_lock(struct ocfs2_super *osb,
                                        struct ocfs2_lock_res *lockres);
 static inline void ocfs2_recover_from_dlm_error(struct ocfs2_lock_res *lockres,
                                                int convert);
-#define ocfs2_log_dlm_error(_func, _err, _lockres) do {                        \
-       mlog(ML_ERROR, "DLM error %d while calling %s on resource %s\n", \
-            _err, _func, _lockres->l_name);                            \
+#define ocfs2_log_dlm_error(_func, _err, _lockres) do {                                        \
+       if ((_lockres)->l_type != OCFS2_LOCK_TYPE_DENTRY)                               \
+               mlog(ML_ERROR, "DLM error %d while calling %s on resource %s\n",        \
+                    _err, _func, _lockres->l_name);                                    \
+       else                                                                            \
+               mlog(ML_ERROR, "DLM error %d while calling %s on resource %.*s%08x\n",  \
+                    _err, _func, OCFS2_DENTRY_LOCK_INO_START - 1, (_lockres)->l_name,  \
+                    (unsigned int)ocfs2_get_dentry_lock_ino(_lockres));                \
 } while (0)
 static int ocfs2_downconvert_thread(void *arg);
 static void ocfs2_downconvert_on_unlock(struct ocfs2_super *osb,
index 3c3532e1307c838495b60e52d9eb9eada0ab69fd..172850a9a12a7d78cc115e80500979673f4ae7f5 100644 (file)
@@ -513,8 +513,10 @@ static inline int ocfs2_jbd2_file_inode(handle_t *handle, struct inode *inode)
 static inline int ocfs2_begin_ordered_truncate(struct inode *inode,
                                               loff_t new_size)
 {
-       return jbd2_journal_begin_ordered_truncate(&OCFS2_I(inode)->ip_jinode,
-                                                  new_size);
+       return jbd2_journal_begin_ordered_truncate(
+                               OCFS2_SB(inode->i_sb)->journal->j_journal,
+                               &OCFS2_I(inode)->ip_jinode,
+                               new_size);
 }
 
 #endif /* OCFS2_JOURNAL_H */
index 077384135f4ea763cd30105b9df51521b9565227..946d3c34b90ba29e0e1cc0d44df7ca9bfe1878f5 100644 (file)
@@ -341,6 +341,9 @@ struct ocfs2_super
        struct ocfs2_node_map           osb_recovering_orphan_dirs;
        unsigned int                    *osb_orphan_wipes;
        wait_queue_head_t               osb_wipe_event;
+
+       /* used to protect metaecc calculation check of xattr. */
+       spinlock_t osb_xattr_lock;
 };
 
 #define OCFS2_SB(sb)       ((struct ocfs2_super *)(sb)->s_fs_info)
index b1cb38fbe80706817a2fdf6be8dda71f348eb568..7ac83a81ee55d86466329d7f9b568432666b5144 100644 (file)
@@ -1537,6 +1537,13 @@ static int ocfs2_get_sector(struct super_block *sb,
        unlock_buffer(*bh);
        ll_rw_block(READ, 1, bh);
        wait_on_buffer(*bh);
+       if (!buffer_uptodate(*bh)) {
+               mlog_errno(-EIO);
+               brelse(*bh);
+               *bh = NULL;
+               return -EIO;
+       }
+
        return 0;
 }
 
@@ -1747,6 +1754,7 @@ static int ocfs2_initialize_super(struct super_block *sb,
        INIT_LIST_HEAD(&osb->blocked_lock_list);
        osb->blocked_lock_count = 0;
        spin_lock_init(&osb->osb_lock);
+       spin_lock_init(&osb->osb_xattr_lock);
        ocfs2_init_inode_steal_slot(osb);
 
        atomic_set(&osb->alloc_stats.moves, 0);
index 915039fffe6ed37149a47d1929929f79b0865d5c..4ddd788add67bcc9df070da373a47e9105b0c242 100644 (file)
@@ -82,13 +82,14 @@ struct ocfs2_xattr_set_ctxt {
 
 #define OCFS2_XATTR_ROOT_SIZE  (sizeof(struct ocfs2_xattr_def_value_root))
 #define OCFS2_XATTR_INLINE_SIZE        80
+#define OCFS2_XATTR_HEADER_GAP 4
 #define OCFS2_XATTR_FREE_IN_IBODY      (OCFS2_MIN_XATTR_INLINE_SIZE \
                                         - sizeof(struct ocfs2_xattr_header) \
-                                        - sizeof(__u32))
+                                        - OCFS2_XATTR_HEADER_GAP)
 #define OCFS2_XATTR_FREE_IN_BLOCK(ptr) ((ptr)->i_sb->s_blocksize \
                                         - sizeof(struct ocfs2_xattr_block) \
                                         - sizeof(struct ocfs2_xattr_header) \
-                                        - sizeof(__u32))
+                                        - OCFS2_XATTR_HEADER_GAP)
 
 static struct ocfs2_xattr_def_value_root def_xv = {
        .xv.xr_list.l_count = cpu_to_le16(1),
@@ -274,10 +275,12 @@ static int ocfs2_read_xattr_bucket(struct ocfs2_xattr_bucket *bucket,
                               bucket->bu_blocks, bucket->bu_bhs, 0,
                               NULL);
        if (!rc) {
+               spin_lock(&OCFS2_SB(bucket->bu_inode->i_sb)->osb_xattr_lock);
                rc = ocfs2_validate_meta_ecc_bhs(bucket->bu_inode->i_sb,
                                                 bucket->bu_bhs,
                                                 bucket->bu_blocks,
                                                 &bucket_xh(bucket)->xh_check);
+               spin_unlock(&OCFS2_SB(bucket->bu_inode->i_sb)->osb_xattr_lock);
                if (rc)
                        mlog_errno(rc);
        }
@@ -310,9 +313,11 @@ static void ocfs2_xattr_bucket_journal_dirty(handle_t *handle,
 {
        int i;
 
+       spin_lock(&OCFS2_SB(bucket->bu_inode->i_sb)->osb_xattr_lock);
        ocfs2_compute_meta_ecc_bhs(bucket->bu_inode->i_sb,
                                   bucket->bu_bhs, bucket->bu_blocks,
                                   &bucket_xh(bucket)->xh_check);
+       spin_unlock(&OCFS2_SB(bucket->bu_inode->i_sb)->osb_xattr_lock);
 
        for (i = 0; i < bucket->bu_blocks; i++)
                ocfs2_journal_dirty(handle, bucket->bu_bhs[i]);
@@ -1507,7 +1512,7 @@ static int ocfs2_xattr_set_entry(struct inode *inode,
                last += 1;
        }
 
-       free = min_offs - ((void *)last - xs->base) - sizeof(__u32);
+       free = min_offs - ((void *)last - xs->base) - OCFS2_XATTR_HEADER_GAP;
        if (free < 0)
                return -EIO;
 
@@ -2190,7 +2195,7 @@ static int ocfs2_xattr_can_be_in_inode(struct inode *inode,
                last += 1;
        }
 
-       free = min_offs - ((void *)last - xs->base) - sizeof(__u32);
+       free = min_offs - ((void *)last - xs->base) - OCFS2_XATTR_HEADER_GAP;
        if (free < 0)
                return 0;
 
@@ -2592,8 +2597,9 @@ static int __ocfs2_xattr_set_handle(struct inode *inode,
 
        if (!ret) {
                /* Update inode ctime. */
-               ret = ocfs2_journal_access(ctxt->handle, inode, xis->inode_bh,
-                                          OCFS2_JOURNAL_ACCESS_WRITE);
+               ret = ocfs2_journal_access_di(ctxt->handle, inode,
+                                             xis->inode_bh,
+                                             OCFS2_JOURNAL_ACCESS_WRITE);
                if (ret) {
                        mlog_errno(ret);
                        goto out;
@@ -5060,8 +5066,8 @@ try_again:
        xh_free_start = le16_to_cpu(xh->xh_free_start);
        header_size = sizeof(struct ocfs2_xattr_header) +
                        count * sizeof(struct ocfs2_xattr_entry);
-       max_free = OCFS2_XATTR_BUCKET_SIZE -
-               le16_to_cpu(xh->xh_name_value_len) - header_size;
+       max_free = OCFS2_XATTR_BUCKET_SIZE - header_size -
+               le16_to_cpu(xh->xh_name_value_len) - OCFS2_XATTR_HEADER_GAP;
 
        mlog_bug_on_msg(header_size > blocksize, "bucket %llu has header size "
                        "of %u which exceed block size\n",
@@ -5094,7 +5100,7 @@ try_again:
                        need = 0;
        }
 
-       free = xh_free_start - header_size;
+       free = xh_free_start - header_size - OCFS2_XATTR_HEADER_GAP;
        /*
         * We need to make sure the new name/value pair
         * can exist in the same block.
@@ -5127,7 +5133,8 @@ try_again:
                        }
 
                        xh_free_start = le16_to_cpu(xh->xh_free_start);
-                       free = xh_free_start - header_size;
+                       free = xh_free_start - header_size
+                               - OCFS2_XATTR_HEADER_GAP;
                        if (xh_free_start % blocksize < need)
                                free -= xh_free_start % blocksize;
 
index 3e76bb9b3ad668d8ceab574a8f6d7d4a5f2e6ef6..d8bb5c671f420a83c17c740425e6f71f9d85799e 100644 (file)
@@ -485,8 +485,10 @@ struct inode *proc_get_inode(struct super_block *sb, unsigned int ino,
                        }
                }
                unlock_new_inode(inode);
-       } else
+       } else {
               module_put(de->owner);
+              de_put(de);
+       }
        return inode;
 
 out_ino:
index 767d95a6d1b1bfdd713226915fb20bcca921347d..2d1345112a42d83ea0317dcd551e4766fb879bb8 100644 (file)
@@ -107,7 +107,7 @@ static ssize_t kpageflags_read(struct file *file, char __user *buf,
                else
                        kflags = ppage->flags;
 
-               uflags = kpf_copy_bit(KPF_LOCKED, PG_locked, kflags) |
+               uflags = kpf_copy_bit(kflags, KPF_LOCKED, PG_locked) |
                        kpf_copy_bit(kflags, KPF_ERROR, PG_error) |
                        kpf_copy_bit(kflags, KPF_REFERENCED, PG_referenced) |
                        kpf_copy_bit(kflags, KPF_UPTODATE, PG_uptodate) |
index 5267098532bfc8a3a6c25026119a14c144d49f5c..a1a4cfe1921040d6044657e6c235e2f5d55f8292 100644 (file)
@@ -48,8 +48,16 @@ int seq_open(struct file *file, const struct seq_operations *op)
         */
        file->f_version = 0;
 
-       /* SEQ files support lseek, but not pread/pwrite */
-       file->f_mode &= ~(FMODE_PREAD | FMODE_PWRITE);
+       /*
+        * seq_files support lseek() and pread().  They do not implement
+        * write() at all, but we clear FMODE_PWRITE here for historical
+        * reasons.
+        *
+        * If a client of seq_files a) implements file.write() and b) wishes to
+        * support pwrite() then that client will need to implement its own
+        * file.open() which calls seq_open() and then sets FMODE_PWRITE.
+        */
+       file->f_mode &= ~FMODE_PWRITE;
        return 0;
 }
 EXPORT_SYMBOL(seq_open);
@@ -131,6 +139,22 @@ ssize_t seq_read(struct file *file, char __user *buf, size_t size, loff_t *ppos)
        int err = 0;
 
        mutex_lock(&m->lock);
+
+       /* Don't assume *ppos is where we left it */
+       if (unlikely(*ppos != m->read_pos)) {
+               m->read_pos = *ppos;
+               while ((err = traverse(m, *ppos)) == -EAGAIN)
+                       ;
+               if (err) {
+                       /* With prejudice... */
+                       m->read_pos = 0;
+                       m->version = 0;
+                       m->index = 0;
+                       m->count = 0;
+                       goto Done;
+               }
+       }
+
        /*
         * seq_file->op->..m_start/m_stop/m_next may do special actions
         * or optimisations based on the file->f_version, so we want to
@@ -230,8 +254,10 @@ Fill:
 Done:
        if (!copied)
                copied = err;
-       else
+       else {
                *ppos += copied;
+               m->read_pos += copied;
+       }
        file->f_version = m->version;
        mutex_unlock(&m->lock);
        return copied;
@@ -266,16 +292,18 @@ loff_t seq_lseek(struct file *file, loff_t offset, int origin)
                        if (offset < 0)
                                break;
                        retval = offset;
-                       if (offset != file->f_pos) {
+                       if (offset != m->read_pos) {
                                while ((retval=traverse(m, offset)) == -EAGAIN)
                                        ;
                                if (retval) {
                                        /* with extreme prejudice... */
                                        file->f_pos = 0;
+                                       m->read_pos = 0;
                                        m->version = 0;
                                        m->index = 0;
                                        m->count = 0;
                                } else {
+                                       m->read_pos = offset;
                                        retval = file->f_pos = offset;
                                }
                        }
index 61dce001dd572ef74685c42b0a1b83fa7307703b..8349ed6b1412aa13e9f23d17fad91e66c9ec1915 100644 (file)
@@ -82,7 +82,22 @@ static struct super_block *alloc_super(struct file_system_type *type)
                 * lock ordering than usbfs:
                 */
                lockdep_set_class(&s->s_lock, &type->s_lock_key);
-               down_write(&s->s_umount);
+               /*
+                * sget() can have s_umount recursion.
+                *
+                * When it cannot find a suitable sb, it allocates a new
+                * one (this one), and tries again to find a suitable old
+                * one.
+                *
+                * In case that succeeds, it will acquire the s_umount
+                * lock of the old one. Since these are clearly distrinct
+                * locks, and this object isn't exposed yet, there's no
+                * risk of deadlocks.
+                *
+                * Annotate this by putting this lock in a different
+                * subclass.
+                */
+               down_write_nested(&s->s_umount, SINGLE_DEPTH_NESTING);
                s->s_count = S_BIAS;
                atomic_set(&s->s_active, 1);
                mutex_init(&s->s_vfs_rename_mutex);
index 6a123b8ff3f5605735255f7ccaf084af547743dd..b042bd7034b1fc74d6cd6399e24b3a2057689a2f 100644 (file)
@@ -186,10 +186,9 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
        BUILD_BUG_ON(TFD_CLOEXEC != O_CLOEXEC);
        BUILD_BUG_ON(TFD_NONBLOCK != O_NONBLOCK);
 
-       if (flags & ~(TFD_CLOEXEC | TFD_NONBLOCK))
-               return -EINVAL;
-       if (clockid != CLOCK_MONOTONIC &&
-           clockid != CLOCK_REALTIME)
+       if ((flags & ~TFD_CREATE_FLAGS) ||
+           (clockid != CLOCK_MONOTONIC &&
+            clockid != CLOCK_REALTIME))
                return -EINVAL;
 
        ctx = kzalloc(sizeof(*ctx), GFP_KERNEL);
@@ -201,7 +200,7 @@ SYSCALL_DEFINE2(timerfd_create, int, clockid, int, flags)
        hrtimer_init(&ctx->tmr, clockid, HRTIMER_MODE_ABS);
 
        ufd = anon_inode_getfd("[timerfd]", &timerfd_fops, ctx,
-                              flags & (O_CLOEXEC | O_NONBLOCK));
+                              flags & TFD_SHARED_FCNTL_FLAGS);
        if (ufd < 0)
                kfree(ctx);
 
@@ -219,7 +218,8 @@ SYSCALL_DEFINE4(timerfd_settime, int, ufd, int, flags,
        if (copy_from_user(&ktmr, utmr, sizeof(ktmr)))
                return -EFAULT;
 
-       if (!timespec_valid(&ktmr.it_value) ||
+       if ((flags & ~TFD_SETTIME_FLAGS) ||
+           !timespec_valid(&ktmr.it_value) ||
            !timespec_valid(&ktmr.it_interval))
                return -EINVAL;
 
index d71dc44e21edbe7077bda8d35f9b259aac61522d..cb329edc925b915ae5e590edeb4840810f811326 100644 (file)
@@ -165,6 +165,75 @@ test_page_region(
        return (mask && (page_private(page) & mask) == mask);
 }
 
+/*
+ *     Mapping of multi-page buffers into contiguous virtual space
+ */
+
+typedef struct a_list {
+       void            *vm_addr;
+       struct a_list   *next;
+} a_list_t;
+
+static a_list_t                *as_free_head;
+static int             as_list_len;
+static DEFINE_SPINLOCK(as_lock);
+
+/*
+ *     Try to batch vunmaps because they are costly.
+ */
+STATIC void
+free_address(
+       void            *addr)
+{
+       a_list_t        *aentry;
+
+#ifdef CONFIG_XEN
+       /*
+        * Xen needs to be able to make sure it can get an exclusive
+        * RO mapping of pages it wants to turn into a pagetable.  If
+        * a newly allocated page is also still being vmap()ed by xfs,
+        * it will cause pagetable construction to fail.  This is a
+        * quick workaround to always eagerly unmap pages so that Xen
+        * is happy.
+        */
+       vunmap(addr);
+       return;
+#endif
+
+       aentry = kmalloc(sizeof(a_list_t), GFP_NOWAIT);
+       if (likely(aentry)) {
+               spin_lock(&as_lock);
+               aentry->next = as_free_head;
+               aentry->vm_addr = addr;
+               as_free_head = aentry;
+               as_list_len++;
+               spin_unlock(&as_lock);
+       } else {
+               vunmap(addr);
+       }
+}
+
+STATIC void
+purge_addresses(void)
+{
+       a_list_t        *aentry, *old;
+
+       if (as_free_head == NULL)
+               return;
+
+       spin_lock(&as_lock);
+       aentry = as_free_head;
+       as_free_head = NULL;
+       as_list_len = 0;
+       spin_unlock(&as_lock);
+
+       while ((old = aentry) != NULL) {
+               vunmap(aentry->vm_addr);
+               aentry = aentry->next;
+               kfree(old);
+       }
+}
+
 /*
  *     Internal xfs_buf_t object manipulation
  */
@@ -264,7 +333,7 @@ xfs_buf_free(
                uint            i;
 
                if ((bp->b_flags & XBF_MAPPED) && (bp->b_page_count > 1))
-                       vm_unmap_ram(bp->b_addr - bp->b_offset, bp->b_page_count);
+                       free_address(bp->b_addr - bp->b_offset);
 
                for (i = 0; i < bp->b_page_count; i++) {
                        struct page     *page = bp->b_pages[i];
@@ -386,8 +455,10 @@ _xfs_buf_map_pages(
                bp->b_addr = page_address(bp->b_pages[0]) + bp->b_offset;
                bp->b_flags |= XBF_MAPPED;
        } else if (flags & XBF_MAPPED) {
-               bp->b_addr = vm_map_ram(bp->b_pages, bp->b_page_count,
-                                       -1, PAGE_KERNEL);
+               if (as_list_len > 64)
+                       purge_addresses();
+               bp->b_addr = vmap(bp->b_pages, bp->b_page_count,
+                                       VM_MAP, PAGE_KERNEL);
                if (unlikely(bp->b_addr == NULL))
                        return -ENOMEM;
                bp->b_addr += bp->b_offset;
@@ -1672,6 +1743,8 @@ xfsbufd(
                        count++;
                }
 
+               if (as_list_len > 0)
+                       purge_addresses();
                if (count)
                        blk_run_address_space(target->bt_mapping);
 
index 83c51aba534b727a363d22559eaa153dd90c9dda..e16fdb1f4f4fe11caada4239cbc621f084936552 100644 (file)
@@ -478,7 +478,7 @@ static inline pte_t pte_modify(pte_t pte, pgprot_t newprot)
 #define __swp_type(x)                  (((x).val >> 2) & 0x1f)
 #define __swp_offset(x)                        ((x).val >> 8)
 #define __swp_entry(type, offset)      ((swp_entry_t) { ((type) << 2) | ((offset) << 8) })
-#define __pte_to_swp_entry(pte)                ((swp_entry_t) { (pte).pte })
+#define __pte_to_swp_entry(_pte)       ((swp_entry_t) { (_pte).pte })
 #define __swp_entry_to_pte(x)          ((pte_t) { (x).val })
 
 static inline int pte_file(pte_t pte)
index 8190b9bcc2d967e366833e04823f6899e9e33aea..e5f4ae989abf15bd0b7ead6428840584cede0f85 100644 (file)
@@ -1321,6 +1321,8 @@ void drm_gem_object_free(struct kref *kref);
 struct drm_gem_object *drm_gem_object_alloc(struct drm_device *dev,
                                            size_t size);
 void drm_gem_object_handle_free(struct kref *kref);
+void drm_gem_vm_open(struct vm_area_struct *vma);
+void drm_gem_vm_close(struct vm_area_struct *vma);
 int drm_gem_mmap(struct file *filp, struct vm_area_struct *vma);
 
 static inline void
index d54de24bf371f52025d6bad298f01b50b8b5522f..5ded1acfb5430fd969094e9fa817c285aefa9611 100644 (file)
@@ -609,7 +609,7 @@ extern char *drm_get_dvi_i_subconnector_name(int val);
 extern char *drm_get_dvi_i_select_name(int val);
 extern char *drm_get_tv_subconnector_name(int val);
 extern char *drm_get_tv_select_name(int val);
-extern void drm_fb_release(struct file *filp);
+extern void drm_fb_release(struct drm_file *file_priv);
 extern int drm_mode_group_init_legacy_group(struct drm_device *dev, struct drm_mode_group *group);
 extern struct edid *drm_get_edid(struct drm_connector *connector,
                                 struct i2c_adapter *adapter);
index 0c6f0e11b41bcfc823d94571c3be853087440e5a..c7d4b2e606a5f73f5fbed9217449b16c504b7e4d 100644 (file)
@@ -54,13 +54,13 @@ struct drm_crtc_helper_funcs {
                           struct drm_display_mode *mode,
                           struct drm_display_mode *adjusted_mode);
        /* Actually set the mode */
-       void (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
-                        struct drm_display_mode *adjusted_mode, int x, int y,
-                        struct drm_framebuffer *old_fb);
+       int (*mode_set)(struct drm_crtc *crtc, struct drm_display_mode *mode,
+                       struct drm_display_mode *adjusted_mode, int x, int y,
+                       struct drm_framebuffer *old_fb);
 
        /* Move the crtc on the current fb to the given position *optional* */
-       void (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
-                             struct drm_framebuffer *old_fb);
+       int (*mode_set_base)(struct drm_crtc *crtc, int x, int y,
+                            struct drm_framebuffer *old_fb);
 };
 
 struct drm_encoder_helper_funcs {
@@ -76,6 +76,7 @@ struct drm_encoder_helper_funcs {
        void (*mode_set)(struct drm_encoder *encoder,
                         struct drm_display_mode *mode,
                         struct drm_display_mode *adjusted_mode);
+       struct drm_crtc *(*get_crtc)(struct drm_encoder *encoder);
        /* detect for DAC style encoders */
        enum drm_connector_status (*detect)(struct drm_encoder *encoder,
                                            struct drm_connector *connector);
index c707c15f5164ef3a9410dbc98d246f34189be804..ff8d27af47869b611067a2bef26c140042bf03d7 100644 (file)
@@ -58,10 +58,10 @@ struct detailed_pixel_timing {
        u8 hsync_pulse_width_lo;
        u8 vsync_pulse_width_lo:4;
        u8 vsync_offset_lo:4;
-       u8 hsync_pulse_width_hi:2;
-       u8 hsync_offset_hi:2;
        u8 vsync_pulse_width_hi:2;
        u8 vsync_offset_hi:2;
+       u8 hsync_pulse_width_hi:2;
+       u8 hsync_offset_hi:2;
        u8 width_mm_lo;
        u8 height_mm_lo;
        u8 height_mm_hi:4;
index b97cdc516a8fcb078e29f1b2745db7f6040a880a..e9581fd9fb66b45499a5e4b490ea301b50f2405e 100644 (file)
@@ -52,6 +52,7 @@ header-y += const.h
 header-y += cgroupstats.h
 header-y += cramfs_fs.h
 header-y += cycx_cfm.h
+header-y += dcbnl.h
 header-y += dlmconstants.h
 header-y += dlm_device.h
 header-y += dlm_netlink.h
@@ -114,6 +115,7 @@ header-y += mqueue.h
 header-y += mtio.h
 header-y += ncp_no.h
 header-y += neighbour.h
+header-y += net_dropmon.h
 header-y += netfilter_arp.h
 header-y += netrom.h
 header-y += nfs2.h
index 2aa283ab062b215ddb37975d8e55193ecd502c5f..1b16108a54174346e2f64be1aca0b6474c1e13e8 100644 (file)
@@ -171,8 +171,6 @@ struct bio {
 #define BIO_RW_FAILFAST_TRANSPORT      8
 #define BIO_RW_FAILFAST_DRIVER         9
 
-#define BIO_RW_SYNC    (BIO_RW_SYNCIO | BIO_RW_UNPLUG)
-
 #define bio_rw_flagged(bio, flag)      ((bio)->bi_rw & (1 << (flag)))
 
 /*
index dcaa0fd84b02c36453f8d7cc211c5eaf3d12aa7b..465d6babc847a2603d4f23a5e842cd7dc07b308e 100644 (file)
@@ -708,6 +708,8 @@ struct req_iterator {
 };
 
 /* This should not be used directly - use rq_for_each_segment */
+#define for_each_bio(_bio)             \
+       for (; _bio; _bio = _bio->bi_next)
 #define __rq_for_each_bio(_bio, rq)    \
        if ((rq->bio))                  \
                for (_bio = (rq)->bio; _bio; _bio = _bio->bi_next)
index 25379cba2370f2dd6cb11931d9a6649aaee40a8d..6e915878e88c2a4c8b27bea51e1a6e010fee93e9 100644 (file)
@@ -15,6 +15,7 @@ enum blktrace_cat {
        BLK_TC_WRITE    = 1 << 1,       /* writes */
        BLK_TC_BARRIER  = 1 << 2,       /* barrier */
        BLK_TC_SYNC     = 1 << 3,       /* sync IO */
+       BLK_TC_SYNCIO   = BLK_TC_SYNC,
        BLK_TC_QUEUE    = 1 << 4,       /* queueing/merging */
        BLK_TC_REQUEUE  = 1 << 5,       /* requeueing */
        BLK_TC_ISSUE    = 1 << 6,       /* issue */
index b00a753eda53e6af1e50e7d892defdcb402913d8..9c20c7e87d0aa830ac3009a676328e691f926903 100644 (file)
@@ -1,3 +1,23 @@
+/*
+ * Copyright(c) 2007 - 2009 Intel Corporation. All rights reserved.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU General Public License as published by the Free
+ * Software Foundation; either version 2 of the License, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc., 59
+ * Temple Place - Suite 330, Boston, MA  02111-1307, USA.
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called COPYING.
+ */
 #ifndef DCA_H
 #define DCA_H
 /* DCA Provider API */
index b0ef274e00319d575082168ef3bb763fdf6447b9..7d2e10006188415694e16bcbba545f6fd28381de 100644 (file)
 #ifndef __LINUX_DCBNL_H__
 #define __LINUX_DCBNL_H__
 
+#include <linux/types.h>
+
 #define DCB_PROTO_VERSION 1
 
 struct dcbmsg {
-       unsigned char      dcb_family;
+       __u8               dcb_family;
        __u8               cmd;
        __u16              dcb_pad;
 };
index 45e5b1921fbb5ceeb50a33514a423b53d9d46cd0..47f343c7bddaaca551c8fb2114160fb5f362c4e1 100644 (file)
@@ -147,6 +147,8 @@ extern void put_driver(struct device_driver *drv);
 extern struct device_driver *driver_find(const char *name,
                                         struct bus_type *bus);
 extern int driver_probe_done(void);
+extern int wait_for_device_probe(void);
+
 
 /* sysfs interface for exporting driver attributes */
 
index 3e68469c1885e3df7e7078b0c39aab5237cb7f06..f0413845f20ee75481543cb97c570d6dbda142b4 100644 (file)
@@ -121,6 +121,7 @@ struct dma_chan_percpu {
  * @local: per-cpu pointer to a struct dma_chan_percpu
  * @client-count: how many clients are using this channel
  * @table_count: number of appearances in the mem-to-mem allocation table
+ * @private: private data for certain client-channel associations
  */
 struct dma_chan {
        struct dma_device *device;
@@ -134,6 +135,7 @@ struct dma_chan {
        struct dma_chan_percpu *local;
        int client_count;
        int table_count;
+       void *private;
 };
 
 /**
index 27c67a5422354dde23433ccd4c50676bd54b4198..131b127b70f8a1fb07ffa0e2a4aaba2166f12f78 100644 (file)
@@ -7,6 +7,7 @@
  * Portions Copyright 2002 Intel (eli.kupermann@intel.com,
  *                                christopher.leech@intel.com,
  *                                scott.feldman@intel.com)
+ * Portions Copyright (C) Sun Microsystems 2008
  */
 
 #ifndef _LINUX_ETHTOOL_H
@@ -287,10 +288,75 @@ enum ethtool_flags {
        ETH_FLAG_LRO            = (1 << 15),    /* LRO is enabled */
 };
 
-struct ethtool_rxnfc {
-       __u32           cmd;
+/* The following structures are for supporting RX network flow
+ * classification configuration. Note, all multibyte fields, e.g.,
+ * ip4src, ip4dst, psrc, pdst, spi, etc. are expected to be in network
+ * byte order.
+ */
+struct ethtool_tcpip4_spec {
+       __be32  ip4src;
+       __be32  ip4dst;
+       __be16  psrc;
+       __be16  pdst;
+       __u8    tos;
+};
+
+struct ethtool_ah_espip4_spec {
+       __be32  ip4src;
+       __be32  ip4dst;
+       __be32  spi;
+       __u8    tos;
+};
+
+struct ethtool_rawip4_spec {
+       __be32  ip4src;
+       __be32  ip4dst;
+       __u8    hdata[64];
+};
+
+struct ethtool_ether_spec {
+       __be16  ether_type;
+       __u8    frame_size;
+       __u8    eframe[16];
+};
+
+#define        ETH_RX_NFC_IP4  1
+#define        ETH_RX_NFC_IP6  2
+
+struct ethtool_usrip4_spec {
+       __be32  ip4src;
+       __be32  ip4dst;
+       __be32  l4_4_bytes;
+       __u8    tos;
+       __u8    ip_ver;
+       __u8    proto;
+};
+
+struct ethtool_rx_flow_spec {
        __u32           flow_type;
-       __u64           data;
+       union {
+               struct ethtool_tcpip4_spec              tcp_ip4_spec;
+               struct ethtool_tcpip4_spec              udp_ip4_spec;
+               struct ethtool_tcpip4_spec              sctp_ip4_spec;
+               struct ethtool_ah_espip4_spec           ah_ip4_spec;
+               struct ethtool_ah_espip4_spec           esp_ip4_spec;
+               struct ethtool_rawip4_spec              raw_ip4_spec;
+               struct ethtool_ether_spec               ether_spec;
+               struct ethtool_usrip4_spec              usr_ip4_spec;
+               __u8                                    hdata[64];
+       } h_u, m_u; /* entry, mask */
+       __u64           ring_cookie;
+       __u32           location;
+};
+
+struct ethtool_rxnfc {
+       __u32                           cmd;
+       __u32                           flow_type;
+       /* The rx flow hash value or the rule DB size */
+       __u64                           data;
+       struct ethtool_rx_flow_spec     fs;
+       __u32                           rule_cnt;
+       __u32                           rule_locs[0];
 };
 
 #ifdef __KERNEL__
@@ -417,8 +483,8 @@ struct ethtool_ops {
        /* the following hooks are obsolete */
        int     (*self_test_count)(struct net_device *);/* use get_sset_count */
        int     (*get_stats_count)(struct net_device *);/* use get_sset_count */
-       int     (*get_rxhash)(struct net_device *, struct ethtool_rxnfc *);
-       int     (*set_rxhash)(struct net_device *, struct ethtool_rxnfc *);
+       int     (*get_rxnfc)(struct net_device *, struct ethtool_rxnfc *, void *);
+       int     (*set_rxnfc)(struct net_device *, struct ethtool_rxnfc *);
 };
 #endif /* __KERNEL__ */
 
@@ -469,6 +535,12 @@ struct ethtool_ops {
 #define        ETHTOOL_SRXFH           0x0000002a /* Set RX flow hash configuration */
 #define ETHTOOL_GGRO           0x0000002b /* Get GRO enable (ethtool_value) */
 #define ETHTOOL_SGRO           0x0000002c /* Set GRO enable (ethtool_value) */
+#define        ETHTOOL_GRXRINGS        0x0000002d /* Get RX rings available for LB */
+#define        ETHTOOL_GRXCLSRLCNT     0x0000002e /* Get RX class rule count */
+#define        ETHTOOL_GRXCLSRULE      0x0000002f /* Get RX classification rule */
+#define        ETHTOOL_GRXCLSRLALL     0x00000030 /* Get all RX classification rule */
+#define        ETHTOOL_SRXCLSRLDEL     0x00000031 /* Delete RX classification rule */
+#define        ETHTOOL_SRXCLSRLINS     0x00000032 /* Insert RX classification rule */
 
 /* compatibility with older code */
 #define SPARC_ETH_GSET         ETHTOOL_GSET
@@ -565,9 +637,13 @@ struct ethtool_ops {
 #define        UDP_V6_FLOW     0x06
 #define        SCTP_V6_FLOW    0x07
 #define        AH_ESP_V6_FLOW  0x08
+#define        AH_V4_FLOW      0x09
+#define        ESP_V4_FLOW     0x0a
+#define        AH_V6_FLOW      0x0b
+#define        ESP_V6_FLOW     0x0c
+#define        IP_USER_FLOW    0x0d
 
 /* L3-L4 network traffic flow hash options */
-#define        RXH_DEV_PORT    (1 << 0)
 #define        RXH_L2DA        (1 << 1)
 #define        RXH_VLAN        (1 << 2)
 #define        RXH_L3_PROTO    (1 << 3)
@@ -577,5 +653,6 @@ struct ethtool_ops {
 #define        RXH_L4_B_2_3    (1 << 7) /* dst port in case of TCP/UDP/SCTP */
 #define        RXH_DISCARD     (1 << 31)
 
+#define        RX_CLS_FLOW_DISC        0xffffffffffffffffULL
 
 #endif /* _LINUX_ETHTOOL_H */
index 6e199c8dfacc4f3c40307076535d41da914afeb8..cca686b39123dca178f26512e5fcbf0db114a41b 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * include/linux/firmware-map.h:
  *  Copyright (C) 2008 SUSE LINUX Products GmbH
- *  by Bernhard Walle <bwalle@suse.de>
+ *  by Bernhard Walle <bernhard.walle@gmx.de>
  *
  * This program is free software; you can redistribute it and/or modify
  * it under the terms of the GNU General Public License v2.0 as published by
index 6022f44043f2a01305bb09564c82d78bd08ad006..92734c0012e679cb3326ba25be08f52dce81fbc8 100644 (file)
@@ -54,24 +54,30 @@ struct inodes_stat_t {
 #define MAY_ACCESS 16
 #define MAY_OPEN 32
 
+/*
+ * flags in file.f_mode.  Note that FMODE_READ and FMODE_WRITE must correspond
+ * to O_WRONLY and O_RDWR via the strange trick in __dentry_open()
+ */
+
 /* file is open for reading */
 #define FMODE_READ             ((__force fmode_t)1)
 /* file is open for writing */
 #define FMODE_WRITE            ((__force fmode_t)2)
 /* file is seekable */
 #define FMODE_LSEEK            ((__force fmode_t)4)
-/* file can be accessed using pread/pwrite */
+/* file can be accessed using pread */
 #define FMODE_PREAD            ((__force fmode_t)8)
-#define FMODE_PWRITE           FMODE_PREAD     /* These go hand in hand */
+/* file can be accessed using pwrite */
+#define FMODE_PWRITE           ((__force fmode_t)16)
 /* File is opened for execution with sys_execve / sys_uselib */
-#define FMODE_EXEC             ((__force fmode_t)16)
+#define FMODE_EXEC             ((__force fmode_t)32)
 /* File is opened with O_NDELAY (only set for block devices) */
-#define FMODE_NDELAY           ((__force fmode_t)32)
+#define FMODE_NDELAY           ((__force fmode_t)64)
 /* File is opened with O_EXCL (only set for block devices) */
-#define FMODE_EXCL             ((__force fmode_t)64)
+#define FMODE_EXCL             ((__force fmode_t)128)
 /* File is opened using open(.., 3, ..) and is writeable only for ioctls
    (specialy hack for floppy.c) */
-#define FMODE_WRITE_IOCTL      ((__force fmode_t)128)
+#define FMODE_WRITE_IOCTL      ((__force fmode_t)256)
 
 /*
  * Don't update ctime and mtime.
@@ -87,10 +93,10 @@ struct inodes_stat_t {
 #define WRITE 1
 #define READA 2                /* read-ahead  - don't block if no resources */
 #define SWRITE 3       /* for ll_rw_block() - wait for buffer lock */
-#define READ_SYNC      (READ | (1 << BIO_RW_SYNC))
+#define READ_SYNC      (READ | (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG))
 #define READ_META      (READ | (1 << BIO_RW_META))
-#define WRITE_SYNC     (WRITE | (1 << BIO_RW_SYNC))
-#define SWRITE_SYNC    (SWRITE | (1 << BIO_RW_SYNC))
+#define WRITE_SYNC     (WRITE | (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG))
+#define SWRITE_SYNC    (SWRITE | (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG))
 #define WRITE_BARRIER  (WRITE | (1 << BIO_RW_BARRIER))
 #define DISCARD_NOBARRIER (1 << BIO_RW_DISCARD)
 #define DISCARD_BARRIER ((1 << BIO_RW_DISCARD) | (1 << BIO_RW_BARRIER))
index 13f4e74609ac10747eceffb84f3f1293a83e71a7..0ffa41df0ee8ca007d9cda5b40fdbe315ee0a845 100644 (file)
@@ -22,7 +22,7 @@ struct gnet_stats_basic
 {
        __u64   bytes;
        __u32   packets;
-};
+} __attribute__ ((packed));
 
 /**
  * struct gnet_stats_rate_est - rate estimator
index 311315b56b611a7b2b9d44a2b930eb8c3b9b8def..fd53bfd2647044be7d48d26adc4de31b6c5d238e 100644 (file)
@@ -33,7 +33,7 @@
  */
 #define I2C_RETRIES    0x0701  /* number of times a device address should
                                   be polled when not acknowledging */
-#define I2C_TIMEOUT    0x0702  /* set timeout in jiffies - call with int */
+#define I2C_TIMEOUT    0x0702  /* set timeout in units of 10 ms */
 
 /* NOTE: Slave address is 7 or 10 bits, but 10-bit addresses
  * are NOT supported! (due to code brokenness)
index fcfbfea3af72d670d7100ca221014c7dece36363..c86c3b07604c2cf46cd492ef948e826f2d9c58d0 100644 (file)
@@ -361,7 +361,7 @@ struct i2c_adapter {
        struct mutex bus_lock;
        struct mutex clist_lock;
 
-       int timeout;
+       int timeout;                    /* in jiffies */
        int retries;
        struct device dev;              /* the adapter device */
 
index 194da5a4b0d683a0d0c42628c00f2c3459ac109d..fe235b65207ee74d43e74818d94bdaf6759816d5 100644 (file)
@@ -663,7 +663,7 @@ typedef struct ide_drive_s ide_drive_t;
 #define to_ide_device(dev)             container_of(dev, ide_drive_t, gendev)
 
 #define to_ide_drv(obj, cont_type)     \
-       container_of(obj, struct cont_type, kref)
+       container_of(obj, struct cont_type, dev)
 
 #define ide_drv_g(disk, cont_type)     \
        container_of((disk)->private_data, struct cont_type, driver)
index f8ff918c208f047f86b42894dfb3a6c211db2238..e1ff5b14310e817197fbf77c5af9522f2b862f6b 100644 (file)
@@ -210,6 +210,7 @@ static inline struct sk_buff *__vlan_put_tag(struct sk_buff *skb, u16 vlan_tci)
 
        /* Move the mac addresses to the beginning of the new header. */
        memmove(skb->data, skb->data + VLAN_HLEN, 2 * VLAN_ETH_ALEN);
+       skb->mac_header -= VLAN_HLEN;
 
        /* first, the ethernet type */
        veth->h_vlan_proto = htons(ETH_P_8021Q);
index c4f6c101dbcddd91e0b7d045a345a4d6fba28777..d2e3cbfba14f45ea30b34bc78e36735c5db2755d 100644 (file)
@@ -194,6 +194,7 @@ static inline void dmar_writeq(void __iomem *addr, u64 val)
 /* FSTS_REG */
 #define DMA_FSTS_PPF ((u32)2)
 #define DMA_FSTS_PFO ((u32)1)
+#define DMA_FSTS_IQE (1 << 4)
 #define dma_fsts_fault_record_index(s) (((s) >> 8) & 0xff)
 
 /* FRCD_REG, 32 bits access */
@@ -328,7 +329,7 @@ extern int qi_flush_iotlb(struct intel_iommu *iommu, u16 did, u64 addr,
                          unsigned int size_order, u64 type,
                          int non_present_entry_flush);
 
-extern void qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu);
+extern int qi_submit_sync(struct qi_desc *desc, struct intel_iommu *iommu);
 
 extern void *intel_alloc_coherent(struct device *, size_t, dma_addr_t *, gfp_t);
 extern void intel_free_coherent(struct device *, size_t, void *, dma_addr_t);
index 82df31726a546de40a1d010c588f56f7c1d3955c..0adb0f91568c1cfd407b1e88c1dce5b39d0080d5 100644 (file)
  * See Documentation/io_mapping.txt
  */
 
-/* this struct isn't actually defined anywhere */
-struct io_mapping;
-
 #ifdef CONFIG_HAVE_ATOMIC_IOMAP
 
+struct io_mapping {
+       resource_size_t base;
+       unsigned long size;
+       pgprot_t prot;
+};
+
 /*
  * For small address space machines, mapping large objects
  * into the kernel virtual space isn't practical. Where
@@ -43,23 +46,40 @@ struct io_mapping;
  */
 
 static inline struct io_mapping *
-io_mapping_create_wc(unsigned long base, unsigned long size)
+io_mapping_create_wc(resource_size_t base, unsigned long size)
 {
-       return (struct io_mapping *) base;
+       struct io_mapping *iomap;
+
+       if (!is_io_mapping_possible(base, size))
+               return NULL;
+
+       iomap = kmalloc(sizeof(*iomap), GFP_KERNEL);
+       if (!iomap)
+               return NULL;
+
+       iomap->base = base;
+       iomap->size = size;
+       iomap->prot = pgprot_writecombine(__pgprot(__PAGE_KERNEL));
+       return iomap;
 }
 
 static inline void
 io_mapping_free(struct io_mapping *mapping)
 {
+       kfree(mapping);
 }
 
 /* Atomic map/unmap */
 static inline void *
 io_mapping_map_atomic_wc(struct io_mapping *mapping, unsigned long offset)
 {
-       offset += (unsigned long) mapping;
-       return iomap_atomic_prot_pfn(offset >> PAGE_SHIFT, KM_USER0,
-                                    __pgprot(__PAGE_KERNEL_WC));
+       resource_size_t phys_addr;
+       unsigned long pfn;
+
+       BUG_ON(offset >= mapping->size);
+       phys_addr = mapping->base + offset;
+       pfn = (unsigned long) (phys_addr >> PAGE_SHIFT);
+       return iomap_atomic_prot_pfn(pfn, KM_USER0, mapping->prot);
 }
 
 static inline void
@@ -71,8 +91,12 @@ io_mapping_unmap_atomic(void *vaddr)
 static inline void *
 io_mapping_map_wc(struct io_mapping *mapping, unsigned long offset)
 {
-       offset += (unsigned long) mapping;
-       return ioremap_wc(offset, PAGE_SIZE);
+       resource_size_t phys_addr;
+
+       BUG_ON(offset >= mapping->size);
+       phys_addr = mapping->base + offset;
+
+       return ioremap_wc(phys_addr, PAGE_SIZE);
 }
 
 static inline void
@@ -83,9 +107,12 @@ io_mapping_unmap(void *vaddr)
 
 #else
 
+/* this struct isn't actually defined anywhere */
+struct io_mapping;
+
 /* Create the io_mapping object*/
 static inline struct io_mapping *
-io_mapping_create_wc(unsigned long base, unsigned long size)
+io_mapping_create_wc(resource_size_t base, unsigned long size)
 {
        return (struct io_mapping *) ioremap_wc(base, size);
 }
index b28b37eb11c626da84e8152f4878b8c593125ec3..4d248b3f1323d828170a9de92d2aba1db7c5f0f4 100644 (file)
@@ -1150,7 +1150,8 @@ extern int           jbd2_journal_clear_err  (journal_t *);
 extern int        jbd2_journal_bmap(journal_t *, unsigned long, unsigned long long *);
 extern int        jbd2_journal_force_commit(journal_t *);
 extern int        jbd2_journal_file_inode(handle_t *handle, struct jbd2_inode *inode);
-extern int        jbd2_journal_begin_ordered_truncate(struct jbd2_inode *inode, loff_t new_size);
+extern int        jbd2_journal_begin_ordered_truncate(journal_t *journal,
+                               struct jbd2_inode *inode, loff_t new_size);
 extern void       jbd2_journal_init_jbd_inode(struct jbd2_inode *jinode, struct inode *inode);
 extern void       jbd2_journal_release_jbd_inode(journal_t *journal, struct jbd2_inode *jinode);
 
index 5715f190760161fbbdfbdd3231f6e87c9a905b72..0424326f167963d5b764554ebec95029b8b99439 100644 (file)
@@ -58,10 +58,10 @@ struct kvm_irqchip {
        __u32 pad;
         union {
                char dummy[512];  /* reserving space */
-#ifdef CONFIG_X86
+#ifdef __KVM_HAVE_PIT
                struct kvm_pic_state pic;
 #endif
-#if defined(CONFIG_X86) || defined(CONFIG_IA64)
+#ifdef __KVM_HAVE_IOAPIC
                struct kvm_ioapic_state ioapic;
 #endif
        } chip;
@@ -384,16 +384,16 @@ struct kvm_trace_rec {
 #define KVM_CAP_MP_STATE 14
 #define KVM_CAP_COALESCED_MMIO 15
 #define KVM_CAP_SYNC_MMU 16  /* Changes to host mmap are reflected in guest */
-#if defined(CONFIG_X86)||defined(CONFIG_IA64)
+#ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
 #define KVM_CAP_DEVICE_ASSIGNMENT 17
 #endif
 #define KVM_CAP_IOMMU 18
-#if defined(CONFIG_X86)
+#ifdef __KVM_HAVE_MSI
 #define KVM_CAP_DEVICE_MSI 20
 #endif
 /* Bug in KVM_SET_USER_MEMORY_REGION fixed: */
 #define KVM_CAP_DESTROY_MEMORY_REGION_WORKS 21
-#if defined(CONFIG_X86)
+#ifdef __KVM_HAVE_USER_NMI
 #define KVM_CAP_USER_NMI 22
 #endif
 
index ec49d0be7f5245614c00e566a5f3702bccd6fa5e..bf6f703642fc81c21b33608cb48aff5477a0605b 100644 (file)
@@ -285,6 +285,7 @@ void kvm_free_physmem(struct kvm *kvm);
 struct  kvm *kvm_arch_create_vm(void);
 void kvm_arch_destroy_vm(struct kvm *kvm);
 void kvm_free_all_assigned_devices(struct kvm *kvm);
+void kvm_arch_sync_events(struct kvm *kvm);
 
 int kvm_cpu_get_interrupt(struct kvm_vcpu *v);
 int kvm_cpu_has_interrupt(struct kvm_vcpu *v);
index 323561582c100bf1b18c3a3b6084eda970f89eeb..065cdf8c09fb50fcce6ff67bcae848ac555c6b7a 100644 (file)
@@ -1041,10 +1041,23 @@ extern void free_bootmem_with_active_regions(int nid,
 typedef int (*work_fn_t)(unsigned long, unsigned long, void *);
 extern void work_with_active_regions(int nid, work_fn_t work_fn, void *data);
 extern void sparse_memory_present_with_active_regions(int nid);
-#ifndef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID
-extern int early_pfn_to_nid(unsigned long pfn);
-#endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */
 #endif /* CONFIG_ARCH_POPULATES_NODE_MAP */
+
+#if !defined(CONFIG_ARCH_POPULATES_NODE_MAP) && \
+    !defined(CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID)
+static inline int __early_pfn_to_nid(unsigned long pfn)
+{
+       return 0;
+}
+#else
+/* please see mm/page_alloc.c */
+extern int __meminit early_pfn_to_nid(unsigned long pfn);
+#ifdef CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID
+/* there is a per-arch backend function. */
+extern int __meminit __early_pfn_to_nid(unsigned long pfn);
+#endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */
+#endif
+
 extern void set_dma_reserve(unsigned long new_dma_reserve);
 extern void memmap_init_zone(unsigned long, int, unsigned long,
                                unsigned long, enum memmap_context);
@@ -1159,6 +1172,7 @@ extern int filemap_fault(struct vm_area_struct *, struct vm_fault *);
 
 /* mm/page-writeback.c */
 int write_one_page(struct page *page, int wait);
+void task_dirty_inc(struct task_struct *tsk);
 
 /* readahead.c */
 #define VM_MAX_READAHEAD       128     /* kbytes */
@@ -1304,5 +1318,6 @@ void vmemmap_populate_print_last(void);
 
 extern void *alloc_locked_buffer(size_t size);
 extern void free_locked_buffer(void *buffer, size_t size);
+extern void release_locked_buffer(void *buffer, size_t size);
 #endif /* __KERNEL__ */
 #endif /* _LINUX_MM_H */
index 09c14e213b63eb72f2f614695a886e67da7444d8..1aca6cebbb78916aaeb4764b3ec7e7da3276cf91 100644 (file)
@@ -1071,7 +1071,7 @@ void sparse_init(void);
 #endif /* CONFIG_SPARSEMEM */
 
 #ifdef CONFIG_NODES_SPAN_OTHER_NODES
-#define early_pfn_in_nid(pfn, nid)     (early_pfn_to_nid(pfn) == (nid))
+bool early_pfn_in_nid(unsigned long pfn, int nid);
 #else
 #define early_pfn_in_nid(pfn, nid)     (1)
 #endif
index 8730d5dae1bc2a3c5b8a33aab453cb8382a19dcf..12c9de1384517e7097a74e5df7da825472bf1f64 100644 (file)
@@ -31,6 +31,7 @@ enum
  *     Neighbor Cache Entry Flags
  */
 
+#define NTF_USE                0x01
 #define NTF_PROXY      0x08    /* == ATF_PUBL */
 #define NTF_ROUTER     0x80
 
index 4515efae4c392bf1c33441159163a04ba80a3ff6..4fc2ffd527f9386e613afe1e54a552268a491eb5 100644 (file)
@@ -129,11 +129,15 @@ struct socket {
        socket_state            state;
        short                   type;
        unsigned long           flags;
-       const struct proto_ops  *ops;
+       /*
+        * Please keep fasync_list & wait fields in the same cache line
+        */
        struct fasync_struct    *fasync_list;
+       wait_queue_head_t       wait;
+
        struct file             *file;
        struct sock             *sk;
-       wait_queue_head_t       wait;
+       const struct proto_ops  *ops;
 };
 
 struct vm_area_struct;
diff --git a/include/linux/net_dropmon.h b/include/linux/net_dropmon.h
new file mode 100644 (file)
index 0000000..0217fb8
--- /dev/null
@@ -0,0 +1,56 @@
+#ifndef __NET_DROPMON_H
+#define __NET_DROPMON_H
+
+#include <linux/netlink.h>
+
+struct net_dm_drop_point {
+       __u8 pc[8];
+       __u32 count;
+};
+
+#define NET_DM_CFG_VERSION  0
+#define NET_DM_CFG_ALERT_COUNT  1
+#define NET_DM_CFG_ALERT_DELAY 2
+#define NET_DM_CFG_MAX 3
+
+struct net_dm_config_entry {
+       __u32 type;
+       __u64 data __attribute__((aligned(8)));
+};
+
+struct net_dm_config_msg {
+       __u32 entries;
+       struct net_dm_config_entry options[0];
+};
+
+struct net_dm_alert_msg {
+       __u32 entries;
+       struct net_dm_drop_point points[0];
+};
+
+struct net_dm_user_msg {
+       union {
+               struct net_dm_config_msg user;
+               struct net_dm_alert_msg alert;
+       } u;
+};
+
+
+/* These are the netlink message types for this protocol */
+
+enum {
+       NET_DM_CMD_UNSPEC = 0,
+       NET_DM_CMD_ALERT,
+       NET_DM_CMD_CONFIG,
+       NET_DM_CMD_START,
+       NET_DM_CMD_STOP,
+       _NET_DM_CMD_MAX,
+};
+
+#define NET_DM_CMD_MAX (_NET_DM_CMD_MAX - 1)
+
+/*
+ * Our group identifiers
+ */
+#define NET_DM_GRP_ALERT 1
+#endif
index bd8b4ca85a2ab339888d126b15143df3a182b3a4..be3ebd7e8ce58d62d6c59c2a0b489017a4dc774e 100644 (file)
@@ -330,6 +330,14 @@ enum
        NAPI_STATE_NPSVC,       /* Netpoll - don't dequeue from poll_list */
 };
 
+enum {
+       GRO_MERGED,
+       GRO_MERGED_FREE,
+       GRO_HELD,
+       GRO_NORMAL,
+       GRO_DROP,
+};
+
 extern void __napi_schedule(struct napi_struct *n);
 
 static inline int napi_disable_pending(struct napi_struct *n)
@@ -1085,6 +1093,7 @@ extern void               synchronize_net(void);
 extern int             register_netdevice_notifier(struct notifier_block *nb);
 extern int             unregister_netdevice_notifier(struct notifier_block *nb);
 extern int             init_dummy_netdev(struct net_device *dev);
+extern void            netdev_resync_ops(struct net_device *dev);
 
 extern int call_netdevice_notifiers(unsigned long val, struct net_device *dev);
 extern struct net_device       *dev_get_by_index(struct net *net, int ifindex);
index cdcd0ed58f7aced31dd8f909452a9d7e2dcb1bd8..4b36aeb46a102a14f7b261cbbd00819243e920da 100644 (file)
@@ -2,7 +2,7 @@
 #define _XT_NFLOG_TARGET
 
 #define XT_NFLOG_DEFAULT_GROUP         0x1
-#define XT_NFLOG_DEFAULT_THRESHOLD     1
+#define XT_NFLOG_DEFAULT_THRESHOLD     0
 
 #define XT_NFLOG_MASK                  0x0
 
index 51b09a1f46c3bde1da65df6d096cbaa4b409c541..1e6bf995435c1f9b1ca444d706c7ecfb5b126638 100644 (file)
@@ -103,6 +103,7 @@ struct nlmsgerr
 #define NETLINK_ADD_MEMBERSHIP 1
 #define NETLINK_DROP_MEMBERSHIP        2
 #define NETLINK_PKTINFO                3
+#define NETLINK_BROADCAST_ERROR        4
 
 struct nl_pktinfo
 {
index e38d3c9dccda9471e62f0102a6e20c5a3140e032..de99025f2c5d5d6ba1fa48775ef6c51f203dd47a 100644 (file)
@@ -63,6 +63,13 @@ static inline int netpoll_rx(struct sk_buff *skb)
        return ret;
 }
 
+static inline int netpoll_rx_on(struct sk_buff *skb)
+{
+       struct netpoll_info *npinfo = skb->dev->npinfo;
+
+       return npinfo && (npinfo->rx_np || npinfo->rx_flags);
+}
+
 static inline int netpoll_receive_skb(struct sk_buff *skb)
 {
        if (!list_empty(&skb->dev->napi_list))
@@ -99,6 +106,10 @@ static inline int netpoll_rx(struct sk_buff *skb)
 {
        return 0;
 }
+static inline int netpoll_rx_on(struct sk_buff *skb)
+{
+       return 0;
+}
 static inline int netpoll_receive_skb(struct sk_buff *skb)
 {
        return 0;
index 8802d1bda382a1d674ce1ae29cf6f84fc1bb0cf3..f33aa08dd9b37d6a7b8e1414ec99022ada1673a1 100644 (file)
  * @NL80211_CMD_SCAN_ABORTED: scan was aborted, for unspecified reasons,
  *     partial scan results may be available
  *
+ * @NL80211_CMD_REG_CHANGE: indicates to userspace the regulatory domain
+ *     has been changed and provides details of the request information
+ *     that caused the change such as who initiated the regulatory request
+ *     (%NL80211_ATTR_REG_INITIATOR), the wiphy_idx
+ *     (%NL80211_ATTR_REG_ALPHA2) on which the request was made from if
+ *     the initiator was %NL80211_REGDOM_SET_BY_COUNTRY_IE or
+ *     %NL80211_REGDOM_SET_BY_DRIVER, the type of regulatory domain
+ *     set (%NL80211_ATTR_REG_TYPE), if the type of regulatory domain is
+ *     %NL80211_REG_TYPE_COUNTRY the alpha2 to which we have moved on
+ *     to (%NL80211_ATTR_REG_ALPHA2).
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -204,6 +215,8 @@ enum nl80211_commands {
        NL80211_CMD_NEW_SCAN_RESULTS,
        NL80211_CMD_SCAN_ABORTED,
 
+       NL80211_CMD_REG_CHANGE,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -218,6 +231,8 @@ enum nl80211_commands {
 #define NL80211_CMD_SET_BSS NL80211_CMD_SET_BSS
 #define NL80211_CMD_SET_MGMT_EXTRA_IE NL80211_CMD_SET_MGMT_EXTRA_IE
 
+#define NL80211_CMD_REG_CHANGE NL80211_CMD_REG_CHANGE
+
 /**
  * enum nl80211_attrs - nl80211 netlink attributes
  *
@@ -329,6 +344,11 @@ enum nl80211_commands {
  *     messages carried the same generation number)
  * @NL80211_ATTR_BSS: scan result BSS
  *
+ * @NL80211_ATTR_REG_INITIATOR: indicates who requested the regulatory domain
+ *     currently in effect. This could be any of the %NL80211_REGDOM_SET_BY_*
+ * @NL80211_ATTR_REG_TYPE: indicates the type of the regulatory domain currently
+ *     set. This can be one of the nl80211_reg_type (%NL80211_REGDOM_TYPE_*)
+ *
  * @NL80211_ATTR_MAX: highest attribute number currently defined
  * @__NL80211_ATTR_AFTER_LAST: internal use
  */
@@ -403,6 +423,9 @@ enum nl80211_attrs {
        NL80211_ATTR_SCAN_GENERATION,
        NL80211_ATTR_BSS,
 
+       NL80211_ATTR_REG_INITIATOR,
+       NL80211_ATTR_REG_TYPE,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -420,6 +443,8 @@ enum nl80211_attrs {
 #define NL80211_ATTR_WIPHY_CHANNEL_TYPE NL80211_ATTR_WIPHY_CHANNEL_TYPE
 #define NL80211_ATTR_MGMT_SUBTYPE NL80211_ATTR_MGMT_SUBTYPE
 #define NL80211_ATTR_IE NL80211_ATTR_IE
+#define NL80211_ATTR_REG_INITIATOR NL80211_ATTR_REG_INITIATOR
+#define NL80211_ATTR_REG_TYPE NL80211_ATTR_REG_TYPE
 
 #define NL80211_MAX_SUPP_RATES                 32
 #define NL80211_MAX_SUPP_REG_RULES             32
@@ -526,6 +551,9 @@ enum nl80211_rate_info {
  * @NL80211_STA_INFO_SIGNAL: signal strength of last received PPDU (u8, dBm)
  * @NL80211_STA_INFO_TX_BITRATE: current unicast tx rate, nested attribute
  *     containing info as possible, see &enum nl80211_sta_info_txrate.
+ * @NL80211_STA_INFO_RX_PACKETS: total received packet (u32, from this station)
+ * @NL80211_STA_INFO_TX_PACKETS: total transmitted packets (u32, to this
+ *     station)
  */
 enum nl80211_sta_info {
        __NL80211_STA_INFO_INVALID,
@@ -537,6 +565,8 @@ enum nl80211_sta_info {
        NL80211_STA_INFO_PLINK_STATE,
        NL80211_STA_INFO_SIGNAL,
        NL80211_STA_INFO_TX_BITRATE,
+       NL80211_STA_INFO_RX_PACKETS,
+       NL80211_STA_INFO_TX_PACKETS,
 
        /* keep last */
        __NL80211_STA_INFO_AFTER_LAST,
@@ -667,6 +697,48 @@ enum nl80211_bitrate_attr {
        NL80211_BITRATE_ATTR_MAX = __NL80211_BITRATE_ATTR_AFTER_LAST - 1
 };
 
+/**
+ * enum nl80211_initiator - Indicates the initiator of a reg domain request
+ * @NL80211_REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world
+ *     regulatory domain.
+ * @NL80211_REGDOM_SET_BY_USER: User asked the wireless core to set the
+ *     regulatory domain.
+ * @NL80211_REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the
+ *     wireless core it thinks its knows the regulatory domain we should be in.
+ * @NL80211_REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an
+ *     802.11 country information element with regulatory information it
+ *     thinks we should consider.
+ */
+enum nl80211_reg_initiator {
+       NL80211_REGDOM_SET_BY_CORE,
+       NL80211_REGDOM_SET_BY_USER,
+       NL80211_REGDOM_SET_BY_DRIVER,
+       NL80211_REGDOM_SET_BY_COUNTRY_IE,
+};
+
+/**
+ * enum nl80211_reg_type - specifies the type of regulatory domain
+ * @NL80211_REGDOM_TYPE_COUNTRY: the regulatory domain set is one that pertains
+ *     to a specific country. When this is set you can count on the
+ *     ISO / IEC 3166 alpha2 country code being valid.
+ * @NL80211_REGDOM_TYPE_WORLD: the regulatory set domain is the world regulatory
+ *     domain.
+ * @NL80211_REGDOM_TYPE_CUSTOM_WORLD: the regulatory domain set is a custom
+ *     driver specific world regulatory domain. These do not apply system-wide
+ *     and are only applicable to the individual devices which have requested
+ *     them to be applied.
+ * @NL80211_REGDOM_TYPE_INTERSECTION: the regulatory domain set is the product
+ *     of an intersection between two regulatory domains -- the previously
+ *     set regulatory domain on the system and the last accepted regulatory
+ *     domain request to be processed.
+ */
+enum nl80211_reg_type {
+       NL80211_REGDOM_TYPE_COUNTRY,
+       NL80211_REGDOM_TYPE_WORLD,
+       NL80211_REGDOM_TYPE_CUSTOM_WORLD,
+       NL80211_REGDOM_TYPE_INTERSECTION,
+};
+
 /**
  * enum nl80211_reg_rule_attr - regulatory rule attributes
  * @NL80211_ATTR_REG_RULE_FLAGS: a set of flags which specify additional
index 966e02332990443c3f8f010ca9db7cffc730dace..3f9687a71e322b9aa36a83792aca128788d7cc68 100644 (file)
 #define PCI_DEVICE_ID_VIA_VT3351       0x0351
 #define PCI_DEVICE_ID_VIA_VT3364       0x0364
 #define PCI_DEVICE_ID_VIA_8371_0       0x0391
+#define PCI_DEVICE_ID_VIA_6415         0x0415
 #define PCI_DEVICE_ID_VIA_8501_0       0x0501
 #define PCI_DEVICE_ID_VIA_82C561       0x0561
 #define PCI_DEVICE_ID_VIA_82C586_1     0x0571
 #define PCI_DEVICE_ID_DIGI_DF_M_E      0x0071
 #define PCI_DEVICE_ID_DIGI_DF_M_IOM2_A 0x0072
 #define PCI_DEVICE_ID_DIGI_DF_M_A      0x0073
+#define PCI_DEVICE_ID_DIGI_NEO_8       0x00B1
 #define PCI_DEVICE_ID_NEO_2DB9          0x00C8
 #define PCI_DEVICE_ID_NEO_2DB9PRI       0x00C9
 #define PCI_DEVICE_ID_NEO_2RJ45         0x00CA
 #define PCI_DEVICE_ID_INTEL_82378      0x0484
 #define PCI_DEVICE_ID_INTEL_I960       0x0960
 #define PCI_DEVICE_ID_INTEL_I960RM     0x0962
+#define PCI_DEVICE_ID_INTEL_8257X_SOL  0x1062
+#define PCI_DEVICE_ID_INTEL_82573E_SOL 0x1085
+#define PCI_DEVICE_ID_INTEL_82573L_SOL 0x108F
 #define PCI_DEVICE_ID_INTEL_82815_MC   0x1130
 #define PCI_DEVICE_ID_INTEL_82815_CGC  0x1132
 #define PCI_DEVICE_ID_INTEL_82092AA_0  0x1221
index d7e54d98869f8881666d927caf956074d42b4f97..32cf14a4b034aac659f89286821e553b0955b255 100644 (file)
@@ -315,8 +315,7 @@ struct phy_device {
 
        /* Interrupt and Polling infrastructure */
        struct work_struct phy_queue;
-       struct work_struct state_queue;
-       struct timer_list phy_timer;
+       struct delayed_work state_queue;
        atomic_t irq_disable;
 
        struct mutex lock;
index de2e0a8f6728c668a2005ee3b36147a3b3caeec6..24ba5f67b3a3a590480b6ad32b62326be2156c9f 100644 (file)
@@ -381,10 +381,12 @@ struct dev_pm_info {
 
 #ifdef CONFIG_PM_SLEEP
 extern void device_pm_lock(void);
+extern int sysdev_resume(void);
 extern void device_power_up(pm_message_t state);
 extern void device_resume(pm_message_t state);
 
 extern void device_pm_unlock(void);
+extern int sysdev_suspend(pm_message_t state);
 extern int device_power_down(pm_message_t state);
 extern int device_suspend(pm_message_t state);
 extern int device_prepare_suspend(pm_message_t state);
index 9d64bdf147703560d3065cac35b0853b95e7f75b..0d3fa63e90ea28fc8494447aaeaa5eda27bb38c4 100644 (file)
@@ -40,8 +40,8 @@ struct ppp_channel {
        int             mtu;            /* max transmit packet size */
        int             hdrlen;         /* amount of headroom channel needs */
        void            *ppp;           /* opaque to channel */
-       /* the following are not used at present */
        int             speed;          /* transfer rate (bytes/second) */
+       /* the following is not used at present */
        int             latency;        /* overhead time in milliseconds */
 };
 
index f3f697df1d71b439b677efbc0da952ae6d25d066..80044a4f3ab9e1c890021fc0ff9dca533c00f71e 100644 (file)
@@ -181,4 +181,10 @@ extern long rcu_batches_completed_bh(void);
 #define rcu_enter_nohz()       do { } while (0)
 #define rcu_exit_nohz()                do { } while (0)
 
+/* A context switch is a grace period for rcuclassic. */
+static inline int rcu_blocking_is_gp(void)
+{
+       return num_online_cpus() == 1;
+}
+
 #endif /* __LINUX_RCUCLASSIC_H */
index 921340a7b71cf4c88638e2f905aa0fdc1385f958..528343e6da51a7c19cda8797c55cd6640612cb58 100644 (file)
@@ -52,6 +52,9 @@ struct rcu_head {
        void (*func)(struct rcu_head *head);
 };
 
+/* Internal to kernel, but needed by rcupreempt.h. */
+extern int rcu_scheduler_active;
+
 #if defined(CONFIG_CLASSIC_RCU)
 #include <linux/rcuclassic.h>
 #elif defined(CONFIG_TREE_RCU)
@@ -265,6 +268,7 @@ extern void rcu_barrier_sched(void);
 
 /* Internal to kernel */
 extern void rcu_init(void);
+extern void rcu_scheduler_starting(void);
 extern int rcu_needs_cpu(int cpu);
 
 #endif /* __LINUX_RCUPDATE_H */
index 3e05c09b54a22408db83e0f0a87a5a8bf9a40e8f..74304b4538d833ec7bcd26be28bdec8f436d73f7 100644 (file)
@@ -142,4 +142,19 @@ static inline void rcu_exit_nohz(void)
 #define rcu_exit_nohz()                do { } while (0)
 #endif /* CONFIG_NO_HZ */
 
+/*
+ * A context switch is a grace period for rcupreempt synchronize_rcu()
+ * only during early boot, before the scheduler has been initialized.
+ * So, how the heck do we get a context switch?  Well, if the caller
+ * invokes synchronize_rcu(), they are willing to accept a context
+ * switch, so we simply pretend that one happened.
+ *
+ * After boot, there might be a blocked or preempted task in an RCU
+ * read-side critical section, so we cannot then take the fastpath.
+ */
+static inline int rcu_blocking_is_gp(void)
+{
+       return num_online_cpus() == 1 && !rcu_scheduler_active;
+}
+
 #endif /* __LINUX_RCUPREEMPT_H */
index d4368b7975c3d09d5b1c08d2a822adebb06e62ac..a722fb67bb2d5a2500852c4fd5593f0e91777af0 100644 (file)
@@ -326,4 +326,10 @@ static inline void rcu_exit_nohz(void)
 }
 #endif /* CONFIG_NO_HZ */
 
+/* A context switch is a grace period for rcutree. */
+static inline int rcu_blocking_is_gp(void)
+{
+       return num_online_cpus() == 1;
+}
+
 #endif /* __LINUX_RCUTREE_H */
diff --git a/include/linux/rds.h b/include/linux/rds.h
new file mode 100644 (file)
index 0000000..d91dc91
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Copyright (c) 2008 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+
+#ifndef _LINUX_RDS_H
+#define _LINUX_RDS_H
+
+#include <linux/types.h>
+
+/* These sparse annotated types shouldn't be in any user
+ * visible header file. We should clean this up rather
+ * than kludging around them. */
+#ifndef __KERNEL__
+#define __be16 u_int16_t
+#define __be32 u_int32_t
+#define __be64 u_int64_t
+#endif
+
+#define RDS_IB_ABI_VERSION             0x301
+
+/*
+ * setsockopt/getsockopt for SOL_RDS
+ */
+#define RDS_CANCEL_SENT_TO             1
+#define RDS_GET_MR                     2
+#define RDS_FREE_MR                    3
+/* deprecated: RDS_BARRIER 4 */
+#define RDS_RECVERR                    5
+#define RDS_CONG_MONITOR               6
+
+/*
+ * Control message types for SOL_RDS.
+ *
+ * CMSG_RDMA_ARGS (sendmsg)
+ *     Request a RDMA transfer to/from the specified
+ *     memory ranges.
+ *     The cmsg_data is a struct rds_rdma_args.
+ * RDS_CMSG_RDMA_DEST (recvmsg, sendmsg)
+ *     Kernel informs application about intended
+ *     source/destination of a RDMA transfer
+ * RDS_CMSG_RDMA_MAP (sendmsg)
+ *     Application asks kernel to map the given
+ *     memory range into a IB MR, and send the
+ *     R_Key along in an RDS extension header.
+ *     The cmsg_data is a struct rds_get_mr_args,
+ *     the same as for the GET_MR setsockopt.
+ * RDS_CMSG_RDMA_STATUS (recvmsg)
+ *     Returns the status of a completed RDMA operation.
+ */
+#define RDS_CMSG_RDMA_ARGS             1
+#define RDS_CMSG_RDMA_DEST             2
+#define RDS_CMSG_RDMA_MAP              3
+#define RDS_CMSG_RDMA_STATUS           4
+#define RDS_CMSG_CONG_UPDATE           5
+
+#define RDS_INFO_FIRST                 10000
+#define RDS_INFO_COUNTERS              10000
+#define RDS_INFO_CONNECTIONS           10001
+/* 10002 aka RDS_INFO_FLOWS is deprecated */
+#define RDS_INFO_SEND_MESSAGES         10003
+#define RDS_INFO_RETRANS_MESSAGES       10004
+#define RDS_INFO_RECV_MESSAGES          10005
+#define RDS_INFO_SOCKETS                10006
+#define RDS_INFO_TCP_SOCKETS            10007
+#define RDS_INFO_IB_CONNECTIONS                10008
+#define RDS_INFO_CONNECTION_STATS      10009
+#define RDS_INFO_IWARP_CONNECTIONS     10010
+#define RDS_INFO_LAST                  10010
+
+struct rds_info_counter {
+       u_int8_t        name[32];
+       u_int64_t       value;
+} __attribute__((packed));
+
+#define RDS_INFO_CONNECTION_FLAG_SENDING       0x01
+#define RDS_INFO_CONNECTION_FLAG_CONNECTING    0x02
+#define RDS_INFO_CONNECTION_FLAG_CONNECTED     0x04
+
+#define TRANSNAMSIZ    16
+
+struct rds_info_connection {
+       u_int64_t       next_tx_seq;
+       u_int64_t       next_rx_seq;
+       __be32          laddr;
+       __be32          faddr;
+       u_int8_t        transport[TRANSNAMSIZ];         /* null term ascii */
+       u_int8_t        flags;
+} __attribute__((packed));
+
+struct rds_info_flow {
+       __be32          laddr;
+       __be32          faddr;
+       u_int32_t       bytes;
+       __be16          lport;
+       __be16          fport;
+} __attribute__((packed));
+
+#define RDS_INFO_MESSAGE_FLAG_ACK               0x01
+#define RDS_INFO_MESSAGE_FLAG_FAST_ACK          0x02
+
+struct rds_info_message {
+       u_int64_t       seq;
+       u_int32_t       len;
+       __be32          laddr;
+       __be32          faddr;
+       __be16          lport;
+       __be16          fport;
+       u_int8_t        flags;
+} __attribute__((packed));
+
+struct rds_info_socket {
+       u_int32_t       sndbuf;
+       __be32          bound_addr;
+       __be32          connected_addr;
+       __be16          bound_port;
+       __be16          connected_port;
+       u_int32_t       rcvbuf;
+       u_int64_t       inum;
+} __attribute__((packed));
+
+#define RDS_IB_GID_LEN 16
+struct rds_info_rdma_connection {
+       __be32          src_addr;
+       __be32          dst_addr;
+       uint8_t         src_gid[RDS_IB_GID_LEN];
+       uint8_t         dst_gid[RDS_IB_GID_LEN];
+
+       uint32_t        max_send_wr;
+       uint32_t        max_recv_wr;
+       uint32_t        max_send_sge;
+       uint32_t        rdma_mr_max;
+       uint32_t        rdma_mr_size;
+};
+
+/*
+ * Congestion monitoring.
+ * Congestion control in RDS happens at the host connection
+ * level by exchanging a bitmap marking congested ports.
+ * By default, a process sleeping in poll() is always woken
+ * up when the congestion map is updated.
+ * With explicit monitoring, an application can have more
+ * fine-grained control.
+ * The application installs a 64bit mask value in the socket,
+ * where each bit corresponds to a group of ports.
+ * When a congestion update arrives, RDS checks the set of
+ * ports that are now uncongested against the list bit mask
+ * installed in the socket, and if they overlap, we queue a
+ * cong_notification on the socket.
+ *
+ * To install the congestion monitor bitmask, use RDS_CONG_MONITOR
+ * with the 64bit mask.
+ * Congestion updates are received via RDS_CMSG_CONG_UPDATE
+ * control messages.
+ *
+ * The correspondence between bits and ports is
+ *     1 << (portnum % 64)
+ */
+#define RDS_CONG_MONITOR_SIZE  64
+#define RDS_CONG_MONITOR_BIT(port)  (((unsigned int) port) % RDS_CONG_MONITOR_SIZE)
+#define RDS_CONG_MONITOR_MASK(port) (1ULL << RDS_CONG_MONITOR_BIT(port))
+
+/*
+ * RDMA related types
+ */
+
+/*
+ * This encapsulates a remote memory location.
+ * In the current implementation, it contains the R_Key
+ * of the remote memory region, and the offset into it
+ * (so that the application does not have to worry about
+ * alignment).
+ */
+typedef u_int64_t      rds_rdma_cookie_t;
+
+struct rds_iovec {
+       u_int64_t       addr;
+       u_int64_t       bytes;
+};
+
+struct rds_get_mr_args {
+       struct rds_iovec vec;
+       u_int64_t       cookie_addr;
+       uint64_t        flags;
+};
+
+struct rds_free_mr_args {
+       rds_rdma_cookie_t cookie;
+       u_int64_t       flags;
+};
+
+struct rds_rdma_args {
+       rds_rdma_cookie_t cookie;
+       struct rds_iovec remote_vec;
+       u_int64_t       local_vec_addr;
+       u_int64_t       nr_local;
+       u_int64_t       flags;
+       u_int64_t       user_token;
+};
+
+struct rds_rdma_notify {
+       u_int64_t       user_token;
+       int32_t         status;
+};
+
+#define RDS_RDMA_SUCCESS       0
+#define RDS_RDMA_REMOTE_ERROR  1
+#define RDS_RDMA_CANCELED      2
+#define RDS_RDMA_DROPPED       3
+#define RDS_RDMA_OTHER_ERROR   4
+
+/*
+ * Common set of flags for all RDMA related structs
+ */
+#define RDS_RDMA_READWRITE     0x0001
+#define RDS_RDMA_FENCE         0x0002  /* use FENCE for immediate send */
+#define RDS_RDMA_INVALIDATE    0x0004  /* invalidate R_Key after freeing MR */
+#define RDS_RDMA_USE_ONCE      0x0008  /* free MR after use */
+#define RDS_RDMA_DONTWAIT      0x0010  /* Don't wait in SET_BARRIER */
+#define RDS_RDMA_NOTIFY_ME     0x0020  /* Notify when operation completes */
+
+#endif /* IB_RDS_H */
index 1e5f6730ff31f412b65b731a5c7b375e4ddf0046..ba3254ecf7fbf12fa14edf4141aac0393b1cad3a 100644 (file)
@@ -217,6 +217,7 @@ enum
 #define RTPROT_DNROUTED        13      /* DECnet routing daemon */
 #define RTPROT_XORP    14      /* XORP */
 #define RTPROT_NTK     15      /* Netsukuku */
+#define RTPROT_DHCP    16      /* DHCP client */
 
 /* rtm_scope
 
@@ -622,8 +623,8 @@ static __inline__ int rtattr_strcmp(const struct rtattr *rta, const char *str)
 
 extern int rtnetlink_send(struct sk_buff *skb, struct net *net, u32 pid, u32 group, int echo);
 extern int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid);
-extern int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
-                      struct nlmsghdr *nlh, gfp_t flags);
+extern void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid,
+                       u32 group, struct nlmsghdr *nlh, gfp_t flags);
 extern void rtnl_set_sk_err(struct net *net, u32 group, int error);
 extern int rtnetlink_put_metrics(struct sk_buff *skb, u32 *metrics);
 extern int rtnl_put_cacheinfo(struct sk_buff *skb, struct dst_entry *dst,
index 8981e52c714f05f19ad5727031058509e06bf6a8..8c216e057c94230ea01c110b0f5bc2c28e8f9ee3 100644 (file)
@@ -2291,9 +2291,13 @@ extern long sched_group_rt_runtime(struct task_group *tg);
 extern int sched_group_set_rt_period(struct task_group *tg,
                                      long rt_period_us);
 extern long sched_group_rt_period(struct task_group *tg);
+extern int sched_rt_can_attach(struct task_group *tg, struct task_struct *tsk);
 #endif
 #endif
 
+extern int task_can_switch_user(struct user_struct *up,
+                                       struct task_struct *tsk);
+
 #ifdef CONFIG_TASK_XACCT
 static inline void add_rchar(struct task_struct *tsk, ssize_t amt)
 {
index 40ea5058c2ec0ced97079290c08cd5bac08d1dca..f616f31576d719597cd91b25498fece72e24cc8d 100644 (file)
@@ -19,6 +19,7 @@ struct seq_file {
        size_t from;
        size_t count;
        loff_t index;
+       loff_t read_pos;
        u64 version;
        struct mutex lock;
        const struct seq_operations *op;
index 90bbbf0b1161bd592a19c1b2cc3f6803776c53df..df9245c7bd3be3b384146434a0494eea946225dd 100644 (file)
@@ -296,6 +296,7 @@ struct uart_port {
 #define UPF_HARDPPS_CD         ((__force upf_t) (1 << 11))
 #define UPF_LOW_LATENCY                ((__force upf_t) (1 << 13))
 #define UPF_BUGGY_UART         ((__force upf_t) (1 << 14))
+#define UPF_NO_TXEN_TEST       ((__force upf_t) (1 << 15))
 #define UPF_MAGIC_MULTIPLIER   ((__force upf_t) (1 << 16))
 #define UPF_CONS_FLOW          ((__force upf_t) (1 << 23))
 #define UPF_SHARE_IRQ          ((__force upf_t) (1 << 24))
index f96bc91bf0a359099e3b91ba1e210e453b339434..bb1981fd60f3596f89a4c2a363f19583e3dac019 100644 (file)
@@ -135,8 +135,7 @@ struct skb_frag_struct {
 #define HAVE_HW_TIME_STAMP
 
 /**
- * skb_shared_hwtstamps - hardware time stamps
- *
+ * struct skb_shared_hwtstamps - hardware time stamps
  * @hwtstamp:  hardware time stamp transformed into duration
  *             since arbitrary point in time
  * @syststamp: hwtstamp transformed to system time base
@@ -164,8 +163,7 @@ struct skb_shared_hwtstamps {
 };
 
 /**
- * skb_shared_tx - instructions for time stamping of outgoing packets
- *
+ * struct skb_shared_tx - instructions for time stamping of outgoing packets
  * @hardware:          generate hardware time stamp
  * @software:          generate software time stamp
  * @in_progress:       device driver is going to provide
@@ -423,6 +421,7 @@ extern void skb_dma_unmap(struct device *dev, struct sk_buff *skb,
 #endif
 
 extern void kfree_skb(struct sk_buff *skb);
+extern void consume_skb(struct sk_buff *skb);
 extern void           __kfree_skb(struct sk_buff *skb);
 extern struct sk_buff *__alloc_skb(unsigned int size,
                                   gfp_t priority, int fclone, int node);
@@ -461,20 +460,12 @@ extern int               skb_to_sgvec(struct sk_buff *skb,
 extern int            skb_cow_data(struct sk_buff *skb, int tailbits,
                                    struct sk_buff **trailer);
 extern int            skb_pad(struct sk_buff *skb, int pad);
-#define dev_kfree_skb(a)       kfree_skb(a)
+#define dev_kfree_skb(a)       consume_skb(a)
+#define dev_consume_skb(a)     kfree_skb_clean(a)
 extern void          skb_over_panic(struct sk_buff *skb, int len,
                                     void *here);
 extern void          skb_under_panic(struct sk_buff *skb, int len,
                                      void *here);
-extern void          skb_truesize_bug(struct sk_buff *skb);
-
-static inline void skb_truesize_check(struct sk_buff *skb)
-{
-       int len = sizeof(struct sk_buff) + skb->len;
-
-       if (unlikely((int)skb->truesize < len))
-               skb_truesize_bug(skb);
-}
 
 extern int skb_append_datato_frags(struct sock *sk, struct sk_buff *skb,
                        int getfrag(void *from, char *to, int offset,
@@ -1978,7 +1969,7 @@ static inline void skb_set_queue_mapping(struct sk_buff *skb, u16 queue_mapping)
        skb->queue_mapping = queue_mapping;
 }
 
-static inline u16 skb_get_queue_mapping(struct sk_buff *skb)
+static inline u16 skb_get_queue_mapping(const struct sk_buff *skb)
 {
        return skb->queue_mapping;
 }
@@ -1993,16 +1984,19 @@ static inline void skb_record_rx_queue(struct sk_buff *skb, u16 rx_queue)
        skb->queue_mapping = rx_queue + 1;
 }
 
-static inline u16 skb_get_rx_queue(struct sk_buff *skb)
+static inline u16 skb_get_rx_queue(const struct sk_buff *skb)
 {
        return skb->queue_mapping - 1;
 }
 
-static inline bool skb_rx_queue_recorded(struct sk_buff *skb)
+static inline bool skb_rx_queue_recorded(const struct sk_buff *skb)
 {
        return (skb->queue_mapping != 0);
 }
 
+extern u16 skb_tx_hash(const struct net_device *dev,
+                      const struct sk_buff *skb);
+
 #ifdef CONFIG_XFRM
 static inline struct sec_path *skb_sec_path(struct sk_buff *skb)
 {
index f96d13c281e81d03bf0b791ccb10b1a918e12055..24c5602bee99d268f2a1fd29238279d6c9bb3db3 100644 (file)
@@ -127,6 +127,7 @@ int kmem_ptr_validate(struct kmem_cache *cachep, const void *ptr);
 void * __must_check __krealloc(const void *, size_t, gfp_t);
 void * __must_check krealloc(const void *, size_t, gfp_t);
 void kfree(const void *);
+void kzfree(const void *);
 size_t ksize(const void *);
 
 /*
index 20fc4bbfca42b4327c346fd1f491661838062e34..9c90dc403efc0b05d00f3fa366cf7f492c71907b 100644 (file)
@@ -179,6 +179,7 @@ struct ucred {
 #define AF_ASH         18      /* Ash                          */
 #define AF_ECONET      19      /* Acorn Econet                 */
 #define AF_ATMSVC      20      /* ATM SVCs                     */
+#define AF_RDS         21      /* RDS sockets                  */
 #define AF_SNA         22      /* Linux SNA Project (nutters!) */
 #define AF_IRDA                23      /* IRDA sockets                 */
 #define AF_PPPOX       24      /* PPPoX sockets                */
@@ -217,6 +218,7 @@ struct ucred {
 #define PF_ASH         AF_ASH
 #define PF_ECONET      AF_ECONET
 #define PF_ATMSVC      AF_ATMSVC
+#define PF_RDS         AF_RDS
 #define PF_SNA         AF_SNA
 #define PF_IRDA                AF_IRDA
 #define PF_PPPOX       AF_PPPOX
@@ -298,6 +300,7 @@ struct ucred {
 #define SOL_PPPOL2TP   273
 #define SOL_BLUETOOTH  274
 #define SOL_PNPIPE     275
+#define SOL_RDS                276
 
 /* IPX options */
 #define IPX_TYPE       1
index bf8de281b4ed2a8e8131d34274711f81520d70f6..eed4254bd503f639f7a161dac634f3f68a93d9ed 100644 (file)
@@ -83,6 +83,13 @@ extern int spi_bitbang_stop(struct spi_bitbang *spi);
  *  int getmiso(struct spi_device *);
  *  void spidelay(unsigned);
  *
+ * setsck()'s is_on parameter is a zero/nonzero boolean.
+ *
+ * setmosi()'s is_on parameter is a zero/nonzero boolean.
+ *
+ * getmiso() is required to return 0 or 1 only. Any other value is invalid
+ * and will result in improper operation.
+ *
  * A non-inlined routine would call bitbang_txrx_*() routines.  The
  * main loop could easily compile down to a handful of instructions,
  * especially if the delay is a NOP (to run at peak speed).
index 17d9b58f637991d4c3b91eb445c5c37c3c40dc98..5ae8fa22d331922e6fc84db7269bb0b891f2e44b 100644 (file)
@@ -339,6 +339,10 @@ extern int ssb_bus_pcmciabus_register(struct ssb_bus *bus,
 
 extern void ssb_bus_unregister(struct ssb_bus *bus);
 
+/* Set a fallback SPROM.
+ * See kdoc at the function definition for complete documentation. */
+extern int ssb_arch_set_fallback_sprom(const struct ssb_sprom *sprom);
+
 /* Suspend a SSB bus.
  * Call this from the parent bus suspend routine. */
 extern int ssb_bus_suspend(struct ssb_bus *bus);
index 0cd99e6baca5b4cb947672483ba4d128274358b5..9d5078bd23a38a08285e81d4d4e63407646ff873 100644 (file)
@@ -218,7 +218,6 @@ struct tcp_options_received {
                snd_wscale : 4, /* Window scaling received from sender  */
                rcv_wscale : 4; /* Window scaling to send to receiver   */
 /*     SACKs data      */
-       u8      eff_sacks;      /* Size of SACK array to send with next packet */
        u8      num_sacks;      /* Number of SACK blocks                */
        u16     user_mss;       /* mss requested by user in ioctl */
        u16     mss_clamp;      /* Maximal mss, negotiated at connection setup */
@@ -249,7 +248,7 @@ struct tcp_sock {
        /* inet_connection_sock has to be the first member of tcp_sock */
        struct inet_connection_sock     inet_conn;
        u16     tcp_header_len; /* Bytes of tcp header to send          */
-       u16     xmit_size_goal; /* Goal for segmenting output packets   */
+       u16     xmit_size_goal_segs; /* Goal for segmenting output packets */
 
 /*
  *     Header prediction flags
index 86cb0501d3e20428b749eb2156bf5abc301e1c20..2d0792983f8c2d7500b8e7a595b48b36ff6579f2 100644 (file)
 /* For O_CLOEXEC and O_NONBLOCK */
 #include <linux/fcntl.h>
 
-/* Flags for timerfd_settime.  */
+/*
+ * CAREFUL: Check include/asm-generic/fcntl.h when defining
+ * new flags, since they might collide with O_* ones. We want
+ * to re-use O_* flags that couldn't possibly have a meaning
+ * from eventfd, in order to leave a free define-space for
+ * shared O_* flags.
+ */
 #define TFD_TIMER_ABSTIME (1 << 0)
-
-/* Flags for timerfd_create.  */
 #define TFD_CLOEXEC O_CLOEXEC
 #define TFD_NONBLOCK O_NONBLOCK
 
+#define TFD_SHARED_FCNTL_FLAGS (TFD_CLOEXEC | TFD_NONBLOCK)
+/* Flags for timerfd_create.  */
+#define TFD_CREATE_FLAGS TFD_SHARED_FCNTL_FLAGS
+/* Flags for timerfd_settime.  */
+#define TFD_SETTIME_FLAGS TFD_TIMER_ABSTIME
 
 #endif /* _LINUX_TIMERFD_H */
-
index 7d38222430741f5e78e5ec26e9bffb8ccff11af8..36fabb95c7d38f073de7536ebb1956687441198f 100644 (file)
@@ -176,6 +176,11 @@ struct skb_data {  /* skb->cb is one of these */
        size_t                  length;
 };
 
+extern int usbnet_open (struct net_device *net);
+extern int usbnet_stop (struct net_device *net);
+extern int usbnet_start_xmit (struct sk_buff *skb, struct net_device *net);
+extern void usbnet_tx_timeout (struct net_device *net);
+extern int usbnet_change_mtu (struct net_device *net, int new_mtu);
 
 extern int usbnet_get_endpoints(struct usbnet *, struct usb_interface *);
 extern void usbnet_defer_kevent (struct usbnet *, int);
index 315bcd375224869a0e54cbaab27274588452d4d3..cc4f45361dbbc8a956f9a9fad2a865dc7f4add33 100644 (file)
@@ -13,6 +13,7 @@ struct user_namespace {
        struct kref             kref;
        struct hlist_head       uidhash_table[UIDHASH_SZ];
        struct user_struct      *creator;
+       struct work_struct      destroyer;
 };
 
 extern struct user_namespace init_user_ns;
index 506e7620a986332cf5fda9e04d04050a88a49129..9c0890c7a06a357dd62e12cde059ca86764f8efa 100644 (file)
@@ -84,6 +84,10 @@ extern struct vm_struct *get_vm_area_caller(unsigned long size,
                                        unsigned long flags, void *caller);
 extern struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
                                        unsigned long start, unsigned long end);
+extern struct vm_struct *__get_vm_area_caller(unsigned long size,
+                                       unsigned long flags,
+                                       unsigned long start, unsigned long end,
+                                       void *caller);
 extern struct vm_struct *get_vm_area_node(unsigned long size,
                                          unsigned long flags, int node,
                                          gfp_t gfp_mask);
index ba0c49399a8345ce2b82c0583d462d46f66fb797..c703e034042371732ad3591bc9800fe4b213e1f5 100644 (file)
@@ -178,7 +178,7 @@ void __d_head(char *head, size_t head_size,
                WARN_ON(1);
        } else
                snprintf(head, head_size, "%s %s: ",
-                        dev_driver_string(dev), dev->bus_id);
+                        dev_driver_string(dev), dev_name(dev));
 }
 
 
index 74198f5bb4dc926186865453f568dff2d634e894..d5148a7889a6350f43b4bae0ae757545fd1621e6 100644 (file)
@@ -207,6 +207,7 @@ enum i2400m_pt {
        I2400M_PT_TRACE,        /* For device debug */
        I2400M_PT_RESET_WARM,   /* device reset */
        I2400M_PT_RESET_COLD,   /* USB[transport] reset, like reconnect */
+       I2400M_PT_EDATA,        /* Extended RX data */
        I2400M_PT_ILLEGAL
 };
 
@@ -221,6 +222,48 @@ struct i2400m_pl_data_hdr {
 } __attribute__((packed));
 
 
+/*
+ * Payload for an extended data packet
+ *
+ * New in fw v1.4
+ *
+ * @reorder: if this payload has to be reorder or not (and how)
+ * @cs: the type of data in the packet, as defined per (802.16e
+ *     T11.13.19.1). Currently only 2 (IPv4 packet) supported.
+ *
+ * This is prefixed to each and every INCOMING DATA packet.
+ */
+struct i2400m_pl_edata_hdr {
+       __le32 reorder;         /* bits defined in i2400m_ro */
+       __u8 cs;
+       __u8 reserved[11];
+} __attribute__((packed));
+
+enum i2400m_cs {
+       I2400M_CS_IPV4_0 = 0,
+       I2400M_CS_IPV4 = 2,
+};
+
+enum i2400m_ro {
+       I2400M_RO_NEEDED     = 0x01,
+       I2400M_RO_TYPE       = 0x03,
+       I2400M_RO_TYPE_SHIFT = 1,
+       I2400M_RO_CIN        = 0x0f,
+       I2400M_RO_CIN_SHIFT  = 4,
+       I2400M_RO_FBN        = 0x07ff,
+       I2400M_RO_FBN_SHIFT  = 8,
+       I2400M_RO_SN         = 0x07ff,
+       I2400M_RO_SN_SHIFT   = 21,
+};
+
+enum i2400m_ro_type {
+       I2400M_RO_TYPE_RESET = 0,
+       I2400M_RO_TYPE_PACKET,
+       I2400M_RO_TYPE_WS,
+       I2400M_RO_TYPE_PACKET_WS,
+};
+
+
 /* Misc constants */
 enum {
        I2400M_PL_PAD = 16,     /* Payload data size alignment */
@@ -381,6 +424,9 @@ enum i2400m_tlv {
        I2400M_TLV_RF_STATUS = 163,
        I2400M_TLV_DEVICE_RESET_TYPE = 132,
        I2400M_TLV_CONFIG_IDLE_PARAMETERS = 601,
+       I2400M_TLV_CONFIG_IDLE_TIMEOUT = 611,
+       I2400M_TLV_CONFIG_D2H_DATA_FORMAT = 614,
+       I2400M_TLV_CONFIG_DL_HOST_REORDER = 615,
 };
 
 
@@ -509,4 +555,27 @@ struct i2400m_tlv_media_status {
        __le32 media_status;
 } __attribute__((packed));
 
+
+/* New in v1.4 */
+struct i2400m_tlv_config_idle_timeout {
+       struct i2400m_tlv_hdr hdr;
+       __le32 timeout; /* 100 to 300000 ms [5min], 100 increments
+                        * 0 disabled */
+} __attribute__((packed));
+
+/* New in v1.4 -- for backward compat, will be removed */
+struct i2400m_tlv_config_d2h_data_format {
+       struct i2400m_tlv_hdr hdr;
+       __u8 format;            /* 0 old format, 1 enhanced */
+       __u8 reserved[3];
+} __attribute__((packed));
+
+/* New in v1.4 */
+struct i2400m_tlv_config_dl_host_reorder {
+       struct i2400m_tlv_hdr hdr;
+       __u8 reorder;           /* 0 disabled, 1 enabled */
+       __u8 reserved[3];
+} __attribute__((packed));
+
+
 #endif /* #ifndef __LINUX__WIMAX__I2400M_H__ */
index a04f8463ac7eec813cba0f9dfcb23e0e484036a5..3ad5390a4dd5b61f8abbaeab00ba50d0cd17b07e 100644 (file)
 #define SOL_SCO                17
 #define SOL_RFCOMM     18
 
+#define BT_SECURITY    4
+struct bt_security {
+       __u8 level;
+};
+#define BT_SECURITY_SDP                0
+#define BT_SECURITY_LOW                1
+#define BT_SECURITY_MEDIUM     2
+#define BT_SECURITY_HIGH       3
+
+#define BT_DEFER_SETUP 7
+
 #define BT_INFO(fmt, arg...) printk(KERN_INFO "Bluetooth: " fmt "\n" , ## arg)
 #define BT_ERR(fmt, arg...)  printk(KERN_ERR "%s: " fmt "\n" , __func__ , ## arg)
 #define BT_DBG(fmt, arg...)  pr_debug("%s: " fmt "\n" , __func__ , ## arg)
@@ -108,6 +119,7 @@ struct bt_sock {
        bdaddr_t    dst;
        struct list_head accept_q;
        struct sock *parent;
+       u32 defer_setup;
 };
 
 struct bt_sock_list {
index 3645139e68c7d804dc53132435934f3325bb40f2..f69f015bbcc0093f7b11b5fb645bad6b5e2529d6 100644 (file)
@@ -133,8 +133,13 @@ enum {
 #define ESCO_EV3       0x0008
 #define ESCO_EV4       0x0010
 #define ESCO_EV5       0x0020
+#define ESCO_2EV3      0x0040
+#define ESCO_3EV3      0x0080
+#define ESCO_2EV5      0x0100
+#define ESCO_3EV5      0x0200
 
 #define SCO_ESCO_MASK  (ESCO_HV1 | ESCO_HV2 | ESCO_HV3)
+#define EDR_ESCO_MASK  (ESCO_2EV3 | ESCO_3EV3 | ESCO_2EV5 | ESCO_3EV5)
 
 /* ACL flags */
 #define ACL_CONT               0x01
@@ -176,6 +181,9 @@ enum {
 #define LMP_EV5                0x02
 
 #define LMP_SNIFF_SUBR 0x02
+#define LMP_EDR_ESCO_2M        0x20
+#define LMP_EDR_ESCO_3M        0x40
+#define LMP_EDR_3S_ESCO        0x80
 
 #define LMP_SIMPLE_PAIR        0x08
 
index 46a43b721dd6a104ed3252f211d9dfaa2b3d36e9..01f9316b4c23259caa5f227e1a3e292c6f2eadbd 100644 (file)
@@ -169,6 +169,7 @@ struct hci_conn {
        __u16            link_policy;
        __u32            link_mode;
        __u8             auth_type;
+       __u8             sec_level;
        __u8             power_save;
        unsigned long    pend;
 
@@ -325,12 +326,11 @@ int hci_conn_del(struct hci_conn *conn);
 void hci_conn_hash_flush(struct hci_dev *hdev);
 void hci_conn_check_pending(struct hci_dev *hdev);
 
-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 auth_type);
+struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type);
 int hci_conn_check_link_mode(struct hci_conn *conn);
-int hci_conn_auth(struct hci_conn *conn);
-int hci_conn_encrypt(struct hci_conn *conn);
+int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type);
 int hci_conn_change_link_key(struct hci_conn *conn);
-int hci_conn_switch_role(struct hci_conn *conn, uint8_t role);
+int hci_conn_switch_role(struct hci_conn *conn, __u8 role);
 
 void hci_conn_enter_active_mode(struct hci_conn *conn);
 void hci_conn_enter_sniff_mode(struct hci_conn *conn);
@@ -470,26 +470,26 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 
 /* ----- HCI protocols ----- */
 struct hci_proto {
-       char            *name;
+       char            *name;
        unsigned int    id;
        unsigned long   flags;
 
        void            *priv;
 
-       int (*connect_ind)      (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type);
+       int (*connect_ind)      (struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type);
        int (*connect_cfm)      (struct hci_conn *conn, __u8 status);
-       int (*disconn_ind)      (struct hci_conn *conn, __u8 reason);
+       int (*disconn_ind)      (struct hci_conn *conn);
+       int (*disconn_cfm)      (struct hci_conn *conn, __u8 reason);
        int (*recv_acldata)     (struct hci_conn *conn, struct sk_buff *skb, __u16 flags);
        int (*recv_scodata)     (struct hci_conn *conn, struct sk_buff *skb);
-       int (*auth_cfm)         (struct hci_conn *conn, __u8 status);
-       int (*encrypt_cfm)      (struct hci_conn *conn, __u8 status, __u8 encrypt);
+       int (*security_cfm)     (struct hci_conn *conn, __u8 status, __u8 encrypt);
 };
 
 static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
 {
        register struct hci_proto *hp;
        int mask = 0;
-       
+
        hp = hci_proto[HCI_PROTO_L2CAP];
        if (hp && hp->connect_ind)
                mask |= hp->connect_ind(hdev, bdaddr, type);
@@ -514,30 +514,52 @@ static inline void hci_proto_connect_cfm(struct hci_conn *conn, __u8 status)
                hp->connect_cfm(conn, status);
 }
 
-static inline void hci_proto_disconn_ind(struct hci_conn *conn, __u8 reason)
+static inline int hci_proto_disconn_ind(struct hci_conn *conn)
 {
        register struct hci_proto *hp;
+       int reason = 0x13;
 
        hp = hci_proto[HCI_PROTO_L2CAP];
        if (hp && hp->disconn_ind)
-               hp->disconn_ind(conn, reason);
+               reason = hp->disconn_ind(conn);
 
        hp = hci_proto[HCI_PROTO_SCO];
        if (hp && hp->disconn_ind)
-               hp->disconn_ind(conn, reason);
+               reason = hp->disconn_ind(conn);
+
+       return reason;
+}
+
+static inline void hci_proto_disconn_cfm(struct hci_conn *conn, __u8 reason)
+{
+       register struct hci_proto *hp;
+
+       hp = hci_proto[HCI_PROTO_L2CAP];
+       if (hp && hp->disconn_cfm)
+               hp->disconn_cfm(conn, reason);
+
+       hp = hci_proto[HCI_PROTO_SCO];
+       if (hp && hp->disconn_cfm)
+               hp->disconn_cfm(conn, reason);
 }
 
 static inline void hci_proto_auth_cfm(struct hci_conn *conn, __u8 status)
 {
        register struct hci_proto *hp;
+       __u8 encrypt;
+
+       if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
+               return;
+
+       encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
 
        hp = hci_proto[HCI_PROTO_L2CAP];
-       if (hp && hp->auth_cfm)
-               hp->auth_cfm(conn, status);
+       if (hp && hp->security_cfm)
+               hp->security_cfm(conn, status, encrypt);
 
        hp = hci_proto[HCI_PROTO_SCO];
-       if (hp && hp->auth_cfm)
-               hp->auth_cfm(conn, status);
+       if (hp && hp->security_cfm)
+               hp->security_cfm(conn, status, encrypt);
 }
 
 static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encrypt)
@@ -545,12 +567,12 @@ static inline void hci_proto_encrypt_cfm(struct hci_conn *conn, __u8 status, __u
        register struct hci_proto *hp;
 
        hp = hci_proto[HCI_PROTO_L2CAP];
-       if (hp && hp->encrypt_cfm)
-               hp->encrypt_cfm(conn, status, encrypt);
+       if (hp && hp->security_cfm)
+               hp->security_cfm(conn, status, encrypt);
 
        hp = hci_proto[HCI_PROTO_SCO];
-       if (hp && hp->encrypt_cfm)
-               hp->encrypt_cfm(conn, status, encrypt);
+       if (hp && hp->security_cfm)
+               hp->security_cfm(conn, status, encrypt);
 }
 
 int hci_register_proto(struct hci_proto *hproto);
@@ -562,8 +584,7 @@ struct hci_cb {
 
        char *name;
 
-       void (*auth_cfm)        (struct hci_conn *conn, __u8 status);
-       void (*encrypt_cfm)     (struct hci_conn *conn, __u8 status, __u8 encrypt);
+       void (*security_cfm)    (struct hci_conn *conn, __u8 status, __u8 encrypt);
        void (*key_change_cfm)  (struct hci_conn *conn, __u8 status);
        void (*role_switch_cfm) (struct hci_conn *conn, __u8 status, __u8 role);
 };
@@ -571,14 +592,20 @@ struct hci_cb {
 static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
 {
        struct list_head *p;
+       __u8 encrypt;
 
        hci_proto_auth_cfm(conn, status);
 
+       if (test_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
+               return;
+
+       encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
+
        read_lock_bh(&hci_cb_list_lock);
        list_for_each(p, &hci_cb_list) {
                struct hci_cb *cb = list_entry(p, struct hci_cb, list);
-               if (cb->auth_cfm)
-                       cb->auth_cfm(conn, status);
+               if (cb->security_cfm)
+                       cb->security_cfm(conn, status, encrypt);
        }
        read_unlock_bh(&hci_cb_list_lock);
 }
@@ -587,13 +614,16 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status, __u8 encr
 {
        struct list_head *p;
 
+       if (conn->sec_level == BT_SECURITY_SDP)
+               conn->sec_level = BT_SECURITY_LOW;
+
        hci_proto_encrypt_cfm(conn, status, encrypt);
 
        read_lock_bh(&hci_cb_list_lock);
        list_for_each(p, &hci_cb_list) {
                struct hci_cb *cb = list_entry(p, struct hci_cb, list);
-               if (cb->encrypt_cfm)
-                       cb->encrypt_cfm(conn, status, encrypt);
+               if (cb->security_cfm)
+                       cb->security_cfm(conn, status, encrypt);
        }
        read_unlock_bh(&hci_cb_list_lock);
 }
index 73e115bc12dda4f688555c087d0c98558373d576..f566aa1f0a4c9f64229af015ec7e0d16da817791 100644 (file)
@@ -37,6 +37,7 @@ struct sockaddr_l2 {
        sa_family_t     l2_family;
        __le16          l2_psm;
        bdaddr_t        l2_bdaddr;
+       __le16          l2_cid;
 };
 
 /* L2CAP socket options */
@@ -185,6 +186,7 @@ struct l2cap_info_rsp {
 /* info type */
 #define L2CAP_IT_CL_MTU     0x0001
 #define L2CAP_IT_FEAT_MASK  0x0002
+#define L2CAP_IT_FIXED_CHAN 0x0003
 
 /* info result */
 #define L2CAP_IR_SUCCESS    0x0000
@@ -219,11 +221,14 @@ struct l2cap_conn {
        __u8            rx_ident;
        __u8            tx_ident;
 
+       __u8            disc_reason;
+
        struct l2cap_chan_list chan_list;
 };
 
 #define L2CAP_INFO_CL_MTU_REQ_SENT     0x01
-#define L2CAP_INFO_FEAT_MASK_REQ_SENT  0x02
+#define L2CAP_INFO_FEAT_MASK_REQ_SENT  0x04
+#define L2CAP_INFO_FEAT_MASK_REQ_DONE  0x08
 
 /* ----- L2CAP channel and socket info ----- */
 #define l2cap_pi(sk) ((struct l2cap_pinfo *) sk)
@@ -237,8 +242,9 @@ struct l2cap_pinfo {
        __u16           imtu;
        __u16           omtu;
        __u16           flush_to;
-
-       __u32           link_mode;
+       __u8            sec_level;
+       __u8            role_switch;
+       __u8            force_reliable;
 
        __u8            conf_req[64];
        __u8            conf_len;
@@ -257,6 +263,7 @@ struct l2cap_pinfo {
 #define L2CAP_CONF_REQ_SENT    0x01
 #define L2CAP_CONF_INPUT_DONE  0x02
 #define L2CAP_CONF_OUTPUT_DONE 0x04
+#define L2CAP_CONF_CONNECT_PEND        0x80
 
 #define L2CAP_CONF_MAX_RETRIES 2
 
index 4dc8d92a4638e993a5c097a484bebf4e3e9fa7ae..80072611d26a44820304593292398f0e3d67d7eb 100644 (file)
@@ -183,8 +183,9 @@ struct rfcomm_dlc {
        u8            remote_v24_sig;
        u8            mscex;
        u8            out;
-
-       u32           link_mode;
+       u8            sec_level;
+       u8            role_switch;
+       u32           defer_setup;
 
        uint          mtu;
        uint          cfc;
@@ -202,10 +203,12 @@ struct rfcomm_dlc {
 #define RFCOMM_RX_THROTTLED 0
 #define RFCOMM_TX_THROTTLED 1
 #define RFCOMM_TIMED_OUT    2
-#define RFCOMM_MSC_PENDING  3 
-#define RFCOMM_AUTH_PENDING 4
-#define RFCOMM_AUTH_ACCEPT  5
-#define RFCOMM_AUTH_REJECT  6
+#define RFCOMM_MSC_PENDING  3
+#define RFCOMM_SEC_PENDING  4
+#define RFCOMM_AUTH_PENDING 5
+#define RFCOMM_AUTH_ACCEPT  6
+#define RFCOMM_AUTH_REJECT  7
+#define RFCOMM_DEFER_SETUP  8
 
 /* Scheduling flags and events */
 #define RFCOMM_SCHED_STATE  0
@@ -239,6 +242,7 @@ int  rfcomm_dlc_close(struct rfcomm_dlc *d, int reason);
 int  rfcomm_dlc_send(struct rfcomm_dlc *d, struct sk_buff *skb);
 int  rfcomm_dlc_set_modem_status(struct rfcomm_dlc *d, u8 v24_sig);
 int  rfcomm_dlc_get_modem_status(struct rfcomm_dlc *d, u8 *v24_sig);
+void rfcomm_dlc_accept(struct rfcomm_dlc *d);
 
 #define rfcomm_dlc_lock(d)     spin_lock(&d->lock)
 #define rfcomm_dlc_unlock(d)   spin_unlock(&d->lock)
@@ -304,7 +308,8 @@ struct rfcomm_pinfo {
        struct bt_sock bt;
        struct rfcomm_dlc   *dlc;
        u8     channel;
-       u32    link_mode;
+       u8     sec_level;
+       u8     role_switch;
 };
 
 int  rfcomm_init_sockets(void);
@@ -333,7 +338,6 @@ struct rfcomm_dev_req {
        bdaddr_t src;
        bdaddr_t dst;
        u8       channel;
-       
 };
 
 struct rfcomm_dev_info {
index c0d1f5b708c5836d3fcf0cc9ededd748bc9a6657..50f3fd9ff52430c7bc196bdddfc3dd17df3abb35 100644 (file)
@@ -178,6 +178,8 @@ struct station_parameters {
  * @STATION_INFO_SIGNAL: @signal filled
  * @STATION_INFO_TX_BITRATE: @tx_bitrate fields are filled
  *  (tx_bitrate, tx_bitrate_flags and tx_bitrate_mcs)
+ * @STATION_INFO_RX_PACKETS: @rx_packets filled
+ * @STATION_INFO_TX_PACKETS: @tx_packets filled
  */
 enum station_info_flags {
        STATION_INFO_INACTIVE_TIME      = 1<<0,
@@ -188,6 +190,8 @@ enum station_info_flags {
        STATION_INFO_PLINK_STATE        = 1<<5,
        STATION_INFO_SIGNAL             = 1<<6,
        STATION_INFO_TX_BITRATE         = 1<<7,
+       STATION_INFO_RX_PACKETS         = 1<<8,
+       STATION_INFO_TX_PACKETS         = 1<<9,
 };
 
 /**
@@ -235,6 +239,8 @@ struct rate_info {
  * @plink_state: mesh peer link state
  * @signal: signal strength of last received packet in dBm
  * @txrate: current unicast bitrate to this station
+ * @rx_packets: packets received from this station
+ * @tx_packets: packets transmitted to this station
  */
 struct station_info {
        u32 filled;
@@ -246,6 +252,8 @@ struct station_info {
        u8 plink_state;
        s8 signal;
        struct rate_info txrate;
+       u32 rx_packets;
+       u32 tx_packets;
 };
 
 /**
@@ -340,31 +348,10 @@ struct bss_parameters {
        u8 basic_rates_len;
 };
 
-/**
- * enum reg_set_by - Indicates who is trying to set the regulatory domain
- * @REGDOM_SET_BY_INIT: regulatory domain was set by initialization. We will be
- *     using a static world regulatory domain by default.
- * @REGDOM_SET_BY_CORE: Core queried CRDA for a dynamic world regulatory domain.
- * @REGDOM_SET_BY_USER: User asked the wireless core to set the
- *     regulatory domain.
- * @REGDOM_SET_BY_DRIVER: a wireless drivers has hinted to the wireless core
- *     it thinks its knows the regulatory domain we should be in.
- * @REGDOM_SET_BY_COUNTRY_IE: the wireless core has received an 802.11 country
- *     information element with regulatory information it thinks we
- *     should consider.
- */
-enum reg_set_by {
-       REGDOM_SET_BY_INIT,
-       REGDOM_SET_BY_CORE,
-       REGDOM_SET_BY_USER,
-       REGDOM_SET_BY_DRIVER,
-       REGDOM_SET_BY_COUNTRY_IE,
-};
-
 /**
  * enum environment_cap - Environment parsed from country IE
  * @ENVIRON_ANY: indicates country IE applies to both indoor and
- *     outdoor operation.
+ *     outdoor operation.
  * @ENVIRON_INDOOR: indicates country IE applies only to indoor operation
  * @ENVIRON_OUTDOOR: indicates country IE applies only to outdoor operation
  */
@@ -375,15 +362,15 @@ enum environment_cap {
 };
 
 /**
- * struct regulatory_request - receipt of last regulatory request
+ * struct regulatory_request - used to keep track of regulatory requests
  *
- * @wiphy: this is set if this request's initiator is
+ * @wiphy_idx: this is set if this request's initiator is
  *     %REGDOM_SET_BY_COUNTRY_IE or %REGDOM_SET_BY_DRIVER. This
  *     can be used by the wireless core to deal with conflicts
  *     and potentially inform users of which devices specifically
  *     cased the conflicts.
  * @initiator: indicates who sent this request, could be any of
- *     of those set in reg_set_by, %REGDOM_SET_BY_*
+ *     of those set in nl80211_reg_initiator (%NL80211_REGDOM_SET_BY_*)
  * @alpha2: the ISO / IEC 3166 alpha2 country code of the requested
  *     regulatory domain. We have a few special codes:
  *     00 - World regulatory domain
@@ -396,14 +383,16 @@ enum environment_cap {
  *     country IE
  * @country_ie_env: lets us know if the AP is telling us we are outdoor,
  *     indoor, or if it doesn't matter
+ * @list: used to insert into the reg_requests_list linked list
  */
 struct regulatory_request {
-       struct wiphy *wiphy;
-       enum reg_set_by initiator;
+       int wiphy_idx;
+       enum nl80211_reg_initiator initiator;
        char alpha2[2];
        bool intersect;
        u32 country_ie_checksum;
        enum environment_cap country_ie_env;
+       struct list_head list;
 };
 
 struct ieee80211_freq_range {
@@ -525,6 +514,8 @@ struct cfg80211_ssid {
  * @n_ssids: number of SSIDs
  * @channels: channels to scan on.
  * @n_channels: number of channels for each band
+ * @ie: optional information element(s) to add into Probe Request or %NULL
+ * @ie_len: length of ie in octets
  * @wiphy: the wiphy this was for
  * @ifidx: the interface index
  */
@@ -533,6 +524,8 @@ struct cfg80211_scan_request {
        int n_ssids;
        struct ieee80211_channel **channels;
        u32 n_channels;
+       u8 *ie;
+       size_t ie_len;
 
        /* internal */
        struct wiphy *wiphy;
@@ -565,8 +558,7 @@ enum cfg80211_signal_type {
  * @information_elements: the information elements (Note that there
  *     is no guarantee that these are well-formed!)
  * @len_information_elements: total length of the information elements
- * @signal: signal strength value
- * @signal_type: signal type
+ * @signal: signal strength value (type depends on the wiphy's signal_type)
  * @free_priv: function pointer to free private data
  * @priv: private area for driver use, has at least wiphy->bss_priv_size bytes
  */
@@ -581,7 +573,6 @@ struct cfg80211_bss {
        size_t len_information_elements;
 
        s32 signal;
-       enum cfg80211_signal_type signal_type;
 
        void (*free_priv)(struct cfg80211_bss *bss);
        u8 priv[0] __attribute__((__aligned__(sizeof(void *))));
@@ -755,6 +746,9 @@ int cfg80211_wext_siwscan(struct net_device *dev,
 int cfg80211_wext_giwscan(struct net_device *dev,
                          struct iw_request_info *info,
                          struct iw_point *data, char *extra);
+int cfg80211_wext_giwrange(struct net_device *dev,
+                          struct iw_request_info *info,
+                          struct iw_point *data, char *extra);
 
 /**
  * cfg80211_scan_done - notify that scan finished
@@ -770,6 +764,7 @@ void cfg80211_scan_done(struct cfg80211_scan_request *request, bool aborted);
  *
  * @wiphy: the wiphy reporting the BSS
  * @bss: the found BSS
+ * @signal: the signal strength, type depends on the wiphy's signal_type
  * @gfp: context flags
  *
  * This informs cfg80211 that BSS information was found and
@@ -779,8 +774,7 @@ struct cfg80211_bss*
 cfg80211_inform_bss_frame(struct wiphy *wiphy,
                          struct ieee80211_channel *channel,
                          struct ieee80211_mgmt *mgmt, size_t len,
-                         s32 signal, enum cfg80211_signal_type sigtype,
-                         gfp_t gfp);
+                         s32 signal, gfp_t gfp);
 
 struct cfg80211_bss *cfg80211_get_bss(struct wiphy *wiphy,
                                      struct ieee80211_channel *channel,
index 52e97bfca5a1e5e83a2641c287c4ec3db88a990e..839f768f9e35c6ac175ff03d42b694839f7fd49a 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * include/net/dsa.h - Driver for Distributed Switch Architecture switch chips
- * Copyright (c) 2008 Marvell Semiconductor
+ * Copyright (c) 2008-2009 Marvell Semiconductor
  *
  * 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
 #ifndef __LINUX_NET_DSA_H
 #define __LINUX_NET_DSA_H
 
-#define DSA_MAX_PORTS  12
+#define DSA_MAX_SWITCHES       4
+#define DSA_MAX_PORTS          12
+
+struct dsa_chip_data {
+       /*
+        * How to access the switch configuration registers.
+        */
+       struct device   *mii_bus;
+       int             sw_addr;
+
+       /*
+        * The names of the switch's ports.  Use "cpu" to
+        * designate the switch port that the cpu is connected to,
+        * "dsa" to indicate that this port is a DSA link to
+        * another switch, NULL to indicate the port is unused,
+        * or any other string to indicate this is a physical port.
+        */
+       char            *port_names[DSA_MAX_PORTS];
+
+       /*
+        * An array (with nr_chips elements) of which element [a]
+        * indicates which port on this switch should be used to
+        * send packets to that are destined for switch a.  Can be
+        * NULL if there is only one switch chip.
+        */
+       s8              *rtable;
+};
 
 struct dsa_platform_data {
        /*
         * Reference to a Linux network interface that connects
-        * to the switch chip.
+        * to the root switch chip of the tree.
         */
        struct device   *netdev;
 
        /*
-        * How to access the switch configuration registers, and
-        * the names of the switch ports (use "cpu" to designate
-        * the switch port that the cpu is connected to).
+        * Info structs describing each of the switch chips
+        * connected via this network interface.
         */
-       struct device   *mii_bus;
-       int             sw_addr;
-       char            *port_names[DSA_MAX_PORTS];
+       int             nr_chips;
+       struct dsa_chip_data    *chip;
 };
 
 extern bool dsa_uses_dsa_tags(void *dsa_ptr);
index c8effa4b1feb68eea3e20e303e05021a45874c86..38b78132019b29bc3c0702d2fd0ed09938e7bcee 100644 (file)
@@ -39,8 +39,6 @@ struct inet6_ifaddr
        
        __u32                   valid_lft;
        __u32                   prefered_lft;
-       unsigned long           cstamp; /* created timestamp */
-       unsigned long           tstamp; /* updated timestamp */
        atomic_t                refcnt;
        spinlock_t              lock;
 
@@ -49,6 +47,9 @@ struct inet6_ifaddr
 
        __u16                   scope;
 
+       unsigned long           cstamp; /* created timestamp */
+       unsigned long           tstamp; /* updated timestamp */
+
        struct timer_list       timer;
 
        struct inet6_dev        *idev;
index e081eefd6f471a9a5241e3e694f9687be35446bc..39f2dc9439086b83e45b6495e712ebfe91daa2a4 100644 (file)
@@ -61,7 +61,8 @@ void inet_frag_destroy(struct inet_frag_queue *q,
                                struct inet_frags *f, int *work);
 int inet_frag_evictor(struct netns_frags *nf, struct inet_frags *f);
 struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,
-               struct inet_frags *f, void *key, unsigned int hash);
+               struct inet_frags *f, void *key, unsigned int hash)
+       __releases(&f->lock);
 
 static inline void inet_frag_put(struct inet_frag_queue *q, struct inet_frags *f)
 {
index 88fa3e03e3e9dbf4746f59851c27cfd9407fe7bf..12a52efcd0d1d8a864224347f3ccf3601c942c25 100644 (file)
@@ -1022,11 +1022,6 @@ static inline int ieee80211_num_regular_queues(struct ieee80211_hw *hw)
        return hw->queues;
 }
 
-static inline int ieee80211_num_queues(struct ieee80211_hw *hw)
-{
-       return hw->queues + hw->ampdu_queues;
-}
-
 static inline struct ieee80211_rate *
 ieee80211_get_tx_rate(const struct ieee80211_hw *hw,
                      const struct ieee80211_tx_info *c)
@@ -1329,6 +1324,12 @@ enum ieee80211_ampdu_mlme_action {
  *     because the hardware is turned off! Anything else is a bug!
  *     Returns a negative error code which will be seen in userspace.
  *
+ * @sw_scan_start: Notifier function that is called just before a software scan
+ *     is started. Can be NULL, if the driver doesn't need this notification.
+ *
+ * @sw_scan_complete: Notifier function that is called just after a software scan
+ *     finished. Can be NULL, if the driver doesn't need this notification.
+ *
  * @get_stats: Return low-level statistics.
  *     Returns zero if statistics are available.
  *
@@ -1408,6 +1409,8 @@ struct ieee80211_ops {
                        u32 iv32, u16 *phase1key);
        int (*hw_scan)(struct ieee80211_hw *hw,
                       struct cfg80211_scan_request *req);
+       void (*sw_scan_start)(struct ieee80211_hw *hw);
+       void (*sw_scan_complete)(struct ieee80211_hw *hw);
        int (*get_stats)(struct ieee80211_hw *hw,
                         struct ieee80211_low_level_stats *stats);
        void (*get_tkip_seq)(struct ieee80211_hw *hw, u8 hw_key_idx,
@@ -1979,6 +1982,16 @@ struct ieee80211_sta *ieee80211_find_sta(struct ieee80211_hw *hw,
 
 /* Rate control API */
 
+/**
+ * enum rate_control_changed - flags to indicate which parameter changed
+ *
+ * @IEEE80211_RC_HT_CHANGED: The HT parameters of the operating channel have
+ *     changed, rate control algorithm can update its internal state if needed.
+ */
+enum rate_control_changed {
+       IEEE80211_RC_HT_CHANGED = BIT(0)
+};
+
 /**
  * struct ieee80211_tx_rate_control - rate control information for/from RC algo
  *
@@ -2015,6 +2028,9 @@ struct rate_control_ops {
        void *(*alloc_sta)(void *priv, struct ieee80211_sta *sta, gfp_t gfp);
        void (*rate_init)(void *priv, struct ieee80211_supported_band *sband,
                          struct ieee80211_sta *sta, void *priv_sta);
+       void (*rate_update)(void *priv, struct ieee80211_supported_band *sband,
+                           struct ieee80211_sta *sta,
+                           void *priv_sta, u32 changed);
        void (*free_sta)(void *priv, struct ieee80211_sta *sta,
                         void *priv_sta);
 
index 6fc13d905c5ffaced2e1658038ab97934d61f42d..ded434b032a44ec406a0fa8bcb11d688d95b7efa 100644 (file)
@@ -109,11 +109,6 @@ extern struct list_head net_namespace_list;
 #ifdef CONFIG_NET_NS
 extern void __put_net(struct net *net);
 
-static inline int net_alive(struct net *net)
-{
-       return net && atomic_read(&net->count);
-}
-
 static inline struct net *get_net(struct net *net)
 {
        atomic_inc(&net->count);
@@ -145,11 +140,6 @@ int net_eq(const struct net *net1, const struct net *net2)
 }
 #else
 
-static inline int net_alive(struct net *net)
-{
-       return 1;
-}
-
 static inline struct net *get_net(struct net *net)
 {
        return net;
@@ -234,6 +224,23 @@ struct pernet_operations {
        void (*exit)(struct net *net);
 };
 
+/*
+ * Use these carefully.  If you implement a network device and it
+ * needs per network namespace operations use device pernet operations,
+ * otherwise use pernet subsys operations.
+ *
+ * This is critically important.  Most of the network code cleanup
+ * runs with the assumption that dev_remove_pack has been called so no
+ * new packets will arrive during and after the cleanup functions have
+ * been called.  dev_remove_pack is not per namespace so instead the
+ * guarantee of no more packets arriving in a network namespace is
+ * provided by ensuring that all network devices and all sockets have
+ * left the network namespace before the cleanup methods are called.
+ *
+ * For the longest time the ipv4 icmp code was registered as a pernet
+ * device which caused kernel oops, and panics during network
+ * namespace cleanup.   So please don't get this wrong.
+ */
 extern int register_pernet_subsys(struct pernet_operations *);
 extern void unregister_pernet_subsys(struct pernet_operations *);
 extern int register_pernet_gen_subsys(int *id, struct pernet_operations *);
index e78afe7f28e35ad48204b83bd43dfc5d710d2f1c..5a449b44ba33255f4acebc28879a37ae7e3ab3bd 100644 (file)
@@ -59,10 +59,11 @@ static inline int nf_conntrack_confirm(struct sk_buff *skb)
        struct nf_conn *ct = (struct nf_conn *)skb->nfct;
        int ret = NF_ACCEPT;
 
-       if (ct) {
+       if (ct && ct != &nf_conntrack_untracked) {
                if (!nf_ct_is_confirmed(ct) && !nf_ct_is_dying(ct))
                        ret = __nf_conntrack_confirm(skb);
-               nf_ct_deliver_cached_events(ct);
+               if (likely(ret == NF_ACCEPT))
+                       nf_ct_deliver_cached_events(ct);
        }
        return ret;
 }
index b2e01cc3fc8a1c892bad42efc008d0c2ba80aa87..fe456c295b04400e3e05d489ea7d22349ec486b4 100644 (file)
@@ -1,7 +1,11 @@
 #ifndef _NET_PSNAP_H
 #define _NET_PSNAP_H
 
-extern struct datalink_proto *register_snap_client(unsigned char *desc, int (*rcvfunc)(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *orig_dev));
+extern struct datalink_proto *
+register_snap_client(const unsigned char *desc,
+                    int (*rcvfunc)(struct sk_buff *, struct net_device *,
+                                   struct packet_type *,
+                                   struct net_device *orig_dev));
 extern void unregister_snap_client(struct datalink_proto *proto);
 
 #endif
index 3d78a4d224601f5003aef260f4363bc88707d3be..964ffa0d8815139ae22d351590b5673a4dd38850 100644 (file)
@@ -49,18 +49,10 @@ struct Qdisc
        int                     padded;
        struct Qdisc_ops        *ops;
        struct qdisc_size_table *stab;
+       struct list_head        list;
        u32                     handle;
        u32                     parent;
        atomic_t                refcnt;
-       unsigned long           state;
-       struct sk_buff          *gso_skb;
-       struct sk_buff_head     q;
-       struct netdev_queue     *dev_queue;
-       struct Qdisc            *next_sched;
-       struct list_head        list;
-
-       struct gnet_stats_basic bstats;
-       struct gnet_stats_queue qstats;
        struct gnet_stats_rate_est      rate_est;
        int                     (*reshape_fail)(struct sk_buff *skb,
                                        struct Qdisc *q);
@@ -71,6 +63,17 @@ struct Qdisc
         * and it will live until better solution will be invented.
         */
        struct Qdisc            *__parent;
+       struct netdev_queue     *dev_queue;
+       struct Qdisc            *next_sched;
+
+       struct sk_buff          *gso_skb;
+       /*
+        * For performance sake on SMP, we put highly modified fields at the end
+        */
+       unsigned long           state;
+       struct sk_buff_head     q;
+       struct gnet_stats_basic bstats;
+       struct gnet_stats_queue qstats;
 };
 
 struct Qdisc_class_ops
index 88988ab03d751fb1c476a63a3648eb4e058aab5e..3b966802e05d2724ed6940e5e9a7326176192b8f 100644 (file)
@@ -77,7 +77,8 @@ typedef enum {
        SCTP_CMD_HB_TIMERS_START,    /* Start the heartbeat timers. */
        SCTP_CMD_HB_TIMER_UPDATE,    /* Update a heartbeat timers.  */
        SCTP_CMD_HB_TIMERS_STOP,     /* Stop the heartbeat timers.  */
-       SCTP_CMD_TRANSPORT_RESET,    /* Reset the status of a transport. */
+       SCTP_CMD_TRANSPORT_HB_SENT,  /* Reset the status of a transport. */
+       SCTP_CMD_TRANSPORT_IDLE,     /* Do manipulations on idle transport */
        SCTP_CMD_TRANSPORT_ON,       /* Mark the transport as active. */
        SCTP_CMD_REPORT_ERROR,   /* Pass this error back out of the sm. */
        SCTP_CMD_REPORT_BAD_TAG, /* Verification tags didn't match. */
index 9e226be3be69d45c25a2cc83a86033645ff537c4..9f80a766828923a8b41ad0588d91b40fcf12a8be 100644 (file)
  *   and will continue to evolve.
  */
 
-
-
-#ifdef TEST_FRAME
-#undef CONFIG_SCTP_DBG_OBJCNT
-#undef CONFIG_SYSCTL
-#endif /* TEST_FRAME */
-
 #include <linux/types.h>
 #include <linux/slab.h>
 #include <linux/in.h>
index cc9d5bcb06f74cf9fce61647e108354a4a0a2245..4bb1ff9fd15bcc2b1bbc24c3cbd853fcd796da5c 100644 (file)
@@ -867,7 +867,6 @@ static inline void sk_mem_uncharge(struct sock *sk, int size)
 
 static inline void sk_wmem_free_skb(struct sock *sk, struct sk_buff *skb)
 {
-       skb_truesize_check(skb);
        sock_set_flag(sk, SOCK_QUEUE_SHRUNK);
        sk->sk_wmem_queued -= skb->truesize;
        sk_mem_uncharge(sk, skb->truesize);
index 218235de89637f9471027f299dfd19fcd9d6c858..e54c76d754951159c71a2bacdce45ec1a1dab593 100644 (file)
@@ -481,7 +481,16 @@ static inline void tcp_clear_xmit_timers(struct sock *sk)
 }
 
 extern unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu);
-extern unsigned int tcp_current_mss(struct sock *sk, int large);
+extern unsigned int tcp_current_mss(struct sock *sk);
+
+/* Bound MSS / TSO packet size with the half of the window */
+static inline int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize)
+{
+       if (tp->max_window && pktsize > (tp->max_window >> 1))
+               return max(tp->max_window >> 1, 68U - tp->tcp_header_len);
+       else
+               return pktsize;
+}
 
 /* tcp.c */
 extern void tcp_get_info(struct sock *, struct tcp_info *);
@@ -685,6 +694,7 @@ extern void tcp_get_allowed_congestion_control(char *buf, size_t len);
 extern int tcp_set_allowed_congestion_control(char *allowed);
 extern int tcp_set_congestion_control(struct sock *sk, const char *name);
 extern void tcp_slow_start(struct tcp_sock *tp);
+extern void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w);
 
 extern struct tcp_congestion_ops tcp_init_congestion_ops;
 extern u32 tcp_reno_ssthresh(struct sock *sk);
@@ -821,15 +831,15 @@ static inline void tcp_push_pending_frames(struct sock *sk)
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
-       __tcp_push_pending_frames(sk, tcp_current_mss(sk, 1), tp->nonagle);
+       __tcp_push_pending_frames(sk, tcp_current_mss(sk), tp->nonagle);
 }
 
-static inline void tcp_init_wl(struct tcp_sock *tp, u32 ack, u32 seq)
+static inline void tcp_init_wl(struct tcp_sock *tp, u32 seq)
 {
        tp->snd_wl1 = seq;
 }
 
-static inline void tcp_update_wl(struct tcp_sock *tp, u32 ack, u32 seq)
+static inline void tcp_update_wl(struct tcp_sock *tp, u32 seq)
 {
        tp->snd_wl1 = seq;
 }
@@ -925,7 +935,6 @@ extern void tcp_done(struct sock *sk);
 static inline void tcp_sack_reset(struct tcp_options_received *rx_opt)
 {
        rx_opt->dsack = 0;
-       rx_opt->eff_sacks = 0;
        rx_opt->num_sacks = 0;
 }
 
@@ -997,11 +1006,21 @@ static inline int tcp_fin_time(const struct sock *sk)
        return fin_timeout;
 }
 
-static inline int tcp_paws_check(const struct tcp_options_received *rx_opt, int rst)
+static inline int tcp_paws_check(const struct tcp_options_received *rx_opt,
+                                int paws_win)
 {
-       if ((s32)(rx_opt->rcv_tsval - rx_opt->ts_recent) >= 0)
-               return 0;
-       if (get_seconds() >= rx_opt->ts_recent_stamp + TCP_PAWS_24DAYS)
+       if ((s32)(rx_opt->ts_recent - rx_opt->rcv_tsval) <= paws_win)
+               return 1;
+       if (unlikely(get_seconds() >= rx_opt->ts_recent_stamp + TCP_PAWS_24DAYS))
+               return 1;
+
+       return 0;
+}
+
+static inline int tcp_paws_reject(const struct tcp_options_received *rx_opt,
+                                 int rst)
+{
+       if (tcp_paws_check(rx_opt, 0))
                return 0;
 
        /* RST segments are not recommended to carry timestamp,
index 1c6285eb166668dbf267d7c79d3d9d8be7307133..64a76208580c66ec4d8f2bc3562f5b86287fd723 100644 (file)
@@ -69,6 +69,9 @@ enum ieee80211_channel_flags {
  * @band: band this channel belongs to.
  * @max_antenna_gain: maximum antenna gain in dBi
  * @max_power: maximum transmission power (in dBm)
+ * @beacon_found: helper to regulatory code to indicate when a beacon
+ *     has been found on this channel. Use regulatory_hint_found_beacon()
+ *     to enable this, this is is useful only on 5 GHz band.
  * @orig_mag: internal use
  * @orig_mpwr: internal use
  */
@@ -80,6 +83,7 @@ struct ieee80211_channel {
        u32 flags;
        int max_antenna_gain;
        int max_power;
+       bool beacon_found;
        u32 orig_flags;
        int orig_mag, orig_mpwr;
 };
@@ -200,6 +204,7 @@ struct ieee80211_supported_band {
  *     the regulatory_hint() API. This can be used by the driver
  *     on the reg_notifier() if it chooses to ignore future
  *     regulatory domain changes caused by other drivers.
+ * @signal_type: signal type reported in &struct cfg80211_bss.
  */
 struct wiphy {
        /* assign these fields before you register the wiphy */
@@ -213,6 +218,8 @@ struct wiphy {
        bool custom_regulatory;
        bool strict_regulatory;
 
+       enum cfg80211_signal_type signal_type;
+
        int bss_priv_size;
        u8 max_scan_ssids;
 
@@ -398,8 +405,15 @@ ieee80211_get_response_rate(struct ieee80211_supported_band *sband,
  * domain should be in or by providing a completely build regulatory domain.
  * If the driver provides an ISO/IEC 3166 alpha2 userspace will be queried
  * for a regulatory domain structure for the respective country.
+ *
+ * The wiphy must have been registered to cfg80211 prior to this call.
+ * For cfg80211 drivers this means you must first use wiphy_register(),
+ * for mac80211 drivers you must first use ieee80211_register_hw().
+ *
+ * Drivers should check the return value, its possible you can get
+ * an -ENOMEM.
  */
-extern void regulatory_hint(struct wiphy *wiphy, const char *alpha2);
+extern int regulatory_hint(struct wiphy *wiphy, const char *alpha2);
 
 /**
  * regulatory_hint_11d - hints a country IE as a regulatory domain
@@ -415,7 +429,6 @@ extern void regulatory_hint(struct wiphy *wiphy, const char *alpha2);
 extern void regulatory_hint_11d(struct wiphy *wiphy,
                                u8 *country_ie,
                                u8 country_ie_len);
-
 /**
  * wiphy_apply_custom_regulatory - apply a custom driver regulatory domain
  * @wiphy: the wireless device we want to process the regulatory domain on
diff --git a/include/trace/skb.h b/include/trace/skb.h
new file mode 100644 (file)
index 0000000..3aa8646
--- /dev/null
@@ -0,0 +1,8 @@
+#ifndef _TRACE_SKB_H_
+#define _TRACE_SKB_H_
+
+DECLARE_TRACE(kfree_skb,
+       TPPROTO(struct sk_buff *skb, void *location),
+       TPARGS(skb, location));
+
+#endif
index 708105e163df8fbbbe69c7fc74a29693d6f3ed58..8d4ff5afc1d80b56963cbf119b162a3ebce61124 100644 (file)
@@ -370,10 +370,14 @@ void __init prepare_namespace(void)
                ssleep(root_delay);
        }
 
-       /* wait for the known devices to complete their probing */
-       while (driver_probe_done() != 0)
-               msleep(100);
-       async_synchronize_full();
+       /*
+        * wait for the known devices to complete their probing
+        *
+        * Note: this is a potential source of long boot delays.
+        * For example, it is not atypical to wait 5 seconds here
+        * for the touchpad of a laptop to initialize.
+        */
+       wait_for_device_probe();
 
        md_run_setup();
 
@@ -399,6 +403,7 @@ void __init prepare_namespace(void)
                while (driver_probe_done() != 0 ||
                        (ROOT_DEV = name_to_dev_t(saved_root_name)) == 0)
                        msleep(100);
+               async_synchronize_full();
        }
 
        is_floppy = MAJOR(ROOT_DEV) == FLOPPY_MAJOR;
index ff95e319288472caaf3aa086c0fca769b0706b2f..9bdddbcb3d6a62614b0d43783abc9a265948bdde 100644 (file)
@@ -281,8 +281,9 @@ static void __init autodetect_raid(void)
         */
        printk(KERN_INFO "md: Waiting for all devices to be available before autodetect\n");
        printk(KERN_INFO "md: If you don't use raid, use raid=noautodetect\n");
-       while (driver_probe_done() < 0)
-               msleep(100);
+
+       wait_for_device_probe();
+
        fd = sys_open("/dev/md0", 0, 0);
        if (fd >= 0) {
                sys_ioctl(fd, RAID_AUTORUN, raid_autopart);
index 844209453c02c2248114972fca3f0fcddbdf513d..83697e160b3a786d3d91c14000f116a441f61bfc 100644 (file)
@@ -97,7 +97,7 @@ static inline void mark_rodata_ro(void) { }
 extern void tc_init(void);
 #endif
 
-enum system_states system_state;
+enum system_states system_state __read_mostly;
 EXPORT_SYMBOL(system_state);
 
 /*
@@ -463,6 +463,7 @@ static noinline void __init_refok rest_init(void)
         * at least once to get things moving:
         */
        init_idle_bootup_task(current);
+       rcu_scheduler_starting();
        preempt_enable_no_resched();
        schedule();
        preempt_disable();
index 170a9213c1b68d6cee652fb7758fef556ecf127f..e4791b3ba55d45c163f3dd8cc0551f0aa7a1e766 100644 (file)
@@ -51,6 +51,7 @@ obj-$(CONFIG_UID16) += uid16.o
 obj-$(CONFIG_MODULES) += module.o
 obj-$(CONFIG_KALLSYMS) += kallsyms.o
 obj-$(CONFIG_PM) += power/
+obj-$(CONFIG_FREEZER) += power/
 obj-$(CONFIG_BSD_PROCESS_ACCT) += acct.o
 obj-$(CONFIG_KEXEC) += kexec.o
 obj-$(CONFIG_BACKTRACE_SELF_TEST) += backtracetest.o
index e14db9c089b9db31df71296b199f173974b7410e..9edb5c4b79b4f1a88a0487f588c36fc6207f54a9 100644 (file)
@@ -1122,8 +1122,8 @@ static void cgroup_kill_sb(struct super_block *sb) {
 
        mutex_unlock(&cgroup_mutex);
 
-       kfree(root);
        kill_litter_super(sb);
+       kfree(root);
 }
 
 static struct file_system_type cgroup_fs_type = {
index f89d373a9c6d7ff5e6848404d4db5b84eb35819f..438701adce2344faab6551f3c833f3bb36c60b05 100644 (file)
@@ -1165,6 +1165,7 @@ static int futex_wait(u32 __user *uaddr, int fshared,
                      u32 val, ktime_t *abs_time, u32 bitset, int clockrt)
 {
        struct task_struct *curr = current;
+       struct restart_block *restart;
        DECLARE_WAITQUEUE(wait, curr);
        struct futex_hash_bucket *hb;
        struct futex_q q;
@@ -1216,11 +1217,13 @@ retry:
 
                if (!ret)
                        goto retry;
-               return ret;
+               goto out;
        }
        ret = -EWOULDBLOCK;
-       if (uval != val)
-               goto out_unlock_put_key;
+       if (unlikely(uval != val)) {
+               queue_unlock(&q, hb);
+               goto out_put_key;
+       }
 
        /* Only actually queue if *uaddr contained val.  */
        queue_me(&q, hb);
@@ -1284,38 +1287,38 @@ retry:
         */
 
        /* If we were woken (and unqueued), we succeeded, whatever. */
+       ret = 0;
        if (!unqueue_me(&q))
-               return 0;
+               goto out_put_key;
+       ret = -ETIMEDOUT;
        if (rem)
-               return -ETIMEDOUT;
+               goto out_put_key;
 
        /*
         * We expect signal_pending(current), but another thread may
         * have handled it for us already.
         */
+       ret = -ERESTARTSYS;
        if (!abs_time)
-               return -ERESTARTSYS;
-       else {
-               struct restart_block *restart;
-               restart = &current_thread_info()->restart_block;
-               restart->fn = futex_wait_restart;
-               restart->futex.uaddr = (u32 *)uaddr;
-               restart->futex.val = val;
-               restart->futex.time = abs_time->tv64;
-               restart->futex.bitset = bitset;
-               restart->futex.flags = 0;
-
-               if (fshared)
-                       restart->futex.flags |= FLAGS_SHARED;
-               if (clockrt)
-                       restart->futex.flags |= FLAGS_CLOCKRT;
-               return -ERESTART_RESTARTBLOCK;
-       }
+               goto out_put_key;
 
-out_unlock_put_key:
-       queue_unlock(&q, hb);
-       put_futex_key(fshared, &q.key);
+       restart = &current_thread_info()->restart_block;
+       restart->fn = futex_wait_restart;
+       restart->futex.uaddr = (u32 *)uaddr;
+       restart->futex.val = val;
+       restart->futex.time = abs_time->tv64;
+       restart->futex.bitset = bitset;
+       restart->futex.flags = 0;
+
+       if (fshared)
+               restart->futex.flags |= FLAGS_SHARED;
+       if (clockrt)
+               restart->futex.flags |= FLAGS_CLOCKRT;
 
+       ret = -ERESTART_RESTARTBLOCK;
+
+out_put_key:
+       put_futex_key(fshared, &q.key);
 out:
        return ret;
 }
index 8a6d7b08864ea199108cae686adbe1a8886a56a5..483899578259ebc725264bedae6abb132295b9d3 100644 (file)
@@ -1465,6 +1465,11 @@ int kernel_kexec(void)
                error = device_power_down(PMSG_FREEZE);
                if (error)
                        goto Enable_irqs;
+
+               /* Suspend system devices */
+               error = sysdev_suspend(PMSG_FREEZE);
+               if (error)
+                       goto Power_up_devices;
        } else
 #endif
        {
@@ -1477,6 +1482,8 @@ int kernel_kexec(void)
 
 #ifdef CONFIG_KEXEC_JUMP
        if (kexec_image->preserve_context) {
+               sysdev_resume();
+ Power_up_devices:
                device_power_up(PMSG_RESTORE);
  Enable_irqs:
                local_irq_enable();
index 2313a4cc14ea19d94faffaf4e6c6f7e0a109581e..e976e505648d2cf9d8e94085bcce6f1ec16afd8b 100644 (file)
@@ -680,6 +680,33 @@ static void cpu_timer_fire(struct k_itimer *timer)
        }
 }
 
+/*
+ * Sample a process (thread group) timer for the given group_leader task.
+ * Must be called with tasklist_lock held for reading.
+ */
+static int cpu_timer_sample_group(const clockid_t which_clock,
+                                 struct task_struct *p,
+                                 union cpu_time_count *cpu)
+{
+       struct task_cputime cputime;
+
+       thread_group_cputimer(p, &cputime);
+       switch (CPUCLOCK_WHICH(which_clock)) {
+       default:
+               return -EINVAL;
+       case CPUCLOCK_PROF:
+               cpu->cpu = cputime_add(cputime.utime, cputime.stime);
+               break;
+       case CPUCLOCK_VIRT:
+               cpu->cpu = cputime.utime;
+               break;
+       case CPUCLOCK_SCHED:
+               cpu->sched = cputime.sum_exec_runtime + task_delta_exec(p);
+               break;
+       }
+       return 0;
+}
+
 /*
  * Guts of sys_timer_settime for CPU timers.
  * This is called with the timer locked and interrupts disabled.
@@ -741,7 +768,7 @@ int posix_cpu_timer_set(struct k_itimer *timer, int flags,
        if (CPUCLOCK_PERTHREAD(timer->it_clock)) {
                cpu_clock_sample(timer->it_clock, p, &val);
        } else {
-               cpu_clock_sample_group(timer->it_clock, p, &val);
+               cpu_timer_sample_group(timer->it_clock, p, &val);
        }
 
        if (old) {
@@ -889,7 +916,7 @@ void posix_cpu_timer_get(struct k_itimer *timer, struct itimerspec *itp)
                        read_unlock(&tasklist_lock);
                        goto dead;
                } else {
-                       cpu_clock_sample_group(timer->it_clock, p, &now);
+                       cpu_timer_sample_group(timer->it_clock, p, &now);
                        clear_dead = (unlikely(p->exit_state) &&
                                      thread_group_empty(p));
                }
@@ -1244,7 +1271,7 @@ void posix_cpu_timer_schedule(struct k_itimer *timer)
                        clear_dead_task(timer, now);
                        goto out_unlock;
                }
-               cpu_clock_sample_group(timer->it_clock, p, &now);
+               cpu_timer_sample_group(timer->it_clock, p, &now);
                bump_cpu_timer(timer, now);
                /* Leave the tasklist_lock locked for the call below.  */
        }
@@ -1408,33 +1435,6 @@ void run_posix_cpu_timers(struct task_struct *tsk)
        }
 }
 
-/*
- * Sample a process (thread group) timer for the given group_leader task.
- * Must be called with tasklist_lock held for reading.
- */
-static int cpu_timer_sample_group(const clockid_t which_clock,
-                                 struct task_struct *p,
-                                 union cpu_time_count *cpu)
-{
-       struct task_cputime cputime;
-
-       thread_group_cputimer(p, &cputime);
-       switch (CPUCLOCK_WHICH(which_clock)) {
-       default:
-               return -EINVAL;
-       case CPUCLOCK_PROF:
-               cpu->cpu = cputime_add(cputime.utime, cputime.stime);
-               break;
-       case CPUCLOCK_VIRT:
-               cpu->cpu = cputime.utime;
-               break;
-       case CPUCLOCK_SCHED:
-               cpu->sched = cputime.sum_exec_runtime + task_delta_exec(p);
-               break;
-       }
-       return 0;
-}
-
 /*
  * Set one of the process-wide special case CPU timers.
  * The tsk->sighand->siglock must be held by the caller.
index d7a10167a25b37d787418bfbee02e68ba4e28c55..720ea4f781bd4896ef8922b9e55442f447967ab5 100644 (file)
@@ -3,7 +3,7 @@ ifeq ($(CONFIG_PM_DEBUG),y)
 EXTRA_CFLAGS   +=      -DDEBUG
 endif
 
-obj-y                          := main.o
+obj-$(CONFIG_PM)               += main.o
 obj-$(CONFIG_PM_SLEEP)         += console.o
 obj-$(CONFIG_FREEZER)          += process.o
 obj-$(CONFIG_HIBERNATION)      += swsusp.o disk.o snapshot.o swap.o user.o
index b8628be2a465c4841ccc69135d91618b56b2d6ca..a3961b205de743c30f9588e02d28f1f959b46db6 100644 (file)
@@ -78,6 +78,12 @@ void pm_restore_console(void)
        }
        set_console(orig_fgconsole);
        release_console_sem();
+
+       if (vt_waitactive(orig_fgconsole)) {
+               pr_debug("Resume: Can't switch VCs.");
+               return;
+       }
+
        kmsg_redirect = orig_kmsg;
 }
 #endif
index 432ee575c9ee4fd201481a9ebdb674c29b96dab8..4a4a206b1979c657c887df31907166080a004d8f 100644 (file)
@@ -227,6 +227,12 @@ static int create_image(int platform_mode)
                        "aborting hibernation\n");
                goto Enable_irqs;
        }
+       sysdev_suspend(PMSG_FREEZE);
+       if (error) {
+               printk(KERN_ERR "PM: Some devices failed to power down, "
+                       "aborting hibernation\n");
+               goto Power_up_devices;
+       }
 
        if (hibernation_test(TEST_CORE))
                goto Power_up;
@@ -242,9 +248,11 @@ static int create_image(int platform_mode)
        if (!in_suspend)
                platform_leave(platform_mode);
  Power_up:
+       sysdev_resume();
        /* NOTE:  device_power_up() is just a resume() for devices
         * that suspended with irqs off ... no overall powerup.
         */
+ Power_up_devices:
        device_power_up(in_suspend ?
                (error ? PMSG_RECOVER : PMSG_THAW) : PMSG_RESTORE);
  Enable_irqs:
@@ -335,6 +343,7 @@ static int resume_target_kernel(void)
                        "aborting resume\n");
                goto Enable_irqs;
        }
+       sysdev_suspend(PMSG_QUIESCE);
        /* We'll ignore saved state, but this gets preempt count (etc) right */
        save_processor_state();
        error = restore_highmem();
@@ -357,6 +366,7 @@ static int resume_target_kernel(void)
        swsusp_free();
        restore_processor_state();
        touch_softlockup_watchdog();
+       sysdev_resume();
        device_power_up(PMSG_RECOVER);
  Enable_irqs:
        local_irq_enable();
@@ -440,6 +450,7 @@ int hibernation_platform_enter(void)
        local_irq_disable();
        error = device_power_down(PMSG_HIBERNATE);
        if (!error) {
+               sysdev_suspend(PMSG_HIBERNATE);
                hibernation_ops->enter();
                /* We should never get here */
                while (1);
@@ -594,6 +605,12 @@ static int software_resume(void)
        int error;
        unsigned int flags;
 
+       /*
+        * If the user said "noresume".. bail out early.
+        */
+       if (noresume)
+               return 0;
+
        /*
         * name_to_dev_t() below takes a sysfs buffer mutex when sysfs
         * is configured into the kernel. Since the regular hibernate
@@ -610,6 +627,11 @@ static int software_resume(void)
                        mutex_unlock(&pm_mutex);
                        return -ENOENT;
                }
+               /*
+                * Some device discovery might still be in progress; we need
+                * to wait for this to finish.
+                */
+               wait_for_device_probe();
                swsusp_resume_device = name_to_dev_t(resume_file);
                pr_debug("PM: Resume from partition %s\n", resume_file);
        } else {
index b4d219016b6ca351f19ad2a08e6f7c9aada2ab7e..c9632f841f646fbfc146ecee855fd04068a548ae 100644 (file)
@@ -298,8 +298,12 @@ static int suspend_enter(suspend_state_t state)
                goto Done;
        }
 
-       if (!suspend_test(TEST_CORE))
-               error = suspend_ops->enter(state);
+       error = sysdev_suspend(PMSG_SUSPEND);
+       if (!error) {
+               if (!suspend_test(TEST_CORE))
+                       error = suspend_ops->enter(state);
+               sysdev_resume();
+       }
 
        device_power_up(PMSG_RESUME);
  Done:
index 6da14358537c8779db14f4ccab91a64365270d16..505f319e489c901ad0fbba6fecd1b508246fec14 100644 (file)
@@ -60,6 +60,7 @@ static struct block_device *resume_bdev;
 static int submit(int rw, pgoff_t page_off, struct page *page,
                        struct bio **bio_chain)
 {
+       const int bio_rw = rw | (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG);
        struct bio *bio;
 
        bio = bio_alloc(__GFP_WAIT | __GFP_HIGH, 1);
@@ -80,7 +81,7 @@ static int submit(int rw, pgoff_t page_off, struct page *page,
        bio_get(bio);
 
        if (bio_chain == NULL) {
-               submit_bio(rw | (1 << BIO_RW_SYNC), bio);
+               submit_bio(bio_rw, bio);
                wait_on_page_locked(page);
                if (rw == READ)
                        bio_set_pages_dirty(bio);
@@ -90,7 +91,7 @@ static int submit(int rw, pgoff_t page_off, struct page *page,
                        get_page(page); /* These pages are freed later */
                bio->bi_private = *bio_chain;
                *bio_chain = bio;
-               submit_bio(rw | (1 << BIO_RW_SYNC), bio);
+               submit_bio(bio_rw, bio);
        }
        return 0;
 }
index 005b93d839ba1268da0c80c3106739ee388d996a..6c85359364f2bcfd31bb06e77ec0eda7585e08dc 100644 (file)
@@ -95,15 +95,15 @@ static int snapshot_open(struct inode *inode, struct file *filp)
                data->swap = swsusp_resume_device ?
                        swap_type_of(swsusp_resume_device, 0, NULL) : -1;
                data->mode = O_RDONLY;
-               error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
+               error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
                if (error)
-                       pm_notifier_call_chain(PM_POST_RESTORE);
+                       pm_notifier_call_chain(PM_POST_HIBERNATION);
        } else {
                data->swap = -1;
                data->mode = O_WRONLY;
-               error = pm_notifier_call_chain(PM_HIBERNATION_PREPARE);
+               error = pm_notifier_call_chain(PM_RESTORE_PREPARE);
                if (error)
-                       pm_notifier_call_chain(PM_POST_HIBERNATION);
+                       pm_notifier_call_chain(PM_POST_RESTORE);
        }
        if (error)
                atomic_inc(&snapshot_device_available);
index 69188f226a93251009d22d6dc453ce3d59220816..e3602d0755b0dd99c9fb47887fd67d371cdd5424 100644 (file)
@@ -73,7 +73,6 @@ EXPORT_SYMBOL(oops_in_progress);
  * driver system.
  */
 static DECLARE_MUTEX(console_sem);
-static DECLARE_MUTEX(secondary_console_sem);
 struct console *console_drivers;
 EXPORT_SYMBOL_GPL(console_drivers);
 
@@ -891,12 +890,14 @@ void suspend_console(void)
        printk("Suspending console(s) (use no_console_suspend to debug)\n");
        acquire_console_sem();
        console_suspended = 1;
+       up(&console_sem);
 }
 
 void resume_console(void)
 {
        if (!console_suspend_enabled)
                return;
+       down(&console_sem);
        console_suspended = 0;
        release_console_sem();
 }
@@ -912,11 +913,9 @@ void resume_console(void)
 void acquire_console_sem(void)
 {
        BUG_ON(in_interrupt());
-       if (console_suspended) {
-               down(&secondary_console_sem);
-               return;
-       }
        down(&console_sem);
+       if (console_suspended)
+               return;
        console_locked = 1;
        console_may_schedule = 1;
 }
@@ -926,6 +925,10 @@ int try_acquire_console_sem(void)
 {
        if (down_trylock(&console_sem))
                return -1;
+       if (console_suspended) {
+               up(&console_sem);
+               return -1;
+       }
        console_locked = 1;
        console_may_schedule = 0;
        return 0;
@@ -979,7 +982,7 @@ void release_console_sem(void)
        unsigned wake_klogd = 0;
 
        if (console_suspended) {
-               up(&secondary_console_sem);
+               up(&console_sem);
                return;
        }
 
index bd5a9003497c200d7ef7a44ec252b2d96b2ac562..654c640a6b9c137b6a44c1e57159fbdeeac48b61 100644 (file)
@@ -679,8 +679,8 @@ int rcu_needs_cpu(int cpu)
 void rcu_check_callbacks(int cpu, int user)
 {
        if (user ||
-           (idle_cpu(cpu) && !in_softirq() &&
-                               hardirq_count() <= (1 << HARDIRQ_SHIFT))) {
+           (idle_cpu(cpu) && rcu_scheduler_active &&
+            !in_softirq() && hardirq_count() <= (1 << HARDIRQ_SHIFT))) {
 
                /*
                 * Get here if this CPU took its interrupt from user
index d92a76a881aa47a9aa059c3221910834f6c50cf8..cae8a059cf47f4fab142b001c5f4d25ec8e95006 100644 (file)
@@ -44,6 +44,7 @@
 #include <linux/cpu.h>
 #include <linux/mutex.h>
 #include <linux/module.h>
+#include <linux/kernel_stat.h>
 
 enum rcu_barrier {
        RCU_BARRIER_STD,
@@ -55,6 +56,7 @@ static DEFINE_PER_CPU(struct rcu_head, rcu_barrier_head) = {NULL};
 static atomic_t rcu_barrier_cpu_count;
 static DEFINE_MUTEX(rcu_barrier_mutex);
 static struct completion rcu_barrier_completion;
+int rcu_scheduler_active __read_mostly;
 
 /*
  * Awaken the corresponding synchronize_rcu() instance now that a
@@ -80,6 +82,10 @@ void wakeme_after_rcu(struct rcu_head  *head)
 void synchronize_rcu(void)
 {
        struct rcu_synchronize rcu;
+
+       if (rcu_blocking_is_gp())
+               return;
+
        init_completion(&rcu.completion);
        /* Will wake me after RCU finished. */
        call_rcu(&rcu.head, wakeme_after_rcu);
@@ -175,3 +181,9 @@ void __init rcu_init(void)
        __rcu_init();
 }
 
+void rcu_scheduler_starting(void)
+{
+       WARN_ON(num_online_cpus() != 1);
+       WARN_ON(nr_context_switches() > 0);
+       rcu_scheduler_active = 1;
+}
index 33cfc50781f9968d06e79edcb93049441a2a4231..5d59e850fb71f6f58b854cdbd0a1f1792f59c8ad 100644 (file)
@@ -1181,6 +1181,9 @@ void __synchronize_sched(void)
 {
        struct rcu_synchronize rcu;
 
+       if (num_online_cpus() == 1)
+               return;  /* blocking is gp if only one CPU! */
+
        init_completion(&rcu.completion);
        /* Will wake me after RCU finished. */
        call_rcu_sched(&rcu.head, wakeme_after_rcu);
index b2fd602a6f6f0433553a36a79e3a24172a8a2a2f..97ce31579ec0664682e1b2efb792cd77e7c0030e 100644 (file)
@@ -948,8 +948,8 @@ static void rcu_do_batch(struct rcu_data *rdp)
 void rcu_check_callbacks(int cpu, int user)
 {
        if (user ||
-           (idle_cpu(cpu) && !in_softirq() &&
-                               hardirq_count() <= (1 << HARDIRQ_SHIFT))) {
+           (idle_cpu(cpu) && rcu_scheduler_active &&
+            !in_softirq() && hardirq_count() <= (1 << HARDIRQ_SHIFT))) {
 
                /*
                 * Get here if this CPU took its interrupt from user
index c1d0ed360088f5a5378ae4b6db9555e7e0b90f21..8e2558c2ba67be440ef7bcb2d95ff8138c806404 100644 (file)
@@ -223,7 +223,7 @@ static void start_rt_bandwidth(struct rt_bandwidth *rt_b)
 {
        ktime_t now;
 
-       if (rt_bandwidth_enabled() && rt_b->rt_runtime == RUNTIME_INF)
+       if (!rt_bandwidth_enabled() || rt_b->rt_runtime == RUNTIME_INF)
                return;
 
        if (hrtimer_active(&rt_b->rt_period_timer))
@@ -6944,20 +6944,26 @@ static void free_rootdomain(struct root_domain *rd)
 
 static void rq_attach_root(struct rq *rq, struct root_domain *rd)
 {
+       struct root_domain *old_rd = NULL;
        unsigned long flags;
 
        spin_lock_irqsave(&rq->lock, flags);
 
        if (rq->rd) {
-               struct root_domain *old_rd = rq->rd;
+               old_rd = rq->rd;
 
                if (cpumask_test_cpu(rq->cpu, old_rd->online))
                        set_rq_offline(rq);
 
                cpumask_clear_cpu(rq->cpu, old_rd->span);
 
-               if (atomic_dec_and_test(&old_rd->refcount))
-                       free_rootdomain(old_rd);
+               /*
+                * If we dont want to free the old_rt yet then
+                * set old_rd to NULL to skip the freeing later
+                * in this function:
+                */
+               if (!atomic_dec_and_test(&old_rd->refcount))
+                       old_rd = NULL;
        }
 
        atomic_inc(&rd->refcount);
@@ -6968,6 +6974,9 @@ static void rq_attach_root(struct rq *rq, struct root_domain *rd)
                set_rq_online(rq);
 
        spin_unlock_irqrestore(&rq->lock, flags);
+
+       if (old_rd)
+               free_rootdomain(old_rd);
 }
 
 static int __init_refok init_rootdomain(struct root_domain *rd, bool bootmem)
@@ -9215,6 +9224,16 @@ static int sched_rt_global_constraints(void)
 
        return ret;
 }
+
+int sched_rt_can_attach(struct task_group *tg, struct task_struct *tsk)
+{
+       /* Don't accept realtime tasks when there is no way for them to run */
+       if (rt_task(tsk) && tg->rt_bandwidth.rt_runtime == 0)
+               return 0;
+
+       return 1;
+}
+
 #else /* !CONFIG_RT_GROUP_SCHED */
 static int sched_rt_global_constraints(void)
 {
@@ -9308,8 +9327,7 @@ cpu_cgroup_can_attach(struct cgroup_subsys *ss, struct cgroup *cgrp,
                      struct task_struct *tsk)
 {
 #ifdef CONFIG_RT_GROUP_SCHED
-       /* Don't accept realtime tasks when there is no way for them to run */
-       if (rt_task(tsk) && cgroup_tg(cgrp)->rt_bandwidth.rt_runtime == 0)
+       if (!sched_rt_can_attach(cgroup_tg(cgrp), tsk))
                return -EINVAL;
 #else
        /* We don't support RT-tasks being in separate groups */
index ad64fcb731f231d22e539d0e1b094cdd59c7d759..57d4b13b631de36161349feb99ae6f76a2984b06 100644 (file)
@@ -8,6 +8,7 @@
 
 #include <linux/seccomp.h>
 #include <linux/sched.h>
+#include <linux/compat.h>
 
 /* #define SECCOMP_DEBUG 1 */
 #define NR_SECCOMP_MODES 1
@@ -22,7 +23,7 @@ static int mode1_syscalls[] = {
        0, /* null terminated */
 };
 
-#ifdef TIF_32BIT
+#ifdef CONFIG_COMPAT
 static int mode1_syscalls_32[] = {
        __NR_seccomp_read_32, __NR_seccomp_write_32, __NR_seccomp_exit_32, __NR_seccomp_sigreturn_32,
        0, /* null terminated */
@@ -37,8 +38,8 @@ void __secure_computing(int this_syscall)
        switch (mode) {
        case 1:
                syscall = mode1_syscalls;
-#ifdef TIF_32BIT
-               if (test_thread_flag(TIF_32BIT))
+#ifdef CONFIG_COMPAT
+               if (is_compat_task())
                        syscall = mode1_syscalls_32;
 #endif
                do {
index f145c415bc160e62b6d888cf6fa9d3198c00b4a7..37f458e6882adbd1f2b0697e5077c92e4252e03f 100644 (file)
@@ -559,7 +559,7 @@ error:
        abort_creds(new);
        return retval;
 }
-  
+
 /*
  * change the user struct in a credentials set to match the new UID
  */
@@ -571,6 +571,11 @@ static int set_user(struct cred *new)
        if (!new_user)
                return -EAGAIN;
 
+       if (!task_can_switch_user(new_user, current)) {
+               free_uid(new_user);
+               return -EINVAL;
+       }
+
        if (atomic_read(&new_user->processes) >=
                                current->signal->rlim[RLIMIT_NPROC].rlim_cur &&
                        new_user != INIT_USER) {
@@ -631,10 +636,11 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, uid_t, euid)
                        goto error;
        }
 
-       retval = -EAGAIN;
-       if (new->uid != old->uid && set_user(new) < 0)
-               goto error;
-
+       if (new->uid != old->uid) {
+               retval = set_user(new);
+               if (retval < 0)
+                       goto error;
+       }
        if (ruid != (uid_t) -1 ||
            (euid != (uid_t) -1 && euid != old->uid))
                new->suid = new->euid;
@@ -680,9 +686,10 @@ SYSCALL_DEFINE1(setuid, uid_t, uid)
        retval = -EPERM;
        if (capable(CAP_SETUID)) {
                new->suid = new->uid = uid;
-               if (uid != old->uid && set_user(new) < 0) {
-                       retval = -EAGAIN;
-                       goto error;
+               if (uid != old->uid) {
+                       retval = set_user(new);
+                       if (retval < 0)
+                               goto error;
                }
        } else if (uid != old->uid && uid != new->suid) {
                goto error;
@@ -734,11 +741,13 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, uid_t, euid, uid_t, suid)
                        goto error;
        }
 
-       retval = -EAGAIN;
        if (ruid != (uid_t) -1) {
                new->uid = ruid;
-               if (ruid != old->uid && set_user(new) < 0)
-                       goto error;
+               if (ruid != old->uid) {
+                       retval = set_user(new);
+                       if (retval < 0)
+                               goto error;
+               }
        }
        if (euid != (uid_t) -1)
                new->euid = euid;
index e2a4ff6fc3a6bb1509472dad03d0ad41df855748..34e707e5ab87f002ab93f0eb70e776cb09704354 100644 (file)
@@ -52,6 +52,7 @@ config FUNCTION_TRACER
        depends on HAVE_FUNCTION_TRACER
        depends on DEBUG_KERNEL
        select FRAME_POINTER
+       select KALLSYMS
        select TRACING
        select CONTEXT_SWITCH_TRACER
        help
@@ -238,6 +239,7 @@ config STACK_TRACER
        depends on DEBUG_KERNEL
        select FUNCTION_TRACER
        select STACKTRACE
+       select KALLSYMS
        help
          This special tracer records the maximum stack footprint of the
          kernel and displays it in debugfs/tracing/stack_trace.
@@ -302,4 +304,27 @@ config FTRACE_STARTUP_TEST
          functioning properly. It will do tests on all the configured
          tracers of ftrace.
 
+config MMIOTRACE
+       bool "Memory mapped IO tracing"
+       depends on HAVE_MMIOTRACE_SUPPORT && DEBUG_KERNEL && PCI
+       select TRACING
+       help
+         Mmiotrace traces Memory Mapped I/O access and is meant for
+         debugging and reverse engineering. It is called from the ioremap
+         implementation and works via page faults. Tracing is disabled by
+         default and can be enabled at run-time.
+
+         See Documentation/tracers/mmiotrace.txt.
+         If you are not helping to develop drivers, say N.
+
+config MMIOTRACE_TEST
+       tristate "Test module for mmiotrace"
+       depends on MMIOTRACE && m
+       help
+         This is a dumb module for testing mmiotrace. It is very dangerous
+         as it will write garbage to IO memory starting at a given address.
+         However, it should be safe to use on e.g. unused portion of VRAM.
+
+         Say N, unless you absolutely know what you are doing.
+
 endmenu
index 9a236ffe2aa45188cacabfc8fbc15e81c6091f64..fdf913dfc7e8eada7de16b320b62d283b18447a5 100644 (file)
@@ -2033,7 +2033,7 @@ free:
 static int start_graph_tracing(void)
 {
        struct ftrace_ret_stack **ret_stack_list;
-       int ret;
+       int ret, cpu;
 
        ret_stack_list = kmalloc(FTRACE_RETSTACK_ALLOC_SIZE *
                                sizeof(struct ftrace_ret_stack *),
@@ -2042,6 +2042,10 @@ static int start_graph_tracing(void)
        if (!ret_stack_list)
                return -ENOMEM;
 
+       /* The cpu_boot init_task->ret_stack will never be freed */
+       for_each_online_cpu(cpu)
+               ftrace_graph_init_task(idle_task(cpu));
+
        do {
                ret = alloc_retstack_tasklist(ret_stack_list);
        } while (ret == -EAGAIN);
index fffcb069f1dcb48213ec0c51a4c8d1774e8235a4..80e503ef6136c208cef128006578ec7227a35678 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/kernel.h>
 #include <linux/mmiotrace.h>
 #include <linux/pci.h>
+#include <asm/atomic.h>
 
 #include "trace.h"
 
@@ -19,6 +20,7 @@ struct header_iter {
 static struct trace_array *mmio_trace_array;
 static bool overrun_detected;
 static unsigned long prev_overruns;
+static atomic_t dropped_count;
 
 static void mmio_reset_data(struct trace_array *tr)
 {
@@ -121,11 +123,11 @@ static void mmio_close(struct trace_iterator *iter)
 
 static unsigned long count_overruns(struct trace_iterator *iter)
 {
-       unsigned long cnt = 0;
+       unsigned long cnt = atomic_xchg(&dropped_count, 0);
        unsigned long over = ring_buffer_overruns(iter->tr->buffer);
 
        if (over > prev_overruns)
-               cnt = over - prev_overruns;
+               cnt += over - prev_overruns;
        prev_overruns = over;
        return cnt;
 }
@@ -310,8 +312,10 @@ static void __trace_mmiotrace_rw(struct trace_array *tr,
 
        event   = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
                                           &irq_flags);
-       if (!event)
+       if (!event) {
+               atomic_inc(&dropped_count);
                return;
+       }
        entry   = ring_buffer_event_data(event);
        tracing_generic_entry_update(&entry->ent, 0, preempt_count());
        entry->ent.type                 = TRACE_MMIO_RW;
@@ -338,8 +342,10 @@ static void __trace_mmiotrace_map(struct trace_array *tr,
 
        event   = ring_buffer_lock_reserve(tr->buffer, sizeof(*entry),
                                           &irq_flags);
-       if (!event)
+       if (!event) {
+               atomic_inc(&dropped_count);
                return;
+       }
        entry   = ring_buffer_event_data(event);
        tracing_generic_entry_update(&entry->ent, 0, preempt_count());
        entry->ent.type                 = TRACE_MMIO_MAP;
index 88c8eb70f54aeb3508dda9c668f082b9a43b0c78..bc8e80a86bca4c0cf730fcf6b7bc568f2808f7e7 100644 (file)
@@ -23,10 +23,20 @@ static int trace_test_buffer_cpu(struct trace_array *tr, int cpu)
 {
        struct ring_buffer_event *event;
        struct trace_entry *entry;
+       unsigned int loops = 0;
 
        while ((event = ring_buffer_consume(tr->buffer, cpu, NULL))) {
                entry = ring_buffer_event_data(event);
 
+               /*
+                * The ring buffer is a size of trace_buf_size, if
+                * we loop more than the size, there's something wrong
+                * with the ring buffer.
+                */
+               if (loops++ > trace_buf_size) {
+                       printk(KERN_CONT ".. bad ring buffer ");
+                       goto failed;
+               }
                if (!trace_valid_entry(entry)) {
                        printk(KERN_CONT ".. invalid entry %d ",
                                entry->type);
@@ -57,11 +67,20 @@ static int trace_test_buffer(struct trace_array *tr, unsigned long *count)
 
        cnt = ring_buffer_entries(tr->buffer);
 
+       /*
+        * The trace_test_buffer_cpu runs a while loop to consume all data.
+        * If the calling tracer is broken, and is constantly filling
+        * the buffer, this will run forever, and hard lock the box.
+        * We disable the ring buffer while we do this test to prevent
+        * a hard lock up.
+        */
+       tracing_off();
        for_each_possible_cpu(cpu) {
                ret = trace_test_buffer_cpu(tr, cpu);
                if (ret)
                        break;
        }
+       tracing_on();
        __raw_spin_unlock(&ftrace_max_lock);
        local_irq_restore(flags);
 
index 3551ac742395c40af9edeb7d94d0d0b936caba9b..6a9b696128c855f9ddacfc9e3a7a128141379e49 100644 (file)
@@ -362,6 +362,24 @@ static void free_user(struct user_struct *up, unsigned long flags)
 
 #endif
 
+#if defined(CONFIG_RT_GROUP_SCHED) && defined(CONFIG_USER_SCHED)
+/*
+ * We need to check if a setuid can take place. This function should be called
+ * before successfully completing the setuid.
+ */
+int task_can_switch_user(struct user_struct *up, struct task_struct *tsk)
+{
+
+       return sched_rt_can_attach(up->tg, tsk);
+
+}
+#else
+int task_can_switch_user(struct user_struct *up, struct task_struct *tsk)
+{
+       return 1;
+}
+#endif
+
 /*
  * Locate the user_struct for the passed UID.  If found, take a ref on it.  The
  * caller must undo that ref with free_uid().
index 79084311ee5779a1e12b411ff37a5f04da08e360..076c7c8215b0e15289130fa5339bfc26dced7514 100644 (file)
@@ -60,12 +60,25 @@ int create_user_ns(struct cred *new)
        return 0;
 }
 
-void free_user_ns(struct kref *kref)
+/*
+ * Deferred destructor for a user namespace.  This is required because
+ * free_user_ns() may be called with uidhash_lock held, but we need to call
+ * back to free_uid() which will want to take the lock again.
+ */
+static void free_user_ns_work(struct work_struct *work)
 {
-       struct user_namespace *ns;
-
-       ns = container_of(kref, struct user_namespace, kref);
+       struct user_namespace *ns =
+               container_of(work, struct user_namespace, destroyer);
        free_uid(ns->creator);
        kfree(ns);
 }
+
+void free_user_ns(struct kref *kref)
+{
+       struct user_namespace *ns =
+               container_of(kref, struct user_namespace, kref);
+
+       INIT_WORK(&ns->destroyer, free_user_ns_work);
+       schedule_work(&ns->destroyer);
+}
 EXPORT_SYMBOL(free_user_ns);
index 29044f500269c3b9ad9b834adc21a77557ac897b..1bcf9cd4baa08a85633e5758721b7ef21f4df787 100644 (file)
@@ -838,7 +838,7 @@ config FIREWIRE_OHCI_REMOTE_DMA
 
          If unsure, say N.
 
-menuconfig BUILD_DOCSRC
+config BUILD_DOCSRC
        bool "Build targets in Documentation/ tree"
        depends on HEADERS_CHECK
        help
index 037161d61b4e72432d9d6bae71507d251b522afc..cbe9e0581b75dcaf06335ccc017a68789d6247d2 100644 (file)
@@ -660,7 +660,7 @@ void *alloc_locked_buffer(size_t size)
        return buffer;
 }
 
-void free_locked_buffer(void *buffer, size_t size)
+void release_locked_buffer(void *buffer, size_t size)
 {
        unsigned long pgsz = PAGE_ALIGN(size) >> PAGE_SHIFT;
 
@@ -670,6 +670,11 @@ void free_locked_buffer(void *buffer, size_t size)
        current->mm->locked_vm -= pgsz;
 
        up_write(&current->mm->mmap_sem);
+}
+
+void free_locked_buffer(void *buffer, size_t size)
+{
+       release_locked_buffer(buffer, size);
 
        kfree(buffer);
 }
index 3c84128596ba88892cd1394e334d6c0c5bd12e3d..74dc57c74349ff124dd31a3e04531ee503ecedca 100644 (file)
@@ -240,7 +240,7 @@ void bdi_writeout_inc(struct backing_dev_info *bdi)
 }
 EXPORT_SYMBOL_GPL(bdi_writeout_inc);
 
-static inline void task_dirty_inc(struct task_struct *tsk)
+void task_dirty_inc(struct task_struct *tsk)
 {
        prop_inc_single(&vm_dirties, &tsk->dirties);
 }
@@ -1230,6 +1230,7 @@ int __set_page_dirty_nobuffers(struct page *page)
                                __inc_zone_page_state(page, NR_FILE_DIRTY);
                                __inc_bdi_stat(mapping->backing_dev_info,
                                                BDI_RECLAIMABLE);
+                               task_dirty_inc(current);
                                task_io_account_write(PAGE_CACHE_SIZE);
                        }
                        radix_tree_tag_set(&mapping->page_tree,
@@ -1262,7 +1263,7 @@ EXPORT_SYMBOL(redirty_page_for_writepage);
  * If the mapping doesn't provide a set_page_dirty a_op, then
  * just fall through and assume that it wants buffer_heads.
  */
-static int __set_page_dirty(struct page *page)
+int set_page_dirty(struct page *page)
 {
        struct address_space *mapping = page_mapping(page);
 
@@ -1280,14 +1281,6 @@ static int __set_page_dirty(struct page *page)
        }
        return 0;
 }
-
-int set_page_dirty(struct page *page)
-{
-       int ret = __set_page_dirty(page);
-       if (ret)
-               task_dirty_inc(current);
-       return ret;
-}
 EXPORT_SYMBOL(set_page_dirty);
 
 /*
index 5675b30738546451c47771e5703f06830a63898a..5c44ed49ca93c5a1d7a39f5570b0d1254a45de80 100644 (file)
@@ -2989,7 +2989,7 @@ static int __meminit next_active_region_index_in_nid(int index, int nid)
  * was used and there are no special requirements, this is a convenient
  * alternative
  */
-int __meminit early_pfn_to_nid(unsigned long pfn)
+int __meminit __early_pfn_to_nid(unsigned long pfn)
 {
        int i;
 
@@ -3000,10 +3000,33 @@ int __meminit early_pfn_to_nid(unsigned long pfn)
                if (start_pfn <= pfn && pfn < end_pfn)
                        return early_node_map[i].nid;
        }
+       /* This is a memory hole */
+       return -1;
+}
+#endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */
+
+int __meminit early_pfn_to_nid(unsigned long pfn)
+{
+       int nid;
 
+       nid = __early_pfn_to_nid(pfn);
+       if (nid >= 0)
+               return nid;
+       /* just returns 0 */
        return 0;
 }
-#endif /* CONFIG_HAVE_ARCH_EARLY_PFN_TO_NID */
+
+#ifdef CONFIG_NODES_SPAN_OTHER_NODES
+bool __meminit early_pfn_in_nid(unsigned long pfn, int node)
+{
+       int nid;
+
+       nid = __early_pfn_to_nid(pfn);
+       if (nid >= 0 && nid != node)
+               return false;
+       return true;
+}
+#endif
 
 /* Basic iterator support to walk early_node_map[] */
 #define for_each_active_range_index_in_nid(i, nid) \
index dc6ce0afbded84abdfa553300e6ac9d06e00d0a9..3023c475e0415fc0c6ec537a556e6d3835a2b1d9 100644 (file)
@@ -111,7 +111,7 @@ int swap_writepage(struct page *page, struct writeback_control *wbc)
                goto out;
        }
        if (wbc->sync_mode == WB_SYNC_ALL)
-               rw |= (1 << BIO_RW_SYNC);
+               rw |= (1 << BIO_RW_SYNCIO) | (1 << BIO_RW_UNPLUG);
        count_vm_event(PSWPOUT);
        set_page_writeback(page);
        unlock_page(page);
index 19d566ccdeeab8c6a1f0431602b3bd3dd5a76026..4103a239ce843326faca51c61c5b0b105797b24b 100644 (file)
@@ -169,13 +169,13 @@ static inline struct shmem_sb_info *SHMEM_SB(struct super_block *sb)
  */
 static inline int shmem_acct_size(unsigned long flags, loff_t size)
 {
-       return (flags & VM_ACCOUNT) ?
-               security_vm_enough_memory_kern(VM_ACCT(size)) : 0;
+       return (flags & VM_NORESERVE) ?
+               0 : security_vm_enough_memory_kern(VM_ACCT(size));
 }
 
 static inline void shmem_unacct_size(unsigned long flags, loff_t size)
 {
-       if (flags & VM_ACCOUNT)
+       if (!(flags & VM_NORESERVE))
                vm_unacct_memory(VM_ACCT(size));
 }
 
@@ -187,13 +187,13 @@ static inline void shmem_unacct_size(unsigned long flags, loff_t size)
  */
 static inline int shmem_acct_block(unsigned long flags)
 {
-       return (flags & VM_ACCOUNT) ?
-               0 : security_vm_enough_memory_kern(VM_ACCT(PAGE_CACHE_SIZE));
+       return (flags & VM_NORESERVE) ?
+               security_vm_enough_memory_kern(VM_ACCT(PAGE_CACHE_SIZE)) : 0;
 }
 
 static inline void shmem_unacct_blocks(unsigned long flags, long pages)
 {
-       if (!(flags & VM_ACCOUNT))
+       if (flags & VM_NORESERVE)
                vm_unacct_memory(pages * VM_ACCT(PAGE_CACHE_SIZE));
 }
 
@@ -1515,8 +1515,8 @@ static int shmem_mmap(struct file *file, struct vm_area_struct *vma)
        return 0;
 }
 
-static struct inode *
-shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
+static struct inode *shmem_get_inode(struct super_block *sb, int mode,
+                                       dev_t dev, unsigned long flags)
 {
        struct inode *inode;
        struct shmem_inode_info *info;
@@ -1537,6 +1537,7 @@ shmem_get_inode(struct super_block *sb, int mode, dev_t dev)
                info = SHMEM_I(inode);
                memset(info, 0, (char *)inode - (char *)info);
                spin_lock_init(&info->lock);
+               info->flags = flags & VM_NORESERVE;
                INIT_LIST_HEAD(&info->swaplist);
 
                switch (mode & S_IFMT) {
@@ -1779,9 +1780,10 @@ static int shmem_statfs(struct dentry *dentry, struct kstatfs *buf)
 static int
 shmem_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev)
 {
-       struct inode *inode = shmem_get_inode(dir->i_sb, mode, dev);
+       struct inode *inode;
        int error = -ENOSPC;
 
+       inode = shmem_get_inode(dir->i_sb, mode, dev, VM_NORESERVE);
        if (inode) {
                error = security_inode_init_security(inode, dir, NULL, NULL,
                                                     NULL);
@@ -1920,7 +1922,7 @@ static int shmem_symlink(struct inode *dir, struct dentry *dentry, const char *s
        if (len > PAGE_CACHE_SIZE)
                return -ENAMETOOLONG;
 
-       inode = shmem_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0);
+       inode = shmem_get_inode(dir->i_sb, S_IFLNK|S_IRWXUGO, 0, VM_NORESERVE);
        if (!inode)
                return -ENOSPC;
 
@@ -2332,7 +2334,7 @@ static int shmem_fill_super(struct super_block *sb,
        sb->s_flags |= MS_POSIXACL;
 #endif
 
-       inode = shmem_get_inode(sb, S_IFDIR | sbinfo->mode, 0);
+       inode = shmem_get_inode(sb, S_IFDIR | sbinfo->mode, 0, VM_NORESERVE);
        if (!inode)
                goto failed;
        inode->i_uid = sbinfo->uid;
@@ -2574,12 +2576,12 @@ int shmem_unuse(swp_entry_t entry, struct page *page)
        return 0;
 }
 
-#define shmem_file_operations ramfs_file_operations
-#define shmem_vm_ops generic_file_vm_ops
-#define shmem_get_inode ramfs_get_inode
-#define shmem_acct_size(a, b) 0
-#define shmem_unacct_size(a, b) do {} while (0)
-#define SHMEM_MAX_BYTES LLONG_MAX
+#define shmem_vm_ops                           generic_file_vm_ops
+#define shmem_file_operations                  ramfs_file_operations
+#define shmem_get_inode(sb, mode, dev, flags)  ramfs_get_inode(sb, mode, dev)
+#define shmem_acct_size(flags, size)           0
+#define shmem_unacct_size(flags, size)         do {} while (0)
+#define SHMEM_MAX_BYTES                                LLONG_MAX
 
 #endif /* CONFIG_SHMEM */
 
@@ -2589,7 +2591,7 @@ int shmem_unuse(swp_entry_t entry, struct page *page)
  * shmem_file_setup - get an unlinked file living in tmpfs
  * @name: name for dentry (to be seen in /proc/<pid>/maps
  * @size: size to be set for the file
- * @flags: vm_flags
+ * @flags: VM_NORESERVE suppresses pre-accounting of the entire object size
  */
 struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags)
 {
@@ -2623,13 +2625,10 @@ struct file *shmem_file_setup(char *name, loff_t size, unsigned long flags)
                goto put_dentry;
 
        error = -ENOSPC;
-       inode = shmem_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0);
+       inode = shmem_get_inode(root->d_sb, S_IFREG | S_IRWXUGO, 0, flags);
        if (!inode)
                goto close_file;
 
-#ifdef CONFIG_SHMEM
-       SHMEM_I(inode)->flags = (flags & VM_NORESERVE) ? 0 : VM_ACCOUNT;
-#endif
        d_instantiate(dentry, inode);
        inode->i_size = size;
        inode->i_nlink = 0;     /* It is unlinked */
index 7e6304dfafab174884bad5820a0194f449906a32..312fafe0ab6ed4815ac02da3f712aca18bacbbad 100644 (file)
@@ -635,7 +635,7 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p)
 
                if (!bdev) {
                        if (bdev_p)
-                               *bdev_p = sis->bdev;
+                               *bdev_p = bdget(sis->bdev->bd_dev);
 
                        spin_unlock(&swap_lock);
                        return i;
@@ -647,7 +647,7 @@ int swap_type_of(dev_t device, sector_t offset, struct block_device **bdev_p)
                                        struct swap_extent, list);
                        if (se->start_block == offset) {
                                if (bdev_p)
-                                       *bdev_p = sis->bdev;
+                                       *bdev_p = bdget(sis->bdev->bd_dev);
 
                                spin_unlock(&swap_lock);
                                bdput(bdev);
index cb00b748ce47886446975d96466c2154f4d52fa3..37eaccdf3054e13d60cd83cf5c6cb9869731aec1 100644 (file)
--- a/mm/util.c
+++ b/mm/util.c
@@ -129,6 +129,26 @@ void *krealloc(const void *p, size_t new_size, gfp_t flags)
 }
 EXPORT_SYMBOL(krealloc);
 
+/**
+ * kzfree - like kfree but zero memory
+ * @p: object to free memory of
+ *
+ * The memory of the object @p points to is zeroed before freed.
+ * If @p is %NULL, kzfree() does nothing.
+ */
+void kzfree(const void *p)
+{
+       size_t ks;
+       void *mem = (void *)p;
+
+       if (unlikely(ZERO_OR_NULL_PTR(mem)))
+               return;
+       ks = ksize(mem);
+       memset(mem, 0, ks);
+       kfree(mem);
+}
+EXPORT_SYMBOL(kzfree);
+
 /*
  * strndup_user - duplicate an existing string from user space
  * @s: The string to duplicate
index 75f49d312e8c1d47648f3e96b8a1eb6d14076405..520a7598026995c1aafe82dfbf523e9fcb7143a2 100644 (file)
@@ -323,6 +323,7 @@ static struct vmap_area *alloc_vmap_area(unsigned long size,
        unsigned long addr;
        int purged = 0;
 
+       BUG_ON(!size);
        BUG_ON(size & ~PAGE_MASK);
 
        va = kmalloc_node(sizeof(struct vmap_area),
@@ -334,6 +335,9 @@ retry:
        addr = ALIGN(vstart, align);
 
        spin_lock(&vmap_area_lock);
+       if (addr + size - 1 < addr)
+               goto overflow;
+
        /* XXX: could have a last_hole cache */
        n = vmap_area_root.rb_node;
        if (n) {
@@ -365,6 +369,8 @@ retry:
 
                while (addr + size > first->va_start && addr + size <= vend) {
                        addr = ALIGN(first->va_end + PAGE_SIZE, align);
+                       if (addr + size - 1 < addr)
+                               goto overflow;
 
                        n = rb_next(&first->rb_node);
                        if (n)
@@ -375,6 +381,7 @@ retry:
        }
 found:
        if (addr + size > vend) {
+overflow:
                spin_unlock(&vmap_area_lock);
                if (!purged) {
                        purge_vmap_area_lazy();
@@ -498,6 +505,7 @@ static void __purge_vmap_area_lazy(unsigned long *start, unsigned long *end,
        static DEFINE_SPINLOCK(purge_lock);
        LIST_HEAD(valist);
        struct vmap_area *va;
+       struct vmap_area *n_va;
        int nr = 0;
 
        /*
@@ -537,7 +545,7 @@ static void __purge_vmap_area_lazy(unsigned long *start, unsigned long *end,
 
        if (nr) {
                spin_lock(&vmap_area_lock);
-               list_for_each_entry(va, &valist, purge_list)
+               list_for_each_entry_safe(va, n_va, &valist, purge_list)
                        __free_vmap_area(va);
                spin_unlock(&vmap_area_lock);
        }
@@ -1012,6 +1020,8 @@ void __init vmalloc_init(void)
 void unmap_kernel_range(unsigned long addr, unsigned long size)
 {
        unsigned long end = addr + size;
+
+       flush_cache_vunmap(addr, end);
        vunmap_page_range(addr, end);
        flush_tlb_kernel_range(addr, end);
 }
@@ -1106,6 +1116,14 @@ struct vm_struct *__get_vm_area(unsigned long size, unsigned long flags,
 }
 EXPORT_SYMBOL_GPL(__get_vm_area);
 
+struct vm_struct *__get_vm_area_caller(unsigned long size, unsigned long flags,
+                                      unsigned long start, unsigned long end,
+                                      void *caller)
+{
+       return __get_vm_area_node(size, flags, start, end, -1, GFP_KERNEL,
+                                 caller);
+}
+
 /**
  *     get_vm_area  -  reserve a contiguous kernel virtual area
  *     @size:          size of the area
index 9a27c44aa327f8f46ddbde07776df8644db82de5..6177e3bcd66bdc7b8fc74cb583d47bb89c4940ef 100644 (file)
@@ -2057,31 +2057,31 @@ static unsigned long shrink_all_zones(unsigned long nr_pages, int prio,
                                      int pass, struct scan_control *sc)
 {
        struct zone *zone;
-       unsigned long nr_to_scan, ret = 0;
-       enum lru_list l;
+       unsigned long ret = 0;
 
        for_each_zone(zone) {
+               enum lru_list l;
 
                if (!populated_zone(zone))
                        continue;
-
                if (zone_is_all_unreclaimable(zone) && prio != DEF_PRIORITY)
                        continue;
 
                for_each_evictable_lru(l) {
+                       enum zone_stat_item ls = NR_LRU_BASE + l;
+                       unsigned long lru_pages = zone_page_state(zone, ls);
+
                        /* For pass = 0, we don't shrink the active list */
-                       if (pass == 0 &&
-                               (l == LRU_ACTIVE || l == LRU_ACTIVE_FILE))
+                       if (pass == 0 && (l == LRU_ACTIVE_ANON ||
+                                               l == LRU_ACTIVE_FILE))
                                continue;
 
-                       zone->lru[l].nr_scan +=
-                               (zone_page_state(zone, NR_LRU_BASE + l)
-                                                               >> prio) + 1;
+                       zone->lru[l].nr_scan += (lru_pages >> prio) + 1;
                        if (zone->lru[l].nr_scan >= nr_pages || pass > 3) {
+                               unsigned long nr_to_scan;
+
                                zone->lru[l].nr_scan = 0;
-                               nr_to_scan = min(nr_pages,
-                                       zone_page_state(zone,
-                                                       NR_LRU_BASE + l));
+                               nr_to_scan = min(nr_pages, lru_pages);
                                ret += shrink_list(l, nr_to_scan, zone,
                                                                sc, prio);
                                if (ret >= nr_pages)
@@ -2089,7 +2089,6 @@ static unsigned long shrink_all_zones(unsigned long nr_pages, int prio,
                        }
                }
        }
-
        return ret;
 }
 
@@ -2112,7 +2111,6 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
                .may_swap = 0,
                .swap_cluster_max = nr_pages,
                .may_writepage = 1,
-               .swappiness = vm_swappiness,
                .isolate_pages = isolate_pages_global,
        };
 
@@ -2146,10 +2144,8 @@ unsigned long shrink_all_memory(unsigned long nr_pages)
                int prio;
 
                /* Force reclaiming mapped pages in the passes #3 and #4 */
-               if (pass > 2) {
+               if (pass > 2)
                        sc.may_swap = 1;
-                       sc.swappiness = 100;
-               }
 
                for (prio = DEF_PRIORITY; prio >= 0; prio--) {
                        unsigned long nr_to_scan = nr_pages - ret;
index 6ed711748f26a55d49e2073fb7f061c438e2ccd8..6fea0750662b847d048587e423618b8e4fa8b8b8 100644 (file)
@@ -29,7 +29,7 @@ static struct llc_sap *snap_sap;
 /*
  *     Find a snap client by matching the 5 bytes.
  */
-static struct datalink_proto *find_snap_client(unsigned char *desc)
+static struct datalink_proto *find_snap_client(const unsigned char *desc)
 {
        struct datalink_proto *proto = NULL, *p;
 
@@ -95,15 +95,16 @@ static int snap_request(struct datalink_proto *dl,
 EXPORT_SYMBOL(register_snap_client);
 EXPORT_SYMBOL(unregister_snap_client);
 
-static char snap_err_msg[] __initdata =
+static const char snap_err_msg[] __initconst =
        KERN_CRIT "SNAP - unable to register with 802.2\n";
 
 static int __init snap_init(void)
 {
        snap_sap = llc_sap_open(0xAA, snap_rcv);
-
-       if (!snap_sap)
+       if (!snap_sap) {
                printk(snap_err_msg);
+               return -EBUSY;
+       }
 
        return 0;
 }
@@ -121,7 +122,7 @@ module_exit(snap_exit);
 /*
  *     Register SNAP clients. We don't yet use this for IP.
  */
-struct datalink_proto *register_snap_client(unsigned char *desc,
+struct datalink_proto *register_snap_client(const unsigned char *desc,
                                            int (*rcvfunc)(struct sk_buff *,
                                                           struct net_device *,
                                                           struct packet_type *,
@@ -136,7 +137,7 @@ struct datalink_proto *register_snap_client(unsigned char *desc,
 
        proto = kmalloc(sizeof(*proto), GFP_ATOMIC);
        if (proto) {
-               memcpy(proto->type, desc,5);
+               memcpy(proto->type, desc, 5);
                proto->rcvfunc          = rcvfunc;
                proto->header_length    = 5 + 3; /* snap + 802.2 */
                proto->request          = snap_request;
index 158150fee462fdbca4a2fa2175532b71dd2f862d..e7eb13084d71945a83b4d5064515e53653d43fea 100644 (file)
@@ -486,6 +486,7 @@ static struct rif_cache *rif_get_idx(loff_t pos)
 }
 
 static void *rif_seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(&rif_lock)
 {
        spin_lock_irq(&rif_lock);
 
@@ -517,6 +518,7 @@ static void *rif_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 }
 
 static void rif_seq_stop(struct seq_file *seq, void *v)
+       __releases(&rif_lock)
 {
        spin_unlock_irq(&rif_lock);
 }
@@ -668,3 +670,5 @@ module_init(rif_init);
 
 EXPORT_SYMBOL(tr_type_trans);
 EXPORT_SYMBOL(alloc_trdev);
+
+MODULE_LICENSE("GPL");
index 4163ea65bf4152c40d29f978f4e75f7fbe6e10dc..2b7390e377b3f3a7d6a9e92fb2cbea73d8b6d401 100644 (file)
@@ -51,7 +51,7 @@ const char vlan_version[] = DRV_VERSION;
 static const char vlan_copyright[] = "Ben Greear <greearb@candelatech.com>";
 static const char vlan_buggyright[] = "David S. Miller <davem@redhat.com>";
 
-static struct packet_type vlan_packet_type = {
+static struct packet_type vlan_packet_type __read_mostly = {
        .type = cpu_to_be16(ETH_P_8021Q),
        .func = vlan_skb_recv, /* VLAN receive method */
 };
index 70435af153f24c56b6dba620a0b44852e2580ad9..654e45f5719df2fbaa03ad3523f5925c9dc4127a 100644 (file)
@@ -1,12 +1,16 @@
 #include <linux/skbuff.h>
 #include <linux/netdevice.h>
 #include <linux/if_vlan.h>
+#include <linux/netpoll.h>
 #include "vlan.h"
 
 /* VLAN rx hw acceleration helper.  This acts like netif_{rx,receive_skb}(). */
 int __vlan_hwaccel_rx(struct sk_buff *skb, struct vlan_group *grp,
                      u16 vlan_tci, int polling)
 {
+       if (netpoll_rx(skb))
+               return NET_RX_DROP;
+
        if (skb_bond_should_drop(skb))
                goto drop;
 
@@ -94,12 +98,15 @@ static int vlan_gro_common(struct napi_struct *napi, struct vlan_group *grp,
        return dev_gro_receive(napi, skb);
 
 drop:
-       return 2;
+       return GRO_DROP;
 }
 
 int vlan_gro_receive(struct napi_struct *napi, struct vlan_group *grp,
                     unsigned int vlan_tci, struct sk_buff *skb)
 {
+       if (netpoll_rx_on(skb))
+               return vlan_hwaccel_receive_skb(skb, grp, vlan_tci);
+
        skb_gro_reset_offset(skb);
 
        return napi_skb_finish(vlan_gro_common(napi, grp, vlan_tci, skb), skb);
@@ -114,6 +121,9 @@ int vlan_gro_frags(struct napi_struct *napi, struct vlan_group *grp,
        if (!skb)
                return NET_RX_DROP;
 
+       if (netpoll_rx_on(skb))
+               return vlan_hwaccel_receive_skb(skb, grp, vlan_tci);
+
        return napi_frags_finish(napi, skb,
                                 vlan_gro_common(napi, grp, vlan_tci, skb));
 }
index 4a19acd3a32ba06eaf3fbe4b80f8e5d3fe699d17..1b34135cf9902e737b91475b7a02c018fc6568f5 100644 (file)
@@ -553,7 +553,7 @@ static int vlan_dev_neigh_setup(struct net_device *dev, struct neigh_parms *pa)
        int err = 0;
 
        if (netif_device_present(real_dev) && ops->ndo_neigh_setup)
-               err = ops->ndo_neigh_setup(dev, pa);
+               err = ops->ndo_neigh_setup(real_dev, pa);
 
        return err;
 }
@@ -639,6 +639,7 @@ static int vlan_dev_init(struct net_device *dev)
                dev->hard_header_len = real_dev->hard_header_len + VLAN_HLEN;
                dev->netdev_ops         = &vlan_netdev_ops;
        }
+       netdev_resync_ops(dev);
 
        if (is_vlan_dev(real_dev))
                subclass = 1;
index 1df0356f242b651ddedaa937394a4cd9944e8c27..c613ed08a5ee345d723bac311c76ee191137437e 100644 (file)
@@ -417,7 +417,7 @@ static int p9_fd_write(struct p9_client *client, void *v, int len)
        oldfs = get_fs();
        set_fs(get_ds());
        /* The cast to a user pointer is valid due to the set_fs() */
-       ret = vfs_write(ts->wr, (void __user *)v, len, &ts->wr->f_pos);
+       ret = vfs_write(ts->wr, (__force void __user *)v, len, &ts->wr->f_pos);
        set_fs(oldfs);
 
        if (ret <= 0 && ret != -ERESTARTSYS && ret != -EAGAIN)
index a12bae0e3fe9b59f5df801b7e0bc417a2f0847c7..93998a9c39c232be9223c664ad5db350cf23e8ba 100644 (file)
@@ -24,9 +24,6 @@ if NET
 
 menu "Networking options"
 
-config COMPAT_NET_DEV_OPS
-       def_bool y
-
 source "net/packet/Kconfig"
 source "net/unix/Kconfig"
 source "net/xfrm/Kconfig"
@@ -171,6 +168,7 @@ endif
 
 source "net/dccp/Kconfig"
 source "net/sctp/Kconfig"
+source "net/rds/Kconfig"
 source "net/tipc/Kconfig"
 source "net/atm/Kconfig"
 source "net/802/Kconfig"
@@ -221,6 +219,17 @@ config NET_TCPPROBE
        To compile this code as a module, choose M here: the
        module will be called tcp_probe.
 
+config NET_DROP_MONITOR
+       boolean "Network packet drop alerting service"
+       depends on INET && EXPERIMENTAL && TRACEPOINTS
+       ---help---
+       This feature provides an alerting service to userspace in the
+       event that packets are discarded in the network stack.  Alerts
+       are broadcast via netlink socket to any listening user space
+       process.  If you don't need network drop alerts, or if you are ok
+       just checking the various proc files and other utilities for
+       drop statistics, say N here.
+
 endmenu
 
 endmenu
index 0fcce89d71691e3f707773599ff96f3b75f84e0a..9e00a55a901bc29a708949bb5d1c4ad9e7d5b5c6 100644 (file)
@@ -49,6 +49,7 @@ obj-y                         += 8021q/
 endif
 obj-$(CONFIG_IP_DCCP)          += dccp/
 obj-$(CONFIG_IP_SCTP)          += sctp/
+obj-$(CONFIG_RDS)              += rds/
 obj-y                          += wireless/
 obj-$(CONFIG_MAC80211)         += mac80211/
 obj-$(CONFIG_TIPC)             += tipc/
index 510a6782da8f83e70a324c21cb0d47b976e2f952..3e0671df3a3f4e0acca576ac223fd5983c8cd63c 100644 (file)
@@ -1860,12 +1860,12 @@ static struct notifier_block ddp_notifier = {
        .notifier_call  = ddp_device_event,
 };
 
-static struct packet_type ltalk_packet_type = {
+static struct packet_type ltalk_packet_type __read_mostly = {
        .type           = cpu_to_be16(ETH_P_LOCALTALK),
        .func           = ltalk_rcv,
 };
 
-static struct packet_type ppptalk_packet_type = {
+static struct packet_type ppptalk_packet_type __read_mostly = {
        .type           = cpu_to_be16(ETH_P_PPPTALK),
        .func           = atalk_rcv,
 };
@@ -1877,7 +1877,7 @@ EXPORT_SYMBOL(aarp_send_ddp);
 EXPORT_SYMBOL(atrtr_get_dev);
 EXPORT_SYMBOL(atalk_find_dev_addr);
 
-static char atalk_err_snap[] __initdata =
+static const char atalk_err_snap[] __initconst =
        KERN_CRIT "Unable to register DDP with SNAP.\n";
 
 /* Called by proto.c on kernel start up */
index da42fd06b61fc6c6c93a47b7336d15bca2438373..3dc0a3a42a574c43ba71aaed05f29e6246445b24 100644 (file)
@@ -552,10 +552,13 @@ static int clip_setentry(struct atm_vcc *vcc, __be32 ip)
        return error;
 }
 
+static const struct net_device_ops clip_netdev_ops = {
+       .ndo_start_xmit = clip_start_xmit,
+};
+
 static void clip_setup(struct net_device *dev)
 {
-       dev->hard_start_xmit = clip_start_xmit;
-       /* sg_xmit ... */
+       dev->netdev_ops = &clip_netdev_ops;
        dev->type = ARPHRD_ATM;
        dev->hard_header_len = RFC1483LLC_LEN;
        dev->mtu = RFC1626_MTU;
@@ -615,7 +618,7 @@ static int clip_device_event(struct notifier_block *this, unsigned long event,
        }
 
        /* ignore non-CLIP devices */
-       if (dev->type != ARPHRD_ATM || dev->hard_start_xmit != clip_start_xmit)
+       if (dev->type != ARPHRD_ATM || dev->netdev_ops != &clip_netdev_ops)
                return NOTIFY_DONE;
 
        switch (event) {
index c0cba9a037e842d92ac7116907b21c950b001b2d..199b6bb79f429aadeaf6a26ad6c3b65d200d1644 100644 (file)
@@ -502,7 +502,7 @@ static int lec_atm_send(struct atm_vcc *vcc, struct sk_buff *skb)
                priv->lane2_ops = NULL;
                if (priv->lane_version > 1)
                        priv->lane2_ops = &lane2_ops;
-               if (dev->change_mtu(dev, mesg->content.config.mtu))
+               if (dev_set_mtu(dev, mesg->content.config.mtu))
                        printk("%s: change_mtu to %d failed\n", dev->name,
                               mesg->content.config.mtu);
                priv->is_proxy = mesg->content.config.is_proxy;
index 039d5cc72c3df648d1b413ed042a296b7071a65f..e5bf11453a18b60b7b30ac2a4f3aea91ff60e978 100644 (file)
@@ -286,33 +286,32 @@ static void start_mpc(struct mpoa_client *mpc, struct net_device *dev)
 {
 
        dprintk("mpoa: (%s) start_mpc:\n", mpc->dev->name);
-       if (dev->hard_start_xmit == NULL) {
-               printk("mpoa: (%s) start_mpc: dev->hard_start_xmit == NULL, not starting\n",
-                      dev->name);
-               return;
+       if (!dev->netdev_ops)
+               printk("mpoa: (%s) start_mpc  not starting\n", dev->name);
+       else {
+               mpc->old_ops = dev->netdev_ops;
+               mpc->new_ops = *mpc->old_ops;
+               mpc->new_ops.ndo_start_xmit = mpc_send_packet;
+               dev->netdev_ops = &mpc->new_ops;
        }
-       mpc->old_hard_start_xmit = dev->hard_start_xmit;
-       dev->hard_start_xmit = mpc_send_packet;
-
-       return;
 }
 
 static void stop_mpc(struct mpoa_client *mpc)
 {
-
+       struct net_device *dev = mpc->dev;
        dprintk("mpoa: (%s) stop_mpc:", mpc->dev->name);
 
        /* Lets not nullify lec device's dev->hard_start_xmit */
-       if (mpc->dev->hard_start_xmit != mpc_send_packet) {
+       if (dev->netdev_ops != &mpc->new_ops) {
                dprintk(" mpc already stopped, not fatal\n");
                return;
        }
        dprintk("\n");
-       mpc->dev->hard_start_xmit = mpc->old_hard_start_xmit;
-       mpc->old_hard_start_xmit = NULL;
-       /* close_shortcuts(mpc);    ??? FIXME */
 
-       return;
+       dev->netdev_ops = mpc->old_ops;
+       mpc->old_ops = NULL;
+
+       /* close_shortcuts(mpc);    ??? FIXME */
 }
 
 static const char *mpoa_device_type_string(char type) __attribute__ ((unused));
@@ -531,7 +530,6 @@ static int send_via_shortcut(struct sk_buff *skb, struct mpoa_client *mpc)
  */
 static int mpc_send_packet(struct sk_buff *skb, struct net_device *dev)
 {
-       int retval;
        struct mpoa_client *mpc;
        struct ethhdr *eth;
        int i = 0;
@@ -561,9 +559,7 @@ static int mpc_send_packet(struct sk_buff *skb, struct net_device *dev)
        }
 
  non_ip:
-       retval = mpc->old_hard_start_xmit(skb,dev);
-
-       return retval;
+       return mpc->old_ops->ndo_start_xmit(skb,dev);
 }
 
 static int atm_mpoa_vcc_attach(struct atm_vcc *vcc, void __user *arg)
index 24c386c35f5700442fcbee0134c6480daf8fa2a3..0919a88bbc70e8e0f39c231d89b5f076bb887a40 100644 (file)
@@ -15,7 +15,7 @@ struct mpoa_client {
        struct mpoa_client *next;
        struct net_device *dev;      /* lec in question                     */
        int dev_num;                 /* e.g. 2 for lec2                     */
-       int (*old_hard_start_xmit)(struct sk_buff *skb, struct net_device *dev);
+
        struct atm_vcc *mpoad_vcc;   /* control channel to mpoad            */
        uint8_t mps_ctrl_addr[ATM_ESA_LEN];  /* MPS control ATM address     */
        uint8_t our_ctrl_addr[ATM_ESA_LEN];  /* MPC's control ATM address   */
@@ -31,6 +31,9 @@ struct mpoa_client {
        uint8_t *mps_macs;           /* array of MPS MAC addresses, >=1     */
        int number_of_mps_macs;      /* number of the above MAC addresses   */
        struct mpc_parameters parameters;  /* parameters for this client    */
+
+       const struct net_device_ops *old_ops;
+       struct net_device_ops new_ops;
 };
 
 
index d127fd3ba5c6acd8a7c3ce0f6b4ea5ee8b25f47b..7da5ebb84e976c2689cb4fd338dd6c43586bdbf4 100644 (file)
@@ -1435,6 +1435,11 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock,
        size_t size;
        int lv, err, addr_len = msg->msg_namelen;
 
+       /* AX.25 empty data frame has no meaning : don't send */
+       if (len == 0) {
+               return (0);
+       }
+
        if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT))
                return -EINVAL;
 
@@ -1529,10 +1534,8 @@ static int ax25_sendmsg(struct kiocb *iocb, struct socket *sock,
                dp = ax25->digipeat;
        }
 
-       SOCK_DEBUG(sk, "AX.25: sendto: Addresses built.\n");
-
        /* Build a packet */
-       SOCK_DEBUG(sk, "AX.25: sendto: building packet.\n");
+       SOCK_DEBUG(sk, "AX.25: sendto: Addresses built. Building packet.\n");
 
        /* Assume the worst case */
        size = len + ax25->ax25_dev->dev->hard_header_len;
@@ -1636,6 +1639,13 @@ static int ax25_recvmsg(struct kiocb *iocb, struct socket *sock,
        skb_reset_transport_header(skb);
        copied = skb->len;
 
+       /* AX.25 empty data frame has no meaning : ignore it */
+       if (copied == 0) {
+               err = copied;
+               skb_free_datagram(sk, skb);
+               goto out;
+       }
+
        if (copied > size) {
                copied = size;
                msg->msg_flags |= MSG_TRUNC;
@@ -1985,9 +1995,8 @@ static const struct proto_ops ax25_proto_ops = {
 /*
  *     Called by socket.c on kernel start up
  */
-static struct packet_type ax25_packet_type = {
+static struct packet_type ax25_packet_type __read_mostly = {
        .type   =       cpu_to_be16(ETH_P_AX25),
-       .dev    =       NULL,                           /* All devices */
        .func   =       ax25_kiss_rcv,
 };
 
index 744ed3f07ef38374f6c1b0480d56954d4cf77eac..02b9baa1930b86e641447e1247b6214616c59906 100644 (file)
 
 #include <net/bluetooth/bluetooth.h>
 
-#define VERSION "2.14"
+#define VERSION "2.15"
 
 /* Bluetooth sockets */
 #define BT_MAX_PROTO   8
 static struct net_proto_family *bt_proto[BT_MAX_PROTO];
 static DEFINE_RWLOCK(bt_proto_lock);
 
-#ifdef CONFIG_DEBUG_LOCK_ALLOC
 static struct lock_class_key bt_lock_key[BT_MAX_PROTO];
 static const char *bt_key_strings[BT_MAX_PROTO] = {
        "sk_lock-AF_BLUETOOTH-BTPROTO_L2CAP",
@@ -86,11 +85,6 @@ static inline void bt_sock_reclassify_lock(struct socket *sock, int proto)
                        bt_slock_key_strings[proto], &bt_slock_key[proto],
                                bt_key_strings[proto], &bt_lock_key[proto]);
 }
-#else
-static inline void bt_sock_reclassify_lock(struct socket *sock, int proto)
-{
-}
-#endif
 
 int bt_sock_register(int proto, struct net_proto_family *ops)
 {
@@ -217,7 +211,8 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
                        continue;
                }
 
-               if (sk->sk_state == BT_CONNECTED || !newsock) {
+               if (sk->sk_state == BT_CONNECTED || !newsock ||
+                                               bt_sk(parent)->defer_setup) {
                        bt_accept_unlink(sk);
                        if (newsock)
                                sock_graft(sk, newsock);
@@ -232,7 +227,7 @@ struct sock *bt_accept_dequeue(struct sock *parent, struct socket *newsock)
 EXPORT_SYMBOL(bt_accept_dequeue);
 
 int bt_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
-       struct msghdr *msg, size_t len, int flags)
+                               struct msghdr *msg, size_t len, int flags)
 {
        int noblock = flags & MSG_DONTWAIT;
        struct sock *sk = sock->sk;
@@ -277,7 +272,9 @@ static inline unsigned int bt_accept_poll(struct sock *parent)
 
        list_for_each_safe(p, n, &bt_sk(parent)->accept_q) {
                sk = (struct sock *) list_entry(p, struct bt_sock, accept_q);
-               if (sk->sk_state == BT_CONNECTED)
+               if (sk->sk_state == BT_CONNECTED ||
+                                       (bt_sk(parent)->defer_setup &&
+                                               sk->sk_state == BT_CONNECT2))
                        return POLLIN | POLLRDNORM;
        }
 
index c9cac7719efe757ddcbd5567f1d464ee4cf12f47..0073ec8495da2e1ff04ad1266a1f2a815a3cc10d 100644 (file)
@@ -126,8 +126,7 @@ static inline void cmtp_add_msgpart(struct cmtp_session *session, int id, const
 
        session->reassembly[id] = nskb;
 
-       if (skb)
-               kfree_skb(skb);
+       kfree_skb(skb);
 }
 
 static inline int cmtp_recv_frame(struct cmtp_session *session, struct sk_buff *skb)
index a4a789f24c8d4668d7b54997654f8a516d62898a..1181db08d9de0303a72d30670521e1c9b27a32b6 100644 (file)
@@ -123,6 +123,8 @@ void hci_add_sco(struct hci_conn *conn, __u16 handle)
        conn->state = BT_CONNECT;
        conn->out = 1;
 
+       conn->attempt++;
+
        cp.handle   = cpu_to_le16(handle);
        cp.pkt_type = cpu_to_le16(conn->pkt_type);
 
@@ -139,6 +141,8 @@ void hci_setup_sync(struct hci_conn *conn, __u16 handle)
        conn->state = BT_CONNECT;
        conn->out = 1;
 
+       conn->attempt++;
+
        cp.handle   = cpu_to_le16(handle);
        cp.pkt_type = cpu_to_le16(conn->pkt_type);
 
@@ -155,6 +159,7 @@ static void hci_conn_timeout(unsigned long arg)
 {
        struct hci_conn *conn = (void *) arg;
        struct hci_dev *hdev = conn->hdev;
+       __u8 reason;
 
        BT_DBG("conn %p state %d", conn, conn->state);
 
@@ -173,7 +178,8 @@ static void hci_conn_timeout(unsigned long arg)
                break;
        case BT_CONFIG:
        case BT_CONNECTED:
-               hci_acl_disconn(conn, 0x13);
+               reason = hci_proto_disconn_ind(conn);
+               hci_acl_disconn(conn, reason);
                break;
        default:
                conn->state = BT_CLOSED;
@@ -216,12 +222,13 @@ struct hci_conn *hci_conn_add(struct hci_dev *hdev, int type, bdaddr_t *dst)
                break;
        case SCO_LINK:
                if (lmp_esco_capable(hdev))
-                       conn->pkt_type = hdev->esco_type & SCO_ESCO_MASK;
+                       conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
+                                       (hdev->esco_type & EDR_ESCO_MASK);
                else
                        conn->pkt_type = hdev->pkt_type & SCO_PTYPE_MASK;
                break;
        case ESCO_LINK:
-               conn->pkt_type = hdev->esco_type;
+               conn->pkt_type = hdev->esco_type & ~EDR_ESCO_MASK;
                break;
        }
 
@@ -280,6 +287,8 @@ int hci_conn_del(struct hci_conn *conn)
 
        skb_queue_purge(&conn->data_q);
 
+       hci_conn_del_sysfs(conn);
+
        return 0;
 }
 
@@ -325,7 +334,7 @@ EXPORT_SYMBOL(hci_get_route);
 
 /* Create SCO or ACL connection.
  * Device _must_ be locked */
-struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 auth_type)
+struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8 sec_level, __u8 auth_type)
 {
        struct hci_conn *acl;
        struct hci_conn *sco;
@@ -340,6 +349,7 @@ struct hci_conn *hci_connect(struct hci_dev *hdev, int type, bdaddr_t *dst, __u8
        hci_conn_hold(acl);
 
        if (acl->state == BT_OPEN || acl->state == BT_CLOSED) {
+               acl->sec_level = sec_level;
                acl->auth_type = auth_type;
                hci_acl_connect(acl);
        }
@@ -385,51 +395,59 @@ int hci_conn_check_link_mode(struct hci_conn *conn)
 EXPORT_SYMBOL(hci_conn_check_link_mode);
 
 /* Authenticate remote device */
-int hci_conn_auth(struct hci_conn *conn)
+static int hci_conn_auth(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 {
        BT_DBG("conn %p", conn);
 
-       if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0) {
-               if (!(conn->auth_type & 0x01)) {
-                       conn->auth_type |= 0x01;
-                       conn->link_mode &= ~HCI_LM_AUTH;
-               }
-       }
-
-       if (conn->link_mode & HCI_LM_AUTH)
+       if (sec_level > conn->sec_level)
+               conn->sec_level = sec_level;
+       else if (conn->link_mode & HCI_LM_AUTH)
                return 1;
 
+       conn->auth_type = auth_type;
+
        if (!test_and_set_bit(HCI_CONN_AUTH_PEND, &conn->pend)) {
                struct hci_cp_auth_requested cp;
                cp.handle = cpu_to_le16(conn->handle);
                hci_send_cmd(conn->hdev, HCI_OP_AUTH_REQUESTED,
                                                        sizeof(cp), &cp);
        }
+
        return 0;
 }
-EXPORT_SYMBOL(hci_conn_auth);
 
-/* Enable encryption */
-int hci_conn_encrypt(struct hci_conn *conn)
+/* Enable security */
+int hci_conn_security(struct hci_conn *conn, __u8 sec_level, __u8 auth_type)
 {
        BT_DBG("conn %p", conn);
 
+       if (sec_level == BT_SECURITY_SDP)
+               return 1;
+
+       if (sec_level == BT_SECURITY_LOW) {
+               if (conn->ssp_mode > 0 && conn->hdev->ssp_mode > 0)
+                       return hci_conn_auth(conn, sec_level, auth_type);
+               else
+                       return 1;
+       }
+
        if (conn->link_mode & HCI_LM_ENCRYPT)
-               return hci_conn_auth(conn);
+               return hci_conn_auth(conn, sec_level, auth_type);
 
        if (test_and_set_bit(HCI_CONN_ENCRYPT_PEND, &conn->pend))
                return 0;
 
-       if (hci_conn_auth(conn)) {
+       if (hci_conn_auth(conn, sec_level, auth_type)) {
                struct hci_cp_set_conn_encrypt cp;
                cp.handle  = cpu_to_le16(conn->handle);
                cp.encrypt = 1;
                hci_send_cmd(conn->hdev, HCI_OP_SET_CONN_ENCRYPT,
                                                        sizeof(cp), &cp);
        }
+
        return 0;
 }
-EXPORT_SYMBOL(hci_conn_encrypt);
+EXPORT_SYMBOL(hci_conn_security);
 
 /* Change link key */
 int hci_conn_change_link_key(struct hci_conn *conn)
@@ -442,12 +460,13 @@ int hci_conn_change_link_key(struct hci_conn *conn)
                hci_send_cmd(conn->hdev, HCI_OP_CHANGE_CONN_LINK_KEY,
                                                        sizeof(cp), &cp);
        }
+
        return 0;
 }
 EXPORT_SYMBOL(hci_conn_change_link_key);
 
 /* Switch role */
-int hci_conn_switch_role(struct hci_conn *conn, uint8_t role)
+int hci_conn_switch_role(struct hci_conn *conn, __u8 role)
 {
        BT_DBG("conn %p", conn);
 
@@ -460,6 +479,7 @@ int hci_conn_switch_role(struct hci_conn *conn, uint8_t role)
                cp.role = role;
                hci_send_cmd(conn->hdev, HCI_OP_SWITCH_ROLE, sizeof(cp), &cp);
        }
+
        return 0;
 }
 EXPORT_SYMBOL(hci_conn_switch_role);
@@ -542,9 +562,7 @@ void hci_conn_hash_flush(struct hci_dev *hdev)
 
                c->state = BT_CLOSED;
 
-               hci_conn_del_sysfs(c);
-
-               hci_proto_disconn_ind(c, 0x16);
+               hci_proto_disconn_cfm(c, 0x16);
                hci_conn_del(c);
        }
 }
index ba78cc1eb8d9aaa8973c3a2395af86a98e71d4d6..cd061510b6bd8356140c428a1187235e87ed31dc 100644 (file)
@@ -1565,8 +1565,7 @@ static void hci_cmd_task(unsigned long arg)
 
        /* Send queued commands */
        if (atomic_read(&hdev->cmd_cnt) && (skb = skb_dequeue(&hdev->cmd_q))) {
-               if (hdev->sent_cmd)
-                       kfree_skb(hdev->sent_cmd);
+               kfree_skb(hdev->sent_cmd);
 
                if ((hdev->sent_cmd = skb_clone(skb, GFP_ATOMIC))) {
                        atomic_dec(&hdev->cmd_cnt);
index f91ba690f5d29cfc932deb3cf0ae810ce6993ae5..55534244c3a029b4336aab5ad14c89d9d75ea9b2 100644 (file)
@@ -484,6 +484,15 @@ static void hci_cc_read_local_features(struct hci_dev *hdev, struct sk_buff *skb
        if (hdev->features[4] & LMP_EV5)
                hdev->esco_type |= (ESCO_EV5);
 
+       if (hdev->features[5] & LMP_EDR_ESCO_2M)
+               hdev->esco_type |= (ESCO_2EV3);
+
+       if (hdev->features[5] & LMP_EDR_ESCO_3M)
+               hdev->esco_type |= (ESCO_3EV3);
+
+       if (hdev->features[5] & LMP_EDR_3S_ESCO)
+               hdev->esco_type |= (ESCO_2EV5 | ESCO_3EV5);
+
        BT_DBG("%s features 0x%.2x%.2x%.2x%.2x%.2x%.2x%.2x%.2x", hdev->name,
                                        hdev->features[0], hdev->features[1],
                                        hdev->features[2], hdev->features[3],
@@ -914,7 +923,8 @@ static inline void hci_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *s
        if (ev->status) {
                hci_proto_connect_cfm(conn, ev->status);
                hci_conn_del(conn);
-       }
+       } else if (ev->link_type != ACL_LINK)
+               hci_proto_connect_cfm(conn, ev->status);
 
 unlock:
        hci_dev_unlock(hdev);
@@ -1009,9 +1019,7 @@ static inline void hci_disconn_complete_evt(struct hci_dev *hdev, struct sk_buff
        if (conn) {
                conn->state = BT_CLOSED;
 
-               hci_conn_del_sysfs(conn);
-
-               hci_proto_disconn_ind(conn, ev->reason);
+               hci_proto_disconn_cfm(conn, ev->reason);
                hci_conn_del(conn);
        }
 
@@ -1600,7 +1608,8 @@ static inline void hci_remote_ext_features_evt(struct hci_dev *hdev, struct sk_b
 
                if (conn->state == BT_CONFIG) {
                        if (!ev->status && hdev->ssp_mode > 0 &&
-                                       conn->ssp_mode > 0 && conn->out) {
+                                       conn->ssp_mode > 0 && conn->out &&
+                                       conn->sec_level != BT_SECURITY_SDP) {
                                struct hci_cp_auth_requested cp;
                                cp.handle = ev->handle;
                                hci_send_cmd(hdev, HCI_OP_AUTH_REQUESTED,
@@ -1637,6 +1646,13 @@ static inline void hci_sync_conn_complete_evt(struct hci_dev *hdev, struct sk_bu
                conn->type = SCO_LINK;
        }
 
+       if (conn->out && ev->status == 0x1c && conn->attempt < 2) {
+               conn->pkt_type = (hdev->esco_type & SCO_ESCO_MASK) |
+                                       (hdev->esco_type & EDR_ESCO_MASK);
+               hci_setup_sync(conn, conn->link->handle);
+               goto unlock;
+       }
+
        if (!ev->status) {
                conn->handle = __le16_to_cpu(ev->handle);
                conn->state  = BT_CONNECTED;
index b93748e224ff1505bd0f8c2448f1070f3854a796..ca4d3b40d5cea5ac310dafe77177499eab6e554a 100644 (file)
 #include <net/bluetooth/hci_core.h>
 #include <net/bluetooth/l2cap.h>
 
-#define VERSION "2.11"
+#define VERSION "2.13"
 
-static u32 l2cap_feat_mask = 0x0000;
+static u32 l2cap_feat_mask = 0x0080;
+static u8 l2cap_fixed_chan[8] = { 0x02, };
 
 static const struct proto_ops l2cap_sock_ops;
 
@@ -77,9 +78,10 @@ static void l2cap_sock_timeout(unsigned long arg)
 
        bh_lock_sock(sk);
 
-       if (sk->sk_state == BT_CONNECT &&
-                       (l2cap_pi(sk)->link_mode & (L2CAP_LM_AUTH |
-                                       L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)))
+       if (sk->sk_state == BT_CONNECTED || sk->sk_state == BT_CONFIG)
+               reason = ECONNREFUSED;
+       else if (sk->sk_state == BT_CONNECT &&
+                               l2cap_pi(sk)->sec_level != BT_SECURITY_SDP)
                reason = ECONNREFUSED;
        else
                reason = ETIMEDOUT;
@@ -204,6 +206,8 @@ static void __l2cap_chan_add(struct l2cap_conn *conn, struct sock *sk, struct so
 
        BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn, l2cap_pi(sk)->psm, l2cap_pi(sk)->dcid);
 
+       conn->disc_reason = 0x13;
+
        l2cap_pi(sk)->conn = conn;
 
        if (sk->sk_type == SOCK_SEQPACKET) {
@@ -259,18 +263,35 @@ static void l2cap_chan_del(struct sock *sk, int err)
 }
 
 /* Service level security */
-static inline int l2cap_check_link_mode(struct sock *sk)
+static inline int l2cap_check_security(struct sock *sk)
 {
        struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+       __u8 auth_type;
 
-       if ((l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT) ||
-                               (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE))
-               return hci_conn_encrypt(conn->hcon);
+       if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
+               if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+                       auth_type = HCI_AT_NO_BONDING_MITM;
+               else
+                        auth_type = HCI_AT_NO_BONDING;
 
-       if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH)
-               return hci_conn_auth(conn->hcon);
+               if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
+                       l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
+       } else {
+               switch (l2cap_pi(sk)->sec_level) {
+               case BT_SECURITY_HIGH:
+                       auth_type = HCI_AT_GENERAL_BONDING_MITM;
+                       break;
+               case BT_SECURITY_MEDIUM:
+                       auth_type = HCI_AT_GENERAL_BONDING;
+                       break;
+               default:
+                       auth_type = HCI_AT_NO_BONDING;
+                       break;
+               }
+       }
 
-       return 1;
+       return hci_conn_security(conn->hcon, l2cap_pi(sk)->sec_level,
+                                                               auth_type);
 }
 
 static inline u8 l2cap_get_ident(struct l2cap_conn *conn)
@@ -312,7 +333,10 @@ static void l2cap_do_start(struct sock *sk)
        struct l2cap_conn *conn = l2cap_pi(sk)->conn;
 
        if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
-               if (l2cap_check_link_mode(sk)) {
+               if (!(conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE))
+                       return;
+
+               if (l2cap_check_security(sk)) {
                        struct l2cap_conn_req req;
                        req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
                        req.psm  = l2cap_pi(sk)->psm;
@@ -356,7 +380,7 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                }
 
                if (sk->sk_state == BT_CONNECT) {
-                       if (l2cap_check_link_mode(sk)) {
+                       if (l2cap_check_security(sk)) {
                                struct l2cap_conn_req req;
                                req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
                                req.psm  = l2cap_pi(sk)->psm;
@@ -371,10 +395,18 @@ static void l2cap_conn_start(struct l2cap_conn *conn)
                        rsp.scid = cpu_to_le16(l2cap_pi(sk)->dcid);
                        rsp.dcid = cpu_to_le16(l2cap_pi(sk)->scid);
 
-                       if (l2cap_check_link_mode(sk)) {
-                               sk->sk_state = BT_CONFIG;
-                               rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
-                               rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+                       if (l2cap_check_security(sk)) {
+                               if (bt_sk(sk)->defer_setup) {
+                                       struct sock *parent = bt_sk(sk)->parent;
+                                       rsp.result = cpu_to_le16(L2CAP_CR_PEND);
+                                       rsp.status = cpu_to_le16(L2CAP_CS_AUTHOR_PEND);
+                                       parent->sk_data_ready(parent, 0);
+
+                               } else {
+                                       sk->sk_state = BT_CONFIG;
+                                       rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
+                                       rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+                               }
                        } else {
                                rsp.result = cpu_to_le16(L2CAP_CR_PEND);
                                rsp.status = cpu_to_le16(L2CAP_CS_AUTHEN_PEND);
@@ -426,7 +458,7 @@ static void l2cap_conn_unreliable(struct l2cap_conn *conn, int err)
        read_lock(&l->lock);
 
        for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-               if (l2cap_pi(sk)->link_mode & L2CAP_LM_RELIABLE)
+               if (l2cap_pi(sk)->force_reliable)
                        sk->sk_err = err;
        }
 
@@ -437,6 +469,7 @@ static void l2cap_info_timeout(unsigned long arg)
 {
        struct l2cap_conn *conn = (void *) arg;
 
+       conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
        conn->info_ident = 0;
 
        l2cap_conn_start(conn);
@@ -470,6 +503,8 @@ static struct l2cap_conn *l2cap_conn_add(struct hci_conn *hcon, u8 status)
        spin_lock_init(&conn->lock);
        rwlock_init(&conn->chan_list.lock);
 
+       conn->disc_reason = 0x13;
+
        return conn;
 }
 
@@ -483,8 +518,7 @@ static void l2cap_conn_del(struct hci_conn *hcon, int err)
 
        BT_DBG("hcon %p conn %p, err %d", hcon, conn, err);
 
-       if (conn->rx_skb)
-               kfree_skb(conn->rx_skb);
+       kfree_skb(conn->rx_skb);
 
        /* Kill channels */
        while ((sk = conn->chan_list.head)) {
@@ -608,7 +642,6 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
 
        case BT_CONNECTED:
        case BT_CONFIG:
-       case BT_CONNECT2:
                if (sk->sk_type == SOCK_SEQPACKET) {
                        struct l2cap_conn *conn = l2cap_pi(sk)->conn;
                        struct l2cap_disconn_req req;
@@ -624,6 +657,27 @@ static void __l2cap_sock_close(struct sock *sk, int reason)
                        l2cap_chan_del(sk, reason);
                break;
 
+       case BT_CONNECT2:
+               if (sk->sk_type == SOCK_SEQPACKET) {
+                       struct l2cap_conn *conn = l2cap_pi(sk)->conn;
+                       struct l2cap_conn_rsp rsp;
+                       __u16 result;
+
+                       if (bt_sk(sk)->defer_setup)
+                               result = L2CAP_CR_SEC_BLOCK;
+                       else
+                               result = L2CAP_CR_BAD_PSM;
+
+                       rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
+                       rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
+                       rsp.result = cpu_to_le16(result);
+                       rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+                       l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
+                                       L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+               } else
+                       l2cap_chan_del(sk, reason);
+               break;
+
        case BT_CONNECT:
        case BT_DISCONN:
                l2cap_chan_del(sk, reason);
@@ -653,13 +707,19 @@ static void l2cap_sock_init(struct sock *sk, struct sock *parent)
 
        if (parent) {
                sk->sk_type = parent->sk_type;
+               bt_sk(sk)->defer_setup = bt_sk(parent)->defer_setup;
+
                pi->imtu = l2cap_pi(parent)->imtu;
                pi->omtu = l2cap_pi(parent)->omtu;
-               pi->link_mode = l2cap_pi(parent)->link_mode;
+               pi->sec_level = l2cap_pi(parent)->sec_level;
+               pi->role_switch = l2cap_pi(parent)->role_switch;
+               pi->force_reliable = l2cap_pi(parent)->force_reliable;
        } else {
                pi->imtu = L2CAP_DEFAULT_MTU;
                pi->omtu = 0;
-               pi->link_mode = 0;
+               pi->sec_level = BT_SECURITY_LOW;
+               pi->role_switch = 0;
+               pi->force_reliable = 0;
        }
 
        /* Default config options */
@@ -723,17 +783,24 @@ static int l2cap_sock_create(struct net *net, struct socket *sock, int protocol)
        return 0;
 }
 
-static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_len)
+static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int alen)
 {
-       struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
        struct sock *sk = sock->sk;
-       int err = 0;
+       struct sockaddr_l2 la;
+       int len, err = 0;
 
-       BT_DBG("sk %p, %s %d", sk, batostr(&la->l2_bdaddr), la->l2_psm);
+       BT_DBG("sk %p", sk);
 
        if (!addr || addr->sa_family != AF_BLUETOOTH)
                return -EINVAL;
 
+       memset(&la, 0, sizeof(la));
+       len = min_t(unsigned int, sizeof(la), alen);
+       memcpy(&la, addr, len);
+
+       if (la.l2_cid)
+               return -EINVAL;
+
        lock_sock(sk);
 
        if (sk->sk_state != BT_OPEN) {
@@ -741,7 +808,7 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_
                goto done;
        }
 
-       if (la->l2_psm && btohs(la->l2_psm) < 0x1001 &&
+       if (la.l2_psm && btohs(la.l2_psm) < 0x1001 &&
                                !capable(CAP_NET_BIND_SERVICE)) {
                err = -EACCES;
                goto done;
@@ -749,14 +816,17 @@ static int l2cap_sock_bind(struct socket *sock, struct sockaddr *addr, int addr_
 
        write_lock_bh(&l2cap_sk_list.lock);
 
-       if (la->l2_psm && __l2cap_get_sock_by_addr(la->l2_psm, &la->l2_bdaddr)) {
+       if (la.l2_psm && __l2cap_get_sock_by_addr(la.l2_psm, &la.l2_bdaddr)) {
                err = -EADDRINUSE;
        } else {
                /* Save source address */
-               bacpy(&bt_sk(sk)->src, &la->l2_bdaddr);
-               l2cap_pi(sk)->psm   = la->l2_psm;
-               l2cap_pi(sk)->sport = la->l2_psm;
+               bacpy(&bt_sk(sk)->src, &la.l2_bdaddr);
+               l2cap_pi(sk)->psm   = la.l2_psm;
+               l2cap_pi(sk)->sport = la.l2_psm;
                sk->sk_state = BT_BOUND;
+
+               if (btohs(la.l2_psm) == 0x0001 || btohs(la.l2_psm) == 0x0003)
+                       l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
        }
 
        write_unlock_bh(&l2cap_sk_list.lock);
@@ -776,7 +846,8 @@ static int l2cap_do_connect(struct sock *sk)
        __u8 auth_type;
        int err = 0;
 
-       BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst), l2cap_pi(sk)->psm);
+       BT_DBG("%s -> %s psm 0x%2.2x", batostr(src), batostr(dst),
+                                                       l2cap_pi(sk)->psm);
 
        if (!(hdev = hci_get_route(dst, src)))
                return -EHOSTUNREACH;
@@ -785,21 +856,42 @@ static int l2cap_do_connect(struct sock *sk)
 
        err = -ENOMEM;
 
-       if (l2cap_pi(sk)->link_mode & L2CAP_LM_AUTH ||
-                       l2cap_pi(sk)->link_mode & L2CAP_LM_ENCRYPT ||
-                               l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE) {
-               if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001))
+       if (sk->sk_type == SOCK_RAW) {
+               switch (l2cap_pi(sk)->sec_level) {
+               case BT_SECURITY_HIGH:
+                       auth_type = HCI_AT_DEDICATED_BONDING_MITM;
+                       break;
+               case BT_SECURITY_MEDIUM:
+                       auth_type = HCI_AT_DEDICATED_BONDING;
+                       break;
+               default:
+                       auth_type = HCI_AT_NO_BONDING;
+                       break;
+               }
+       } else if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001)) {
+               if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
                        auth_type = HCI_AT_NO_BONDING_MITM;
                else
-                       auth_type = HCI_AT_GENERAL_BONDING_MITM;
-       } else {
-               if (l2cap_pi(sk)->psm == cpu_to_le16(0x0001))
                        auth_type = HCI_AT_NO_BONDING;
-               else
+
+               if (l2cap_pi(sk)->sec_level == BT_SECURITY_LOW)
+                       l2cap_pi(sk)->sec_level = BT_SECURITY_SDP;
+       } else {
+               switch (l2cap_pi(sk)->sec_level) {
+               case BT_SECURITY_HIGH:
+                       auth_type = HCI_AT_GENERAL_BONDING_MITM;
+                       break;
+               case BT_SECURITY_MEDIUM:
                        auth_type = HCI_AT_GENERAL_BONDING;
+                       break;
+               default:
+                       auth_type = HCI_AT_NO_BONDING;
+                       break;
+               }
        }
 
-       hcon = hci_connect(hdev, ACL_LINK, dst, auth_type);
+       hcon = hci_connect(hdev, ACL_LINK, dst,
+                                       l2cap_pi(sk)->sec_level, auth_type);
        if (!hcon)
                goto done;
 
@@ -835,20 +927,25 @@ done:
 
 static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int alen, int flags)
 {
-       struct sockaddr_l2 *la = (struct sockaddr_l2 *) addr;
        struct sock *sk = sock->sk;
-       int err = 0;
-
-       lock_sock(sk);
+       struct sockaddr_l2 la;
+       int len, err = 0;
 
        BT_DBG("sk %p", sk);
 
-       if (addr->sa_family != AF_BLUETOOTH || alen < sizeof(struct sockaddr_l2)) {
-               err = -EINVAL;
-               goto done;
-       }
+       if (!addr || addr->sa_family != AF_BLUETOOTH)
+               return -EINVAL;
+
+       memset(&la, 0, sizeof(la));
+       len = min_t(unsigned int, sizeof(la), alen);
+       memcpy(&la, addr, len);
+
+       if (la.l2_cid)
+               return -EINVAL;
+
+       lock_sock(sk);
 
-       if (sk->sk_type == SOCK_SEQPACKET && !la->l2_psm) {
+       if (sk->sk_type == SOCK_SEQPACKET && !la.l2_psm) {
                err = -EINVAL;
                goto done;
        }
@@ -875,8 +972,8 @@ static int l2cap_sock_connect(struct socket *sock, struct sockaddr *addr, int al
        }
 
        /* Set destination address and psm */
-       bacpy(&bt_sk(sk)->dst, &la->l2_bdaddr);
-       l2cap_pi(sk)->psm = la->l2_psm;
+       bacpy(&bt_sk(sk)->dst, &la.l2_bdaddr);
+       l2cap_pi(sk)->psm = la.l2_psm;
 
        if ((err = l2cap_do_connect(sk)))
                goto done;
@@ -1000,12 +1097,16 @@ static int l2cap_sock_getname(struct socket *sock, struct sockaddr *addr, int *l
        addr->sa_family = AF_BLUETOOTH;
        *len = sizeof(struct sockaddr_l2);
 
-       if (peer)
+       if (peer) {
+               la->l2_psm = l2cap_pi(sk)->psm;
                bacpy(&la->l2_bdaddr, &bt_sk(sk)->dst);
-       else
+               la->l2_cid = htobs(l2cap_pi(sk)->dcid);
+       } else {
+               la->l2_psm = l2cap_pi(sk)->sport;
                bacpy(&la->l2_bdaddr, &bt_sk(sk)->src);
+               la->l2_cid = htobs(l2cap_pi(sk)->scid);
+       }
 
-       la->l2_psm = l2cap_pi(sk)->psm;
        return 0;
 }
 
@@ -1106,11 +1207,38 @@ static int l2cap_sock_sendmsg(struct kiocb *iocb, struct socket *sock, struct ms
        return err;
 }
 
-static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
+static int l2cap_sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t len, int flags)
+{
+       struct sock *sk = sock->sk;
+
+       lock_sock(sk);
+
+       if (sk->sk_state == BT_CONNECT2 && bt_sk(sk)->defer_setup) {
+               struct l2cap_conn_rsp rsp;
+
+               sk->sk_state = BT_CONFIG;
+
+               rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
+               rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
+               rsp.result = cpu_to_le16(L2CAP_CR_SUCCESS);
+               rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
+               l2cap_send_cmd(l2cap_pi(sk)->conn, l2cap_pi(sk)->ident,
+                                       L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+
+               release_sock(sk);
+               return 0;
+       }
+
+       release_sock(sk);
+
+       return bt_sock_recvmsg(iocb, sock, msg, len, flags);
+}
+
+static int l2cap_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, int optlen)
 {
        struct sock *sk = sock->sk;
        struct l2cap_options opts;
-       int err = 0, len;
+       int len, err = 0;
        u32 opt;
 
        BT_DBG("sk %p", sk);
@@ -1140,7 +1268,15 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
                        break;
                }
 
-               l2cap_pi(sk)->link_mode = opt;
+               if (opt & L2CAP_LM_AUTH)
+                       l2cap_pi(sk)->sec_level = BT_SECURITY_LOW;
+               if (opt & L2CAP_LM_ENCRYPT)
+                       l2cap_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
+               if (opt & L2CAP_LM_SECURE)
+                       l2cap_pi(sk)->sec_level = BT_SECURITY_HIGH;
+
+               l2cap_pi(sk)->role_switch    = (opt & L2CAP_LM_MASTER);
+               l2cap_pi(sk)->force_reliable = (opt & L2CAP_LM_RELIABLE);
                break;
 
        default:
@@ -1152,12 +1288,77 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, ch
        return err;
 }
 
-static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
+static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
+{
+       struct sock *sk = sock->sk;
+       struct bt_security sec;
+       int len, err = 0;
+       u32 opt;
+
+       BT_DBG("sk %p", sk);
+
+       if (level == SOL_L2CAP)
+               return l2cap_sock_setsockopt_old(sock, optname, optval, optlen);
+
+       if (level != SOL_BLUETOOTH)
+               return -ENOPROTOOPT;
+
+       lock_sock(sk);
+
+       switch (optname) {
+       case BT_SECURITY:
+               if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_RAW) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               sec.level = BT_SECURITY_LOW;
+
+               len = min_t(unsigned int, sizeof(sec), optlen);
+               if (copy_from_user((char *) &sec, optval, len)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               if (sec.level < BT_SECURITY_LOW ||
+                                       sec.level > BT_SECURITY_HIGH) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               l2cap_pi(sk)->sec_level = sec.level;
+               break;
+
+       case BT_DEFER_SETUP:
+               if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (get_user(opt, (u32 __user *) optval)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               bt_sk(sk)->defer_setup = opt;
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       release_sock(sk);
+       return err;
+}
+
+static int l2cap_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
        struct l2cap_options opts;
        struct l2cap_conninfo cinfo;
        int len, err = 0;
+       u32 opt;
 
        BT_DBG("sk %p", sk);
 
@@ -1180,12 +1381,36 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
                break;
 
        case L2CAP_LM:
-               if (put_user(l2cap_pi(sk)->link_mode, (u32 __user *) optval))
+               switch (l2cap_pi(sk)->sec_level) {
+               case BT_SECURITY_LOW:
+                       opt = L2CAP_LM_AUTH;
+                       break;
+               case BT_SECURITY_MEDIUM:
+                       opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT;
+                       break;
+               case BT_SECURITY_HIGH:
+                       opt = L2CAP_LM_AUTH | L2CAP_LM_ENCRYPT |
+                                                       L2CAP_LM_SECURE;
+                       break;
+               default:
+                       opt = 0;
+                       break;
+               }
+
+               if (l2cap_pi(sk)->role_switch)
+                       opt |= L2CAP_LM_MASTER;
+
+               if (l2cap_pi(sk)->force_reliable)
+                       opt |= L2CAP_LM_RELIABLE;
+
+               if (put_user(opt, (u32 __user *) optval))
                        err = -EFAULT;
                break;
 
        case L2CAP_CONNINFO:
-               if (sk->sk_state != BT_CONNECTED) {
+               if (sk->sk_state != BT_CONNECTED &&
+                                       !(sk->sk_state == BT_CONNECT2 &&
+                                               bt_sk(sk)->defer_setup)) {
                        err = -ENOTCONN;
                        break;
                }
@@ -1208,6 +1433,60 @@ static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, ch
        return err;
 }
 
+static int l2cap_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
+{
+       struct sock *sk = sock->sk;
+       struct bt_security sec;
+       int len, err = 0;
+
+       BT_DBG("sk %p", sk);
+
+       if (level == SOL_L2CAP)
+               return l2cap_sock_getsockopt_old(sock, optname, optval, optlen);
+
+       if (level != SOL_BLUETOOTH)
+               return -ENOPROTOOPT;
+
+       if (get_user(len, optlen))
+               return -EFAULT;
+
+       lock_sock(sk);
+
+       switch (optname) {
+       case BT_SECURITY:
+               if (sk->sk_type != SOCK_SEQPACKET && sk->sk_type != SOCK_RAW) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               sec.level = l2cap_pi(sk)->sec_level;
+
+               len = min_t(unsigned int, len, sizeof(sec));
+               if (copy_to_user(optval, (char *) &sec, len))
+                       err = -EFAULT;
+
+               break;
+
+       case BT_DEFER_SETUP:
+               if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval))
+                       err = -EFAULT;
+
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       release_sock(sk);
+       return err;
+}
+
 static int l2cap_sock_shutdown(struct socket *sock, int how)
 {
        struct sock *sk = sock->sk;
@@ -1270,11 +1549,6 @@ static void l2cap_chan_ready(struct sock *sk)
                 */
                parent->sk_data_ready(parent, 0);
        }
-
-       if (l2cap_pi(sk)->link_mode & L2CAP_LM_SECURE) {
-               struct l2cap_conn *conn = l2cap_pi(sk)->conn;
-               hci_conn_change_link_key(conn->hcon);
-       }
 }
 
 /* Copy frame to all raw sockets on that connection */
@@ -1549,8 +1823,11 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
        if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
                                        cmd->ident == conn->info_ident) {
-               conn->info_ident = 0;
                del_timer(&conn->info_timer);
+
+               conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
+               conn->info_ident = 0;
+
                l2cap_conn_start(conn);
        }
 
@@ -1580,6 +1857,7 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
        /* Check if the ACL is secure enough (if not SDP) */
        if (psm != cpu_to_le16(0x0001) &&
                                !hci_conn_check_link_mode(conn->hcon)) {
+               conn->disc_reason = 0x05;
                result = L2CAP_CR_SEC_BLOCK;
                goto response;
        }
@@ -1621,11 +1899,18 @@ static inline int l2cap_connect_req(struct l2cap_conn *conn, struct l2cap_cmd_hd
 
        l2cap_pi(sk)->ident = cmd->ident;
 
-       if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) {
-               if (l2cap_check_link_mode(sk)) {
-                       sk->sk_state = BT_CONFIG;
-                       result = L2CAP_CR_SUCCESS;
-                       status = L2CAP_CS_NO_INFO;
+       if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE) {
+               if (l2cap_check_security(sk)) {
+                       if (bt_sk(sk)->defer_setup) {
+                               sk->sk_state = BT_CONNECT2;
+                               result = L2CAP_CR_PEND;
+                               status = L2CAP_CS_AUTHOR_PEND;
+                               parent->sk_data_ready(parent, 0);
+                       } else {
+                               sk->sk_state = BT_CONFIG;
+                               result = L2CAP_CR_SUCCESS;
+                               status = L2CAP_CS_NO_INFO;
+                       }
                } else {
                        sk->sk_state = BT_CONNECT2;
                        result = L2CAP_CR_PEND;
@@ -1695,11 +1980,14 @@ static inline int l2cap_connect_rsp(struct l2cap_conn *conn, struct l2cap_cmd_hd
                l2cap_pi(sk)->dcid = dcid;
                l2cap_pi(sk)->conf_state |= L2CAP_CONF_REQ_SENT;
 
+               l2cap_pi(sk)->conf_state &= ~L2CAP_CONF_CONNECT_PEND;
+
                l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_CONF_REQ,
                                        l2cap_build_conf_req(sk, req), req);
                break;
 
        case L2CAP_CR_PEND:
+               l2cap_pi(sk)->conf_state |= L2CAP_CONF_CONNECT_PEND;
                break;
 
        default:
@@ -1908,6 +2196,14 @@ static inline int l2cap_information_req(struct l2cap_conn *conn, struct l2cap_cm
                put_unaligned(cpu_to_le32(l2cap_feat_mask), (__le32 *) rsp->data);
                l2cap_send_cmd(conn, cmd->ident,
                                        L2CAP_INFO_RSP, sizeof(buf), buf);
+       } else if (type == L2CAP_IT_FIXED_CHAN) {
+               u8 buf[12];
+               struct l2cap_info_rsp *rsp = (struct l2cap_info_rsp *) buf;
+               rsp->type   = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
+               rsp->result = cpu_to_le16(L2CAP_IR_SUCCESS);
+               memcpy(buf + 4, l2cap_fixed_chan, 8);
+               l2cap_send_cmd(conn, cmd->ident,
+                                       L2CAP_INFO_RSP, sizeof(buf), buf);
        } else {
                struct l2cap_info_rsp rsp;
                rsp.type   = cpu_to_le16(type);
@@ -1929,14 +2225,31 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn, struct l2cap_cm
 
        BT_DBG("type 0x%4.4x result 0x%2.2x", type, result);
 
-       conn->info_ident = 0;
-
        del_timer(&conn->info_timer);
 
-       if (type == L2CAP_IT_FEAT_MASK)
+       if (type == L2CAP_IT_FEAT_MASK) {
                conn->feat_mask = get_unaligned_le32(rsp->data);
 
-       l2cap_conn_start(conn);
+               if (conn->feat_mask & 0x0080) {
+                       struct l2cap_info_req req;
+                       req.type = cpu_to_le16(L2CAP_IT_FIXED_CHAN);
+
+                       conn->info_ident = l2cap_get_ident(conn);
+
+                       l2cap_send_cmd(conn, conn->info_ident,
+                                       L2CAP_INFO_REQ, sizeof(req), &req);
+               } else {
+                       conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
+                       conn->info_ident = 0;
+
+                       l2cap_conn_start(conn);
+               }
+       } else if (type == L2CAP_IT_FIXED_CHAN) {
+               conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
+               conn->info_ident = 0;
+
+               l2cap_conn_start(conn);
+       }
 
        return 0;
 }
@@ -2143,10 +2456,15 @@ static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
                        continue;
 
                if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr)) {
-                       lm1 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
+                       lm1 |= HCI_LM_ACCEPT;
+                       if (l2cap_pi(sk)->role_switch)
+                               lm1 |= HCI_LM_MASTER;
                        exact++;
-               } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY))
-                       lm2 |= (HCI_LM_ACCEPT | l2cap_pi(sk)->link_mode);
+               } else if (!bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
+                       lm2 |= HCI_LM_ACCEPT;
+                       if (l2cap_pi(sk)->role_switch)
+                               lm2 |= HCI_LM_MASTER;
+               }
        }
        read_unlock(&l2cap_sk_list.lock);
 
@@ -2172,89 +2490,48 @@ static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
        return 0;
 }
 
-static int l2cap_disconn_ind(struct hci_conn *hcon, u8 reason)
+static int l2cap_disconn_ind(struct hci_conn *hcon)
 {
-       BT_DBG("hcon %p reason %d", hcon, reason);
+       struct l2cap_conn *conn = hcon->l2cap_data;
 
-       if (hcon->type != ACL_LINK)
-               return 0;
+       BT_DBG("hcon %p", hcon);
 
-       l2cap_conn_del(hcon, bt_err(reason));
+       if (hcon->type != ACL_LINK || !conn)
+               return 0x13;
 
-       return 0;
+       return conn->disc_reason;
 }
 
-static int l2cap_auth_cfm(struct hci_conn *hcon, u8 status)
+static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
 {
-       struct l2cap_chan_list *l;
-       struct l2cap_conn *conn = hcon->l2cap_data;
-       struct sock *sk;
+       BT_DBG("hcon %p reason %d", hcon, reason);
 
-       if (!conn)
+       if (hcon->type != ACL_LINK)
                return 0;
 
-       l = &conn->chan_list;
-
-       BT_DBG("conn %p", conn);
-
-       read_lock(&l->lock);
-
-       for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-               struct l2cap_pinfo *pi = l2cap_pi(sk);
-
-               bh_lock_sock(sk);
-
-               if ((pi->link_mode & (L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)) &&
-                                       !(hcon->link_mode & HCI_LM_ENCRYPT) &&
-                                                               !status) {
-                       bh_unlock_sock(sk);
-                       continue;
-               }
-
-               if (sk->sk_state == BT_CONNECT) {
-                       if (!status) {
-                               struct l2cap_conn_req req;
-                               req.scid = cpu_to_le16(l2cap_pi(sk)->scid);
-                               req.psm  = l2cap_pi(sk)->psm;
-
-                               l2cap_pi(sk)->ident = l2cap_get_ident(conn);
-
-                               l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
-                                       L2CAP_CONN_REQ, sizeof(req), &req);
-                       } else {
-                               l2cap_sock_clear_timer(sk);
-                               l2cap_sock_set_timer(sk, HZ / 10);
-                       }
-               } else if (sk->sk_state == BT_CONNECT2) {
-                       struct l2cap_conn_rsp rsp;
-                       __u16 result;
+       l2cap_conn_del(hcon, bt_err(reason));
 
-                       if (!status) {
-                               sk->sk_state = BT_CONFIG;
-                               result = L2CAP_CR_SUCCESS;
-                       } else {
-                               sk->sk_state = BT_DISCONN;
-                               l2cap_sock_set_timer(sk, HZ / 10);
-                               result = L2CAP_CR_SEC_BLOCK;
-                       }
+       return 0;
+}
 
-                       rsp.scid   = cpu_to_le16(l2cap_pi(sk)->dcid);
-                       rsp.dcid   = cpu_to_le16(l2cap_pi(sk)->scid);
-                       rsp.result = cpu_to_le16(result);
-                       rsp.status = cpu_to_le16(L2CAP_CS_NO_INFO);
-                       l2cap_send_cmd(conn, l2cap_pi(sk)->ident,
-                                       L2CAP_CONN_RSP, sizeof(rsp), &rsp);
-               }
+static inline void l2cap_check_encryption(struct sock *sk, u8 encrypt)
+{
+       if (sk->sk_type != SOCK_SEQPACKET)
+               return;
 
-               bh_unlock_sock(sk);
+       if (encrypt == 0x00) {
+               if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM) {
+                       l2cap_sock_clear_timer(sk);
+                       l2cap_sock_set_timer(sk, HZ * 5);
+               } else if (l2cap_pi(sk)->sec_level == BT_SECURITY_HIGH)
+                       __l2cap_sock_close(sk, ECONNREFUSED);
+       } else {
+               if (l2cap_pi(sk)->sec_level == BT_SECURITY_MEDIUM)
+                       l2cap_sock_clear_timer(sk);
        }
-
-       read_unlock(&l->lock);
-
-       return 0;
 }
 
-static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
+static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
 {
        struct l2cap_chan_list *l;
        struct l2cap_conn *conn = hcon->l2cap_data;
@@ -2270,15 +2547,16 @@ static int l2cap_encrypt_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
        read_lock(&l->lock);
 
        for (sk = l->head; sk; sk = l2cap_pi(sk)->next_c) {
-               struct l2cap_pinfo *pi = l2cap_pi(sk);
-
                bh_lock_sock(sk);
 
-               if ((pi->link_mode & (L2CAP_LM_ENCRYPT | L2CAP_LM_SECURE)) &&
-                                       (sk->sk_state == BT_CONNECTED ||
-                                               sk->sk_state == BT_CONFIG) &&
-                                               !status && encrypt == 0x00) {
-                       __l2cap_sock_close(sk, ECONNREFUSED);
+               if (l2cap_pi(sk)->conf_state & L2CAP_CONF_CONNECT_PEND) {
+                       bh_unlock_sock(sk);
+                       continue;
+               }
+
+               if (!status && (sk->sk_state == BT_CONNECTED ||
+                                               sk->sk_state == BT_CONFIG)) {
+                       l2cap_check_encryption(sk, encrypt);
                        bh_unlock_sock(sk);
                        continue;
                }
@@ -2376,7 +2654,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
                        goto drop;
 
                skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
-                             skb->len);
+                                                               skb->len);
                conn->rx_len = len - skb->len;
        } else {
                BT_DBG("Cont: frag len %d (expecting %d)", skb->len, conn->rx_len);
@@ -2398,7 +2676,7 @@ static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 fl
                }
 
                skb_copy_from_linear_data(skb, skb_put(conn->rx_skb, skb->len),
-                             skb->len);
+                                                               skb->len);
                conn->rx_len -= skb->len;
 
                if (!conn->rx_len) {
@@ -2424,10 +2702,10 @@ static ssize_t l2cap_sysfs_show(struct class *dev, char *buf)
        sk_for_each(sk, node, &l2cap_sk_list.head) {
                struct l2cap_pinfo *pi = l2cap_pi(sk);
 
-               str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d 0x%x\n",
+               str += sprintf(str, "%s %s %d %d 0x%4.4x 0x%4.4x %d %d %d\n",
                                batostr(&bt_sk(sk)->src), batostr(&bt_sk(sk)->dst),
                                sk->sk_state, btohs(pi->psm), pi->scid, pi->dcid,
-                               pi->imtu, pi->omtu, pi->link_mode);
+                               pi->imtu, pi->omtu, pi->sec_level);
        }
 
        read_unlock_bh(&l2cap_sk_list.lock);
@@ -2447,7 +2725,7 @@ static const struct proto_ops l2cap_sock_ops = {
        .accept         = l2cap_sock_accept,
        .getname        = l2cap_sock_getname,
        .sendmsg        = l2cap_sock_sendmsg,
-       .recvmsg        = bt_sock_recvmsg,
+       .recvmsg        = l2cap_sock_recvmsg,
        .poll           = bt_sock_poll,
        .ioctl          = bt_sock_ioctl,
        .mmap           = sock_no_mmap,
@@ -2469,8 +2747,8 @@ static struct hci_proto l2cap_hci_proto = {
        .connect_ind    = l2cap_connect_ind,
        .connect_cfm    = l2cap_connect_cfm,
        .disconn_ind    = l2cap_disconn_ind,
-       .auth_cfm       = l2cap_auth_cfm,
-       .encrypt_cfm    = l2cap_encrypt_cfm,
+       .disconn_cfm    = l2cap_disconn_cfm,
+       .security_cfm   = l2cap_security_cfm,
        .recv_acldata   = l2cap_recv_acldata
 };
 
index acd84fd524b856c25cf1f7c40560c3a6726d7236..1d0fb0f23c63162ddd008eaf4d39ece9384a45f6 100644 (file)
@@ -46,7 +46,7 @@
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/rfcomm.h>
 
-#define VERSION "1.10"
+#define VERSION "1.11"
 
 static int disable_cfc = 0;
 static int channel_mtu = -1;
@@ -223,19 +223,25 @@ static int rfcomm_l2sock_create(struct socket **sock)
        return err;
 }
 
-static inline int rfcomm_check_link_mode(struct rfcomm_dlc *d)
+static inline int rfcomm_check_security(struct rfcomm_dlc *d)
 {
        struct sock *sk = d->session->sock->sk;
+       __u8 auth_type;
 
-       if (d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) {
-               if (!hci_conn_encrypt(l2cap_pi(sk)->conn->hcon))
-                       return 1;
-       } else if (d->link_mode & RFCOMM_LM_AUTH) {
-               if (!hci_conn_auth(l2cap_pi(sk)->conn->hcon))
-                       return 1;
+       switch (d->sec_level) {
+       case BT_SECURITY_HIGH:
+               auth_type = HCI_AT_GENERAL_BONDING_MITM;
+               break;
+       case BT_SECURITY_MEDIUM:
+               auth_type = HCI_AT_GENERAL_BONDING;
+               break;
+       default:
+               auth_type = HCI_AT_NO_BONDING;
+               break;
        }
 
-       return 0;
+       return hci_conn_security(l2cap_pi(sk)->conn->hcon, d->sec_level,
+                                                               auth_type);
 }
 
 /* ---- RFCOMM DLCs ---- */
@@ -388,10 +394,10 @@ static int __rfcomm_dlc_open(struct rfcomm_dlc *d, bdaddr_t *src, bdaddr_t *dst,
        d->cfc = (s->cfc == RFCOMM_CFC_UNKNOWN) ? 0 : s->cfc;
 
        if (s->state == BT_CONNECTED) {
-               if (rfcomm_check_link_mode(d))
-                       set_bit(RFCOMM_AUTH_PENDING, &d->flags);
-               else
+               if (rfcomm_check_security(d))
                        rfcomm_send_pn(s, 1, d);
+               else
+                       set_bit(RFCOMM_AUTH_PENDING, &d->flags);
        }
 
        rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
@@ -421,9 +427,16 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
                        d, d->state, d->dlci, err, s);
 
        switch (d->state) {
-       case BT_CONNECTED:
-       case BT_CONFIG:
        case BT_CONNECT:
+       case BT_CONFIG:
+               if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
+                       set_bit(RFCOMM_AUTH_REJECT, &d->flags);
+                       rfcomm_schedule(RFCOMM_SCHED_AUTH);
+                       break;
+               }
+               /* Fall through */
+
+       case BT_CONNECTED:
                d->state = BT_DISCONN;
                if (skb_queue_empty(&d->tx_queue)) {
                        rfcomm_send_disc(s, d->dlci);
@@ -434,6 +447,15 @@ static int __rfcomm_dlc_close(struct rfcomm_dlc *d, int err)
                }
                break;
 
+       case BT_OPEN:
+       case BT_CONNECT2:
+               if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
+                       set_bit(RFCOMM_AUTH_REJECT, &d->flags);
+                       rfcomm_schedule(RFCOMM_SCHED_AUTH);
+                       break;
+               }
+               /* Fall through */
+
        default:
                rfcomm_dlc_clear_timer(d);
 
@@ -636,6 +658,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst
        bacpy(&addr.l2_bdaddr, src);
        addr.l2_family = AF_BLUETOOTH;
        addr.l2_psm    = 0;
+       addr.l2_cid    = 0;
        *err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
        if (*err < 0)
                goto failed;
@@ -657,6 +680,7 @@ static struct rfcomm_session *rfcomm_session_create(bdaddr_t *src, bdaddr_t *dst
        bacpy(&addr.l2_bdaddr, dst);
        addr.l2_family = AF_BLUETOOTH;
        addr.l2_psm    = htobs(RFCOMM_PSM);
+       addr.l2_cid    = 0;
        *err = kernel_connect(sock, (struct sockaddr *) &addr, sizeof(addr), O_NONBLOCK);
        if (*err == 0 || *err == -EINPROGRESS)
                return s;
@@ -1162,7 +1186,7 @@ static int rfcomm_recv_disc(struct rfcomm_session *s, u8 dlci)
        return 0;
 }
 
-static void rfcomm_dlc_accept(struct rfcomm_dlc *d)
+void rfcomm_dlc_accept(struct rfcomm_dlc *d)
 {
        struct sock *sk = d->session->sock->sk;
 
@@ -1175,12 +1199,31 @@ static void rfcomm_dlc_accept(struct rfcomm_dlc *d)
        d->state_change(d, 0);
        rfcomm_dlc_unlock(d);
 
-       if (d->link_mode & RFCOMM_LM_MASTER)
+       if (d->role_switch)
                hci_conn_switch_role(l2cap_pi(sk)->conn->hcon, 0x00);
 
        rfcomm_send_msc(d->session, 1, d->dlci, d->v24_sig);
 }
 
+static void rfcomm_check_accept(struct rfcomm_dlc *d)
+{
+       if (rfcomm_check_security(d)) {
+               if (d->defer_setup) {
+                       set_bit(RFCOMM_DEFER_SETUP, &d->flags);
+                       rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
+
+                       rfcomm_dlc_lock(d);
+                       d->state = BT_CONNECT2;
+                       d->state_change(d, 0);
+                       rfcomm_dlc_unlock(d);
+               } else
+                       rfcomm_dlc_accept(d);
+       } else {
+               set_bit(RFCOMM_AUTH_PENDING, &d->flags);
+               rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
+       }
+}
+
 static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
 {
        struct rfcomm_dlc *d;
@@ -1203,11 +1246,7 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
        if (d) {
                if (d->state == BT_OPEN) {
                        /* DLC was previously opened by PN request */
-                       if (rfcomm_check_link_mode(d)) {
-                               set_bit(RFCOMM_AUTH_PENDING, &d->flags);
-                               rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
-                       } else
-                               rfcomm_dlc_accept(d);
+                       rfcomm_check_accept(d);
                }
                return 0;
        }
@@ -1219,11 +1258,7 @@ static int rfcomm_recv_sabm(struct rfcomm_session *s, u8 dlci)
                d->addr = __addr(s->initiator, dlci);
                rfcomm_dlc_link(s, d);
 
-               if (rfcomm_check_link_mode(d)) {
-                       set_bit(RFCOMM_AUTH_PENDING, &d->flags);
-                       rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
-               } else
-                       rfcomm_dlc_accept(d);
+               rfcomm_check_accept(d);
        } else {
                rfcomm_send_dm(s, dlci);
        }
@@ -1637,11 +1672,12 @@ static void rfcomm_process_connect(struct rfcomm_session *s)
                d = list_entry(p, struct rfcomm_dlc, list);
                if (d->state == BT_CONFIG) {
                        d->mtu = s->mtu;
-                       if (rfcomm_check_link_mode(d)) {
+                       if (rfcomm_check_security(d)) {
+                               rfcomm_send_pn(s, 1, d);
+                       } else {
                                set_bit(RFCOMM_AUTH_PENDING, &d->flags);
                                rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
-                       } else
-                               rfcomm_send_pn(s, 1, d);
+                       }
                }
        }
 }
@@ -1717,11 +1753,17 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
                        if (d->out) {
                                rfcomm_send_pn(s, 1, d);
                                rfcomm_dlc_set_timer(d, RFCOMM_CONN_TIMEOUT);
-                       } else
-                               rfcomm_dlc_accept(d);
-                       if (d->link_mode & RFCOMM_LM_SECURE) {
-                               struct sock *sk = s->sock->sk;
-                               hci_conn_change_link_key(l2cap_pi(sk)->conn->hcon);
+                       } else {
+                               if (d->defer_setup) {
+                                       set_bit(RFCOMM_DEFER_SETUP, &d->flags);
+                                       rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
+
+                                       rfcomm_dlc_lock(d);
+                                       d->state = BT_CONNECT2;
+                                       d->state_change(d, 0);
+                                       rfcomm_dlc_unlock(d);
+                               } else
+                                       rfcomm_dlc_accept(d);
                        }
                        continue;
                } else if (test_and_clear_bit(RFCOMM_AUTH_REJECT, &d->flags)) {
@@ -1734,6 +1776,9 @@ static inline void rfcomm_process_dlcs(struct rfcomm_session *s)
                        continue;
                }
 
+               if (test_bit(RFCOMM_SEC_PENDING, &d->flags))
+                       continue;
+
                if (test_bit(RFCOMM_TX_THROTTLED, &s->flags))
                        continue;
 
@@ -1876,6 +1921,7 @@ static int rfcomm_add_listener(bdaddr_t *ba)
        bacpy(&addr.l2_bdaddr, ba);
        addr.l2_family = AF_BLUETOOTH;
        addr.l2_psm    = htobs(RFCOMM_PSM);
+       addr.l2_cid    = 0;
        err = kernel_bind(sock, (struct sockaddr *) &addr, sizeof(addr));
        if (err < 0) {
                BT_ERR("Bind failed %d", err);
@@ -1947,42 +1993,7 @@ static int rfcomm_run(void *unused)
        return 0;
 }
 
-static void rfcomm_auth_cfm(struct hci_conn *conn, u8 status)
-{
-       struct rfcomm_session *s;
-       struct rfcomm_dlc *d;
-       struct list_head *p, *n;
-
-       BT_DBG("conn %p status 0x%02x", conn, status);
-
-       s = rfcomm_session_get(&conn->hdev->bdaddr, &conn->dst);
-       if (!s)
-               return;
-
-       rfcomm_session_hold(s);
-
-       list_for_each_safe(p, n, &s->dlcs) {
-               d = list_entry(p, struct rfcomm_dlc, list);
-
-               if ((d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) &&
-                               !(conn->link_mode & HCI_LM_ENCRYPT) && !status)
-                       continue;
-
-               if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))
-                       continue;
-
-               if (!status)
-                       set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);
-               else
-                       set_bit(RFCOMM_AUTH_REJECT, &d->flags);
-       }
-
-       rfcomm_session_put(s);
-
-       rfcomm_schedule(RFCOMM_SCHED_AUTH);
-}
-
-static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
+static void rfcomm_security_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
 {
        struct rfcomm_session *s;
        struct rfcomm_dlc *d;
@@ -1999,18 +2010,29 @@ static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
        list_for_each_safe(p, n, &s->dlcs) {
                d = list_entry(p, struct rfcomm_dlc, list);
 
-               if ((d->link_mode & (RFCOMM_LM_ENCRYPT | RFCOMM_LM_SECURE)) &&
-                                       (d->state == BT_CONNECTED ||
-                                               d->state == BT_CONFIG) &&
-                                               !status && encrypt == 0x00) {
-                       __rfcomm_dlc_close(d, ECONNREFUSED);
-                       continue;
+               if (test_and_clear_bit(RFCOMM_SEC_PENDING, &d->flags)) {
+                       rfcomm_dlc_clear_timer(d);
+                       if (status || encrypt == 0x00) {
+                               __rfcomm_dlc_close(d, ECONNREFUSED);
+                               continue;
+                       }
+               }
+
+               if (d->state == BT_CONNECTED && !status && encrypt == 0x00) {
+                       if (d->sec_level == BT_SECURITY_MEDIUM) {
+                               set_bit(RFCOMM_SEC_PENDING, &d->flags);
+                               rfcomm_dlc_set_timer(d, RFCOMM_AUTH_TIMEOUT);
+                               continue;
+                       } else if (d->sec_level == BT_SECURITY_HIGH) {
+                               __rfcomm_dlc_close(d, ECONNREFUSED);
+                               continue;
+                       }
                }
 
                if (!test_and_clear_bit(RFCOMM_AUTH_PENDING, &d->flags))
                        continue;
 
-               if (!status && encrypt)
+               if (!status)
                        set_bit(RFCOMM_AUTH_ACCEPT, &d->flags);
                else
                        set_bit(RFCOMM_AUTH_REJECT, &d->flags);
@@ -2023,8 +2045,7 @@ static void rfcomm_encrypt_cfm(struct hci_conn *conn, u8 status, u8 encrypt)
 
 static struct hci_cb rfcomm_cb = {
        .name           = "RFCOMM",
-       .auth_cfm       = rfcomm_auth_cfm,
-       .encrypt_cfm    = rfcomm_encrypt_cfm
+       .security_cfm   = rfcomm_security_cfm
 };
 
 static ssize_t rfcomm_dlc_sysfs_show(struct class *dev, char *buf)
index d3fc6fca38d0892af7fe2e2d0f18328a82b6df2e..7f482784e9f7b3a3e2033c58459e0d9136053701 100644 (file)
@@ -261,12 +261,19 @@ static void rfcomm_sock_init(struct sock *sk, struct sock *parent)
 
        if (parent) {
                sk->sk_type = parent->sk_type;
-               pi->link_mode = rfcomm_pi(parent)->link_mode;
+               pi->dlc->defer_setup = bt_sk(parent)->defer_setup;
+
+               pi->sec_level = rfcomm_pi(parent)->sec_level;
+               pi->role_switch = rfcomm_pi(parent)->role_switch;
        } else {
-               pi->link_mode = 0;
+               pi->dlc->defer_setup = 0;
+
+               pi->sec_level = BT_SECURITY_LOW;
+               pi->role_switch = 0;
        }
 
-       pi->dlc->link_mode = pi->link_mode;
+       pi->dlc->sec_level = pi->sec_level;
+       pi->dlc->role_switch = pi->role_switch;
 }
 
 static struct proto rfcomm_proto = {
@@ -406,7 +413,8 @@ static int rfcomm_sock_connect(struct socket *sock, struct sockaddr *addr, int a
        bacpy(&bt_sk(sk)->dst, &sa->rc_bdaddr);
        rfcomm_pi(sk)->channel = sa->rc_channel;
 
-       d->link_mode = rfcomm_pi(sk)->link_mode;
+       d->sec_level = rfcomm_pi(sk)->sec_level;
+       d->role_switch = rfcomm_pi(sk)->role_switch;
 
        err = rfcomm_dlc_open(d, &bt_sk(sk)->src, &sa->rc_bdaddr, sa->rc_channel);
        if (!err)
@@ -554,6 +562,9 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
        struct sk_buff *skb;
        int sent = 0;
 
+       if (test_bit(RFCOMM_DEFER_SETUP, &d->flags))
+               return -ENOTCONN;
+
        if (msg->msg_flags & MSG_OOB)
                return -EOPNOTSUPP;
 
@@ -570,8 +581,11 @@ static int rfcomm_sock_sendmsg(struct kiocb *iocb, struct socket *sock,
 
                skb = sock_alloc_send_skb(sk, size + RFCOMM_SKB_RESERVE,
                                msg->msg_flags & MSG_DONTWAIT, &err);
-               if (!skb)
+               if (!skb) {
+                       if (sent == 0)
+                               sent = err;
                        break;
+               }
                skb_reserve(skb, RFCOMM_SKB_HEAD_RESERVE);
 
                err = memcpy_fromiovec(skb_put(skb, size), msg->msg_iov, size);
@@ -630,10 +644,16 @@ static int rfcomm_sock_recvmsg(struct kiocb *iocb, struct socket *sock,
                               struct msghdr *msg, size_t size, int flags)
 {
        struct sock *sk = sock->sk;
+       struct rfcomm_dlc *d = rfcomm_pi(sk)->dlc;
        int err = 0;
        size_t target, copied = 0;
        long timeo;
 
+       if (test_and_clear_bit(RFCOMM_DEFER_SETUP, &d->flags)) {
+               rfcomm_dlc_accept(d);
+               return 0;
+       }
+
        if (flags & MSG_OOB)
                return -EOPNOTSUPP;
 
@@ -710,7 +730,7 @@ out:
        return copied ? : err;
 }
 
-static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
+static int rfcomm_sock_setsockopt_old(struct socket *sock, int optname, char __user *optval, int optlen)
 {
        struct sock *sk = sock->sk;
        int err = 0;
@@ -727,7 +747,14 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
                        break;
                }
 
-               rfcomm_pi(sk)->link_mode = opt;
+               if (opt & RFCOMM_LM_AUTH)
+                       rfcomm_pi(sk)->sec_level = BT_SECURITY_LOW;
+               if (opt & RFCOMM_LM_ENCRYPT)
+                       rfcomm_pi(sk)->sec_level = BT_SECURITY_MEDIUM;
+               if (opt & RFCOMM_LM_SECURE)
+                       rfcomm_pi(sk)->sec_level = BT_SECURITY_HIGH;
+
+               rfcomm_pi(sk)->role_switch = (opt & RFCOMM_LM_MASTER);
                break;
 
        default:
@@ -739,12 +766,76 @@ static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, c
        return err;
 }
 
-static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
+static int rfcomm_sock_setsockopt(struct socket *sock, int level, int optname, char __user *optval, int optlen)
+{
+       struct sock *sk = sock->sk;
+       struct bt_security sec;
+       int len, err = 0;
+       u32 opt;
+
+       BT_DBG("sk %p", sk);
+
+       if (level == SOL_RFCOMM)
+               return rfcomm_sock_setsockopt_old(sock, optname, optval, optlen);
+
+       if (level != SOL_BLUETOOTH)
+               return -ENOPROTOOPT;
+
+       lock_sock(sk);
+
+       switch (optname) {
+       case BT_SECURITY:
+               if (sk->sk_type != SOCK_STREAM) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               sec.level = BT_SECURITY_LOW;
+
+               len = min_t(unsigned int, sizeof(sec), optlen);
+               if (copy_from_user((char *) &sec, optval, len)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               if (sec.level > BT_SECURITY_HIGH) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               rfcomm_pi(sk)->sec_level = sec.level;
+               break;
+
+       case BT_DEFER_SETUP:
+               if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (get_user(opt, (u32 __user *) optval)) {
+                       err = -EFAULT;
+                       break;
+               }
+
+               bt_sk(sk)->defer_setup = opt;
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       release_sock(sk);
+       return err;
+}
+
+static int rfcomm_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
        struct sock *l2cap_sk;
        struct rfcomm_conninfo cinfo;
        int len, err = 0;
+       u32 opt;
 
        BT_DBG("sk %p", sk);
 
@@ -755,12 +846,32 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c
 
        switch (optname) {
        case RFCOMM_LM:
-               if (put_user(rfcomm_pi(sk)->link_mode, (u32 __user *) optval))
+               switch (rfcomm_pi(sk)->sec_level) {
+               case BT_SECURITY_LOW:
+                       opt = RFCOMM_LM_AUTH;
+                       break;
+               case BT_SECURITY_MEDIUM:
+                       opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT;
+                       break;
+               case BT_SECURITY_HIGH:
+                       opt = RFCOMM_LM_AUTH | RFCOMM_LM_ENCRYPT |
+                                                       RFCOMM_LM_SECURE;
+                       break;
+               default:
+                       opt = 0;
+                       break;
+               }
+
+               if (rfcomm_pi(sk)->role_switch)
+                       opt |= RFCOMM_LM_MASTER;
+
+               if (put_user(opt, (u32 __user *) optval))
                        err = -EFAULT;
                break;
 
        case RFCOMM_CONNINFO:
-               if (sk->sk_state != BT_CONNECTED) {
+               if (sk->sk_state != BT_CONNECTED &&
+                                       !rfcomm_pi(sk)->dlc->defer_setup) {
                        err = -ENOTCONN;
                        break;
                }
@@ -785,6 +896,60 @@ static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, c
        return err;
 }
 
+static int rfcomm_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
+{
+       struct sock *sk = sock->sk;
+       struct bt_security sec;
+       int len, err = 0;
+
+       BT_DBG("sk %p", sk);
+
+       if (level == SOL_RFCOMM)
+               return rfcomm_sock_getsockopt_old(sock, optname, optval, optlen);
+
+       if (level != SOL_BLUETOOTH)
+               return -ENOPROTOOPT;
+
+       if (get_user(len, optlen))
+               return -EFAULT;
+
+       lock_sock(sk);
+
+       switch (optname) {
+       case BT_SECURITY:
+               if (sk->sk_type != SOCK_STREAM) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               sec.level = rfcomm_pi(sk)->sec_level;
+
+               len = min_t(unsigned int, len, sizeof(sec));
+               if (copy_to_user(optval, (char *) &sec, len))
+                       err = -EFAULT;
+
+               break;
+
+       case BT_DEFER_SETUP:
+               if (sk->sk_state != BT_BOUND && sk->sk_state != BT_LISTEN) {
+                       err = -EINVAL;
+                       break;
+               }
+
+               if (put_user(bt_sk(sk)->defer_setup, (u32 __user *) optval))
+                       err = -EFAULT;
+
+               break;
+
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       release_sock(sk);
+       return err;
+}
+
 static int rfcomm_sock_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 {
        struct sock *sk __maybe_unused = sock->sk;
@@ -888,6 +1053,10 @@ int rfcomm_connect_ind(struct rfcomm_session *s, u8 channel, struct rfcomm_dlc *
 
 done:
        bh_unlock_sock(parent);
+
+       if (bt_sk(parent)->defer_setup)
+               parent->sk_state_change(parent);
+
        return result;
 }
 
index 46fd8bf9a69056fcf69d2aa6d5f7617768bb8ef1..51ae0c3e470a3ae5884c82ce5f62afb5942eab05 100644 (file)
@@ -195,7 +195,7 @@ static int sco_connect(struct sock *sk)
        else
                type = SCO_LINK;
 
-       hcon = hci_connect(hdev, type, dst, HCI_AT_NO_BONDING);
+       hcon = hci_connect(hdev, type, dst, BT_SECURITY_LOW, HCI_AT_NO_BONDING);
        if (!hcon)
                goto done;
 
@@ -668,7 +668,7 @@ static int sco_sock_setsockopt(struct socket *sock, int level, int optname, char
        return err;
 }
 
-static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
+static int sco_sock_getsockopt_old(struct socket *sock, int optname, char __user *optval, int __user *optlen)
 {
        struct sock *sk = sock->sk;
        struct sco_options opts;
@@ -723,6 +723,31 @@ static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char
        return err;
 }
 
+static int sco_sock_getsockopt(struct socket *sock, int level, int optname, char __user *optval, int __user *optlen)
+{
+       struct sock *sk = sock->sk;
+       int len, err = 0;
+
+       BT_DBG("sk %p", sk);
+
+       if (level == SOL_SCO)
+               return sco_sock_getsockopt_old(sock, optname, optval, optlen);
+
+       if (get_user(len, optlen))
+               return -EFAULT;
+
+       lock_sock(sk);
+
+       switch (optname) {
+       default:
+               err = -ENOPROTOOPT;
+               break;
+       }
+
+       release_sock(sk);
+       return err;
+}
+
 static int sco_sock_release(struct socket *sock)
 {
        struct sock *sk = sock->sk;
@@ -832,10 +857,30 @@ done:
 /* ----- SCO interface with lower layer (HCI) ----- */
 static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
 {
+       register struct sock *sk;
+       struct hlist_node *node;
+       int lm = 0;
+
+       if (type != SCO_LINK && type != ESCO_LINK)
+               return 0;
+
        BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
 
-       /* Always accept connection */
-       return HCI_LM_ACCEPT;
+       /* Find listening sockets */
+       read_lock(&sco_sk_list.lock);
+       sk_for_each(sk, node, &sco_sk_list.head) {
+               if (sk->sk_state != BT_LISTEN)
+                       continue;
+
+               if (!bacmp(&bt_sk(sk)->src, &hdev->bdaddr) ||
+                               !bacmp(&bt_sk(sk)->src, BDADDR_ANY)) {
+                       lm |= HCI_LM_ACCEPT;
+                       break;
+               }
+       }
+       read_unlock(&sco_sk_list.lock);
+
+       return lm;
 }
 
 static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
@@ -857,7 +902,7 @@ static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
        return 0;
 }
 
-static int sco_disconn_ind(struct hci_conn *hcon, __u8 reason)
+static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
 {
        BT_DBG("hcon %p reason %d", hcon, reason);
 
@@ -940,7 +985,7 @@ static struct hci_proto sco_hci_proto = {
        .id             = HCI_PROTO_SCO,
        .connect_ind    = sco_connect_ind,
        .connect_cfm    = sco_connect_cfm,
-       .disconn_ind    = sco_disconn_ind,
+       .disconn_cfm    = sco_disconn_cfm,
        .recv_scodata   = sco_recv_scodata
 };
 
index ba7be195803c596e9234ebc985eeff99ce08b5c8..fcffb3fb1177aa57352f4fdbcc0247944d1959ac 100644 (file)
@@ -98,7 +98,8 @@ void br_ifinfo_notify(int event, struct net_bridge_port *port)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
+       rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_ATOMIC);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_LINK, err);
index d90e8dd975fcf05d842be52fd41ef8e1f369d411..547bafc79e28585c44f5d59b46c9884ec1d414da 100644 (file)
@@ -273,8 +273,7 @@ int can_send(struct sk_buff *skb, int loop)
                err = net_xmit_errno(err);
 
        if (err) {
-               if (newskb)
-                       kfree_skb(newskb);
+               kfree_skb(newskb);
                return err;
        }
 
index 26a37cb3192316a715f7128bb717a3346d8ae76c..796f46eece5f18b3843e5d75942ef27318dc1b4a 100644 (file)
@@ -17,3 +17,6 @@ obj-$(CONFIG_NET_PKTGEN) += pktgen.o
 obj-$(CONFIG_NETPOLL) += netpoll.o
 obj-$(CONFIG_NET_DMA) += user_dma.o
 obj-$(CONFIG_FIB_RULES) += fib_rules.o
+obj-$(CONFIG_TRACEPOINTS) += net-traces.o
+obj-$(CONFIG_NET_DROP_MONITOR) += drop_monitor.o
+
index 5e2ac0c4b07cfdab7b2a5a2c74e2c2ddcd337328..d0de644b378d5a71e161a905c85d847622df49d2 100644 (file)
@@ -208,7 +208,7 @@ struct sk_buff *skb_recv_datagram(struct sock *sk, unsigned flags,
 
 void skb_free_datagram(struct sock *sk, struct sk_buff *skb)
 {
-       kfree_skb(skb);
+       consume_skb(skb);
        sk_mem_reclaim_partial(sk);
 }
 
index d393fc997cd96683dc0f61b6be11e6b78b06d49b..052dd478d3e112b769b66ab83db5b82996d88061 100644 (file)
 /* This should be increased if a protocol with a bigger head is added. */
 #define GRO_MAX_HEAD (MAX_HEADER + 128)
 
-enum {
-       GRO_MERGED,
-       GRO_MERGED_FREE,
-       GRO_HELD,
-       GRO_NORMAL,
-       GRO_DROP,
-};
-
 /*
  *     The list of packet types we will receive (as opposed to discard)
  *     and the routines to invoke.
@@ -1672,23 +1664,12 @@ static int dev_gso_segment(struct sk_buff *skb)
        return 0;
 }
 
-static void tstamp_tx(struct sk_buff *skb)
-{
-       union skb_shared_tx *shtx =
-               skb_tx(skb);
-       if (unlikely(shtx->software &&
-                       !shtx->in_progress)) {
-               skb_tstamp_tx(skb, NULL);
-       }
-}
-
 int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
                        struct netdev_queue *txq)
 {
        const struct net_device_ops *ops = dev->netdev_ops;
        int rc;
 
-       prefetch(&dev->netdev_ops->ndo_start_xmit);
        if (likely(!skb->next)) {
                if (!list_empty(&ptype_all))
                        dev_queue_xmit_nit(skb, dev);
@@ -1715,8 +1696,6 @@ int dev_hard_start_xmit(struct sk_buff *skb, struct net_device *dev,
                 * the skb destructor before the call and restoring it
                 * afterwards, then doing the skb_orphan() ourselves?
                 */
-               if (likely(!rc))
-                       tstamp_tx(skb);
                return rc;
        }
 
@@ -1732,7 +1711,6 @@ gso:
                        skb->next = nskb;
                        return rc;
                }
-               tstamp_tx(skb);
                if (unlikely(netif_tx_queue_stopped(txq) && skb->next))
                        return NETDEV_TX_BUSY;
        } while (skb->next);
@@ -1745,17 +1723,11 @@ out_kfree_skb:
 }
 
 static u32 skb_tx_hashrnd;
-static int skb_tx_hashrnd_initialized = 0;
 
-static u16 skb_tx_hash(struct net_device *dev, struct sk_buff *skb)
+u16 skb_tx_hash(const struct net_device *dev, const struct sk_buff *skb)
 {
        u32 hash;
 
-       if (unlikely(!skb_tx_hashrnd_initialized)) {
-               get_random_bytes(&skb_tx_hashrnd, 4);
-               skb_tx_hashrnd_initialized = 1;
-       }
-
        if (skb_rx_queue_recorded(skb)) {
                hash = skb_get_rx_queue(skb);
        } else if (skb->sk && skb->sk->sk_hash) {
@@ -1767,6 +1739,7 @@ static u16 skb_tx_hash(struct net_device *dev, struct sk_buff *skb)
 
        return (u16) (((u64) hash * dev->real_num_tx_queues) >> 32);
 }
+EXPORT_SYMBOL(skb_tx_hash);
 
 static struct netdev_queue *dev_pick_tx(struct net_device *dev,
                                        struct sk_buff *skb)
@@ -2273,12 +2246,6 @@ int netif_receive_skb(struct sk_buff *skb)
 
        rcu_read_lock();
 
-       /* Don't receive packets in an exiting network namespace */
-       if (!net_alive(dev_net(skb->dev))) {
-               kfree_skb(skb);
-               goto out;
-       }
-
 #ifdef CONFIG_NET_CLS_ACT
        if (skb->tc_verd & TC_NCLS) {
                skb->tc_verd = CLR_TC_NCLS(skb->tc_verd);
@@ -2499,6 +2466,9 @@ static int __napi_gro_receive(struct napi_struct *napi, struct sk_buff *skb)
 {
        struct sk_buff *p;
 
+       if (netpoll_rx_on(skb))
+               return GRO_NORMAL;
+
        for (p = napi->gro_list; p; p = p->next) {
                NAPI_GRO_CB(p)->same_flow = !compare_ether_header(
                        skb_mac_header(p), skb_gro_mac_header(skb));
@@ -2657,9 +2627,9 @@ static int process_backlog(struct napi_struct *napi, int quota)
                local_irq_disable();
                skb = __skb_dequeue(&queue->input_pkt_queue);
                if (!skb) {
-                       __napi_complete(napi);
                        local_irq_enable();
-                       break;
+                       napi_complete(napi);
+                       goto out;
                }
                local_irq_enable();
 
@@ -2668,6 +2638,7 @@ static int process_backlog(struct napi_struct *napi, int quota)
 
        napi_gro_flush(napi);
 
+out:
        return work;
 }
 
@@ -2741,7 +2712,7 @@ void netif_napi_del(struct napi_struct *napi)
        struct sk_buff *skb, *next;
 
        list_del_init(&napi->dev_list);
-       kfree(napi->skb);
+       kfree_skb(napi->skb);
 
        for (skb = napi->gro_list; skb; skb = next) {
                next = skb->next;
@@ -4355,6 +4326,39 @@ unsigned long netdev_fix_features(unsigned long features, const char *name)
 }
 EXPORT_SYMBOL(netdev_fix_features);
 
+/* Some devices need to (re-)set their netdev_ops inside
+ * ->init() or similar.  If that happens, we have to setup
+ * the compat pointers again.
+ */
+void netdev_resync_ops(struct net_device *dev)
+{
+#ifdef CONFIG_COMPAT_NET_DEV_OPS
+       const struct net_device_ops *ops = dev->netdev_ops;
+
+       dev->init = ops->ndo_init;
+       dev->uninit = ops->ndo_uninit;
+       dev->open = ops->ndo_open;
+       dev->change_rx_flags = ops->ndo_change_rx_flags;
+       dev->set_rx_mode = ops->ndo_set_rx_mode;
+       dev->set_multicast_list = ops->ndo_set_multicast_list;
+       dev->set_mac_address = ops->ndo_set_mac_address;
+       dev->validate_addr = ops->ndo_validate_addr;
+       dev->do_ioctl = ops->ndo_do_ioctl;
+       dev->set_config = ops->ndo_set_config;
+       dev->change_mtu = ops->ndo_change_mtu;
+       dev->neigh_setup = ops->ndo_neigh_setup;
+       dev->tx_timeout = ops->ndo_tx_timeout;
+       dev->get_stats = ops->ndo_get_stats;
+       dev->vlan_rx_register = ops->ndo_vlan_rx_register;
+       dev->vlan_rx_add_vid = ops->ndo_vlan_rx_add_vid;
+       dev->vlan_rx_kill_vid = ops->ndo_vlan_rx_kill_vid;
+#ifdef CONFIG_NET_POLL_CONTROLLER
+       dev->poll_controller = ops->ndo_poll_controller;
+#endif
+#endif
+}
+EXPORT_SYMBOL(netdev_resync_ops);
+
 /**
  *     register_netdevice      - register a network device
  *     @dev: device to register
@@ -4399,27 +4403,7 @@ int register_netdevice(struct net_device *dev)
         * This is temporary until all network devices are converted.
         */
        if (dev->netdev_ops) {
-               const struct net_device_ops *ops = dev->netdev_ops;
-
-               dev->init = ops->ndo_init;
-               dev->uninit = ops->ndo_uninit;
-               dev->open = ops->ndo_open;
-               dev->change_rx_flags = ops->ndo_change_rx_flags;
-               dev->set_rx_mode = ops->ndo_set_rx_mode;
-               dev->set_multicast_list = ops->ndo_set_multicast_list;
-               dev->set_mac_address = ops->ndo_set_mac_address;
-               dev->validate_addr = ops->ndo_validate_addr;
-               dev->do_ioctl = ops->ndo_do_ioctl;
-               dev->set_config = ops->ndo_set_config;
-               dev->change_mtu = ops->ndo_change_mtu;
-               dev->tx_timeout = ops->ndo_tx_timeout;
-               dev->get_stats = ops->ndo_get_stats;
-               dev->vlan_rx_register = ops->ndo_vlan_rx_register;
-               dev->vlan_rx_add_vid = ops->ndo_vlan_rx_add_vid;
-               dev->vlan_rx_kill_vid = ops->ndo_vlan_rx_kill_vid;
-#ifdef CONFIG_NET_POLL_CONTROLLER
-               dev->poll_controller = ops->ndo_poll_controller;
-#endif
+               netdev_resync_ops(dev);
        } else {
                char drivername[64];
                pr_info("%s (%s): not using net_device_ops yet\n",
@@ -5291,6 +5275,14 @@ out:
 
 subsys_initcall(net_dev_init);
 
+static int __init initialize_hashrnd(void)
+{
+       get_random_bytes(&skb_tx_hashrnd, sizeof(skb_tx_hashrnd));
+       return 0;
+}
+
+late_initcall_sync(initialize_hashrnd);
+
 EXPORT_SYMBOL(__dev_get_by_index);
 EXPORT_SYMBOL(__dev_get_by_name);
 EXPORT_SYMBOL(__dev_remove_pack);
diff --git a/net/core/drop_monitor.c b/net/core/drop_monitor.c
new file mode 100644 (file)
index 0000000..9fd0dc3
--- /dev/null
@@ -0,0 +1,263 @@
+/*
+ * Monitoring code for network dropped packet alerts
+ *
+ * Copyright (C) 2009 Neil Horman <nhorman@tuxdriver.com>
+ */
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/string.h>
+#include <linux/if_arp.h>
+#include <linux/inetdevice.h>
+#include <linux/inet.h>
+#include <linux/interrupt.h>
+#include <linux/netpoll.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <linux/netlink.h>
+#include <linux/net_dropmon.h>
+#include <linux/percpu.h>
+#include <linux/timer.h>
+#include <linux/bitops.h>
+#include <net/genetlink.h>
+
+#include <trace/skb.h>
+
+#include <asm/unaligned.h>
+
+#define TRACE_ON 1
+#define TRACE_OFF 0
+
+static void send_dm_alert(struct work_struct *unused);
+
+
+/*
+ * Globals, our netlink socket pointer
+ * and the work handle that will send up
+ * netlink alerts
+ */
+struct sock *dm_sock;
+
+struct per_cpu_dm_data {
+       struct work_struct dm_alert_work;
+       struct sk_buff *skb;
+       atomic_t dm_hit_count;
+       struct timer_list send_timer;
+};
+
+static struct genl_family net_drop_monitor_family = {
+       .id             = GENL_ID_GENERATE,
+       .hdrsize        = 0,
+       .name           = "NET_DM",
+       .version        = 1,
+       .maxattr        = NET_DM_CMD_MAX,
+};
+
+static DEFINE_PER_CPU(struct per_cpu_dm_data, dm_cpu_data);
+
+static int dm_hit_limit = 64;
+static int dm_delay = 1;
+
+
+static void reset_per_cpu_data(struct per_cpu_dm_data *data)
+{
+       size_t al;
+       struct net_dm_alert_msg *msg;
+
+       al = sizeof(struct net_dm_alert_msg);
+       al += dm_hit_limit * sizeof(struct net_dm_drop_point);
+       data->skb = genlmsg_new(al, GFP_KERNEL);
+       genlmsg_put(data->skb, 0, 0, &net_drop_monitor_family,
+                       0, NET_DM_CMD_ALERT);
+       msg = __nla_reserve_nohdr(data->skb, sizeof(struct net_dm_alert_msg));
+       memset(msg, 0, al);
+       atomic_set(&data->dm_hit_count, dm_hit_limit);
+}
+
+static void send_dm_alert(struct work_struct *unused)
+{
+       struct sk_buff *skb;
+       struct per_cpu_dm_data *data = &__get_cpu_var(dm_cpu_data);
+
+       /*
+        * Grab the skb we're about to send
+        */
+       skb = data->skb;
+
+       /*
+        * Replace it with a new one
+        */
+       reset_per_cpu_data(data);
+
+       /*
+        * Ship it!
+        */
+       genlmsg_multicast(skb, 0, NET_DM_GRP_ALERT, GFP_KERNEL);
+
+}
+
+/*
+ * This is the timer function to delay the sending of an alert
+ * in the event that more drops will arrive during the
+ * hysteresis period.  Note that it operates under the timer interrupt
+ * so we don't need to disable preemption here
+ */
+static void sched_send_work(unsigned long unused)
+{
+       struct per_cpu_dm_data *data =  &__get_cpu_var(dm_cpu_data);
+
+       schedule_work(&data->dm_alert_work);
+}
+
+static void trace_kfree_skb_hit(struct sk_buff *skb, void *location)
+{
+       struct net_dm_alert_msg *msg;
+       struct nlmsghdr *nlh;
+       int i;
+       struct per_cpu_dm_data *data = &__get_cpu_var(dm_cpu_data);
+
+
+       if (!atomic_add_unless(&data->dm_hit_count, -1, 0)) {
+               /*
+                * we're already at zero, discard this hit
+                */
+               goto out;
+       }
+
+       nlh = (struct nlmsghdr *)data->skb->data;
+       msg = genlmsg_data(nlmsg_data(nlh));
+       for (i = 0; i < msg->entries; i++) {
+               if (!memcmp(&location, msg->points[i].pc, sizeof(void *))) {
+                       msg->points[i].count++;
+                       goto out;
+               }
+       }
+
+       /*
+        * We need to create a new entry
+        */
+       __nla_reserve_nohdr(data->skb, sizeof(struct net_dm_drop_point));
+       memcpy(msg->points[msg->entries].pc, &location, sizeof(void *));
+       msg->points[msg->entries].count = 1;
+       msg->entries++;
+
+       if (!timer_pending(&data->send_timer)) {
+               data->send_timer.expires = jiffies + dm_delay * HZ;
+               add_timer_on(&data->send_timer, smp_processor_id());
+       }
+
+out:
+       return;
+}
+
+static int set_all_monitor_traces(int state)
+{
+       int rc = 0;
+
+       switch (state) {
+       case TRACE_ON:
+               rc |= register_trace_kfree_skb(trace_kfree_skb_hit);
+               break;
+       case TRACE_OFF:
+               rc |= unregister_trace_kfree_skb(trace_kfree_skb_hit);
+
+               tracepoint_synchronize_unregister();
+               break;
+       default:
+               rc = 1;
+               break;
+       }
+
+       if (rc)
+               return -EINPROGRESS;
+       return rc;
+}
+
+
+static int net_dm_cmd_config(struct sk_buff *skb,
+                       struct genl_info *info)
+{
+       return -ENOTSUPP;
+}
+
+static int net_dm_cmd_trace(struct sk_buff *skb,
+                       struct genl_info *info)
+{
+       switch (info->genlhdr->cmd) {
+       case NET_DM_CMD_START:
+               return set_all_monitor_traces(TRACE_ON);
+               break;
+       case NET_DM_CMD_STOP:
+               return set_all_monitor_traces(TRACE_OFF);
+               break;
+       }
+
+       return -ENOTSUPP;
+}
+
+
+static struct genl_ops dropmon_ops[] = {
+       {
+               .cmd = NET_DM_CMD_CONFIG,
+               .doit = net_dm_cmd_config,
+       },
+       {
+               .cmd = NET_DM_CMD_START,
+               .doit = net_dm_cmd_trace,
+       },
+       {
+               .cmd = NET_DM_CMD_STOP,
+               .doit = net_dm_cmd_trace,
+       },
+};
+
+static int __init init_net_drop_monitor(void)
+{
+       int cpu;
+       int rc, i, ret;
+       struct per_cpu_dm_data *data;
+       printk(KERN_INFO "Initalizing network drop monitor service\n");
+
+       if (sizeof(void *) > 8) {
+               printk(KERN_ERR "Unable to store program counters on this arch, Drop monitor failed\n");
+               return -ENOSPC;
+       }
+
+       if (genl_register_family(&net_drop_monitor_family) < 0) {
+               printk(KERN_ERR "Could not create drop monitor netlink family\n");
+               return -EFAULT;
+       }
+
+       rc = -EFAULT;
+
+       for (i = 0; i < ARRAY_SIZE(dropmon_ops); i++) {
+               ret = genl_register_ops(&net_drop_monitor_family,
+                                       &dropmon_ops[i]);
+               if (ret) {
+                       printk(KERN_CRIT "failed to register operation %d\n",
+                               dropmon_ops[i].cmd);
+                       goto out_unreg;
+               }
+       }
+
+       rc = 0;
+
+       for_each_present_cpu(cpu) {
+               data = &per_cpu(dm_cpu_data, cpu);
+               reset_per_cpu_data(data);
+               INIT_WORK(&data->dm_alert_work, send_dm_alert);
+               init_timer(&data->send_timer);
+               data->send_timer.data = cpu;
+               data->send_timer.function = sched_send_work;
+       }
+       goto out;
+
+out_unreg:
+       genl_unregister_family(&net_drop_monitor_family);
+out:
+       return rc;
+}
+
+late_initcall(init_net_drop_monitor);
index 947710a36ced534e0599a59dbd7860600e833376..244ca56dffac3eb57536142f5aa36e2f4a6f12a5 100644 (file)
@@ -209,34 +209,62 @@ static int ethtool_get_drvinfo(struct net_device *dev, void __user *useraddr)
        return 0;
 }
 
-static int ethtool_set_rxhash(struct net_device *dev, void __user *useraddr)
+static int ethtool_set_rxnfc(struct net_device *dev, void __user *useraddr)
 {
        struct ethtool_rxnfc cmd;
 
-       if (!dev->ethtool_ops->set_rxhash)
+       if (!dev->ethtool_ops->set_rxnfc)
                return -EOPNOTSUPP;
 
        if (copy_from_user(&cmd, useraddr, sizeof(cmd)))
                return -EFAULT;
 
-       return dev->ethtool_ops->set_rxhash(dev, &cmd);
+       return dev->ethtool_ops->set_rxnfc(dev, &cmd);
 }
 
-static int ethtool_get_rxhash(struct net_device *dev, void __user *useraddr)
+static int ethtool_get_rxnfc(struct net_device *dev, void __user *useraddr)
 {
        struct ethtool_rxnfc info;
+       const struct ethtool_ops *ops = dev->ethtool_ops;
+       int ret;
+       void *rule_buf = NULL;
 
-       if (!dev->ethtool_ops->get_rxhash)
+       if (!ops->get_rxnfc)
                return -EOPNOTSUPP;
 
        if (copy_from_user(&info, useraddr, sizeof(info)))
                return -EFAULT;
 
-       dev->ethtool_ops->get_rxhash(dev, &info);
+       if (info.cmd == ETHTOOL_GRXCLSRLALL) {
+               if (info.rule_cnt > 0) {
+                       rule_buf = kmalloc(info.rule_cnt * sizeof(u32),
+                                          GFP_USER);
+                       if (!rule_buf)
+                               return -ENOMEM;
+               }
+       }
 
+       ret = ops->get_rxnfc(dev, &info, rule_buf);
+       if (ret < 0)
+               goto err_out;
+
+       ret = -EFAULT;
        if (copy_to_user(useraddr, &info, sizeof(info)))
-               return -EFAULT;
-       return 0;
+               goto err_out;
+
+       if (rule_buf) {
+               useraddr += offsetof(struct ethtool_rxnfc, rule_locs);
+               if (copy_to_user(useraddr, rule_buf,
+                                info.rule_cnt * sizeof(u32)))
+                       goto err_out;
+       }
+       ret = 0;
+
+err_out:
+       if (rule_buf)
+               kfree(rule_buf);
+
+       return ret;
 }
 
 static int ethtool_get_regs(struct net_device *dev, char __user *useraddr)
@@ -901,6 +929,10 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
        case ETHTOOL_GFLAGS:
        case ETHTOOL_GPFLAGS:
        case ETHTOOL_GRXFH:
+       case ETHTOOL_GRXRINGS:
+       case ETHTOOL_GRXCLSRLCNT:
+       case ETHTOOL_GRXCLSRULE:
+       case ETHTOOL_GRXCLSRLALL:
                break;
        default:
                if (!capable(CAP_NET_ADMIN))
@@ -1052,10 +1084,16 @@ int dev_ethtool(struct net *net, struct ifreq *ifr)
                                       dev->ethtool_ops->set_priv_flags);
                break;
        case ETHTOOL_GRXFH:
-               rc = ethtool_get_rxhash(dev, useraddr);
+       case ETHTOOL_GRXRINGS:
+       case ETHTOOL_GRXCLSRLCNT:
+       case ETHTOOL_GRXCLSRULE:
+       case ETHTOOL_GRXCLSRLALL:
+               rc = ethtool_get_rxnfc(dev, useraddr);
                break;
        case ETHTOOL_SRXFH:
-               rc = ethtool_set_rxhash(dev, useraddr);
+       case ETHTOOL_SRXCLSRLDEL:
+       case ETHTOOL_SRXCLSRLINS:
+               rc = ethtool_set_rxnfc(dev, useraddr);
                break;
        case ETHTOOL_GGRO:
                rc = ethtool_get_gro(dev, useraddr);
index 32b3a0152d7adba2079e5a1bc5f5ba9001037996..98691e1466b80699b664983e5403b4b1a3a19db2 100644 (file)
@@ -588,7 +588,8 @@ static void notify_rule_change(int event, struct fib_rule *rule,
                goto errout;
        }
 
-       err = rtnl_notify(skb, net, pid, ops->nlgroup, nlh, GFP_KERNEL);
+       rtnl_notify(skb, net, pid, ops->nlgroup, nlh, GFP_KERNEL);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, ops->nlgroup, err);
index 278a142d1047bcdd93e118326e3b56a952d14d5e..a1cbce7fdae5851f6534f433eb0aa3be3a06e1e6 100644 (file)
@@ -871,8 +871,7 @@ static void neigh_timer_handler(unsigned long arg)
                write_unlock(&neigh->lock);
                neigh->ops->solicit(neigh, skb);
                atomic_inc(&neigh->probes);
-               if (skb)
-                       kfree_skb(skb);
+               kfree_skb(skb);
        } else {
 out:
                write_unlock(&neigh->lock);
@@ -908,8 +907,7 @@ int __neigh_event_send(struct neighbour *neigh, struct sk_buff *skb)
                        neigh->updated = jiffies;
                        write_unlock_bh(&neigh->lock);
 
-                       if (skb)
-                               kfree_skb(skb);
+                       kfree_skb(skb);
                        return 1;
                }
        } else if (neigh->nud_state & NUD_STALE) {
@@ -1656,7 +1654,11 @@ static int neigh_add(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                                flags &= ~NEIGH_UPDATE_F_OVERRIDE;
                }
 
-               err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
+               if (ndm->ndm_flags & NTF_USE) {
+                       neigh_event_send(neigh, NULL);
+                       err = 0;
+               } else
+                       err = neigh_update(neigh, lladdr, ndm->ndm_state, flags);
                neigh_release(neigh);
                goto out_dev_put;
        }
@@ -2534,7 +2536,8 @@ static void __neigh_notify(struct neighbour *n, int type, int flags)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
+       rtnl_notify(skb, net, 0, RTNLGRP_NEIGH, NULL, GFP_ATOMIC);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_NEIGH, err);
index 6ac29a46e23e188be0c3f246c7ff77e538d04ab1..2da59a0ac4ac4a527f3db356893b614ed0a0a585 100644 (file)
@@ -77,7 +77,9 @@ static ssize_t netdev_store(struct device *dev, struct device_attribute *attr,
        if (endp == buf)
                goto err;
 
-       rtnl_lock();
+       if (!rtnl_trylock())
+               return -ERESTARTSYS;
+
        if (dev_isalive(net)) {
                if ((ret = (*set)(net, new)) == 0)
                        ret = len;
@@ -496,7 +498,7 @@ int netdev_register_kobject(struct net_device *net)
        dev->groups = groups;
 
        BUILD_BUG_ON(BUS_ID_SIZE < IFNAMSIZ);
-       dev_set_name(dev, net->name);
+       dev_set_name(dev, "%s", net->name);
 
 #ifdef CONFIG_SYSFS
        *groups++ = &netstat_group;
diff --git a/net/core/net-traces.c b/net/core/net-traces.c
new file mode 100644 (file)
index 0000000..c8fb456
--- /dev/null
@@ -0,0 +1,29 @@
+/*
+ * consolidates trace point definitions
+ *
+ * Copyright (C) 2009 Neil Horman <nhorman@tuxdriver.com>
+ */
+
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/string.h>
+#include <linux/if_arp.h>
+#include <linux/inetdevice.h>
+#include <linux/inet.h>
+#include <linux/interrupt.h>
+#include <linux/netpoll.h>
+#include <linux/sched.h>
+#include <linux/delay.h>
+#include <linux/rcupdate.h>
+#include <linux/types.h>
+#include <linux/workqueue.h>
+#include <linux/netlink.h>
+#include <linux/net_dropmon.h>
+#include <trace/skb.h>
+
+#include <asm/unaligned.h>
+#include <asm/bitops.h>
+
+
+DEFINE_TRACE(kfree_skb);
+EXPORT_TRACEPOINT_SYMBOL_GPL(kfree_skb);
index 55151faaf90c1793c53e38bed732ff3c5bd53397..e3bebd36f053ef5ad656b7ea81fa1a03e0c2dc74 100644 (file)
@@ -32,24 +32,14 @@ static __net_init int setup_net(struct net *net)
 {
        /* Must be called with net_mutex held */
        struct pernet_operations *ops;
-       int error;
-       struct net_generic *ng;
+       int error = 0;
 
        atomic_set(&net->count, 1);
+
 #ifdef NETNS_REFCNT_DEBUG
        atomic_set(&net->use_count, 0);
 #endif
 
-       error = -ENOMEM;
-       ng = kzalloc(sizeof(struct net_generic) +
-                       INITIAL_NET_GEN_PTRS * sizeof(void *), GFP_KERNEL);
-       if (ng == NULL)
-               goto out;
-
-       ng->len = INITIAL_NET_GEN_PTRS;
-       rcu_assign_pointer(net->gen, ng);
-
-       error = 0;
        list_for_each_entry(ops, &pernet_list, list) {
                if (ops->init) {
                        error = ops->init(net);
@@ -70,24 +60,50 @@ out_undo:
        }
 
        rcu_barrier();
-       kfree(ng);
        goto out;
 }
 
+static struct net_generic *net_alloc_generic(void)
+{
+       struct net_generic *ng;
+       size_t generic_size = sizeof(struct net_generic) +
+               INITIAL_NET_GEN_PTRS * sizeof(void *);
+
+       ng = kzalloc(generic_size, GFP_KERNEL);
+       if (ng)
+               ng->len = INITIAL_NET_GEN_PTRS;
+
+       return ng;
+}
+
 #ifdef CONFIG_NET_NS
 static struct kmem_cache *net_cachep;
 static struct workqueue_struct *netns_wq;
 
 static struct net *net_alloc(void)
 {
-       return kmem_cache_zalloc(net_cachep, GFP_KERNEL);
+       struct net *net = NULL;
+       struct net_generic *ng;
+
+       ng = net_alloc_generic();
+       if (!ng)
+               goto out;
+
+       net = kmem_cache_zalloc(net_cachep, GFP_KERNEL);
+       if (!net)
+               goto out_free;
+
+       rcu_assign_pointer(net->gen, ng);
+out:
+       return net;
+
+out_free:
+       kfree(ng);
+       goto out;
 }
 
 static void net_free(struct net *net)
 {
-       if (!net)
-               return;
-
 #ifdef NETNS_REFCNT_DEBUG
        if (unlikely(atomic_read(&net->use_count) != 0)) {
                printk(KERN_EMERG "network namespace not free! Usage: %d\n",
@@ -112,27 +128,28 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net)
        err = -ENOMEM;
        new_net = net_alloc();
        if (!new_net)
-               goto out;
+               goto out_err;
 
        mutex_lock(&net_mutex);
        err = setup_net(new_net);
-       if (err)
-               goto out_unlock;
-
-       rtnl_lock();
-       list_add_tail(&new_net->list, &net_namespace_list);
-       rtnl_unlock();
-
-
-out_unlock:
+       if (!err) {
+               rtnl_lock();
+               list_add_tail(&new_net->list, &net_namespace_list);
+               rtnl_unlock();
+       }
        mutex_unlock(&net_mutex);
+
+       if (err)
+               goto out_free;
 out:
        put_net(old_net);
-       if (err) {
-               net_free(new_net);
-               new_net = ERR_PTR(err);
-       }
        return new_net;
+
+out_free:
+       net_free(new_net);
+out_err:
+       new_net = ERR_PTR(err);
+       goto out;
 }
 
 static void cleanup_net(struct work_struct *work)
@@ -140,9 +157,6 @@ static void cleanup_net(struct work_struct *work)
        struct pernet_operations *ops;
        struct net *net;
 
-       /* Be very certain incoming network packets will not find us */
-       rcu_barrier();
-
        net = container_of(work, struct net, work);
 
        mutex_lock(&net_mutex);
@@ -188,6 +202,7 @@ struct net *copy_net_ns(unsigned long flags, struct net *old_net)
 
 static int __init net_ns_init(void)
 {
+       struct net_generic *ng;
        int err;
 
        printk(KERN_INFO "net_namespace: %zd bytes\n", sizeof(struct net));
@@ -202,6 +217,12 @@ static int __init net_ns_init(void)
                panic("Could not create netns workq");
 #endif
 
+       ng = net_alloc_generic();
+       if (!ng)
+               panic("Could not allocate generic netns");
+
+       rcu_assign_pointer(init_net.gen, ng);
+
        mutex_lock(&net_mutex);
        err = setup_net(&init_net);
 
index 65498483325aa09dc1507284fee54759da6e8c66..32d419f5ac983e2601cda6ce189476a87886c699 100644 (file)
@@ -3275,8 +3275,7 @@ static void pktgen_stop(struct pktgen_thread *t)
 
        list_for_each_entry(pkt_dev, &t->if_list, list) {
                pktgen_stop_device(pkt_dev);
-               if (pkt_dev->skb)
-                       kfree_skb(pkt_dev->skb);
+               kfree_skb(pkt_dev->skb);
 
                pkt_dev->skb = NULL;
        }
@@ -3303,8 +3302,7 @@ static void pktgen_rem_one_if(struct pktgen_thread *t)
                if (!cur->removal_mark)
                        continue;
 
-               if (cur->skb)
-                       kfree_skb(cur->skb);
+               kfree_skb(cur->skb);
                cur->skb = NULL;
 
                pktgen_remove_device(t, cur);
@@ -3328,8 +3326,7 @@ static void pktgen_rem_all_ifs(struct pktgen_thread *t)
        list_for_each_safe(q, n, &t->if_list) {
                cur = list_entry(q, struct pktgen_dev, list);
 
-               if (cur->skb)
-                       kfree_skb(cur->skb);
+               kfree_skb(cur->skb);
                cur->skb = NULL;
 
                pktgen_remove_device(t, cur);
@@ -3393,8 +3390,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
 
                if (!netif_running(odev)) {
                        pktgen_stop_device(pkt_dev);
-                       if (pkt_dev->skb)
-                               kfree_skb(pkt_dev->skb);
+                       kfree_skb(pkt_dev->skb);
                        pkt_dev->skb = NULL;
                        goto out;
                }
@@ -3415,8 +3411,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
                if ((++pkt_dev->clone_count >= pkt_dev->clone_skb)
                    || (!pkt_dev->skb)) {
                        /* build a new pkt */
-                       if (pkt_dev->skb)
-                               kfree_skb(pkt_dev->skb);
+                       kfree_skb(pkt_dev->skb);
 
                        pkt_dev->skb = fill_packet(odev, pkt_dev);
                        if (pkt_dev->skb == NULL) {
@@ -3498,8 +3493,7 @@ static __inline__ void pktgen_xmit(struct pktgen_dev *pkt_dev)
 
                /* Done with this */
                pktgen_stop_device(pkt_dev);
-               if (pkt_dev->skb)
-                       kfree_skb(pkt_dev->skb);
+               kfree_skb(pkt_dev->skb);
                pkt_dev->skb = NULL;
        }
 out:;
index 790dd205bb5d9b9a9704734934b74db6029a44c0..d78030f88bd0f21733d4f06f517de5fc4fc39a67 100644 (file)
@@ -455,8 +455,8 @@ int rtnl_unicast(struct sk_buff *skb, struct net *net, u32 pid)
        return nlmsg_unicast(rtnl, skb, pid);
 }
 
-int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
-               struct nlmsghdr *nlh, gfp_t flags)
+void rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
+                struct nlmsghdr *nlh, gfp_t flags)
 {
        struct sock *rtnl = net->rtnl;
        int report = 0;
@@ -464,7 +464,7 @@ int rtnl_notify(struct sk_buff *skb, struct net *net, u32 pid, u32 group,
        if (nlh)
                report = nlmsg_report(nlh);
 
-       return nlmsg_notify(rtnl, skb, pid, group, report, flags);
+       nlmsg_notify(rtnl, skb, pid, group, report, flags);
 }
 
 void rtnl_set_sk_err(struct net *net, u32 group, int error)
@@ -1246,7 +1246,8 @@ void rtmsg_ifinfo(int type, struct net_device *dev, unsigned change)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
+       rtnl_notify(skb, net, 0, RTNLGRP_LINK, NULL, GFP_KERNEL);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_LINK, err);
index e5a8351ff12d5be925fedaad8f7d3ec0d2a3849c..6acbf9e79eb1dc2076bc192f774c8b5591566c42 100644 (file)
@@ -65,6 +65,7 @@
 
 #include <asm/uaccess.h>
 #include <asm/system.h>
+#include <trace/skb.h>
 
 #include "kmap_skb.h"
 
@@ -146,14 +147,6 @@ void skb_under_panic(struct sk_buff *skb, int sz, void *here)
 }
 EXPORT_SYMBOL(skb_under_panic);
 
-void skb_truesize_bug(struct sk_buff *skb)
-{
-       WARN(net_ratelimit(), KERN_ERR "SKB BUG: Invalid truesize (%u) "
-              "len=%u, sizeof(sk_buff)=%Zd\n",
-              skb->truesize, skb->len, sizeof(struct sk_buff));
-}
-EXPORT_SYMBOL(skb_truesize_bug);
-
 /*     Allocate a new skbuff. We do this ourselves so we can fill in a few
  *     'private' fields and also do memory statistics to find all the
  *     [BEEP] leaks.
@@ -450,10 +443,31 @@ void kfree_skb(struct sk_buff *skb)
                smp_rmb();
        else if (likely(!atomic_dec_and_test(&skb->users)))
                return;
+       trace_kfree_skb(skb, __builtin_return_address(0));
        __kfree_skb(skb);
 }
 EXPORT_SYMBOL(kfree_skb);
 
+/**
+ *     consume_skb - free an skbuff
+ *     @skb: buffer to free
+ *
+ *     Drop a ref to the buffer and free it if the usage count has hit zero
+ *     Functions identically to kfree_skb, but kfree_skb assumes that the frame
+ *     is being dropped after a failure and notes that
+ */
+void consume_skb(struct sk_buff *skb)
+{
+       if (unlikely(!skb))
+               return;
+       if (likely(atomic_read(&skb->users) == 1))
+               smp_rmb();
+       else if (likely(!atomic_dec_and_test(&skb->users)))
+               return;
+       __kfree_skb(skb);
+}
+EXPORT_SYMBOL(consume_skb);
+
 /**
  *     skb_recycle_check - check if skb can be reused for receive
  *     @skb: buffer
@@ -1216,8 +1230,7 @@ unsigned char *__pskb_pull_tail(struct sk_buff *skb, int delta)
                                        insp = list;
                                }
                                if (!pskb_pull(list, eat)) {
-                                       if (clone)
-                                               kfree_skb(clone);
+                                       kfree_skb(clone);
                                        return NULL;
                                }
                                break;
index 40887e76652c1b187ac81728b65ded5c46e708a8..0620046e4eba837d0ecdf72b5eb6dcc192060ed5 100644 (file)
@@ -150,7 +150,7 @@ static const char *af_family_key_strings[AF_MAX+1] = {
   "sk_lock-AF_DECnet", "sk_lock-AF_NETBEUI"  , "sk_lock-AF_SECURITY" ,
   "sk_lock-AF_KEY"   , "sk_lock-AF_NETLINK"  , "sk_lock-AF_PACKET"   ,
   "sk_lock-AF_ASH"   , "sk_lock-AF_ECONET"   , "sk_lock-AF_ATMSVC"   ,
-  "sk_lock-21"       , "sk_lock-AF_SNA"      , "sk_lock-AF_IRDA"     ,
+  "sk_lock-AF_RDS"   , "sk_lock-AF_SNA"      , "sk_lock-AF_IRDA"     ,
   "sk_lock-AF_PPPOX" , "sk_lock-AF_WANPIPE"  , "sk_lock-AF_LLC"      ,
   "sk_lock-27"       , "sk_lock-28"          , "sk_lock-AF_CAN"      ,
   "sk_lock-AF_TIPC"  , "sk_lock-AF_BLUETOOTH", "sk_lock-IUCV"        ,
@@ -165,7 +165,7 @@ static const char *af_family_slock_key_strings[AF_MAX+1] = {
   "slock-AF_DECnet", "slock-AF_NETBEUI"  , "slock-AF_SECURITY" ,
   "slock-AF_KEY"   , "slock-AF_NETLINK"  , "slock-AF_PACKET"   ,
   "slock-AF_ASH"   , "slock-AF_ECONET"   , "slock-AF_ATMSVC"   ,
-  "slock-21"       , "slock-AF_SNA"      , "slock-AF_IRDA"     ,
+  "slock-AF_RDS"   , "slock-AF_SNA"      , "slock-AF_IRDA"     ,
   "slock-AF_PPPOX" , "slock-AF_WANPIPE"  , "slock-AF_LLC"      ,
   "slock-27"       , "slock-28"          , "slock-AF_CAN"      ,
   "slock-AF_TIPC"  , "slock-AF_BLUETOOTH", "slock-AF_IUCV"     ,
@@ -180,7 +180,7 @@ static const char *af_family_clock_key_strings[AF_MAX+1] = {
   "clock-AF_DECnet", "clock-AF_NETBEUI"  , "clock-AF_SECURITY" ,
   "clock-AF_KEY"   , "clock-AF_NETLINK"  , "clock-AF_PACKET"   ,
   "clock-AF_ASH"   , "clock-AF_ECONET"   , "clock-AF_ATMSVC"   ,
-  "clock-21"       , "clock-AF_SNA"      , "clock-AF_IRDA"     ,
+  "clock-AF_RDS"   , "clock-AF_SNA"      , "clock-AF_IRDA"     ,
   "clock-AF_PPPOX" , "clock-AF_WANPIPE"  , "clock-AF_LLC"      ,
   "clock-27"       , "clock-28"          , "clock-AF_CAN"      ,
   "clock-AF_TIPC"  , "clock-AF_BLUETOOTH", "clock-AF_IUCV"     ,
@@ -725,7 +725,7 @@ int sock_getsockopt(struct socket *sock, int level, int optname,
        if (len < 0)
                return -EINVAL;
 
-       v.val = 0;
+       memset(&v, 0, sizeof(v));
 
        switch(optname) {
        case SO_DEBUG:
@@ -1185,7 +1185,6 @@ void sock_rfree(struct sk_buff *skb)
 {
        struct sock *sk = skb->sk;
 
-       skb_truesize_check(skb);
        atomic_sub(skb->truesize, &sk->sk_rmem_alloc);
        sk_mem_uncharge(skb->sk, skb->truesize);
 }
index 83d3398559ea80d3823140856b375dd5c2419927..7db1de0497c63bbde324cc354423dc11a06ef636 100644 (file)
@@ -11,6 +11,7 @@
 #include <linux/socket.h>
 #include <linux/netdevice.h>
 #include <linux/init.h>
+#include <net/ip.h>
 #include <net/sock.h>
 
 static struct ctl_table net_core_table[] = {
index 45f95e55f873f47674601a617b7d8284e8f0763f..7ea557b7c6b15aa15bf326622ce3ba400f389fa5 100644 (file)
@@ -20,6 +20,9 @@
 /* We can spread an ack vector across multiple options */
 #define DCCP_MAX_ACKVEC_LEN (DCCP_SINGLE_OPT_MAXLEN * 2)
 
+/* Estimated minimum average Ack Vector length - used for updating MPS */
+#define DCCPAV_MIN_OPTLEN      16
+
 #define DCCP_ACKVEC_STATE_RECEIVED     0
 #define DCCP_ACKVEC_STATE_ECN_MARKED   (1 << 6)
 #define DCCP_ACKVEC_STATE_NOT_RECEIVED (3 << 6)
index 08a569ff02d1283816a7f11818cb06dd5dd7da87..d6bc47363b1c0b75006b4fc95556515d90e3088c 100644 (file)
@@ -63,11 +63,14 @@ extern void dccp_time_wait(struct sock *sk, int state, int timeo);
  *    - DCCP-Reset    with ACK Subheader and 4 bytes of Reset Code fields
  *  Hence a safe upper bound for the maximum option length is 1020-28 = 992
  */
-#define MAX_DCCP_SPECIFIC_HEADER (255 * sizeof(int))
+#define MAX_DCCP_SPECIFIC_HEADER (255 * sizeof(uint32_t))
 #define DCCP_MAX_PACKET_HDR 28
 #define DCCP_MAX_OPT_LEN (MAX_DCCP_SPECIFIC_HEADER - DCCP_MAX_PACKET_HDR)
 #define MAX_DCCP_HEADER (MAX_DCCP_SPECIFIC_HEADER + MAX_HEADER)
 
+/* Upper bound for initial feature-negotiation overhead (padded to 32 bits) */
+#define DCCP_FEATNEG_OVERHEAD   (32 * sizeof(uint32_t))
+
 #define DCCP_TIMEWAIT_LEN (60 * HZ) /* how long to wait to destroy TIME-WAIT
                                     * state, about 60 seconds */
 
index 22a618af48936aa9954978cdf8d94117e02d7bac..36bcc00654d350f408c88f6c4d0f16945c2f7d63 100644 (file)
@@ -161,21 +161,27 @@ unsigned int dccp_sync_mss(struct sock *sk, u32 pmtu)
        struct inet_connection_sock *icsk = inet_csk(sk);
        struct dccp_sock *dp = dccp_sk(sk);
        u32 ccmps = dccp_determine_ccmps(dp);
-       int cur_mps = ccmps ? min(pmtu, ccmps) : pmtu;
+       u32 cur_mps = ccmps ? min(pmtu, ccmps) : pmtu;
 
        /* Account for header lengths and IPv4/v6 option overhead */
        cur_mps -= (icsk->icsk_af_ops->net_header_len + icsk->icsk_ext_hdr_len +
                    sizeof(struct dccp_hdr) + sizeof(struct dccp_hdr_ext));
 
        /*
-        * FIXME: this should come from the CCID infrastructure, where, say,
-        * TFRC will say it wants TIMESTAMPS, ELAPSED time, etc, for now lets
-        * put a rough estimate for NDP + TIMESTAMP + TIMESTAMP_ECHO + ELAPSED
-        * TIME + TFRC_OPT_LOSS_EVENT_RATE + TFRC_OPT_RECEIVE_RATE + padding to
-        * make it a multiple of 4
+        * Leave enough headroom for common DCCP header options.
+        * This only considers options which may appear on DCCP-Data packets, as
+        * per table 3 in RFC 4340, 5.8. When running out of space for other
+        * options (eg. Ack Vector which can take up to 255 bytes), it is better
+        * to schedule a separate Ack. Thus we leave headroom for the following:
+        *  - 1 byte for Slow Receiver (11.6)
+        *  - 6 bytes for Timestamp (13.1)
+        *  - 10 bytes for Timestamp Echo (13.3)
+        *  - 8 bytes for NDP count (7.7, when activated)
+        *  - 6 bytes for Data Checksum (9.3)
+        *  - %DCCPAV_MIN_OPTLEN bytes for Ack Vector size (11.4, when enabled)
         */
-
-       cur_mps -= roundup(5 + 6 + 10 + 6 + 6 + 6, 4);
+       cur_mps -= roundup(1 + 6 + 10 + dp->dccps_send_ndp_count * 8 + 6 +
+                          (dp->dccps_hc_rx_ackvec ? DCCPAV_MIN_OPTLEN : 0), 4);
 
        /* And store cached results */
        icsk->icsk_pmtu_cookie = pmtu;
@@ -270,7 +276,20 @@ void dccp_write_xmit(struct sock *sk, int block)
                        const int len = skb->len;
 
                        if (sk->sk_state == DCCP_PARTOPEN) {
-                               /* See 8.1.5.  Handshake Completion */
+                               const u32 cur_mps = dp->dccps_mss_cache - DCCP_FEATNEG_OVERHEAD;
+                               /*
+                                * See 8.1.5 - Handshake Completion.
+                                *
+                                * For robustness we resend Confirm options until the client has
+                                * entered OPEN. During the initial feature negotiation, the MPS
+                                * is smaller than usual, reduced by the Change/Confirm options.
+                                */
+                               if (!list_empty(&dp->dccps_featneg) && len > cur_mps) {
+                                       DCCP_WARN("Payload too large (%d) for featneg.\n", len);
+                                       dccp_send_ack(sk);
+                                       dccp_feat_list_purge(&dp->dccps_featneg);
+                               }
+
                                inet_csk_schedule_ack(sk);
                                inet_csk_reset_xmit_timer(sk, ICSK_TIME_DACK,
                                                  inet_csk(sk)->icsk_rto,
index 12bf7d4c16c641dd31a33904331b43d0069a666f..9647d911f916c792a3c0e7c4a6b01f2715fd2aa7 100644 (file)
@@ -1246,11 +1246,12 @@ static int dn_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
 
        case TIOCINQ:
                lock_sock(sk);
-               if ((skb = skb_peek(&scp->other_receive_queue)) != NULL) {
+               skb = skb_peek(&scp->other_receive_queue);
+               if (skb) {
                        amount = skb->len;
                } else {
-                       struct sk_buff *skb = sk->sk_receive_queue.next;
-                       for(;;) {
+                       skb = sk->sk_receive_queue.next;
+                       for (;;) {
                                if (skb ==
                                    (struct sk_buff *)&sk->sk_receive_queue)
                                        break;
@@ -1579,16 +1580,16 @@ static int __dn_getsockopt(struct socket *sock, int level,int optname, char __us
                default:
 #ifdef CONFIG_NETFILTER
                {
-                       int val, len;
+                       int ret, len;
 
                        if(get_user(len, optlen))
                                return -EFAULT;
 
-                       val = nf_getsockopt(sk, PF_DECnet, optname,
+                       ret = nf_getsockopt(sk, PF_DECnet, optname,
                                                        optval, &len);
-                       if (val >= 0)
-                               val = put_user(len, optlen);
-                       return val;
+                       if (ret >= 0)
+                               ret = put_user(len, optlen);
+                       return ret;
                }
 #endif
                case DSO_STREAM:
@@ -2071,8 +2072,7 @@ static int dn_sendmsg(struct kiocb *iocb, struct socket *sock,
        }
 out:
 
-       if (skb)
-               kfree_skb(skb);
+       kfree_skb(skb);
 
        release_sock(sk);
 
@@ -2112,9 +2112,8 @@ static struct notifier_block dn_dev_notifier = {
 
 extern int dn_route_rcv(struct sk_buff *, struct net_device *, struct packet_type *, struct net_device *);
 
-static struct packet_type dn_dix_packet_type = {
+static struct packet_type dn_dix_packet_type __read_mostly = {
        .type =         cpu_to_be16(ETH_P_DNA_RT),
-       .dev =          NULL,           /* All devices */
        .func =         dn_route_rcv,
 };
 
index daf2b98b15fef79d3d9d1915ebe48a36b6007d1e..1c6a5bb6f0c8da8cba2e31021ad0f1171f0aeecf 100644 (file)
@@ -684,7 +684,6 @@ static int dn_nl_newaddr(struct sk_buff *skb, struct nlmsghdr *nlh, void *arg)
                return -ENODEV;
 
        if ((dn_db = dev->dn_ptr) == NULL) {
-               int err;
                dn_db = dn_dev_create(dev, &err);
                if (!dn_db)
                        return err;
@@ -769,7 +768,8 @@ static void dn_ifaddr_notify(int event, struct dn_ifaddr *ifa)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, &init_net, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);
+       rtnl_notify(skb, &init_net, 0, RTNLGRP_DECnet_IFADDR, NULL, GFP_KERNEL);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_IFADDR, err);
@@ -1322,6 +1322,7 @@ static inline int is_dn_dev(struct net_device *dev)
 }
 
 static void *dn_dev_seq_start(struct seq_file *seq, loff_t *pos)
+       __acquires(&dev_base_lock)
 {
        int i;
        struct net_device *dev;
@@ -1364,6 +1365,7 @@ static void *dn_dev_seq_next(struct seq_file *seq, void *v, loff_t *pos)
 }
 
 static void dn_dev_seq_stop(struct seq_file *seq, void *v)
+       __releases(&dev_base_lock)
 {
        read_unlock(&dev_base_lock);
 }
index 5130dee0b384023911306aaf29da23aab1a1dc30..0cc4394117dfa0a7417a35652363c5bb99e5de5a 100644 (file)
@@ -380,7 +380,6 @@ static int dn_return_short(struct sk_buff *skb)
        unsigned char *ptr;
        __le16 *src;
        __le16 *dst;
-       __le16 tmp;
 
        /* Add back headers */
        skb_push(skb, skb->data - skb_network_header(skb));
@@ -399,10 +398,7 @@ static int dn_return_short(struct sk_buff *skb)
        ptr += 2;
        *ptr = 0; /* Zero hop count */
 
-       /* Swap source and destination */
-       tmp  = *src;
-       *src = *dst;
-       *dst = tmp;
+       swap(*src, *dst);
 
        skb->pkt_type = PACKET_OUTGOING;
        dn_rt_finish_output(skb, NULL, NULL);
index 69ad9280c6936a99975bdf2f7d8361b8924783c7..67054b0d550f9a26b47b469c3a542d083ef5a00f 100644 (file)
@@ -375,7 +375,8 @@ static void dn_rtmsg_fib(int event, struct dn_fib_node *f, int z, u32 tb_id,
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, &init_net, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
+       rtnl_notify(skb, &init_net, pid, RTNLGRP_DECnet_ROUTE, nlh, GFP_KERNEL);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(&init_net, RTNLGRP_DECnet_ROUTE, err);
index 965397af9a80f3f1d9c0fc99e84b436485431605..5bcd592ae6dd0f3883d25e4543e0085ca81133ea 100644 (file)
@@ -179,7 +179,7 @@ static int dn_node_address_handler(ctl_table *table, int write,
        }
 
        if (write) {
-               int len = (*lenp < DN_ASCBUF_LEN) ? *lenp : (DN_ASCBUF_LEN-1);
+               len = (*lenp < DN_ASCBUF_LEN) ? *lenp : (DN_ASCBUF_LEN-1);
 
                if (copy_from_user(addr, buffer, len))
                        return -EFAULT;
index 49211b35725ba74c5661717522075e7b968f303f..c51b55400dc56818a2f4e0cca68cb74be38048a3 100644 (file)
@@ -41,13 +41,13 @@ config NET_DSA_MV88E6XXX_NEED_PPU
        default n
 
 config NET_DSA_MV88E6131
-       bool "Marvell 88E6131 ethernet switch chip support"
+       bool "Marvell 88E6095/6095F/6131 ethernet switch chip support"
        select NET_DSA_MV88E6XXX
        select NET_DSA_MV88E6XXX_NEED_PPU
        select NET_DSA_TAG_DSA
        ---help---
-         This enables support for the Marvell 88E6131 ethernet switch
-         chip.
+         This enables support for the Marvell 88E6095/6095F/6131
+         ethernet switch chips.
 
 config NET_DSA_MV88E6123_61_65
        bool "Marvell 88E6123/6161/6165 ethernet switch chip support"
index 33e99462023abccab58c8807d1bb7f57962b7ebc..71489f69a42c1e38f59b5c61dfe6c2d2b557242d 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * net/dsa/dsa.c - Hardware switch handling
- * Copyright (c) 2008 Marvell Semiconductor
+ * Copyright (c) 2008-2009 Marvell Semiconductor
  *
  * 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
@@ -67,12 +67,13 @@ dsa_switch_probe(struct mii_bus *bus, int sw_addr, char **_name)
 
 /* basic switch operations **************************************************/
 static struct dsa_switch *
-dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
-                struct mii_bus *bus, struct net_device *dev)
+dsa_switch_setup(struct dsa_switch_tree *dst, int index,
+                struct device *parent, struct mii_bus *bus)
 {
+       struct dsa_chip_data *pd = dst->pd->chip + index;
+       struct dsa_switch_driver *drv;
        struct dsa_switch *ds;
        int ret;
-       struct dsa_switch_driver *drv;
        char *name;
        int i;
 
@@ -81,11 +82,12 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
         */
        drv = dsa_switch_probe(bus, pd->sw_addr, &name);
        if (drv == NULL) {
-               printk(KERN_ERR "%s: could not detect attached switch\n",
-                      dev->name);
+               printk(KERN_ERR "%s[%d]: could not detect attached switch\n",
+                      dst->master_netdev->name, index);
                return ERR_PTR(-EINVAL);
        }
-       printk(KERN_INFO "%s: detected a %s switch\n", dev->name, name);
+       printk(KERN_INFO "%s[%d]: detected a %s switch\n",
+               dst->master_netdev->name, index, name);
 
 
        /*
@@ -95,18 +97,16 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
        if (ds == NULL)
                return ERR_PTR(-ENOMEM);
 
-       ds->pd = pd;
-       ds->master_netdev = dev;
-       ds->master_mii_bus = bus;
-
+       ds->dst = dst;
+       ds->index = index;
+       ds->pd = dst->pd->chip + index;
        ds->drv = drv;
-       ds->tag_protocol = drv->tag_protocol;
+       ds->master_mii_bus = bus;
 
 
        /*
         * Validate supplied switch configuration.
         */
-       ds->cpu_port = -1;
        for (i = 0; i < DSA_MAX_PORTS; i++) {
                char *name;
 
@@ -115,32 +115,28 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
                        continue;
 
                if (!strcmp(name, "cpu")) {
-                       if (ds->cpu_port != -1) {
+                       if (dst->cpu_switch != -1) {
                                printk(KERN_ERR "multiple cpu ports?!\n");
                                ret = -EINVAL;
                                goto out;
                        }
-                       ds->cpu_port = i;
+                       dst->cpu_switch = index;
+                       dst->cpu_port = i;
+               } else if (!strcmp(name, "dsa")) {
+                       ds->dsa_port_mask |= 1 << i;
                } else {
-                       ds->valid_port_mask |= 1 << i;
+                       ds->phys_port_mask |= 1 << i;
                }
        }
 
-       if (ds->cpu_port == -1) {
-               printk(KERN_ERR "no cpu port?!\n");
-               ret = -EINVAL;
-               goto out;
-       }
-
 
        /*
-        * If we use a tagging format that doesn't have an ethertype
-        * field, make sure that all packets from this point on get
-        * sent to the tag format's receive function.  (Which will
-        * discard received packets until we set ds->ports[] below.)
+        * If the CPU connects to this switch, set the switch tree
+        * tagging protocol to the preferred tagging format of this
+        * switch.
         */
-       wmb();
-       dev->dsa_ptr = (void *)ds;
+       if (ds->dst->cpu_switch == index)
+               ds->dst->tag_protocol = drv->tag_protocol;
 
 
        /*
@@ -150,7 +146,7 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
        if (ret < 0)
                goto out;
 
-       ret = drv->set_addr(ds, dev->dev_addr);
+       ret = drv->set_addr(ds, dst->master_netdev->dev_addr);
        if (ret < 0)
                goto out;
 
@@ -169,18 +165,18 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
        /*
         * Create network devices for physical switch ports.
         */
-       wmb();
        for (i = 0; i < DSA_MAX_PORTS; i++) {
                struct net_device *slave_dev;
 
-               if (!(ds->valid_port_mask & (1 << i)))
+               if (!(ds->phys_port_mask & (1 << i)))
                        continue;
 
                slave_dev = dsa_slave_create(ds, parent, i, pd->port_names[i]);
                if (slave_dev == NULL) {
-                       printk(KERN_ERR "%s: can't create dsa slave "
-                              "device for port %d(%s)\n",
-                              dev->name, i, pd->port_names[i]);
+                       printk(KERN_ERR "%s[%d]: can't create dsa "
+                              "slave device for port %d(%s)\n",
+                              dst->master_netdev->name,
+                              index, i, pd->port_names[i]);
                        continue;
                }
 
@@ -192,7 +188,6 @@ dsa_switch_setup(struct device *parent, struct dsa_platform_data *pd,
 out_free:
        mdiobus_free(ds->slave_mii_bus);
 out:
-       dev->dsa_ptr = NULL;
        kfree(ds);
        return ERR_PTR(ret);
 }
@@ -212,35 +207,42 @@ static void dsa_switch_destroy(struct dsa_switch *ds)
  */
 bool dsa_uses_dsa_tags(void *dsa_ptr)
 {
-       struct dsa_switch *ds = dsa_ptr;
+       struct dsa_switch_tree *dst = dsa_ptr;
 
-       return !!(ds->tag_protocol == htons(ETH_P_DSA));
+       return !!(dst->tag_protocol == htons(ETH_P_DSA));
 }
 
 bool dsa_uses_trailer_tags(void *dsa_ptr)
 {
-       struct dsa_switch *ds = dsa_ptr;
+       struct dsa_switch_tree *dst = dsa_ptr;
 
-       return !!(ds->tag_protocol == htons(ETH_P_TRAILER));
+       return !!(dst->tag_protocol == htons(ETH_P_TRAILER));
 }
 
 
 /* link polling *************************************************************/
 static void dsa_link_poll_work(struct work_struct *ugly)
 {
-       struct dsa_switch *ds;
+       struct dsa_switch_tree *dst;
+       int i;
+
+       dst = container_of(ugly, struct dsa_switch_tree, link_poll_work);
 
-       ds = container_of(ugly, struct dsa_switch, link_poll_work);
+       for (i = 0; i < dst->pd->nr_chips; i++) {
+               struct dsa_switch *ds = dst->ds[i];
 
-       ds->drv->poll_link(ds);
-       mod_timer(&ds->link_poll_timer, round_jiffies(jiffies + HZ));
+               if (ds != NULL && ds->drv->poll_link != NULL)
+                       ds->drv->poll_link(ds);
+       }
+
+       mod_timer(&dst->link_poll_timer, round_jiffies(jiffies + HZ));
 }
 
-static void dsa_link_poll_timer(unsigned long _ds)
+static void dsa_link_poll_timer(unsigned long _dst)
 {
-       struct dsa_switch *ds = (void *)_ds;
+       struct dsa_switch_tree *dst = (void *)_dst;
 
-       schedule_work(&ds->link_poll_work);
+       schedule_work(&dst->link_poll_work);
 }
 
 
@@ -303,18 +305,14 @@ static int dsa_probe(struct platform_device *pdev)
        static int dsa_version_printed;
        struct dsa_platform_data *pd = pdev->dev.platform_data;
        struct net_device *dev;
-       struct mii_bus *bus;
-       struct dsa_switch *ds;
+       struct dsa_switch_tree *dst;
+       int i;
 
        if (!dsa_version_printed++)
                printk(KERN_NOTICE "Distributed Switch Architecture "
                        "driver version %s\n", dsa_driver_version);
 
-       if (pd == NULL || pd->mii_bus == NULL || pd->netdev == NULL)
-               return -EINVAL;
-
-       bus = dev_to_mii_bus(pd->mii_bus);
-       if (bus == NULL)
+       if (pd == NULL || pd->netdev == NULL)
                return -EINVAL;
 
        dev = dev_to_net_device(pd->netdev);
@@ -326,36 +324,79 @@ static int dsa_probe(struct platform_device *pdev)
                return -EEXIST;
        }
 
-       ds = dsa_switch_setup(&pdev->dev, pd, bus, dev);
-       if (IS_ERR(ds)) {
+       dst = kzalloc(sizeof(*dst), GFP_KERNEL);
+       if (dst == NULL) {
                dev_put(dev);
-               return PTR_ERR(ds);
+               return -ENOMEM;
        }
 
-       if (ds->drv->poll_link != NULL) {
-               INIT_WORK(&ds->link_poll_work, dsa_link_poll_work);
-               init_timer(&ds->link_poll_timer);
-               ds->link_poll_timer.data = (unsigned long)ds;
-               ds->link_poll_timer.function = dsa_link_poll_timer;
-               ds->link_poll_timer.expires = round_jiffies(jiffies + HZ);
-               add_timer(&ds->link_poll_timer);
+       platform_set_drvdata(pdev, dst);
+
+       dst->pd = pd;
+       dst->master_netdev = dev;
+       dst->cpu_switch = -1;
+       dst->cpu_port = -1;
+
+       for (i = 0; i < pd->nr_chips; i++) {
+               struct mii_bus *bus;
+               struct dsa_switch *ds;
+
+               bus = dev_to_mii_bus(pd->chip[i].mii_bus);
+               if (bus == NULL) {
+                       printk(KERN_ERR "%s[%d]: no mii bus found for "
+                               "dsa switch\n", dev->name, i);
+                       continue;
+               }
+
+               ds = dsa_switch_setup(dst, i, &pdev->dev, bus);
+               if (IS_ERR(ds)) {
+                       printk(KERN_ERR "%s[%d]: couldn't create dsa switch "
+                               "instance (error %ld)\n", dev->name, i,
+                               PTR_ERR(ds));
+                       continue;
+               }
+
+               dst->ds[i] = ds;
+               if (ds->drv->poll_link != NULL)
+                       dst->link_poll_needed = 1;
        }
 
-       platform_set_drvdata(pdev, ds);
+       /*
+        * If we use a tagging format that doesn't have an ethertype
+        * field, make sure that all packets from this point on get
+        * sent to the tag format's receive function.
+        */
+       wmb();
+       dev->dsa_ptr = (void *)dst;
+
+       if (dst->link_poll_needed) {
+               INIT_WORK(&dst->link_poll_work, dsa_link_poll_work);
+               init_timer(&dst->link_poll_timer);
+               dst->link_poll_timer.data = (unsigned long)dst;
+               dst->link_poll_timer.function = dsa_link_poll_timer;
+               dst->link_poll_timer.expires = round_jiffies(jiffies + HZ);
+               add_timer(&dst->link_poll_timer);
+       }
 
        return 0;
 }
 
 static int dsa_remove(struct platform_device *pdev)
 {
-       struct dsa_switch *ds = platform_get_drvdata(pdev);
+       struct dsa_switch_tree *dst = platform_get_drvdata(pdev);
+       int i;
 
-       if (ds->drv->poll_link != NULL)
-               del_timer_sync(&ds->link_poll_timer);
+       if (dst->link_poll_needed)
+               del_timer_sync(&dst->link_poll_timer);
 
        flush_scheduled_work();
 
-       dsa_switch_destroy(ds);
+       for (i = 0; i < dst->pd->nr_chips; i++) {
+               struct dsa_switch *ds = dst->ds[i];
+
+               if (ds != NULL)
+                       dsa_switch_destroy(ds);
+       }
 
        return 0;
 }
index 7063378a1ebf04559eadc46b3e2e42b89764c4bf..41055f33d28a0e8141748613b5e9be71976de7de 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * net/dsa/dsa_priv.h - Hardware switch handling
- * Copyright (c) 2008 Marvell Semiconductor
+ * Copyright (c) 2008-2009 Marvell Semiconductor
  *
  * 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
 
 struct dsa_switch {
        /*
-        * Configuration data for the platform device that owns
-        * this dsa switch instance.
+        * Parent switch tree, and switch index.
         */
-       struct dsa_platform_data        *pd;
+       struct dsa_switch_tree  *dst;
+       int                     index;
 
        /*
-        * References to network device and mii bus to use.
+        * Configuration data for this switch.
         */
-       struct net_device               *master_netdev;
-       struct mii_bus                  *master_mii_bus;
+       struct dsa_chip_data    *pd;
 
        /*
-        * The used switch driver and frame tagging type.
+        * The used switch driver.
         */
        struct dsa_switch_driver        *drv;
-       __be16                          tag_protocol;
+
+       /*
+        * Reference to mii bus to use.
+        */
+       struct mii_bus          *master_mii_bus;
 
        /*
         * Slave mii_bus and devices for the individual ports.
         */
-       int                             cpu_port;
-       u32                             valid_port_mask;
-       struct mii_bus                  *slave_mii_bus;
-       struct net_device               *ports[DSA_MAX_PORTS];
+       u32                     dsa_port_mask;
+       u32                     phys_port_mask;
+       struct mii_bus          *slave_mii_bus;
+       struct net_device       *ports[DSA_MAX_PORTS];
+};
+
+struct dsa_switch_tree {
+       /*
+        * Configuration data for the platform device that owns
+        * this dsa switch tree instance.
+        */
+       struct dsa_platform_data        *pd;
+
+       /*
+        * Reference to network device to use, and which tagging
+        * protocol to use.
+        */
+       struct net_device       *master_netdev;
+       __be16                  tag_protocol;
+
+       /*
+        * The switch and port to which the CPU is attached.
+        */
+       s8                      cpu_switch;
+       s8                      cpu_port;
 
        /*
         * Link state polling.
         */
-       struct work_struct              link_poll_work;
-       struct timer_list               link_poll_timer;
+       int                     link_poll_needed;
+       struct work_struct      link_poll_work;
+       struct timer_list       link_poll_timer;
+
+       /*
+        * Data for the individual switch chips.
+        */
+       struct dsa_switch       *ds[DSA_MAX_SWITCHES];
 };
 
+static inline bool dsa_is_cpu_port(struct dsa_switch *ds, int p)
+{
+       return !!(ds->index == ds->dst->cpu_switch && p == ds->dst->cpu_port);
+}
+
+static inline u8 dsa_upstream_port(struct dsa_switch *ds)
+{
+       struct dsa_switch_tree *dst = ds->dst;
+
+       /*
+        * If this is the root switch (i.e. the switch that connects
+        * to the CPU), return the cpu port number on this switch.
+        * Else return the (DSA) port number that connects to the
+        * switch that is one hop closer to the cpu.
+        */
+       if (dst->cpu_switch == ds->index)
+               return dst->cpu_port;
+       else
+               return ds->pd->rtable[dst->cpu_switch];
+}
+
 struct dsa_slave_priv {
+       /*
+        * The linux network interface corresponding to this
+        * switch port.
+        */
        struct net_device       *dev;
+
+       /*
+        * Which switch this port is a part of, and the port index
+        * for this port.
+        */
        struct dsa_switch       *parent;
-       int                     port;
+       u8                      port;
+
+       /*
+        * The phylib phy_device pointer for the PHY connected
+        * to this port.
+        */
        struct phy_device       *phy;
 };
 
index 85081ae9fe8915b13cde725d9c6064ba0d49a348..83277f463af76c0a611ff312d3f39a1020584830 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * net/dsa/mv88e6060.c - Driver for Marvell 88e6060 switch chips
- * Copyright (c) 2008 Marvell Semiconductor
+ * Copyright (c) 2008-2009 Marvell Semiconductor
  *
  * 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
@@ -81,7 +81,7 @@ static int mv88e6060_switch_reset(struct dsa_switch *ds)
        /*
         * Reset the switch.
         */
-       REG_WRITE(REG_GLOBAL, 0x0A, 0xa130);
+       REG_WRITE(REG_GLOBAL, 0x0a, 0xa130);
 
        /*
         * Wait up to one second for reset to complete.
@@ -128,7 +128,7 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
         * state to Forwarding.  Additionally, if this is the CPU
         * port, enable Ingress and Egress Trailer tagging mode.
         */
-       REG_WRITE(addr, 0x04, (p == ds->cpu_port) ? 0x4103 : 0x0003);
+       REG_WRITE(addr, 0x04, dsa_is_cpu_port(ds, p) ?  0x4103 : 0x0003);
 
        /*
         * Port based VLAN map: give each port its own address
@@ -138,9 +138,9 @@ static int mv88e6060_setup_port(struct dsa_switch *ds, int p)
         */
        REG_WRITE(addr, 0x06,
                        ((p & 0xf) << 12) |
-                        ((p == ds->cpu_port) ?
-                               ds->valid_port_mask :
-                               (1 << ds->cpu_port)));
+                        (dsa_is_cpu_port(ds, p) ?
+                               ds->phys_port_mask :
+                               (1 << ds->dst->cpu_port)));
 
        /*
         * Port Association Vector: when learning source addresses
index 1003187222146c2a7708258369c7a30d15243762..52faaa21a4d927e1a943840b01e2c85bb20464b9 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * net/dsa/mv88e6123_61_65.c - Marvell 88e6123/6161/6165 switch chip support
- * Copyright (c) 2008 Marvell Semiconductor
+ * Copyright (c) 2008-2009 Marvell Semiconductor
  *
  * 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
@@ -98,17 +98,17 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
                return ret;
 
        /*
-        * Configure the cpu port, and configure the cpu port as the
-        * port to which ingress and egress monitor frames are to be
-        * sent.
+        * Configure the upstream port, and configure the upstream
+        * port as the port to which ingress and egress monitor frames
+        * are to be sent.
         */
-       REG_WRITE(REG_GLOBAL, 0x1a, (ds->cpu_port * 0x1110));
+       REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1110));
 
        /*
         * Disable remote management for now, and set the switch's
-        * DSA device number to zero.
+        * DSA device number.
         */
-       REG_WRITE(REG_GLOBAL, 0x1c, 0x0000);
+       REG_WRITE(REG_GLOBAL, 0x1c, ds->index & 0x1f);
 
        /*
         * Send all frames with destination addresses matching
@@ -133,10 +133,17 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
        REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
 
        /*
-        * Map all DSA device IDs to the CPU port.
+        * Program the DSA routing table.
         */
-       for (i = 0; i < 32; i++)
-               REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | ds->cpu_port);
+       for (i = 0; i < 32; i++) {
+               int nexthop;
+
+               nexthop = 0x1f;
+               if (i != ds->index && i < ds->dst->pd->nr_chips)
+                       nexthop = ds->pd->rtable[i] & 0x1f;
+
+               REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
+       }
 
        /*
         * Clear all trunk masks.
@@ -176,12 +183,18 @@ static int mv88e6123_61_65_setup_global(struct dsa_switch *ds)
 static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
 {
        int addr = REG_PORT(p);
+       u16 val;
 
        /*
         * MAC Forcing register: don't force link, speed, duplex
-        * or flow control state to any particular values.
+        * or flow control state to any particular values on physical
+        * ports, but force the CPU port and all DSA ports to 1000 Mb/s
+        * full duplex.
         */
-       REG_WRITE(addr, 0x01, 0x0003);
+       if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
+               REG_WRITE(addr, 0x01, 0x003e);
+       else
+               REG_WRITE(addr, 0x01, 0x0003);
 
        /*
         * Do not limit the period of time that this port can be
@@ -192,37 +205,50 @@ static int mv88e6123_61_65_setup_port(struct dsa_switch *ds, int p)
 
        /*
         * Port Control: disable Drop-on-Unlock, disable Drop-on-Lock,
-        * configure the requested (DSA/EDSA) tagging mode if this is
-        * the CPU port, disable Header mode, enable IGMP/MLD snooping,
-        * disable VLAN tunneling, determine priority by looking at
-        * 802.1p and IP priority fields (IP prio has precedence), and
-        * set STP state to Forwarding.  Finally, if this is the CPU
-        * port, additionally enable forwarding of unknown unicast and
-        * multicast addresses.
-        */
-       REG_WRITE(addr, 0x04,
-                       (p == ds->cpu_port) ?
-                        (ds->tag_protocol == htons(ETH_P_DSA)) ?
-                         0x053f : 0x373f :
-                        0x0433);
+        * disable Header mode, enable IGMP/MLD snooping, disable VLAN
+        * tunneling, determine priority by looking at 802.1p and IP
+        * priority fields (IP prio has precedence), and set STP state
+        * to Forwarding.
+        *
+        * If this is the CPU link, use DSA or EDSA tagging depending
+        * on which tagging mode was configured.
+        *
+        * If this is a link to another switch, use DSA tagging mode.
+        *
+        * If this is the upstream port for this switch, enable
+        * forwarding of unknown unicasts and multicasts.
+        */
+       val = 0x0433;
+       if (dsa_is_cpu_port(ds, p)) {
+               if (ds->dst->tag_protocol == htons(ETH_P_EDSA))
+                       val |= 0x3300;
+               else
+                       val |= 0x0100;
+       }
+       if (ds->dsa_port_mask & (1 << p))
+               val |= 0x0100;
+       if (p == dsa_upstream_port(ds))
+               val |= 0x000c;
+       REG_WRITE(addr, 0x04, val);
 
        /*
         * Port Control 1: disable trunking.  Also, if this is the
         * CPU port, enable learn messages to be sent to this port.
         */
-       REG_WRITE(addr, 0x05, (p == ds->cpu_port) ? 0x8000 : 0x0000);
+       REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
 
        /*
         * Port based VLAN map: give each port its own address
         * database, allow the CPU port to talk to each of the 'real'
         * ports, and allow each of the 'real' ports to only talk to
-        * the CPU port.
-        */
-       REG_WRITE(addr, 0x06,
-                       ((p & 0xf) << 12) |
-                        ((p == ds->cpu_port) ?
-                               ds->valid_port_mask :
-                               (1 << ds->cpu_port)));
+        * the upstream port.
+        */
+       val = (p & 0xf) << 12;
+       if (dsa_is_cpu_port(ds, p))
+               val |= ds->phys_port_mask;
+       else
+               val |= 1 << dsa_upstream_port(ds);
+       REG_WRITE(addr, 0x06, val);
 
        /*
         * Default VLAN ID and priority: don't set a default VLAN
index 70fae2444cb65e64828e07bcbd9aef5bf35f2b65..bb2b41bc854e4d7d98afb08bdd3892d4145ed375 100644 (file)
@@ -1,6 +1,6 @@
 /*
- * net/dsa/mv88e6131.c - Marvell 88e6131 switch chip support
- * Copyright (c) 2008 Marvell Semiconductor
+ * net/dsa/mv88e6131.c - Marvell 88e6095/6095f/6131 switch chip support
+ * Copyright (c) 2008-2009 Marvell Semiconductor
  *
  * 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
@@ -21,6 +21,8 @@ static char *mv88e6131_probe(struct mii_bus *bus, int sw_addr)
        ret = __mv88e6xxx_reg_read(bus, sw_addr, REG_PORT(0), 0x03);
        if (ret >= 0) {
                ret &= 0xfff0;
+               if (ret == 0x0950)
+                       return "Marvell 88E6095/88E6095F";
                if (ret == 0x1060)
                        return "Marvell 88E6131";
        }
@@ -36,7 +38,7 @@ static int mv88e6131_switch_reset(struct dsa_switch *ds)
        /*
         * Set all ports to the disabled state.
         */
-       for (i = 0; i < 8; i++) {
+       for (i = 0; i < 11; i++) {
                ret = REG_READ(REG_PORT(i), 0x04);
                REG_WRITE(REG_PORT(i), 0x04, ret & 0xfffc);
        }
@@ -100,17 +102,17 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
        REG_WRITE(REG_GLOBAL, 0x19, 0x8100);
 
        /*
-        * Disable ARP mirroring, and configure the cpu port as the
-        * port to which ingress and egress monitor frames are to be
-        * sent.
+        * Disable ARP mirroring, and configure the upstream port as
+        * the port to which ingress and egress monitor frames are to
+        * be sent.
         */
-       REG_WRITE(REG_GLOBAL, 0x1a, (ds->cpu_port * 0x1100) | 0x00f0);
+       REG_WRITE(REG_GLOBAL, 0x1a, (dsa_upstream_port(ds) * 0x1100) | 0x00f0);
 
        /*
         * Disable cascade port functionality, and set the switch's
-        * DSA device number to zero.
+        * DSA device number.
         */
-       REG_WRITE(REG_GLOBAL, 0x1c, 0xe000);
+       REG_WRITE(REG_GLOBAL, 0x1c, 0xe000 | (ds->index & 0x1f));
 
        /*
         * Send all frames with destination addresses matching
@@ -127,16 +129,23 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
        REG_WRITE(REG_GLOBAL2, 0x05, 0x00ff);
 
        /*
-        * Map all DSA device IDs to the CPU port.
+        * Program the DSA routing table.
         */
-       for (i = 0; i < 32; i++)
-               REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | ds->cpu_port);
+       for (i = 0; i < 32; i++) {
+               int nexthop;
+
+               nexthop = 0x1f;
+               if (i != ds->index && i < ds->dst->pd->nr_chips)
+                       nexthop = ds->pd->rtable[i] & 0x1f;
+
+               REG_WRITE(REG_GLOBAL2, 0x06, 0x8000 | (i << 8) | nexthop);
+       }
 
        /*
         * Clear all trunk masks.
         */
        for (i = 0; i < 8; i++)
-               REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0xff);
+               REG_WRITE(REG_GLOBAL2, 0x07, 0x8000 | (i << 12) | 0x7ff);
 
        /*
         * Clear all trunk mappings.
@@ -156,12 +165,18 @@ static int mv88e6131_setup_global(struct dsa_switch *ds)
 static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
 {
        int addr = REG_PORT(p);
+       u16 val;
 
        /*
         * MAC Forcing register: don't force link, speed, duplex
-        * or flow control state to any particular values.
+        * or flow control state to any particular values on physical
+        * ports, but force the CPU port and all DSA ports to 1000 Mb/s
+        * full duplex.
         */
-       REG_WRITE(addr, 0x01, 0x0003);
+       if (dsa_is_cpu_port(ds, p) || ds->dsa_port_mask & (1 << p))
+               REG_WRITE(addr, 0x01, 0x003e);
+       else
+               REG_WRITE(addr, 0x01, 0x0003);
 
        /*
         * Port Control: disable Core Tag, disable Drop-on-Lock,
@@ -169,29 +184,40 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
         * enable IGMP/MLD snoop, disable DoubleTag, disable VLAN
         * tunneling, determine priority by looking at 802.1p and
         * IP priority fields (IP prio has precedence), and set STP
-        * state to Forwarding.  Finally, if this is the CPU port,
-        * additionally enable DSA tagging and forwarding of unknown
-        * unicast addresses.
+        * state to Forwarding.
+        *
+        * If this is the upstream port for this switch, enable
+        * forwarding of unknown unicasts, and enable DSA tagging
+        * mode.
+        *
+        * If this is the link to another switch, use DSA tagging
+        * mode, but do not enable forwarding of unknown unicasts.
         */
-       REG_WRITE(addr, 0x04, (p == ds->cpu_port) ? 0x0537 : 0x0433);
+       val = 0x0433;
+       if (p == dsa_upstream_port(ds))
+               val |= 0x0104;
+       if (ds->dsa_port_mask & (1 << p))
+               val |= 0x0100;
+       REG_WRITE(addr, 0x04, val);
 
        /*
         * Port Control 1: disable trunking.  Also, if this is the
         * CPU port, enable learn messages to be sent to this port.
         */
-       REG_WRITE(addr, 0x05, (p == ds->cpu_port) ? 0x8000 : 0x0000);
+       REG_WRITE(addr, 0x05, dsa_is_cpu_port(ds, p) ? 0x8000 : 0x0000);
 
        /*
         * Port based VLAN map: give each port its own address
         * database, allow the CPU port to talk to each of the 'real'
         * ports, and allow each of the 'real' ports to only talk to
-        * the CPU port.
+        * the upstream port.
         */
-       REG_WRITE(addr, 0x06,
-                       ((p & 0xf) << 12) |
-                        ((p == ds->cpu_port) ?
-                               ds->valid_port_mask :
-                               (1 << ds->cpu_port)));
+       val = (p & 0xf) << 12;
+       if (dsa_is_cpu_port(ds, p))
+               val |= ds->phys_port_mask;
+       else
+               val |= 1 << dsa_upstream_port(ds);
+       REG_WRITE(addr, 0x06, val);
 
        /*
         * Default VLAN ID and priority: don't set a default VLAN
@@ -207,13 +233,15 @@ static int mv88e6131_setup_port(struct dsa_switch *ds, int p)
         * untagged frames on this port, do a destination address
         * lookup on received packets as usual, don't send a copy
         * of all transmitted/received frames on this port to the
-        * CPU, and configure the CPU port number.  Also, if this
-        * is the CPU port, enable forwarding of unknown multicast
-        * addresses.
+        * CPU, and configure the upstream port number.
+        *
+        * If this is the upstream port for this switch, enable
+        * forwarding of unknown multicast addresses.
         */
-       REG_WRITE(addr, 0x08,
-                       ((p == ds->cpu_port) ? 0x00c0 : 0x0080) |
-                        ds->cpu_port);
+       val = 0x0080 | dsa_upstream_port(ds);
+       if (p == dsa_upstream_port(ds))
+               val |= 0x0040;
+       REG_WRITE(addr, 0x08, val);
 
        /*
         * Rate Control: disable ingress rate limiting.
@@ -268,7 +296,7 @@ static int mv88e6131_setup(struct dsa_switch *ds)
        if (ret < 0)
                return ret;
 
-       for (i = 0; i < 6; i++) {
+       for (i = 0; i < 11; i++) {
                ret = mv88e6131_setup_port(ds, i);
                if (ret < 0)
                        return ret;
@@ -279,7 +307,7 @@ static int mv88e6131_setup(struct dsa_switch *ds)
 
 static int mv88e6131_port_to_phy_addr(int port)
 {
-       if (port >= 0 && port != 3 && port <= 7)
+       if (port >= 0 && port <= 11)
                return port;
        return -1;
 }
index a68fd79e9eca0456c45b777be2e1a9140a5a8a3f..ed131181215dc3d8cb642101ca3f958116c74d80 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * net/dsa/slave.c - Slave device handling
- * Copyright (c) 2008 Marvell Semiconductor
+ * Copyright (c) 2008-2009 Marvell Semiconductor
  *
  * 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
@@ -19,7 +19,7 @@ static int dsa_slave_phy_read(struct mii_bus *bus, int addr, int reg)
 {
        struct dsa_switch *ds = bus->priv;
 
-       if (ds->valid_port_mask & (1 << addr))
+       if (ds->phys_port_mask & (1 << addr))
                return ds->drv->phy_read(ds, addr, reg);
 
        return 0xffff;
@@ -29,7 +29,7 @@ static int dsa_slave_phy_write(struct mii_bus *bus, int addr, int reg, u16 val)
 {
        struct dsa_switch *ds = bus->priv;
 
-       if (ds->valid_port_mask & (1 << addr))
+       if (ds->phys_port_mask & (1 << addr))
                return ds->drv->phy_write(ds, addr, reg, val);
 
        return 0;
@@ -43,15 +43,24 @@ void dsa_slave_mii_bus_init(struct dsa_switch *ds)
        ds->slave_mii_bus->write = dsa_slave_phy_write;
        snprintf(ds->slave_mii_bus->id, MII_BUS_ID_SIZE, "%s:%.2x",
                        ds->master_mii_bus->id, ds->pd->sw_addr);
-       ds->slave_mii_bus->parent = &(ds->master_mii_bus->dev);
+       ds->slave_mii_bus->parent = &ds->master_mii_bus->dev;
 }
 
 
 /* slave device handling ****************************************************/
+static int dsa_slave_init(struct net_device *dev)
+{
+       struct dsa_slave_priv *p = netdev_priv(dev);
+
+       dev->iflink = p->parent->dst->master_netdev->ifindex;
+
+       return 0;
+}
+
 static int dsa_slave_open(struct net_device *dev)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
-       struct net_device *master = p->parent->master_netdev;
+       struct net_device *master = p->parent->dst->master_netdev;
        int err;
 
        if (!(master->flags & IFF_UP))
@@ -89,7 +98,7 @@ out:
 static int dsa_slave_close(struct net_device *dev)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
-       struct net_device *master = p->parent->master_netdev;
+       struct net_device *master = p->parent->dst->master_netdev;
 
        dev_mc_unsync(master, dev);
        dev_unicast_unsync(master, dev);
@@ -107,7 +116,7 @@ static int dsa_slave_close(struct net_device *dev)
 static void dsa_slave_change_rx_flags(struct net_device *dev, int change)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
-       struct net_device *master = p->parent->master_netdev;
+       struct net_device *master = p->parent->dst->master_netdev;
 
        if (change & IFF_ALLMULTI)
                dev_set_allmulti(master, dev->flags & IFF_ALLMULTI ? 1 : -1);
@@ -118,7 +127,7 @@ static void dsa_slave_change_rx_flags(struct net_device *dev, int change)
 static void dsa_slave_set_rx_mode(struct net_device *dev)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
-       struct net_device *master = p->parent->master_netdev;
+       struct net_device *master = p->parent->dst->master_netdev;
 
        dev_mc_sync(master, dev);
        dev_unicast_sync(master, dev);
@@ -127,7 +136,7 @@ static void dsa_slave_set_rx_mode(struct net_device *dev)
 static int dsa_slave_set_mac_address(struct net_device *dev, void *a)
 {
        struct dsa_slave_priv *p = netdev_priv(dev);
-       struct net_device *master = p->parent->master_netdev;
+       struct net_device *master = p->parent->dst->master_netdev;
        struct sockaddr *addr = a;
        int err;
 
@@ -288,6 +297,7 @@ static const struct ethtool_ops dsa_slave_ethtool_ops = {
 
 #ifdef CONFIG_NET_DSA_TAG_DSA
 static const struct net_device_ops dsa_netdev_ops = {
+       .ndo_init               = dsa_slave_init,
        .ndo_open               = dsa_slave_open,
        .ndo_stop               = dsa_slave_close,
        .ndo_start_xmit         = dsa_xmit,
@@ -300,6 +310,7 @@ static const struct net_device_ops dsa_netdev_ops = {
 #endif
 #ifdef CONFIG_NET_DSA_TAG_EDSA
 static const struct net_device_ops edsa_netdev_ops = {
+       .ndo_init               = dsa_slave_init,
        .ndo_open               = dsa_slave_open,
        .ndo_stop               = dsa_slave_close,
        .ndo_start_xmit         = edsa_xmit,
@@ -312,6 +323,7 @@ static const struct net_device_ops edsa_netdev_ops = {
 #endif
 #ifdef CONFIG_NET_DSA_TAG_TRAILER
 static const struct net_device_ops trailer_netdev_ops = {
+       .ndo_init               = dsa_slave_init,
        .ndo_open               = dsa_slave_open,
        .ndo_stop               = dsa_slave_close,
        .ndo_start_xmit         = trailer_xmit,
@@ -328,7 +340,7 @@ struct net_device *
 dsa_slave_create(struct dsa_switch *ds, struct device *parent,
                 int port, char *name)
 {
-       struct net_device *master = ds->master_netdev;
+       struct net_device *master = ds->dst->master_netdev;
        struct net_device *slave_dev;
        struct dsa_slave_priv *p;
        int ret;
@@ -343,7 +355,7 @@ dsa_slave_create(struct dsa_switch *ds, struct device *parent,
        memcpy(slave_dev->dev_addr, master->dev_addr, ETH_ALEN);
        slave_dev->tx_queue_len = 0;
 
-       switch (ds->tag_protocol) {
+       switch (ds->dst->tag_protocol) {
 #ifdef CONFIG_NET_DSA_TAG_DSA
        case htons(ETH_P_DSA):
                slave_dev->netdev_ops = &dsa_netdev_ops;
index 63e532a69fdb1186077d0cc6dd658f276ec59565..8fa25bafe6ca299aae59d61c08d0236a268a4166 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * net/dsa/tag_dsa.c - (Non-ethertype) DSA tagging
- * Copyright (c) 2008 Marvell Semiconductor
+ * Copyright (c) 2008-2009 Marvell Semiconductor
  *
  * 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
@@ -36,7 +36,7 @@ int dsa_xmit(struct sk_buff *skb, struct net_device *dev)
                 * Construct tagged FROM_CPU DSA tag from 802.1q tag.
                 */
                dsa_header = skb->data + 2 * ETH_ALEN;
-               dsa_header[0] = 0x60;
+               dsa_header[0] = 0x60 | p->parent->index;
                dsa_header[1] = p->port << 3;
 
                /*
@@ -57,7 +57,7 @@ int dsa_xmit(struct sk_buff *skb, struct net_device *dev)
                 * Construct untagged FROM_CPU DSA tag.
                 */
                dsa_header = skb->data + 2 * ETH_ALEN;
-               dsa_header[0] = 0x40;
+               dsa_header[0] = 0x40 | p->parent->index;
                dsa_header[1] = p->port << 3;
                dsa_header[2] = 0x00;
                dsa_header[3] = 0x00;
@@ -65,7 +65,7 @@ int dsa_xmit(struct sk_buff *skb, struct net_device *dev)
 
        skb->protocol = htons(ETH_P_DSA);
 
-       skb->dev = p->parent->master_netdev;
+       skb->dev = p->parent->dst->master_netdev;
        dev_queue_xmit(skb);
 
        return NETDEV_TX_OK;
@@ -78,11 +78,13 @@ out_free:
 static int dsa_rcv(struct sk_buff *skb, struct net_device *dev,
                   struct packet_type *pt, struct net_device *orig_dev)
 {
-       struct dsa_switch *ds = dev->dsa_ptr;
+       struct dsa_switch_tree *dst = dev->dsa_ptr;
+       struct dsa_switch *ds;
        u8 *dsa_header;
+       int source_device;
        int source_port;
 
-       if (unlikely(ds == NULL))
+       if (unlikely(dst == NULL))
                goto out_drop;
 
        skb = skb_unshare(skb, GFP_ATOMIC);
@@ -98,16 +100,24 @@ static int dsa_rcv(struct sk_buff *skb, struct net_device *dev,
        dsa_header = skb->data - 2;
 
        /*
-        * Check that frame type is either TO_CPU or FORWARD, and
-        * that the source device is zero.
+        * Check that frame type is either TO_CPU or FORWARD.
         */
-       if ((dsa_header[0] & 0xdf) != 0x00 && (dsa_header[0] & 0xdf) != 0xc0)
+       if ((dsa_header[0] & 0xc0) != 0x00 && (dsa_header[0] & 0xc0) != 0xc0)
                goto out_drop;
 
        /*
-        * Check that the source port is a registered DSA port.
+        * Determine source device and port.
         */
+       source_device = dsa_header[0] & 0x1f;
        source_port = (dsa_header[1] >> 3) & 0x1f;
+
+       /*
+        * Check that the source device exists and that the source
+        * port is a registered DSA port.
+        */
+       if (source_device >= dst->pd->nr_chips)
+               goto out_drop;
+       ds = dst->ds[source_device];
        if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
                goto out_drop;
 
@@ -175,7 +185,7 @@ out:
        return 0;
 }
 
-static struct packet_type dsa_packet_type = {
+static struct packet_type dsa_packet_type __read_mostly = {
        .type   = cpu_to_be16(ETH_P_DSA),
        .func   = dsa_rcv,
 };
index 6197f9a7ef421f7eec701f8a61defdbb11bcbbdb..815607bd286f03bfdb1d45b3c18adc92b9ebe83b 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * net/dsa/tag_edsa.c - Ethertype DSA tagging
- * Copyright (c) 2008 Marvell Semiconductor
+ * Copyright (c) 2008-2009 Marvell Semiconductor
  *
  * 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
@@ -45,7 +45,7 @@ int edsa_xmit(struct sk_buff *skb, struct net_device *dev)
                edsa_header[1] = ETH_P_EDSA & 0xff;
                edsa_header[2] = 0x00;
                edsa_header[3] = 0x00;
-               edsa_header[4] = 0x60;
+               edsa_header[4] = 0x60 | p->parent->index;
                edsa_header[5] = p->port << 3;
 
                /*
@@ -70,7 +70,7 @@ int edsa_xmit(struct sk_buff *skb, struct net_device *dev)
                edsa_header[1] = ETH_P_EDSA & 0xff;
                edsa_header[2] = 0x00;
                edsa_header[3] = 0x00;
-               edsa_header[4] = 0x40;
+               edsa_header[4] = 0x40 | p->parent->index;
                edsa_header[5] = p->port << 3;
                edsa_header[6] = 0x00;
                edsa_header[7] = 0x00;
@@ -78,7 +78,7 @@ int edsa_xmit(struct sk_buff *skb, struct net_device *dev)
 
        skb->protocol = htons(ETH_P_EDSA);
 
-       skb->dev = p->parent->master_netdev;
+       skb->dev = p->parent->dst->master_netdev;
        dev_queue_xmit(skb);
 
        return NETDEV_TX_OK;
@@ -91,11 +91,13 @@ out_free:
 static int edsa_rcv(struct sk_buff *skb, struct net_device *dev,
                    struct packet_type *pt, struct net_device *orig_dev)
 {
-       struct dsa_switch *ds = dev->dsa_ptr;
+       struct dsa_switch_tree *dst = dev->dsa_ptr;
+       struct dsa_switch *ds;
        u8 *edsa_header;
+       int source_device;
        int source_port;
 
-       if (unlikely(ds == NULL))
+       if (unlikely(dst == NULL))
                goto out_drop;
 
        skb = skb_unshare(skb, GFP_ATOMIC);
@@ -111,16 +113,24 @@ static int edsa_rcv(struct sk_buff *skb, struct net_device *dev,
        edsa_header = skb->data + 2;
 
        /*
-        * Check that frame type is either TO_CPU or FORWARD, and
-        * that the source device is zero.
+        * Check that frame type is either TO_CPU or FORWARD.
         */
-       if ((edsa_header[0] & 0xdf) != 0x00 && (edsa_header[0] & 0xdf) != 0xc0)
+       if ((edsa_header[0] & 0xc0) != 0x00 && (edsa_header[0] & 0xc0) != 0xc0)
                goto out_drop;
 
        /*
-        * Check that the source port is a registered DSA port.
+        * Determine source device and port.
         */
+       source_device = edsa_header[0] & 0x1f;
        source_port = (edsa_header[1] >> 3) & 0x1f;
+
+       /*
+        * Check that the source device exists and that the source
+        * port is a registered DSA port.
+        */
+       if (source_device >= dst->pd->nr_chips)
+               goto out_drop;
+       ds = dst->ds[source_device];
        if (source_port >= DSA_MAX_PORTS || ds->ports[source_port] == NULL)
                goto out_drop;
 
@@ -194,7 +204,7 @@ out:
        return 0;
 }
 
-static struct packet_type edsa_packet_type = {
+static struct packet_type edsa_packet_type __read_mostly = {
        .type   = cpu_to_be16(ETH_P_EDSA),
        .func   = edsa_rcv,
 };
index d7e7f424ff0c4a09c6bccb8cdff5fbbe556e687e..1c3e30c38b86e69728d7c521f3ea020f874c20c0 100644 (file)
@@ -1,6 +1,6 @@
 /*
  * net/dsa/tag_trailer.c - Trailer tag format handling
- * Copyright (c) 2008 Marvell Semiconductor
+ * Copyright (c) 2008-2009 Marvell Semiconductor
  *
  * 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
@@ -59,7 +59,7 @@ int trailer_xmit(struct sk_buff *skb, struct net_device *dev)
 
        nskb->protocol = htons(ETH_P_TRAILER);
 
-       nskb->dev = p->parent->master_netdev;
+       nskb->dev = p->parent->dst->master_netdev;
        dev_queue_xmit(nskb);
 
        return NETDEV_TX_OK;
@@ -68,12 +68,14 @@ int trailer_xmit(struct sk_buff *skb, struct net_device *dev)
 static int trailer_rcv(struct sk_buff *skb, struct net_device *dev,
                       struct packet_type *pt, struct net_device *orig_dev)
 {
-       struct dsa_switch *ds = dev->dsa_ptr;
+       struct dsa_switch_tree *dst = dev->dsa_ptr;
+       struct dsa_switch *ds;
        u8 *trailer;
        int source_port;
 
-       if (unlikely(ds == NULL))
+       if (unlikely(dst == NULL))
                goto out_drop;
+       ds = dst->ds[0];
 
        skb = skb_unshare(skb, GFP_ATOMIC);
        if (skb == NULL)
@@ -111,7 +113,7 @@ out:
        return 0;
 }
 
-static struct packet_type trailer_packet_type = {
+static struct packet_type trailer_packet_type __read_mostly = {
        .type   = cpu_to_be16(ETH_P_TRAILER),
        .func   = trailer_rcv,
 };
index 7bf35582f65643f97e959b290a77bc66f2b88538..6f479fa522c30c3651dfab020d10d2b6a501efc5 100644 (file)
@@ -1102,7 +1102,7 @@ drop:
        return NET_RX_DROP;
 }
 
-static struct packet_type econet_packet_type = {
+static struct packet_type econet_packet_type __read_mostly = {
        .type =         cpu_to_be16(ETH_P_ECONET),
        .func =         econet_rcv,
 };
index 691268f3a35972ff931c51bc8c7eeca74e73de78..b2cf91e4ccaa11fd140af7ece0c7b11b820e048c 100644 (file)
@@ -35,7 +35,7 @@ config IP_ADVANCED_ROUTER
 
          at boot time after the /proc file system has been mounted.
 
-         If you turn on IP forwarding, you will also get the rp_filter, which
+         If you turn on IP forwarding, you should consider the rp_filter, which
          automatically rejects incoming packets if the routing table entry
          for their source address doesn't match the network interface they're
          arriving on. This has security advantages because it prevents the
@@ -46,12 +46,16 @@ config IP_ADVANCED_ROUTER
          rp_filter on use:
 
          echo 1 > /proc/sys/net/ipv4/conf/<device>/rp_filter
-         or
+          and
          echo 1 > /proc/sys/net/ipv4/conf/all/rp_filter
 
+         Note that some distributions enable it in startup scripts.
+         For details about rp_filter strict and loose mode read
+         <file:Documentation/networking/ip-sysctl.txt>.
+
          If unsure, say N here.
 
-choice 
+choice
        prompt "Choose IP: FIB lookup algorithm (choose FIB_HASH if unsure)"
        depends on IP_ADVANCED_ROUTER
        default ASK_IP_FIB_HASH
@@ -59,27 +63,29 @@ choice
 config ASK_IP_FIB_HASH
        bool "FIB_HASH"
        ---help---
-       Current FIB is very proven and good enough for most users.
+         Current FIB is very proven and good enough for most users.
 
 config IP_FIB_TRIE
        bool "FIB_TRIE"
        ---help---
-       Use new experimental LC-trie as FIB lookup algorithm. 
-        This improves lookup performance if you have a large
-       number of routes.
-
-       LC-trie is a longest matching prefix lookup algorithm which
-       performs better than FIB_HASH for large routing tables.
-       But, it consumes more memory and is more complex.
-       
-       LC-trie is described in:
-       
-       IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson
-       IEEE Journal on Selected Areas in Communications, 17(6):1083-1092, June 1999
-       An experimental study of compression methods for dynamic tries
-       Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002.
-       http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/
-       
+         Use new experimental LC-trie as FIB lookup algorithm.
+         This improves lookup performance if you have a large
+         number of routes.
+
+         LC-trie is a longest matching prefix lookup algorithm which
+         performs better than FIB_HASH for large routing tables.
+         But, it consumes more memory and is more complex.
+
+         LC-trie is described in:
+
+         IP-address lookup using LC-tries. Stefan Nilsson and Gunnar Karlsson
+         IEEE Journal on Selected Areas in Communications, 17(6):1083-1092,
+         June 1999
+
+         An experimental study of compression methods for dynamic tries
+         Stefan Nilsson and Matti Tikkanen. Algorithmica, 33(1):19-33, 2002.
+         http://www.nada.kth.se/~snilsson/public/papers/dyntrie2/
+
 endchoice
 
 config IP_FIB_HASH
@@ -191,7 +197,7 @@ config IP_PNP_RARP
          <file:Documentation/filesystems/nfsroot.txt> for details.
 
 # not yet ready..
-#   bool '    IP: ARP support' CONFIG_IP_PNP_ARP               
+#   bool '    IP: ARP support' CONFIG_IP_PNP_ARP
 config NET_IPIP
        tristate "IP: tunneling"
        select INET_TUNNEL
@@ -361,7 +367,7 @@ config INET_IPCOMP
        ---help---
          Support for IP Payload Compression Protocol (IPComp) (RFC3173),
          typically needed for IPsec.
-         
+
          If unsure, say Y.
 
 config INET_XFRM_TUNNEL
@@ -415,7 +421,7 @@ config INET_DIAG
          Support for INET (TCP, DCCP, etc) socket monitoring interface used by
          native Linux tools such as ss. ss is included in iproute2, currently
          downloadable at <http://linux-net.osdl.org/index.php/Iproute2>.
-         
+
          If unsure, say Y.
 
 config INET_TCP_DIAG
index 627be4dc7fb08e2919c9367e42db7f8c2ea6dae4..d5aaabbb7cb381054df71725d0ca2edc1a8289ff 100644 (file)
@@ -1500,7 +1500,7 @@ static int ipv4_proc_init(void);
  *     IP protocol layer initialiser
  */
 
-static struct packet_type ip_packet_type = {
+static struct packet_type ip_packet_type __read_mostly = {
        .type = cpu_to_be16(ETH_P_IP),
        .func = ip_rcv,
        .gso_send_check = inet_gso_send_check,
index 3f6b7354699bb8fe8df7cb47a1ced87e9816cf06..f11931c1838176de514d5e70666ebeef180e7183 100644 (file)
@@ -801,8 +801,11 @@ static int arp_process(struct sk_buff *skb)
  *  cache.
  */
 
-       /* Special case: IPv4 duplicate address detection packet (RFC2131) */
-       if (sip == 0) {
+       /*
+        *  Special case: IPv4 duplicate address detection packet (RFC2131)
+        *  and Gratuitous ARP/ARP Announce. (RFC3927, Section 2.4)
+        */
+       if (sip == 0 || tip == sip) {
                if (arp->ar_op == htons(ARPOP_REQUEST) &&
                    inet_addr_type(net, tip) == RTN_LOCAL &&
                    !arp_ignore(in_dev, sip, tip))
@@ -892,7 +895,7 @@ static int arp_process(struct sk_buff *skb)
 out:
        if (in_dev)
                in_dev_put(in_dev);
-       kfree_skb(skb);
+       consume_skb(skb);
        return 0;
 }
 
@@ -1225,7 +1228,7 @@ void arp_ifdown(struct net_device *dev)
  *     Called once on startup.
  */
 
-static struct packet_type arp_packet_type = {
+static struct packet_type arp_packet_type __read_mostly = {
        .type = cpu_to_be16(ETH_P_ARP),
        .func = arp_rcv,
 };
index 6bb2635b5dedda5201b0791a58b6a9f76f94ea6f..7bc992976d29bd18b70dd39544791d66f4351901 100644 (file)
@@ -3,11 +3,16 @@
  *
  * This is an implementation of the CIPSO 2.2 protocol as specified in
  * draft-ietf-cipso-ipsecurity-01.txt with additional tag types as found in
- * FIPS-188, copies of both documents can be found in the Documentation
- * directory.  While CIPSO never became a full IETF RFC standard many vendors
+ * FIPS-188.  While CIPSO never became a full IETF RFC standard many vendors
  * have chosen to adopt the protocol and over the years it has become a
  * de-facto standard for labeled networking.
  *
+ * The CIPSO draft specification can be found in the kernel's Documentation
+ * directory as well as the following URL:
+ *   http://netlabel.sourceforge.net/files/draft-ietf-cipso-ipsecurity-01.txt
+ * The FIPS-188 specification can be found at the following URL:
+ *   http://www.itl.nist.gov/fipspubs/fip188.htm
+ *
  * Author: Paul Moore <paul.moore@hp.com>
  *
  */
index d519a6a6672634902f93459e0581e92a2af51f0b..126bb911880fa675861f4b1940655e18fcbe1774 100644 (file)
@@ -1216,7 +1216,8 @@ static void rtmsg_ifa(int event, struct in_ifaddr *ifa, struct nlmsghdr *nlh,
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
+       rtnl_notify(skb, net, pid, RTNLGRP_IPV4_IFADDR, nlh, GFP_KERNEL);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_IPV4_IFADDR, err);
index 741e4fa3e4749e0285c39f65dc306e644fb4032b..cafcc49d0993b6a6b39590f6c2246fc806eb463d 100644 (file)
@@ -275,7 +275,7 @@ int fib_validate_source(__be32 src, __be32 dst, u8 tos, int oif,
        fib_res_put(&res);
        if (no_addr)
                goto last_resort;
-       if (rpf)
+       if (rpf == 1)
                goto e_inval;
        fl.oif = dev->ifindex;
 
index 4817dea3bc737225ec99a605b3b5d5681ac6e082..f831df500907cb9644b601685b150c1a39aa8485 100644 (file)
@@ -322,8 +322,9 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa,
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, info->nl_net, info->pid, RTNLGRP_IPV4_ROUTE,
-                         info->nlh, GFP_KERNEL);
+       rtnl_notify(skb, info->nl_net, info->pid, RTNLGRP_IPV4_ROUTE,
+                   info->nlh, GFP_KERNEL);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(info->nl_net, RTNLGRP_IPV4_ROUTE, err);
index 382800a62b31fd1a862d6e4d66dac2259cbc66c3..3f50807237e08580d3427d687f9cf82f4da9ce59 100644 (file)
@@ -1207,7 +1207,7 @@ static struct pernet_operations __net_initdata icmp_sk_ops = {
 
 int __init icmp_init(void)
 {
-       return register_pernet_device(&icmp_sk_ops);
+       return register_pernet_subsys(&icmp_sk_ops);
 }
 
 EXPORT_SYMBOL(icmp_err_convert);
index 6c52e08f786e6f574e71c589ddbb86b26f2f43a0..eaf3e2c8646a438a938f341151c04920746a3c5f 100644 (file)
@@ -267,6 +267,7 @@ static struct inet_frag_queue *inet_frag_create(struct netns_frags *nf,
 
 struct inet_frag_queue *inet_frag_find(struct netns_frags *nf,
                struct inet_frags *f, void *key, unsigned int hash)
+       __releases(&f->lock)
 {
        struct inet_frag_queue *q;
        struct hlist_node *n;
index 6659ac000eeb81c72666a863177301df3ce59d7f..7985346653bdc9e7c3cf69ae3d477a299d431fd3 100644 (file)
@@ -463,6 +463,7 @@ err:
 static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
                         struct net_device *dev)
 {
+       struct net *net = container_of(qp->q.net, struct net, ipv4.frags);
        struct iphdr *iph;
        struct sk_buff *fp, *head = qp->q.fragments;
        int len;
@@ -548,7 +549,7 @@ static int ip_frag_reasm(struct ipq *qp, struct sk_buff *prev,
        iph = ip_hdr(head);
        iph->frag_off = 0;
        iph->tot_len = htons(len);
-       IP_INC_STATS_BH(dev_net(dev), IPSTATS_MIB_REASMOKS);
+       IP_INC_STATS_BH(net, IPSTATS_MIB_REASMOKS);
        qp->q.fragments = NULL;
        return 0;
 
index 07a188afb3ac7af64650d8eb7f641f27b8eb09b6..e62510d5ea5a60df6b806342e870ace458108962 100644 (file)
@@ -491,7 +491,7 @@ static void ipgre_err(struct sk_buff *skb, u32 info)
        if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
                goto out;
 
-       if (jiffies - t->err_time < IPTUNNEL_ERR_TIMEO)
+       if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
                t->err_count++;
        else
                t->err_count = 1;
@@ -803,7 +803,8 @@ static int ipgre_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
 #endif
 
        if (tunnel->err_count > 0) {
-               if (jiffies - tunnel->err_time < IPTUNNEL_ERR_TIMEO) {
+               if (time_before(jiffies,
+                               tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
                        tunnel->err_count--;
 
                        dst_link_failure(skb);
index 5079dfbc6f38b1423b537cd9f8ba27ab2a08c685..9054139795af480757357dc626815296666f8919 100644 (file)
@@ -327,7 +327,7 @@ static int ipip_err(struct sk_buff *skb, u32 info)
        if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
                goto out;
 
-       if (jiffies - t->err_time < IPTUNNEL_ERR_TIMEO)
+       if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
                t->err_count++;
        else
                t->err_count = 1;
@@ -466,7 +466,8 @@ static int ipip_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        if (tunnel->err_count > 0) {
-               if (jiffies - tunnel->err_time < IPTUNNEL_ERR_TIMEO) {
+               if (time_before(jiffies,
+                               tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
                        tunnel->err_count--;
                        dst_link_failure(skb);
                } else
@@ -750,7 +751,7 @@ static struct xfrm_tunnel ipip_handler = {
        .priority       =       1,
 };
 
-static char banner[] __initdata =
+static const char banner[] __initconst =
        KERN_INFO "IPv4 over IPv4 tunneling driver\n";
 
 static void ipip_destroy_tunnels(struct ipip_net *ipn)
index 90b2f3c192ff47eb4c24d8e416d7d1e04f577677..2451aeb5ac23c72fc3fd99963aa07054d58e98c5 100644 (file)
@@ -661,6 +661,47 @@ struct sk_buff *sk_stream_alloc_skb(struct sock *sk, int size, gfp_t gfp)
        return NULL;
 }
 
+static unsigned int tcp_xmit_size_goal(struct sock *sk, u32 mss_now,
+                                      int large_allowed)
+{
+       struct tcp_sock *tp = tcp_sk(sk);
+       u32 xmit_size_goal, old_size_goal;
+
+       xmit_size_goal = mss_now;
+
+       if (large_allowed && sk_can_gso(sk)) {
+               xmit_size_goal = ((sk->sk_gso_max_size - 1) -
+                                 inet_csk(sk)->icsk_af_ops->net_header_len -
+                                 inet_csk(sk)->icsk_ext_hdr_len -
+                                 tp->tcp_header_len);
+
+               xmit_size_goal = tcp_bound_to_half_wnd(tp, xmit_size_goal);
+
+               /* We try hard to avoid divides here */
+               old_size_goal = tp->xmit_size_goal_segs * mss_now;
+
+               if (likely(old_size_goal <= xmit_size_goal &&
+                          old_size_goal + mss_now > xmit_size_goal)) {
+                       xmit_size_goal = old_size_goal;
+               } else {
+                       tp->xmit_size_goal_segs = xmit_size_goal / mss_now;
+                       xmit_size_goal = tp->xmit_size_goal_segs * mss_now;
+               }
+       }
+
+       return max(xmit_size_goal, mss_now);
+}
+
+static int tcp_send_mss(struct sock *sk, int *size_goal, int flags)
+{
+       int mss_now;
+
+       mss_now = tcp_current_mss(sk);
+       *size_goal = tcp_xmit_size_goal(sk, mss_now, !(flags & MSG_OOB));
+
+       return mss_now;
+}
+
 static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffset,
                         size_t psize, int flags)
 {
@@ -677,13 +718,12 @@ static ssize_t do_tcp_sendpages(struct sock *sk, struct page **pages, int poffse
 
        clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
 
-       mss_now = tcp_current_mss(sk, !(flags&MSG_OOB));
-       size_goal = tp->xmit_size_goal;
+       mss_now = tcp_send_mss(sk, &size_goal, flags);
        copied = 0;
 
        err = -EPIPE;
        if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
-               goto do_error;
+               goto out_err;
 
        while (psize > 0) {
                struct sk_buff *skb = tcp_write_queue_tail(sk);
@@ -761,8 +801,7 @@ wait_for_memory:
                if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
                        goto do_error;
 
-               mss_now = tcp_current_mss(sk, !(flags&MSG_OOB));
-               size_goal = tp->xmit_size_goal;
+               mss_now = tcp_send_mss(sk, &size_goal, flags);
        }
 
 out:
@@ -844,8 +883,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
        /* This should be in poll */
        clear_bit(SOCK_ASYNC_NOSPACE, &sk->sk_socket->flags);
 
-       mss_now = tcp_current_mss(sk, !(flags&MSG_OOB));
-       size_goal = tp->xmit_size_goal;
+       mss_now = tcp_send_mss(sk, &size_goal, flags);
 
        /* Ok commence sending. */
        iovlen = msg->msg_iovlen;
@@ -854,7 +892,7 @@ int tcp_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
 
        err = -EPIPE;
        if (sk->sk_err || (sk->sk_shutdown & SEND_SHUTDOWN))
-               goto do_error;
+               goto out_err;
 
        while (--iovlen >= 0) {
                int seglen = iov->iov_len;
@@ -1007,8 +1045,7 @@ wait_for_memory:
                        if ((err = sk_stream_wait_memory(sk, &timeo)) != 0)
                                goto do_error;
 
-                       mss_now = tcp_current_mss(sk, !(flags&MSG_OOB));
-                       size_goal = tp->xmit_size_goal;
+                       mss_now = tcp_send_mss(sk, &size_goal, flags);
                }
        }
 
@@ -1045,8 +1082,7 @@ out_err:
  */
 
 static int tcp_recv_urg(struct sock *sk, long timeo,
-                       struct msghdr *msg, int len, int flags,
-                       int *addr_len)
+                       struct msghdr *msg, int len, int flags)
 {
        struct tcp_sock *tp = tcp_sk(sk);
 
@@ -1661,7 +1697,7 @@ out:
        return err;
 
 recv_urg:
-       err = tcp_recv_urg(sk, timeo, msg, len, flags, addr_len);
+       err = tcp_recv_urg(sk, timeo, msg, len, flags);
        goto out;
 }
 
index 7eb7636db0d0e0f0b0675d17de4b4a17db32d4b3..3b53fd1af23f04bb2a9023b56204ca45051fa81f 100644 (file)
@@ -149,16 +149,7 @@ static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
                tcp_slow_start(tp);
        else {
                bictcp_update(ca, tp->snd_cwnd);
-
-               /* In dangerous area, increase slowly.
-                * In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd
-                */
-               if (tp->snd_cwnd_cnt >= ca->cnt) {
-                       if (tp->snd_cwnd < tp->snd_cwnd_clamp)
-                               tp->snd_cwnd++;
-                       tp->snd_cwnd_cnt = 0;
-               } else
-                       tp->snd_cwnd_cnt++;
+               tcp_cong_avoid_ai(tp, ca->cnt);
        }
 
 }
index 4ec5b4e97c4e2bc97a07e5887167e26b265b9e72..e92beb9e55e0d834c3184e4b2a5c6e4faa5ea057 100644 (file)
@@ -336,6 +336,19 @@ void tcp_slow_start(struct tcp_sock *tp)
 }
 EXPORT_SYMBOL_GPL(tcp_slow_start);
 
+/* In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd (or alternative w) */
+void tcp_cong_avoid_ai(struct tcp_sock *tp, u32 w)
+{
+       if (tp->snd_cwnd_cnt >= w) {
+               if (tp->snd_cwnd < tp->snd_cwnd_clamp)
+                       tp->snd_cwnd++;
+               tp->snd_cwnd_cnt = 0;
+       } else {
+               tp->snd_cwnd_cnt++;
+       }
+}
+EXPORT_SYMBOL_GPL(tcp_cong_avoid_ai);
+
 /*
  * TCP Reno congestion control
  * This is special case used for fallback as well.
@@ -365,13 +378,7 @@ void tcp_reno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
                                tp->snd_cwnd++;
                }
        } else {
-               /* In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd */
-               if (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
-                       if (tp->snd_cwnd < tp->snd_cwnd_clamp)
-                               tp->snd_cwnd++;
-                       tp->snd_cwnd_cnt = 0;
-               } else
-                       tp->snd_cwnd_cnt++;
+               tcp_cong_avoid_ai(tp, tp->snd_cwnd);
        }
 }
 EXPORT_SYMBOL_GPL(tcp_reno_cong_avoid);
index ee467ec40c4f3c0b08123d042921c2f87481632f..71d5f2f29fa62b92cb4ae4d4762b5322d017f5d3 100644 (file)
@@ -294,16 +294,7 @@ static void bictcp_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
                tcp_slow_start(tp);
        } else {
                bictcp_update(ca, tp->snd_cwnd);
-
-               /* In dangerous area, increase slowly.
-                * In theory this is tp->snd_cwnd += 1 / tp->snd_cwnd
-                */
-               if (tp->snd_cwnd_cnt >= ca->cnt) {
-                       if (tp->snd_cwnd < tp->snd_cwnd_clamp)
-                               tp->snd_cwnd++;
-                       tp->snd_cwnd_cnt = 0;
-               } else
-                       tp->snd_cwnd_cnt++;
+               tcp_cong_avoid_ai(tp, ca->cnt);
        }
 
 }
index 937549b8a9212fa6289964bde303367e2f462d74..26d5c7fc7de51139c28b5a52dad5efe9b631c894 100644 (file)
@@ -115,8 +115,7 @@ static void measure_achieved_throughput(struct sock *sk, u32 pkts_acked, s32 rtt
                return;
 
        /* achieved throughput calculations */
-       if (icsk->icsk_ca_state != TCP_CA_Open &&
-           icsk->icsk_ca_state != TCP_CA_Disorder) {
+       if (!((1 << icsk->icsk_ca_state) & (TCPF_CA_Open | TCPF_CA_Disorder))) {
                ca->packetcount = 0;
                ca->lasttime = now;
                return;
index a6961d75c7ea6b744d699602bfbdf547694764fe..2bc8e27a163daafed09a3bf2ee6a145414848d72 100644 (file)
@@ -64,6 +64,7 @@
 #include <linux/mm.h>
 #include <linux/module.h>
 #include <linux/sysctl.h>
+#include <linux/kernel.h>
 #include <net/dst.h>
 #include <net/tcp.h>
 #include <net/inet_common.h>
@@ -1178,10 +1179,18 @@ static void tcp_mark_lost_retrans(struct sock *sk)
                if (!(TCP_SKB_CB(skb)->sacked & TCPCB_SACKED_RETRANS))
                        continue;
 
-               if (after(received_upto, ack_seq) &&
-                   (tcp_is_fack(tp) ||
-                    !before(received_upto,
-                            ack_seq + tp->reordering * tp->mss_cache))) {
+               /* TODO: We would like to get rid of tcp_is_fack(tp) only
+                * constraint here (see above) but figuring out that at
+                * least tp->reordering SACK blocks reside between ack_seq
+                * and received_upto is not easy task to do cheaply with
+                * the available datastructures.
+                *
+                * Whether FACK should check here for tp->reordering segs
+                * in-between one could argue for either way (it would be
+                * rather simple to implement as we could count fack_count
+                * during the walk and do tp->fackets_out - fack_count).
+                */
+               if (after(received_upto, ack_seq)) {
                        TCP_SKB_CB(skb)->sacked &= ~TCPCB_SACKED_RETRANS;
                        tp->retrans_out -= tcp_skb_pcount(skb);
 
@@ -1374,7 +1383,8 @@ static u8 tcp_sacktag_one(struct sk_buff *skb, struct sock *sk,
 
 static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
                           struct tcp_sacktag_state *state,
-                          unsigned int pcount, int shifted, int mss)
+                          unsigned int pcount, int shifted, int mss,
+                          int dup_sack)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *prev = tcp_write_queue_prev(sk, skb);
@@ -1410,7 +1420,7 @@ static int tcp_shifted_skb(struct sock *sk, struct sk_buff *skb,
        }
 
        /* We discard results */
-       tcp_sacktag_one(skb, sk, state, 0, pcount);
+       tcp_sacktag_one(skb, sk, state, dup_sack, pcount);
 
        /* Difference in this won't matter, both ACKed by the same cumul. ACK */
        TCP_SKB_CB(prev)->sacked |= (TCP_SKB_CB(skb)->sacked & TCPCB_EVER_RETRANS);
@@ -1561,7 +1571,7 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,
 
        if (!skb_shift(prev, skb, len))
                goto fallback;
-       if (!tcp_shifted_skb(sk, skb, state, pcount, len, mss))
+       if (!tcp_shifted_skb(sk, skb, state, pcount, len, mss, dup_sack))
                goto out;
 
        /* Hole filled allows collapsing with the next as well, this is very
@@ -1580,7 +1590,7 @@ static struct sk_buff *tcp_shift_skb_data(struct sock *sk, struct sk_buff *skb,
        len = skb->len;
        if (skb_shift(prev, skb, len)) {
                pcount += tcp_skb_pcount(skb);
-               tcp_shifted_skb(sk, skb, state, tcp_skb_pcount(skb), len, mss);
+               tcp_shifted_skb(sk, skb, state, tcp_skb_pcount(skb), len, mss, 0);
        }
 
 out:
@@ -1793,11 +1803,7 @@ tcp_sacktag_write_queue(struct sock *sk, struct sk_buff *ack_skb,
        for (i = used_sacks - 1; i > 0; i--) {
                for (j = 0; j < i; j++) {
                        if (after(sp[j].start_seq, sp[j + 1].start_seq)) {
-                               struct tcp_sack_block tmp;
-
-                               tmp = sp[j];
-                               sp[j] = sp[j + 1];
-                               sp[j + 1] = tmp;
+                               swap(sp[j], sp[j + 1]);
 
                                /* Track where the first SACK block goes to */
                                if (j == first_sack_index)
@@ -2452,6 +2458,44 @@ static int tcp_time_to_recover(struct sock *sk)
        return 0;
 }
 
+/* New heuristics: it is possible only after we switched to restart timer
+ * each time when something is ACKed. Hence, we can detect timed out packets
+ * during fast retransmit without falling to slow start.
+ *
+ * Usefulness of this as is very questionable, since we should know which of
+ * the segments is the next to timeout which is relatively expensive to find
+ * in general case unless we add some data structure just for that. The
+ * current approach certainly won't find the right one too often and when it
+ * finally does find _something_ it usually marks large part of the window
+ * right away (because a retransmission with a larger timestamp blocks the
+ * loop from advancing). -ij
+ */
+static void tcp_timeout_skbs(struct sock *sk)
+{
+       struct tcp_sock *tp = tcp_sk(sk);
+       struct sk_buff *skb;
+
+       if (!tcp_is_fack(tp) || !tcp_head_timedout(sk))
+               return;
+
+       skb = tp->scoreboard_skb_hint;
+       if (tp->scoreboard_skb_hint == NULL)
+               skb = tcp_write_queue_head(sk);
+
+       tcp_for_write_queue_from(skb, sk) {
+               if (skb == tcp_send_head(sk))
+                       break;
+               if (!tcp_skb_timedout(sk, skb))
+                       break;
+
+               tcp_skb_mark_lost(tp, skb);
+       }
+
+       tp->scoreboard_skb_hint = skb;
+
+       tcp_verify_left_out(tp);
+}
+
 /* Mark head of queue up as lost. With RFC3517 SACK, the packets is
  * is against sacked "cnt", otherwise it's against facked "cnt"
  */
@@ -2524,30 +2568,7 @@ static void tcp_update_scoreboard(struct sock *sk, int fast_rexmit)
                tcp_mark_head_lost(sk, sacked_upto);
        }
 
-       /* New heuristics: it is possible only after we switched
-        * to restart timer each time when something is ACKed.
-        * Hence, we can detect timed out packets during fast
-        * retransmit without falling to slow start.
-        */
-       if (tcp_is_fack(tp) && tcp_head_timedout(sk)) {
-               struct sk_buff *skb;
-
-               skb = tp->scoreboard_skb_hint ? tp->scoreboard_skb_hint
-                       : tcp_write_queue_head(sk);
-
-               tcp_for_write_queue_from(skb, sk) {
-                       if (skb == tcp_send_head(sk))
-                               break;
-                       if (!tcp_skb_timedout(sk, skb))
-                               break;
-
-                       tcp_skb_mark_lost(tp, skb);
-               }
-
-               tp->scoreboard_skb_hint = skb;
-
-               tcp_verify_left_out(tp);
-       }
+       tcp_timeout_skbs(sk);
 }
 
 /* CWND moderation, preventing bursts due to too big ACKs
@@ -2812,7 +2833,7 @@ static void tcp_mtup_probe_failed(struct sock *sk)
        icsk->icsk_mtup.probe_size = 0;
 }
 
-static void tcp_mtup_probe_success(struct sock *sk, struct sk_buff *skb)
+static void tcp_mtup_probe_success(struct sock *sk)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct inet_connection_sock *icsk = inet_csk(sk);
@@ -2840,7 +2861,7 @@ void tcp_simple_retransmit(struct sock *sk)
        const struct inet_connection_sock *icsk = inet_csk(sk);
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *skb;
-       unsigned int mss = tcp_current_mss(sk, 0);
+       unsigned int mss = tcp_current_mss(sk);
        u32 prior_lost = tp->lost_out;
 
        tcp_for_write_queue(skb, sk) {
@@ -3177,7 +3198,6 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
 
        while ((skb = tcp_write_queue_head(sk)) && skb != tcp_send_head(sk)) {
                struct tcp_skb_cb *scb = TCP_SKB_CB(skb);
-               u32 end_seq;
                u32 acked_pcount;
                u8 sacked = scb->sacked;
 
@@ -3192,16 +3212,8 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
                                break;
 
                        fully_acked = 0;
-                       end_seq = tp->snd_una;
                } else {
                        acked_pcount = tcp_skb_pcount(skb);
-                       end_seq = scb->end_seq;
-               }
-
-               /* MTU probing checks */
-               if (fully_acked && icsk->icsk_mtup.probe_size &&
-                   !after(tp->mtu_probe.probe_seq_end, scb->end_seq)) {
-                       tcp_mtup_probe_success(sk, skb);
                }
 
                if (sacked & TCPCB_RETRANS) {
@@ -3266,24 +3278,26 @@ static int tcp_clean_rtx_queue(struct sock *sk, int prior_fackets,
                const struct tcp_congestion_ops *ca_ops
                        = inet_csk(sk)->icsk_ca_ops;
 
+               if (unlikely(icsk->icsk_mtup.probe_size &&
+                            !after(tp->mtu_probe.probe_seq_end, tp->snd_una))) {
+                       tcp_mtup_probe_success(sk);
+               }
+
                tcp_ack_update_rtt(sk, flag, seq_rtt);
                tcp_rearm_rto(sk);
 
                if (tcp_is_reno(tp)) {
                        tcp_remove_reno_sacks(sk, pkts_acked);
                } else {
+                       int delta;
+
                        /* Non-retransmitted hole got filled? That's reordering */
                        if (reord < prior_fackets)
                                tcp_update_reordering(sk, tp->fackets_out - reord, 0);
 
-                       /* No need to care for underflows here because
-                        * the lost_skb_hint gets NULLed if we're past it
-                        * (or something non-trivial happened)
-                        */
-                       if (tcp_is_fack(tp))
-                               tp->lost_cnt_hint -= pkts_acked;
-                       else
-                               tp->lost_cnt_hint -= prior_sacked - tp->sacked_out;
+                       delta = tcp_is_fack(tp) ? pkts_acked :
+                                                 prior_sacked - tp->sacked_out;
+                       tp->lost_cnt_hint -= min(tp->lost_cnt_hint, delta);
                }
 
                tp->fackets_out -= min(pkts_acked, tp->fackets_out);
@@ -3395,7 +3409,7 @@ static int tcp_ack_update_window(struct sock *sk, struct sk_buff *skb, u32 ack,
 
        if (tcp_may_update_window(tp, ack, ack_seq, nwin)) {
                flag |= FLAG_WIN_UPDATE;
-               tcp_update_wl(tp, ack, ack_seq);
+               tcp_update_wl(tp, ack_seq);
 
                if (tp->snd_wnd != nwin) {
                        tp->snd_wnd = nwin;
@@ -3571,15 +3585,18 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
        int prior_packets;
        int frto_cwnd = 0;
 
-       /* If the ack is newer than sent or older than previous acks
+       /* If the ack is older than previous acks
         * then we can probably ignore it.
         */
-       if (after(ack, tp->snd_nxt))
-               goto uninteresting_ack;
-
        if (before(ack, prior_snd_una))
                goto old_ack;
 
+       /* If the ack includes data we haven't sent yet, discard
+        * this segment (RFC793 Section 3.9).
+        */
+       if (after(ack, tp->snd_nxt))
+               goto invalid_ack;
+
        if (after(ack, prior_snd_una))
                flag |= FLAG_SND_UNA_ADVANCED;
 
@@ -3600,7 +3617,7 @@ static int tcp_ack(struct sock *sk, struct sk_buff *skb, int flag)
                 * No more checks are required.
                 * Note, we use the fact that SND.UNA>=SND.WL2.
                 */
-               tcp_update_wl(tp, ack, ack_seq);
+               tcp_update_wl(tp, ack_seq);
                tp->snd_una = ack;
                flag |= FLAG_WIN_UPDATE;
 
@@ -3669,6 +3686,10 @@ no_queue:
                tcp_ack_probe(sk);
        return 1;
 
+invalid_ack:
+       SOCK_DEBUG(sk, "Ack %u after %u:%u\n", ack, tp->snd_una, tp->snd_nxt);
+       return -1;
+
 old_ack:
        if (TCP_SKB_CB(skb)->sacked) {
                tcp_sacktag_write_queue(sk, skb, prior_snd_una);
@@ -3676,8 +3697,7 @@ old_ack:
                        tcp_try_keep_open(sk);
        }
 
-uninteresting_ack:
-       SOCK_DEBUG(sk, "Ack %u out of %u:%u\n", ack, tp->snd_una, tp->snd_nxt);
+       SOCK_DEBUG(sk, "Ack %u before %u:%u\n", ack, tp->snd_una, tp->snd_nxt);
        return 0;
 }
 
@@ -3865,8 +3885,7 @@ static inline void tcp_replace_ts_recent(struct tcp_sock *tp, u32 seq)
                 * Not only, also it occurs for expired timestamps.
                 */
 
-               if ((s32)(tp->rx_opt.rcv_tsval - tp->rx_opt.ts_recent) >= 0 ||
-                  get_seconds() >= tp->rx_opt.ts_recent_stamp + TCP_PAWS_24DAYS)
+               if (tcp_paws_check(&tp->rx_opt, 0))
                        tcp_store_ts_recent(tp);
        }
 }
@@ -3918,9 +3937,9 @@ static inline int tcp_paws_discard(const struct sock *sk,
                                   const struct sk_buff *skb)
 {
        const struct tcp_sock *tp = tcp_sk(sk);
-       return ((s32)(tp->rx_opt.ts_recent - tp->rx_opt.rcv_tsval) > TCP_PAWS_WINDOW &&
-               get_seconds() < tp->rx_opt.ts_recent_stamp + TCP_PAWS_24DAYS &&
-               !tcp_disordered_ack(sk, skb));
+
+       return !tcp_paws_check(&tp->rx_opt, TCP_PAWS_WINDOW) &&
+              !tcp_disordered_ack(sk, skb);
 }
 
 /* Check segment sequence number for validity.
@@ -4078,7 +4097,6 @@ static void tcp_dsack_set(struct sock *sk, u32 seq, u32 end_seq)
                tp->rx_opt.dsack = 1;
                tp->duplicate_sack[0].start_seq = seq;
                tp->duplicate_sack[0].end_seq = end_seq;
-               tp->rx_opt.eff_sacks = tp->rx_opt.num_sacks + 1;
        }
 }
 
@@ -4133,8 +4151,6 @@ static void tcp_sack_maybe_coalesce(struct tcp_sock *tp)
                         * Decrease num_sacks.
                         */
                        tp->rx_opt.num_sacks--;
-                       tp->rx_opt.eff_sacks = tp->rx_opt.num_sacks +
-                                              tp->rx_opt.dsack;
                        for (i = this_sack; i < tp->rx_opt.num_sacks; i++)
                                sp[i] = sp[i + 1];
                        continue;
@@ -4143,20 +4159,6 @@ static void tcp_sack_maybe_coalesce(struct tcp_sock *tp)
        }
 }
 
-static inline void tcp_sack_swap(struct tcp_sack_block *sack1,
-                                struct tcp_sack_block *sack2)
-{
-       __u32 tmp;
-
-       tmp = sack1->start_seq;
-       sack1->start_seq = sack2->start_seq;
-       sack2->start_seq = tmp;
-
-       tmp = sack1->end_seq;
-       sack1->end_seq = sack2->end_seq;
-       sack2->end_seq = tmp;
-}
-
 static void tcp_sack_new_ofo_skb(struct sock *sk, u32 seq, u32 end_seq)
 {
        struct tcp_sock *tp = tcp_sk(sk);
@@ -4171,7 +4173,7 @@ static void tcp_sack_new_ofo_skb(struct sock *sk, u32 seq, u32 end_seq)
                if (tcp_sack_extend(sp, seq, end_seq)) {
                        /* Rotate this_sack to the first one. */
                        for (; this_sack > 0; this_sack--, sp--)
-                               tcp_sack_swap(sp, sp - 1);
+                               swap(*sp, *(sp - 1));
                        if (cur_sacks > 1)
                                tcp_sack_maybe_coalesce(tp);
                        return;
@@ -4197,7 +4199,6 @@ new_sack:
        sp->start_seq = seq;
        sp->end_seq = end_seq;
        tp->rx_opt.num_sacks++;
-       tp->rx_opt.eff_sacks = tp->rx_opt.num_sacks + tp->rx_opt.dsack;
 }
 
 /* RCV.NXT advances, some SACKs should be eaten. */
@@ -4211,7 +4212,6 @@ static void tcp_sack_remove(struct tcp_sock *tp)
        /* Empty ofo queue, hence, all the SACKs are eaten. Clear. */
        if (skb_queue_empty(&tp->out_of_order_queue)) {
                tp->rx_opt.num_sacks = 0;
-               tp->rx_opt.eff_sacks = tp->rx_opt.dsack;
                return;
        }
 
@@ -4232,11 +4232,7 @@ static void tcp_sack_remove(struct tcp_sock *tp)
                this_sack++;
                sp++;
        }
-       if (num_sacks != tp->rx_opt.num_sacks) {
-               tp->rx_opt.num_sacks = num_sacks;
-               tp->rx_opt.eff_sacks = tp->rx_opt.num_sacks +
-                                      tp->rx_opt.dsack;
-       }
+       tp->rx_opt.num_sacks = num_sacks;
 }
 
 /* This one checks to see if we can put data from the
@@ -4312,10 +4308,7 @@ static void tcp_data_queue(struct sock *sk, struct sk_buff *skb)
 
        TCP_ECN_accept_cwr(tp, skb);
 
-       if (tp->rx_opt.dsack) {
-               tp->rx_opt.dsack = 0;
-               tp->rx_opt.eff_sacks = tp->rx_opt.num_sacks;
-       }
+       tp->rx_opt.dsack = 0;
 
        /*  Queue data for delivery to the user.
         *  Packets in sequence go to the receive queue.
@@ -4434,8 +4427,6 @@ drop:
                /* Initial out of order segment, build 1 SACK. */
                if (tcp_is_sack(tp)) {
                        tp->rx_opt.num_sacks = 1;
-                       tp->rx_opt.dsack     = 0;
-                       tp->rx_opt.eff_sacks = 1;
                        tp->selective_acks[0].start_seq = TCP_SKB_CB(skb)->seq;
                        tp->selective_acks[0].end_seq =
                                                TCP_SKB_CB(skb)->end_seq;
@@ -5156,7 +5147,8 @@ int tcp_rcv_established(struct sock *sk, struct sk_buff *skb,
         */
 
        if ((tcp_flag_word(th) & TCP_HP_BITS) == tp->pred_flags &&
-           TCP_SKB_CB(skb)->seq == tp->rcv_nxt) {
+           TCP_SKB_CB(skb)->seq == tp->rcv_nxt &&
+           !after(TCP_SKB_CB(skb)->ack_seq, tp->snd_nxt)) {
                int tcp_header_len = tp->tcp_header_len;
 
                /* Timestamp header prediction: tcp_header_len
@@ -5309,8 +5301,8 @@ slow_path:
                return -res;
 
 step5:
-       if (th->ack)
-               tcp_ack(sk, skb, FLAG_SLOWPATH);
+       if (th->ack && tcp_ack(sk, skb, FLAG_SLOWPATH) < 0)
+               goto discard;
 
        tcp_rcv_rtt_measure_ts(sk, skb);
 
@@ -5408,7 +5400,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb,
                 * never scaled.
                 */
                tp->snd_wnd = ntohs(th->window);
-               tcp_init_wl(tp, TCP_SKB_CB(skb)->ack_seq, TCP_SKB_CB(skb)->seq);
+               tcp_init_wl(tp, TCP_SKB_CB(skb)->seq);
 
                if (!tp->rx_opt.wscale_ok) {
                        tp->rx_opt.snd_wscale = tp->rx_opt.rcv_wscale = 0;
@@ -5509,7 +5501,7 @@ discard:
 
        /* PAWS check. */
        if (tp->rx_opt.ts_recent_stamp && tp->rx_opt.saw_tstamp &&
-           tcp_paws_check(&tp->rx_opt, 0))
+           tcp_paws_reject(&tp->rx_opt, 0))
                goto discard_and_undo;
 
        if (th->syn) {
@@ -5647,7 +5639,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
 
        /* step 5: check the ACK field */
        if (th->ack) {
-               int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH);
+               int acceptable = tcp_ack(sk, skb, FLAG_SLOWPATH) > 0;
 
                switch (sk->sk_state) {
                case TCP_SYN_RECV:
@@ -5669,8 +5661,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
                                tp->snd_una = TCP_SKB_CB(skb)->ack_seq;
                                tp->snd_wnd = ntohs(th->window) <<
                                              tp->rx_opt.snd_wscale;
-                               tcp_init_wl(tp, TCP_SKB_CB(skb)->ack_seq,
-                                           TCP_SKB_CB(skb)->seq);
+                               tcp_init_wl(tp, TCP_SKB_CB(skb)->seq);
 
                                /* tcp_ack considers this ACK as duplicate
                                 * and does not calculate rtt.
index f6b962f56ab425f5bb3480e8433c888e7169a861..d0a314879d811981dec4d00afde21aa3582a7116 100644 (file)
@@ -1226,15 +1226,6 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
        if (want_cookie && !tmp_opt.saw_tstamp)
                tcp_clear_options(&tmp_opt);
 
-       if (tmp_opt.saw_tstamp && !tmp_opt.rcv_tsval) {
-               /* Some OSes (unknown ones, but I see them on web server, which
-                * contains information interesting only for windows'
-                * users) do not send their stamp in SYN. It is easy case.
-                * We simply do not advertise TS support.
-                */
-               tmp_opt.saw_tstamp = 0;
-               tmp_opt.tstamp_ok  = 0;
-       }
        tmp_opt.tstamp_ok = tmp_opt.saw_tstamp;
 
        tcp_openreq_init(req, &tmp_opt, skb);
@@ -2443,7 +2434,7 @@ static struct pernet_operations __net_initdata tcp_sk_ops = {
 void __init tcp_v4_init(void)
 {
        inet_hashinfo_init(&tcp_hashinfo);
-       if (register_pernet_device(&tcp_sk_ops))
+       if (register_pernet_subsys(&tcp_sk_ops))
                panic("Failed to create the TCP control socket.\n");
 }
 
index f67effbb102be04ae72b759fa24bef202612f296..43bbba7926ee40be929849921a7c950e27e10e5a 100644 (file)
@@ -107,7 +107,7 @@ tcp_timewait_state_process(struct inet_timewait_sock *tw, struct sk_buff *skb,
                if (tmp_opt.saw_tstamp) {
                        tmp_opt.ts_recent       = tcptw->tw_ts_recent;
                        tmp_opt.ts_recent_stamp = tcptw->tw_ts_recent_stamp;
-                       paws_reject = tcp_paws_check(&tmp_opt, th->rst);
+                       paws_reject = tcp_paws_reject(&tmp_opt, th->rst);
                }
        }
 
@@ -399,7 +399,7 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
 
                tcp_prequeue_init(newtp);
 
-               tcp_init_wl(newtp, treq->snt_isn, treq->rcv_isn);
+               tcp_init_wl(newtp, treq->rcv_isn);
 
                newtp->srtt = 0;
                newtp->mdev = TCP_TIMEOUT_INIT;
@@ -434,9 +434,8 @@ struct sock *tcp_create_openreq_child(struct sock *sk, struct request_sock *req,
                newtp->rx_opt.saw_tstamp = 0;
 
                newtp->rx_opt.dsack = 0;
-               newtp->rx_opt.eff_sacks = 0;
-
                newtp->rx_opt.num_sacks = 0;
+
                newtp->urg_data = 0;
 
                if (sock_flag(newsk, SOCK_KEEPOPEN))
@@ -512,7 +511,7 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
                         * from another data.
                         */
                        tmp_opt.ts_recent_stamp = get_seconds() - ((TCP_TIMEOUT_INIT/HZ)<<req->retrans);
-                       paws_reject = tcp_paws_check(&tmp_opt, th->rst);
+                       paws_reject = tcp_paws_reject(&tmp_opt, th->rst);
                }
        }
 
index dda42f0bd7a3b986d23be16b6f44c87333af0844..c1f259d2d33b71a6e69b24b964f473de55f51724 100644 (file)
@@ -441,10 +441,7 @@ static void tcp_options_write(__be32 *ptr, struct tcp_sock *tp,
                        *ptr++ = htonl(sp[this_sack].end_seq);
                }
 
-               if (tp->rx_opt.dsack) {
-                       tp->rx_opt.dsack = 0;
-                       tp->rx_opt.eff_sacks = tp->rx_opt.num_sacks;
-               }
+               tp->rx_opt.dsack = 0;
        }
 }
 
@@ -550,6 +547,7 @@ static unsigned tcp_established_options(struct sock *sk, struct sk_buff *skb,
        struct tcp_skb_cb *tcb = skb ? TCP_SKB_CB(skb) : NULL;
        struct tcp_sock *tp = tcp_sk(sk);
        unsigned size = 0;
+       unsigned int eff_sacks;
 
 #ifdef CONFIG_TCP_MD5SIG
        *md5 = tp->af_specific->md5_lookup(sk, sk);
@@ -568,10 +566,11 @@ static unsigned tcp_established_options(struct sock *sk, struct sk_buff *skb,
                size += TCPOLEN_TSTAMP_ALIGNED;
        }
 
-       if (unlikely(tp->rx_opt.eff_sacks)) {
+       eff_sacks = tp->rx_opt.num_sacks + tp->rx_opt.dsack;
+       if (unlikely(eff_sacks)) {
                const unsigned remaining = MAX_TCP_OPTION_SPACE - size;
                opts->num_sack_blocks =
-                       min_t(unsigned, tp->rx_opt.eff_sacks,
+                       min_t(unsigned, eff_sacks,
                              (remaining - TCPOLEN_SACK_BASE_ALIGNED) /
                              TCPOLEN_SACK_PERBLOCK);
                size += TCPOLEN_SACK_BASE_ALIGNED +
@@ -663,10 +662,14 @@ static int tcp_transmit_skb(struct sock *sk, struct sk_buff *skb, int clone_it,
        th->urg_ptr             = 0;
 
        /* The urg_mode check is necessary during a below snd_una win probe */
-       if (unlikely(tcp_urg_mode(tp) &&
-                    between(tp->snd_up, tcb->seq + 1, tcb->seq + 0xFFFF))) {
-               th->urg_ptr             = htons(tp->snd_up - tcb->seq);
-               th->urg                 = 1;
+       if (unlikely(tcp_urg_mode(tp) && before(tcb->seq, tp->snd_up))) {
+               if (before(tp->snd_up, tcb->seq + 0x10000)) {
+                       th->urg_ptr = htons(tp->snd_up - tcb->seq);
+                       th->urg = 1;
+               } else if (after(tcb->seq + 0xFFFF, tp->snd_nxt)) {
+                       th->urg_ptr = 0xFFFF;
+                       th->urg = 1;
+               }
        }
 
        tcp_options_write((__be32 *)(th + 1), tp, &opts, &md5_hash_location);
@@ -763,11 +766,10 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len,
        struct sk_buff *buff;
        int nsize, old_factor;
        int nlen;
-       u16 flags;
+       u8 flags;
 
        BUG_ON(len > skb->len);
 
-       tcp_clear_retrans_hints_partial(tp);
        nsize = skb_headlen(skb) - len;
        if (nsize < 0)
                nsize = 0;
@@ -850,6 +852,12 @@ int tcp_fragment(struct sock *sk, struct sk_buff *skb, u32 len,
                        tcp_verify_left_out(tp);
                }
                tcp_adjust_fackets_out(sk, skb, diff);
+
+               if (tp->lost_skb_hint &&
+                   before(TCP_SKB_CB(skb)->seq,
+                          TCP_SKB_CB(tp->lost_skb_hint)->seq) &&
+                   (tcp_is_fack(tp) || TCP_SKB_CB(skb)->sacked))
+                       tp->lost_cnt_hint -= diff;
        }
 
        /* Link BUFF into the send queue. */
@@ -913,7 +921,7 @@ int tcp_trim_head(struct sock *sk, struct sk_buff *skb, u32 len)
         * factor and mss.
         */
        if (tcp_skb_pcount(skb) > 1)
-               tcp_set_skb_tso_segs(sk, skb, tcp_current_mss(sk, 1));
+               tcp_set_skb_tso_segs(sk, skb, tcp_current_mss(sk));
 
        return 0;
 }
@@ -974,15 +982,6 @@ void tcp_mtup_init(struct sock *sk)
        icsk->icsk_mtup.probe_size = 0;
 }
 
-/* Bound MSS / TSO packet size with the half of the window */
-static int tcp_bound_to_half_wnd(struct tcp_sock *tp, int pktsize)
-{
-       if (tp->max_window && pktsize > (tp->max_window >> 1))
-               return max(tp->max_window >> 1, 68U - tp->tcp_header_len);
-       else
-               return pktsize;
-}
-
 /* This function synchronize snd mss to current pmtu/exthdr set.
 
    tp->rx_opt.user_mss is mss set by user by TCP_MAXSEG. It does NOT counts
@@ -1029,22 +1028,17 @@ unsigned int tcp_sync_mss(struct sock *sk, u32 pmtu)
 /* Compute the current effective MSS, taking SACKs and IP options,
  * and even PMTU discovery events into account.
  */
-unsigned int tcp_current_mss(struct sock *sk, int large_allowed)
+unsigned int tcp_current_mss(struct sock *sk)
 {
        struct tcp_sock *tp = tcp_sk(sk);
        struct dst_entry *dst = __sk_dst_get(sk);
        u32 mss_now;
-       u16 xmit_size_goal;
-       int doing_tso = 0;
        unsigned header_len;
        struct tcp_out_options opts;
        struct tcp_md5sig_key *md5;
 
        mss_now = tp->mss_cache;
 
-       if (large_allowed && sk_can_gso(sk))
-               doing_tso = 1;
-
        if (dst) {
                u32 mtu = dst_mtu(dst);
                if (mtu != inet_csk(sk)->icsk_pmtu_cookie)
@@ -1062,19 +1056,6 @@ unsigned int tcp_current_mss(struct sock *sk, int large_allowed)
                mss_now -= delta;
        }
 
-       xmit_size_goal = mss_now;
-
-       if (doing_tso) {
-               xmit_size_goal = ((sk->sk_gso_max_size - 1) -
-                                 inet_csk(sk)->icsk_af_ops->net_header_len -
-                                 inet_csk(sk)->icsk_ext_hdr_len -
-                                 tp->tcp_header_len);
-
-               xmit_size_goal = tcp_bound_to_half_wnd(tp, xmit_size_goal);
-               xmit_size_goal -= (xmit_size_goal % mss_now);
-       }
-       tp->xmit_size_goal = xmit_size_goal;
-
        return mss_now;
 }
 
@@ -1256,7 +1237,7 @@ int tcp_may_send_now(struct sock *sk)
        struct sk_buff *skb = tcp_send_head(sk);
 
        return (skb &&
-               tcp_snd_test(sk, skb, tcp_current_mss(sk, 1),
+               tcp_snd_test(sk, skb, tcp_current_mss(sk),
                             (tcp_skb_is_last(sk, skb) ?
                              tp->nonagle : TCP_NAGLE_PUSH)));
 }
@@ -1273,7 +1254,7 @@ static int tso_fragment(struct sock *sk, struct sk_buff *skb, unsigned int len,
 {
        struct sk_buff *buff;
        int nlen = skb->len - len;
-       u16 flags;
+       u8 flags;
 
        /* All of a TSO frame must be composed of paged data.  */
        if (skb->len != skb->data_len)
@@ -1352,6 +1333,10 @@ static int tcp_tso_should_defer(struct sock *sk, struct sk_buff *skb)
        if (limit >= sk->sk_gso_max_size)
                goto send_now;
 
+       /* Middle in queue won't get any more data, full sendable already? */
+       if ((skb != tcp_write_queue_tail(sk)) && (limit >= skb->len))
+               goto send_now;
+
        if (sysctl_tcp_tso_win_divisor) {
                u32 chunk = min(tp->snd_wnd, tp->snd_cwnd * tp->mss_cache);
 
@@ -1405,11 +1390,11 @@ static int tcp_mtu_probe(struct sock *sk)
            icsk->icsk_mtup.probe_size ||
            inet_csk(sk)->icsk_ca_state != TCP_CA_Open ||
            tp->snd_cwnd < 11 ||
-           tp->rx_opt.eff_sacks)
+           tp->rx_opt.num_sacks || tp->rx_opt.dsack)
                return -1;
 
        /* Very simple search strategy: just double the MSS. */
-       mss_now = tcp_current_mss(sk, 0);
+       mss_now = tcp_current_mss(sk);
        probe_size = 2 * tp->mss_cache;
        size_needed = probe_size + (tp->reordering + 1) * tp->mss_cache;
        if (probe_size > tcp_mtu_to_mss(sk, icsk->icsk_mtup.search_high)) {
@@ -1754,11 +1739,9 @@ static void tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb)
        struct tcp_sock *tp = tcp_sk(sk);
        struct sk_buff *next_skb = tcp_write_queue_next(sk, skb);
        int skb_size, next_skb_size;
-       u16 flags;
 
        skb_size = skb->len;
        next_skb_size = next_skb->len;
-       flags = TCP_SKB_CB(skb)->flags;
 
        BUG_ON(tcp_skb_pcount(skb) != 1 || tcp_skb_pcount(next_skb) != 1);
 
@@ -1778,9 +1761,8 @@ static void tcp_collapse_retrans(struct sock *sk, struct sk_buff *skb)
        /* Update sequence range on original skb. */
        TCP_SKB_CB(skb)->end_seq = TCP_SKB_CB(next_skb)->end_seq;
 
-       /* Merge over control information. */
-       flags |= TCP_SKB_CB(next_skb)->flags; /* This moves PSH/FIN etc. over */
-       TCP_SKB_CB(skb)->flags = flags;
+       /* Merge over control information. This moves PSH/FIN etc. over */
+       TCP_SKB_CB(skb)->flags |= TCP_SKB_CB(next_skb)->flags;
 
        /* All done, get rid of second SKB and account for it so
         * packet counting does not break.
@@ -1894,7 +1876,7 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
        if (inet_csk(sk)->icsk_af_ops->rebuild_header(sk))
                return -EHOSTUNREACH; /* Routing failure or similar. */
 
-       cur_mss = tcp_current_mss(sk, 0);
+       cur_mss = tcp_current_mss(sk);
 
        /* If receiver has shrunk his window, and skb is out of
         * new window, do not retransmit it. The exception is the
@@ -1908,6 +1890,8 @@ int tcp_retransmit_skb(struct sock *sk, struct sk_buff *skb)
        if (skb->len > cur_mss) {
                if (tcp_fragment(sk, skb, cur_mss, cur_mss))
                        return -ENOMEM; /* We'll try again later. */
+       } else {
+               tcp_init_tso_segs(sk, skb, cur_mss);
        }
 
        tcp_retrans_try_collapse(sk, skb, cur_mss);
@@ -2023,7 +2007,6 @@ void tcp_xmit_retransmit_queue(struct sock *sk)
                last_lost = tp->snd_una;
        }
 
-       /* First pass: retransmit lost packets. */
        tcp_for_write_queue_from(skb, sk) {
                __u8 sacked = TCP_SKB_CB(skb)->sacked;
 
@@ -2062,7 +2045,7 @@ begin_fwd:
                        goto begin_fwd;
 
                } else if (!(sacked & TCPCB_LOST)) {
-                       if (hole == NULL && !(sacked & TCPCB_SACKED_RETRANS))
+                       if (hole == NULL && !(sacked & (TCPCB_SACKED_RETRANS|TCPCB_SACKED_ACKED)))
                                hole = skb;
                        continue;
 
@@ -2101,7 +2084,7 @@ void tcp_send_fin(struct sock *sk)
         * unsent frames.  But be careful about outgoing SACKS
         * and IP options.
         */
-       mss_now = tcp_current_mss(sk, 1);
+       mss_now = tcp_current_mss(sk);
 
        if (tcp_send_head(sk) != NULL) {
                TCP_SKB_CB(skb)->flags |= TCPCB_FLAG_FIN;
@@ -2326,7 +2309,7 @@ static void tcp_connect_init(struct sock *sk)
        sk->sk_err = 0;
        sock_reset_flag(sk, SOCK_DONE);
        tp->snd_wnd = 0;
-       tcp_init_wl(tp, tp->write_seq, 0);
+       tcp_init_wl(tp, 0);
        tp->snd_una = tp->write_seq;
        tp->snd_sml = tp->write_seq;
        tp->snd_up = tp->write_seq;
@@ -2513,7 +2496,7 @@ int tcp_write_wakeup(struct sock *sk)
        if ((skb = tcp_send_head(sk)) != NULL &&
            before(TCP_SKB_CB(skb)->seq, tcp_wnd_end(tp))) {
                int err;
-               unsigned int mss = tcp_current_mss(sk, 0);
+               unsigned int mss = tcp_current_mss(sk);
                unsigned int seg_size = tcp_wnd_end(tp) - TCP_SKB_CB(skb)->seq;
 
                if (before(tp->pushed_seq, TCP_SKB_CB(skb)->end_seq))
index 25524d4e372a387a4897c64281c3bd8eefc70b53..59f5b5e7c56684ff2d3bdbdfcf469ae97b633763 100644 (file)
@@ -165,9 +165,10 @@ static int tcpprobe_sprint(char *tbuf, int n)
 static ssize_t tcpprobe_read(struct file *file, char __user *buf,
                             size_t len, loff_t *ppos)
 {
-       int error = 0, cnt = 0;
+       int error = 0;
+       size_t cnt = 0;
 
-       if (!buf || len < 0)
+       if (!buf)
                return -EINVAL;
 
        while (cnt < len) {
index 2747ec7bfb63e885fdc286836f41f5e157f6ded8..a76513779e2be92fdefbfba84091685bcdf3eaf3 100644 (file)
@@ -1,6 +1,6 @@
 /* Tom Kelly's Scalable TCP
  *
- * See htt://www-lce.eng.cam.ac.uk/~ctk21/scalable/
+ * See http://www.deneholme.net/tom/scalable/
  *
  * John Heffner <jheffner@sc.edu>
  */
@@ -24,14 +24,8 @@ static void tcp_scalable_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
 
        if (tp->snd_cwnd <= tp->snd_ssthresh)
                tcp_slow_start(tp);
-       else {
-               tp->snd_cwnd_cnt++;
-               if (tp->snd_cwnd_cnt > min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT)){
-                       if (tp->snd_cwnd < tp->snd_cwnd_clamp)
-                               tp->snd_cwnd++;
-                       tp->snd_cwnd_cnt = 0;
-               }
-       }
+       else
+               tcp_cong_avoid_ai(tp, min(tp->snd_cwnd, TCP_SCALABLE_AI_CNT));
 }
 
 static u32 tcp_scalable_ssthresh(struct sock *sk)
index 0170e914f1b0472efb13b5d26179936faaa66ec0..b144a26359bcf34a4b0606e171f97dc709afdfbb 100644 (file)
@@ -328,19 +328,16 @@ static void tcp_retransmit_timer(struct sock *sk)
        if (icsk->icsk_retransmits == 0) {
                int mib_idx;
 
-               if (icsk->icsk_ca_state == TCP_CA_Disorder ||
-                   icsk->icsk_ca_state == TCP_CA_Recovery) {
-                       if (tcp_is_sack(tp)) {
-                               if (icsk->icsk_ca_state == TCP_CA_Recovery)
-                                       mib_idx = LINUX_MIB_TCPSACKRECOVERYFAIL;
-                               else
-                                       mib_idx = LINUX_MIB_TCPSACKFAILURES;
-                       } else {
-                               if (icsk->icsk_ca_state == TCP_CA_Recovery)
-                                       mib_idx = LINUX_MIB_TCPRENORECOVERYFAIL;
-                               else
-                                       mib_idx = LINUX_MIB_TCPRENOFAILURES;
-                       }
+               if (icsk->icsk_ca_state == TCP_CA_Disorder) {
+                       if (tcp_is_sack(tp))
+                               mib_idx = LINUX_MIB_TCPSACKFAILURES;
+                       else
+                               mib_idx = LINUX_MIB_TCPRENOFAILURES;
+               } else if (icsk->icsk_ca_state == TCP_CA_Recovery) {
+                       if (tcp_is_sack(tp))
+                               mib_idx = LINUX_MIB_TCPSACKRECOVERYFAIL;
+                       else
+                               mib_idx = LINUX_MIB_TCPRENORECOVERYFAIL;
                } else if (icsk->icsk_ca_state == TCP_CA_Loss) {
                        mib_idx = LINUX_MIB_TCPLOSSFAILURES;
                } else {
index d08b2e855c229334fcec88bb765cb26dbb6e34c7..e9bbff746488e6be777d538bf641fa6dd4244274 100644 (file)
@@ -159,12 +159,7 @@ static void tcp_veno_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
                                /* In the "non-congestive state", increase cwnd
                                 *  every rtt.
                                 */
-                               if (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
-                                       if (tp->snd_cwnd < tp->snd_cwnd_clamp)
-                                               tp->snd_cwnd++;
-                                       tp->snd_cwnd_cnt = 0;
-                               } else
-                                       tp->snd_cwnd_cnt++;
+                               tcp_cong_avoid_ai(tp, tp->snd_cwnd);
                        } else {
                                /* In the "congestive state", increase cwnd
                                 * every other rtt.
index 9ec843a9bbb2507a9d96cc088ef6b167747ea603..66b6821b984ed6cde6d0f77bcaeb06baf0d21de7 100644 (file)
@@ -94,14 +94,7 @@ static void tcp_yeah_cong_avoid(struct sock *sk, u32 ack, u32 in_flight)
 
        } else {
                /* Reno */
-
-               if (tp->snd_cwnd_cnt < tp->snd_cwnd)
-                       tp->snd_cwnd_cnt++;
-
-               if (tp->snd_cwnd_cnt >= tp->snd_cwnd) {
-                       tp->snd_cwnd++;
-                       tp->snd_cwnd_cnt = 0;
-               }
+               tcp_cong_avoid_ai(tp, tp->snd_cwnd);
        }
 
        /* The key players are v_vegas.beg_snd_una and v_beg_snd_nxt.
index 4bd178a111d567a81a1219fdcd28ce0e10712b14..05b7abb99f699378674eb107db0f0eedc61bf2e3 100644 (file)
@@ -1184,7 +1184,7 @@ static int __udp4_lib_mcast_deliver(struct net *net, struct sk_buff *skb,
                        sk = sknext;
                } while (sknext);
        } else
-               kfree_skb(skb);
+               consume_skb(skb);
        spin_unlock(&hslot->lock);
        return 0;
 }
index 03e2a1ad71e9605e95ed47f2688412cd9f86b8df..8499da9e76a22a742afcd77621c547d47ee41c26 100644 (file)
@@ -40,6 +40,7 @@
 
 #include <linux/errno.h>
 #include <linux/types.h>
+#include <linux/kernel.h>
 #include <linux/socket.h>
 #include <linux/sockios.h>
 #include <linux/net.h>
@@ -493,15 +494,17 @@ static void addrconf_forward_change(struct net *net, __s32 newf)
        read_unlock(&dev_base_lock);
 }
 
-static void addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
+static int addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
 {
        struct net *net;
 
        net = (struct net *)table->extra2;
        if (p == &net->ipv6.devconf_dflt->forwarding)
-               return;
+               return 0;
+
+       if (!rtnl_trylock())
+               return -ERESTARTSYS;
 
-       rtnl_lock();
        if (p == &net->ipv6.devconf_all->forwarding) {
                __s32 newf = net->ipv6.devconf_all->forwarding;
                net->ipv6.devconf_dflt->forwarding = newf;
@@ -512,6 +515,7 @@ static void addrconf_fixup_forwarding(struct ctl_table *table, int *p, int old)
 
        if (*p)
                rt6_purge_dflt_routers(net);
+       return 1;
 }
 #endif
 
@@ -587,6 +591,7 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
 {
        struct inet6_ifaddr *ifa = NULL;
        struct rt6_info *rt;
+       struct net *net = dev_net(idev->dev);
        int hash;
        int err = 0;
        int addr_type = ipv6_addr_type(addr);
@@ -603,6 +608,11 @@ ipv6_add_addr(struct inet6_dev *idev, const struct in6_addr *addr, int pfxlen,
                goto out2;
        }
 
+       if (idev->cnf.disable_ipv6 || net->ipv6.devconf_all->disable_ipv6) {
+               err = -EACCES;
+               goto out2;
+       }
+
        write_lock(&addrconf_hash_lock);
 
        /* Ignore adding duplicate addresses on an interface */
@@ -1206,16 +1216,12 @@ int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev,
                                        }
                                        break;
                                } else if (minihiscore < miniscore) {
-                                       struct ipv6_saddr_score *tmp;
-
                                        if (hiscore->ifa)
                                                in6_ifa_put(hiscore->ifa);
 
                                        in6_ifa_hold(score->ifa);
 
-                                       tmp = hiscore;
-                                       hiscore = score;
-                                       score = tmp;
+                                       swap(hiscore, score);
 
                                        /* restore our iterator */
                                        score->ifa = hiscore->ifa;
@@ -1430,6 +1436,11 @@ static void addrconf_dad_stop(struct inet6_ifaddr *ifp)
 void addrconf_dad_failure(struct inet6_ifaddr *ifp)
 {
        struct inet6_dev *idev = ifp->idev;
+
+       if (net_ratelimit())
+               printk(KERN_INFO "%s: IPv6 duplicate address detected!\n",
+                       ifp->idev->dev->name);
+
        if (idev->cnf.accept_dad > 1 && !idev->cnf.disable_ipv6) {
                struct in6_addr addr;
 
@@ -1440,11 +1451,12 @@ void addrconf_dad_failure(struct inet6_ifaddr *ifp)
                    ipv6_addr_equal(&ifp->addr, &addr)) {
                        /* DAD failed for link-local based on MAC address */
                        idev->cnf.disable_ipv6 = 1;
+
+                       printk(KERN_INFO "%s: IPv6 being disabled!\n",
+                               ifp->idev->dev->name);
                }
        }
 
-       if (net_ratelimit())
-               printk(KERN_INFO "%s: duplicate address detected!\n", ifp->idev->dev->name);
        addrconf_dad_stop(ifp);
 }
 
@@ -2599,9 +2611,6 @@ static int addrconf_ifdown(struct net_device *dev, int how)
 
        ASSERT_RTNL();
 
-       if ((dev->flags & IFF_LOOPBACK) && how == 1)
-               how = 0;
-
        rt6_ifdown(net, dev);
        neigh_ifdown(&nd_tbl, dev);
 
@@ -2823,11 +2832,6 @@ static void addrconf_dad_timer(unsigned long data)
                read_unlock_bh(&idev->lock);
                goto out;
        }
-       if (idev->cnf.accept_dad > 1 && idev->cnf.disable_ipv6) {
-               read_unlock_bh(&idev->lock);
-               addrconf_dad_failure(ifp);
-               return;
-       }
        spin_lock_bh(&ifp->lock);
        if (ifp->probes == 0) {
                /*
@@ -3638,7 +3642,8 @@ static void inet6_ifa_notify(int event, struct inet6_ifaddr *ifa)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+       rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
@@ -3849,7 +3854,8 @@ void inet6_ifinfo_notify(int event, struct inet6_dev *idev)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+       rtnl_notify(skb, net, 0, RTNLGRP_IPV6_IFADDR, NULL, GFP_ATOMIC);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_IPV6_IFADDR, err);
@@ -3919,7 +3925,8 @@ static void inet6_prefix_notify(int event, struct inet6_dev *idev,
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
+       rtnl_notify(skb, net, 0, RTNLGRP_IPV6_PREFIX, NULL, GFP_ATOMIC);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_IPV6_PREFIX, err);
@@ -3974,7 +3981,7 @@ int addrconf_sysctl_forward(ctl_table *ctl, int write, struct file * filp,
        ret = proc_dointvec(ctl, write, filp, buffer, lenp, ppos);
 
        if (write)
-               addrconf_fixup_forwarding(ctl, valp, val);
+               ret = addrconf_fixup_forwarding(ctl, valp, val);
        return ret;
 }
 
@@ -4010,8 +4017,7 @@ static int addrconf_sysctl_forward_strategy(ctl_table *table,
        }
 
        *valp = new;
-       addrconf_fixup_forwarding(table, valp, val);
-       return 1;
+       return addrconf_fixup_forwarding(table, valp, val);
 }
 
 static struct addrconf_sysctl_table
@@ -4437,25 +4443,6 @@ int unregister_inet6addr_notifier(struct notifier_block *nb)
 
 EXPORT_SYMBOL(unregister_inet6addr_notifier);
 
-static void addrconf_net_exit(struct net *net)
-{
-       struct net_device *dev;
-
-       rtnl_lock();
-       /* clean dev list */
-       for_each_netdev(net, dev) {
-               if (__in6_dev_get(dev) == NULL)
-                       continue;
-               addrconf_ifdown(dev, 1);
-       }
-       addrconf_ifdown(net->loopback_dev, 2);
-       rtnl_unlock();
-}
-
-static struct pernet_operations addrconf_net_ops = {
-       .exit = addrconf_net_exit,
-};
-
 /*
  *     Init / cleanup code
  */
@@ -4497,10 +4484,6 @@ int __init addrconf_init(void)
        if (err)
                goto errlo;
 
-       err = register_pernet_device(&addrconf_net_ops);
-       if (err)
-               return err;
-
        register_netdevice_notifier(&ipv6_dev_notf);
 
        addrconf_verify(0);
@@ -4530,15 +4513,22 @@ errlo:
 void addrconf_cleanup(void)
 {
        struct inet6_ifaddr *ifa;
+       struct net_device *dev;
        int i;
 
        unregister_netdevice_notifier(&ipv6_dev_notf);
-       unregister_pernet_device(&addrconf_net_ops);
-
        unregister_pernet_subsys(&addrconf_ops);
 
        rtnl_lock();
 
+       /* clean dev list */
+       for_each_netdev(&init_net, dev) {
+               if (__in6_dev_get(dev) == NULL)
+                       continue;
+               addrconf_ifdown(dev, 1);
+       }
+       addrconf_ifdown(init_net.loopback_dev, 2);
+
        /*
         *      Check hash table.
         */
@@ -4559,6 +4549,4 @@ void addrconf_cleanup(void)
 
        del_timer(&addr_chk_timer);
        rtnl_unlock();
-
-       unregister_pernet_subsys(&addrconf_net_ops);
 }
index fa2ac7ee662fa3de8bc162ca2a2429b2dcebde28..fbf533cc9dcefdfb5b41f001224192518f855855 100644 (file)
@@ -72,6 +72,10 @@ MODULE_LICENSE("GPL");
 static struct list_head inetsw6[SOCK_MAX];
 static DEFINE_SPINLOCK(inetsw6_lock);
 
+static int disable_ipv6 = 0;
+module_param_named(disable, disable_ipv6, int, 0);
+MODULE_PARM_DESC(disable, "Disable IPv6 such that it is non-functional");
+
 static __inline__ struct ipv6_pinfo *inet6_sk_generic(struct sock *sk)
 {
        const int offset = sk->sk_prot->obj_size - sizeof(struct ipv6_pinfo);
@@ -889,7 +893,7 @@ out_unlock:
        return err;
 }
 
-static struct packet_type ipv6_packet_type = {
+static struct packet_type ipv6_packet_type __read_mostly = {
        .type = cpu_to_be16(ETH_P_IPV6),
        .func = ipv6_rcv,
        .gso_send_check = ipv6_gso_send_check,
@@ -1001,10 +1005,21 @@ static int __init inet6_init(void)
 {
        struct sk_buff *dummy_skb;
        struct list_head *r;
-       int err;
+       int err = 0;
 
        BUILD_BUG_ON(sizeof(struct inet6_skb_parm) > sizeof(dummy_skb->cb));
 
+       /* Register the socket-side information for inet6_create.  */
+       for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r)
+               INIT_LIST_HEAD(r);
+
+       if (disable_ipv6) {
+               printk(KERN_INFO
+                      "IPv6: Loaded, but administratively disabled, "
+                      "reboot required to enable\n");
+               goto out;
+       }
+
        err = proto_register(&tcpv6_prot, 1);
        if (err)
                goto out;
@@ -1022,10 +1037,6 @@ static int __init inet6_init(void)
                goto out_unregister_udplite_proto;
 
 
-       /* Register the socket-side information for inet6_create.  */
-       for(r = &inetsw6[0]; r < &inetsw6[SOCK_MAX]; ++r)
-               INIT_LIST_HEAD(r);
-
        /* We MUST register RAW sockets before we create the ICMP6,
         * IGMP6, or NDISC control sockets.
         */
@@ -1191,6 +1202,9 @@ module_init(inet6_init);
 
 static void __exit inet6_exit(void)
 {
+       if (disable_ipv6)
+               return;
+
        /* First of all disallow new sockets creation. */
        sock_unregister(PF_INET6);
        /* Disallow any further netlink messages */
index 8fe267feb81e2af5e110f97e67916345df0493a1..1bcc3431859ede58e1166a9efaa101461e1cc8e6 100644 (file)
@@ -258,11 +258,11 @@ unique:
 
        if (twp != NULL) {
                *twp = tw;
-               NET_INC_STATS_BH(twsk_net(tw), LINUX_MIB_TIMEWAITRECYCLED);
+               NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED);
        } else if (tw != NULL) {
                /* Silly. Should hash-dance instead... */
                inet_twsk_deschedule(tw, death_row);
-               NET_INC_STATS_BH(twsk_net(tw), LINUX_MIB_TIMEWAITRECYCLED);
+               NET_INC_STATS_BH(net, LINUX_MIB_TIMEWAITRECYCLED);
 
                inet_twsk_put(tw);
        }
index 40f324655e2439cf6ba62dddecda75c9208a6c5c..d31df0f4bc9aa3ce017dc798a2af3be61a7a5c9a 100644 (file)
@@ -218,8 +218,7 @@ static int do_ipv6_setsockopt(struct sock *sk, int level, int optname,
                        if (opt)
                                sock_kfree_s(sk, opt, opt->tot_len);
                        pktopt = xchg(&np->pktoptions, NULL);
-                       if (pktopt)
-                               kfree_skb(pktopt);
+                       kfree_skb(pktopt);
 
                        sk->sk_destruct = inet_sock_destruct;
                        /*
index 3cd83b85e9efd39ddaa12d1541568cdb7d83f490..9f061d1adbc2b3770d987ff0fe239a2ef29417bc 100644 (file)
@@ -1095,11 +1095,7 @@ static void ndisc_ra_useropt(struct sk_buff *ra, struct nd_opt_hdr *opt)
                &ipv6_hdr(ra)->saddr);
        nlmsg_end(skb, nlh);
 
-       err = rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL,
-                         GFP_ATOMIC);
-       if (err < 0)
-               goto errout;
-
+       rtnl_notify(skb, net, 0, RTNLGRP_ND_USEROPT, NULL, GFP_ATOMIC);
        return;
 
 nla_put_failure:
index 165b256a6fa063943e22617853fe8f59cd572f65..41b8a956e1becaa1ef2261d5af1d7397291c764d 100644 (file)
@@ -205,8 +205,9 @@ icmpv6_error(struct net *net, struct sk_buff *skb, unsigned int dataoff,
 
        if (net->ct.sysctl_checksum && hooknum == NF_INET_PRE_ROUTING &&
            nf_ip6_checksum(skb, hooknum, dataoff, IPPROTO_ICMPV6)) {
-               nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL,
-                             "nf_ct_icmpv6: ICMPv6 checksum failed\n");
+               if (LOG_INVALID(net, IPPROTO_ICMPV6))
+                       nf_log_packet(PF_INET6, 0, skb, NULL, NULL, NULL,
+                                     "nf_ct_icmpv6: ICMPv6 checksum failed ");
                return -NF_ACCEPT;
        }
 
index ed4d79a9e4a6263225a83f4874692fbca1911754..058a5e4a60c37e743c6dc001bcf603dc05474c82 100644 (file)
@@ -528,14 +528,14 @@ find_prev_fhdr(struct sk_buff *skb, u8 *prevhdrp, int *prevhoff, int *fhoff)
                if (!ipv6_ext_hdr(nexthdr)) {
                        return -1;
                }
-               if (len < (int)sizeof(struct ipv6_opt_hdr)) {
-                       pr_debug("too short\n");
-                       return -1;
-               }
                if (nexthdr == NEXTHDR_NONE) {
                        pr_debug("next header is none\n");
                        return -1;
                }
+               if (len < (int)sizeof(struct ipv6_opt_hdr)) {
+                       pr_debug("too short\n");
+                       return -1;
+               }
                if (skb_copy_bits(skb, start, &hdr, sizeof(hdr)))
                        BUG();
                if (nexthdr == NEXTHDR_AUTH)
index 3c575118fca51d05d73c35968a0960b1b92a6005..e9ac7a12f5951f58f1c211b7e064c8dfcf43cf53 100644 (file)
@@ -452,6 +452,7 @@ err:
 static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
                          struct net_device *dev)
 {
+       struct net *net = container_of(fq->q.net, struct net, ipv6.frags);
        struct sk_buff *fp, *head = fq->q.fragments;
        int    payload_len;
        unsigned int nhoff;
@@ -551,8 +552,7 @@ static int ip6_frag_reasm(struct frag_queue *fq, struct sk_buff *prev,
                                          head->csum);
 
        rcu_read_lock();
-       IP6_INC_STATS_BH(dev_net(dev),
-                        __in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
+       IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMOKS);
        rcu_read_unlock();
        fq->q.fragments = NULL;
        return 1;
@@ -566,8 +566,7 @@ out_oom:
                printk(KERN_DEBUG "ip6_frag_reasm: no memory for reassembly\n");
 out_fail:
        rcu_read_lock();
-       IP6_INC_STATS_BH(dev_net(dev),
-                        __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
+       IP6_INC_STATS_BH(net, __in6_dev_get(dev), IPSTATS_MIB_REASMFAILS);
        rcu_read_unlock();
        return -1;
 }
index c3d486a3edad17f4a9125829462863850ced9a65..1394ddb6e35c5a570cc34f0be3d6d11b55651cc3 100644 (file)
@@ -2400,8 +2400,9 @@ void inet6_rt_notify(int event, struct rt6_info *rt, struct nl_info *info)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, net, info->pid, RTNLGRP_IPV6_ROUTE,
-                         info->nlh, gfp_any());
+       rtnl_notify(skb, net, info->pid, RTNLGRP_IPV6_ROUTE,
+                   info->nlh, gfp_any());
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(net, RTNLGRP_IPV6_ROUTE, err);
index d3467e563f0232c3bc1f6879e43c6ef99c80c3a4..664ab82e03b2ed1a1191a5111fb01e4014410235 100644 (file)
@@ -188,9 +188,9 @@ static struct ip_tunnel * ipip6_tunnel_locate(struct net *net,
        }
 
        nt = netdev_priv(dev);
-       ipip6_tunnel_init(dev);
 
        nt->parms = *parms;
+       ipip6_tunnel_init(dev);
 
        if (parms->i_flags & SIT_ISATAP)
                dev->priv_flags |= IFF_ISATAP;
@@ -454,7 +454,7 @@ static int ipip6_err(struct sk_buff *skb, u32 info)
        if (t->parms.iph.ttl == 0 && type == ICMP_TIME_EXCEEDED)
                goto out;
 
-       if (jiffies - t->err_time < IPTUNNEL_ERR_TIMEO)
+       if (time_before(jiffies, t->err_time + IPTUNNEL_ERR_TIMEO))
                t->err_count++;
        else
                t->err_count = 1;
@@ -658,7 +658,8 @@ static int ipip6_tunnel_xmit(struct sk_buff *skb, struct net_device *dev)
        }
 
        if (tunnel->err_count > 0) {
-               if (jiffies - tunnel->err_time < IPTUNNEL_ERR_TIMEO) {
+               if (time_before(jiffies,
+                               tunnel->err_time + IPTUNNEL_ERR_TIMEO)) {
                        tunnel->err_count--;
                        dst_link_failure(skb);
                } else
index 00f1269e11e95e3691a388836592ef905433648b..4b5aa1854260642ec15fcb6124607dfba10f21b1 100644 (file)
@@ -533,8 +533,7 @@ static inline void syn_flood_warning(struct sk_buff *skb)
 
 static void tcp_v6_reqsk_destructor(struct request_sock *req)
 {
-       if (inet6_rsk(req)->pktopts)
-               kfree_skb(inet6_rsk(req)->pktopts);
+       kfree_skb(inet6_rsk(req)->pktopts);
 }
 
 #ifdef CONFIG_TCP_MD5SIG
@@ -1611,8 +1610,7 @@ ipv6_pktoptions:
                }
        }
 
-       if (opt_skb)
-               kfree_skb(opt_skb);
+       kfree_skb(opt_skb);
        return 0;
 }
 
index 0e685b05496ee6456e5b2d7ab2d5feddd2b52e07..f417b77fa0e15762715a9498974fbd8f5071401d 100644 (file)
@@ -69,7 +69,7 @@ __xfrm6_sort(void **dst, void **src, int n, int (*cmp)(void *p), int maxclass)
 
        for (i = 0; i < n; i++) {
                dst[count[class[i] - 1]++] = src[i];
-               src[i] = 0;
+               src[i] = NULL;
        }
 
        return 0;
index 43d0ffc6d5655ab2e5b18d77c249e21a2b33e28e..1627050e29fd76b44438c086aa69fcc7c8f93d6b 100644 (file)
@@ -1958,12 +1958,12 @@ static const struct proto_ops SOCKOPS_WRAPPED(ipx_dgram_ops) = {
 
 SOCKOPS_WRAP(ipx_dgram, PF_IPX);
 
-static struct packet_type ipx_8023_packet_type = {
+static struct packet_type ipx_8023_packet_type __read_mostly = {
        .type           = cpu_to_be16(ETH_P_802_3),
        .func           = ipx_rcv,
 };
 
-static struct packet_type ipx_dix_packet_type = {
+static struct packet_type ipx_dix_packet_type __read_mostly = {
        .type           = cpu_to_be16(ETH_P_IPX),
        .func           = ipx_rcv,
 };
@@ -1975,15 +1975,15 @@ static struct notifier_block ipx_dev_notifier = {
 extern struct datalink_proto *make_EII_client(void);
 extern void destroy_EII_client(struct datalink_proto *);
 
-static unsigned char ipx_8022_type = 0xE0;
-static unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };
-static char ipx_EII_err_msg[] __initdata =
+static const unsigned char ipx_8022_type = 0xE0;
+static const unsigned char ipx_snap_id[5] = { 0x0, 0x0, 0x0, 0x81, 0x37 };
+static const char ipx_EII_err_msg[] __initconst =
        KERN_CRIT "IPX: Unable to register with Ethernet II\n";
-static char ipx_8023_err_msg[] __initdata =
+static const char ipx_8023_err_msg[] __initconst =
        KERN_CRIT "IPX: Unable to register with 802.3\n";
-static char ipx_llc_err_msg[] __initdata =
+static const char ipx_llc_err_msg[] __initconst =
        KERN_CRIT "IPX: Unable to register with 802.2\n";
-static char ipx_snap_err_msg[] __initdata =
+static const char ipx_snap_err_msg[] __initconst =
        KERN_CRIT "IPX: Unable to register with SNAP\n";
 
 static int __init ipx_init(void)
index ea319e3ddc18c77a441d1093bc1b9bdac615f931..bf92e147344736bd39a4fce6b3977bc5c8ee1739 100644 (file)
@@ -149,13 +149,14 @@ int irda_device_is_receiving(struct net_device *dev)
 
        IRDA_DEBUG(2, "%s()\n", __func__);
 
-       if (!dev->do_ioctl) {
+       if (!dev->netdev_ops->ndo_do_ioctl) {
                IRDA_ERROR("%s: do_ioctl not impl. by device driver\n",
                           __func__);
                return -1;
        }
 
-       ret = dev->do_ioctl(dev, (struct ifreq *) &req, SIOCGRECEIVING);
+       ret = (dev->netdev_ops->ndo_do_ioctl)(dev, (struct ifreq *) &req,
+                                             SIOCGRECEIVING);
        if (ret < 0)
                return ret;
 
index 05112be99569f3eab7eb785cbbc00c9a0e749ec8..724bcf951b806b4fcf277599ce6de6bccfc09ef4 100644 (file)
@@ -45,6 +45,16 @@ static int  irlan_eth_xmit(struct sk_buff *skb, struct net_device *dev);
 static void irlan_eth_set_multicast_list( struct net_device *dev);
 static struct net_device_stats *irlan_eth_get_stats(struct net_device *dev);
 
+static const struct net_device_ops irlan_eth_netdev_ops = {
+       .ndo_open               = irlan_eth_open,
+       .ndo_stop               = irlan_eth_close,
+       .ndo_start_xmit         = irlan_eth_xmit,
+       .ndo_get_stats          = irlan_eth_get_stats,
+       .ndo_set_multicast_list = irlan_eth_set_multicast_list,
+       .ndo_change_mtu         = eth_change_mtu,
+       .ndo_validate_addr      = eth_validate_addr,
+};
+
 /*
  * Function irlan_eth_setup (dev)
  *
@@ -53,14 +63,11 @@ static struct net_device_stats *irlan_eth_get_stats(struct net_device *dev);
  */
 static void irlan_eth_setup(struct net_device *dev)
 {
-       dev->open               = irlan_eth_open;
-       dev->stop               = irlan_eth_close;
-       dev->hard_start_xmit    = irlan_eth_xmit;
-       dev->get_stats          = irlan_eth_get_stats;
-       dev->set_multicast_list = irlan_eth_set_multicast_list;
+       ether_setup(dev);
+
+       dev->netdev_ops         = &irlan_eth_netdev_ops;
        dev->destructor         = free_netdev;
 
-       ether_setup(dev);
 
        /*
         * Lets do all queueing in IrTTP instead of this device driver.
index 1bb607f2f5c7715222ed3f3f0108fca3391bff80..303a68d92731085226366bbd72579ea4c7d97027 100644 (file)
@@ -55,7 +55,7 @@ EXPORT_SYMBOL(irda_debug);
 /* Packet type handler.
  * Tell the kernel how IrDA packets should be handled.
  */
-static struct packet_type irda_packet_type = {
+static struct packet_type irda_packet_type __read_mostly = {
        .type   = cpu_to_be16(ETH_P_IRDA),
        .func   = irlap_driver_rcv,     /* Packet type handler irlap_frame.c */
 };
index eb8a2a0b6eb71fc10671097563e71c3b7ae97ed9..49e786535dc82aecf96b6eea4179864cdb0cee85 100644 (file)
@@ -1171,8 +1171,7 @@ static void iucv_callback_txdone(struct iucv_path *path,
 
                spin_unlock_irqrestore(&list->lock, flags);
 
-               if (this)
-                       kfree_skb(this);
+               kfree_skb(this);
        }
        BUG_ON(!this);
 
index 7dcbde3ea7d9e7afdbfd382d8775b28b7fd9ea40..643c1be2d02e85c4622d87830db0b90942cdb2e3 100644 (file)
@@ -313,8 +313,7 @@ static int pfkey_broadcast(struct sk_buff *skb, gfp_t allocation,
        if (one_sk != NULL)
                err = pfkey_broadcast_one(skb, &skb2, allocation, one_sk);
 
-       if (skb2)
-               kfree_skb(skb2);
+       kfree_skb(skb2);
        kfree_skb(skb);
        return err;
 }
@@ -3573,8 +3572,7 @@ static int pfkey_sendmsg(struct kiocb *kiocb,
 out:
        if (err && hdr && pfkey_error(hdr, err, sk) == 0)
                err = 0;
-       if (skb)
-               kfree_skb(skb);
+       kfree_skb(skb);
 
        return err ? : len;
 }
index 56fd85ab358e3b9c93bf2ff811acd4a9499491ea..febae702685cf58726918601bc613caba15f3af6 100644 (file)
@@ -1118,11 +1118,11 @@ static const struct proto_ops llc_ui_ops = {
        .sendpage    = sock_no_sendpage,
 };
 
-static char llc_proc_err_msg[] __initdata =
+static const char llc_proc_err_msg[] __initconst =
        KERN_CRIT "LLC: Unable to register the proc_fs entries\n";
-static char llc_sysctl_err_msg[] __initdata =
+static const char llc_sysctl_err_msg[] __initconst =
        KERN_CRIT "LLC: Unable to register the sysctl entries\n";
-static char llc_sock_err_msg[] __initdata =
+static const char llc_sock_err_msg[] __initconst =
        KERN_CRIT "LLC: Unable to register the network family\n";
 
 static int __init llc2_init(void)
index 5c6d89c6d51d2726dd008162181f307c6825e8d3..3477624a4906ec3fc65957a1eb1567f0864153f4 100644 (file)
@@ -332,8 +332,7 @@ int llc_conn_remove_acked_pdus(struct sock *sk, u8 nr, u16 *how_many_unacked)
 
        for (i = 0; i < pdu_pos && i < q_len; i++) {
                skb = skb_dequeue(&llc->pdu_unack_q);
-               if (skb)
-                       kfree_skb(skb);
+               kfree_skb(skb);
                nbr_acked++;
        }
 out:
index a7fe1adc378d68834a70f44739c98f927659d927..ff4c0ab96a69364eaca829618dcf9a66d7c5022e 100644 (file)
@@ -147,12 +147,12 @@ void llc_sap_close(struct llc_sap *sap)
        kfree(sap);
 }
 
-static struct packet_type llc_packet_type = {
+static struct packet_type llc_packet_type __read_mostly = {
        .type = cpu_to_be16(ETH_P_802_2),
        .func = llc_rcv,
 };
 
-static struct packet_type llc_tr_packet_type = {
+static struct packet_type llc_tr_packet_type __read_mostly = {
        .type = cpu_to_be16(ETH_P_TR_802_2),
        .func = llc_rcv,
 };
index 3503a3d21318a79673a2e0c5058850b0df17b5cc..0e3ab88bb7063adac42e90c69d5985c86656ff1a 100644 (file)
@@ -9,6 +9,7 @@ mac80211-y := \
        wpa.o \
        scan.o \
        ht.o agg-tx.o agg-rx.o \
+       ibss.o \
        mlme.o \
        iface.o \
        rate.o \
index 3112bfd441b6e76aecda61ddcb8df94a55446d4a..a95affc94629254ea98a75b5c41966d059acb54d 100644 (file)
@@ -129,7 +129,6 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
                                      u8 dialog_token, u16 status, u16 policy,
                                      u16 buf_size, u16 timeout)
 {
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
@@ -151,8 +150,9 @@ static void ieee80211_send_addba_resp(struct ieee80211_sub_if_data *sdata, u8 *d
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
            sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
-       else
-               memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+       else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
+
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
 
index 1232d9f01ca9203e44f81d75c5b42adac014eb8b..1df116d4d6e786498b8cad51511161a9418045f5 100644 (file)
@@ -49,7 +49,6 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
                                         u16 agg_size, u16 timeout)
 {
        struct ieee80211_local *local = sdata->local;
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
        u16 capab;
@@ -69,8 +68,8 @@ static void ieee80211_send_addba_request(struct ieee80211_sub_if_data *sdata,
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
            sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
-       else
-               memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+       else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
 
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
@@ -132,9 +131,24 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
 
        state = &sta->ampdu_mlme.tid_state_tx[tid];
 
-       if (local->hw.ampdu_queues)
-               ieee80211_stop_queue(&local->hw, sta->tid_to_tx_q[tid]);
+       if (local->hw.ampdu_queues) {
+               if (initiator) {
+                       /*
+                        * Stop the AC queue to avoid issues where we send
+                        * unaggregated frames already before the delba.
+                        */
+                       ieee80211_stop_queue_by_reason(&local->hw,
+                               local->hw.queues + sta->tid_to_tx_q[tid],
+                               IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+               }
 
+               /*
+                * Pretend the driver woke the queue, just in case
+                * it disabled it before the session was stopped.
+                */
+               ieee80211_wake_queue(
+                       &local->hw, local->hw.queues + sta->tid_to_tx_q[tid]);
+       }
        *state = HT_AGG_STATE_REQ_STOP_BA_MSK |
                (initiator << HT_AGG_STATE_INITIATOR_SHIFT);
 
@@ -144,8 +158,6 @@ static int ___ieee80211_stop_tx_ba_session(struct sta_info *sta, u16 tid,
        /* HW shall not deny going back to legacy */
        if (WARN_ON(ret)) {
                *state = HT_AGG_STATE_OPERATIONAL;
-               if (local->hw.ampdu_queues)
-                       ieee80211_wake_queue(&local->hw, sta->tid_to_tx_q[tid]);
        }
 
        return ret;
@@ -189,14 +201,19 @@ static void sta_addba_resp_timer_expired(unsigned long data)
        spin_unlock_bh(&sta->lock);
 }
 
+static inline int ieee80211_ac_from_tid(int tid)
+{
+       return ieee802_1d_to_ac[tid & 7];
+}
+
 int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        struct sta_info *sta;
        struct ieee80211_sub_if_data *sdata;
-       u16 start_seq_num;
        u8 *state;
-       int ret = 0;
+       int i, qn = -1, ret = 0;
+       u16 start_seq_num;
 
        if (WARN_ON(!local->ops->ampdu_action))
                return -EINVAL;
@@ -209,6 +226,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
               ra, tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
 
+       if (hw->ampdu_queues && ieee80211_ac_from_tid(tid) == 0) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+               printk(KERN_DEBUG "rejecting on voice AC\n");
+#endif
+               return -EINVAL;
+       }
+
        rcu_read_lock();
 
        sta = sta_info_get(local, ra);
@@ -217,7 +241,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
                printk(KERN_DEBUG "Could not find the station\n");
 #endif
                ret = -ENOENT;
-               goto exit;
+               goto unlock;
        }
 
        /*
@@ -230,11 +254,13 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
            sta->sdata->vif.type != NL80211_IFTYPE_AP_VLAN &&
            sta->sdata->vif.type != NL80211_IFTYPE_AP) {
                ret = -EINVAL;
-               goto exit;
+               goto unlock;
        }
 
        spin_lock_bh(&sta->lock);
 
+       sdata = sta->sdata;
+
        /* we have tried too many times, receiver does not want A-MPDU */
        if (sta->ampdu_mlme.addba_req_num[tid] > HT_AGG_MAX_RETRIES) {
                ret = -EBUSY;
@@ -252,6 +278,42 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
                goto err_unlock_sta;
        }
 
+       if (hw->ampdu_queues) {
+               spin_lock(&local->queue_stop_reason_lock);
+               /* reserve a new queue for this session */
+               for (i = 0; i < local->hw.ampdu_queues; i++) {
+                       if (local->ampdu_ac_queue[i] < 0) {
+                               qn = i;
+                               local->ampdu_ac_queue[qn] =
+                                       ieee80211_ac_from_tid(tid);
+                               break;
+                       }
+               }
+               spin_unlock(&local->queue_stop_reason_lock);
+
+               if (qn < 0) {
+#ifdef CONFIG_MAC80211_HT_DEBUG
+                       printk(KERN_DEBUG "BA request denied - "
+                              "queue unavailable for tid %d\n", tid);
+#endif /* CONFIG_MAC80211_HT_DEBUG */
+                       ret = -ENOSPC;
+                       goto err_unlock_sta;
+               }
+
+               /*
+                * If we successfully allocate the session, we can't have
+                * anything going on on the queue this TID maps into, so
+                * stop it for now. This is a "virtual" stop using the same
+                * mechanism that drivers will use.
+                *
+                * XXX: queue up frames for this session in the sta_info
+                *      struct instead to avoid hitting all other STAs.
+                */
+               ieee80211_stop_queue_by_reason(
+                       &local->hw, hw->queues + qn,
+                       IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+       }
+
        /* prepare A-MPDU MLME for Tx aggregation */
        sta->ampdu_mlme.tid_tx[tid] =
                        kmalloc(sizeof(struct tid_ampdu_tx), GFP_ATOMIC);
@@ -262,8 +324,9 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
                                        tid);
 #endif
                ret = -ENOMEM;
-               goto err_unlock_sta;
+               goto err_return_queue;
        }
+
        /* Tx timer */
        sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer.function =
                        sta_addba_resp_timer_expired;
@@ -271,49 +334,25 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
                        (unsigned long)&sta->timer_to_tid[tid];
        init_timer(&sta->ampdu_mlme.tid_tx[tid]->addba_resp_timer);
 
-       if (hw->ampdu_queues) {
-               /* create a new queue for this aggregation */
-               ret = ieee80211_ht_agg_queue_add(local, sta, tid);
-
-               /* case no queue is available to aggregation
-                * don't switch to aggregation */
-               if (ret) {
-#ifdef CONFIG_MAC80211_HT_DEBUG
-                       printk(KERN_DEBUG "BA request denied - "
-                              "queue unavailable for tid %d\n", tid);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-                       goto err_unlock_queue;
-               }
-       }
-       sdata = sta->sdata;
-
        /* Ok, the Addba frame hasn't been sent yet, but if the driver calls the
         * call back right away, it must see that the flow has begun */
        *state |= HT_ADDBA_REQUESTED_MSK;
 
-       /* This is slightly racy because the queue isn't stopped */
        start_seq_num = sta->tid_seq[tid];
 
        ret = local->ops->ampdu_action(hw, IEEE80211_AMPDU_TX_START,
                                       &sta->sta, tid, &start_seq_num);
 
        if (ret) {
-               /* No need to requeue the packets in the agg queue, since we
-                * held the tx lock: no packet could be enqueued to the newly
-                * allocated queue */
-               if (hw->ampdu_queues)
-                       ieee80211_ht_agg_queue_remove(local, sta, tid, 0);
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "BA request denied - HW unavailable for"
                                        " tid %d\n", tid);
 #endif /* CONFIG_MAC80211_HT_DEBUG */
                *state = HT_AGG_STATE_IDLE;
-               goto err_unlock_queue;
+               goto err_free;
        }
+       sta->tid_to_tx_q[tid] = qn;
 
-       /* Will put all the packets in the new SW queue */
-       if (hw->ampdu_queues)
-               ieee80211_requeue(local, ieee802_1d_to_ac[tid]);
        spin_unlock_bh(&sta->lock);
 
        /* send an addBA request */
@@ -322,7 +361,6 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
                        sta->ampdu_mlme.dialog_token_allocator;
        sta->ampdu_mlme.tid_tx[tid]->ssn = start_seq_num;
 
-
        ieee80211_send_addba_request(sta->sdata, ra, tid,
                         sta->ampdu_mlme.tid_tx[tid]->dialog_token,
                         sta->ampdu_mlme.tid_tx[tid]->ssn,
@@ -334,15 +372,24 @@ int ieee80211_start_tx_ba_session(struct ieee80211_hw *hw, u8 *ra, u16 tid)
 #ifdef CONFIG_MAC80211_HT_DEBUG
        printk(KERN_DEBUG "activated addBA response timer on tid %d\n", tid);
 #endif
-       goto exit;
+       goto unlock;
 
-err_unlock_queue:
+ err_free:
        kfree(sta->ampdu_mlme.tid_tx[tid]);
        sta->ampdu_mlme.tid_tx[tid] = NULL;
-       ret = -EBUSY;
-err_unlock_sta:
+ err_return_queue:
+       if (qn >= 0) {
+               /* We failed, so start queue again right away. */
+               ieee80211_wake_queue_by_reason(hw, hw->queues + qn,
+                       IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+               /* give queue back to pool */
+               spin_lock(&local->queue_stop_reason_lock);
+               local->ampdu_ac_queue[qn] = -1;
+               spin_unlock(&local->queue_stop_reason_lock);
+       }
+ err_unlock_sta:
        spin_unlock_bh(&sta->lock);
-exit:
+ unlock:
        rcu_read_unlock();
        return ret;
 }
@@ -375,7 +422,7 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
        state = &sta->ampdu_mlme.tid_state_tx[tid];
        spin_lock_bh(&sta->lock);
 
-       if (!(*state & HT_ADDBA_REQUESTED_MSK)) {
+       if (WARN_ON(!(*state & HT_ADDBA_REQUESTED_MSK))) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "addBA was not requested yet, state is %d\n",
                                *state);
@@ -385,7 +432,8 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
                return;
        }
 
-       WARN_ON_ONCE(*state & HT_ADDBA_DRV_READY_MSK);
+       if (WARN_ON(*state & HT_ADDBA_DRV_READY_MSK))
+               goto out;
 
        *state |= HT_ADDBA_DRV_READY_MSK;
 
@@ -393,9 +441,18 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u16 tid)
 #ifdef CONFIG_MAC80211_HT_DEBUG
                printk(KERN_DEBUG "Aggregation is on for tid %d \n", tid);
 #endif
-               if (hw->ampdu_queues)
-                       ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+               if (hw->ampdu_queues) {
+                       /*
+                        * Wake up this queue, we stopped it earlier,
+                        * this will in turn wake the entire AC.
+                        */
+                       ieee80211_wake_queue_by_reason(hw,
+                               hw->queues + sta->tid_to_tx_q[tid],
+                               IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+               }
        }
+
+ out:
        spin_unlock_bh(&sta->lock);
        rcu_read_unlock();
 }
@@ -485,7 +542,6 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
        struct ieee80211_local *local = hw_to_local(hw);
        struct sta_info *sta;
        u8 *state;
-       int agg_queue;
 
        if (tid >= STA_TID_NUM) {
 #ifdef CONFIG_MAC80211_HT_DEBUG
@@ -527,19 +583,19 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_hw *hw, u8 *ra, u8 tid)
                ieee80211_send_delba(sta->sdata, ra, tid,
                        WLAN_BACK_INITIATOR, WLAN_REASON_QSTA_NOT_USE);
 
-       if (hw->ampdu_queues) {
-               agg_queue = sta->tid_to_tx_q[tid];
-               ieee80211_ht_agg_queue_remove(local, sta, tid, 1);
+       spin_lock_bh(&sta->lock);
 
-               /* We just requeued the all the frames that were in the
-                * removed queue, and since we might miss a softirq we do
-                * netif_schedule_queue.  ieee80211_wake_queue is not used
-                * here as this queue is not necessarily stopped
+       if (*state & HT_AGG_STATE_INITIATOR_MSK &&
+           hw->ampdu_queues) {
+               /*
+                * Wake up this queue, we stopped it earlier,
+                * this will in turn wake the entire AC.
                 */
-               netif_schedule_queue(netdev_get_tx_queue(local->mdev,
-                                                        agg_queue));
+               ieee80211_wake_queue_by_reason(hw,
+                       hw->queues + sta->tid_to_tx_q[tid],
+                       IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
        }
-       spin_lock_bh(&sta->lock);
+
        *state = HT_AGG_STATE_IDLE;
        sta->ampdu_mlme.addba_req_num[tid] = 0;
        kfree(sta->ampdu_mlme.tid_tx[tid]);
@@ -613,12 +669,21 @@ void ieee80211_process_addba_resp(struct ieee80211_local *local,
 #endif /* CONFIG_MAC80211_HT_DEBUG */
        if (le16_to_cpu(mgmt->u.action.u.addba_resp.status)
                        == WLAN_STATUS_SUCCESS) {
+               u8 curstate = *state;
+
                *state |= HT_ADDBA_RECEIVED_MSK;
-               sta->ampdu_mlme.addba_req_num[tid] = 0;
 
-               if (*state == HT_AGG_STATE_OPERATIONAL &&
-                   local->hw.ampdu_queues)
-                       ieee80211_wake_queue(hw, sta->tid_to_tx_q[tid]);
+               if (hw->ampdu_queues && *state != curstate &&
+                   *state == HT_AGG_STATE_OPERATIONAL) {
+                       /*
+                        * Wake up this queue, we stopped it earlier,
+                        * this will in turn wake the entire AC.
+                        */
+                       ieee80211_wake_queue_by_reason(hw,
+                               hw->queues + sta->tid_to_tx_q[tid],
+                               IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+               }
+               sta->ampdu_mlme.addba_req_num[tid] = 0;
 
                if (local->ops->ampdu_action) {
                        (void)local->ops->ampdu_action(hw,
index c8d969be440bd805cfdfa66980f5bf826ee0d846..58693e52d458c3d8431ceae4f35ae8bd099a5ab7 100644 (file)
@@ -341,11 +341,15 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
        sinfo->filled = STATION_INFO_INACTIVE_TIME |
                        STATION_INFO_RX_BYTES |
                        STATION_INFO_TX_BYTES |
+                       STATION_INFO_RX_PACKETS |
+                       STATION_INFO_TX_PACKETS |
                        STATION_INFO_TX_BITRATE;
 
        sinfo->inactive_time = jiffies_to_msecs(jiffies - sta->last_rx);
        sinfo->rx_bytes = sta->rx_bytes;
        sinfo->tx_bytes = sta->tx_bytes;
+       sinfo->rx_packets = sta->rx_packets;
+       sinfo->tx_packets = sta->tx_packets;
 
        if (sta->local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
                sinfo->filled |= STATION_INFO_SIGNAL;
@@ -447,7 +451,8 @@ static int ieee80211_config_beacon(struct ieee80211_sub_if_data *sdata,
         * This is a kludge. beacon interval should really be part
         * of the beacon information.
         */
-       if (params->interval) {
+       if (params->interval && (sdata->local->hw.conf.beacon_int !=
+                                params->interval)) {
                sdata->local->hw.conf.beacon_int = params->interval;
                err = ieee80211_hw_config(sdata->local,
                                        IEEE80211_CONF_CHANGE_BEACON_INTERVAL);
@@ -1180,45 +1185,45 @@ static int set_mgmt_extra_ie_sta(struct ieee80211_sub_if_data *sdata,
                                 u8 subtype, u8 *ies, size_t ies_len)
 {
        struct ieee80211_local *local = sdata->local;
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
        switch (subtype) {
        case IEEE80211_STYPE_PROBE_REQ >> 4:
                if (local->ops->hw_scan)
                        break;
-               kfree(ifsta->ie_probereq);
-               ifsta->ie_probereq = ies;
-               ifsta->ie_probereq_len = ies_len;
+               kfree(ifmgd->ie_probereq);
+               ifmgd->ie_probereq = ies;
+               ifmgd->ie_probereq_len = ies_len;
                return 0;
        case IEEE80211_STYPE_PROBE_RESP >> 4:
-               kfree(ifsta->ie_proberesp);
-               ifsta->ie_proberesp = ies;
-               ifsta->ie_proberesp_len = ies_len;
+               kfree(ifmgd->ie_proberesp);
+               ifmgd->ie_proberesp = ies;
+               ifmgd->ie_proberesp_len = ies_len;
                return 0;
        case IEEE80211_STYPE_AUTH >> 4:
-               kfree(ifsta->ie_auth);
-               ifsta->ie_auth = ies;
-               ifsta->ie_auth_len = ies_len;
+               kfree(ifmgd->ie_auth);
+               ifmgd->ie_auth = ies;
+               ifmgd->ie_auth_len = ies_len;
                return 0;
        case IEEE80211_STYPE_ASSOC_REQ >> 4:
-               kfree(ifsta->ie_assocreq);
-               ifsta->ie_assocreq = ies;
-               ifsta->ie_assocreq_len = ies_len;
+               kfree(ifmgd->ie_assocreq);
+               ifmgd->ie_assocreq = ies;
+               ifmgd->ie_assocreq_len = ies_len;
                return 0;
        case IEEE80211_STYPE_REASSOC_REQ >> 4:
-               kfree(ifsta->ie_reassocreq);
-               ifsta->ie_reassocreq = ies;
-               ifsta->ie_reassocreq_len = ies_len;
+               kfree(ifmgd->ie_reassocreq);
+               ifmgd->ie_reassocreq = ies;
+               ifmgd->ie_reassocreq_len = ies_len;
                return 0;
        case IEEE80211_STYPE_DEAUTH >> 4:
-               kfree(ifsta->ie_deauth);
-               ifsta->ie_deauth = ies;
-               ifsta->ie_deauth_len = ies_len;
+               kfree(ifmgd->ie_deauth);
+               ifmgd->ie_deauth = ies;
+               ifmgd->ie_deauth_len = ies_len;
                return 0;
        case IEEE80211_STYPE_DISASSOC >> 4:
-               kfree(ifsta->ie_disassoc);
-               ifsta->ie_disassoc = ies;
-               ifsta->ie_disassoc_len = ies_len;
+               kfree(ifmgd->ie_disassoc);
+               ifmgd->ie_disassoc = ies;
+               ifmgd->ie_disassoc_len = ies_len;
                return 0;
        }
 
@@ -1248,7 +1253,6 @@ static int ieee80211_set_mgmt_extra_ie(struct wiphy *wiphy,
 
        switch (sdata->vif.type) {
        case NL80211_IFTYPE_STATION:
-       case NL80211_IFTYPE_ADHOC:
                ret = set_mgmt_extra_ie_sta(sdata, params->subtype,
                                            ies, ies_len);
                break;
index c54219301724e1198c824294550edf77d7cc6bdb..e3420329f4e6422db7e4b219c2c4d06103f30dbb 100644 (file)
@@ -94,31 +94,31 @@ IEEE80211_IF_FILE(drop_unencrypted, drop_unencrypted, DEC);
 IEEE80211_IF_FILE(force_unicast_rateidx, force_unicast_rateidx, DEC);
 IEEE80211_IF_FILE(max_ratectrl_rateidx, max_ratectrl_rateidx, DEC);
 
-/* STA/IBSS attributes */
-IEEE80211_IF_FILE(state, u.sta.state, DEC);
-IEEE80211_IF_FILE(bssid, u.sta.bssid, MAC);
-IEEE80211_IF_FILE(prev_bssid, u.sta.prev_bssid, MAC);
-IEEE80211_IF_FILE(ssid_len, u.sta.ssid_len, SIZE);
-IEEE80211_IF_FILE(aid, u.sta.aid, DEC);
-IEEE80211_IF_FILE(ap_capab, u.sta.ap_capab, HEX);
-IEEE80211_IF_FILE(capab, u.sta.capab, HEX);
-IEEE80211_IF_FILE(extra_ie_len, u.sta.extra_ie_len, SIZE);
-IEEE80211_IF_FILE(auth_tries, u.sta.auth_tries, DEC);
-IEEE80211_IF_FILE(assoc_tries, u.sta.assoc_tries, DEC);
-IEEE80211_IF_FILE(auth_algs, u.sta.auth_algs, HEX);
-IEEE80211_IF_FILE(auth_alg, u.sta.auth_alg, DEC);
-IEEE80211_IF_FILE(auth_transaction, u.sta.auth_transaction, DEC);
+/* STA attributes */
+IEEE80211_IF_FILE(state, u.mgd.state, DEC);
+IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
+IEEE80211_IF_FILE(prev_bssid, u.mgd.prev_bssid, MAC);
+IEEE80211_IF_FILE(ssid_len, u.mgd.ssid_len, SIZE);
+IEEE80211_IF_FILE(aid, u.mgd.aid, DEC);
+IEEE80211_IF_FILE(ap_capab, u.mgd.ap_capab, HEX);
+IEEE80211_IF_FILE(capab, u.mgd.capab, HEX);
+IEEE80211_IF_FILE(extra_ie_len, u.mgd.extra_ie_len, SIZE);
+IEEE80211_IF_FILE(auth_tries, u.mgd.auth_tries, DEC);
+IEEE80211_IF_FILE(assoc_tries, u.mgd.assoc_tries, DEC);
+IEEE80211_IF_FILE(auth_algs, u.mgd.auth_algs, HEX);
+IEEE80211_IF_FILE(auth_alg, u.mgd.auth_alg, DEC);
+IEEE80211_IF_FILE(auth_transaction, u.mgd.auth_transaction, DEC);
 
 static ssize_t ieee80211_if_fmt_flags(
        const struct ieee80211_sub_if_data *sdata, char *buf, int buflen)
 {
        return scnprintf(buf, buflen, "%s%s%s%s%s%s%s\n",
-                sdata->u.sta.flags & IEEE80211_STA_SSID_SET ? "SSID\n" : "",
-                sdata->u.sta.flags & IEEE80211_STA_BSSID_SET ? "BSSID\n" : "",
-                sdata->u.sta.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "",
-                sdata->u.sta.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "",
-                sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "",
-                sdata->u.sta.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "",
+                sdata->u.mgd.flags & IEEE80211_STA_SSID_SET ? "SSID\n" : "",
+                sdata->u.mgd.flags & IEEE80211_STA_BSSID_SET ? "BSSID\n" : "",
+                sdata->u.mgd.flags & IEEE80211_STA_PREV_BSSID_SET ? "prev BSSID\n" : "",
+                sdata->u.mgd.flags & IEEE80211_STA_AUTHENTICATED ? "AUTH\n" : "",
+                sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED ? "ASSOC\n" : "",
+                sdata->u.mgd.flags & IEEE80211_STA_PROBEREQ_POLL ? "PROBEREQ POLL\n" : "",
                 sdata->vif.bss_conf.use_cts_prot ? "CTS prot\n" : "");
 }
 __IEEE80211_IF_FILE(flags);
@@ -283,9 +283,11 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
 #endif
                break;
        case NL80211_IFTYPE_STATION:
-       case NL80211_IFTYPE_ADHOC:
                add_sta_files(sdata);
                break;
+       case NL80211_IFTYPE_ADHOC:
+               /* XXX */
+               break;
        case NL80211_IFTYPE_AP:
                add_ap_files(sdata);
                break;
@@ -418,9 +420,11 @@ static void del_files(struct ieee80211_sub_if_data *sdata)
 #endif
                break;
        case NL80211_IFTYPE_STATION:
-       case NL80211_IFTYPE_ADHOC:
                del_sta_files(sdata);
                break;
+       case NL80211_IFTYPE_ADHOC:
+               /* XXX */
+               break;
        case NL80211_IFTYPE_AP:
                del_ap_files(sdata);
                break;
index 82ea0b63a386dad2e2ad7151b151b1138edfb843..4e3c72f20de760c5d24fcaa40c004abd237d5607 100644 (file)
@@ -17,6 +17,7 @@
 #include <net/wireless.h>
 #include <net/mac80211.h>
 #include "ieee80211_i.h"
+#include "rate.h"
 
 void ieee80211_ht_cap_ie_to_sta_ht_cap(struct ieee80211_supported_band *sband,
                                       struct ieee80211_ht_cap *ht_cap_ie,
@@ -93,7 +94,9 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_bss_ht_conf ht;
+       struct sta_info *sta;
        u32 changed = 0;
        bool enable_ht = true, ht_changed;
        enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
@@ -136,6 +139,16 @@ u32 ieee80211_enable_ht(struct ieee80211_sub_if_data *sdata,
        if (ht_changed) {
                 /* channel_type change automatically detected */
                ieee80211_hw_config(local, 0);
+
+               rcu_read_lock();
+
+               sta = sta_info_get(local, ifmgd->bssid);
+               if (sta)
+                       rate_control_rate_update(local, sband, sta,
+                                                IEEE80211_RC_HT_CHANGED);
+
+               rcu_read_unlock();
+
         }
 
        /* disable HT */
@@ -169,7 +182,6 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
                          u16 initiator, u16 reason_code)
 {
        struct ieee80211_local *local = sdata->local;
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
        u16 params;
@@ -190,8 +202,9 @@ void ieee80211_send_delba(struct ieee80211_sub_if_data *sdata,
        if (sdata->vif.type == NL80211_IFTYPE_AP ||
            sdata->vif.type == NL80211_IFTYPE_AP_VLAN)
                memcpy(mgmt->bssid, sdata->dev->dev_addr, ETH_ALEN);
-       else
-               memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+       else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               memcpy(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN);
+
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
 
diff --git a/net/mac80211/ibss.c b/net/mac80211/ibss.c
new file mode 100644 (file)
index 0000000..f4becc1
--- /dev/null
@@ -0,0 +1,907 @@
+/*
+ * IBSS mode implementation
+ * Copyright 2003-2008, Jouni Malinen <j@w1.fi>
+ * Copyright 2004, Instant802 Networks, Inc.
+ * Copyright 2005, Devicescape Software, Inc.
+ * Copyright 2006-2007 Jiri Benc <jbenc@suse.cz>
+ * Copyright 2007, Michael Wu <flamingice@sourmilk.net>
+ * Copyright 2009, Johannes Berg <johannes@sipsolutions.net>
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ */
+
+#include <linux/delay.h>
+#include <linux/if_ether.h>
+#include <linux/skbuff.h>
+#include <linux/if_arp.h>
+#include <linux/etherdevice.h>
+#include <linux/rtnetlink.h>
+#include <net/mac80211.h>
+#include <asm/unaligned.h>
+
+#include "ieee80211_i.h"
+#include "rate.h"
+
+#define IEEE80211_SCAN_INTERVAL (2 * HZ)
+#define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ)
+#define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ)
+
+#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
+#define IEEE80211_IBSS_MERGE_DELAY 0x400000
+#define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)
+
+#define IEEE80211_IBSS_MAX_STA_ENTRIES 128
+
+
+static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
+                                       struct ieee80211_mgmt *mgmt,
+                                       size_t len)
+{
+       u16 auth_alg, auth_transaction, status_code;
+
+       if (len < 24 + 6)
+               return;
+
+       auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
+       auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
+       status_code = le16_to_cpu(mgmt->u.auth.status_code);
+
+       /*
+        * IEEE 802.11 standard does not require authentication in IBSS
+        * networks and most implementations do not seem to use it.
+        * However, try to reply to authentication attempts if someone
+        * has actually implemented this.
+        */
+       if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1)
+               ieee80211_send_auth(sdata, 2, WLAN_AUTH_OPEN, NULL, 0,
+                                   sdata->u.ibss.bssid, 0);
+}
+
+static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
+                                    const u8 *bssid, const int beacon_int,
+                                    const int freq,
+                                    const size_t supp_rates_len,
+                                    const u8 *supp_rates,
+                                    const u16 capability, u64 tsf)
+{
+       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+       struct ieee80211_local *local = sdata->local;
+       int res = 0, rates, i, j;
+       struct sk_buff *skb;
+       struct ieee80211_mgmt *mgmt;
+       u8 *pos;
+       struct ieee80211_supported_band *sband;
+       union iwreq_data wrqu;
+
+       if (local->ops->reset_tsf) {
+               /* Reset own TSF to allow time synchronization work. */
+               local->ops->reset_tsf(local_to_hw(local));
+       }
+
+       if ((ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET) &&
+          memcmp(ifibss->bssid, bssid, ETH_ALEN) == 0)
+               return res;
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400);
+       if (!skb) {
+               printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
+                      "response\n", sdata->dev->name);
+               return -ENOMEM;
+       }
+
+       if (!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET)) {
+               /* Remove possible STA entries from other IBSS networks. */
+               sta_info_flush_delayed(sdata);
+       }
+
+       memcpy(ifibss->bssid, bssid, ETH_ALEN);
+       res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
+       if (res)
+               return res;
+
+       local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10;
+
+       sdata->drop_unencrypted = capability &
+               WLAN_CAPABILITY_PRIVACY ? 1 : 0;
+
+       res = ieee80211_set_freq(sdata, freq);
+
+       if (res)
+               return res;
+
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+       /* Build IBSS probe response */
+
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+
+       mgmt = (struct ieee80211_mgmt *)
+               skb_put(skb, 24 + sizeof(mgmt->u.beacon));
+       memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
+       mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                         IEEE80211_STYPE_PROBE_RESP);
+       memset(mgmt->da, 0xff, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->bssid, ifibss->bssid, ETH_ALEN);
+       mgmt->u.beacon.beacon_int =
+               cpu_to_le16(local->hw.conf.beacon_int);
+       mgmt->u.beacon.timestamp = cpu_to_le64(tsf);
+       mgmt->u.beacon.capab_info = cpu_to_le16(capability);
+
+       pos = skb_put(skb, 2 + ifibss->ssid_len);
+       *pos++ = WLAN_EID_SSID;
+       *pos++ = ifibss->ssid_len;
+       memcpy(pos, ifibss->ssid, ifibss->ssid_len);
+
+       rates = supp_rates_len;
+       if (rates > 8)
+               rates = 8;
+       pos = skb_put(skb, 2 + rates);
+       *pos++ = WLAN_EID_SUPP_RATES;
+       *pos++ = rates;
+       memcpy(pos, supp_rates, rates);
+
+       if (sband->band == IEEE80211_BAND_2GHZ) {
+               pos = skb_put(skb, 2 + 1);
+               *pos++ = WLAN_EID_DS_PARAMS;
+               *pos++ = 1;
+               *pos++ = ieee80211_frequency_to_channel(freq);
+       }
+
+       pos = skb_put(skb, 2 + 2);
+       *pos++ = WLAN_EID_IBSS_PARAMS;
+       *pos++ = 2;
+       /* FIX: set ATIM window based on scan results */
+       *pos++ = 0;
+       *pos++ = 0;
+
+       if (supp_rates_len > 8) {
+               rates = supp_rates_len - 8;
+               pos = skb_put(skb, 2 + rates);
+               *pos++ = WLAN_EID_EXT_SUPP_RATES;
+               *pos++ = rates;
+               memcpy(pos, &supp_rates[8], rates);
+       }
+
+       ifibss->probe_resp = skb;
+
+       ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON |
+                                  IEEE80211_IFCC_BEACON_ENABLED);
+
+
+       rates = 0;
+       for (i = 0; i < supp_rates_len; i++) {
+               int bitrate = (supp_rates[i] & 0x7f) * 5;
+               for (j = 0; j < sband->n_bitrates; j++)
+                       if (sband->bitrates[j].bitrate == bitrate)
+                               rates |= BIT(j);
+       }
+
+       ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates);
+
+       ifibss->flags |= IEEE80211_IBSS_PREV_BSSID_SET;
+       ifibss->state = IEEE80211_IBSS_MLME_JOINED;
+       mod_timer(&ifibss->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+
+       memset(&wrqu, 0, sizeof(wrqu));
+       memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
+       wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL);
+
+       return res;
+}
+
+static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
+                                  struct ieee80211_bss *bss)
+{
+       return __ieee80211_sta_join_ibss(sdata,
+                                        bss->cbss.bssid,
+                                        bss->cbss.beacon_interval,
+                                        bss->cbss.channel->center_freq,
+                                        bss->supp_rates_len, bss->supp_rates,
+                                        bss->cbss.capability,
+                                        bss->cbss.tsf);
+}
+
+static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
+                                 struct ieee80211_mgmt *mgmt,
+                                 size_t len,
+                                 struct ieee80211_rx_status *rx_status,
+                                 struct ieee802_11_elems *elems,
+                                 bool beacon)
+{
+       struct ieee80211_local *local = sdata->local;
+       int freq;
+       struct ieee80211_bss *bss;
+       struct sta_info *sta;
+       struct ieee80211_channel *channel;
+       u64 beacon_timestamp, rx_timestamp;
+       u32 supp_rates = 0;
+       enum ieee80211_band band = rx_status->band;
+
+       if (elems->ds_params && elems->ds_params_len == 1)
+               freq = ieee80211_channel_to_frequency(elems->ds_params[0]);
+       else
+               freq = rx_status->freq;
+
+       channel = ieee80211_get_channel(local->hw.wiphy, freq);
+
+       if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
+               return;
+
+       if (sdata->vif.type == NL80211_IFTYPE_ADHOC && elems->supp_rates &&
+           memcmp(mgmt->bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0) {
+               supp_rates = ieee80211_sta_get_rates(local, elems, band);
+
+               rcu_read_lock();
+
+               sta = sta_info_get(local, mgmt->sa);
+               if (sta) {
+                       u32 prev_rates;
+
+                       prev_rates = sta->sta.supp_rates[band];
+                       /* make sure mandatory rates are always added */
+                       sta->sta.supp_rates[band] = supp_rates |
+                               ieee80211_mandatory_rates(local, band);
+
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+                       if (sta->sta.supp_rates[band] != prev_rates)
+                               printk(KERN_DEBUG "%s: updated supp_rates set "
+                                   "for %pM based on beacon info (0x%llx | "
+                                   "0x%llx -> 0x%llx)\n",
+                                   sdata->dev->name,
+                                   sta->sta.addr,
+                                   (unsigned long long) prev_rates,
+                                   (unsigned long long) supp_rates,
+                                   (unsigned long long) sta->sta.supp_rates[band]);
+#endif
+               } else
+                       ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
+
+               rcu_read_unlock();
+       }
+
+       bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
+                                       channel, beacon);
+       if (!bss)
+               return;
+
+       /* was just updated in ieee80211_bss_info_update */
+       beacon_timestamp = bss->cbss.tsf;
+
+       /* check if we need to merge IBSS */
+
+       /* merge only on beacons (???) */
+       if (!beacon)
+               goto put_bss;
+
+       /* we use a fixed BSSID */
+       if (sdata->u.ibss.flags & IEEE80211_IBSS_BSSID_SET)
+               goto put_bss;
+
+       /* not an IBSS */
+       if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS))
+               goto put_bss;
+
+       /* different channel */
+       if (bss->cbss.channel != local->oper_channel)
+               goto put_bss;
+
+       /* different SSID */
+       if (elems->ssid_len != sdata->u.ibss.ssid_len ||
+           memcmp(elems->ssid, sdata->u.ibss.ssid,
+                               sdata->u.ibss.ssid_len))
+               goto put_bss;
+
+       /* same BSSID */
+       if (memcmp(bss->cbss.bssid, sdata->u.ibss.bssid, ETH_ALEN) == 0)
+               goto put_bss;
+
+       if (rx_status->flag & RX_FLAG_TSFT) {
+               /*
+                * For correct IBSS merging we need mactime; since mactime is
+                * defined as the time the first data symbol of the frame hits
+                * the PHY, and the timestamp of the beacon is defined as "the
+                * time that the data symbol containing the first bit of the
+                * timestamp is transmitted to the PHY plus the transmitting
+                * STA's delays through its local PHY from the MAC-PHY
+                * interface to its interface with the WM" (802.11 11.1.2)
+                * - equals the time this bit arrives at the receiver - we have
+                * to take into account the offset between the two.
+                *
+                * E.g. at 1 MBit that means mactime is 192 usec earlier
+                * (=24 bytes * 8 usecs/byte) than the beacon timestamp.
+                */
+               int rate;
+
+               if (rx_status->flag & RX_FLAG_HT)
+                       rate = 65; /* TODO: HT rates */
+               else
+                       rate = local->hw.wiphy->bands[band]->
+                               bitrates[rx_status->rate_idx].bitrate;
+
+               rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
+       } else if (local && local->ops && local->ops->get_tsf)
+               /* second best option: get current TSF */
+               rx_timestamp = local->ops->get_tsf(local_to_hw(local));
+       else
+               /* can't merge without knowing the TSF */
+               rx_timestamp = -1LLU;
+
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+       printk(KERN_DEBUG "RX beacon SA=%pM BSSID="
+              "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
+              mgmt->sa, mgmt->bssid,
+              (unsigned long long)rx_timestamp,
+              (unsigned long long)beacon_timestamp,
+              (unsigned long long)(rx_timestamp - beacon_timestamp),
+              jiffies);
+#endif
+
+       /* give slow hardware some time to do the TSF sync */
+       if (rx_timestamp < IEEE80211_IBSS_MERGE_DELAY)
+               goto put_bss;
+
+       if (beacon_timestamp > rx_timestamp) {
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+               printk(KERN_DEBUG "%s: beacon TSF higher than "
+                      "local TSF - IBSS merge with BSSID %pM\n",
+                      sdata->dev->name, mgmt->bssid);
+#endif
+               ieee80211_sta_join_ibss(sdata, bss);
+               ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
+       }
+
+ put_bss:
+       ieee80211_rx_bss_put(local, bss);
+}
+
+/*
+ * Add a new IBSS station, will also be called by the RX code when,
+ * in IBSS mode, receiving a frame from a yet-unknown station, hence
+ * must be callable in atomic context.
+ */
+struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
+                                       u8 *bssid,u8 *addr, u32 supp_rates)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct sta_info *sta;
+       int band = local->hw.conf.channel->band;
+
+       /* TODO: Could consider removing the least recently used entry and
+        * allow new one to be added. */
+       if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
+               if (net_ratelimit()) {
+                       printk(KERN_DEBUG "%s: No room for a new IBSS STA "
+                              "entry %pM\n", sdata->dev->name, addr);
+               }
+               return NULL;
+       }
+
+       if (compare_ether_addr(bssid, sdata->u.ibss.bssid))
+               return NULL;
+
+#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
+       printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n",
+              wiphy_name(local->hw.wiphy), addr, sdata->dev->name);
+#endif
+
+       sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
+       if (!sta)
+               return NULL;
+
+       set_sta_flags(sta, WLAN_STA_AUTHORIZED);
+
+       /* make sure mandatory rates are always added */
+       sta->sta.supp_rates[band] = supp_rates |
+                       ieee80211_mandatory_rates(local, band);
+
+       rate_control_rate_init(sta);
+
+       if (sta_info_insert(sta))
+               return NULL;
+
+       return sta;
+}
+
+static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_local *local = sdata->local;
+       int active = 0;
+       struct sta_info *sta;
+
+       rcu_read_lock();
+
+       list_for_each_entry_rcu(sta, &local->sta_list, list) {
+               if (sta->sdata == sdata &&
+                   time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
+                              jiffies)) {
+                       active++;
+                       break;
+               }
+       }
+
+       rcu_read_unlock();
+
+       return active;
+}
+
+
+static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+       mod_timer(&ifibss->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
+
+       ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT);
+       if (ieee80211_sta_active_ibss(sdata))
+               return;
+
+       if ((ifibss->flags & IEEE80211_IBSS_BSSID_SET) &&
+           (!(ifibss->flags & IEEE80211_IBSS_AUTO_CHANNEL_SEL)))
+               return;
+
+       printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
+              "IBSS networks with same SSID (merge)\n", sdata->dev->name);
+
+       /* XXX maybe racy? */
+       if (sdata->local->scan_req)
+               return;
+
+       memcpy(sdata->local->int_scan_req.ssids[0].ssid,
+              ifibss->ssid, IEEE80211_MAX_SSID_LEN);
+       sdata->local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len;
+       ieee80211_request_scan(sdata, &sdata->local->int_scan_req);
+}
+
+static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_supported_band *sband;
+       u8 *pos;
+       u8 bssid[ETH_ALEN];
+       u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
+       u16 capability;
+       int i;
+
+       if (ifibss->flags & IEEE80211_IBSS_BSSID_SET) {
+               memcpy(bssid, ifibss->bssid, ETH_ALEN);
+       } else {
+               /* Generate random, not broadcast, locally administered BSSID. Mix in
+                * own MAC address to make sure that devices that do not have proper
+                * random number generator get different BSSID. */
+               get_random_bytes(bssid, ETH_ALEN);
+               for (i = 0; i < ETH_ALEN; i++)
+                       bssid[i] ^= sdata->dev->dev_addr[i];
+               bssid[0] &= ~0x01;
+               bssid[0] |= 0x02;
+       }
+
+       printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n",
+              sdata->dev->name, bssid);
+
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+       if (local->hw.conf.beacon_int == 0)
+               local->hw.conf.beacon_int = 100;
+
+       capability = WLAN_CAPABILITY_IBSS;
+
+       if (sdata->default_key)
+               capability |= WLAN_CAPABILITY_PRIVACY;
+       else
+               sdata->drop_unencrypted = 0;
+
+       pos = supp_rates;
+       for (i = 0; i < sband->n_bitrates; i++) {
+               int rate = sband->bitrates[i].bitrate;
+               *pos++ = (u8) (rate / 5);
+       }
+
+       return __ieee80211_sta_join_ibss(sdata,
+                                        bssid, local->hw.conf.beacon_int,
+                                        local->hw.conf.channel->center_freq,
+                                        sband->n_bitrates, supp_rates,
+                                        capability, 0);
+}
+
+static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_bss *bss;
+       const u8 *bssid = NULL;
+       int active_ibss;
+
+       if (ifibss->ssid_len == 0)
+               return -EINVAL;
+
+       active_ibss = ieee80211_sta_active_ibss(sdata);
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+       printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
+              sdata->dev->name, active_ibss);
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+
+       if (active_ibss)
+               return 0;
+
+       if (ifibss->flags & IEEE80211_IBSS_BSSID_SET)
+               bssid = ifibss->bssid;
+       bss = (void *)cfg80211_get_bss(local->hw.wiphy, NULL, bssid,
+                                      ifibss->ssid, ifibss->ssid_len,
+                                      WLAN_CAPABILITY_IBSS,
+                                      WLAN_CAPABILITY_IBSS);
+
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+       if (bss)
+               printk(KERN_DEBUG "   sta_find_ibss: selected %pM current "
+                      "%pM\n", bss->cbss.bssid, ifibss->bssid);
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+
+       if (bss &&
+           (!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET) ||
+            memcmp(ifibss->bssid, bss->cbss.bssid, ETH_ALEN))) {
+               int ret;
+
+               printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
+                      " based on configured SSID\n",
+                      sdata->dev->name, bss->cbss.bssid);
+
+               ret = ieee80211_sta_join_ibss(sdata, bss);
+               ieee80211_rx_bss_put(local, bss);
+               return ret;
+       } else if (bss)
+               ieee80211_rx_bss_put(local, bss);
+
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+       printk(KERN_DEBUG "   did not try to join ibss\n");
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+
+       /* Selected IBSS not found in current scan results - try to scan */
+       if (ifibss->state == IEEE80211_IBSS_MLME_JOINED &&
+           !ieee80211_sta_active_ibss(sdata)) {
+               mod_timer(&ifibss->timer, jiffies +
+                                         IEEE80211_IBSS_MERGE_INTERVAL);
+       } else if (time_after(jiffies, local->last_scan_completed +
+                                       IEEE80211_SCAN_INTERVAL)) {
+               printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
+                      "join\n", sdata->dev->name);
+
+               /* XXX maybe racy? */
+               if (local->scan_req)
+                       return -EBUSY;
+
+               memcpy(local->int_scan_req.ssids[0].ssid,
+                      ifibss->ssid, IEEE80211_MAX_SSID_LEN);
+               local->int_scan_req.ssids[0].ssid_len = ifibss->ssid_len;
+               return ieee80211_request_scan(sdata, &local->int_scan_req);
+       } else if (ifibss->state != IEEE80211_IBSS_MLME_JOINED) {
+               int interval = IEEE80211_SCAN_INTERVAL;
+
+               if (time_after(jiffies, ifibss->ibss_join_req +
+                              IEEE80211_IBSS_JOIN_TIMEOUT)) {
+                       if (!(local->oper_channel->flags &
+                                               IEEE80211_CHAN_NO_IBSS))
+                               return ieee80211_sta_create_ibss(sdata);
+                       printk(KERN_DEBUG "%s: IBSS not allowed on"
+                              " %d MHz\n", sdata->dev->name,
+                              local->hw.conf.channel->center_freq);
+
+                       /* No IBSS found - decrease scan interval and continue
+                        * scanning. */
+                       interval = IEEE80211_SCAN_INTERVAL_SLOW;
+               }
+
+               ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
+               mod_timer(&ifibss->timer, jiffies + interval);
+               return 0;
+       }
+
+       return 0;
+}
+
+static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
+                                       struct ieee80211_mgmt *mgmt,
+                                       size_t len)
+{
+       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+       struct ieee80211_local *local = sdata->local;
+       int tx_last_beacon;
+       struct sk_buff *skb;
+       struct ieee80211_mgmt *resp;
+       u8 *pos, *end;
+
+       if (ifibss->state != IEEE80211_IBSS_MLME_JOINED ||
+           len < 24 + 2 || !ifibss->probe_resp)
+               return;
+
+       if (local->ops->tx_last_beacon)
+               tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local));
+       else
+               tx_last_beacon = 1;
+
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+       printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM"
+              " (tx_last_beacon=%d)\n",
+              sdata->dev->name, mgmt->sa, mgmt->da,
+              mgmt->bssid, tx_last_beacon);
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+
+       if (!tx_last_beacon)
+               return;
+
+       if (memcmp(mgmt->bssid, ifibss->bssid, ETH_ALEN) != 0 &&
+           memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
+               return;
+
+       end = ((u8 *) mgmt) + len;
+       pos = mgmt->u.probe_req.variable;
+       if (pos[0] != WLAN_EID_SSID ||
+           pos + 2 + pos[1] > end) {
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+               printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
+                      "from %pM\n",
+                      sdata->dev->name, mgmt->sa);
+#endif
+               return;
+       }
+       if (pos[1] != 0 &&
+           (pos[1] != ifibss->ssid_len ||
+            memcmp(pos + 2, ifibss->ssid, ifibss->ssid_len) != 0)) {
+               /* Ignore ProbeReq for foreign SSID */
+               return;
+       }
+
+       /* Reply with ProbeResp */
+       skb = skb_copy(ifibss->probe_resp, GFP_KERNEL);
+       if (!skb)
+               return;
+
+       resp = (struct ieee80211_mgmt *) skb->data;
+       memcpy(resp->da, mgmt->sa, ETH_ALEN);
+#ifdef CONFIG_MAC80211_IBSS_DEBUG
+       printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n",
+              sdata->dev->name, resp->da);
+#endif /* CONFIG_MAC80211_IBSS_DEBUG */
+       ieee80211_tx_skb(sdata, skb, 0);
+}
+
+static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
+                                        struct ieee80211_mgmt *mgmt,
+                                        size_t len,
+                                        struct ieee80211_rx_status *rx_status)
+{
+       size_t baselen;
+       struct ieee802_11_elems elems;
+
+       if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
+               return; /* ignore ProbeResp to foreign address */
+
+       baselen = (u8 *) mgmt->u.probe_resp.variable - (u8 *) mgmt;
+       if (baselen > len)
+               return;
+
+       ieee802_11_parse_elems(mgmt->u.probe_resp.variable, len - baselen,
+                               &elems);
+
+       ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, false);
+}
+
+static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
+                                    struct ieee80211_mgmt *mgmt,
+                                    size_t len,
+                                    struct ieee80211_rx_status *rx_status)
+{
+       size_t baselen;
+       struct ieee802_11_elems elems;
+
+       /* Process beacon from the current BSS */
+       baselen = (u8 *) mgmt->u.beacon.variable - (u8 *) mgmt;
+       if (baselen > len)
+               return;
+
+       ieee802_11_parse_elems(mgmt->u.beacon.variable, len - baselen, &elems);
+
+       ieee80211_rx_bss_info(sdata, mgmt, len, rx_status, &elems, true);
+}
+
+static void ieee80211_ibss_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
+                                         struct sk_buff *skb)
+{
+       struct ieee80211_rx_status *rx_status;
+       struct ieee80211_mgmt *mgmt;
+       u16 fc;
+
+       rx_status = (struct ieee80211_rx_status *) skb->cb;
+       mgmt = (struct ieee80211_mgmt *) skb->data;
+       fc = le16_to_cpu(mgmt->frame_control);
+
+       switch (fc & IEEE80211_FCTL_STYPE) {
+       case IEEE80211_STYPE_PROBE_REQ:
+               ieee80211_rx_mgmt_probe_req(sdata, mgmt, skb->len);
+               break;
+       case IEEE80211_STYPE_PROBE_RESP:
+               ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len,
+                                            rx_status);
+               break;
+       case IEEE80211_STYPE_BEACON:
+               ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
+                                        rx_status);
+               break;
+       case IEEE80211_STYPE_AUTH:
+               ieee80211_rx_mgmt_auth_ibss(sdata, mgmt, skb->len);
+               break;
+       }
+
+       kfree_skb(skb);
+}
+
+static void ieee80211_ibss_work(struct work_struct *work)
+{
+       struct ieee80211_sub_if_data *sdata =
+               container_of(work, struct ieee80211_sub_if_data, u.ibss.work);
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_if_ibss *ifibss;
+       struct sk_buff *skb;
+
+       if (!netif_running(sdata->dev))
+               return;
+
+       if (local->sw_scanning || local->hw_scanning)
+               return;
+
+       if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_ADHOC))
+               return;
+       ifibss = &sdata->u.ibss;
+
+       while ((skb = skb_dequeue(&ifibss->skb_queue)))
+               ieee80211_ibss_rx_queued_mgmt(sdata, skb);
+
+       if (!test_and_clear_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request))
+               return;
+
+       switch (ifibss->state) {
+       case IEEE80211_IBSS_MLME_SEARCH:
+               ieee80211_sta_find_ibss(sdata);
+               break;
+       case IEEE80211_IBSS_MLME_JOINED:
+               ieee80211_sta_merge_ibss(sdata);
+               break;
+       default:
+               WARN_ON(1);
+               break;
+       }
+}
+
+static void ieee80211_ibss_timer(unsigned long data)
+{
+       struct ieee80211_sub_if_data *sdata =
+               (struct ieee80211_sub_if_data *) data;
+       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+       struct ieee80211_local *local = sdata->local;
+
+       set_bit(IEEE80211_IBSS_REQ_RUN, &ifibss->request);
+       queue_work(local->hw.workqueue, &ifibss->work);
+}
+
+void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+       INIT_WORK(&ifibss->work, ieee80211_ibss_work);
+       setup_timer(&ifibss->timer, ieee80211_ibss_timer,
+                   (unsigned long) sdata);
+       skb_queue_head_init(&ifibss->skb_queue);
+
+       ifibss->flags |= IEEE80211_IBSS_AUTO_BSSID_SEL |
+                       IEEE80211_IBSS_AUTO_CHANNEL_SEL;
+}
+
+int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+       ifibss->flags &= ~IEEE80211_IBSS_PREV_BSSID_SET;
+
+       if (ifibss->ssid_len)
+               ifibss->flags |= IEEE80211_IBSS_SSID_SET;
+       else
+               ifibss->flags &= ~IEEE80211_IBSS_SSID_SET;
+
+       ifibss->ibss_join_req = jiffies;
+       ifibss->state = IEEE80211_IBSS_MLME_SEARCH;
+
+       return ieee80211_sta_find_ibss(sdata);
+}
+
+int ieee80211_ibss_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len)
+{
+       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+       if (len > IEEE80211_MAX_SSID_LEN)
+               return -EINVAL;
+
+       if (ifibss->ssid_len != len || memcmp(ifibss->ssid, ssid, len) != 0) {
+               memset(ifibss->ssid, 0, sizeof(ifibss->ssid));
+               memcpy(ifibss->ssid, ssid, len);
+               ifibss->ssid_len = len;
+       }
+
+       return ieee80211_ibss_commit(sdata);
+}
+
+int ieee80211_ibss_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len)
+{
+       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+       memcpy(ssid, ifibss->ssid, ifibss->ssid_len);
+       *len = ifibss->ssid_len;
+
+       return 0;
+}
+
+int ieee80211_ibss_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid)
+{
+       struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
+
+       if (is_valid_ether_addr(bssid)) {
+               memcpy(ifibss->bssid, bssid, ETH_ALEN);
+               ifibss->flags |= IEEE80211_IBSS_BSSID_SET;
+       } else {
+               memset(ifibss->bssid, 0, ETH_ALEN);
+               ifibss->flags &= ~IEEE80211_IBSS_BSSID_SET;
+       }
+
+       if (netif_running(sdata->dev)) {
+               if (ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID)) {
+                       printk(KERN_DEBUG "%s: Failed to config new BSSID to "
+                              "the low-level driver\n", sdata->dev->name);
+               }
+       }
+
+       return ieee80211_ibss_commit(sdata);
+}
+
+/* scan finished notification */
+void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local)
+{
+       struct ieee80211_sub_if_data *sdata = local->scan_sdata;
+       struct ieee80211_if_ibss *ifibss;
+
+       if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+               ifibss = &sdata->u.ibss;
+               if ((!(ifibss->flags & IEEE80211_IBSS_PREV_BSSID_SET)) ||
+                   !ieee80211_sta_active_ibss(sdata))
+                       ieee80211_sta_find_ibss(sdata);
+       }
+}
+
+ieee80211_rx_result
+ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+                      struct ieee80211_rx_status *rx_status)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_mgmt *mgmt;
+       u16 fc;
+
+       if (skb->len < 24)
+               return RX_DROP_MONITOR;
+
+       mgmt = (struct ieee80211_mgmt *) skb->data;
+       fc = le16_to_cpu(mgmt->frame_control);
+
+       switch (fc & IEEE80211_FCTL_STYPE) {
+       case IEEE80211_STYPE_PROBE_RESP:
+       case IEEE80211_STYPE_BEACON:
+               memcpy(skb->cb, rx_status, sizeof(*rx_status));
+       case IEEE80211_STYPE_PROBE_REQ:
+       case IEEE80211_STYPE_AUTH:
+               skb_queue_tail(&sdata->u.ibss.skb_queue, skb);
+               queue_work(local->hw.workqueue, &sdata->u.ibss.work);
+               return RX_QUEUED;
+       }
+
+       return RX_DROP_MONITOR;
+}
index 2cb743ed9f9c715dc830bc5a96357346fdaa5176..fbb91f1aebb2a9775a5093937bfde9091c27c078 100644 (file)
@@ -239,7 +239,7 @@ struct mesh_preq_queue {
        u8 flags;
 };
 
-/* flags used in struct ieee80211_if_sta.flags */
+/* flags used in struct ieee80211_if_managed.flags */
 #define IEEE80211_STA_SSID_SET         BIT(0)
 #define IEEE80211_STA_BSSID_SET                BIT(1)
 #define IEEE80211_STA_PREV_BSSID_SET   BIT(2)
@@ -262,31 +262,30 @@ struct mesh_preq_queue {
 #define IEEE80211_STA_REQ_AUTH 2
 #define IEEE80211_STA_REQ_RUN  3
 
-/* STA/IBSS MLME states */
-enum ieee80211_sta_mlme_state {
-       IEEE80211_STA_MLME_DISABLED,
-       IEEE80211_STA_MLME_DIRECT_PROBE,
-       IEEE80211_STA_MLME_AUTHENTICATE,
-       IEEE80211_STA_MLME_ASSOCIATE,
-       IEEE80211_STA_MLME_ASSOCIATED,
-       IEEE80211_STA_MLME_IBSS_SEARCH,
-       IEEE80211_STA_MLME_IBSS_JOINED,
-};
-
 /* bitfield of allowed auth algs */
 #define IEEE80211_AUTH_ALG_OPEN BIT(0)
 #define IEEE80211_AUTH_ALG_SHARED_KEY BIT(1)
 #define IEEE80211_AUTH_ALG_LEAP BIT(2)
 
-struct ieee80211_if_sta {
+struct ieee80211_if_managed {
        struct timer_list timer;
        struct timer_list chswitch_timer;
        struct work_struct work;
        struct work_struct chswitch_work;
+
        u8 bssid[ETH_ALEN], prev_bssid[ETH_ALEN];
+
        u8 ssid[IEEE80211_MAX_SSID_LEN];
-       enum ieee80211_sta_mlme_state state;
        size_t ssid_len;
+
+       enum {
+               IEEE80211_STA_MLME_DISABLED,
+               IEEE80211_STA_MLME_DIRECT_PROBE,
+               IEEE80211_STA_MLME_AUTHENTICATE,
+               IEEE80211_STA_MLME_ASSOCIATE,
+               IEEE80211_STA_MLME_ASSOCIATED,
+       } state;
+
        u16 aid;
        u16 ap_capab, capab;
        u8 *extra_ie; /* to be added to the end of AssocReq */
@@ -319,10 +318,6 @@ struct ieee80211_if_sta {
                IEEE80211_MFP_REQUIRED
        } mfp; /* management frame protection */
 
-       unsigned long ibss_join_req;
-       struct sk_buff *probe_resp; /* ProbeResp template for IBSS */
-       u32 supp_rates_bits[IEEE80211_NUM_BANDS];
-
        int wmm_last_param_set;
 
        /* Extra IE data for management frames */
@@ -342,6 +337,42 @@ struct ieee80211_if_sta {
        size_t ie_disassoc_len;
 };
 
+enum ieee80211_ibss_flags {
+       IEEE80211_IBSS_AUTO_CHANNEL_SEL         = BIT(0),
+       IEEE80211_IBSS_AUTO_BSSID_SEL           = BIT(1),
+       IEEE80211_IBSS_BSSID_SET                = BIT(2),
+       IEEE80211_IBSS_PREV_BSSID_SET           = BIT(3),
+       IEEE80211_IBSS_SSID_SET                 = BIT(4),
+};
+
+enum ieee80211_ibss_request {
+       IEEE80211_IBSS_REQ_RUN  = 0,
+};
+
+struct ieee80211_if_ibss {
+       struct timer_list timer;
+       struct work_struct work;
+
+       struct sk_buff_head skb_queue;
+
+       u8 ssid[IEEE80211_MAX_SSID_LEN];
+       u8 ssid_len;
+
+       u32 flags;
+
+       u8 bssid[ETH_ALEN];
+
+       unsigned long request;
+
+       unsigned long ibss_join_req;
+       struct sk_buff *probe_resp; /* ProbeResp template for IBSS */
+
+       enum {
+               IEEE80211_IBSS_MLME_SEARCH,
+               IEEE80211_IBSS_MLME_JOINED,
+       } state;
+};
+
 struct ieee80211_if_mesh {
        struct work_struct work;
        struct timer_list housekeeping_timer;
@@ -445,7 +476,8 @@ struct ieee80211_sub_if_data {
                struct ieee80211_if_ap ap;
                struct ieee80211_if_wds wds;
                struct ieee80211_if_vlan vlan;
-               struct ieee80211_if_sta sta;
+               struct ieee80211_if_managed mgd;
+               struct ieee80211_if_ibss ibss;
 #ifdef CONFIG_MAC80211_MESH
                struct ieee80211_if_mesh mesh;
 #endif
@@ -564,12 +596,10 @@ enum {
 enum queue_stop_reason {
        IEEE80211_QUEUE_STOP_REASON_DRIVER,
        IEEE80211_QUEUE_STOP_REASON_PS,
-       IEEE80211_QUEUE_STOP_REASON_CSA
+       IEEE80211_QUEUE_STOP_REASON_CSA,
+       IEEE80211_QUEUE_STOP_REASON_AGGREGATION,
 };
 
-/* maximum number of hardware queues we support. */
-#define QD_MAX_QUEUES (IEEE80211_MAX_AMPDU_QUEUES + IEEE80211_MAX_QUEUES)
-
 struct ieee80211_master_priv {
        struct ieee80211_local *local;
 };
@@ -582,9 +612,15 @@ struct ieee80211_local {
 
        const struct ieee80211_ops *ops;
 
-       unsigned long queue_pool[BITS_TO_LONGS(QD_MAX_QUEUES)];
-       unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES];
+       /* AC queue corresponding to each AMPDU queue */
+       s8 ampdu_ac_queue[IEEE80211_MAX_AMPDU_QUEUES];
+       unsigned int amdpu_ac_stop_refcnt[IEEE80211_MAX_AMPDU_QUEUES];
+
+       unsigned long queue_stop_reasons[IEEE80211_MAX_QUEUES +
+                                        IEEE80211_MAX_AMPDU_QUEUES];
+       /* also used to protect ampdu_ac_queue and amdpu_ac_stop_refcnt */
        spinlock_t queue_stop_reason_lock;
+
        struct net_device *mdev; /* wmaster# - "master" 802.11 device */
        int open_count;
        int monitors, cooked_mntrs;
@@ -888,34 +924,41 @@ void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx);
 void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
                                      u32 changed);
 void ieee80211_configure_filter(struct ieee80211_local *local);
+u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata);
 
 /* wireless extensions */
 extern const struct iw_handler_def ieee80211_iw_handler_def;
 
-/* STA/IBSS code */
+/* STA code */
 void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata);
-void ieee80211_scan_work(struct work_struct *work);
-void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
-                          struct ieee80211_rx_status *rx_status);
+ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
+                                         struct sk_buff *skb,
+                                         struct ieee80211_rx_status *rx_status);
+int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata);
 int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len);
 int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len);
 int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid);
-void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata,
-                           struct ieee80211_if_sta *ifsta);
-struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
-                                       u8 *bssid, u8 *addr, u32 supp_rates);
+void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata);
 int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason);
 int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason);
-u32 ieee80211_reset_erp_info(struct ieee80211_sub_if_data *sdata);
-u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
-                           struct ieee802_11_elems *elems,
-                           enum ieee80211_band band);
-void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
-                             u8 *ssid, size_t ssid_len);
 void ieee80211_send_pspoll(struct ieee80211_local *local,
                           struct ieee80211_sub_if_data *sdata);
 
+/* IBSS code */
+int ieee80211_ibss_commit(struct ieee80211_sub_if_data *sdata);
+int ieee80211_ibss_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len);
+int ieee80211_ibss_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len);
+int ieee80211_ibss_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid);
+void ieee80211_ibss_notify_scan_completed(struct ieee80211_local *local);
+void ieee80211_ibss_setup_sdata(struct ieee80211_sub_if_data *sdata);
+ieee80211_rx_result
+ieee80211_ibss_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
+                      struct ieee80211_rx_status *rx_status);
+struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
+                                       u8 *bssid, u8 *addr, u32 supp_rates);
+
 /* scan/BSS handling */
+void ieee80211_scan_work(struct work_struct *work);
 int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
                           struct cfg80211_scan_request *req);
 int ieee80211_scan_results(struct ieee80211_local *local,
@@ -929,6 +972,7 @@ int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata,
                               char *ie, size_t len);
 
 void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local);
+void ieee80211_scan_failed(struct ieee80211_local *local);
 int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
                         struct cfg80211_scan_request *req);
 struct ieee80211_bss *
@@ -1042,6 +1086,25 @@ void ieee80211_wake_queues_by_reason(struct ieee80211_hw *hw,
                                     enum queue_stop_reason reason);
 void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
                                     enum queue_stop_reason reason);
+void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
+                                   enum queue_stop_reason reason);
+void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
+                                   enum queue_stop_reason reason);
+
+void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
+                        u16 transaction, u16 auth_alg,
+                        u8 *extra, size_t extra_len,
+                        const u8 *bssid, int encrypt);
+void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
+                             u8 *ssid, size_t ssid_len,
+                             u8 *ie, size_t ie_len);
+
+void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
+                                 const size_t supp_rates_len,
+                                 const u8 *supp_rates);
+u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
+                           struct ieee802_11_elems *elems,
+                           enum ieee80211_band band);
 
 #ifdef CONFIG_MAC80211_NOINLINE
 #define debug_noinline noinline
index df94b936526472a5f334559b9c7c7300698fbe4d..f9f27b9cadbe0e8ea79a2a18648395de1d622dd8 100644 (file)
@@ -236,7 +236,10 @@ static int ieee80211_open(struct net_device *dev)
                break;
        case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_ADHOC:
-               sdata->u.sta.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
+               if (sdata->vif.type == NL80211_IFTYPE_STATION)
+                       sdata->u.mgd.flags &= ~IEEE80211_STA_PREV_BSSID_SET;
+               else
+                       sdata->u.ibss.flags &= ~IEEE80211_IBSS_PREV_BSSID_SET;
                /* fall through */
        default:
                conf.vif = &sdata->vif;
@@ -321,11 +324,10 @@ static int ieee80211_open(struct net_device *dev)
         * yet be effective. Trigger execution of ieee80211_sta_work
         * to fix this.
         */
-       if (sdata->vif.type == NL80211_IFTYPE_STATION ||
-           sdata->vif.type == NL80211_IFTYPE_ADHOC) {
-               struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-               queue_work(local->hw.workqueue, &ifsta->work);
-       }
+       if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               queue_work(local->hw.workqueue, &sdata->u.mgd.work);
+       else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+               queue_work(local->hw.workqueue, &sdata->u.ibss.work);
 
        netif_tx_start_all_queues(dev);
 
@@ -367,6 +369,18 @@ static int ieee80211_stop(struct net_device *dev)
 
        rcu_read_unlock();
 
+       /*
+        * Announce that we are leaving the network, in case we are a
+        * station interface type. This must be done before removing
+        * all stations associated with sta_info_flush, otherwise STA
+        * information will be gone and no announce being done.
+        */
+       if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+               if (sdata->u.mgd.state != IEEE80211_STA_MLME_DISABLED)
+                       ieee80211_sta_deauthenticate(sdata,
+                               WLAN_REASON_DEAUTH_LEAVING);
+       }
+
        /*
         * Remove all stations associated with this interface.
         *
@@ -452,15 +466,9 @@ static int ieee80211_stop(struct net_device *dev)
                netif_addr_unlock_bh(local->mdev);
                break;
        case NL80211_IFTYPE_STATION:
-       case NL80211_IFTYPE_ADHOC:
-               /* Announce that we are leaving the network. */
-               if (sdata->u.sta.state != IEEE80211_STA_MLME_DISABLED)
-                       ieee80211_sta_deauthenticate(sdata,
-                                               WLAN_REASON_DEAUTH_LEAVING);
-
-               memset(sdata->u.sta.bssid, 0, ETH_ALEN);
-               del_timer_sync(&sdata->u.sta.chswitch_timer);
-               del_timer_sync(&sdata->u.sta.timer);
+               memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
+               del_timer_sync(&sdata->u.mgd.chswitch_timer);
+               del_timer_sync(&sdata->u.mgd.timer);
                /*
                 * If the timer fired while we waited for it, it will have
                 * requeued the work. Now the work will be running again
@@ -468,8 +476,8 @@ static int ieee80211_stop(struct net_device *dev)
                 * whether the interface is running, which, at this point,
                 * it no longer is.
                 */
-               cancel_work_sync(&sdata->u.sta.work);
-               cancel_work_sync(&sdata->u.sta.chswitch_work);
+               cancel_work_sync(&sdata->u.mgd.work);
+               cancel_work_sync(&sdata->u.mgd.chswitch_work);
                /*
                 * When we get here, the interface is marked down.
                 * Call synchronize_rcu() to wait for the RX path
@@ -477,13 +485,22 @@ static int ieee80211_stop(struct net_device *dev)
                 * frames at this very time on another CPU.
                 */
                synchronize_rcu();
-               skb_queue_purge(&sdata->u.sta.skb_queue);
+               skb_queue_purge(&sdata->u.mgd.skb_queue);
 
-               sdata->u.sta.flags &= ~(IEEE80211_STA_PRIVACY_INVOKED |
+               sdata->u.mgd.flags &= ~(IEEE80211_STA_PRIVACY_INVOKED |
                                        IEEE80211_STA_TKIP_WEP_USED);
-               kfree(sdata->u.sta.extra_ie);
-               sdata->u.sta.extra_ie = NULL;
-               sdata->u.sta.extra_ie_len = 0;
+               kfree(sdata->u.mgd.extra_ie);
+               sdata->u.mgd.extra_ie = NULL;
+               sdata->u.mgd.extra_ie_len = 0;
+               /* fall through */
+       case NL80211_IFTYPE_ADHOC:
+               if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+                       memset(sdata->u.ibss.bssid, 0, ETH_ALEN);
+                       del_timer_sync(&sdata->u.ibss.timer);
+                       cancel_work_sync(&sdata->u.ibss.work);
+                       synchronize_rcu();
+                       skb_queue_purge(&sdata->u.ibss.skb_queue);
+               }
                /* fall through */
        case NL80211_IFTYPE_MESH_POINT:
                if (ieee80211_vif_is_mesh(&sdata->vif)) {
@@ -629,19 +646,20 @@ static void ieee80211_teardown_sdata(struct net_device *dev)
                if (ieee80211_vif_is_mesh(&sdata->vif))
                        mesh_rmc_free(sdata);
                break;
-       case NL80211_IFTYPE_STATION:
        case NL80211_IFTYPE_ADHOC:
-               kfree(sdata->u.sta.extra_ie);
-               kfree(sdata->u.sta.assocreq_ies);
-               kfree(sdata->u.sta.assocresp_ies);
-               kfree_skb(sdata->u.sta.probe_resp);
-               kfree(sdata->u.sta.ie_probereq);
-               kfree(sdata->u.sta.ie_proberesp);
-               kfree(sdata->u.sta.ie_auth);
-               kfree(sdata->u.sta.ie_assocreq);
-               kfree(sdata->u.sta.ie_reassocreq);
-               kfree(sdata->u.sta.ie_deauth);
-               kfree(sdata->u.sta.ie_disassoc);
+               kfree_skb(sdata->u.ibss.probe_resp);
+               break;
+       case NL80211_IFTYPE_STATION:
+               kfree(sdata->u.mgd.extra_ie);
+               kfree(sdata->u.mgd.assocreq_ies);
+               kfree(sdata->u.mgd.assocresp_ies);
+               kfree(sdata->u.mgd.ie_probereq);
+               kfree(sdata->u.mgd.ie_proberesp);
+               kfree(sdata->u.mgd.ie_auth);
+               kfree(sdata->u.mgd.ie_assocreq);
+               kfree(sdata->u.mgd.ie_reassocreq);
+               kfree(sdata->u.mgd.ie_deauth);
+               kfree(sdata->u.mgd.ie_disassoc);
                break;
        case NL80211_IFTYPE_WDS:
        case NL80211_IFTYPE_AP_VLAN:
@@ -708,9 +726,11 @@ static void ieee80211_setup_sdata(struct ieee80211_sub_if_data *sdata,
                INIT_LIST_HEAD(&sdata->u.ap.vlans);
                break;
        case NL80211_IFTYPE_STATION:
-       case NL80211_IFTYPE_ADHOC:
                ieee80211_sta_setup_sdata(sdata);
                break;
+       case NL80211_IFTYPE_ADHOC:
+               ieee80211_ibss_setup_sdata(sdata);
+               break;
        case NL80211_IFTYPE_MESH_POINT:
                if (ieee80211_vif_is_mesh(&sdata->vif))
                        ieee80211_mesh_init_sdata(sdata);
@@ -798,6 +818,7 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 
        memcpy(ndev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
        SET_NETDEV_DEV(ndev, wiphy_dev(local->hw.wiphy));
+       ndev->features |= NETIF_F_NETNS_LOCAL;
 
        /* don't use IEEE80211_DEV_TO_SUB_IF because it checks too much */
        sdata = netdev_priv(ndev);
index 19b480de4bbcbfa498f1d520ca9db8f798d26cce..687acf23054d9ecfefeaa810d360020e360a3a83 100644 (file)
@@ -400,7 +400,7 @@ void ieee80211_key_link(struct ieee80211_key *key,
                         */
 
                        /* same here, the AP could be using QoS */
-                       ap = sta_info_get(key->local, key->sdata->u.sta.bssid);
+                       ap = sta_info_get(key->local, key->sdata->u.mgd.bssid);
                        if (ap) {
                                if (test_sta_flags(ap, WLAN_STA_WME))
                                        key->conf.flags |=
index 5667f4e8067fdd4f885a507fa15a5085003f1dcd..f38db4d37e5d6bd93c93ceff48652ce78f6bb0bf 100644 (file)
@@ -169,9 +169,10 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
 
        memset(&conf, 0, sizeof(conf));
 
-       if (sdata->vif.type == NL80211_IFTYPE_STATION ||
-           sdata->vif.type == NL80211_IFTYPE_ADHOC)
-               conf.bssid = sdata->u.sta.bssid;
+       if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               conf.bssid = sdata->u.mgd.bssid;
+       else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+               conf.bssid = sdata->u.ibss.bssid;
        else if (sdata->vif.type == NL80211_IFTYPE_AP)
                conf.bssid = sdata->dev->dev_addr;
        else if (ieee80211_vif_is_mesh(&sdata->vif)) {
@@ -210,7 +211,7 @@ int ieee80211_if_config(struct ieee80211_sub_if_data *sdata, u32 changed)
                                        !!rcu_dereference(sdata->u.ap.beacon);
                                break;
                        case NL80211_IFTYPE_ADHOC:
-                               conf.enable_beacon = !!sdata->u.sta.probe_resp;
+                               conf.enable_beacon = !!sdata->u.ibss.probe_resp;
                                break;
                        case NL80211_IFTYPE_MESH_POINT:
                                conf.enable_beacon = true;
@@ -705,7 +706,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
                                        const struct ieee80211_ops *ops)
 {
        struct ieee80211_local *local;
-       int priv_size;
+       int priv_size, i;
        struct wiphy *wiphy;
 
        /* Ensure 32-byte alignment of our private data and hw private data.
@@ -779,6 +780,11 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        setup_timer(&local->dynamic_ps_timer,
                    ieee80211_dynamic_ps_timer, (unsigned long) local);
 
+       for (i = 0; i < IEEE80211_MAX_AMPDU_QUEUES; i++)
+               local->ampdu_ac_queue[i] = -1;
+       /* using an s8 won't work with more than that */
+       BUILD_BUG_ON(IEEE80211_MAX_AMPDU_QUEUES > 127);
+
        sta_info_init(local);
 
        tasklet_init(&local->tx_pending_tasklet, ieee80211_tx_pending,
@@ -855,6 +861,11 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        /* mac80211 always supports monitor */
        local->hw.wiphy->interface_modes |= BIT(NL80211_IFTYPE_MONITOR);
 
+       if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
+               local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
+       else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
+               local->hw.wiphy->signal_type = CFG80211_SIGNAL_TYPE_UNSPEC;
+
        result = wiphy_register(local->hw.wiphy);
        if (result < 0)
                goto fail_wiphy_register;
@@ -872,7 +883,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        mdev = alloc_netdev_mq(sizeof(struct ieee80211_master_priv),
                               "wmaster%d", ieee80211_master_setup,
-                              ieee80211_num_queues(hw));
+                              hw->queues);
        if (!mdev)
                goto fail_mdev_alloc;
 
@@ -916,6 +927,7 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
 
        memcpy(local->mdev->dev_addr, local->hw.wiphy->perm_addr, ETH_ALEN);
        SET_NETDEV_DEV(local->mdev, wiphy_dev(local->hw.wiphy));
+       local->mdev->features |= NETIF_F_NETNS_LOCAL;
 
        result = register_netdevice(local->mdev);
        if (result < 0)
index fbb766afe599df30166e66faff75e0df4da39062..841b8450b3de787823a79b7ffe6ce6e437247d75 100644 (file)
 #include <linux/if_ether.h>
 #include <linux/skbuff.h>
 #include <linux/if_arp.h>
-#include <linux/wireless.h>
-#include <linux/random.h>
 #include <linux/etherdevice.h>
 #include <linux/rtnetlink.h>
-#include <net/iw_handler.h>
 #include <net/mac80211.h>
 #include <asm/unaligned.h>
 
 #define IEEE80211_MONITORING_INTERVAL (2 * HZ)
 #define IEEE80211_PROBE_INTERVAL (60 * HZ)
 #define IEEE80211_RETRY_AUTH_INTERVAL (1 * HZ)
-#define IEEE80211_SCAN_INTERVAL (2 * HZ)
-#define IEEE80211_SCAN_INTERVAL_SLOW (15 * HZ)
-#define IEEE80211_IBSS_JOIN_TIMEOUT (7 * HZ)
-
-#define IEEE80211_IBSS_MERGE_INTERVAL (30 * HZ)
-#define IEEE80211_IBSS_INACTIVITY_LIMIT (60 * HZ)
-
-#define IEEE80211_IBSS_MAX_STA_ENTRIES 128
-
 
 /* utils */
 static int ecw2cw(int ecw)
@@ -92,43 +80,6 @@ static int ieee80211_compatible_rates(struct ieee80211_bss *bss,
        return count;
 }
 
-/* also used by mesh code */
-u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
-                           struct ieee802_11_elems *elems,
-                           enum ieee80211_band band)
-{
-       struct ieee80211_supported_band *sband;
-       struct ieee80211_rate *bitrates;
-       size_t num_rates;
-       u32 supp_rates;
-       int i, j;
-       sband = local->hw.wiphy->bands[band];
-
-       if (!sband) {
-               WARN_ON(1);
-               sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-       }
-
-       bitrates = sband->bitrates;
-       num_rates = sband->n_bitrates;
-       supp_rates = 0;
-       for (i = 0; i < elems->supp_rates_len +
-                    elems->ext_supp_rates_len; i++) {
-               u8 rate = 0;
-               int own_rate;
-               if (i < elems->supp_rates_len)
-                       rate = elems->supp_rates[i];
-               else if (elems->ext_supp_rates)
-                       rate = elems->ext_supp_rates
-                               [i - elems->supp_rates_len];
-               own_rate = 5 * (rate & 0x7f);
-               for (j = 0; j < num_rates; j++)
-                       if (bitrates[j].bitrate == own_rate)
-                               supp_rates |= BIT(j);
-       }
-       return supp_rates;
-}
-
 /* frame sending functions */
 
 static void add_extra_ies(struct sk_buff *skb, u8 *ies, size_t ies_len)
@@ -137,113 +88,9 @@ static void add_extra_ies(struct sk_buff *skb, u8 *ies, size_t ies_len)
                memcpy(skb_put(skb, ies_len), ies, ies_len);
 }
 
-/* also used by scanning code */
-void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
-                             u8 *ssid, size_t ssid_len)
-{
-       struct ieee80211_local *local = sdata->local;
-       struct ieee80211_supported_band *sband;
-       struct sk_buff *skb;
-       struct ieee80211_mgmt *mgmt;
-       u8 *pos, *supp_rates, *esupp_rates = NULL;
-       int i;
-
-       skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 +
-                           sdata->u.sta.ie_probereq_len);
-       if (!skb) {
-               printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
-                      "request\n", sdata->dev->name);
-               return;
-       }
-       skb_reserve(skb, local->hw.extra_tx_headroom);
-
-       mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
-       memset(mgmt, 0, 24);
-       mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-                                         IEEE80211_STYPE_PROBE_REQ);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
-       if (dst) {
-               memcpy(mgmt->da, dst, ETH_ALEN);
-               memcpy(mgmt->bssid, dst, ETH_ALEN);
-       } else {
-               memset(mgmt->da, 0xff, ETH_ALEN);
-               memset(mgmt->bssid, 0xff, ETH_ALEN);
-       }
-       pos = skb_put(skb, 2 + ssid_len);
-       *pos++ = WLAN_EID_SSID;
-       *pos++ = ssid_len;
-       memcpy(pos, ssid, ssid_len);
-
-       supp_rates = skb_put(skb, 2);
-       supp_rates[0] = WLAN_EID_SUPP_RATES;
-       supp_rates[1] = 0;
-       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
-       for (i = 0; i < sband->n_bitrates; i++) {
-               struct ieee80211_rate *rate = &sband->bitrates[i];
-               if (esupp_rates) {
-                       pos = skb_put(skb, 1);
-                       esupp_rates[1]++;
-               } else if (supp_rates[1] == 8) {
-                       esupp_rates = skb_put(skb, 3);
-                       esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES;
-                       esupp_rates[1] = 1;
-                       pos = &esupp_rates[2];
-               } else {
-                       pos = skb_put(skb, 1);
-                       supp_rates[1]++;
-               }
-               *pos = rate->bitrate / 5;
-       }
-
-       add_extra_ies(skb, sdata->u.sta.ie_probereq,
-                     sdata->u.sta.ie_probereq_len);
-
-       ieee80211_tx_skb(sdata, skb, 0);
-}
-
-static void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
-                               struct ieee80211_if_sta *ifsta,
-                               int transaction, u8 *extra, size_t extra_len,
-                               int encrypt)
-{
-       struct ieee80211_local *local = sdata->local;
-       struct sk_buff *skb;
-       struct ieee80211_mgmt *mgmt;
-
-       skb = dev_alloc_skb(local->hw.extra_tx_headroom +
-                           sizeof(*mgmt) + 6 + extra_len +
-                           sdata->u.sta.ie_auth_len);
-       if (!skb) {
-               printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
-                      "frame\n", sdata->dev->name);
-               return;
-       }
-       skb_reserve(skb, local->hw.extra_tx_headroom);
-
-       mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
-       memset(mgmt, 0, 24 + 6);
-       mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-                                         IEEE80211_STYPE_AUTH);
-       if (encrypt)
-               mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
-       memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
-       memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-       mgmt->u.auth.auth_alg = cpu_to_le16(ifsta->auth_alg);
-       mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
-       ifsta->auth_transaction = transaction + 1;
-       mgmt->u.auth.status_code = cpu_to_le16(0);
-       if (extra)
-               memcpy(skb_put(skb, extra_len), extra, extra_len);
-       add_extra_ies(skb, sdata->u.sta.ie_auth, sdata->u.sta.ie_auth_len);
-
-       ieee80211_tx_skb(sdata, skb, encrypt);
-}
-
-static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
-                                struct ieee80211_if_sta *ifsta)
+static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
 {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
@@ -256,17 +103,17 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
        u32 rates = 0;
        size_t e_ies_len;
 
-       if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) {
-               e_ies = sdata->u.sta.ie_reassocreq;
-               e_ies_len = sdata->u.sta.ie_reassocreq_len;
+       if (ifmgd->flags & IEEE80211_IBSS_PREV_BSSID_SET) {
+               e_ies = sdata->u.mgd.ie_reassocreq;
+               e_ies_len = sdata->u.mgd.ie_reassocreq_len;
        } else {
-               e_ies = sdata->u.sta.ie_assocreq;
-               e_ies_len = sdata->u.sta.ie_assocreq_len;
+               e_ies = sdata->u.mgd.ie_assocreq;
+               e_ies_len = sdata->u.mgd.ie_assocreq_len;
        }
 
        skb = dev_alloc_skb(local->hw.extra_tx_headroom +
-                           sizeof(*mgmt) + 200 + ifsta->extra_ie_len +
-                           ifsta->ssid_len + e_ies_len);
+                           sizeof(*mgmt) + 200 + ifmgd->extra_ie_len +
+                           ifmgd->ssid_len + e_ies_len);
        if (!skb) {
                printk(KERN_DEBUG "%s: failed to allocate buffer for assoc "
                       "frame\n", sdata->dev->name);
@@ -276,7 +123,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
 
        sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
 
-       capab = ifsta->capab;
+       capab = ifmgd->capab;
 
        if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ) {
                if (!(local->hw.flags & IEEE80211_HW_2GHZ_SHORT_SLOT_INCAPABLE))
@@ -285,9 +132,9 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
                        capab |= WLAN_CAPABILITY_SHORT_PREAMBLE;
        }
 
-       bss = ieee80211_rx_bss_get(local, ifsta->bssid,
+       bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
                                   local->hw.conf.channel->center_freq,
-                                  ifsta->ssid, ifsta->ssid_len);
+                                  ifmgd->ssid, ifmgd->ssid_len);
        if (bss) {
                if (bss->cbss.capability & WLAN_CAPABILITY_PRIVACY)
                        capab |= WLAN_CAPABILITY_PRIVACY;
@@ -312,18 +159,18 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
 
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
        memset(mgmt, 0, 24);
-       memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
+       memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN);
        memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
-       memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+       memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN);
 
-       if (ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) {
+       if (ifmgd->flags & IEEE80211_STA_PREV_BSSID_SET) {
                skb_put(skb, 10);
                mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                                  IEEE80211_STYPE_REASSOC_REQ);
                mgmt->u.reassoc_req.capab_info = cpu_to_le16(capab);
                mgmt->u.reassoc_req.listen_interval =
                                cpu_to_le16(local->hw.conf.listen_interval);
-               memcpy(mgmt->u.reassoc_req.current_ap, ifsta->prev_bssid,
+               memcpy(mgmt->u.reassoc_req.current_ap, ifmgd->prev_bssid,
                       ETH_ALEN);
        } else {
                skb_put(skb, 4);
@@ -335,10 +182,10 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
        }
 
        /* SSID */
-       ies = pos = skb_put(skb, 2 + ifsta->ssid_len);
+       ies = pos = skb_put(skb, 2 + ifmgd->ssid_len);
        *pos++ = WLAN_EID_SSID;
-       *pos++ = ifsta->ssid_len;
-       memcpy(pos, ifsta->ssid, ifsta->ssid_len);
+       *pos++ = ifmgd->ssid_len;
+       memcpy(pos, ifmgd->ssid, ifmgd->ssid_len);
 
        /* add all rates which were marked to be used above */
        supp_rates_len = rates_len;
@@ -393,12 +240,12 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
                }
        }
 
-       if (ifsta->extra_ie) {
-               pos = skb_put(skb, ifsta->extra_ie_len);
-               memcpy(pos, ifsta->extra_ie, ifsta->extra_ie_len);
+       if (ifmgd->extra_ie) {
+               pos = skb_put(skb, ifmgd->extra_ie_len);
+               memcpy(pos, ifmgd->extra_ie, ifmgd->extra_ie_len);
        }
 
-       if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED)) {
+       if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED)) {
                pos = skb_put(skb, 9);
                *pos++ = WLAN_EID_VENDOR_SPECIFIC;
                *pos++ = 7; /* len */
@@ -418,11 +265,11 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
         * mode (11a/b/g) if any one of these ciphers is
         * configured as pairwise.
         */
-       if (wmm && (ifsta->flags & IEEE80211_STA_WMM_ENABLED) &&
+       if (wmm && (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) &&
            sband->ht_cap.ht_supported &&
            (ht_ie = ieee80211_bss_get_ie(bss, WLAN_EID_HT_INFORMATION)) &&
            ht_ie[1] >= sizeof(struct ieee80211_ht_info) &&
-           (!(ifsta->flags & IEEE80211_STA_TKIP_WEP_USED))) {
+           (!(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED))) {
                struct ieee80211_ht_info *ht_info =
                        (struct ieee80211_ht_info *)(ht_ie + 2);
                u16 cap = sband->ht_cap.cap;
@@ -459,11 +306,11 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata,
 
        add_extra_ies(skb, e_ies, e_ies_len);
 
-       kfree(ifsta->assocreq_ies);
-       ifsta->assocreq_ies_len = (skb->data + skb->len) - ies;
-       ifsta->assocreq_ies = kmalloc(ifsta->assocreq_ies_len, GFP_KERNEL);
-       if (ifsta->assocreq_ies)
-               memcpy(ifsta->assocreq_ies, ies, ifsta->assocreq_ies_len);
+       kfree(ifmgd->assocreq_ies);
+       ifmgd->assocreq_ies_len = (skb->data + skb->len) - ies;
+       ifmgd->assocreq_ies = kmalloc(ifmgd->assocreq_ies_len, GFP_KERNEL);
+       if (ifmgd->assocreq_ies)
+               memcpy(ifmgd->assocreq_ies, ies, ifmgd->assocreq_ies_len);
 
        ieee80211_tx_skb(sdata, skb, 0);
 }
@@ -473,18 +320,18 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
                                           u16 stype, u16 reason)
 {
        struct ieee80211_local *local = sdata->local;
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct sk_buff *skb;
        struct ieee80211_mgmt *mgmt;
        u8 *ies;
        size_t ies_len;
 
        if (stype == IEEE80211_STYPE_DEAUTH) {
-               ies = sdata->u.sta.ie_deauth;
-               ies_len = sdata->u.sta.ie_deauth_len;
+               ies = sdata->u.mgd.ie_deauth;
+               ies_len = sdata->u.mgd.ie_deauth_len;
        } else {
-               ies = sdata->u.sta.ie_disassoc;
-               ies_len = sdata->u.sta.ie_disassoc_len;
+               ies = sdata->u.mgd.ie_disassoc;
+               ies_len = sdata->u.mgd.ie_disassoc_len;
        }
 
        skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) +
@@ -498,9 +345,9 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
 
        mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
        memset(mgmt, 0, 24);
-       memcpy(mgmt->da, ifsta->bssid, ETH_ALEN);
+       memcpy(mgmt->da, ifmgd->bssid, ETH_ALEN);
        memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
-       memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
+       memcpy(mgmt->bssid, ifmgd->bssid, ETH_ALEN);
        mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT | stype);
        skb_put(skb, 2);
        /* u.deauth.reason_code == u.disassoc.reason_code */
@@ -508,13 +355,13 @@ static void ieee80211_send_deauth_disassoc(struct ieee80211_sub_if_data *sdata,
 
        add_extra_ies(skb, ies, ies_len);
 
-       ieee80211_tx_skb(sdata, skb, ifsta->flags & IEEE80211_STA_MFP_ENABLED);
+       ieee80211_tx_skb(sdata, skb, ifmgd->flags & IEEE80211_STA_MFP_ENABLED);
 }
 
 void ieee80211_send_pspoll(struct ieee80211_local *local,
                           struct ieee80211_sub_if_data *sdata)
 {
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_pspoll *pspoll;
        struct sk_buff *skb;
        u16 fc;
@@ -531,43 +378,20 @@ void ieee80211_send_pspoll(struct ieee80211_local *local,
        memset(pspoll, 0, sizeof(*pspoll));
        fc = IEEE80211_FTYPE_CTL | IEEE80211_STYPE_PSPOLL | IEEE80211_FCTL_PM;
        pspoll->frame_control = cpu_to_le16(fc);
-       pspoll->aid = cpu_to_le16(ifsta->aid);
+       pspoll->aid = cpu_to_le16(ifmgd->aid);
 
        /* aid in PS-Poll has its two MSBs each set to 1 */
        pspoll->aid |= cpu_to_le16(1 << 15 | 1 << 14);
 
-       memcpy(pspoll->bssid, ifsta->bssid, ETH_ALEN);
+       memcpy(pspoll->bssid, ifmgd->bssid, ETH_ALEN);
        memcpy(pspoll->ta, sdata->dev->dev_addr, ETH_ALEN);
 
        ieee80211_tx_skb(sdata, skb, 0);
-
-       return;
 }
 
 /* MLME */
-static void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
-                                        const size_t supp_rates_len,
-                                        const u8 *supp_rates)
-{
-       struct ieee80211_local *local = sdata->local;
-       int i, have_higher_than_11mbit = 0;
-
-       /* cf. IEEE 802.11 9.2.12 */
-       for (i = 0; i < supp_rates_len; i++)
-               if ((supp_rates[i] & 0x7f) * 5 > 110)
-                       have_higher_than_11mbit = 1;
-
-       if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
-           have_higher_than_11mbit)
-               sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
-       else
-               sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
-
-       ieee80211_set_wmm_default(sdata);
-}
-
 static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
-                                    struct ieee80211_if_sta *ifsta,
+                                    struct ieee80211_if_managed *ifmgd,
                                     u8 *wmm_param, size_t wmm_param_len)
 {
        struct ieee80211_tx_queue_params params;
@@ -575,7 +399,7 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
        int count;
        u8 *pos;
 
-       if (!(ifsta->flags & IEEE80211_STA_WMM_ENABLED))
+       if (!(ifmgd->flags & IEEE80211_STA_WMM_ENABLED))
                return;
 
        if (!wmm_param)
@@ -584,18 +408,15 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
        if (wmm_param_len < 8 || wmm_param[5] /* version */ != 1)
                return;
        count = wmm_param[6] & 0x0f;
-       if (count == ifsta->wmm_last_param_set)
+       if (count == ifmgd->wmm_last_param_set)
                return;
-       ifsta->wmm_last_param_set = count;
+       ifmgd->wmm_last_param_set = count;
 
        pos = wmm_param + 8;
        left = wmm_param_len - 8;
 
        memset(&params, 0, sizeof(params));
 
-       if (!local->ops->conf_tx)
-               return;
-
        local->wmm_acm = 0;
        for (; left >= 4; left -= 4, pos += 4) {
                int aci = (pos[0] >> 5) & 0x03;
@@ -603,26 +424,26 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
                int queue;
 
                switch (aci) {
-               case 1:
+               case 1: /* AC_BK */
                        queue = 3;
                        if (acm)
-                               local->wmm_acm |= BIT(0) | BIT(3);
+                               local->wmm_acm |= BIT(1) | BIT(2); /* BK/- */
                        break;
-               case 2:
+               case 2: /* AC_VI */
                        queue = 1;
                        if (acm)
-                               local->wmm_acm |= BIT(4) | BIT(5);
+                               local->wmm_acm |= BIT(4) | BIT(5); /* CL/VI */
                        break;
-               case 3:
+               case 3: /* AC_VO */
                        queue = 0;
                        if (acm)
-                               local->wmm_acm |= BIT(6) | BIT(7);
+                               local->wmm_acm |= BIT(6) | BIT(7); /* VO/NC */
                        break;
-               case 0:
+               case 0: /* AC_BE */
                default:
                        queue = 2;
                        if (acm)
-                               local->wmm_acm |= BIT(1) | BIT(2);
+                               local->wmm_acm |= BIT(0) | BIT(3); /* BE/EE */
                        break;
                }
 
@@ -636,9 +457,8 @@ static void ieee80211_sta_wmm_params(struct ieee80211_local *local,
                       local->mdev->name, queue, aci, acm, params.aifs, params.cw_min,
                       params.cw_max, params.txop);
 #endif
-               /* TODO: handle ACM (block TX, fallback to next lowest allowed
-                * AC for now) */
-               if (local->ops->conf_tx(local_to_hw(local), queue, &params)) {
+               if (local->ops->conf_tx &&
+                   local->ops->conf_tx(local_to_hw(local), queue, &params)) {
                        printk(KERN_DEBUG "%s: failed to set TX queue "
                               "parameters for queue %d\n", local->mdev->name, queue);
                }
@@ -671,7 +491,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
 {
        struct ieee80211_bss_conf *bss_conf = &sdata->vif.bss_conf;
 #ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 #endif
        u32 changed = 0;
        bool use_protection;
@@ -694,7 +514,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
                        printk(KERN_DEBUG "%s: CTS protection %s (BSSID=%pM)\n",
                               sdata->dev->name,
                               use_protection ? "enabled" : "disabled",
-                              ifsta->bssid);
+                              ifmgd->bssid);
                }
 #endif
                bss_conf->use_cts_prot = use_protection;
@@ -708,7 +528,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
                               " (BSSID=%pM)\n",
                               sdata->dev->name,
                               use_short_preamble ? "short" : "long",
-                              ifsta->bssid);
+                              ifmgd->bssid);
                }
 #endif
                bss_conf->use_short_preamble = use_short_preamble;
@@ -722,7 +542,7 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
                               " (BSSID=%pM)\n",
                               sdata->dev->name,
                               use_short_slot ? "short" : "long",
-                              ifsta->bssid);
+                              ifmgd->bssid);
                }
 #endif
                bss_conf->use_short_slot = use_short_slot;
@@ -732,57 +552,57 @@ static u32 ieee80211_handle_bss_capability(struct ieee80211_sub_if_data *sdata,
        return changed;
 }
 
-static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata,
-                                       struct ieee80211_if_sta *ifsta)
+static void ieee80211_sta_send_apinfo(struct ieee80211_sub_if_data *sdata)
 {
        union iwreq_data wrqu;
+
        memset(&wrqu, 0, sizeof(wrqu));
-       if (ifsta->flags & IEEE80211_STA_ASSOCIATED)
-               memcpy(wrqu.ap_addr.sa_data, sdata->u.sta.bssid, ETH_ALEN);
+       if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED)
+               memcpy(wrqu.ap_addr.sa_data, sdata->u.mgd.bssid, ETH_ALEN);
        wrqu.ap_addr.sa_family = ARPHRD_ETHER;
        wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL);
 }
 
-static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata,
-                                        struct ieee80211_if_sta *ifsta)
+static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata)
 {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        char *buf;
        size_t len;
        int i;
        union iwreq_data wrqu;
 
-       if (!ifsta->assocreq_ies && !ifsta->assocresp_ies)
+       if (!ifmgd->assocreq_ies && !ifmgd->assocresp_ies)
                return;
 
-       buf = kmalloc(50 + 2 * (ifsta->assocreq_ies_len +
-                               ifsta->assocresp_ies_len), GFP_KERNEL);
+       buf = kmalloc(50 + 2 * (ifmgd->assocreq_ies_len +
+                               ifmgd->assocresp_ies_len), GFP_KERNEL);
        if (!buf)
                return;
 
        len = sprintf(buf, "ASSOCINFO(");
-       if (ifsta->assocreq_ies) {
+       if (ifmgd->assocreq_ies) {
                len += sprintf(buf + len, "ReqIEs=");
-               for (i = 0; i < ifsta->assocreq_ies_len; i++) {
+               for (i = 0; i < ifmgd->assocreq_ies_len; i++) {
                        len += sprintf(buf + len, "%02x",
-                                      ifsta->assocreq_ies[i]);
+                                      ifmgd->assocreq_ies[i]);
                }
        }
-       if (ifsta->assocresp_ies) {
-               if (ifsta->assocreq_ies)
+       if (ifmgd->assocresp_ies) {
+               if (ifmgd->assocreq_ies)
                        len += sprintf(buf + len, " ");
                len += sprintf(buf + len, "RespIEs=");
-               for (i = 0; i < ifsta->assocresp_ies_len; i++) {
+               for (i = 0; i < ifmgd->assocresp_ies_len; i++) {
                        len += sprintf(buf + len, "%02x",
-                                      ifsta->assocresp_ies[i]);
+                                      ifmgd->assocresp_ies[i]);
                }
        }
        len += sprintf(buf + len, ")");
 
        if (len > IW_CUSTOM_MAX) {
                len = sprintf(buf, "ASSOCRESPIE=");
-               for (i = 0; i < ifsta->assocresp_ies_len; i++) {
+               for (i = 0; i < ifmgd->assocresp_ies_len; i++) {
                        len += sprintf(buf + len, "%02x",
-                                      ifsta->assocresp_ies[i]);
+                                      ifmgd->assocresp_ies[i]);
                }
        }
 
@@ -797,20 +617,20 @@ static void ieee80211_sta_send_associnfo(struct ieee80211_sub_if_data *sdata,
 
 
 static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
-                                    struct ieee80211_if_sta *ifsta,
                                     u32 bss_info_changed)
 {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_conf *conf = &local_to_hw(local)->conf;
 
        struct ieee80211_bss *bss;
 
        bss_info_changed |= BSS_CHANGED_ASSOC;
-       ifsta->flags |= IEEE80211_STA_ASSOCIATED;
+       ifmgd->flags |= IEEE80211_STA_ASSOCIATED;
 
-       bss = ieee80211_rx_bss_get(local, ifsta->bssid,
+       bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
                                   conf->channel->center_freq,
-                                  ifsta->ssid, ifsta->ssid_len);
+                                  ifmgd->ssid, ifmgd->ssid_len);
        if (bss) {
                /* set timing information */
                sdata->vif.bss_conf.beacon_int = bss->cbss.beacon_interval;
@@ -823,11 +643,11 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
                ieee80211_rx_bss_put(local, bss);
        }
 
-       ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;
-       memcpy(ifsta->prev_bssid, sdata->u.sta.bssid, ETH_ALEN);
-       ieee80211_sta_send_associnfo(sdata, ifsta);
+       ifmgd->flags |= IEEE80211_STA_PREV_BSSID_SET;
+       memcpy(ifmgd->prev_bssid, sdata->u.mgd.bssid, ETH_ALEN);
+       ieee80211_sta_send_associnfo(sdata);
 
-       ifsta->last_probe = jiffies;
+       ifmgd->last_probe = jiffies;
        ieee80211_led_assoc(local, 1);
 
        sdata->vif.bss_conf.assoc = 1;
@@ -856,70 +676,74 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
        netif_tx_start_all_queues(sdata->dev);
        netif_carrier_on(sdata->dev);
 
-       ieee80211_sta_send_apinfo(sdata, ifsta);
+       ieee80211_sta_send_apinfo(sdata);
 }
 
-static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata,
-                                  struct ieee80211_if_sta *ifsta)
+static void ieee80211_direct_probe(struct ieee80211_sub_if_data *sdata)
 {
-       ifsta->direct_probe_tries++;
-       if (ifsta->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+       ifmgd->direct_probe_tries++;
+       if (ifmgd->direct_probe_tries > IEEE80211_AUTH_MAX_TRIES) {
                printk(KERN_DEBUG "%s: direct probe to AP %pM timed out\n",
-                      sdata->dev->name, ifsta->bssid);
-               ifsta->state = IEEE80211_STA_MLME_DISABLED;
-               ieee80211_sta_send_apinfo(sdata, ifsta);
+                      sdata->dev->name, ifmgd->bssid);
+               ifmgd->state = IEEE80211_STA_MLME_DISABLED;
+               ieee80211_sta_send_apinfo(sdata);
 
                /*
                 * Most likely AP is not in the range so remove the
                 * bss information associated to the AP
                 */
-               ieee80211_rx_bss_remove(sdata, ifsta->bssid,
+               ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
                                sdata->local->hw.conf.channel->center_freq,
-                               ifsta->ssid, ifsta->ssid_len);
+                               ifmgd->ssid, ifmgd->ssid_len);
                return;
        }
 
        printk(KERN_DEBUG "%s: direct probe to AP %pM try %d\n",
-                       sdata->dev->name, ifsta->bssid,
-                       ifsta->direct_probe_tries);
+                       sdata->dev->name, ifmgd->bssid,
+                       ifmgd->direct_probe_tries);
 
-       ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;
+       ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE;
 
-       set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifsta->request);
+       set_bit(IEEE80211_STA_REQ_DIRECT_PROBE, &ifmgd->request);
 
        /* Direct probe is sent to broadcast address as some APs
         * will not answer to direct packet in unassociated state.
         */
        ieee80211_send_probe_req(sdata, NULL,
-                                ifsta->ssid, ifsta->ssid_len);
+                                ifmgd->ssid, ifmgd->ssid_len, NULL, 0);
 
-       mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
+       mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
 }
 
 
-static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
-                                  struct ieee80211_if_sta *ifsta)
+static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata)
 {
-       ifsta->auth_tries++;
-       if (ifsta->auth_tries > IEEE80211_AUTH_MAX_TRIES) {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+       ifmgd->auth_tries++;
+       if (ifmgd->auth_tries > IEEE80211_AUTH_MAX_TRIES) {
                printk(KERN_DEBUG "%s: authentication with AP %pM"
                       " timed out\n",
-                      sdata->dev->name, ifsta->bssid);
-               ifsta->state = IEEE80211_STA_MLME_DISABLED;
-               ieee80211_sta_send_apinfo(sdata, ifsta);
-               ieee80211_rx_bss_remove(sdata, ifsta->bssid,
+                      sdata->dev->name, ifmgd->bssid);
+               ifmgd->state = IEEE80211_STA_MLME_DISABLED;
+               ieee80211_sta_send_apinfo(sdata);
+               ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
                                sdata->local->hw.conf.channel->center_freq,
-                               ifsta->ssid, ifsta->ssid_len);
+                               ifmgd->ssid, ifmgd->ssid_len);
                return;
        }
 
-       ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
+       ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;
        printk(KERN_DEBUG "%s: authenticate with AP %pM\n",
-              sdata->dev->name, ifsta->bssid);
+              sdata->dev->name, ifmgd->bssid);
 
-       ieee80211_send_auth(sdata, ifsta, 1, NULL, 0, 0);
+       ieee80211_send_auth(sdata, 1, ifmgd->auth_alg, NULL, 0,
+                           ifmgd->bssid, 0);
+       ifmgd->auth_transaction = 2;
 
-       mod_timer(&ifsta->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
+       mod_timer(&ifmgd->timer, jiffies + IEEE80211_AUTH_TIMEOUT);
 }
 
 /*
@@ -927,27 +751,28 @@ static void ieee80211_authenticate(struct ieee80211_sub_if_data *sdata,
  * if self disconnected or a reason code from the AP.
  */
 static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
-                                  struct ieee80211_if_sta *ifsta, bool deauth,
-                                  bool self_disconnected, u16 reason)
+                                  bool deauth, bool self_disconnected,
+                                  u16 reason)
 {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
        u32 changed = 0, config_changed = 0;
 
        rcu_read_lock();
 
-       sta = sta_info_get(local, ifsta->bssid);
+       sta = sta_info_get(local, ifmgd->bssid);
        if (!sta) {
                rcu_read_unlock();
                return;
        }
 
        if (deauth) {
-               ifsta->direct_probe_tries = 0;
-               ifsta->auth_tries = 0;
+               ifmgd->direct_probe_tries = 0;
+               ifmgd->auth_tries = 0;
        }
-       ifsta->assoc_scan_tries = 0;
-       ifsta->assoc_tries = 0;
+       ifmgd->assoc_scan_tries = 0;
+       ifmgd->assoc_tries = 0;
 
        netif_tx_stop_all_queues(sdata->dev);
        netif_carrier_off(sdata->dev);
@@ -963,20 +788,20 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
                                IEEE80211_STYPE_DISASSOC, reason);
        }
 
-       ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
+       ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED;
        changed |= ieee80211_reset_erp_info(sdata);
 
        ieee80211_led_assoc(local, 0);
        changed |= BSS_CHANGED_ASSOC;
        sdata->vif.bss_conf.assoc = false;
 
-       ieee80211_sta_send_apinfo(sdata, ifsta);
+       ieee80211_sta_send_apinfo(sdata);
 
        if (self_disconnected || reason == WLAN_REASON_DISASSOC_STA_HAS_LEFT) {
-               ifsta->state = IEEE80211_STA_MLME_DISABLED;
-               ieee80211_rx_bss_remove(sdata, ifsta->bssid,
+               ifmgd->state = IEEE80211_STA_MLME_DISABLED;
+               ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
                                sdata->local->hw.conf.channel->center_freq,
-                               ifsta->ssid, ifsta->ssid_len);
+                               ifmgd->ssid, ifmgd->ssid_len);
        }
 
        rcu_read_unlock();
@@ -999,7 +824,7 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
 
        rcu_read_lock();
 
-       sta = sta_info_get(local, ifsta->bssid);
+       sta = sta_info_get(local, ifmgd->bssid);
        if (!sta) {
                rcu_read_unlock();
                return;
@@ -1020,27 +845,27 @@ static int ieee80211_sta_wep_configured(struct ieee80211_sub_if_data *sdata)
        return 1;
 }
 
-static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata,
-                                     struct ieee80211_if_sta *ifsta)
+static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata)
 {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_bss *bss;
        int bss_privacy;
        int wep_privacy;
        int privacy_invoked;
 
-       if (!ifsta || (ifsta->flags & IEEE80211_STA_MIXED_CELL))
+       if (!ifmgd || (ifmgd->flags & IEEE80211_STA_MIXED_CELL))
                return 0;
 
-       bss = ieee80211_rx_bss_get(local, ifsta->bssid,
+       bss = ieee80211_rx_bss_get(local, ifmgd->bssid,
                                   local->hw.conf.channel->center_freq,
-                                  ifsta->ssid, ifsta->ssid_len);
+                                  ifmgd->ssid, ifmgd->ssid_len);
        if (!bss)
                return 0;
 
        bss_privacy = !!(bss->cbss.capability & WLAN_CAPABILITY_PRIVACY);
        wep_privacy = !!ieee80211_sta_wep_configured(sdata);
-       privacy_invoked = !!(ifsta->flags & IEEE80211_STA_PRIVACY_INVOKED);
+       privacy_invoked = !!(ifmgd->flags & IEEE80211_STA_PRIVACY_INVOKED);
 
        ieee80211_rx_bss_put(local, bss);
 
@@ -1050,41 +875,42 @@ static int ieee80211_privacy_mismatch(struct ieee80211_sub_if_data *sdata,
        return 1;
 }
 
-static void ieee80211_associate(struct ieee80211_sub_if_data *sdata,
-                               struct ieee80211_if_sta *ifsta)
+static void ieee80211_associate(struct ieee80211_sub_if_data *sdata)
 {
-       ifsta->assoc_tries++;
-       if (ifsta->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
+       ifmgd->assoc_tries++;
+       if (ifmgd->assoc_tries > IEEE80211_ASSOC_MAX_TRIES) {
                printk(KERN_DEBUG "%s: association with AP %pM"
                       " timed out\n",
-                      sdata->dev->name, ifsta->bssid);
-               ifsta->state = IEEE80211_STA_MLME_DISABLED;
-               ieee80211_sta_send_apinfo(sdata, ifsta);
-               ieee80211_rx_bss_remove(sdata, ifsta->bssid,
+                      sdata->dev->name, ifmgd->bssid);
+               ifmgd->state = IEEE80211_STA_MLME_DISABLED;
+               ieee80211_sta_send_apinfo(sdata);
+               ieee80211_rx_bss_remove(sdata, ifmgd->bssid,
                                sdata->local->hw.conf.channel->center_freq,
-                               ifsta->ssid, ifsta->ssid_len);
+                               ifmgd->ssid, ifmgd->ssid_len);
                return;
        }
 
-       ifsta->state = IEEE80211_STA_MLME_ASSOCIATE;
+       ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE;
        printk(KERN_DEBUG "%s: associate with AP %pM\n",
-              sdata->dev->name, ifsta->bssid);
-       if (ieee80211_privacy_mismatch(sdata, ifsta)) {
+              sdata->dev->name, ifmgd->bssid);
+       if (ieee80211_privacy_mismatch(sdata)) {
                printk(KERN_DEBUG "%s: mismatch in privacy configuration and "
                       "mixed-cell disabled - abort association\n", sdata->dev->name);
-               ifsta->state = IEEE80211_STA_MLME_DISABLED;
+               ifmgd->state = IEEE80211_STA_MLME_DISABLED;
                return;
        }
 
-       ieee80211_send_assoc(sdata, ifsta);
+       ieee80211_send_assoc(sdata);
 
-       mod_timer(&ifsta->timer, jiffies + IEEE80211_ASSOC_TIMEOUT);
+       mod_timer(&ifmgd->timer, jiffies + IEEE80211_ASSOC_TIMEOUT);
 }
 
 
-static void ieee80211_associated(struct ieee80211_sub_if_data *sdata,
-                                struct ieee80211_if_sta *ifsta)
+static void ieee80211_associated(struct ieee80211_sub_if_data *sdata)
 {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
        struct sta_info *sta;
        int disassoc;
@@ -1094,38 +920,40 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata,
         * for better APs. */
        /* TODO: remove expired BSSes */
 
-       ifsta->state = IEEE80211_STA_MLME_ASSOCIATED;
+       ifmgd->state = IEEE80211_STA_MLME_ASSOCIATED;
 
        rcu_read_lock();
 
-       sta = sta_info_get(local, ifsta->bssid);
+       sta = sta_info_get(local, ifmgd->bssid);
        if (!sta) {
                printk(KERN_DEBUG "%s: No STA entry for own AP %pM\n",
-                      sdata->dev->name, ifsta->bssid);
+                      sdata->dev->name, ifmgd->bssid);
                disassoc = 1;
        } else {
                disassoc = 0;
                if (time_after(jiffies,
                               sta->last_rx + IEEE80211_MONITORING_INTERVAL)) {
-                       if (ifsta->flags & IEEE80211_STA_PROBEREQ_POLL) {
+                       if (ifmgd->flags & IEEE80211_STA_PROBEREQ_POLL) {
                                printk(KERN_DEBUG "%s: No ProbeResp from "
                                       "current AP %pM - assume out of "
                                       "range\n",
-                                      sdata->dev->name, ifsta->bssid);
+                                      sdata->dev->name, ifmgd->bssid);
                                disassoc = 1;
                        } else
-                               ieee80211_send_probe_req(sdata, ifsta->bssid,
-                                                        ifsta->ssid,
-                                                        ifsta->ssid_len);
-                       ifsta->flags ^= IEEE80211_STA_PROBEREQ_POLL;
+                               ieee80211_send_probe_req(sdata, ifmgd->bssid,
+                                                        ifmgd->ssid,
+                                                        ifmgd->ssid_len,
+                                                        NULL, 0);
+                       ifmgd->flags ^= IEEE80211_STA_PROBEREQ_POLL;
                } else {
-                       ifsta->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
-                       if (time_after(jiffies, ifsta->last_probe +
+                       ifmgd->flags &= ~IEEE80211_STA_PROBEREQ_POLL;
+                       if (time_after(jiffies, ifmgd->last_probe +
                                       IEEE80211_PROBE_INTERVAL)) {
-                               ifsta->last_probe = jiffies;
-                               ieee80211_send_probe_req(sdata, ifsta->bssid,
-                                                        ifsta->ssid,
-                                                        ifsta->ssid_len);
+                               ifmgd->last_probe = jiffies;
+                               ieee80211_send_probe_req(sdata, ifmgd->bssid,
+                                                        ifmgd->ssid,
+                                                        ifmgd->ssid_len,
+                                                        NULL, 0);
                        }
                }
        }
@@ -1133,25 +961,25 @@ static void ieee80211_associated(struct ieee80211_sub_if_data *sdata,
        rcu_read_unlock();
 
        if (disassoc)
-               ieee80211_set_disassoc(sdata, ifsta, true, true,
+               ieee80211_set_disassoc(sdata, true, true,
                                        WLAN_REASON_PREV_AUTH_NOT_VALID);
        else
-               mod_timer(&ifsta->timer, jiffies +
+               mod_timer(&ifmgd->timer, jiffies +
                                      IEEE80211_MONITORING_INTERVAL);
 }
 
 
-static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata,
-                                    struct ieee80211_if_sta *ifsta)
+static void ieee80211_auth_completed(struct ieee80211_sub_if_data *sdata)
 {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+
        printk(KERN_DEBUG "%s: authenticated\n", sdata->dev->name);
-       ifsta->flags |= IEEE80211_STA_AUTHENTICATED;
-       ieee80211_associate(sdata, ifsta);
+       ifmgd->flags |= IEEE80211_STA_AUTHENTICATED;
+       ieee80211_associate(sdata);
 }
 
 
 static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
-                                    struct ieee80211_if_sta *ifsta,
                                     struct ieee80211_mgmt *mgmt,
                                     size_t len)
 {
@@ -1162,59 +990,37 @@ static void ieee80211_auth_challenge(struct ieee80211_sub_if_data *sdata,
        ieee802_11_parse_elems(pos, len - (pos - (u8 *) mgmt), &elems);
        if (!elems.challenge)
                return;
-       ieee80211_send_auth(sdata, ifsta, 3, elems.challenge - 2,
-                           elems.challenge_len + 2, 1);
-}
-
-static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
-                                       struct ieee80211_if_sta *ifsta,
-                                       struct ieee80211_mgmt *mgmt,
-                                       size_t len)
-{
-       u16 auth_alg, auth_transaction, status_code;
-
-       if (len < 24 + 6)
-               return;
-
-       auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
-       auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
-       status_code = le16_to_cpu(mgmt->u.auth.status_code);
-
-       /*
-        * IEEE 802.11 standard does not require authentication in IBSS
-        * networks and most implementations do not seem to use it.
-        * However, try to reply to authentication attempts if someone
-        * has actually implemented this.
-        */
-       if (auth_alg == WLAN_AUTH_OPEN && auth_transaction == 1)
-               ieee80211_send_auth(sdata, ifsta, 2, NULL, 0, 0);
+       ieee80211_send_auth(sdata, 3, sdata->u.mgd.auth_alg,
+                           elems.challenge - 2, elems.challenge_len + 2,
+                           sdata->u.mgd.bssid, 1);
+       sdata->u.mgd.auth_transaction = 4;
 }
 
 static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
-                                  struct ieee80211_if_sta *ifsta,
                                   struct ieee80211_mgmt *mgmt,
                                   size_t len)
 {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        u16 auth_alg, auth_transaction, status_code;
 
-       if (ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE)
+       if (ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE)
                return;
 
        if (len < 24 + 6)
                return;
 
-       if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)
+       if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0)
                return;
 
-       if (memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
+       if (memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0)
                return;
 
        auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
        auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
        status_code = le16_to_cpu(mgmt->u.auth.status_code);
 
-       if (auth_alg != ifsta->auth_alg ||
-           auth_transaction != ifsta->auth_transaction)
+       if (auth_alg != ifmgd->auth_alg ||
+           auth_transaction != ifmgd->auth_transaction)
                return;
 
        if (status_code != WLAN_STATUS_SUCCESS) {
@@ -1223,15 +1029,15 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
                        const int num_algs = ARRAY_SIZE(algs);
                        int i, pos;
                        algs[0] = algs[1] = algs[2] = 0xff;
-                       if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN)
+                       if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_OPEN)
                                algs[0] = WLAN_AUTH_OPEN;
-                       if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)
+                       if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)
                                algs[1] = WLAN_AUTH_SHARED_KEY;
-                       if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP)
+                       if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP)
                                algs[2] = WLAN_AUTH_LEAP;
-                       if (ifsta->auth_alg == WLAN_AUTH_OPEN)
+                       if (ifmgd->auth_alg == WLAN_AUTH_OPEN)
                                pos = 0;
-                       else if (ifsta->auth_alg == WLAN_AUTH_SHARED_KEY)
+                       else if (ifmgd->auth_alg == WLAN_AUTH_SHARED_KEY)
                                pos = 1;
                        else
                                pos = 2;
@@ -1239,101 +1045,101 @@ static void ieee80211_rx_mgmt_auth(struct ieee80211_sub_if_data *sdata,
                                pos++;
                                if (pos >= num_algs)
                                        pos = 0;
-                               if (algs[pos] == ifsta->auth_alg ||
+                               if (algs[pos] == ifmgd->auth_alg ||
                                    algs[pos] == 0xff)
                                        continue;
                                if (algs[pos] == WLAN_AUTH_SHARED_KEY &&
                                    !ieee80211_sta_wep_configured(sdata))
                                        continue;
-                               ifsta->auth_alg = algs[pos];
+                               ifmgd->auth_alg = algs[pos];
                                break;
                        }
                }
                return;
        }
 
-       switch (ifsta->auth_alg) {
+       switch (ifmgd->auth_alg) {
        case WLAN_AUTH_OPEN:
        case WLAN_AUTH_LEAP:
-               ieee80211_auth_completed(sdata, ifsta);
+               ieee80211_auth_completed(sdata);
                break;
        case WLAN_AUTH_SHARED_KEY:
-               if (ifsta->auth_transaction == 4)
-                       ieee80211_auth_completed(sdata, ifsta);
+               if (ifmgd->auth_transaction == 4)
+                       ieee80211_auth_completed(sdata);
                else
-                       ieee80211_auth_challenge(sdata, ifsta, mgmt, len);
+                       ieee80211_auth_challenge(sdata, mgmt, len);
                break;
        }
 }
 
 
 static void ieee80211_rx_mgmt_deauth(struct ieee80211_sub_if_data *sdata,
-                                    struct ieee80211_if_sta *ifsta,
                                     struct ieee80211_mgmt *mgmt,
                                     size_t len)
 {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        u16 reason_code;
 
        if (len < 24 + 2)
                return;
 
-       if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN))
+       if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN))
                return;
 
        reason_code = le16_to_cpu(mgmt->u.deauth.reason_code);
 
-       if (ifsta->flags & IEEE80211_STA_AUTHENTICATED)
+       if (ifmgd->flags & IEEE80211_STA_AUTHENTICATED)
                printk(KERN_DEBUG "%s: deauthenticated (Reason: %u)\n",
                                sdata->dev->name, reason_code);
 
-       if (ifsta->state == IEEE80211_STA_MLME_AUTHENTICATE ||
-           ifsta->state == IEEE80211_STA_MLME_ASSOCIATE ||
-           ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) {
-               ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;
-               mod_timer(&ifsta->timer, jiffies +
+       if (ifmgd->state == IEEE80211_STA_MLME_AUTHENTICATE ||
+           ifmgd->state == IEEE80211_STA_MLME_ASSOCIATE ||
+           ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) {
+               ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE;
+               mod_timer(&ifmgd->timer, jiffies +
                                      IEEE80211_RETRY_AUTH_INTERVAL);
        }
 
-       ieee80211_set_disassoc(sdata, ifsta, true, false, 0);
-       ifsta->flags &= ~IEEE80211_STA_AUTHENTICATED;
+       ieee80211_set_disassoc(sdata, true, false, 0);
+       ifmgd->flags &= ~IEEE80211_STA_AUTHENTICATED;
 }
 
 
 static void ieee80211_rx_mgmt_disassoc(struct ieee80211_sub_if_data *sdata,
-                                      struct ieee80211_if_sta *ifsta,
                                       struct ieee80211_mgmt *mgmt,
                                       size_t len)
 {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        u16 reason_code;
 
        if (len < 24 + 2)
                return;
 
-       if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN))
+       if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN))
                return;
 
        reason_code = le16_to_cpu(mgmt->u.disassoc.reason_code);
 
-       if (ifsta->flags & IEEE80211_STA_ASSOCIATED)
+       if (ifmgd->flags & IEEE80211_STA_ASSOCIATED)
                printk(KERN_DEBUG "%s: disassociated (Reason: %u)\n",
                                sdata->dev->name, reason_code);
 
-       if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED) {
-               ifsta->state = IEEE80211_STA_MLME_ASSOCIATE;
-               mod_timer(&ifsta->timer, jiffies +
+       if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED) {
+               ifmgd->state = IEEE80211_STA_MLME_ASSOCIATE;
+               mod_timer(&ifmgd->timer, jiffies +
                                      IEEE80211_RETRY_AUTH_INTERVAL);
        }
 
-       ieee80211_set_disassoc(sdata, ifsta, false, false, reason_code);
+       ieee80211_set_disassoc(sdata, false, false, reason_code);
 }
 
 
 static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
-                                        struct ieee80211_if_sta *ifsta,
                                         struct ieee80211_mgmt *mgmt,
                                         size_t len,
                                         int reassoc)
 {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_supported_band *sband;
        struct sta_info *sta;
@@ -1350,13 +1156,13 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        /* AssocResp and ReassocResp have identical structure, so process both
         * of them in this function. */
 
-       if (ifsta->state != IEEE80211_STA_MLME_ASSOCIATE)
+       if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE)
                return;
 
        if (len < 24 + 6)
                return;
 
-       if (memcmp(ifsta->bssid, mgmt->sa, ETH_ALEN) != 0)
+       if (memcmp(ifmgd->bssid, mgmt->sa, ETH_ALEN) != 0)
                return;
 
        capab_info = le16_to_cpu(mgmt->u.assoc_resp.capab_info);
@@ -1381,7 +1187,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                       "comeback duration %u TU (%u ms)\n",
                       sdata->dev->name, tu, ms);
                if (ms > IEEE80211_ASSOC_TIMEOUT)
-                       mod_timer(&ifsta->timer,
+                       mod_timer(&ifmgd->timer,
                                  jiffies + msecs_to_jiffies(ms));
                return;
        }
@@ -1392,7 +1198,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
                /* if this was a reassociation, ensure we try a "full"
                 * association next time. This works around some broken APs
                 * which do not correctly reject reassociation requests. */
-               ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
+               ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
                return;
        }
 
@@ -1408,23 +1214,23 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        }
 
        printk(KERN_DEBUG "%s: associated\n", sdata->dev->name);
-       ifsta->aid = aid;
-       ifsta->ap_capab = capab_info;
+       ifmgd->aid = aid;
+       ifmgd->ap_capab = capab_info;
 
-       kfree(ifsta->assocresp_ies);
-       ifsta->assocresp_ies_len = len - (pos - (u8 *) mgmt);
-       ifsta->assocresp_ies = kmalloc(ifsta->assocresp_ies_len, GFP_KERNEL);
-       if (ifsta->assocresp_ies)
-               memcpy(ifsta->assocresp_ies, pos, ifsta->assocresp_ies_len);
+       kfree(ifmgd->assocresp_ies);
+       ifmgd->assocresp_ies_len = len - (pos - (u8 *) mgmt);
+       ifmgd->assocresp_ies = kmalloc(ifmgd->assocresp_ies_len, GFP_KERNEL);
+       if (ifmgd->assocresp_ies)
+               memcpy(ifmgd->assocresp_ies, pos, ifmgd->assocresp_ies_len);
 
        rcu_read_lock();
 
        /* Add STA entry for the AP */
-       sta = sta_info_get(local, ifsta->bssid);
+       sta = sta_info_get(local, ifmgd->bssid);
        if (!sta) {
                newsta = true;
 
-               sta = sta_info_alloc(sdata, ifsta->bssid, GFP_ATOMIC);
+               sta = sta_info_alloc(sdata, ifmgd->bssid, GFP_ATOMIC);
                if (!sta) {
                        printk(KERN_DEBUG "%s: failed to alloc STA entry for"
                               " the AP\n", sdata->dev->name);
@@ -1497,7 +1303,8 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        else
                sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
 
-       if (elems.ht_cap_elem)
+       /* If TKIP/WEP is used, no need to parse AP's HT capabilities */
+       if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED))
                ieee80211_ht_cap_ie_to_sta_ht_cap(sband,
                                elems.ht_cap_elem, &sta->sta.ht_cap);
 
@@ -1505,7 +1312,7 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
 
        rate_control_rate_init(sta);
 
-       if (ifsta->flags & IEEE80211_STA_MFP_ENABLED)
+       if (ifmgd->flags & IEEE80211_STA_MFP_ENABLED)
                set_sta_flags(sta, WLAN_STA_MFP);
 
        if (elems.wmm_param)
@@ -1524,11 +1331,12 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
        rcu_read_unlock();
 
        if (elems.wmm_param)
-               ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param,
+               ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,
                                         elems.wmm_param_len);
 
        if (elems.ht_info_elem && elems.wmm_param &&
-           (ifsta->flags & IEEE80211_STA_WMM_ENABLED))
+           (ifmgd->flags & IEEE80211_STA_WMM_ENABLED) &&
+           !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED))
                changed |= ieee80211_enable_ht(sdata, elems.ht_info_elem,
                                               ap_ht_cap_flags);
 
@@ -1536,163 +1344,12 @@ static void ieee80211_rx_mgmt_assoc_resp(struct ieee80211_sub_if_data *sdata,
         * ieee80211_set_associated() will tell the driver */
        bss_conf->aid = aid;
        bss_conf->assoc_capability = capab_info;
-       ieee80211_set_associated(sdata, ifsta, changed);
+       ieee80211_set_associated(sdata, changed);
 
-       ieee80211_associated(sdata, ifsta);
+       ieee80211_associated(sdata);
 }
 
 
-static int __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
-                                    struct ieee80211_if_sta *ifsta,
-                                    const u8 *bssid, const int beacon_int,
-                                    const int freq,
-                                    const size_t supp_rates_len,
-                                    const u8 *supp_rates,
-                                    const u16 capability)
-{
-       struct ieee80211_local *local = sdata->local;
-       int res = 0, rates, i, j;
-       struct sk_buff *skb;
-       struct ieee80211_mgmt *mgmt;
-       u8 *pos;
-       struct ieee80211_supported_band *sband;
-       union iwreq_data wrqu;
-
-       if (local->ops->reset_tsf) {
-               /* Reset own TSF to allow time synchronization work. */
-               local->ops->reset_tsf(local_to_hw(local));
-       }
-
-       if ((ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) &&
-          memcmp(ifsta->bssid, bssid, ETH_ALEN) == 0)
-               return res;
-
-       skb = dev_alloc_skb(local->hw.extra_tx_headroom + 400 +
-                           sdata->u.sta.ie_proberesp_len);
-       if (!skb) {
-               printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
-                      "response\n", sdata->dev->name);
-               return -ENOMEM;
-       }
-
-       if (!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) {
-               /* Remove possible STA entries from other IBSS networks. */
-               sta_info_flush_delayed(sdata);
-       }
-
-       memcpy(ifsta->bssid, bssid, ETH_ALEN);
-       res = ieee80211_if_config(sdata, IEEE80211_IFCC_BSSID);
-       if (res)
-               return res;
-
-       local->hw.conf.beacon_int = beacon_int >= 10 ? beacon_int : 10;
-
-       sdata->drop_unencrypted = capability &
-               WLAN_CAPABILITY_PRIVACY ? 1 : 0;
-
-       res = ieee80211_set_freq(sdata, freq);
-
-       if (res)
-               return res;
-
-       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
-       /* Build IBSS probe response */
-
-       skb_reserve(skb, local->hw.extra_tx_headroom);
-
-       mgmt = (struct ieee80211_mgmt *)
-               skb_put(skb, 24 + sizeof(mgmt->u.beacon));
-       memset(mgmt, 0, 24 + sizeof(mgmt->u.beacon));
-       mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
-                                         IEEE80211_STYPE_PROBE_RESP);
-       memset(mgmt->da, 0xff, ETH_ALEN);
-       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
-       memcpy(mgmt->bssid, ifsta->bssid, ETH_ALEN);
-       mgmt->u.beacon.beacon_int =
-               cpu_to_le16(local->hw.conf.beacon_int);
-       mgmt->u.beacon.capab_info = cpu_to_le16(capability);
-
-       pos = skb_put(skb, 2 + ifsta->ssid_len);
-       *pos++ = WLAN_EID_SSID;
-       *pos++ = ifsta->ssid_len;
-       memcpy(pos, ifsta->ssid, ifsta->ssid_len);
-
-       rates = supp_rates_len;
-       if (rates > 8)
-               rates = 8;
-       pos = skb_put(skb, 2 + rates);
-       *pos++ = WLAN_EID_SUPP_RATES;
-       *pos++ = rates;
-       memcpy(pos, supp_rates, rates);
-
-       if (sband->band == IEEE80211_BAND_2GHZ) {
-               pos = skb_put(skb, 2 + 1);
-               *pos++ = WLAN_EID_DS_PARAMS;
-               *pos++ = 1;
-               *pos++ = ieee80211_frequency_to_channel(freq);
-       }
-
-       pos = skb_put(skb, 2 + 2);
-       *pos++ = WLAN_EID_IBSS_PARAMS;
-       *pos++ = 2;
-       /* FIX: set ATIM window based on scan results */
-       *pos++ = 0;
-       *pos++ = 0;
-
-       if (supp_rates_len > 8) {
-               rates = supp_rates_len - 8;
-               pos = skb_put(skb, 2 + rates);
-               *pos++ = WLAN_EID_EXT_SUPP_RATES;
-               *pos++ = rates;
-               memcpy(pos, &supp_rates[8], rates);
-       }
-
-       add_extra_ies(skb, sdata->u.sta.ie_proberesp,
-                     sdata->u.sta.ie_proberesp_len);
-
-       ifsta->probe_resp = skb;
-
-       ieee80211_if_config(sdata, IEEE80211_IFCC_BEACON |
-                                  IEEE80211_IFCC_BEACON_ENABLED);
-
-
-       rates = 0;
-       for (i = 0; i < supp_rates_len; i++) {
-               int bitrate = (supp_rates[i] & 0x7f) * 5;
-               for (j = 0; j < sband->n_bitrates; j++)
-                       if (sband->bitrates[j].bitrate == bitrate)
-                               rates |= BIT(j);
-       }
-       ifsta->supp_rates_bits[local->hw.conf.channel->band] = rates;
-
-       ieee80211_sta_def_wmm_params(sdata, supp_rates_len, supp_rates);
-
-       ifsta->flags |= IEEE80211_STA_PREV_BSSID_SET;
-       ifsta->state = IEEE80211_STA_MLME_IBSS_JOINED;
-       mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
-
-       ieee80211_led_assoc(local, true);
-
-       memset(&wrqu, 0, sizeof(wrqu));
-       memcpy(wrqu.ap_addr.sa_data, bssid, ETH_ALEN);
-       wireless_send_event(sdata->dev, SIOCGIWAP, &wrqu, NULL);
-
-       return res;
-}
-
-static int ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
-                                  struct ieee80211_if_sta *ifsta,
-                                  struct ieee80211_bss *bss)
-{
-       return __ieee80211_sta_join_ibss(sdata, ifsta,
-                                        bss->cbss.bssid,
-                                        bss->cbss.beacon_interval,
-                                        bss->cbss.channel->center_freq,
-                                        bss->supp_rates_len, bss->supp_rates,
-                                        bss->cbss.capability);
-}
-
 static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                                  struct ieee80211_mgmt *mgmt,
                                  size_t len,
@@ -1703,11 +1360,7 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_local *local = sdata->local;
        int freq;
        struct ieee80211_bss *bss;
-       struct sta_info *sta;
        struct ieee80211_channel *channel;
-       u64 beacon_timestamp, rx_timestamp;
-       u32 supp_rates = 0;
-       enum ieee80211_band band = rx_status->band;
 
        if (elems->ds_params && elems->ds_params_len == 1)
                freq = ieee80211_channel_to_frequency(elems->ds_params[0]);
@@ -1719,133 +1372,18 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
        if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
                return;
 
-       if (sdata->vif.type == NL80211_IFTYPE_ADHOC && elems->supp_rates &&
-           memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0) {
-               supp_rates = ieee80211_sta_get_rates(local, elems, band);
-
-               rcu_read_lock();
-
-               sta = sta_info_get(local, mgmt->sa);
-               if (sta) {
-                       u32 prev_rates;
-
-                       prev_rates = sta->sta.supp_rates[band];
-                       /* make sure mandatory rates are always added */
-                       sta->sta.supp_rates[band] = supp_rates |
-                               ieee80211_mandatory_rates(local, band);
-
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-                       if (sta->sta.supp_rates[band] != prev_rates)
-                               printk(KERN_DEBUG "%s: updated supp_rates set "
-                                   "for %pM based on beacon info (0x%llx | "
-                                   "0x%llx -> 0x%llx)\n",
-                                   sdata->dev->name,
-                                   sta->sta.addr,
-                                   (unsigned long long) prev_rates,
-                                   (unsigned long long) supp_rates,
-                                   (unsigned long long) sta->sta.supp_rates[band]);
-#endif
-               } else {
-                       ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
-               }
-
-               rcu_read_unlock();
-       }
-
        bss = ieee80211_bss_info_update(local, rx_status, mgmt, len, elems,
                                        channel, beacon);
        if (!bss)
                return;
 
        if (elems->ch_switch_elem && (elems->ch_switch_elem_len == 3) &&
-           (memcmp(mgmt->bssid, sdata->u.sta.bssid, ETH_ALEN) == 0)) {
+           (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN) == 0)) {
                struct ieee80211_channel_sw_ie *sw_elem =
                        (struct ieee80211_channel_sw_ie *)elems->ch_switch_elem;
                ieee80211_process_chanswitch(sdata, sw_elem, bss);
        }
 
-       /* was just updated in ieee80211_bss_info_update */
-       beacon_timestamp = bss->cbss.tsf;
-
-       if (sdata->vif.type != NL80211_IFTYPE_ADHOC)
-               goto put_bss;
-
-       /* check if we need to merge IBSS */
-
-       /* merge only on beacons (???) */
-       if (!beacon)
-               goto put_bss;
-
-       /* we use a fixed BSSID */
-       if (sdata->u.sta.flags & IEEE80211_STA_BSSID_SET)
-               goto put_bss;
-
-       /* not an IBSS */
-       if (!(bss->cbss.capability & WLAN_CAPABILITY_IBSS))
-               goto put_bss;
-
-       /* different channel */
-       if (bss->cbss.channel != local->oper_channel)
-               goto put_bss;
-
-       /* different SSID */
-       if (elems->ssid_len != sdata->u.sta.ssid_len ||
-           memcmp(elems->ssid, sdata->u.sta.ssid,
-                               sdata->u.sta.ssid_len))
-               goto put_bss;
-
-       if (rx_status->flag & RX_FLAG_TSFT) {
-               /*
-                * For correct IBSS merging we need mactime; since mactime is
-                * defined as the time the first data symbol of the frame hits
-                * the PHY, and the timestamp of the beacon is defined as "the
-                * time that the data symbol containing the first bit of the
-                * timestamp is transmitted to the PHY plus the transmitting
-                * STA's delays through its local PHY from the MAC-PHY
-                * interface to its interface with the WM" (802.11 11.1.2)
-                * - equals the time this bit arrives at the receiver - we have
-                * to take into account the offset between the two.
-                *
-                * E.g. at 1 MBit that means mactime is 192 usec earlier
-                * (=24 bytes * 8 usecs/byte) than the beacon timestamp.
-                */
-               int rate;
-
-               if (rx_status->flag & RX_FLAG_HT)
-                       rate = 65; /* TODO: HT rates */
-               else
-                       rate = local->hw.wiphy->bands[band]->
-                               bitrates[rx_status->rate_idx].bitrate;
-
-               rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
-       } else if (local && local->ops && local->ops->get_tsf)
-               /* second best option: get current TSF */
-               rx_timestamp = local->ops->get_tsf(local_to_hw(local));
-       else
-               /* can't merge without knowing the TSF */
-               rx_timestamp = -1LLU;
-
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-       printk(KERN_DEBUG "RX beacon SA=%pM BSSID="
-              "%pM TSF=0x%llx BCN=0x%llx diff=%lld @%lu\n",
-              mgmt->sa, mgmt->bssid,
-              (unsigned long long)rx_timestamp,
-              (unsigned long long)beacon_timestamp,
-              (unsigned long long)(rx_timestamp - beacon_timestamp),
-              jiffies);
-#endif
-
-       if (beacon_timestamp > rx_timestamp) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-               printk(KERN_DEBUG "%s: beacon TSF higher than "
-                      "local TSF - IBSS merge with BSSID %pM\n",
-                      sdata->dev->name, mgmt->bssid);
-#endif
-               ieee80211_sta_join_ibss(sdata, &sdata->u.sta, bss);
-               ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, supp_rates);
-       }
-
- put_bss:
        ieee80211_rx_bss_put(local, bss);
 }
 
@@ -1857,7 +1395,6 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
 {
        size_t baselen;
        struct ieee802_11_elems elems;
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
 
        if (memcmp(mgmt->da, sdata->dev->dev_addr, ETH_ALEN))
                return; /* ignore ProbeResp to foreign address */
@@ -1873,20 +1410,19 @@ static void ieee80211_rx_mgmt_probe_resp(struct ieee80211_sub_if_data *sdata,
 
        /* direct probe may be part of the association flow */
        if (test_and_clear_bit(IEEE80211_STA_REQ_DIRECT_PROBE,
-                                                       &ifsta->request)) {
+           &sdata->u.mgd.request)) {
                printk(KERN_DEBUG "%s direct probe responded\n",
                       sdata->dev->name);
-               ieee80211_authenticate(sdata, ifsta);
+               ieee80211_authenticate(sdata);
        }
 }
 
-
 static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                                     struct ieee80211_mgmt *mgmt,
                                     size_t len,
                                     struct ieee80211_rx_status *rx_status)
 {
-       struct ieee80211_if_sta *ifsta;
+       struct ieee80211_if_managed *ifmgd;
        size_t baselen;
        struct ieee802_11_elems elems;
        struct ieee80211_local *local = sdata->local;
@@ -1905,21 +1441,21 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 
        if (sdata->vif.type != NL80211_IFTYPE_STATION)
                return;
-       ifsta = &sdata->u.sta;
 
-       if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED) ||
-           memcmp(ifsta->bssid, mgmt->bssid, ETH_ALEN) != 0)
+       ifmgd = &sdata->u.mgd;
+
+       if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED) ||
+           memcmp(ifmgd->bssid, mgmt->bssid, ETH_ALEN) != 0)
                return;
 
        if (rx_status->freq != local->hw.conf.channel->center_freq)
                return;
 
-       ieee80211_sta_wmm_params(local, ifsta, elems.wmm_param,
+       ieee80211_sta_wmm_params(local, ifmgd, elems.wmm_param,
                                 elems.wmm_param_len);
 
-       if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK &&
-           local->hw.conf.flags & IEEE80211_CONF_PS) {
-               directed_tim = ieee80211_check_tim(&elems, ifsta->aid);
+       if (local->hw.flags & IEEE80211_HW_PS_NULLFUNC_STACK) {
+               directed_tim = ieee80211_check_tim(&elems, ifmgd->aid);
 
                if (directed_tim) {
                        if (local->hw.conf.dynamic_ps_timeout > 0) {
@@ -1954,14 +1490,15 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                        erp_valid, erp_value);
 
 
-       if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param) {
+       if (elems.ht_cap_elem && elems.ht_info_elem && elems.wmm_param &&
+           !(ifmgd->flags & IEEE80211_STA_TKIP_WEP_USED)) {
                struct sta_info *sta;
                struct ieee80211_supported_band *sband;
                u16 ap_ht_cap_flags;
 
                rcu_read_lock();
 
-               sta = sta_info_get(local, ifsta->bssid);
+               sta = sta_info_get(local, ifmgd->bssid);
                if (!sta) {
                        rcu_read_unlock();
                        return;
@@ -1997,85 +1534,16 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
        ieee80211_bss_info_change_notify(sdata, changed);
 }
 
-
-static void ieee80211_rx_mgmt_probe_req(struct ieee80211_sub_if_data *sdata,
-                                       struct ieee80211_if_sta *ifsta,
-                                       struct ieee80211_mgmt *mgmt,
-                                       size_t len)
+ieee80211_rx_result ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata,
+                                         struct sk_buff *skb,
+                                         struct ieee80211_rx_status *rx_status)
 {
        struct ieee80211_local *local = sdata->local;
-       int tx_last_beacon;
-       struct sk_buff *skb;
-       struct ieee80211_mgmt *resp;
-       u8 *pos, *end;
-
-       if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED ||
-           len < 24 + 2 || !ifsta->probe_resp)
-               return;
-
-       if (local->ops->tx_last_beacon)
-               tx_last_beacon = local->ops->tx_last_beacon(local_to_hw(local));
-       else
-               tx_last_beacon = 1;
-
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-       printk(KERN_DEBUG "%s: RX ProbeReq SA=%pM DA=%pM BSSID=%pM"
-              " (tx_last_beacon=%d)\n",
-              sdata->dev->name, mgmt->sa, mgmt->da,
-              mgmt->bssid, tx_last_beacon);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
-
-       if (!tx_last_beacon)
-               return;
-
-       if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0 &&
-           memcmp(mgmt->bssid, "\xff\xff\xff\xff\xff\xff", ETH_ALEN) != 0)
-               return;
-
-       end = ((u8 *) mgmt) + len;
-       pos = mgmt->u.probe_req.variable;
-       if (pos[0] != WLAN_EID_SSID ||
-           pos + 2 + pos[1] > end) {
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-               printk(KERN_DEBUG "%s: Invalid SSID IE in ProbeReq "
-                      "from %pM\n",
-                      sdata->dev->name, mgmt->sa);
-#endif
-               return;
-       }
-       if (pos[1] != 0 &&
-           (pos[1] != ifsta->ssid_len ||
-            memcmp(pos + 2, ifsta->ssid, ifsta->ssid_len) != 0)) {
-               /* Ignore ProbeReq for foreign SSID */
-               return;
-       }
-
-       /* Reply with ProbeResp */
-       skb = skb_copy(ifsta->probe_resp, GFP_KERNEL);
-       if (!skb)
-               return;
-
-       resp = (struct ieee80211_mgmt *) skb->data;
-       memcpy(resp->da, mgmt->sa, ETH_ALEN);
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-       printk(KERN_DEBUG "%s: Sending ProbeResp to %pM\n",
-              sdata->dev->name, resp->da);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
-       ieee80211_tx_skb(sdata, skb, 0);
-}
-
-void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
-                          struct ieee80211_rx_status *rx_status)
-{
-       struct ieee80211_local *local = sdata->local;
-       struct ieee80211_if_sta *ifsta;
        struct ieee80211_mgmt *mgmt;
        u16 fc;
 
        if (skb->len < 24)
-               goto fail;
-
-       ifsta = &sdata->u.sta;
+               return RX_DROP_MONITOR;
 
        mgmt = (struct ieee80211_mgmt *) skb->data;
        fc = le16_to_cpu(mgmt->frame_control);
@@ -2090,147 +1558,68 @@ void ieee80211_sta_rx_mgmt(struct ieee80211_sub_if_data *sdata, struct sk_buff *
        case IEEE80211_STYPE_REASSOC_RESP:
        case IEEE80211_STYPE_DEAUTH:
        case IEEE80211_STYPE_DISASSOC:
-               skb_queue_tail(&ifsta->skb_queue, skb);
-               queue_work(local->hw.workqueue, &ifsta->work);
-               return;
+               skb_queue_tail(&sdata->u.mgd.skb_queue, skb);
+               queue_work(local->hw.workqueue, &sdata->u.mgd.work);
+               return RX_QUEUED;
        }
 
- fail:
-       kfree_skb(skb);
+       return RX_DROP_MONITOR;
 }
 
 static void ieee80211_sta_rx_queued_mgmt(struct ieee80211_sub_if_data *sdata,
                                         struct sk_buff *skb)
 {
        struct ieee80211_rx_status *rx_status;
-       struct ieee80211_if_sta *ifsta;
        struct ieee80211_mgmt *mgmt;
        u16 fc;
 
-       ifsta = &sdata->u.sta;
-
        rx_status = (struct ieee80211_rx_status *) skb->cb;
        mgmt = (struct ieee80211_mgmt *) skb->data;
        fc = le16_to_cpu(mgmt->frame_control);
 
-       if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
-               switch (fc & IEEE80211_FCTL_STYPE) {
-               case IEEE80211_STYPE_PROBE_REQ:
-                       ieee80211_rx_mgmt_probe_req(sdata, ifsta, mgmt,
-                                                   skb->len);
-                       break;
-               case IEEE80211_STYPE_PROBE_RESP:
-                       ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len,
-                                                    rx_status);
-                       break;
-               case IEEE80211_STYPE_BEACON:
-                       ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
-                                                rx_status);
-                       break;
-               case IEEE80211_STYPE_AUTH:
-                       ieee80211_rx_mgmt_auth_ibss(sdata, ifsta, mgmt,
-                                                   skb->len);
-                       break;
-               }
-       } else { /* NL80211_IFTYPE_STATION */
-               switch (fc & IEEE80211_FCTL_STYPE) {
-               case IEEE80211_STYPE_PROBE_RESP:
-                       ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len,
-                                                    rx_status);
-                       break;
-               case IEEE80211_STYPE_BEACON:
-                       ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
-                                                rx_status);
-                       break;
-               case IEEE80211_STYPE_AUTH:
-                       ieee80211_rx_mgmt_auth(sdata, ifsta, mgmt, skb->len);
-                       break;
-               case IEEE80211_STYPE_ASSOC_RESP:
-                       ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt,
-                                                    skb->len, 0);
-                       break;
-               case IEEE80211_STYPE_REASSOC_RESP:
-                       ieee80211_rx_mgmt_assoc_resp(sdata, ifsta, mgmt,
-                                                    skb->len, 1);
-                       break;
-               case IEEE80211_STYPE_DEAUTH:
-                       ieee80211_rx_mgmt_deauth(sdata, ifsta, mgmt, skb->len);
-                       break;
-               case IEEE80211_STYPE_DISASSOC:
-                       ieee80211_rx_mgmt_disassoc(sdata, ifsta, mgmt,
-                                                  skb->len);
-                       break;
-               }
+       switch (fc & IEEE80211_FCTL_STYPE) {
+       case IEEE80211_STYPE_PROBE_RESP:
+               ieee80211_rx_mgmt_probe_resp(sdata, mgmt, skb->len,
+                                            rx_status);
+               break;
+       case IEEE80211_STYPE_BEACON:
+               ieee80211_rx_mgmt_beacon(sdata, mgmt, skb->len,
+                                        rx_status);
+               break;
+       case IEEE80211_STYPE_AUTH:
+               ieee80211_rx_mgmt_auth(sdata, mgmt, skb->len);
+               break;
+       case IEEE80211_STYPE_ASSOC_RESP:
+               ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 0);
+               break;
+       case IEEE80211_STYPE_REASSOC_RESP:
+               ieee80211_rx_mgmt_assoc_resp(sdata, mgmt, skb->len, 1);
+               break;
+       case IEEE80211_STYPE_DEAUTH:
+               ieee80211_rx_mgmt_deauth(sdata, mgmt, skb->len);
+               break;
+       case IEEE80211_STYPE_DISASSOC:
+               ieee80211_rx_mgmt_disassoc(sdata, mgmt, skb->len);
+               break;
        }
 
        kfree_skb(skb);
 }
 
-
-static int ieee80211_sta_active_ibss(struct ieee80211_sub_if_data *sdata)
-{
-       struct ieee80211_local *local = sdata->local;
-       int active = 0;
-       struct sta_info *sta;
-
-       rcu_read_lock();
-
-       list_for_each_entry_rcu(sta, &local->sta_list, list) {
-               if (sta->sdata == sdata &&
-                   time_after(sta->last_rx + IEEE80211_IBSS_MERGE_INTERVAL,
-                              jiffies)) {
-                       active++;
-                       break;
-               }
-       }
-
-       rcu_read_unlock();
-
-       return active;
-}
-
-
-static void ieee80211_sta_merge_ibss(struct ieee80211_sub_if_data *sdata,
-                                    struct ieee80211_if_sta *ifsta)
-{
-       mod_timer(&ifsta->timer, jiffies + IEEE80211_IBSS_MERGE_INTERVAL);
-
-       ieee80211_sta_expire(sdata, IEEE80211_IBSS_INACTIVITY_LIMIT);
-       if (ieee80211_sta_active_ibss(sdata))
-               return;
-
-       if ((sdata->u.sta.flags & IEEE80211_STA_BSSID_SET) &&
-           (!(sdata->u.sta.flags & IEEE80211_STA_AUTO_CHANNEL_SEL)))
-               return;
-
-       printk(KERN_DEBUG "%s: No active IBSS STAs - trying to scan for other "
-              "IBSS networks with same SSID (merge)\n", sdata->dev->name);
-
-       /* XXX maybe racy? */
-       if (sdata->local->scan_req)
-               return;
-
-       memcpy(sdata->local->int_scan_req.ssids[0].ssid,
-              ifsta->ssid, IEEE80211_MAX_SSID_LEN);
-       sdata->local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len;
-       ieee80211_request_scan(sdata, &sdata->local->int_scan_req);
-}
-
-
 static void ieee80211_sta_timer(unsigned long data)
 {
        struct ieee80211_sub_if_data *sdata =
                (struct ieee80211_sub_if_data *) data;
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
 
-       set_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);
-       queue_work(local->hw.workqueue, &ifsta->work);
+       set_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request);
+       queue_work(local->hw.workqueue, &ifmgd->work);
 }
 
-static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata,
-                                    struct ieee80211_if_sta *ifsta)
+static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata)
 {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
 
        if (local->ops->reset_tsf) {
@@ -2238,191 +1627,39 @@ static void ieee80211_sta_reset_auth(struct ieee80211_sub_if_data *sdata,
                local->ops->reset_tsf(local_to_hw(local));
        }
 
-       ifsta->wmm_last_param_set = -1; /* allow any WMM update */
+       ifmgd->wmm_last_param_set = -1; /* allow any WMM update */
 
 
-       if (ifsta->auth_algs & IEEE80211_AUTH_ALG_OPEN)
-               ifsta->auth_alg = WLAN_AUTH_OPEN;
-       else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)
-               ifsta->auth_alg = WLAN_AUTH_SHARED_KEY;
-       else if (ifsta->auth_algs & IEEE80211_AUTH_ALG_LEAP)
-               ifsta->auth_alg = WLAN_AUTH_LEAP;
+       if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_OPEN)
+               ifmgd->auth_alg = WLAN_AUTH_OPEN;
+       else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_SHARED_KEY)
+               ifmgd->auth_alg = WLAN_AUTH_SHARED_KEY;
+       else if (ifmgd->auth_algs & IEEE80211_AUTH_ALG_LEAP)
+               ifmgd->auth_alg = WLAN_AUTH_LEAP;
        else
-               ifsta->auth_alg = WLAN_AUTH_OPEN;
-       ifsta->auth_transaction = -1;
-       ifsta->flags &= ~IEEE80211_STA_ASSOCIATED;
-       ifsta->assoc_scan_tries = 0;
-       ifsta->direct_probe_tries = 0;
-       ifsta->auth_tries = 0;
-       ifsta->assoc_tries = 0;
+               ifmgd->auth_alg = WLAN_AUTH_OPEN;
+       ifmgd->auth_transaction = -1;
+       ifmgd->flags &= ~IEEE80211_STA_ASSOCIATED;
+       ifmgd->assoc_scan_tries = 0;
+       ifmgd->direct_probe_tries = 0;
+       ifmgd->auth_tries = 0;
+       ifmgd->assoc_tries = 0;
        netif_tx_stop_all_queues(sdata->dev);
        netif_carrier_off(sdata->dev);
 }
 
-static int ieee80211_sta_create_ibss(struct ieee80211_sub_if_data *sdata,
-                                    struct ieee80211_if_sta *ifsta)
-{
-       struct ieee80211_local *local = sdata->local;
-       struct ieee80211_supported_band *sband;
-       u8 *pos;
-       u8 bssid[ETH_ALEN];
-       u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
-       u16 capability;
-       int i;
-
-       if (sdata->u.sta.flags & IEEE80211_STA_BSSID_SET) {
-               memcpy(bssid, ifsta->bssid, ETH_ALEN);
-       } else {
-               /* Generate random, not broadcast, locally administered BSSID. Mix in
-                * own MAC address to make sure that devices that do not have proper
-                * random number generator get different BSSID. */
-               get_random_bytes(bssid, ETH_ALEN);
-               for (i = 0; i < ETH_ALEN; i++)
-                       bssid[i] ^= sdata->dev->dev_addr[i];
-               bssid[0] &= ~0x01;
-               bssid[0] |= 0x02;
-       }
-
-       printk(KERN_DEBUG "%s: Creating new IBSS network, BSSID %pM\n",
-              sdata->dev->name, bssid);
-
-       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
-
-       if (local->hw.conf.beacon_int == 0)
-               local->hw.conf.beacon_int = 100;
-
-       capability = WLAN_CAPABILITY_IBSS;
-
-       if (sdata->default_key)
-               capability |= WLAN_CAPABILITY_PRIVACY;
-       else
-               sdata->drop_unencrypted = 0;
-
-       pos = supp_rates;
-       for (i = 0; i < sband->n_bitrates; i++) {
-               int rate = sband->bitrates[i].bitrate;
-               *pos++ = (u8) (rate / 5);
-       }
-
-       return __ieee80211_sta_join_ibss(sdata, ifsta,
-                                        bssid, local->hw.conf.beacon_int,
-                                        local->hw.conf.channel->center_freq,
-                                        sband->n_bitrates, supp_rates,
-                                        capability);
-}
-
-
-static int ieee80211_sta_find_ibss(struct ieee80211_sub_if_data *sdata,
-                                  struct ieee80211_if_sta *ifsta)
-{
-       struct ieee80211_local *local = sdata->local;
-       struct ieee80211_bss *bss;
-       int active_ibss;
-
-       if (ifsta->ssid_len == 0)
-               return -EINVAL;
-
-       active_ibss = ieee80211_sta_active_ibss(sdata);
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-       printk(KERN_DEBUG "%s: sta_find_ibss (active_ibss=%d)\n",
-              sdata->dev->name, active_ibss);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
-
-       if (active_ibss)
-               return 0;
-
-       if (ifsta->flags & IEEE80211_STA_BSSID_SET)
-               bss = ieee80211_rx_bss_get(local, ifsta->bssid, 0,
-                                          ifsta->ssid, ifsta->ssid_len);
-       else
-               bss = (void *)cfg80211_get_ibss(local->hw.wiphy,
-                                               NULL,
-                                               ifsta->ssid, ifsta->ssid_len);
-
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-       if (bss)
-               printk(KERN_DEBUG "   sta_find_ibss: selected %pM current "
-                      "%pM\n", bss->cbss.bssid, ifsta->bssid);
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
-
-       if (bss &&
-           (!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET) ||
-            memcmp(ifsta->bssid, bss->cbss.bssid, ETH_ALEN))) {
-               int ret;
-
-               printk(KERN_DEBUG "%s: Selected IBSS BSSID %pM"
-                      " based on configured SSID\n",
-                      sdata->dev->name, bss->cbss.bssid);
-
-               ret = ieee80211_sta_join_ibss(sdata, ifsta, bss);
-               ieee80211_rx_bss_put(local, bss);
-               return ret;
-       } else if (bss)
-               ieee80211_rx_bss_put(local, bss);
-
-#ifdef CONFIG_MAC80211_IBSS_DEBUG
-       printk(KERN_DEBUG "   did not try to join ibss\n");
-#endif /* CONFIG_MAC80211_IBSS_DEBUG */
-
-       /* Selected IBSS not found in current scan results - try to scan */
-       if (ifsta->state == IEEE80211_STA_MLME_IBSS_JOINED &&
-           !ieee80211_sta_active_ibss(sdata)) {
-               mod_timer(&ifsta->timer, jiffies +
-                                     IEEE80211_IBSS_MERGE_INTERVAL);
-       } else if (time_after(jiffies, local->last_scan_completed +
-                             IEEE80211_SCAN_INTERVAL)) {
-               printk(KERN_DEBUG "%s: Trigger new scan to find an IBSS to "
-                      "join\n", sdata->dev->name);
-
-               /* XXX maybe racy? */
-               if (local->scan_req)
-                       return -EBUSY;
-
-               memcpy(local->int_scan_req.ssids[0].ssid,
-                      ifsta->ssid, IEEE80211_MAX_SSID_LEN);
-               local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len;
-               return ieee80211_request_scan(sdata, &local->int_scan_req);
-       } else if (ifsta->state != IEEE80211_STA_MLME_IBSS_JOINED) {
-               int interval = IEEE80211_SCAN_INTERVAL;
-
-               if (time_after(jiffies, ifsta->ibss_join_req +
-                              IEEE80211_IBSS_JOIN_TIMEOUT)) {
-                       if ((ifsta->flags & IEEE80211_STA_CREATE_IBSS) &&
-                           (!(local->oper_channel->flags &
-                                       IEEE80211_CHAN_NO_IBSS)))
-                               return ieee80211_sta_create_ibss(sdata, ifsta);
-                       if (ifsta->flags & IEEE80211_STA_CREATE_IBSS) {
-                               printk(KERN_DEBUG "%s: IBSS not allowed on"
-                                      " %d MHz\n", sdata->dev->name,
-                                      local->hw.conf.channel->center_freq);
-                       }
-
-                       /* No IBSS found - decrease scan interval and continue
-                        * scanning. */
-                       interval = IEEE80211_SCAN_INTERVAL_SLOW;
-               }
-
-               ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH;
-               mod_timer(&ifsta->timer, jiffies + interval);
-               return 0;
-       }
-
-       return 0;
-}
-
-
-static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata,
-                                    struct ieee80211_if_sta *ifsta)
+static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata)
 {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
        struct ieee80211_bss *bss;
-       u8 *bssid = ifsta->bssid, *ssid = ifsta->ssid;
-       u8 ssid_len = ifsta->ssid_len;
+       u8 *bssid = ifmgd->bssid, *ssid = ifmgd->ssid;
+       u8 ssid_len = ifmgd->ssid_len;
        u16 capa_mask = WLAN_CAPABILITY_ESS;
        u16 capa_val = WLAN_CAPABILITY_ESS;
        struct ieee80211_channel *chan = local->oper_channel;
 
-       if (ifsta->flags & (IEEE80211_STA_AUTO_SSID_SEL |
+       if (ifmgd->flags & (IEEE80211_STA_AUTO_SSID_SEL |
                            IEEE80211_STA_AUTO_BSSID_SEL |
                            IEEE80211_STA_AUTO_CHANNEL_SEL)) {
                capa_mask |= WLAN_CAPABILITY_PRIVACY;
@@ -2430,13 +1667,13 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata,
                        capa_val |= WLAN_CAPABILITY_PRIVACY;
        }
 
-       if (ifsta->flags & IEEE80211_STA_AUTO_CHANNEL_SEL)
+       if (ifmgd->flags & IEEE80211_STA_AUTO_CHANNEL_SEL)
                chan = NULL;
 
-       if (ifsta->flags & IEEE80211_STA_AUTO_BSSID_SEL)
+       if (ifmgd->flags & IEEE80211_STA_AUTO_BSSID_SEL)
                bssid = NULL;
 
-       if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL) {
+       if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL) {
                ssid = NULL;
                ssid_len = 0;
        }
@@ -2447,16 +1684,16 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata,
 
        if (bss) {
                ieee80211_set_freq(sdata, bss->cbss.channel->center_freq);
-               if (!(ifsta->flags & IEEE80211_STA_SSID_SET))
+               if (!(ifmgd->flags & IEEE80211_STA_SSID_SET))
                        ieee80211_sta_set_ssid(sdata, bss->ssid,
                                               bss->ssid_len);
                ieee80211_sta_set_bssid(sdata, bss->cbss.bssid);
                ieee80211_sta_def_wmm_params(sdata, bss->supp_rates_len,
                                                    bss->supp_rates);
-               if (sdata->u.sta.mfp == IEEE80211_MFP_REQUIRED)
-                       sdata->u.sta.flags |= IEEE80211_STA_MFP_ENABLED;
+               if (sdata->u.mgd.mfp == IEEE80211_MFP_REQUIRED)
+                       sdata->u.mgd.flags |= IEEE80211_STA_MFP_ENABLED;
                else
-                       sdata->u.sta.flags &= ~IEEE80211_STA_MFP_ENABLED;
+                       sdata->u.mgd.flags &= ~IEEE80211_STA_MFP_ENABLED;
 
                /* Send out direct probe if no probe resp was received or
                 * the one we have is outdated
@@ -2464,31 +1701,34 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata,
                if (!bss->last_probe_resp ||
                    time_after(jiffies, bss->last_probe_resp
                                        + IEEE80211_SCAN_RESULT_EXPIRE))
-                       ifsta->state = IEEE80211_STA_MLME_DIRECT_PROBE;
+                       ifmgd->state = IEEE80211_STA_MLME_DIRECT_PROBE;
                else
-                       ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
+                       ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;
 
                ieee80211_rx_bss_put(local, bss);
-               ieee80211_sta_reset_auth(sdata, ifsta);
+               ieee80211_sta_reset_auth(sdata);
                return 0;
        } else {
-               if (ifsta->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) {
-                       ifsta->assoc_scan_tries++;
+               if (ifmgd->assoc_scan_tries < IEEE80211_ASSOC_SCANS_MAX_TRIES) {
+                       ifmgd->assoc_scan_tries++;
                        /* XXX maybe racy? */
                        if (local->scan_req)
                                return -1;
                        memcpy(local->int_scan_req.ssids[0].ssid,
-                              ifsta->ssid, IEEE80211_MAX_SSID_LEN);
-                       if (ifsta->flags & IEEE80211_STA_AUTO_SSID_SEL)
+                              ifmgd->ssid, IEEE80211_MAX_SSID_LEN);
+                       if (ifmgd->flags & IEEE80211_STA_AUTO_SSID_SEL)
                                local->int_scan_req.ssids[0].ssid_len = 0;
                        else
-                               local->int_scan_req.ssids[0].ssid_len = ifsta->ssid_len;
-                       ieee80211_start_scan(sdata, &local->int_scan_req);
-                       ifsta->state = IEEE80211_STA_MLME_AUTHENTICATE;
-                       set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
+                               local->int_scan_req.ssids[0].ssid_len = ifmgd->ssid_len;
+
+                       if (ieee80211_start_scan(sdata, &local->int_scan_req))
+                               ieee80211_scan_failed(local);
+
+                       ifmgd->state = IEEE80211_STA_MLME_AUTHENTICATE;
+                       set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request);
                } else {
-                       ifsta->assoc_scan_tries = 0;
-                       ifsta->state = IEEE80211_STA_MLME_DISABLED;
+                       ifmgd->assoc_scan_tries = 0;
+                       ifmgd->state = IEEE80211_STA_MLME_DISABLED;
                }
        }
        return -1;
@@ -2498,9 +1738,9 @@ static int ieee80211_sta_config_auth(struct ieee80211_sub_if_data *sdata,
 static void ieee80211_sta_work(struct work_struct *work)
 {
        struct ieee80211_sub_if_data *sdata =
-               container_of(work, struct ieee80211_sub_if_data, u.sta.work);
+               container_of(work, struct ieee80211_sub_if_data, u.mgd.work);
        struct ieee80211_local *local = sdata->local;
-       struct ieee80211_if_sta *ifsta;
+       struct ieee80211_if_managed *ifmgd;
        struct sk_buff *skb;
 
        if (!netif_running(sdata->dev))
@@ -2509,60 +1749,60 @@ static void ieee80211_sta_work(struct work_struct *work)
        if (local->sw_scanning || local->hw_scanning)
                return;
 
-       if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION &&
-                   sdata->vif.type != NL80211_IFTYPE_ADHOC))
+       if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
                return;
-       ifsta = &sdata->u.sta;
+       ifmgd = &sdata->u.mgd;
 
-       while ((skb = skb_dequeue(&ifsta->skb_queue)))
+       while ((skb = skb_dequeue(&ifmgd->skb_queue)))
                ieee80211_sta_rx_queued_mgmt(sdata, skb);
 
-       if (ifsta->state != IEEE80211_STA_MLME_DIRECT_PROBE &&
-           ifsta->state != IEEE80211_STA_MLME_AUTHENTICATE &&
-           ifsta->state != IEEE80211_STA_MLME_ASSOCIATE &&
-           test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request)) {
-               ieee80211_start_scan(sdata, local->scan_req);
+       if (ifmgd->state != IEEE80211_STA_MLME_DIRECT_PROBE &&
+           ifmgd->state != IEEE80211_STA_MLME_AUTHENTICATE &&
+           ifmgd->state != IEEE80211_STA_MLME_ASSOCIATE &&
+           test_and_clear_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request)) {
+               /*
+                * The call to ieee80211_start_scan can fail but ieee80211_request_scan
+                * (which queued ieee80211_sta_work) did not return an error. Thus, call
+                * ieee80211_scan_failed here if ieee80211_start_scan fails in order to
+                * notify the scan requester.
+                */
+               if (ieee80211_start_scan(sdata, local->scan_req))
+                       ieee80211_scan_failed(local);
                return;
        }
 
-       if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request)) {
-               if (ieee80211_sta_config_auth(sdata, ifsta))
+       if (test_and_clear_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request)) {
+               if (ieee80211_sta_config_auth(sdata))
                        return;
-               clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request);
-       } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifsta->request))
+               clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request);
+       } else if (!test_and_clear_bit(IEEE80211_STA_REQ_RUN, &ifmgd->request))
                return;
 
-       switch (ifsta->state) {
+       switch (ifmgd->state) {
        case IEEE80211_STA_MLME_DISABLED:
                break;
        case IEEE80211_STA_MLME_DIRECT_PROBE:
-               ieee80211_direct_probe(sdata, ifsta);
+               ieee80211_direct_probe(sdata);
                break;
        case IEEE80211_STA_MLME_AUTHENTICATE:
-               ieee80211_authenticate(sdata, ifsta);
+               ieee80211_authenticate(sdata);
                break;
        case IEEE80211_STA_MLME_ASSOCIATE:
-               ieee80211_associate(sdata, ifsta);
+               ieee80211_associate(sdata);
                break;
        case IEEE80211_STA_MLME_ASSOCIATED:
-               ieee80211_associated(sdata, ifsta);
-               break;
-       case IEEE80211_STA_MLME_IBSS_SEARCH:
-               ieee80211_sta_find_ibss(sdata, ifsta);
-               break;
-       case IEEE80211_STA_MLME_IBSS_JOINED:
-               ieee80211_sta_merge_ibss(sdata, ifsta);
+               ieee80211_associated(sdata);
                break;
        default:
                WARN_ON(1);
                break;
        }
 
-       if (ieee80211_privacy_mismatch(sdata, ifsta)) {
+       if (ieee80211_privacy_mismatch(sdata)) {
                printk(KERN_DEBUG "%s: privacy configuration mismatch and "
                       "mixed-cell disabled - disassociate\n", sdata->dev->name);
 
-               ieee80211_set_disassoc(sdata, ifsta, false, true,
+               ieee80211_set_disassoc(sdata, false, true,
                                        WLAN_REASON_UNSPECIFIED);
        }
 }
@@ -2571,155 +1811,106 @@ static void ieee80211_restart_sta_timer(struct ieee80211_sub_if_data *sdata)
 {
        if (sdata->vif.type == NL80211_IFTYPE_STATION)
                queue_work(sdata->local->hw.workqueue,
-                          &sdata->u.sta.work);
+                          &sdata->u.mgd.work);
 }
 
 /* interface setup */
 void ieee80211_sta_setup_sdata(struct ieee80211_sub_if_data *sdata)
 {
-       struct ieee80211_if_sta *ifsta;
+       struct ieee80211_if_managed *ifmgd;
 
-       ifsta = &sdata->u.sta;
-       INIT_WORK(&ifsta->work, ieee80211_sta_work);
-       INIT_WORK(&ifsta->chswitch_work, ieee80211_chswitch_work);
-       setup_timer(&ifsta->timer, ieee80211_sta_timer,
+       ifmgd = &sdata->u.mgd;
+       INIT_WORK(&ifmgd->work, ieee80211_sta_work);
+       INIT_WORK(&ifmgd->chswitch_work, ieee80211_chswitch_work);
+       setup_timer(&ifmgd->timer, ieee80211_sta_timer,
                    (unsigned long) sdata);
-       setup_timer(&ifsta->chswitch_timer, ieee80211_chswitch_timer,
+       setup_timer(&ifmgd->chswitch_timer, ieee80211_chswitch_timer,
                    (unsigned long) sdata);
-       skb_queue_head_init(&ifsta->skb_queue);
+       skb_queue_head_init(&ifmgd->skb_queue);
 
-       ifsta->capab = WLAN_CAPABILITY_ESS;
-       ifsta->auth_algs = IEEE80211_AUTH_ALG_OPEN |
+       ifmgd->capab = WLAN_CAPABILITY_ESS;
+       ifmgd->auth_algs = IEEE80211_AUTH_ALG_OPEN |
                IEEE80211_AUTH_ALG_SHARED_KEY;
-       ifsta->flags |= IEEE80211_STA_CREATE_IBSS |
+       ifmgd->flags |= IEEE80211_STA_CREATE_IBSS |
                IEEE80211_STA_AUTO_BSSID_SEL |
                IEEE80211_STA_AUTO_CHANNEL_SEL;
        if (ieee80211_num_regular_queues(&sdata->local->hw) >= 4)
-               ifsta->flags |= IEEE80211_STA_WMM_ENABLED;
-}
-
-/*
- * Add a new IBSS station, will also be called by the RX code when,
- * in IBSS mode, receiving a frame from a yet-unknown station, hence
- * must be callable in atomic context.
- */
-struct sta_info *ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
-                                       u8 *bssid,u8 *addr, u32 supp_rates)
-{
-       struct ieee80211_local *local = sdata->local;
-       struct sta_info *sta;
-       int band = local->hw.conf.channel->band;
-
-       /* TODO: Could consider removing the least recently used entry and
-        * allow new one to be added. */
-       if (local->num_sta >= IEEE80211_IBSS_MAX_STA_ENTRIES) {
-               if (net_ratelimit()) {
-                       printk(KERN_DEBUG "%s: No room for a new IBSS STA "
-                              "entry %pM\n", sdata->dev->name, addr);
-               }
-               return NULL;
-       }
-
-       if (compare_ether_addr(bssid, sdata->u.sta.bssid))
-               return NULL;
-
-#ifdef CONFIG_MAC80211_VERBOSE_DEBUG
-       printk(KERN_DEBUG "%s: Adding new IBSS station %pM (dev=%s)\n",
-              wiphy_name(local->hw.wiphy), addr, sdata->dev->name);
-#endif
-
-       sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
-       if (!sta)
-               return NULL;
-
-       set_sta_flags(sta, WLAN_STA_AUTHORIZED);
-
-       /* make sure mandatory rates are always added */
-       sta->sta.supp_rates[band] = supp_rates |
-                       ieee80211_mandatory_rates(local, band);
-
-       rate_control_rate_init(sta);
-
-       if (sta_info_insert(sta))
-               return NULL;
-
-       return sta;
+               ifmgd->flags |= IEEE80211_STA_WMM_ENABLED;
 }
 
 /* configuration hooks */
-void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata,
-                           struct ieee80211_if_sta *ifsta)
+void ieee80211_sta_req_auth(struct ieee80211_sub_if_data *sdata)
 {
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        struct ieee80211_local *local = sdata->local;
 
-       if (sdata->vif.type != NL80211_IFTYPE_STATION)
+       if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
                return;
 
-       if ((ifsta->flags & (IEEE80211_STA_BSSID_SET |
+       if ((ifmgd->flags & (IEEE80211_STA_BSSID_SET |
                             IEEE80211_STA_AUTO_BSSID_SEL)) &&
-           (ifsta->flags & (IEEE80211_STA_SSID_SET |
+           (ifmgd->flags & (IEEE80211_STA_SSID_SET |
                             IEEE80211_STA_AUTO_SSID_SEL))) {
 
-               if (ifsta->state == IEEE80211_STA_MLME_ASSOCIATED)
-                       ieee80211_set_disassoc(sdata, ifsta, true, true,
+               if (ifmgd->state == IEEE80211_STA_MLME_ASSOCIATED)
+                       ieee80211_set_disassoc(sdata, true, true,
                                               WLAN_REASON_DEAUTH_LEAVING);
 
-               set_bit(IEEE80211_STA_REQ_AUTH, &ifsta->request);
-               queue_work(local->hw.workqueue, &ifsta->work);
+               set_bit(IEEE80211_STA_REQ_AUTH, &ifmgd->request);
+               queue_work(local->hw.workqueue, &ifmgd->work);
        }
 }
 
-int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len)
+int ieee80211_sta_commit(struct ieee80211_sub_if_data *sdata)
 {
-       struct ieee80211_if_sta *ifsta;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
-       if (len > IEEE80211_MAX_SSID_LEN)
-               return -EINVAL;
+       ifmgd->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
 
-       ifsta = &sdata->u.sta;
+       if (ifmgd->ssid_len)
+               ifmgd->flags |= IEEE80211_STA_SSID_SET;
+       else
+               ifmgd->flags &= ~IEEE80211_STA_SSID_SET;
 
-       if (ifsta->ssid_len != len || memcmp(ifsta->ssid, ssid, len) != 0) {
-               memset(ifsta->ssid, 0, sizeof(ifsta->ssid));
-               memcpy(ifsta->ssid, ssid, len);
-               ifsta->ssid_len = len;
-       }
+       return 0;
+}
 
-       ifsta->flags &= ~IEEE80211_STA_PREV_BSSID_SET;
+int ieee80211_sta_set_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t len)
+{
+       struct ieee80211_if_managed *ifmgd;
 
-       if (len)
-               ifsta->flags |= IEEE80211_STA_SSID_SET;
-       else
-               ifsta->flags &= ~IEEE80211_STA_SSID_SET;
+       if (len > IEEE80211_MAX_SSID_LEN)
+               return -EINVAL;
+
+       ifmgd = &sdata->u.mgd;
 
-       if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
-               ifsta->ibss_join_req = jiffies;
-               ifsta->state = IEEE80211_STA_MLME_IBSS_SEARCH;
-               return ieee80211_sta_find_ibss(sdata, ifsta);
+       if (ifmgd->ssid_len != len || memcmp(ifmgd->ssid, ssid, len) != 0) {
+               memset(ifmgd->ssid, 0, sizeof(ifmgd->ssid));
+               memcpy(ifmgd->ssid, ssid, len);
+               ifmgd->ssid_len = len;
        }
 
-       return 0;
+       return ieee80211_sta_commit(sdata);
 }
 
 int ieee80211_sta_get_ssid(struct ieee80211_sub_if_data *sdata, char *ssid, size_t *len)
 {
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-       memcpy(ssid, ifsta->ssid, ifsta->ssid_len);
-       *len = ifsta->ssid_len;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
+       memcpy(ssid, ifmgd->ssid, ifmgd->ssid_len);
+       *len = ifmgd->ssid_len;
        return 0;
 }
 
 int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid)
 {
-       struct ieee80211_if_sta *ifsta;
-
-       ifsta = &sdata->u.sta;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
        if (is_valid_ether_addr(bssid)) {
-               memcpy(ifsta->bssid, bssid, ETH_ALEN);
-               ifsta->flags |= IEEE80211_STA_BSSID_SET;
+               memcpy(ifmgd->bssid, bssid, ETH_ALEN);
+               ifmgd->flags |= IEEE80211_STA_BSSID_SET;
        } else {
-               memset(ifsta->bssid, 0, ETH_ALEN);
-               ifsta->flags &= ~IEEE80211_STA_BSSID_SET;
+               memset(ifmgd->bssid, 0, ETH_ALEN);
+               ifmgd->flags &= ~IEEE80211_STA_BSSID_SET;
        }
 
        if (netif_running(sdata->dev)) {
@@ -2729,47 +1920,44 @@ int ieee80211_sta_set_bssid(struct ieee80211_sub_if_data *sdata, u8 *bssid)
                }
        }
 
-       return ieee80211_sta_set_ssid(sdata, ifsta->ssid, ifsta->ssid_len);
+       return ieee80211_sta_commit(sdata);
 }
 
 int ieee80211_sta_set_extra_ie(struct ieee80211_sub_if_data *sdata, char *ie, size_t len)
 {
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
-       kfree(ifsta->extra_ie);
+       kfree(ifmgd->extra_ie);
        if (len == 0) {
-               ifsta->extra_ie = NULL;
-               ifsta->extra_ie_len = 0;
+               ifmgd->extra_ie = NULL;
+               ifmgd->extra_ie_len = 0;
                return 0;
        }
-       ifsta->extra_ie = kmalloc(len, GFP_KERNEL);
-       if (!ifsta->extra_ie) {
-               ifsta->extra_ie_len = 0;
+       ifmgd->extra_ie = kmalloc(len, GFP_KERNEL);
+       if (!ifmgd->extra_ie) {
+               ifmgd->extra_ie_len = 0;
                return -ENOMEM;
        }
-       memcpy(ifsta->extra_ie, ie, len);
-       ifsta->extra_ie_len = len;
+       memcpy(ifmgd->extra_ie, ie, len);
+       ifmgd->extra_ie_len = len;
        return 0;
 }
 
 int ieee80211_sta_deauthenticate(struct ieee80211_sub_if_data *sdata, u16 reason)
 {
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-
        printk(KERN_DEBUG "%s: deauthenticating by local choice (reason=%d)\n",
               sdata->dev->name, reason);
 
-       if (sdata->vif.type != NL80211_IFTYPE_STATION &&
-           sdata->vif.type != NL80211_IFTYPE_ADHOC)
+       if (sdata->vif.type != NL80211_IFTYPE_STATION)
                return -EINVAL;
 
-       ieee80211_set_disassoc(sdata, ifsta, true, true, reason);
+       ieee80211_set_disassoc(sdata, true, true, reason);
        return 0;
 }
 
 int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason)
 {
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
        printk(KERN_DEBUG "%s: disassociating by local choice (reason=%d)\n",
               sdata->dev->name, reason);
@@ -2777,10 +1965,10 @@ int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason)
        if (sdata->vif.type != NL80211_IFTYPE_STATION)
                return -EINVAL;
 
-       if (!(ifsta->flags & IEEE80211_STA_ASSOCIATED))
-               return -1;
+       if (!(ifmgd->flags & IEEE80211_STA_ASSOCIATED))
+               return -ENOLINK;
 
-       ieee80211_set_disassoc(sdata, ifsta, false, true, reason);
+       ieee80211_set_disassoc(sdata, false, true, reason);
        return 0;
 }
 
@@ -2788,14 +1976,6 @@ int ieee80211_sta_disassociate(struct ieee80211_sub_if_data *sdata, u16 reason)
 void ieee80211_mlme_notify_scan_completed(struct ieee80211_local *local)
 {
        struct ieee80211_sub_if_data *sdata = local->scan_sdata;
-       struct ieee80211_if_sta *ifsta;
-
-       if (sdata && sdata->vif.type == NL80211_IFTYPE_ADHOC) {
-               ifsta = &sdata->u.sta;
-               if ((!(ifsta->flags & IEEE80211_STA_PREV_BSSID_SET)) ||
-                   !ieee80211_sta_active_ibss(sdata))
-                       ieee80211_sta_find_ibss(sdata, ifsta);
-       }
 
        /* Restart STA timers */
        rcu_read_lock();
@@ -2842,3 +2022,36 @@ void ieee80211_dynamic_ps_timer(unsigned long data)
 
        queue_work(local->hw.workqueue, &local->dynamic_ps_enable_work);
 }
+
+void ieee80211_send_nullfunc(struct ieee80211_local *local,
+                            struct ieee80211_sub_if_data *sdata,
+                            int powersave)
+{
+       struct sk_buff *skb;
+       struct ieee80211_hdr *nullfunc;
+       __le16 fc;
+
+       if (WARN_ON(sdata->vif.type != NL80211_IFTYPE_STATION))
+               return;
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
+       if (!skb) {
+               printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
+                      "frame\n", sdata->dev->name);
+               return;
+       }
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+
+       nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
+       memset(nullfunc, 0, 24);
+       fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
+                        IEEE80211_FCTL_TODS);
+       if (powersave)
+               fc |= cpu_to_le16(IEEE80211_FCTL_PM);
+       nullfunc->frame_control = fc;
+       memcpy(nullfunc->addr1, sdata->u.mgd.bssid, ETH_ALEN);
+       memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(nullfunc->addr3, sdata->u.mgd.bssid, ETH_ALEN);
+
+       ieee80211_tx_skb(sdata, skb, 0);
+}
index 928da625e281557ccecc0f1923def7b9bfa72415..b9164c9a9563750ebd1f604931d0548b3242be07 100644 (file)
@@ -62,6 +62,18 @@ static inline void rate_control_rate_init(struct sta_info *sta)
        ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
 }
 
+static inline void rate_control_rate_update(struct ieee80211_local *local,
+                                   struct ieee80211_supported_band *sband,
+                                   struct sta_info *sta, u32 changed)
+{
+       struct rate_control_ref *ref = local->rate_ctrl;
+       struct ieee80211_sta *ista = &sta->sta;
+       void *priv_sta = sta->rate_ctrl_priv;
+
+       if (ref->ops->rate_update)
+               ref->ops->rate_update(ref->priv, sband, ista,
+                                     priv_sta, changed);
+}
 
 static inline void *rate_control_alloc_sta(struct rate_control_ref *ref,
                                           struct ieee80211_sta *sta,
index 1327d424bf3138675b69588cfb513145768a5323..66f7ecf51b924078a8ea52e6f88e85c3ff1f07d4 100644 (file)
@@ -838,7 +838,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
        if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
                u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
                                                NL80211_IFTYPE_ADHOC);
-               if (compare_ether_addr(bssid, rx->sdata->u.sta.bssid) == 0)
+               if (compare_ether_addr(bssid, rx->sdata->u.ibss.bssid) == 0)
                        sta->last_rx = jiffies;
        } else
        if (!is_multicast_ether_addr(hdr->addr1) ||
@@ -1702,13 +1702,13 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
                return;
        }
 
-       if (compare_ether_addr(mgmt->sa, sdata->u.sta.bssid) != 0 ||
-           compare_ether_addr(mgmt->bssid, sdata->u.sta.bssid) != 0) {
+       if (compare_ether_addr(mgmt->sa, sdata->u.mgd.bssid) != 0 ||
+           compare_ether_addr(mgmt->bssid, sdata->u.mgd.bssid) != 0) {
                /* Not from the current AP. */
                return;
        }
 
-       if (sdata->u.sta.state == IEEE80211_STA_MLME_ASSOCIATE) {
+       if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATE) {
                /* Association in progress; ignore SA Query */
                return;
        }
@@ -1727,7 +1727,7 @@ static void ieee80211_process_sa_query_req(struct ieee80211_sub_if_data *sdata,
        memset(resp, 0, 24);
        memcpy(resp->da, mgmt->sa, ETH_ALEN);
        memcpy(resp->sa, sdata->dev->dev_addr, ETH_ALEN);
-       memcpy(resp->bssid, sdata->u.sta.bssid, ETH_ALEN);
+       memcpy(resp->bssid, sdata->u.mgd.bssid, ETH_ALEN);
        resp->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
                                          IEEE80211_STYPE_ACTION);
        skb_put(skb, 1 + sizeof(resp->u.action.u.sa_query));
@@ -1745,7 +1745,6 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_local *local = rx->local;
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(rx->dev);
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *) rx->skb->data;
        struct ieee80211_bss *bss;
        int len = rx->skb->len;
@@ -1803,6 +1802,10 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
        case WLAN_CATEGORY_SPECTRUM_MGMT:
                if (local->hw.conf.channel->band != IEEE80211_BAND_5GHZ)
                        return RX_DROP_MONITOR;
+
+               if (sdata->vif.type != NL80211_IFTYPE_STATION)
+                       return RX_DROP_MONITOR;
+
                switch (mgmt->u.action.u.measurement.action_code) {
                case WLAN_ACTION_SPCT_MSR_REQ:
                        if (len < (IEEE80211_MIN_ACTION_SIZE +
@@ -1815,12 +1818,13 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                                   sizeof(mgmt->u.action.u.chan_switch)))
                                return RX_DROP_MONITOR;
 
-                       if (memcmp(mgmt->bssid, ifsta->bssid, ETH_ALEN) != 0)
+                       if (memcmp(mgmt->bssid, sdata->u.mgd.bssid, ETH_ALEN))
                                return RX_DROP_MONITOR;
 
-                       bss = ieee80211_rx_bss_get(local, ifsta->bssid,
+                       bss = ieee80211_rx_bss_get(local, sdata->u.mgd.bssid,
                                           local->hw.conf.channel->center_freq,
-                                          ifsta->ssid, ifsta->ssid_len);
+                                          sdata->u.mgd.ssid,
+                                          sdata->u.mgd.ssid_len);
                        if (!bss)
                                return RX_DROP_MONITOR;
 
@@ -1876,11 +1880,14 @@ ieee80211_rx_h_mgmt(struct ieee80211_rx_data *rx)
            sdata->vif.type != NL80211_IFTYPE_ADHOC)
                return RX_DROP_MONITOR;
 
-       if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
-               return RX_DROP_MONITOR;
 
-       ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status);
-       return RX_QUEUED;
+       if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+               if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
+                       return RX_DROP_MONITOR;
+               return ieee80211_sta_rx_mgmt(sdata, rx->skb, rx->status);
+       }
+
+       return ieee80211_ibss_rx_mgmt(sdata, rx->skb, rx->status);
 }
 
 static void ieee80211_rx_michael_mic_report(struct net_device *dev,
@@ -2083,7 +2090,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
        case NL80211_IFTYPE_STATION:
                if (!bssid)
                        return 0;
-               if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
+               if (!ieee80211_bssid_match(bssid, sdata->u.mgd.bssid)) {
                        if (!(rx->flags & IEEE80211_RX_IN_SCAN))
                                return 0;
                        rx->flags &= ~IEEE80211_RX_RA_MATCH;
@@ -2101,7 +2108,7 @@ static int prepare_for_handlers(struct ieee80211_sub_if_data *sdata,
                if (ieee80211_is_beacon(hdr->frame_control)) {
                        return 1;
                }
-               else if (!ieee80211_bssid_match(bssid, sdata->u.sta.bssid)) {
+               else if (!ieee80211_bssid_match(bssid, sdata->u.ibss.bssid)) {
                        if (!(rx->flags & IEEE80211_RX_IN_SCAN))
                                return 0;
                        rx->flags &= ~IEEE80211_RX_RA_MATCH;
index f883ab9f1e6e436de1f4a311963410a341a931cd..5030a3c87509a28fe8957d10cc4312e4f9ee99f9 100644 (file)
@@ -63,20 +63,15 @@ ieee80211_bss_info_update(struct ieee80211_local *local,
 {
        struct ieee80211_bss *bss;
        int clen;
-       enum cfg80211_signal_type sigtype = CFG80211_SIGNAL_TYPE_NONE;
        s32 signal = 0;
 
-       if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
-               sigtype = CFG80211_SIGNAL_TYPE_MBM;
+       if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
                signal = rx_status->signal * 100;
-       } else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) {
-               sigtype = CFG80211_SIGNAL_TYPE_UNSPEC;
+       else if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
                signal = (rx_status->signal * 100) / local->hw.max_signal;
-       }
 
        bss = (void *)cfg80211_inform_bss_frame(local->hw.wiphy, channel,
-                                               mgmt, len, signal, sigtype,
-                                               GFP_ATOMIC);
+                                               mgmt, len, signal, GFP_ATOMIC);
 
        if (!bss)
                return NULL;
@@ -207,34 +202,16 @@ ieee80211_scan_rx(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
        return RX_QUEUED;
 }
 
-void ieee80211_send_nullfunc(struct ieee80211_local *local,
-                                   struct ieee80211_sub_if_data *sdata,
-                                   int powersave)
+void ieee80211_scan_failed(struct ieee80211_local *local)
 {
-       struct sk_buff *skb;
-       struct ieee80211_hdr *nullfunc;
-       __le16 fc;
-
-       skb = dev_alloc_skb(local->hw.extra_tx_headroom + 24);
-       if (!skb) {
-               printk(KERN_DEBUG "%s: failed to allocate buffer for nullfunc "
-                      "frame\n", sdata->dev->name);
+       if (WARN_ON(!local->scan_req))
                return;
-       }
-       skb_reserve(skb, local->hw.extra_tx_headroom);
-
-       nullfunc = (struct ieee80211_hdr *) skb_put(skb, 24);
-       memset(nullfunc, 0, 24);
-       fc = cpu_to_le16(IEEE80211_FTYPE_DATA | IEEE80211_STYPE_NULLFUNC |
-                        IEEE80211_FCTL_TODS);
-       if (powersave)
-               fc |= cpu_to_le16(IEEE80211_FCTL_PM);
-       nullfunc->frame_control = fc;
-       memcpy(nullfunc->addr1, sdata->u.sta.bssid, ETH_ALEN);
-       memcpy(nullfunc->addr2, sdata->dev->dev_addr, ETH_ALEN);
-       memcpy(nullfunc->addr3, sdata->u.sta.bssid, ETH_ALEN);
-
-       ieee80211_tx_skb(sdata, skb, 0);
+
+       /* notify cfg80211 about the failed scan */
+       if (local->scan_req != &local->int_scan_req)
+               cfg80211_scan_done(local->scan_req, true);
+
+       local->scan_req = NULL;
 }
 
 void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
@@ -280,6 +257,9 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
        netif_addr_unlock(local->mdev);
        netif_tx_unlock_bh(local->mdev);
 
+       if (local->ops->sw_scan_complete)
+               local->ops->sw_scan_complete(local_to_hw(local));
+
        mutex_lock(&local->iflist_mtx);
        list_for_each_entry(sdata, &local->interfaces, list) {
                if (!netif_running(sdata->dev))
@@ -287,7 +267,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 
                /* Tell AP we're back */
                if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-                       if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
+                       if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
                                ieee80211_send_nullfunc(local, sdata, 0);
                                netif_tx_wake_all_queues(sdata->dev);
                        }
@@ -305,6 +285,7 @@ void ieee80211_scan_completed(struct ieee80211_hw *hw, bool aborted)
 
  done:
        ieee80211_mlme_notify_scan_completed(local);
+       ieee80211_ibss_notify_scan_completed(local);
        ieee80211_mesh_notify_scan_completed(local);
 }
 EXPORT_SYMBOL(ieee80211_scan_completed);
@@ -367,7 +348,8 @@ void ieee80211_scan_work(struct work_struct *work)
                        ieee80211_send_probe_req(
                                sdata, NULL,
                                local->scan_req->ssids[i].ssid,
-                               local->scan_req->ssids[i].ssid_len);
+                               local->scan_req->ssids[i].ssid_len,
+                               local->scan_req->ie, local->scan_req->ie_len);
                next_delay = IEEE80211_CHANNEL_TIME;
                break;
        }
@@ -428,6 +410,8 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
        }
 
        local->sw_scanning = true;
+       if (local->ops->sw_scan_start)
+               local->ops->sw_scan_start(local_to_hw(local));
 
        mutex_lock(&local->iflist_mtx);
        list_for_each_entry(sdata, &local->interfaces, list) {
@@ -442,7 +426,7 @@ int ieee80211_start_scan(struct ieee80211_sub_if_data *scan_sdata,
                                            IEEE80211_IFCC_BEACON_ENABLED);
 
                if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-                       if (sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED) {
+                       if (sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED) {
                                netif_tx_stop_all_queues(sdata->dev);
                                ieee80211_send_nullfunc(local, sdata, 1);
                        }
@@ -477,7 +461,7 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
                           struct cfg80211_scan_request *req)
 {
        struct ieee80211_local *local = sdata->local;
-       struct ieee80211_if_sta *ifsta;
+       struct ieee80211_if_managed *ifmgd;
 
        if (!req)
                return -EINVAL;
@@ -502,9 +486,9 @@ int ieee80211_request_scan(struct ieee80211_sub_if_data *sdata,
                return -EBUSY;
        }
 
-       ifsta = &sdata->u.sta;
-       set_bit(IEEE80211_STA_REQ_SCAN, &ifsta->request);
-       queue_work(local->hw.workqueue, &ifsta->work);
+       ifmgd = &sdata->u.mgd;
+       set_bit(IEEE80211_STA_REQ_SCAN, &ifmgd->request);
+       queue_work(local->hw.workqueue, &ifmgd->work);
 
        return 0;
 }
index 47bb2aed2813fd980e99fe55724fbdf62ce77bf3..5f7a2624ed7475988d541418ef738494dc0d11e0 100644 (file)
@@ -88,16 +88,16 @@ void ieee80211_process_measurement_req(struct ieee80211_sub_if_data *sdata,
 void ieee80211_chswitch_work(struct work_struct *work)
 {
        struct ieee80211_sub_if_data *sdata =
-               container_of(work, struct ieee80211_sub_if_data, u.sta.chswitch_work);
+               container_of(work, struct ieee80211_sub_if_data, u.mgd.chswitch_work);
        struct ieee80211_bss *bss;
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
        if (!netif_running(sdata->dev))
                return;
 
-       bss = ieee80211_rx_bss_get(sdata->local, ifsta->bssid,
+       bss = ieee80211_rx_bss_get(sdata->local, ifmgd->bssid,
                                   sdata->local->hw.conf.channel->center_freq,
-                                  ifsta->ssid, ifsta->ssid_len);
+                                  ifmgd->ssid, ifmgd->ssid_len);
        if (!bss)
                goto exit;
 
@@ -108,7 +108,7 @@ void ieee80211_chswitch_work(struct work_struct *work)
 
        ieee80211_rx_bss_put(sdata->local, bss);
 exit:
-       ifsta->flags &= ~IEEE80211_STA_CSA_RECEIVED;
+       ifmgd->flags &= ~IEEE80211_STA_CSA_RECEIVED;
        ieee80211_wake_queues_by_reason(&sdata->local->hw,
                                        IEEE80211_QUEUE_STOP_REASON_CSA);
 }
@@ -117,9 +117,9 @@ void ieee80211_chswitch_timer(unsigned long data)
 {
        struct ieee80211_sub_if_data *sdata =
                (struct ieee80211_sub_if_data *) data;
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
 
-       queue_work(sdata->local->hw.workqueue, &ifsta->chswitch_work);
+       queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work);
 }
 
 void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata,
@@ -127,14 +127,14 @@ void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                                  struct ieee80211_bss *bss)
 {
        struct ieee80211_channel *new_ch;
-       struct ieee80211_if_sta *ifsta = &sdata->u.sta;
+       struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        int new_freq = ieee80211_channel_to_frequency(sw_elem->new_ch_num);
 
        /* FIXME: Handle ADHOC later */
        if (sdata->vif.type != NL80211_IFTYPE_STATION)
                return;
 
-       if (ifsta->state != IEEE80211_STA_MLME_ASSOCIATED)
+       if (ifmgd->state != IEEE80211_STA_MLME_ASSOCIATED)
                return;
 
        if (sdata->local->sw_scanning || sdata->local->hw_scanning)
@@ -143,7 +143,7 @@ void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        /* Disregard subsequent beacons if we are already running a timer
           processing a CSA */
 
-       if (ifsta->flags & IEEE80211_STA_CSA_RECEIVED)
+       if (ifmgd->flags & IEEE80211_STA_CSA_RECEIVED)
                return;
 
        new_ch = ieee80211_get_channel(sdata->local->hw.wiphy, new_freq);
@@ -153,12 +153,12 @@ void ieee80211_process_chanswitch(struct ieee80211_sub_if_data *sdata,
        sdata->local->csa_channel = new_ch;
 
        if (sw_elem->count <= 1) {
-               queue_work(sdata->local->hw.workqueue, &ifsta->chswitch_work);
+               queue_work(sdata->local->hw.workqueue, &ifmgd->chswitch_work);
        } else {
                ieee80211_stop_queues_by_reason(&sdata->local->hw,
                                                IEEE80211_QUEUE_STOP_REASON_CSA);
-               ifsta->flags |= IEEE80211_STA_CSA_RECEIVED;
-               mod_timer(&ifsta->chswitch_timer,
+               ifmgd->flags |= IEEE80211_STA_CSA_RECEIVED;
+               mod_timer(&ifmgd->chswitch_timer,
                          jiffies +
                          msecs_to_jiffies(sw_elem->count *
                                           bss->cbss.beacon_interval));
index 634f65c0130e2ca0f21c8a2645d2d4f4352d7dd8..4ba3c540fcf3adedf2402833b67bf2cedc9d6b8a 100644 (file)
@@ -202,6 +202,18 @@ void sta_info_destroy(struct sta_info *sta)
                /* Make sure timer won't free the tid_rx struct, see below */
                if (tid_rx)
                        tid_rx->shutdown = true;
+
+               /*
+                * The stop callback cannot find this station any more, but
+                * it didn't complete its work -- start the queue if necessary
+                */
+               if (sta->ampdu_mlme.tid_state_tx[i] & HT_AGG_STATE_INITIATOR_MSK &&
+                   sta->ampdu_mlme.tid_state_tx[i] & HT_AGG_STATE_REQ_STOP_BA_MSK &&
+                   local->hw.ampdu_queues)
+                       ieee80211_wake_queue_by_reason(&local->hw,
+                               local->hw.queues + sta->tid_to_tx_q[i],
+                               IEEE80211_QUEUE_STOP_REASON_AGGREGATION);
+
                spin_unlock_bh(&sta->lock);
 
                /*
@@ -275,8 +287,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
                 * enable session_timer's data differentiation. refer to
                 * sta_rx_agg_session_timer_expired for useage */
                sta->timer_to_tid[i] = i;
-               /* tid to tx queue: initialize according to HW (0 is valid) */
-               sta->tid_to_tx_q[i] = ieee80211_num_queues(&local->hw);
+               sta->tid_to_tx_q[i] = -1;
                /* rx */
                sta->ampdu_mlme.tid_state_rx[i] = HT_AGG_STATE_IDLE;
                sta->ampdu_mlme.tid_rx[i] = NULL;
index d9653231992fb1e882429ada4e871ba50e1a435d..1f45573c580c4a837857f714290c8128faf2567e 100644 (file)
@@ -90,6 +90,7 @@ struct tid_ampdu_tx {
  * @buf_size: buffer size for incoming A-MPDUs
  * @timeout: reset timer value (in TUs).
  * @dialog_token: dialog token for aggregation session
+ * @shutdown: this session is being shut down due to STA removal
  */
 struct tid_ampdu_rx {
        struct sk_buff **reorder_buf;
@@ -200,7 +201,7 @@ struct sta_ampdu_mlme {
  * @tid_seq: per-TID sequence numbers for sending to this STA
  * @ampdu_mlme: A-MPDU state machine state
  * @timer_to_tid: identity mapping to ID timers
- * @tid_to_tx_q: map tid to tx queue
+ * @tid_to_tx_q: map tid to tx queue (invalid == negative values)
  * @llid: Local link ID
  * @plid: Peer link ID
  * @reason: Cancel reason on PLINK_HOLDING state
@@ -275,7 +276,7 @@ struct sta_info {
         */
        struct sta_ampdu_mlme ampdu_mlme;
        u8 timer_to_tid[STA_TID_NUM];
-       u8 tid_to_tx_q[STA_TID_NUM];
+       s8 tid_to_tx_q[STA_TID_NUM];
 
 #ifdef CONFIG_MAC80211_MESH
        /*
index 33926831c64889cc5836fafe065a6f9dd9d5cebd..457238a2f3fc392a087944c7edb5808b2b004c37 100644 (file)
@@ -784,6 +784,8 @@ ieee80211_tx_h_fragment(struct ieee80211_tx_data *tx)
                skb_copy_queue_mapping(frag, first);
 
                frag->do_not_encrypt = first->do_not_encrypt;
+               frag->dev = first->dev;
+               frag->iif = first->iif;
 
                pos += copylen;
                left -= copylen;
@@ -876,7 +878,6 @@ ieee80211_tx_h_stats(struct ieee80211_tx_data *tx)
        return TX_CONTINUE;
 }
 
-
 /* actual transmit path */
 
 /*
@@ -1016,12 +1017,20 @@ __ieee80211_tx_prepare(struct ieee80211_tx_data *tx,
        tx->sta = sta_info_get(local, hdr->addr1);
 
        if (tx->sta && ieee80211_is_data_qos(hdr->frame_control)) {
+               unsigned long flags;
                qc = ieee80211_get_qos_ctl(hdr);
                tid = *qc & IEEE80211_QOS_CTL_TID_MASK;
 
+               spin_lock_irqsave(&tx->sta->lock, flags);
                state = &tx->sta->ampdu_mlme.tid_state_tx[tid];
-               if (*state == HT_AGG_STATE_OPERATIONAL)
+               if (*state == HT_AGG_STATE_OPERATIONAL) {
                        info->flags |= IEEE80211_TX_CTL_AMPDU;
+                       if (local->hw.ampdu_queues)
+                               skb_set_queue_mapping(
+                                       skb, tx->local->hw.queues +
+                                            tx->sta->tid_to_tx_q[tid]);
+               }
+               spin_unlock_irqrestore(&tx->sta->lock, flags);
        }
 
        if (is_multicast_ether_addr(hdr->addr1)) {
@@ -1085,7 +1094,8 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
        int ret, i;
 
        if (skb) {
-               if (netif_subqueue_stopped(local->mdev, skb))
+               if (ieee80211_queue_stopped(&local->hw,
+                                           skb_get_queue_mapping(skb)))
                        return IEEE80211_TX_PENDING;
 
                ret = local->ops->tx(local_to_hw(local), skb);
@@ -1101,8 +1111,8 @@ static int __ieee80211_tx(struct ieee80211_local *local, struct sk_buff *skb,
                        info = IEEE80211_SKB_CB(tx->extra_frag[i]);
                        info->flags &= ~(IEEE80211_TX_CTL_CLEAR_PS_FILT |
                                         IEEE80211_TX_CTL_FIRST_FRAGMENT);
-                       if (netif_subqueue_stopped(local->mdev,
-                                                  tx->extra_frag[i]))
+                       if (ieee80211_queue_stopped(&local->hw,
+                                       skb_get_queue_mapping(tx->extra_frag[i])))
                                return IEEE80211_TX_FRAG_AGAIN;
 
                        ret = local->ops->tx(local_to_hw(local),
@@ -1625,7 +1635,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
        case NL80211_IFTYPE_STATION:
                fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
                /* BSSID SA DA */
-               memcpy(hdr.addr1, sdata->u.sta.bssid, ETH_ALEN);
+               memcpy(hdr.addr1, sdata->u.mgd.bssid, ETH_ALEN);
                memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
                memcpy(hdr.addr3, skb->data, ETH_ALEN);
                hdrlen = 24;
@@ -1634,7 +1644,7 @@ int ieee80211_subif_start_xmit(struct sk_buff *skb,
                /* DA SA BSSID */
                memcpy(hdr.addr1, skb->data, ETH_ALEN);
                memcpy(hdr.addr2, skb->data + ETH_ALEN, ETH_ALEN);
-               memcpy(hdr.addr3, sdata->u.sta.bssid, ETH_ALEN);
+               memcpy(hdr.addr3, sdata->u.ibss.bssid, ETH_ALEN);
                hdrlen = 24;
                break;
        default:
@@ -1920,7 +1930,6 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
        struct ieee80211_tx_info *info;
        struct ieee80211_sub_if_data *sdata = NULL;
        struct ieee80211_if_ap *ap = NULL;
-       struct ieee80211_if_sta *ifsta = NULL;
        struct beacon_data *beacon;
        struct ieee80211_supported_band *sband;
        enum ieee80211_band band = local->hw.conf.channel->band;
@@ -1972,13 +1981,13 @@ struct sk_buff *ieee80211_beacon_get(struct ieee80211_hw *hw,
                } else
                        goto out;
        } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+               struct ieee80211_if_ibss *ifibss = &sdata->u.ibss;
                struct ieee80211_hdr *hdr;
-               ifsta = &sdata->u.sta;
 
-               if (!ifsta->probe_resp)
+               if (!ifibss->probe_resp)
                        goto out;
 
-               skb = skb_copy(ifsta->probe_resp, GFP_ATOMIC);
+               skb = skb_copy(ifibss->probe_resp, GFP_ATOMIC);
                if (!skb)
                        goto out;
 
index 73c7d7345abd19877e320dc40f559ed7d9180611..e0431a1d218b1a299c092560c6d07b4f6c181780 100644 (file)
@@ -344,15 +344,36 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
 {
        struct ieee80211_local *local = hw_to_local(hw);
 
-       /* we don't need to track ampdu queues */
-       if (queue < ieee80211_num_regular_queues(hw)) {
-               __clear_bit(reason, &local->queue_stop_reasons[queue]);
+       if (queue >= hw->queues) {
+               if (local->ampdu_ac_queue[queue - hw->queues] < 0)
+                       return;
+
+               /*
+                * for virtual aggregation queues, we need to refcount the
+                * internal mac80211 disable (multiple times!), keep track of
+                * driver disable _and_ make sure the regular queue is
+                * actually enabled.
+                */
+               if (reason == IEEE80211_QUEUE_STOP_REASON_AGGREGATION)
+                       local->amdpu_ac_stop_refcnt[queue - hw->queues]--;
+               else
+                       __clear_bit(reason, &local->queue_stop_reasons[queue]);
 
-               if (local->queue_stop_reasons[queue] != 0)
-                       /* someone still has this queue stopped */
+               if (local->queue_stop_reasons[queue] ||
+                   local->amdpu_ac_stop_refcnt[queue - hw->queues])
                        return;
+
+               /* now go on to treat the corresponding regular queue */
+               queue = local->ampdu_ac_queue[queue - hw->queues];
+               reason = IEEE80211_QUEUE_STOP_REASON_AGGREGATION;
        }
 
+       __clear_bit(reason, &local->queue_stop_reasons[queue]);
+
+       if (local->queue_stop_reasons[queue] != 0)
+               /* someone still has this queue stopped */
+               return;
+
        if (test_bit(queue, local->queues_pending)) {
                set_bit(queue, local->queues_pending_run);
                tasklet_schedule(&local->tx_pending_tasklet);
@@ -361,8 +382,8 @@ static void __ieee80211_wake_queue(struct ieee80211_hw *hw, int queue,
        }
 }
 
-static void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
-                                          enum queue_stop_reason reason)
+void ieee80211_wake_queue_by_reason(struct ieee80211_hw *hw, int queue,
+                                   enum queue_stop_reason reason)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        unsigned long flags;
@@ -384,15 +405,33 @@ static void __ieee80211_stop_queue(struct ieee80211_hw *hw, int queue,
 {
        struct ieee80211_local *local = hw_to_local(hw);
 
-       /* we don't need to track ampdu queues */
-       if (queue < ieee80211_num_regular_queues(hw))
-               __set_bit(reason, &local->queue_stop_reasons[queue]);
+       if (queue >= hw->queues) {
+               if (local->ampdu_ac_queue[queue - hw->queues] < 0)
+                       return;
+
+               /*
+                * for virtual aggregation queues, we need to refcount the
+                * internal mac80211 disable (multiple times!), keep track of
+                * driver disable _and_ make sure the regular queue is
+                * actually enabled.
+                */
+               if (reason == IEEE80211_QUEUE_STOP_REASON_AGGREGATION)
+                       local->amdpu_ac_stop_refcnt[queue - hw->queues]++;
+               else
+                       __set_bit(reason, &local->queue_stop_reasons[queue]);
+
+               /* now go on to treat the corresponding regular queue */
+               queue = local->ampdu_ac_queue[queue - hw->queues];
+               reason = IEEE80211_QUEUE_STOP_REASON_AGGREGATION;
+       }
+
+       __set_bit(reason, &local->queue_stop_reasons[queue]);
 
        netif_stop_subqueue(local->mdev, queue);
 }
 
-static void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
-                                          enum queue_stop_reason reason)
+void ieee80211_stop_queue_by_reason(struct ieee80211_hw *hw, int queue,
+                                   enum queue_stop_reason reason)
 {
        struct ieee80211_local *local = hw_to_local(hw);
        unsigned long flags;
@@ -418,7 +457,7 @@ void ieee80211_stop_queues_by_reason(struct ieee80211_hw *hw,
 
        spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
 
-       for (i = 0; i < ieee80211_num_queues(hw); i++)
+       for (i = 0; i < hw->queues; i++)
                __ieee80211_stop_queue(hw, i, reason);
 
        spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
@@ -434,6 +473,16 @@ EXPORT_SYMBOL(ieee80211_stop_queues);
 int ieee80211_queue_stopped(struct ieee80211_hw *hw, int queue)
 {
        struct ieee80211_local *local = hw_to_local(hw);
+       unsigned long flags;
+
+       if (queue >= hw->queues) {
+               spin_lock_irqsave(&local->queue_stop_reason_lock, flags);
+               queue = local->ampdu_ac_queue[queue - hw->queues];
+               spin_unlock_irqrestore(&local->queue_stop_reason_lock, flags);
+               if (queue < 0)
+                       return true;
+       }
+
        return __netif_subqueue_stopped(local->mdev, queue);
 }
 EXPORT_SYMBOL(ieee80211_queue_stopped);
@@ -701,6 +750,27 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata)
                local->ops->conf_tx(local_to_hw(local), i, &qparam);
 }
 
+void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
+                                 const size_t supp_rates_len,
+                                 const u8 *supp_rates)
+{
+       struct ieee80211_local *local = sdata->local;
+       int i, have_higher_than_11mbit = 0;
+
+       /* cf. IEEE 802.11 9.2.12 */
+       for (i = 0; i < supp_rates_len; i++)
+               if ((supp_rates[i] & 0x7f) * 5 > 110)
+                       have_higher_than_11mbit = 1;
+
+       if (local->hw.conf.channel->band == IEEE80211_BAND_2GHZ &&
+           have_higher_than_11mbit)
+               sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
+       else
+               sdata->flags &= ~IEEE80211_SDATA_OPERATING_GMODE;
+
+       ieee80211_set_wmm_default(sdata);
+}
+
 void ieee80211_tx_skb(struct ieee80211_sub_if_data *sdata, struct sk_buff *skb,
                      int encrypt)
 {
@@ -767,3 +837,161 @@ u32 ieee80211_mandatory_rates(struct ieee80211_local *local,
                        mandatory_rates |= BIT(i);
        return mandatory_rates;
 }
+
+void ieee80211_send_auth(struct ieee80211_sub_if_data *sdata,
+                        u16 transaction, u16 auth_alg,
+                        u8 *extra, size_t extra_len,
+                        const u8 *bssid, int encrypt)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct sk_buff *skb;
+       struct ieee80211_mgmt *mgmt;
+       const u8 *ie_auth = NULL;
+       int ie_auth_len = 0;
+
+       if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+               ie_auth_len = sdata->u.mgd.ie_auth_len;
+               ie_auth = sdata->u.mgd.ie_auth;
+       }
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom +
+                           sizeof(*mgmt) + 6 + extra_len + ie_auth_len);
+       if (!skb) {
+               printk(KERN_DEBUG "%s: failed to allocate buffer for auth "
+                      "frame\n", sdata->dev->name);
+               return;
+       }
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+
+       mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24 + 6);
+       memset(mgmt, 0, 24 + 6);
+       mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                         IEEE80211_STYPE_AUTH);
+       if (encrypt)
+               mgmt->frame_control |= cpu_to_le16(IEEE80211_FCTL_PROTECTED);
+       memcpy(mgmt->da, bssid, ETH_ALEN);
+       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       memcpy(mgmt->bssid, bssid, ETH_ALEN);
+       mgmt->u.auth.auth_alg = cpu_to_le16(auth_alg);
+       mgmt->u.auth.auth_transaction = cpu_to_le16(transaction);
+       mgmt->u.auth.status_code = cpu_to_le16(0);
+       if (extra)
+               memcpy(skb_put(skb, extra_len), extra, extra_len);
+       if (ie_auth)
+               memcpy(skb_put(skb, ie_auth_len), ie_auth, ie_auth_len);
+
+       ieee80211_tx_skb(sdata, skb, encrypt);
+}
+
+void ieee80211_send_probe_req(struct ieee80211_sub_if_data *sdata, u8 *dst,
+                             u8 *ssid, size_t ssid_len,
+                             u8 *ie, size_t ie_len)
+{
+       struct ieee80211_local *local = sdata->local;
+       struct ieee80211_supported_band *sband;
+       struct sk_buff *skb;
+       struct ieee80211_mgmt *mgmt;
+       u8 *pos, *supp_rates, *esupp_rates = NULL, *extra_preq_ie = NULL;
+       int i, extra_preq_ie_len = 0;
+
+       switch (sdata->vif.type) {
+       case NL80211_IFTYPE_STATION:
+               extra_preq_ie_len = sdata->u.mgd.ie_probereq_len;
+               extra_preq_ie = sdata->u.mgd.ie_probereq;
+               break;
+       default:
+               break;
+       }
+
+       skb = dev_alloc_skb(local->hw.extra_tx_headroom + sizeof(*mgmt) + 200 +
+                           ie_len + extra_preq_ie_len);
+       if (!skb) {
+               printk(KERN_DEBUG "%s: failed to allocate buffer for probe "
+                      "request\n", sdata->dev->name);
+               return;
+       }
+       skb_reserve(skb, local->hw.extra_tx_headroom);
+
+       mgmt = (struct ieee80211_mgmt *) skb_put(skb, 24);
+       memset(mgmt, 0, 24);
+       mgmt->frame_control = cpu_to_le16(IEEE80211_FTYPE_MGMT |
+                                         IEEE80211_STYPE_PROBE_REQ);
+       memcpy(mgmt->sa, sdata->dev->dev_addr, ETH_ALEN);
+       if (dst) {
+               memcpy(mgmt->da, dst, ETH_ALEN);
+               memcpy(mgmt->bssid, dst, ETH_ALEN);
+       } else {
+               memset(mgmt->da, 0xff, ETH_ALEN);
+               memset(mgmt->bssid, 0xff, ETH_ALEN);
+       }
+       pos = skb_put(skb, 2 + ssid_len);
+       *pos++ = WLAN_EID_SSID;
+       *pos++ = ssid_len;
+       memcpy(pos, ssid, ssid_len);
+
+       supp_rates = skb_put(skb, 2);
+       supp_rates[0] = WLAN_EID_SUPP_RATES;
+       supp_rates[1] = 0;
+       sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+
+       for (i = 0; i < sband->n_bitrates; i++) {
+               struct ieee80211_rate *rate = &sband->bitrates[i];
+               if (esupp_rates) {
+                       pos = skb_put(skb, 1);
+                       esupp_rates[1]++;
+               } else if (supp_rates[1] == 8) {
+                       esupp_rates = skb_put(skb, 3);
+                       esupp_rates[0] = WLAN_EID_EXT_SUPP_RATES;
+                       esupp_rates[1] = 1;
+                       pos = &esupp_rates[2];
+               } else {
+                       pos = skb_put(skb, 1);
+                       supp_rates[1]++;
+               }
+               *pos = rate->bitrate / 5;
+       }
+
+       if (ie)
+               memcpy(skb_put(skb, ie_len), ie, ie_len);
+       if (extra_preq_ie)
+               memcpy(skb_put(skb, extra_preq_ie_len), extra_preq_ie,
+                      extra_preq_ie_len);
+
+       ieee80211_tx_skb(sdata, skb, 0);
+}
+
+u32 ieee80211_sta_get_rates(struct ieee80211_local *local,
+                           struct ieee802_11_elems *elems,
+                           enum ieee80211_band band)
+{
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_rate *bitrates;
+       size_t num_rates;
+       u32 supp_rates;
+       int i, j;
+       sband = local->hw.wiphy->bands[band];
+
+       if (!sband) {
+               WARN_ON(1);
+               sband = local->hw.wiphy->bands[local->hw.conf.channel->band];
+       }
+
+       bitrates = sband->bitrates;
+       num_rates = sband->n_bitrates;
+       supp_rates = 0;
+       for (i = 0; i < elems->supp_rates_len +
+                    elems->ext_supp_rates_len; i++) {
+               u8 rate = 0;
+               int own_rate;
+               if (i < elems->supp_rates_len)
+                       rate = elems->supp_rates[i];
+               else if (elems->ext_supp_rates)
+                       rate = elems->ext_supp_rates
+                               [i - elems->supp_rates_len];
+               own_rate = 5 * (rate & 0x7f);
+               for (j = 0; j < num_rates; j++)
+                       if (bitrates[j].bitrate == own_rate)
+                               supp_rates |= BIT(j);
+       }
+       return supp_rates;
+}
index 2b023dce8b24618a2130df07a072df1c08d1f4a9..935c63ed3dfae554e52cc2563a13588aec4fccff 100644 (file)
@@ -132,139 +132,37 @@ static int ieee80211_ioctl_siwgenie(struct net_device *dev,
        if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME)
                return -EOPNOTSUPP;
 
-       if (sdata->vif.type == NL80211_IFTYPE_STATION ||
-           sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+       if (sdata->vif.type == NL80211_IFTYPE_STATION) {
                int ret = ieee80211_sta_set_extra_ie(sdata, extra, data->length);
                if (ret)
                        return ret;
-               sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
-               ieee80211_sta_req_auth(sdata, &sdata->u.sta);
+               sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
+               ieee80211_sta_req_auth(sdata);
                return 0;
        }
 
        return -EOPNOTSUPP;
 }
 
-static u8 ieee80211_get_wstats_flags(struct ieee80211_local *local)
-{
-       u8 wstats_flags = 0;
-
-       wstats_flags |= local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
-                                          IEEE80211_HW_SIGNAL_DBM) ?
-                               IW_QUAL_QUAL_UPDATED : IW_QUAL_QUAL_INVALID;
-       wstats_flags |= local->hw.flags & IEEE80211_HW_NOISE_DBM ?
-                               IW_QUAL_NOISE_UPDATED : IW_QUAL_NOISE_INVALID;
-       if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
-               wstats_flags |= IW_QUAL_DBM;
-
-       return wstats_flags;
-}
-
-static int ieee80211_ioctl_giwrange(struct net_device *dev,
-                                struct iw_request_info *info,
-                                struct iw_point *data, char *extra)
-{
-       struct ieee80211_local *local = wdev_priv(dev->ieee80211_ptr);
-       struct iw_range *range = (struct iw_range *) extra;
-       enum ieee80211_band band;
-       int c = 0;
-
-       data->length = sizeof(struct iw_range);
-       memset(range, 0, sizeof(struct iw_range));
-
-       range->we_version_compiled = WIRELESS_EXT;
-       range->we_version_source = 21;
-       range->retry_capa = IW_RETRY_LIMIT;
-       range->retry_flags = IW_RETRY_LIMIT;
-       range->min_retry = 0;
-       range->max_retry = 255;
-       range->min_rts = 0;
-       range->max_rts = 2347;
-       range->min_frag = 256;
-       range->max_frag = 2346;
-
-       range->encoding_size[0] = 5;
-       range->encoding_size[1] = 13;
-       range->num_encoding_sizes = 2;
-       range->max_encoding_tokens = NUM_DEFAULT_KEYS;
-
-       /* cfg80211 requires this, and enforces 0..100 */
-       if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC)
-               range->max_qual.level = 100;
-       else if  (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
-               range->max_qual.level = -110;
-       else
-               range->max_qual.level = 0;
-
-       if (local->hw.flags & IEEE80211_HW_NOISE_DBM)
-               range->max_qual.noise = -110;
-       else
-               range->max_qual.noise = 0;
-
-       range->max_qual.qual = 100;
-       range->max_qual.updated = ieee80211_get_wstats_flags(local);
-
-       range->avg_qual.qual = 50;
-       /* not always true but better than nothing */
-       range->avg_qual.level = range->max_qual.level / 2;
-       range->avg_qual.noise = range->max_qual.noise / 2;
-       range->avg_qual.updated = ieee80211_get_wstats_flags(local);
-
-       range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
-                         IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
-
-
-       for (band = 0; band < IEEE80211_NUM_BANDS; band ++) {
-               int i;
-               struct ieee80211_supported_band *sband;
-
-               sband = local->hw.wiphy->bands[band];
-
-               if (!sband)
-                       continue;
-
-               for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) {
-                       struct ieee80211_channel *chan = &sband->channels[i];
-
-                       if (!(chan->flags & IEEE80211_CHAN_DISABLED)) {
-                               range->freq[c].i =
-                                       ieee80211_frequency_to_channel(
-                                               chan->center_freq);
-                               range->freq[c].m = chan->center_freq;
-                               range->freq[c].e = 6;
-                               c++;
-                       }
-               }
-       }
-       range->num_channels = c;
-       range->num_frequency = c;
-
-       IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
-       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
-       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
-
-       range->scan_capa |= IW_SCAN_CAPA_ESSID;
-
-       return 0;
-}
-
-
 static int ieee80211_ioctl_siwfreq(struct net_device *dev,
                                   struct iw_request_info *info,
                                   struct iw_freq *freq, char *extra)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
 
-       if (sdata->vif.type == NL80211_IFTYPE_ADHOC ||
-           sdata->vif.type == NL80211_IFTYPE_STATION)
-               sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;
+       if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+               sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_CHANNEL_SEL;
+       else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_CHANNEL_SEL;
 
        /* freq->e == 0: freq->m = channel; otherwise freq = m * 10^e */
        if (freq->e == 0) {
                if (freq->m < 0) {
-                       if (sdata->vif.type == NL80211_IFTYPE_ADHOC ||
-                           sdata->vif.type == NL80211_IFTYPE_STATION)
-                               sdata->u.sta.flags |=
+                       if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+                               sdata->u.ibss.flags |=
+                                       IEEE80211_IBSS_AUTO_CHANNEL_SEL;
+                       else if (sdata->vif.type == NL80211_IFTYPE_STATION)
+                               sdata->u.mgd.flags |=
                                        IEEE80211_STA_AUTO_CHANNEL_SEL;
                        return 0;
                } else
@@ -301,32 +199,35 @@ static int ieee80211_ioctl_siwessid(struct net_device *dev,
 {
        struct ieee80211_sub_if_data *sdata;
        size_t len = data->length;
+       int ret;
 
        /* iwconfig uses nul termination in SSID.. */
        if (len > 0 && ssid[len - 1] == '\0')
                len--;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->vif.type == NL80211_IFTYPE_STATION ||
-           sdata->vif.type == NL80211_IFTYPE_ADHOC) {
-               int ret;
+       if (sdata->vif.type == NL80211_IFTYPE_STATION) {
                if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
                        if (len > IEEE80211_MAX_SSID_LEN)
                                return -EINVAL;
-                       memcpy(sdata->u.sta.ssid, ssid, len);
-                       sdata->u.sta.ssid_len = len;
+                       memcpy(sdata->u.mgd.ssid, ssid, len);
+                       sdata->u.mgd.ssid_len = len;
                        return 0;
                }
+
                if (data->flags)
-                       sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
+                       sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_SSID_SEL;
                else
-                       sdata->u.sta.flags |= IEEE80211_STA_AUTO_SSID_SEL;
+                       sdata->u.mgd.flags |= IEEE80211_STA_AUTO_SSID_SEL;
+
                ret = ieee80211_sta_set_ssid(sdata, ssid, len);
                if (ret)
                        return ret;
-               ieee80211_sta_req_auth(sdata, &sdata->u.sta);
+
+               ieee80211_sta_req_auth(sdata);
                return 0;
-       }
+       } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC)
+               return ieee80211_ibss_set_ssid(sdata, ssid, len);
 
        return -EOPNOTSUPP;
 }
@@ -340,8 +241,7 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev,
 
        struct ieee80211_sub_if_data *sdata;
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->vif.type == NL80211_IFTYPE_STATION ||
-           sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+       if (sdata->vif.type == NL80211_IFTYPE_STATION) {
                int res = ieee80211_sta_get_ssid(sdata, ssid, &len);
                if (res == 0) {
                        data->length = len;
@@ -349,6 +249,14 @@ static int ieee80211_ioctl_giwessid(struct net_device *dev,
                } else
                        data->flags = 0;
                return res;
+       } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+               int res = ieee80211_ibss_get_ssid(sdata, ssid, &len);
+               if (res == 0) {
+                       data->length = len;
+                       data->flags = 1;
+               } else
+                       data->flags = 0;
+               return res;
        }
 
        return -EOPNOTSUPP;
@@ -362,26 +270,35 @@ static int ieee80211_ioctl_siwap(struct net_device *dev,
        struct ieee80211_sub_if_data *sdata;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->vif.type == NL80211_IFTYPE_STATION ||
-           sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+       if (sdata->vif.type == NL80211_IFTYPE_STATION) {
                int ret;
                if (sdata->flags & IEEE80211_SDATA_USERSPACE_MLME) {
-                       memcpy(sdata->u.sta.bssid, (u8 *) &ap_addr->sa_data,
+                       memcpy(sdata->u.mgd.bssid, (u8 *) &ap_addr->sa_data,
                               ETH_ALEN);
                        return 0;
                }
                if (is_zero_ether_addr((u8 *) &ap_addr->sa_data))
-                       sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL |
+                       sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL |
                                IEEE80211_STA_AUTO_CHANNEL_SEL;
                else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
-                       sdata->u.sta.flags |= IEEE80211_STA_AUTO_BSSID_SEL;
+                       sdata->u.mgd.flags |= IEEE80211_STA_AUTO_BSSID_SEL;
                else
-                       sdata->u.sta.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
+                       sdata->u.mgd.flags &= ~IEEE80211_STA_AUTO_BSSID_SEL;
                ret = ieee80211_sta_set_bssid(sdata, (u8 *) &ap_addr->sa_data);
                if (ret)
                        return ret;
-               ieee80211_sta_req_auth(sdata, &sdata->u.sta);
+               ieee80211_sta_req_auth(sdata);
                return 0;
+       } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+               if (is_zero_ether_addr((u8 *) &ap_addr->sa_data))
+                       sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL |
+                                              IEEE80211_IBSS_AUTO_CHANNEL_SEL;
+               else if (is_broadcast_ether_addr((u8 *) &ap_addr->sa_data))
+                       sdata->u.ibss.flags |= IEEE80211_IBSS_AUTO_BSSID_SEL;
+               else
+                       sdata->u.ibss.flags &= ~IEEE80211_IBSS_AUTO_BSSID_SEL;
+
+               return ieee80211_ibss_set_bssid(sdata, (u8 *) &ap_addr->sa_data);
        } else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
                /*
                 * If it is necessary to update the WDS peer address
@@ -410,17 +327,20 @@ static int ieee80211_ioctl_giwap(struct net_device *dev,
        struct ieee80211_sub_if_data *sdata;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->vif.type == NL80211_IFTYPE_STATION ||
-           sdata->vif.type == NL80211_IFTYPE_ADHOC) {
-               if (sdata->u.sta.state == IEEE80211_STA_MLME_ASSOCIATED ||
-                   sdata->u.sta.state == IEEE80211_STA_MLME_IBSS_JOINED) {
+       if (sdata->vif.type == NL80211_IFTYPE_STATION) {
+               if (sdata->u.mgd.state == IEEE80211_STA_MLME_ASSOCIATED) {
                        ap_addr->sa_family = ARPHRD_ETHER;
-                       memcpy(&ap_addr->sa_data, sdata->u.sta.bssid, ETH_ALEN);
-                       return 0;
-               } else {
+                       memcpy(&ap_addr->sa_data, sdata->u.mgd.bssid, ETH_ALEN);
+               } else
                        memset(&ap_addr->sa_data, 0, ETH_ALEN);
-                       return 0;
-               }
+               return 0;
+       } else if (sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+               if (sdata->u.ibss.state == IEEE80211_IBSS_MLME_JOINED) {
+                       ap_addr->sa_family = ARPHRD_ETHER;
+                       memcpy(&ap_addr->sa_data, sdata->u.ibss.bssid, ETH_ALEN);
+               } else
+                       memset(&ap_addr->sa_data, 0, ETH_ALEN);
+               return 0;
        } else if (sdata->vif.type == NL80211_IFTYPE_WDS) {
                ap_addr->sa_family = ARPHRD_ETHER;
                memcpy(&ap_addr->sa_data, sdata->u.wds.remote_addr, ETH_ALEN);
@@ -486,7 +406,7 @@ static int ieee80211_ioctl_giwrate(struct net_device *dev,
 
        rcu_read_lock();
 
-       sta = sta_info_get(local, sdata->u.sta.bssid);
+       sta = sta_info_get(local, sdata->u.mgd.bssid);
 
        if (sta && !(sta->last_tx_rate.flags & IEEE80211_TX_RC_MCS))
                rate->value = sband->bitrates[sta->last_tx_rate.idx].bitrate;
@@ -687,8 +607,7 @@ static int ieee80211_ioctl_siwmlme(struct net_device *dev,
        struct iw_mlme *mlme = (struct iw_mlme *) extra;
 
        sdata = IEEE80211_DEV_TO_SUB_IF(dev);
-       if (sdata->vif.type != NL80211_IFTYPE_STATION &&
-           sdata->vif.type != NL80211_IFTYPE_ADHOC)
+       if (!(sdata->vif.type == NL80211_IFTYPE_STATION))
                return -EINVAL;
 
        switch (mlme->cmd) {
@@ -784,8 +703,7 @@ static int ieee80211_ioctl_giwencode(struct net_device *dev,
        erq->flags |= IW_ENCODE_ENABLED;
 
        if (sdata->vif.type == NL80211_IFTYPE_STATION) {
-               struct ieee80211_if_sta *ifsta = &sdata->u.sta;
-               switch (ifsta->auth_alg) {
+               switch (sdata->u.mgd.auth_alg) {
                case WLAN_AUTH_OPEN:
                case WLAN_AUTH_LEAP:
                        erq->flags |= IW_ENCODE_OPEN;
@@ -849,7 +767,7 @@ static int ieee80211_ioctl_siwpower(struct net_device *dev,
                ret = ieee80211_hw_config(local,
                                          IEEE80211_CONF_CHANGE_DYNPS_TIMEOUT);
 
-       if (!(sdata->u.sta.flags & IEEE80211_STA_ASSOCIATED))
+       if (!(sdata->u.mgd.flags & IEEE80211_STA_ASSOCIATED))
                return ret;
 
        if (conf->dynamic_ps_timeout > 0 &&
@@ -908,10 +826,10 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev,
                if (sdata->vif.type == NL80211_IFTYPE_STATION) {
                        if (data->value & (IW_AUTH_CIPHER_WEP40 |
                            IW_AUTH_CIPHER_WEP104 | IW_AUTH_CIPHER_TKIP))
-                               sdata->u.sta.flags |=
+                               sdata->u.mgd.flags |=
                                        IEEE80211_STA_TKIP_WEP_USED;
                        else
-                               sdata->u.sta.flags &=
+                               sdata->u.mgd.flags &=
                                        ~IEEE80211_STA_TKIP_WEP_USED;
                }
                break;
@@ -922,21 +840,20 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev,
                if (sdata->vif.type != NL80211_IFTYPE_STATION)
                        ret = -EINVAL;
                else {
-                       sdata->u.sta.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
+                       sdata->u.mgd.flags &= ~IEEE80211_STA_PRIVACY_INVOKED;
                        /*
                         * Privacy invoked by wpa_supplicant, store the
                         * value and allow associating to a protected
                         * network without having a key up front.
                         */
                        if (data->value)
-                               sdata->u.sta.flags |=
+                               sdata->u.mgd.flags |=
                                        IEEE80211_STA_PRIVACY_INVOKED;
                }
                break;
        case IW_AUTH_80211_AUTH_ALG:
-               if (sdata->vif.type == NL80211_IFTYPE_STATION ||
-                   sdata->vif.type == NL80211_IFTYPE_ADHOC)
-                       sdata->u.sta.auth_algs = data->value;
+               if (sdata->vif.type == NL80211_IFTYPE_STATION)
+                       sdata->u.mgd.auth_algs = data->value;
                else
                        ret = -EOPNOTSUPP;
                break;
@@ -945,17 +862,16 @@ static int ieee80211_ioctl_siwauth(struct net_device *dev,
                        ret = -EOPNOTSUPP;
                        break;
                }
-               if (sdata->vif.type == NL80211_IFTYPE_STATION ||
-                   sdata->vif.type == NL80211_IFTYPE_ADHOC) {
+               if (sdata->vif.type == NL80211_IFTYPE_STATION) {
                        switch (data->value) {
                        case IW_AUTH_MFP_DISABLED:
-                               sdata->u.sta.mfp = IEEE80211_MFP_DISABLED;
+                               sdata->u.mgd.mfp = IEEE80211_MFP_DISABLED;
                                break;
                        case IW_AUTH_MFP_OPTIONAL:
-                               sdata->u.sta.mfp = IEEE80211_MFP_OPTIONAL;
+                               sdata->u.mgd.mfp = IEEE80211_MFP_OPTIONAL;
                                break;
                        case IW_AUTH_MFP_REQUIRED:
-                               sdata->u.sta.mfp = IEEE80211_MFP_REQUIRED;
+                               sdata->u.mgd.mfp = IEEE80211_MFP_REQUIRED;
                                break;
                        default:
                                ret = -EINVAL;
@@ -980,9 +896,9 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev
 
        rcu_read_lock();
 
-       if (sdata->vif.type == NL80211_IFTYPE_STATION ||
-           sdata->vif.type == NL80211_IFTYPE_ADHOC)
-               sta = sta_info_get(local, sdata->u.sta.bssid);
+       if (sdata->vif.type == NL80211_IFTYPE_STATION)
+               sta = sta_info_get(local, sdata->u.mgd.bssid);
+
        if (!sta) {
                wstats->discard.fragment = 0;
                wstats->discard.misc = 0;
@@ -991,10 +907,45 @@ static struct iw_statistics *ieee80211_get_wireless_stats(struct net_device *dev
                wstats->qual.noise = 0;
                wstats->qual.updated = IW_QUAL_ALL_INVALID;
        } else {
-               wstats->qual.level = sta->last_signal;
-               wstats->qual.qual = sta->last_qual;
-               wstats->qual.noise = sta->last_noise;
-               wstats->qual.updated = ieee80211_get_wstats_flags(local);
+               wstats->qual.updated = 0;
+               /*
+                * mirror what cfg80211 does for iwrange/scan results,
+                * otherwise userspace gets confused.
+                */
+               if (local->hw.flags & (IEEE80211_HW_SIGNAL_UNSPEC |
+                                      IEEE80211_HW_SIGNAL_DBM)) {
+                       wstats->qual.updated |= IW_QUAL_LEVEL_UPDATED;
+                       wstats->qual.updated |= IW_QUAL_QUAL_UPDATED;
+               } else {
+                       wstats->qual.updated |= IW_QUAL_LEVEL_INVALID;
+                       wstats->qual.updated |= IW_QUAL_QUAL_INVALID;
+               }
+
+               if (local->hw.flags & IEEE80211_HW_SIGNAL_UNSPEC) {
+                       wstats->qual.level = sta->last_signal;
+                       wstats->qual.qual = sta->last_signal;
+               } else if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM) {
+                       int sig = sta->last_signal;
+
+                       wstats->qual.updated |= IW_QUAL_DBM;
+                       wstats->qual.level = sig;
+                       if (sig < -110)
+                               sig = -110;
+                       else if (sig > -40)
+                               sig = -40;
+                       wstats->qual.qual = sig + 110;
+               }
+
+               if (local->hw.flags & IEEE80211_HW_NOISE_DBM) {
+                       /*
+                        * This assumes that if driver reports noise, it also
+                        * reports signal in dBm.
+                        */
+                       wstats->qual.noise = sta->last_noise;
+                       wstats->qual.updated |= IW_QUAL_NOISE_UPDATED;
+               } else {
+                       wstats->qual.updated |= IW_QUAL_NOISE_INVALID;
+               }
        }
 
        rcu_read_unlock();
@@ -1011,9 +962,8 @@ static int ieee80211_ioctl_giwauth(struct net_device *dev,
 
        switch (data->flags & IW_AUTH_INDEX) {
        case IW_AUTH_80211_AUTH_ALG:
-               if (sdata->vif.type == NL80211_IFTYPE_STATION ||
-                   sdata->vif.type == NL80211_IFTYPE_ADHOC)
-                       data->value = sdata->u.sta.auth_algs;
+               if (sdata->vif.type == NL80211_IFTYPE_STATION)
+                       data->value = sdata->u.mgd.auth_algs;
                else
                        ret = -EOPNOTSUPP;
                break;
@@ -1116,7 +1066,7 @@ static const iw_handler ieee80211_handler[] =
        (iw_handler) NULL,                              /* SIOCSIWSENS */
        (iw_handler) NULL,                              /* SIOCGIWSENS */
        (iw_handler) NULL /* not used */,               /* SIOCSIWRANGE */
-       (iw_handler) ieee80211_ioctl_giwrange,          /* SIOCGIWRANGE */
+       (iw_handler) cfg80211_wext_giwrange,            /* SIOCGIWRANGE */
        (iw_handler) NULL /* not used */,               /* SIOCSIWPRIV */
        (iw_handler) NULL /* kernel code */,            /* SIOCGIWPRIV */
        (iw_handler) NULL /* not used */,               /* SIOCSIWSTATS */
index ac71b38f7cb5cb217180bb2cef3bcfa4b6540b40..0b8ad1f4ecdd8dbb1f77532874c1c5d6f3a60d1a 100644 (file)
@@ -99,10 +99,13 @@ static u16 classify80211(struct ieee80211_local *local, struct sk_buff *skb)
        /* in case we are a client verify acm is not set for this ac */
        while (unlikely(local->wmm_acm & BIT(skb->priority))) {
                if (wme_downgrade_ac(skb)) {
-                       /* The old code would drop the packet in this
-                        * case.
+                       /*
+                        * This should not really happen. The AP has marked all
+                        * lower ACs to require admission control which is not
+                        * a reasonable configuration. Allow the frame to be
+                        * transmitted using AC_BK as a workaround.
                         */
-                       return 0;
+                       break;
                }
        }
 
@@ -114,9 +117,7 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
 {
        struct ieee80211_master_priv *mpriv = netdev_priv(dev);
        struct ieee80211_local *local = mpriv->local;
-       struct ieee80211_hw *hw = &local->hw;
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-       struct sta_info *sta;
        u16 queue;
        u8 tid;
 
@@ -124,29 +125,11 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
        if (unlikely(queue >= local->hw.queues))
                queue = local->hw.queues - 1;
 
-       if (skb->requeue) {
-               if (!hw->ampdu_queues)
-                       return queue;
-
-               rcu_read_lock();
-               sta = sta_info_get(local, hdr->addr1);
-               tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
-               if (sta) {
-                       int ampdu_queue = sta->tid_to_tx_q[tid];
-
-                       if ((ampdu_queue < ieee80211_num_queues(hw)) &&
-                           test_bit(ampdu_queue, local->queue_pool))
-                               queue = ampdu_queue;
-               }
-               rcu_read_unlock();
-
-               return queue;
-       }
-
-       /* Now we know the 1d priority, fill in the QoS header if
-        * there is one.
+       /*
+        * Now we know the 1d priority, fill in the QoS header if
+        * there is one (and we haven't done this before).
         */
-       if (ieee80211_is_data_qos(hdr->frame_control)) {
+       if (!skb->requeue && ieee80211_is_data_qos(hdr->frame_control)) {
                u8 *p = ieee80211_get_qos_ctl(hdr);
                u8 ack_policy = 0;
                tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
@@ -156,140 +139,7 @@ u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb)
                /* qos header is 2 bytes, second reserved */
                *p++ = ack_policy | tid;
                *p = 0;
-
-               if (!hw->ampdu_queues)
-                       return queue;
-
-               rcu_read_lock();
-
-               sta = sta_info_get(local, hdr->addr1);
-               if (sta) {
-                       int ampdu_queue = sta->tid_to_tx_q[tid];
-
-                       if ((ampdu_queue < ieee80211_num_queues(hw)) &&
-                           test_bit(ampdu_queue, local->queue_pool))
-                               queue = ampdu_queue;
-               }
-
-               rcu_read_unlock();
        }
 
        return queue;
 }
-
-int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
-                              struct sta_info *sta, u16 tid)
-{
-       int i;
-
-       /* XXX: currently broken due to cb/requeue use */
-       return -EPERM;
-
-       /* prepare the filter and save it for the SW queue
-        * matching the received HW queue */
-
-       if (!local->hw.ampdu_queues)
-               return -EPERM;
-
-       /* try to get a Qdisc from the pool */
-       for (i = local->hw.queues; i < ieee80211_num_queues(&local->hw); i++)
-               if (!test_and_set_bit(i, local->queue_pool)) {
-                       ieee80211_stop_queue(local_to_hw(local), i);
-                       sta->tid_to_tx_q[tid] = i;
-
-                       /* IF there are already pending packets
-                        * on this tid first we need to drain them
-                        * on the previous queue
-                        * since HT is strict in order */
-#ifdef CONFIG_MAC80211_HT_DEBUG
-                       if (net_ratelimit())
-                               printk(KERN_DEBUG "allocated aggregation queue"
-                                       " %d tid %d addr %pM pool=0x%lX\n",
-                                       i, tid, sta->sta.addr,
-                                       local->queue_pool[0]);
-#endif /* CONFIG_MAC80211_HT_DEBUG */
-                       return 0;
-               }
-
-       return -EAGAIN;
-}
-
-/**
- * the caller needs to hold netdev_get_tx_queue(local->mdev, X)->lock
- */
-void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
-                                  struct sta_info *sta, u16 tid,
-                                  u8 requeue)
-{
-       int agg_queue = sta->tid_to_tx_q[tid];
-       struct ieee80211_hw *hw = &local->hw;
-
-       /* return the qdisc to the pool */
-       clear_bit(agg_queue, local->queue_pool);
-       sta->tid_to_tx_q[tid] = ieee80211_num_queues(hw);
-
-       if (requeue) {
-               ieee80211_requeue(local, agg_queue);
-       } else {
-               struct netdev_queue *txq;
-               spinlock_t *root_lock;
-               struct Qdisc *q;
-
-               txq = netdev_get_tx_queue(local->mdev, agg_queue);
-               q = rcu_dereference(txq->qdisc);
-               root_lock = qdisc_lock(q);
-
-               spin_lock_bh(root_lock);
-               qdisc_reset(q);
-               spin_unlock_bh(root_lock);
-       }
-}
-
-void ieee80211_requeue(struct ieee80211_local *local, int queue)
-{
-       struct netdev_queue *txq = netdev_get_tx_queue(local->mdev, queue);
-       struct sk_buff_head list;
-       spinlock_t *root_lock;
-       struct Qdisc *qdisc;
-       u32 len;
-
-       rcu_read_lock_bh();
-
-       qdisc = rcu_dereference(txq->qdisc);
-       if (!qdisc || !qdisc->dequeue)
-               goto out_unlock;
-
-       skb_queue_head_init(&list);
-
-       root_lock = qdisc_root_lock(qdisc);
-       spin_lock(root_lock);
-       for (len = qdisc->q.qlen; len > 0; len--) {
-               struct sk_buff *skb = qdisc->dequeue(qdisc);
-
-               if (skb)
-                       __skb_queue_tail(&list, skb);
-       }
-       spin_unlock(root_lock);
-
-       for (len = list.qlen; len > 0; len--) {
-               struct sk_buff *skb = __skb_dequeue(&list);
-               u16 new_queue;
-
-               BUG_ON(!skb);
-               new_queue = ieee80211_select_queue(local->mdev, skb);
-               skb_set_queue_mapping(skb, new_queue);
-
-               txq = netdev_get_tx_queue(local->mdev, new_queue);
-
-
-               qdisc = rcu_dereference(txq->qdisc);
-               root_lock = qdisc_root_lock(qdisc);
-
-               spin_lock(root_lock);
-               qdisc_enqueue_root(skb, qdisc);
-               spin_unlock(root_lock);
-       }
-
-out_unlock:
-       rcu_read_unlock_bh();
-}
index bc62f28a4d3df6951ecb02b7f0e70e0ce6aad30f..7520d2e014dce1f83deec7fc628ca20cc2beadfd 100644 (file)
 extern const int ieee802_1d_to_ac[8];
 
 u16 ieee80211_select_queue(struct net_device *dev, struct sk_buff *skb);
-int ieee80211_ht_agg_queue_add(struct ieee80211_local *local,
-                              struct sta_info *sta, u16 tid);
-void ieee80211_ht_agg_queue_remove(struct ieee80211_local *local,
-                                  struct sta_info *sta, u16 tid,
-                                  u8 requeue);
-void ieee80211_requeue(struct ieee80211_local *local, int queue);
 
 #endif /* _WME_H */
index 55befe59e1c038c01abe63ebc2b1e5d00a84a886..dfb447b584da889d50dcd5b383be31f475a1b11b 100644 (file)
@@ -728,7 +728,7 @@ nf_conntrack_in(struct net *net, u_int8_t pf, unsigned int hooknum,
        NF_CT_ASSERT(skb->nfct);
 
        ret = l4proto->packet(ct, skb, dataoff, ctinfo, pf, hooknum);
-       if (ret < 0) {
+       if (ret <= 0) {
                /* Invalid: inverse of the return code tells
                 * the netfilter core what to do */
                pr_debug("nf_conntrack_in: Can't track with proto module\n");
index 1b75c9efb0eb1c5ba4b302ad1a466a1416a917ca..7a16bd462f82386bb1f7be34935ccf754bcbd72f 100644 (file)
@@ -1763,6 +1763,7 @@ ctnetlink_create_expect(struct nlattr *cda[], u_int8_t u3, u32 pid, int report)
                goto out;
        }
 
+       exp->class = 0;
        exp->expectfn = NULL;
        exp->flags = 0;
        exp->master = ct;
index 7d3944f02ea13f45f7a9c4355db18976e048008b..e46f3b79adb3ade44627d5567c0752921ea2c676 100644 (file)
@@ -861,7 +861,7 @@ static int tcp_packet(struct nf_conn *ct,
                         */
                        if (nf_ct_kill(ct))
                                return -NF_REPEAT;
-                       return -NF_DROP;
+                       return NF_DROP;
                }
                /* Fall through */
        case TCP_CONNTRACK_IGNORE:
@@ -894,7 +894,7 @@ static int tcp_packet(struct nf_conn *ct,
                                nf_log_packet(pf, 0, skb, NULL, NULL, NULL,
                                          "nf_ct_tcp: killing out of sync session ");
                        nf_ct_kill(ct);
-                       return -NF_DROP;
+                       return NF_DROP;
                }
                ct->proto.tcp.last_index = index;
                ct->proto.tcp.last_dir = dir;
index 3eae3fca29d87c010a0ec327d97db8c6834a630d..fd326ac27ec8b3382203d41ed7e61ead165550c8 100644 (file)
@@ -39,7 +39,7 @@
 #endif
 
 #define NFULNL_NLBUFSIZ_DEFAULT        NLMSG_GOODSIZE
-#define NFULNL_TIMEOUT_DEFAULT         HZ      /* every second */
+#define NFULNL_TIMEOUT_DEFAULT         100     /* every second */
 #define NFULNL_QTHRESH_DEFAULT         100     /* 100 packets */
 #define NFULNL_COPY_RANGE_MAX  0xFFFF  /* max packet size is limited by 16-bit struct nfattr nfa_len field */
 
@@ -590,8 +590,10 @@ nfulnl_log_packet(u_int8_t pf,
 
        qthreshold = inst->qthreshold;
        /* per-rule qthreshold overrides per-instance */
-       if (qthreshold > li->u.ulog.qthreshold)
-               qthreshold = li->u.ulog.qthreshold;
+       if (li->u.ulog.qthreshold)
+               if (qthreshold > li->u.ulog.qthreshold)
+                       qthreshold = li->u.ulog.qthreshold;
+
 
        switch (inst->copy_mode) {
        case NFULNL_COPY_META:
index bfcac92d55639d648d2e48b2e19c3bafc34e10c8..509a95621f9f5e68a93916414717beae2b69a60f 100644 (file)
@@ -843,59 +843,143 @@ static const struct file_operations xt_table_ops = {
        .release = seq_release_net,
 };
 
-static void *xt_match_seq_start(struct seq_file *seq, loff_t *pos)
+/*
+ * Traverse state for ip{,6}_{tables,matches} for helping crossing
+ * the multi-AF mutexes.
+ */
+struct nf_mttg_trav {
+       struct list_head *head, *curr;
+       uint8_t class, nfproto;
+};
+
+enum {
+       MTTG_TRAV_INIT,
+       MTTG_TRAV_NFP_UNSPEC,
+       MTTG_TRAV_NFP_SPEC,
+       MTTG_TRAV_DONE,
+};
+
+static void *xt_mttg_seq_next(struct seq_file *seq, void *v, loff_t *ppos,
+    bool is_target)
 {
-       struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private;
-       u_int16_t af = (unsigned long)pde->data;
+       static const uint8_t next_class[] = {
+               [MTTG_TRAV_NFP_UNSPEC] = MTTG_TRAV_NFP_SPEC,
+               [MTTG_TRAV_NFP_SPEC]   = MTTG_TRAV_DONE,
+       };
+       struct nf_mttg_trav *trav = seq->private;
+
+       switch (trav->class) {
+       case MTTG_TRAV_INIT:
+               trav->class = MTTG_TRAV_NFP_UNSPEC;
+               mutex_lock(&xt[NFPROTO_UNSPEC].mutex);
+               trav->head = trav->curr = is_target ?
+                       &xt[NFPROTO_UNSPEC].target : &xt[NFPROTO_UNSPEC].match;
+               break;
+       case MTTG_TRAV_NFP_UNSPEC:
+               trav->curr = trav->curr->next;
+               if (trav->curr != trav->head)
+                       break;
+               mutex_unlock(&xt[NFPROTO_UNSPEC].mutex);
+               mutex_lock(&xt[trav->nfproto].mutex);
+               trav->head = trav->curr = is_target ?
+                       &xt[trav->nfproto].target : &xt[trav->nfproto].match;
+               trav->class = next_class[trav->class];
+               break;
+       case MTTG_TRAV_NFP_SPEC:
+               trav->curr = trav->curr->next;
+               if (trav->curr != trav->head)
+                       break;
+               /* fallthru, _stop will unlock */
+       default:
+               return NULL;
+       }
 
-       mutex_lock(&xt[af].mutex);
-       return seq_list_start(&xt[af].match, *pos);
+       if (ppos != NULL)
+               ++*ppos;
+       return trav;
 }
 
-static void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+static void *xt_mttg_seq_start(struct seq_file *seq, loff_t *pos,
+    bool is_target)
 {
-       struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private;
-       u_int16_t af = (unsigned long)pde->data;
+       struct nf_mttg_trav *trav = seq->private;
+       unsigned int j;
 
-       return seq_list_next(v, &xt[af].match, pos);
+       trav->class = MTTG_TRAV_INIT;
+       for (j = 0; j < *pos; ++j)
+               if (xt_mttg_seq_next(seq, NULL, NULL, is_target) == NULL)
+                       return NULL;
+       return trav;
 }
 
-static void xt_match_seq_stop(struct seq_file *seq, void *v)
+static void xt_mttg_seq_stop(struct seq_file *seq, void *v)
 {
-       struct proc_dir_entry *pde = seq->private;
-       u_int16_t af = (unsigned long)pde->data;
+       struct nf_mttg_trav *trav = seq->private;
+
+       switch (trav->class) {
+       case MTTG_TRAV_NFP_UNSPEC:
+               mutex_unlock(&xt[NFPROTO_UNSPEC].mutex);
+               break;
+       case MTTG_TRAV_NFP_SPEC:
+               mutex_unlock(&xt[trav->nfproto].mutex);
+               break;
+       }
+}
 
-       mutex_unlock(&xt[af].mutex);
+static void *xt_match_seq_start(struct seq_file *seq, loff_t *pos)
+{
+       return xt_mttg_seq_start(seq, pos, false);
 }
 
-static int xt_match_seq_show(struct seq_file *seq, void *v)
+static void *xt_match_seq_next(struct seq_file *seq, void *v, loff_t *ppos)
 {
-       struct xt_match *match = list_entry(v, struct xt_match, list);
+       return xt_mttg_seq_next(seq, v, ppos, false);
+}
 
-       if (strlen(match->name))
-               return seq_printf(seq, "%s\n", match->name);
-       else
-               return 0;
+static int xt_match_seq_show(struct seq_file *seq, void *v)
+{
+       const struct nf_mttg_trav *trav = seq->private;
+       const struct xt_match *match;
+
+       switch (trav->class) {
+       case MTTG_TRAV_NFP_UNSPEC:
+       case MTTG_TRAV_NFP_SPEC:
+               if (trav->curr == trav->head)
+                       return 0;
+               match = list_entry(trav->curr, struct xt_match, list);
+               return (*match->name == '\0') ? 0 :
+                      seq_printf(seq, "%s\n", match->name);
+       }
+       return 0;
 }
 
 static const struct seq_operations xt_match_seq_ops = {
        .start  = xt_match_seq_start,
        .next   = xt_match_seq_next,
-       .stop   = xt_match_seq_stop,
+       .stop   = xt_mttg_seq_stop,
        .show   = xt_match_seq_show,
 };
 
 static int xt_match_open(struct inode *inode, struct file *file)
 {
+       struct seq_file *seq;
+       struct nf_mttg_trav *trav;
        int ret;
 
-       ret = seq_open(file, &xt_match_seq_ops);
-       if (!ret) {
-               struct seq_file *seq = file->private_data;
+       trav = kmalloc(sizeof(*trav), GFP_KERNEL);
+       if (trav == NULL)
+               return -ENOMEM;
 
-               seq->private = PDE(inode);
+       ret = seq_open(file, &xt_match_seq_ops);
+       if (ret < 0) {
+               kfree(trav);
+               return ret;
        }
-       return ret;
+
+       seq = file->private_data;
+       seq->private = trav;
+       trav->nfproto = (unsigned long)PDE(inode)->data;
+       return 0;
 }
 
 static const struct file_operations xt_match_ops = {
@@ -903,62 +987,63 @@ static const struct file_operations xt_match_ops = {
        .open    = xt_match_open,
        .read    = seq_read,
        .llseek  = seq_lseek,
-       .release = seq_release,
+       .release = seq_release_private,
 };
 
 static void *xt_target_seq_start(struct seq_file *seq, loff_t *pos)
 {
-       struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private;
-       u_int16_t af = (unsigned long)pde->data;
-
-       mutex_lock(&xt[af].mutex);
-       return seq_list_start(&xt[af].target, *pos);
+       return xt_mttg_seq_start(seq, pos, true);
 }
 
-static void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *pos)
+static void *xt_target_seq_next(struct seq_file *seq, void *v, loff_t *ppos)
 {
-       struct proc_dir_entry *pde = (struct proc_dir_entry *)seq->private;
-       u_int16_t af = (unsigned long)pde->data;
-
-       return seq_list_next(v, &xt[af].target, pos);
-}
-
-static void xt_target_seq_stop(struct seq_file *seq, void *v)
-{
-       struct proc_dir_entry *pde = seq->private;
-       u_int16_t af = (unsigned long)pde->data;
-
-       mutex_unlock(&xt[af].mutex);
+       return xt_mttg_seq_next(seq, v, ppos, true);
 }
 
 static int xt_target_seq_show(struct seq_file *seq, void *v)
 {
-       struct xt_target *target = list_entry(v, struct xt_target, list);
-
-       if (strlen(target->name))
-               return seq_printf(seq, "%s\n", target->name);
-       else
-               return 0;
+       const struct nf_mttg_trav *trav = seq->private;
+       const struct xt_target *target;
+
+       switch (trav->class) {
+       case MTTG_TRAV_NFP_UNSPEC:
+       case MTTG_TRAV_NFP_SPEC:
+               if (trav->curr == trav->head)
+                       return 0;
+               target = list_entry(trav->curr, struct xt_target, list);
+               return (*target->name == '\0') ? 0 :
+                      seq_printf(seq, "%s\n", target->name);
+       }
+       return 0;
 }
 
 static const struct seq_operations xt_target_seq_ops = {
        .start  = xt_target_seq_start,
        .next   = xt_target_seq_next,
-       .stop   = xt_target_seq_stop,
+       .stop   = xt_mttg_seq_stop,
        .show   = xt_target_seq_show,
 };
 
 static int xt_target_open(struct inode *inode, struct file *file)
 {
+       struct seq_file *seq;
+       struct nf_mttg_trav *trav;
        int ret;
 
-       ret = seq_open(file, &xt_target_seq_ops);
-       if (!ret) {
-               struct seq_file *seq = file->private_data;
+       trav = kmalloc(sizeof(*trav), GFP_KERNEL);
+       if (trav == NULL)
+               return -ENOMEM;
 
-               seq->private = PDE(inode);
+       ret = seq_open(file, &xt_target_seq_ops);
+       if (ret < 0) {
+               kfree(trav);
+               return ret;
        }
-       return ret;
+
+       seq = file->private_data;
+       seq->private = trav;
+       trav->nfproto = (unsigned long)PDE(inode)->data;
+       return 0;
 }
 
 static const struct file_operations xt_target_ops = {
@@ -966,7 +1051,7 @@ static const struct file_operations xt_target_ops = {
        .open    = xt_target_open,
        .read    = seq_read,
        .llseek  = seq_lseek,
-       .release = seq_release,
+       .release = seq_release_private,
 };
 
 #define FORMAT_TABLES  "_tables_names"
index fe80b614a40033014f48cfe1fad26f3806af85c2..791e030ea9031358d8d19f6da099554fb090b304 100644 (file)
@@ -542,7 +542,7 @@ recent_mt_proc_write(struct file *file, const char __user *input,
        struct recent_entry *e;
        char buf[sizeof("+b335:1d35:1e55:dead:c0de:1715:5afe:c0de")];
        const char *c = buf;
-       union nf_inet_addr addr;
+       union nf_inet_addr addr = {};
        u_int16_t family;
        bool add, succ;
 
index 5b33879c642211c892a26db2cba051cf6ff4ad03..b73d4e61c5ac02225ea6c1db41f4da3eb563ac17 100644 (file)
@@ -85,6 +85,7 @@ struct netlink_sock {
 
 #define NETLINK_KERNEL_SOCKET  0x1
 #define NETLINK_RECV_PKTINFO   0x2
+#define NETLINK_BROADCAST_SEND_ERROR   0x4
 
 static inline struct netlink_sock *nlk_sk(struct sock *sk)
 {
@@ -995,12 +996,15 @@ static inline int do_one_broadcast(struct sock *sk,
                netlink_overrun(sk);
                /* Clone failed. Notify ALL listeners. */
                p->failure = 1;
+               if (nlk->flags & NETLINK_BROADCAST_SEND_ERROR)
+                       p->delivery_failure = 1;
        } else if (sk_filter(sk, p->skb2)) {
                kfree_skb(p->skb2);
                p->skb2 = NULL;
        } else if ((val = netlink_broadcast_deliver(sk, p->skb2)) < 0) {
                netlink_overrun(sk);
-               p->delivery_failure = 1;
+               if (nlk->flags & NETLINK_BROADCAST_SEND_ERROR)
+                       p->delivery_failure = 1;
        } else {
                p->congested |= val;
                p->delivered = 1;
@@ -1045,10 +1049,9 @@ int netlink_broadcast(struct sock *ssk, struct sk_buff *skb, u32 pid,
 
        netlink_unlock_table();
 
-       if (info.skb2)
-               kfree_skb(info.skb2);
+       kfree_skb(info.skb2);
 
-       if (info.delivery_failure || info.failure)
+       if (info.delivery_failure)
                return -ENOBUFS;
 
        if (info.delivered) {
@@ -1088,6 +1091,13 @@ out:
        return 0;
 }
 
+/**
+ * netlink_set_err - report error to broadcast listeners
+ * @ssk: the kernel netlink socket, as returned by netlink_kernel_create()
+ * @pid: the PID of a process that we want to skip (if any)
+ * @groups: the broadcast group that will notice the error
+ * @code: error code, must be negative (as usual in kernelspace)
+ */
 void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)
 {
        struct netlink_set_err_data info;
@@ -1097,7 +1107,8 @@ void netlink_set_err(struct sock *ssk, u32 pid, u32 group, int code)
        info.exclude_sk = ssk;
        info.pid = pid;
        info.group = group;
-       info.code = code;
+       /* sk->sk_err wants a positive error value */
+       info.code = -code;
 
        read_lock(&nl_table_lock);
 
@@ -1164,6 +1175,13 @@ static int netlink_setsockopt(struct socket *sock, int level, int optname,
                err = 0;
                break;
        }
+       case NETLINK_BROADCAST_ERROR:
+               if (val)
+                       nlk->flags |= NETLINK_BROADCAST_SEND_ERROR;
+               else
+                       nlk->flags &= ~NETLINK_BROADCAST_SEND_ERROR;
+               err = 0;
+               break;
        default:
                err = -ENOPROTOOPT;
        }
@@ -1196,6 +1214,16 @@ static int netlink_getsockopt(struct socket *sock, int level, int optname,
                        return -EFAULT;
                err = 0;
                break;
+       case NETLINK_BROADCAST_ERROR:
+               if (len < sizeof(int))
+                       return -EINVAL;
+               len = sizeof(int);
+               val = nlk->flags & NETLINK_BROADCAST_SEND_ERROR ? 1 : 0;
+               if (put_user(len, optlen) ||
+                   put_user(val, optval))
+                       return -EFAULT;
+               err = 0;
+               break;
        default:
                err = -ENOPROTOOPT;
        }
@@ -1522,8 +1550,7 @@ EXPORT_SYMBOL(netlink_set_nonroot);
 
 static void netlink_destroy_callback(struct netlink_callback *cb)
 {
-       if (cb->skb)
-               kfree_skb(cb->skb);
+       kfree_skb(cb->skb);
        kfree(cb);
 }
 
@@ -1740,12 +1767,18 @@ int nlmsg_notify(struct sock *sk, struct sk_buff *skb, u32 pid,
                        exclude_pid = pid;
                }
 
-               /* errors reported via destination sk->sk_err */
-               nlmsg_multicast(sk, skb, exclude_pid, group, flags);
+               /* errors reported via destination sk->sk_err, but propagate
+                * delivery errors if NETLINK_BROADCAST_ERROR flag is set */
+               err = nlmsg_multicast(sk, skb, exclude_pid, group, flags);
        }
 
-       if (report)
-               err = nlmsg_unicast(sk, skb, pid);
+       if (report) {
+               int err2;
+
+               err2 = nlmsg_unicast(sk, skb, pid);
+               if (!err || err == -ESRCH)
+                       err = err2;
+       }
 
        return err;
 }
index cba7849de98e26988d93bd4ee6058be4ce7f0558..6d9c58ec56ac70193adb3cddcb2ef0968ee1906c 100644 (file)
@@ -1037,6 +1037,10 @@ static int nr_sendmsg(struct kiocb *iocb, struct socket *sock,
        unsigned char *asmptr;
        int size;
 
+       /* Netrom empty data frame has no meaning : don't send */
+       if (len == 0)
+               return 0;
+
        if (msg->msg_flags & ~(MSG_DONTWAIT|MSG_EOR|MSG_CMSG_COMPAT))
                return -EINVAL;
 
@@ -1167,6 +1171,11 @@ static int nr_recvmsg(struct kiocb *iocb, struct socket *sock,
        skb_reset_transport_header(skb);
        copied     = skb->len;
 
+       /* NetRom empty data frame has no meaning : ignore it */
+       if (copied == 0) {
+               goto out;
+       }
+
        if (copied > size) {
                copied = size;
                msg->msg_flags |= MSG_TRUNC;
@@ -1182,7 +1191,7 @@ static int nr_recvmsg(struct kiocb *iocb, struct socket *sock,
 
        msg->msg_namelen = sizeof(*sax);
 
-       skb_free_datagram(sk, skb);
+out:   skb_free_datagram(sk, skb);
 
        release_sock(sk);
        return copied;
index 1fc4a7885c410f59ce5c81399d6829084a99cdbd..74776de523ec52239627bf54ca7c50f546d01627 100644 (file)
@@ -584,7 +584,7 @@ drop_n_restore:
                skb->len = skb_len;
        }
 drop:
-       kfree_skb(skb);
+       consume_skb(skb);
        return 0;
 }
 
@@ -756,8 +756,7 @@ ring_is_full:
        spin_unlock(&sk->sk_receive_queue.lock);
 
        sk->sk_data_ready(sk, 0);
-       if (copy_skb)
-               kfree_skb(copy_skb);
+       kfree_skb(copy_skb);
        goto drop_n_restore;
 }
 
index 81795ea87794af8b10540451313c5969e0beb4d7..a662e62a99cfa0adcf7589aa457a19bfeb21b48a 100644 (file)
@@ -382,9 +382,8 @@ out:
        return NET_RX_DROP;
 }
 
-static struct packet_type phonet_packet_type = {
+static struct packet_type phonet_packet_type __read_mostly = {
        .type = cpu_to_be16(ETH_P_PHONET),
-       .dev = NULL,
        .func = phonet_rcv,
 };
 
index 1ceea1f92413d2d4b03d545152f339e628ab9b33..cec4e59516817ecc0b64a8fdaa04c11de52aa0b2 100644 (file)
@@ -47,8 +47,9 @@ static void rtmsg_notify(int event, struct net_device *dev, u8 addr)
                kfree_skb(skb);
                goto errout;
        }
-       err = rtnl_notify(skb, dev_net(dev), 0,
-                         RTNLGRP_PHONET_IFADDR, NULL, GFP_KERNEL);
+       rtnl_notify(skb, dev_net(dev), 0,
+                   RTNLGRP_PHONET_IFADDR, NULL, GFP_KERNEL);
+       return;
 errout:
        if (err < 0)
                rtnl_set_sk_err(dev_net(dev), RTNLGRP_PHONET_IFADDR, err);
diff --git a/net/rds/Kconfig b/net/rds/Kconfig
new file mode 100644 (file)
index 0000000..796773b
--- /dev/null
@@ -0,0 +1,14 @@
+
+config RDS
+       tristate "Reliable Datagram Sockets (RDS) (EXPERIMENTAL)"
+       depends on INET && INFINIBAND_IPOIB && EXPERIMENTAL
+       depends on INFINIBAND && INFINIBAND_ADDR_TRANS
+       ---help---
+         RDS provides reliable, sequenced delivery of datagrams
+         over Infiniband.
+
+config RDS_DEBUG
+        bool "Debugging messages"
+       depends on RDS
+        default n
+
diff --git a/net/rds/Makefile b/net/rds/Makefile
new file mode 100644 (file)
index 0000000..51f2758
--- /dev/null
@@ -0,0 +1,14 @@
+obj-$(CONFIG_RDS) += rds.o
+rds-y :=       af_rds.o bind.o cong.o connection.o info.o message.o   \
+                       recv.o send.o stats.o sysctl.o threads.o transport.o \
+                       loop.o page.o rdma.o \
+                       rdma_transport.o \
+                       ib.o ib_cm.o ib_recv.o ib_ring.o ib_send.o ib_stats.o \
+                       ib_sysctl.o ib_rdma.o \
+                       iw.o iw_cm.o iw_recv.o iw_ring.o iw_send.o iw_stats.o \
+                       iw_sysctl.o iw_rdma.o
+
+ifeq ($(CONFIG_RDS_DEBUG), y)
+EXTRA_CFLAGS += -DDEBUG
+endif
+
diff --git a/net/rds/af_rds.c b/net/rds/af_rds.c
new file mode 100644 (file)
index 0000000..20cf16f
--- /dev/null
@@ -0,0 +1,586 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/module.h>
+#include <linux/errno.h>
+#include <linux/kernel.h>
+#include <linux/in.h>
+#include <linux/poll.h>
+#include <linux/version.h>
+#include <net/sock.h>
+
+#include "rds.h"
+#include "rdma.h"
+#include "rdma_transport.h"
+
+/* this is just used for stats gathering :/ */
+static DEFINE_SPINLOCK(rds_sock_lock);
+static unsigned long rds_sock_count;
+static LIST_HEAD(rds_sock_list);
+DECLARE_WAIT_QUEUE_HEAD(rds_poll_waitq);
+
+/*
+ * This is called as the final descriptor referencing this socket is closed.
+ * We have to unbind the socket so that another socket can be bound to the
+ * address it was using.
+ *
+ * We have to be careful about racing with the incoming path.  sock_orphan()
+ * sets SOCK_DEAD and we use that as an indicator to the rx path that new
+ * messages shouldn't be queued.
+ */
+static int rds_release(struct socket *sock)
+{
+       struct sock *sk = sock->sk;
+       struct rds_sock *rs;
+       unsigned long flags;
+
+       if (sk == NULL)
+               goto out;
+
+       rs = rds_sk_to_rs(sk);
+
+       sock_orphan(sk);
+       /* Note - rds_clear_recv_queue grabs rs_recv_lock, so
+        * that ensures the recv path has completed messing
+        * with the socket. */
+       rds_clear_recv_queue(rs);
+       rds_cong_remove_socket(rs);
+       rds_remove_bound(rs);
+       rds_send_drop_to(rs, NULL);
+       rds_rdma_drop_keys(rs);
+       rds_notify_queue_get(rs, NULL);
+
+       spin_lock_irqsave(&rds_sock_lock, flags);
+       list_del_init(&rs->rs_item);
+       rds_sock_count--;
+       spin_unlock_irqrestore(&rds_sock_lock, flags);
+
+       sock->sk = NULL;
+       sock_put(sk);
+out:
+       return 0;
+}
+
+/*
+ * Careful not to race with rds_release -> sock_orphan which clears sk_sleep.
+ * _bh() isn't OK here, we're called from interrupt handlers.  It's probably OK
+ * to wake the waitqueue after sk_sleep is clear as we hold a sock ref, but
+ * this seems more conservative.
+ * NB - normally, one would use sk_callback_lock for this, but we can
+ * get here from interrupts, whereas the network code grabs sk_callback_lock
+ * with _lock_bh only - so relying on sk_callback_lock introduces livelocks.
+ */
+void rds_wake_sk_sleep(struct rds_sock *rs)
+{
+       unsigned long flags;
+
+       read_lock_irqsave(&rs->rs_recv_lock, flags);
+       __rds_wake_sk_sleep(rds_rs_to_sk(rs));
+       read_unlock_irqrestore(&rs->rs_recv_lock, flags);
+}
+
+static int rds_getname(struct socket *sock, struct sockaddr *uaddr,
+                      int *uaddr_len, int peer)
+{
+       struct sockaddr_in *sin = (struct sockaddr_in *)uaddr;
+       struct rds_sock *rs = rds_sk_to_rs(sock->sk);
+
+       memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+
+       /* racey, don't care */
+       if (peer) {
+               if (!rs->rs_conn_addr)
+                       return -ENOTCONN;
+
+               sin->sin_port = rs->rs_conn_port;
+               sin->sin_addr.s_addr = rs->rs_conn_addr;
+       } else {
+               sin->sin_port = rs->rs_bound_port;
+               sin->sin_addr.s_addr = rs->rs_bound_addr;
+       }
+
+       sin->sin_family = AF_INET;
+
+       *uaddr_len = sizeof(*sin);
+       return 0;
+}
+
+/*
+ * RDS' poll is without a doubt the least intuitive part of the interface,
+ * as POLLIN and POLLOUT do not behave entirely as you would expect from
+ * a network protocol.
+ *
+ * POLLIN is asserted if
+ *  -  there is data on the receive queue.
+ *  -  to signal that a previously congested destination may have become
+ *     uncongested
+ *  -  A notification has been queued to the socket (this can be a congestion
+ *     update, or a RDMA completion).
+ *
+ * POLLOUT is asserted if there is room on the send queue. This does not mean
+ * however, that the next sendmsg() call will succeed. If the application tries
+ * to send to a congested destination, the system call may still fail (and
+ * return ENOBUFS).
+ */
+static unsigned int rds_poll(struct file *file, struct socket *sock,
+                            poll_table *wait)
+{
+       struct sock *sk = sock->sk;
+       struct rds_sock *rs = rds_sk_to_rs(sk);
+       unsigned int mask = 0;
+       unsigned long flags;
+
+       poll_wait(file, sk->sk_sleep, wait);
+
+       poll_wait(file, &rds_poll_waitq, wait);
+
+       read_lock_irqsave(&rs->rs_recv_lock, flags);
+       if (!rs->rs_cong_monitor) {
+               /* When a congestion map was updated, we signal POLLIN for
+                * "historical" reasons. Applications can also poll for
+                * WRBAND instead. */
+               if (rds_cong_updated_since(&rs->rs_cong_track))
+                       mask |= (POLLIN | POLLRDNORM | POLLWRBAND);
+       } else {
+               spin_lock(&rs->rs_lock);
+               if (rs->rs_cong_notify)
+                       mask |= (POLLIN | POLLRDNORM);
+               spin_unlock(&rs->rs_lock);
+       }
+       if (!list_empty(&rs->rs_recv_queue)
+        || !list_empty(&rs->rs_notify_queue))
+               mask |= (POLLIN | POLLRDNORM);
+       if (rs->rs_snd_bytes < rds_sk_sndbuf(rs))
+               mask |= (POLLOUT | POLLWRNORM);
+       read_unlock_irqrestore(&rs->rs_recv_lock, flags);
+
+       return mask;
+}
+
+static int rds_ioctl(struct socket *sock, unsigned int cmd, unsigned long arg)
+{
+       return -ENOIOCTLCMD;
+}
+
+static int rds_cancel_sent_to(struct rds_sock *rs, char __user *optval,
+                             int len)
+{
+       struct sockaddr_in sin;
+       int ret = 0;
+
+       /* racing with another thread binding seems ok here */
+       if (rs->rs_bound_addr == 0) {
+               ret = -ENOTCONN; /* XXX not a great errno */
+               goto out;
+       }
+
+       if (len < sizeof(struct sockaddr_in)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (copy_from_user(&sin, optval, sizeof(sin))) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       rds_send_drop_to(rs, &sin);
+out:
+       return ret;
+}
+
+static int rds_set_bool_option(unsigned char *optvar, char __user *optval,
+                              int optlen)
+{
+       int value;
+
+       if (optlen < sizeof(int))
+               return -EINVAL;
+       if (get_user(value, (int __user *) optval))
+               return -EFAULT;
+       *optvar = !!value;
+       return 0;
+}
+
+static int rds_cong_monitor(struct rds_sock *rs, char __user *optval,
+                           int optlen)
+{
+       int ret;
+
+       ret = rds_set_bool_option(&rs->rs_cong_monitor, optval, optlen);
+       if (ret == 0) {
+               if (rs->rs_cong_monitor) {
+                       rds_cong_add_socket(rs);
+               } else {
+                       rds_cong_remove_socket(rs);
+                       rs->rs_cong_mask = 0;
+                       rs->rs_cong_notify = 0;
+               }
+       }
+       return ret;
+}
+
+static int rds_setsockopt(struct socket *sock, int level, int optname,
+                         char __user *optval, int optlen)
+{
+       struct rds_sock *rs = rds_sk_to_rs(sock->sk);
+       int ret;
+
+       if (level != SOL_RDS) {
+               ret = -ENOPROTOOPT;
+               goto out;
+       }
+
+       switch (optname) {
+       case RDS_CANCEL_SENT_TO:
+               ret = rds_cancel_sent_to(rs, optval, optlen);
+               break;
+       case RDS_GET_MR:
+               ret = rds_get_mr(rs, optval, optlen);
+               break;
+       case RDS_FREE_MR:
+               ret = rds_free_mr(rs, optval, optlen);
+               break;
+       case RDS_RECVERR:
+               ret = rds_set_bool_option(&rs->rs_recverr, optval, optlen);
+               break;
+       case RDS_CONG_MONITOR:
+               ret = rds_cong_monitor(rs, optval, optlen);
+               break;
+       default:
+               ret = -ENOPROTOOPT;
+       }
+out:
+       return ret;
+}
+
+static int rds_getsockopt(struct socket *sock, int level, int optname,
+                         char __user *optval, int __user *optlen)
+{
+       struct rds_sock *rs = rds_sk_to_rs(sock->sk);
+       int ret = -ENOPROTOOPT, len;
+
+       if (level != SOL_RDS)
+               goto out;
+
+       if (get_user(len, optlen)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       switch (optname) {
+       case RDS_INFO_FIRST ... RDS_INFO_LAST:
+               ret = rds_info_getsockopt(sock, optname, optval,
+                                         optlen);
+               break;
+
+       case RDS_RECVERR:
+               if (len < sizeof(int))
+                       ret = -EINVAL;
+               else
+               if (put_user(rs->rs_recverr, (int __user *) optval)
+                || put_user(sizeof(int), optlen))
+                       ret = -EFAULT;
+               else
+                       ret = 0;
+               break;
+       default:
+               break;
+       }
+
+out:
+       return ret;
+
+}
+
+static int rds_connect(struct socket *sock, struct sockaddr *uaddr,
+                      int addr_len, int flags)
+{
+       struct sock *sk = sock->sk;
+       struct sockaddr_in *sin = (struct sockaddr_in *)uaddr;
+       struct rds_sock *rs = rds_sk_to_rs(sk);
+       int ret = 0;
+
+       lock_sock(sk);
+
+       if (addr_len != sizeof(struct sockaddr_in)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       if (sin->sin_family != AF_INET) {
+               ret = -EAFNOSUPPORT;
+               goto out;
+       }
+
+       if (sin->sin_addr.s_addr == htonl(INADDR_ANY)) {
+               ret = -EDESTADDRREQ;
+               goto out;
+       }
+
+       rs->rs_conn_addr = sin->sin_addr.s_addr;
+       rs->rs_conn_port = sin->sin_port;
+
+out:
+       release_sock(sk);
+       return ret;
+}
+
+static struct proto rds_proto = {
+       .name     = "RDS",
+       .owner    = THIS_MODULE,
+       .obj_size = sizeof(struct rds_sock),
+};
+
+static struct proto_ops rds_proto_ops = {
+       .family =       AF_RDS,
+       .owner =        THIS_MODULE,
+       .release =      rds_release,
+       .bind =         rds_bind,
+       .connect =      rds_connect,
+       .socketpair =   sock_no_socketpair,
+       .accept =       sock_no_accept,
+       .getname =      rds_getname,
+       .poll =         rds_poll,
+       .ioctl =        rds_ioctl,
+       .listen =       sock_no_listen,
+       .shutdown =     sock_no_shutdown,
+       .setsockopt =   rds_setsockopt,
+       .getsockopt =   rds_getsockopt,
+       .sendmsg =      rds_sendmsg,
+       .recvmsg =      rds_recvmsg,
+       .mmap =         sock_no_mmap,
+       .sendpage =     sock_no_sendpage,
+};
+
+static int __rds_create(struct socket *sock, struct sock *sk, int protocol)
+{
+       unsigned long flags;
+       struct rds_sock *rs;
+
+       sock_init_data(sock, sk);
+       sock->ops               = &rds_proto_ops;
+       sk->sk_protocol         = protocol;
+
+       rs = rds_sk_to_rs(sk);
+       spin_lock_init(&rs->rs_lock);
+       rwlock_init(&rs->rs_recv_lock);
+       INIT_LIST_HEAD(&rs->rs_send_queue);
+       INIT_LIST_HEAD(&rs->rs_recv_queue);
+       INIT_LIST_HEAD(&rs->rs_notify_queue);
+       INIT_LIST_HEAD(&rs->rs_cong_list);
+       spin_lock_init(&rs->rs_rdma_lock);
+       rs->rs_rdma_keys = RB_ROOT;
+
+       spin_lock_irqsave(&rds_sock_lock, flags);
+       list_add_tail(&rs->rs_item, &rds_sock_list);
+       rds_sock_count++;
+       spin_unlock_irqrestore(&rds_sock_lock, flags);
+
+       return 0;
+}
+
+static int rds_create(struct net *net, struct socket *sock, int protocol)
+{
+       struct sock *sk;
+
+       if (sock->type != SOCK_SEQPACKET || protocol)
+               return -ESOCKTNOSUPPORT;
+
+       sk = sk_alloc(net, AF_RDS, GFP_ATOMIC, &rds_proto);
+       if (!sk)
+               return -ENOMEM;
+
+       return __rds_create(sock, sk, protocol);
+}
+
+void rds_sock_addref(struct rds_sock *rs)
+{
+       sock_hold(rds_rs_to_sk(rs));
+}
+
+void rds_sock_put(struct rds_sock *rs)
+{
+       sock_put(rds_rs_to_sk(rs));
+}
+
+static struct net_proto_family rds_family_ops = {
+       .family =       AF_RDS,
+       .create =       rds_create,
+       .owner  =       THIS_MODULE,
+};
+
+static void rds_sock_inc_info(struct socket *sock, unsigned int len,
+                             struct rds_info_iterator *iter,
+                             struct rds_info_lengths *lens)
+{
+       struct rds_sock *rs;
+       struct sock *sk;
+       struct rds_incoming *inc;
+       unsigned long flags;
+       unsigned int total = 0;
+
+       len /= sizeof(struct rds_info_message);
+
+       spin_lock_irqsave(&rds_sock_lock, flags);
+
+       list_for_each_entry(rs, &rds_sock_list, rs_item) {
+               sk = rds_rs_to_sk(rs);
+               read_lock(&rs->rs_recv_lock);
+
+               /* XXX too lazy to maintain counts.. */
+               list_for_each_entry(inc, &rs->rs_recv_queue, i_item) {
+                       total++;
+                       if (total <= len)
+                               rds_inc_info_copy(inc, iter, inc->i_saddr,
+                                                 rs->rs_bound_addr, 1);
+               }
+
+               read_unlock(&rs->rs_recv_lock);
+       }
+
+       spin_unlock_irqrestore(&rds_sock_lock, flags);
+
+       lens->nr = total;
+       lens->each = sizeof(struct rds_info_message);
+}
+
+static void rds_sock_info(struct socket *sock, unsigned int len,
+                         struct rds_info_iterator *iter,
+                         struct rds_info_lengths *lens)
+{
+       struct rds_info_socket sinfo;
+       struct rds_sock *rs;
+       unsigned long flags;
+
+       len /= sizeof(struct rds_info_socket);
+
+       spin_lock_irqsave(&rds_sock_lock, flags);
+
+       if (len < rds_sock_count)
+               goto out;
+
+       list_for_each_entry(rs, &rds_sock_list, rs_item) {
+               sinfo.sndbuf = rds_sk_sndbuf(rs);
+               sinfo.rcvbuf = rds_sk_rcvbuf(rs);
+               sinfo.bound_addr = rs->rs_bound_addr;
+               sinfo.connected_addr = rs->rs_conn_addr;
+               sinfo.bound_port = rs->rs_bound_port;
+               sinfo.connected_port = rs->rs_conn_port;
+               sinfo.inum = sock_i_ino(rds_rs_to_sk(rs));
+
+               rds_info_copy(iter, &sinfo, sizeof(sinfo));
+       }
+
+out:
+       lens->nr = rds_sock_count;
+       lens->each = sizeof(struct rds_info_socket);
+
+       spin_unlock_irqrestore(&rds_sock_lock, flags);
+}
+
+static void __exit rds_exit(void)
+{
+       rds_rdma_exit();
+       sock_unregister(rds_family_ops.family);
+       proto_unregister(&rds_proto);
+       rds_conn_exit();
+       rds_cong_exit();
+       rds_sysctl_exit();
+       rds_threads_exit();
+       rds_stats_exit();
+       rds_page_exit();
+       rds_info_deregister_func(RDS_INFO_SOCKETS, rds_sock_info);
+       rds_info_deregister_func(RDS_INFO_RECV_MESSAGES, rds_sock_inc_info);
+}
+module_exit(rds_exit);
+
+static int __init rds_init(void)
+{
+       int ret;
+
+       ret = rds_conn_init();
+       if (ret)
+               goto out;
+       ret = rds_threads_init();
+       if (ret)
+               goto out_conn;
+       ret = rds_sysctl_init();
+       if (ret)
+               goto out_threads;
+       ret = rds_stats_init();
+       if (ret)
+               goto out_sysctl;
+       ret = proto_register(&rds_proto, 1);
+       if (ret)
+               goto out_stats;
+       ret = sock_register(&rds_family_ops);
+       if (ret)
+               goto out_proto;
+
+       rds_info_register_func(RDS_INFO_SOCKETS, rds_sock_info);
+       rds_info_register_func(RDS_INFO_RECV_MESSAGES, rds_sock_inc_info);
+
+       /* ib/iwarp transports currently compiled-in */
+       ret = rds_rdma_init();
+       if (ret)
+               goto out_sock;
+       goto out;
+
+out_sock:
+       sock_unregister(rds_family_ops.family);
+out_proto:
+       proto_unregister(&rds_proto);
+out_stats:
+       rds_stats_exit();
+out_sysctl:
+       rds_sysctl_exit();
+out_threads:
+       rds_threads_exit();
+out_conn:
+       rds_conn_exit();
+       rds_cong_exit();
+       rds_page_exit();
+out:
+       return ret;
+}
+module_init(rds_init);
+
+#define DRV_VERSION     "4.0"
+#define DRV_RELDATE     "Feb 12, 2009"
+
+MODULE_AUTHOR("Oracle Corporation <rds-devel@oss.oracle.com>");
+MODULE_DESCRIPTION("RDS: Reliable Datagram Sockets"
+                  " v" DRV_VERSION " (" DRV_RELDATE ")");
+MODULE_VERSION(DRV_VERSION);
+MODULE_LICENSE("Dual BSD/GPL");
+MODULE_ALIAS_NETPROTO(PF_RDS);
diff --git a/net/rds/bind.c b/net/rds/bind.c
new file mode 100644 (file)
index 0000000..c17cc39
--- /dev/null
@@ -0,0 +1,199 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <net/sock.h>
+#include <linux/in.h>
+#include <linux/if_arp.h>
+#include "rds.h"
+
+/*
+ * XXX this probably still needs more work.. no INADDR_ANY, and rbtrees aren't
+ * particularly zippy.
+ *
+ * This is now called for every incoming frame so we arguably care much more
+ * about it than we used to.
+ */
+static DEFINE_SPINLOCK(rds_bind_lock);
+static struct rb_root rds_bind_tree = RB_ROOT;
+
+static struct rds_sock *rds_bind_tree_walk(__be32 addr, __be16 port,
+                                          struct rds_sock *insert)
+{
+       struct rb_node **p = &rds_bind_tree.rb_node;
+       struct rb_node *parent = NULL;
+       struct rds_sock *rs;
+       u64 cmp;
+       u64 needle = ((u64)be32_to_cpu(addr) << 32) | be16_to_cpu(port);
+
+       while (*p) {
+               parent = *p;
+               rs = rb_entry(parent, struct rds_sock, rs_bound_node);
+
+               cmp = ((u64)be32_to_cpu(rs->rs_bound_addr) << 32) |
+                     be16_to_cpu(rs->rs_bound_port);
+
+               if (needle < cmp)
+                       p = &(*p)->rb_left;
+               else if (needle > cmp)
+                       p = &(*p)->rb_right;
+               else
+                       return rs;
+       }
+
+       if (insert) {
+               rb_link_node(&insert->rs_bound_node, parent, p);
+               rb_insert_color(&insert->rs_bound_node, &rds_bind_tree);
+       }
+       return NULL;
+}
+
+/*
+ * Return the rds_sock bound at the given local address.
+ *
+ * The rx path can race with rds_release.  We notice if rds_release() has
+ * marked this socket and don't return a rs ref to the rx path.
+ */
+struct rds_sock *rds_find_bound(__be32 addr, __be16 port)
+{
+       struct rds_sock *rs;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rds_bind_lock, flags);
+       rs = rds_bind_tree_walk(addr, port, NULL);
+       if (rs && !sock_flag(rds_rs_to_sk(rs), SOCK_DEAD))
+               rds_sock_addref(rs);
+       else
+               rs = NULL;
+       spin_unlock_irqrestore(&rds_bind_lock, flags);
+
+       rdsdebug("returning rs %p for %pI4:%u\n", rs, &addr,
+               ntohs(port));
+       return rs;
+}
+
+/* returns -ve errno or +ve port */
+static int rds_add_bound(struct rds_sock *rs, __be32 addr, __be16 *port)
+{
+       unsigned long flags;
+       int ret = -EADDRINUSE;
+       u16 rover, last;
+
+       if (*port != 0) {
+               rover = be16_to_cpu(*port);
+               last = rover;
+       } else {
+               rover = max_t(u16, net_random(), 2);
+               last = rover - 1;
+       }
+
+       spin_lock_irqsave(&rds_bind_lock, flags);
+
+       do {
+               if (rover == 0)
+                       rover++;
+               if (rds_bind_tree_walk(addr, cpu_to_be16(rover), rs) == NULL) {
+                       *port = cpu_to_be16(rover);
+                       ret = 0;
+                       break;
+               }
+       } while (rover++ != last);
+
+       if (ret == 0)  {
+               rs->rs_bound_addr = addr;
+               rs->rs_bound_port = *port;
+               rds_sock_addref(rs);
+
+               rdsdebug("rs %p binding to %pI4:%d\n",
+                 rs, &addr, (int)ntohs(*port));
+       }
+
+       spin_unlock_irqrestore(&rds_bind_lock, flags);
+
+       return ret;
+}
+
+void rds_remove_bound(struct rds_sock *rs)
+{
+       unsigned long flags;
+
+       spin_lock_irqsave(&rds_bind_lock, flags);
+
+       if (rs->rs_bound_addr) {
+               rdsdebug("rs %p unbinding from %pI4:%d\n",
+                 rs, &rs->rs_bound_addr,
+                 ntohs(rs->rs_bound_port));
+
+               rb_erase(&rs->rs_bound_node, &rds_bind_tree);
+               rds_sock_put(rs);
+               rs->rs_bound_addr = 0;
+       }
+
+       spin_unlock_irqrestore(&rds_bind_lock, flags);
+}
+
+int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len)
+{
+       struct sock *sk = sock->sk;
+       struct sockaddr_in *sin = (struct sockaddr_in *)uaddr;
+       struct rds_sock *rs = rds_sk_to_rs(sk);
+       struct rds_transport *trans;
+       int ret = 0;
+
+       lock_sock(sk);
+
+       if (addr_len != sizeof(struct sockaddr_in) ||
+           sin->sin_family != AF_INET ||
+           rs->rs_bound_addr ||
+           sin->sin_addr.s_addr == htonl(INADDR_ANY)) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       ret = rds_add_bound(rs, sin->sin_addr.s_addr, &sin->sin_port);
+       if (ret)
+               goto out;
+
+       trans = rds_trans_get_preferred(sin->sin_addr.s_addr);
+       if (trans == NULL) {
+               ret = -EADDRNOTAVAIL;
+               rds_remove_bound(rs);
+               goto out;
+       }
+
+       rs->rs_transport = trans;
+       ret = 0;
+
+out:
+       release_sock(sk);
+       return ret;
+}
diff --git a/net/rds/cong.c b/net/rds/cong.c
new file mode 100644 (file)
index 0000000..710e459
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+ * Copyright (c) 2007 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/types.h>
+#include <linux/rbtree.h>
+
+#include <asm-generic/bitops/le.h>
+
+#include "rds.h"
+
+/*
+ * This file implements the receive side of the unconventional congestion
+ * management in RDS.
+ *
+ * Messages waiting in the receive queue on the receiving socket are accounted
+ * against the sockets SO_RCVBUF option value.  Only the payload bytes in the
+ * message are accounted for.  If the number of bytes queued equals or exceeds
+ * rcvbuf then the socket is congested.  All sends attempted to this socket's
+ * address should return block or return -EWOULDBLOCK.
+ *
+ * Applications are expected to be reasonably tuned such that this situation
+ * very rarely occurs.  An application encountering this "back-pressure" is
+ * considered a bug.
+ *
+ * This is implemented by having each node maintain bitmaps which indicate
+ * which ports on bound addresses are congested.  As the bitmap changes it is
+ * sent through all the connections which terminate in the local address of the
+ * bitmap which changed.
+ *
+ * The bitmaps are allocated as connections are brought up.  This avoids
+ * allocation in the interrupt handling path which queues messages on sockets.
+ * The dense bitmaps let transports send the entire bitmap on any bitmap change
+ * reasonably efficiently.  This is much easier to implement than some
+ * finer-grained communication of per-port congestion.  The sender does a very
+ * inexpensive bit test to test if the port it's about to send to is congested
+ * or not.
+ */
+
+/*
+ * Interaction with poll is a tad tricky. We want all processes stuck in
+ * poll to wake up and check whether a congested destination became uncongested.
+ * The really sad thing is we have no idea which destinations the application
+ * wants to send to - we don't even know which rds_connections are involved.
+ * So until we implement a more flexible rds poll interface, we have to make
+ * do with this:
+ * We maintain a global counter that is incremented each time a congestion map
+ * update is received. Each rds socket tracks this value, and if rds_poll
+ * finds that the saved generation number is smaller than the global generation
+ * number, it wakes up the process.
+ */
+static atomic_t                rds_cong_generation = ATOMIC_INIT(0);
+
+/*
+ * Congestion monitoring
+ */
+static LIST_HEAD(rds_cong_monitor);
+static DEFINE_RWLOCK(rds_cong_monitor_lock);
+
+/*
+ * Yes, a global lock.  It's used so infrequently that it's worth keeping it
+ * global to simplify the locking.  It's only used in the following
+ * circumstances:
+ *
+ *  - on connection buildup to associate a conn with its maps
+ *  - on map changes to inform conns of a new map to send
+ *
+ *  It's sadly ordered under the socket callback lock and the connection lock.
+ *  Receive paths can mark ports congested from interrupt context so the
+ *  lock masks interrupts.
+ */
+static DEFINE_SPINLOCK(rds_cong_lock);
+static struct rb_root rds_cong_tree = RB_ROOT;
+
+static struct rds_cong_map *rds_cong_tree_walk(__be32 addr,
+                                              struct rds_cong_map *insert)
+{
+       struct rb_node **p = &rds_cong_tree.rb_node;
+       struct rb_node *parent = NULL;
+       struct rds_cong_map *map;
+
+       while (*p) {
+               parent = *p;
+               map = rb_entry(parent, struct rds_cong_map, m_rb_node);
+
+               if (addr < map->m_addr)
+                       p = &(*p)->rb_left;
+               else if (addr > map->m_addr)
+                       p = &(*p)->rb_right;
+               else
+                       return map;
+       }
+
+       if (insert) {
+               rb_link_node(&insert->m_rb_node, parent, p);
+               rb_insert_color(&insert->m_rb_node, &rds_cong_tree);
+       }
+       return NULL;
+}
+
+/*
+ * There is only ever one bitmap for any address.  Connections try and allocate
+ * these bitmaps in the process getting pointers to them.  The bitmaps are only
+ * ever freed as the module is removed after all connections have been freed.
+ */
+static struct rds_cong_map *rds_cong_from_addr(__be32 addr)
+{
+       struct rds_cong_map *map;
+       struct rds_cong_map *ret = NULL;
+       unsigned long zp;
+       unsigned long i;
+       unsigned long flags;
+
+       map = kzalloc(sizeof(struct rds_cong_map), GFP_KERNEL);
+       if (map == NULL)
+               return NULL;
+
+       map->m_addr = addr;
+       init_waitqueue_head(&map->m_waitq);
+       INIT_LIST_HEAD(&map->m_conn_list);
+
+       for (i = 0; i < RDS_CONG_MAP_PAGES; i++) {
+               zp = get_zeroed_page(GFP_KERNEL);
+               if (zp == 0)
+                       goto out;
+               map->m_page_addrs[i] = zp;
+       }
+
+       spin_lock_irqsave(&rds_cong_lock, flags);
+       ret = rds_cong_tree_walk(addr, map);
+       spin_unlock_irqrestore(&rds_cong_lock, flags);
+
+       if (ret == NULL) {
+               ret = map;
+               map = NULL;
+       }
+
+out:
+       if (map) {
+               for (i = 0; i < RDS_CONG_MAP_PAGES && map->m_page_addrs[i]; i++)
+                       free_page(map->m_page_addrs[i]);
+               kfree(map);
+       }
+
+       rdsdebug("map %p for addr %x\n", ret, be32_to_cpu(addr));
+
+       return ret;
+}
+
+/*
+ * Put the conn on its local map's list.  This is called when the conn is
+ * really added to the hash.  It's nested under the rds_conn_lock, sadly.
+ */
+void rds_cong_add_conn(struct rds_connection *conn)
+{
+       unsigned long flags;
+
+       rdsdebug("conn %p now on map %p\n", conn, conn->c_lcong);
+       spin_lock_irqsave(&rds_cong_lock, flags);
+       list_add_tail(&conn->c_map_item, &conn->c_lcong->m_conn_list);
+       spin_unlock_irqrestore(&rds_cong_lock, flags);
+}
+
+void rds_cong_remove_conn(struct rds_connection *conn)
+{
+       unsigned long flags;
+
+       rdsdebug("removing conn %p from map %p\n", conn, conn->c_lcong);
+       spin_lock_irqsave(&rds_cong_lock, flags);
+       list_del_init(&conn->c_map_item);
+       spin_unlock_irqrestore(&rds_cong_lock, flags);
+}
+
+int rds_cong_get_maps(struct rds_connection *conn)
+{
+       conn->c_lcong = rds_cong_from_addr(conn->c_laddr);
+       conn->c_fcong = rds_cong_from_addr(conn->c_faddr);
+
+       if (conn->c_lcong == NULL || conn->c_fcong == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
+
+void rds_cong_queue_updates(struct rds_cong_map *map)
+{
+       struct rds_connection *conn;
+       unsigned long flags;
+
+       spin_lock_irqsave(&rds_cong_lock, flags);
+
+       list_for_each_entry(conn, &map->m_conn_list, c_map_item) {
+               if (!test_and_set_bit(0, &conn->c_map_queued)) {
+                       rds_stats_inc(s_cong_update_queued);
+                       queue_delayed_work(rds_wq, &conn->c_send_w, 0);
+               }
+       }
+
+       spin_unlock_irqrestore(&rds_cong_lock, flags);
+}
+
+void rds_cong_map_updated(struct rds_cong_map *map, uint64_t portmask)
+{
+       rdsdebug("waking map %p for %pI4\n",
+         map, &map->m_addr);
+       rds_stats_inc(s_cong_update_received);
+       atomic_inc(&rds_cong_generation);
+       if (waitqueue_active(&map->m_waitq))
+               wake_up(&map->m_waitq);
+       if (waitqueue_active(&rds_poll_waitq))
+               wake_up_all(&rds_poll_waitq);
+
+       if (portmask && !list_empty(&rds_cong_monitor)) {
+               unsigned long flags;
+               struct rds_sock *rs;
+
+               read_lock_irqsave(&rds_cong_monitor_lock, flags);
+               list_for_each_entry(rs, &rds_cong_monitor, rs_cong_list) {
+                       spin_lock(&rs->rs_lock);
+                       rs->rs_cong_notify |= (rs->rs_cong_mask & portmask);
+                       rs->rs_cong_mask &= ~portmask;
+                       spin_unlock(&rs->rs_lock);
+                       if (rs->rs_cong_notify)
+                               rds_wake_sk_sleep(rs);
+               }
+               read_unlock_irqrestore(&rds_cong_monitor_lock, flags);
+       }
+}
+
+int rds_cong_updated_since(unsigned long *recent)
+{
+       unsigned long gen = atomic_read(&rds_cong_generation);
+
+       if (likely(*recent == gen))
+               return 0;
+       *recent = gen;
+       return 1;
+}
+
+/*
+ * We're called under the locking that protects the sockets receive buffer
+ * consumption.  This makes it a lot easier for the caller to only call us
+ * when it knows that an existing set bit needs to be cleared, and vice versa.
+ * We can't block and we need to deal with concurrent sockets working against
+ * the same per-address map.
+ */
+void rds_cong_set_bit(struct rds_cong_map *map, __be16 port)
+{
+       unsigned long i;
+       unsigned long off;
+
+       rdsdebug("setting congestion for %pI4:%u in map %p\n",
+         &map->m_addr, ntohs(port), map);
+
+       i = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS;
+       off = be16_to_cpu(port) % RDS_CONG_MAP_PAGE_BITS;
+
+       generic___set_le_bit(off, (void *)map->m_page_addrs[i]);
+}
+
+void rds_cong_clear_bit(struct rds_cong_map *map, __be16 port)
+{
+       unsigned long i;
+       unsigned long off;
+
+       rdsdebug("clearing congestion for %pI4:%u in map %p\n",
+         &map->m_addr, ntohs(port), map);
+
+       i = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS;
+       off = be16_to_cpu(port) % RDS_CONG_MAP_PAGE_BITS;
+
+       generic___clear_le_bit(off, (void *)map->m_page_addrs[i]);
+}
+
+static int rds_cong_test_bit(struct rds_cong_map *map, __be16 port)
+{
+       unsigned long i;
+       unsigned long off;
+
+       i = be16_to_cpu(port) / RDS_CONG_MAP_PAGE_BITS;
+       off = be16_to_cpu(port) % RDS_CONG_MAP_PAGE_BITS;
+
+       return generic_test_le_bit(off, (void *)map->m_page_addrs[i]);
+}
+
+void rds_cong_add_socket(struct rds_sock *rs)
+{
+       unsigned long flags;
+
+       write_lock_irqsave(&rds_cong_monitor_lock, flags);
+       if (list_empty(&rs->rs_cong_list))
+               list_add(&rs->rs_cong_list, &rds_cong_monitor);
+       write_unlock_irqrestore(&rds_cong_monitor_lock, flags);
+}
+
+void rds_cong_remove_socket(struct rds_sock *rs)
+{
+       unsigned long flags;
+       struct rds_cong_map *map;
+
+       write_lock_irqsave(&rds_cong_monitor_lock, flags);
+       list_del_init(&rs->rs_cong_list);
+       write_unlock_irqrestore(&rds_cong_monitor_lock, flags);
+
+       /* update congestion map for now-closed port */
+       spin_lock_irqsave(&rds_cong_lock, flags);
+       map = rds_cong_tree_walk(rs->rs_bound_addr, NULL);
+       spin_unlock_irqrestore(&rds_cong_lock, flags);
+
+       if (map && rds_cong_test_bit(map, rs->rs_bound_port)) {
+               rds_cong_clear_bit(map, rs->rs_bound_port);
+               rds_cong_queue_updates(map);
+       }
+}
+
+int rds_cong_wait(struct rds_cong_map *map, __be16 port, int nonblock,
+                 struct rds_sock *rs)
+{
+       if (!rds_cong_test_bit(map, port))
+               return 0;
+       if (nonblock) {
+               if (rs && rs->rs_cong_monitor) {
+                       unsigned long flags;
+
+                       /* It would have been nice to have an atomic set_bit on
+                        * a uint64_t. */
+                       spin_lock_irqsave(&rs->rs_lock, flags);
+                       rs->rs_cong_mask |= RDS_CONG_MONITOR_MASK(ntohs(port));
+                       spin_unlock_irqrestore(&rs->rs_lock, flags);
+
+                       /* Test again - a congestion update may have arrived in
+                        * the meantime. */
+                       if (!rds_cong_test_bit(map, port))
+                               return 0;
+               }
+               rds_stats_inc(s_cong_send_error);
+               return -ENOBUFS;
+       }
+
+       rds_stats_inc(s_cong_send_blocked);
+       rdsdebug("waiting on map %p for port %u\n", map, be16_to_cpu(port));
+
+       return wait_event_interruptible(map->m_waitq,
+                                       !rds_cong_test_bit(map, port));
+}
+
+void rds_cong_exit(void)
+{
+       struct rb_node *node;
+       struct rds_cong_map *map;
+       unsigned long i;
+
+       while ((node = rb_first(&rds_cong_tree))) {
+               map = rb_entry(node, struct rds_cong_map, m_rb_node);
+               rdsdebug("freeing map %p\n", map);
+               rb_erase(&map->m_rb_node, &rds_cong_tree);
+               for (i = 0; i < RDS_CONG_MAP_PAGES && map->m_page_addrs[i]; i++)
+                       free_page(map->m_page_addrs[i]);
+               kfree(map);
+       }
+}
+
+/*
+ * Allocate a RDS message containing a congestion update.
+ */
+struct rds_message *rds_cong_update_alloc(struct rds_connection *conn)
+{
+       struct rds_cong_map *map = conn->c_lcong;
+       struct rds_message *rm;
+
+       rm = rds_message_map_pages(map->m_page_addrs, RDS_CONG_MAP_BYTES);
+       if (!IS_ERR(rm))
+               rm->m_inc.i_hdr.h_flags = RDS_FLAG_CONG_BITMAP;
+
+       return rm;
+}
diff --git a/net/rds/connection.c b/net/rds/connection.c
new file mode 100644 (file)
index 0000000..273f064
--- /dev/null
@@ -0,0 +1,487 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/list.h>
+#include <net/inet_hashtables.h>
+
+#include "rds.h"
+#include "loop.h"
+#include "rdma.h"
+
+#define RDS_CONNECTION_HASH_BITS 12
+#define RDS_CONNECTION_HASH_ENTRIES (1 << RDS_CONNECTION_HASH_BITS)
+#define RDS_CONNECTION_HASH_MASK (RDS_CONNECTION_HASH_ENTRIES - 1)
+
+/* converting this to RCU is a chore for another day.. */
+static DEFINE_SPINLOCK(rds_conn_lock);
+static unsigned long rds_conn_count;
+static struct hlist_head rds_conn_hash[RDS_CONNECTION_HASH_ENTRIES];
+static struct kmem_cache *rds_conn_slab;
+
+static struct hlist_head *rds_conn_bucket(__be32 laddr, __be32 faddr)
+{
+       /* Pass NULL, don't need struct net for hash */
+       unsigned long hash = inet_ehashfn(NULL,
+                                         be32_to_cpu(laddr), 0,
+                                         be32_to_cpu(faddr), 0);
+       return &rds_conn_hash[hash & RDS_CONNECTION_HASH_MASK];
+}
+
+#define rds_conn_info_set(var, test, suffix) do {              \
+       if (test)                                               \
+               var |= RDS_INFO_CONNECTION_FLAG_##suffix;       \
+} while (0)
+
+static inline int rds_conn_is_sending(struct rds_connection *conn)
+{
+       int ret = 0;
+
+       if (!mutex_trylock(&conn->c_send_lock))
+               ret = 1;
+       else
+               mutex_unlock(&conn->c_send_lock);
+
+       return ret;
+}
+
+static struct rds_connection *rds_conn_lookup(struct hlist_head *head,
+                                             __be32 laddr, __be32 faddr,
+                                             struct rds_transport *trans)
+{
+       struct rds_connection *conn, *ret = NULL;
+       struct hlist_node *pos;
+
+       hlist_for_each_entry(conn, pos, head, c_hash_node) {
+               if (conn->c_faddr == faddr && conn->c_laddr == laddr &&
+                               conn->c_trans == trans) {
+                       ret = conn;
+                       break;
+               }
+       }
+       rdsdebug("returning conn %p for %pI4 -> %pI4\n", ret,
+                &laddr, &faddr);
+       return ret;
+}
+
+/*
+ * This is called by transports as they're bringing down a connection.
+ * It clears partial message state so that the transport can start sending
+ * and receiving over this connection again in the future.  It is up to
+ * the transport to have serialized this call with its send and recv.
+ */
+void rds_conn_reset(struct rds_connection *conn)
+{
+       rdsdebug("connection %pI4 to %pI4 reset\n",
+         &conn->c_laddr, &conn->c_faddr);
+
+       rds_stats_inc(s_conn_reset);
+       rds_send_reset(conn);
+       conn->c_flags = 0;
+
+       /* Do not clear next_rx_seq here, else we cannot distinguish
+        * retransmitted packets from new packets, and will hand all
+        * of them to the application. That is not consistent with the
+        * reliability guarantees of RDS. */
+}
+
+/*
+ * There is only every one 'conn' for a given pair of addresses in the
+ * system at a time.  They contain messages to be retransmitted and so
+ * span the lifetime of the actual underlying transport connections.
+ *
+ * For now they are not garbage collected once they're created.  They
+ * are torn down as the module is removed, if ever.
+ */
+static struct rds_connection *__rds_conn_create(__be32 laddr, __be32 faddr,
+                                      struct rds_transport *trans, gfp_t gfp,
+                                      int is_outgoing)
+{
+       struct rds_connection *conn, *tmp, *parent = NULL;
+       struct hlist_head *head = rds_conn_bucket(laddr, faddr);
+       unsigned long flags;
+       int ret;
+
+       spin_lock_irqsave(&rds_conn_lock, flags);
+       conn = rds_conn_lookup(head, laddr, faddr, trans);
+       if (conn
+        && conn->c_loopback
+        && conn->c_trans != &rds_loop_transport
+        && !is_outgoing) {
+               /* This is a looped back IB connection, and we're
+                * called by the code handling the incoming connect.
+                * We need a second connection object into which we
+                * can stick the other QP. */
+               parent = conn;
+               conn = parent->c_passive;
+       }
+       spin_unlock_irqrestore(&rds_conn_lock, flags);
+       if (conn)
+               goto out;
+
+       conn = kmem_cache_alloc(rds_conn_slab, gfp);
+       if (conn == NULL) {
+               conn = ERR_PTR(-ENOMEM);
+               goto out;
+       }
+
+       memset(conn, 0, sizeof(*conn));
+
+       INIT_HLIST_NODE(&conn->c_hash_node);
+       conn->c_version = RDS_PROTOCOL_3_0;
+       conn->c_laddr = laddr;
+       conn->c_faddr = faddr;
+       spin_lock_init(&conn->c_lock);
+       conn->c_next_tx_seq = 1;
+
+       mutex_init(&conn->c_send_lock);
+       INIT_LIST_HEAD(&conn->c_send_queue);
+       INIT_LIST_HEAD(&conn->c_retrans);
+
+       ret = rds_cong_get_maps(conn);
+       if (ret) {
+               kmem_cache_free(rds_conn_slab, conn);
+               conn = ERR_PTR(ret);
+               goto out;
+       }
+
+       /*
+        * This is where a connection becomes loopback.  If *any* RDS sockets
+        * can bind to the destination address then we'd rather the messages
+        * flow through loopback rather than either transport.
+        */
+       if (rds_trans_get_preferred(faddr)) {
+               conn->c_loopback = 1;
+               if (is_outgoing && trans->t_prefer_loopback) {
+                       /* "outgoing" connection - and the transport
+                        * says it wants the connection handled by the
+                        * loopback transport. This is what TCP does.
+                        */
+                       trans = &rds_loop_transport;
+               }
+       }
+
+       conn->c_trans = trans;
+
+       ret = trans->conn_alloc(conn, gfp);
+       if (ret) {
+               kmem_cache_free(rds_conn_slab, conn);
+               conn = ERR_PTR(ret);
+               goto out;
+       }
+
+       atomic_set(&conn->c_state, RDS_CONN_DOWN);
+       conn->c_reconnect_jiffies = 0;
+       INIT_DELAYED_WORK(&conn->c_send_w, rds_send_worker);
+       INIT_DELAYED_WORK(&conn->c_recv_w, rds_recv_worker);
+       INIT_DELAYED_WORK(&conn->c_conn_w, rds_connect_worker);
+       INIT_WORK(&conn->c_down_w, rds_shutdown_worker);
+       mutex_init(&conn->c_cm_lock);
+       conn->c_flags = 0;
+
+       rdsdebug("allocated conn %p for %pI4 -> %pI4 over %s %s\n",
+         conn, &laddr, &faddr,
+         trans->t_name ? trans->t_name : "[unknown]",
+         is_outgoing ? "(outgoing)" : "");
+
+       spin_lock_irqsave(&rds_conn_lock, flags);
+       if (parent == NULL) {
+               tmp = rds_conn_lookup(head, laddr, faddr, trans);
+               if (tmp == NULL)
+                       hlist_add_head(&conn->c_hash_node, head);
+       } else {
+               tmp = parent->c_passive;
+               if (!tmp)
+                       parent->c_passive = conn;
+       }
+
+       if (tmp) {
+               trans->conn_free(conn->c_transport_data);
+               kmem_cache_free(rds_conn_slab, conn);
+               conn = tmp;
+       } else {
+               rds_cong_add_conn(conn);
+               rds_conn_count++;
+       }
+
+       spin_unlock_irqrestore(&rds_conn_lock, flags);
+
+out:
+       return conn;
+}
+
+struct rds_connection *rds_conn_create(__be32 laddr, __be32 faddr,
+                                      struct rds_transport *trans, gfp_t gfp)
+{
+       return __rds_conn_create(laddr, faddr, trans, gfp, 0);
+}
+
+struct rds_connection *rds_conn_create_outgoing(__be32 laddr, __be32 faddr,
+                                      struct rds_transport *trans, gfp_t gfp)
+{
+       return __rds_conn_create(laddr, faddr, trans, gfp, 1);
+}
+
+void rds_conn_destroy(struct rds_connection *conn)
+{
+       struct rds_message *rm, *rtmp;
+
+       rdsdebug("freeing conn %p for %pI4 -> "
+                "%pI4\n", conn, &conn->c_laddr,
+                &conn->c_faddr);
+
+       hlist_del_init(&conn->c_hash_node);
+
+       /* wait for the rds thread to shut it down */
+       atomic_set(&conn->c_state, RDS_CONN_ERROR);
+       cancel_delayed_work(&conn->c_conn_w);
+       queue_work(rds_wq, &conn->c_down_w);
+       flush_workqueue(rds_wq);
+
+       /* tear down queued messages */
+       list_for_each_entry_safe(rm, rtmp,
+                                &conn->c_send_queue,
+                                m_conn_item) {
+               list_del_init(&rm->m_conn_item);
+               BUG_ON(!list_empty(&rm->m_sock_item));
+               rds_message_put(rm);
+       }
+       if (conn->c_xmit_rm)
+               rds_message_put(conn->c_xmit_rm);
+
+       conn->c_trans->conn_free(conn->c_transport_data);
+
+       /*
+        * The congestion maps aren't freed up here.  They're
+        * freed by rds_cong_exit() after all the connections
+        * have been freed.
+        */
+       rds_cong_remove_conn(conn);
+
+       BUG_ON(!list_empty(&conn->c_retrans));
+       kmem_cache_free(rds_conn_slab, conn);
+
+       rds_conn_count--;
+}
+
+static void rds_conn_message_info(struct socket *sock, unsigned int len,
+                                 struct rds_info_iterator *iter,
+                                 struct rds_info_lengths *lens,
+                                 int want_send)
+{
+       struct hlist_head *head;
+       struct hlist_node *pos;
+       struct list_head *list;
+       struct rds_connection *conn;
+       struct rds_message *rm;
+       unsigned long flags;
+       unsigned int total = 0;
+       size_t i;
+
+       len /= sizeof(struct rds_info_message);
+
+       spin_lock_irqsave(&rds_conn_lock, flags);
+
+       for (i = 0, head = rds_conn_hash; i < ARRAY_SIZE(rds_conn_hash);
+            i++, head++) {
+               hlist_for_each_entry(conn, pos, head, c_hash_node) {
+                       if (want_send)
+                               list = &conn->c_send_queue;
+                       else
+                               list = &conn->c_retrans;
+
+                       spin_lock(&conn->c_lock);
+
+                       /* XXX too lazy to maintain counts.. */
+                       list_for_each_entry(rm, list, m_conn_item) {
+                               total++;
+                               if (total <= len)
+                                       rds_inc_info_copy(&rm->m_inc, iter,
+                                                         conn->c_laddr,
+                                                         conn->c_faddr, 0);
+                       }
+
+                       spin_unlock(&conn->c_lock);
+               }
+       }
+
+       spin_unlock_irqrestore(&rds_conn_lock, flags);
+
+       lens->nr = total;
+       lens->each = sizeof(struct rds_info_message);
+}
+
+static void rds_conn_message_info_send(struct socket *sock, unsigned int len,
+                                      struct rds_info_iterator *iter,
+                                      struct rds_info_lengths *lens)
+{
+       rds_conn_message_info(sock, len, iter, lens, 1);
+}
+
+static void rds_conn_message_info_retrans(struct socket *sock,
+                                         unsigned int len,
+                                         struct rds_info_iterator *iter,
+                                         struct rds_info_lengths *lens)
+{
+       rds_conn_message_info(sock, len, iter, lens, 0);
+}
+
+void rds_for_each_conn_info(struct socket *sock, unsigned int len,
+                         struct rds_info_iterator *iter,
+                         struct rds_info_lengths *lens,
+                         int (*visitor)(struct rds_connection *, void *),
+                         size_t item_len)
+{
+       uint64_t buffer[(item_len + 7) / 8];
+       struct hlist_head *head;
+       struct hlist_node *pos;
+       struct hlist_node *tmp;
+       struct rds_connection *conn;
+       unsigned long flags;
+       size_t i;
+
+       spin_lock_irqsave(&rds_conn_lock, flags);
+
+       lens->nr = 0;
+       lens->each = item_len;
+
+       for (i = 0, head = rds_conn_hash; i < ARRAY_SIZE(rds_conn_hash);
+            i++, head++) {
+               hlist_for_each_entry_safe(conn, pos, tmp, head, c_hash_node) {
+
+                       /* XXX no c_lock usage.. */
+                       if (!visitor(conn, buffer))
+                               continue;
+
+                       /* We copy as much as we can fit in the buffer,
+                        * but we count all items so that the caller
+                        * can resize the buffer. */
+                       if (len >= item_len) {
+                               rds_info_copy(iter, buffer, item_len);
+                               len -= item_len;
+                       }
+                       lens->nr++;
+               }
+       }
+
+       spin_unlock_irqrestore(&rds_conn_lock, flags);
+}
+
+static int rds_conn_info_visitor(struct rds_connection *conn,
+                                 void *buffer)
+{
+       struct rds_info_connection *cinfo = buffer;
+
+       cinfo->next_tx_seq = conn->c_next_tx_seq;
+       cinfo->next_rx_seq = conn->c_next_rx_seq;
+       cinfo->laddr = conn->c_laddr;
+       cinfo->faddr = conn->c_faddr;
+       strncpy(cinfo->transport, conn->c_trans->t_name,
+               sizeof(cinfo->transport));
+       cinfo->flags = 0;
+
+       rds_conn_info_set(cinfo->flags,
+                         rds_conn_is_sending(conn), SENDING);
+       /* XXX Future: return the state rather than these funky bits */
+       rds_conn_info_set(cinfo->flags,
+                         atomic_read(&conn->c_state) == RDS_CONN_CONNECTING,
+                         CONNECTING);
+       rds_conn_info_set(cinfo->flags,
+                         atomic_read(&conn->c_state) == RDS_CONN_UP,
+                         CONNECTED);
+       return 1;
+}
+
+static void rds_conn_info(struct socket *sock, unsigned int len,
+                         struct rds_info_iterator *iter,
+                         struct rds_info_lengths *lens)
+{
+       rds_for_each_conn_info(sock, len, iter, lens,
+                               rds_conn_info_visitor,
+                               sizeof(struct rds_info_connection));
+}
+
+int __init rds_conn_init(void)
+{
+       rds_conn_slab = kmem_cache_create("rds_connection",
+                                         sizeof(struct rds_connection),
+                                         0, 0, NULL);
+       if (rds_conn_slab == NULL)
+               return -ENOMEM;
+
+       rds_info_register_func(RDS_INFO_CONNECTIONS, rds_conn_info);
+       rds_info_register_func(RDS_INFO_SEND_MESSAGES,
+                              rds_conn_message_info_send);
+       rds_info_register_func(RDS_INFO_RETRANS_MESSAGES,
+                              rds_conn_message_info_retrans);
+
+       return 0;
+}
+
+void rds_conn_exit(void)
+{
+       rds_loop_exit();
+
+       WARN_ON(!hlist_empty(rds_conn_hash));
+
+       kmem_cache_destroy(rds_conn_slab);
+
+       rds_info_deregister_func(RDS_INFO_CONNECTIONS, rds_conn_info);
+       rds_info_deregister_func(RDS_INFO_SEND_MESSAGES,
+                                rds_conn_message_info_send);
+       rds_info_deregister_func(RDS_INFO_RETRANS_MESSAGES,
+                                rds_conn_message_info_retrans);
+}
+
+/*
+ * Force a disconnect
+ */
+void rds_conn_drop(struct rds_connection *conn)
+{
+       atomic_set(&conn->c_state, RDS_CONN_ERROR);
+       queue_work(rds_wq, &conn->c_down_w);
+}
+
+/*
+ * An error occurred on the connection
+ */
+void
+__rds_conn_error(struct rds_connection *conn, const char *fmt, ...)
+{
+       va_list ap;
+
+       va_start(ap, fmt);
+       vprintk(fmt, ap);
+       va_end(ap);
+
+       rds_conn_drop(conn);
+}
diff --git a/net/rds/ib.c b/net/rds/ib.c
new file mode 100644 (file)
index 0000000..06a7b79
--- /dev/null
@@ -0,0 +1,323 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/in.h>
+#include <linux/if.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/if_arp.h>
+#include <linux/delay.h>
+
+#include "rds.h"
+#include "ib.h"
+
+unsigned int fmr_pool_size = RDS_FMR_POOL_SIZE;
+unsigned int fmr_message_size = RDS_FMR_SIZE + 1; /* +1 allows for unaligned MRs */
+
+module_param(fmr_pool_size, int, 0444);
+MODULE_PARM_DESC(fmr_pool_size, " Max number of fmr per HCA");
+module_param(fmr_message_size, int, 0444);
+MODULE_PARM_DESC(fmr_message_size, " Max size of a RDMA transfer");
+
+struct list_head rds_ib_devices;
+
+DEFINE_SPINLOCK(ib_nodev_conns_lock);
+LIST_HEAD(ib_nodev_conns);
+
+void rds_ib_add_one(struct ib_device *device)
+{
+       struct rds_ib_device *rds_ibdev;
+       struct ib_device_attr *dev_attr;
+
+       /* Only handle IB (no iWARP) devices */
+       if (device->node_type != RDMA_NODE_IB_CA)
+               return;
+
+       dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL);
+       if (!dev_attr)
+               return;
+
+       if (ib_query_device(device, dev_attr)) {
+               rdsdebug("Query device failed for %s\n", device->name);
+               goto free_attr;
+       }
+
+       rds_ibdev = kmalloc(sizeof *rds_ibdev, GFP_KERNEL);
+       if (!rds_ibdev)
+               goto free_attr;
+
+       spin_lock_init(&rds_ibdev->spinlock);
+
+       rds_ibdev->max_wrs = dev_attr->max_qp_wr;
+       rds_ibdev->max_sge = min(dev_attr->max_sge, RDS_IB_MAX_SGE);
+
+       rds_ibdev->fmr_page_shift = max(9, ffs(dev_attr->page_size_cap) - 1);
+       rds_ibdev->fmr_page_size  = 1 << rds_ibdev->fmr_page_shift;
+       rds_ibdev->fmr_page_mask  = ~((u64) rds_ibdev->fmr_page_size - 1);
+       rds_ibdev->fmr_max_remaps = dev_attr->max_map_per_fmr?: 32;
+       rds_ibdev->max_fmrs = dev_attr->max_fmr ?
+                       min_t(unsigned int, dev_attr->max_fmr, fmr_pool_size) :
+                       fmr_pool_size;
+
+       rds_ibdev->dev = device;
+       rds_ibdev->pd = ib_alloc_pd(device);
+       if (IS_ERR(rds_ibdev->pd))
+               goto free_dev;
+
+       rds_ibdev->mr = ib_get_dma_mr(rds_ibdev->pd,
+                                     IB_ACCESS_LOCAL_WRITE);
+       if (IS_ERR(rds_ibdev->mr))
+               goto err_pd;
+
+       rds_ibdev->mr_pool = rds_ib_create_mr_pool(rds_ibdev);
+       if (IS_ERR(rds_ibdev->mr_pool)) {
+               rds_ibdev->mr_pool = NULL;
+               goto err_mr;
+       }
+
+       INIT_LIST_HEAD(&rds_ibdev->ipaddr_list);
+       INIT_LIST_HEAD(&rds_ibdev->conn_list);
+       list_add_tail(&rds_ibdev->list, &rds_ib_devices);
+
+       ib_set_client_data(device, &rds_ib_client, rds_ibdev);
+
+       goto free_attr;
+
+err_mr:
+       ib_dereg_mr(rds_ibdev->mr);
+err_pd:
+       ib_dealloc_pd(rds_ibdev->pd);
+free_dev:
+       kfree(rds_ibdev);
+free_attr:
+       kfree(dev_attr);
+}
+
+void rds_ib_remove_one(struct ib_device *device)
+{
+       struct rds_ib_device *rds_ibdev;
+       struct rds_ib_ipaddr *i_ipaddr, *i_next;
+
+       rds_ibdev = ib_get_client_data(device, &rds_ib_client);
+       if (!rds_ibdev)
+               return;
+
+       list_for_each_entry_safe(i_ipaddr, i_next, &rds_ibdev->ipaddr_list, list) {
+               list_del(&i_ipaddr->list);
+               kfree(i_ipaddr);
+       }
+
+       rds_ib_remove_conns(rds_ibdev);
+
+       if (rds_ibdev->mr_pool)
+               rds_ib_destroy_mr_pool(rds_ibdev->mr_pool);
+
+       ib_dereg_mr(rds_ibdev->mr);
+
+       while (ib_dealloc_pd(rds_ibdev->pd)) {
+               rdsdebug("Failed to dealloc pd %p\n", rds_ibdev->pd);
+               msleep(1);
+       }
+
+       list_del(&rds_ibdev->list);
+       kfree(rds_ibdev);
+}
+
+struct ib_client rds_ib_client = {
+       .name   = "rds_ib",
+       .add    = rds_ib_add_one,
+       .remove = rds_ib_remove_one
+};
+
+static int rds_ib_conn_info_visitor(struct rds_connection *conn,
+                                   void *buffer)
+{
+       struct rds_info_rdma_connection *iinfo = buffer;
+       struct rds_ib_connection *ic;
+
+       /* We will only ever look at IB transports */
+       if (conn->c_trans != &rds_ib_transport)
+               return 0;
+
+       iinfo->src_addr = conn->c_laddr;
+       iinfo->dst_addr = conn->c_faddr;
+
+       memset(&iinfo->src_gid, 0, sizeof(iinfo->src_gid));
+       memset(&iinfo->dst_gid, 0, sizeof(iinfo->dst_gid));
+       if (rds_conn_state(conn) == RDS_CONN_UP) {
+               struct rds_ib_device *rds_ibdev;
+               struct rdma_dev_addr *dev_addr;
+
+               ic = conn->c_transport_data;
+               dev_addr = &ic->i_cm_id->route.addr.dev_addr;
+
+               ib_addr_get_sgid(dev_addr, (union ib_gid *) &iinfo->src_gid);
+               ib_addr_get_dgid(dev_addr, (union ib_gid *) &iinfo->dst_gid);
+
+               rds_ibdev = ib_get_client_data(ic->i_cm_id->device, &rds_ib_client);
+               iinfo->max_send_wr = ic->i_send_ring.w_nr;
+               iinfo->max_recv_wr = ic->i_recv_ring.w_nr;
+               iinfo->max_send_sge = rds_ibdev->max_sge;
+               rds_ib_get_mr_info(rds_ibdev, iinfo);
+       }
+       return 1;
+}
+
+static void rds_ib_ic_info(struct socket *sock, unsigned int len,
+                          struct rds_info_iterator *iter,
+                          struct rds_info_lengths *lens)
+{
+       rds_for_each_conn_info(sock, len, iter, lens,
+                               rds_ib_conn_info_visitor,
+                               sizeof(struct rds_info_rdma_connection));
+}
+
+
+/*
+ * Early RDS/IB was built to only bind to an address if there is an IPoIB
+ * device with that address set.
+ *
+ * If it were me, I'd advocate for something more flexible.  Sending and
+ * receiving should be device-agnostic.  Transports would try and maintain
+ * connections between peers who have messages queued.  Userspace would be
+ * allowed to influence which paths have priority.  We could call userspace
+ * asserting this policy "routing".
+ */
+static int rds_ib_laddr_check(__be32 addr)
+{
+       int ret;
+       struct rdma_cm_id *cm_id;
+       struct sockaddr_in sin;
+
+       /* Create a CMA ID and try to bind it. This catches both
+        * IB and iWARP capable NICs.
+        */
+       cm_id = rdma_create_id(NULL, NULL, RDMA_PS_TCP);
+       if (!cm_id)
+               return -EADDRNOTAVAIL;
+
+       memset(&sin, 0, sizeof(sin));
+       sin.sin_family = AF_INET;
+       sin.sin_addr.s_addr = addr;
+
+       /* rdma_bind_addr will only succeed for IB & iWARP devices */
+       ret = rdma_bind_addr(cm_id, (struct sockaddr *)&sin);
+       /* due to this, we will claim to support iWARP devices unless we
+          check node_type. */
+       if (ret || cm_id->device->node_type != RDMA_NODE_IB_CA)
+               ret = -EADDRNOTAVAIL;
+
+       rdsdebug("addr %pI4 ret %d node type %d\n",
+               &addr, ret,
+               cm_id->device ? cm_id->device->node_type : -1);
+
+       rdma_destroy_id(cm_id);
+
+       return ret;
+}
+
+void rds_ib_exit(void)
+{
+       rds_info_deregister_func(RDS_INFO_IB_CONNECTIONS, rds_ib_ic_info);
+       rds_ib_remove_nodev_conns();
+       ib_unregister_client(&rds_ib_client);
+       rds_ib_sysctl_exit();
+       rds_ib_recv_exit();
+       rds_trans_unregister(&rds_ib_transport);
+}
+
+struct rds_transport rds_ib_transport = {
+       .laddr_check            = rds_ib_laddr_check,
+       .xmit_complete          = rds_ib_xmit_complete,
+       .xmit                   = rds_ib_xmit,
+       .xmit_cong_map          = NULL,
+       .xmit_rdma              = rds_ib_xmit_rdma,
+       .recv                   = rds_ib_recv,
+       .conn_alloc             = rds_ib_conn_alloc,
+       .conn_free              = rds_ib_conn_free,
+       .conn_connect           = rds_ib_conn_connect,
+       .conn_shutdown          = rds_ib_conn_shutdown,
+       .inc_copy_to_user       = rds_ib_inc_copy_to_user,
+       .inc_purge              = rds_ib_inc_purge,
+       .inc_free               = rds_ib_inc_free,
+       .cm_initiate_connect    = rds_ib_cm_initiate_connect,
+       .cm_handle_connect      = rds_ib_cm_handle_connect,
+       .cm_connect_complete    = rds_ib_cm_connect_complete,
+       .stats_info_copy        = rds_ib_stats_info_copy,
+       .exit                   = rds_ib_exit,
+       .get_mr                 = rds_ib_get_mr,
+       .sync_mr                = rds_ib_sync_mr,
+       .free_mr                = rds_ib_free_mr,
+       .flush_mrs              = rds_ib_flush_mrs,
+       .t_owner                = THIS_MODULE,
+       .t_name                 = "infiniband",
+};
+
+int __init rds_ib_init(void)
+{
+       int ret;
+
+       INIT_LIST_HEAD(&rds_ib_devices);
+
+       ret = ib_register_client(&rds_ib_client);
+       if (ret)
+               goto out;
+
+       ret = rds_ib_sysctl_init();
+       if (ret)
+               goto out_ibreg;
+
+       ret = rds_ib_recv_init();
+       if (ret)
+               goto out_sysctl;
+
+       ret = rds_trans_register(&rds_ib_transport);
+       if (ret)
+               goto out_recv;
+
+       rds_info_register_func(RDS_INFO_IB_CONNECTIONS, rds_ib_ic_info);
+
+       goto out;
+
+out_recv:
+       rds_ib_recv_exit();
+out_sysctl:
+       rds_ib_sysctl_exit();
+out_ibreg:
+       ib_unregister_client(&rds_ib_client);
+out:
+       return ret;
+}
+
+MODULE_LICENSE("GPL");
+
diff --git a/net/rds/ib.h b/net/rds/ib.h
new file mode 100644 (file)
index 0000000..8be563a
--- /dev/null
@@ -0,0 +1,367 @@
+#ifndef _RDS_IB_H
+#define _RDS_IB_H
+
+#include <rdma/ib_verbs.h>
+#include <rdma/rdma_cm.h>
+#include "rds.h"
+#include "rdma_transport.h"
+
+#define RDS_FMR_SIZE                   256
+#define RDS_FMR_POOL_SIZE              4096
+
+#define RDS_IB_MAX_SGE                 8
+#define RDS_IB_RECV_SGE                2
+
+#define RDS_IB_DEFAULT_RECV_WR         1024
+#define RDS_IB_DEFAULT_SEND_WR         256
+
+#define RDS_IB_SUPPORTED_PROTOCOLS     0x00000003      /* minor versions supported */
+
+extern struct list_head rds_ib_devices;
+
+/*
+ * IB posts RDS_FRAG_SIZE fragments of pages to the receive queues to
+ * try and minimize the amount of memory tied up both the device and
+ * socket receive queues.
+ */
+/* page offset of the final full frag that fits in the page */
+#define RDS_PAGE_LAST_OFF (((PAGE_SIZE  / RDS_FRAG_SIZE) - 1) * RDS_FRAG_SIZE)
+struct rds_page_frag {
+       struct list_head        f_item;
+       struct page             *f_page;
+       unsigned long           f_offset;
+       dma_addr_t              f_mapped;
+};
+
+struct rds_ib_incoming {
+       struct list_head        ii_frags;
+       struct rds_incoming     ii_inc;
+};
+
+struct rds_ib_connect_private {
+       /* Add new fields at the end, and don't permute existing fields. */
+       __be32                  dp_saddr;
+       __be32                  dp_daddr;
+       u8                      dp_protocol_major;
+       u8                      dp_protocol_minor;
+       __be16                  dp_protocol_minor_mask; /* bitmask */
+       __be32                  dp_reserved1;
+       __be64                  dp_ack_seq;
+       __be32                  dp_credit;              /* non-zero enables flow ctl */
+};
+
+struct rds_ib_send_work {
+       struct rds_message      *s_rm;
+       struct rds_rdma_op      *s_op;
+       struct ib_send_wr       s_wr;
+       struct ib_sge           s_sge[RDS_IB_MAX_SGE];
+       unsigned long           s_queued;
+};
+
+struct rds_ib_recv_work {
+       struct rds_ib_incoming  *r_ibinc;
+       struct rds_page_frag    *r_frag;
+       struct ib_recv_wr       r_wr;
+       struct ib_sge           r_sge[2];
+};
+
+struct rds_ib_work_ring {
+       u32             w_nr;
+       u32             w_alloc_ptr;
+       u32             w_alloc_ctr;
+       u32             w_free_ptr;
+       atomic_t        w_free_ctr;
+};
+
+struct rds_ib_device;
+
+struct rds_ib_connection {
+
+       struct list_head        ib_node;
+       struct rds_ib_device    *rds_ibdev;
+       struct rds_connection   *conn;
+
+       /* alphabet soup, IBTA style */
+       struct rdma_cm_id       *i_cm_id;
+       struct ib_pd            *i_pd;
+       struct ib_mr            *i_mr;
+       struct ib_cq            *i_send_cq;
+       struct ib_cq            *i_recv_cq;
+
+       /* tx */
+       struct rds_ib_work_ring i_send_ring;
+       struct rds_message      *i_rm;
+       struct rds_header       *i_send_hdrs;
+       u64                     i_send_hdrs_dma;
+       struct rds_ib_send_work *i_sends;
+
+       /* rx */
+       struct mutex            i_recv_mutex;
+       struct rds_ib_work_ring i_recv_ring;
+       struct rds_ib_incoming  *i_ibinc;
+       u32                     i_recv_data_rem;
+       struct rds_header       *i_recv_hdrs;
+       u64                     i_recv_hdrs_dma;
+       struct rds_ib_recv_work *i_recvs;
+       struct rds_page_frag    i_frag;
+       u64                     i_ack_recv;     /* last ACK received */
+
+       /* sending acks */
+       unsigned long           i_ack_flags;
+       u64                     i_ack_next;     /* next ACK to send */
+       struct rds_header       *i_ack;
+       struct ib_send_wr       i_ack_wr;
+       struct ib_sge           i_ack_sge;
+       u64                     i_ack_dma;
+       unsigned long           i_ack_queued;
+
+       /* Flow control related information
+        *
+        * Our algorithm uses a pair variables that we need to access
+        * atomically - one for the send credits, and one posted
+        * recv credits we need to transfer to remote.
+        * Rather than protect them using a slow spinlock, we put both into
+        * a single atomic_t and update it using cmpxchg
+        */
+       atomic_t                i_credits;
+
+       /* Protocol version specific information */
+       unsigned int            i_flowctl:1;    /* enable/disable flow ctl */
+
+       /* Batched completions */
+       unsigned int            i_unsignaled_wrs;
+       long                    i_unsignaled_bytes;
+};
+
+/* This assumes that atomic_t is at least 32 bits */
+#define IB_GET_SEND_CREDITS(v) ((v) & 0xffff)
+#define IB_GET_POST_CREDITS(v) ((v) >> 16)
+#define IB_SET_SEND_CREDITS(v) ((v) & 0xffff)
+#define IB_SET_POST_CREDITS(v) ((v) << 16)
+
+struct rds_ib_ipaddr {
+       struct list_head        list;
+       __be32                  ipaddr;
+};
+
+struct rds_ib_device {
+       struct list_head        list;
+       struct list_head        ipaddr_list;
+       struct list_head        conn_list;
+       struct ib_device        *dev;
+       struct ib_pd            *pd;
+       struct ib_mr            *mr;
+       struct rds_ib_mr_pool   *mr_pool;
+       int                     fmr_page_shift;
+       int                     fmr_page_size;
+       u64                     fmr_page_mask;
+       unsigned int            fmr_max_remaps;
+       unsigned int            max_fmrs;
+       int                     max_sge;
+       unsigned int            max_wrs;
+       spinlock_t              spinlock;       /* protect the above */
+};
+
+/* bits for i_ack_flags */
+#define IB_ACK_IN_FLIGHT       0
+#define IB_ACK_REQUESTED       1
+
+/* Magic WR_ID for ACKs */
+#define RDS_IB_ACK_WR_ID       (~(u64) 0)
+
+struct rds_ib_statistics {
+       uint64_t        s_ib_connect_raced;
+       uint64_t        s_ib_listen_closed_stale;
+       uint64_t        s_ib_tx_cq_call;
+       uint64_t        s_ib_tx_cq_event;
+       uint64_t        s_ib_tx_ring_full;
+       uint64_t        s_ib_tx_throttle;
+       uint64_t        s_ib_tx_sg_mapping_failure;
+       uint64_t        s_ib_tx_stalled;
+       uint64_t        s_ib_tx_credit_updates;
+       uint64_t        s_ib_rx_cq_call;
+       uint64_t        s_ib_rx_cq_event;
+       uint64_t        s_ib_rx_ring_empty;
+       uint64_t        s_ib_rx_refill_from_cq;
+       uint64_t        s_ib_rx_refill_from_thread;
+       uint64_t        s_ib_rx_alloc_limit;
+       uint64_t        s_ib_rx_credit_updates;
+       uint64_t        s_ib_ack_sent;
+       uint64_t        s_ib_ack_send_failure;
+       uint64_t        s_ib_ack_send_delayed;
+       uint64_t        s_ib_ack_send_piggybacked;
+       uint64_t        s_ib_ack_received;
+       uint64_t        s_ib_rdma_mr_alloc;
+       uint64_t        s_ib_rdma_mr_free;
+       uint64_t        s_ib_rdma_mr_used;
+       uint64_t        s_ib_rdma_mr_pool_flush;
+       uint64_t        s_ib_rdma_mr_pool_wait;
+       uint64_t        s_ib_rdma_mr_pool_depleted;
+};
+
+extern struct workqueue_struct *rds_ib_wq;
+
+/*
+ * Fake ib_dma_sync_sg_for_{cpu,device} as long as ib_verbs.h
+ * doesn't define it.
+ */
+static inline void rds_ib_dma_sync_sg_for_cpu(struct ib_device *dev,
+               struct scatterlist *sg, unsigned int sg_dma_len, int direction)
+{
+       unsigned int i;
+
+       for (i = 0; i < sg_dma_len; ++i) {
+               ib_dma_sync_single_for_cpu(dev,
+                               ib_sg_dma_address(dev, &sg[i]),
+                               ib_sg_dma_len(dev, &sg[i]),
+                               direction);
+       }
+}
+#define ib_dma_sync_sg_for_cpu rds_ib_dma_sync_sg_for_cpu
+
+static inline void rds_ib_dma_sync_sg_for_device(struct ib_device *dev,
+               struct scatterlist *sg, unsigned int sg_dma_len, int direction)
+{
+       unsigned int i;
+
+       for (i = 0; i < sg_dma_len; ++i) {
+               ib_dma_sync_single_for_device(dev,
+                               ib_sg_dma_address(dev, &sg[i]),
+                               ib_sg_dma_len(dev, &sg[i]),
+                               direction);
+       }
+}
+#define ib_dma_sync_sg_for_device      rds_ib_dma_sync_sg_for_device
+
+
+/* ib.c */
+extern struct rds_transport rds_ib_transport;
+extern void rds_ib_add_one(struct ib_device *device);
+extern void rds_ib_remove_one(struct ib_device *device);
+extern struct ib_client rds_ib_client;
+
+extern unsigned int fmr_pool_size;
+extern unsigned int fmr_message_size;
+
+extern spinlock_t ib_nodev_conns_lock;
+extern struct list_head ib_nodev_conns;
+
+/* ib_cm.c */
+int rds_ib_conn_alloc(struct rds_connection *conn, gfp_t gfp);
+void rds_ib_conn_free(void *arg);
+int rds_ib_conn_connect(struct rds_connection *conn);
+void rds_ib_conn_shutdown(struct rds_connection *conn);
+void rds_ib_state_change(struct sock *sk);
+int __init rds_ib_listen_init(void);
+void rds_ib_listen_stop(void);
+void __rds_ib_conn_error(struct rds_connection *conn, const char *, ...);
+int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
+                            struct rdma_cm_event *event);
+int rds_ib_cm_initiate_connect(struct rdma_cm_id *cm_id);
+void rds_ib_cm_connect_complete(struct rds_connection *conn,
+                               struct rdma_cm_event *event);
+
+
+#define rds_ib_conn_error(conn, fmt...) \
+       __rds_ib_conn_error(conn, KERN_WARNING "RDS/IB: " fmt)
+
+/* ib_rdma.c */
+int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr);
+int rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn);
+void rds_ib_remove_nodev_conns(void);
+void rds_ib_remove_conns(struct rds_ib_device *rds_ibdev);
+struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *);
+void rds_ib_get_mr_info(struct rds_ib_device *rds_ibdev, struct rds_info_rdma_connection *iinfo);
+void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *);
+void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
+                   struct rds_sock *rs, u32 *key_ret);
+void rds_ib_sync_mr(void *trans_private, int dir);
+void rds_ib_free_mr(void *trans_private, int invalidate);
+void rds_ib_flush_mrs(void);
+
+/* ib_recv.c */
+int __init rds_ib_recv_init(void);
+void rds_ib_recv_exit(void);
+int rds_ib_recv(struct rds_connection *conn);
+int rds_ib_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
+                      gfp_t page_gfp, int prefill);
+void rds_ib_inc_purge(struct rds_incoming *inc);
+void rds_ib_inc_free(struct rds_incoming *inc);
+int rds_ib_inc_copy_to_user(struct rds_incoming *inc, struct iovec *iov,
+                            size_t size);
+void rds_ib_recv_cq_comp_handler(struct ib_cq *cq, void *context);
+void rds_ib_recv_init_ring(struct rds_ib_connection *ic);
+void rds_ib_recv_clear_ring(struct rds_ib_connection *ic);
+void rds_ib_recv_init_ack(struct rds_ib_connection *ic);
+void rds_ib_attempt_ack(struct rds_ib_connection *ic);
+void rds_ib_ack_send_complete(struct rds_ib_connection *ic);
+u64 rds_ib_piggyb_ack(struct rds_ib_connection *ic);
+
+/* ib_ring.c */
+void rds_ib_ring_init(struct rds_ib_work_ring *ring, u32 nr);
+void rds_ib_ring_resize(struct rds_ib_work_ring *ring, u32 nr);
+u32 rds_ib_ring_alloc(struct rds_ib_work_ring *ring, u32 val, u32 *pos);
+void rds_ib_ring_free(struct rds_ib_work_ring *ring, u32 val);
+void rds_ib_ring_unalloc(struct rds_ib_work_ring *ring, u32 val);
+int rds_ib_ring_empty(struct rds_ib_work_ring *ring);
+int rds_ib_ring_low(struct rds_ib_work_ring *ring);
+u32 rds_ib_ring_oldest(struct rds_ib_work_ring *ring);
+u32 rds_ib_ring_completed(struct rds_ib_work_ring *ring, u32 wr_id, u32 oldest);
+extern wait_queue_head_t rds_ib_ring_empty_wait;
+
+/* ib_send.c */
+void rds_ib_xmit_complete(struct rds_connection *conn);
+int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
+               unsigned int hdr_off, unsigned int sg, unsigned int off);
+void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context);
+void rds_ib_send_init_ring(struct rds_ib_connection *ic);
+void rds_ib_send_clear_ring(struct rds_ib_connection *ic);
+int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op);
+void rds_ib_send_add_credits(struct rds_connection *conn, unsigned int credits);
+void rds_ib_advertise_credits(struct rds_connection *conn, unsigned int posted);
+int rds_ib_send_grab_credits(struct rds_ib_connection *ic, u32 wanted,
+                            u32 *adv_credits, int need_posted);
+
+/* ib_stats.c */
+DECLARE_PER_CPU(struct rds_ib_statistics, rds_ib_stats);
+#define rds_ib_stats_inc(member) rds_stats_inc_which(rds_ib_stats, member)
+unsigned int rds_ib_stats_info_copy(struct rds_info_iterator *iter,
+                                   unsigned int avail);
+
+/* ib_sysctl.c */
+int __init rds_ib_sysctl_init(void);
+void rds_ib_sysctl_exit(void);
+extern unsigned long rds_ib_sysctl_max_send_wr;
+extern unsigned long rds_ib_sysctl_max_recv_wr;
+extern unsigned long rds_ib_sysctl_max_unsig_wrs;
+extern unsigned long rds_ib_sysctl_max_unsig_bytes;
+extern unsigned long rds_ib_sysctl_max_recv_allocation;
+extern unsigned int rds_ib_sysctl_flow_control;
+extern ctl_table rds_ib_sysctl_table[];
+
+/*
+ * Helper functions for getting/setting the header and data SGEs in
+ * RDS packets (not RDMA)
+ */
+static inline struct ib_sge *
+rds_ib_header_sge(struct rds_ib_connection *ic, struct ib_sge *sge)
+{
+       return &sge[0];
+}
+
+static inline struct ib_sge *
+rds_ib_data_sge(struct rds_ib_connection *ic, struct ib_sge *sge)
+{
+       return &sge[1];
+}
+
+static inline void rds_ib_set_64bit(u64 *ptr, u64 val)
+{
+#if BITS_PER_LONG == 64
+       *ptr = val;
+#else
+       set_64bit(ptr, val);
+#endif
+}
+
+#endif
diff --git a/net/rds/ib_cm.c b/net/rds/ib_cm.c
new file mode 100644 (file)
index 0000000..0532237
--- /dev/null
@@ -0,0 +1,726 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/in.h>
+#include <linux/vmalloc.h>
+
+#include "rds.h"
+#include "ib.h"
+
+/*
+ * Set the selected protocol version
+ */
+static void rds_ib_set_protocol(struct rds_connection *conn, unsigned int version)
+{
+       conn->c_version = version;
+}
+
+/*
+ * Set up flow control
+ */
+static void rds_ib_set_flow_control(struct rds_connection *conn, u32 credits)
+{
+       struct rds_ib_connection *ic = conn->c_transport_data;
+
+       if (rds_ib_sysctl_flow_control && credits != 0) {
+               /* We're doing flow control */
+               ic->i_flowctl = 1;
+               rds_ib_send_add_credits(conn, credits);
+       } else {
+               ic->i_flowctl = 0;
+       }
+}
+
+/*
+ * Tune RNR behavior. Without flow control, we use a rather
+ * low timeout, but not the absolute minimum - this should
+ * be tunable.
+ *
+ * We already set the RNR retry count to 7 (which is the
+ * smallest infinite number :-) above.
+ * If flow control is off, we want to change this back to 0
+ * so that we learn quickly when our credit accounting is
+ * buggy.
+ *
+ * Caller passes in a qp_attr pointer - don't waste stack spacv
+ * by allocation this twice.
+ */
+static void
+rds_ib_tune_rnr(struct rds_ib_connection *ic, struct ib_qp_attr *attr)
+{
+       int ret;
+
+       attr->min_rnr_timer = IB_RNR_TIMER_000_32;
+       ret = ib_modify_qp(ic->i_cm_id->qp, attr, IB_QP_MIN_RNR_TIMER);
+       if (ret)
+               printk(KERN_NOTICE "ib_modify_qp(IB_QP_MIN_RNR_TIMER): err=%d\n", -ret);
+}
+
+/*
+ * Connection established.
+ * We get here for both outgoing and incoming connection.
+ */
+void rds_ib_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_event *event)
+{
+       const struct rds_ib_connect_private *dp = NULL;
+       struct rds_ib_connection *ic = conn->c_transport_data;
+       struct rds_ib_device *rds_ibdev;
+       struct ib_qp_attr qp_attr;
+       int err;
+
+       if (event->param.conn.private_data_len) {
+               dp = event->param.conn.private_data;
+
+               rds_ib_set_protocol(conn,
+                               RDS_PROTOCOL(dp->dp_protocol_major,
+                                       dp->dp_protocol_minor));
+               rds_ib_set_flow_control(conn, be32_to_cpu(dp->dp_credit));
+       }
+
+       printk(KERN_NOTICE "RDS/IB: connected to %pI4 version %u.%u%s\n",
+                       &conn->c_laddr,
+                       RDS_PROTOCOL_MAJOR(conn->c_version),
+                       RDS_PROTOCOL_MINOR(conn->c_version),
+                       ic->i_flowctl ? ", flow control" : "");
+
+       /* Tune RNR behavior */
+       rds_ib_tune_rnr(ic, &qp_attr);
+
+       qp_attr.qp_state = IB_QPS_RTS;
+       err = ib_modify_qp(ic->i_cm_id->qp, &qp_attr, IB_QP_STATE);
+       if (err)
+               printk(KERN_NOTICE "ib_modify_qp(IB_QP_STATE, RTS): err=%d\n", err);
+
+       /* update ib_device with this local ipaddr & conn */
+       rds_ibdev = ib_get_client_data(ic->i_cm_id->device, &rds_ib_client);
+       err = rds_ib_update_ipaddr(rds_ibdev, conn->c_laddr);
+       if (err)
+               printk(KERN_ERR "rds_ib_update_ipaddr failed (%d)\n", err);
+       err = rds_ib_add_conn(rds_ibdev, conn);
+       if (err)
+               printk(KERN_ERR "rds_ib_add_conn failed (%d)\n", err);
+
+       /* If the peer gave us the last packet it saw, process this as if
+        * we had received a regular ACK. */
+       if (dp && dp->dp_ack_seq)
+               rds_send_drop_acked(conn, be64_to_cpu(dp->dp_ack_seq), NULL);
+
+       rds_connect_complete(conn);
+}
+
+static void rds_ib_cm_fill_conn_param(struct rds_connection *conn,
+                       struct rdma_conn_param *conn_param,
+                       struct rds_ib_connect_private *dp,
+                       u32 protocol_version)
+{
+       memset(conn_param, 0, sizeof(struct rdma_conn_param));
+       /* XXX tune these? */
+       conn_param->responder_resources = 1;
+       conn_param->initiator_depth = 1;
+       conn_param->retry_count = 7;
+       conn_param->rnr_retry_count = 7;
+
+       if (dp) {
+               struct rds_ib_connection *ic = conn->c_transport_data;
+
+               memset(dp, 0, sizeof(*dp));
+               dp->dp_saddr = conn->c_laddr;
+               dp->dp_daddr = conn->c_faddr;
+               dp->dp_protocol_major = RDS_PROTOCOL_MAJOR(protocol_version);
+               dp->dp_protocol_minor = RDS_PROTOCOL_MINOR(protocol_version);
+               dp->dp_protocol_minor_mask = cpu_to_be16(RDS_IB_SUPPORTED_PROTOCOLS);
+               dp->dp_ack_seq = rds_ib_piggyb_ack(ic);
+
+               /* Advertise flow control */
+               if (ic->i_flowctl) {
+                       unsigned int credits;
+
+                       credits = IB_GET_POST_CREDITS(atomic_read(&ic->i_credits));
+                       dp->dp_credit = cpu_to_be32(credits);
+                       atomic_sub(IB_SET_POST_CREDITS(credits), &ic->i_credits);
+               }
+
+               conn_param->private_data = dp;
+               conn_param->private_data_len = sizeof(*dp);
+       }
+}
+
+static void rds_ib_cq_event_handler(struct ib_event *event, void *data)
+{
+       rdsdebug("event %u data %p\n", event->event, data);
+}
+
+static void rds_ib_qp_event_handler(struct ib_event *event, void *data)
+{
+       struct rds_connection *conn = data;
+       struct rds_ib_connection *ic = conn->c_transport_data;
+
+       rdsdebug("conn %p ic %p event %u\n", conn, ic, event->event);
+
+       switch (event->event) {
+       case IB_EVENT_COMM_EST:
+               rdma_notify(ic->i_cm_id, IB_EVENT_COMM_EST);
+               break;
+       default:
+               printk(KERN_WARNING "RDS/ib: unhandled QP event %u "
+                      "on connection to %pI4\n", event->event,
+                      &conn->c_faddr);
+               break;
+       }
+}
+
+/*
+ * This needs to be very careful to not leave IS_ERR pointers around for
+ * cleanup to trip over.
+ */
+static int rds_ib_setup_qp(struct rds_connection *conn)
+{
+       struct rds_ib_connection *ic = conn->c_transport_data;
+       struct ib_device *dev = ic->i_cm_id->device;
+       struct ib_qp_init_attr attr;
+       struct rds_ib_device *rds_ibdev;
+       int ret;
+
+       /* rds_ib_add_one creates a rds_ib_device object per IB device,
+        * and allocates a protection domain, memory range and FMR pool
+        * for each.  If that fails for any reason, it will not register
+        * the rds_ibdev at all.
+        */
+       rds_ibdev = ib_get_client_data(dev, &rds_ib_client);
+       if (rds_ibdev == NULL) {
+               if (printk_ratelimit())
+                       printk(KERN_NOTICE "RDS/IB: No client_data for device %s\n",
+                                       dev->name);
+               return -EOPNOTSUPP;
+       }
+
+       if (rds_ibdev->max_wrs < ic->i_send_ring.w_nr + 1)
+               rds_ib_ring_resize(&ic->i_send_ring, rds_ibdev->max_wrs - 1);
+       if (rds_ibdev->max_wrs < ic->i_recv_ring.w_nr + 1)
+               rds_ib_ring_resize(&ic->i_recv_ring, rds_ibdev->max_wrs - 1);
+
+       /* Protection domain and memory range */
+       ic->i_pd = rds_ibdev->pd;
+       ic->i_mr = rds_ibdev->mr;
+
+       ic->i_send_cq = ib_create_cq(dev, rds_ib_send_cq_comp_handler,
+                                    rds_ib_cq_event_handler, conn,
+                                    ic->i_send_ring.w_nr + 1, 0);
+       if (IS_ERR(ic->i_send_cq)) {
+               ret = PTR_ERR(ic->i_send_cq);
+               ic->i_send_cq = NULL;
+               rdsdebug("ib_create_cq send failed: %d\n", ret);
+               goto out;
+       }
+
+       ic->i_recv_cq = ib_create_cq(dev, rds_ib_recv_cq_comp_handler,
+                                    rds_ib_cq_event_handler, conn,
+                                    ic->i_recv_ring.w_nr, 0);
+       if (IS_ERR(ic->i_recv_cq)) {
+               ret = PTR_ERR(ic->i_recv_cq);
+               ic->i_recv_cq = NULL;
+               rdsdebug("ib_create_cq recv failed: %d\n", ret);
+               goto out;
+       }
+
+       ret = ib_req_notify_cq(ic->i_send_cq, IB_CQ_NEXT_COMP);
+       if (ret) {
+               rdsdebug("ib_req_notify_cq send failed: %d\n", ret);
+               goto out;
+       }
+
+       ret = ib_req_notify_cq(ic->i_recv_cq, IB_CQ_SOLICITED);
+       if (ret) {
+               rdsdebug("ib_req_notify_cq recv failed: %d\n", ret);
+               goto out;
+       }
+
+       /* XXX negotiate max send/recv with remote? */
+       memset(&attr, 0, sizeof(attr));
+       attr.event_handler = rds_ib_qp_event_handler;
+       attr.qp_context = conn;
+       /* + 1 to allow for the single ack message */
+       attr.cap.max_send_wr = ic->i_send_ring.w_nr + 1;
+       attr.cap.max_recv_wr = ic->i_recv_ring.w_nr + 1;
+       attr.cap.max_send_sge = rds_ibdev->max_sge;
+       attr.cap.max_recv_sge = RDS_IB_RECV_SGE;
+       attr.sq_sig_type = IB_SIGNAL_REQ_WR;
+       attr.qp_type = IB_QPT_RC;
+       attr.send_cq = ic->i_send_cq;
+       attr.recv_cq = ic->i_recv_cq;
+
+       /*
+        * XXX this can fail if max_*_wr is too large?  Are we supposed
+        * to back off until we get a value that the hardware can support?
+        */
+       ret = rdma_create_qp(ic->i_cm_id, ic->i_pd, &attr);
+       if (ret) {
+               rdsdebug("rdma_create_qp failed: %d\n", ret);
+               goto out;
+       }
+
+       ic->i_send_hdrs = ib_dma_alloc_coherent(dev,
+                                          ic->i_send_ring.w_nr *
+                                               sizeof(struct rds_header),
+                                          &ic->i_send_hdrs_dma, GFP_KERNEL);
+       if (ic->i_send_hdrs == NULL) {
+               ret = -ENOMEM;
+               rdsdebug("ib_dma_alloc_coherent send failed\n");
+               goto out;
+       }
+
+       ic->i_recv_hdrs = ib_dma_alloc_coherent(dev,
+                                          ic->i_recv_ring.w_nr *
+                                               sizeof(struct rds_header),
+                                          &ic->i_recv_hdrs_dma, GFP_KERNEL);
+       if (ic->i_recv_hdrs == NULL) {
+               ret = -ENOMEM;
+               rdsdebug("ib_dma_alloc_coherent recv failed\n");
+               goto out;
+       }
+
+       ic->i_ack = ib_dma_alloc_coherent(dev, sizeof(struct rds_header),
+                                      &ic->i_ack_dma, GFP_KERNEL);
+       if (ic->i_ack == NULL) {
+               ret = -ENOMEM;
+               rdsdebug("ib_dma_alloc_coherent ack failed\n");
+               goto out;
+       }
+
+       ic->i_sends = vmalloc(ic->i_send_ring.w_nr * sizeof(struct rds_ib_send_work));
+       if (ic->i_sends == NULL) {
+               ret = -ENOMEM;
+               rdsdebug("send allocation failed\n");
+               goto out;
+       }
+       rds_ib_send_init_ring(ic);
+
+       ic->i_recvs = vmalloc(ic->i_recv_ring.w_nr * sizeof(struct rds_ib_recv_work));
+       if (ic->i_recvs == NULL) {
+               ret = -ENOMEM;
+               rdsdebug("recv allocation failed\n");
+               goto out;
+       }
+
+       rds_ib_recv_init_ring(ic);
+       rds_ib_recv_init_ack(ic);
+
+       /* Post receive buffers - as a side effect, this will update
+        * the posted credit count. */
+       rds_ib_recv_refill(conn, GFP_KERNEL, GFP_HIGHUSER, 1);
+
+       rdsdebug("conn %p pd %p mr %p cq %p %p\n", conn, ic->i_pd, ic->i_mr,
+                ic->i_send_cq, ic->i_recv_cq);
+
+out:
+       return ret;
+}
+
+static u32 rds_ib_protocol_compatible(const struct rds_ib_connect_private *dp)
+{
+       u16 common;
+       u32 version = 0;
+
+       /* rdma_cm private data is odd - when there is any private data in the
+        * request, we will be given a pretty large buffer without telling us the
+        * original size. The only way to tell the difference is by looking at
+        * the contents, which are initialized to zero.
+        * If the protocol version fields aren't set, this is a connection attempt
+        * from an older version. This could could be 3.0 or 2.0 - we can't tell.
+        * We really should have changed this for OFED 1.3 :-( */
+       if (dp->dp_protocol_major == 0)
+               return RDS_PROTOCOL_3_0;
+
+       common = be16_to_cpu(dp->dp_protocol_minor_mask) & RDS_IB_SUPPORTED_PROTOCOLS;
+       if (dp->dp_protocol_major == 3 && common) {
+               version = RDS_PROTOCOL_3_0;
+               while ((common >>= 1) != 0)
+                       version++;
+       } else if (printk_ratelimit()) {
+               printk(KERN_NOTICE "RDS: Connection from %pI4 using "
+                       "incompatible protocol version %u.%u\n",
+                       &dp->dp_saddr,
+                       dp->dp_protocol_major,
+                       dp->dp_protocol_minor);
+       }
+       return version;
+}
+
+int rds_ib_cm_handle_connect(struct rdma_cm_id *cm_id,
+                                   struct rdma_cm_event *event)
+{
+       __be64 lguid = cm_id->route.path_rec->sgid.global.interface_id;
+       __be64 fguid = cm_id->route.path_rec->dgid.global.interface_id;
+       const struct rds_ib_connect_private *dp = event->param.conn.private_data;
+       struct rds_ib_connect_private dp_rep;
+       struct rds_connection *conn = NULL;
+       struct rds_ib_connection *ic = NULL;
+       struct rdma_conn_param conn_param;
+       u32 version;
+       int err, destroy = 1;
+
+       /* Check whether the remote protocol version matches ours. */
+       version = rds_ib_protocol_compatible(dp);
+       if (!version)
+               goto out;
+
+       rdsdebug("saddr %pI4 daddr %pI4 RDSv%u.%u lguid 0x%llx fguid "
+                "0x%llx\n", &dp->dp_saddr, &dp->dp_daddr,
+                RDS_PROTOCOL_MAJOR(version), RDS_PROTOCOL_MINOR(version),
+                (unsigned long long)be64_to_cpu(lguid),
+                (unsigned long long)be64_to_cpu(fguid));
+
+       conn = rds_conn_create(dp->dp_daddr, dp->dp_saddr, &rds_ib_transport,
+                              GFP_KERNEL);
+       if (IS_ERR(conn)) {
+               rdsdebug("rds_conn_create failed (%ld)\n", PTR_ERR(conn));
+               conn = NULL;
+               goto out;
+       }
+
+       /*
+        * The connection request may occur while the
+        * previous connection exist, e.g. in case of failover.
+        * But as connections may be initiated simultaneously
+        * by both hosts, we have a random backoff mechanism -
+        * see the comment above rds_queue_reconnect()
+        */
+       mutex_lock(&conn->c_cm_lock);
+       if (!rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_CONNECTING)) {
+               if (rds_conn_state(conn) == RDS_CONN_UP) {
+                       rdsdebug("incoming connect while connecting\n");
+                       rds_conn_drop(conn);
+                       rds_ib_stats_inc(s_ib_listen_closed_stale);
+               } else
+               if (rds_conn_state(conn) == RDS_CONN_CONNECTING) {
+                       /* Wait and see - our connect may still be succeeding */
+                       rds_ib_stats_inc(s_ib_connect_raced);
+               }
+               mutex_unlock(&conn->c_cm_lock);
+               goto out;
+       }
+
+       ic = conn->c_transport_data;
+
+       rds_ib_set_protocol(conn, version);
+       rds_ib_set_flow_control(conn, be32_to_cpu(dp->dp_credit));
+
+       /* If the peer gave us the last packet it saw, process this as if
+        * we had received a regular ACK. */
+       if (dp->dp_ack_seq)
+               rds_send_drop_acked(conn, be64_to_cpu(dp->dp_ack_seq), NULL);
+
+       BUG_ON(cm_id->context);
+       BUG_ON(ic->i_cm_id);
+
+       ic->i_cm_id = cm_id;
+       cm_id->context = conn;
+
+       /* We got halfway through setting up the ib_connection, if we
+        * fail now, we have to take the long route out of this mess. */
+       destroy = 0;
+
+       err = rds_ib_setup_qp(conn);
+       if (err) {
+               rds_ib_conn_error(conn, "rds_ib_setup_qp failed (%d)\n", err);
+               goto out;
+       }
+
+       rds_ib_cm_fill_conn_param(conn, &conn_param, &dp_rep, version);
+
+       /* rdma_accept() calls rdma_reject() internally if it fails */
+       err = rdma_accept(cm_id, &conn_param);
+       mutex_unlock(&conn->c_cm_lock);
+       if (err) {
+               rds_ib_conn_error(conn, "rdma_accept failed (%d)\n", err);
+               goto out;
+       }
+
+       return 0;
+
+out:
+       rdma_reject(cm_id, NULL, 0);
+       return destroy;
+}
+
+
+int rds_ib_cm_initiate_connect(struct rdma_cm_id *cm_id)
+{
+       struct rds_connection *conn = cm_id->context;
+       struct rds_ib_connection *ic = conn->c_transport_data;
+       struct rdma_conn_param conn_param;
+       struct rds_ib_connect_private dp;
+       int ret;
+
+       /* If the peer doesn't do protocol negotiation, we must
+        * default to RDSv3.0 */
+       rds_ib_set_protocol(conn, RDS_PROTOCOL_3_0);
+       ic->i_flowctl = rds_ib_sysctl_flow_control;     /* advertise flow control */
+
+       ret = rds_ib_setup_qp(conn);
+       if (ret) {
+               rds_ib_conn_error(conn, "rds_ib_setup_qp failed (%d)\n", ret);
+               goto out;
+       }
+
+       rds_ib_cm_fill_conn_param(conn, &conn_param, &dp, RDS_PROTOCOL_VERSION);
+
+       ret = rdma_connect(cm_id, &conn_param);
+       if (ret)
+               rds_ib_conn_error(conn, "rdma_connect failed (%d)\n", ret);
+
+out:
+       /* Beware - returning non-zero tells the rdma_cm to destroy
+        * the cm_id. We should certainly not do it as long as we still
+        * "own" the cm_id. */
+       if (ret) {
+               if (ic->i_cm_id == cm_id)
+                       ret = 0;
+       }
+       return ret;
+}
+
+int rds_ib_conn_connect(struct rds_connection *conn)
+{
+       struct rds_ib_connection *ic = conn->c_transport_data;
+       struct sockaddr_in src, dest;
+       int ret;
+
+       /* XXX I wonder what affect the port space has */
+       /* delegate cm event handler to rdma_transport */
+       ic->i_cm_id = rdma_create_id(rds_rdma_cm_event_handler, conn,
+                                    RDMA_PS_TCP);
+       if (IS_ERR(ic->i_cm_id)) {
+               ret = PTR_ERR(ic->i_cm_id);
+               ic->i_cm_id = NULL;
+               rdsdebug("rdma_create_id() failed: %d\n", ret);
+               goto out;
+       }
+
+       rdsdebug("created cm id %p for conn %p\n", ic->i_cm_id, conn);
+
+       src.sin_family = AF_INET;
+       src.sin_addr.s_addr = (__force u32)conn->c_laddr;
+       src.sin_port = (__force u16)htons(0);
+
+       dest.sin_family = AF_INET;
+       dest.sin_addr.s_addr = (__force u32)conn->c_faddr;
+       dest.sin_port = (__force u16)htons(RDS_PORT);
+
+       ret = rdma_resolve_addr(ic->i_cm_id, (struct sockaddr *)&src,
+                               (struct sockaddr *)&dest,
+                               RDS_RDMA_RESOLVE_TIMEOUT_MS);
+       if (ret) {
+               rdsdebug("addr resolve failed for cm id %p: %d\n", ic->i_cm_id,
+                        ret);
+               rdma_destroy_id(ic->i_cm_id);
+               ic->i_cm_id = NULL;
+       }
+
+out:
+       return ret;
+}
+
+/*
+ * This is so careful about only cleaning up resources that were built up
+ * so that it can be called at any point during startup.  In fact it
+ * can be called multiple times for a given connection.
+ */
+void rds_ib_conn_shutdown(struct rds_connection *conn)
+{
+       struct rds_ib_connection *ic = conn->c_transport_data;
+       int err = 0;
+
+       rdsdebug("cm %p pd %p cq %p %p qp %p\n", ic->i_cm_id,
+                ic->i_pd, ic->i_send_cq, ic->i_recv_cq,
+                ic->i_cm_id ? ic->i_cm_id->qp : NULL);
+
+       if (ic->i_cm_id) {
+               struct ib_device *dev = ic->i_cm_id->device;
+
+               rdsdebug("disconnecting cm %p\n", ic->i_cm_id);
+               err = rdma_disconnect(ic->i_cm_id);
+               if (err) {
+                       /* Actually this may happen quite frequently, when
+                        * an outgoing connect raced with an incoming connect.
+                        */
+                       rdsdebug("failed to disconnect, cm: %p err %d\n",
+                               ic->i_cm_id, err);
+               }
+
+               wait_event(rds_ib_ring_empty_wait,
+                       rds_ib_ring_empty(&ic->i_send_ring) &&
+                       rds_ib_ring_empty(&ic->i_recv_ring));
+
+               if (ic->i_send_hdrs)
+                       ib_dma_free_coherent(dev,
+                                          ic->i_send_ring.w_nr *
+                                               sizeof(struct rds_header),
+                                          ic->i_send_hdrs,
+                                          ic->i_send_hdrs_dma);
+
+               if (ic->i_recv_hdrs)
+                       ib_dma_free_coherent(dev,
+                                          ic->i_recv_ring.w_nr *
+                                               sizeof(struct rds_header),
+                                          ic->i_recv_hdrs,
+                                          ic->i_recv_hdrs_dma);
+
+               if (ic->i_ack)
+                       ib_dma_free_coherent(dev, sizeof(struct rds_header),
+                                            ic->i_ack, ic->i_ack_dma);
+
+               if (ic->i_sends)
+                       rds_ib_send_clear_ring(ic);
+               if (ic->i_recvs)
+                       rds_ib_recv_clear_ring(ic);
+
+               if (ic->i_cm_id->qp)
+                       rdma_destroy_qp(ic->i_cm_id);
+               if (ic->i_send_cq)
+                       ib_destroy_cq(ic->i_send_cq);
+               if (ic->i_recv_cq)
+                       ib_destroy_cq(ic->i_recv_cq);
+               rdma_destroy_id(ic->i_cm_id);
+
+               /*
+                * Move connection back to the nodev list.
+                */
+               if (ic->rds_ibdev) {
+
+                       spin_lock_irq(&ic->rds_ibdev->spinlock);
+                       BUG_ON(list_empty(&ic->ib_node));
+                       list_del(&ic->ib_node);
+                       spin_unlock_irq(&ic->rds_ibdev->spinlock);
+
+                       spin_lock_irq(&ib_nodev_conns_lock);
+                       list_add_tail(&ic->ib_node, &ib_nodev_conns);
+                       spin_unlock_irq(&ib_nodev_conns_lock);
+                       ic->rds_ibdev = NULL;
+               }
+
+               ic->i_cm_id = NULL;
+               ic->i_pd = NULL;
+               ic->i_mr = NULL;
+               ic->i_send_cq = NULL;
+               ic->i_recv_cq = NULL;
+               ic->i_send_hdrs = NULL;
+               ic->i_recv_hdrs = NULL;
+               ic->i_ack = NULL;
+       }
+       BUG_ON(ic->rds_ibdev);
+
+       /* Clear pending transmit */
+       if (ic->i_rm) {
+               rds_message_put(ic->i_rm);
+               ic->i_rm = NULL;
+       }
+
+       /* Clear the ACK state */
+       clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags);
+       rds_ib_set_64bit(&ic->i_ack_next, 0);
+       ic->i_ack_recv = 0;
+
+       /* Clear flow control state */
+       ic->i_flowctl = 0;
+       atomic_set(&ic->i_credits, 0);
+
+       rds_ib_ring_init(&ic->i_send_ring, rds_ib_sysctl_max_send_wr);
+       rds_ib_ring_init(&ic->i_recv_ring, rds_ib_sysctl_max_recv_wr);
+
+       if (ic->i_ibinc) {
+               rds_inc_put(&ic->i_ibinc->ii_inc);
+               ic->i_ibinc = NULL;
+       }
+
+       vfree(ic->i_sends);
+       ic->i_sends = NULL;
+       vfree(ic->i_recvs);
+       ic->i_recvs = NULL;
+}
+
+int rds_ib_conn_alloc(struct rds_connection *conn, gfp_t gfp)
+{
+       struct rds_ib_connection *ic;
+       unsigned long flags;
+
+       /* XXX too lazy? */
+       ic = kzalloc(sizeof(struct rds_ib_connection), GFP_KERNEL);
+       if (ic == NULL)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&ic->ib_node);
+       mutex_init(&ic->i_recv_mutex);
+
+       /*
+        * rds_ib_conn_shutdown() waits for these to be emptied so they
+        * must be initialized before it can be called.
+        */
+       rds_ib_ring_init(&ic->i_send_ring, rds_ib_sysctl_max_send_wr);
+       rds_ib_ring_init(&ic->i_recv_ring, rds_ib_sysctl_max_recv_wr);
+
+       ic->conn = conn;
+       conn->c_transport_data = ic;
+
+       spin_lock_irqsave(&ib_nodev_conns_lock, flags);
+       list_add_tail(&ic->ib_node, &ib_nodev_conns);
+       spin_unlock_irqrestore(&ib_nodev_conns_lock, flags);
+
+
+       rdsdebug("conn %p conn ic %p\n", conn, conn->c_transport_data);
+       return 0;
+}
+
+void rds_ib_conn_free(void *arg)
+{
+       struct rds_ib_connection *ic = arg;
+       rdsdebug("ic %p\n", ic);
+       list_del(&ic->ib_node);
+       kfree(ic);
+}
+
+
+/*
+ * An error occurred on the connection
+ */
+void
+__rds_ib_conn_error(struct rds_connection *conn, const char *fmt, ...)
+{
+       va_list ap;
+
+       rds_conn_drop(conn);
+
+       va_start(ap, fmt);
+       vprintk(fmt, ap);
+       va_end(ap);
+}
diff --git a/net/rds/ib_rdma.c b/net/rds/ib_rdma.c
new file mode 100644 (file)
index 0000000..69a6289
--- /dev/null
@@ -0,0 +1,641 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+
+#include "rds.h"
+#include "rdma.h"
+#include "ib.h"
+
+
+/*
+ * This is stored as mr->r_trans_private.
+ */
+struct rds_ib_mr {
+       struct rds_ib_device    *device;
+       struct rds_ib_mr_pool   *pool;
+       struct ib_fmr           *fmr;
+       struct list_head        list;
+       unsigned int            remap_count;
+
+       struct scatterlist      *sg;
+       unsigned int            sg_len;
+       u64                     *dma;
+       int                     sg_dma_len;
+};
+
+/*
+ * Our own little FMR pool
+ */
+struct rds_ib_mr_pool {
+       struct mutex            flush_lock;             /* serialize fmr invalidate */
+       struct work_struct      flush_worker;           /* flush worker */
+
+       spinlock_t              list_lock;              /* protect variables below */
+       atomic_t                item_count;             /* total # of MRs */
+       atomic_t                dirty_count;            /* # dirty of MRs */
+       struct list_head        drop_list;              /* MRs that have reached their max_maps limit */
+       struct list_head        free_list;              /* unused MRs */
+       struct list_head        clean_list;             /* unused & unamapped MRs */
+       atomic_t                free_pinned;            /* memory pinned by free MRs */
+       unsigned long           max_items;
+       unsigned long           max_items_soft;
+       unsigned long           max_free_pinned;
+       struct ib_fmr_attr      fmr_attr;
+};
+
+static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, int free_all);
+static void rds_ib_teardown_mr(struct rds_ib_mr *ibmr);
+static void rds_ib_mr_pool_flush_worker(struct work_struct *work);
+
+static struct rds_ib_device *rds_ib_get_device(__be32 ipaddr)
+{
+       struct rds_ib_device *rds_ibdev;
+       struct rds_ib_ipaddr *i_ipaddr;
+
+       list_for_each_entry(rds_ibdev, &rds_ib_devices, list) {
+               spin_lock_irq(&rds_ibdev->spinlock);
+               list_for_each_entry(i_ipaddr, &rds_ibdev->ipaddr_list, list) {
+                       if (i_ipaddr->ipaddr == ipaddr) {
+                               spin_unlock_irq(&rds_ibdev->spinlock);
+                               return rds_ibdev;
+                       }
+               }
+               spin_unlock_irq(&rds_ibdev->spinlock);
+       }
+
+       return NULL;
+}
+
+static int rds_ib_add_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
+{
+       struct rds_ib_ipaddr *i_ipaddr;
+
+       i_ipaddr = kmalloc(sizeof *i_ipaddr, GFP_KERNEL);
+       if (!i_ipaddr)
+               return -ENOMEM;
+
+       i_ipaddr->ipaddr = ipaddr;
+
+       spin_lock_irq(&rds_ibdev->spinlock);
+       list_add_tail(&i_ipaddr->list, &rds_ibdev->ipaddr_list);
+       spin_unlock_irq(&rds_ibdev->spinlock);
+
+       return 0;
+}
+
+static void rds_ib_remove_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
+{
+       struct rds_ib_ipaddr *i_ipaddr, *next;
+
+       spin_lock_irq(&rds_ibdev->spinlock);
+       list_for_each_entry_safe(i_ipaddr, next, &rds_ibdev->ipaddr_list, list) {
+               if (i_ipaddr->ipaddr == ipaddr) {
+                       list_del(&i_ipaddr->list);
+                       kfree(i_ipaddr);
+                       break;
+               }
+       }
+       spin_unlock_irq(&rds_ibdev->spinlock);
+}
+
+int rds_ib_update_ipaddr(struct rds_ib_device *rds_ibdev, __be32 ipaddr)
+{
+       struct rds_ib_device *rds_ibdev_old;
+
+       rds_ibdev_old = rds_ib_get_device(ipaddr);
+       if (rds_ibdev_old)
+               rds_ib_remove_ipaddr(rds_ibdev_old, ipaddr);
+
+       return rds_ib_add_ipaddr(rds_ibdev, ipaddr);
+}
+
+int rds_ib_add_conn(struct rds_ib_device *rds_ibdev, struct rds_connection *conn)
+{
+       struct rds_ib_connection *ic = conn->c_transport_data;
+
+       /* conn was previously on the nodev_conns_list */
+       spin_lock_irq(&ib_nodev_conns_lock);
+       BUG_ON(list_empty(&ib_nodev_conns));
+       BUG_ON(list_empty(&ic->ib_node));
+       list_del(&ic->ib_node);
+       spin_unlock_irq(&ib_nodev_conns_lock);
+
+       spin_lock_irq(&rds_ibdev->spinlock);
+       list_add_tail(&ic->ib_node, &rds_ibdev->conn_list);
+       spin_unlock_irq(&rds_ibdev->spinlock);
+
+       ic->rds_ibdev = rds_ibdev;
+
+       return 0;
+}
+
+void rds_ib_remove_nodev_conns(void)
+{
+       struct rds_ib_connection *ic, *_ic;
+       LIST_HEAD(tmp_list);
+
+       /* avoid calling conn_destroy with irqs off */
+       spin_lock_irq(&ib_nodev_conns_lock);
+       list_splice(&ib_nodev_conns, &tmp_list);
+       INIT_LIST_HEAD(&ib_nodev_conns);
+       spin_unlock_irq(&ib_nodev_conns_lock);
+
+       list_for_each_entry_safe(ic, _ic, &tmp_list, ib_node) {
+               if (ic->conn->c_passive)
+                       rds_conn_destroy(ic->conn->c_passive);
+               rds_conn_destroy(ic->conn);
+       }
+}
+
+void rds_ib_remove_conns(struct rds_ib_device *rds_ibdev)
+{
+       struct rds_ib_connection *ic, *_ic;
+       LIST_HEAD(tmp_list);
+
+       /* avoid calling conn_destroy with irqs off */
+       spin_lock_irq(&rds_ibdev->spinlock);
+       list_splice(&rds_ibdev->conn_list, &tmp_list);
+       INIT_LIST_HEAD(&rds_ibdev->conn_list);
+       spin_unlock_irq(&rds_ibdev->spinlock);
+
+       list_for_each_entry_safe(ic, _ic, &tmp_list, ib_node) {
+               if (ic->conn->c_passive)
+                       rds_conn_destroy(ic->conn->c_passive);
+               rds_conn_destroy(ic->conn);
+       }
+}
+
+struct rds_ib_mr_pool *rds_ib_create_mr_pool(struct rds_ib_device *rds_ibdev)
+{
+       struct rds_ib_mr_pool *pool;
+
+       pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+       if (!pool)
+               return ERR_PTR(-ENOMEM);
+
+       INIT_LIST_HEAD(&pool->free_list);
+       INIT_LIST_HEAD(&pool->drop_list);
+       INIT_LIST_HEAD(&pool->clean_list);
+       mutex_init(&pool->flush_lock);
+       spin_lock_init(&pool->list_lock);
+       INIT_WORK(&pool->flush_worker, rds_ib_mr_pool_flush_worker);
+
+       pool->fmr_attr.max_pages = fmr_message_size;
+       pool->fmr_attr.max_maps = rds_ibdev->fmr_max_remaps;
+       pool->fmr_attr.page_shift = rds_ibdev->fmr_page_shift;
+       pool->max_free_pinned = rds_ibdev->max_fmrs * fmr_message_size / 4;
+
+       /* We never allow more than max_items MRs to be allocated.
+        * When we exceed more than max_items_soft, we start freeing
+        * items more aggressively.
+        * Make sure that max_items > max_items_soft > max_items / 2
+        */
+       pool->max_items_soft = rds_ibdev->max_fmrs * 3 / 4;
+       pool->max_items = rds_ibdev->max_fmrs;
+
+       return pool;
+}
+
+void rds_ib_get_mr_info(struct rds_ib_device *rds_ibdev, struct rds_info_rdma_connection *iinfo)
+{
+       struct rds_ib_mr_pool *pool = rds_ibdev->mr_pool;
+
+       iinfo->rdma_mr_max = pool->max_items;
+       iinfo->rdma_mr_size = pool->fmr_attr.max_pages;
+}
+
+void rds_ib_destroy_mr_pool(struct rds_ib_mr_pool *pool)
+{
+       flush_workqueue(rds_wq);
+       rds_ib_flush_mr_pool(pool, 1);
+       BUG_ON(atomic_read(&pool->item_count));
+       BUG_ON(atomic_read(&pool->free_pinned));
+       kfree(pool);
+}
+
+static inline struct rds_ib_mr *rds_ib_reuse_fmr(struct rds_ib_mr_pool *pool)
+{
+       struct rds_ib_mr *ibmr = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pool->list_lock, flags);
+       if (!list_empty(&pool->clean_list)) {
+               ibmr = list_entry(pool->clean_list.next, struct rds_ib_mr, list);
+               list_del_init(&ibmr->list);
+       }
+       spin_unlock_irqrestore(&pool->list_lock, flags);
+
+       return ibmr;
+}
+
+static struct rds_ib_mr *rds_ib_alloc_fmr(struct rds_ib_device *rds_ibdev)
+{
+       struct rds_ib_mr_pool *pool = rds_ibdev->mr_pool;
+       struct rds_ib_mr *ibmr = NULL;
+       int err = 0, iter = 0;
+
+       while (1) {
+               ibmr = rds_ib_reuse_fmr(pool);
+               if (ibmr)
+                       return ibmr;
+
+               /* No clean MRs - now we have the choice of either
+                * allocating a fresh MR up to the limit imposed by the
+                * driver, or flush any dirty unused MRs.
+                * We try to avoid stalling in the send path if possible,
+                * so we allocate as long as we're allowed to.
+                *
+                * We're fussy with enforcing the FMR limit, though. If the driver
+                * tells us we can't use more than N fmrs, we shouldn't start
+                * arguing with it */
+               if (atomic_inc_return(&pool->item_count) <= pool->max_items)
+                       break;
+
+               atomic_dec(&pool->item_count);
+
+               if (++iter > 2) {
+                       rds_ib_stats_inc(s_ib_rdma_mr_pool_depleted);
+                       return ERR_PTR(-EAGAIN);
+               }
+
+               /* We do have some empty MRs. Flush them out. */
+               rds_ib_stats_inc(s_ib_rdma_mr_pool_wait);
+               rds_ib_flush_mr_pool(pool, 0);
+       }
+
+       ibmr = kzalloc(sizeof(*ibmr), GFP_KERNEL);
+       if (!ibmr) {
+               err = -ENOMEM;
+               goto out_no_cigar;
+       }
+
+       ibmr->fmr = ib_alloc_fmr(rds_ibdev->pd,
+                       (IB_ACCESS_LOCAL_WRITE |
+                        IB_ACCESS_REMOTE_READ |
+                        IB_ACCESS_REMOTE_WRITE),
+                       &pool->fmr_attr);
+       if (IS_ERR(ibmr->fmr)) {
+               err = PTR_ERR(ibmr->fmr);
+               ibmr->fmr = NULL;
+               printk(KERN_WARNING "RDS/IB: ib_alloc_fmr failed (err=%d)\n", err);
+               goto out_no_cigar;
+       }
+
+       rds_ib_stats_inc(s_ib_rdma_mr_alloc);
+       return ibmr;
+
+out_no_cigar:
+       if (ibmr) {
+               if (ibmr->fmr)
+                       ib_dealloc_fmr(ibmr->fmr);
+               kfree(ibmr);
+       }
+       atomic_dec(&pool->item_count);
+       return ERR_PTR(err);
+}
+
+static int rds_ib_map_fmr(struct rds_ib_device *rds_ibdev, struct rds_ib_mr *ibmr,
+              struct scatterlist *sg, unsigned int nents)
+{
+       struct ib_device *dev = rds_ibdev->dev;
+       struct scatterlist *scat = sg;
+       u64 io_addr = 0;
+       u64 *dma_pages;
+       u32 len;
+       int page_cnt, sg_dma_len;
+       int i, j;
+       int ret;
+
+       sg_dma_len = ib_dma_map_sg(dev, sg, nents,
+                                DMA_BIDIRECTIONAL);
+       if (unlikely(!sg_dma_len)) {
+               printk(KERN_WARNING "RDS/IB: dma_map_sg failed!\n");
+               return -EBUSY;
+       }
+
+       len = 0;
+       page_cnt = 0;
+
+       for (i = 0; i < sg_dma_len; ++i) {
+               unsigned int dma_len = ib_sg_dma_len(dev, &scat[i]);
+               u64 dma_addr = ib_sg_dma_address(dev, &scat[i]);
+
+               if (dma_addr & ~rds_ibdev->fmr_page_mask) {
+                       if (i > 0)
+                               return -EINVAL;
+                       else
+                               ++page_cnt;
+               }
+               if ((dma_addr + dma_len) & ~rds_ibdev->fmr_page_mask) {
+                       if (i < sg_dma_len - 1)
+                               return -EINVAL;
+                       else
+                               ++page_cnt;
+               }
+
+               len += dma_len;
+       }
+
+       page_cnt += len >> rds_ibdev->fmr_page_shift;
+       if (page_cnt > fmr_message_size)
+               return -EINVAL;
+
+       dma_pages = kmalloc(sizeof(u64) * page_cnt, GFP_ATOMIC);
+       if (!dma_pages)
+               return -ENOMEM;
+
+       page_cnt = 0;
+       for (i = 0; i < sg_dma_len; ++i) {
+               unsigned int dma_len = ib_sg_dma_len(dev, &scat[i]);
+               u64 dma_addr = ib_sg_dma_address(dev, &scat[i]);
+
+               for (j = 0; j < dma_len; j += rds_ibdev->fmr_page_size)
+                       dma_pages[page_cnt++] =
+                               (dma_addr & rds_ibdev->fmr_page_mask) + j;
+       }
+
+       ret = ib_map_phys_fmr(ibmr->fmr,
+                                  dma_pages, page_cnt, io_addr);
+       if (ret)
+               goto out;
+
+       /* Success - we successfully remapped the MR, so we can
+        * safely tear down the old mapping. */
+       rds_ib_teardown_mr(ibmr);
+
+       ibmr->sg = scat;
+       ibmr->sg_len = nents;
+       ibmr->sg_dma_len = sg_dma_len;
+       ibmr->remap_count++;
+
+       rds_ib_stats_inc(s_ib_rdma_mr_used);
+       ret = 0;
+
+out:
+       kfree(dma_pages);
+
+       return ret;
+}
+
+void rds_ib_sync_mr(void *trans_private, int direction)
+{
+       struct rds_ib_mr *ibmr = trans_private;
+       struct rds_ib_device *rds_ibdev = ibmr->device;
+
+       switch (direction) {
+       case DMA_FROM_DEVICE:
+               ib_dma_sync_sg_for_cpu(rds_ibdev->dev, ibmr->sg,
+                       ibmr->sg_dma_len, DMA_BIDIRECTIONAL);
+               break;
+       case DMA_TO_DEVICE:
+               ib_dma_sync_sg_for_device(rds_ibdev->dev, ibmr->sg,
+                       ibmr->sg_dma_len, DMA_BIDIRECTIONAL);
+               break;
+       }
+}
+
+static void __rds_ib_teardown_mr(struct rds_ib_mr *ibmr)
+{
+       struct rds_ib_device *rds_ibdev = ibmr->device;
+
+       if (ibmr->sg_dma_len) {
+               ib_dma_unmap_sg(rds_ibdev->dev,
+                               ibmr->sg, ibmr->sg_len,
+                               DMA_BIDIRECTIONAL);
+               ibmr->sg_dma_len = 0;
+       }
+
+       /* Release the s/g list */
+       if (ibmr->sg_len) {
+               unsigned int i;
+
+               for (i = 0; i < ibmr->sg_len; ++i) {
+                       struct page *page = sg_page(&ibmr->sg[i]);
+
+                       /* FIXME we need a way to tell a r/w MR
+                        * from a r/o MR */
+                       set_page_dirty(page);
+                       put_page(page);
+               }
+               kfree(ibmr->sg);
+
+               ibmr->sg = NULL;
+               ibmr->sg_len = 0;
+       }
+}
+
+static void rds_ib_teardown_mr(struct rds_ib_mr *ibmr)
+{
+       unsigned int pinned = ibmr->sg_len;
+
+       __rds_ib_teardown_mr(ibmr);
+       if (pinned) {
+               struct rds_ib_device *rds_ibdev = ibmr->device;
+               struct rds_ib_mr_pool *pool = rds_ibdev->mr_pool;
+
+               atomic_sub(pinned, &pool->free_pinned);
+       }
+}
+
+static inline unsigned int rds_ib_flush_goal(struct rds_ib_mr_pool *pool, int free_all)
+{
+       unsigned int item_count;
+
+       item_count = atomic_read(&pool->item_count);
+       if (free_all)
+               return item_count;
+
+       return 0;
+}
+
+/*
+ * Flush our pool of MRs.
+ * At a minimum, all currently unused MRs are unmapped.
+ * If the number of MRs allocated exceeds the limit, we also try
+ * to free as many MRs as needed to get back to this limit.
+ */
+static int rds_ib_flush_mr_pool(struct rds_ib_mr_pool *pool, int free_all)
+{
+       struct rds_ib_mr *ibmr, *next;
+       LIST_HEAD(unmap_list);
+       LIST_HEAD(fmr_list);
+       unsigned long unpinned = 0;
+       unsigned long flags;
+       unsigned int nfreed = 0, ncleaned = 0, free_goal;
+       int ret = 0;
+
+       rds_ib_stats_inc(s_ib_rdma_mr_pool_flush);
+
+       mutex_lock(&pool->flush_lock);
+
+       spin_lock_irqsave(&pool->list_lock, flags);
+       /* Get the list of all MRs to be dropped. Ordering matters -
+        * we want to put drop_list ahead of free_list. */
+       list_splice_init(&pool->free_list, &unmap_list);
+       list_splice_init(&pool->drop_list, &unmap_list);
+       if (free_all)
+               list_splice_init(&pool->clean_list, &unmap_list);
+       spin_unlock_irqrestore(&pool->list_lock, flags);
+
+       free_goal = rds_ib_flush_goal(pool, free_all);
+
+       if (list_empty(&unmap_list))
+               goto out;
+
+       /* String all ib_mr's onto one list and hand them to ib_unmap_fmr */
+       list_for_each_entry(ibmr, &unmap_list, list)
+               list_add(&ibmr->fmr->list, &fmr_list);
+       ret = ib_unmap_fmr(&fmr_list);
+       if (ret)
+               printk(KERN_WARNING "RDS/IB: ib_unmap_fmr failed (err=%d)\n", ret);
+
+       /* Now we can destroy the DMA mapping and unpin any pages */
+       list_for_each_entry_safe(ibmr, next, &unmap_list, list) {
+               unpinned += ibmr->sg_len;
+               __rds_ib_teardown_mr(ibmr);
+               if (nfreed < free_goal || ibmr->remap_count >= pool->fmr_attr.max_maps) {
+                       rds_ib_stats_inc(s_ib_rdma_mr_free);
+                       list_del(&ibmr->list);
+                       ib_dealloc_fmr(ibmr->fmr);
+                       kfree(ibmr);
+                       nfreed++;
+               }
+               ncleaned++;
+       }
+
+       spin_lock_irqsave(&pool->list_lock, flags);
+       list_splice(&unmap_list, &pool->clean_list);
+       spin_unlock_irqrestore(&pool->list_lock, flags);
+
+       atomic_sub(unpinned, &pool->free_pinned);
+       atomic_sub(ncleaned, &pool->dirty_count);
+       atomic_sub(nfreed, &pool->item_count);
+
+out:
+       mutex_unlock(&pool->flush_lock);
+       return ret;
+}
+
+static void rds_ib_mr_pool_flush_worker(struct work_struct *work)
+{
+       struct rds_ib_mr_pool *pool = container_of(work, struct rds_ib_mr_pool, flush_worker);
+
+       rds_ib_flush_mr_pool(pool, 0);
+}
+
+void rds_ib_free_mr(void *trans_private, int invalidate)
+{
+       struct rds_ib_mr *ibmr = trans_private;
+       struct rds_ib_device *rds_ibdev = ibmr->device;
+       struct rds_ib_mr_pool *pool = rds_ibdev->mr_pool;
+       unsigned long flags;
+
+       rdsdebug("RDS/IB: free_mr nents %u\n", ibmr->sg_len);
+
+       /* Return it to the pool's free list */
+       spin_lock_irqsave(&pool->list_lock, flags);
+       if (ibmr->remap_count >= pool->fmr_attr.max_maps)
+               list_add(&ibmr->list, &pool->drop_list);
+       else
+               list_add(&ibmr->list, &pool->free_list);
+
+       atomic_add(ibmr->sg_len, &pool->free_pinned);
+       atomic_inc(&pool->dirty_count);
+       spin_unlock_irqrestore(&pool->list_lock, flags);
+
+       /* If we've pinned too many pages, request a flush */
+       if (atomic_read(&pool->free_pinned) >= pool->max_free_pinned
+        || atomic_read(&pool->dirty_count) >= pool->max_items / 10)
+               queue_work(rds_wq, &pool->flush_worker);
+
+       if (invalidate) {
+               if (likely(!in_interrupt())) {
+                       rds_ib_flush_mr_pool(pool, 0);
+               } else {
+                       /* We get here if the user created a MR marked
+                        * as use_once and invalidate at the same time. */
+                       queue_work(rds_wq, &pool->flush_worker);
+               }
+       }
+}
+
+void rds_ib_flush_mrs(void)
+{
+       struct rds_ib_device *rds_ibdev;
+
+       list_for_each_entry(rds_ibdev, &rds_ib_devices, list) {
+               struct rds_ib_mr_pool *pool = rds_ibdev->mr_pool;
+
+               if (pool)
+                       rds_ib_flush_mr_pool(pool, 0);
+       }
+}
+
+void *rds_ib_get_mr(struct scatterlist *sg, unsigned long nents,
+                   struct rds_sock *rs, u32 *key_ret)
+{
+       struct rds_ib_device *rds_ibdev;
+       struct rds_ib_mr *ibmr = NULL;
+       int ret;
+
+       rds_ibdev = rds_ib_get_device(rs->rs_bound_addr);
+       if (!rds_ibdev) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       if (!rds_ibdev->mr_pool) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       ibmr = rds_ib_alloc_fmr(rds_ibdev);
+       if (IS_ERR(ibmr))
+               return ibmr;
+
+       ret = rds_ib_map_fmr(rds_ibdev, ibmr, sg, nents);
+       if (ret == 0)
+               *key_ret = ibmr->fmr->rkey;
+       else
+               printk(KERN_WARNING "RDS/IB: map_fmr failed (errno=%d)\n", ret);
+
+       ibmr->device = rds_ibdev;
+
+ out:
+       if (ret) {
+               if (ibmr)
+                       rds_ib_free_mr(ibmr, 0);
+               ibmr = ERR_PTR(ret);
+       }
+       return ibmr;
+}
diff --git a/net/rds/ib_recv.c b/net/rds/ib_recv.c
new file mode 100644 (file)
index 0000000..5061b55
--- /dev/null
@@ -0,0 +1,869 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <rdma/rdma_cm.h>
+
+#include "rds.h"
+#include "ib.h"
+
+static struct kmem_cache *rds_ib_incoming_slab;
+static struct kmem_cache *rds_ib_frag_slab;
+static atomic_t        rds_ib_allocation = ATOMIC_INIT(0);
+
+static void rds_ib_frag_drop_page(struct rds_page_frag *frag)
+{
+       rdsdebug("frag %p page %p\n", frag, frag->f_page);
+       __free_page(frag->f_page);
+       frag->f_page = NULL;
+}
+
+static void rds_ib_frag_free(struct rds_page_frag *frag)
+{
+       rdsdebug("frag %p page %p\n", frag, frag->f_page);
+       BUG_ON(frag->f_page != NULL);
+       kmem_cache_free(rds_ib_frag_slab, frag);
+}
+
+/*
+ * We map a page at a time.  Its fragments are posted in order.  This
+ * is called in fragment order as the fragments get send completion events.
+ * Only the last frag in the page performs the unmapping.
+ *
+ * It's OK for ring cleanup to call this in whatever order it likes because
+ * DMA is not in flight and so we can unmap while other ring entries still
+ * hold page references in their frags.
+ */
+static void rds_ib_recv_unmap_page(struct rds_ib_connection *ic,
+                                  struct rds_ib_recv_work *recv)
+{
+       struct rds_page_frag *frag = recv->r_frag;
+
+       rdsdebug("recv %p frag %p page %p\n", recv, frag, frag->f_page);
+       if (frag->f_mapped)
+               ib_dma_unmap_page(ic->i_cm_id->device,
+                              frag->f_mapped,
+                              RDS_FRAG_SIZE, DMA_FROM_DEVICE);
+       frag->f_mapped = 0;
+}
+
+void rds_ib_recv_init_ring(struct rds_ib_connection *ic)
+{
+       struct rds_ib_recv_work *recv;
+       u32 i;
+
+       for (i = 0, recv = ic->i_recvs; i < ic->i_recv_ring.w_nr; i++, recv++) {
+               struct ib_sge *sge;
+
+               recv->r_ibinc = NULL;
+               recv->r_frag = NULL;
+
+               recv->r_wr.next = NULL;
+               recv->r_wr.wr_id = i;
+               recv->r_wr.sg_list = recv->r_sge;
+               recv->r_wr.num_sge = RDS_IB_RECV_SGE;
+
+               sge = rds_ib_data_sge(ic, recv->r_sge);
+               sge->addr = 0;
+               sge->length = RDS_FRAG_SIZE;
+               sge->lkey = ic->i_mr->lkey;
+
+               sge = rds_ib_header_sge(ic, recv->r_sge);
+               sge->addr = ic->i_recv_hdrs_dma + (i * sizeof(struct rds_header));
+               sge->length = sizeof(struct rds_header);
+               sge->lkey = ic->i_mr->lkey;
+       }
+}
+
+static void rds_ib_recv_clear_one(struct rds_ib_connection *ic,
+                                 struct rds_ib_recv_work *recv)
+{
+       if (recv->r_ibinc) {
+               rds_inc_put(&recv->r_ibinc->ii_inc);
+               recv->r_ibinc = NULL;
+       }
+       if (recv->r_frag) {
+               rds_ib_recv_unmap_page(ic, recv);
+               if (recv->r_frag->f_page)
+                       rds_ib_frag_drop_page(recv->r_frag);
+               rds_ib_frag_free(recv->r_frag);
+               recv->r_frag = NULL;
+       }
+}
+
+void rds_ib_recv_clear_ring(struct rds_ib_connection *ic)
+{
+       u32 i;
+
+       for (i = 0; i < ic->i_recv_ring.w_nr; i++)
+               rds_ib_recv_clear_one(ic, &ic->i_recvs[i]);
+
+       if (ic->i_frag.f_page)
+               rds_ib_frag_drop_page(&ic->i_frag);
+}
+
+static int rds_ib_recv_refill_one(struct rds_connection *conn,
+                                 struct rds_ib_recv_work *recv,
+                                 gfp_t kptr_gfp, gfp_t page_gfp)
+{
+       struct rds_ib_connection *ic = conn->c_transport_data;
+       dma_addr_t dma_addr;
+       struct ib_sge *sge;
+       int ret = -ENOMEM;
+
+       if (recv->r_ibinc == NULL) {
+               if (atomic_read(&rds_ib_allocation) >= rds_ib_sysctl_max_recv_allocation) {
+                       rds_ib_stats_inc(s_ib_rx_alloc_limit);
+                       goto out;
+               }
+               recv->r_ibinc = kmem_cache_alloc(rds_ib_incoming_slab,
+                                                kptr_gfp);
+               if (recv->r_ibinc == NULL)
+                       goto out;
+               atomic_inc(&rds_ib_allocation);
+               INIT_LIST_HEAD(&recv->r_ibinc->ii_frags);
+               rds_inc_init(&recv->r_ibinc->ii_inc, conn, conn->c_faddr);
+       }
+
+       if (recv->r_frag == NULL) {
+               recv->r_frag = kmem_cache_alloc(rds_ib_frag_slab, kptr_gfp);
+               if (recv->r_frag == NULL)
+                       goto out;
+               INIT_LIST_HEAD(&recv->r_frag->f_item);
+               recv->r_frag->f_page = NULL;
+       }
+
+       if (ic->i_frag.f_page == NULL) {
+               ic->i_frag.f_page = alloc_page(page_gfp);
+               if (ic->i_frag.f_page == NULL)
+                       goto out;
+               ic->i_frag.f_offset = 0;
+       }
+
+       dma_addr = ib_dma_map_page(ic->i_cm_id->device,
+                                 ic->i_frag.f_page,
+                                 ic->i_frag.f_offset,
+                                 RDS_FRAG_SIZE,
+                                 DMA_FROM_DEVICE);
+       if (ib_dma_mapping_error(ic->i_cm_id->device, dma_addr))
+               goto out;
+
+       /*
+        * Once we get the RDS_PAGE_LAST_OFF frag then rds_ib_frag_unmap()
+        * must be called on this recv.  This happens as completions hit
+        * in order or on connection shutdown.
+        */
+       recv->r_frag->f_page = ic->i_frag.f_page;
+       recv->r_frag->f_offset = ic->i_frag.f_offset;
+       recv->r_frag->f_mapped = dma_addr;
+
+       sge = rds_ib_data_sge(ic, recv->r_sge);
+       sge->addr = dma_addr;
+       sge->length = RDS_FRAG_SIZE;
+
+       sge = rds_ib_header_sge(ic, recv->r_sge);
+       sge->addr = ic->i_recv_hdrs_dma + (recv - ic->i_recvs) * sizeof(struct rds_header);
+       sge->length = sizeof(struct rds_header);
+
+       get_page(recv->r_frag->f_page);
+
+       if (ic->i_frag.f_offset < RDS_PAGE_LAST_OFF) {
+               ic->i_frag.f_offset += RDS_FRAG_SIZE;
+       } else {
+               put_page(ic->i_frag.f_page);
+               ic->i_frag.f_page = NULL;
+               ic->i_frag.f_offset = 0;
+       }
+
+       ret = 0;
+out:
+       return ret;
+}
+
+/*
+ * This tries to allocate and post unused work requests after making sure that
+ * they have all the allocations they need to queue received fragments into
+ * sockets.  The i_recv_mutex is held here so that ring_alloc and _unalloc
+ * pairs don't go unmatched.
+ *
+ * -1 is returned if posting fails due to temporary resource exhaustion.
+ */
+int rds_ib_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
+                      gfp_t page_gfp, int prefill)
+{
+       struct rds_ib_connection *ic = conn->c_transport_data;
+       struct rds_ib_recv_work *recv;
+       struct ib_recv_wr *failed_wr;
+       unsigned int posted = 0;
+       int ret = 0;
+       u32 pos;
+
+       while ((prefill || rds_conn_up(conn))
+                       && rds_ib_ring_alloc(&ic->i_recv_ring, 1, &pos)) {
+               if (pos >= ic->i_recv_ring.w_nr) {
+                       printk(KERN_NOTICE "Argh - ring alloc returned pos=%u\n",
+                                       pos);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               recv = &ic->i_recvs[pos];
+               ret = rds_ib_recv_refill_one(conn, recv, kptr_gfp, page_gfp);
+               if (ret) {
+                       ret = -1;
+                       break;
+               }
+
+               /* XXX when can this fail? */
+               ret = ib_post_recv(ic->i_cm_id->qp, &recv->r_wr, &failed_wr);
+               rdsdebug("recv %p ibinc %p page %p addr %lu ret %d\n", recv,
+                        recv->r_ibinc, recv->r_frag->f_page,
+                        (long) recv->r_frag->f_mapped, ret);
+               if (ret) {
+                       rds_ib_conn_error(conn, "recv post on "
+                              "%pI4 returned %d, disconnecting and "
+                              "reconnecting\n", &conn->c_faddr,
+                              ret);
+                       ret = -1;
+                       break;
+               }
+
+               posted++;
+       }
+
+       /* We're doing flow control - update the window. */
+       if (ic->i_flowctl && posted)
+               rds_ib_advertise_credits(conn, posted);
+
+       if (ret)
+               rds_ib_ring_unalloc(&ic->i_recv_ring, 1);
+       return ret;
+}
+
+void rds_ib_inc_purge(struct rds_incoming *inc)
+{
+       struct rds_ib_incoming *ibinc;
+       struct rds_page_frag *frag;
+       struct rds_page_frag *pos;
+
+       ibinc = container_of(inc, struct rds_ib_incoming, ii_inc);
+       rdsdebug("purging ibinc %p inc %p\n", ibinc, inc);
+
+       list_for_each_entry_safe(frag, pos, &ibinc->ii_frags, f_item) {
+               list_del_init(&frag->f_item);
+               rds_ib_frag_drop_page(frag);
+               rds_ib_frag_free(frag);
+       }
+}
+
+void rds_ib_inc_free(struct rds_incoming *inc)
+{
+       struct rds_ib_incoming *ibinc;
+
+       ibinc = container_of(inc, struct rds_ib_incoming, ii_inc);
+
+       rds_ib_inc_purge(inc);
+       rdsdebug("freeing ibinc %p inc %p\n", ibinc, inc);
+       BUG_ON(!list_empty(&ibinc->ii_frags));
+       kmem_cache_free(rds_ib_incoming_slab, ibinc);
+       atomic_dec(&rds_ib_allocation);
+       BUG_ON(atomic_read(&rds_ib_allocation) < 0);
+}
+
+int rds_ib_inc_copy_to_user(struct rds_incoming *inc, struct iovec *first_iov,
+                           size_t size)
+{
+       struct rds_ib_incoming *ibinc;
+       struct rds_page_frag *frag;
+       struct iovec *iov = first_iov;
+       unsigned long to_copy;
+       unsigned long frag_off = 0;
+       unsigned long iov_off = 0;
+       int copied = 0;
+       int ret;
+       u32 len;
+
+       ibinc = container_of(inc, struct rds_ib_incoming, ii_inc);
+       frag = list_entry(ibinc->ii_frags.next, struct rds_page_frag, f_item);
+       len = be32_to_cpu(inc->i_hdr.h_len);
+
+       while (copied < size && copied < len) {
+               if (frag_off == RDS_FRAG_SIZE) {
+                       frag = list_entry(frag->f_item.next,
+                                         struct rds_page_frag, f_item);
+                       frag_off = 0;
+               }
+               while (iov_off == iov->iov_len) {
+                       iov_off = 0;
+                       iov++;
+               }
+
+               to_copy = min(iov->iov_len - iov_off, RDS_FRAG_SIZE - frag_off);
+               to_copy = min_t(size_t, to_copy, size - copied);
+               to_copy = min_t(unsigned long, to_copy, len - copied);
+
+               rdsdebug("%lu bytes to user [%p, %zu] + %lu from frag "
+                        "[%p, %lu] + %lu\n",
+                        to_copy, iov->iov_base, iov->iov_len, iov_off,
+                        frag->f_page, frag->f_offset, frag_off);
+
+               /* XXX needs + offset for multiple recvs per page */
+               ret = rds_page_copy_to_user(frag->f_page,
+                                           frag->f_offset + frag_off,
+                                           iov->iov_base + iov_off,
+                                           to_copy);
+               if (ret) {
+                       copied = ret;
+                       break;
+               }
+
+               iov_off += to_copy;
+               frag_off += to_copy;
+               copied += to_copy;
+       }
+
+       return copied;
+}
+
+/* ic starts out kzalloc()ed */
+void rds_ib_recv_init_ack(struct rds_ib_connection *ic)
+{
+       struct ib_send_wr *wr = &ic->i_ack_wr;
+       struct ib_sge *sge = &ic->i_ack_sge;
+
+       sge->addr = ic->i_ack_dma;
+       sge->length = sizeof(struct rds_header);
+       sge->lkey = ic->i_mr->lkey;
+
+       wr->sg_list = sge;
+       wr->num_sge = 1;
+       wr->opcode = IB_WR_SEND;
+       wr->wr_id = RDS_IB_ACK_WR_ID;
+       wr->send_flags = IB_SEND_SIGNALED | IB_SEND_SOLICITED;
+}
+
+/*
+ * You'd think that with reliable IB connections you wouldn't need to ack
+ * messages that have been received.  The problem is that IB hardware generates
+ * an ack message before it has DMAed the message into memory.  This creates a
+ * potential message loss if the HCA is disabled for any reason between when it
+ * sends the ack and before the message is DMAed and processed.  This is only a
+ * potential issue if another HCA is available for fail-over.
+ *
+ * When the remote host receives our ack they'll free the sent message from
+ * their send queue.  To decrease the latency of this we always send an ack
+ * immediately after we've received messages.
+ *
+ * For simplicity, we only have one ack in flight at a time.  This puts
+ * pressure on senders to have deep enough send queues to absorb the latency of
+ * a single ack frame being in flight.  This might not be good enough.
+ *
+ * This is implemented by have a long-lived send_wr and sge which point to a
+ * statically allocated ack frame.  This ack wr does not fall under the ring
+ * accounting that the tx and rx wrs do.  The QP attribute specifically makes
+ * room for it beyond the ring size.  Send completion notices its special
+ * wr_id and avoids working with the ring in that case.
+ */
+static void rds_ib_set_ack(struct rds_ib_connection *ic, u64 seq,
+                               int ack_required)
+{
+       rds_ib_set_64bit(&ic->i_ack_next, seq);
+       if (ack_required) {
+               smp_mb__before_clear_bit();
+               set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
+       }
+}
+
+static u64 rds_ib_get_ack(struct rds_ib_connection *ic)
+{
+       clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
+       smp_mb__after_clear_bit();
+
+       return ic->i_ack_next;
+}
+
+static void rds_ib_send_ack(struct rds_ib_connection *ic, unsigned int adv_credits)
+{
+       struct rds_header *hdr = ic->i_ack;
+       struct ib_send_wr *failed_wr;
+       u64 seq;
+       int ret;
+
+       seq = rds_ib_get_ack(ic);
+
+       rdsdebug("send_ack: ic %p ack %llu\n", ic, (unsigned long long) seq);
+       rds_message_populate_header(hdr, 0, 0, 0);
+       hdr->h_ack = cpu_to_be64(seq);
+       hdr->h_credit = adv_credits;
+       rds_message_make_checksum(hdr);
+       ic->i_ack_queued = jiffies;
+
+       ret = ib_post_send(ic->i_cm_id->qp, &ic->i_ack_wr, &failed_wr);
+       if (unlikely(ret)) {
+               /* Failed to send. Release the WR, and
+                * force another ACK.
+                */
+               clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags);
+               set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
+
+               rds_ib_stats_inc(s_ib_ack_send_failure);
+               /* Need to finesse this later. */
+               BUG();
+       } else
+               rds_ib_stats_inc(s_ib_ack_sent);
+}
+
+/*
+ * There are 3 ways of getting acknowledgements to the peer:
+ *  1. We call rds_ib_attempt_ack from the recv completion handler
+ *     to send an ACK-only frame.
+ *     However, there can be only one such frame in the send queue
+ *     at any time, so we may have to postpone it.
+ *  2. When another (data) packet is transmitted while there's
+ *     an ACK in the queue, we piggyback the ACK sequence number
+ *     on the data packet.
+ *  3. If the ACK WR is done sending, we get called from the
+ *     send queue completion handler, and check whether there's
+ *     another ACK pending (postponed because the WR was on the
+ *     queue). If so, we transmit it.
+ *
+ * We maintain 2 variables:
+ *  -  i_ack_flags, which keeps track of whether the ACK WR
+ *     is currently in the send queue or not (IB_ACK_IN_FLIGHT)
+ *  -  i_ack_next, which is the last sequence number we received
+ *
+ * Potentially, send queue and receive queue handlers can run concurrently.
+ *
+ * Reconnecting complicates this picture just slightly. When we
+ * reconnect, we may be seeing duplicate packets. The peer
+ * is retransmitting them, because it hasn't seen an ACK for
+ * them. It is important that we ACK these.
+ *
+ * ACK mitigation adds a header flag "ACK_REQUIRED"; any packet with
+ * this flag set *MUST* be acknowledged immediately.
+ */
+
+/*
+ * When we get here, we're called from the recv queue handler.
+ * Check whether we ought to transmit an ACK.
+ */
+void rds_ib_attempt_ack(struct rds_ib_connection *ic)
+{
+       unsigned int adv_credits;
+
+       if (!test_bit(IB_ACK_REQUESTED, &ic->i_ack_flags))
+               return;
+
+       if (test_and_set_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags)) {
+               rds_ib_stats_inc(s_ib_ack_send_delayed);
+               return;
+       }
+
+       /* Can we get a send credit? */
+       if (!rds_ib_send_grab_credits(ic, 1, &adv_credits, 0)) {
+               rds_ib_stats_inc(s_ib_tx_throttle);
+               clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags);
+               return;
+       }
+
+       clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
+       rds_ib_send_ack(ic, adv_credits);
+}
+
+/*
+ * We get here from the send completion handler, when the
+ * adapter tells us the ACK frame was sent.
+ */
+void rds_ib_ack_send_complete(struct rds_ib_connection *ic)
+{
+       clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags);
+       rds_ib_attempt_ack(ic);
+}
+
+/*
+ * This is called by the regular xmit code when it wants to piggyback
+ * an ACK on an outgoing frame.
+ */
+u64 rds_ib_piggyb_ack(struct rds_ib_connection *ic)
+{
+       if (test_and_clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags))
+               rds_ib_stats_inc(s_ib_ack_send_piggybacked);
+       return rds_ib_get_ack(ic);
+}
+
+/*
+ * It's kind of lame that we're copying from the posted receive pages into
+ * long-lived bitmaps.  We could have posted the bitmaps and rdma written into
+ * them.  But receiving new congestion bitmaps should be a *rare* event, so
+ * hopefully we won't need to invest that complexity in making it more
+ * efficient.  By copying we can share a simpler core with TCP which has to
+ * copy.
+ */
+static void rds_ib_cong_recv(struct rds_connection *conn,
+                             struct rds_ib_incoming *ibinc)
+{
+       struct rds_cong_map *map;
+       unsigned int map_off;
+       unsigned int map_page;
+       struct rds_page_frag *frag;
+       unsigned long frag_off;
+       unsigned long to_copy;
+       unsigned long copied;
+       uint64_t uncongested = 0;
+       void *addr;
+
+       /* catch completely corrupt packets */
+       if (be32_to_cpu(ibinc->ii_inc.i_hdr.h_len) != RDS_CONG_MAP_BYTES)
+               return;
+
+       map = conn->c_fcong;
+       map_page = 0;
+       map_off = 0;
+
+       frag = list_entry(ibinc->ii_frags.next, struct rds_page_frag, f_item);
+       frag_off = 0;
+
+       copied = 0;
+
+       while (copied < RDS_CONG_MAP_BYTES) {
+               uint64_t *src, *dst;
+               unsigned int k;
+
+               to_copy = min(RDS_FRAG_SIZE - frag_off, PAGE_SIZE - map_off);
+               BUG_ON(to_copy & 7); /* Must be 64bit aligned. */
+
+               addr = kmap_atomic(frag->f_page, KM_SOFTIRQ0);
+
+               src = addr + frag_off;
+               dst = (void *)map->m_page_addrs[map_page] + map_off;
+               for (k = 0; k < to_copy; k += 8) {
+                       /* Record ports that became uncongested, ie
+                        * bits that changed from 0 to 1. */
+                       uncongested |= ~(*src) & *dst;
+                       *dst++ = *src++;
+               }
+               kunmap_atomic(addr, KM_SOFTIRQ0);
+
+               copied += to_copy;
+
+               map_off += to_copy;
+               if (map_off == PAGE_SIZE) {
+                       map_off = 0;
+                       map_page++;
+               }
+
+               frag_off += to_copy;
+               if (frag_off == RDS_FRAG_SIZE) {
+                       frag = list_entry(frag->f_item.next,
+                                         struct rds_page_frag, f_item);
+                       frag_off = 0;
+               }
+       }
+
+       /* the congestion map is in little endian order */
+       uncongested = le64_to_cpu(uncongested);
+
+       rds_cong_map_updated(map, uncongested);
+}
+
+/*
+ * Rings are posted with all the allocations they'll need to queue the
+ * incoming message to the receiving socket so this can't fail.
+ * All fragments start with a header, so we can make sure we're not receiving
+ * garbage, and we can tell a small 8 byte fragment from an ACK frame.
+ */
+struct rds_ib_ack_state {
+       u64             ack_next;
+       u64             ack_recv;
+       unsigned int    ack_required:1;
+       unsigned int    ack_next_valid:1;
+       unsigned int    ack_recv_valid:1;
+};
+
+static void rds_ib_process_recv(struct rds_connection *conn,
+                               struct rds_ib_recv_work *recv, u32 byte_len,
+                               struct rds_ib_ack_state *state)
+{
+       struct rds_ib_connection *ic = conn->c_transport_data;
+       struct rds_ib_incoming *ibinc = ic->i_ibinc;
+       struct rds_header *ihdr, *hdr;
+
+       /* XXX shut down the connection if port 0,0 are seen? */
+
+       rdsdebug("ic %p ibinc %p recv %p byte len %u\n", ic, ibinc, recv,
+                byte_len);
+
+       if (byte_len < sizeof(struct rds_header)) {
+               rds_ib_conn_error(conn, "incoming message "
+                      "from %pI4 didn't inclue a "
+                      "header, disconnecting and "
+                      "reconnecting\n",
+                      &conn->c_faddr);
+               return;
+       }
+       byte_len -= sizeof(struct rds_header);
+
+       ihdr = &ic->i_recv_hdrs[recv - ic->i_recvs];
+
+       /* Validate the checksum. */
+       if (!rds_message_verify_checksum(ihdr)) {
+               rds_ib_conn_error(conn, "incoming message "
+                      "from %pI4 has corrupted header - "
+                      "forcing a reconnect\n",
+                      &conn->c_faddr);
+               rds_stats_inc(s_recv_drop_bad_checksum);
+               return;
+       }
+
+       /* Process the ACK sequence which comes with every packet */
+       state->ack_recv = be64_to_cpu(ihdr->h_ack);
+       state->ack_recv_valid = 1;
+
+       /* Process the credits update if there was one */
+       if (ihdr->h_credit)
+               rds_ib_send_add_credits(conn, ihdr->h_credit);
+
+       if (ihdr->h_sport == 0 && ihdr->h_dport == 0 && byte_len == 0) {
+               /* This is an ACK-only packet. The fact that it gets
+                * special treatment here is that historically, ACKs
+                * were rather special beasts.
+                */
+               rds_ib_stats_inc(s_ib_ack_received);
+
+               /*
+                * Usually the frags make their way on to incs and are then freed as
+                * the inc is freed.  We don't go that route, so we have to drop the
+                * page ref ourselves.  We can't just leave the page on the recv
+                * because that confuses the dma mapping of pages and each recv's use
+                * of a partial page.  We can leave the frag, though, it will be
+                * reused.
+                *
+                * FIXME: Fold this into the code path below.
+                */
+               rds_ib_frag_drop_page(recv->r_frag);
+               return;
+       }
+
+       /*
+        * If we don't already have an inc on the connection then this
+        * fragment has a header and starts a message.. copy its header
+        * into the inc and save the inc so we can hang upcoming fragments
+        * off its list.
+        */
+       if (ibinc == NULL) {
+               ibinc = recv->r_ibinc;
+               recv->r_ibinc = NULL;
+               ic->i_ibinc = ibinc;
+
+               hdr = &ibinc->ii_inc.i_hdr;
+               memcpy(hdr, ihdr, sizeof(*hdr));
+               ic->i_recv_data_rem = be32_to_cpu(hdr->h_len);
+
+               rdsdebug("ic %p ibinc %p rem %u flag 0x%x\n", ic, ibinc,
+                        ic->i_recv_data_rem, hdr->h_flags);
+       } else {
+               hdr = &ibinc->ii_inc.i_hdr;
+               /* We can't just use memcmp here; fragments of a
+                * single message may carry different ACKs */
+               if (hdr->h_sequence != ihdr->h_sequence
+                || hdr->h_len != ihdr->h_len
+                || hdr->h_sport != ihdr->h_sport
+                || hdr->h_dport != ihdr->h_dport) {
+                       rds_ib_conn_error(conn,
+                               "fragment header mismatch; forcing reconnect\n");
+                       return;
+               }
+       }
+
+       list_add_tail(&recv->r_frag->f_item, &ibinc->ii_frags);
+       recv->r_frag = NULL;
+
+       if (ic->i_recv_data_rem > RDS_FRAG_SIZE)
+               ic->i_recv_data_rem -= RDS_FRAG_SIZE;
+       else {
+               ic->i_recv_data_rem = 0;
+               ic->i_ibinc = NULL;
+
+               if (ibinc->ii_inc.i_hdr.h_flags == RDS_FLAG_CONG_BITMAP)
+                       rds_ib_cong_recv(conn, ibinc);
+               else {
+                       rds_recv_incoming(conn, conn->c_faddr, conn->c_laddr,
+                                         &ibinc->ii_inc, GFP_ATOMIC,
+                                         KM_SOFTIRQ0);
+                       state->ack_next = be64_to_cpu(hdr->h_sequence);
+                       state->ack_next_valid = 1;
+               }
+
+               /* Evaluate the ACK_REQUIRED flag *after* we received
+                * the complete frame, and after bumping the next_rx
+                * sequence. */
+               if (hdr->h_flags & RDS_FLAG_ACK_REQUIRED) {
+                       rds_stats_inc(s_recv_ack_required);
+                       state->ack_required = 1;
+               }
+
+               rds_inc_put(&ibinc->ii_inc);
+       }
+}
+
+/*
+ * Plucking the oldest entry from the ring can be done concurrently with
+ * the thread refilling the ring.  Each ring operation is protected by
+ * spinlocks and the transient state of refilling doesn't change the
+ * recording of which entry is oldest.
+ *
+ * This relies on IB only calling one cq comp_handler for each cq so that
+ * there will only be one caller of rds_recv_incoming() per RDS connection.
+ */
+void rds_ib_recv_cq_comp_handler(struct ib_cq *cq, void *context)
+{
+       struct rds_connection *conn = context;
+       struct rds_ib_connection *ic = conn->c_transport_data;
+       struct ib_wc wc;
+       struct rds_ib_ack_state state = { 0, };
+       struct rds_ib_recv_work *recv;
+
+       rdsdebug("conn %p cq %p\n", conn, cq);
+
+       rds_ib_stats_inc(s_ib_rx_cq_call);
+
+       ib_req_notify_cq(cq, IB_CQ_SOLICITED);
+
+       while (ib_poll_cq(cq, 1, &wc) > 0) {
+               rdsdebug("wc wr_id 0x%llx status %u byte_len %u imm_data %u\n",
+                        (unsigned long long)wc.wr_id, wc.status, wc.byte_len,
+                        be32_to_cpu(wc.ex.imm_data));
+               rds_ib_stats_inc(s_ib_rx_cq_event);
+
+               recv = &ic->i_recvs[rds_ib_ring_oldest(&ic->i_recv_ring)];
+
+               rds_ib_recv_unmap_page(ic, recv);
+
+               /*
+                * Also process recvs in connecting state because it is possible
+                * to get a recv completion _before_ the rdmacm ESTABLISHED
+                * event is processed.
+                */
+               if (rds_conn_up(conn) || rds_conn_connecting(conn)) {
+                       /* We expect errors as the qp is drained during shutdown */
+                       if (wc.status == IB_WC_SUCCESS) {
+                               rds_ib_process_recv(conn, recv, wc.byte_len, &state);
+                       } else {
+                               rds_ib_conn_error(conn, "recv completion on "
+                                      "%pI4 had status %u, disconnecting and "
+                                      "reconnecting\n", &conn->c_faddr,
+                                      wc.status);
+                       }
+               }
+
+               rds_ib_ring_free(&ic->i_recv_ring, 1);
+       }
+
+       if (state.ack_next_valid)
+               rds_ib_set_ack(ic, state.ack_next, state.ack_required);
+       if (state.ack_recv_valid && state.ack_recv > ic->i_ack_recv) {
+               rds_send_drop_acked(conn, state.ack_recv, NULL);
+               ic->i_ack_recv = state.ack_recv;
+       }
+       if (rds_conn_up(conn))
+               rds_ib_attempt_ack(ic);
+
+       /* If we ever end up with a really empty receive ring, we're
+        * in deep trouble, as the sender will definitely see RNR
+        * timeouts. */
+       if (rds_ib_ring_empty(&ic->i_recv_ring))
+               rds_ib_stats_inc(s_ib_rx_ring_empty);
+
+       /*
+        * If the ring is running low, then schedule the thread to refill.
+        */
+       if (rds_ib_ring_low(&ic->i_recv_ring))
+               queue_delayed_work(rds_wq, &conn->c_recv_w, 0);
+}
+
+int rds_ib_recv(struct rds_connection *conn)
+{
+       struct rds_ib_connection *ic = conn->c_transport_data;
+       int ret = 0;
+
+       rdsdebug("conn %p\n", conn);
+
+       /*
+        * If we get a temporary posting failure in this context then
+        * we're really low and we want the caller to back off for a bit.
+        */
+       mutex_lock(&ic->i_recv_mutex);
+       if (rds_ib_recv_refill(conn, GFP_KERNEL, GFP_HIGHUSER, 0))
+               ret = -ENOMEM;
+       else
+               rds_ib_stats_inc(s_ib_rx_refill_from_thread);
+       mutex_unlock(&ic->i_recv_mutex);
+
+       if (rds_conn_up(conn))
+               rds_ib_attempt_ack(ic);
+
+       return ret;
+}
+
+int __init rds_ib_recv_init(void)
+{
+       struct sysinfo si;
+       int ret = -ENOMEM;
+
+       /* Default to 30% of all available RAM for recv memory */
+       si_meminfo(&si);
+       rds_ib_sysctl_max_recv_allocation = si.totalram / 3 * PAGE_SIZE / RDS_FRAG_SIZE;
+
+       rds_ib_incoming_slab = kmem_cache_create("rds_ib_incoming",
+                                       sizeof(struct rds_ib_incoming),
+                                       0, 0, NULL);
+       if (rds_ib_incoming_slab == NULL)
+               goto out;
+
+       rds_ib_frag_slab = kmem_cache_create("rds_ib_frag",
+                                       sizeof(struct rds_page_frag),
+                                       0, 0, NULL);
+       if (rds_ib_frag_slab == NULL)
+               kmem_cache_destroy(rds_ib_incoming_slab);
+       else
+               ret = 0;
+out:
+       return ret;
+}
+
+void rds_ib_recv_exit(void)
+{
+       kmem_cache_destroy(rds_ib_incoming_slab);
+       kmem_cache_destroy(rds_ib_frag_slab);
+}
diff --git a/net/rds/ib_ring.c b/net/rds/ib_ring.c
new file mode 100644 (file)
index 0000000..99a6cca
--- /dev/null
@@ -0,0 +1,168 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+
+#include "rds.h"
+#include "ib.h"
+
+/*
+ * Locking for IB rings.
+ * We assume that allocation is always protected by a mutex
+ * in the caller (this is a valid assumption for the current
+ * implementation).
+ *
+ * Freeing always happens in an interrupt, and hence only
+ * races with allocations, but not with other free()s.
+ *
+ * The interaction between allocation and freeing is that
+ * the alloc code has to determine the number of free entries.
+ * To this end, we maintain two counters; an allocation counter
+ * and a free counter. Both are allowed to run freely, and wrap
+ * around.
+ * The number of used entries is always (alloc_ctr - free_ctr) % NR.
+ *
+ * The current implementation makes free_ctr atomic. When the
+ * caller finds an allocation fails, it should set an "alloc fail"
+ * bit and retry the allocation. The "alloc fail" bit essentially tells
+ * the CQ completion handlers to wake it up after freeing some
+ * more entries.
+ */
+
+/*
+ * This only happens on shutdown.
+ */
+DECLARE_WAIT_QUEUE_HEAD(rds_ib_ring_empty_wait);
+
+void rds_ib_ring_init(struct rds_ib_work_ring *ring, u32 nr)
+{
+       memset(ring, 0, sizeof(*ring));
+       ring->w_nr = nr;
+       rdsdebug("ring %p nr %u\n", ring, ring->w_nr);
+}
+
+static inline u32 __rds_ib_ring_used(struct rds_ib_work_ring *ring)
+{
+       u32 diff;
+
+       /* This assumes that atomic_t has at least as many bits as u32 */
+       diff = ring->w_alloc_ctr - (u32) atomic_read(&ring->w_free_ctr);
+       BUG_ON(diff > ring->w_nr);
+
+       return diff;
+}
+
+void rds_ib_ring_resize(struct rds_ib_work_ring *ring, u32 nr)
+{
+       /* We only ever get called from the connection setup code,
+        * prior to creating the QP. */
+       BUG_ON(__rds_ib_ring_used(ring));
+       ring->w_nr = nr;
+}
+
+static int __rds_ib_ring_empty(struct rds_ib_work_ring *ring)
+{
+       return __rds_ib_ring_used(ring) == 0;
+}
+
+u32 rds_ib_ring_alloc(struct rds_ib_work_ring *ring, u32 val, u32 *pos)
+{
+       u32 ret = 0, avail;
+
+       avail = ring->w_nr - __rds_ib_ring_used(ring);
+
+       rdsdebug("ring %p val %u next %u free %u\n", ring, val,
+                ring->w_alloc_ptr, avail);
+
+       if (val && avail) {
+               ret = min(val, avail);
+               *pos = ring->w_alloc_ptr;
+
+               ring->w_alloc_ptr = (ring->w_alloc_ptr + ret) % ring->w_nr;
+               ring->w_alloc_ctr += ret;
+       }
+
+       return ret;
+}
+
+void rds_ib_ring_free(struct rds_ib_work_ring *ring, u32 val)
+{
+       ring->w_free_ptr = (ring->w_free_ptr + val) % ring->w_nr;
+       atomic_add(val, &ring->w_free_ctr);
+
+       if (__rds_ib_ring_empty(ring) &&
+           waitqueue_active(&rds_ib_ring_empty_wait))
+               wake_up(&rds_ib_ring_empty_wait);
+}
+
+void rds_ib_ring_unalloc(struct rds_ib_work_ring *ring, u32 val)
+{
+       ring->w_alloc_ptr = (ring->w_alloc_ptr - val) % ring->w_nr;
+       ring->w_alloc_ctr -= val;
+}
+
+int rds_ib_ring_empty(struct rds_ib_work_ring *ring)
+{
+       return __rds_ib_ring_empty(ring);
+}
+
+int rds_ib_ring_low(struct rds_ib_work_ring *ring)
+{
+       return __rds_ib_ring_used(ring) <= (ring->w_nr >> 2);
+}
+
+/*
+ * returns the oldest alloced ring entry.  This will be the next one
+ * freed.  This can't be called if there are none allocated.
+ */
+u32 rds_ib_ring_oldest(struct rds_ib_work_ring *ring)
+{
+       return ring->w_free_ptr;
+}
+
+/*
+ * returns the number of completed work requests.
+ */
+
+u32 rds_ib_ring_completed(struct rds_ib_work_ring *ring, u32 wr_id, u32 oldest)
+{
+       u32 ret;
+
+       if (oldest <= (unsigned long long)wr_id)
+               ret = (unsigned long long)wr_id - oldest + 1;
+       else
+               ret = ring->w_nr - oldest + (unsigned long long)wr_id + 1;
+
+       rdsdebug("ring %p ret %u wr_id %u oldest %u\n", ring, ret,
+                wr_id, oldest);
+       return ret;
+}
diff --git a/net/rds/ib_send.c b/net/rds/ib_send.c
new file mode 100644 (file)
index 0000000..cb6c52c
--- /dev/null
@@ -0,0 +1,874 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/in.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+
+#include "rds.h"
+#include "rdma.h"
+#include "ib.h"
+
+static void rds_ib_send_rdma_complete(struct rds_message *rm,
+                                     int wc_status)
+{
+       int notify_status;
+
+       switch (wc_status) {
+       case IB_WC_WR_FLUSH_ERR:
+               return;
+
+       case IB_WC_SUCCESS:
+               notify_status = RDS_RDMA_SUCCESS;
+               break;
+
+       case IB_WC_REM_ACCESS_ERR:
+               notify_status = RDS_RDMA_REMOTE_ERROR;
+               break;
+
+       default:
+               notify_status = RDS_RDMA_OTHER_ERROR;
+               break;
+       }
+       rds_rdma_send_complete(rm, notify_status);
+}
+
+static void rds_ib_send_unmap_rdma(struct rds_ib_connection *ic,
+                                  struct rds_rdma_op *op)
+{
+       if (op->r_mapped) {
+               ib_dma_unmap_sg(ic->i_cm_id->device,
+                       op->r_sg, op->r_nents,
+                       op->r_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               op->r_mapped = 0;
+       }
+}
+
+static void rds_ib_send_unmap_rm(struct rds_ib_connection *ic,
+                         struct rds_ib_send_work *send,
+                         int wc_status)
+{
+       struct rds_message *rm = send->s_rm;
+
+       rdsdebug("ic %p send %p rm %p\n", ic, send, rm);
+
+       ib_dma_unmap_sg(ic->i_cm_id->device,
+                    rm->m_sg, rm->m_nents,
+                    DMA_TO_DEVICE);
+
+       if (rm->m_rdma_op != NULL) {
+               rds_ib_send_unmap_rdma(ic, rm->m_rdma_op);
+
+               /* If the user asked for a completion notification on this
+                * message, we can implement three different semantics:
+                *  1.  Notify when we received the ACK on the RDS message
+                *      that was queued with the RDMA. This provides reliable
+                *      notification of RDMA status at the expense of a one-way
+                *      packet delay.
+                *  2.  Notify when the IB stack gives us the completion event for
+                *      the RDMA operation.
+                *  3.  Notify when the IB stack gives us the completion event for
+                *      the accompanying RDS messages.
+                * Here, we implement approach #3. To implement approach #2,
+                * call rds_rdma_send_complete from the cq_handler. To implement #1,
+                * don't call rds_rdma_send_complete at all, and fall back to the notify
+                * handling in the ACK processing code.
+                *
+                * Note: There's no need to explicitly sync any RDMA buffers using
+                * ib_dma_sync_sg_for_cpu - the completion for the RDMA
+                * operation itself unmapped the RDMA buffers, which takes care
+                * of synching.
+                */
+               rds_ib_send_rdma_complete(rm, wc_status);
+
+               if (rm->m_rdma_op->r_write)
+                       rds_stats_add(s_send_rdma_bytes, rm->m_rdma_op->r_bytes);
+               else
+                       rds_stats_add(s_recv_rdma_bytes, rm->m_rdma_op->r_bytes);
+       }
+
+       /* If anyone waited for this message to get flushed out, wake
+        * them up now */
+       rds_message_unmapped(rm);
+
+       rds_message_put(rm);
+       send->s_rm = NULL;
+}
+
+void rds_ib_send_init_ring(struct rds_ib_connection *ic)
+{
+       struct rds_ib_send_work *send;
+       u32 i;
+
+       for (i = 0, send = ic->i_sends; i < ic->i_send_ring.w_nr; i++, send++) {
+               struct ib_sge *sge;
+
+               send->s_rm = NULL;
+               send->s_op = NULL;
+
+               send->s_wr.wr_id = i;
+               send->s_wr.sg_list = send->s_sge;
+               send->s_wr.num_sge = 1;
+               send->s_wr.opcode = IB_WR_SEND;
+               send->s_wr.send_flags = 0;
+               send->s_wr.ex.imm_data = 0;
+
+               sge = rds_ib_data_sge(ic, send->s_sge);
+               sge->lkey = ic->i_mr->lkey;
+
+               sge = rds_ib_header_sge(ic, send->s_sge);
+               sge->addr = ic->i_send_hdrs_dma + (i * sizeof(struct rds_header));
+               sge->length = sizeof(struct rds_header);
+               sge->lkey = ic->i_mr->lkey;
+       }
+}
+
+void rds_ib_send_clear_ring(struct rds_ib_connection *ic)
+{
+       struct rds_ib_send_work *send;
+       u32 i;
+
+       for (i = 0, send = ic->i_sends; i < ic->i_send_ring.w_nr; i++, send++) {
+               if (send->s_wr.opcode == 0xdead)
+                       continue;
+               if (send->s_rm)
+                       rds_ib_send_unmap_rm(ic, send, IB_WC_WR_FLUSH_ERR);
+               if (send->s_op)
+                       rds_ib_send_unmap_rdma(ic, send->s_op);
+       }
+}
+
+/*
+ * The _oldest/_free ring operations here race cleanly with the alloc/unalloc
+ * operations performed in the send path.  As the sender allocs and potentially
+ * unallocs the next free entry in the ring it doesn't alter which is
+ * the next to be freed, which is what this is concerned with.
+ */
+void rds_ib_send_cq_comp_handler(struct ib_cq *cq, void *context)
+{
+       struct rds_connection *conn = context;
+       struct rds_ib_connection *ic = conn->c_transport_data;
+       struct ib_wc wc;
+       struct rds_ib_send_work *send;
+       u32 completed;
+       u32 oldest;
+       u32 i = 0;
+       int ret;
+
+       rdsdebug("cq %p conn %p\n", cq, conn);
+       rds_ib_stats_inc(s_ib_tx_cq_call);
+       ret = ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+       if (ret)
+               rdsdebug("ib_req_notify_cq send failed: %d\n", ret);
+
+       while (ib_poll_cq(cq, 1, &wc) > 0) {
+               rdsdebug("wc wr_id 0x%llx status %u byte_len %u imm_data %u\n",
+                        (unsigned long long)wc.wr_id, wc.status, wc.byte_len,
+                        be32_to_cpu(wc.ex.imm_data));
+               rds_ib_stats_inc(s_ib_tx_cq_event);
+
+               if (wc.wr_id == RDS_IB_ACK_WR_ID) {
+                       if (ic->i_ack_queued + HZ/2 < jiffies)
+                               rds_ib_stats_inc(s_ib_tx_stalled);
+                       rds_ib_ack_send_complete(ic);
+                       continue;
+               }
+
+               oldest = rds_ib_ring_oldest(&ic->i_send_ring);
+
+               completed = rds_ib_ring_completed(&ic->i_send_ring, wc.wr_id, oldest);
+
+               for (i = 0; i < completed; i++) {
+                       send = &ic->i_sends[oldest];
+
+                       /* In the error case, wc.opcode sometimes contains garbage */
+                       switch (send->s_wr.opcode) {
+                       case IB_WR_SEND:
+                               if (send->s_rm)
+                                       rds_ib_send_unmap_rm(ic, send, wc.status);
+                               break;
+                       case IB_WR_RDMA_WRITE:
+                       case IB_WR_RDMA_READ:
+                               /* Nothing to be done - the SG list will be unmapped
+                                * when the SEND completes. */
+                               break;
+                       default:
+                               if (printk_ratelimit())
+                                       printk(KERN_NOTICE
+                                               "RDS/IB: %s: unexpected opcode 0x%x in WR!\n",
+                                               __func__, send->s_wr.opcode);
+                               break;
+                       }
+
+                       send->s_wr.opcode = 0xdead;
+                       send->s_wr.num_sge = 1;
+                       if (send->s_queued + HZ/2 < jiffies)
+                               rds_ib_stats_inc(s_ib_tx_stalled);
+
+                       /* If a RDMA operation produced an error, signal this right
+                        * away. If we don't, the subsequent SEND that goes with this
+                        * RDMA will be canceled with ERR_WFLUSH, and the application
+                        * never learn that the RDMA failed. */
+                       if (unlikely(wc.status == IB_WC_REM_ACCESS_ERR && send->s_op)) {
+                               struct rds_message *rm;
+
+                               rm = rds_send_get_message(conn, send->s_op);
+                               if (rm)
+                                       rds_ib_send_rdma_complete(rm, wc.status);
+                       }
+
+                       oldest = (oldest + 1) % ic->i_send_ring.w_nr;
+               }
+
+               rds_ib_ring_free(&ic->i_send_ring, completed);
+
+               if (test_and_clear_bit(RDS_LL_SEND_FULL, &conn->c_flags)
+                || test_bit(0, &conn->c_map_queued))
+                       queue_delayed_work(rds_wq, &conn->c_send_w, 0);
+
+               /* We expect errors as the qp is drained during shutdown */
+               if (wc.status != IB_WC_SUCCESS && rds_conn_up(conn)) {
+                       rds_ib_conn_error(conn,
+                               "send completion on %pI4 "
+                               "had status %u, disconnecting and reconnecting\n",
+                               &conn->c_faddr, wc.status);
+               }
+       }
+}
+
+/*
+ * This is the main function for allocating credits when sending
+ * messages.
+ *
+ * Conceptually, we have two counters:
+ *  -  send credits: this tells us how many WRs we're allowed
+ *     to submit without overruning the reciever's queue. For
+ *     each SEND WR we post, we decrement this by one.
+ *
+ *  -  posted credits: this tells us how many WRs we recently
+ *     posted to the receive queue. This value is transferred
+ *     to the peer as a "credit update" in a RDS header field.
+ *     Every time we transmit credits to the peer, we subtract
+ *     the amount of transferred credits from this counter.
+ *
+ * It is essential that we avoid situations where both sides have
+ * exhausted their send credits, and are unable to send new credits
+ * to the peer. We achieve this by requiring that we send at least
+ * one credit update to the peer before exhausting our credits.
+ * When new credits arrive, we subtract one credit that is withheld
+ * until we've posted new buffers and are ready to transmit these
+ * credits (see rds_ib_send_add_credits below).
+ *
+ * The RDS send code is essentially single-threaded; rds_send_xmit
+ * grabs c_send_lock to ensure exclusive access to the send ring.
+ * However, the ACK sending code is independent and can race with
+ * message SENDs.
+ *
+ * In the send path, we need to update the counters for send credits
+ * and the counter of posted buffers atomically - when we use the
+ * last available credit, we cannot allow another thread to race us
+ * and grab the posted credits counter.  Hence, we have to use a
+ * spinlock to protect the credit counter, or use atomics.
+ *
+ * Spinlocks shared between the send and the receive path are bad,
+ * because they create unnecessary delays. An early implementation
+ * using a spinlock showed a 5% degradation in throughput at some
+ * loads.
+ *
+ * This implementation avoids spinlocks completely, putting both
+ * counters into a single atomic, and updating that atomic using
+ * atomic_add (in the receive path, when receiving fresh credits),
+ * and using atomic_cmpxchg when updating the two counters.
+ */
+int rds_ib_send_grab_credits(struct rds_ib_connection *ic,
+                            u32 wanted, u32 *adv_credits, int need_posted)
+{
+       unsigned int avail, posted, got = 0, advertise;
+       long oldval, newval;
+
+       *adv_credits = 0;
+       if (!ic->i_flowctl)
+               return wanted;
+
+try_again:
+       advertise = 0;
+       oldval = newval = atomic_read(&ic->i_credits);
+       posted = IB_GET_POST_CREDITS(oldval);
+       avail = IB_GET_SEND_CREDITS(oldval);
+
+       rdsdebug("rds_ib_send_grab_credits(%u): credits=%u posted=%u\n",
+                       wanted, avail, posted);
+
+       /* The last credit must be used to send a credit update. */
+       if (avail && !posted)
+               avail--;
+
+       if (avail < wanted) {
+               struct rds_connection *conn = ic->i_cm_id->context;
+
+               /* Oops, there aren't that many credits left! */
+               set_bit(RDS_LL_SEND_FULL, &conn->c_flags);
+               got = avail;
+       } else {
+               /* Sometimes you get what you want, lalala. */
+               got = wanted;
+       }
+       newval -= IB_SET_SEND_CREDITS(got);
+
+       /*
+        * If need_posted is non-zero, then the caller wants
+        * the posted regardless of whether any send credits are
+        * available.
+        */
+       if (posted && (got || need_posted)) {
+               advertise = min_t(unsigned int, posted, RDS_MAX_ADV_CREDIT);
+               newval -= IB_SET_POST_CREDITS(advertise);
+       }
+
+       /* Finally bill everything */
+       if (atomic_cmpxchg(&ic->i_credits, oldval, newval) != oldval)
+               goto try_again;
+
+       *adv_credits = advertise;
+       return got;
+}
+
+void rds_ib_send_add_credits(struct rds_connection *conn, unsigned int credits)
+{
+       struct rds_ib_connection *ic = conn->c_transport_data;
+
+       if (credits == 0)
+               return;
+
+       rdsdebug("rds_ib_send_add_credits(%u): current=%u%s\n",
+                       credits,
+                       IB_GET_SEND_CREDITS(atomic_read(&ic->i_credits)),
+                       test_bit(RDS_LL_SEND_FULL, &conn->c_flags) ? ", ll_send_full" : "");
+
+       atomic_add(IB_SET_SEND_CREDITS(credits), &ic->i_credits);
+       if (test_and_clear_bit(RDS_LL_SEND_FULL, &conn->c_flags))
+               queue_delayed_work(rds_wq, &conn->c_send_w, 0);
+
+       WARN_ON(IB_GET_SEND_CREDITS(credits) >= 16384);
+
+       rds_ib_stats_inc(s_ib_rx_credit_updates);
+}
+
+void rds_ib_advertise_credits(struct rds_connection *conn, unsigned int posted)
+{
+       struct rds_ib_connection *ic = conn->c_transport_data;
+
+       if (posted == 0)
+               return;
+
+       atomic_add(IB_SET_POST_CREDITS(posted), &ic->i_credits);
+
+       /* Decide whether to send an update to the peer now.
+        * If we would send a credit update for every single buffer we
+        * post, we would end up with an ACK storm (ACK arrives,
+        * consumes buffer, we refill the ring, send ACK to remote
+        * advertising the newly posted buffer... ad inf)
+        *
+        * Performance pretty much depends on how often we send
+        * credit updates - too frequent updates mean lots of ACKs.
+        * Too infrequent updates, and the peer will run out of
+        * credits and has to throttle.
+        * For the time being, 16 seems to be a good compromise.
+        */
+       if (IB_GET_POST_CREDITS(atomic_read(&ic->i_credits)) >= 16)
+               set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
+}
+
+static inline void
+rds_ib_xmit_populate_wr(struct rds_ib_connection *ic,
+               struct rds_ib_send_work *send, unsigned int pos,
+               unsigned long buffer, unsigned int length,
+               int send_flags)
+{
+       struct ib_sge *sge;
+
+       WARN_ON(pos != send - ic->i_sends);
+
+       send->s_wr.send_flags = send_flags;
+       send->s_wr.opcode = IB_WR_SEND;
+       send->s_wr.num_sge = 2;
+       send->s_wr.next = NULL;
+       send->s_queued = jiffies;
+       send->s_op = NULL;
+
+       if (length != 0) {
+               sge = rds_ib_data_sge(ic, send->s_sge);
+               sge->addr = buffer;
+               sge->length = length;
+               sge->lkey = ic->i_mr->lkey;
+
+               sge = rds_ib_header_sge(ic, send->s_sge);
+       } else {
+               /* We're sending a packet with no payload. There is only
+                * one SGE */
+               send->s_wr.num_sge = 1;
+               sge = &send->s_sge[0];
+       }
+
+       sge->addr = ic->i_send_hdrs_dma + (pos * sizeof(struct rds_header));
+       sge->length = sizeof(struct rds_header);
+       sge->lkey = ic->i_mr->lkey;
+}
+
+/*
+ * This can be called multiple times for a given message.  The first time
+ * we see a message we map its scatterlist into the IB device so that
+ * we can provide that mapped address to the IB scatter gather entries
+ * in the IB work requests.  We translate the scatterlist into a series
+ * of work requests that fragment the message.  These work requests complete
+ * in order so we pass ownership of the message to the completion handler
+ * once we send the final fragment.
+ *
+ * The RDS core uses the c_send_lock to only enter this function once
+ * per connection.  This makes sure that the tx ring alloc/unalloc pairs
+ * don't get out of sync and confuse the ring.
+ */
+int rds_ib_xmit(struct rds_connection *conn, struct rds_message *rm,
+               unsigned int hdr_off, unsigned int sg, unsigned int off)
+{
+       struct rds_ib_connection *ic = conn->c_transport_data;
+       struct ib_device *dev = ic->i_cm_id->device;
+       struct rds_ib_send_work *send = NULL;
+       struct rds_ib_send_work *first;
+       struct rds_ib_send_work *prev;
+       struct ib_send_wr *failed_wr;
+       struct scatterlist *scat;
+       u32 pos;
+       u32 i;
+       u32 work_alloc;
+       u32 credit_alloc;
+       u32 posted;
+       u32 adv_credits = 0;
+       int send_flags = 0;
+       int sent;
+       int ret;
+       int flow_controlled = 0;
+
+       BUG_ON(off % RDS_FRAG_SIZE);
+       BUG_ON(hdr_off != 0 && hdr_off != sizeof(struct rds_header));
+
+       /* FIXME we may overallocate here */
+       if (be32_to_cpu(rm->m_inc.i_hdr.h_len) == 0)
+               i = 1;
+       else
+               i = ceil(be32_to_cpu(rm->m_inc.i_hdr.h_len), RDS_FRAG_SIZE);
+
+       work_alloc = rds_ib_ring_alloc(&ic->i_send_ring, i, &pos);
+       if (work_alloc == 0) {
+               set_bit(RDS_LL_SEND_FULL, &conn->c_flags);
+               rds_ib_stats_inc(s_ib_tx_ring_full);
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       credit_alloc = work_alloc;
+       if (ic->i_flowctl) {
+               credit_alloc = rds_ib_send_grab_credits(ic, work_alloc, &posted, 0);
+               adv_credits += posted;
+               if (credit_alloc < work_alloc) {
+                       rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc - credit_alloc);
+                       work_alloc = credit_alloc;
+                       flow_controlled++;
+               }
+               if (work_alloc == 0) {
+                       rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
+                       rds_ib_stats_inc(s_ib_tx_throttle);
+                       ret = -ENOMEM;
+                       goto out;
+               }
+       }
+
+       /* map the message the first time we see it */
+       if (ic->i_rm == NULL) {
+               /*
+               printk(KERN_NOTICE "rds_ib_xmit prep msg dport=%u flags=0x%x len=%d\n",
+                               be16_to_cpu(rm->m_inc.i_hdr.h_dport),
+                               rm->m_inc.i_hdr.h_flags,
+                               be32_to_cpu(rm->m_inc.i_hdr.h_len));
+                  */
+               if (rm->m_nents) {
+                       rm->m_count = ib_dma_map_sg(dev,
+                                        rm->m_sg, rm->m_nents, DMA_TO_DEVICE);
+                       rdsdebug("ic %p mapping rm %p: %d\n", ic, rm, rm->m_count);
+                       if (rm->m_count == 0) {
+                               rds_ib_stats_inc(s_ib_tx_sg_mapping_failure);
+                               rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
+                               ret = -ENOMEM; /* XXX ? */
+                               goto out;
+                       }
+               } else {
+                       rm->m_count = 0;
+               }
+
+               ic->i_unsignaled_wrs = rds_ib_sysctl_max_unsig_wrs;
+               ic->i_unsignaled_bytes = rds_ib_sysctl_max_unsig_bytes;
+               rds_message_addref(rm);
+               ic->i_rm = rm;
+
+               /* Finalize the header */
+               if (test_bit(RDS_MSG_ACK_REQUIRED, &rm->m_flags))
+                       rm->m_inc.i_hdr.h_flags |= RDS_FLAG_ACK_REQUIRED;
+               if (test_bit(RDS_MSG_RETRANSMITTED, &rm->m_flags))
+                       rm->m_inc.i_hdr.h_flags |= RDS_FLAG_RETRANSMITTED;
+
+               /* If it has a RDMA op, tell the peer we did it. This is
+                * used by the peer to release use-once RDMA MRs. */
+               if (rm->m_rdma_op) {
+                       struct rds_ext_header_rdma ext_hdr;
+
+                       ext_hdr.h_rdma_rkey = cpu_to_be32(rm->m_rdma_op->r_key);
+                       rds_message_add_extension(&rm->m_inc.i_hdr,
+                                       RDS_EXTHDR_RDMA, &ext_hdr, sizeof(ext_hdr));
+               }
+               if (rm->m_rdma_cookie) {
+                       rds_message_add_rdma_dest_extension(&rm->m_inc.i_hdr,
+                                       rds_rdma_cookie_key(rm->m_rdma_cookie),
+                                       rds_rdma_cookie_offset(rm->m_rdma_cookie));
+               }
+
+               /* Note - rds_ib_piggyb_ack clears the ACK_REQUIRED bit, so
+                * we should not do this unless we have a chance of at least
+                * sticking the header into the send ring. Which is why we
+                * should call rds_ib_ring_alloc first. */
+               rm->m_inc.i_hdr.h_ack = cpu_to_be64(rds_ib_piggyb_ack(ic));
+               rds_message_make_checksum(&rm->m_inc.i_hdr);
+
+               /*
+                * Update adv_credits since we reset the ACK_REQUIRED bit.
+                */
+               rds_ib_send_grab_credits(ic, 0, &posted, 1);
+               adv_credits += posted;
+               BUG_ON(adv_credits > 255);
+       } else if (ic->i_rm != rm)
+               BUG();
+
+       send = &ic->i_sends[pos];
+       first = send;
+       prev = NULL;
+       scat = &rm->m_sg[sg];
+       sent = 0;
+       i = 0;
+
+       /* Sometimes you want to put a fence between an RDMA
+        * READ and the following SEND.
+        * We could either do this all the time
+        * or when requested by the user. Right now, we let
+        * the application choose.
+        */
+       if (rm->m_rdma_op && rm->m_rdma_op->r_fence)
+               send_flags = IB_SEND_FENCE;
+
+       /*
+        * We could be copying the header into the unused tail of the page.
+        * That would need to be changed in the future when those pages might
+        * be mapped userspace pages or page cache pages.  So instead we always
+        * use a second sge and our long-lived ring of mapped headers.  We send
+        * the header after the data so that the data payload can be aligned on
+        * the receiver.
+        */
+
+       /* handle a 0-len message */
+       if (be32_to_cpu(rm->m_inc.i_hdr.h_len) == 0) {
+               rds_ib_xmit_populate_wr(ic, send, pos, 0, 0, send_flags);
+               goto add_header;
+       }
+
+       /* if there's data reference it with a chain of work reqs */
+       for (; i < work_alloc && scat != &rm->m_sg[rm->m_count]; i++) {
+               unsigned int len;
+
+               send = &ic->i_sends[pos];
+
+               len = min(RDS_FRAG_SIZE, ib_sg_dma_len(dev, scat) - off);
+               rds_ib_xmit_populate_wr(ic, send, pos,
+                               ib_sg_dma_address(dev, scat) + off, len,
+                               send_flags);
+
+               /*
+                * We want to delay signaling completions just enough to get
+                * the batching benefits but not so much that we create dead time
+                * on the wire.
+                */
+               if (ic->i_unsignaled_wrs-- == 0) {
+                       ic->i_unsignaled_wrs = rds_ib_sysctl_max_unsig_wrs;
+                       send->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
+               }
+
+               ic->i_unsignaled_bytes -= len;
+               if (ic->i_unsignaled_bytes <= 0) {
+                       ic->i_unsignaled_bytes = rds_ib_sysctl_max_unsig_bytes;
+                       send->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
+               }
+
+               /*
+                * Always signal the last one if we're stopping due to flow control.
+                */
+               if (flow_controlled && i == (work_alloc-1))
+                       send->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
+
+               rdsdebug("send %p wr %p num_sge %u next %p\n", send,
+                        &send->s_wr, send->s_wr.num_sge, send->s_wr.next);
+
+               sent += len;
+               off += len;
+               if (off == ib_sg_dma_len(dev, scat)) {
+                       scat++;
+                       off = 0;
+               }
+
+add_header:
+               /* Tack on the header after the data. The header SGE should already
+                * have been set up to point to the right header buffer. */
+               memcpy(&ic->i_send_hdrs[pos], &rm->m_inc.i_hdr, sizeof(struct rds_header));
+
+               if (0) {
+                       struct rds_header *hdr = &ic->i_send_hdrs[pos];
+
+                       printk(KERN_NOTICE "send WR dport=%u flags=0x%x len=%d\n",
+                               be16_to_cpu(hdr->h_dport),
+                               hdr->h_flags,
+                               be32_to_cpu(hdr->h_len));
+               }
+               if (adv_credits) {
+                       struct rds_header *hdr = &ic->i_send_hdrs[pos];
+
+                       /* add credit and redo the header checksum */
+                       hdr->h_credit = adv_credits;
+                       rds_message_make_checksum(hdr);
+                       adv_credits = 0;
+                       rds_ib_stats_inc(s_ib_tx_credit_updates);
+               }
+
+               if (prev)
+                       prev->s_wr.next = &send->s_wr;
+               prev = send;
+
+               pos = (pos + 1) % ic->i_send_ring.w_nr;
+       }
+
+       /* Account the RDS header in the number of bytes we sent, but just once.
+        * The caller has no concept of fragmentation. */
+       if (hdr_off == 0)
+               sent += sizeof(struct rds_header);
+
+       /* if we finished the message then send completion owns it */
+       if (scat == &rm->m_sg[rm->m_count]) {
+               prev->s_rm = ic->i_rm;
+               prev->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
+               ic->i_rm = NULL;
+       }
+
+       if (i < work_alloc) {
+               rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc - i);
+               work_alloc = i;
+       }
+       if (ic->i_flowctl && i < credit_alloc)
+               rds_ib_send_add_credits(conn, credit_alloc - i);
+
+       /* XXX need to worry about failed_wr and partial sends. */
+       failed_wr = &first->s_wr;
+       ret = ib_post_send(ic->i_cm_id->qp, &first->s_wr, &failed_wr);
+       rdsdebug("ic %p first %p (wr %p) ret %d wr %p\n", ic,
+                first, &first->s_wr, ret, failed_wr);
+       BUG_ON(failed_wr != &first->s_wr);
+       if (ret) {
+               printk(KERN_WARNING "RDS/IB: ib_post_send to %pI4 "
+                      "returned %d\n", &conn->c_faddr, ret);
+               rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
+               if (prev->s_rm) {
+                       ic->i_rm = prev->s_rm;
+                       prev->s_rm = NULL;
+               }
+               /* Finesse this later */
+               BUG();
+               goto out;
+       }
+
+       ret = sent;
+out:
+       BUG_ON(adv_credits);
+       return ret;
+}
+
+int rds_ib_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
+{
+       struct rds_ib_connection *ic = conn->c_transport_data;
+       struct rds_ib_send_work *send = NULL;
+       struct rds_ib_send_work *first;
+       struct rds_ib_send_work *prev;
+       struct ib_send_wr *failed_wr;
+       struct rds_ib_device *rds_ibdev;
+       struct scatterlist *scat;
+       unsigned long len;
+       u64 remote_addr = op->r_remote_addr;
+       u32 pos;
+       u32 work_alloc;
+       u32 i;
+       u32 j;
+       int sent;
+       int ret;
+       int num_sge;
+
+       rds_ibdev = ib_get_client_data(ic->i_cm_id->device, &rds_ib_client);
+
+       /* map the message the first time we see it */
+       if (!op->r_mapped) {
+               op->r_count = ib_dma_map_sg(ic->i_cm_id->device,
+                                       op->r_sg, op->r_nents, (op->r_write) ?
+                                       DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               rdsdebug("ic %p mapping op %p: %d\n", ic, op, op->r_count);
+               if (op->r_count == 0) {
+                       rds_ib_stats_inc(s_ib_tx_sg_mapping_failure);
+                       ret = -ENOMEM; /* XXX ? */
+                       goto out;
+               }
+
+               op->r_mapped = 1;
+       }
+
+       /*
+        * Instead of knowing how to return a partial rdma read/write we insist that there
+        * be enough work requests to send the entire message.
+        */
+       i = ceil(op->r_count, rds_ibdev->max_sge);
+
+       work_alloc = rds_ib_ring_alloc(&ic->i_send_ring, i, &pos);
+       if (work_alloc != i) {
+               rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
+               rds_ib_stats_inc(s_ib_tx_ring_full);
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       send = &ic->i_sends[pos];
+       first = send;
+       prev = NULL;
+       scat = &op->r_sg[0];
+       sent = 0;
+       num_sge = op->r_count;
+
+       for (i = 0; i < work_alloc && scat != &op->r_sg[op->r_count]; i++) {
+               send->s_wr.send_flags = 0;
+               send->s_queued = jiffies;
+               /*
+                * We want to delay signaling completions just enough to get
+                * the batching benefits but not so much that we create dead time on the wire.
+                */
+               if (ic->i_unsignaled_wrs-- == 0) {
+                       ic->i_unsignaled_wrs = rds_ib_sysctl_max_unsig_wrs;
+                       send->s_wr.send_flags = IB_SEND_SIGNALED;
+               }
+
+               send->s_wr.opcode = op->r_write ? IB_WR_RDMA_WRITE : IB_WR_RDMA_READ;
+               send->s_wr.wr.rdma.remote_addr = remote_addr;
+               send->s_wr.wr.rdma.rkey = op->r_key;
+               send->s_op = op;
+
+               if (num_sge > rds_ibdev->max_sge) {
+                       send->s_wr.num_sge = rds_ibdev->max_sge;
+                       num_sge -= rds_ibdev->max_sge;
+               } else {
+                       send->s_wr.num_sge = num_sge;
+               }
+
+               send->s_wr.next = NULL;
+
+               if (prev)
+                       prev->s_wr.next = &send->s_wr;
+
+               for (j = 0; j < send->s_wr.num_sge && scat != &op->r_sg[op->r_count]; j++) {
+                       len = ib_sg_dma_len(ic->i_cm_id->device, scat);
+                       send->s_sge[j].addr =
+                                ib_sg_dma_address(ic->i_cm_id->device, scat);
+                       send->s_sge[j].length = len;
+                       send->s_sge[j].lkey = ic->i_mr->lkey;
+
+                       sent += len;
+                       rdsdebug("ic %p sent %d remote_addr %llu\n", ic, sent, remote_addr);
+
+                       remote_addr += len;
+                       scat++;
+               }
+
+               rdsdebug("send %p wr %p num_sge %u next %p\n", send,
+                       &send->s_wr, send->s_wr.num_sge, send->s_wr.next);
+
+               prev = send;
+               if (++send == &ic->i_sends[ic->i_send_ring.w_nr])
+                       send = ic->i_sends;
+       }
+
+       /* if we finished the message then send completion owns it */
+       if (scat == &op->r_sg[op->r_count])
+               prev->s_wr.send_flags = IB_SEND_SIGNALED;
+
+       if (i < work_alloc) {
+               rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc - i);
+               work_alloc = i;
+       }
+
+       failed_wr = &first->s_wr;
+       ret = ib_post_send(ic->i_cm_id->qp, &first->s_wr, &failed_wr);
+       rdsdebug("ic %p first %p (wr %p) ret %d wr %p\n", ic,
+                first, &first->s_wr, ret, failed_wr);
+       BUG_ON(failed_wr != &first->s_wr);
+       if (ret) {
+               printk(KERN_WARNING "RDS/IB: rdma ib_post_send to %pI4 "
+                      "returned %d\n", &conn->c_faddr, ret);
+               rds_ib_ring_unalloc(&ic->i_send_ring, work_alloc);
+               goto out;
+       }
+
+       if (unlikely(failed_wr != &first->s_wr)) {
+               printk(KERN_WARNING "RDS/IB: ib_post_send() rc=%d, but failed_wqe updated!\n", ret);
+               BUG_ON(failed_wr != &first->s_wr);
+       }
+
+
+out:
+       return ret;
+}
+
+void rds_ib_xmit_complete(struct rds_connection *conn)
+{
+       struct rds_ib_connection *ic = conn->c_transport_data;
+
+       /* We may have a pending ACK or window update we were unable
+        * to send previously (due to flow control). Try again. */
+       rds_ib_attempt_ack(ic);
+}
diff --git a/net/rds/ib_stats.c b/net/rds/ib_stats.c
new file mode 100644 (file)
index 0000000..02e3e3d
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/percpu.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+
+#include "rds.h"
+#include "ib.h"
+
+DEFINE_PER_CPU(struct rds_ib_statistics, rds_ib_stats) ____cacheline_aligned;
+
+static char *rds_ib_stat_names[] = {
+       "ib_connect_raced",
+       "ib_listen_closed_stale",
+       "ib_tx_cq_call",
+       "ib_tx_cq_event",
+       "ib_tx_ring_full",
+       "ib_tx_throttle",
+       "ib_tx_sg_mapping_failure",
+       "ib_tx_stalled",
+       "ib_tx_credit_updates",
+       "ib_rx_cq_call",
+       "ib_rx_cq_event",
+       "ib_rx_ring_empty",
+       "ib_rx_refill_from_cq",
+       "ib_rx_refill_from_thread",
+       "ib_rx_alloc_limit",
+       "ib_rx_credit_updates",
+       "ib_ack_sent",
+       "ib_ack_send_failure",
+       "ib_ack_send_delayed",
+       "ib_ack_send_piggybacked",
+       "ib_ack_received",
+       "ib_rdma_mr_alloc",
+       "ib_rdma_mr_free",
+       "ib_rdma_mr_used",
+       "ib_rdma_mr_pool_flush",
+       "ib_rdma_mr_pool_wait",
+       "ib_rdma_mr_pool_depleted",
+};
+
+unsigned int rds_ib_stats_info_copy(struct rds_info_iterator *iter,
+                                   unsigned int avail)
+{
+       struct rds_ib_statistics stats = {0, };
+       uint64_t *src;
+       uint64_t *sum;
+       size_t i;
+       int cpu;
+
+       if (avail < ARRAY_SIZE(rds_ib_stat_names))
+               goto out;
+
+       for_each_online_cpu(cpu) {
+               src = (uint64_t *)&(per_cpu(rds_ib_stats, cpu));
+               sum = (uint64_t *)&stats;
+               for (i = 0; i < sizeof(stats) / sizeof(uint64_t); i++)
+                       *(sum++) += *(src++);
+       }
+
+       rds_stats_info_copy(iter, (uint64_t *)&stats, rds_ib_stat_names,
+                           ARRAY_SIZE(rds_ib_stat_names));
+out:
+       return ARRAY_SIZE(rds_ib_stat_names);
+}
diff --git a/net/rds/ib_sysctl.c b/net/rds/ib_sysctl.c
new file mode 100644 (file)
index 0000000..d87830d
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+
+#include "ib.h"
+
+static struct ctl_table_header *rds_ib_sysctl_hdr;
+
+unsigned long rds_ib_sysctl_max_send_wr = RDS_IB_DEFAULT_SEND_WR;
+unsigned long rds_ib_sysctl_max_recv_wr = RDS_IB_DEFAULT_RECV_WR;
+unsigned long rds_ib_sysctl_max_recv_allocation = (128 * 1024 * 1024) / RDS_FRAG_SIZE;
+static unsigned long rds_ib_sysctl_max_wr_min = 1;
+/* hardware will fail CQ creation long before this */
+static unsigned long rds_ib_sysctl_max_wr_max = (u32)~0;
+
+unsigned long rds_ib_sysctl_max_unsig_wrs = 16;
+static unsigned long rds_ib_sysctl_max_unsig_wr_min = 1;
+static unsigned long rds_ib_sysctl_max_unsig_wr_max = 64;
+
+unsigned long rds_ib_sysctl_max_unsig_bytes = (16 << 20);
+static unsigned long rds_ib_sysctl_max_unsig_bytes_min = 1;
+static unsigned long rds_ib_sysctl_max_unsig_bytes_max = ~0UL;
+
+unsigned int rds_ib_sysctl_flow_control = 1;
+
+ctl_table rds_ib_sysctl_table[] = {
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "max_send_wr",
+               .data           = &rds_ib_sysctl_max_send_wr,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &proc_doulongvec_minmax,
+               .extra1         = &rds_ib_sysctl_max_wr_min,
+               .extra2         = &rds_ib_sysctl_max_wr_max,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "max_recv_wr",
+               .data           = &rds_ib_sysctl_max_recv_wr,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &proc_doulongvec_minmax,
+               .extra1         = &rds_ib_sysctl_max_wr_min,
+               .extra2         = &rds_ib_sysctl_max_wr_max,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "max_unsignaled_wr",
+               .data           = &rds_ib_sysctl_max_unsig_wrs,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &proc_doulongvec_minmax,
+               .extra1         = &rds_ib_sysctl_max_unsig_wr_min,
+               .extra2         = &rds_ib_sysctl_max_unsig_wr_max,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "max_unsignaled_bytes",
+               .data           = &rds_ib_sysctl_max_unsig_bytes,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &proc_doulongvec_minmax,
+               .extra1         = &rds_ib_sysctl_max_unsig_bytes_min,
+               .extra2         = &rds_ib_sysctl_max_unsig_bytes_max,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "max_recv_allocation",
+               .data           = &rds_ib_sysctl_max_recv_allocation,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &proc_doulongvec_minmax,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "flow_control",
+               .data           = &rds_ib_sysctl_flow_control,
+               .maxlen         = sizeof(rds_ib_sysctl_flow_control),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+       { .ctl_name = 0}
+};
+
+static struct ctl_path rds_ib_sysctl_path[] = {
+       { .procname = "net", .ctl_name = CTL_NET, },
+       { .procname = "rds", .ctl_name = CTL_UNNUMBERED, },
+       { .procname = "ib", .ctl_name = CTL_UNNUMBERED, },
+       { }
+};
+
+void rds_ib_sysctl_exit(void)
+{
+       if (rds_ib_sysctl_hdr)
+               unregister_sysctl_table(rds_ib_sysctl_hdr);
+}
+
+int __init rds_ib_sysctl_init(void)
+{
+       rds_ib_sysctl_hdr = register_sysctl_paths(rds_ib_sysctl_path, rds_ib_sysctl_table);
+       if (rds_ib_sysctl_hdr == NULL)
+               return -ENOMEM;
+       return 0;
+}
diff --git a/net/rds/info.c b/net/rds/info.c
new file mode 100644 (file)
index 0000000..1d88553
--- /dev/null
@@ -0,0 +1,241 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/percpu.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+
+#include "rds.h"
+
+/*
+ * This file implements a getsockopt() call which copies a set of fixed
+ * sized structs into a user-specified buffer as a means of providing
+ * read-only information about RDS.
+ *
+ * For a given information source there are a given number of fixed sized
+ * structs at a given time.  The structs are only copied if the user-specified
+ * buffer is big enough.  The destination pages that make up the buffer
+ * are pinned for the duration of the copy.
+ *
+ * This gives us the following benefits:
+ *
+ * - simple implementation, no copy "position" across multiple calls
+ * - consistent snapshot of an info source
+ * - atomic copy works well with whatever locking info source has
+ * - one portable tool to get rds info across implementations
+ * - long-lived tool can get info without allocating
+ *
+ * at the following costs:
+ *
+ * - info source copy must be pinned, may be "large"
+ */
+
+struct rds_info_iterator {
+       struct page **pages;
+       void *addr;
+       unsigned long offset;
+};
+
+static DEFINE_SPINLOCK(rds_info_lock);
+static rds_info_func rds_info_funcs[RDS_INFO_LAST - RDS_INFO_FIRST + 1];
+
+void rds_info_register_func(int optname, rds_info_func func)
+{
+       int offset = optname - RDS_INFO_FIRST;
+
+       BUG_ON(optname < RDS_INFO_FIRST || optname > RDS_INFO_LAST);
+
+       spin_lock(&rds_info_lock);
+       BUG_ON(rds_info_funcs[offset] != NULL);
+       rds_info_funcs[offset] = func;
+       spin_unlock(&rds_info_lock);
+}
+
+void rds_info_deregister_func(int optname, rds_info_func func)
+{
+       int offset = optname - RDS_INFO_FIRST;
+
+       BUG_ON(optname < RDS_INFO_FIRST || optname > RDS_INFO_LAST);
+
+       spin_lock(&rds_info_lock);
+       BUG_ON(rds_info_funcs[offset] != func);
+       rds_info_funcs[offset] = NULL;
+       spin_unlock(&rds_info_lock);
+}
+
+/*
+ * Typically we hold an atomic kmap across multiple rds_info_copy() calls
+ * because the kmap is so expensive.  This must be called before using blocking
+ * operations while holding the mapping and as the iterator is torn down.
+ */
+void rds_info_iter_unmap(struct rds_info_iterator *iter)
+{
+       if (iter->addr != NULL) {
+               kunmap_atomic(iter->addr, KM_USER0);
+               iter->addr = NULL;
+       }
+}
+
+/*
+ * get_user_pages() called flush_dcache_page() on the pages for us.
+ */
+void rds_info_copy(struct rds_info_iterator *iter, void *data,
+                  unsigned long bytes)
+{
+       unsigned long this;
+
+       while (bytes) {
+               if (iter->addr == NULL)
+                       iter->addr = kmap_atomic(*iter->pages, KM_USER0);
+
+               this = min(bytes, PAGE_SIZE - iter->offset);
+
+               rdsdebug("page %p addr %p offset %lu this %lu data %p "
+                         "bytes %lu\n", *iter->pages, iter->addr,
+                         iter->offset, this, data, bytes);
+
+               memcpy(iter->addr + iter->offset, data, this);
+
+               data += this;
+               bytes -= this;
+               iter->offset += this;
+
+               if (iter->offset == PAGE_SIZE) {
+                       kunmap_atomic(iter->addr, KM_USER0);
+                       iter->addr = NULL;
+                       iter->offset = 0;
+                       iter->pages++;
+               }
+       }
+}
+
+/*
+ * @optval points to the userspace buffer that the information snapshot
+ * will be copied into.
+ *
+ * @optlen on input is the size of the buffer in userspace.  @optlen
+ * on output is the size of the requested snapshot in bytes.
+ *
+ * This function returns -errno if there is a failure, particularly -ENOSPC
+ * if the given userspace buffer was not large enough to fit the snapshot.
+ * On success it returns the positive number of bytes of each array element
+ * in the snapshot.
+ */
+int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval,
+                       int __user *optlen)
+{
+       struct rds_info_iterator iter;
+       struct rds_info_lengths lens;
+       unsigned long nr_pages = 0;
+       unsigned long start;
+       unsigned long i;
+       rds_info_func func;
+       struct page **pages = NULL;
+       int ret;
+       int len;
+       int total;
+
+       if (get_user(len, optlen)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       /* check for all kinds of wrapping and the like */
+       start = (unsigned long)optval;
+       if (len < 0 || len + PAGE_SIZE - 1 < len || start + len < start) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       /* a 0 len call is just trying to probe its length */
+       if (len == 0)
+               goto call_func;
+
+       nr_pages = (PAGE_ALIGN(start + len) - (start & PAGE_MASK))
+                       >> PAGE_SHIFT;
+
+       pages = kmalloc(nr_pages * sizeof(struct page *), GFP_KERNEL);
+       if (pages == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       down_read(&current->mm->mmap_sem);
+       ret = get_user_pages(current, current->mm, start, nr_pages, 1, 0,
+                            pages, NULL);
+       up_read(&current->mm->mmap_sem);
+       if (ret != nr_pages) {
+               if (ret > 0)
+                       nr_pages = ret;
+               else
+                       nr_pages = 0;
+               ret = -EAGAIN; /* XXX ? */
+               goto out;
+       }
+
+       rdsdebug("len %d nr_pages %lu\n", len, nr_pages);
+
+call_func:
+       func = rds_info_funcs[optname - RDS_INFO_FIRST];
+       if (func == NULL) {
+               ret = -ENOPROTOOPT;
+               goto out;
+       }
+
+       iter.pages = pages;
+       iter.addr = NULL;
+       iter.offset = start & (PAGE_SIZE - 1);
+
+       func(sock, len, &iter, &lens);
+       BUG_ON(lens.each == 0);
+
+       total = lens.nr * lens.each;
+
+       rds_info_iter_unmap(&iter);
+
+       if (total > len) {
+               len = total;
+               ret = -ENOSPC;
+       } else {
+               len = total;
+               ret = lens.each;
+       }
+
+       if (put_user(len, optlen))
+               ret = -EFAULT;
+
+out:
+       for (i = 0; pages != NULL && i < nr_pages; i++)
+               put_page(pages[i]);
+       kfree(pages);
+
+       return ret;
+}
diff --git a/net/rds/info.h b/net/rds/info.h
new file mode 100644 (file)
index 0000000..b6c052c
--- /dev/null
@@ -0,0 +1,30 @@
+#ifndef _RDS_INFO_H
+#define _RDS_INFO_H
+
+struct rds_info_lengths {
+       unsigned int    nr;
+       unsigned int    each;
+};
+
+struct rds_info_iterator;
+
+/*
+ * These functions must fill in the fields of @lens to reflect the size
+ * of the available info source.  If the snapshot fits in @len then it
+ * should be copied using @iter.  The caller will deduce if it was copied
+ * or not by comparing the lengths.
+ */
+typedef void (*rds_info_func)(struct socket *sock, unsigned int len,
+                             struct rds_info_iterator *iter,
+                             struct rds_info_lengths *lens);
+
+void rds_info_register_func(int optname, rds_info_func func);
+void rds_info_deregister_func(int optname, rds_info_func func);
+int rds_info_getsockopt(struct socket *sock, int optname, char __user *optval,
+                       int __user *optlen);
+void rds_info_copy(struct rds_info_iterator *iter, void *data,
+                  unsigned long bytes);
+void rds_info_iter_unmap(struct rds_info_iterator *iter);
+
+
+#endif
diff --git a/net/rds/iw.c b/net/rds/iw.c
new file mode 100644 (file)
index 0000000..1b56905
--- /dev/null
@@ -0,0 +1,333 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/in.h>
+#include <linux/if.h>
+#include <linux/netdevice.h>
+#include <linux/inetdevice.h>
+#include <linux/if_arp.h>
+#include <linux/delay.h>
+
+#include "rds.h"
+#include "iw.h"
+
+unsigned int fastreg_pool_size = RDS_FASTREG_POOL_SIZE;
+unsigned int fastreg_message_size = RDS_FASTREG_SIZE + 1; /* +1 allows for unaligned MRs */
+
+module_param(fastreg_pool_size, int, 0444);
+MODULE_PARM_DESC(fastreg_pool_size, " Max number of fastreg MRs per device");
+module_param(fastreg_message_size, int, 0444);
+MODULE_PARM_DESC(fastreg_message_size, " Max size of a RDMA transfer (fastreg MRs)");
+
+struct list_head rds_iw_devices;
+
+DEFINE_SPINLOCK(iw_nodev_conns_lock);
+LIST_HEAD(iw_nodev_conns);
+
+void rds_iw_add_one(struct ib_device *device)
+{
+       struct rds_iw_device *rds_iwdev;
+       struct ib_device_attr *dev_attr;
+
+       /* Only handle iwarp devices */
+       if (device->node_type != RDMA_NODE_RNIC)
+               return;
+
+       dev_attr = kmalloc(sizeof *dev_attr, GFP_KERNEL);
+       if (!dev_attr)
+               return;
+
+       if (ib_query_device(device, dev_attr)) {
+               rdsdebug("Query device failed for %s\n", device->name);
+               goto free_attr;
+       }
+
+       rds_iwdev = kmalloc(sizeof *rds_iwdev, GFP_KERNEL);
+       if (!rds_iwdev)
+               goto free_attr;
+
+       spin_lock_init(&rds_iwdev->spinlock);
+
+       rds_iwdev->dma_local_lkey = !!(dev_attr->device_cap_flags & IB_DEVICE_LOCAL_DMA_LKEY);
+       rds_iwdev->max_wrs = dev_attr->max_qp_wr;
+       rds_iwdev->max_sge = min(dev_attr->max_sge, RDS_IW_MAX_SGE);
+
+       rds_iwdev->page_shift = max(PAGE_SHIFT, ffs(dev_attr->page_size_cap) - 1);
+
+       rds_iwdev->dev = device;
+       rds_iwdev->pd = ib_alloc_pd(device);
+       if (IS_ERR(rds_iwdev->pd))
+               goto free_dev;
+
+       if (!rds_iwdev->dma_local_lkey) {
+               if (device->node_type != RDMA_NODE_RNIC) {
+                       rds_iwdev->mr = ib_get_dma_mr(rds_iwdev->pd,
+                                               IB_ACCESS_LOCAL_WRITE);
+               } else {
+                       rds_iwdev->mr = ib_get_dma_mr(rds_iwdev->pd,
+                                               IB_ACCESS_REMOTE_READ |
+                                               IB_ACCESS_REMOTE_WRITE |
+                                               IB_ACCESS_LOCAL_WRITE);
+               }
+               if (IS_ERR(rds_iwdev->mr))
+                       goto err_pd;
+       } else
+               rds_iwdev->mr = NULL;
+
+       rds_iwdev->mr_pool = rds_iw_create_mr_pool(rds_iwdev);
+       if (IS_ERR(rds_iwdev->mr_pool)) {
+               rds_iwdev->mr_pool = NULL;
+               goto err_mr;
+       }
+
+       INIT_LIST_HEAD(&rds_iwdev->cm_id_list);
+       INIT_LIST_HEAD(&rds_iwdev->conn_list);
+       list_add_tail(&rds_iwdev->list, &rds_iw_devices);
+
+       ib_set_client_data(device, &rds_iw_client, rds_iwdev);
+
+       goto free_attr;
+
+err_mr:
+       if (rds_iwdev->mr)
+               ib_dereg_mr(rds_iwdev->mr);
+err_pd:
+       ib_dealloc_pd(rds_iwdev->pd);
+free_dev:
+       kfree(rds_iwdev);
+free_attr:
+       kfree(dev_attr);
+}
+
+void rds_iw_remove_one(struct ib_device *device)
+{
+       struct rds_iw_device *rds_iwdev;
+       struct rds_iw_cm_id *i_cm_id, *next;
+
+       rds_iwdev = ib_get_client_data(device, &rds_iw_client);
+       if (!rds_iwdev)
+               return;
+
+       spin_lock_irq(&rds_iwdev->spinlock);
+       list_for_each_entry_safe(i_cm_id, next, &rds_iwdev->cm_id_list, list) {
+               list_del(&i_cm_id->list);
+               kfree(i_cm_id);
+       }
+       spin_unlock_irq(&rds_iwdev->spinlock);
+
+       rds_iw_remove_conns(rds_iwdev);
+
+       if (rds_iwdev->mr_pool)
+               rds_iw_destroy_mr_pool(rds_iwdev->mr_pool);
+
+       if (rds_iwdev->mr)
+               ib_dereg_mr(rds_iwdev->mr);
+
+       while (ib_dealloc_pd(rds_iwdev->pd)) {
+               rdsdebug("Failed to dealloc pd %p\n", rds_iwdev->pd);
+               msleep(1);
+       }
+
+       list_del(&rds_iwdev->list);
+       kfree(rds_iwdev);
+}
+
+struct ib_client rds_iw_client = {
+       .name   = "rds_iw",
+       .add    = rds_iw_add_one,
+       .remove = rds_iw_remove_one
+};
+
+static int rds_iw_conn_info_visitor(struct rds_connection *conn,
+                                   void *buffer)
+{
+       struct rds_info_rdma_connection *iinfo = buffer;
+       struct rds_iw_connection *ic;
+
+       /* We will only ever look at IB transports */
+       if (conn->c_trans != &rds_iw_transport)
+               return 0;
+
+       iinfo->src_addr = conn->c_laddr;
+       iinfo->dst_addr = conn->c_faddr;
+
+       memset(&iinfo->src_gid, 0, sizeof(iinfo->src_gid));
+       memset(&iinfo->dst_gid, 0, sizeof(iinfo->dst_gid));
+       if (rds_conn_state(conn) == RDS_CONN_UP) {
+               struct rds_iw_device *rds_iwdev;
+               struct rdma_dev_addr *dev_addr;
+
+               ic = conn->c_transport_data;
+               dev_addr = &ic->i_cm_id->route.addr.dev_addr;
+
+               ib_addr_get_sgid(dev_addr, (union ib_gid *) &iinfo->src_gid);
+               ib_addr_get_dgid(dev_addr, (union ib_gid *) &iinfo->dst_gid);
+
+               rds_iwdev = ib_get_client_data(ic->i_cm_id->device, &rds_iw_client);
+               iinfo->max_send_wr = ic->i_send_ring.w_nr;
+               iinfo->max_recv_wr = ic->i_recv_ring.w_nr;
+               iinfo->max_send_sge = rds_iwdev->max_sge;
+               rds_iw_get_mr_info(rds_iwdev, iinfo);
+       }
+       return 1;
+}
+
+static void rds_iw_ic_info(struct socket *sock, unsigned int len,
+                          struct rds_info_iterator *iter,
+                          struct rds_info_lengths *lens)
+{
+       rds_for_each_conn_info(sock, len, iter, lens,
+                               rds_iw_conn_info_visitor,
+                               sizeof(struct rds_info_rdma_connection));
+}
+
+
+/*
+ * Early RDS/IB was built to only bind to an address if there is an IPoIB
+ * device with that address set.
+ *
+ * If it were me, I'd advocate for something more flexible.  Sending and
+ * receiving should be device-agnostic.  Transports would try and maintain
+ * connections between peers who have messages queued.  Userspace would be
+ * allowed to influence which paths have priority.  We could call userspace
+ * asserting this policy "routing".
+ */
+static int rds_iw_laddr_check(__be32 addr)
+{
+       int ret;
+       struct rdma_cm_id *cm_id;
+       struct sockaddr_in sin;
+
+       /* Create a CMA ID and try to bind it. This catches both
+        * IB and iWARP capable NICs.
+        */
+       cm_id = rdma_create_id(NULL, NULL, RDMA_PS_TCP);
+       if (!cm_id)
+               return -EADDRNOTAVAIL;
+
+       memset(&sin, 0, sizeof(sin));
+       sin.sin_family = AF_INET;
+       sin.sin_addr.s_addr = addr;
+
+       /* rdma_bind_addr will only succeed for IB & iWARP devices */
+       ret = rdma_bind_addr(cm_id, (struct sockaddr *)&sin);
+       /* due to this, we will claim to support IB devices unless we
+          check node_type. */
+       if (ret || cm_id->device->node_type != RDMA_NODE_RNIC)
+               ret = -EADDRNOTAVAIL;
+
+       rdsdebug("addr %pI4 ret %d node type %d\n",
+               &addr, ret,
+               cm_id->device ? cm_id->device->node_type : -1);
+
+       rdma_destroy_id(cm_id);
+
+       return ret;
+}
+
+void rds_iw_exit(void)
+{
+       rds_info_deregister_func(RDS_INFO_IWARP_CONNECTIONS, rds_iw_ic_info);
+       rds_iw_remove_nodev_conns();
+       ib_unregister_client(&rds_iw_client);
+       rds_iw_sysctl_exit();
+       rds_iw_recv_exit();
+       rds_trans_unregister(&rds_iw_transport);
+}
+
+struct rds_transport rds_iw_transport = {
+       .laddr_check            = rds_iw_laddr_check,
+       .xmit_complete          = rds_iw_xmit_complete,
+       .xmit                   = rds_iw_xmit,
+       .xmit_cong_map          = NULL,
+       .xmit_rdma              = rds_iw_xmit_rdma,
+       .recv                   = rds_iw_recv,
+       .conn_alloc             = rds_iw_conn_alloc,
+       .conn_free              = rds_iw_conn_free,
+       .conn_connect           = rds_iw_conn_connect,
+       .conn_shutdown          = rds_iw_conn_shutdown,
+       .inc_copy_to_user       = rds_iw_inc_copy_to_user,
+       .inc_purge              = rds_iw_inc_purge,
+       .inc_free               = rds_iw_inc_free,
+       .cm_initiate_connect    = rds_iw_cm_initiate_connect,
+       .cm_handle_connect      = rds_iw_cm_handle_connect,
+       .cm_connect_complete    = rds_iw_cm_connect_complete,
+       .stats_info_copy        = rds_iw_stats_info_copy,
+       .exit                   = rds_iw_exit,
+       .get_mr                 = rds_iw_get_mr,
+       .sync_mr                = rds_iw_sync_mr,
+       .free_mr                = rds_iw_free_mr,
+       .flush_mrs              = rds_iw_flush_mrs,
+       .t_owner                = THIS_MODULE,
+       .t_name                 = "iwarp",
+       .t_prefer_loopback      = 1,
+};
+
+int __init rds_iw_init(void)
+{
+       int ret;
+
+       INIT_LIST_HEAD(&rds_iw_devices);
+
+       ret = ib_register_client(&rds_iw_client);
+       if (ret)
+               goto out;
+
+       ret = rds_iw_sysctl_init();
+       if (ret)
+               goto out_ibreg;
+
+       ret = rds_iw_recv_init();
+       if (ret)
+               goto out_sysctl;
+
+       ret = rds_trans_register(&rds_iw_transport);
+       if (ret)
+               goto out_recv;
+
+       rds_info_register_func(RDS_INFO_IWARP_CONNECTIONS, rds_iw_ic_info);
+
+       goto out;
+
+out_recv:
+       rds_iw_recv_exit();
+out_sysctl:
+       rds_iw_sysctl_exit();
+out_ibreg:
+       ib_unregister_client(&rds_iw_client);
+out:
+       return ret;
+}
+
+MODULE_LICENSE("GPL");
+
diff --git a/net/rds/iw.h b/net/rds/iw.h
new file mode 100644 (file)
index 0000000..0ddda34
--- /dev/null
@@ -0,0 +1,395 @@
+#ifndef _RDS_IW_H
+#define _RDS_IW_H
+
+#include <rdma/ib_verbs.h>
+#include <rdma/rdma_cm.h>
+#include "rds.h"
+#include "rdma_transport.h"
+
+#define RDS_FASTREG_SIZE               20
+#define RDS_FASTREG_POOL_SIZE          2048
+
+#define RDS_IW_MAX_SGE                 8
+#define RDS_IW_RECV_SGE                2
+
+#define RDS_IW_DEFAULT_RECV_WR         1024
+#define RDS_IW_DEFAULT_SEND_WR         256
+
+#define RDS_IW_SUPPORTED_PROTOCOLS     0x00000003      /* minor versions supported */
+
+extern struct list_head rds_iw_devices;
+
+/*
+ * IB posts RDS_FRAG_SIZE fragments of pages to the receive queues to
+ * try and minimize the amount of memory tied up both the device and
+ * socket receive queues.
+ */
+/* page offset of the final full frag that fits in the page */
+#define RDS_PAGE_LAST_OFF (((PAGE_SIZE  / RDS_FRAG_SIZE) - 1) * RDS_FRAG_SIZE)
+struct rds_page_frag {
+       struct list_head        f_item;
+       struct page             *f_page;
+       unsigned long           f_offset;
+       dma_addr_t              f_mapped;
+};
+
+struct rds_iw_incoming {
+       struct list_head        ii_frags;
+       struct rds_incoming     ii_inc;
+};
+
+struct rds_iw_connect_private {
+       /* Add new fields at the end, and don't permute existing fields. */
+       __be32                  dp_saddr;
+       __be32                  dp_daddr;
+       u8                      dp_protocol_major;
+       u8                      dp_protocol_minor;
+       __be16                  dp_protocol_minor_mask; /* bitmask */
+       __be32                  dp_reserved1;
+       __be64                  dp_ack_seq;
+       __be32                  dp_credit;              /* non-zero enables flow ctl */
+};
+
+struct rds_iw_scatterlist {
+       struct scatterlist      *list;
+       unsigned int            len;
+       int                     dma_len;
+       unsigned int            dma_npages;
+       unsigned int            bytes;
+};
+
+struct rds_iw_mapping {
+       spinlock_t              m_lock; /* protect the mapping struct */
+       struct list_head        m_list;
+       struct rds_iw_mr        *m_mr;
+       uint32_t                m_rkey;
+       struct rds_iw_scatterlist m_sg;
+};
+
+struct rds_iw_send_work {
+       struct rds_message      *s_rm;
+
+       /* We should really put these into a union: */
+       struct rds_rdma_op      *s_op;
+       struct rds_iw_mapping   *s_mapping;
+       struct ib_mr            *s_mr;
+       struct ib_fast_reg_page_list *s_page_list;
+       unsigned char           s_remap_count;
+
+       struct ib_send_wr       s_wr;
+       struct ib_sge           s_sge[RDS_IW_MAX_SGE];
+       unsigned long           s_queued;
+};
+
+struct rds_iw_recv_work {
+       struct rds_iw_incoming  *r_iwinc;
+       struct rds_page_frag    *r_frag;
+       struct ib_recv_wr       r_wr;
+       struct ib_sge           r_sge[2];
+};
+
+struct rds_iw_work_ring {
+       u32             w_nr;
+       u32             w_alloc_ptr;
+       u32             w_alloc_ctr;
+       u32             w_free_ptr;
+       atomic_t        w_free_ctr;
+};
+
+struct rds_iw_device;
+
+struct rds_iw_connection {
+
+       struct list_head        iw_node;
+       struct rds_iw_device    *rds_iwdev;
+       struct rds_connection   *conn;
+
+       /* alphabet soup, IBTA style */
+       struct rdma_cm_id       *i_cm_id;
+       struct ib_pd            *i_pd;
+       struct ib_mr            *i_mr;
+       struct ib_cq            *i_send_cq;
+       struct ib_cq            *i_recv_cq;
+
+       /* tx */
+       struct rds_iw_work_ring i_send_ring;
+       struct rds_message      *i_rm;
+       struct rds_header       *i_send_hdrs;
+       u64                     i_send_hdrs_dma;
+       struct rds_iw_send_work *i_sends;
+
+       /* rx */
+       struct mutex            i_recv_mutex;
+       struct rds_iw_work_ring i_recv_ring;
+       struct rds_iw_incoming  *i_iwinc;
+       u32                     i_recv_data_rem;
+       struct rds_header       *i_recv_hdrs;
+       u64                     i_recv_hdrs_dma;
+       struct rds_iw_recv_work *i_recvs;
+       struct rds_page_frag    i_frag;
+       u64                     i_ack_recv;     /* last ACK received */
+
+       /* sending acks */
+       unsigned long           i_ack_flags;
+       u64                     i_ack_next;     /* next ACK to send */
+       struct rds_header       *i_ack;
+       struct ib_send_wr       i_ack_wr;
+       struct ib_sge           i_ack_sge;
+       u64                     i_ack_dma;
+       unsigned long           i_ack_queued;
+
+       /* Flow control related information
+        *
+        * Our algorithm uses a pair variables that we need to access
+        * atomically - one for the send credits, and one posted
+        * recv credits we need to transfer to remote.
+        * Rather than protect them using a slow spinlock, we put both into
+        * a single atomic_t and update it using cmpxchg
+        */
+       atomic_t                i_credits;
+
+       /* Protocol version specific information */
+       unsigned int            i_flowctl:1;    /* enable/disable flow ctl */
+       unsigned int            i_dma_local_lkey:1;
+       unsigned int            i_fastreg_posted:1; /* fastreg posted on this connection */
+       /* Batched completions */
+       unsigned int            i_unsignaled_wrs;
+       long                    i_unsignaled_bytes;
+};
+
+/* This assumes that atomic_t is at least 32 bits */
+#define IB_GET_SEND_CREDITS(v) ((v) & 0xffff)
+#define IB_GET_POST_CREDITS(v) ((v) >> 16)
+#define IB_SET_SEND_CREDITS(v) ((v) & 0xffff)
+#define IB_SET_POST_CREDITS(v) ((v) << 16)
+
+struct rds_iw_cm_id {
+       struct list_head        list;
+       struct rdma_cm_id       *cm_id;
+};
+
+struct rds_iw_device {
+       struct list_head        list;
+       struct list_head        cm_id_list;
+       struct list_head        conn_list;
+       struct ib_device        *dev;
+       struct ib_pd            *pd;
+       struct ib_mr            *mr;
+       struct rds_iw_mr_pool   *mr_pool;
+       int                     page_shift;
+       int                     max_sge;
+       unsigned int            max_wrs;
+       unsigned int            dma_local_lkey:1;
+       spinlock_t              spinlock;       /* protect the above */
+};
+
+/* bits for i_ack_flags */
+#define IB_ACK_IN_FLIGHT       0
+#define IB_ACK_REQUESTED       1
+
+/* Magic WR_ID for ACKs */
+#define RDS_IW_ACK_WR_ID       ((u64)0xffffffffffffffffULL)
+#define RDS_IW_FAST_REG_WR_ID  ((u64)0xefefefefefefefefULL)
+#define RDS_IW_LOCAL_INV_WR_ID ((u64)0xdfdfdfdfdfdfdfdfULL)
+
+struct rds_iw_statistics {
+       uint64_t        s_iw_connect_raced;
+       uint64_t        s_iw_listen_closed_stale;
+       uint64_t        s_iw_tx_cq_call;
+       uint64_t        s_iw_tx_cq_event;
+       uint64_t        s_iw_tx_ring_full;
+       uint64_t        s_iw_tx_throttle;
+       uint64_t        s_iw_tx_sg_mapping_failure;
+       uint64_t        s_iw_tx_stalled;
+       uint64_t        s_iw_tx_credit_updates;
+       uint64_t        s_iw_rx_cq_call;
+       uint64_t        s_iw_rx_cq_event;
+       uint64_t        s_iw_rx_ring_empty;
+       uint64_t        s_iw_rx_refill_from_cq;
+       uint64_t        s_iw_rx_refill_from_thread;
+       uint64_t        s_iw_rx_alloc_limit;
+       uint64_t        s_iw_rx_credit_updates;
+       uint64_t        s_iw_ack_sent;
+       uint64_t        s_iw_ack_send_failure;
+       uint64_t        s_iw_ack_send_delayed;
+       uint64_t        s_iw_ack_send_piggybacked;
+       uint64_t        s_iw_ack_received;
+       uint64_t        s_iw_rdma_mr_alloc;
+       uint64_t        s_iw_rdma_mr_free;
+       uint64_t        s_iw_rdma_mr_used;
+       uint64_t        s_iw_rdma_mr_pool_flush;
+       uint64_t        s_iw_rdma_mr_pool_wait;
+       uint64_t        s_iw_rdma_mr_pool_depleted;
+};
+
+extern struct workqueue_struct *rds_iw_wq;
+
+/*
+ * Fake ib_dma_sync_sg_for_{cpu,device} as long as ib_verbs.h
+ * doesn't define it.
+ */
+static inline void rds_iw_dma_sync_sg_for_cpu(struct ib_device *dev,
+               struct scatterlist *sg, unsigned int sg_dma_len, int direction)
+{
+       unsigned int i;
+
+       for (i = 0; i < sg_dma_len; ++i) {
+               ib_dma_sync_single_for_cpu(dev,
+                               ib_sg_dma_address(dev, &sg[i]),
+                               ib_sg_dma_len(dev, &sg[i]),
+                               direction);
+       }
+}
+#define ib_dma_sync_sg_for_cpu rds_iw_dma_sync_sg_for_cpu
+
+static inline void rds_iw_dma_sync_sg_for_device(struct ib_device *dev,
+               struct scatterlist *sg, unsigned int sg_dma_len, int direction)
+{
+       unsigned int i;
+
+       for (i = 0; i < sg_dma_len; ++i) {
+               ib_dma_sync_single_for_device(dev,
+                               ib_sg_dma_address(dev, &sg[i]),
+                               ib_sg_dma_len(dev, &sg[i]),
+                               direction);
+       }
+}
+#define ib_dma_sync_sg_for_device      rds_iw_dma_sync_sg_for_device
+
+static inline u32 rds_iw_local_dma_lkey(struct rds_iw_connection *ic)
+{
+       return ic->i_dma_local_lkey ? ic->i_cm_id->device->local_dma_lkey : ic->i_mr->lkey;
+}
+
+/* ib.c */
+extern struct rds_transport rds_iw_transport;
+extern void rds_iw_add_one(struct ib_device *device);
+extern void rds_iw_remove_one(struct ib_device *device);
+extern struct ib_client rds_iw_client;
+
+extern unsigned int fastreg_pool_size;
+extern unsigned int fastreg_message_size;
+
+extern spinlock_t iw_nodev_conns_lock;
+extern struct list_head iw_nodev_conns;
+
+/* ib_cm.c */
+int rds_iw_conn_alloc(struct rds_connection *conn, gfp_t gfp);
+void rds_iw_conn_free(void *arg);
+int rds_iw_conn_connect(struct rds_connection *conn);
+void rds_iw_conn_shutdown(struct rds_connection *conn);
+void rds_iw_state_change(struct sock *sk);
+int __init rds_iw_listen_init(void);
+void rds_iw_listen_stop(void);
+void __rds_iw_conn_error(struct rds_connection *conn, const char *, ...);
+int rds_iw_cm_handle_connect(struct rdma_cm_id *cm_id,
+                            struct rdma_cm_event *event);
+int rds_iw_cm_initiate_connect(struct rdma_cm_id *cm_id);
+void rds_iw_cm_connect_complete(struct rds_connection *conn,
+                               struct rdma_cm_event *event);
+
+
+#define rds_iw_conn_error(conn, fmt...) \
+       __rds_iw_conn_error(conn, KERN_WARNING "RDS/IW: " fmt)
+
+/* ib_rdma.c */
+int rds_iw_update_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_id);
+int rds_iw_add_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn);
+void rds_iw_remove_nodev_conns(void);
+void rds_iw_remove_conns(struct rds_iw_device *rds_iwdev);
+struct rds_iw_mr_pool *rds_iw_create_mr_pool(struct rds_iw_device *);
+void rds_iw_get_mr_info(struct rds_iw_device *rds_iwdev, struct rds_info_rdma_connection *iinfo);
+void rds_iw_destroy_mr_pool(struct rds_iw_mr_pool *);
+void *rds_iw_get_mr(struct scatterlist *sg, unsigned long nents,
+                   struct rds_sock *rs, u32 *key_ret);
+void rds_iw_sync_mr(void *trans_private, int dir);
+void rds_iw_free_mr(void *trans_private, int invalidate);
+void rds_iw_flush_mrs(void);
+void rds_iw_remove_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_id);
+
+/* ib_recv.c */
+int __init rds_iw_recv_init(void);
+void rds_iw_recv_exit(void);
+int rds_iw_recv(struct rds_connection *conn);
+int rds_iw_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
+                      gfp_t page_gfp, int prefill);
+void rds_iw_inc_purge(struct rds_incoming *inc);
+void rds_iw_inc_free(struct rds_incoming *inc);
+int rds_iw_inc_copy_to_user(struct rds_incoming *inc, struct iovec *iov,
+                            size_t size);
+void rds_iw_recv_cq_comp_handler(struct ib_cq *cq, void *context);
+void rds_iw_recv_init_ring(struct rds_iw_connection *ic);
+void rds_iw_recv_clear_ring(struct rds_iw_connection *ic);
+void rds_iw_recv_init_ack(struct rds_iw_connection *ic);
+void rds_iw_attempt_ack(struct rds_iw_connection *ic);
+void rds_iw_ack_send_complete(struct rds_iw_connection *ic);
+u64 rds_iw_piggyb_ack(struct rds_iw_connection *ic);
+
+/* ib_ring.c */
+void rds_iw_ring_init(struct rds_iw_work_ring *ring, u32 nr);
+void rds_iw_ring_resize(struct rds_iw_work_ring *ring, u32 nr);
+u32 rds_iw_ring_alloc(struct rds_iw_work_ring *ring, u32 val, u32 *pos);
+void rds_iw_ring_free(struct rds_iw_work_ring *ring, u32 val);
+void rds_iw_ring_unalloc(struct rds_iw_work_ring *ring, u32 val);
+int rds_iw_ring_empty(struct rds_iw_work_ring *ring);
+int rds_iw_ring_low(struct rds_iw_work_ring *ring);
+u32 rds_iw_ring_oldest(struct rds_iw_work_ring *ring);
+u32 rds_iw_ring_completed(struct rds_iw_work_ring *ring, u32 wr_id, u32 oldest);
+extern wait_queue_head_t rds_iw_ring_empty_wait;
+
+/* ib_send.c */
+void rds_iw_xmit_complete(struct rds_connection *conn);
+int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
+               unsigned int hdr_off, unsigned int sg, unsigned int off);
+void rds_iw_send_cq_comp_handler(struct ib_cq *cq, void *context);
+void rds_iw_send_init_ring(struct rds_iw_connection *ic);
+void rds_iw_send_clear_ring(struct rds_iw_connection *ic);
+int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op);
+void rds_iw_send_add_credits(struct rds_connection *conn, unsigned int credits);
+void rds_iw_advertise_credits(struct rds_connection *conn, unsigned int posted);
+int rds_iw_send_grab_credits(struct rds_iw_connection *ic, u32 wanted,
+                            u32 *adv_credits, int need_posted);
+
+/* ib_stats.c */
+DECLARE_PER_CPU(struct rds_iw_statistics, rds_iw_stats);
+#define rds_iw_stats_inc(member) rds_stats_inc_which(rds_iw_stats, member)
+unsigned int rds_iw_stats_info_copy(struct rds_info_iterator *iter,
+                                   unsigned int avail);
+
+/* ib_sysctl.c */
+int __init rds_iw_sysctl_init(void);
+void rds_iw_sysctl_exit(void);
+extern unsigned long rds_iw_sysctl_max_send_wr;
+extern unsigned long rds_iw_sysctl_max_recv_wr;
+extern unsigned long rds_iw_sysctl_max_unsig_wrs;
+extern unsigned long rds_iw_sysctl_max_unsig_bytes;
+extern unsigned long rds_iw_sysctl_max_recv_allocation;
+extern unsigned int rds_iw_sysctl_flow_control;
+extern ctl_table rds_iw_sysctl_table[];
+
+/*
+ * Helper functions for getting/setting the header and data SGEs in
+ * RDS packets (not RDMA)
+ */
+static inline struct ib_sge *
+rds_iw_header_sge(struct rds_iw_connection *ic, struct ib_sge *sge)
+{
+       return &sge[0];
+}
+
+static inline struct ib_sge *
+rds_iw_data_sge(struct rds_iw_connection *ic, struct ib_sge *sge)
+{
+       return &sge[1];
+}
+
+static inline void rds_iw_set_64bit(u64 *ptr, u64 val)
+{
+#if BITS_PER_LONG == 64
+       *ptr = val;
+#else
+       set_64bit(ptr, val);
+#endif
+}
+
+#endif
diff --git a/net/rds/iw_cm.c b/net/rds/iw_cm.c
new file mode 100644 (file)
index 0000000..57ecb3d
--- /dev/null
@@ -0,0 +1,750 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/in.h>
+#include <linux/vmalloc.h>
+
+#include "rds.h"
+#include "iw.h"
+
+/*
+ * Set the selected protocol version
+ */
+static void rds_iw_set_protocol(struct rds_connection *conn, unsigned int version)
+{
+       conn->c_version = version;
+}
+
+/*
+ * Set up flow control
+ */
+static void rds_iw_set_flow_control(struct rds_connection *conn, u32 credits)
+{
+       struct rds_iw_connection *ic = conn->c_transport_data;
+
+       if (rds_iw_sysctl_flow_control && credits != 0) {
+               /* We're doing flow control */
+               ic->i_flowctl = 1;
+               rds_iw_send_add_credits(conn, credits);
+       } else {
+               ic->i_flowctl = 0;
+       }
+}
+
+/*
+ * Connection established.
+ * We get here for both outgoing and incoming connection.
+ */
+void rds_iw_cm_connect_complete(struct rds_connection *conn, struct rdma_cm_event *event)
+{
+       const struct rds_iw_connect_private *dp = NULL;
+       struct rds_iw_connection *ic = conn->c_transport_data;
+       struct rds_iw_device *rds_iwdev;
+       int err;
+
+       if (event->param.conn.private_data_len) {
+               dp = event->param.conn.private_data;
+
+               rds_iw_set_protocol(conn,
+                               RDS_PROTOCOL(dp->dp_protocol_major,
+                                       dp->dp_protocol_minor));
+               rds_iw_set_flow_control(conn, be32_to_cpu(dp->dp_credit));
+       }
+
+       /* update ib_device with this local ipaddr & conn */
+       rds_iwdev = ib_get_client_data(ic->i_cm_id->device, &rds_iw_client);
+       err = rds_iw_update_cm_id(rds_iwdev, ic->i_cm_id);
+       if (err)
+               printk(KERN_ERR "rds_iw_update_ipaddr failed (%d)\n", err);
+       err = rds_iw_add_conn(rds_iwdev, conn);
+       if (err)
+               printk(KERN_ERR "rds_iw_add_conn failed (%d)\n", err);
+
+       /* If the peer gave us the last packet it saw, process this as if
+        * we had received a regular ACK. */
+       if (dp && dp->dp_ack_seq)
+               rds_send_drop_acked(conn, be64_to_cpu(dp->dp_ack_seq), NULL);
+
+       printk(KERN_NOTICE "RDS/IW: connected to %pI4<->%pI4 version %u.%u%s\n",
+                       &conn->c_laddr, &conn->c_faddr,
+                       RDS_PROTOCOL_MAJOR(conn->c_version),
+                       RDS_PROTOCOL_MINOR(conn->c_version),
+                       ic->i_flowctl ? ", flow control" : "");
+
+       rds_connect_complete(conn);
+}
+
+static void rds_iw_cm_fill_conn_param(struct rds_connection *conn,
+                       struct rdma_conn_param *conn_param,
+                       struct rds_iw_connect_private *dp,
+                       u32 protocol_version)
+{
+       struct rds_iw_connection *ic = conn->c_transport_data;
+
+       memset(conn_param, 0, sizeof(struct rdma_conn_param));
+       /* XXX tune these? */
+       conn_param->responder_resources = 1;
+       conn_param->initiator_depth = 1;
+
+       if (dp) {
+               memset(dp, 0, sizeof(*dp));
+               dp->dp_saddr = conn->c_laddr;
+               dp->dp_daddr = conn->c_faddr;
+               dp->dp_protocol_major = RDS_PROTOCOL_MAJOR(protocol_version);
+               dp->dp_protocol_minor = RDS_PROTOCOL_MINOR(protocol_version);
+               dp->dp_protocol_minor_mask = cpu_to_be16(RDS_IW_SUPPORTED_PROTOCOLS);
+               dp->dp_ack_seq = rds_iw_piggyb_ack(ic);
+
+               /* Advertise flow control */
+               if (ic->i_flowctl) {
+                       unsigned int credits;
+
+                       credits = IB_GET_POST_CREDITS(atomic_read(&ic->i_credits));
+                       dp->dp_credit = cpu_to_be32(credits);
+                       atomic_sub(IB_SET_POST_CREDITS(credits), &ic->i_credits);
+               }
+
+               conn_param->private_data = dp;
+               conn_param->private_data_len = sizeof(*dp);
+       }
+}
+
+static void rds_iw_cq_event_handler(struct ib_event *event, void *data)
+{
+       rdsdebug("event %u data %p\n", event->event, data);
+}
+
+static void rds_iw_qp_event_handler(struct ib_event *event, void *data)
+{
+       struct rds_connection *conn = data;
+       struct rds_iw_connection *ic = conn->c_transport_data;
+
+       rdsdebug("conn %p ic %p event %u\n", conn, ic, event->event);
+
+       switch (event->event) {
+       case IB_EVENT_COMM_EST:
+               rdma_notify(ic->i_cm_id, IB_EVENT_COMM_EST);
+               break;
+       case IB_EVENT_QP_REQ_ERR:
+       case IB_EVENT_QP_FATAL:
+       default:
+               rds_iw_conn_error(conn, "RDS/IW: Fatal QP Event %u - connection %pI4->%pI4...reconnecting\n",
+                       event->event, &conn->c_laddr,
+                       &conn->c_faddr);
+               break;
+       }
+}
+
+/*
+ * Create a QP
+ */
+static int rds_iw_init_qp_attrs(struct ib_qp_init_attr *attr,
+               struct rds_iw_device *rds_iwdev,
+               struct rds_iw_work_ring *send_ring,
+               void (*send_cq_handler)(struct ib_cq *, void *),
+               struct rds_iw_work_ring *recv_ring,
+               void (*recv_cq_handler)(struct ib_cq *, void *),
+               void *context)
+{
+       struct ib_device *dev = rds_iwdev->dev;
+       unsigned int send_size, recv_size;
+       int ret;
+
+       /* The offset of 1 is to accomodate the additional ACK WR. */
+       send_size = min_t(unsigned int, rds_iwdev->max_wrs, rds_iw_sysctl_max_send_wr + 1);
+       recv_size = min_t(unsigned int, rds_iwdev->max_wrs, rds_iw_sysctl_max_recv_wr + 1);
+       rds_iw_ring_resize(send_ring, send_size - 1);
+       rds_iw_ring_resize(recv_ring, recv_size - 1);
+
+       memset(attr, 0, sizeof(*attr));
+       attr->event_handler = rds_iw_qp_event_handler;
+       attr->qp_context = context;
+       attr->cap.max_send_wr = send_size;
+       attr->cap.max_recv_wr = recv_size;
+       attr->cap.max_send_sge = rds_iwdev->max_sge;
+       attr->cap.max_recv_sge = RDS_IW_RECV_SGE;
+       attr->sq_sig_type = IB_SIGNAL_REQ_WR;
+       attr->qp_type = IB_QPT_RC;
+
+       attr->send_cq = ib_create_cq(dev, send_cq_handler,
+                                    rds_iw_cq_event_handler,
+                                    context, send_size, 0);
+       if (IS_ERR(attr->send_cq)) {
+               ret = PTR_ERR(attr->send_cq);
+               attr->send_cq = NULL;
+               rdsdebug("ib_create_cq send failed: %d\n", ret);
+               goto out;
+       }
+
+       attr->recv_cq = ib_create_cq(dev, recv_cq_handler,
+                                    rds_iw_cq_event_handler,
+                                    context, recv_size, 0);
+       if (IS_ERR(attr->recv_cq)) {
+               ret = PTR_ERR(attr->recv_cq);
+               attr->recv_cq = NULL;
+               rdsdebug("ib_create_cq send failed: %d\n", ret);
+               goto out;
+       }
+
+       ret = ib_req_notify_cq(attr->send_cq, IB_CQ_NEXT_COMP);
+       if (ret) {
+               rdsdebug("ib_req_notify_cq send failed: %d\n", ret);
+               goto out;
+       }
+
+       ret = ib_req_notify_cq(attr->recv_cq, IB_CQ_SOLICITED);
+       if (ret) {
+               rdsdebug("ib_req_notify_cq recv failed: %d\n", ret);
+               goto out;
+       }
+
+out:
+       if (ret) {
+               if (attr->send_cq)
+                       ib_destroy_cq(attr->send_cq);
+               if (attr->recv_cq)
+                       ib_destroy_cq(attr->recv_cq);
+       }
+       return ret;
+}
+
+/*
+ * This needs to be very careful to not leave IS_ERR pointers around for
+ * cleanup to trip over.
+ */
+static int rds_iw_setup_qp(struct rds_connection *conn)
+{
+       struct rds_iw_connection *ic = conn->c_transport_data;
+       struct ib_device *dev = ic->i_cm_id->device;
+       struct ib_qp_init_attr attr;
+       struct rds_iw_device *rds_iwdev;
+       int ret;
+
+       /* rds_iw_add_one creates a rds_iw_device object per IB device,
+        * and allocates a protection domain, memory range and MR pool
+        * for each.  If that fails for any reason, it will not register
+        * the rds_iwdev at all.
+        */
+       rds_iwdev = ib_get_client_data(dev, &rds_iw_client);
+       if (rds_iwdev == NULL) {
+               if (printk_ratelimit())
+                       printk(KERN_NOTICE "RDS/IW: No client_data for device %s\n",
+                                       dev->name);
+               return -EOPNOTSUPP;
+       }
+
+       /* Protection domain and memory range */
+       ic->i_pd = rds_iwdev->pd;
+       ic->i_mr = rds_iwdev->mr;
+
+       ret = rds_iw_init_qp_attrs(&attr, rds_iwdev,
+                       &ic->i_send_ring, rds_iw_send_cq_comp_handler,
+                       &ic->i_recv_ring, rds_iw_recv_cq_comp_handler,
+                       conn);
+       if (ret < 0)
+               goto out;
+
+       ic->i_send_cq = attr.send_cq;
+       ic->i_recv_cq = attr.recv_cq;
+
+       /*
+        * XXX this can fail if max_*_wr is too large?  Are we supposed
+        * to back off until we get a value that the hardware can support?
+        */
+       ret = rdma_create_qp(ic->i_cm_id, ic->i_pd, &attr);
+       if (ret) {
+               rdsdebug("rdma_create_qp failed: %d\n", ret);
+               goto out;
+       }
+
+       ic->i_send_hdrs = ib_dma_alloc_coherent(dev,
+                                          ic->i_send_ring.w_nr *
+                                               sizeof(struct rds_header),
+                                          &ic->i_send_hdrs_dma, GFP_KERNEL);
+       if (ic->i_send_hdrs == NULL) {
+               ret = -ENOMEM;
+               rdsdebug("ib_dma_alloc_coherent send failed\n");
+               goto out;
+       }
+
+       ic->i_recv_hdrs = ib_dma_alloc_coherent(dev,
+                                          ic->i_recv_ring.w_nr *
+                                               sizeof(struct rds_header),
+                                          &ic->i_recv_hdrs_dma, GFP_KERNEL);
+       if (ic->i_recv_hdrs == NULL) {
+               ret = -ENOMEM;
+               rdsdebug("ib_dma_alloc_coherent recv failed\n");
+               goto out;
+       }
+
+       ic->i_ack = ib_dma_alloc_coherent(dev, sizeof(struct rds_header),
+                                      &ic->i_ack_dma, GFP_KERNEL);
+       if (ic->i_ack == NULL) {
+               ret = -ENOMEM;
+               rdsdebug("ib_dma_alloc_coherent ack failed\n");
+               goto out;
+       }
+
+       ic->i_sends = vmalloc(ic->i_send_ring.w_nr * sizeof(struct rds_iw_send_work));
+       if (ic->i_sends == NULL) {
+               ret = -ENOMEM;
+               rdsdebug("send allocation failed\n");
+               goto out;
+       }
+       rds_iw_send_init_ring(ic);
+
+       ic->i_recvs = vmalloc(ic->i_recv_ring.w_nr * sizeof(struct rds_iw_recv_work));
+       if (ic->i_recvs == NULL) {
+               ret = -ENOMEM;
+               rdsdebug("recv allocation failed\n");
+               goto out;
+       }
+
+       rds_iw_recv_init_ring(ic);
+       rds_iw_recv_init_ack(ic);
+
+       /* Post receive buffers - as a side effect, this will update
+        * the posted credit count. */
+       rds_iw_recv_refill(conn, GFP_KERNEL, GFP_HIGHUSER, 1);
+
+       rdsdebug("conn %p pd %p mr %p cq %p %p\n", conn, ic->i_pd, ic->i_mr,
+                ic->i_send_cq, ic->i_recv_cq);
+
+out:
+       return ret;
+}
+
+static u32 rds_iw_protocol_compatible(const struct rds_iw_connect_private *dp)
+{
+       u16 common;
+       u32 version = 0;
+
+       /* rdma_cm private data is odd - when there is any private data in the
+        * request, we will be given a pretty large buffer without telling us the
+        * original size. The only way to tell the difference is by looking at
+        * the contents, which are initialized to zero.
+        * If the protocol version fields aren't set, this is a connection attempt
+        * from an older version. This could could be 3.0 or 2.0 - we can't tell.
+        * We really should have changed this for OFED 1.3 :-( */
+       if (dp->dp_protocol_major == 0)
+               return RDS_PROTOCOL_3_0;
+
+       common = be16_to_cpu(dp->dp_protocol_minor_mask) & RDS_IW_SUPPORTED_PROTOCOLS;
+       if (dp->dp_protocol_major == 3 && common) {
+               version = RDS_PROTOCOL_3_0;
+               while ((common >>= 1) != 0)
+                       version++;
+       } else if (printk_ratelimit()) {
+               printk(KERN_NOTICE "RDS: Connection from %pI4 using "
+                       "incompatible protocol version %u.%u\n",
+                       &dp->dp_saddr,
+                       dp->dp_protocol_major,
+                       dp->dp_protocol_minor);
+       }
+       return version;
+}
+
+int rds_iw_cm_handle_connect(struct rdma_cm_id *cm_id,
+                                   struct rdma_cm_event *event)
+{
+       const struct rds_iw_connect_private *dp = event->param.conn.private_data;
+       struct rds_iw_connect_private dp_rep;
+       struct rds_connection *conn = NULL;
+       struct rds_iw_connection *ic = NULL;
+       struct rdma_conn_param conn_param;
+       struct rds_iw_device *rds_iwdev;
+       u32 version;
+       int err, destroy = 1;
+
+       /* Check whether the remote protocol version matches ours. */
+       version = rds_iw_protocol_compatible(dp);
+       if (!version)
+               goto out;
+
+       rdsdebug("saddr %pI4 daddr %pI4 RDSv%u.%u\n",
+                &dp->dp_saddr, &dp->dp_daddr,
+                RDS_PROTOCOL_MAJOR(version), RDS_PROTOCOL_MINOR(version));
+
+       conn = rds_conn_create(dp->dp_daddr, dp->dp_saddr, &rds_iw_transport,
+                              GFP_KERNEL);
+       if (IS_ERR(conn)) {
+               rdsdebug("rds_conn_create failed (%ld)\n", PTR_ERR(conn));
+               conn = NULL;
+               goto out;
+       }
+
+       /*
+        * The connection request may occur while the
+        * previous connection exist, e.g. in case of failover.
+        * But as connections may be initiated simultaneously
+        * by both hosts, we have a random backoff mechanism -
+        * see the comment above rds_queue_reconnect()
+        */
+       mutex_lock(&conn->c_cm_lock);
+       if (!rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_CONNECTING)) {
+               if (rds_conn_state(conn) == RDS_CONN_UP) {
+                       rdsdebug("incoming connect while connecting\n");
+                       rds_conn_drop(conn);
+                       rds_iw_stats_inc(s_iw_listen_closed_stale);
+               } else
+               if (rds_conn_state(conn) == RDS_CONN_CONNECTING) {
+                       /* Wait and see - our connect may still be succeeding */
+                       rds_iw_stats_inc(s_iw_connect_raced);
+               }
+               mutex_unlock(&conn->c_cm_lock);
+               goto out;
+       }
+
+       ic = conn->c_transport_data;
+
+       rds_iw_set_protocol(conn, version);
+       rds_iw_set_flow_control(conn, be32_to_cpu(dp->dp_credit));
+
+       /* If the peer gave us the last packet it saw, process this as if
+        * we had received a regular ACK. */
+       if (dp->dp_ack_seq)
+               rds_send_drop_acked(conn, be64_to_cpu(dp->dp_ack_seq), NULL);
+
+       BUG_ON(cm_id->context);
+       BUG_ON(ic->i_cm_id);
+
+       ic->i_cm_id = cm_id;
+       cm_id->context = conn;
+
+       rds_iwdev = ib_get_client_data(cm_id->device, &rds_iw_client);
+       ic->i_dma_local_lkey = rds_iwdev->dma_local_lkey;
+
+       /* We got halfway through setting up the ib_connection, if we
+        * fail now, we have to take the long route out of this mess. */
+       destroy = 0;
+
+       err = rds_iw_setup_qp(conn);
+       if (err) {
+               rds_iw_conn_error(conn, "rds_iw_setup_qp failed (%d)\n", err);
+               goto out;
+       }
+
+       rds_iw_cm_fill_conn_param(conn, &conn_param, &dp_rep, version);
+
+       /* rdma_accept() calls rdma_reject() internally if it fails */
+       err = rdma_accept(cm_id, &conn_param);
+       mutex_unlock(&conn->c_cm_lock);
+       if (err) {
+               rds_iw_conn_error(conn, "rdma_accept failed (%d)\n", err);
+               goto out;
+       }
+
+       return 0;
+
+out:
+       rdma_reject(cm_id, NULL, 0);
+       return destroy;
+}
+
+
+int rds_iw_cm_initiate_connect(struct rdma_cm_id *cm_id)
+{
+       struct rds_connection *conn = cm_id->context;
+       struct rds_iw_connection *ic = conn->c_transport_data;
+       struct rdma_conn_param conn_param;
+       struct rds_iw_connect_private dp;
+       int ret;
+
+       /* If the peer doesn't do protocol negotiation, we must
+        * default to RDSv3.0 */
+       rds_iw_set_protocol(conn, RDS_PROTOCOL_3_0);
+       ic->i_flowctl = rds_iw_sysctl_flow_control;     /* advertise flow control */
+
+       ret = rds_iw_setup_qp(conn);
+       if (ret) {
+               rds_iw_conn_error(conn, "rds_iw_setup_qp failed (%d)\n", ret);
+               goto out;
+       }
+
+       rds_iw_cm_fill_conn_param(conn, &conn_param, &dp, RDS_PROTOCOL_VERSION);
+
+       ret = rdma_connect(cm_id, &conn_param);
+       if (ret)
+               rds_iw_conn_error(conn, "rdma_connect failed (%d)\n", ret);
+
+out:
+       /* Beware - returning non-zero tells the rdma_cm to destroy
+        * the cm_id. We should certainly not do it as long as we still
+        * "own" the cm_id. */
+       if (ret) {
+               struct rds_iw_connection *ic = conn->c_transport_data;
+
+               if (ic->i_cm_id == cm_id)
+                       ret = 0;
+       }
+       return ret;
+}
+
+int rds_iw_conn_connect(struct rds_connection *conn)
+{
+       struct rds_iw_connection *ic = conn->c_transport_data;
+       struct rds_iw_device *rds_iwdev;
+       struct sockaddr_in src, dest;
+       int ret;
+
+       /* XXX I wonder what affect the port space has */
+       /* delegate cm event handler to rdma_transport */
+       ic->i_cm_id = rdma_create_id(rds_rdma_cm_event_handler, conn,
+                                    RDMA_PS_TCP);
+       if (IS_ERR(ic->i_cm_id)) {
+               ret = PTR_ERR(ic->i_cm_id);
+               ic->i_cm_id = NULL;
+               rdsdebug("rdma_create_id() failed: %d\n", ret);
+               goto out;
+       }
+
+       rdsdebug("created cm id %p for conn %p\n", ic->i_cm_id, conn);
+
+       src.sin_family = AF_INET;
+       src.sin_addr.s_addr = (__force u32)conn->c_laddr;
+       src.sin_port = (__force u16)htons(0);
+
+       /* First, bind to the local address and device. */
+       ret = rdma_bind_addr(ic->i_cm_id, (struct sockaddr *) &src);
+       if (ret) {
+               rdsdebug("rdma_bind_addr(%pI4) failed: %d\n",
+                               &conn->c_laddr, ret);
+               rdma_destroy_id(ic->i_cm_id);
+               ic->i_cm_id = NULL;
+               goto out;
+       }
+
+       rds_iwdev = ib_get_client_data(ic->i_cm_id->device, &rds_iw_client);
+       ic->i_dma_local_lkey = rds_iwdev->dma_local_lkey;
+
+       dest.sin_family = AF_INET;
+       dest.sin_addr.s_addr = (__force u32)conn->c_faddr;
+       dest.sin_port = (__force u16)htons(RDS_PORT);
+
+       ret = rdma_resolve_addr(ic->i_cm_id, (struct sockaddr *)&src,
+                               (struct sockaddr *)&dest,
+                               RDS_RDMA_RESOLVE_TIMEOUT_MS);
+       if (ret) {
+               rdsdebug("addr resolve failed for cm id %p: %d\n", ic->i_cm_id,
+                        ret);
+               rdma_destroy_id(ic->i_cm_id);
+               ic->i_cm_id = NULL;
+       }
+
+out:
+       return ret;
+}
+
+/*
+ * This is so careful about only cleaning up resources that were built up
+ * so that it can be called at any point during startup.  In fact it
+ * can be called multiple times for a given connection.
+ */
+void rds_iw_conn_shutdown(struct rds_connection *conn)
+{
+       struct rds_iw_connection *ic = conn->c_transport_data;
+       int err = 0;
+       struct ib_qp_attr qp_attr;
+
+       rdsdebug("cm %p pd %p cq %p %p qp %p\n", ic->i_cm_id,
+                ic->i_pd, ic->i_send_cq, ic->i_recv_cq,
+                ic->i_cm_id ? ic->i_cm_id->qp : NULL);
+
+       if (ic->i_cm_id) {
+               struct ib_device *dev = ic->i_cm_id->device;
+
+               rdsdebug("disconnecting cm %p\n", ic->i_cm_id);
+               err = rdma_disconnect(ic->i_cm_id);
+               if (err) {
+                       /* Actually this may happen quite frequently, when
+                        * an outgoing connect raced with an incoming connect.
+                        */
+                       rdsdebug("rds_iw_conn_shutdown: failed to disconnect,"
+                                  " cm: %p err %d\n", ic->i_cm_id, err);
+               }
+
+               if (ic->i_cm_id->qp) {
+                       qp_attr.qp_state = IB_QPS_ERR;
+                       ib_modify_qp(ic->i_cm_id->qp, &qp_attr, IB_QP_STATE);
+               }
+
+               wait_event(rds_iw_ring_empty_wait,
+                       rds_iw_ring_empty(&ic->i_send_ring) &&
+                       rds_iw_ring_empty(&ic->i_recv_ring));
+
+               if (ic->i_send_hdrs)
+                       ib_dma_free_coherent(dev,
+                                          ic->i_send_ring.w_nr *
+                                               sizeof(struct rds_header),
+                                          ic->i_send_hdrs,
+                                          ic->i_send_hdrs_dma);
+
+               if (ic->i_recv_hdrs)
+                       ib_dma_free_coherent(dev,
+                                          ic->i_recv_ring.w_nr *
+                                               sizeof(struct rds_header),
+                                          ic->i_recv_hdrs,
+                                          ic->i_recv_hdrs_dma);
+
+               if (ic->i_ack)
+                       ib_dma_free_coherent(dev, sizeof(struct rds_header),
+                                            ic->i_ack, ic->i_ack_dma);
+
+               if (ic->i_sends)
+                       rds_iw_send_clear_ring(ic);
+               if (ic->i_recvs)
+                       rds_iw_recv_clear_ring(ic);
+
+               if (ic->i_cm_id->qp)
+                       rdma_destroy_qp(ic->i_cm_id);
+               if (ic->i_send_cq)
+                       ib_destroy_cq(ic->i_send_cq);
+               if (ic->i_recv_cq)
+                       ib_destroy_cq(ic->i_recv_cq);
+
+               /*
+                * If associated with an rds_iw_device:
+                *      Move connection back to the nodev list.
+                *      Remove cm_id from the device cm_id list.
+                */
+               if (ic->rds_iwdev) {
+
+                       spin_lock_irq(&ic->rds_iwdev->spinlock);
+                       BUG_ON(list_empty(&ic->iw_node));
+                       list_del(&ic->iw_node);
+                       spin_unlock_irq(&ic->rds_iwdev->spinlock);
+
+                       spin_lock_irq(&iw_nodev_conns_lock);
+                       list_add_tail(&ic->iw_node, &iw_nodev_conns);
+                       spin_unlock_irq(&iw_nodev_conns_lock);
+                       rds_iw_remove_cm_id(ic->rds_iwdev, ic->i_cm_id);
+                       ic->rds_iwdev = NULL;
+               }
+
+               rdma_destroy_id(ic->i_cm_id);
+
+               ic->i_cm_id = NULL;
+               ic->i_pd = NULL;
+               ic->i_mr = NULL;
+               ic->i_send_cq = NULL;
+               ic->i_recv_cq = NULL;
+               ic->i_send_hdrs = NULL;
+               ic->i_recv_hdrs = NULL;
+               ic->i_ack = NULL;
+       }
+       BUG_ON(ic->rds_iwdev);
+
+       /* Clear pending transmit */
+       if (ic->i_rm) {
+               rds_message_put(ic->i_rm);
+               ic->i_rm = NULL;
+       }
+
+       /* Clear the ACK state */
+       clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags);
+       rds_iw_set_64bit(&ic->i_ack_next, 0);
+       ic->i_ack_recv = 0;
+
+       /* Clear flow control state */
+       ic->i_flowctl = 0;
+       atomic_set(&ic->i_credits, 0);
+
+       rds_iw_ring_init(&ic->i_send_ring, rds_iw_sysctl_max_send_wr);
+       rds_iw_ring_init(&ic->i_recv_ring, rds_iw_sysctl_max_recv_wr);
+
+       if (ic->i_iwinc) {
+               rds_inc_put(&ic->i_iwinc->ii_inc);
+               ic->i_iwinc = NULL;
+       }
+
+       vfree(ic->i_sends);
+       ic->i_sends = NULL;
+       vfree(ic->i_recvs);
+       ic->i_recvs = NULL;
+       rdsdebug("shutdown complete\n");
+}
+
+int rds_iw_conn_alloc(struct rds_connection *conn, gfp_t gfp)
+{
+       struct rds_iw_connection *ic;
+       unsigned long flags;
+
+       /* XXX too lazy? */
+       ic = kzalloc(sizeof(struct rds_iw_connection), GFP_KERNEL);
+       if (ic == NULL)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&ic->iw_node);
+       mutex_init(&ic->i_recv_mutex);
+
+       /*
+        * rds_iw_conn_shutdown() waits for these to be emptied so they
+        * must be initialized before it can be called.
+        */
+       rds_iw_ring_init(&ic->i_send_ring, rds_iw_sysctl_max_send_wr);
+       rds_iw_ring_init(&ic->i_recv_ring, rds_iw_sysctl_max_recv_wr);
+
+       ic->conn = conn;
+       conn->c_transport_data = ic;
+
+       spin_lock_irqsave(&iw_nodev_conns_lock, flags);
+       list_add_tail(&ic->iw_node, &iw_nodev_conns);
+       spin_unlock_irqrestore(&iw_nodev_conns_lock, flags);
+
+
+       rdsdebug("conn %p conn ic %p\n", conn, conn->c_transport_data);
+       return 0;
+}
+
+void rds_iw_conn_free(void *arg)
+{
+       struct rds_iw_connection *ic = arg;
+       rdsdebug("ic %p\n", ic);
+       list_del(&ic->iw_node);
+       kfree(ic);
+}
+
+/*
+ * An error occurred on the connection
+ */
+void
+__rds_iw_conn_error(struct rds_connection *conn, const char *fmt, ...)
+{
+       va_list ap;
+
+       rds_conn_drop(conn);
+
+       va_start(ap, fmt);
+       vprintk(fmt, ap);
+       va_end(ap);
+}
diff --git a/net/rds/iw_rdma.c b/net/rds/iw_rdma.c
new file mode 100644 (file)
index 0000000..1c02a8f
--- /dev/null
@@ -0,0 +1,888 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+
+#include "rds.h"
+#include "rdma.h"
+#include "iw.h"
+
+
+/*
+ * This is stored as mr->r_trans_private.
+ */
+struct rds_iw_mr {
+       struct rds_iw_device    *device;
+       struct rds_iw_mr_pool   *pool;
+       struct rdma_cm_id       *cm_id;
+
+       struct ib_mr    *mr;
+       struct ib_fast_reg_page_list *page_list;
+
+       struct rds_iw_mapping   mapping;
+       unsigned char           remap_count;
+};
+
+/*
+ * Our own little MR pool
+ */
+struct rds_iw_mr_pool {
+       struct rds_iw_device    *device;                /* back ptr to the device that owns us */
+
+       struct mutex            flush_lock;             /* serialize fmr invalidate */
+       struct work_struct      flush_worker;           /* flush worker */
+
+       spinlock_t              list_lock;              /* protect variables below */
+       atomic_t                item_count;             /* total # of MRs */
+       atomic_t                dirty_count;            /* # dirty of MRs */
+       struct list_head        dirty_list;             /* dirty mappings */
+       struct list_head        clean_list;             /* unused & unamapped MRs */
+       atomic_t                free_pinned;            /* memory pinned by free MRs */
+       unsigned long           max_message_size;       /* in pages */
+       unsigned long           max_items;
+       unsigned long           max_items_soft;
+       unsigned long           max_free_pinned;
+       int                     max_pages;
+};
+
+static int rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all);
+static void rds_iw_mr_pool_flush_worker(struct work_struct *work);
+static int rds_iw_init_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
+static int rds_iw_map_fastreg(struct rds_iw_mr_pool *pool,
+                         struct rds_iw_mr *ibmr,
+                         struct scatterlist *sg, unsigned int nents);
+static void rds_iw_free_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
+static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool,
+                       struct list_head *unmap_list,
+                       struct list_head *kill_list);
+static void rds_iw_destroy_fastreg(struct rds_iw_mr_pool *pool, struct rds_iw_mr *ibmr);
+
+static int rds_iw_get_device(struct rds_sock *rs, struct rds_iw_device **rds_iwdev, struct rdma_cm_id **cm_id)
+{
+       struct rds_iw_device *iwdev;
+       struct rds_iw_cm_id *i_cm_id;
+
+       *rds_iwdev = NULL;
+       *cm_id = NULL;
+
+       list_for_each_entry(iwdev, &rds_iw_devices, list) {
+               spin_lock_irq(&iwdev->spinlock);
+               list_for_each_entry(i_cm_id, &iwdev->cm_id_list, list) {
+                       struct sockaddr_in *src_addr, *dst_addr;
+
+                       src_addr = (struct sockaddr_in *)&i_cm_id->cm_id->route.addr.src_addr;
+                       dst_addr = (struct sockaddr_in *)&i_cm_id->cm_id->route.addr.dst_addr;
+
+                       rdsdebug("local ipaddr = %x port %d, "
+                                "remote ipaddr = %x port %d"
+                                "..looking for %x port %d, "
+                                "remote ipaddr = %x port %d\n",
+                               src_addr->sin_addr.s_addr,
+                               src_addr->sin_port,
+                               dst_addr->sin_addr.s_addr,
+                               dst_addr->sin_port,
+                               rs->rs_bound_addr,
+                               rs->rs_bound_port,
+                               rs->rs_conn_addr,
+                               rs->rs_conn_port);
+#ifdef WORKING_TUPLE_DETECTION
+                       if (src_addr->sin_addr.s_addr == rs->rs_bound_addr &&
+                           src_addr->sin_port == rs->rs_bound_port &&
+                           dst_addr->sin_addr.s_addr == rs->rs_conn_addr &&
+                           dst_addr->sin_port == rs->rs_conn_port) {
+#else
+                       /* FIXME - needs to compare the local and remote
+                        * ipaddr/port tuple, but the ipaddr is the only
+                        * available infomation in the rds_sock (as the rest are
+                        * zero'ed.  It doesn't appear to be properly populated
+                        * during connection setup...
+                        */
+                       if (src_addr->sin_addr.s_addr == rs->rs_bound_addr) {
+#endif
+                               spin_unlock_irq(&iwdev->spinlock);
+                               *rds_iwdev = iwdev;
+                               *cm_id = i_cm_id->cm_id;
+                               return 0;
+                       }
+               }
+               spin_unlock_irq(&iwdev->spinlock);
+       }
+
+       return 1;
+}
+
+static int rds_iw_add_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_id)
+{
+       struct rds_iw_cm_id *i_cm_id;
+
+       i_cm_id = kmalloc(sizeof *i_cm_id, GFP_KERNEL);
+       if (!i_cm_id)
+               return -ENOMEM;
+
+       i_cm_id->cm_id = cm_id;
+
+       spin_lock_irq(&rds_iwdev->spinlock);
+       list_add_tail(&i_cm_id->list, &rds_iwdev->cm_id_list);
+       spin_unlock_irq(&rds_iwdev->spinlock);
+
+       return 0;
+}
+
+void rds_iw_remove_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_id)
+{
+       struct rds_iw_cm_id *i_cm_id;
+
+       spin_lock_irq(&rds_iwdev->spinlock);
+       list_for_each_entry(i_cm_id, &rds_iwdev->cm_id_list, list) {
+               if (i_cm_id->cm_id == cm_id) {
+                       list_del(&i_cm_id->list);
+                       kfree(i_cm_id);
+                       break;
+               }
+       }
+       spin_unlock_irq(&rds_iwdev->spinlock);
+}
+
+
+int rds_iw_update_cm_id(struct rds_iw_device *rds_iwdev, struct rdma_cm_id *cm_id)
+{
+       struct sockaddr_in *src_addr, *dst_addr;
+       struct rds_iw_device *rds_iwdev_old;
+       struct rds_sock rs;
+       struct rdma_cm_id *pcm_id;
+       int rc;
+
+       src_addr = (struct sockaddr_in *)&cm_id->route.addr.src_addr;
+       dst_addr = (struct sockaddr_in *)&cm_id->route.addr.dst_addr;
+
+       rs.rs_bound_addr = src_addr->sin_addr.s_addr;
+       rs.rs_bound_port = src_addr->sin_port;
+       rs.rs_conn_addr = dst_addr->sin_addr.s_addr;
+       rs.rs_conn_port = dst_addr->sin_port;
+
+       rc = rds_iw_get_device(&rs, &rds_iwdev_old, &pcm_id);
+       if (rc)
+               rds_iw_remove_cm_id(rds_iwdev, cm_id);
+
+       return rds_iw_add_cm_id(rds_iwdev, cm_id);
+}
+
+int rds_iw_add_conn(struct rds_iw_device *rds_iwdev, struct rds_connection *conn)
+{
+       struct rds_iw_connection *ic = conn->c_transport_data;
+
+       /* conn was previously on the nodev_conns_list */
+       spin_lock_irq(&iw_nodev_conns_lock);
+       BUG_ON(list_empty(&iw_nodev_conns));
+       BUG_ON(list_empty(&ic->iw_node));
+       list_del(&ic->iw_node);
+       spin_unlock_irq(&iw_nodev_conns_lock);
+
+       spin_lock_irq(&rds_iwdev->spinlock);
+       list_add_tail(&ic->iw_node, &rds_iwdev->conn_list);
+       spin_unlock_irq(&rds_iwdev->spinlock);
+
+       ic->rds_iwdev = rds_iwdev;
+
+       return 0;
+}
+
+void rds_iw_remove_nodev_conns(void)
+{
+       struct rds_iw_connection *ic, *_ic;
+       LIST_HEAD(tmp_list);
+
+       /* avoid calling conn_destroy with irqs off */
+       spin_lock_irq(&iw_nodev_conns_lock);
+       list_splice(&iw_nodev_conns, &tmp_list);
+       INIT_LIST_HEAD(&iw_nodev_conns);
+       spin_unlock_irq(&iw_nodev_conns_lock);
+
+       list_for_each_entry_safe(ic, _ic, &tmp_list, iw_node) {
+               if (ic->conn->c_passive)
+                       rds_conn_destroy(ic->conn->c_passive);
+               rds_conn_destroy(ic->conn);
+       }
+}
+
+void rds_iw_remove_conns(struct rds_iw_device *rds_iwdev)
+{
+       struct rds_iw_connection *ic, *_ic;
+       LIST_HEAD(tmp_list);
+
+       /* avoid calling conn_destroy with irqs off */
+       spin_lock_irq(&rds_iwdev->spinlock);
+       list_splice(&rds_iwdev->conn_list, &tmp_list);
+       INIT_LIST_HEAD(&rds_iwdev->conn_list);
+       spin_unlock_irq(&rds_iwdev->spinlock);
+
+       list_for_each_entry_safe(ic, _ic, &tmp_list, iw_node) {
+               if (ic->conn->c_passive)
+                       rds_conn_destroy(ic->conn->c_passive);
+               rds_conn_destroy(ic->conn);
+       }
+}
+
+static void rds_iw_set_scatterlist(struct rds_iw_scatterlist *sg,
+               struct scatterlist *list, unsigned int sg_len)
+{
+       sg->list = list;
+       sg->len = sg_len;
+       sg->dma_len = 0;
+       sg->dma_npages = 0;
+       sg->bytes = 0;
+}
+
+static u64 *rds_iw_map_scatterlist(struct rds_iw_device *rds_iwdev,
+                       struct rds_iw_scatterlist *sg,
+                       unsigned int dma_page_shift)
+{
+       struct ib_device *dev = rds_iwdev->dev;
+       u64 *dma_pages = NULL;
+       u64 dma_mask;
+       unsigned int dma_page_size;
+       int i, j, ret;
+
+       dma_page_size = 1 << dma_page_shift;
+       dma_mask = dma_page_size - 1;
+
+       WARN_ON(sg->dma_len);
+
+       sg->dma_len = ib_dma_map_sg(dev, sg->list, sg->len, DMA_BIDIRECTIONAL);
+       if (unlikely(!sg->dma_len)) {
+               printk(KERN_WARNING "RDS/IW: dma_map_sg failed!\n");
+               return ERR_PTR(-EBUSY);
+       }
+
+       sg->bytes = 0;
+       sg->dma_npages = 0;
+
+       ret = -EINVAL;
+       for (i = 0; i < sg->dma_len; ++i) {
+               unsigned int dma_len = ib_sg_dma_len(dev, &sg->list[i]);
+               u64 dma_addr = ib_sg_dma_address(dev, &sg->list[i]);
+               u64 end_addr;
+
+               sg->bytes += dma_len;
+
+               end_addr = dma_addr + dma_len;
+               if (dma_addr & dma_mask) {
+                       if (i > 0)
+                               goto out_unmap;
+                       dma_addr &= ~dma_mask;
+               }
+               if (end_addr & dma_mask) {
+                       if (i < sg->dma_len - 1)
+                               goto out_unmap;
+                       end_addr = (end_addr + dma_mask) & ~dma_mask;
+               }
+
+               sg->dma_npages += (end_addr - dma_addr) >> dma_page_shift;
+       }
+
+       /* Now gather the dma addrs into one list */
+       if (sg->dma_npages > fastreg_message_size)
+               goto out_unmap;
+
+       dma_pages = kmalloc(sizeof(u64) * sg->dma_npages, GFP_ATOMIC);
+       if (!dma_pages) {
+               ret = -ENOMEM;
+               goto out_unmap;
+       }
+
+       for (i = j = 0; i < sg->dma_len; ++i) {
+               unsigned int dma_len = ib_sg_dma_len(dev, &sg->list[i]);
+               u64 dma_addr = ib_sg_dma_address(dev, &sg->list[i]);
+               u64 end_addr;
+
+               end_addr = dma_addr + dma_len;
+               dma_addr &= ~dma_mask;
+               for (; dma_addr < end_addr; dma_addr += dma_page_size)
+                       dma_pages[j++] = dma_addr;
+               BUG_ON(j > sg->dma_npages);
+       }
+
+       return dma_pages;
+
+out_unmap:
+       ib_dma_unmap_sg(rds_iwdev->dev, sg->list, sg->len, DMA_BIDIRECTIONAL);
+       sg->dma_len = 0;
+       kfree(dma_pages);
+       return ERR_PTR(ret);
+}
+
+
+struct rds_iw_mr_pool *rds_iw_create_mr_pool(struct rds_iw_device *rds_iwdev)
+{
+       struct rds_iw_mr_pool *pool;
+
+       pool = kzalloc(sizeof(*pool), GFP_KERNEL);
+       if (!pool) {
+               printk(KERN_WARNING "RDS/IW: rds_iw_create_mr_pool alloc error\n");
+               return ERR_PTR(-ENOMEM);
+       }
+
+       pool->device = rds_iwdev;
+       INIT_LIST_HEAD(&pool->dirty_list);
+       INIT_LIST_HEAD(&pool->clean_list);
+       mutex_init(&pool->flush_lock);
+       spin_lock_init(&pool->list_lock);
+       INIT_WORK(&pool->flush_worker, rds_iw_mr_pool_flush_worker);
+
+       pool->max_message_size = fastreg_message_size;
+       pool->max_items = fastreg_pool_size;
+       pool->max_free_pinned = pool->max_items * pool->max_message_size / 4;
+       pool->max_pages = fastreg_message_size;
+
+       /* We never allow more than max_items MRs to be allocated.
+        * When we exceed more than max_items_soft, we start freeing
+        * items more aggressively.
+        * Make sure that max_items > max_items_soft > max_items / 2
+        */
+       pool->max_items_soft = pool->max_items * 3 / 4;
+
+       return pool;
+}
+
+void rds_iw_get_mr_info(struct rds_iw_device *rds_iwdev, struct rds_info_rdma_connection *iinfo)
+{
+       struct rds_iw_mr_pool *pool = rds_iwdev->mr_pool;
+
+       iinfo->rdma_mr_max = pool->max_items;
+       iinfo->rdma_mr_size = pool->max_pages;
+}
+
+void rds_iw_destroy_mr_pool(struct rds_iw_mr_pool *pool)
+{
+       flush_workqueue(rds_wq);
+       rds_iw_flush_mr_pool(pool, 1);
+       BUG_ON(atomic_read(&pool->item_count));
+       BUG_ON(atomic_read(&pool->free_pinned));
+       kfree(pool);
+}
+
+static inline struct rds_iw_mr *rds_iw_reuse_fmr(struct rds_iw_mr_pool *pool)
+{
+       struct rds_iw_mr *ibmr = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&pool->list_lock, flags);
+       if (!list_empty(&pool->clean_list)) {
+               ibmr = list_entry(pool->clean_list.next, struct rds_iw_mr, mapping.m_list);
+               list_del_init(&ibmr->mapping.m_list);
+       }
+       spin_unlock_irqrestore(&pool->list_lock, flags);
+
+       return ibmr;
+}
+
+static struct rds_iw_mr *rds_iw_alloc_mr(struct rds_iw_device *rds_iwdev)
+{
+       struct rds_iw_mr_pool *pool = rds_iwdev->mr_pool;
+       struct rds_iw_mr *ibmr = NULL;
+       int err = 0, iter = 0;
+
+       while (1) {
+               ibmr = rds_iw_reuse_fmr(pool);
+               if (ibmr)
+                       return ibmr;
+
+               /* No clean MRs - now we have the choice of either
+                * allocating a fresh MR up to the limit imposed by the
+                * driver, or flush any dirty unused MRs.
+                * We try to avoid stalling in the send path if possible,
+                * so we allocate as long as we're allowed to.
+                *
+                * We're fussy with enforcing the FMR limit, though. If the driver
+                * tells us we can't use more than N fmrs, we shouldn't start
+                * arguing with it */
+               if (atomic_inc_return(&pool->item_count) <= pool->max_items)
+                       break;
+
+               atomic_dec(&pool->item_count);
+
+               if (++iter > 2) {
+                       rds_iw_stats_inc(s_iw_rdma_mr_pool_depleted);
+                       return ERR_PTR(-EAGAIN);
+               }
+
+               /* We do have some empty MRs. Flush them out. */
+               rds_iw_stats_inc(s_iw_rdma_mr_pool_wait);
+               rds_iw_flush_mr_pool(pool, 0);
+       }
+
+       ibmr = kzalloc(sizeof(*ibmr), GFP_KERNEL);
+       if (!ibmr) {
+               err = -ENOMEM;
+               goto out_no_cigar;
+       }
+
+       spin_lock_init(&ibmr->mapping.m_lock);
+       INIT_LIST_HEAD(&ibmr->mapping.m_list);
+       ibmr->mapping.m_mr = ibmr;
+
+       err = rds_iw_init_fastreg(pool, ibmr);
+       if (err)
+               goto out_no_cigar;
+
+       rds_iw_stats_inc(s_iw_rdma_mr_alloc);
+       return ibmr;
+
+out_no_cigar:
+       if (ibmr) {
+               rds_iw_destroy_fastreg(pool, ibmr);
+               kfree(ibmr);
+       }
+       atomic_dec(&pool->item_count);
+       return ERR_PTR(err);
+}
+
+void rds_iw_sync_mr(void *trans_private, int direction)
+{
+       struct rds_iw_mr *ibmr = trans_private;
+       struct rds_iw_device *rds_iwdev = ibmr->device;
+
+       switch (direction) {
+       case DMA_FROM_DEVICE:
+               ib_dma_sync_sg_for_cpu(rds_iwdev->dev, ibmr->mapping.m_sg.list,
+                       ibmr->mapping.m_sg.dma_len, DMA_BIDIRECTIONAL);
+               break;
+       case DMA_TO_DEVICE:
+               ib_dma_sync_sg_for_device(rds_iwdev->dev, ibmr->mapping.m_sg.list,
+                       ibmr->mapping.m_sg.dma_len, DMA_BIDIRECTIONAL);
+               break;
+       }
+}
+
+static inline unsigned int rds_iw_flush_goal(struct rds_iw_mr_pool *pool, int free_all)
+{
+       unsigned int item_count;
+
+       item_count = atomic_read(&pool->item_count);
+       if (free_all)
+               return item_count;
+
+       return 0;
+}
+
+/*
+ * Flush our pool of MRs.
+ * At a minimum, all currently unused MRs are unmapped.
+ * If the number of MRs allocated exceeds the limit, we also try
+ * to free as many MRs as needed to get back to this limit.
+ */
+static int rds_iw_flush_mr_pool(struct rds_iw_mr_pool *pool, int free_all)
+{
+       struct rds_iw_mr *ibmr, *next;
+       LIST_HEAD(unmap_list);
+       LIST_HEAD(kill_list);
+       unsigned long flags;
+       unsigned int nfreed = 0, ncleaned = 0, free_goal;
+       int ret = 0;
+
+       rds_iw_stats_inc(s_iw_rdma_mr_pool_flush);
+
+       mutex_lock(&pool->flush_lock);
+
+       spin_lock_irqsave(&pool->list_lock, flags);
+       /* Get the list of all mappings to be destroyed */
+       list_splice_init(&pool->dirty_list, &unmap_list);
+       if (free_all)
+               list_splice_init(&pool->clean_list, &kill_list);
+       spin_unlock_irqrestore(&pool->list_lock, flags);
+
+       free_goal = rds_iw_flush_goal(pool, free_all);
+
+       /* Batched invalidate of dirty MRs.
+        * For FMR based MRs, the mappings on the unmap list are
+        * actually members of an ibmr (ibmr->mapping). They either
+        * migrate to the kill_list, or have been cleaned and should be
+        * moved to the clean_list.
+        * For fastregs, they will be dynamically allocated, and
+        * will be destroyed by the unmap function.
+        */
+       if (!list_empty(&unmap_list)) {
+               ncleaned = rds_iw_unmap_fastreg_list(pool, &unmap_list, &kill_list);
+               /* If we've been asked to destroy all MRs, move those
+                * that were simply cleaned to the kill list */
+               if (free_all)
+                       list_splice_init(&unmap_list, &kill_list);
+       }
+
+       /* Destroy any MRs that are past their best before date */
+       list_for_each_entry_safe(ibmr, next, &kill_list, mapping.m_list) {
+               rds_iw_stats_inc(s_iw_rdma_mr_free);
+               list_del(&ibmr->mapping.m_list);
+               rds_iw_destroy_fastreg(pool, ibmr);
+               kfree(ibmr);
+               nfreed++;
+       }
+
+       /* Anything that remains are laundered ibmrs, which we can add
+        * back to the clean list. */
+       if (!list_empty(&unmap_list)) {
+               spin_lock_irqsave(&pool->list_lock, flags);
+               list_splice(&unmap_list, &pool->clean_list);
+               spin_unlock_irqrestore(&pool->list_lock, flags);
+       }
+
+       atomic_sub(ncleaned, &pool->dirty_count);
+       atomic_sub(nfreed, &pool->item_count);
+
+       mutex_unlock(&pool->flush_lock);
+       return ret;
+}
+
+static void rds_iw_mr_pool_flush_worker(struct work_struct *work)
+{
+       struct rds_iw_mr_pool *pool = container_of(work, struct rds_iw_mr_pool, flush_worker);
+
+       rds_iw_flush_mr_pool(pool, 0);
+}
+
+void rds_iw_free_mr(void *trans_private, int invalidate)
+{
+       struct rds_iw_mr *ibmr = trans_private;
+       struct rds_iw_mr_pool *pool = ibmr->device->mr_pool;
+
+       rdsdebug("RDS/IW: free_mr nents %u\n", ibmr->mapping.m_sg.len);
+       if (!pool)
+               return;
+
+       /* Return it to the pool's free list */
+       rds_iw_free_fastreg(pool, ibmr);
+
+       /* If we've pinned too many pages, request a flush */
+       if (atomic_read(&pool->free_pinned) >= pool->max_free_pinned
+        || atomic_read(&pool->dirty_count) >= pool->max_items / 10)
+               queue_work(rds_wq, &pool->flush_worker);
+
+       if (invalidate) {
+               if (likely(!in_interrupt())) {
+                       rds_iw_flush_mr_pool(pool, 0);
+               } else {
+                       /* We get here if the user created a MR marked
+                        * as use_once and invalidate at the same time. */
+                       queue_work(rds_wq, &pool->flush_worker);
+               }
+       }
+}
+
+void rds_iw_flush_mrs(void)
+{
+       struct rds_iw_device *rds_iwdev;
+
+       list_for_each_entry(rds_iwdev, &rds_iw_devices, list) {
+               struct rds_iw_mr_pool *pool = rds_iwdev->mr_pool;
+
+               if (pool)
+                       rds_iw_flush_mr_pool(pool, 0);
+       }
+}
+
+void *rds_iw_get_mr(struct scatterlist *sg, unsigned long nents,
+                   struct rds_sock *rs, u32 *key_ret)
+{
+       struct rds_iw_device *rds_iwdev;
+       struct rds_iw_mr *ibmr = NULL;
+       struct rdma_cm_id *cm_id;
+       int ret;
+
+       ret = rds_iw_get_device(rs, &rds_iwdev, &cm_id);
+       if (ret || !cm_id) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       if (!rds_iwdev->mr_pool) {
+               ret = -ENODEV;
+               goto out;
+       }
+
+       ibmr = rds_iw_alloc_mr(rds_iwdev);
+       if (IS_ERR(ibmr))
+               return ibmr;
+
+       ibmr->cm_id = cm_id;
+       ibmr->device = rds_iwdev;
+
+       ret = rds_iw_map_fastreg(rds_iwdev->mr_pool, ibmr, sg, nents);
+       if (ret == 0)
+               *key_ret = ibmr->mr->rkey;
+       else
+               printk(KERN_WARNING "RDS/IW: failed to map mr (errno=%d)\n", ret);
+
+out:
+       if (ret) {
+               if (ibmr)
+                       rds_iw_free_mr(ibmr, 0);
+               ibmr = ERR_PTR(ret);
+       }
+       return ibmr;
+}
+
+/*
+ * iWARP fastreg handling
+ *
+ * The life cycle of a fastreg registration is a bit different from
+ * FMRs.
+ * The idea behind fastreg is to have one MR, to which we bind different
+ * mappings over time. To avoid stalling on the expensive map and invalidate
+ * operations, these operations are pipelined on the same send queue on
+ * which we want to send the message containing the r_key.
+ *
+ * This creates a bit of a problem for us, as we do not have the destination
+ * IP in GET_MR, so the connection must be setup prior to the GET_MR call for
+ * RDMA to be correctly setup.  If a fastreg request is present, rds_iw_xmit
+ * will try to queue a LOCAL_INV (if needed) and a FAST_REG_MR work request
+ * before queuing the SEND. When completions for these arrive, they are
+ * dispatched to the MR has a bit set showing that RDMa can be performed.
+ *
+ * There is another interesting aspect that's related to invalidation.
+ * The application can request that a mapping is invalidated in FREE_MR.
+ * The expectation there is that this invalidation step includes ALL
+ * PREVIOUSLY FREED MRs.
+ */
+static int rds_iw_init_fastreg(struct rds_iw_mr_pool *pool,
+                               struct rds_iw_mr *ibmr)
+{
+       struct rds_iw_device *rds_iwdev = pool->device;
+       struct ib_fast_reg_page_list *page_list = NULL;
+       struct ib_mr *mr;
+       int err;
+
+       mr = ib_alloc_fast_reg_mr(rds_iwdev->pd, pool->max_message_size);
+       if (IS_ERR(mr)) {
+               err = PTR_ERR(mr);
+
+               printk(KERN_WARNING "RDS/IW: ib_alloc_fast_reg_mr failed (err=%d)\n", err);
+               return err;
+       }
+
+       /* FIXME - this is overkill, but mapping->m_sg.dma_len/mapping->m_sg.dma_npages
+        * is not filled in.
+        */
+       page_list = ib_alloc_fast_reg_page_list(rds_iwdev->dev, pool->max_message_size);
+       if (IS_ERR(page_list)) {
+               err = PTR_ERR(page_list);
+
+               printk(KERN_WARNING "RDS/IW: ib_alloc_fast_reg_page_list failed (err=%d)\n", err);
+               ib_dereg_mr(mr);
+               return err;
+       }
+
+       ibmr->page_list = page_list;
+       ibmr->mr = mr;
+       return 0;
+}
+
+static int rds_iw_rdma_build_fastreg(struct rds_iw_mapping *mapping)
+{
+       struct rds_iw_mr *ibmr = mapping->m_mr;
+       struct ib_send_wr f_wr, *failed_wr;
+       int ret;
+
+       /*
+        * Perform a WR for the fast_reg_mr. Each individual page
+        * in the sg list is added to the fast reg page list and placed
+        * inside the fast_reg_mr WR.  The key used is a rolling 8bit
+        * counter, which should guarantee uniqueness.
+        */
+       ib_update_fast_reg_key(ibmr->mr, ibmr->remap_count++);
+       mapping->m_rkey = ibmr->mr->rkey;
+
+       memset(&f_wr, 0, sizeof(f_wr));
+       f_wr.wr_id = RDS_IW_FAST_REG_WR_ID;
+       f_wr.opcode = IB_WR_FAST_REG_MR;
+       f_wr.wr.fast_reg.length = mapping->m_sg.bytes;
+       f_wr.wr.fast_reg.rkey = mapping->m_rkey;
+       f_wr.wr.fast_reg.page_list = ibmr->page_list;
+       f_wr.wr.fast_reg.page_list_len = mapping->m_sg.dma_len;
+       f_wr.wr.fast_reg.page_shift = ibmr->device->page_shift;
+       f_wr.wr.fast_reg.access_flags = IB_ACCESS_LOCAL_WRITE |
+                               IB_ACCESS_REMOTE_READ |
+                               IB_ACCESS_REMOTE_WRITE;
+       f_wr.wr.fast_reg.iova_start = 0;
+       f_wr.send_flags = IB_SEND_SIGNALED;
+
+       failed_wr = &f_wr;
+       ret = ib_post_send(ibmr->cm_id->qp, &f_wr, &failed_wr);
+       BUG_ON(failed_wr != &f_wr);
+       if (ret && printk_ratelimit())
+               printk(KERN_WARNING "RDS/IW: %s:%d ib_post_send returned %d\n",
+                       __func__, __LINE__, ret);
+       return ret;
+}
+
+static int rds_iw_rdma_fastreg_inv(struct rds_iw_mr *ibmr)
+{
+       struct ib_send_wr s_wr, *failed_wr;
+       int ret = 0;
+
+       if (!ibmr->cm_id->qp || !ibmr->mr)
+               goto out;
+
+       memset(&s_wr, 0, sizeof(s_wr));
+       s_wr.wr_id = RDS_IW_LOCAL_INV_WR_ID;
+       s_wr.opcode = IB_WR_LOCAL_INV;
+       s_wr.ex.invalidate_rkey = ibmr->mr->rkey;
+       s_wr.send_flags = IB_SEND_SIGNALED;
+
+       failed_wr = &s_wr;
+       ret = ib_post_send(ibmr->cm_id->qp, &s_wr, &failed_wr);
+       if (ret && printk_ratelimit()) {
+               printk(KERN_WARNING "RDS/IW: %s:%d ib_post_send returned %d\n",
+                       __func__, __LINE__, ret);
+               goto out;
+       }
+out:
+       return ret;
+}
+
+static int rds_iw_map_fastreg(struct rds_iw_mr_pool *pool,
+                       struct rds_iw_mr *ibmr,
+                       struct scatterlist *sg,
+                       unsigned int sg_len)
+{
+       struct rds_iw_device *rds_iwdev = pool->device;
+       struct rds_iw_mapping *mapping = &ibmr->mapping;
+       u64 *dma_pages;
+       int i, ret = 0;
+
+       rds_iw_set_scatterlist(&mapping->m_sg, sg, sg_len);
+
+       dma_pages = rds_iw_map_scatterlist(rds_iwdev,
+                               &mapping->m_sg,
+                               rds_iwdev->page_shift);
+       if (IS_ERR(dma_pages)) {
+               ret = PTR_ERR(dma_pages);
+               dma_pages = NULL;
+               goto out;
+       }
+
+       if (mapping->m_sg.dma_len > pool->max_message_size) {
+               ret = -EMSGSIZE;
+               goto out;
+       }
+
+       for (i = 0; i < mapping->m_sg.dma_npages; ++i)
+               ibmr->page_list->page_list[i] = dma_pages[i];
+
+       ret = rds_iw_rdma_build_fastreg(mapping);
+       if (ret)
+               goto out;
+
+       rds_iw_stats_inc(s_iw_rdma_mr_used);
+
+out:
+       kfree(dma_pages);
+
+       return ret;
+}
+
+/*
+ * "Free" a fastreg MR.
+ */
+static void rds_iw_free_fastreg(struct rds_iw_mr_pool *pool,
+               struct rds_iw_mr *ibmr)
+{
+       unsigned long flags;
+       int ret;
+
+       if (!ibmr->mapping.m_sg.dma_len)
+               return;
+
+       ret = rds_iw_rdma_fastreg_inv(ibmr);
+       if (ret)
+               return;
+
+       /* Try to post the LOCAL_INV WR to the queue. */
+       spin_lock_irqsave(&pool->list_lock, flags);
+
+       list_add_tail(&ibmr->mapping.m_list, &pool->dirty_list);
+       atomic_add(ibmr->mapping.m_sg.len, &pool->free_pinned);
+       atomic_inc(&pool->dirty_count);
+
+       spin_unlock_irqrestore(&pool->list_lock, flags);
+}
+
+static unsigned int rds_iw_unmap_fastreg_list(struct rds_iw_mr_pool *pool,
+                               struct list_head *unmap_list,
+                               struct list_head *kill_list)
+{
+       struct rds_iw_mapping *mapping, *next;
+       unsigned int ncleaned = 0;
+       LIST_HEAD(laundered);
+
+       /* Batched invalidation of fastreg MRs.
+        * Why do we do it this way, even though we could pipeline unmap
+        * and remap? The reason is the application semantics - when the
+        * application requests an invalidation of MRs, it expects all
+        * previously released R_Keys to become invalid.
+        *
+        * If we implement MR reuse naively, we risk memory corruption
+        * (this has actually been observed). So the default behavior
+        * requires that a MR goes through an explicit unmap operation before
+        * we can reuse it again.
+        *
+        * We could probably improve on this a little, by allowing immediate
+        * reuse of a MR on the same socket (eg you could add small
+        * cache of unused MRs to strct rds_socket - GET_MR could grab one
+        * of these without requiring an explicit invalidate).
+        */
+       while (!list_empty(unmap_list)) {
+               unsigned long flags;
+
+               spin_lock_irqsave(&pool->list_lock, flags);
+               list_for_each_entry_safe(mapping, next, unmap_list, m_list) {
+                       list_move(&mapping->m_list, &laundered);
+                       ncleaned++;
+               }
+               spin_unlock_irqrestore(&pool->list_lock, flags);
+       }
+
+       /* Move all laundered mappings back to the unmap list.
+        * We do not kill any WRs right now - it doesn't seem the
+        * fastreg API has a max_remap limit. */
+       list_splice_init(&laundered, unmap_list);
+
+       return ncleaned;
+}
+
+static void rds_iw_destroy_fastreg(struct rds_iw_mr_pool *pool,
+               struct rds_iw_mr *ibmr)
+{
+       if (ibmr->page_list)
+               ib_free_fast_reg_page_list(ibmr->page_list);
+       if (ibmr->mr)
+               ib_dereg_mr(ibmr->mr);
+}
diff --git a/net/rds/iw_recv.c b/net/rds/iw_recv.c
new file mode 100644 (file)
index 0000000..a1931f0
--- /dev/null
@@ -0,0 +1,869 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/pci.h>
+#include <linux/dma-mapping.h>
+#include <rdma/rdma_cm.h>
+
+#include "rds.h"
+#include "iw.h"
+
+static struct kmem_cache *rds_iw_incoming_slab;
+static struct kmem_cache *rds_iw_frag_slab;
+static atomic_t        rds_iw_allocation = ATOMIC_INIT(0);
+
+static void rds_iw_frag_drop_page(struct rds_page_frag *frag)
+{
+       rdsdebug("frag %p page %p\n", frag, frag->f_page);
+       __free_page(frag->f_page);
+       frag->f_page = NULL;
+}
+
+static void rds_iw_frag_free(struct rds_page_frag *frag)
+{
+       rdsdebug("frag %p page %p\n", frag, frag->f_page);
+       BUG_ON(frag->f_page != NULL);
+       kmem_cache_free(rds_iw_frag_slab, frag);
+}
+
+/*
+ * We map a page at a time.  Its fragments are posted in order.  This
+ * is called in fragment order as the fragments get send completion events.
+ * Only the last frag in the page performs the unmapping.
+ *
+ * It's OK for ring cleanup to call this in whatever order it likes because
+ * DMA is not in flight and so we can unmap while other ring entries still
+ * hold page references in their frags.
+ */
+static void rds_iw_recv_unmap_page(struct rds_iw_connection *ic,
+                                  struct rds_iw_recv_work *recv)
+{
+       struct rds_page_frag *frag = recv->r_frag;
+
+       rdsdebug("recv %p frag %p page %p\n", recv, frag, frag->f_page);
+       if (frag->f_mapped)
+               ib_dma_unmap_page(ic->i_cm_id->device,
+                              frag->f_mapped,
+                              RDS_FRAG_SIZE, DMA_FROM_DEVICE);
+       frag->f_mapped = 0;
+}
+
+void rds_iw_recv_init_ring(struct rds_iw_connection *ic)
+{
+       struct rds_iw_recv_work *recv;
+       u32 i;
+
+       for (i = 0, recv = ic->i_recvs; i < ic->i_recv_ring.w_nr; i++, recv++) {
+               struct ib_sge *sge;
+
+               recv->r_iwinc = NULL;
+               recv->r_frag = NULL;
+
+               recv->r_wr.next = NULL;
+               recv->r_wr.wr_id = i;
+               recv->r_wr.sg_list = recv->r_sge;
+               recv->r_wr.num_sge = RDS_IW_RECV_SGE;
+
+               sge = rds_iw_data_sge(ic, recv->r_sge);
+               sge->addr = 0;
+               sge->length = RDS_FRAG_SIZE;
+               sge->lkey = 0;
+
+               sge = rds_iw_header_sge(ic, recv->r_sge);
+               sge->addr = ic->i_recv_hdrs_dma + (i * sizeof(struct rds_header));
+               sge->length = sizeof(struct rds_header);
+               sge->lkey = 0;
+       }
+}
+
+static void rds_iw_recv_clear_one(struct rds_iw_connection *ic,
+                                 struct rds_iw_recv_work *recv)
+{
+       if (recv->r_iwinc) {
+               rds_inc_put(&recv->r_iwinc->ii_inc);
+               recv->r_iwinc = NULL;
+       }
+       if (recv->r_frag) {
+               rds_iw_recv_unmap_page(ic, recv);
+               if (recv->r_frag->f_page)
+                       rds_iw_frag_drop_page(recv->r_frag);
+               rds_iw_frag_free(recv->r_frag);
+               recv->r_frag = NULL;
+       }
+}
+
+void rds_iw_recv_clear_ring(struct rds_iw_connection *ic)
+{
+       u32 i;
+
+       for (i = 0; i < ic->i_recv_ring.w_nr; i++)
+               rds_iw_recv_clear_one(ic, &ic->i_recvs[i]);
+
+       if (ic->i_frag.f_page)
+               rds_iw_frag_drop_page(&ic->i_frag);
+}
+
+static int rds_iw_recv_refill_one(struct rds_connection *conn,
+                                 struct rds_iw_recv_work *recv,
+                                 gfp_t kptr_gfp, gfp_t page_gfp)
+{
+       struct rds_iw_connection *ic = conn->c_transport_data;
+       dma_addr_t dma_addr;
+       struct ib_sge *sge;
+       int ret = -ENOMEM;
+
+       if (recv->r_iwinc == NULL) {
+               if (atomic_read(&rds_iw_allocation) >= rds_iw_sysctl_max_recv_allocation) {
+                       rds_iw_stats_inc(s_iw_rx_alloc_limit);
+                       goto out;
+               }
+               recv->r_iwinc = kmem_cache_alloc(rds_iw_incoming_slab,
+                                                kptr_gfp);
+               if (recv->r_iwinc == NULL)
+                       goto out;
+               atomic_inc(&rds_iw_allocation);
+               INIT_LIST_HEAD(&recv->r_iwinc->ii_frags);
+               rds_inc_init(&recv->r_iwinc->ii_inc, conn, conn->c_faddr);
+       }
+
+       if (recv->r_frag == NULL) {
+               recv->r_frag = kmem_cache_alloc(rds_iw_frag_slab, kptr_gfp);
+               if (recv->r_frag == NULL)
+                       goto out;
+               INIT_LIST_HEAD(&recv->r_frag->f_item);
+               recv->r_frag->f_page = NULL;
+       }
+
+       if (ic->i_frag.f_page == NULL) {
+               ic->i_frag.f_page = alloc_page(page_gfp);
+               if (ic->i_frag.f_page == NULL)
+                       goto out;
+               ic->i_frag.f_offset = 0;
+       }
+
+       dma_addr = ib_dma_map_page(ic->i_cm_id->device,
+                                 ic->i_frag.f_page,
+                                 ic->i_frag.f_offset,
+                                 RDS_FRAG_SIZE,
+                                 DMA_FROM_DEVICE);
+       if (ib_dma_mapping_error(ic->i_cm_id->device, dma_addr))
+               goto out;
+
+       /*
+        * Once we get the RDS_PAGE_LAST_OFF frag then rds_iw_frag_unmap()
+        * must be called on this recv.  This happens as completions hit
+        * in order or on connection shutdown.
+        */
+       recv->r_frag->f_page = ic->i_frag.f_page;
+       recv->r_frag->f_offset = ic->i_frag.f_offset;
+       recv->r_frag->f_mapped = dma_addr;
+
+       sge = rds_iw_data_sge(ic, recv->r_sge);
+       sge->addr = dma_addr;
+       sge->length = RDS_FRAG_SIZE;
+
+       sge = rds_iw_header_sge(ic, recv->r_sge);
+       sge->addr = ic->i_recv_hdrs_dma + (recv - ic->i_recvs) * sizeof(struct rds_header);
+       sge->length = sizeof(struct rds_header);
+
+       get_page(recv->r_frag->f_page);
+
+       if (ic->i_frag.f_offset < RDS_PAGE_LAST_OFF) {
+               ic->i_frag.f_offset += RDS_FRAG_SIZE;
+       } else {
+               put_page(ic->i_frag.f_page);
+               ic->i_frag.f_page = NULL;
+               ic->i_frag.f_offset = 0;
+       }
+
+       ret = 0;
+out:
+       return ret;
+}
+
+/*
+ * This tries to allocate and post unused work requests after making sure that
+ * they have all the allocations they need to queue received fragments into
+ * sockets.  The i_recv_mutex is held here so that ring_alloc and _unalloc
+ * pairs don't go unmatched.
+ *
+ * -1 is returned if posting fails due to temporary resource exhaustion.
+ */
+int rds_iw_recv_refill(struct rds_connection *conn, gfp_t kptr_gfp,
+                      gfp_t page_gfp, int prefill)
+{
+       struct rds_iw_connection *ic = conn->c_transport_data;
+       struct rds_iw_recv_work *recv;
+       struct ib_recv_wr *failed_wr;
+       unsigned int posted = 0;
+       int ret = 0;
+       u32 pos;
+
+       while ((prefill || rds_conn_up(conn))
+                       && rds_iw_ring_alloc(&ic->i_recv_ring, 1, &pos)) {
+               if (pos >= ic->i_recv_ring.w_nr) {
+                       printk(KERN_NOTICE "Argh - ring alloc returned pos=%u\n",
+                                       pos);
+                       ret = -EINVAL;
+                       break;
+               }
+
+               recv = &ic->i_recvs[pos];
+               ret = rds_iw_recv_refill_one(conn, recv, kptr_gfp, page_gfp);
+               if (ret) {
+                       ret = -1;
+                       break;
+               }
+
+               /* XXX when can this fail? */
+               ret = ib_post_recv(ic->i_cm_id->qp, &recv->r_wr, &failed_wr);
+               rdsdebug("recv %p iwinc %p page %p addr %lu ret %d\n", recv,
+                        recv->r_iwinc, recv->r_frag->f_page,
+                        (long) recv->r_frag->f_mapped, ret);
+               if (ret) {
+                       rds_iw_conn_error(conn, "recv post on "
+                              "%pI4 returned %d, disconnecting and "
+                              "reconnecting\n", &conn->c_faddr,
+                              ret);
+                       ret = -1;
+                       break;
+               }
+
+               posted++;
+       }
+
+       /* We're doing flow control - update the window. */
+       if (ic->i_flowctl && posted)
+               rds_iw_advertise_credits(conn, posted);
+
+       if (ret)
+               rds_iw_ring_unalloc(&ic->i_recv_ring, 1);
+       return ret;
+}
+
+void rds_iw_inc_purge(struct rds_incoming *inc)
+{
+       struct rds_iw_incoming *iwinc;
+       struct rds_page_frag *frag;
+       struct rds_page_frag *pos;
+
+       iwinc = container_of(inc, struct rds_iw_incoming, ii_inc);
+       rdsdebug("purging iwinc %p inc %p\n", iwinc, inc);
+
+       list_for_each_entry_safe(frag, pos, &iwinc->ii_frags, f_item) {
+               list_del_init(&frag->f_item);
+               rds_iw_frag_drop_page(frag);
+               rds_iw_frag_free(frag);
+       }
+}
+
+void rds_iw_inc_free(struct rds_incoming *inc)
+{
+       struct rds_iw_incoming *iwinc;
+
+       iwinc = container_of(inc, struct rds_iw_incoming, ii_inc);
+
+       rds_iw_inc_purge(inc);
+       rdsdebug("freeing iwinc %p inc %p\n", iwinc, inc);
+       BUG_ON(!list_empty(&iwinc->ii_frags));
+       kmem_cache_free(rds_iw_incoming_slab, iwinc);
+       atomic_dec(&rds_iw_allocation);
+       BUG_ON(atomic_read(&rds_iw_allocation) < 0);
+}
+
+int rds_iw_inc_copy_to_user(struct rds_incoming *inc, struct iovec *first_iov,
+                           size_t size)
+{
+       struct rds_iw_incoming *iwinc;
+       struct rds_page_frag *frag;
+       struct iovec *iov = first_iov;
+       unsigned long to_copy;
+       unsigned long frag_off = 0;
+       unsigned long iov_off = 0;
+       int copied = 0;
+       int ret;
+       u32 len;
+
+       iwinc = container_of(inc, struct rds_iw_incoming, ii_inc);
+       frag = list_entry(iwinc->ii_frags.next, struct rds_page_frag, f_item);
+       len = be32_to_cpu(inc->i_hdr.h_len);
+
+       while (copied < size && copied < len) {
+               if (frag_off == RDS_FRAG_SIZE) {
+                       frag = list_entry(frag->f_item.next,
+                                         struct rds_page_frag, f_item);
+                       frag_off = 0;
+               }
+               while (iov_off == iov->iov_len) {
+                       iov_off = 0;
+                       iov++;
+               }
+
+               to_copy = min(iov->iov_len - iov_off, RDS_FRAG_SIZE - frag_off);
+               to_copy = min_t(size_t, to_copy, size - copied);
+               to_copy = min_t(unsigned long, to_copy, len - copied);
+
+               rdsdebug("%lu bytes to user [%p, %zu] + %lu from frag "
+                        "[%p, %lu] + %lu\n",
+                        to_copy, iov->iov_base, iov->iov_len, iov_off,
+                        frag->f_page, frag->f_offset, frag_off);
+
+               /* XXX needs + offset for multiple recvs per page */
+               ret = rds_page_copy_to_user(frag->f_page,
+                                           frag->f_offset + frag_off,
+                                           iov->iov_base + iov_off,
+                                           to_copy);
+               if (ret) {
+                       copied = ret;
+                       break;
+               }
+
+               iov_off += to_copy;
+               frag_off += to_copy;
+               copied += to_copy;
+       }
+
+       return copied;
+}
+
+/* ic starts out kzalloc()ed */
+void rds_iw_recv_init_ack(struct rds_iw_connection *ic)
+{
+       struct ib_send_wr *wr = &ic->i_ack_wr;
+       struct ib_sge *sge = &ic->i_ack_sge;
+
+       sge->addr = ic->i_ack_dma;
+       sge->length = sizeof(struct rds_header);
+       sge->lkey = rds_iw_local_dma_lkey(ic);
+
+       wr->sg_list = sge;
+       wr->num_sge = 1;
+       wr->opcode = IB_WR_SEND;
+       wr->wr_id = RDS_IW_ACK_WR_ID;
+       wr->send_flags = IB_SEND_SIGNALED | IB_SEND_SOLICITED;
+}
+
+/*
+ * You'd think that with reliable IB connections you wouldn't need to ack
+ * messages that have been received.  The problem is that IB hardware generates
+ * an ack message before it has DMAed the message into memory.  This creates a
+ * potential message loss if the HCA is disabled for any reason between when it
+ * sends the ack and before the message is DMAed and processed.  This is only a
+ * potential issue if another HCA is available for fail-over.
+ *
+ * When the remote host receives our ack they'll free the sent message from
+ * their send queue.  To decrease the latency of this we always send an ack
+ * immediately after we've received messages.
+ *
+ * For simplicity, we only have one ack in flight at a time.  This puts
+ * pressure on senders to have deep enough send queues to absorb the latency of
+ * a single ack frame being in flight.  This might not be good enough.
+ *
+ * This is implemented by have a long-lived send_wr and sge which point to a
+ * statically allocated ack frame.  This ack wr does not fall under the ring
+ * accounting that the tx and rx wrs do.  The QP attribute specifically makes
+ * room for it beyond the ring size.  Send completion notices its special
+ * wr_id and avoids working with the ring in that case.
+ */
+static void rds_iw_set_ack(struct rds_iw_connection *ic, u64 seq,
+                               int ack_required)
+{
+       rds_iw_set_64bit(&ic->i_ack_next, seq);
+       if (ack_required) {
+               smp_mb__before_clear_bit();
+               set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
+       }
+}
+
+static u64 rds_iw_get_ack(struct rds_iw_connection *ic)
+{
+       clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
+       smp_mb__after_clear_bit();
+
+       return ic->i_ack_next;
+}
+
+static void rds_iw_send_ack(struct rds_iw_connection *ic, unsigned int adv_credits)
+{
+       struct rds_header *hdr = ic->i_ack;
+       struct ib_send_wr *failed_wr;
+       u64 seq;
+       int ret;
+
+       seq = rds_iw_get_ack(ic);
+
+       rdsdebug("send_ack: ic %p ack %llu\n", ic, (unsigned long long) seq);
+       rds_message_populate_header(hdr, 0, 0, 0);
+       hdr->h_ack = cpu_to_be64(seq);
+       hdr->h_credit = adv_credits;
+       rds_message_make_checksum(hdr);
+       ic->i_ack_queued = jiffies;
+
+       ret = ib_post_send(ic->i_cm_id->qp, &ic->i_ack_wr, &failed_wr);
+       if (unlikely(ret)) {
+               /* Failed to send. Release the WR, and
+                * force another ACK.
+                */
+               clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags);
+               set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
+
+               rds_iw_stats_inc(s_iw_ack_send_failure);
+               /* Need to finesse this later. */
+               BUG();
+       } else
+               rds_iw_stats_inc(s_iw_ack_sent);
+}
+
+/*
+ * There are 3 ways of getting acknowledgements to the peer:
+ *  1. We call rds_iw_attempt_ack from the recv completion handler
+ *     to send an ACK-only frame.
+ *     However, there can be only one such frame in the send queue
+ *     at any time, so we may have to postpone it.
+ *  2. When another (data) packet is transmitted while there's
+ *     an ACK in the queue, we piggyback the ACK sequence number
+ *     on the data packet.
+ *  3. If the ACK WR is done sending, we get called from the
+ *     send queue completion handler, and check whether there's
+ *     another ACK pending (postponed because the WR was on the
+ *     queue). If so, we transmit it.
+ *
+ * We maintain 2 variables:
+ *  -  i_ack_flags, which keeps track of whether the ACK WR
+ *     is currently in the send queue or not (IB_ACK_IN_FLIGHT)
+ *  -  i_ack_next, which is the last sequence number we received
+ *
+ * Potentially, send queue and receive queue handlers can run concurrently.
+ *
+ * Reconnecting complicates this picture just slightly. When we
+ * reconnect, we may be seeing duplicate packets. The peer
+ * is retransmitting them, because it hasn't seen an ACK for
+ * them. It is important that we ACK these.
+ *
+ * ACK mitigation adds a header flag "ACK_REQUIRED"; any packet with
+ * this flag set *MUST* be acknowledged immediately.
+ */
+
+/*
+ * When we get here, we're called from the recv queue handler.
+ * Check whether we ought to transmit an ACK.
+ */
+void rds_iw_attempt_ack(struct rds_iw_connection *ic)
+{
+       unsigned int adv_credits;
+
+       if (!test_bit(IB_ACK_REQUESTED, &ic->i_ack_flags))
+               return;
+
+       if (test_and_set_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags)) {
+               rds_iw_stats_inc(s_iw_ack_send_delayed);
+               return;
+       }
+
+       /* Can we get a send credit? */
+       if (!rds_iw_send_grab_credits(ic, 1, &adv_credits, 0)) {
+               rds_iw_stats_inc(s_iw_tx_throttle);
+               clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags);
+               return;
+       }
+
+       clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
+       rds_iw_send_ack(ic, adv_credits);
+}
+
+/*
+ * We get here from the send completion handler, when the
+ * adapter tells us the ACK frame was sent.
+ */
+void rds_iw_ack_send_complete(struct rds_iw_connection *ic)
+{
+       clear_bit(IB_ACK_IN_FLIGHT, &ic->i_ack_flags);
+       rds_iw_attempt_ack(ic);
+}
+
+/*
+ * This is called by the regular xmit code when it wants to piggyback
+ * an ACK on an outgoing frame.
+ */
+u64 rds_iw_piggyb_ack(struct rds_iw_connection *ic)
+{
+       if (test_and_clear_bit(IB_ACK_REQUESTED, &ic->i_ack_flags))
+               rds_iw_stats_inc(s_iw_ack_send_piggybacked);
+       return rds_iw_get_ack(ic);
+}
+
+/*
+ * It's kind of lame that we're copying from the posted receive pages into
+ * long-lived bitmaps.  We could have posted the bitmaps and rdma written into
+ * them.  But receiving new congestion bitmaps should be a *rare* event, so
+ * hopefully we won't need to invest that complexity in making it more
+ * efficient.  By copying we can share a simpler core with TCP which has to
+ * copy.
+ */
+static void rds_iw_cong_recv(struct rds_connection *conn,
+                             struct rds_iw_incoming *iwinc)
+{
+       struct rds_cong_map *map;
+       unsigned int map_off;
+       unsigned int map_page;
+       struct rds_page_frag *frag;
+       unsigned long frag_off;
+       unsigned long to_copy;
+       unsigned long copied;
+       uint64_t uncongested = 0;
+       void *addr;
+
+       /* catch completely corrupt packets */
+       if (be32_to_cpu(iwinc->ii_inc.i_hdr.h_len) != RDS_CONG_MAP_BYTES)
+               return;
+
+       map = conn->c_fcong;
+       map_page = 0;
+       map_off = 0;
+
+       frag = list_entry(iwinc->ii_frags.next, struct rds_page_frag, f_item);
+       frag_off = 0;
+
+       copied = 0;
+
+       while (copied < RDS_CONG_MAP_BYTES) {
+               uint64_t *src, *dst;
+               unsigned int k;
+
+               to_copy = min(RDS_FRAG_SIZE - frag_off, PAGE_SIZE - map_off);
+               BUG_ON(to_copy & 7); /* Must be 64bit aligned. */
+
+               addr = kmap_atomic(frag->f_page, KM_SOFTIRQ0);
+
+               src = addr + frag_off;
+               dst = (void *)map->m_page_addrs[map_page] + map_off;
+               for (k = 0; k < to_copy; k += 8) {
+                       /* Record ports that became uncongested, ie
+                        * bits that changed from 0 to 1. */
+                       uncongested |= ~(*src) & *dst;
+                       *dst++ = *src++;
+               }
+               kunmap_atomic(addr, KM_SOFTIRQ0);
+
+               copied += to_copy;
+
+               map_off += to_copy;
+               if (map_off == PAGE_SIZE) {
+                       map_off = 0;
+                       map_page++;
+               }
+
+               frag_off += to_copy;
+               if (frag_off == RDS_FRAG_SIZE) {
+                       frag = list_entry(frag->f_item.next,
+                                         struct rds_page_frag, f_item);
+                       frag_off = 0;
+               }
+       }
+
+       /* the congestion map is in little endian order */
+       uncongested = le64_to_cpu(uncongested);
+
+       rds_cong_map_updated(map, uncongested);
+}
+
+/*
+ * Rings are posted with all the allocations they'll need to queue the
+ * incoming message to the receiving socket so this can't fail.
+ * All fragments start with a header, so we can make sure we're not receiving
+ * garbage, and we can tell a small 8 byte fragment from an ACK frame.
+ */
+struct rds_iw_ack_state {
+       u64             ack_next;
+       u64             ack_recv;
+       unsigned int    ack_required:1;
+       unsigned int    ack_next_valid:1;
+       unsigned int    ack_recv_valid:1;
+};
+
+static void rds_iw_process_recv(struct rds_connection *conn,
+                               struct rds_iw_recv_work *recv, u32 byte_len,
+                               struct rds_iw_ack_state *state)
+{
+       struct rds_iw_connection *ic = conn->c_transport_data;
+       struct rds_iw_incoming *iwinc = ic->i_iwinc;
+       struct rds_header *ihdr, *hdr;
+
+       /* XXX shut down the connection if port 0,0 are seen? */
+
+       rdsdebug("ic %p iwinc %p recv %p byte len %u\n", ic, iwinc, recv,
+                byte_len);
+
+       if (byte_len < sizeof(struct rds_header)) {
+               rds_iw_conn_error(conn, "incoming message "
+                      "from %pI4 didn't inclue a "
+                      "header, disconnecting and "
+                      "reconnecting\n",
+                      &conn->c_faddr);
+               return;
+       }
+       byte_len -= sizeof(struct rds_header);
+
+       ihdr = &ic->i_recv_hdrs[recv - ic->i_recvs];
+
+       /* Validate the checksum. */
+       if (!rds_message_verify_checksum(ihdr)) {
+               rds_iw_conn_error(conn, "incoming message "
+                      "from %pI4 has corrupted header - "
+                      "forcing a reconnect\n",
+                      &conn->c_faddr);
+               rds_stats_inc(s_recv_drop_bad_checksum);
+               return;
+       }
+
+       /* Process the ACK sequence which comes with every packet */
+       state->ack_recv = be64_to_cpu(ihdr->h_ack);
+       state->ack_recv_valid = 1;
+
+       /* Process the credits update if there was one */
+       if (ihdr->h_credit)
+               rds_iw_send_add_credits(conn, ihdr->h_credit);
+
+       if (ihdr->h_sport == 0 && ihdr->h_dport == 0 && byte_len == 0) {
+               /* This is an ACK-only packet. The fact that it gets
+                * special treatment here is that historically, ACKs
+                * were rather special beasts.
+                */
+               rds_iw_stats_inc(s_iw_ack_received);
+
+               /*
+                * Usually the frags make their way on to incs and are then freed as
+                * the inc is freed.  We don't go that route, so we have to drop the
+                * page ref ourselves.  We can't just leave the page on the recv
+                * because that confuses the dma mapping of pages and each recv's use
+                * of a partial page.  We can leave the frag, though, it will be
+                * reused.
+                *
+                * FIXME: Fold this into the code path below.
+                */
+               rds_iw_frag_drop_page(recv->r_frag);
+               return;
+       }
+
+       /*
+        * If we don't already have an inc on the connection then this
+        * fragment has a header and starts a message.. copy its header
+        * into the inc and save the inc so we can hang upcoming fragments
+        * off its list.
+        */
+       if (iwinc == NULL) {
+               iwinc = recv->r_iwinc;
+               recv->r_iwinc = NULL;
+               ic->i_iwinc = iwinc;
+
+               hdr = &iwinc->ii_inc.i_hdr;
+               memcpy(hdr, ihdr, sizeof(*hdr));
+               ic->i_recv_data_rem = be32_to_cpu(hdr->h_len);
+
+               rdsdebug("ic %p iwinc %p rem %u flag 0x%x\n", ic, iwinc,
+                        ic->i_recv_data_rem, hdr->h_flags);
+       } else {
+               hdr = &iwinc->ii_inc.i_hdr;
+               /* We can't just use memcmp here; fragments of a
+                * single message may carry different ACKs */
+               if (hdr->h_sequence != ihdr->h_sequence
+                || hdr->h_len != ihdr->h_len
+                || hdr->h_sport != ihdr->h_sport
+                || hdr->h_dport != ihdr->h_dport) {
+                       rds_iw_conn_error(conn,
+                               "fragment header mismatch; forcing reconnect\n");
+                       return;
+               }
+       }
+
+       list_add_tail(&recv->r_frag->f_item, &iwinc->ii_frags);
+       recv->r_frag = NULL;
+
+       if (ic->i_recv_data_rem > RDS_FRAG_SIZE)
+               ic->i_recv_data_rem -= RDS_FRAG_SIZE;
+       else {
+               ic->i_recv_data_rem = 0;
+               ic->i_iwinc = NULL;
+
+               if (iwinc->ii_inc.i_hdr.h_flags == RDS_FLAG_CONG_BITMAP)
+                       rds_iw_cong_recv(conn, iwinc);
+               else {
+                       rds_recv_incoming(conn, conn->c_faddr, conn->c_laddr,
+                                         &iwinc->ii_inc, GFP_ATOMIC,
+                                         KM_SOFTIRQ0);
+                       state->ack_next = be64_to_cpu(hdr->h_sequence);
+                       state->ack_next_valid = 1;
+               }
+
+               /* Evaluate the ACK_REQUIRED flag *after* we received
+                * the complete frame, and after bumping the next_rx
+                * sequence. */
+               if (hdr->h_flags & RDS_FLAG_ACK_REQUIRED) {
+                       rds_stats_inc(s_recv_ack_required);
+                       state->ack_required = 1;
+               }
+
+               rds_inc_put(&iwinc->ii_inc);
+       }
+}
+
+/*
+ * Plucking the oldest entry from the ring can be done concurrently with
+ * the thread refilling the ring.  Each ring operation is protected by
+ * spinlocks and the transient state of refilling doesn't change the
+ * recording of which entry is oldest.
+ *
+ * This relies on IB only calling one cq comp_handler for each cq so that
+ * there will only be one caller of rds_recv_incoming() per RDS connection.
+ */
+void rds_iw_recv_cq_comp_handler(struct ib_cq *cq, void *context)
+{
+       struct rds_connection *conn = context;
+       struct rds_iw_connection *ic = conn->c_transport_data;
+       struct ib_wc wc;
+       struct rds_iw_ack_state state = { 0, };
+       struct rds_iw_recv_work *recv;
+
+       rdsdebug("conn %p cq %p\n", conn, cq);
+
+       rds_iw_stats_inc(s_iw_rx_cq_call);
+
+       ib_req_notify_cq(cq, IB_CQ_SOLICITED);
+
+       while (ib_poll_cq(cq, 1, &wc) > 0) {
+               rdsdebug("wc wr_id 0x%llx status %u byte_len %u imm_data %u\n",
+                        (unsigned long long)wc.wr_id, wc.status, wc.byte_len,
+                        be32_to_cpu(wc.ex.imm_data));
+               rds_iw_stats_inc(s_iw_rx_cq_event);
+
+               recv = &ic->i_recvs[rds_iw_ring_oldest(&ic->i_recv_ring)];
+
+               rds_iw_recv_unmap_page(ic, recv);
+
+               /*
+                * Also process recvs in connecting state because it is possible
+                * to get a recv completion _before_ the rdmacm ESTABLISHED
+                * event is processed.
+                */
+               if (rds_conn_up(conn) || rds_conn_connecting(conn)) {
+                       /* We expect errors as the qp is drained during shutdown */
+                       if (wc.status == IB_WC_SUCCESS) {
+                               rds_iw_process_recv(conn, recv, wc.byte_len, &state);
+                       } else {
+                               rds_iw_conn_error(conn, "recv completion on "
+                                      "%pI4 had status %u, disconnecting and "
+                                      "reconnecting\n", &conn->c_faddr,
+                                      wc.status);
+                       }
+               }
+
+               rds_iw_ring_free(&ic->i_recv_ring, 1);
+       }
+
+       if (state.ack_next_valid)
+               rds_iw_set_ack(ic, state.ack_next, state.ack_required);
+       if (state.ack_recv_valid && state.ack_recv > ic->i_ack_recv) {
+               rds_send_drop_acked(conn, state.ack_recv, NULL);
+               ic->i_ack_recv = state.ack_recv;
+       }
+       if (rds_conn_up(conn))
+               rds_iw_attempt_ack(ic);
+
+       /* If we ever end up with a really empty receive ring, we're
+        * in deep trouble, as the sender will definitely see RNR
+        * timeouts. */
+       if (rds_iw_ring_empty(&ic->i_recv_ring))
+               rds_iw_stats_inc(s_iw_rx_ring_empty);
+
+       /*
+        * If the ring is running low, then schedule the thread to refill.
+        */
+       if (rds_iw_ring_low(&ic->i_recv_ring))
+               queue_delayed_work(rds_wq, &conn->c_recv_w, 0);
+}
+
+int rds_iw_recv(struct rds_connection *conn)
+{
+       struct rds_iw_connection *ic = conn->c_transport_data;
+       int ret = 0;
+
+       rdsdebug("conn %p\n", conn);
+
+       /*
+        * If we get a temporary posting failure in this context then
+        * we're really low and we want the caller to back off for a bit.
+        */
+       mutex_lock(&ic->i_recv_mutex);
+       if (rds_iw_recv_refill(conn, GFP_KERNEL, GFP_HIGHUSER, 0))
+               ret = -ENOMEM;
+       else
+               rds_iw_stats_inc(s_iw_rx_refill_from_thread);
+       mutex_unlock(&ic->i_recv_mutex);
+
+       if (rds_conn_up(conn))
+               rds_iw_attempt_ack(ic);
+
+       return ret;
+}
+
+int __init rds_iw_recv_init(void)
+{
+       struct sysinfo si;
+       int ret = -ENOMEM;
+
+       /* Default to 30% of all available RAM for recv memory */
+       si_meminfo(&si);
+       rds_iw_sysctl_max_recv_allocation = si.totalram / 3 * PAGE_SIZE / RDS_FRAG_SIZE;
+
+       rds_iw_incoming_slab = kmem_cache_create("rds_iw_incoming",
+                                       sizeof(struct rds_iw_incoming),
+                                       0, 0, NULL);
+       if (rds_iw_incoming_slab == NULL)
+               goto out;
+
+       rds_iw_frag_slab = kmem_cache_create("rds_iw_frag",
+                                       sizeof(struct rds_page_frag),
+                                       0, 0, NULL);
+       if (rds_iw_frag_slab == NULL)
+               kmem_cache_destroy(rds_iw_incoming_slab);
+       else
+               ret = 0;
+out:
+       return ret;
+}
+
+void rds_iw_recv_exit(void)
+{
+       kmem_cache_destroy(rds_iw_incoming_slab);
+       kmem_cache_destroy(rds_iw_frag_slab);
+}
diff --git a/net/rds/iw_ring.c b/net/rds/iw_ring.c
new file mode 100644 (file)
index 0000000..d422d4b
--- /dev/null
@@ -0,0 +1,169 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+
+#include "rds.h"
+#include "iw.h"
+
+/*
+ * Locking for IB rings.
+ * We assume that allocation is always protected by a mutex
+ * in the caller (this is a valid assumption for the current
+ * implementation).
+ *
+ * Freeing always happens in an interrupt, and hence only
+ * races with allocations, but not with other free()s.
+ *
+ * The interaction between allocation and freeing is that
+ * the alloc code has to determine the number of free entries.
+ * To this end, we maintain two counters; an allocation counter
+ * and a free counter. Both are allowed to run freely, and wrap
+ * around.
+ * The number of used entries is always (alloc_ctr - free_ctr) % NR.
+ *
+ * The current implementation makes free_ctr atomic. When the
+ * caller finds an allocation fails, it should set an "alloc fail"
+ * bit and retry the allocation. The "alloc fail" bit essentially tells
+ * the CQ completion handlers to wake it up after freeing some
+ * more entries.
+ */
+
+/*
+ * This only happens on shutdown.
+ */
+DECLARE_WAIT_QUEUE_HEAD(rds_iw_ring_empty_wait);
+
+void rds_iw_ring_init(struct rds_iw_work_ring *ring, u32 nr)
+{
+       memset(ring, 0, sizeof(*ring));
+       ring->w_nr = nr;
+       rdsdebug("ring %p nr %u\n", ring, ring->w_nr);
+}
+
+static inline u32 __rds_iw_ring_used(struct rds_iw_work_ring *ring)
+{
+       u32 diff;
+
+       /* This assumes that atomic_t has at least as many bits as u32 */
+       diff = ring->w_alloc_ctr - (u32) atomic_read(&ring->w_free_ctr);
+       BUG_ON(diff > ring->w_nr);
+
+       return diff;
+}
+
+void rds_iw_ring_resize(struct rds_iw_work_ring *ring, u32 nr)
+{
+       /* We only ever get called from the connection setup code,
+        * prior to creating the QP. */
+       BUG_ON(__rds_iw_ring_used(ring));
+       ring->w_nr = nr;
+}
+
+static int __rds_iw_ring_empty(struct rds_iw_work_ring *ring)
+{
+       return __rds_iw_ring_used(ring) == 0;
+}
+
+u32 rds_iw_ring_alloc(struct rds_iw_work_ring *ring, u32 val, u32 *pos)
+{
+       u32 ret = 0, avail;
+
+       avail = ring->w_nr - __rds_iw_ring_used(ring);
+
+       rdsdebug("ring %p val %u next %u free %u\n", ring, val,
+                ring->w_alloc_ptr, avail);
+
+       if (val && avail) {
+               ret = min(val, avail);
+               *pos = ring->w_alloc_ptr;
+
+               ring->w_alloc_ptr = (ring->w_alloc_ptr + ret) % ring->w_nr;
+               ring->w_alloc_ctr += ret;
+       }
+
+       return ret;
+}
+
+void rds_iw_ring_free(struct rds_iw_work_ring *ring, u32 val)
+{
+       ring->w_free_ptr = (ring->w_free_ptr + val) % ring->w_nr;
+       atomic_add(val, &ring->w_free_ctr);
+
+       if (__rds_iw_ring_empty(ring) &&
+           waitqueue_active(&rds_iw_ring_empty_wait))
+               wake_up(&rds_iw_ring_empty_wait);
+}
+
+void rds_iw_ring_unalloc(struct rds_iw_work_ring *ring, u32 val)
+{
+       ring->w_alloc_ptr = (ring->w_alloc_ptr - val) % ring->w_nr;
+       ring->w_alloc_ctr -= val;
+}
+
+int rds_iw_ring_empty(struct rds_iw_work_ring *ring)
+{
+       return __rds_iw_ring_empty(ring);
+}
+
+int rds_iw_ring_low(struct rds_iw_work_ring *ring)
+{
+       return __rds_iw_ring_used(ring) <= (ring->w_nr >> 2);
+}
+
+
+/*
+ * returns the oldest alloced ring entry.  This will be the next one
+ * freed.  This can't be called if there are none allocated.
+ */
+u32 rds_iw_ring_oldest(struct rds_iw_work_ring *ring)
+{
+       return ring->w_free_ptr;
+}
+
+/*
+ * returns the number of completed work requests.
+ */
+
+u32 rds_iw_ring_completed(struct rds_iw_work_ring *ring, u32 wr_id, u32 oldest)
+{
+       u32 ret;
+
+       if (oldest <= (unsigned long long)wr_id)
+               ret = (unsigned long long)wr_id - oldest + 1;
+       else
+               ret = ring->w_nr - oldest + (unsigned long long)wr_id + 1;
+
+       rdsdebug("ring %p ret %u wr_id %u oldest %u\n", ring, ret,
+                wr_id, oldest);
+       return ret;
+}
diff --git a/net/rds/iw_send.c b/net/rds/iw_send.c
new file mode 100644 (file)
index 0000000..22dd38f
--- /dev/null
@@ -0,0 +1,975 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/in.h>
+#include <linux/device.h>
+#include <linux/dmapool.h>
+
+#include "rds.h"
+#include "rdma.h"
+#include "iw.h"
+
+static void rds_iw_send_rdma_complete(struct rds_message *rm,
+                                     int wc_status)
+{
+       int notify_status;
+
+       switch (wc_status) {
+       case IB_WC_WR_FLUSH_ERR:
+               return;
+
+       case IB_WC_SUCCESS:
+               notify_status = RDS_RDMA_SUCCESS;
+               break;
+
+       case IB_WC_REM_ACCESS_ERR:
+               notify_status = RDS_RDMA_REMOTE_ERROR;
+               break;
+
+       default:
+               notify_status = RDS_RDMA_OTHER_ERROR;
+               break;
+       }
+       rds_rdma_send_complete(rm, notify_status);
+}
+
+static void rds_iw_send_unmap_rdma(struct rds_iw_connection *ic,
+                                  struct rds_rdma_op *op)
+{
+       if (op->r_mapped) {
+               ib_dma_unmap_sg(ic->i_cm_id->device,
+                       op->r_sg, op->r_nents,
+                       op->r_write ? DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               op->r_mapped = 0;
+       }
+}
+
+static void rds_iw_send_unmap_rm(struct rds_iw_connection *ic,
+                         struct rds_iw_send_work *send,
+                         int wc_status)
+{
+       struct rds_message *rm = send->s_rm;
+
+       rdsdebug("ic %p send %p rm %p\n", ic, send, rm);
+
+       ib_dma_unmap_sg(ic->i_cm_id->device,
+                    rm->m_sg, rm->m_nents,
+                    DMA_TO_DEVICE);
+
+       if (rm->m_rdma_op != NULL) {
+               rds_iw_send_unmap_rdma(ic, rm->m_rdma_op);
+
+               /* If the user asked for a completion notification on this
+                * message, we can implement three different semantics:
+                *  1.  Notify when we received the ACK on the RDS message
+                *      that was queued with the RDMA. This provides reliable
+                *      notification of RDMA status at the expense of a one-way
+                *      packet delay.
+                *  2.  Notify when the IB stack gives us the completion event for
+                *      the RDMA operation.
+                *  3.  Notify when the IB stack gives us the completion event for
+                *      the accompanying RDS messages.
+                * Here, we implement approach #3. To implement approach #2,
+                * call rds_rdma_send_complete from the cq_handler. To implement #1,
+                * don't call rds_rdma_send_complete at all, and fall back to the notify
+                * handling in the ACK processing code.
+                *
+                * Note: There's no need to explicitly sync any RDMA buffers using
+                * ib_dma_sync_sg_for_cpu - the completion for the RDMA
+                * operation itself unmapped the RDMA buffers, which takes care
+                * of synching.
+                */
+               rds_iw_send_rdma_complete(rm, wc_status);
+
+               if (rm->m_rdma_op->r_write)
+                       rds_stats_add(s_send_rdma_bytes, rm->m_rdma_op->r_bytes);
+               else
+                       rds_stats_add(s_recv_rdma_bytes, rm->m_rdma_op->r_bytes);
+       }
+
+       /* If anyone waited for this message to get flushed out, wake
+        * them up now */
+       rds_message_unmapped(rm);
+
+       rds_message_put(rm);
+       send->s_rm = NULL;
+}
+
+void rds_iw_send_init_ring(struct rds_iw_connection *ic)
+{
+       struct rds_iw_send_work *send;
+       u32 i;
+
+       for (i = 0, send = ic->i_sends; i < ic->i_send_ring.w_nr; i++, send++) {
+               struct ib_sge *sge;
+
+               send->s_rm = NULL;
+               send->s_op = NULL;
+               send->s_mapping = NULL;
+
+               send->s_wr.next = NULL;
+               send->s_wr.wr_id = i;
+               send->s_wr.sg_list = send->s_sge;
+               send->s_wr.num_sge = 1;
+               send->s_wr.opcode = IB_WR_SEND;
+               send->s_wr.send_flags = 0;
+               send->s_wr.ex.imm_data = 0;
+
+               sge = rds_iw_data_sge(ic, send->s_sge);
+               sge->lkey = 0;
+
+               sge = rds_iw_header_sge(ic, send->s_sge);
+               sge->addr = ic->i_send_hdrs_dma + (i * sizeof(struct rds_header));
+               sge->length = sizeof(struct rds_header);
+               sge->lkey = 0;
+
+               send->s_mr = ib_alloc_fast_reg_mr(ic->i_pd, fastreg_message_size);
+               if (IS_ERR(send->s_mr)) {
+                       printk(KERN_WARNING "RDS/IW: ib_alloc_fast_reg_mr failed\n");
+                       break;
+               }
+
+               send->s_page_list = ib_alloc_fast_reg_page_list(
+                       ic->i_cm_id->device, fastreg_message_size);
+               if (IS_ERR(send->s_page_list)) {
+                       printk(KERN_WARNING "RDS/IW: ib_alloc_fast_reg_page_list failed\n");
+                       break;
+               }
+       }
+}
+
+void rds_iw_send_clear_ring(struct rds_iw_connection *ic)
+{
+       struct rds_iw_send_work *send;
+       u32 i;
+
+       for (i = 0, send = ic->i_sends; i < ic->i_send_ring.w_nr; i++, send++) {
+               BUG_ON(!send->s_mr);
+               ib_dereg_mr(send->s_mr);
+               BUG_ON(!send->s_page_list);
+               ib_free_fast_reg_page_list(send->s_page_list);
+               if (send->s_wr.opcode == 0xdead)
+                       continue;
+               if (send->s_rm)
+                       rds_iw_send_unmap_rm(ic, send, IB_WC_WR_FLUSH_ERR);
+               if (send->s_op)
+                       rds_iw_send_unmap_rdma(ic, send->s_op);
+       }
+}
+
+/*
+ * The _oldest/_free ring operations here race cleanly with the alloc/unalloc
+ * operations performed in the send path.  As the sender allocs and potentially
+ * unallocs the next free entry in the ring it doesn't alter which is
+ * the next to be freed, which is what this is concerned with.
+ */
+void rds_iw_send_cq_comp_handler(struct ib_cq *cq, void *context)
+{
+       struct rds_connection *conn = context;
+       struct rds_iw_connection *ic = conn->c_transport_data;
+       struct ib_wc wc;
+       struct rds_iw_send_work *send;
+       u32 completed;
+       u32 oldest;
+       u32 i;
+       int ret;
+
+       rdsdebug("cq %p conn %p\n", cq, conn);
+       rds_iw_stats_inc(s_iw_tx_cq_call);
+       ret = ib_req_notify_cq(cq, IB_CQ_NEXT_COMP);
+       if (ret)
+               rdsdebug("ib_req_notify_cq send failed: %d\n", ret);
+
+       while (ib_poll_cq(cq, 1, &wc) > 0) {
+               rdsdebug("wc wr_id 0x%llx status %u byte_len %u imm_data %u\n",
+                        (unsigned long long)wc.wr_id, wc.status, wc.byte_len,
+                        be32_to_cpu(wc.ex.imm_data));
+               rds_iw_stats_inc(s_iw_tx_cq_event);
+
+               if (wc.status != IB_WC_SUCCESS) {
+                       printk(KERN_ERR "WC Error:  status = %d opcode = %d\n", wc.status, wc.opcode);
+                       break;
+               }
+
+               if (wc.opcode == IB_WC_LOCAL_INV && wc.wr_id == RDS_IW_LOCAL_INV_WR_ID) {
+                       ic->i_fastreg_posted = 0;
+                       continue;
+               }
+
+               if (wc.opcode == IB_WC_FAST_REG_MR && wc.wr_id == RDS_IW_FAST_REG_WR_ID) {
+                       ic->i_fastreg_posted = 1;
+                       continue;
+               }
+
+               if (wc.wr_id == RDS_IW_ACK_WR_ID) {
+                       if (ic->i_ack_queued + HZ/2 < jiffies)
+                               rds_iw_stats_inc(s_iw_tx_stalled);
+                       rds_iw_ack_send_complete(ic);
+                       continue;
+               }
+
+               oldest = rds_iw_ring_oldest(&ic->i_send_ring);
+
+               completed = rds_iw_ring_completed(&ic->i_send_ring, wc.wr_id, oldest);
+
+               for (i = 0; i < completed; i++) {
+                       send = &ic->i_sends[oldest];
+
+                       /* In the error case, wc.opcode sometimes contains garbage */
+                       switch (send->s_wr.opcode) {
+                       case IB_WR_SEND:
+                               if (send->s_rm)
+                                       rds_iw_send_unmap_rm(ic, send, wc.status);
+                               break;
+                       case IB_WR_FAST_REG_MR:
+                       case IB_WR_RDMA_WRITE:
+                       case IB_WR_RDMA_READ:
+                       case IB_WR_RDMA_READ_WITH_INV:
+                               /* Nothing to be done - the SG list will be unmapped
+                                * when the SEND completes. */
+                               break;
+                       default:
+                               if (printk_ratelimit())
+                                       printk(KERN_NOTICE
+                                               "RDS/IW: %s: unexpected opcode 0x%x in WR!\n",
+                                               __func__, send->s_wr.opcode);
+                               break;
+                       }
+
+                       send->s_wr.opcode = 0xdead;
+                       send->s_wr.num_sge = 1;
+                       if (send->s_queued + HZ/2 < jiffies)
+                               rds_iw_stats_inc(s_iw_tx_stalled);
+
+                       /* If a RDMA operation produced an error, signal this right
+                        * away. If we don't, the subsequent SEND that goes with this
+                        * RDMA will be canceled with ERR_WFLUSH, and the application
+                        * never learn that the RDMA failed. */
+                       if (unlikely(wc.status == IB_WC_REM_ACCESS_ERR && send->s_op)) {
+                               struct rds_message *rm;
+
+                               rm = rds_send_get_message(conn, send->s_op);
+                               if (rm)
+                                       rds_iw_send_rdma_complete(rm, wc.status);
+                       }
+
+                       oldest = (oldest + 1) % ic->i_send_ring.w_nr;
+               }
+
+               rds_iw_ring_free(&ic->i_send_ring, completed);
+
+               if (test_and_clear_bit(RDS_LL_SEND_FULL, &conn->c_flags)
+                || test_bit(0, &conn->c_map_queued))
+                       queue_delayed_work(rds_wq, &conn->c_send_w, 0);
+
+               /* We expect errors as the qp is drained during shutdown */
+               if (wc.status != IB_WC_SUCCESS && rds_conn_up(conn)) {
+                       rds_iw_conn_error(conn,
+                               "send completion on %pI4 "
+                               "had status %u, disconnecting and reconnecting\n",
+                               &conn->c_faddr, wc.status);
+               }
+       }
+}
+
+/*
+ * This is the main function for allocating credits when sending
+ * messages.
+ *
+ * Conceptually, we have two counters:
+ *  -  send credits: this tells us how many WRs we're allowed
+ *     to submit without overruning the reciever's queue. For
+ *     each SEND WR we post, we decrement this by one.
+ *
+ *  -  posted credits: this tells us how many WRs we recently
+ *     posted to the receive queue. This value is transferred
+ *     to the peer as a "credit update" in a RDS header field.
+ *     Every time we transmit credits to the peer, we subtract
+ *     the amount of transferred credits from this counter.
+ *
+ * It is essential that we avoid situations where both sides have
+ * exhausted their send credits, and are unable to send new credits
+ * to the peer. We achieve this by requiring that we send at least
+ * one credit update to the peer before exhausting our credits.
+ * When new credits arrive, we subtract one credit that is withheld
+ * until we've posted new buffers and are ready to transmit these
+ * credits (see rds_iw_send_add_credits below).
+ *
+ * The RDS send code is essentially single-threaded; rds_send_xmit
+ * grabs c_send_lock to ensure exclusive access to the send ring.
+ * However, the ACK sending code is independent and can race with
+ * message SENDs.
+ *
+ * In the send path, we need to update the counters for send credits
+ * and the counter of posted buffers atomically - when we use the
+ * last available credit, we cannot allow another thread to race us
+ * and grab the posted credits counter.  Hence, we have to use a
+ * spinlock to protect the credit counter, or use atomics.
+ *
+ * Spinlocks shared between the send and the receive path are bad,
+ * because they create unnecessary delays. An early implementation
+ * using a spinlock showed a 5% degradation in throughput at some
+ * loads.
+ *
+ * This implementation avoids spinlocks completely, putting both
+ * counters into a single atomic, and updating that atomic using
+ * atomic_add (in the receive path, when receiving fresh credits),
+ * and using atomic_cmpxchg when updating the two counters.
+ */
+int rds_iw_send_grab_credits(struct rds_iw_connection *ic,
+                            u32 wanted, u32 *adv_credits, int need_posted)
+{
+       unsigned int avail, posted, got = 0, advertise;
+       long oldval, newval;
+
+       *adv_credits = 0;
+       if (!ic->i_flowctl)
+               return wanted;
+
+try_again:
+       advertise = 0;
+       oldval = newval = atomic_read(&ic->i_credits);
+       posted = IB_GET_POST_CREDITS(oldval);
+       avail = IB_GET_SEND_CREDITS(oldval);
+
+       rdsdebug("rds_iw_send_grab_credits(%u): credits=%u posted=%u\n",
+                       wanted, avail, posted);
+
+       /* The last credit must be used to send a credit update. */
+       if (avail && !posted)
+               avail--;
+
+       if (avail < wanted) {
+               struct rds_connection *conn = ic->i_cm_id->context;
+
+               /* Oops, there aren't that many credits left! */
+               set_bit(RDS_LL_SEND_FULL, &conn->c_flags);
+               got = avail;
+       } else {
+               /* Sometimes you get what you want, lalala. */
+               got = wanted;
+       }
+       newval -= IB_SET_SEND_CREDITS(got);
+
+       /*
+        * If need_posted is non-zero, then the caller wants
+        * the posted regardless of whether any send credits are
+        * available.
+        */
+       if (posted && (got || need_posted)) {
+               advertise = min_t(unsigned int, posted, RDS_MAX_ADV_CREDIT);
+               newval -= IB_SET_POST_CREDITS(advertise);
+       }
+
+       /* Finally bill everything */
+       if (atomic_cmpxchg(&ic->i_credits, oldval, newval) != oldval)
+               goto try_again;
+
+       *adv_credits = advertise;
+       return got;
+}
+
+void rds_iw_send_add_credits(struct rds_connection *conn, unsigned int credits)
+{
+       struct rds_iw_connection *ic = conn->c_transport_data;
+
+       if (credits == 0)
+               return;
+
+       rdsdebug("rds_iw_send_add_credits(%u): current=%u%s\n",
+                       credits,
+                       IB_GET_SEND_CREDITS(atomic_read(&ic->i_credits)),
+                       test_bit(RDS_LL_SEND_FULL, &conn->c_flags) ? ", ll_send_full" : "");
+
+       atomic_add(IB_SET_SEND_CREDITS(credits), &ic->i_credits);
+       if (test_and_clear_bit(RDS_LL_SEND_FULL, &conn->c_flags))
+               queue_delayed_work(rds_wq, &conn->c_send_w, 0);
+
+       WARN_ON(IB_GET_SEND_CREDITS(credits) >= 16384);
+
+       rds_iw_stats_inc(s_iw_rx_credit_updates);
+}
+
+void rds_iw_advertise_credits(struct rds_connection *conn, unsigned int posted)
+{
+       struct rds_iw_connection *ic = conn->c_transport_data;
+
+       if (posted == 0)
+               return;
+
+       atomic_add(IB_SET_POST_CREDITS(posted), &ic->i_credits);
+
+       /* Decide whether to send an update to the peer now.
+        * If we would send a credit update for every single buffer we
+        * post, we would end up with an ACK storm (ACK arrives,
+        * consumes buffer, we refill the ring, send ACK to remote
+        * advertising the newly posted buffer... ad inf)
+        *
+        * Performance pretty much depends on how often we send
+        * credit updates - too frequent updates mean lots of ACKs.
+        * Too infrequent updates, and the peer will run out of
+        * credits and has to throttle.
+        * For the time being, 16 seems to be a good compromise.
+        */
+       if (IB_GET_POST_CREDITS(atomic_read(&ic->i_credits)) >= 16)
+               set_bit(IB_ACK_REQUESTED, &ic->i_ack_flags);
+}
+
+static inline void
+rds_iw_xmit_populate_wr(struct rds_iw_connection *ic,
+               struct rds_iw_send_work *send, unsigned int pos,
+               unsigned long buffer, unsigned int length,
+               int send_flags)
+{
+       struct ib_sge *sge;
+
+       WARN_ON(pos != send - ic->i_sends);
+
+       send->s_wr.send_flags = send_flags;
+       send->s_wr.opcode = IB_WR_SEND;
+       send->s_wr.num_sge = 2;
+       send->s_wr.next = NULL;
+       send->s_queued = jiffies;
+       send->s_op = NULL;
+
+       if (length != 0) {
+               sge = rds_iw_data_sge(ic, send->s_sge);
+               sge->addr = buffer;
+               sge->length = length;
+               sge->lkey = rds_iw_local_dma_lkey(ic);
+
+               sge = rds_iw_header_sge(ic, send->s_sge);
+       } else {
+               /* We're sending a packet with no payload. There is only
+                * one SGE */
+               send->s_wr.num_sge = 1;
+               sge = &send->s_sge[0];
+       }
+
+       sge->addr = ic->i_send_hdrs_dma + (pos * sizeof(struct rds_header));
+       sge->length = sizeof(struct rds_header);
+       sge->lkey = rds_iw_local_dma_lkey(ic);
+}
+
+/*
+ * This can be called multiple times for a given message.  The first time
+ * we see a message we map its scatterlist into the IB device so that
+ * we can provide that mapped address to the IB scatter gather entries
+ * in the IB work requests.  We translate the scatterlist into a series
+ * of work requests that fragment the message.  These work requests complete
+ * in order so we pass ownership of the message to the completion handler
+ * once we send the final fragment.
+ *
+ * The RDS core uses the c_send_lock to only enter this function once
+ * per connection.  This makes sure that the tx ring alloc/unalloc pairs
+ * don't get out of sync and confuse the ring.
+ */
+int rds_iw_xmit(struct rds_connection *conn, struct rds_message *rm,
+               unsigned int hdr_off, unsigned int sg, unsigned int off)
+{
+       struct rds_iw_connection *ic = conn->c_transport_data;
+       struct ib_device *dev = ic->i_cm_id->device;
+       struct rds_iw_send_work *send = NULL;
+       struct rds_iw_send_work *first;
+       struct rds_iw_send_work *prev;
+       struct ib_send_wr *failed_wr;
+       struct scatterlist *scat;
+       u32 pos;
+       u32 i;
+       u32 work_alloc;
+       u32 credit_alloc;
+       u32 posted;
+       u32 adv_credits = 0;
+       int send_flags = 0;
+       int sent;
+       int ret;
+       int flow_controlled = 0;
+
+       BUG_ON(off % RDS_FRAG_SIZE);
+       BUG_ON(hdr_off != 0 && hdr_off != sizeof(struct rds_header));
+
+       /* Fastreg support */
+       if (rds_rdma_cookie_key(rm->m_rdma_cookie)
+        && !ic->i_fastreg_posted) {
+               ret = -EAGAIN;
+               goto out;
+       }
+
+       /* FIXME we may overallocate here */
+       if (be32_to_cpu(rm->m_inc.i_hdr.h_len) == 0)
+               i = 1;
+       else
+               i = ceil(be32_to_cpu(rm->m_inc.i_hdr.h_len), RDS_FRAG_SIZE);
+
+       work_alloc = rds_iw_ring_alloc(&ic->i_send_ring, i, &pos);
+       if (work_alloc == 0) {
+               set_bit(RDS_LL_SEND_FULL, &conn->c_flags);
+               rds_iw_stats_inc(s_iw_tx_ring_full);
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       credit_alloc = work_alloc;
+       if (ic->i_flowctl) {
+               credit_alloc = rds_iw_send_grab_credits(ic, work_alloc, &posted, 0);
+               adv_credits += posted;
+               if (credit_alloc < work_alloc) {
+                       rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc - credit_alloc);
+                       work_alloc = credit_alloc;
+                       flow_controlled++;
+               }
+               if (work_alloc == 0) {
+                       rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc);
+                       rds_iw_stats_inc(s_iw_tx_throttle);
+                       ret = -ENOMEM;
+                       goto out;
+               }
+       }
+
+       /* map the message the first time we see it */
+       if (ic->i_rm == NULL) {
+               /*
+               printk(KERN_NOTICE "rds_iw_xmit prep msg dport=%u flags=0x%x len=%d\n",
+                               be16_to_cpu(rm->m_inc.i_hdr.h_dport),
+                               rm->m_inc.i_hdr.h_flags,
+                               be32_to_cpu(rm->m_inc.i_hdr.h_len));
+                  */
+               if (rm->m_nents) {
+                       rm->m_count = ib_dma_map_sg(dev,
+                                        rm->m_sg, rm->m_nents, DMA_TO_DEVICE);
+                       rdsdebug("ic %p mapping rm %p: %d\n", ic, rm, rm->m_count);
+                       if (rm->m_count == 0) {
+                               rds_iw_stats_inc(s_iw_tx_sg_mapping_failure);
+                               rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc);
+                               ret = -ENOMEM; /* XXX ? */
+                               goto out;
+                       }
+               } else {
+                       rm->m_count = 0;
+               }
+
+               ic->i_unsignaled_wrs = rds_iw_sysctl_max_unsig_wrs;
+               ic->i_unsignaled_bytes = rds_iw_sysctl_max_unsig_bytes;
+               rds_message_addref(rm);
+               ic->i_rm = rm;
+
+               /* Finalize the header */
+               if (test_bit(RDS_MSG_ACK_REQUIRED, &rm->m_flags))
+                       rm->m_inc.i_hdr.h_flags |= RDS_FLAG_ACK_REQUIRED;
+               if (test_bit(RDS_MSG_RETRANSMITTED, &rm->m_flags))
+                       rm->m_inc.i_hdr.h_flags |= RDS_FLAG_RETRANSMITTED;
+
+               /* If it has a RDMA op, tell the peer we did it. This is
+                * used by the peer to release use-once RDMA MRs. */
+               if (rm->m_rdma_op) {
+                       struct rds_ext_header_rdma ext_hdr;
+
+                       ext_hdr.h_rdma_rkey = cpu_to_be32(rm->m_rdma_op->r_key);
+                       rds_message_add_extension(&rm->m_inc.i_hdr,
+                                       RDS_EXTHDR_RDMA, &ext_hdr, sizeof(ext_hdr));
+               }
+               if (rm->m_rdma_cookie) {
+                       rds_message_add_rdma_dest_extension(&rm->m_inc.i_hdr,
+                                       rds_rdma_cookie_key(rm->m_rdma_cookie),
+                                       rds_rdma_cookie_offset(rm->m_rdma_cookie));
+               }
+
+               /* Note - rds_iw_piggyb_ack clears the ACK_REQUIRED bit, so
+                * we should not do this unless we have a chance of at least
+                * sticking the header into the send ring. Which is why we
+                * should call rds_iw_ring_alloc first. */
+               rm->m_inc.i_hdr.h_ack = cpu_to_be64(rds_iw_piggyb_ack(ic));
+               rds_message_make_checksum(&rm->m_inc.i_hdr);
+
+               /*
+                * Update adv_credits since we reset the ACK_REQUIRED bit.
+                */
+               rds_iw_send_grab_credits(ic, 0, &posted, 1);
+               adv_credits += posted;
+               BUG_ON(adv_credits > 255);
+       } else if (ic->i_rm != rm)
+               BUG();
+
+       send = &ic->i_sends[pos];
+       first = send;
+       prev = NULL;
+       scat = &rm->m_sg[sg];
+       sent = 0;
+       i = 0;
+
+       /* Sometimes you want to put a fence between an RDMA
+        * READ and the following SEND.
+        * We could either do this all the time
+        * or when requested by the user. Right now, we let
+        * the application choose.
+        */
+       if (rm->m_rdma_op && rm->m_rdma_op->r_fence)
+               send_flags = IB_SEND_FENCE;
+
+       /*
+        * We could be copying the header into the unused tail of the page.
+        * That would need to be changed in the future when those pages might
+        * be mapped userspace pages or page cache pages.  So instead we always
+        * use a second sge and our long-lived ring of mapped headers.  We send
+        * the header after the data so that the data payload can be aligned on
+        * the receiver.
+        */
+
+       /* handle a 0-len message */
+       if (be32_to_cpu(rm->m_inc.i_hdr.h_len) == 0) {
+               rds_iw_xmit_populate_wr(ic, send, pos, 0, 0, send_flags);
+               goto add_header;
+       }
+
+       /* if there's data reference it with a chain of work reqs */
+       for (; i < work_alloc && scat != &rm->m_sg[rm->m_count]; i++) {
+               unsigned int len;
+
+               send = &ic->i_sends[pos];
+
+               len = min(RDS_FRAG_SIZE, ib_sg_dma_len(dev, scat) - off);
+               rds_iw_xmit_populate_wr(ic, send, pos,
+                               ib_sg_dma_address(dev, scat) + off, len,
+                               send_flags);
+
+               /*
+                * We want to delay signaling completions just enough to get
+                * the batching benefits but not so much that we create dead time
+                * on the wire.
+                */
+               if (ic->i_unsignaled_wrs-- == 0) {
+                       ic->i_unsignaled_wrs = rds_iw_sysctl_max_unsig_wrs;
+                       send->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
+               }
+
+               ic->i_unsignaled_bytes -= len;
+               if (ic->i_unsignaled_bytes <= 0) {
+                       ic->i_unsignaled_bytes = rds_iw_sysctl_max_unsig_bytes;
+                       send->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
+               }
+
+               /*
+                * Always signal the last one if we're stopping due to flow control.
+                */
+               if (flow_controlled && i == (work_alloc-1))
+                       send->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
+
+               rdsdebug("send %p wr %p num_sge %u next %p\n", send,
+                        &send->s_wr, send->s_wr.num_sge, send->s_wr.next);
+
+               sent += len;
+               off += len;
+               if (off == ib_sg_dma_len(dev, scat)) {
+                       scat++;
+                       off = 0;
+               }
+
+add_header:
+               /* Tack on the header after the data. The header SGE should already
+                * have been set up to point to the right header buffer. */
+               memcpy(&ic->i_send_hdrs[pos], &rm->m_inc.i_hdr, sizeof(struct rds_header));
+
+               if (0) {
+                       struct rds_header *hdr = &ic->i_send_hdrs[pos];
+
+                       printk(KERN_NOTICE "send WR dport=%u flags=0x%x len=%d\n",
+                               be16_to_cpu(hdr->h_dport),
+                               hdr->h_flags,
+                               be32_to_cpu(hdr->h_len));
+               }
+               if (adv_credits) {
+                       struct rds_header *hdr = &ic->i_send_hdrs[pos];
+
+                       /* add credit and redo the header checksum */
+                       hdr->h_credit = adv_credits;
+                       rds_message_make_checksum(hdr);
+                       adv_credits = 0;
+                       rds_iw_stats_inc(s_iw_tx_credit_updates);
+               }
+
+               if (prev)
+                       prev->s_wr.next = &send->s_wr;
+               prev = send;
+
+               pos = (pos + 1) % ic->i_send_ring.w_nr;
+       }
+
+       /* Account the RDS header in the number of bytes we sent, but just once.
+        * The caller has no concept of fragmentation. */
+       if (hdr_off == 0)
+               sent += sizeof(struct rds_header);
+
+       /* if we finished the message then send completion owns it */
+       if (scat == &rm->m_sg[rm->m_count]) {
+               prev->s_rm = ic->i_rm;
+               prev->s_wr.send_flags |= IB_SEND_SIGNALED | IB_SEND_SOLICITED;
+               ic->i_rm = NULL;
+       }
+
+       if (i < work_alloc) {
+               rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc - i);
+               work_alloc = i;
+       }
+       if (ic->i_flowctl && i < credit_alloc)
+               rds_iw_send_add_credits(conn, credit_alloc - i);
+
+       /* XXX need to worry about failed_wr and partial sends. */
+       failed_wr = &first->s_wr;
+       ret = ib_post_send(ic->i_cm_id->qp, &first->s_wr, &failed_wr);
+       rdsdebug("ic %p first %p (wr %p) ret %d wr %p\n", ic,
+                first, &first->s_wr, ret, failed_wr);
+       BUG_ON(failed_wr != &first->s_wr);
+       if (ret) {
+               printk(KERN_WARNING "RDS/IW: ib_post_send to %pI4 "
+                      "returned %d\n", &conn->c_faddr, ret);
+               rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc);
+               if (prev->s_rm) {
+                       ic->i_rm = prev->s_rm;
+                       prev->s_rm = NULL;
+               }
+               goto out;
+       }
+
+       ret = sent;
+out:
+       BUG_ON(adv_credits);
+       return ret;
+}
+
+static void rds_iw_build_send_fastreg(struct rds_iw_device *rds_iwdev, struct rds_iw_connection *ic, struct rds_iw_send_work *send, int nent, int len, u64 sg_addr)
+{
+       BUG_ON(nent > send->s_page_list->max_page_list_len);
+       /*
+        * Perform a WR for the fast_reg_mr. Each individual page
+        * in the sg list is added to the fast reg page list and placed
+        * inside the fast_reg_mr WR.
+        */
+       send->s_wr.opcode = IB_WR_FAST_REG_MR;
+       send->s_wr.wr.fast_reg.length = len;
+       send->s_wr.wr.fast_reg.rkey = send->s_mr->rkey;
+       send->s_wr.wr.fast_reg.page_list = send->s_page_list;
+       send->s_wr.wr.fast_reg.page_list_len = nent;
+       send->s_wr.wr.fast_reg.page_shift = rds_iwdev->page_shift;
+       send->s_wr.wr.fast_reg.access_flags = IB_ACCESS_REMOTE_WRITE;
+       send->s_wr.wr.fast_reg.iova_start = sg_addr;
+
+       ib_update_fast_reg_key(send->s_mr, send->s_remap_count++);
+}
+
+int rds_iw_xmit_rdma(struct rds_connection *conn, struct rds_rdma_op *op)
+{
+       struct rds_iw_connection *ic = conn->c_transport_data;
+       struct rds_iw_send_work *send = NULL;
+       struct rds_iw_send_work *first;
+       struct rds_iw_send_work *prev;
+       struct ib_send_wr *failed_wr;
+       struct rds_iw_device *rds_iwdev;
+       struct scatterlist *scat;
+       unsigned long len;
+       u64 remote_addr = op->r_remote_addr;
+       u32 pos, fr_pos;
+       u32 work_alloc;
+       u32 i;
+       u32 j;
+       int sent;
+       int ret;
+       int num_sge;
+
+       rds_iwdev = ib_get_client_data(ic->i_cm_id->device, &rds_iw_client);
+
+       /* map the message the first time we see it */
+       if (!op->r_mapped) {
+               op->r_count = ib_dma_map_sg(ic->i_cm_id->device,
+                                       op->r_sg, op->r_nents, (op->r_write) ?
+                                       DMA_TO_DEVICE : DMA_FROM_DEVICE);
+               rdsdebug("ic %p mapping op %p: %d\n", ic, op, op->r_count);
+               if (op->r_count == 0) {
+                       rds_iw_stats_inc(s_iw_tx_sg_mapping_failure);
+                       ret = -ENOMEM; /* XXX ? */
+                       goto out;
+               }
+
+               op->r_mapped = 1;
+       }
+
+       if (!op->r_write) {
+               /* Alloc space on the send queue for the fastreg */
+               work_alloc = rds_iw_ring_alloc(&ic->i_send_ring, 1, &fr_pos);
+               if (work_alloc != 1) {
+                       rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc);
+                       rds_iw_stats_inc(s_iw_tx_ring_full);
+                       ret = -ENOMEM;
+                       goto out;
+               }
+       }
+
+       /*
+        * Instead of knowing how to return a partial rdma read/write we insist that there
+        * be enough work requests to send the entire message.
+        */
+       i = ceil(op->r_count, rds_iwdev->max_sge);
+
+       work_alloc = rds_iw_ring_alloc(&ic->i_send_ring, i, &pos);
+       if (work_alloc != i) {
+               rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc);
+               rds_iw_stats_inc(s_iw_tx_ring_full);
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       send = &ic->i_sends[pos];
+       if (!op->r_write) {
+               first = prev = &ic->i_sends[fr_pos];
+       } else {
+               first = send;
+               prev = NULL;
+       }
+       scat = &op->r_sg[0];
+       sent = 0;
+       num_sge = op->r_count;
+
+       for (i = 0; i < work_alloc && scat != &op->r_sg[op->r_count]; i++) {
+               send->s_wr.send_flags = 0;
+               send->s_queued = jiffies;
+
+               /*
+                * We want to delay signaling completions just enough to get
+                * the batching benefits but not so much that we create dead time on the wire.
+                */
+               if (ic->i_unsignaled_wrs-- == 0) {
+                       ic->i_unsignaled_wrs = rds_iw_sysctl_max_unsig_wrs;
+                       send->s_wr.send_flags = IB_SEND_SIGNALED;
+               }
+
+               /* To avoid the need to have the plumbing to invalidate the fastreg_mr used
+                * for local access after RDS is finished with it, using
+                * IB_WR_RDMA_READ_WITH_INV will invalidate it after the read has completed.
+                */
+               if (op->r_write)
+                       send->s_wr.opcode = IB_WR_RDMA_WRITE;
+               else
+                       send->s_wr.opcode = IB_WR_RDMA_READ_WITH_INV;
+
+               send->s_wr.wr.rdma.remote_addr = remote_addr;
+               send->s_wr.wr.rdma.rkey = op->r_key;
+               send->s_op = op;
+
+               if (num_sge > rds_iwdev->max_sge) {
+                       send->s_wr.num_sge = rds_iwdev->max_sge;
+                       num_sge -= rds_iwdev->max_sge;
+               } else
+                       send->s_wr.num_sge = num_sge;
+
+               send->s_wr.next = NULL;
+
+               if (prev)
+                       prev->s_wr.next = &send->s_wr;
+
+               for (j = 0; j < send->s_wr.num_sge && scat != &op->r_sg[op->r_count]; j++) {
+                       len = ib_sg_dma_len(ic->i_cm_id->device, scat);
+
+                       if (send->s_wr.opcode == IB_WR_RDMA_READ_WITH_INV)
+                               send->s_page_list->page_list[j] = ib_sg_dma_address(ic->i_cm_id->device, scat);
+                       else {
+                               send->s_sge[j].addr = ib_sg_dma_address(ic->i_cm_id->device, scat);
+                               send->s_sge[j].length = len;
+                               send->s_sge[j].lkey = rds_iw_local_dma_lkey(ic);
+                       }
+
+                       sent += len;
+                       rdsdebug("ic %p sent %d remote_addr %llu\n", ic, sent, remote_addr);
+                       remote_addr += len;
+
+                       scat++;
+               }
+
+               if (send->s_wr.opcode == IB_WR_RDMA_READ_WITH_INV) {
+                       send->s_wr.num_sge = 1;
+                       send->s_sge[0].addr = conn->c_xmit_rm->m_rs->rs_user_addr;
+                       send->s_sge[0].length = conn->c_xmit_rm->m_rs->rs_user_bytes;
+                       send->s_sge[0].lkey = ic->i_sends[fr_pos].s_mr->lkey;
+               }
+
+               rdsdebug("send %p wr %p num_sge %u next %p\n", send,
+                       &send->s_wr, send->s_wr.num_sge, send->s_wr.next);
+
+               prev = send;
+               if (++send == &ic->i_sends[ic->i_send_ring.w_nr])
+                       send = ic->i_sends;
+       }
+
+       /* if we finished the message then send completion owns it */
+       if (scat == &op->r_sg[op->r_count])
+               first->s_wr.send_flags = IB_SEND_SIGNALED;
+
+       if (i < work_alloc) {
+               rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc - i);
+               work_alloc = i;
+       }
+
+       /* On iWARP, local memory access by a remote system (ie, RDMA Read) is not
+        * recommended.  Putting the lkey on the wire is a security hole, as it can
+        * allow for memory access to all of memory on the remote system.  Some
+        * adapters do not allow using the lkey for this at all.  To bypass this use a
+        * fastreg_mr (or possibly a dma_mr)
+        */
+       if (!op->r_write) {
+               rds_iw_build_send_fastreg(rds_iwdev, ic, &ic->i_sends[fr_pos],
+                       op->r_count, sent, conn->c_xmit_rm->m_rs->rs_user_addr);
+               work_alloc++;
+       }
+
+       failed_wr = &first->s_wr;
+       ret = ib_post_send(ic->i_cm_id->qp, &first->s_wr, &failed_wr);
+       rdsdebug("ic %p first %p (wr %p) ret %d wr %p\n", ic,
+                first, &first->s_wr, ret, failed_wr);
+       BUG_ON(failed_wr != &first->s_wr);
+       if (ret) {
+               printk(KERN_WARNING "RDS/IW: rdma ib_post_send to %pI4 "
+                      "returned %d\n", &conn->c_faddr, ret);
+               rds_iw_ring_unalloc(&ic->i_send_ring, work_alloc);
+               goto out;
+       }
+
+out:
+       return ret;
+}
+
+void rds_iw_xmit_complete(struct rds_connection *conn)
+{
+       struct rds_iw_connection *ic = conn->c_transport_data;
+
+       /* We may have a pending ACK or window update we were unable
+        * to send previously (due to flow control). Try again. */
+       rds_iw_attempt_ack(ic);
+}
diff --git a/net/rds/iw_stats.c b/net/rds/iw_stats.c
new file mode 100644 (file)
index 0000000..ccc7e8f
--- /dev/null
@@ -0,0 +1,95 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/percpu.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+
+#include "rds.h"
+#include "iw.h"
+
+DEFINE_PER_CPU(struct rds_iw_statistics, rds_iw_stats) ____cacheline_aligned;
+
+static char *rds_iw_stat_names[] = {
+       "iw_connect_raced",
+       "iw_listen_closed_stale",
+       "iw_tx_cq_call",
+       "iw_tx_cq_event",
+       "iw_tx_ring_full",
+       "iw_tx_throttle",
+       "iw_tx_sg_mapping_failure",
+       "iw_tx_stalled",
+       "iw_tx_credit_updates",
+       "iw_rx_cq_call",
+       "iw_rx_cq_event",
+       "iw_rx_ring_empty",
+       "iw_rx_refill_from_cq",
+       "iw_rx_refill_from_thread",
+       "iw_rx_alloc_limit",
+       "iw_rx_credit_updates",
+       "iw_ack_sent",
+       "iw_ack_send_failure",
+       "iw_ack_send_delayed",
+       "iw_ack_send_piggybacked",
+       "iw_ack_received",
+       "iw_rdma_mr_alloc",
+       "iw_rdma_mr_free",
+       "iw_rdma_mr_used",
+       "iw_rdma_mr_pool_flush",
+       "iw_rdma_mr_pool_wait",
+       "iw_rdma_mr_pool_depleted",
+};
+
+unsigned int rds_iw_stats_info_copy(struct rds_info_iterator *iter,
+                                   unsigned int avail)
+{
+       struct rds_iw_statistics stats = {0, };
+       uint64_t *src;
+       uint64_t *sum;
+       size_t i;
+       int cpu;
+
+       if (avail < ARRAY_SIZE(rds_iw_stat_names))
+               goto out;
+
+       for_each_online_cpu(cpu) {
+               src = (uint64_t *)&(per_cpu(rds_iw_stats, cpu));
+               sum = (uint64_t *)&stats;
+               for (i = 0; i < sizeof(stats) / sizeof(uint64_t); i++)
+                       *(sum++) += *(src++);
+       }
+
+       rds_stats_info_copy(iter, (uint64_t *)&stats, rds_iw_stat_names,
+                           ARRAY_SIZE(rds_iw_stat_names));
+out:
+       return ARRAY_SIZE(rds_iw_stat_names);
+}
diff --git a/net/rds/iw_sysctl.c b/net/rds/iw_sysctl.c
new file mode 100644 (file)
index 0000000..9590678
--- /dev/null
@@ -0,0 +1,137 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+
+#include "iw.h"
+
+static struct ctl_table_header *rds_iw_sysctl_hdr;
+
+unsigned long rds_iw_sysctl_max_send_wr = RDS_IW_DEFAULT_SEND_WR;
+unsigned long rds_iw_sysctl_max_recv_wr = RDS_IW_DEFAULT_RECV_WR;
+unsigned long rds_iw_sysctl_max_recv_allocation = (128 * 1024 * 1024) / RDS_FRAG_SIZE;
+static unsigned long rds_iw_sysctl_max_wr_min = 1;
+/* hardware will fail CQ creation long before this */
+static unsigned long rds_iw_sysctl_max_wr_max = (u32)~0;
+
+unsigned long rds_iw_sysctl_max_unsig_wrs = 16;
+static unsigned long rds_iw_sysctl_max_unsig_wr_min = 1;
+static unsigned long rds_iw_sysctl_max_unsig_wr_max = 64;
+
+unsigned long rds_iw_sysctl_max_unsig_bytes = (16 << 20);
+static unsigned long rds_iw_sysctl_max_unsig_bytes_min = 1;
+static unsigned long rds_iw_sysctl_max_unsig_bytes_max = ~0UL;
+
+unsigned int rds_iw_sysctl_flow_control = 1;
+
+ctl_table rds_iw_sysctl_table[] = {
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "max_send_wr",
+               .data           = &rds_iw_sysctl_max_send_wr,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &proc_doulongvec_minmax,
+               .extra1         = &rds_iw_sysctl_max_wr_min,
+               .extra2         = &rds_iw_sysctl_max_wr_max,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "max_recv_wr",
+               .data           = &rds_iw_sysctl_max_recv_wr,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &proc_doulongvec_minmax,
+               .extra1         = &rds_iw_sysctl_max_wr_min,
+               .extra2         = &rds_iw_sysctl_max_wr_max,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "max_unsignaled_wr",
+               .data           = &rds_iw_sysctl_max_unsig_wrs,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &proc_doulongvec_minmax,
+               .extra1         = &rds_iw_sysctl_max_unsig_wr_min,
+               .extra2         = &rds_iw_sysctl_max_unsig_wr_max,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "max_unsignaled_bytes",
+               .data           = &rds_iw_sysctl_max_unsig_bytes,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &proc_doulongvec_minmax,
+               .extra1         = &rds_iw_sysctl_max_unsig_bytes_min,
+               .extra2         = &rds_iw_sysctl_max_unsig_bytes_max,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "max_recv_allocation",
+               .data           = &rds_iw_sysctl_max_recv_allocation,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &proc_doulongvec_minmax,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "flow_control",
+               .data           = &rds_iw_sysctl_flow_control,
+               .maxlen         = sizeof(rds_iw_sysctl_flow_control),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+       { .ctl_name = 0}
+};
+
+static struct ctl_path rds_iw_sysctl_path[] = {
+       { .procname = "net", .ctl_name = CTL_NET, },
+       { .procname = "rds", .ctl_name = CTL_UNNUMBERED, },
+       { .procname = "iw", .ctl_name = CTL_UNNUMBERED, },
+       { }
+};
+
+void rds_iw_sysctl_exit(void)
+{
+       if (rds_iw_sysctl_hdr)
+               unregister_sysctl_table(rds_iw_sysctl_hdr);
+}
+
+int __init rds_iw_sysctl_init(void)
+{
+       rds_iw_sysctl_hdr = register_sysctl_paths(rds_iw_sysctl_path, rds_iw_sysctl_table);
+       if (rds_iw_sysctl_hdr == NULL)
+               return -ENOMEM;
+       return 0;
+}
diff --git a/net/rds/loop.c b/net/rds/loop.c
new file mode 100644 (file)
index 0000000..4a61997
--- /dev/null
@@ -0,0 +1,188 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/in.h>
+
+#include "rds.h"
+#include "loop.h"
+
+static DEFINE_SPINLOCK(loop_conns_lock);
+static LIST_HEAD(loop_conns);
+
+/*
+ * This 'loopback' transport is a special case for flows that originate
+ * and terminate on the same machine.
+ *
+ * Connection build-up notices if the destination address is thought of
+ * as a local address by a transport.  At that time it decides to use the
+ * loopback transport instead of the bound transport of the sending socket.
+ *
+ * The loopback transport's sending path just hands the sent rds_message
+ * straight to the receiving path via an embedded rds_incoming.
+ */
+
+/*
+ * Usually a message transits both the sender and receiver's conns as it
+ * flows to the receiver.  In the loopback case, though, the receive path
+ * is handed the sending conn so the sense of the addresses is reversed.
+ */
+static int rds_loop_xmit(struct rds_connection *conn, struct rds_message *rm,
+                        unsigned int hdr_off, unsigned int sg,
+                        unsigned int off)
+{
+       BUG_ON(hdr_off || sg || off);
+
+       rds_inc_init(&rm->m_inc, conn, conn->c_laddr);
+       rds_message_addref(rm); /* for the inc */
+
+       rds_recv_incoming(conn, conn->c_laddr, conn->c_faddr, &rm->m_inc,
+                         GFP_KERNEL, KM_USER0);
+
+       rds_send_drop_acked(conn, be64_to_cpu(rm->m_inc.i_hdr.h_sequence),
+                           NULL);
+
+       rds_inc_put(&rm->m_inc);
+
+       return sizeof(struct rds_header) + be32_to_cpu(rm->m_inc.i_hdr.h_len);
+}
+
+static int rds_loop_xmit_cong_map(struct rds_connection *conn,
+                                 struct rds_cong_map *map,
+                                 unsigned long offset)
+{
+       unsigned long i;
+
+       BUG_ON(offset);
+       BUG_ON(map != conn->c_lcong);
+
+       for (i = 0; i < RDS_CONG_MAP_PAGES; i++) {
+               memcpy((void *)conn->c_fcong->m_page_addrs[i],
+                      (void *)map->m_page_addrs[i], PAGE_SIZE);
+       }
+
+       rds_cong_map_updated(conn->c_fcong, ~(u64) 0);
+
+       return sizeof(struct rds_header) + RDS_CONG_MAP_BYTES;
+}
+
+/* we need to at least give the thread something to succeed */
+static int rds_loop_recv(struct rds_connection *conn)
+{
+       return 0;
+}
+
+struct rds_loop_connection {
+       struct list_head loop_node;
+       struct rds_connection *conn;
+};
+
+/*
+ * Even the loopback transport needs to keep track of its connections,
+ * so it can call rds_conn_destroy() on them on exit. N.B. there are
+ * 1+ loopback addresses (127.*.*.*) so it's not a bug to have
+ * multiple loopback conns allocated, although rather useless.
+ */
+static int rds_loop_conn_alloc(struct rds_connection *conn, gfp_t gfp)
+{
+       struct rds_loop_connection *lc;
+       unsigned long flags;
+
+       lc = kzalloc(sizeof(struct rds_loop_connection), GFP_KERNEL);
+       if (lc == NULL)
+               return -ENOMEM;
+
+       INIT_LIST_HEAD(&lc->loop_node);
+       lc->conn = conn;
+       conn->c_transport_data = lc;
+
+       spin_lock_irqsave(&loop_conns_lock, flags);
+       list_add_tail(&lc->loop_node, &loop_conns);
+       spin_unlock_irqrestore(&loop_conns_lock, flags);
+
+       return 0;
+}
+
+static void rds_loop_conn_free(void *arg)
+{
+       struct rds_loop_connection *lc = arg;
+       rdsdebug("lc %p\n", lc);
+       list_del(&lc->loop_node);
+       kfree(lc);
+}
+
+static int rds_loop_conn_connect(struct rds_connection *conn)
+{
+       rds_connect_complete(conn);
+       return 0;
+}
+
+static void rds_loop_conn_shutdown(struct rds_connection *conn)
+{
+}
+
+void rds_loop_exit(void)
+{
+       struct rds_loop_connection *lc, *_lc;
+       LIST_HEAD(tmp_list);
+
+       /* avoid calling conn_destroy with irqs off */
+       spin_lock_irq(&loop_conns_lock);
+       list_splice(&loop_conns, &tmp_list);
+       INIT_LIST_HEAD(&loop_conns);
+       spin_unlock_irq(&loop_conns_lock);
+
+       list_for_each_entry_safe(lc, _lc, &tmp_list, loop_node) {
+               WARN_ON(lc->conn->c_passive);
+               rds_conn_destroy(lc->conn);
+       }
+}
+
+/*
+ * This is missing .xmit_* because loop doesn't go through generic
+ * rds_send_xmit() and doesn't call rds_recv_incoming().  .listen_stop and
+ * .laddr_check are missing because transport.c doesn't iterate over
+ * rds_loop_transport.
+ */
+struct rds_transport rds_loop_transport = {
+       .xmit                   = rds_loop_xmit,
+       .xmit_cong_map          = rds_loop_xmit_cong_map,
+       .recv                   = rds_loop_recv,
+       .conn_alloc             = rds_loop_conn_alloc,
+       .conn_free              = rds_loop_conn_free,
+       .conn_connect           = rds_loop_conn_connect,
+       .conn_shutdown          = rds_loop_conn_shutdown,
+       .inc_copy_to_user       = rds_message_inc_copy_to_user,
+       .inc_purge              = rds_message_inc_purge,
+       .inc_free               = rds_message_inc_free,
+       .t_name                 = "loopback",
+};
diff --git a/net/rds/loop.h b/net/rds/loop.h
new file mode 100644 (file)
index 0000000..f32b093
--- /dev/null
@@ -0,0 +1,9 @@
+#ifndef _RDS_LOOP_H
+#define _RDS_LOOP_H
+
+/* loop.c */
+extern struct rds_transport rds_loop_transport;
+
+void rds_loop_exit(void);
+
+#endif
diff --git a/net/rds/message.c b/net/rds/message.c
new file mode 100644 (file)
index 0000000..5a15dc8
--- /dev/null
@@ -0,0 +1,402 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+
+#include "rds.h"
+#include "rdma.h"
+
+static DECLARE_WAIT_QUEUE_HEAD(rds_message_flush_waitq);
+
+static unsigned int    rds_exthdr_size[__RDS_EXTHDR_MAX] = {
+[RDS_EXTHDR_NONE]      = 0,
+[RDS_EXTHDR_VERSION]   = sizeof(struct rds_ext_header_version),
+[RDS_EXTHDR_RDMA]      = sizeof(struct rds_ext_header_rdma),
+[RDS_EXTHDR_RDMA_DEST] = sizeof(struct rds_ext_header_rdma_dest),
+};
+
+
+void rds_message_addref(struct rds_message *rm)
+{
+       rdsdebug("addref rm %p ref %d\n", rm, atomic_read(&rm->m_refcount));
+       atomic_inc(&rm->m_refcount);
+}
+
+/*
+ * This relies on dma_map_sg() not touching sg[].page during merging.
+ */
+static void rds_message_purge(struct rds_message *rm)
+{
+       unsigned long i;
+
+       if (unlikely(test_bit(RDS_MSG_PAGEVEC, &rm->m_flags)))
+               return;
+
+       for (i = 0; i < rm->m_nents; i++) {
+               rdsdebug("putting data page %p\n", (void *)sg_page(&rm->m_sg[i]));
+               /* XXX will have to put_page for page refs */
+               __free_page(sg_page(&rm->m_sg[i]));
+       }
+       rm->m_nents = 0;
+
+       if (rm->m_rdma_op)
+               rds_rdma_free_op(rm->m_rdma_op);
+       if (rm->m_rdma_mr)
+               rds_mr_put(rm->m_rdma_mr);
+}
+
+void rds_message_inc_purge(struct rds_incoming *inc)
+{
+       struct rds_message *rm = container_of(inc, struct rds_message, m_inc);
+       rds_message_purge(rm);
+}
+
+void rds_message_put(struct rds_message *rm)
+{
+       rdsdebug("put rm %p ref %d\n", rm, atomic_read(&rm->m_refcount));
+
+       if (atomic_dec_and_test(&rm->m_refcount)) {
+               BUG_ON(!list_empty(&rm->m_sock_item));
+               BUG_ON(!list_empty(&rm->m_conn_item));
+               rds_message_purge(rm);
+
+               kfree(rm);
+       }
+}
+
+void rds_message_inc_free(struct rds_incoming *inc)
+{
+       struct rds_message *rm = container_of(inc, struct rds_message, m_inc);
+       rds_message_put(rm);
+}
+
+void rds_message_populate_header(struct rds_header *hdr, __be16 sport,
+                                __be16 dport, u64 seq)
+{
+       hdr->h_flags = 0;
+       hdr->h_sport = sport;
+       hdr->h_dport = dport;
+       hdr->h_sequence = cpu_to_be64(seq);
+       hdr->h_exthdr[0] = RDS_EXTHDR_NONE;
+}
+
+int rds_message_add_extension(struct rds_header *hdr,
+               unsigned int type, const void *data, unsigned int len)
+{
+       unsigned int ext_len = sizeof(u8) + len;
+       unsigned char *dst;
+
+       /* For now, refuse to add more than one extension header */
+       if (hdr->h_exthdr[0] != RDS_EXTHDR_NONE)
+               return 0;
+
+       if (type >= __RDS_EXTHDR_MAX
+        || len != rds_exthdr_size[type])
+               return 0;
+
+       if (ext_len >= RDS_HEADER_EXT_SPACE)
+               return 0;
+       dst = hdr->h_exthdr;
+
+       *dst++ = type;
+       memcpy(dst, data, len);
+
+       dst[len] = RDS_EXTHDR_NONE;
+       return 1;
+}
+
+/*
+ * If a message has extension headers, retrieve them here.
+ * Call like this:
+ *
+ * unsigned int pos = 0;
+ *
+ * while (1) {
+ *     buflen = sizeof(buffer);
+ *     type = rds_message_next_extension(hdr, &pos, buffer, &buflen);
+ *     if (type == RDS_EXTHDR_NONE)
+ *             break;
+ *     ...
+ * }
+ */
+int rds_message_next_extension(struct rds_header *hdr,
+               unsigned int *pos, void *buf, unsigned int *buflen)
+{
+       unsigned int offset, ext_type, ext_len;
+       u8 *src = hdr->h_exthdr;
+
+       offset = *pos;
+       if (offset >= RDS_HEADER_EXT_SPACE)
+               goto none;
+
+       /* Get the extension type and length. For now, the
+        * length is implied by the extension type. */
+       ext_type = src[offset++];
+
+       if (ext_type == RDS_EXTHDR_NONE || ext_type >= __RDS_EXTHDR_MAX)
+               goto none;
+       ext_len = rds_exthdr_size[ext_type];
+       if (offset + ext_len > RDS_HEADER_EXT_SPACE)
+               goto none;
+
+       *pos = offset + ext_len;
+       if (ext_len < *buflen)
+               *buflen = ext_len;
+       memcpy(buf, src + offset, *buflen);
+       return ext_type;
+
+none:
+       *pos = RDS_HEADER_EXT_SPACE;
+       *buflen = 0;
+       return RDS_EXTHDR_NONE;
+}
+
+int rds_message_add_version_extension(struct rds_header *hdr, unsigned int version)
+{
+       struct rds_ext_header_version ext_hdr;
+
+       ext_hdr.h_version = cpu_to_be32(version);
+       return rds_message_add_extension(hdr, RDS_EXTHDR_VERSION, &ext_hdr, sizeof(ext_hdr));
+}
+
+int rds_message_get_version_extension(struct rds_header *hdr, unsigned int *version)
+{
+       struct rds_ext_header_version ext_hdr;
+       unsigned int pos = 0, len = sizeof(ext_hdr);
+
+       /* We assume the version extension is the only one present */
+       if (rds_message_next_extension(hdr, &pos, &ext_hdr, &len) != RDS_EXTHDR_VERSION)
+               return 0;
+       *version = be32_to_cpu(ext_hdr.h_version);
+       return 1;
+}
+
+int rds_message_add_rdma_dest_extension(struct rds_header *hdr, u32 r_key, u32 offset)
+{
+       struct rds_ext_header_rdma_dest ext_hdr;
+
+       ext_hdr.h_rdma_rkey = cpu_to_be32(r_key);
+       ext_hdr.h_rdma_offset = cpu_to_be32(offset);
+       return rds_message_add_extension(hdr, RDS_EXTHDR_RDMA_DEST, &ext_hdr, sizeof(ext_hdr));
+}
+
+struct rds_message *rds_message_alloc(unsigned int nents, gfp_t gfp)
+{
+       struct rds_message *rm;
+
+       rm = kzalloc(sizeof(struct rds_message) +
+                    (nents * sizeof(struct scatterlist)), gfp);
+       if (!rm)
+               goto out;
+
+       if (nents)
+               sg_init_table(rm->m_sg, nents);
+       atomic_set(&rm->m_refcount, 1);
+       INIT_LIST_HEAD(&rm->m_sock_item);
+       INIT_LIST_HEAD(&rm->m_conn_item);
+       spin_lock_init(&rm->m_rs_lock);
+
+out:
+       return rm;
+}
+
+struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned int total_len)
+{
+       struct rds_message *rm;
+       unsigned int i;
+
+       rm = rds_message_alloc(ceil(total_len, PAGE_SIZE), GFP_KERNEL);
+       if (rm == NULL)
+               return ERR_PTR(-ENOMEM);
+
+       set_bit(RDS_MSG_PAGEVEC, &rm->m_flags);
+       rm->m_inc.i_hdr.h_len = cpu_to_be32(total_len);
+       rm->m_nents = ceil(total_len, PAGE_SIZE);
+
+       for (i = 0; i < rm->m_nents; ++i) {
+               sg_set_page(&rm->m_sg[i],
+                               virt_to_page(page_addrs[i]),
+                               PAGE_SIZE, 0);
+       }
+
+       return rm;
+}
+
+struct rds_message *rds_message_copy_from_user(struct iovec *first_iov,
+                                              size_t total_len)
+{
+       unsigned long to_copy;
+       unsigned long iov_off;
+       unsigned long sg_off;
+       struct rds_message *rm;
+       struct iovec *iov;
+       struct scatterlist *sg;
+       int ret;
+
+       rm = rds_message_alloc(ceil(total_len, PAGE_SIZE), GFP_KERNEL);
+       if (rm == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       rm->m_inc.i_hdr.h_len = cpu_to_be32(total_len);
+
+       /*
+        * now allocate and copy in the data payload.
+        */
+       sg = rm->m_sg;
+       iov = first_iov;
+       iov_off = 0;
+       sg_off = 0; /* Dear gcc, sg->page will be null from kzalloc. */
+
+       while (total_len) {
+               if (sg_page(sg) == NULL) {
+                       ret = rds_page_remainder_alloc(sg, total_len,
+                                                      GFP_HIGHUSER);
+                       if (ret)
+                               goto out;
+                       rm->m_nents++;
+                       sg_off = 0;
+               }
+
+               while (iov_off == iov->iov_len) {
+                       iov_off = 0;
+                       iov++;
+               }
+
+               to_copy = min(iov->iov_len - iov_off, sg->length - sg_off);
+               to_copy = min_t(size_t, to_copy, total_len);
+
+               rdsdebug("copying %lu bytes from user iov [%p, %zu] + %lu to "
+                        "sg [%p, %u, %u] + %lu\n",
+                        to_copy, iov->iov_base, iov->iov_len, iov_off,
+                        (void *)sg_page(sg), sg->offset, sg->length, sg_off);
+
+               ret = rds_page_copy_from_user(sg_page(sg), sg->offset + sg_off,
+                                             iov->iov_base + iov_off,
+                                             to_copy);
+               if (ret)
+                       goto out;
+
+               iov_off += to_copy;
+               total_len -= to_copy;
+               sg_off += to_copy;
+
+               if (sg_off == sg->length)
+                       sg++;
+       }
+
+       ret = 0;
+out:
+       if (ret) {
+               if (rm)
+                       rds_message_put(rm);
+               rm = ERR_PTR(ret);
+       }
+       return rm;
+}
+
+int rds_message_inc_copy_to_user(struct rds_incoming *inc,
+                                struct iovec *first_iov, size_t size)
+{
+       struct rds_message *rm;
+       struct iovec *iov;
+       struct scatterlist *sg;
+       unsigned long to_copy;
+       unsigned long iov_off;
+       unsigned long vec_off;
+       int copied;
+       int ret;
+       u32 len;
+
+       rm = container_of(inc, struct rds_message, m_inc);
+       len = be32_to_cpu(rm->m_inc.i_hdr.h_len);
+
+       iov = first_iov;
+       iov_off = 0;
+       sg = rm->m_sg;
+       vec_off = 0;
+       copied = 0;
+
+       while (copied < size && copied < len) {
+               while (iov_off == iov->iov_len) {
+                       iov_off = 0;
+                       iov++;
+               }
+
+               to_copy = min(iov->iov_len - iov_off, sg->length - vec_off);
+               to_copy = min_t(size_t, to_copy, size - copied);
+               to_copy = min_t(unsigned long, to_copy, len - copied);
+
+               rdsdebug("copying %lu bytes to user iov [%p, %zu] + %lu to "
+                        "sg [%p, %u, %u] + %lu\n",
+                        to_copy, iov->iov_base, iov->iov_len, iov_off,
+                        sg_page(sg), sg->offset, sg->length, vec_off);
+
+               ret = rds_page_copy_to_user(sg_page(sg), sg->offset + vec_off,
+                                           iov->iov_base + iov_off,
+                                           to_copy);
+               if (ret) {
+                       copied = ret;
+                       break;
+               }
+
+               iov_off += to_copy;
+               vec_off += to_copy;
+               copied += to_copy;
+
+               if (vec_off == sg->length) {
+                       vec_off = 0;
+                       sg++;
+               }
+       }
+
+       return copied;
+}
+
+/*
+ * If the message is still on the send queue, wait until the transport
+ * is done with it. This is particularly important for RDMA operations.
+ */
+void rds_message_wait(struct rds_message *rm)
+{
+       wait_event(rds_message_flush_waitq,
+                       !test_bit(RDS_MSG_MAPPED, &rm->m_flags));
+}
+
+void rds_message_unmapped(struct rds_message *rm)
+{
+       clear_bit(RDS_MSG_MAPPED, &rm->m_flags);
+       if (waitqueue_active(&rds_message_flush_waitq))
+               wake_up(&rds_message_flush_waitq);
+}
+
diff --git a/net/rds/page.c b/net/rds/page.c
new file mode 100644 (file)
index 0000000..c460743
--- /dev/null
@@ -0,0 +1,221 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/highmem.h>
+
+#include "rds.h"
+
+struct rds_page_remainder {
+       struct page     *r_page;
+       unsigned long   r_offset;
+};
+
+DEFINE_PER_CPU(struct rds_page_remainder, rds_page_remainders) ____cacheline_aligned;
+
+/*
+ * returns 0 on success or -errno on failure.
+ *
+ * We don't have to worry about flush_dcache_page() as this only works
+ * with private pages.  If, say, we were to do directed receive to pinned
+ * user pages we'd have to worry more about cache coherence.  (Though
+ * the flush_dcache_page() in get_user_pages() would probably be enough).
+ */
+int rds_page_copy_user(struct page *page, unsigned long offset,
+                      void __user *ptr, unsigned long bytes,
+                      int to_user)
+{
+       unsigned long ret;
+       void *addr;
+
+       if (to_user)
+               rds_stats_add(s_copy_to_user, bytes);
+       else
+               rds_stats_add(s_copy_from_user, bytes);
+
+       addr = kmap_atomic(page, KM_USER0);
+       if (to_user)
+               ret = __copy_to_user_inatomic(ptr, addr + offset, bytes);
+       else
+               ret = __copy_from_user_inatomic(addr + offset, ptr, bytes);
+       kunmap_atomic(addr, KM_USER0);
+
+       if (ret) {
+               addr = kmap(page);
+               if (to_user)
+                       ret = copy_to_user(ptr, addr + offset, bytes);
+               else
+                       ret = copy_from_user(addr + offset, ptr, bytes);
+               kunmap(page);
+               if (ret)
+                       return -EFAULT;
+       }
+
+       return 0;
+}
+
+/*
+ * Message allocation uses this to build up regions of a message.
+ *
+ * @bytes - the number of bytes needed.
+ * @gfp - the waiting behaviour of the allocation
+ *
+ * @gfp is always ored with __GFP_HIGHMEM.  Callers must be prepared to
+ * kmap the pages, etc.
+ *
+ * If @bytes is at least a full page then this just returns a page from
+ * alloc_page().
+ *
+ * If @bytes is a partial page then this stores the unused region of the
+ * page in a per-cpu structure.  Future partial-page allocations may be
+ * satisfied from that cached region.  This lets us waste less memory on
+ * small allocations with minimal complexity.  It works because the transmit
+ * path passes read-only page regions down to devices.  They hold a page
+ * reference until they are done with the region.
+ */
+int rds_page_remainder_alloc(struct scatterlist *scat, unsigned long bytes,
+                            gfp_t gfp)
+{
+       struct rds_page_remainder *rem;
+       unsigned long flags;
+       struct page *page;
+       int ret;
+
+       gfp |= __GFP_HIGHMEM;
+
+       /* jump straight to allocation if we're trying for a huge page */
+       if (bytes >= PAGE_SIZE) {
+               page = alloc_page(gfp);
+               if (page == NULL) {
+                       ret = -ENOMEM;
+               } else {
+                       sg_set_page(scat, page, PAGE_SIZE, 0);
+                       ret = 0;
+               }
+               goto out;
+       }
+
+       rem = &per_cpu(rds_page_remainders, get_cpu());
+       local_irq_save(flags);
+
+       while (1) {
+               /* avoid a tiny region getting stuck by tossing it */
+               if (rem->r_page && bytes > (PAGE_SIZE - rem->r_offset)) {
+                       rds_stats_inc(s_page_remainder_miss);
+                       __free_page(rem->r_page);
+                       rem->r_page = NULL;
+               }
+
+               /* hand out a fragment from the cached page */
+               if (rem->r_page && bytes <= (PAGE_SIZE - rem->r_offset)) {
+                       sg_set_page(scat, rem->r_page, bytes, rem->r_offset);
+                       get_page(sg_page(scat));
+
+                       if (rem->r_offset != 0)
+                               rds_stats_inc(s_page_remainder_hit);
+
+                       rem->r_offset += bytes;
+                       if (rem->r_offset == PAGE_SIZE) {
+                               __free_page(rem->r_page);
+                               rem->r_page = NULL;
+                       }
+                       ret = 0;
+                       break;
+               }
+
+               /* alloc if there is nothing for us to use */
+               local_irq_restore(flags);
+               put_cpu();
+
+               page = alloc_page(gfp);
+
+               rem = &per_cpu(rds_page_remainders, get_cpu());
+               local_irq_save(flags);
+
+               if (page == NULL) {
+                       ret = -ENOMEM;
+                       break;
+               }
+
+               /* did someone race to fill the remainder before us? */
+               if (rem->r_page) {
+                       __free_page(page);
+                       continue;
+               }
+
+               /* otherwise install our page and loop around to alloc */
+               rem->r_page = page;
+               rem->r_offset = 0;
+       }
+
+       local_irq_restore(flags);
+       put_cpu();
+out:
+       rdsdebug("bytes %lu ret %d %p %u %u\n", bytes, ret,
+                ret ? NULL : sg_page(scat), ret ? 0 : scat->offset,
+                ret ? 0 : scat->length);
+       return ret;
+}
+
+static int rds_page_remainder_cpu_notify(struct notifier_block *self,
+                                        unsigned long action, void *hcpu)
+{
+       struct rds_page_remainder *rem;
+       long cpu = (long)hcpu;
+
+       rem = &per_cpu(rds_page_remainders, cpu);
+
+       rdsdebug("cpu %ld action 0x%lx\n", cpu, action);
+
+       switch (action) {
+       case CPU_DEAD:
+               if (rem->r_page)
+                       __free_page(rem->r_page);
+               rem->r_page = NULL;
+               break;
+       }
+
+       return 0;
+}
+
+static struct notifier_block rds_page_remainder_nb = {
+       .notifier_call = rds_page_remainder_cpu_notify,
+};
+
+void rds_page_exit(void)
+{
+       int i;
+
+       for_each_possible_cpu(i)
+               rds_page_remainder_cpu_notify(&rds_page_remainder_nb,
+                                             (unsigned long)CPU_DEAD,
+                                             (void *)(long)i);
+}
diff --git a/net/rds/rdma.c b/net/rds/rdma.c
new file mode 100644 (file)
index 0000000..eaeeb91
--- /dev/null
@@ -0,0 +1,679 @@
+/*
+ * Copyright (c) 2007 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/pagemap.h>
+#include <linux/rbtree.h>
+#include <linux/dma-mapping.h> /* for DMA_*_DEVICE */
+
+#include "rdma.h"
+
+/*
+ * XXX
+ *  - build with sparse
+ *  - should we limit the size of a mr region?  let transport return failure?
+ *  - should we detect duplicate keys on a socket?  hmm.
+ *  - an rdma is an mlock, apply rlimit?
+ */
+
+/*
+ * get the number of pages by looking at the page indices that the start and
+ * end addresses fall in.
+ *
+ * Returns 0 if the vec is invalid.  It is invalid if the number of bytes
+ * causes the address to wrap or overflows an unsigned int.  This comes
+ * from being stored in the 'length' member of 'struct scatterlist'.
+ */
+static unsigned int rds_pages_in_vec(struct rds_iovec *vec)
+{
+       if ((vec->addr + vec->bytes <= vec->addr) ||
+           (vec->bytes > (u64)UINT_MAX))
+               return 0;
+
+       return ((vec->addr + vec->bytes + PAGE_SIZE - 1) >> PAGE_SHIFT) -
+               (vec->addr >> PAGE_SHIFT);
+}
+
+static struct rds_mr *rds_mr_tree_walk(struct rb_root *root, u64 key,
+                                      struct rds_mr *insert)
+{
+       struct rb_node **p = &root->rb_node;
+       struct rb_node *parent = NULL;
+       struct rds_mr *mr;
+
+       while (*p) {
+               parent = *p;
+               mr = rb_entry(parent, struct rds_mr, r_rb_node);
+
+               if (key < mr->r_key)
+                       p = &(*p)->rb_left;
+               else if (key > mr->r_key)
+                       p = &(*p)->rb_right;
+               else
+                       return mr;
+       }
+
+       if (insert) {
+               rb_link_node(&insert->r_rb_node, parent, p);
+               rb_insert_color(&insert->r_rb_node, root);
+               atomic_inc(&insert->r_refcount);
+       }
+       return NULL;
+}
+
+/*
+ * Destroy the transport-specific part of a MR.
+ */
+static void rds_destroy_mr(struct rds_mr *mr)
+{
+       struct rds_sock *rs = mr->r_sock;
+       void *trans_private = NULL;
+       unsigned long flags;
+
+       rdsdebug("RDS: destroy mr key is %x refcnt %u\n",
+                       mr->r_key, atomic_read(&mr->r_refcount));
+
+       if (test_and_set_bit(RDS_MR_DEAD, &mr->r_state))
+               return;
+
+       spin_lock_irqsave(&rs->rs_rdma_lock, flags);
+       if (!RB_EMPTY_NODE(&mr->r_rb_node))
+               rb_erase(&mr->r_rb_node, &rs->rs_rdma_keys);
+       trans_private = mr->r_trans_private;
+       mr->r_trans_private = NULL;
+       spin_unlock_irqrestore(&rs->rs_rdma_lock, flags);
+
+       if (trans_private)
+               mr->r_trans->free_mr(trans_private, mr->r_invalidate);
+}
+
+void __rds_put_mr_final(struct rds_mr *mr)
+{
+       rds_destroy_mr(mr);
+       kfree(mr);
+}
+
+/*
+ * By the time this is called we can't have any more ioctls called on
+ * the socket so we don't need to worry about racing with others.
+ */
+void rds_rdma_drop_keys(struct rds_sock *rs)
+{
+       struct rds_mr *mr;
+       struct rb_node *node;
+
+       /* Release any MRs associated with this socket */
+       while ((node = rb_first(&rs->rs_rdma_keys))) {
+               mr = container_of(node, struct rds_mr, r_rb_node);
+               if (mr->r_trans == rs->rs_transport)
+                       mr->r_invalidate = 0;
+               rds_mr_put(mr);
+       }
+
+       if (rs->rs_transport && rs->rs_transport->flush_mrs)
+               rs->rs_transport->flush_mrs();
+}
+
+/*
+ * Helper function to pin user pages.
+ */
+static int rds_pin_pages(unsigned long user_addr, unsigned int nr_pages,
+                       struct page **pages, int write)
+{
+       int ret;
+
+       down_read(&current->mm->mmap_sem);
+       ret = get_user_pages(current, current->mm, user_addr,
+                            nr_pages, write, 0, pages, NULL);
+       up_read(&current->mm->mmap_sem);
+
+       if (0 <= ret && (unsigned) ret < nr_pages) {
+               while (ret--)
+                       put_page(pages[ret]);
+               ret = -EFAULT;
+       }
+
+       return ret;
+}
+
+static int __rds_rdma_map(struct rds_sock *rs, struct rds_get_mr_args *args,
+                               u64 *cookie_ret, struct rds_mr **mr_ret)
+{
+       struct rds_mr *mr = NULL, *found;
+       unsigned int nr_pages;
+       struct page **pages = NULL;
+       struct scatterlist *sg;
+       void *trans_private;
+       unsigned long flags;
+       rds_rdma_cookie_t cookie;
+       unsigned int nents;
+       long i;
+       int ret;
+
+       if (rs->rs_bound_addr == 0) {
+               ret = -ENOTCONN; /* XXX not a great errno */
+               goto out;
+       }
+
+       if (rs->rs_transport->get_mr == NULL) {
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       nr_pages = rds_pages_in_vec(&args->vec);
+       if (nr_pages == 0) {
+               ret = -EINVAL;
+               goto out;
+       }
+
+       rdsdebug("RDS: get_mr addr %llx len %llu nr_pages %u\n",
+               args->vec.addr, args->vec.bytes, nr_pages);
+
+       /* XXX clamp nr_pages to limit the size of this alloc? */
+       pages = kcalloc(nr_pages, sizeof(struct page *), GFP_KERNEL);
+       if (pages == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       mr = kzalloc(sizeof(struct rds_mr), GFP_KERNEL);
+       if (mr == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       atomic_set(&mr->r_refcount, 1);
+       RB_CLEAR_NODE(&mr->r_rb_node);
+       mr->r_trans = rs->rs_transport;
+       mr->r_sock = rs;
+
+       if (args->flags & RDS_RDMA_USE_ONCE)
+               mr->r_use_once = 1;
+       if (args->flags & RDS_RDMA_INVALIDATE)
+               mr->r_invalidate = 1;
+       if (args->flags & RDS_RDMA_READWRITE)
+               mr->r_write = 1;
+
+       /*
+        * Pin the pages that make up the user buffer and transfer the page
+        * pointers to the mr's sg array.  We check to see if we've mapped
+        * the whole region after transferring the partial page references
+        * to the sg array so that we can have one page ref cleanup path.
+        *
+        * For now we have no flag that tells us whether the mapping is
+        * r/o or r/w. We need to assume r/w, or we'll do a lot of RDMA to
+        * the zero page.
+        */
+       ret = rds_pin_pages(args->vec.addr & PAGE_MASK, nr_pages, pages, 1);
+       if (ret < 0)
+               goto out;
+
+       nents = ret;
+       sg = kcalloc(nents, sizeof(*sg), GFP_KERNEL);
+       if (sg == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+       WARN_ON(!nents);
+       sg_init_table(sg, nents);
+
+       /* Stick all pages into the scatterlist */
+       for (i = 0 ; i < nents; i++)
+               sg_set_page(&sg[i], pages[i], PAGE_SIZE, 0);
+
+       rdsdebug("RDS: trans_private nents is %u\n", nents);
+
+       /* Obtain a transport specific MR. If this succeeds, the
+        * s/g list is now owned by the MR.
+        * Note that dma_map() implies that pending writes are
+        * flushed to RAM, so no dma_sync is needed here. */
+       trans_private = rs->rs_transport->get_mr(sg, nents, rs,
+                                                &mr->r_key);
+
+       if (IS_ERR(trans_private)) {
+               for (i = 0 ; i < nents; i++)
+                       put_page(sg_page(&sg[i]));
+               kfree(sg);
+               ret = PTR_ERR(trans_private);
+               goto out;
+       }
+
+       mr->r_trans_private = trans_private;
+
+       rdsdebug("RDS: get_mr put_user key is %x cookie_addr %p\n",
+              mr->r_key, (void *)(unsigned long) args->cookie_addr);
+
+       /* The user may pass us an unaligned address, but we can only
+        * map page aligned regions. So we keep the offset, and build
+        * a 64bit cookie containing <R_Key, offset> and pass that
+        * around. */
+       cookie = rds_rdma_make_cookie(mr->r_key, args->vec.addr & ~PAGE_MASK);
+       if (cookie_ret)
+               *cookie_ret = cookie;
+
+       if (args->cookie_addr && put_user(cookie, (u64 __user *)(unsigned long) args->cookie_addr)) {
+               ret = -EFAULT;
+               goto out;
+       }
+
+       /* Inserting the new MR into the rbtree bumps its
+        * reference count. */
+       spin_lock_irqsave(&rs->rs_rdma_lock, flags);
+       found = rds_mr_tree_walk(&rs->rs_rdma_keys, mr->r_key, mr);
+       spin_unlock_irqrestore(&rs->rs_rdma_lock, flags);
+
+       BUG_ON(found && found != mr);
+
+       rdsdebug("RDS: get_mr key is %x\n", mr->r_key);
+       if (mr_ret) {
+               atomic_inc(&mr->r_refcount);
+               *mr_ret = mr;
+       }
+
+       ret = 0;
+out:
+       kfree(pages);
+       if (mr)
+               rds_mr_put(mr);
+       return ret;
+}
+
+int rds_get_mr(struct rds_sock *rs, char __user *optval, int optlen)
+{
+       struct rds_get_mr_args args;
+
+       if (optlen != sizeof(struct rds_get_mr_args))
+               return -EINVAL;
+
+       if (copy_from_user(&args, (struct rds_get_mr_args __user *)optval,
+                          sizeof(struct rds_get_mr_args)))
+               return -EFAULT;
+
+       return __rds_rdma_map(rs, &args, NULL, NULL);
+}
+
+/*
+ * Free the MR indicated by the given R_Key
+ */
+int rds_free_mr(struct rds_sock *rs, char __user *optval, int optlen)
+{
+       struct rds_free_mr_args args;
+       struct rds_mr *mr;
+       unsigned long flags;
+
+       if (optlen != sizeof(struct rds_free_mr_args))
+               return -EINVAL;
+
+       if (copy_from_user(&args, (struct rds_free_mr_args __user *)optval,
+                          sizeof(struct rds_free_mr_args)))
+               return -EFAULT;
+
+       /* Special case - a null cookie means flush all unused MRs */
+       if (args.cookie == 0) {
+               if (!rs->rs_transport || !rs->rs_transport->flush_mrs)
+                       return -EINVAL;
+               rs->rs_transport->flush_mrs();
+               return 0;
+       }
+
+       /* Look up the MR given its R_key and remove it from the rbtree
+        * so nobody else finds it.
+        * This should also prevent races with rds_rdma_unuse.
+        */
+       spin_lock_irqsave(&rs->rs_rdma_lock, flags);
+       mr = rds_mr_tree_walk(&rs->rs_rdma_keys, rds_rdma_cookie_key(args.cookie), NULL);
+       if (mr) {
+               rb_erase(&mr->r_rb_node, &rs->rs_rdma_keys);
+               RB_CLEAR_NODE(&mr->r_rb_node);
+               if (args.flags & RDS_RDMA_INVALIDATE)
+                       mr->r_invalidate = 1;
+       }
+       spin_unlock_irqrestore(&rs->rs_rdma_lock, flags);
+
+       if (!mr)
+               return -EINVAL;
+
+       /*
+        * call rds_destroy_mr() ourselves so that we're sure it's done by the time
+        * we return.  If we let rds_mr_put() do it it might not happen until
+        * someone else drops their ref.
+        */
+       rds_destroy_mr(mr);
+       rds_mr_put(mr);
+       return 0;
+}
+
+/*
+ * This is called when we receive an extension header that
+ * tells us this MR was used. It allows us to implement
+ * use_once semantics
+ */
+void rds_rdma_unuse(struct rds_sock *rs, u32 r_key, int force)
+{
+       struct rds_mr *mr;
+       unsigned long flags;
+       int zot_me = 0;
+
+       spin_lock_irqsave(&rs->rs_rdma_lock, flags);
+       mr = rds_mr_tree_walk(&rs->rs_rdma_keys, r_key, NULL);
+       if (mr && (mr->r_use_once || force)) {
+               rb_erase(&mr->r_rb_node, &rs->rs_rdma_keys);
+               RB_CLEAR_NODE(&mr->r_rb_node);
+               zot_me = 1;
+       } else if (mr)
+               atomic_inc(&mr->r_refcount);
+       spin_unlock_irqrestore(&rs->rs_rdma_lock, flags);
+
+       /* May have to issue a dma_sync on this memory region.
+        * Note we could avoid this if the operation was a RDMA READ,
+        * but at this point we can't tell. */
+       if (mr != NULL) {
+               if (mr->r_trans->sync_mr)
+                       mr->r_trans->sync_mr(mr->r_trans_private, DMA_FROM_DEVICE);
+
+               /* If the MR was marked as invalidate, this will
+                * trigger an async flush. */
+               if (zot_me)
+                       rds_destroy_mr(mr);
+               rds_mr_put(mr);
+       }
+}
+
+void rds_rdma_free_op(struct rds_rdma_op *ro)
+{
+       unsigned int i;
+
+       for (i = 0; i < ro->r_nents; i++) {
+               struct page *page = sg_page(&ro->r_sg[i]);
+
+               /* Mark page dirty if it was possibly modified, which
+                * is the case for a RDMA_READ which copies from remote
+                * to local memory */
+               if (!ro->r_write)
+                       set_page_dirty(page);
+               put_page(page);
+       }
+
+       kfree(ro->r_notifier);
+       kfree(ro);
+}
+
+/*
+ * args is a pointer to an in-kernel copy in the sendmsg cmsg.
+ */
+static struct rds_rdma_op *rds_rdma_prepare(struct rds_sock *rs,
+                                           struct rds_rdma_args *args)
+{
+       struct rds_iovec vec;
+       struct rds_rdma_op *op = NULL;
+       unsigned int nr_pages;
+       unsigned int max_pages;
+       unsigned int nr_bytes;
+       struct page **pages = NULL;
+       struct rds_iovec __user *local_vec;
+       struct scatterlist *sg;
+       unsigned int nr;
+       unsigned int i, j;
+       int ret;
+
+
+       if (rs->rs_bound_addr == 0) {
+               ret = -ENOTCONN; /* XXX not a great errno */
+               goto out;
+       }
+
+       if (args->nr_local > (u64)UINT_MAX) {
+               ret = -EMSGSIZE;
+               goto out;
+       }
+
+       nr_pages = 0;
+       max_pages = 0;
+
+       local_vec = (struct rds_iovec __user *)(unsigned long) args->local_vec_addr;
+
+       /* figure out the number of pages in the vector */
+       for (i = 0; i < args->nr_local; i++) {
+               if (copy_from_user(&vec, &local_vec[i],
+                                  sizeof(struct rds_iovec))) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+
+               nr = rds_pages_in_vec(&vec);
+               if (nr == 0) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               max_pages = max(nr, max_pages);
+               nr_pages += nr;
+       }
+
+       pages = kcalloc(max_pages, sizeof(struct page *), GFP_KERNEL);
+       if (pages == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       op = kzalloc(offsetof(struct rds_rdma_op, r_sg[nr_pages]), GFP_KERNEL);
+       if (op == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       op->r_write = !!(args->flags & RDS_RDMA_READWRITE);
+       op->r_fence = !!(args->flags & RDS_RDMA_FENCE);
+       op->r_notify = !!(args->flags & RDS_RDMA_NOTIFY_ME);
+       op->r_recverr = rs->rs_recverr;
+       WARN_ON(!nr_pages);
+       sg_init_table(op->r_sg, nr_pages);
+
+       if (op->r_notify || op->r_recverr) {
+               /* We allocate an uninitialized notifier here, because
+                * we don't want to do that in the completion handler. We
+                * would have to use GFP_ATOMIC there, and don't want to deal
+                * with failed allocations.
+                */
+               op->r_notifier = kmalloc(sizeof(struct rds_notifier), GFP_KERNEL);
+               if (!op->r_notifier) {
+                       ret = -ENOMEM;
+                       goto out;
+               }
+               op->r_notifier->n_user_token = args->user_token;
+               op->r_notifier->n_status = RDS_RDMA_SUCCESS;
+       }
+
+       /* The cookie contains the R_Key of the remote memory region, and
+        * optionally an offset into it. This is how we implement RDMA into
+        * unaligned memory.
+        * When setting up the RDMA, we need to add that offset to the
+        * destination address (which is really an offset into the MR)
+        * FIXME: We may want to move this into ib_rdma.c
+        */
+       op->r_key = rds_rdma_cookie_key(args->cookie);
+       op->r_remote_addr = args->remote_vec.addr + rds_rdma_cookie_offset(args->cookie);
+
+       nr_bytes = 0;
+
+       rdsdebug("RDS: rdma prepare nr_local %llu rva %llx rkey %x\n",
+              (unsigned long long)args->nr_local,
+              (unsigned long long)args->remote_vec.addr,
+              op->r_key);
+
+       for (i = 0; i < args->nr_local; i++) {
+               if (copy_from_user(&vec, &local_vec[i],
+                                  sizeof(struct rds_iovec))) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+
+               nr = rds_pages_in_vec(&vec);
+               if (nr == 0) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+
+               rs->rs_user_addr = vec.addr;
+               rs->rs_user_bytes = vec.bytes;
+
+               /* did the user change the vec under us? */
+               if (nr > max_pages || op->r_nents + nr > nr_pages) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+               /* If it's a WRITE operation, we want to pin the pages for reading.
+                * If it's a READ operation, we need to pin the pages for writing.
+                */
+               ret = rds_pin_pages(vec.addr & PAGE_MASK, nr, pages, !op->r_write);
+               if (ret < 0)
+                       goto out;
+
+               rdsdebug("RDS: nr_bytes %u nr %u vec.bytes %llu vec.addr %llx\n",
+                      nr_bytes, nr, vec.bytes, vec.addr);
+
+               nr_bytes += vec.bytes;
+
+               for (j = 0; j < nr; j++) {
+                       unsigned int offset = vec.addr & ~PAGE_MASK;
+
+                       sg = &op->r_sg[op->r_nents + j];
+                       sg_set_page(sg, pages[j],
+                                       min_t(unsigned int, vec.bytes, PAGE_SIZE - offset),
+                                       offset);
+
+                       rdsdebug("RDS: sg->offset %x sg->len %x vec.addr %llx vec.bytes %llu\n",
+                              sg->offset, sg->length, vec.addr, vec.bytes);
+
+                       vec.addr += sg->length;
+                       vec.bytes -= sg->length;
+               }
+
+               op->r_nents += nr;
+       }
+
+
+       if (nr_bytes > args->remote_vec.bytes) {
+               rdsdebug("RDS nr_bytes %u remote_bytes %u do not match\n",
+                               nr_bytes,
+                               (unsigned int) args->remote_vec.bytes);
+               ret = -EINVAL;
+               goto out;
+       }
+       op->r_bytes = nr_bytes;
+
+       ret = 0;
+out:
+       kfree(pages);
+       if (ret) {
+               if (op)
+                       rds_rdma_free_op(op);
+               op = ERR_PTR(ret);
+       }
+       return op;
+}
+
+/*
+ * The application asks for a RDMA transfer.
+ * Extract all arguments and set up the rdma_op
+ */
+int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
+                         struct cmsghdr *cmsg)
+{
+       struct rds_rdma_op *op;
+
+       if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct rds_rdma_args))
+        || rm->m_rdma_op != NULL)
+               return -EINVAL;
+
+       op = rds_rdma_prepare(rs, CMSG_DATA(cmsg));
+       if (IS_ERR(op))
+               return PTR_ERR(op);
+       rds_stats_inc(s_send_rdma);
+       rm->m_rdma_op = op;
+       return 0;
+}
+
+/*
+ * The application wants us to pass an RDMA destination (aka MR)
+ * to the remote
+ */
+int rds_cmsg_rdma_dest(struct rds_sock *rs, struct rds_message *rm,
+                         struct cmsghdr *cmsg)
+{
+       unsigned long flags;
+       struct rds_mr *mr;
+       u32 r_key;
+       int err = 0;
+
+       if (cmsg->cmsg_len < CMSG_LEN(sizeof(rds_rdma_cookie_t))
+        || rm->m_rdma_cookie != 0)
+               return -EINVAL;
+
+       memcpy(&rm->m_rdma_cookie, CMSG_DATA(cmsg), sizeof(rm->m_rdma_cookie));
+
+       /* We are reusing a previously mapped MR here. Most likely, the
+        * application has written to the buffer, so we need to explicitly
+        * flush those writes to RAM. Otherwise the HCA may not see them
+        * when doing a DMA from that buffer.
+        */
+       r_key = rds_rdma_cookie_key(rm->m_rdma_cookie);
+
+       spin_lock_irqsave(&rs->rs_rdma_lock, flags);
+       mr = rds_mr_tree_walk(&rs->rs_rdma_keys, r_key, NULL);
+       if (mr == NULL)
+               err = -EINVAL;  /* invalid r_key */
+       else
+               atomic_inc(&mr->r_refcount);
+       spin_unlock_irqrestore(&rs->rs_rdma_lock, flags);
+
+       if (mr) {
+               mr->r_trans->sync_mr(mr->r_trans_private, DMA_TO_DEVICE);
+               rm->m_rdma_mr = mr;
+       }
+       return err;
+}
+
+/*
+ * The application passes us an address range it wants to enable RDMA
+ * to/from. We map the area, and save the <R_Key,offset> pair
+ * in rm->m_rdma_cookie. This causes it to be sent along to the peer
+ * in an extension header.
+ */
+int rds_cmsg_rdma_map(struct rds_sock *rs, struct rds_message *rm,
+                         struct cmsghdr *cmsg)
+{
+       if (cmsg->cmsg_len < CMSG_LEN(sizeof(struct rds_get_mr_args))
+        || rm->m_rdma_cookie != 0)
+               return -EINVAL;
+
+       return __rds_rdma_map(rs, CMSG_DATA(cmsg), &rm->m_rdma_cookie, &rm->m_rdma_mr);
+}
diff --git a/net/rds/rdma.h b/net/rds/rdma.h
new file mode 100644 (file)
index 0000000..4255120
--- /dev/null
@@ -0,0 +1,84 @@
+#ifndef _RDS_RDMA_H
+#define _RDS_RDMA_H
+
+#include <linux/rbtree.h>
+#include <linux/spinlock.h>
+#include <linux/scatterlist.h>
+
+#include "rds.h"
+
+struct rds_mr {
+       struct rb_node          r_rb_node;
+       atomic_t                r_refcount;
+       u32                     r_key;
+
+       /* A copy of the creation flags */
+       unsigned int            r_use_once:1;
+       unsigned int            r_invalidate:1;
+       unsigned int            r_write:1;
+
+       /* This is for RDS_MR_DEAD.
+        * It would be nice & consistent to make this part of the above
+        * bit field here, but we need to use test_and_set_bit.
+        */
+       unsigned long           r_state;
+       struct rds_sock         *r_sock; /* back pointer to the socket that owns us */
+       struct rds_transport    *r_trans;
+       void                    *r_trans_private;
+};
+
+/* Flags for mr->r_state */
+#define RDS_MR_DEAD            0
+
+struct rds_rdma_op {
+       u32                     r_key;
+       u64                     r_remote_addr;
+       unsigned int            r_write:1;
+       unsigned int            r_fence:1;
+       unsigned int            r_notify:1;
+       unsigned int            r_recverr:1;
+       unsigned int            r_mapped:1;
+       struct rds_notifier     *r_notifier;
+       unsigned int            r_bytes;
+       unsigned int            r_nents;
+       unsigned int            r_count;
+       struct scatterlist      r_sg[0];
+};
+
+static inline rds_rdma_cookie_t rds_rdma_make_cookie(u32 r_key, u32 offset)
+{
+       return r_key | (((u64) offset) << 32);
+}
+
+static inline u32 rds_rdma_cookie_key(rds_rdma_cookie_t cookie)
+{
+       return cookie;
+}
+
+static inline u32 rds_rdma_cookie_offset(rds_rdma_cookie_t cookie)
+{
+       return cookie >> 32;
+}
+
+int rds_get_mr(struct rds_sock *rs, char __user *optval, int optlen);
+int rds_free_mr(struct rds_sock *rs, char __user *optval, int optlen);
+void rds_rdma_drop_keys(struct rds_sock *rs);
+int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
+                         struct cmsghdr *cmsg);
+int rds_cmsg_rdma_dest(struct rds_sock *rs, struct rds_message *rm,
+                         struct cmsghdr *cmsg);
+int rds_cmsg_rdma_args(struct rds_sock *rs, struct rds_message *rm,
+                         struct cmsghdr *cmsg);
+int rds_cmsg_rdma_map(struct rds_sock *rs, struct rds_message *rm,
+                         struct cmsghdr *cmsg);
+void rds_rdma_free_op(struct rds_rdma_op *ro);
+void rds_rdma_send_complete(struct rds_message *rm, int);
+
+extern void __rds_put_mr_final(struct rds_mr *mr);
+static inline void rds_mr_put(struct rds_mr *mr)
+{
+       if (atomic_dec_and_test(&mr->r_refcount))
+               __rds_put_mr_final(mr);
+}
+
+#endif
diff --git a/net/rds/rdma_transport.c b/net/rds/rdma_transport.c
new file mode 100644 (file)
index 0000000..7b19024
--- /dev/null
@@ -0,0 +1,214 @@
+/*
+ * Copyright (c) 2009 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <rdma/rdma_cm.h>
+
+#include "rdma_transport.h"
+
+static struct rdma_cm_id *rds_iw_listen_id;
+
+int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
+                             struct rdma_cm_event *event)
+{
+       /* this can be null in the listening path */
+       struct rds_connection *conn = cm_id->context;
+       struct rds_transport *trans;
+       int ret = 0;
+
+       rdsdebug("conn %p id %p handling event %u\n", conn, cm_id,
+                event->event);
+
+       if (cm_id->device->node_type == RDMA_NODE_RNIC)
+               trans = &rds_iw_transport;
+       else
+               trans = &rds_ib_transport;
+
+       /* Prevent shutdown from tearing down the connection
+        * while we're executing. */
+       if (conn) {
+               mutex_lock(&conn->c_cm_lock);
+
+               /* If the connection is being shut down, bail out
+                * right away. We return 0 so cm_id doesn't get
+                * destroyed prematurely */
+               if (rds_conn_state(conn) == RDS_CONN_DISCONNECTING) {
+                       /* Reject incoming connections while we're tearing
+                        * down an existing one. */
+                       if (event->event == RDMA_CM_EVENT_CONNECT_REQUEST)
+                               ret = 1;
+                       goto out;
+               }
+       }
+
+       switch (event->event) {
+       case RDMA_CM_EVENT_CONNECT_REQUEST:
+               ret = trans->cm_handle_connect(cm_id, event);
+               break;
+
+       case RDMA_CM_EVENT_ADDR_RESOLVED:
+               /* XXX do we need to clean up if this fails? */
+               ret = rdma_resolve_route(cm_id,
+                                        RDS_RDMA_RESOLVE_TIMEOUT_MS);
+               break;
+
+       case RDMA_CM_EVENT_ROUTE_RESOLVED:
+               /* XXX worry about racing with listen acceptance */
+               ret = trans->cm_initiate_connect(cm_id);
+               break;
+
+       case RDMA_CM_EVENT_ESTABLISHED:
+               trans->cm_connect_complete(conn, event);
+               break;
+
+       case RDMA_CM_EVENT_ADDR_ERROR:
+       case RDMA_CM_EVENT_ROUTE_ERROR:
+       case RDMA_CM_EVENT_CONNECT_ERROR:
+       case RDMA_CM_EVENT_UNREACHABLE:
+       case RDMA_CM_EVENT_REJECTED:
+       case RDMA_CM_EVENT_DEVICE_REMOVAL:
+       case RDMA_CM_EVENT_ADDR_CHANGE:
+               if (conn)
+                       rds_conn_drop(conn);
+               break;
+
+       case RDMA_CM_EVENT_DISCONNECTED:
+               printk(KERN_WARNING "RDS/IW: DISCONNECT event - dropping connection "
+                       "%pI4->%pI4\n", &conn->c_laddr,
+                        &conn->c_faddr);
+               rds_conn_drop(conn);
+               break;
+
+       default:
+               /* things like device disconnect? */
+               printk(KERN_ERR "unknown event %u\n", event->event);
+               BUG();
+               break;
+       }
+
+out:
+       if (conn)
+               mutex_unlock(&conn->c_cm_lock);
+
+       rdsdebug("id %p event %u handling ret %d\n", cm_id, event->event, ret);
+
+       return ret;
+}
+
+static int __init rds_rdma_listen_init(void)
+{
+       struct sockaddr_in sin;
+       struct rdma_cm_id *cm_id;
+       int ret;
+
+       cm_id = rdma_create_id(rds_rdma_cm_event_handler, NULL, RDMA_PS_TCP);
+       if (IS_ERR(cm_id)) {
+               ret = PTR_ERR(cm_id);
+               printk(KERN_ERR "RDS/IW: failed to setup listener, "
+                      "rdma_create_id() returned %d\n", ret);
+               goto out;
+       }
+
+       sin.sin_family = PF_INET,
+       sin.sin_addr.s_addr = (__force u32)htonl(INADDR_ANY);
+       sin.sin_port = (__force u16)htons(RDS_PORT);
+
+       /*
+        * XXX I bet this binds the cm_id to a device.  If we want to support
+        * fail-over we'll have to take this into consideration.
+        */
+       ret = rdma_bind_addr(cm_id, (struct sockaddr *)&sin);
+       if (ret) {
+               printk(KERN_ERR "RDS/IW: failed to setup listener, "
+                      "rdma_bind_addr() returned %d\n", ret);
+               goto out;
+       }
+
+       ret = rdma_listen(cm_id, 128);
+       if (ret) {
+               printk(KERN_ERR "RDS/IW: failed to setup listener, "
+                      "rdma_listen() returned %d\n", ret);
+               goto out;
+       }
+
+       rdsdebug("cm %p listening on port %u\n", cm_id, RDS_PORT);
+
+       rds_iw_listen_id = cm_id;
+       cm_id = NULL;
+out:
+       if (cm_id)
+               rdma_destroy_id(cm_id);
+       return ret;
+}
+
+static void rds_rdma_listen_stop(void)
+{
+       if (rds_iw_listen_id) {
+               rdsdebug("cm %p\n", rds_iw_listen_id);
+               rdma_destroy_id(rds_iw_listen_id);
+               rds_iw_listen_id = NULL;
+       }
+}
+
+int __init rds_rdma_init(void)
+{
+       int ret;
+
+       ret = rds_rdma_listen_init();
+       if (ret)
+               goto out;
+
+       ret = rds_iw_init();
+       if (ret)
+               goto err_iw_init;
+
+       ret = rds_ib_init();
+       if (ret)
+               goto err_ib_init;
+
+       goto out;
+
+err_ib_init:
+       rds_iw_exit();
+err_iw_init:
+       rds_rdma_listen_stop();
+out:
+       return ret;
+}
+
+void rds_rdma_exit(void)
+{
+       /* stop listening first to ensure no new connections are attempted */
+       rds_rdma_listen_stop();
+       rds_ib_exit();
+       rds_iw_exit();
+}
+
diff --git a/net/rds/rdma_transport.h b/net/rds/rdma_transport.h
new file mode 100644 (file)
index 0000000..2f2c7d9
--- /dev/null
@@ -0,0 +1,28 @@
+#ifndef _RDMA_TRANSPORT_H
+#define _RDMA_TRANSPORT_H
+
+#include <rdma/ib_verbs.h>
+#include <rdma/rdma_cm.h>
+#include "rds.h"
+
+#define RDS_RDMA_RESOLVE_TIMEOUT_MS     5000
+
+int rds_rdma_conn_connect(struct rds_connection *conn);
+int rds_rdma_cm_event_handler(struct rdma_cm_id *cm_id,
+                             struct rdma_cm_event *event);
+
+/* from rdma_transport.c */
+int rds_rdma_init(void);
+void rds_rdma_exit(void);
+
+/* from ib.c */
+extern struct rds_transport rds_ib_transport;
+int rds_ib_init(void);
+void rds_ib_exit(void);
+
+/* from iw.c */
+extern struct rds_transport rds_iw_transport;
+int rds_iw_init(void);
+void rds_iw_exit(void);
+
+#endif
diff --git a/net/rds/rds.h b/net/rds/rds.h
new file mode 100644 (file)
index 0000000..0604007
--- /dev/null
@@ -0,0 +1,686 @@
+#ifndef _RDS_RDS_H
+#define _RDS_RDS_H
+
+#include <net/sock.h>
+#include <linux/scatterlist.h>
+#include <linux/highmem.h>
+#include <rdma/rdma_cm.h>
+#include <linux/mutex.h>
+#include <linux/rds.h>
+
+#include "info.h"
+
+/*
+ * RDS Network protocol version
+ */
+#define RDS_PROTOCOL_3_0       0x0300
+#define RDS_PROTOCOL_3_1       0x0301
+#define RDS_PROTOCOL_VERSION   RDS_PROTOCOL_3_1
+#define RDS_PROTOCOL_MAJOR(v)  ((v) >> 8)
+#define RDS_PROTOCOL_MINOR(v)  ((v) & 255)
+#define RDS_PROTOCOL(maj, min) (((maj) << 8) | min)
+
+/*
+ * XXX randomly chosen, but at least seems to be unused:
+ * #               18464-18768 Unassigned
+ * We should do better.  We want a reserved port to discourage unpriv'ed
+ * userspace from listening.
+ */
+#define RDS_PORT       18634
+
+#ifdef DEBUG
+#define rdsdebug(fmt, args...) pr_debug("%s(): " fmt, __func__ , ##args)
+#else
+/* sigh, pr_debug() causes unused variable warnings */
+static inline void __attribute__ ((format (printf, 1, 2)))
+rdsdebug(char *fmt, ...)
+{
+}
+#endif
+
+/* XXX is there one of these somewhere? */
+#define ceil(x, y) \
+       ({ unsigned long __x = (x), __y = (y); (__x + __y - 1) / __y; })
+
+#define RDS_FRAG_SHIFT 12
+#define RDS_FRAG_SIZE  ((unsigned int)(1 << RDS_FRAG_SHIFT))
+
+#define RDS_CONG_MAP_BYTES     (65536 / 8)
+#define RDS_CONG_MAP_LONGS     (RDS_CONG_MAP_BYTES / sizeof(unsigned long))
+#define RDS_CONG_MAP_PAGES     (PAGE_ALIGN(RDS_CONG_MAP_BYTES) / PAGE_SIZE)
+#define RDS_CONG_MAP_PAGE_BITS (PAGE_SIZE * 8)
+
+struct rds_cong_map {
+       struct rb_node          m_rb_node;
+       __be32                  m_addr;
+       wait_queue_head_t       m_waitq;
+       struct list_head        m_conn_list;
+       unsigned long           m_page_addrs[RDS_CONG_MAP_PAGES];
+};
+
+
+/*
+ * This is how we will track the connection state:
+ * A connection is always in one of the following
+ * states. Updates to the state are atomic and imply
+ * a memory barrier.
+ */
+enum {
+       RDS_CONN_DOWN = 0,
+       RDS_CONN_CONNECTING,
+       RDS_CONN_DISCONNECTING,
+       RDS_CONN_UP,
+       RDS_CONN_ERROR,
+};
+
+/* Bits for c_flags */
+#define RDS_LL_SEND_FULL       0
+#define RDS_RECONNECT_PENDING  1
+
+struct rds_connection {
+       struct hlist_node       c_hash_node;
+       __be32                  c_laddr;
+       __be32                  c_faddr;
+       unsigned int            c_loopback:1;
+       struct rds_connection   *c_passive;
+
+       struct rds_cong_map     *c_lcong;
+       struct rds_cong_map     *c_fcong;
+
+       struct mutex            c_send_lock;    /* protect send ring */
+       struct rds_message      *c_xmit_rm;
+       unsigned long           c_xmit_sg;
+       unsigned int            c_xmit_hdr_off;
+       unsigned int            c_xmit_data_off;
+       unsigned int            c_xmit_rdma_sent;
+
+       spinlock_t              c_lock;         /* protect msg queues */
+       u64                     c_next_tx_seq;
+       struct list_head        c_send_queue;
+       struct list_head        c_retrans;
+
+       u64                     c_next_rx_seq;
+
+       struct rds_transport    *c_trans;
+       void                    *c_transport_data;
+
+       atomic_t                c_state;
+       unsigned long           c_flags;
+       unsigned long           c_reconnect_jiffies;
+       struct delayed_work     c_send_w;
+       struct delayed_work     c_recv_w;
+       struct delayed_work     c_conn_w;
+       struct work_struct      c_down_w;
+       struct mutex            c_cm_lock;      /* protect conn state & cm */
+
+       struct list_head        c_map_item;
+       unsigned long           c_map_queued;
+       unsigned long           c_map_offset;
+       unsigned long           c_map_bytes;
+
+       unsigned int            c_unacked_packets;
+       unsigned int            c_unacked_bytes;
+
+       /* Protocol version */
+       unsigned int            c_version;
+};
+
+#define RDS_FLAG_CONG_BITMAP   0x01
+#define RDS_FLAG_ACK_REQUIRED  0x02
+#define RDS_FLAG_RETRANSMITTED 0x04
+#define RDS_MAX_ADV_CREDIT     127
+
+/*
+ * Maximum space available for extension headers.
+ */
+#define RDS_HEADER_EXT_SPACE   16
+
+struct rds_header {
+       __be64  h_sequence;
+       __be64  h_ack;
+       __be32  h_len;
+       __be16  h_sport;
+       __be16  h_dport;
+       u8      h_flags;
+       u8      h_credit;
+       u8      h_padding[4];
+       __sum16 h_csum;
+
+       u8      h_exthdr[RDS_HEADER_EXT_SPACE];
+};
+
+/*
+ * Reserved - indicates end of extensions
+ */
+#define RDS_EXTHDR_NONE                0
+
+/*
+ * This extension header is included in the very
+ * first message that is sent on a new connection,
+ * and identifies the protocol level. This will help
+ * rolling updates if a future change requires breaking
+ * the protocol.
+ * NB: This is no longer true for IB, where we do a version
+ * negotiation during the connection setup phase (protocol
+ * version information is included in the RDMA CM private data).
+ */
+#define RDS_EXTHDR_VERSION     1
+struct rds_ext_header_version {
+       __be32                  h_version;
+};
+
+/*
+ * This extension header is included in the RDS message
+ * chasing an RDMA operation.
+ */
+#define RDS_EXTHDR_RDMA                2
+struct rds_ext_header_rdma {
+       __be32                  h_rdma_rkey;
+};
+
+/*
+ * This extension header tells the peer about the
+ * destination <R_Key,offset> of the requested RDMA
+ * operation.
+ */
+#define RDS_EXTHDR_RDMA_DEST   3
+struct rds_ext_header_rdma_dest {
+       __be32                  h_rdma_rkey;
+       __be32                  h_rdma_offset;
+};
+
+#define __RDS_EXTHDR_MAX       16 /* for now */
+
+struct rds_incoming {
+       atomic_t                i_refcount;
+       struct list_head        i_item;
+       struct rds_connection   *i_conn;
+       struct rds_header       i_hdr;
+       unsigned long           i_rx_jiffies;
+       __be32                  i_saddr;
+
+       rds_rdma_cookie_t       i_rdma_cookie;
+};
+
+/*
+ * m_sock_item and m_conn_item are on lists that are serialized under
+ * conn->c_lock.  m_sock_item has additional meaning in that once it is empty
+ * the message will not be put back on the retransmit list after being sent.
+ * messages that are canceled while being sent rely on this.
+ *
+ * m_inc is used by loopback so that it can pass an incoming message straight
+ * back up into the rx path.  It embeds a wire header which is also used by
+ * the send path, which is kind of awkward.
+ *
+ * m_sock_item indicates the message's presence on a socket's send or receive
+ * queue.  m_rs will point to that socket.
+ *
+ * m_daddr is used by cancellation to prune messages to a given destination.
+ *
+ * The RDS_MSG_ON_SOCK and RDS_MSG_ON_CONN flags are used to avoid lock
+ * nesting.  As paths iterate over messages on a sock, or conn, they must
+ * also lock the conn, or sock, to remove the message from those lists too.
+ * Testing the flag to determine if the message is still on the lists lets
+ * us avoid testing the list_head directly.  That means each path can use
+ * the message's list_head to keep it on a local list while juggling locks
+ * without confusing the other path.
+ *
+ * m_ack_seq is an optional field set by transports who need a different
+ * sequence number range to invalidate.  They can use this in a callback
+ * that they pass to rds_send_drop_acked() to see if each message has been
+ * acked.  The HAS_ACK_SEQ flag can be used to detect messages which haven't
+ * had ack_seq set yet.
+ */
+#define RDS_MSG_ON_SOCK                1
+#define RDS_MSG_ON_CONN                2
+#define RDS_MSG_HAS_ACK_SEQ    3
+#define RDS_MSG_ACK_REQUIRED   4
+#define RDS_MSG_RETRANSMITTED  5
+#define RDS_MSG_MAPPED         6
+#define RDS_MSG_PAGEVEC                7
+
+struct rds_message {
+       atomic_t                m_refcount;
+       struct list_head        m_sock_item;
+       struct list_head        m_conn_item;
+       struct rds_incoming     m_inc;
+       u64                     m_ack_seq;
+       __be32                  m_daddr;
+       unsigned long           m_flags;
+
+       /* Never access m_rs without holding m_rs_lock.
+        * Lock nesting is
+        *  rm->m_rs_lock
+        *   -> rs->rs_lock
+        */
+       spinlock_t              m_rs_lock;
+       struct rds_sock         *m_rs;
+       struct rds_rdma_op      *m_rdma_op;
+       rds_rdma_cookie_t       m_rdma_cookie;
+       struct rds_mr           *m_rdma_mr;
+       unsigned int            m_nents;
+       unsigned int            m_count;
+       struct scatterlist      m_sg[0];
+};
+
+/*
+ * The RDS notifier is used (optionally) to tell the application about
+ * completed RDMA operations. Rather than keeping the whole rds message
+ * around on the queue, we allocate a small notifier that is put on the
+ * socket's notifier_list. Notifications are delivered to the application
+ * through control messages.
+ */
+struct rds_notifier {
+       struct list_head        n_list;
+       uint64_t                n_user_token;
+       int                     n_status;
+};
+
+/**
+ * struct rds_transport -  transport specific behavioural hooks
+ *
+ * @xmit: .xmit is called by rds_send_xmit() to tell the transport to send
+ *        part of a message.  The caller serializes on the send_sem so this
+ *        doesn't need to be reentrant for a given conn.  The header must be
+ *        sent before the data payload.  .xmit must be prepared to send a
+ *        message with no data payload.  .xmit should return the number of
+ *        bytes that were sent down the connection, including header bytes.
+ *        Returning 0 tells the caller that it doesn't need to perform any
+ *        additional work now.  This is usually the case when the transport has
+ *        filled the sending queue for its connection and will handle
+ *        triggering the rds thread to continue the send when space becomes
+ *        available.  Returning -EAGAIN tells the caller to retry the send
+ *        immediately.  Returning -ENOMEM tells the caller to retry the send at
+ *        some point in the future.
+ *
+ * @conn_shutdown: conn_shutdown stops traffic on the given connection.  Once
+ *                 it returns the connection can not call rds_recv_incoming().
+ *                 This will only be called once after conn_connect returns
+ *                 non-zero success and will The caller serializes this with
+ *                 the send and connecting paths (xmit_* and conn_*).  The
+ *                 transport is responsible for other serialization, including
+ *                 rds_recv_incoming().  This is called in process context but
+ *                 should try hard not to block.
+ *
+ * @xmit_cong_map: This asks the transport to send the local bitmap down the
+ *                given connection.  XXX get a better story about the bitmap
+ *                flag and header.
+ */
+
+struct rds_transport {
+       char                    t_name[TRANSNAMSIZ];
+       struct list_head        t_item;
+       struct module           *t_owner;
+       unsigned int            t_prefer_loopback:1;
+
+       int (*laddr_check)(__be32 addr);
+       int (*conn_alloc)(struct rds_connection *conn, gfp_t gfp);
+       void (*conn_free)(void *data);
+       int (*conn_connect)(struct rds_connection *conn);
+       void (*conn_shutdown)(struct rds_connection *conn);
+       void (*xmit_prepare)(struct rds_connection *conn);
+       void (*xmit_complete)(struct rds_connection *conn);
+       int (*xmit)(struct rds_connection *conn, struct rds_message *rm,
+                   unsigned int hdr_off, unsigned int sg, unsigned int off);
+       int (*xmit_cong_map)(struct rds_connection *conn,
+                            struct rds_cong_map *map, unsigned long offset);
+       int (*xmit_rdma)(struct rds_connection *conn, struct rds_rdma_op *op);
+       int (*recv)(struct rds_connection *conn);
+       int (*inc_copy_to_user)(struct rds_incoming *inc, struct iovec *iov,
+                               size_t size);
+       void (*inc_purge)(struct rds_incoming *inc);
+       void (*inc_free)(struct rds_incoming *inc);
+
+       int (*cm_handle_connect)(struct rdma_cm_id *cm_id,
+                                struct rdma_cm_event *event);
+       int (*cm_initiate_connect)(struct rdma_cm_id *cm_id);
+       void (*cm_connect_complete)(struct rds_connection *conn,
+                                   struct rdma_cm_event *event);
+
+       unsigned int (*stats_info_copy)(struct rds_info_iterator *iter,
+                                       unsigned int avail);
+       void (*exit)(void);
+       void *(*get_mr)(struct scatterlist *sg, unsigned long nr_sg,
+                       struct rds_sock *rs, u32 *key_ret);
+       void (*sync_mr)(void *trans_private, int direction);
+       void (*free_mr)(void *trans_private, int invalidate);
+       void (*flush_mrs)(void);
+};
+
+struct rds_sock {
+       struct sock             rs_sk;
+
+       u64                     rs_user_addr;
+       u64                     rs_user_bytes;
+
+       /*
+        * bound_addr used for both incoming and outgoing, no INADDR_ANY
+        * support.
+        */
+       struct rb_node          rs_bound_node;
+       __be32                  rs_bound_addr;
+       __be32                  rs_conn_addr;
+       __be16                  rs_bound_port;
+       __be16                  rs_conn_port;
+
+       /*
+        * This is only used to communicate the transport between bind and
+        * initiating connections.  All other trans use is referenced through
+        * the connection.
+        */
+       struct rds_transport    *rs_transport;
+
+       /*
+        * rds_sendmsg caches the conn it used the last time around.
+        * This helps avoid costly lookups.
+        */
+       struct rds_connection   *rs_conn;
+
+       /* flag indicating we were congested or not */
+       int                     rs_congested;
+
+       /* rs_lock protects all these adjacent members before the newline */
+       spinlock_t              rs_lock;
+       struct list_head        rs_send_queue;
+       u32                     rs_snd_bytes;
+       int                     rs_rcv_bytes;
+       struct list_head        rs_notify_queue;        /* currently used for failed RDMAs */
+
+       /* Congestion wake_up. If rs_cong_monitor is set, we use cong_mask
+        * to decide whether the application should be woken up.
+        * If not set, we use rs_cong_track to find out whether a cong map
+        * update arrived.
+        */
+       uint64_t                rs_cong_mask;
+       uint64_t                rs_cong_notify;
+       struct list_head        rs_cong_list;
+       unsigned long           rs_cong_track;
+
+       /*
+        * rs_recv_lock protects the receive queue, and is
+        * used to serialize with rds_release.
+        */
+       rwlock_t                rs_recv_lock;
+       struct list_head        rs_recv_queue;
+
+       /* just for stats reporting */
+       struct list_head        rs_item;
+
+       /* these have their own lock */
+       spinlock_t              rs_rdma_lock;
+       struct rb_root          rs_rdma_keys;
+
+       /* Socket options - in case there will be more */
+       unsigned char           rs_recverr,
+                               rs_cong_monitor;
+};
+
+static inline struct rds_sock *rds_sk_to_rs(const struct sock *sk)
+{
+       return container_of(sk, struct rds_sock, rs_sk);
+}
+static inline struct sock *rds_rs_to_sk(struct rds_sock *rs)
+{
+       return &rs->rs_sk;
+}
+
+/*
+ * The stack assigns sk_sndbuf and sk_rcvbuf to twice the specified value
+ * to account for overhead.  We don't account for overhead, we just apply
+ * the number of payload bytes to the specified value.
+ */
+static inline int rds_sk_sndbuf(struct rds_sock *rs)
+{
+       return rds_rs_to_sk(rs)->sk_sndbuf / 2;
+}
+static inline int rds_sk_rcvbuf(struct rds_sock *rs)
+{
+       return rds_rs_to_sk(rs)->sk_rcvbuf / 2;
+}
+
+struct rds_statistics {
+       uint64_t        s_conn_reset;
+       uint64_t        s_recv_drop_bad_checksum;
+       uint64_t        s_recv_drop_old_seq;
+       uint64_t        s_recv_drop_no_sock;
+       uint64_t        s_recv_drop_dead_sock;
+       uint64_t        s_recv_deliver_raced;
+       uint64_t        s_recv_delivered;
+       uint64_t        s_recv_queued;
+       uint64_t        s_recv_immediate_retry;
+       uint64_t        s_recv_delayed_retry;
+       uint64_t        s_recv_ack_required;
+       uint64_t        s_recv_rdma_bytes;
+       uint64_t        s_recv_ping;
+       uint64_t        s_send_queue_empty;
+       uint64_t        s_send_queue_full;
+       uint64_t        s_send_sem_contention;
+       uint64_t        s_send_sem_queue_raced;
+       uint64_t        s_send_immediate_retry;
+       uint64_t        s_send_delayed_retry;
+       uint64_t        s_send_drop_acked;
+       uint64_t        s_send_ack_required;
+       uint64_t        s_send_queued;
+       uint64_t        s_send_rdma;
+       uint64_t        s_send_rdma_bytes;
+       uint64_t        s_send_pong;
+       uint64_t        s_page_remainder_hit;
+       uint64_t        s_page_remainder_miss;
+       uint64_t        s_copy_to_user;
+       uint64_t        s_copy_from_user;
+       uint64_t        s_cong_update_queued;
+       uint64_t        s_cong_update_received;
+       uint64_t        s_cong_send_error;
+       uint64_t        s_cong_send_blocked;
+};
+
+/* af_rds.c */
+void rds_sock_addref(struct rds_sock *rs);
+void rds_sock_put(struct rds_sock *rs);
+void rds_wake_sk_sleep(struct rds_sock *rs);
+static inline void __rds_wake_sk_sleep(struct sock *sk)
+{
+       wait_queue_head_t *waitq = sk->sk_sleep;
+
+       if (!sock_flag(sk, SOCK_DEAD) && waitq)
+               wake_up(waitq);
+}
+extern wait_queue_head_t rds_poll_waitq;
+
+
+/* bind.c */
+int rds_bind(struct socket *sock, struct sockaddr *uaddr, int addr_len);
+void rds_remove_bound(struct rds_sock *rs);
+struct rds_sock *rds_find_bound(__be32 addr, __be16 port);
+
+/* cong.c */
+int rds_cong_get_maps(struct rds_connection *conn);
+void rds_cong_add_conn(struct rds_connection *conn);
+void rds_cong_remove_conn(struct rds_connection *conn);
+void rds_cong_set_bit(struct rds_cong_map *map, __be16 port);
+void rds_cong_clear_bit(struct rds_cong_map *map, __be16 port);
+int rds_cong_wait(struct rds_cong_map *map, __be16 port, int nonblock, struct rds_sock *rs);
+void rds_cong_queue_updates(struct rds_cong_map *map);
+void rds_cong_map_updated(struct rds_cong_map *map, uint64_t);
+int rds_cong_updated_since(unsigned long *recent);
+void rds_cong_add_socket(struct rds_sock *);
+void rds_cong_remove_socket(struct rds_sock *);
+void rds_cong_exit(void);
+struct rds_message *rds_cong_update_alloc(struct rds_connection *conn);
+
+/* conn.c */
+int __init rds_conn_init(void);
+void rds_conn_exit(void);
+struct rds_connection *rds_conn_create(__be32 laddr, __be32 faddr,
+                                      struct rds_transport *trans, gfp_t gfp);
+struct rds_connection *rds_conn_create_outgoing(__be32 laddr, __be32 faddr,
+                              struct rds_transport *trans, gfp_t gfp);
+void rds_conn_destroy(struct rds_connection *conn);
+void rds_conn_reset(struct rds_connection *conn);
+void rds_conn_drop(struct rds_connection *conn);
+void rds_for_each_conn_info(struct socket *sock, unsigned int len,
+                         struct rds_info_iterator *iter,
+                         struct rds_info_lengths *lens,
+                         int (*visitor)(struct rds_connection *, void *),
+                         size_t item_len);
+void __rds_conn_error(struct rds_connection *conn, const char *, ...)
+                               __attribute__ ((format (printf, 2, 3)));
+#define rds_conn_error(conn, fmt...) \
+       __rds_conn_error(conn, KERN_WARNING "RDS: " fmt)
+
+static inline int
+rds_conn_transition(struct rds_connection *conn, int old, int new)
+{
+       return atomic_cmpxchg(&conn->c_state, old, new) == old;
+}
+
+static inline int
+rds_conn_state(struct rds_connection *conn)
+{
+       return atomic_read(&conn->c_state);
+}
+
+static inline int
+rds_conn_up(struct rds_connection *conn)
+{
+       return atomic_read(&conn->c_state) == RDS_CONN_UP;
+}
+
+static inline int
+rds_conn_connecting(struct rds_connection *conn)
+{
+       return atomic_read(&conn->c_state) == RDS_CONN_CONNECTING;
+}
+
+/* message.c */
+struct rds_message *rds_message_alloc(unsigned int nents, gfp_t gfp);
+struct rds_message *rds_message_copy_from_user(struct iovec *first_iov,
+                                              size_t total_len);
+struct rds_message *rds_message_map_pages(unsigned long *page_addrs, unsigned int total_len);
+void rds_message_populate_header(struct rds_header *hdr, __be16 sport,
+                                __be16 dport, u64 seq);
+int rds_message_add_extension(struct rds_header *hdr,
+                             unsigned int type, const void *data, unsigned int len);
+int rds_message_next_extension(struct rds_header *hdr,
+                              unsigned int *pos, void *buf, unsigned int *buflen);
+int rds_message_add_version_extension(struct rds_header *hdr, unsigned int version);
+int rds_message_get_version_extension(struct rds_header *hdr, unsigned int *version);
+int rds_message_add_rdma_dest_extension(struct rds_header *hdr, u32 r_key, u32 offset);
+int rds_message_inc_copy_to_user(struct rds_incoming *inc,
+                                struct iovec *first_iov, size_t size);
+void rds_message_inc_purge(struct rds_incoming *inc);
+void rds_message_inc_free(struct rds_incoming *inc);
+void rds_message_addref(struct rds_message *rm);
+void rds_message_put(struct rds_message *rm);
+void rds_message_wait(struct rds_message *rm);
+void rds_message_unmapped(struct rds_message *rm);
+
+static inline void rds_message_make_checksum(struct rds_header *hdr)
+{
+       hdr->h_csum = 0;
+       hdr->h_csum = ip_fast_csum((void *) hdr, sizeof(*hdr) >> 2);
+}
+
+static inline int rds_message_verify_checksum(const struct rds_header *hdr)
+{
+       return !hdr->h_csum || ip_fast_csum((void *) hdr, sizeof(*hdr) >> 2) == 0;
+}
+
+
+/* page.c */
+int rds_page_remainder_alloc(struct scatterlist *scat, unsigned long bytes,
+                            gfp_t gfp);
+int rds_page_copy_user(struct page *page, unsigned long offset,
+                      void __user *ptr, unsigned long bytes,
+                      int to_user);
+#define rds_page_copy_to_user(page, offset, ptr, bytes) \
+       rds_page_copy_user(page, offset, ptr, bytes, 1)
+#define rds_page_copy_from_user(page, offset, ptr, bytes) \
+       rds_page_copy_user(page, offset, ptr, bytes, 0)
+void rds_page_exit(void);
+
+/* recv.c */
+void rds_inc_init(struct rds_incoming *inc, struct rds_connection *conn,
+                 __be32 saddr);
+void rds_inc_addref(struct rds_incoming *inc);
+void rds_inc_put(struct rds_incoming *inc);
+void rds_recv_incoming(struct rds_connection *conn, __be32 saddr, __be32 daddr,
+                      struct rds_incoming *inc, gfp_t gfp, enum km_type km);
+int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
+               size_t size, int msg_flags);
+void rds_clear_recv_queue(struct rds_sock *rs);
+int rds_notify_queue_get(struct rds_sock *rs, struct msghdr *msg);
+void rds_inc_info_copy(struct rds_incoming *inc,
+                      struct rds_info_iterator *iter,
+                      __be32 saddr, __be32 daddr, int flip);
+
+/* send.c */
+int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
+               size_t payload_len);
+void rds_send_reset(struct rds_connection *conn);
+int rds_send_xmit(struct rds_connection *conn);
+struct sockaddr_in;
+void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest);
+typedef int (*is_acked_func)(struct rds_message *rm, uint64_t ack);
+void rds_send_drop_acked(struct rds_connection *conn, u64 ack,
+                        is_acked_func is_acked);
+int rds_send_acked_before(struct rds_connection *conn, u64 seq);
+void rds_send_remove_from_sock(struct list_head *messages, int status);
+int rds_send_pong(struct rds_connection *conn, __be16 dport);
+struct rds_message *rds_send_get_message(struct rds_connection *,
+                                        struct rds_rdma_op *);
+
+/* rdma.c */
+void rds_rdma_unuse(struct rds_sock *rs, u32 r_key, int force);
+
+/* stats.c */
+DECLARE_PER_CPU(struct rds_statistics, rds_stats);
+#define rds_stats_inc_which(which, member) do {                \
+       per_cpu(which, get_cpu()).member++;             \
+       put_cpu();                                      \
+} while (0)
+#define rds_stats_inc(member) rds_stats_inc_which(rds_stats, member)
+#define rds_stats_add_which(which, member, count) do {         \
+       per_cpu(which, get_cpu()).member += count;      \
+       put_cpu();                                      \
+} while (0)
+#define rds_stats_add(member, count) rds_stats_add_which(rds_stats, member, count)
+int __init rds_stats_init(void);
+void rds_stats_exit(void);
+void rds_stats_info_copy(struct rds_info_iterator *iter,
+                        uint64_t *values, char **names, size_t nr);
+
+/* sysctl.c */
+int __init rds_sysctl_init(void);
+void rds_sysctl_exit(void);
+extern unsigned long rds_sysctl_sndbuf_min;
+extern unsigned long rds_sysctl_sndbuf_default;
+extern unsigned long rds_sysctl_sndbuf_max;
+extern unsigned long rds_sysctl_reconnect_min_jiffies;
+extern unsigned long rds_sysctl_reconnect_max_jiffies;
+extern unsigned int  rds_sysctl_max_unacked_packets;
+extern unsigned int  rds_sysctl_max_unacked_bytes;
+extern unsigned int  rds_sysctl_ping_enable;
+extern unsigned long rds_sysctl_trace_flags;
+extern unsigned int  rds_sysctl_trace_level;
+
+/* threads.c */
+int __init rds_threads_init(void);
+void rds_threads_exit(void);
+extern struct workqueue_struct *rds_wq;
+void rds_connect_worker(struct work_struct *);
+void rds_shutdown_worker(struct work_struct *);
+void rds_send_worker(struct work_struct *);
+void rds_recv_worker(struct work_struct *);
+void rds_connect_complete(struct rds_connection *conn);
+
+/* transport.c */
+int rds_trans_register(struct rds_transport *trans);
+void rds_trans_unregister(struct rds_transport *trans);
+struct rds_transport *rds_trans_get_preferred(__be32 addr);
+unsigned int rds_trans_stats_info_copy(struct rds_info_iterator *iter,
+                                      unsigned int avail);
+int __init rds_trans_init(void);
+void rds_trans_exit(void);
+
+#endif
diff --git a/net/rds/recv.c b/net/rds/recv.c
new file mode 100644 (file)
index 0000000..f2118c5
--- /dev/null
@@ -0,0 +1,542 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <net/sock.h>
+#include <linux/in.h>
+
+#include "rds.h"
+#include "rdma.h"
+
+void rds_inc_init(struct rds_incoming *inc, struct rds_connection *conn,
+                 __be32 saddr)
+{
+       atomic_set(&inc->i_refcount, 1);
+       INIT_LIST_HEAD(&inc->i_item);
+       inc->i_conn = conn;
+       inc->i_saddr = saddr;
+       inc->i_rdma_cookie = 0;
+}
+
+void rds_inc_addref(struct rds_incoming *inc)
+{
+       rdsdebug("addref inc %p ref %d\n", inc, atomic_read(&inc->i_refcount));
+       atomic_inc(&inc->i_refcount);
+}
+
+void rds_inc_put(struct rds_incoming *inc)
+{
+       rdsdebug("put inc %p ref %d\n", inc, atomic_read(&inc->i_refcount));
+       if (atomic_dec_and_test(&inc->i_refcount)) {
+               BUG_ON(!list_empty(&inc->i_item));
+
+               inc->i_conn->c_trans->inc_free(inc);
+       }
+}
+
+static void rds_recv_rcvbuf_delta(struct rds_sock *rs, struct sock *sk,
+                                 struct rds_cong_map *map,
+                                 int delta, __be16 port)
+{
+       int now_congested;
+
+       if (delta == 0)
+               return;
+
+       rs->rs_rcv_bytes += delta;
+       now_congested = rs->rs_rcv_bytes > rds_sk_rcvbuf(rs);
+
+       rdsdebug("rs %p (%pI4:%u) recv bytes %d buf %d "
+         "now_cong %d delta %d\n",
+         rs, &rs->rs_bound_addr,
+         ntohs(rs->rs_bound_port), rs->rs_rcv_bytes,
+         rds_sk_rcvbuf(rs), now_congested, delta);
+
+       /* wasn't -> am congested */
+       if (!rs->rs_congested && now_congested) {
+               rs->rs_congested = 1;
+               rds_cong_set_bit(map, port);
+               rds_cong_queue_updates(map);
+       }
+       /* was -> aren't congested */
+       /* Require more free space before reporting uncongested to prevent
+          bouncing cong/uncong state too often */
+       else if (rs->rs_congested && (rs->rs_rcv_bytes < (rds_sk_rcvbuf(rs)/2))) {
+               rs->rs_congested = 0;
+               rds_cong_clear_bit(map, port);
+               rds_cong_queue_updates(map);
+       }
+
+       /* do nothing if no change in cong state */
+}
+
+/*
+ * Process all extension headers that come with this message.
+ */
+static void rds_recv_incoming_exthdrs(struct rds_incoming *inc, struct rds_sock *rs)
+{
+       struct rds_header *hdr = &inc->i_hdr;
+       unsigned int pos = 0, type, len;
+       union {
+               struct rds_ext_header_version version;
+               struct rds_ext_header_rdma rdma;
+               struct rds_ext_header_rdma_dest rdma_dest;
+       } buffer;
+
+       while (1) {
+               len = sizeof(buffer);
+               type = rds_message_next_extension(hdr, &pos, &buffer, &len);
+               if (type == RDS_EXTHDR_NONE)
+                       break;
+               /* Process extension header here */
+               switch (type) {
+               case RDS_EXTHDR_RDMA:
+                       rds_rdma_unuse(rs, be32_to_cpu(buffer.rdma.h_rdma_rkey), 0);
+                       break;
+
+               case RDS_EXTHDR_RDMA_DEST:
+                       /* We ignore the size for now. We could stash it
+                        * somewhere and use it for error checking. */
+                       inc->i_rdma_cookie = rds_rdma_make_cookie(
+                                       be32_to_cpu(buffer.rdma_dest.h_rdma_rkey),
+                                       be32_to_cpu(buffer.rdma_dest.h_rdma_offset));
+
+                       break;
+               }
+       }
+}
+
+/*
+ * The transport must make sure that this is serialized against other
+ * rx and conn reset on this specific conn.
+ *
+ * We currently assert that only one fragmented message will be sent
+ * down a connection at a time.  This lets us reassemble in the conn
+ * instead of per-flow which means that we don't have to go digging through
+ * flows to tear down partial reassembly progress on conn failure and
+ * we save flow lookup and locking for each frag arrival.  It does mean
+ * that small messages will wait behind large ones.  Fragmenting at all
+ * is only to reduce the memory consumption of pre-posted buffers.
+ *
+ * The caller passes in saddr and daddr instead of us getting it from the
+ * conn.  This lets loopback, who only has one conn for both directions,
+ * tell us which roles the addrs in the conn are playing for this message.
+ */
+void rds_recv_incoming(struct rds_connection *conn, __be32 saddr, __be32 daddr,
+                      struct rds_incoming *inc, gfp_t gfp, enum km_type km)
+{
+       struct rds_sock *rs = NULL;
+       struct sock *sk;
+       unsigned long flags;
+
+       inc->i_conn = conn;
+       inc->i_rx_jiffies = jiffies;
+
+       rdsdebug("conn %p next %llu inc %p seq %llu len %u sport %u dport %u "
+                "flags 0x%x rx_jiffies %lu\n", conn,
+                (unsigned long long)conn->c_next_rx_seq,
+                inc,
+                (unsigned long long)be64_to_cpu(inc->i_hdr.h_sequence),
+                be32_to_cpu(inc->i_hdr.h_len),
+                be16_to_cpu(inc->i_hdr.h_sport),
+                be16_to_cpu(inc->i_hdr.h_dport),
+                inc->i_hdr.h_flags,
+                inc->i_rx_jiffies);
+
+       /*
+        * Sequence numbers should only increase.  Messages get their
+        * sequence number as they're queued in a sending conn.  They
+        * can be dropped, though, if the sending socket is closed before
+        * they hit the wire.  So sequence numbers can skip forward
+        * under normal operation.  They can also drop back in the conn
+        * failover case as previously sent messages are resent down the
+        * new instance of a conn.  We drop those, otherwise we have
+        * to assume that the next valid seq does not come after a
+        * hole in the fragment stream.
+        *
+        * The headers don't give us a way to realize if fragments of
+        * a message have been dropped.  We assume that frags that arrive
+        * to a flow are part of the current message on the flow that is
+        * being reassembled.  This means that senders can't drop messages
+        * from the sending conn until all their frags are sent.
+        *
+        * XXX we could spend more on the wire to get more robust failure
+        * detection, arguably worth it to avoid data corruption.
+        */
+       if (be64_to_cpu(inc->i_hdr.h_sequence) < conn->c_next_rx_seq
+        && (inc->i_hdr.h_flags & RDS_FLAG_RETRANSMITTED)) {
+               rds_stats_inc(s_recv_drop_old_seq);
+               goto out;
+       }
+       conn->c_next_rx_seq = be64_to_cpu(inc->i_hdr.h_sequence) + 1;
+
+       if (rds_sysctl_ping_enable && inc->i_hdr.h_dport == 0) {
+               rds_stats_inc(s_recv_ping);
+               rds_send_pong(conn, inc->i_hdr.h_sport);
+               goto out;
+       }
+
+       rs = rds_find_bound(daddr, inc->i_hdr.h_dport);
+       if (rs == NULL) {
+               rds_stats_inc(s_recv_drop_no_sock);
+               goto out;
+       }
+
+       /* Process extension headers */
+       rds_recv_incoming_exthdrs(inc, rs);
+
+       /* We can be racing with rds_release() which marks the socket dead. */
+       sk = rds_rs_to_sk(rs);
+
+       /* serialize with rds_release -> sock_orphan */
+       write_lock_irqsave(&rs->rs_recv_lock, flags);
+       if (!sock_flag(sk, SOCK_DEAD)) {
+               rdsdebug("adding inc %p to rs %p's recv queue\n", inc, rs);
+               rds_stats_inc(s_recv_queued);
+               rds_recv_rcvbuf_delta(rs, sk, inc->i_conn->c_lcong,
+                                     be32_to_cpu(inc->i_hdr.h_len),
+                                     inc->i_hdr.h_dport);
+               rds_inc_addref(inc);
+               list_add_tail(&inc->i_item, &rs->rs_recv_queue);
+               __rds_wake_sk_sleep(sk);
+       } else {
+               rds_stats_inc(s_recv_drop_dead_sock);
+       }
+       write_unlock_irqrestore(&rs->rs_recv_lock, flags);
+
+out:
+       if (rs)
+               rds_sock_put(rs);
+}
+
+/*
+ * be very careful here.  This is being called as the condition in
+ * wait_event_*() needs to cope with being called many times.
+ */
+static int rds_next_incoming(struct rds_sock *rs, struct rds_incoming **inc)
+{
+       unsigned long flags;
+
+       if (*inc == NULL) {
+               read_lock_irqsave(&rs->rs_recv_lock, flags);
+               if (!list_empty(&rs->rs_recv_queue)) {
+                       *inc = list_entry(rs->rs_recv_queue.next,
+                                         struct rds_incoming,
+                                         i_item);
+                       rds_inc_addref(*inc);
+               }
+               read_unlock_irqrestore(&rs->rs_recv_lock, flags);
+       }
+
+       return *inc != NULL;
+}
+
+static int rds_still_queued(struct rds_sock *rs, struct rds_incoming *inc,
+                           int drop)
+{
+       struct sock *sk = rds_rs_to_sk(rs);
+       int ret = 0;
+       unsigned long flags;
+
+       write_lock_irqsave(&rs->rs_recv_lock, flags);
+       if (!list_empty(&inc->i_item)) {
+               ret = 1;
+               if (drop) {
+                       /* XXX make sure this i_conn is reliable */
+                       rds_recv_rcvbuf_delta(rs, sk, inc->i_conn->c_lcong,
+                                             -be32_to_cpu(inc->i_hdr.h_len),
+                                             inc->i_hdr.h_dport);
+                       list_del_init(&inc->i_item);
+                       rds_inc_put(inc);
+               }
+       }
+       write_unlock_irqrestore(&rs->rs_recv_lock, flags);
+
+       rdsdebug("inc %p rs %p still %d dropped %d\n", inc, rs, ret, drop);
+       return ret;
+}
+
+/*
+ * Pull errors off the error queue.
+ * If msghdr is NULL, we will just purge the error queue.
+ */
+int rds_notify_queue_get(struct rds_sock *rs, struct msghdr *msghdr)
+{
+       struct rds_notifier *notifier;
+       struct rds_rdma_notify cmsg;
+       unsigned int count = 0, max_messages = ~0U;
+       unsigned long flags;
+       LIST_HEAD(copy);
+       int err = 0;
+
+
+       /* put_cmsg copies to user space and thus may sleep. We can't do this
+        * with rs_lock held, so first grab as many notifications as we can stuff
+        * in the user provided cmsg buffer. We don't try to copy more, to avoid
+        * losing notifications - except when the buffer is so small that it wouldn't
+        * even hold a single notification. Then we give him as much of this single
+        * msg as we can squeeze in, and set MSG_CTRUNC.
+        */
+       if (msghdr) {
+               max_messages = msghdr->msg_controllen / CMSG_SPACE(sizeof(cmsg));
+               if (!max_messages)
+                       max_messages = 1;
+       }
+
+       spin_lock_irqsave(&rs->rs_lock, flags);
+       while (!list_empty(&rs->rs_notify_queue) && count < max_messages) {
+               notifier = list_entry(rs->rs_notify_queue.next,
+                               struct rds_notifier, n_list);
+               list_move(&notifier->n_list, &copy);
+               count++;
+       }
+       spin_unlock_irqrestore(&rs->rs_lock, flags);
+
+       if (!count)
+               return 0;
+
+       while (!list_empty(&copy)) {
+               notifier = list_entry(copy.next, struct rds_notifier, n_list);
+
+               if (msghdr) {
+                       cmsg.user_token = notifier->n_user_token;
+                       cmsg.status  = notifier->n_status;
+
+                       err = put_cmsg(msghdr, SOL_RDS, RDS_CMSG_RDMA_STATUS,
+                                       sizeof(cmsg), &cmsg);
+                       if (err)
+                               break;
+               }
+
+               list_del_init(&notifier->n_list);
+               kfree(notifier);
+       }
+
+       /* If we bailed out because of an error in put_cmsg,
+        * we may be left with one or more notifications that we
+        * didn't process. Return them to the head of the list. */
+       if (!list_empty(&copy)) {
+               spin_lock_irqsave(&rs->rs_lock, flags);
+               list_splice(&copy, &rs->rs_notify_queue);
+               spin_unlock_irqrestore(&rs->rs_lock, flags);
+       }
+
+       return err;
+}
+
+/*
+ * Queue a congestion notification
+ */
+static int rds_notify_cong(struct rds_sock *rs, struct msghdr *msghdr)
+{
+       uint64_t notify = rs->rs_cong_notify;
+       unsigned long flags;
+       int err;
+
+       err = put_cmsg(msghdr, SOL_RDS, RDS_CMSG_CONG_UPDATE,
+                       sizeof(notify), &notify);
+       if (err)
+               return err;
+
+       spin_lock_irqsave(&rs->rs_lock, flags);
+       rs->rs_cong_notify &= ~notify;
+       spin_unlock_irqrestore(&rs->rs_lock, flags);
+
+       return 0;
+}
+
+/*
+ * Receive any control messages.
+ */
+static int rds_cmsg_recv(struct rds_incoming *inc, struct msghdr *msg)
+{
+       int ret = 0;
+
+       if (inc->i_rdma_cookie) {
+               ret = put_cmsg(msg, SOL_RDS, RDS_CMSG_RDMA_DEST,
+                               sizeof(inc->i_rdma_cookie), &inc->i_rdma_cookie);
+               if (ret)
+                       return ret;
+       }
+
+       return 0;
+}
+
+int rds_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
+               size_t size, int msg_flags)
+{
+       struct sock *sk = sock->sk;
+       struct rds_sock *rs = rds_sk_to_rs(sk);
+       long timeo;
+       int ret = 0, nonblock = msg_flags & MSG_DONTWAIT;
+       struct sockaddr_in *sin;
+       struct rds_incoming *inc = NULL;
+
+       /* udp_recvmsg()->sock_recvtimeo() gets away without locking too.. */
+       timeo = sock_rcvtimeo(sk, nonblock);
+
+       rdsdebug("size %zu flags 0x%x timeo %ld\n", size, msg_flags, timeo);
+
+       if (msg_flags & MSG_OOB)
+               goto out;
+
+       /* If there are pending notifications, do those - and nothing else */
+       if (!list_empty(&rs->rs_notify_queue)) {
+               ret = rds_notify_queue_get(rs, msg);
+               goto out;
+       }
+
+       if (rs->rs_cong_notify) {
+               ret = rds_notify_cong(rs, msg);
+               goto out;
+       }
+
+       while (1) {
+               if (!rds_next_incoming(rs, &inc)) {
+                       if (nonblock) {
+                               ret = -EAGAIN;
+                               break;
+                       }
+
+                       timeo = wait_event_interruptible_timeout(*sk->sk_sleep,
+                                               rds_next_incoming(rs, &inc),
+                                               timeo);
+                       rdsdebug("recvmsg woke inc %p timeo %ld\n", inc,
+                                timeo);
+                       if (timeo > 0 || timeo == MAX_SCHEDULE_TIMEOUT)
+                               continue;
+
+                       ret = timeo;
+                       if (ret == 0)
+                               ret = -ETIMEDOUT;
+                       break;
+               }
+
+               rdsdebug("copying inc %p from %pI4:%u to user\n", inc,
+                        &inc->i_conn->c_faddr,
+                        ntohs(inc->i_hdr.h_sport));
+               ret = inc->i_conn->c_trans->inc_copy_to_user(inc, msg->msg_iov,
+                                                            size);
+               if (ret < 0)
+                       break;
+
+               /*
+                * if the message we just copied isn't at the head of the
+                * recv queue then someone else raced us to return it, try
+                * to get the next message.
+                */
+               if (!rds_still_queued(rs, inc, !(msg_flags & MSG_PEEK))) {
+                       rds_inc_put(inc);
+                       inc = NULL;
+                       rds_stats_inc(s_recv_deliver_raced);
+                       continue;
+               }
+
+               if (ret < be32_to_cpu(inc->i_hdr.h_len)) {
+                       if (msg_flags & MSG_TRUNC)
+                               ret = be32_to_cpu(inc->i_hdr.h_len);
+                       msg->msg_flags |= MSG_TRUNC;
+               }
+
+               if (rds_cmsg_recv(inc, msg)) {
+                       ret = -EFAULT;
+                       goto out;
+               }
+
+               rds_stats_inc(s_recv_delivered);
+
+               sin = (struct sockaddr_in *)msg->msg_name;
+               if (sin) {
+                       sin->sin_family = AF_INET;
+                       sin->sin_port = inc->i_hdr.h_sport;
+                       sin->sin_addr.s_addr = inc->i_saddr;
+                       memset(sin->sin_zero, 0, sizeof(sin->sin_zero));
+               }
+               break;
+       }
+
+       if (inc)
+               rds_inc_put(inc);
+
+out:
+       return ret;
+}
+
+/*
+ * The socket is being shut down and we're asked to drop messages that were
+ * queued for recvmsg.  The caller has unbound the socket so the receive path
+ * won't queue any more incoming fragments or messages on the socket.
+ */
+void rds_clear_recv_queue(struct rds_sock *rs)
+{
+       struct sock *sk = rds_rs_to_sk(rs);
+       struct rds_incoming *inc, *tmp;
+       unsigned long flags;
+
+       write_lock_irqsave(&rs->rs_recv_lock, flags);
+       list_for_each_entry_safe(inc, tmp, &rs->rs_recv_queue, i_item) {
+               rds_recv_rcvbuf_delta(rs, sk, inc->i_conn->c_lcong,
+                                     -be32_to_cpu(inc->i_hdr.h_len),
+                                     inc->i_hdr.h_dport);
+               list_del_init(&inc->i_item);
+               rds_inc_put(inc);
+       }
+       write_unlock_irqrestore(&rs->rs_recv_lock, flags);
+}
+
+/*
+ * inc->i_saddr isn't used here because it is only set in the receive
+ * path.
+ */
+void rds_inc_info_copy(struct rds_incoming *inc,
+                      struct rds_info_iterator *iter,
+                      __be32 saddr, __be32 daddr, int flip)
+{
+       struct rds_info_message minfo;
+
+       minfo.seq = be64_to_cpu(inc->i_hdr.h_sequence);
+       minfo.len = be32_to_cpu(inc->i_hdr.h_len);
+
+       if (flip) {
+               minfo.laddr = daddr;
+               minfo.faddr = saddr;
+               minfo.lport = inc->i_hdr.h_dport;
+               minfo.fport = inc->i_hdr.h_sport;
+       } else {
+               minfo.laddr = saddr;
+               minfo.faddr = daddr;
+               minfo.lport = inc->i_hdr.h_sport;
+               minfo.fport = inc->i_hdr.h_dport;
+       }
+
+       rds_info_copy(iter, &minfo, sizeof(minfo));
+}
diff --git a/net/rds/send.c b/net/rds/send.c
new file mode 100644 (file)
index 0000000..1b37364
--- /dev/null
@@ -0,0 +1,1003 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <net/sock.h>
+#include <linux/in.h>
+#include <linux/list.h>
+
+#include "rds.h"
+#include "rdma.h"
+
+/* When transmitting messages in rds_send_xmit, we need to emerge from
+ * time to time and briefly release the CPU. Otherwise the softlock watchdog
+ * will kick our shin.
+ * Also, it seems fairer to not let one busy connection stall all the
+ * others.
+ *
+ * send_batch_count is the number of times we'll loop in send_xmit. Setting
+ * it to 0 will restore the old behavior (where we looped until we had
+ * drained the queue).
+ */
+static int send_batch_count = 64;
+module_param(send_batch_count, int, 0444);
+MODULE_PARM_DESC(send_batch_count, " batch factor when working the send queue");
+
+/*
+ * Reset the send state. Caller must hold c_send_lock when calling here.
+ */
+void rds_send_reset(struct rds_connection *conn)
+{
+       struct rds_message *rm, *tmp;
+       unsigned long flags;
+
+       if (conn->c_xmit_rm) {
+               /* Tell the user the RDMA op is no longer mapped by the
+                * transport. This isn't entirely true (it's flushed out
+                * independently) but as the connection is down, there's
+                * no ongoing RDMA to/from that memory */
+               rds_message_unmapped(conn->c_xmit_rm);
+               rds_message_put(conn->c_xmit_rm);
+               conn->c_xmit_rm = NULL;
+       }
+       conn->c_xmit_sg = 0;
+       conn->c_xmit_hdr_off = 0;
+       conn->c_xmit_data_off = 0;
+       conn->c_xmit_rdma_sent = 0;
+
+       conn->c_map_queued = 0;
+
+       conn->c_unacked_packets = rds_sysctl_max_unacked_packets;
+       conn->c_unacked_bytes = rds_sysctl_max_unacked_bytes;
+
+       /* Mark messages as retransmissions, and move them to the send q */
+       spin_lock_irqsave(&conn->c_lock, flags);
+       list_for_each_entry_safe(rm, tmp, &conn->c_retrans, m_conn_item) {
+               set_bit(RDS_MSG_ACK_REQUIRED, &rm->m_flags);
+               set_bit(RDS_MSG_RETRANSMITTED, &rm->m_flags);
+       }
+       list_splice_init(&conn->c_retrans, &conn->c_send_queue);
+       spin_unlock_irqrestore(&conn->c_lock, flags);
+}
+
+/*
+ * We're making the concious trade-off here to only send one message
+ * down the connection at a time.
+ *   Pro:
+ *      - tx queueing is a simple fifo list
+ *     - reassembly is optional and easily done by transports per conn
+ *      - no per flow rx lookup at all, straight to the socket
+ *     - less per-frag memory and wire overhead
+ *   Con:
+ *      - queued acks can be delayed behind large messages
+ *   Depends:
+ *      - small message latency is higher behind queued large messages
+ *      - large message latency isn't starved by intervening small sends
+ */
+int rds_send_xmit(struct rds_connection *conn)
+{
+       struct rds_message *rm;
+       unsigned long flags;
+       unsigned int tmp;
+       unsigned int send_quota = send_batch_count;
+       struct scatterlist *sg;
+       int ret = 0;
+       int was_empty = 0;
+       LIST_HEAD(to_be_dropped);
+
+       /*
+        * sendmsg calls here after having queued its message on the send
+        * queue.  We only have one task feeding the connection at a time.  If
+        * another thread is already feeding the queue then we back off.  This
+        * avoids blocking the caller and trading per-connection data between
+        * caches per message.
+        *
+        * The sem holder will issue a retry if they notice that someone queued
+        * a message after they stopped walking the send queue but before they
+        * dropped the sem.
+        */
+       if (!mutex_trylock(&conn->c_send_lock)) {
+               rds_stats_inc(s_send_sem_contention);
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       if (conn->c_trans->xmit_prepare)
+               conn->c_trans->xmit_prepare(conn);
+
+       /*
+        * spin trying to push headers and data down the connection until
+        * the connection doens't make forward progress.
+        */
+       while (--send_quota) {
+               /*
+                * See if need to send a congestion map update if we're
+                * between sending messages.  The send_sem protects our sole
+                * use of c_map_offset and _bytes.
+                * Note this is used only by transports that define a special
+                * xmit_cong_map function. For all others, we create allocate
+                * a cong_map message and treat it just like any other send.
+                */
+               if (conn->c_map_bytes) {
+                       ret = conn->c_trans->xmit_cong_map(conn, conn->c_lcong,
+                                               conn->c_map_offset);
+                       if (ret <= 0)
+                               break;
+
+                       conn->c_map_offset += ret;
+                       conn->c_map_bytes -= ret;
+                       if (conn->c_map_bytes)
+                               continue;
+               }
+
+               /* If we're done sending the current message, clear the
+                * offset and S/G temporaries.
+                */
+               rm = conn->c_xmit_rm;
+               if (rm != NULL &&
+                   conn->c_xmit_hdr_off == sizeof(struct rds_header) &&
+                   conn->c_xmit_sg == rm->m_nents) {
+                       conn->c_xmit_rm = NULL;
+                       conn->c_xmit_sg = 0;
+                       conn->c_xmit_hdr_off = 0;
+                       conn->c_xmit_data_off = 0;
+                       conn->c_xmit_rdma_sent = 0;
+
+                       /* Release the reference to the previous message. */
+                       rds_message_put(rm);
+                       rm = NULL;
+               }
+
+               /* If we're asked to send a cong map update, do so.
+                */
+               if (rm == NULL && test_and_clear_bit(0, &conn->c_map_queued)) {
+                       if (conn->c_trans->xmit_cong_map != NULL) {
+                               conn->c_map_offset = 0;
+                               conn->c_map_bytes = sizeof(struct rds_header) +
+                                       RDS_CONG_MAP_BYTES;
+                               continue;
+                       }
+
+                       rm = rds_cong_update_alloc(conn);
+                       if (IS_ERR(rm)) {
+                               ret = PTR_ERR(rm);
+                               break;
+                       }
+
+                       conn->c_xmit_rm = rm;
+               }
+
+               /*
+                * Grab the next message from the send queue, if there is one.
+                *
+                * c_xmit_rm holds a ref while we're sending this message down
+                * the connction.  We can use this ref while holding the
+                * send_sem.. rds_send_reset() is serialized with it.
+                */
+               if (rm == NULL) {
+                       unsigned int len;
+
+                       spin_lock_irqsave(&conn->c_lock, flags);
+
+                       if (!list_empty(&conn->c_send_queue)) {
+                               rm = list_entry(conn->c_send_queue.next,
+                                               struct rds_message,
+                                               m_conn_item);
+                               rds_message_addref(rm);
+
+                               /*
+                                * Move the message from the send queue to the retransmit
+                                * list right away.
+                                */
+                               list_move_tail(&rm->m_conn_item, &conn->c_retrans);
+                       }
+
+                       spin_unlock_irqrestore(&conn->c_lock, flags);
+
+                       if (rm == NULL) {
+                               was_empty = 1;
+                               break;
+                       }
+
+                       /* Unfortunately, the way Infiniband deals with
+                        * RDMA to a bad MR key is by moving the entire
+                        * queue pair to error state. We cold possibly
+                        * recover from that, but right now we drop the
+                        * connection.
+                        * Therefore, we never retransmit messages with RDMA ops.
+                        */
+                       if (rm->m_rdma_op
+                        && test_bit(RDS_MSG_RETRANSMITTED, &rm->m_flags)) {
+                               spin_lock_irqsave(&conn->c_lock, flags);
+                               if (test_and_clear_bit(RDS_MSG_ON_CONN, &rm->m_flags))
+                                       list_move(&rm->m_conn_item, &to_be_dropped);
+                               spin_unlock_irqrestore(&conn->c_lock, flags);
+                               rds_message_put(rm);
+                               continue;
+                       }
+
+                       /* Require an ACK every once in a while */
+                       len = ntohl(rm->m_inc.i_hdr.h_len);
+                       if (conn->c_unacked_packets == 0
+                        || conn->c_unacked_bytes < len) {
+                               __set_bit(RDS_MSG_ACK_REQUIRED, &rm->m_flags);
+
+                               conn->c_unacked_packets = rds_sysctl_max_unacked_packets;
+                               conn->c_unacked_bytes = rds_sysctl_max_unacked_bytes;
+                               rds_stats_inc(s_send_ack_required);
+                       } else {
+                               conn->c_unacked_bytes -= len;
+                               conn->c_unacked_packets--;
+                       }
+
+                       conn->c_xmit_rm = rm;
+               }
+
+               /*
+                * Try and send an rdma message.  Let's see if we can
+                * keep this simple and require that the transport either
+                * send the whole rdma or none of it.
+                */
+               if (rm->m_rdma_op && !conn->c_xmit_rdma_sent) {
+                       ret = conn->c_trans->xmit_rdma(conn, rm->m_rdma_op);
+                       if (ret)
+                               break;
+                       conn->c_xmit_rdma_sent = 1;
+                       /* The transport owns the mapped memory for now.
+                        * You can't unmap it while it's on the send queue */
+                       set_bit(RDS_MSG_MAPPED, &rm->m_flags);
+               }
+
+               if (conn->c_xmit_hdr_off < sizeof(struct rds_header) ||
+                   conn->c_xmit_sg < rm->m_nents) {
+                       ret = conn->c_trans->xmit(conn, rm,
+                                                 conn->c_xmit_hdr_off,
+                                                 conn->c_xmit_sg,
+                                                 conn->c_xmit_data_off);
+                       if (ret <= 0)
+                               break;
+
+                       if (conn->c_xmit_hdr_off < sizeof(struct rds_header)) {
+                               tmp = min_t(int, ret,
+                                           sizeof(struct rds_header) -
+                                           conn->c_xmit_hdr_off);
+                               conn->c_xmit_hdr_off += tmp;
+                               ret -= tmp;
+                       }
+
+                       sg = &rm->m_sg[conn->c_xmit_sg];
+                       while (ret) {
+                               tmp = min_t(int, ret, sg->length -
+                                                     conn->c_xmit_data_off);
+                               conn->c_xmit_data_off += tmp;
+                               ret -= tmp;
+                               if (conn->c_xmit_data_off == sg->length) {
+                                       conn->c_xmit_data_off = 0;
+                                       sg++;
+                                       conn->c_xmit_sg++;
+                                       BUG_ON(ret != 0 &&
+                                              conn->c_xmit_sg == rm->m_nents);
+                               }
+                       }
+               }
+       }
+
+       /* Nuke any messages we decided not to retransmit. */
+       if (!list_empty(&to_be_dropped))
+               rds_send_remove_from_sock(&to_be_dropped, RDS_RDMA_DROPPED);
+
+       if (conn->c_trans->xmit_complete)
+               conn->c_trans->xmit_complete(conn);
+
+       /*
+        * We might be racing with another sender who queued a message but
+        * backed off on noticing that we held the c_send_lock.  If we check
+        * for queued messages after dropping the sem then either we'll
+        * see the queued message or the queuer will get the sem.  If we
+        * notice the queued message then we trigger an immediate retry.
+        *
+        * We need to be careful only to do this when we stopped processing
+        * the send queue because it was empty.  It's the only way we
+        * stop processing the loop when the transport hasn't taken
+        * responsibility for forward progress.
+        */
+       mutex_unlock(&conn->c_send_lock);
+
+       if (conn->c_map_bytes || (send_quota == 0 && !was_empty)) {
+               /* We exhausted the send quota, but there's work left to
+                * do. Return and (re-)schedule the send worker.
+                */
+               ret = -EAGAIN;
+       }
+
+       if (ret == 0 && was_empty) {
+               /* A simple bit test would be way faster than taking the
+                * spin lock */
+               spin_lock_irqsave(&conn->c_lock, flags);
+               if (!list_empty(&conn->c_send_queue)) {
+                       rds_stats_inc(s_send_sem_queue_raced);
+                       ret = -EAGAIN;
+               }
+               spin_unlock_irqrestore(&conn->c_lock, flags);
+       }
+out:
+       return ret;
+}
+
+static void rds_send_sndbuf_remove(struct rds_sock *rs, struct rds_message *rm)
+{
+       u32 len = be32_to_cpu(rm->m_inc.i_hdr.h_len);
+
+       assert_spin_locked(&rs->rs_lock);
+
+       BUG_ON(rs->rs_snd_bytes < len);
+       rs->rs_snd_bytes -= len;
+
+       if (rs->rs_snd_bytes == 0)
+               rds_stats_inc(s_send_queue_empty);
+}
+
+static inline int rds_send_is_acked(struct rds_message *rm, u64 ack,
+                                   is_acked_func is_acked)
+{
+       if (is_acked)
+               return is_acked(rm, ack);
+       return be64_to_cpu(rm->m_inc.i_hdr.h_sequence) <= ack;
+}
+
+/*
+ * Returns true if there are no messages on the send and retransmit queues
+ * which have a sequence number greater than or equal to the given sequence
+ * number.
+ */
+int rds_send_acked_before(struct rds_connection *conn, u64 seq)
+{
+       struct rds_message *rm, *tmp;
+       int ret = 1;
+
+       spin_lock(&conn->c_lock);
+
+       list_for_each_entry_safe(rm, tmp, &conn->c_retrans, m_conn_item) {
+               if (be64_to_cpu(rm->m_inc.i_hdr.h_sequence) < seq)
+                       ret = 0;
+               break;
+       }
+
+       list_for_each_entry_safe(rm, tmp, &conn->c_send_queue, m_conn_item) {
+               if (be64_to_cpu(rm->m_inc.i_hdr.h_sequence) < seq)
+                       ret = 0;
+               break;
+       }
+
+       spin_unlock(&conn->c_lock);
+
+       return ret;
+}
+
+/*
+ * This is pretty similar to what happens below in the ACK
+ * handling code - except that we call here as soon as we get
+ * the IB send completion on the RDMA op and the accompanying
+ * message.
+ */
+void rds_rdma_send_complete(struct rds_message *rm, int status)
+{
+       struct rds_sock *rs = NULL;
+       struct rds_rdma_op *ro;
+       struct rds_notifier *notifier;
+
+       spin_lock(&rm->m_rs_lock);
+
+       ro = rm->m_rdma_op;
+       if (test_bit(RDS_MSG_ON_SOCK, &rm->m_flags)
+        && ro && ro->r_notify && ro->r_notifier) {
+               notifier = ro->r_notifier;
+               rs = rm->m_rs;
+               sock_hold(rds_rs_to_sk(rs));
+
+               notifier->n_status = status;
+               spin_lock(&rs->rs_lock);
+               list_add_tail(&notifier->n_list, &rs->rs_notify_queue);
+               spin_unlock(&rs->rs_lock);
+
+               ro->r_notifier = NULL;
+       }
+
+       spin_unlock(&rm->m_rs_lock);
+
+       if (rs) {
+               rds_wake_sk_sleep(rs);
+               sock_put(rds_rs_to_sk(rs));
+       }
+}
+
+/*
+ * This is the same as rds_rdma_send_complete except we
+ * don't do any locking - we have all the ingredients (message,
+ * socket, socket lock) and can just move the notifier.
+ */
+static inline void
+__rds_rdma_send_complete(struct rds_sock *rs, struct rds_message *rm, int status)
+{
+       struct rds_rdma_op *ro;
+
+       ro = rm->m_rdma_op;
+       if (ro && ro->r_notify && ro->r_notifier) {
+               ro->r_notifier->n_status = status;
+               list_add_tail(&ro->r_notifier->n_list, &rs->rs_notify_queue);
+               ro->r_notifier = NULL;
+       }
+
+       /* No need to wake the app - caller does this */
+}
+
+/*
+ * This is called from the IB send completion when we detect
+ * a RDMA operation that failed with remote access error.
+ * So speed is not an issue here.
+ */
+struct rds_message *rds_send_get_message(struct rds_connection *conn,
+                                        struct rds_rdma_op *op)
+{
+       struct rds_message *rm, *tmp, *found = NULL;
+       unsigned long flags;
+
+       spin_lock_irqsave(&conn->c_lock, flags);
+
+       list_for_each_entry_safe(rm, tmp, &conn->c_retrans, m_conn_item) {
+               if (rm->m_rdma_op == op) {
+                       atomic_inc(&rm->m_refcount);
+                       found = rm;
+                       goto out;
+               }
+       }
+
+       list_for_each_entry_safe(rm, tmp, &conn->c_send_queue, m_conn_item) {
+               if (rm->m_rdma_op == op) {
+                       atomic_inc(&rm->m_refcount);
+                       found = rm;
+                       break;
+               }
+       }
+
+out:
+       spin_unlock_irqrestore(&conn->c_lock, flags);
+
+       return found;
+}
+
+/*
+ * This removes messages from the socket's list if they're on it.  The list
+ * argument must be private to the caller, we must be able to modify it
+ * without locks.  The messages must have a reference held for their
+ * position on the list.  This function will drop that reference after
+ * removing the messages from the 'messages' list regardless of if it found
+ * the messages on the socket list or not.
+ */
+void rds_send_remove_from_sock(struct list_head *messages, int status)
+{
+       unsigned long flags = 0; /* silence gcc :P */
+       struct rds_sock *rs = NULL;
+       struct rds_message *rm;
+
+       local_irq_save(flags);
+       while (!list_empty(messages)) {
+               rm = list_entry(messages->next, struct rds_message,
+                               m_conn_item);
+               list_del_init(&rm->m_conn_item);
+
+               /*
+                * If we see this flag cleared then we're *sure* that someone
+                * else beat us to removing it from the sock.  If we race
+                * with their flag update we'll get the lock and then really
+                * see that the flag has been cleared.
+                *
+                * The message spinlock makes sure nobody clears rm->m_rs
+                * while we're messing with it. It does not prevent the
+                * message from being removed from the socket, though.
+                */
+               spin_lock(&rm->m_rs_lock);
+               if (!test_bit(RDS_MSG_ON_SOCK, &rm->m_flags))
+                       goto unlock_and_drop;
+
+               if (rs != rm->m_rs) {
+                       if (rs) {
+                               spin_unlock(&rs->rs_lock);
+                               rds_wake_sk_sleep(rs);
+                               sock_put(rds_rs_to_sk(rs));
+                       }
+                       rs = rm->m_rs;
+                       spin_lock(&rs->rs_lock);
+                       sock_hold(rds_rs_to_sk(rs));
+               }
+
+               if (test_and_clear_bit(RDS_MSG_ON_SOCK, &rm->m_flags)) {
+                       struct rds_rdma_op *ro = rm->m_rdma_op;
+                       struct rds_notifier *notifier;
+
+                       list_del_init(&rm->m_sock_item);
+                       rds_send_sndbuf_remove(rs, rm);
+
+                       if (ro && ro->r_notifier
+                          && (status || ro->r_notify)) {
+                               notifier = ro->r_notifier;
+                               list_add_tail(&notifier->n_list,
+                                               &rs->rs_notify_queue);
+                               if (!notifier->n_status)
+                                       notifier->n_status = status;
+                               rm->m_rdma_op->r_notifier = NULL;
+                       }
+                       rds_message_put(rm);
+                       rm->m_rs = NULL;
+               }
+
+unlock_and_drop:
+               spin_unlock(&rm->m_rs_lock);
+               rds_message_put(rm);
+       }
+
+       if (rs) {
+               spin_unlock(&rs->rs_lock);
+               rds_wake_sk_sleep(rs);
+               sock_put(rds_rs_to_sk(rs));
+       }
+       local_irq_restore(flags);
+}
+
+/*
+ * Transports call here when they've determined that the receiver queued
+ * messages up to, and including, the given sequence number.  Messages are
+ * moved to the retrans queue when rds_send_xmit picks them off the send
+ * queue. This means that in the TCP case, the message may not have been
+ * assigned the m_ack_seq yet - but that's fine as long as tcp_is_acked
+ * checks the RDS_MSG_HAS_ACK_SEQ bit.
+ *
+ * XXX It's not clear to me how this is safely serialized with socket
+ * destruction.  Maybe it should bail if it sees SOCK_DEAD.
+ */
+void rds_send_drop_acked(struct rds_connection *conn, u64 ack,
+                        is_acked_func is_acked)
+{
+       struct rds_message *rm, *tmp;
+       unsigned long flags;
+       LIST_HEAD(list);
+
+       spin_lock_irqsave(&conn->c_lock, flags);
+
+       list_for_each_entry_safe(rm, tmp, &conn->c_retrans, m_conn_item) {
+               if (!rds_send_is_acked(rm, ack, is_acked))
+                       break;
+
+               list_move(&rm->m_conn_item, &list);
+               clear_bit(RDS_MSG_ON_CONN, &rm->m_flags);
+       }
+
+       /* order flag updates with spin locks */
+       if (!list_empty(&list))
+               smp_mb__after_clear_bit();
+
+       spin_unlock_irqrestore(&conn->c_lock, flags);
+
+       /* now remove the messages from the sock list as needed */
+       rds_send_remove_from_sock(&list, RDS_RDMA_SUCCESS);
+}
+
+void rds_send_drop_to(struct rds_sock *rs, struct sockaddr_in *dest)
+{
+       struct rds_message *rm, *tmp;
+       struct rds_connection *conn;
+       unsigned long flags;
+       LIST_HEAD(list);
+       int wake = 0;
+
+       /* get all the messages we're dropping under the rs lock */
+       spin_lock_irqsave(&rs->rs_lock, flags);
+
+       list_for_each_entry_safe(rm, tmp, &rs->rs_send_queue, m_sock_item) {
+               if (dest && (dest->sin_addr.s_addr != rm->m_daddr ||
+                            dest->sin_port != rm->m_inc.i_hdr.h_dport))
+                       continue;
+
+               wake = 1;
+               list_move(&rm->m_sock_item, &list);
+               rds_send_sndbuf_remove(rs, rm);
+               clear_bit(RDS_MSG_ON_SOCK, &rm->m_flags);
+
+               /* If this is a RDMA operation, notify the app. */
+               __rds_rdma_send_complete(rs, rm, RDS_RDMA_CANCELED);
+       }
+
+       /* order flag updates with the rs lock */
+       if (wake)
+               smp_mb__after_clear_bit();
+
+       spin_unlock_irqrestore(&rs->rs_lock, flags);
+
+       if (wake)
+               rds_wake_sk_sleep(rs);
+
+       conn = NULL;
+
+       /* now remove the messages from the conn list as needed */
+       list_for_each_entry(rm, &list, m_sock_item) {
+               /* We do this here rather than in the loop above, so that
+                * we don't have to nest m_rs_lock under rs->rs_lock */
+               spin_lock(&rm->m_rs_lock);
+               rm->m_rs = NULL;
+               spin_unlock(&rm->m_rs_lock);
+
+               /*
+                * If we see this flag cleared then we're *sure* that someone
+                * else beat us to removing it from the conn.  If we race
+                * with their flag update we'll get the lock and then really
+                * see that the flag has been cleared.
+                */
+               if (!test_bit(RDS_MSG_ON_CONN, &rm->m_flags))
+                       continue;
+
+               if (conn != rm->m_inc.i_conn) {
+                       if (conn)
+                               spin_unlock_irqrestore(&conn->c_lock, flags);
+                       conn = rm->m_inc.i_conn;
+                       spin_lock_irqsave(&conn->c_lock, flags);
+               }
+
+               if (test_and_clear_bit(RDS_MSG_ON_CONN, &rm->m_flags)) {
+                       list_del_init(&rm->m_conn_item);
+                       rds_message_put(rm);
+               }
+       }
+
+       if (conn)
+               spin_unlock_irqrestore(&conn->c_lock, flags);
+
+       while (!list_empty(&list)) {
+               rm = list_entry(list.next, struct rds_message, m_sock_item);
+               list_del_init(&rm->m_sock_item);
+
+               rds_message_wait(rm);
+               rds_message_put(rm);
+       }
+}
+
+/*
+ * we only want this to fire once so we use the callers 'queued'.  It's
+ * possible that another thread can race with us and remove the
+ * message from the flow with RDS_CANCEL_SENT_TO.
+ */
+static int rds_send_queue_rm(struct rds_sock *rs, struct rds_connection *conn,
+                            struct rds_message *rm, __be16 sport,
+                            __be16 dport, int *queued)
+{
+       unsigned long flags;
+       u32 len;
+
+       if (*queued)
+               goto out;
+
+       len = be32_to_cpu(rm->m_inc.i_hdr.h_len);
+
+       /* this is the only place which holds both the socket's rs_lock
+        * and the connection's c_lock */
+       spin_lock_irqsave(&rs->rs_lock, flags);
+
+       /*
+        * If there is a little space in sndbuf, we don't queue anything,
+        * and userspace gets -EAGAIN. But poll() indicates there's send
+        * room. This can lead to bad behavior (spinning) if snd_bytes isn't
+        * freed up by incoming acks. So we check the *old* value of
+        * rs_snd_bytes here to allow the last msg to exceed the buffer,
+        * and poll() now knows no more data can be sent.
+        */
+       if (rs->rs_snd_bytes < rds_sk_sndbuf(rs)) {
+               rs->rs_snd_bytes += len;
+
+               /* let recv side know we are close to send space exhaustion.
+                * This is probably not the optimal way to do it, as this
+                * means we set the flag on *all* messages as soon as our
+                * throughput hits a certain threshold.
+                */
+               if (rs->rs_snd_bytes >= rds_sk_sndbuf(rs) / 2)
+                       __set_bit(RDS_MSG_ACK_REQUIRED, &rm->m_flags);
+
+               list_add_tail(&rm->m_sock_item, &rs->rs_send_queue);
+               set_bit(RDS_MSG_ON_SOCK, &rm->m_flags);
+               rds_message_addref(rm);
+               rm->m_rs = rs;
+
+               /* The code ordering is a little weird, but we're
+                  trying to minimize the time we hold c_lock */
+               rds_message_populate_header(&rm->m_inc.i_hdr, sport, dport, 0);
+               rm->m_inc.i_conn = conn;
+               rds_message_addref(rm);
+
+               spin_lock(&conn->c_lock);
+               rm->m_inc.i_hdr.h_sequence = cpu_to_be64(conn->c_next_tx_seq++);
+               list_add_tail(&rm->m_conn_item, &conn->c_send_queue);
+               set_bit(RDS_MSG_ON_CONN, &rm->m_flags);
+               spin_unlock(&conn->c_lock);
+
+               rdsdebug("queued msg %p len %d, rs %p bytes %d seq %llu\n",
+                        rm, len, rs, rs->rs_snd_bytes,
+                        (unsigned long long)be64_to_cpu(rm->m_inc.i_hdr.h_sequence));
+
+               *queued = 1;
+       }
+
+       spin_unlock_irqrestore(&rs->rs_lock, flags);
+out:
+       return *queued;
+}
+
+static int rds_cmsg_send(struct rds_sock *rs, struct rds_message *rm,
+                        struct msghdr *msg, int *allocated_mr)
+{
+       struct cmsghdr *cmsg;
+       int ret = 0;
+
+       for (cmsg = CMSG_FIRSTHDR(msg); cmsg; cmsg = CMSG_NXTHDR(msg, cmsg)) {
+               if (!CMSG_OK(msg, cmsg))
+                       return -EINVAL;
+
+               if (cmsg->cmsg_level != SOL_RDS)
+                       continue;
+
+               /* As a side effect, RDMA_DEST and RDMA_MAP will set
+                * rm->m_rdma_cookie and rm->m_rdma_mr.
+                */
+               switch (cmsg->cmsg_type) {
+               case RDS_CMSG_RDMA_ARGS:
+                       ret = rds_cmsg_rdma_args(rs, rm, cmsg);
+                       break;
+
+               case RDS_CMSG_RDMA_DEST:
+                       ret = rds_cmsg_rdma_dest(rs, rm, cmsg);
+                       break;
+
+               case RDS_CMSG_RDMA_MAP:
+                       ret = rds_cmsg_rdma_map(rs, rm, cmsg);
+                       if (!ret)
+                               *allocated_mr = 1;
+                       break;
+
+               default:
+                       return -EINVAL;
+               }
+
+               if (ret)
+                       break;
+       }
+
+       return ret;
+}
+
+int rds_sendmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg,
+               size_t payload_len)
+{
+       struct sock *sk = sock->sk;
+       struct rds_sock *rs = rds_sk_to_rs(sk);
+       struct sockaddr_in *usin = (struct sockaddr_in *)msg->msg_name;
+       __be32 daddr;
+       __be16 dport;
+       struct rds_message *rm = NULL;
+       struct rds_connection *conn;
+       int ret = 0;
+       int queued = 0, allocated_mr = 0;
+       int nonblock = msg->msg_flags & MSG_DONTWAIT;
+       long timeo = sock_rcvtimeo(sk, nonblock);
+
+       /* Mirror Linux UDP mirror of BSD error message compatibility */
+       /* XXX: Perhaps MSG_MORE someday */
+       if (msg->msg_flags & ~(MSG_DONTWAIT | MSG_CMSG_COMPAT)) {
+               printk(KERN_INFO "msg_flags 0x%08X\n", msg->msg_flags);
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       if (msg->msg_namelen) {
+               /* XXX fail non-unicast destination IPs? */
+               if (msg->msg_namelen < sizeof(*usin) || usin->sin_family != AF_INET) {
+                       ret = -EINVAL;
+                       goto out;
+               }
+               daddr = usin->sin_addr.s_addr;
+               dport = usin->sin_port;
+       } else {
+               /* We only care about consistency with ->connect() */
+               lock_sock(sk);
+               daddr = rs->rs_conn_addr;
+               dport = rs->rs_conn_port;
+               release_sock(sk);
+       }
+
+       /* racing with another thread binding seems ok here */
+       if (daddr == 0 || rs->rs_bound_addr == 0) {
+               ret = -ENOTCONN; /* XXX not a great errno */
+               goto out;
+       }
+
+       rm = rds_message_copy_from_user(msg->msg_iov, payload_len);
+       if (IS_ERR(rm)) {
+               ret = PTR_ERR(rm);
+               rm = NULL;
+               goto out;
+       }
+
+       rm->m_daddr = daddr;
+
+       /* Parse any control messages the user may have included. */
+       ret = rds_cmsg_send(rs, rm, msg, &allocated_mr);
+       if (ret)
+               goto out;
+
+       /* rds_conn_create has a spinlock that runs with IRQ off.
+        * Caching the conn in the socket helps a lot. */
+       if (rs->rs_conn && rs->rs_conn->c_faddr == daddr)
+               conn = rs->rs_conn;
+       else {
+               conn = rds_conn_create_outgoing(rs->rs_bound_addr, daddr,
+                                       rs->rs_transport,
+                                       sock->sk->sk_allocation);
+               if (IS_ERR(conn)) {
+                       ret = PTR_ERR(conn);
+                       goto out;
+               }
+               rs->rs_conn = conn;
+       }
+
+       if ((rm->m_rdma_cookie || rm->m_rdma_op)
+        && conn->c_trans->xmit_rdma == NULL) {
+               if (printk_ratelimit())
+                       printk(KERN_NOTICE "rdma_op %p conn xmit_rdma %p\n",
+                               rm->m_rdma_op, conn->c_trans->xmit_rdma);
+               ret = -EOPNOTSUPP;
+               goto out;
+       }
+
+       /* If the connection is down, trigger a connect. We may
+        * have scheduled a delayed reconnect however - in this case
+        * we should not interfere.
+        */
+       if (rds_conn_state(conn) == RDS_CONN_DOWN
+        && !test_and_set_bit(RDS_RECONNECT_PENDING, &conn->c_flags))
+               queue_delayed_work(rds_wq, &conn->c_conn_w, 0);
+
+       ret = rds_cong_wait(conn->c_fcong, dport, nonblock, rs);
+       if (ret)
+               goto out;
+
+       while (!rds_send_queue_rm(rs, conn, rm, rs->rs_bound_port,
+                                 dport, &queued)) {
+               rds_stats_inc(s_send_queue_full);
+               /* XXX make sure this is reasonable */
+               if (payload_len > rds_sk_sndbuf(rs)) {
+                       ret = -EMSGSIZE;
+                       goto out;
+               }
+               if (nonblock) {
+                       ret = -EAGAIN;
+                       goto out;
+               }
+
+               timeo = wait_event_interruptible_timeout(*sk->sk_sleep,
+                                       rds_send_queue_rm(rs, conn, rm,
+                                                         rs->rs_bound_port,
+                                                         dport,
+                                                         &queued),
+                                       timeo);
+               rdsdebug("sendmsg woke queued %d timeo %ld\n", queued, timeo);
+               if (timeo > 0 || timeo == MAX_SCHEDULE_TIMEOUT)
+                       continue;
+
+               ret = timeo;
+               if (ret == 0)
+                       ret = -ETIMEDOUT;
+               goto out;
+       }
+
+       /*
+        * By now we've committed to the send.  We reuse rds_send_worker()
+        * to retry sends in the rds thread if the transport asks us to.
+        */
+       rds_stats_inc(s_send_queued);
+
+       if (!test_bit(RDS_LL_SEND_FULL, &conn->c_flags))
+               rds_send_worker(&conn->c_send_w.work);
+
+       rds_message_put(rm);
+       return payload_len;
+
+out:
+       /* If the user included a RDMA_MAP cmsg, we allocated a MR on the fly.
+        * If the sendmsg goes through, we keep the MR. If it fails with EAGAIN
+        * or in any other way, we need to destroy the MR again */
+       if (allocated_mr)
+               rds_rdma_unuse(rs, rds_rdma_cookie_key(rm->m_rdma_cookie), 1);
+
+       if (rm)
+               rds_message_put(rm);
+       return ret;
+}
+
+/*
+ * Reply to a ping packet.
+ */
+int
+rds_send_pong(struct rds_connection *conn, __be16 dport)
+{
+       struct rds_message *rm;
+       unsigned long flags;
+       int ret = 0;
+
+       rm = rds_message_alloc(0, GFP_ATOMIC);
+       if (rm == NULL) {
+               ret = -ENOMEM;
+               goto out;
+       }
+
+       rm->m_daddr = conn->c_faddr;
+
+       /* If the connection is down, trigger a connect. We may
+        * have scheduled a delayed reconnect however - in this case
+        * we should not interfere.
+        */
+       if (rds_conn_state(conn) == RDS_CONN_DOWN
+        && !test_and_set_bit(RDS_RECONNECT_PENDING, &conn->c_flags))
+               queue_delayed_work(rds_wq, &conn->c_conn_w, 0);
+
+       ret = rds_cong_wait(conn->c_fcong, dport, 1, NULL);
+       if (ret)
+               goto out;
+
+       spin_lock_irqsave(&conn->c_lock, flags);
+       list_add_tail(&rm->m_conn_item, &conn->c_send_queue);
+       set_bit(RDS_MSG_ON_CONN, &rm->m_flags);
+       rds_message_addref(rm);
+       rm->m_inc.i_conn = conn;
+
+       rds_message_populate_header(&rm->m_inc.i_hdr, 0, dport,
+                                   conn->c_next_tx_seq);
+       conn->c_next_tx_seq++;
+       spin_unlock_irqrestore(&conn->c_lock, flags);
+
+       rds_stats_inc(s_send_queued);
+       rds_stats_inc(s_send_pong);
+
+       queue_delayed_work(rds_wq, &conn->c_send_w, 0);
+       rds_message_put(rm);
+       return 0;
+
+out:
+       if (rm)
+               rds_message_put(rm);
+       return ret;
+}
diff --git a/net/rds/stats.c b/net/rds/stats.c
new file mode 100644 (file)
index 0000000..6371468
--- /dev/null
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/percpu.h>
+#include <linux/seq_file.h>
+#include <linux/proc_fs.h>
+
+#include "rds.h"
+
+DEFINE_PER_CPU_SHARED_ALIGNED(struct rds_statistics, rds_stats);
+
+/* :.,$s/unsigned long\>.*\<s_\(.*\);/"\1",/g */
+
+static char *rds_stat_names[] = {
+       "conn_reset",
+       "recv_drop_bad_checksum",
+       "recv_drop_old_seq",
+       "recv_drop_no_sock",
+       "recv_drop_dead_sock",
+       "recv_deliver_raced",
+       "recv_delivered",
+       "recv_queued",
+       "recv_immediate_retry",
+       "recv_delayed_retry",
+       "recv_ack_required",
+       "recv_rdma_bytes",
+       "recv_ping",
+       "send_queue_empty",
+       "send_queue_full",
+       "send_sem_contention",
+       "send_sem_queue_raced",
+       "send_immediate_retry",
+       "send_delayed_retry",
+       "send_drop_acked",
+       "send_ack_required",
+       "send_queued",
+       "send_rdma",
+       "send_rdma_bytes",
+       "send_pong",
+       "page_remainder_hit",
+       "page_remainder_miss",
+       "copy_to_user",
+       "copy_from_user",
+       "cong_update_queued",
+       "cong_update_received",
+       "cong_send_error",
+       "cong_send_blocked",
+};
+
+void rds_stats_info_copy(struct rds_info_iterator *iter,
+                        uint64_t *values, char **names, size_t nr)
+{
+       struct rds_info_counter ctr;
+       size_t i;
+
+       for (i = 0; i < nr; i++) {
+               BUG_ON(strlen(names[i]) >= sizeof(ctr.name));
+               strncpy(ctr.name, names[i], sizeof(ctr.name) - 1);
+               ctr.value = values[i];
+
+               rds_info_copy(iter, &ctr, sizeof(ctr));
+       }
+}
+
+/*
+ * This gives global counters across all the transports.  The strings
+ * are copied in so that the tool doesn't need knowledge of the specific
+ * stats that we're exporting.  Some are pretty implementation dependent
+ * and may change over time.  That doesn't stop them from being useful.
+ *
+ * This is the only function in the chain that knows about the byte granular
+ * length in userspace.  It converts it to number of stat entries that the
+ * rest of the functions operate in.
+ */
+static void rds_stats_info(struct socket *sock, unsigned int len,
+                          struct rds_info_iterator *iter,
+                          struct rds_info_lengths *lens)
+{
+       struct rds_statistics stats = {0, };
+       uint64_t *src;
+       uint64_t *sum;
+       size_t i;
+       int cpu;
+       unsigned int avail;
+
+       avail = len / sizeof(struct rds_info_counter);
+
+       if (avail < ARRAY_SIZE(rds_stat_names)) {
+               avail = 0;
+               goto trans;
+       }
+
+       for_each_online_cpu(cpu) {
+               src = (uint64_t *)&(per_cpu(rds_stats, cpu));
+               sum = (uint64_t *)&stats;
+               for (i = 0; i < sizeof(stats) / sizeof(uint64_t); i++)
+                       *(sum++) += *(src++);
+       }
+
+       rds_stats_info_copy(iter, (uint64_t *)&stats, rds_stat_names,
+                           ARRAY_SIZE(rds_stat_names));
+       avail -= ARRAY_SIZE(rds_stat_names);
+
+trans:
+       lens->each = sizeof(struct rds_info_counter);
+       lens->nr = rds_trans_stats_info_copy(iter, avail) +
+                  ARRAY_SIZE(rds_stat_names);
+}
+
+void rds_stats_exit(void)
+{
+       rds_info_deregister_func(RDS_INFO_COUNTERS, rds_stats_info);
+}
+
+int __init rds_stats_init(void)
+{
+       rds_info_register_func(RDS_INFO_COUNTERS, rds_stats_info);
+       return 0;
+}
diff --git a/net/rds/sysctl.c b/net/rds/sysctl.c
new file mode 100644 (file)
index 0000000..307dc5c
--- /dev/null
@@ -0,0 +1,122 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/sysctl.h>
+#include <linux/proc_fs.h>
+
+#include "rds.h"
+
+static struct ctl_table_header *rds_sysctl_reg_table;
+
+static unsigned long rds_sysctl_reconnect_min = 1;
+static unsigned long rds_sysctl_reconnect_max = ~0UL;
+
+unsigned long rds_sysctl_reconnect_min_jiffies;
+unsigned long rds_sysctl_reconnect_max_jiffies = HZ;
+
+unsigned int  rds_sysctl_max_unacked_packets = 8;
+unsigned int  rds_sysctl_max_unacked_bytes = (16 << 20);
+
+unsigned int rds_sysctl_ping_enable = 1;
+
+static ctl_table rds_sysctl_rds_table[] = {
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "reconnect_min_delay_ms",
+               .data           = &rds_sysctl_reconnect_min_jiffies,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &proc_doulongvec_ms_jiffies_minmax,
+               .extra1         = &rds_sysctl_reconnect_min,
+               .extra2         = &rds_sysctl_reconnect_max_jiffies,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "reconnect_max_delay_ms",
+               .data           = &rds_sysctl_reconnect_max_jiffies,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &proc_doulongvec_ms_jiffies_minmax,
+               .extra1         = &rds_sysctl_reconnect_min_jiffies,
+               .extra2         = &rds_sysctl_reconnect_max,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "max_unacked_packets",
+               .data           = &rds_sysctl_max_unacked_packets,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "max_unacked_bytes",
+               .data           = &rds_sysctl_max_unacked_bytes,
+               .maxlen         = sizeof(unsigned long),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+       {
+               .ctl_name       = CTL_UNNUMBERED,
+               .procname       = "ping_enable",
+               .data           = &rds_sysctl_ping_enable,
+               .maxlen         = sizeof(int),
+               .mode           = 0644,
+               .proc_handler   = &proc_dointvec,
+       },
+       { .ctl_name = 0}
+};
+
+static struct ctl_path rds_sysctl_path[] = {
+       { .procname = "net", .ctl_name = CTL_NET, },
+       { .procname = "rds", .ctl_name = CTL_UNNUMBERED, },
+       { }
+};
+
+
+void rds_sysctl_exit(void)
+{
+       if (rds_sysctl_reg_table)
+               unregister_sysctl_table(rds_sysctl_reg_table);
+}
+
+int __init rds_sysctl_init(void)
+{
+       rds_sysctl_reconnect_min = msecs_to_jiffies(1);
+       rds_sysctl_reconnect_min_jiffies = rds_sysctl_reconnect_min;
+
+       rds_sysctl_reg_table = register_sysctl_paths(rds_sysctl_path, rds_sysctl_rds_table);
+       if (rds_sysctl_reg_table == NULL)
+               return -ENOMEM;
+       return 0;
+}
diff --git a/net/rds/threads.c b/net/rds/threads.c
new file mode 100644 (file)
index 0000000..828a1bf
--- /dev/null
@@ -0,0 +1,265 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/random.h>
+
+#include "rds.h"
+
+/*
+ * All of connection management is simplified by serializing it through
+ * work queues that execute in a connection managing thread.
+ *
+ * TCP wants to send acks through sendpage() in response to data_ready(),
+ * but it needs a process context to do so.
+ *
+ * The receive paths need to allocate but can't drop packets (!) so we have
+ * a thread around to block allocating if the receive fast path sees an
+ * allocation failure.
+ */
+
+/* Grand Unified Theory of connection life cycle:
+ * At any point in time, the connection can be in one of these states:
+ * DOWN, CONNECTING, UP, DISCONNECTING, ERROR
+ *
+ * The following transitions are possible:
+ *  ANY                  -> ERROR
+ *  UP           -> DISCONNECTING
+ *  ERROR        -> DISCONNECTING
+ *  DISCONNECTING -> DOWN
+ *  DOWN         -> CONNECTING
+ *  CONNECTING   -> UP
+ *
+ * Transition to state DISCONNECTING/DOWN:
+ *  -  Inside the shutdown worker; synchronizes with xmit path
+ *     through c_send_lock, and with connection management callbacks
+ *     via c_cm_lock.
+ *
+ *     For receive callbacks, we rely on the underlying transport
+ *     (TCP, IB/RDMA) to provide the necessary synchronisation.
+ */
+struct workqueue_struct *rds_wq;
+
+void rds_connect_complete(struct rds_connection *conn)
+{
+       if (!rds_conn_transition(conn, RDS_CONN_CONNECTING, RDS_CONN_UP)) {
+               printk(KERN_WARNING "%s: Cannot transition to state UP, "
+                               "current state is %d\n",
+                               __func__,
+                               atomic_read(&conn->c_state));
+               atomic_set(&conn->c_state, RDS_CONN_ERROR);
+               queue_work(rds_wq, &conn->c_down_w);
+               return;
+       }
+
+       rdsdebug("conn %p for %pI4 to %pI4 complete\n",
+         conn, &conn->c_laddr, &conn->c_faddr);
+
+       conn->c_reconnect_jiffies = 0;
+       set_bit(0, &conn->c_map_queued);
+       queue_delayed_work(rds_wq, &conn->c_send_w, 0);
+       queue_delayed_work(rds_wq, &conn->c_recv_w, 0);
+}
+
+/*
+ * This random exponential backoff is relied on to eventually resolve racing
+ * connects.
+ *
+ * If connect attempts race then both parties drop both connections and come
+ * here to wait for a random amount of time before trying again.  Eventually
+ * the backoff range will be so much greater than the time it takes to
+ * establish a connection that one of the pair will establish the connection
+ * before the other's random delay fires.
+ *
+ * Connection attempts that arrive while a connection is already established
+ * are also considered to be racing connects.  This lets a connection from
+ * a rebooted machine replace an existing stale connection before the transport
+ * notices that the connection has failed.
+ *
+ * We should *always* start with a random backoff; otherwise a broken connection
+ * will always take several iterations to be re-established.
+ */
+static void rds_queue_reconnect(struct rds_connection *conn)
+{
+       unsigned long rand;
+
+       rdsdebug("conn %p for %pI4 to %pI4 reconnect jiffies %lu\n",
+         conn, &conn->c_laddr, &conn->c_faddr,
+         conn->c_reconnect_jiffies);
+
+       set_bit(RDS_RECONNECT_PENDING, &conn->c_flags);
+       if (conn->c_reconnect_jiffies == 0) {
+               conn->c_reconnect_jiffies = rds_sysctl_reconnect_min_jiffies;
+               queue_delayed_work(rds_wq, &conn->c_conn_w, 0);
+               return;
+       }
+
+       get_random_bytes(&rand, sizeof(rand));
+       rdsdebug("%lu delay %lu ceil conn %p for %pI4 -> %pI4\n",
+                rand % conn->c_reconnect_jiffies, conn->c_reconnect_jiffies,
+                conn, &conn->c_laddr, &conn->c_faddr);
+       queue_delayed_work(rds_wq, &conn->c_conn_w,
+                          rand % conn->c_reconnect_jiffies);
+
+       conn->c_reconnect_jiffies = min(conn->c_reconnect_jiffies * 2,
+                                       rds_sysctl_reconnect_max_jiffies);
+}
+
+void rds_connect_worker(struct work_struct *work)
+{
+       struct rds_connection *conn = container_of(work, struct rds_connection, c_conn_w.work);
+       int ret;
+
+       clear_bit(RDS_RECONNECT_PENDING, &conn->c_flags);
+       if (rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_CONNECTING)) {
+               ret = conn->c_trans->conn_connect(conn);
+               rdsdebug("conn %p for %pI4 to %pI4 dispatched, ret %d\n",
+                       conn, &conn->c_laddr, &conn->c_faddr, ret);
+
+               if (ret) {
+                       if (rds_conn_transition(conn, RDS_CONN_CONNECTING, RDS_CONN_DOWN))
+                               rds_queue_reconnect(conn);
+                       else
+                               rds_conn_error(conn, "RDS: connect failed\n");
+               }
+       }
+}
+
+void rds_shutdown_worker(struct work_struct *work)
+{
+       struct rds_connection *conn = container_of(work, struct rds_connection, c_down_w);
+
+       /* shut it down unless it's down already */
+       if (!rds_conn_transition(conn, RDS_CONN_DOWN, RDS_CONN_DOWN)) {
+               /*
+                * Quiesce the connection mgmt handlers before we start tearing
+                * things down. We don't hold the mutex for the entire
+                * duration of the shutdown operation, else we may be
+                * deadlocking with the CM handler. Instead, the CM event
+                * handler is supposed to check for state DISCONNECTING
+                */
+               mutex_lock(&conn->c_cm_lock);
+               if (!rds_conn_transition(conn, RDS_CONN_UP, RDS_CONN_DISCONNECTING)
+                && !rds_conn_transition(conn, RDS_CONN_ERROR, RDS_CONN_DISCONNECTING)) {
+                       rds_conn_error(conn, "shutdown called in state %d\n",
+                                       atomic_read(&conn->c_state));
+                       mutex_unlock(&conn->c_cm_lock);
+                       return;
+               }
+               mutex_unlock(&conn->c_cm_lock);
+
+               mutex_lock(&conn->c_send_lock);
+               conn->c_trans->conn_shutdown(conn);
+               rds_conn_reset(conn);
+               mutex_unlock(&conn->c_send_lock);
+
+               if (!rds_conn_transition(conn, RDS_CONN_DISCONNECTING, RDS_CONN_DOWN)) {
+                       /* This can happen - eg when we're in the middle of tearing
+                        * down the connection, and someone unloads the rds module.
+                        * Quite reproduceable with loopback connections.
+                        * Mostly harmless.
+                        */
+                       rds_conn_error(conn,
+                               "%s: failed to transition to state DOWN, "
+                               "current state is %d\n",
+                               __func__,
+                               atomic_read(&conn->c_state));
+                       return;
+               }
+       }
+
+       /* Then reconnect if it's still live.
+        * The passive side of an IB loopback connection is never added
+        * to the conn hash, so we never trigger a reconnect on this
+        * conn - the reconnect is always triggered by the active peer. */
+       cancel_delayed_work(&conn->c_conn_w);
+       if (!hlist_unhashed(&conn->c_hash_node))
+               rds_queue_reconnect(conn);
+}
+
+void rds_send_worker(struct work_struct *work)
+{
+       struct rds_connection *conn = container_of(work, struct rds_connection, c_send_w.work);
+       int ret;
+
+       if (rds_conn_state(conn) == RDS_CONN_UP) {
+               ret = rds_send_xmit(conn);
+               rdsdebug("conn %p ret %d\n", conn, ret);
+               switch (ret) {
+               case -EAGAIN:
+                       rds_stats_inc(s_send_immediate_retry);
+                       queue_delayed_work(rds_wq, &conn->c_send_w, 0);
+                       break;
+               case -ENOMEM:
+                       rds_stats_inc(s_send_delayed_retry);
+                       queue_delayed_work(rds_wq, &conn->c_send_w, 2);
+               default:
+                       break;
+               }
+       }
+}
+
+void rds_recv_worker(struct work_struct *work)
+{
+       struct rds_connection *conn = container_of(work, struct rds_connection, c_recv_w.work);
+       int ret;
+
+       if (rds_conn_state(conn) == RDS_CONN_UP) {
+               ret = conn->c_trans->recv(conn);
+               rdsdebug("conn %p ret %d\n", conn, ret);
+               switch (ret) {
+               case -EAGAIN:
+                       rds_stats_inc(s_recv_immediate_retry);
+                       queue_delayed_work(rds_wq, &conn->c_recv_w, 0);
+                       break;
+               case -ENOMEM:
+                       rds_stats_inc(s_recv_delayed_retry);
+                       queue_delayed_work(rds_wq, &conn->c_recv_w, 2);
+               default:
+                       break;
+               }
+       }
+}
+
+void rds_threads_exit(void)
+{
+       destroy_workqueue(rds_wq);
+}
+
+int __init rds_threads_init(void)
+{
+       rds_wq = create_singlethread_workqueue("krdsd");
+       if (rds_wq == NULL)
+               return -ENOMEM;
+
+       return 0;
+}
diff --git a/net/rds/transport.c b/net/rds/transport.c
new file mode 100644 (file)
index 0000000..767da61
--- /dev/null
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2006 Oracle.  All rights reserved.
+ *
+ * This software is available to you under a choice of one of two
+ * licenses.  You may choose to be licensed under the terms of the GNU
+ * General Public License (GPL) Version 2, available from the file
+ * COPYING in the main directory of this source tree, or the
+ * OpenIB.org BSD license below:
+ *
+ *     Redistribution and use in source and binary forms, with or
+ *     without modification, are permitted provided that the following
+ *     conditions are met:
+ *
+ *      - Redistributions of source code must retain the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer.
+ *
+ *      - Redistributions in binary form must reproduce the above
+ *        copyright notice, this list of conditions and the following
+ *        disclaimer in the documentation and/or other materials
+ *        provided with the distribution.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
+ * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+ * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
+ * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
+ * BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
+ * ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
+ * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
+ * SOFTWARE.
+ *
+ */
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/in.h>
+
+#include "rds.h"
+#include "loop.h"
+
+static LIST_HEAD(rds_transports);
+static DECLARE_RWSEM(rds_trans_sem);
+
+int rds_trans_register(struct rds_transport *trans)
+{
+       BUG_ON(strlen(trans->t_name) + 1 > TRANSNAMSIZ);
+
+       down_write(&rds_trans_sem);
+
+       list_add_tail(&trans->t_item, &rds_transports);
+       printk(KERN_INFO "Registered RDS/%s transport\n", trans->t_name);
+
+       up_write(&rds_trans_sem);
+
+       return 0;
+}
+
+void rds_trans_unregister(struct rds_transport *trans)
+{
+       down_write(&rds_trans_sem);
+
+       list_del_init(&trans->t_item);
+       printk(KERN_INFO "Unregistered RDS/%s transport\n", trans->t_name);
+
+       up_write(&rds_trans_sem);
+}
+
+struct rds_transport *rds_trans_get_preferred(__be32 addr)
+{
+       struct rds_transport *trans;
+       struct rds_transport *ret = NULL;
+
+       if (IN_LOOPBACK(ntohl(addr)))
+               return &rds_loop_transport;
+
+       down_read(&rds_trans_sem);
+       list_for_each_entry(trans, &rds_transports, t_item) {
+               if (trans->laddr_check(addr) == 0) {
+                       ret = trans;
+                       break;
+               }
+       }
+       up_read(&rds_trans_sem);
+
+       return ret;
+}
+
+/*
+ * This returns the number of stats entries in the snapshot and only
+ * copies them using the iter if there is enough space for them.  The
+ * caller passes in the global stats so that we can size and copy while
+ * holding the lock.
+ */
+unsigned int rds_trans_stats_info_copy(struct rds_info_iterator *iter,
+                                      unsigned int avail)
+
+{
+       struct rds_transport *trans;
+       unsigned int total = 0;
+       unsigned int part;
+
+       rds_info_iter_unmap(iter);
+       down_read(&rds_trans_sem);
+
+       list_for_each_entry(trans, &rds_transports, t_item) {
+               if (trans->stats_info_copy == NULL)
+                       continue;
+
+               part = trans->stats_info_copy(iter, avail);
+               avail -= min(avail, part);
+               total += part;
+       }
+
+       up_read(&rds_trans_sem);
+
+       return total;
+}
+
index 5c72a116b1a4513405735349391a01ff1c9b376a..f8f047b6124560c76d8cae54fa20062854553c48 100644 (file)
@@ -183,13 +183,6 @@ override:
                if (R_tab == NULL)
                        goto failure;
 
-               if (!est && (ret == ACT_P_CREATED ||
-                            !gen_estimator_active(&police->tcf_bstats,
-                                                  &police->tcf_rate_est))) {
-                       err = -EINVAL;
-                       goto failure;
-               }
-
                if (parm->peakrate.rate) {
                        P_tab = qdisc_get_rtab(&parm->peakrate,
                                               tb[TCA_POLICE_PEAKRATE]);
@@ -205,6 +198,12 @@ override:
                                            &police->tcf_lock, est);
                if (err)
                        goto failure_unlock;
+       } else if (tb[TCA_POLICE_AVRATE] &&
+                  (ret == ACT_P_CREATED ||
+                   !gen_estimator_active(&police->tcf_bstats,
+                                         &police->tcf_rate_est))) {
+               err = -EINVAL;
+               goto failure_unlock;
        }
 
        /* No failure allowed after this point */
index 9e43ed949167affccd96c7e9a11e88e493206f6c..d728d8111732f0d74b783c54927e2c42822f1dbe 100644 (file)
@@ -1960,8 +1960,11 @@ static int cbq_delete(struct Qdisc *sch, unsigned long arg)
        cbq_rmprio(q, cl);
        sch_tree_unlock(sch);
 
-       if (--cl->refcnt == 0)
-               cbq_destroy_class(sch, cl);
+       BUG_ON(--cl->refcnt == 0);
+       /*
+        * This shouldn't happen: we "hold" one cops->get() when called
+        * from tc_ctl_tclass; the destroy method is done from cops->put().
+        */
 
        return 0;
 }
index f6b4fa97df70e353b58ed04ba4a74f50f4c8fbcf..7597fe14686600e6fa2584544b69ebdfb1144edf 100644 (file)
@@ -66,11 +66,15 @@ static int drr_change_class(struct Qdisc *sch, u32 classid, u32 parentid,
 {
        struct drr_sched *q = qdisc_priv(sch);
        struct drr_class *cl = (struct drr_class *)*arg;
+       struct nlattr *opt = tca[TCA_OPTIONS];
        struct nlattr *tb[TCA_DRR_MAX + 1];
        u32 quantum;
        int err;
 
-       err = nla_parse_nested(tb, TCA_DRR_MAX, tca[TCA_OPTIONS], drr_policy);
+       if (!opt)
+               return -EINVAL;
+
+       err = nla_parse_nested(tb, TCA_DRR_MAX, opt, drr_policy);
        if (err < 0)
                return err;
 
@@ -151,8 +155,11 @@ static int drr_delete_class(struct Qdisc *sch, unsigned long arg)
        drr_purge_queue(cl);
        qdisc_class_hash_remove(&q->clhash, &cl->common);
 
-       if (--cl->refcnt == 0)
-               drr_destroy_class(sch, cl);
+       BUG_ON(--cl->refcnt == 0);
+       /*
+        * This shouldn't happen: we "hold" one cops->get() when called
+        * from tc_ctl_tclass; the destroy method is done from cops->put().
+        */
 
        sch_tree_unlock(sch);
        return 0;
index 74226b265528cb9d2e37a5aed39cb48dc0c2f6db..5022f9c1f34be595e391801728e124273f479692 100644 (file)
@@ -1139,8 +1139,11 @@ hfsc_delete_class(struct Qdisc *sch, unsigned long arg)
        hfsc_purge_queue(sch, cl);
        qdisc_class_hash_remove(&q->clhash, &cl->cl_common);
 
-       if (--cl->refcnt == 0)
-               hfsc_destroy_class(sch, cl);
+       BUG_ON(--cl->refcnt == 0);
+       /*
+        * This shouldn't happen: we "hold" one cops->get() when called
+        * from tc_ctl_tclass; the destroy method is done from cops->put().
+        */
 
        sch_tree_unlock(sch);
        return 0;
index 355974f610c5946286eadbbcb978b337061698e8..88cd0262662138f02fa18393a72667fc172e91c1 100644 (file)
@@ -1275,8 +1275,11 @@ static int htb_delete(struct Qdisc *sch, unsigned long arg)
        if (last_child)
                htb_parent_to_leaf(q, cl, new_q);
 
-       if (--cl->refcnt == 0)
-               htb_destroy_class(sch, cl);
+       BUG_ON(--cl->refcnt == 0);
+       /*
+        * This shouldn't happen: we "hold" one cops->get() when called
+        * from tc_ctl_tclass; the destroy method is done from cops->put().
+        */
 
        sch_tree_unlock(sch);
        return 0;
index a2f93c09f3cc2490b5131df91659112b3fc10693..e22dfe85e43ed5e38213f3bf8d09449d699d43ca 100644 (file)
@@ -236,7 +236,6 @@ static int tbf_change(struct Qdisc* sch, struct nlattr *opt)
        struct tc_tbf_qopt *qopt;
        struct qdisc_rate_table *rtab = NULL;
        struct qdisc_rate_table *ptab = NULL;
-       struct qdisc_rate_table *tmp;
        struct Qdisc *child = NULL;
        int max_size,n;
 
@@ -295,13 +294,9 @@ static int tbf_change(struct Qdisc* sch, struct nlattr *opt)
        q->tokens = q->buffer;
        q->ptokens = q->mtu;
 
-       tmp = q->R_tab;
-       q->R_tab = rtab;
-       rtab = tmp;
+       swap(q->R_tab, rtab);
+       swap(q->P_tab, ptab);
 
-       tmp = q->P_tab;
-       q->P_tab = ptab;
-       ptab = tmp;
        sch_tree_unlock(sch);
        err = 0;
 done:
index 67715f4eb8495e49fa3eb21fa33a96bf80c51514..7ff548a30cfb63b7a85147faed3292c574ae18ef 100644 (file)
@@ -86,6 +86,9 @@ const char *sctp_cname(const sctp_subtype_t cid)
        case SCTP_CID_FWD_TSN:
                return "FWD_TSN";
 
+       case SCTP_CID_AUTH:
+               return "AUTH";
+
        default:
                break;
        }
@@ -135,6 +138,7 @@ static const char *sctp_primitive_tbl[SCTP_NUM_PRIMITIVE_TYPES] = {
        "PRIMITIVE_ABORT",
        "PRIMITIVE_SEND",
        "PRIMITIVE_REQUESTHEARTBEAT",
+       "PRIMITIVE_ASCONF",
 };
 
 /* Lookup primitive debug name. */
index 4c8d9f45ce0999b5141f7fb92a7ee4ab1b03ef99..905fda582b92b652aebd8108feaa12f9cf92fb79 100644 (file)
@@ -111,7 +111,8 @@ static struct sctp_endpoint *sctp_endpoint_init(struct sctp_endpoint *ep,
                if (sctp_addip_enable) {
                        auth_chunks->chunks[0] = SCTP_CID_ASCONF;
                        auth_chunks->chunks[1] = SCTP_CID_ASCONF_ACK;
-                       auth_chunks->param_hdr.length += htons(2);
+                       auth_chunks->param_hdr.length =
+                                       htons(sizeof(sctp_paramhdr_t) + 2);
                }
        }
 
index 07d58903a74625dd2ec25982a617a6cad2d59ae3..7d08f522ec844ea73f9e69dc4a7061d4f6885de3 100644 (file)
 #include <linux/ipv6.h>
 #include <linux/init.h>
 #include <net/inet_ecn.h>
+#include <net/ip.h>
 #include <net/icmp.h>
 #include <net/net_namespace.h>
 
-#ifndef TEST_FRAME
-#include <net/tcp.h>
-#endif /* TEST_FRAME (not defined) */
-
 #include <linux/socket.h> /* for sa_family_t */
 #include <net/sock.h>
 
index bc411c89621635159713716a1747253f6d138a27..d765fc53e74dd63447d5d47a96664ecedbde45a8 100644 (file)
@@ -428,7 +428,8 @@ void sctp_retransmit_mark(struct sctp_outq *q,
                         * retransmitting due to T3 timeout.
                         */
                        if (reason == SCTP_RTXR_T3_RTX &&
-                           (jiffies - chunk->sent_at) < transport->last_rto)
+                           time_before(jiffies, chunk->sent_at +
+                                                transport->last_rto))
                                continue;
 
                        /* RFC 2960 6.2.1 Processing a Received SACK
@@ -1757,6 +1758,9 @@ static void sctp_generate_fwdtsn(struct sctp_outq *q, __u32 ctsn)
        struct sctp_chunk *chunk;
        struct list_head *lchunk, *temp;
 
+       if (!asoc->peer.prsctp_capable)
+               return;
+
        /* PR-SCTP C1) Let SackCumAck be the Cumulative TSN ACK carried in the
         * received SACK.
         *
index c1e316ee7155d52abad10d8ec40b926a2d3c6e42..cb198af8887c97628a82a903b1c93623dcb992e8 100644 (file)
@@ -692,15 +692,20 @@ static int sctp_inetaddr_event(struct notifier_block *this, unsigned long ev,
 static int sctp_ctl_sock_init(void)
 {
        int err;
-       sa_family_t family;
+       sa_family_t family = PF_INET;
 
        if (sctp_get_pf_specific(PF_INET6))
                family = PF_INET6;
-       else
-               family = PF_INET;
 
        err = inet_ctl_sock_create(&sctp_ctl_sock, family,
                                   SOCK_SEQPACKET, IPPROTO_SCTP, &init_net);
+
+       /* If IPv6 socket could not be created, try the IPv4 socket */
+       if (err < 0 && family == PF_INET6)
+               err = inet_ctl_sock_create(&sctp_ctl_sock, AF_INET,
+                                          SOCK_SEQPACKET, IPPROTO_SCTP,
+                                          &init_net);
+
        if (err < 0) {
                printk(KERN_ERR
                       "SCTP: Failed to create the SCTP control socket.\n");
@@ -1297,9 +1302,8 @@ SCTP_STATIC __init int sctp_init(void)
 out:
        return status;
 err_v6_add_protocol:
-       sctp_v6_del_protocol();
-err_add_protocol:
        sctp_v4_del_protocol();
+err_add_protocol:
        inet_ctl_sock_destroy(sctp_ctl_sock);
 err_ctl_sock_init:
        sctp_v6_protosw_exit();
@@ -1310,7 +1314,6 @@ err_protosw_init:
        sctp_v4_pf_exit();
        sctp_v6_pf_exit();
        sctp_sysctl_unregister();
-       list_del(&sctp_af_inet.list);
        free_pages((unsigned long)sctp_port_hashtable,
                   get_order(sctp_port_hashsize *
                             sizeof(struct sctp_bind_hashbucket)));
@@ -1358,7 +1361,6 @@ SCTP_STATIC __exit void sctp_exit(void)
        sctp_v4_pf_exit();
 
        sctp_sysctl_unregister();
-       list_del(&sctp_af_inet.list);
 
        free_pages((unsigned long)sctp_assoc_hashtable,
                   get_order(sctp_assoc_hashsize *
index b40e95f9851b243870f2c1306c730ee7ff72e215..6851ee94e974a76530d3f7587a4c7be064290b13 100644 (file)
@@ -224,7 +224,9 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
                num_ext += 2;
        }
 
-       chunksize += sizeof(aiparam);
+       if (sp->adaptation_ind)
+               chunksize += sizeof(aiparam);
+
        chunksize += vparam_len;
 
        /* Account for AUTH related parameters */
@@ -304,10 +306,12 @@ struct sctp_chunk *sctp_make_init(const struct sctp_association *asoc,
        if (sctp_prsctp_enable)
                sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
 
-       aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
-       aiparam.param_hdr.length = htons(sizeof(aiparam));
-       aiparam.adaptation_ind = htonl(sp->adaptation_ind);
-       sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
+       if (sp->adaptation_ind) {
+               aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
+               aiparam.param_hdr.length = htons(sizeof(aiparam));
+               aiparam.adaptation_ind = htonl(sp->adaptation_ind);
+               sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
+       }
 
        /* Add SCTP-AUTH chunks to the parameter list */
        if (sctp_auth_enable) {
@@ -332,6 +336,7 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
        sctp_inithdr_t initack;
        struct sctp_chunk *retval;
        union sctp_params addrs;
+       struct sctp_sock *sp;
        int addrs_len;
        sctp_cookie_param_t *cookie;
        int cookie_len;
@@ -366,22 +371,24 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
        /* Calculate the total size of allocation, include the reserved
         * space for reporting unknown parameters if it is specified.
         */
+       sp = sctp_sk(asoc->base.sk);
        chunksize = sizeof(initack) + addrs_len + cookie_len + unkparam_len;
 
        /* Tell peer that we'll do ECN only if peer advertised such cap.  */
        if (asoc->peer.ecn_capable)
                chunksize += sizeof(ecap_param);
 
-       if (sctp_prsctp_enable)
+       if (asoc->peer.prsctp_capable)
                chunksize += sizeof(prsctp_param);
 
-       if (sctp_addip_enable) {
+       if (asoc->peer.asconf_capable) {
                extensions[num_ext] = SCTP_CID_ASCONF;
                extensions[num_ext+1] = SCTP_CID_ASCONF_ACK;
                num_ext += 2;
        }
 
-       chunksize += sizeof(aiparam);
+       if (sp->adaptation_ind)
+               chunksize += sizeof(aiparam);
 
        if (asoc->peer.auth_capable) {
                auth_random = (sctp_paramhdr_t *)asoc->c.auth_random;
@@ -432,10 +439,12 @@ struct sctp_chunk *sctp_make_init_ack(const struct sctp_association *asoc,
        if (asoc->peer.prsctp_capable)
                sctp_addto_chunk(retval, sizeof(prsctp_param), &prsctp_param);
 
-       aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
-       aiparam.param_hdr.length = htons(sizeof(aiparam));
-       aiparam.adaptation_ind = htonl(sctp_sk(asoc->base.sk)->adaptation_ind);
-       sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
+       if (sp->adaptation_ind) {
+               aiparam.param_hdr.type = SCTP_PARAM_ADAPTATION_LAYER_IND;
+               aiparam.param_hdr.length = htons(sizeof(aiparam));
+               aiparam.adaptation_ind = htonl(sp->adaptation_ind);
+               sctp_addto_chunk(retval, sizeof(aiparam), &aiparam);
+       }
 
        if (asoc->peer.auth_capable) {
                sctp_addto_chunk(retval, ntohs(auth_random->length),
index 0146cfb1f1820c0f3408f61d9f6bcb889fd0d193..e2020eb2c8ca53ecc5fa1bad42e49d7c487b05f7 100644 (file)
@@ -434,7 +434,8 @@ sctp_timer_event_t *sctp_timer_events[SCTP_NUM_TIMEOUT_TYPES] = {
  *
  */
 static void sctp_do_8_2_transport_strike(struct sctp_association *asoc,
-                                        struct sctp_transport *transport)
+                                        struct sctp_transport *transport,
+                                        int is_hb)
 {
        /* The check for association's overall error counter exceeding the
         * threshold is done in the state function.
@@ -466,7 +467,7 @@ static void sctp_do_8_2_transport_strike(struct sctp_association *asoc,
         * The first unacknowleged HB triggers it.  We do this with a flag
         * that indicates that we have an outstanding HB.
         */
-       if (transport->hb_sent) {
+       if (!is_hb || transport->hb_sent) {
                transport->last_rto = transport->rto;
                transport->rto = min((transport->rto * 2), transport->asoc->rto_max);
        }
@@ -657,20 +658,6 @@ static void sctp_cmd_transport_on(sctp_cmd_seq_t *cmds,
                sctp_transport_hold(t);
 }
 
-/* Helper function to do a transport reset at the expiry of the hearbeat
- * timer.
- */
-static void sctp_cmd_transport_reset(sctp_cmd_seq_t *cmds,
-                                    struct sctp_association *asoc,
-                                    struct sctp_transport *t)
-{
-       sctp_transport_lower_cwnd(t, SCTP_LOWER_CWND_INACTIVE);
-
-       /* Mark one strike against a transport.  */
-       sctp_do_8_2_transport_strike(asoc, t);
-
-       t->hb_sent = 1;
-}
 
 /* Helper function to process the process SACK command.  */
 static int sctp_cmd_process_sack(sctp_cmd_seq_t *cmds,
@@ -800,36 +787,48 @@ static void sctp_cmd_process_operr(sctp_cmd_seq_t *cmds,
                                   struct sctp_association *asoc,
                                   struct sctp_chunk *chunk)
 {
-       struct sctp_operr_chunk *operr_chunk;
        struct sctp_errhdr *err_hdr;
+       struct sctp_ulpevent *ev;
 
-       operr_chunk = (struct sctp_operr_chunk *)chunk->chunk_hdr;
-       err_hdr = &operr_chunk->err_hdr;
+       while (chunk->chunk_end > chunk->skb->data) {
+               err_hdr = (struct sctp_errhdr *)(chunk->skb->data);
 
-       switch (err_hdr->cause) {
-       case SCTP_ERROR_UNKNOWN_CHUNK:
-       {
-               struct sctp_chunkhdr *unk_chunk_hdr;
+               ev = sctp_ulpevent_make_remote_error(asoc, chunk, 0,
+                                                    GFP_ATOMIC);
+               if (!ev)
+                       return;
 
-               unk_chunk_hdr = (struct sctp_chunkhdr *)err_hdr->variable;
-               switch (unk_chunk_hdr->type) {
-               /* ADDIP 4.1 A9) If the peer responds to an ASCONF with an
-                * ERROR chunk reporting that it did not recognized the ASCONF
-                * chunk type, the sender of the ASCONF MUST NOT send any
-                * further ASCONF chunks and MUST stop its T-4 timer.
-                */
-               case SCTP_CID_ASCONF:
-                       asoc->peer.asconf_capable = 0;
-                       sctp_add_cmd_sf(cmds, SCTP_CMD_TIMER_STOP,
+               sctp_ulpq_tail_event(&asoc->ulpq, ev);
+
+               switch (err_hdr->cause) {
+               case SCTP_ERROR_UNKNOWN_CHUNK:
+               {
+                       sctp_chunkhdr_t *unk_chunk_hdr;
+
+                       unk_chunk_hdr = (sctp_chunkhdr_t *)err_hdr->variable;
+                       switch (unk_chunk_hdr->type) {
+                       /* ADDIP 4.1 A9) If the peer responds to an ASCONF with
+                        * an ERROR chunk reporting that it did not recognized
+                        * the ASCONF chunk type, the sender of the ASCONF MUST
+                        * NOT send any further ASCONF chunks and MUST stop its
+                        * T-4 timer.
+                        */
+                       case SCTP_CID_ASCONF:
+                               if (asoc->peer.asconf_capable == 0)
+                                       break;
+
+                               asoc->peer.asconf_capable = 0;
+                               sctp_add_cmd_sf(cmds, SCTP_CMD_TIMER_STOP,
                                        SCTP_TO(SCTP_EVENT_TIMEOUT_T4_RTO));
+                               break;
+                       default:
+                               break;
+                       }
                        break;
+               }
                default:
                        break;
                }
-               break;
-       }
-       default:
-               break;
        }
 }
 
@@ -1459,12 +1458,19 @@ static int sctp_cmd_interpreter(sctp_event_t event_type,
 
                case SCTP_CMD_STRIKE:
                        /* Mark one strike against a transport.  */
-                       sctp_do_8_2_transport_strike(asoc, cmd->obj.transport);
+                       sctp_do_8_2_transport_strike(asoc, cmd->obj.transport,
+                                                   0);
+                       break;
+
+               case SCTP_CMD_TRANSPORT_IDLE:
+                       t = cmd->obj.transport;
+                       sctp_transport_lower_cwnd(t, SCTP_LOWER_CWND_INACTIVE);
                        break;
 
-               case SCTP_CMD_TRANSPORT_RESET:
+               case SCTP_CMD_TRANSPORT_HB_SENT:
                        t = cmd->obj.transport;
-                       sctp_cmd_transport_reset(commands, asoc, t);
+                       sctp_do_8_2_transport_strike(asoc, t, 1);
+                       t->hb_sent = 1;
                        break;
 
                case SCTP_CMD_TRANSPORT_ON:
index 3a0cd075914f44b261b85a7a27aaa899955a22fa..55a61aa69662ccbb26ddae10f5a30e2d7ce44d59 100644 (file)
@@ -988,7 +988,9 @@ sctp_disposition_t sctp_sf_sendbeat_8_3(const struct sctp_endpoint *ep,
                /* Set transport error counter and association error counter
                 * when sending heartbeat.
                 */
-               sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_RESET,
+               sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_IDLE,
+                               SCTP_TRANSPORT(transport));
+               sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_HB_SENT,
                                SCTP_TRANSPORT(transport));
        }
        sctp_add_cmd_sf(commands, SCTP_CMD_HB_TIMER_UPDATE,
@@ -3163,7 +3165,6 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
                                        sctp_cmd_seq_t *commands)
 {
        struct sctp_chunk *chunk = arg;
-       struct sctp_ulpevent *ev;
 
        if (!sctp_vtag_verify(chunk, asoc))
                return sctp_sf_pdiscard(ep, asoc, type, arg, commands);
@@ -3173,21 +3174,10 @@ sctp_disposition_t sctp_sf_operr_notify(const struct sctp_endpoint *ep,
                return sctp_sf_violation_chunklen(ep, asoc, type, arg,
                                                  commands);
 
-       while (chunk->chunk_end > chunk->skb->data) {
-               ev = sctp_ulpevent_make_remote_error(asoc, chunk, 0,
-                                                    GFP_ATOMIC);
-               if (!ev)
-                       goto nomem;
+       sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_OPERR,
+                       SCTP_CHUNK(chunk));
 
-               sctp_add_cmd_sf(commands, SCTP_CMD_EVENT_ULP,
-                               SCTP_ULPEVENT(ev));
-               sctp_add_cmd_sf(commands, SCTP_CMD_PROCESS_OPERR,
-                               SCTP_CHUNK(chunk));
-       }
        return SCTP_DISPOSITION_CONSUME;
-
-nomem:
-       return SCTP_DISPOSITION_NOMEM;
 }
 
 /*
@@ -4967,7 +4957,7 @@ sctp_disposition_t sctp_sf_do_prm_requestheartbeat(
         *    to that address and not acknowledged within one RTO.
         *
         */
-       sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_RESET,
+       sctp_add_cmd_sf(commands, SCTP_CMD_TRANSPORT_HB_SENT,
                        SCTP_TRANSPORT(arg));
        return SCTP_DISPOSITION_CONSUME;
 }
index dea864f5de54cd1fab32036ad4e89350f6e32a12..5fb3a8c9792e741dac08902a0f8b7cc1f43dc872 100644 (file)
@@ -3069,9 +3069,6 @@ static int sctp_setsockopt_maxburst(struct sock *sk,
        int val;
        int assoc_id = 0;
 
-       if (optlen < sizeof(int))
-               return -EINVAL;
-
        if (optlen == sizeof(int)) {
                printk(KERN_WARNING
                   "SCTP: Use of int in max_burst socket option deprecated\n");
@@ -5283,16 +5280,14 @@ static int sctp_getsockopt_maxburst(struct sock *sk, int len,
        struct sctp_sock *sp;
        struct sctp_association *asoc;
 
-       if (len < sizeof(int))
-               return -EINVAL;
-
        if (len == sizeof(int)) {
                printk(KERN_WARNING
                   "SCTP: Use of int in max_burst socket option deprecated\n");
                printk(KERN_WARNING
                   "SCTP: Use struct sctp_assoc_value instead\n");
                params.assoc_id = 0;
-       } else if (len == sizeof (struct sctp_assoc_value)) {
+       } else if (len >= sizeof(struct sctp_assoc_value)) {
+               len = sizeof(struct sctp_assoc_value);
                if (copy_from_user(&params, optval, len))
                        return -EFAULT;
        } else
@@ -5848,37 +5843,28 @@ static int sctp_get_port(struct sock *sk, unsigned short snum)
 }
 
 /*
- * 3.1.3 listen() - UDP Style Syntax
- *
- *   By default, new associations are not accepted for UDP style sockets.
- *   An application uses listen() to mark a socket as being able to
- *   accept new associations.
+ *  Move a socket to LISTENING state.
  */
-SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
+SCTP_STATIC int sctp_listen_start(struct sock *sk, int backlog)
 {
        struct sctp_sock *sp = sctp_sk(sk);
        struct sctp_endpoint *ep = sp->ep;
+       struct crypto_hash *tfm = NULL;
 
-       /* Only UDP style sockets that are not peeled off are allowed to
-        * listen().
-        */
-       if (!sctp_style(sk, UDP))
-               return -EINVAL;
-
-       /* If backlog is zero, disable listening. */
-       if (!backlog) {
-               if (sctp_sstate(sk, CLOSED))
-                       return 0;
-
-               sctp_unhash_endpoint(ep);
-               sk->sk_state = SCTP_SS_CLOSED;
-               return 0;
+       /* Allocate HMAC for generating cookie. */
+       if (!sctp_sk(sk)->hmac && sctp_hmac_alg) {
+               tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC);
+               if (IS_ERR(tfm)) {
+                       if (net_ratelimit()) {
+                               printk(KERN_INFO
+                                      "SCTP: failed to load transform for %s: %ld\n",
+                                       sctp_hmac_alg, PTR_ERR(tfm));
+                       }
+                       return -ENOSYS;
+               }
+               sctp_sk(sk)->hmac = tfm;
        }
 
-       /* Return if we are already listening. */
-       if (sctp_sstate(sk, LISTENING))
-               return 0;
-
        /*
         * If a bind() or sctp_bindx() is not called prior to a listen()
         * call that allows new associations to be accepted, the system
@@ -5889,7 +5875,6 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
         * extensions draft, but follows the practice as seen in TCP
         * sockets.
         *
-        * Additionally, turn off fastreuse flag since we are not listening
         */
        sk->sk_state = SCTP_SS_LISTENING;
        if (!ep->base.bind_addr.port) {
@@ -5900,113 +5885,71 @@ SCTP_STATIC int sctp_seqpacket_listen(struct sock *sk, int backlog)
                        sk->sk_state = SCTP_SS_CLOSED;
                        return -EADDRINUSE;
                }
-               sctp_sk(sk)->bind_hash->fastreuse = 0;
        }
 
-       sctp_hash_endpoint(ep);
-       return 0;
-}
-
-/*
- * 4.1.3 listen() - TCP Style Syntax
- *
- *   Applications uses listen() to ready the SCTP endpoint for accepting
- *   inbound associations.
- */
-SCTP_STATIC int sctp_stream_listen(struct sock *sk, int backlog)
-{
-       struct sctp_sock *sp = sctp_sk(sk);
-       struct sctp_endpoint *ep = sp->ep;
-
-       /* If backlog is zero, disable listening. */
-       if (!backlog) {
-               if (sctp_sstate(sk, CLOSED))
-                       return 0;
-
-               sctp_unhash_endpoint(ep);
-               sk->sk_state = SCTP_SS_CLOSED;
-               return 0;
-       }
-
-       if (sctp_sstate(sk, LISTENING))
-               return 0;
-
-       /*
-        * If a bind() or sctp_bindx() is not called prior to a listen()
-        * call that allows new associations to be accepted, the system
-        * picks an ephemeral port and will choose an address set equivalent
-        * to binding with a wildcard address.
-        *
-        * This is not currently spelled out in the SCTP sockets
-        * extensions draft, but follows the practice as seen in TCP
-        * sockets.
-        */
-       sk->sk_state = SCTP_SS_LISTENING;
-       if (!ep->base.bind_addr.port) {
-               if (sctp_autobind(sk))
-                       return -EAGAIN;
-       } else
-               sctp_sk(sk)->bind_hash->fastreuse = 0;
-
        sk->sk_max_ack_backlog = backlog;
        sctp_hash_endpoint(ep);
        return 0;
 }
 
 /*
+ * 4.1.3 / 5.1.3 listen()
+ *
+ *   By default, new associations are not accepted for UDP style sockets.
+ *   An application uses listen() to mark a socket as being able to
+ *   accept new associations.
+ *
+ *   On TCP style sockets, applications use listen() to ready the SCTP
+ *   endpoint for accepting inbound associations.
+ *
+ *   On both types of endpoints a backlog of '0' disables listening.
+ *
  *  Move a socket to LISTENING state.
  */
 int sctp_inet_listen(struct socket *sock, int backlog)
 {
        struct sock *sk = sock->sk;
-       struct crypto_hash *tfm = NULL;
+       struct sctp_endpoint *ep = sctp_sk(sk)->ep;
        int err = -EINVAL;
 
        if (unlikely(backlog < 0))
-               goto out;
+               return err;
 
        sctp_lock_sock(sk);
 
+       /* Peeled-off sockets are not allowed to listen().  */
+       if (sctp_style(sk, UDP_HIGH_BANDWIDTH))
+               goto out;
+
        if (sock->state != SS_UNCONNECTED)
                goto out;
 
-       /* Allocate HMAC for generating cookie. */
-       if (!sctp_sk(sk)->hmac && sctp_hmac_alg) {
-               tfm = crypto_alloc_hash(sctp_hmac_alg, 0, CRYPTO_ALG_ASYNC);
-               if (IS_ERR(tfm)) {
-                       if (net_ratelimit()) {
-                               printk(KERN_INFO
-                                      "SCTP: failed to load transform for %s: %ld\n",
-                                       sctp_hmac_alg, PTR_ERR(tfm));
-                       }
-                       err = -ENOSYS;
+       /* If backlog is zero, disable listening. */
+       if (!backlog) {
+               if (sctp_sstate(sk, CLOSED))
                        goto out;
-               }
-       }
 
-       switch (sock->type) {
-       case SOCK_SEQPACKET:
-               err = sctp_seqpacket_listen(sk, backlog);
-               break;
-       case SOCK_STREAM:
-               err = sctp_stream_listen(sk, backlog);
-               break;
-       default:
-               break;
+               err = 0;
+               sctp_unhash_endpoint(ep);
+               sk->sk_state = SCTP_SS_CLOSED;
+               if (sk->sk_reuse)
+                       sctp_sk(sk)->bind_hash->fastreuse = 1;
+               goto out;
        }
 
-       if (err)
-               goto cleanup;
+       /* If we are already listening, just update the backlog */
+       if (sctp_sstate(sk, LISTENING))
+               sk->sk_max_ack_backlog = backlog;
+       else {
+               err = sctp_listen_start(sk, backlog);
+               if (err)
+                       goto out;
+       }
 
-       /* Store away the transform reference. */
-       if (!sctp_sk(sk)->hmac)
-               sctp_sk(sk)->hmac = tfm;
+       err = 0;
 out:
        sctp_release_sock(sk);
        return err;
-cleanup:
-       crypto_free_hash(tfm);
-       goto out;
 }
 
 /*
index 5c29b14ee9afc43a33c9866757b9461b8acc6cab..e5dde45c79d32ee1be4b0a2532d0a885a2a57145 100644 (file)
@@ -543,8 +543,8 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
                 * congestion indications more than once every window of
                 * data (or more loosely more than once every round-trip time).
                 */
-               if ((jiffies - transport->last_time_ecne_reduced) >
-                   transport->rtt) {
+               if (time_after(jiffies, transport->last_time_ecne_reduced +
+                                       transport->rtt)) {
                        transport->ssthresh = max(transport->cwnd/2,
                                                  4*transport->asoc->pathmtu);
                        transport->cwnd = transport->ssthresh;
@@ -561,7 +561,8 @@ void sctp_transport_lower_cwnd(struct sctp_transport *transport,
                 * to be done every RTO interval, we do it every hearbeat
                 * interval.
                 */
-               if ((jiffies - transport->last_time_used) > transport->rto)
+               if (time_after(jiffies, transport->last_time_used +
+                                       transport->rto))
                        transport->cwnd = max(transport->cwnd/2,
                                                 4*transport->asoc->pathmtu);
                break;
index 3ddaff42d1bbbe8292d3be98d7b8dd8e0bcbfceb..a3bfd40649125721809b51ca419770d6321dd8ad 100644 (file)
@@ -119,7 +119,7 @@ static struct bclink *bclink = NULL;
 static struct link *bcl = NULL;
 static DEFINE_SPINLOCK(bc_lock);
 
-char tipc_bclink_name[] = "multicast-link";
+const char tipc_bclink_name[] = "multicast-link";
 
 
 static u32 buf_seqno(struct sk_buff *buf)
@@ -800,7 +800,7 @@ int tipc_bclink_init(void)
        tipc_link_set_queue_limits(bcl, BCLINK_WIN_DEFAULT);
        bcl->b_ptr = &bcbearer->bearer;
        bcl->state = WORKING_WORKING;
-       sprintf(bcl->name, tipc_bclink_name);
+       strlcpy(bcl->name, tipc_bclink_name, TIPC_MAX_LINK_NAME);
 
        if (BCLINK_LOG_BUF_SIZE) {
                char *pb = kmalloc(BCLINK_LOG_BUF_SIZE, GFP_ATOMIC);
index 2f2d731bc1c29bbb79cdc6ad1ed666784ad2a4fc..4c1771e95c99ed2ad0b43a07f2690fa69d043af0 100644 (file)
@@ -70,7 +70,7 @@ struct port_list {
 
 struct tipc_node;
 
-extern char tipc_bclink_name[];
+extern const char tipc_bclink_name[];
 
 
 /**
index 29ecae8516683df21403c78a934b44da7a714c88..1885a7edb0c8014831e3e6f2a9f9a91ba326674d 100644 (file)
@@ -258,7 +258,7 @@ void tipc_printf(struct print_buf *pb, const char *fmt, ...)
        }
 
        if (pb->echo)
-               printk(print_string);
+               printk("%s", print_string);
 
        spin_unlock_bh(&print_lock);
 }
index 20d98c56e152685a5ab84e584e9a31a33cb1bfec..2c24e7d6d9506a38a0072c2517da793ed57b81ba 100644 (file)
@@ -703,7 +703,7 @@ struct sk_buff *tipc_node_get_links(const void *req_tlv_area, int req_tlv_space)
 
        link_info.dest = htonl(tipc_own_addr & 0xfffff00);
        link_info.up = htonl(1);
-       sprintf(link_info.str, tipc_bclink_name);
+       strlcpy(link_info.str, tipc_bclink_name, TIPC_MAX_LINK_NAME);
        tipc_cfg_append_tlv(buf, TIPC_TLV_LINK_INFO, &link_info, sizeof(link_info));
 
        /* Add TLVs for any other links in scope */
index d1b89820ab4f34bc5ad8d00d7fa221691f7876c5..baac91049b0ea0efcafb0259ff4146cc2d0e41f6 100644 (file)
@@ -1178,8 +1178,7 @@ out_unlock:
                unix_state_unlock(other);
 
 out:
-       if (skb)
-               kfree_skb(skb);
+       kfree_skb(skb);
        if (newsk)
                unix_release_sock(newsk, 0);
        if (other)
index 39701dec1dbae7c400cfcfcf72ad471d489eb776..466e2d22d256de7151551575607999ff6f1e95a9 100644 (file)
@@ -86,8 +86,10 @@ static int wanrouter_device_del_if(struct wan_device *wandev,
 
 static struct wan_device *wanrouter_find_device(char *name);
 static int wanrouter_delete_interface(struct wan_device *wandev, char *name);
-static void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
-static void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags);
+static void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags)
+       __acquires(lock);
+static void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags)
+       __releases(lock);
 
 
 
@@ -763,12 +765,14 @@ static int wanrouter_delete_interface(struct wan_device *wandev, char *name)
 }
 
 static void lock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags)
+       __acquires(lock)
 {
        spin_lock_irqsave(lock, *smp_flags);
 }
 
 
 static void unlock_adapter_irq(spinlock_t *lock, unsigned long *smp_flags)
+       __releases(lock)
 {
        spin_unlock_irqrestore(lock, *smp_flags);
 }
index 267f7ff498270e3f397430d20f72cf151fb2217e..c44d96b3a437a6019ba254b99877cc7ee025f765 100644 (file)
@@ -80,6 +80,7 @@ static struct proc_dir_entry *proc_router;
  *     Iterator
  */
 static void *r_start(struct seq_file *m, loff_t *pos)
+       __acquires(kernel_lock)
 {
        struct wan_device *wandev;
        loff_t l = *pos;
@@ -101,6 +102,7 @@ static void *r_next(struct seq_file *m, void *v, loff_t *pos)
 }
 
 static void r_stop(struct seq_file *m, void *v)
+       __releases(kernel_lock)
 {
        unlock_kernel();
 }
index e28e2b8fa436edc1290e8704bab478781a308111..092ae6faccca896a272b24d7d87ee59f07d332cf 100644 (file)
@@ -102,3 +102,13 @@ config LIB80211_CRYPT_CCMP
 
 config LIB80211_CRYPT_TKIP
        tristate
+
+config LIB80211_DEBUG
+       bool "lib80211 debugging messages"
+       depends on LIB80211
+       default n
+       ---help---
+         You can enable this if you want verbose debugging messages
+         from lib80211.
+
+         If unsure, say N.
index 0668b2bfc1dafb4c880b565a1a12ec8e30e9e329..17fe39049740ddd6bb9914884be34b44c963b6b6 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/if.h>
 #include <linux/module.h>
 #include <linux/err.h>
-#include <linux/mutex.h>
 #include <linux/list.h>
 #include <linux/nl80211.h>
 #include <linux/debugfs.h>
@@ -31,18 +30,29 @@ MODULE_DESCRIPTION("wireless configuration support");
  * only read the list, and that can happen quite
  * often because we need to do it for each command */
 LIST_HEAD(cfg80211_drv_list);
-DEFINE_MUTEX(cfg80211_drv_mutex);
+
+/*
+ * This is used to protect the cfg80211_drv_list, cfg80211_regdomain,
+ * country_ie_regdomain, the reg_beacon_list and the the last regulatory
+ * request receipt (last_request).
+ */
+DEFINE_MUTEX(cfg80211_mutex);
 
 /* for debugfs */
 static struct dentry *ieee80211_debugfs_dir;
 
-/* requires cfg80211_drv_mutex to be held! */
-static struct cfg80211_registered_device *cfg80211_drv_by_wiphy(int wiphy)
+/* requires cfg80211_mutex to be held! */
+struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx)
 {
        struct cfg80211_registered_device *result = NULL, *drv;
 
+       if (!wiphy_idx_valid(wiphy_idx))
+               return NULL;
+
+       assert_cfg80211_lock();
+
        list_for_each_entry(drv, &cfg80211_drv_list, list) {
-               if (drv->idx == wiphy) {
+               if (drv->wiphy_idx == wiphy_idx) {
                        result = drv;
                        break;
                }
@@ -51,17 +61,44 @@ static struct cfg80211_registered_device *cfg80211_drv_by_wiphy(int wiphy)
        return result;
 }
 
+int get_wiphy_idx(struct wiphy *wiphy)
+{
+       struct cfg80211_registered_device *drv;
+       if (!wiphy)
+               return WIPHY_IDX_STALE;
+       drv = wiphy_to_dev(wiphy);
+       return drv->wiphy_idx;
+}
+
 /* requires cfg80211_drv_mutex to be held! */
+struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx)
+{
+       struct cfg80211_registered_device *drv;
+
+       if (!wiphy_idx_valid(wiphy_idx))
+               return NULL;
+
+       assert_cfg80211_lock();
+
+       drv = cfg80211_drv_by_wiphy_idx(wiphy_idx);
+       if (!drv)
+               return NULL;
+       return &drv->wiphy;
+}
+
+/* requires cfg80211_mutex to be held! */
 static struct cfg80211_registered_device *
 __cfg80211_drv_from_info(struct genl_info *info)
 {
        int ifindex;
-       struct cfg80211_registered_device *bywiphy = NULL, *byifidx = NULL;
+       struct cfg80211_registered_device *bywiphyidx = NULL, *byifidx = NULL;
        struct net_device *dev;
        int err = -EINVAL;
 
+       assert_cfg80211_lock();
+
        if (info->attrs[NL80211_ATTR_WIPHY]) {
-               bywiphy = cfg80211_drv_by_wiphy(
+               bywiphyidx = cfg80211_drv_by_wiphy_idx(
                                nla_get_u32(info->attrs[NL80211_ATTR_WIPHY]));
                err = -ENODEV;
        }
@@ -78,14 +115,14 @@ __cfg80211_drv_from_info(struct genl_info *info)
                err = -ENODEV;
        }
 
-       if (bywiphy && byifidx) {
-               if (bywiphy != byifidx)
+       if (bywiphyidx && byifidx) {
+               if (bywiphyidx != byifidx)
                        return ERR_PTR(-EINVAL);
                else
-                       return bywiphy; /* == byifidx */
+                       return bywiphyidx; /* == byifidx */
        }
-       if (bywiphy)
-               return bywiphy;
+       if (bywiphyidx)
+               return bywiphyidx;
 
        if (byifidx)
                return byifidx;
@@ -98,7 +135,7 @@ cfg80211_get_dev_from_info(struct genl_info *info)
 {
        struct cfg80211_registered_device *drv;
 
-       mutex_lock(&cfg80211_drv_mutex);
+       mutex_lock(&cfg80211_mutex);
        drv = __cfg80211_drv_from_info(info);
 
        /* if it is not an error we grab the lock on
@@ -107,7 +144,7 @@ cfg80211_get_dev_from_info(struct genl_info *info)
        if (!IS_ERR(drv))
                mutex_lock(&drv->mtx);
 
-       mutex_unlock(&cfg80211_drv_mutex);
+       mutex_unlock(&cfg80211_mutex);
 
        return drv;
 }
@@ -118,7 +155,7 @@ cfg80211_get_dev_from_ifindex(int ifindex)
        struct cfg80211_registered_device *drv = ERR_PTR(-ENODEV);
        struct net_device *dev;
 
-       mutex_lock(&cfg80211_drv_mutex);
+       mutex_lock(&cfg80211_mutex);
        dev = dev_get_by_index(&init_net, ifindex);
        if (!dev)
                goto out;
@@ -129,7 +166,7 @@ cfg80211_get_dev_from_ifindex(int ifindex)
                drv = ERR_PTR(-ENODEV);
        dev_put(dev);
  out:
-       mutex_unlock(&cfg80211_drv_mutex);
+       mutex_unlock(&cfg80211_mutex);
        return drv;
 }
 
@@ -143,16 +180,16 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
                        char *newname)
 {
        struct cfg80211_registered_device *drv;
-       int idx, taken = -1, result, digits;
+       int wiphy_idx, taken = -1, result, digits;
 
-       mutex_lock(&cfg80211_drv_mutex);
+       mutex_lock(&cfg80211_mutex);
 
        /* prohibit calling the thing phy%d when %d is not its number */
-       sscanf(newname, PHY_NAME "%d%n", &idx, &taken);
-       if (taken == strlen(newname) && idx != rdev->idx) {
-               /* count number of places needed to print idx */
+       sscanf(newname, PHY_NAME "%d%n", &wiphy_idx, &taken);
+       if (taken == strlen(newname) && wiphy_idx != rdev->wiphy_idx) {
+               /* count number of places needed to print wiphy_idx */
                digits = 1;
-               while (idx /= 10)
+               while (wiphy_idx /= 10)
                        digits++;
                /*
                 * deny the name if it is phy<idx> where <idx> is printed
@@ -193,7 +230,7 @@ int cfg80211_dev_rename(struct cfg80211_registered_device *rdev,
 
        result = 0;
 out_unlock:
-       mutex_unlock(&cfg80211_drv_mutex);
+       mutex_unlock(&cfg80211_mutex);
        if (result == 0)
                nl80211_notify_dev_rename(rdev);
 
@@ -220,22 +257,22 @@ struct wiphy *wiphy_new(struct cfg80211_ops *ops, int sizeof_priv)
 
        drv->ops = ops;
 
-       mutex_lock(&cfg80211_drv_mutex);
+       mutex_lock(&cfg80211_mutex);
 
-       drv->idx = wiphy_counter++;
+       drv->wiphy_idx = wiphy_counter++;
 
-       if (unlikely(drv->idx < 0)) {
+       if (unlikely(!wiphy_idx_valid(drv->wiphy_idx))) {
                wiphy_counter--;
-               mutex_unlock(&cfg80211_drv_mutex);
+               mutex_unlock(&cfg80211_mutex);
                /* ugh, wrapped! */
                kfree(drv);
                return NULL;
        }
 
-       mutex_unlock(&cfg80211_drv_mutex);
+       mutex_unlock(&cfg80211_mutex);
 
        /* give it a proper name */
-       dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->idx);
+       dev_set_name(&drv->wiphy.dev, PHY_NAME "%d", drv->wiphy_idx);
 
        mutex_init(&drv->mtx);
        mutex_init(&drv->devlist_mtx);
@@ -310,10 +347,10 @@ int wiphy_register(struct wiphy *wiphy)
        /* check and set up bitrates */
        ieee80211_set_bitrate_flags(wiphy);
 
-       mutex_lock(&cfg80211_drv_mutex);
+       mutex_lock(&cfg80211_mutex);
 
        /* set up regulatory info */
-       wiphy_update_regulatory(wiphy, REGDOM_SET_BY_CORE);
+       wiphy_update_regulatory(wiphy, NL80211_REGDOM_SET_BY_CORE);
 
        res = device_add(&drv->wiphy.dev);
        if (res)
@@ -328,9 +365,20 @@ int wiphy_register(struct wiphy *wiphy)
        if (IS_ERR(drv->wiphy.debugfsdir))
                drv->wiphy.debugfsdir = NULL;
 
+       if (wiphy->custom_regulatory) {
+               struct regulatory_request request;
+
+               request.wiphy_idx = get_wiphy_idx(wiphy);
+               request.initiator = NL80211_REGDOM_SET_BY_DRIVER;
+               request.alpha2[0] = '9';
+               request.alpha2[1] = '9';
+
+               nl80211_send_reg_change_event(&request);
+       }
+
        res = 0;
 out_unlock:
-       mutex_unlock(&cfg80211_drv_mutex);
+       mutex_unlock(&cfg80211_mutex);
        return res;
 }
 EXPORT_SYMBOL(wiphy_register);
@@ -340,7 +388,7 @@ void wiphy_unregister(struct wiphy *wiphy)
        struct cfg80211_registered_device *drv = wiphy_to_dev(wiphy);
 
        /* protect the device list */
-       mutex_lock(&cfg80211_drv_mutex);
+       mutex_lock(&cfg80211_mutex);
 
        BUG_ON(!list_empty(&drv->netdev_list));
 
@@ -366,7 +414,7 @@ void wiphy_unregister(struct wiphy *wiphy)
        device_del(&drv->wiphy.dev);
        debugfs_remove(drv->wiphy.debugfsdir);
 
-       mutex_unlock(&cfg80211_drv_mutex);
+       mutex_unlock(&cfg80211_mutex);
 }
 EXPORT_SYMBOL(wiphy_unregister);
 
index e29ad4cd464f3587fca6f06ff6892f1a6a04fc6f..6acd483a61f838f7359aa946dbf488aeff50c1d0 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/netdevice.h>
 #include <linux/kref.h>
 #include <linux/rbtree.h>
+#include <linux/mutex.h>
 #include <net/genetlink.h>
 #include <net/wireless.h>
 #include <net/cfg80211.h>
@@ -37,7 +38,7 @@ struct cfg80211_registered_device {
        enum environment_cap env;
 
        /* wiphy index, internal only */
-       int idx;
+       int wiphy_idx;
 
        /* associate netdev list */
        struct mutex devlist_mtx;
@@ -49,6 +50,7 @@ struct cfg80211_registered_device {
        struct rb_root bss_tree;
        u32 bss_generation;
        struct cfg80211_scan_request *scan_req; /* protected by RTNL */
+       unsigned long suspend_at;
 
        /* must be last because of the way we do wiphy_priv(),
         * and it should at least be aligned to NETDEV_ALIGN */
@@ -62,9 +64,27 @@ struct cfg80211_registered_device *wiphy_to_dev(struct wiphy *wiphy)
        return container_of(wiphy, struct cfg80211_registered_device, wiphy);
 }
 
-extern struct mutex cfg80211_drv_mutex;
+/* Note 0 is valid, hence phy0 */
+static inline
+bool wiphy_idx_valid(int wiphy_idx)
+{
+       return (wiphy_idx >= 0);
+}
+
+extern struct mutex cfg80211_mutex;
 extern struct list_head cfg80211_drv_list;
 
+static inline void assert_cfg80211_lock(void)
+{
+       WARN_ON(!mutex_is_locked(&cfg80211_mutex));
+}
+
+/*
+ * You can use this to mark a wiphy_idx as not having an associated wiphy.
+ * It guarantees cfg80211_drv_by_wiphy_idx(wiphy_idx) will return NULL
+ */
+#define WIPHY_IDX_STALE -1
+
 struct cfg80211_internal_bss {
        struct list_head list;
        struct rb_node rbn;
@@ -74,6 +94,9 @@ struct cfg80211_internal_bss {
        struct cfg80211_bss pub;
 };
 
+struct cfg80211_registered_device *cfg80211_drv_by_wiphy_idx(int wiphy_idx);
+int get_wiphy_idx(struct wiphy *wiphy);
+
 /*
  * This function returns a pointer to the driver
  * that the genl_info item that is passed refers to.
@@ -81,13 +104,13 @@ struct cfg80211_internal_bss {
  * the driver's mutex!
  *
  * This means that you need to call cfg80211_put_dev()
- * before being allowed to acquire &cfg80211_drv_mutex!
+ * before being allowed to acquire &cfg80211_mutex!
  *
  * This is necessary because we need to lock the global
  * mutex to get an item off the list safely, and then
  * we lock the drv mutex so it doesn't go away under us.
  *
- * We don't want to keep cfg80211_drv_mutex locked
+ * We don't want to keep cfg80211_mutex locked
  * for all the time in order to allow requests on
  * other interfaces to go through at the same time.
  *
@@ -97,6 +120,9 @@ struct cfg80211_internal_bss {
 extern struct cfg80211_registered_device *
 cfg80211_get_dev_from_info(struct genl_info *info);
 
+/* requires cfg80211_drv_mutex to be held! */
+struct wiphy *wiphy_idx_to_wiphy(int wiphy_idx);
+
 /* identical to cfg80211_get_dev_from_info but only operate on ifindex */
 extern struct cfg80211_registered_device *
 cfg80211_get_dev_from_ifindex(int ifindex);
@@ -110,8 +136,11 @@ extern int cfg80211_dev_rename(struct cfg80211_registered_device *drv,
                               char *newname);
 
 void ieee80211_set_bitrate_flags(struct wiphy *wiphy);
-void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby);
+void wiphy_update_regulatory(struct wiphy *wiphy,
+                            enum nl80211_reg_initiator setby);
 
 void cfg80211_bss_expire(struct cfg80211_registered_device *dev);
+void cfg80211_bss_age(struct cfg80211_registered_device *dev,
+                      unsigned long age_secs);
 
 #endif /* __NET_WIRELESS_CORE_H */
index db428194c16ae184cd9e1829c09de2a1b8afd138..2301dc1edc4cda417335e0747f7505f748de7d8e 100644 (file)
@@ -337,6 +337,7 @@ static int lib80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        pos += 8;
 
        if (ccmp_replay_check(pn, key->rx_pn)) {
+#ifdef CONFIG_LIB80211_DEBUG
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "CCMP: replay detected: STA=%pM "
                                 "previous PN %02x%02x%02x%02x%02x%02x "
@@ -346,6 +347,7 @@ static int lib80211_ccmp_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
                                 key->rx_pn[3], key->rx_pn[4], key->rx_pn[5],
                                 pn[0], pn[1], pn[2], pn[3], pn[4], pn[5]);
                }
+#endif
                key->dot11RSNAStatsCCMPReplays++;
                return -4;
        }
index 7e8e22bfed90a09bf6f1d66543a1ebbe8867808d..c36287399d7ea2155f53a535a1e0ad540e104be3 100644 (file)
@@ -465,12 +465,14 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
        pos += 8;
 
        if (tkip_replay_check(iv32, iv16, tkey->rx_iv32, tkey->rx_iv16)) {
+#ifdef CONFIG_LIB80211_DEBUG
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "TKIP: replay detected: STA=%pM"
                               " previous TSC %08x%04x received TSC "
                               "%08x%04x\n", hdr->addr2,
                               tkey->rx_iv32, tkey->rx_iv16, iv32, iv16);
                }
+#endif
                tkey->dot11RSNAStatsTKIPReplays++;
                return -4;
        }
@@ -505,10 +507,12 @@ static int lib80211_tkip_decrypt(struct sk_buff *skb, int hdr_len, void *priv)
                         * it needs to be recalculated for the next packet. */
                        tkey->rx_phase1_done = 0;
                }
+#ifdef CONFIG_LIB80211_DEBUG
                if (net_ratelimit()) {
                        printk(KERN_DEBUG "TKIP: ICV error detected: STA="
                               "%pM\n", hdr->addr2);
                }
+#endif
                tkey->dot11RSNAStatsTKIPICVErrors++;
                return -5;
        }
index 298a4de5994833b39380d7936e75dbf66e98a85b..ab9d8f14e15103a4d762c08fdd132e1565c15df3 100644 (file)
@@ -7,7 +7,6 @@
 #include <linux/if.h>
 #include <linux/module.h>
 #include <linux/err.h>
-#include <linux/mutex.h>
 #include <linux/list.h>
 #include <linux/if_ether.h>
 #include <linux/ieee80211.h>
@@ -142,7 +141,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        if (!hdr)
                return -1;
 
-       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->idx);
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, dev->wiphy_idx);
        NLA_PUT_STRING(msg, NL80211_ATTR_WIPHY_NAME, wiphy_name(&dev->wiphy));
        NLA_PUT_U8(msg, NL80211_ATTR_MAX_NUM_SCAN_SSIDS,
                   dev->wiphy.max_scan_ssids);
@@ -256,7 +255,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
        int start = cb->args[0];
        struct cfg80211_registered_device *dev;
 
-       mutex_lock(&cfg80211_drv_mutex);
+       mutex_lock(&cfg80211_mutex);
        list_for_each_entry(dev, &cfg80211_drv_list, list) {
                if (++idx <= start)
                        continue;
@@ -267,7 +266,7 @@ static int nl80211_dump_wiphy(struct sk_buff *skb, struct netlink_callback *cb)
                        break;
                }
        }
-       mutex_unlock(&cfg80211_drv_mutex);
+       mutex_unlock(&cfg80211_mutex);
 
        cb->args[0] = idx;
 
@@ -470,7 +469,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
        struct cfg80211_registered_device *dev;
        struct wireless_dev *wdev;
 
-       mutex_lock(&cfg80211_drv_mutex);
+       mutex_lock(&cfg80211_mutex);
        list_for_each_entry(dev, &cfg80211_drv_list, list) {
                if (wp_idx < wp_start) {
                        wp_idx++;
@@ -497,7 +496,7 @@ static int nl80211_dump_interface(struct sk_buff *skb, struct netlink_callback *
                wp_idx++;
        }
  out:
-       mutex_unlock(&cfg80211_drv_mutex);
+       mutex_unlock(&cfg80211_mutex);
 
        cb->args[0] = wp_idx;
        cb->args[1] = if_idx;
@@ -1206,6 +1205,12 @@ static int nl80211_send_station(struct sk_buff *msg, u32 pid, u32 seq,
 
                nla_nest_end(msg, txrate);
        }
+       if (sinfo->filled & STATION_INFO_RX_PACKETS)
+               NLA_PUT_U32(msg, NL80211_STA_INFO_RX_PACKETS,
+                           sinfo->rx_packets);
+       if (sinfo->filled & STATION_INFO_TX_PACKETS)
+               NLA_PUT_U32(msg, NL80211_STA_INFO_TX_PACKETS,
+                           sinfo->tx_packets);
        nla_nest_end(msg, sinfoattr);
 
        return genlmsg_end(msg, hdr);
@@ -1900,6 +1905,19 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
        int r;
        char *data = NULL;
 
+       /*
+        * You should only get this when cfg80211 hasn't yet initialized
+        * completely when built-in to the kernel right between the time
+        * window between nl80211_init() and regulatory_init(), if that is
+        * even possible.
+        */
+       mutex_lock(&cfg80211_mutex);
+       if (unlikely(!cfg80211_regdomain)) {
+               mutex_unlock(&cfg80211_mutex);
+               return -EINPROGRESS;
+       }
+       mutex_unlock(&cfg80211_mutex);
+
        if (!info->attrs[NL80211_ATTR_REG_ALPHA2])
                return -EINVAL;
 
@@ -1910,14 +1928,9 @@ static int nl80211_req_set_reg(struct sk_buff *skb, struct genl_info *info)
        if (is_world_regdom(data))
                return -EINVAL;
 #endif
-       mutex_lock(&cfg80211_drv_mutex);
-       r = __regulatory_hint(NULL, REGDOM_SET_BY_USER, data, 0, ENVIRON_ANY);
-       mutex_unlock(&cfg80211_drv_mutex);
-       /* This means the regulatory domain was already set, however
-        * we don't want to confuse userspace with a "successful error"
-        * message so lets just treat it as a success */
-       if (r == -EALREADY)
-               r = 0;
+
+       r = regulatory_hint_user(data);
+
        return r;
 }
 
@@ -1937,6 +1950,11 @@ static int nl80211_get_mesh_params(struct sk_buff *skb,
        if (err)
                return err;
 
+       if (!drv->ops->get_mesh_params) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
        /* Get the mesh params */
        rtnl_lock();
        err = drv->ops->get_mesh_params(&drv->wiphy, dev, &cur_params);
@@ -2046,6 +2064,11 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
        if (err)
                return err;
 
+       if (!drv->ops->set_mesh_params) {
+               err = -EOPNOTSUPP;
+               goto out;
+       }
+
        /* This makes sure that there aren't more than 32 mesh config
         * parameters (otherwise our bitfield scheme would not work.) */
        BUILD_BUG_ON(NL80211_MESHCONF_ATTR_MAX > 32);
@@ -2090,6 +2113,7 @@ static int nl80211_set_mesh_params(struct sk_buff *skb, struct genl_info *info)
        err = drv->ops->set_mesh_params(&drv->wiphy, dev, &cfg, mask);
        rtnl_unlock();
 
+ out:
        /* cleanup */
        cfg80211_put_dev(drv);
        dev_put(dev);
@@ -2106,7 +2130,7 @@ static int nl80211_get_reg(struct sk_buff *skb, struct genl_info *info)
        unsigned int i;
        int err = -EINVAL;
 
-       mutex_lock(&cfg80211_drv_mutex);
+       mutex_lock(&cfg80211_mutex);
 
        if (!cfg80211_regdomain)
                goto out;
@@ -2169,7 +2193,7 @@ nla_put_failure:
        genlmsg_cancel(msg, hdr);
        err = -EMSGSIZE;
 out:
-       mutex_unlock(&cfg80211_drv_mutex);
+       mutex_unlock(&cfg80211_mutex);
        return err;
 }
 
@@ -2228,9 +2252,9 @@ static int nl80211_set_reg(struct sk_buff *skb, struct genl_info *info)
 
        BUG_ON(rule_idx != num_rules);
 
-       mutex_lock(&cfg80211_drv_mutex);
+       mutex_lock(&cfg80211_mutex);
        r = set_regdom(rd);
-       mutex_unlock(&cfg80211_drv_mutex);
+       mutex_unlock(&cfg80211_mutex);
        return r;
 
  bad_reg:
@@ -2286,6 +2310,7 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        struct wiphy *wiphy;
        int err, tmp, n_ssids = 0, n_channels = 0, i;
        enum ieee80211_band band;
+       size_t ie_len;
 
        err = get_drv_dev_by_info_ifindex(info->attrs, &drv, &dev);
        if (err)
@@ -2327,9 +2352,15 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                goto out_unlock;
        }
 
+       if (info->attrs[NL80211_ATTR_IE])
+               ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+       else
+               ie_len = 0;
+
        request = kzalloc(sizeof(*request)
                        + sizeof(*ssid) * n_ssids
-                       + sizeof(channel) * n_channels, GFP_KERNEL);
+                       + sizeof(channel) * n_channels
+                       + ie_len, GFP_KERNEL);
        if (!request) {
                err = -ENOMEM;
                goto out_unlock;
@@ -2340,6 +2371,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
        if (n_ssids)
                request->ssids = (void *)(request->channels + n_channels);
        request->n_ssids = n_ssids;
+       if (ie_len) {
+               if (request->ssids)
+                       request->ie = (void *)(request->ssids + n_ssids);
+               else
+                       request->ie = (void *)(request->channels + n_channels);
+       }
 
        if (info->attrs[NL80211_ATTR_SCAN_FREQUENCIES]) {
                /* user specified, bail out if channel not found */
@@ -2380,6 +2417,12 @@ static int nl80211_trigger_scan(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
+       if (info->attrs[NL80211_ATTR_IE]) {
+               request->ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
+               memcpy(request->ie, nla_data(info->attrs[NL80211_ATTR_IE]),
+                      request->ie_len);
+       }
+
        request->ifidx = dev->ifindex;
        request->wiphy = &drv->wiphy;
 
@@ -2432,7 +2475,7 @@ static int nl80211_send_bss(struct sk_buff *msg, u32 pid, u32 seq, int flags,
        NLA_PUT_U16(msg, NL80211_BSS_CAPABILITY, res->capability);
        NLA_PUT_U32(msg, NL80211_BSS_FREQUENCY, res->channel->center_freq);
 
-       switch (res->signal_type) {
+       switch (rdev->wiphy.signal_type) {
        case CFG80211_SIGNAL_TYPE_MBM:
                NLA_PUT_U32(msg, NL80211_BSS_SIGNAL_MBM, res->signal);
                break;
@@ -2601,7 +2644,6 @@ static struct genl_ops nl80211_ops[] = {
                .doit = nl80211_get_station,
                .dumpit = nl80211_dump_station,
                .policy = nl80211_policy,
-               .flags = GENL_ADMIN_PERM,
        },
        {
                .cmd = NL80211_CMD_SET_STATION,
@@ -2708,6 +2750,9 @@ static struct genl_multicast_group nl80211_config_mcgrp = {
 static struct genl_multicast_group nl80211_scan_mcgrp = {
        .name = "scan",
 };
+static struct genl_multicast_group nl80211_regulatory_mcgrp = {
+       .name = "regulatory",
+};
 
 /* notification functions */
 
@@ -2739,7 +2784,7 @@ static int nl80211_send_scan_donemsg(struct sk_buff *msg,
        if (!hdr)
                return -1;
 
-       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->idx);
+       NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx);
        NLA_PUT_U32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex);
 
        /* XXX: we should probably bounce back the request? */
@@ -2787,6 +2832,61 @@ void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
        genlmsg_multicast(msg, 0, nl80211_scan_mcgrp.id, GFP_KERNEL);
 }
 
+/*
+ * This can happen on global regulatory changes or device specific settings
+ * based on custom world regulatory domains.
+ */
+void nl80211_send_reg_change_event(struct regulatory_request *request)
+{
+       struct sk_buff *msg;
+       void *hdr;
+
+       msg = nlmsg_new(NLMSG_GOODSIZE, GFP_KERNEL);
+       if (!msg)
+               return;
+
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_REG_CHANGE);
+       if (!hdr) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       /* Userspace can always count this one always being set */
+       NLA_PUT_U8(msg, NL80211_ATTR_REG_INITIATOR, request->initiator);
+
+       if (request->alpha2[0] == '0' && request->alpha2[1] == '0')
+               NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
+                          NL80211_REGDOM_TYPE_WORLD);
+       else if (request->alpha2[0] == '9' && request->alpha2[1] == '9')
+               NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
+                          NL80211_REGDOM_TYPE_CUSTOM_WORLD);
+       else if ((request->alpha2[0] == '9' && request->alpha2[1] == '8') ||
+                request->intersect)
+               NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
+                          NL80211_REGDOM_TYPE_INTERSECTION);
+       else {
+               NLA_PUT_U8(msg, NL80211_ATTR_REG_TYPE,
+                          NL80211_REGDOM_TYPE_COUNTRY);
+               NLA_PUT_STRING(msg, NL80211_ATTR_REG_ALPHA2, request->alpha2);
+       }
+
+       if (wiphy_idx_valid(request->wiphy_idx))
+               NLA_PUT_U32(msg, NL80211_ATTR_WIPHY, request->wiphy_idx);
+
+       if (genlmsg_end(msg, hdr) < 0) {
+               nlmsg_free(msg);
+               return;
+       }
+
+       genlmsg_multicast(msg, 0, nl80211_regulatory_mcgrp.id, GFP_KERNEL);
+
+       return;
+
+nla_put_failure:
+       genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+}
+
 /* initialisation/exit functions */
 
 int nl80211_init(void)
@@ -2811,6 +2911,10 @@ int nl80211_init(void)
        if (err)
                goto err_out;
 
+       err = genl_register_mc_group(&nl80211_fam, &nl80211_regulatory_mcgrp);
+       if (err)
+               goto err_out;
+
        return 0;
  err_out:
        genl_unregister_family(&nl80211_fam);
index b565a5f84e9782af4723956055c19f5ac972dbdf..e65a3c38c52fa2ec30545407efeb23c9e73b83d6 100644 (file)
@@ -11,6 +11,7 @@ extern void nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
                                   struct net_device *netdev);
 extern void nl80211_send_scan_aborted(struct cfg80211_registered_device *rdev,
                                      struct net_device *netdev);
+extern void nl80211_send_reg_change_event(struct regulatory_request *request);
 #else
 static inline int nl80211_init(void)
 {
@@ -27,6 +28,14 @@ static inline void
 nl80211_send_scan_done(struct cfg80211_registered_device *rdev,
                       struct net_device *netdev)
 {}
+static inline void nl80211_send_scan_aborted(
+                                       struct cfg80211_registered_device *rdev,
+                                       struct net_device *netdev)
+{}
+static inline void
+nl80211_send_reg_change_event(struct regulatory_request *request)
+{
+}
 #endif /* CONFIG_NL80211 */
 
 #endif /* __NET_WIRELESS_NL80211_H */
index 2323644330cd775f8022ae9045f0d87cc2b11701..eb8b8ed161554e869148285e5a164496a596686c 100644 (file)
@@ -41,6 +41,7 @@
 #include <net/cfg80211.h>
 #include "core.h"
 #include "reg.h"
+#include "nl80211.h"
 
 /* Receipt of information from last regulatory request */
 static struct regulatory_request *last_request;
@@ -54,22 +55,63 @@ static u32 supported_bandwidths[] = {
        MHZ_TO_KHZ(20),
 };
 
-/* Central wireless core regulatory domains, we only need two,
+/*
+ * Central wireless core regulatory domains, we only need two,
  * the current one and a world regulatory domain in case we have no
- * information to give us an alpha2 */
+ * information to give us an alpha2
+ */
 const struct ieee80211_regdomain *cfg80211_regdomain;
 
-/* We use this as a place for the rd structure built from the
+/*
+ * We use this as a place for the rd structure built from the
  * last parsed country IE to rest until CRDA gets back to us with
- * what it thinks should apply for the same country */
+ * what it thinks should apply for the same country
+ */
 static const struct ieee80211_regdomain *country_ie_regdomain;
 
+/* Used to queue up regulatory hints */
+static LIST_HEAD(reg_requests_list);
+static spinlock_t reg_requests_lock;
+
+/* Used to queue up beacon hints for review */
+static LIST_HEAD(reg_pending_beacons);
+static spinlock_t reg_pending_beacons_lock;
+
+/* Used to keep track of processed beacon hints */
+static LIST_HEAD(reg_beacon_list);
+
+struct reg_beacon {
+       struct list_head list;
+       struct ieee80211_channel chan;
+};
+
 /* We keep a static world regulatory domain in case of the absence of CRDA */
 static const struct ieee80211_regdomain world_regdom = {
-       .n_reg_rules = 1,
+       .n_reg_rules = 5,
        .alpha2 =  "00",
        .reg_rules = {
-               REG_RULE(2412-10, 2462+10, 40, 6, 20,
+               /* IEEE 802.11b/g, channels 1..11 */
+               REG_RULE(2412-10, 2462+10, 40, 6, 20, 0),
+               /* IEEE 802.11b/g, channels 12..13. No HT40
+                * channel fits here. */
+               REG_RULE(2467-10, 2472+10, 20, 6, 20,
+                       NL80211_RRF_PASSIVE_SCAN |
+                       NL80211_RRF_NO_IBSS),
+               /* IEEE 802.11 channel 14 - Only JP enables
+                * this and for 802.11b only */
+               REG_RULE(2484-10, 2484+10, 20, 6, 20,
+                       NL80211_RRF_PASSIVE_SCAN |
+                       NL80211_RRF_NO_IBSS |
+                       NL80211_RRF_NO_OFDM),
+               /* IEEE 802.11a, channel 36..48 */
+               REG_RULE(5180-10, 5240+10, 40, 6, 20,
+                        NL80211_RRF_PASSIVE_SCAN |
+                        NL80211_RRF_NO_IBSS),
+
+               /* NB: 5260 MHz - 5700 MHz requies DFS */
+
+               /* IEEE 802.11a, channel 149..165 */
+               REG_RULE(5745-10, 5825+10, 40, 6, 20,
                        NL80211_RRF_PASSIVE_SCAN |
                        NL80211_RRF_NO_IBSS),
        }
@@ -83,9 +125,11 @@ static char *ieee80211_regdom = "US";
 module_param(ieee80211_regdom, charp, 0444);
 MODULE_PARM_DESC(ieee80211_regdom, "IEEE 802.11 regulatory domain code");
 
-/* We assume 40 MHz bandwidth for the old regulatory work.
+/*
+ * We assume 40 MHz bandwidth for the old regulatory work.
  * We make emphasis we are using the exact same frequencies
- * as before */
+ * as before
+ */
 
 static const struct ieee80211_regdomain us_regdom = {
        .n_reg_rules = 6,
@@ -124,8 +168,10 @@ static const struct ieee80211_regdomain jp_regdom = {
 
 static const struct ieee80211_regdomain eu_regdom = {
        .n_reg_rules = 6,
-       /* This alpha2 is bogus, we leave it here just for stupid
-        * backward compatibility */
+       /*
+        * This alpha2 is bogus, we leave it here just for stupid
+        * backward compatibility
+        */
        .alpha2 =  "EU",
        .reg_rules = {
                /* IEEE 802.11b/g, channels 1..13 */
@@ -194,8 +240,10 @@ static void reset_regdomains(void)
        cfg80211_regdomain = NULL;
 }
 
-/* Dynamic world regulatory domain requested by the wireless
- * core upon initialization */
+/*
+ * Dynamic world regulatory domain requested by the wireless
+ * core upon initialization
+ */
 static void update_world_regdomain(const struct ieee80211_regdomain *rd)
 {
        BUG_ON(!last_request);
@@ -236,8 +284,10 @@ static bool is_unknown_alpha2(const char *alpha2)
 {
        if (!alpha2)
                return false;
-       /* Special case where regulatory domain was built by driver
-        * but a specific alpha2 cannot be determined */
+       /*
+        * Special case where regulatory domain was built by driver
+        * but a specific alpha2 cannot be determined
+        */
        if (alpha2[0] == '9' && alpha2[1] == '9')
                return true;
        return false;
@@ -247,9 +297,11 @@ static bool is_intersected_alpha2(const char *alpha2)
 {
        if (!alpha2)
                return false;
-       /* Special case where regulatory domain is the
+       /*
+        * Special case where regulatory domain is the
         * result of an intersection between two regulatory domain
-        * structures */
+        * structures
+        */
        if (alpha2[0] == '9' && alpha2[1] == '8')
                return true;
        return false;
@@ -274,8 +326,10 @@ static bool alpha2_equal(const char *alpha2_x, const char *alpha2_y)
        return false;
 }
 
-static bool regdom_changed(const char *alpha2)
+static bool regdom_changes(const char *alpha2)
 {
+       assert_cfg80211_lock();
+
        if (!cfg80211_regdomain)
                return true;
        if (alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
@@ -302,8 +356,10 @@ static bool country_ie_integrity_changes(u32 checksum)
        return false;
 }
 
-/* This lets us keep regulatory code which is updated on a regulatory
- * basis in userspace. */
+/*
+ * This lets us keep regulatory code which is updated on a regulatory
+ * basis in userspace.
+ */
 static int call_crda(const char *alpha2)
 {
        char country_env[9 + 2] = "COUNTRY=";
@@ -348,7 +404,8 @@ static bool is_valid_reg_rule(const struct ieee80211_reg_rule *rule)
 
        freq_diff = freq_range->end_freq_khz - freq_range->start_freq_khz;
 
-       if (freq_diff <= 0 || freq_range->max_bandwidth_khz > freq_diff)
+       if (freq_range->end_freq_khz <= freq_range->start_freq_khz ||
+                       freq_range->max_bandwidth_khz > freq_diff)
                return false;
 
        return true;
@@ -414,10 +471,12 @@ static bool freq_in_rule_band(const struct ieee80211_freq_range *freq_range,
 #undef ONE_GHZ_IN_KHZ
 }
 
-/* Converts a country IE to a regulatory domain. A regulatory domain
+/*
+ * Converts a country IE to a regulatory domain. A regulatory domain
  * structure has a lot of information which the IE doesn't yet have,
  * so for the other values we use upper max values as we will intersect
- * with our userspace regulatory agent to get lower bounds. */
+ * with our userspace regulatory agent to get lower bounds.
+ */
 static struct ieee80211_regdomain *country_ie_2_rd(
                                u8 *country_ie,
                                u8 country_ie_len,
@@ -462,9 +521,11 @@ static struct ieee80211_regdomain *country_ie_2_rd(
 
        *checksum ^= ((flags ^ alpha2[0] ^ alpha2[1]) << 8);
 
-       /* We need to build a reg rule for each triplet, but first we must
+       /*
+        * We need to build a reg rule for each triplet, but first we must
         * calculate the number of reg rules we will need. We will need one
-        * for each channel subband */
+        * for each channel subband
+        */
        while (country_ie_len >= 3) {
                int end_channel = 0;
                struct ieee80211_country_ie_triplet *triplet =
@@ -502,9 +563,11 @@ static struct ieee80211_regdomain *country_ie_2_rd(
                if (cur_sub_max_channel < cur_channel)
                        return NULL;
 
-               /* Do not allow overlapping channels. Also channels
+               /*
+                * Do not allow overlapping channels. Also channels
                 * passed in each subband must be monotonically
-                * increasing */
+                * increasing
+                */
                if (last_sub_max_channel) {
                        if (cur_channel <= last_sub_max_channel)
                                return NULL;
@@ -512,10 +575,12 @@ static struct ieee80211_regdomain *country_ie_2_rd(
                                return NULL;
                }
 
-               /* When dot11RegulatoryClassesRequired is supported
+               /*
+                * When dot11RegulatoryClassesRequired is supported
                 * we can throw ext triplets as part of this soup,
                 * for now we don't care when those change as we
-                * don't support them */
+                * don't support them
+                */
                *checksum ^= ((cur_channel ^ cur_sub_max_channel) << 8) |
                  ((cur_sub_max_channel ^ cur_sub_max_channel) << 16) |
                  ((triplet->chans.max_power ^ cur_sub_max_channel) << 24);
@@ -526,8 +591,10 @@ static struct ieee80211_regdomain *country_ie_2_rd(
                country_ie_len -= 3;
                num_rules++;
 
-               /* Note: this is not a IEEE requirement but
-                * simply a memory requirement */
+               /*
+                * Note: this is not a IEEE requirement but
+                * simply a memory requirement
+                */
                if (num_rules > NL80211_MAX_SUPP_REG_RULES)
                        return NULL;
        }
@@ -555,8 +622,10 @@ static struct ieee80211_regdomain *country_ie_2_rd(
                struct ieee80211_freq_range *freq_range = NULL;
                struct ieee80211_power_rule *power_rule = NULL;
 
-               /* Must parse if dot11RegulatoryClassesRequired is true,
-                * we don't support this yet */
+               /*
+                * Must parse if dot11RegulatoryClassesRequired is true,
+                * we don't support this yet
+                */
                if (triplet->ext.reg_extension_id >=
                                IEEE80211_COUNTRY_EXTENSION_ID) {
                        country_ie += 3;
@@ -578,10 +647,12 @@ static struct ieee80211_regdomain *country_ie_2_rd(
                        end_channel =  triplet->chans.first_channel +
                                (4 * (triplet->chans.num_channels - 1));
 
-               /* The +10 is since the regulatory domain expects
+               /*
+                * The +10 is since the regulatory domain expects
                 * the actual band edge, not the center of freq for
                 * its start and end freqs, assuming 20 MHz bandwidth on
-                * the channels passed */
+                * the channels passed
+                */
                freq_range->start_freq_khz =
                        MHZ_TO_KHZ(ieee80211_channel_to_frequency(
                                triplet->chans.first_channel) - 10);
@@ -589,9 +660,11 @@ static struct ieee80211_regdomain *country_ie_2_rd(
                        MHZ_TO_KHZ(ieee80211_channel_to_frequency(
                                end_channel) + 10);
 
-               /* Large arbitrary values, we intersect later */
-               /* Increment this if we ever support >= 40 MHz channels
-                * in IEEE 802.11 */
+               /*
+                * These are large arbitrary values we use to intersect later.
+                * Increment this if we ever support >= 40 MHz channels
+                * in IEEE 802.11
+                */
                freq_range->max_bandwidth_khz = MHZ_TO_KHZ(40);
                power_rule->max_antenna_gain = DBI_TO_MBI(100);
                power_rule->max_eirp = DBM_TO_MBM(100);
@@ -607,8 +680,10 @@ static struct ieee80211_regdomain *country_ie_2_rd(
 }
 
 
-/* Helper for regdom_intersect(), this does the real
- * mathematical intersection fun */
+/*
+ * Helper for regdom_intersect(), this does the real
+ * mathematical intersection fun
+ */
 static int reg_rules_intersect(
        const struct ieee80211_reg_rule *rule1,
        const struct ieee80211_reg_rule *rule2,
@@ -686,11 +761,13 @@ static struct ieee80211_regdomain *regdom_intersect(
        if (!rd1 || !rd2)
                return NULL;
 
-       /* First we get a count of the rules we'll need, then we actually
+       /*
+        * First we get a count of the rules we'll need, then we actually
         * build them. This is to so we can malloc() and free() a
         * regdomain once. The reason we use reg_rules_intersect() here
         * is it will return -EINVAL if the rule computed makes no sense.
-        * All rules that do check out OK are valid. */
+        * All rules that do check out OK are valid.
+        */
 
        for (x = 0; x < rd1->n_reg_rules; x++) {
                rule1 = &rd1->reg_rules[x];
@@ -718,14 +795,18 @@ static struct ieee80211_regdomain *regdom_intersect(
                rule1 = &rd1->reg_rules[x];
                for (y = 0; y < rd2->n_reg_rules; y++) {
                        rule2 = &rd2->reg_rules[y];
-                       /* This time around instead of using the stack lets
+                       /*
+                        * This time around instead of using the stack lets
                         * write to the target rule directly saving ourselves
-                        * a memcpy() */
+                        * a memcpy()
+                        */
                        intersected_rule = &rd->reg_rules[rule_idx];
                        r = reg_rules_intersect(rule1, rule2,
                                intersected_rule);
-                       /* No need to memset here the intersected rule here as
-                        * we're not using the stack anymore */
+                       /*
+                        * No need to memset here the intersected rule here as
+                        * we're not using the stack anymore
+                        */
                        if (r)
                                continue;
                        rule_idx++;
@@ -744,8 +825,10 @@ static struct ieee80211_regdomain *regdom_intersect(
        return rd;
 }
 
-/* XXX: add support for the rest of enum nl80211_reg_rule_flags, we may
- * want to just have the channel structure use these */
+/*
+ * XXX: add support for the rest of enum nl80211_reg_rule_flags, we may
+ * want to just have the channel structure use these
+ */
 static u32 map_regdom_flags(u32 rd_flags)
 {
        u32 channel_flags = 0;
@@ -771,10 +854,12 @@ static int freq_reg_info_regd(struct wiphy *wiphy,
 
        regd = custom_regd ? custom_regd : cfg80211_regdomain;
 
-       /* Follow the driver's regulatory domain, if present, unless a country
-        * IE has been processed or a user wants to help complaince further */
-       if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE &&
-           last_request->initiator != REGDOM_SET_BY_USER &&
+       /*
+        * Follow the driver's regulatory domain, if present, unless a country
+        * IE has been processed or a user wants to help complaince further
+        */
+       if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
+           last_request->initiator != NL80211_REGDOM_SET_BY_USER &&
            wiphy->regd)
                regd = wiphy->regd;
 
@@ -790,9 +875,11 @@ static int freq_reg_info_regd(struct wiphy *wiphy,
                fr = &rr->freq_range;
                pr = &rr->power_rule;
 
-               /* We only need to know if one frequency rule was
+               /*
+                * We only need to know if one frequency rule was
                 * was in center_freq's band, that's enough, so lets
-                * not overwrite it once found */
+                * not overwrite it once found
+                */
                if (!band_rule_found)
                        band_rule_found = freq_in_rule_band(fr, center_freq);
 
@@ -829,6 +916,11 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
        const struct ieee80211_power_rule *power_rule = NULL;
        struct ieee80211_supported_band *sband;
        struct ieee80211_channel *chan;
+       struct wiphy *request_wiphy = NULL;
+
+       assert_cfg80211_lock();
+
+       request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
 
        sband = wiphy->bands[band];
        BUG_ON(chan_idx >= sband->n_channels);
@@ -840,7 +932,8 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
                &max_bandwidth, &reg_rule);
 
        if (r) {
-               /* This means no regulatory rule was found in the country IE
+               /*
+                * This means no regulatory rule was found in the country IE
                 * with a frequency range on the center_freq's band, since
                 * IEEE-802.11 allows for a country IE to have a subset of the
                 * regulatory information provided in a country we ignore
@@ -851,7 +944,8 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
                 * http://tinyurl.com/11d-clarification
                 */
                if (r == -ERANGE &&
-                   last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
+                   last_request->initiator ==
+                   NL80211_REGDOM_SET_BY_COUNTRY_IE) {
 #ifdef CONFIG_CFG80211_REG_DEBUG
                        printk(KERN_DEBUG "cfg80211: Leaving channel %d MHz "
                                "intact on %s - no rule found in band on "
@@ -859,10 +953,13 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
                                chan->center_freq, wiphy_name(wiphy));
 #endif
                } else {
-               /* In this case we know the country IE has at least one reg rule
-                * for the band so we respect its band definitions */
+               /*
+                * In this case we know the country IE has at least one reg rule
+                * for the band so we respect its band definitions
+                */
 #ifdef CONFIG_CFG80211_REG_DEBUG
-                       if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
+                       if (last_request->initiator ==
+                           NL80211_REGDOM_SET_BY_COUNTRY_IE)
                                printk(KERN_DEBUG "cfg80211: Disabling "
                                        "channel %d MHz on %s due to "
                                        "Country IE\n",
@@ -876,12 +973,14 @@ static void handle_channel(struct wiphy *wiphy, enum ieee80211_band band,
 
        power_rule = &reg_rule->power_rule;
 
-       if (last_request->initiator == REGDOM_SET_BY_DRIVER &&
-           last_request->wiphy && last_request->wiphy == wiphy &&
-           last_request->wiphy->strict_regulatory) {
-               /* This gaurantees the driver's requested regulatory domain
+       if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
+           request_wiphy && request_wiphy == wiphy &&
+           request_wiphy->strict_regulatory) {
+               /*
+                * This gaurantees the driver's requested regulatory domain
                 * will always be used as a base for further regulatory
-                * settings */
+                * settings
+                */
                chan->flags = chan->orig_flags =
                        map_regdom_flags(reg_rule->flags);
                chan->max_antenna_gain = chan->orig_mag =
@@ -915,39 +1014,147 @@ static void handle_band(struct wiphy *wiphy, enum ieee80211_band band)
                handle_channel(wiphy, band, i);
 }
 
-static bool ignore_reg_update(struct wiphy *wiphy, enum reg_set_by setby)
+static bool ignore_reg_update(struct wiphy *wiphy,
+                             enum nl80211_reg_initiator initiator)
 {
        if (!last_request)
                return true;
-       if (setby == REGDOM_SET_BY_CORE &&
+       if (initiator == NL80211_REGDOM_SET_BY_CORE &&
                  wiphy->custom_regulatory)
                return true;
-       /* wiphy->regd will be set once the device has its own
-        * desired regulatory domain set */
+       /*
+        * wiphy->regd will be set once the device has its own
+        * desired regulatory domain set
+        */
        if (wiphy->strict_regulatory && !wiphy->regd &&
            !is_world_regdom(last_request->alpha2))
                return true;
        return false;
 }
 
-static void update_all_wiphy_regulatory(enum reg_set_by setby)
+static void update_all_wiphy_regulatory(enum nl80211_reg_initiator initiator)
 {
        struct cfg80211_registered_device *drv;
 
        list_for_each_entry(drv, &cfg80211_drv_list, list)
-               wiphy_update_regulatory(&drv->wiphy, setby);
+               wiphy_update_regulatory(&drv->wiphy, initiator);
 }
 
-void wiphy_update_regulatory(struct wiphy *wiphy, enum reg_set_by setby)
+static void handle_reg_beacon(struct wiphy *wiphy,
+                             unsigned int chan_idx,
+                             struct reg_beacon *reg_beacon)
 {
-       enum ieee80211_band band;
+#ifdef CONFIG_CFG80211_REG_DEBUG
+#define REG_DEBUG_BEACON_FLAG(desc) \
+       printk(KERN_DEBUG "cfg80211: Enabling " desc " on " \
+               "frequency: %d MHz (Ch %d) on %s\n", \
+               reg_beacon->chan.center_freq, \
+               ieee80211_frequency_to_channel(reg_beacon->chan.center_freq), \
+               wiphy_name(wiphy));
+#else
+#define REG_DEBUG_BEACON_FLAG(desc) do {} while (0)
+#endif
+       struct ieee80211_supported_band *sband;
+       struct ieee80211_channel *chan;
+
+       assert_cfg80211_lock();
+
+       sband = wiphy->bands[reg_beacon->chan.band];
+       chan = &sband->channels[chan_idx];
+
+       if (likely(chan->center_freq != reg_beacon->chan.center_freq))
+               return;
+
+       if (chan->flags & IEEE80211_CHAN_PASSIVE_SCAN) {
+               chan->flags &= ~IEEE80211_CHAN_PASSIVE_SCAN;
+               REG_DEBUG_BEACON_FLAG("active scanning");
+       }
+
+       if (chan->flags & IEEE80211_CHAN_NO_IBSS) {
+               chan->flags &= ~IEEE80211_CHAN_NO_IBSS;
+               REG_DEBUG_BEACON_FLAG("beaconing");
+       }
+
+       chan->beacon_found = true;
+#undef REG_DEBUG_BEACON_FLAG
+}
+
+/*
+ * Called when a scan on a wiphy finds a beacon on
+ * new channel
+ */
+static void wiphy_update_new_beacon(struct wiphy *wiphy,
+                                   struct reg_beacon *reg_beacon)
+{
+       unsigned int i;
+       struct ieee80211_supported_band *sband;
+
+       assert_cfg80211_lock();
 
-       if (ignore_reg_update(wiphy, setby))
+       if (!wiphy->bands[reg_beacon->chan.band])
                return;
+
+       sband = wiphy->bands[reg_beacon->chan.band];
+
+       for (i = 0; i < sband->n_channels; i++)
+               handle_reg_beacon(wiphy, i, reg_beacon);
+}
+
+/*
+ * Called upon reg changes or a new wiphy is added
+ */
+static void wiphy_update_beacon_reg(struct wiphy *wiphy)
+{
+       unsigned int i;
+       struct ieee80211_supported_band *sband;
+       struct reg_beacon *reg_beacon;
+
+       assert_cfg80211_lock();
+
+       if (list_empty(&reg_beacon_list))
+               return;
+
+       list_for_each_entry(reg_beacon, &reg_beacon_list, list) {
+               if (!wiphy->bands[reg_beacon->chan.band])
+                       continue;
+               sband = wiphy->bands[reg_beacon->chan.band];
+               for (i = 0; i < sband->n_channels; i++)
+                       handle_reg_beacon(wiphy, i, reg_beacon);
+       }
+}
+
+static bool reg_is_world_roaming(struct wiphy *wiphy)
+{
+       if (is_world_regdom(cfg80211_regdomain->alpha2) ||
+           (wiphy->regd && is_world_regdom(wiphy->regd->alpha2)))
+               return true;
+       if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE &&
+           wiphy->custom_regulatory)
+               return true;
+       return false;
+}
+
+/* Reap the advantages of previously found beacons */
+static void reg_process_beacons(struct wiphy *wiphy)
+{
+       if (!reg_is_world_roaming(wiphy))
+               return;
+       wiphy_update_beacon_reg(wiphy);
+}
+
+void wiphy_update_regulatory(struct wiphy *wiphy,
+                            enum nl80211_reg_initiator initiator)
+{
+       enum ieee80211_band band;
+
+       if (ignore_reg_update(wiphy, initiator))
+               goto out;
        for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
                if (wiphy->bands[band])
                        handle_band(wiphy, band);
        }
+out:
+       reg_process_beacons(wiphy);
        if (wiphy->reg_notifier)
                wiphy->reg_notifier(wiphy, last_request);
 }
@@ -1033,81 +1240,98 @@ static int reg_copy_regd(const struct ieee80211_regdomain **dst_regd,
        return 0;
 }
 
-/* Return value which can be used by ignore_request() to indicate
- * it has been determined we should intersect two regulatory domains */
+/*
+ * Return value which can be used by ignore_request() to indicate
+ * it has been determined we should intersect two regulatory domains
+ */
 #define REG_INTERSECT  1
 
 /* This has the logic which determines when a new request
  * should be ignored. */
-static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
-                         const char *alpha2)
+static int ignore_request(struct wiphy *wiphy,
+                         struct regulatory_request *pending_request)
 {
+       struct wiphy *last_wiphy = NULL;
+
+       assert_cfg80211_lock();
+
        /* All initial requests are respected */
        if (!last_request)
                return 0;
 
-       switch (set_by) {
-       case REGDOM_SET_BY_INIT:
+       switch (pending_request->initiator) {
+       case NL80211_REGDOM_SET_BY_CORE:
                return -EINVAL;
-       case REGDOM_SET_BY_CORE:
-               /*
-                * Always respect new wireless core hints, should only happen
-                * when updating the world regulatory domain at init.
-                */
-               return 0;
-       case REGDOM_SET_BY_COUNTRY_IE:
-               if (unlikely(!is_an_alpha2(alpha2)))
+       case NL80211_REGDOM_SET_BY_COUNTRY_IE:
+
+               last_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
+
+               if (unlikely(!is_an_alpha2(pending_request->alpha2)))
                        return -EINVAL;
-               if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
-                       if (last_request->wiphy != wiphy) {
+               if (last_request->initiator ==
+                   NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+                       if (last_wiphy != wiphy) {
                                /*
                                 * Two cards with two APs claiming different
                                 * different Country IE alpha2s. We could
                                 * intersect them, but that seems unlikely
                                 * to be correct. Reject second one for now.
                                 */
-                               if (!alpha2_equal(alpha2,
-                                                 cfg80211_regdomain->alpha2))
+                               if (regdom_changes(pending_request->alpha2))
                                        return -EOPNOTSUPP;
                                return -EALREADY;
                        }
-                       /* Two consecutive Country IE hints on the same wiphy.
-                        * This should be picked up early by the driver/stack */
-                       if (WARN_ON(!alpha2_equal(cfg80211_regdomain->alpha2,
-                                 alpha2)))
+                       /*
+                        * Two consecutive Country IE hints on the same wiphy.
+                        * This should be picked up early by the driver/stack
+                        */
+                       if (WARN_ON(regdom_changes(pending_request->alpha2)))
                                return 0;
                        return -EALREADY;
                }
                return REG_INTERSECT;
-       case REGDOM_SET_BY_DRIVER:
-               if (last_request->initiator == REGDOM_SET_BY_CORE) {
+       case NL80211_REGDOM_SET_BY_DRIVER:
+               if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE) {
                        if (is_old_static_regdom(cfg80211_regdomain))
                                return 0;
-                       if (!alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
+                       if (regdom_changes(pending_request->alpha2))
                                return 0;
                        return -EALREADY;
                }
+
+               /*
+                * This would happen if you unplug and plug your card
+                * back in or if you add a new device for which the previously
+                * loaded card also agrees on the regulatory domain.
+                */
+               if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
+                   !regdom_changes(pending_request->alpha2))
+                       return -EALREADY;
+
                return REG_INTERSECT;
-       case REGDOM_SET_BY_USER:
-               if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE)
+       case NL80211_REGDOM_SET_BY_USER:
+               if (last_request->initiator == NL80211_REGDOM_SET_BY_COUNTRY_IE)
                        return REG_INTERSECT;
-               /* If the user knows better the user should set the regdom
-                * to their country before the IE is picked up */
-               if (last_request->initiator == REGDOM_SET_BY_USER &&
+               /*
+                * If the user knows better the user should set the regdom
+                * to their country before the IE is picked up
+                */
+               if (last_request->initiator == NL80211_REGDOM_SET_BY_USER &&
                          last_request->intersect)
                        return -EOPNOTSUPP;
-               /* Process user requests only after previous user/driver/core
-                * requests have been processed */
-               if (last_request->initiator == REGDOM_SET_BY_CORE ||
-                   last_request->initiator == REGDOM_SET_BY_DRIVER ||
-                   last_request->initiator == REGDOM_SET_BY_USER) {
-                       if (!alpha2_equal(last_request->alpha2,
-                           cfg80211_regdomain->alpha2))
+               /*
+                * Process user requests only after previous user/driver/core
+                * requests have been processed
+                */
+               if (last_request->initiator == NL80211_REGDOM_SET_BY_CORE ||
+                   last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER ||
+                   last_request->initiator == NL80211_REGDOM_SET_BY_USER) {
+                       if (regdom_changes(last_request->alpha2))
                                return -EAGAIN;
                }
 
                if (!is_old_static_regdom(cfg80211_regdomain) &&
-                   alpha2_equal(cfg80211_regdomain->alpha2, alpha2))
+                   !regdom_changes(pending_request->alpha2))
                        return -EALREADY;
 
                return 0;
@@ -1116,59 +1340,80 @@ static int ignore_request(struct wiphy *wiphy, enum reg_set_by set_by,
        return -EINVAL;
 }
 
-/* Caller must hold &cfg80211_drv_mutex */
-int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
-                       const char *alpha2,
-                       u32 country_ie_checksum,
-                       enum environment_cap env)
+/**
+ * __regulatory_hint - hint to the wireless core a regulatory domain
+ * @wiphy: if the hint comes from country information from an AP, this
+ *     is required to be set to the wiphy that received the information
+ * @pending_request: the regulatory request currently being processed
+ *
+ * The Wireless subsystem can use this function to hint to the wireless core
+ * what it believes should be the current regulatory domain.
+ *
+ * Returns zero if all went fine, %-EALREADY if a regulatory domain had
+ * already been set or other standard error codes.
+ *
+ * Caller must hold &cfg80211_mutex
+ */
+static int __regulatory_hint(struct wiphy *wiphy,
+                            struct regulatory_request *pending_request)
 {
-       struct regulatory_request *request;
        bool intersect = false;
        int r = 0;
 
-       r = ignore_request(wiphy, set_by, alpha2);
+       assert_cfg80211_lock();
+
+       r = ignore_request(wiphy, pending_request);
 
        if (r == REG_INTERSECT) {
-               if (set_by == REGDOM_SET_BY_DRIVER) {
+               if (pending_request->initiator ==
+                   NL80211_REGDOM_SET_BY_DRIVER) {
                        r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);
-                       if (r)
+                       if (r) {
+                               kfree(pending_request);
                                return r;
+                       }
                }
                intersect = true;
        } else if (r) {
-               /* If the regulatory domain being requested by the
+               /*
+                * If the regulatory domain being requested by the
                 * driver has already been set just copy it to the
-                * wiphy */
-               if (r == -EALREADY && set_by == REGDOM_SET_BY_DRIVER) {
+                * wiphy
+                */
+               if (r == -EALREADY &&
+                   pending_request->initiator ==
+                   NL80211_REGDOM_SET_BY_DRIVER) {
                        r = reg_copy_regd(&wiphy->regd, cfg80211_regdomain);
-                       if (r)
+                       if (r) {
+                               kfree(pending_request);
                                return r;
+                       }
                        r = -EALREADY;
                        goto new_request;
                }
+               kfree(pending_request);
                return r;
        }
 
 new_request:
-       request = kzalloc(sizeof(struct regulatory_request),
-                         GFP_KERNEL);
-       if (!request)
-               return -ENOMEM;
+       kfree(last_request);
 
-       request->alpha2[0] = alpha2[0];
-       request->alpha2[1] = alpha2[1];
-       request->initiator = set_by;
-       request->wiphy = wiphy;
-       request->intersect = intersect;
-       request->country_ie_checksum = country_ie_checksum;
-       request->country_ie_env = env;
+       last_request = pending_request;
+       last_request->intersect = intersect;
 
-       kfree(last_request);
-       last_request = request;
+       pending_request = NULL;
 
        /* When r == REG_INTERSECT we do need to call CRDA */
-       if (r < 0)
+       if (r < 0) {
+               /*
+                * Since CRDA will not be called in this case as we already
+                * have applied the requested regulatory domain before we just
+                * inform userspace we have processed the request
+                */
+               if (r == -EALREADY)
+                       nl80211_send_reg_change_event(last_request);
                return r;
+       }
 
        /*
         * Note: When CONFIG_WIRELESS_OLD_REGULATORY is enabled
@@ -1180,34 +1425,194 @@ new_request:
         *
         * to intersect with the static rd
         */
-       return call_crda(alpha2);
+       return call_crda(last_request->alpha2);
 }
 
-void regulatory_hint(struct wiphy *wiphy, const char *alpha2)
+/* This currently only processes user and driver regulatory hints */
+static void reg_process_hint(struct regulatory_request *reg_request)
 {
-       int r;
-       BUG_ON(!alpha2);
+       int r = 0;
+       struct wiphy *wiphy = NULL;
+
+       BUG_ON(!reg_request->alpha2);
+
+       mutex_lock(&cfg80211_mutex);
+
+       if (wiphy_idx_valid(reg_request->wiphy_idx))
+               wiphy = wiphy_idx_to_wiphy(reg_request->wiphy_idx);
+
+       if (reg_request->initiator == NL80211_REGDOM_SET_BY_DRIVER &&
+           !wiphy) {
+               kfree(reg_request);
+               goto out;
+       }
 
-       mutex_lock(&cfg80211_drv_mutex);
-       r = __regulatory_hint(wiphy, REGDOM_SET_BY_DRIVER,
-               alpha2, 0, ENVIRON_ANY);
+       r = __regulatory_hint(wiphy, reg_request);
        /* This is required so that the orig_* parameters are saved */
-       if (r == -EALREADY && wiphy->strict_regulatory)
-               wiphy_update_regulatory(wiphy, REGDOM_SET_BY_DRIVER);
-       mutex_unlock(&cfg80211_drv_mutex);
+       if (r == -EALREADY && wiphy && wiphy->strict_regulatory)
+               wiphy_update_regulatory(wiphy, reg_request->initiator);
+out:
+       mutex_unlock(&cfg80211_mutex);
+}
+
+/* Processes regulatory hints, this is all the NL80211_REGDOM_SET_BY_* */
+static void reg_process_pending_hints(void)
+       {
+       struct regulatory_request *reg_request;
+
+       spin_lock(&reg_requests_lock);
+       while (!list_empty(&reg_requests_list)) {
+               reg_request = list_first_entry(&reg_requests_list,
+                                              struct regulatory_request,
+                                              list);
+               list_del_init(&reg_request->list);
+
+               spin_unlock(&reg_requests_lock);
+               reg_process_hint(reg_request);
+               spin_lock(&reg_requests_lock);
+       }
+       spin_unlock(&reg_requests_lock);
+}
+
+/* Processes beacon hints -- this has nothing to do with country IEs */
+static void reg_process_pending_beacon_hints(void)
+{
+       struct cfg80211_registered_device *drv;
+       struct reg_beacon *pending_beacon, *tmp;
+
+       mutex_lock(&cfg80211_mutex);
+
+       /* This goes through the _pending_ beacon list */
+       spin_lock_bh(&reg_pending_beacons_lock);
+
+       if (list_empty(&reg_pending_beacons)) {
+               spin_unlock_bh(&reg_pending_beacons_lock);
+               goto out;
+       }
+
+       list_for_each_entry_safe(pending_beacon, tmp,
+                                &reg_pending_beacons, list) {
+
+               list_del_init(&pending_beacon->list);
+
+               /* Applies the beacon hint to current wiphys */
+               list_for_each_entry(drv, &cfg80211_drv_list, list)
+                       wiphy_update_new_beacon(&drv->wiphy, pending_beacon);
+
+               /* Remembers the beacon hint for new wiphys or reg changes */
+               list_add_tail(&pending_beacon->list, &reg_beacon_list);
+       }
+
+       spin_unlock_bh(&reg_pending_beacons_lock);
+out:
+       mutex_unlock(&cfg80211_mutex);
+}
+
+static void reg_todo(struct work_struct *work)
+{
+       reg_process_pending_hints();
+       reg_process_pending_beacon_hints();
+}
+
+static DECLARE_WORK(reg_work, reg_todo);
+
+static void queue_regulatory_request(struct regulatory_request *request)
+{
+       spin_lock(&reg_requests_lock);
+       list_add_tail(&request->list, &reg_requests_list);
+       spin_unlock(&reg_requests_lock);
+
+       schedule_work(&reg_work);
+}
+
+/* Core regulatory hint -- happens once during cfg80211_init() */
+static int regulatory_hint_core(const char *alpha2)
+{
+       struct regulatory_request *request;
+
+       BUG_ON(last_request);
+
+       request = kzalloc(sizeof(struct regulatory_request),
+                         GFP_KERNEL);
+       if (!request)
+               return -ENOMEM;
+
+       request->alpha2[0] = alpha2[0];
+       request->alpha2[1] = alpha2[1];
+       request->initiator = NL80211_REGDOM_SET_BY_CORE;
+
+       queue_regulatory_request(request);
+
+       return 0;
+}
+
+/* User hints */
+int regulatory_hint_user(const char *alpha2)
+{
+       struct regulatory_request *request;
+
+       BUG_ON(!alpha2);
+
+       request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
+       if (!request)
+               return -ENOMEM;
+
+       request->wiphy_idx = WIPHY_IDX_STALE;
+       request->alpha2[0] = alpha2[0];
+       request->alpha2[1] = alpha2[1];
+       request->initiator = NL80211_REGDOM_SET_BY_USER,
+
+       queue_regulatory_request(request);
+
+       return 0;
+}
+
+/* Driver hints */
+int regulatory_hint(struct wiphy *wiphy, const char *alpha2)
+{
+       struct regulatory_request *request;
+
+       BUG_ON(!alpha2);
+       BUG_ON(!wiphy);
+
+       request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
+       if (!request)
+               return -ENOMEM;
+
+       request->wiphy_idx = get_wiphy_idx(wiphy);
+
+       /* Must have registered wiphy first */
+       BUG_ON(!wiphy_idx_valid(request->wiphy_idx));
+
+       request->alpha2[0] = alpha2[0];
+       request->alpha2[1] = alpha2[1];
+       request->initiator = NL80211_REGDOM_SET_BY_DRIVER;
+
+       queue_regulatory_request(request);
+
+       return 0;
 }
 EXPORT_SYMBOL(regulatory_hint);
 
 static bool reg_same_country_ie_hint(struct wiphy *wiphy,
                        u32 country_ie_checksum)
 {
-       if (!last_request->wiphy)
+       struct wiphy *request_wiphy;
+
+       assert_cfg80211_lock();
+
+       request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
+
+       if (!request_wiphy)
                return false;
-       if (likely(last_request->wiphy != wiphy))
+
+       if (likely(request_wiphy != wiphy))
                return !country_ie_integrity_changes(country_ie_checksum);
-       /* We should not have let these through at this point, they
+       /*
+        * We should not have let these through at this point, they
         * should have been picked up earlier by the first alpha2 check
-        * on the device */
+        * on the device
+        */
        if (WARN_ON(!country_ie_integrity_changes(country_ie_checksum)))
                return true;
        return false;
@@ -1221,11 +1626,14 @@ void regulatory_hint_11d(struct wiphy *wiphy,
        char alpha2[2];
        u32 checksum = 0;
        enum environment_cap env = ENVIRON_ANY;
+       struct regulatory_request *request;
 
-       if (!last_request)
-               return;
+       mutex_lock(&cfg80211_mutex);
 
-       mutex_lock(&cfg80211_drv_mutex);
+       if (unlikely(!last_request)) {
+               mutex_unlock(&cfg80211_mutex);
+               return;
+       }
 
        /* IE len must be evenly divisible by 2 */
        if (country_ie_len & 0x01)
@@ -1234,9 +1642,11 @@ void regulatory_hint_11d(struct wiphy *wiphy,
        if (country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
                goto out;
 
-       /* Pending country IE processing, this can happen after we
+       /*
+        * Pending country IE processing, this can happen after we
         * call CRDA and wait for a response if a beacon was received before
-        * we were able to process the last regulatory_hint_11d() call */
+        * we were able to process the last regulatory_hint_11d() call
+        */
        if (country_ie_regdomain)
                goto out;
 
@@ -1248,33 +1658,44 @@ void regulatory_hint_11d(struct wiphy *wiphy,
        else if (country_ie[2] == 'O')
                env = ENVIRON_OUTDOOR;
 
-       /* We will run this for *every* beacon processed for the BSSID, so
+       /*
+        * We will run this for *every* beacon processed for the BSSID, so
         * we optimize an early check to exit out early if we don't have to
-        * do anything */
-       if (likely(last_request->wiphy)) {
+        * do anything
+        */
+       if (likely(wiphy_idx_valid(last_request->wiphy_idx))) {
                struct cfg80211_registered_device *drv_last_ie;
 
-               drv_last_ie = wiphy_to_dev(last_request->wiphy);
+               drv_last_ie =
+                       cfg80211_drv_by_wiphy_idx(last_request->wiphy_idx);
 
-               /* Lets keep this simple -- we trust the first AP
-                * after we intersect with CRDA */
-               if (likely(last_request->wiphy == wiphy)) {
-                       /* Ignore IEs coming in on this wiphy with
-                        * the same alpha2 and environment cap */
+               /*
+                * Lets keep this simple -- we trust the first AP
+                * after we intersect with CRDA
+                */
+               if (likely(&drv_last_ie->wiphy == wiphy)) {
+                       /*
+                        * Ignore IEs coming in on this wiphy with
+                        * the same alpha2 and environment cap
+                        */
                        if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,
                                  alpha2) &&
                                  env == drv_last_ie->env)) {
                                goto out;
                        }
-                       /* the wiphy moved on to another BSSID or the AP
+                       /*
+                        * the wiphy moved on to another BSSID or the AP
                         * was reconfigured. XXX: We need to deal with the
                         * case where the user suspends and goes to goes
                         * to another country, and then gets IEs from an
-                        * AP with different settings */
+                        * AP with different settings
+                        */
                        goto out;
                } else {
-                       /* Ignore IEs coming in on two separate wiphys with
-                        * the same alpha2 and environment cap */
+                       /*
+                        * Ignore IEs coming in on two separate wiphys with
+                        * the same alpha2 and environment cap
+                        */
                        if (likely(alpha2_equal(drv_last_ie->country_ie_alpha2,
                                  alpha2) &&
                                  env == drv_last_ie->env)) {
@@ -1289,28 +1710,97 @@ void regulatory_hint_11d(struct wiphy *wiphy,
        if (!rd)
                goto out;
 
-       /* This will not happen right now but we leave it here for the
+       /*
+        * This will not happen right now but we leave it here for the
         * the future when we want to add suspend/resume support and having
         * the user move to another country after doing so, or having the user
-        * move to another AP. Right now we just trust the first AP. This is why
-        * this is marked as likley(). If we hit this before we add this support
-        * we want to be informed of it as it would indicate a mistake in the
-        * current design  */
-       if (likely(WARN_ON(reg_same_country_ie_hint(wiphy, checksum))))
-               goto out;
+        * move to another AP. Right now we just trust the first AP.
+        *
+        * If we hit this before we add this support we want to be informed of
+        * it as it would indicate a mistake in the current design
+        */
+       if (WARN_ON(reg_same_country_ie_hint(wiphy, checksum)))
+               goto free_rd_out;
+
+       request = kzalloc(sizeof(struct regulatory_request), GFP_KERNEL);
+       if (!request)
+               goto free_rd_out;
 
-       /* We keep this around for when CRDA comes back with a response so
-        * we can intersect with that */
+       /*
+        * We keep this around for when CRDA comes back with a response so
+        * we can intersect with that
+        */
        country_ie_regdomain = rd;
 
-       __regulatory_hint(wiphy, REGDOM_SET_BY_COUNTRY_IE,
-               country_ie_regdomain->alpha2, checksum, env);
+       request->wiphy_idx = get_wiphy_idx(wiphy);
+       request->alpha2[0] = rd->alpha2[0];
+       request->alpha2[1] = rd->alpha2[1];
+       request->initiator = NL80211_REGDOM_SET_BY_COUNTRY_IE;
+       request->country_ie_checksum = checksum;
+       request->country_ie_env = env;
 
+       mutex_unlock(&cfg80211_mutex);
+
+       queue_regulatory_request(request);
+
+       return;
+
+free_rd_out:
+       kfree(rd);
 out:
-       mutex_unlock(&cfg80211_drv_mutex);
+       mutex_unlock(&cfg80211_mutex);
 }
 EXPORT_SYMBOL(regulatory_hint_11d);
 
+static bool freq_is_chan_12_13_14(u16 freq)
+{
+       if (freq == ieee80211_channel_to_frequency(12) ||
+           freq == ieee80211_channel_to_frequency(13) ||
+           freq == ieee80211_channel_to_frequency(14))
+               return true;
+       return false;
+}
+
+int regulatory_hint_found_beacon(struct wiphy *wiphy,
+                                struct ieee80211_channel *beacon_chan,
+                                gfp_t gfp)
+{
+       struct reg_beacon *reg_beacon;
+
+       if (likely((beacon_chan->beacon_found ||
+           (beacon_chan->flags & IEEE80211_CHAN_RADAR) ||
+           (beacon_chan->band == IEEE80211_BAND_2GHZ &&
+            !freq_is_chan_12_13_14(beacon_chan->center_freq)))))
+               return 0;
+
+       reg_beacon = kzalloc(sizeof(struct reg_beacon), gfp);
+       if (!reg_beacon)
+               return -ENOMEM;
+
+#ifdef CONFIG_CFG80211_REG_DEBUG
+       printk(KERN_DEBUG "cfg80211: Found new beacon on "
+               "frequency: %d MHz (Ch %d) on %s\n",
+               beacon_chan->center_freq,
+               ieee80211_frequency_to_channel(beacon_chan->center_freq),
+               wiphy_name(wiphy));
+#endif
+       memcpy(&reg_beacon->chan, beacon_chan,
+               sizeof(struct ieee80211_channel));
+
+
+       /*
+        * Since we can be called from BH or and non-BH context
+        * we must use spin_lock_bh()
+        */
+       spin_lock_bh(&reg_pending_beacons_lock);
+       list_add_tail(&reg_beacon->list, &reg_pending_beacons);
+       spin_unlock_bh(&reg_pending_beacons_lock);
+
+       schedule_work(&reg_work);
+
+       return 0;
+}
+
 static void print_rd_rules(const struct ieee80211_regdomain *rd)
 {
        unsigned int i;
@@ -1326,8 +1816,10 @@ static void print_rd_rules(const struct ieee80211_regdomain *rd)
                freq_range = &reg_rule->freq_range;
                power_rule = &reg_rule->power_rule;
 
-               /* There may not be documentation for max antenna gain
-                * in certain regions */
+               /*
+                * There may not be documentation for max antenna gain
+                * in certain regions
+                */
                if (power_rule->max_antenna_gain)
                        printk(KERN_INFO "\t(%d KHz - %d KHz @ %d KHz), "
                                "(%d mBi, %d mBm)\n",
@@ -1350,13 +1842,13 @@ static void print_regdomain(const struct ieee80211_regdomain *rd)
 {
 
        if (is_intersected_alpha2(rd->alpha2)) {
-               struct wiphy *wiphy = NULL;
-               struct cfg80211_registered_device *drv;
 
-               if (last_request->initiator == REGDOM_SET_BY_COUNTRY_IE) {
-                       if (last_request->wiphy) {
-                               wiphy = last_request->wiphy;
-                               drv = wiphy_to_dev(wiphy);
+               if (last_request->initiator ==
+                   NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+                       struct cfg80211_registered_device *drv;
+                       drv = cfg80211_drv_by_wiphy_idx(
+                               last_request->wiphy_idx);
+                       if (drv) {
                                printk(KERN_INFO "cfg80211: Current regulatory "
                                        "domain updated by AP to: %c%c\n",
                                        drv->country_ie_alpha2[0],
@@ -1422,7 +1914,7 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 {
        const struct ieee80211_regdomain *intersected_rd = NULL;
        struct cfg80211_registered_device *drv = NULL;
-       struct wiphy *wiphy = NULL;
+       struct wiphy *request_wiphy;
        /* Some basic sanity checks first */
 
        if (is_world_regdom(rd->alpha2)) {
@@ -1439,23 +1931,27 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
        if (!last_request)
                return -EINVAL;
 
-       /* Lets only bother proceeding on the same alpha2 if the current
+       /*
+        * Lets only bother proceeding on the same alpha2 if the current
         * rd is non static (it means CRDA was present and was used last)
-        * and the pending request came in from a country IE */
-       if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) {
-               /* If someone else asked us to change the rd lets only bother
-                * checking if the alpha2 changes if CRDA was already called */
+        * and the pending request came in from a country IE
+        */
+       if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
+               /*
+                * If someone else asked us to change the rd lets only bother
+                * checking if the alpha2 changes if CRDA was already called
+                */
                if (!is_old_static_regdom(cfg80211_regdomain) &&
-                   !regdom_changed(rd->alpha2))
+                   !regdom_changes(rd->alpha2))
                        return -EINVAL;
        }
 
-       wiphy = last_request->wiphy;
-
-       /* Now lets set the regulatory domain, update all driver channels
+       /*
+        * Now lets set the regulatory domain, update all driver channels
         * and finally inform them of what we have done, in case they want
         * to review or adjust their own settings based on their own
-        * internal EEPROM data */
+        * internal EEPROM data
+        */
 
        if (WARN_ON(!reg_is_valid_request(rd->alpha2)))
                return -EINVAL;
@@ -1467,21 +1963,25 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
                return -EINVAL;
        }
 
+       request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
+
        if (!last_request->intersect) {
                int r;
 
-               if (last_request->initiator != REGDOM_SET_BY_DRIVER) {
+               if (last_request->initiator != NL80211_REGDOM_SET_BY_DRIVER) {
                        reset_regdomains();
                        cfg80211_regdomain = rd;
                        return 0;
                }
 
-               /* For a driver hint, lets copy the regulatory domain the
-                * driver wanted to the wiphy to deal with conflicts */
+               /*
+                * For a driver hint, lets copy the regulatory domain the
+                * driver wanted to the wiphy to deal with conflicts
+                */
 
-               BUG_ON(last_request->wiphy->regd);
+               BUG_ON(request_wiphy->regd);
 
-               r = reg_copy_regd(&last_request->wiphy->regd, rd);
+               r = reg_copy_regd(&request_wiphy->regd, rd);
                if (r)
                        return r;
 
@@ -1492,17 +1992,19 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 
        /* Intersection requires a bit more work */
 
-       if (last_request->initiator != REGDOM_SET_BY_COUNTRY_IE) {
+       if (last_request->initiator != NL80211_REGDOM_SET_BY_COUNTRY_IE) {
 
                intersected_rd = regdom_intersect(rd, cfg80211_regdomain);
                if (!intersected_rd)
                        return -EINVAL;
 
-               /* We can trash what CRDA provided now.
+               /*
+                * We can trash what CRDA provided now.
                 * However if a driver requested this specific regulatory
-                * domain we keep it for its private use */
-               if (last_request->initiator == REGDOM_SET_BY_DRIVER)
-                       last_request->wiphy->regd = rd;
+                * domain we keep it for its private use
+                */
+               if (last_request->initiator == NL80211_REGDOM_SET_BY_DRIVER)
+                       request_wiphy->regd = rd;
                else
                        kfree(rd);
 
@@ -1522,8 +2024,10 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
        BUG_ON(!country_ie_regdomain);
 
        if (rd != country_ie_regdomain) {
-               /* Intersect what CRDA returned and our what we
-                * had built from the Country IE received */
+               /*
+                * Intersect what CRDA returned and our what we
+                * had built from the Country IE received
+                */
 
                intersected_rd = regdom_intersect(rd, country_ie_regdomain);
 
@@ -1533,16 +2037,18 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
                kfree(country_ie_regdomain);
                country_ie_regdomain = NULL;
        } else {
-               /* This would happen when CRDA was not present and
+               /*
+                * This would happen when CRDA was not present and
                 * OLD_REGULATORY was enabled. We intersect our Country
-                * IE rd and what was set on cfg80211 originally */
+                * IE rd and what was set on cfg80211 originally
+                */
                intersected_rd = regdom_intersect(rd, cfg80211_regdomain);
        }
 
        if (!intersected_rd)
                return -EINVAL;
 
-       drv = wiphy_to_dev(wiphy);
+       drv = wiphy_to_dev(request_wiphy);
 
        drv->country_ie_alpha2[0] = rd->alpha2[0];
        drv->country_ie_alpha2[1] = rd->alpha2[1];
@@ -1560,13 +2066,17 @@ static int __set_regdom(const struct ieee80211_regdomain *rd)
 }
 
 
-/* Use this call to set the current regulatory domain. Conflicts with
+/*
+ * Use this call to set the current regulatory domain. Conflicts with
  * multiple drivers can be ironed out later. Caller must've already
- * kmalloc'd the rd structure. Caller must hold cfg80211_drv_mutex */
+ * kmalloc'd the rd structure. Caller must hold cfg80211_mutex
+ */
 int set_regdom(const struct ieee80211_regdomain *rd)
 {
        int r;
 
+       assert_cfg80211_lock();
+
        /* Note that this doesn't update the wiphys, this is done below */
        r = __set_regdom(rd);
        if (r) {
@@ -1583,57 +2093,87 @@ int set_regdom(const struct ieee80211_regdomain *rd)
 
        print_regdomain(cfg80211_regdomain);
 
+       nl80211_send_reg_change_event(last_request);
+
        return r;
 }
 
-/* Caller must hold cfg80211_drv_mutex */
+/* Caller must hold cfg80211_mutex */
 void reg_device_remove(struct wiphy *wiphy)
 {
+       struct wiphy *request_wiphy;
+
+       assert_cfg80211_lock();
+
+       request_wiphy = wiphy_idx_to_wiphy(last_request->wiphy_idx);
+
        kfree(wiphy->regd);
-       if (!last_request || !last_request->wiphy)
+       if (!last_request || !request_wiphy)
                return;
-       if (last_request->wiphy != wiphy)
+       if (request_wiphy != wiphy)
                return;
-       last_request->wiphy = NULL;
+       last_request->wiphy_idx = WIPHY_IDX_STALE;
        last_request->country_ie_env = ENVIRON_ANY;
 }
 
 int regulatory_init(void)
 {
-       int err;
+       int err = 0;
 
        reg_pdev = platform_device_register_simple("regulatory", 0, NULL, 0);
        if (IS_ERR(reg_pdev))
                return PTR_ERR(reg_pdev);
 
+       spin_lock_init(&reg_requests_lock);
+       spin_lock_init(&reg_pending_beacons_lock);
+
 #ifdef CONFIG_WIRELESS_OLD_REGULATORY
        cfg80211_regdomain = static_regdom(ieee80211_regdom);
 
        printk(KERN_INFO "cfg80211: Using static regulatory domain info\n");
        print_regdomain_info(cfg80211_regdomain);
-       /* The old code still requests for a new regdomain and if
+       /*
+        * The old code still requests for a new regdomain and if
         * you have CRDA you get it updated, otherwise you get
         * stuck with the static values. We ignore "EU" code as
-        * that is not a valid ISO / IEC 3166 alpha2 */
+        * that is not a valid ISO / IEC 3166 alpha2
+        */
        if (ieee80211_regdom[0] != 'E' || ieee80211_regdom[1] != 'U')
-               err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE,
-                                       ieee80211_regdom, 0, ENVIRON_ANY);
+               err = regulatory_hint_core(ieee80211_regdom);
 #else
        cfg80211_regdomain = cfg80211_world_regdom;
 
-       err = __regulatory_hint(NULL, REGDOM_SET_BY_CORE, "00", 0, ENVIRON_ANY);
-       if (err)
-               printk(KERN_ERR "cfg80211: calling CRDA failed - "
-                      "unable to update world regulatory domain, "
-                      "using static definition\n");
+       err = regulatory_hint_core("00");
 #endif
+       if (err) {
+               if (err == -ENOMEM)
+                       return err;
+               /*
+                * N.B. kobject_uevent_env() can fail mainly for when we're out
+                * memory which is handled and propagated appropriately above
+                * but it can also fail during a netlink_broadcast() or during
+                * early boot for call_usermodehelper(). For now treat these
+                * errors as non-fatal.
+                */
+               printk(KERN_ERR "cfg80211: kobject_uevent_env() was unable "
+                       "to call CRDA during init");
+#ifdef CONFIG_CFG80211_REG_DEBUG
+               /* We want to find out exactly why when debugging */
+               WARN_ON(err);
+#endif
+       }
 
        return 0;
 }
 
 void regulatory_exit(void)
 {
-       mutex_lock(&cfg80211_drv_mutex);
+       struct regulatory_request *reg_request, *tmp;
+       struct reg_beacon *reg_beacon, *btmp;
+
+       cancel_work_sync(&reg_work);
+
+       mutex_lock(&cfg80211_mutex);
 
        reset_regdomains();
 
@@ -1644,5 +2184,33 @@ void regulatory_exit(void)
 
        platform_device_unregister(reg_pdev);
 
-       mutex_unlock(&cfg80211_drv_mutex);
+       spin_lock_bh(&reg_pending_beacons_lock);
+       if (!list_empty(&reg_pending_beacons)) {
+               list_for_each_entry_safe(reg_beacon, btmp,
+                                        &reg_pending_beacons, list) {
+                       list_del(&reg_beacon->list);
+                       kfree(reg_beacon);
+               }
+       }
+       spin_unlock_bh(&reg_pending_beacons_lock);
+
+       if (!list_empty(&reg_beacon_list)) {
+               list_for_each_entry_safe(reg_beacon, btmp,
+                                        &reg_beacon_list, list) {
+                       list_del(&reg_beacon->list);
+                       kfree(reg_beacon);
+               }
+       }
+
+       spin_lock(&reg_requests_lock);
+       if (!list_empty(&reg_requests_list)) {
+               list_for_each_entry_safe(reg_request, tmp,
+                                        &reg_requests_list, list) {
+                       list_del(&reg_request->list);
+                       kfree(reg_request);
+               }
+       }
+       spin_unlock(&reg_requests_lock);
+
+       mutex_unlock(&cfg80211_mutex);
 }
index fe8c83f34fb7e8465c9dc8d0804bb04aa58ef928..e37829a49dc466fad9a6aff92361afcc26371ad7 100644 (file)
@@ -6,6 +6,8 @@ extern const struct ieee80211_regdomain *cfg80211_regdomain;
 bool is_world_regdom(const char *alpha2);
 bool reg_is_valid_request(const char *alpha2);
 
+int regulatory_hint_user(const char *alpha2);
+
 void reg_device_remove(struct wiphy *wiphy);
 
 int regulatory_init(void);
@@ -14,26 +16,24 @@ void regulatory_exit(void);
 int set_regdom(const struct ieee80211_regdomain *rd);
 
 /**
- * __regulatory_hint - hint to the wireless core a regulatory domain
- * @wiphy: if the hint comes from country information from an AP, this
- *     is required to be set to the wiphy that received the information
- * @alpha2: the ISO/IEC 3166 alpha2 being claimed the regulatory domain
- *     should be in.
- * @country_ie_checksum: checksum of processed country IE, set this to 0
- *     if the hint did not come from a country IE
- * @country_ie_env: the environment the IE told us we are in, %ENVIRON_*
- *
- * The Wireless subsystem can use this function to hint to the wireless core
- * what it believes should be the current regulatory domain by giving it an
- * ISO/IEC 3166 alpha2 country code it knows its regulatory domain should be
- * in.
+ * regulatory_hint_found_beacon - hints a beacon was found on a channel
+ * @wiphy: the wireless device where the beacon was found on
+ * @beacon_chan: the channel on which the beacon was found on
+ * @gfp: context flags
  *
- * Returns zero if all went fine, %-EALREADY if a regulatory domain had
- * already been set or other standard error codes.
+ * This informs the wireless core that a beacon from an AP was found on
+ * the channel provided. This allows the wireless core to make educated
+ * guesses on regulatory to help with world roaming. This is only used for
+ * world roaming -- when we do not know our current location. This is
+ * only useful on channels 12, 13 and 14 on the 2 GHz band as channels
+ * 1-11 are already enabled by the world regulatory domain; and on
+ * non-radar 5 GHz channels.
  *
+ * Drivers do not need to call this, cfg80211 will do it for after a scan
+ * on a newly found BSS.
  */
-extern int __regulatory_hint(struct wiphy *wiphy, enum reg_set_by set_by,
-                            const char *alpha2, u32 country_ie_checksum,
-                            enum environment_cap country_ie_env);
+int regulatory_hint_found_beacon(struct wiphy *wiphy,
+                                       struct ieee80211_channel *beacon_chan,
+                                       gfp_t gfp);
 
 #endif  /* __NET_WIRELESS_REG_H */
index b1893c863b976188970877907edf8b4eeb12449b..280dbcd02c1563e7e56df72dd2e7a771fc8563c9 100644 (file)
@@ -61,6 +61,18 @@ static void bss_release(struct kref *ref)
        kfree(bss);
 }
 
+/* must hold dev->bss_lock! */
+void cfg80211_bss_age(struct cfg80211_registered_device *dev,
+                      unsigned long age_secs)
+{
+       struct cfg80211_internal_bss *bss;
+       unsigned long age_jiffies = msecs_to_jiffies(age_secs * MSEC_PER_SEC);
+
+       list_for_each_entry(bss, &dev->bss_list, list) {
+               bss->ts -= age_jiffies;
+       }
+}
+
 /* must hold dev->bss_lock! */
 void cfg80211_bss_expire(struct cfg80211_registered_device *dev)
 {
@@ -358,7 +370,6 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
                found->pub.beacon_interval = res->pub.beacon_interval;
                found->pub.tsf = res->pub.tsf;
                found->pub.signal = res->pub.signal;
-               found->pub.signal_type = res->pub.signal_type;
                found->pub.capability = res->pub.capability;
                found->ts = res->ts;
                kref_put(&res->ref, bss_release);
@@ -380,8 +391,7 @@ struct cfg80211_bss *
 cfg80211_inform_bss_frame(struct wiphy *wiphy,
                          struct ieee80211_channel *channel,
                          struct ieee80211_mgmt *mgmt, size_t len,
-                         s32 signal, enum cfg80211_signal_type sigtype,
-                         gfp_t gfp)
+                         s32 signal, gfp_t gfp)
 {
        struct cfg80211_internal_bss *res;
        size_t ielen = len - offsetof(struct ieee80211_mgmt,
@@ -389,7 +399,7 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
        bool overwrite;
        size_t privsz = wiphy->bss_priv_size;
 
-       if (WARN_ON(sigtype == NL80211_BSS_SIGNAL_UNSPEC &&
+       if (WARN_ON(wiphy->signal_type == NL80211_BSS_SIGNAL_UNSPEC &&
                    (signal < 0 || signal > 100)))
                return NULL;
 
@@ -403,7 +413,6 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
 
        memcpy(res->pub.bssid, mgmt->bssid, ETH_ALEN);
        res->pub.channel = channel;
-       res->pub.signal_type = sigtype;
        res->pub.signal = signal;
        res->pub.tsf = le64_to_cpu(mgmt->u.probe_resp.timestamp);
        res->pub.beacon_interval = le16_to_cpu(mgmt->u.probe_resp.beacon_int);
@@ -421,6 +430,9 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
        if (!res)
                return NULL;
 
+       if (res->pub.capability & WLAN_CAPABILITY_ESS)
+               regulatory_hint_found_beacon(wiphy, channel, gfp);
+
        /* cfg80211_bss_update gives us a referenced result */
        return &res->pub;
 }
@@ -584,16 +596,25 @@ static void ieee80211_scan_add_ies(struct iw_request_info *info,
        }
 }
 
+static inline unsigned int elapsed_jiffies_msecs(unsigned long start)
+{
+       unsigned long end = jiffies;
+
+       if (end >= start)
+               return jiffies_to_msecs(end - start);
+
+       return jiffies_to_msecs(end + (MAX_JIFFY_OFFSET - start) + 1);
+}
 
 static char *
-ieee80211_bss(struct iw_request_info *info,
-                     struct cfg80211_internal_bss *bss,
-                     char *current_ev, char *end_buf)
+ieee80211_bss(struct wiphy *wiphy, struct iw_request_info *info,
+             struct cfg80211_internal_bss *bss, char *current_ev,
+             char *end_buf)
 {
        struct iw_event iwe;
        u8 *buf, *cfg, *p;
        u8 *ie = bss->pub.information_elements;
-       int rem = bss->pub.len_information_elements, i;
+       int rem = bss->pub.len_information_elements, i, sig;
        bool ismesh = false;
 
        memset(&iwe, 0, sizeof(iwe));
@@ -617,19 +638,28 @@ ieee80211_bss(struct iw_request_info *info,
        current_ev = iwe_stream_add_event(info, current_ev, end_buf, &iwe,
                                          IW_EV_FREQ_LEN);
 
-       if (bss->pub.signal_type != CFG80211_SIGNAL_TYPE_NONE) {
+       if (wiphy->signal_type != CFG80211_SIGNAL_TYPE_NONE) {
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVQUAL;
                iwe.u.qual.updated = IW_QUAL_LEVEL_UPDATED |
                                     IW_QUAL_NOISE_INVALID |
-                                    IW_QUAL_QUAL_INVALID;
-               switch (bss->pub.signal_type) {
+                                    IW_QUAL_QUAL_UPDATED;
+               switch (wiphy->signal_type) {
                case CFG80211_SIGNAL_TYPE_MBM:
-                       iwe.u.qual.level = bss->pub.signal / 100;
+                       sig = bss->pub.signal / 100;
+                       iwe.u.qual.level = sig;
                        iwe.u.qual.updated |= IW_QUAL_DBM;
+                       if (sig < -110)         /* rather bad */
+                               sig = -110;
+                       else if (sig > -40)     /* perfect */
+                               sig = -40;
+                       /* will give a range of 0 .. 70 */
+                       iwe.u.qual.qual = sig + 110;
                        break;
                case CFG80211_SIGNAL_TYPE_UNSPEC:
                        iwe.u.qual.level = bss->pub.signal;
+                       /* will give range 0 .. 100 */
+                       iwe.u.qual.qual = bss->pub.signal;
                        break;
                default:
                        /* not reached */
@@ -763,8 +793,8 @@ ieee80211_bss(struct iw_request_info *info,
                                                  &iwe, buf);
                memset(&iwe, 0, sizeof(iwe));
                iwe.cmd = IWEVCUSTOM;
-               sprintf(buf, " Last beacon: %dms ago",
-                       jiffies_to_msecs(jiffies - bss->ts));
+               sprintf(buf, " Last beacon: %ums ago",
+                       elapsed_jiffies_msecs(bss->ts));
                iwe.u.data.length = strlen(buf);
                current_ev = iwe_stream_add_point(info, current_ev,
                                                  end_buf, &iwe, buf);
@@ -793,8 +823,8 @@ static int ieee80211_scan_results(struct cfg80211_registered_device *dev,
                        spin_unlock_bh(&dev->bss_lock);
                        return -E2BIG;
                }
-               current_ev = ieee80211_bss(info, bss,
-                                                  current_ev, end_buf);
+               current_ev = ieee80211_bss(&dev->wiphy, info, bss,
+                                          current_ev, end_buf);
        }
        spin_unlock_bh(&dev->bss_lock);
        return current_ev - buf;
index 26a72b0797a09e5c6c2ff4595dab1309d007c627..efe3c5c92b2dedbb48271d89d1664cd57cf182cf 100644 (file)
@@ -31,7 +31,7 @@ static ssize_t name ## _show(struct device *dev,                      \
        return sprintf(buf, fmt "\n", dev_to_rdev(dev)->member);        \
 }
 
-SHOW_FMT(index, "%d", idx);
+SHOW_FMT(index, "%d", wiphy_idx);
 SHOW_FMT(macaddress, "%pM", wiphy.perm_addr);
 
 static struct device_attribute ieee80211_dev_attrs[] = {
@@ -60,6 +60,8 @@ static int wiphy_suspend(struct device *dev, pm_message_t state)
        struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
        int ret = 0;
 
+       rdev->suspend_at = get_seconds();
+
        if (rdev->ops->suspend) {
                rtnl_lock();
                ret = rdev->ops->suspend(&rdev->wiphy);
@@ -74,6 +76,11 @@ static int wiphy_resume(struct device *dev)
        struct cfg80211_registered_device *rdev = dev_to_rdev(dev);
        int ret = 0;
 
+       /* Age scan results with time spent in suspend */
+       spin_lock_bh(&rdev->bss_lock);
+       cfg80211_bss_age(rdev, get_seconds() - rdev->suspend_at);
+       spin_unlock_bh(&rdev->bss_lock);
+
        if (rdev->ops->resume) {
                rtnl_lock();
                ret = rdev->ops->resume(&rdev->wiphy);
index 58e489fd4aedf0527241c4c39aa5d20482a6dea2..b84a9b4fe96a79409dc84caf693669c82d3315d0 100644 (file)
@@ -137,3 +137,100 @@ int cfg80211_wext_giwmode(struct net_device *dev, struct iw_request_info *info,
        return 0;
 }
 EXPORT_SYMBOL(cfg80211_wext_giwmode);
+
+
+int cfg80211_wext_giwrange(struct net_device *dev,
+                          struct iw_request_info *info,
+                          struct iw_point *data, char *extra)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct iw_range *range = (struct iw_range *) extra;
+       enum ieee80211_band band;
+       int c = 0;
+
+       if (!wdev)
+               return -EOPNOTSUPP;
+
+       data->length = sizeof(struct iw_range);
+       memset(range, 0, sizeof(struct iw_range));
+
+       range->we_version_compiled = WIRELESS_EXT;
+       range->we_version_source = 21;
+       range->retry_capa = IW_RETRY_LIMIT;
+       range->retry_flags = IW_RETRY_LIMIT;
+       range->min_retry = 0;
+       range->max_retry = 255;
+       range->min_rts = 0;
+       range->max_rts = 2347;
+       range->min_frag = 256;
+       range->max_frag = 2346;
+
+       range->encoding_size[0] = 5;
+       range->encoding_size[1] = 13;
+       range->num_encoding_sizes = 2;
+       range->max_encoding_tokens = 4;
+
+       range->max_qual.updated = IW_QUAL_NOISE_INVALID;
+
+       switch (wdev->wiphy->signal_type) {
+       case CFG80211_SIGNAL_TYPE_NONE:
+               break;
+       case CFG80211_SIGNAL_TYPE_MBM:
+               range->max_qual.level = -110;
+               range->max_qual.qual = 70;
+               range->avg_qual.qual = 35;
+               range->max_qual.updated |= IW_QUAL_DBM;
+               range->max_qual.updated |= IW_QUAL_QUAL_UPDATED;
+               range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED;
+               break;
+       case CFG80211_SIGNAL_TYPE_UNSPEC:
+               range->max_qual.level = 100;
+               range->max_qual.qual = 100;
+               range->avg_qual.qual = 50;
+               range->max_qual.updated |= IW_QUAL_QUAL_UPDATED;
+               range->max_qual.updated |= IW_QUAL_LEVEL_UPDATED;
+               break;
+       }
+
+       range->avg_qual.level = range->max_qual.level / 2;
+       range->avg_qual.noise = range->max_qual.noise / 2;
+       range->avg_qual.updated = range->max_qual.updated;
+
+       range->enc_capa = IW_ENC_CAPA_WPA | IW_ENC_CAPA_WPA2 |
+                         IW_ENC_CAPA_CIPHER_TKIP | IW_ENC_CAPA_CIPHER_CCMP;
+
+
+       for (band = 0; band < IEEE80211_NUM_BANDS; band ++) {
+               int i;
+               struct ieee80211_supported_band *sband;
+
+               sband = wdev->wiphy->bands[band];
+
+               if (!sband)
+                       continue;
+
+               for (i = 0; i < sband->n_channels && c < IW_MAX_FREQUENCIES; i++) {
+                       struct ieee80211_channel *chan = &sband->channels[i];
+
+                       if (!(chan->flags & IEEE80211_CHAN_DISABLED)) {
+                               range->freq[c].i =
+                                       ieee80211_frequency_to_channel(
+                                               chan->center_freq);
+                               range->freq[c].m = chan->center_freq;
+                               range->freq[c].e = 6;
+                               c++;
+                       }
+               }
+       }
+       range->num_channels = c;
+       range->num_frequency = c;
+
+       IW_EVENT_CAPA_SET_KERNEL(range->event_capa);
+       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWAP);
+       IW_EVENT_CAPA_SET(range->event_capa, SIOCGIWSCAN);
+
+       range->scan_capa |= IW_SCAN_CAPA_ESSID;
+
+       return 0;
+}
+EXPORT_SYMBOL(cfg80211_wext_giwrange);
index 8f76f4009c24d3c2c1d596afea65f36317c7d335..9ca17b1ce52e8191f04b401e2f0a1e021062badf 100644 (file)
@@ -951,10 +951,8 @@ int x25_rx_call_request(struct sk_buff *skb, struct x25_neigh *nb,
        /*
         *      Incoming Call User Data.
         */
-       if (skb->len >= 0) {
-               skb_copy_from_linear_data(skb, makex25->calluserdata.cuddata, skb->len);
-               makex25->calluserdata.cudlength = skb->len;
-       }
+       skb_copy_from_linear_data(skb, makex25->calluserdata.cuddata, skb->len);
+       makex25->calluserdata.cudlength = skb->len;
 
        sk->sk_ack_backlog++;
 
@@ -1122,8 +1120,9 @@ static int x25_sendmsg(struct kiocb *iocb, struct socket *sock,
        if (msg->msg_flags & MSG_OOB)
                skb_queue_tail(&x25->interrupt_out_queue, skb);
        else {
-               len = x25_output(sk, skb);
-               if (len < 0)
+               rc = x25_output(sk, skb);
+               len = rc;
+               if (rc < 0)
                        kfree_skb(skb);
                else if (x25->qbitincl)
                        len++;
@@ -1608,7 +1607,7 @@ static const struct proto_ops SOCKOPS_WRAPPED(x25_proto_ops) = {
 
 SOCKOPS_WRAP(x25_proto, AF_X25);
 
-static struct packet_type x25_packet_type = {
+static struct packet_type x25_packet_type __read_mostly = {
        .type = cpu_to_be16(ETH_P_X25),
        .func = x25_lapb_receive_frame,
 };
index e25ff62ab2a62676e239cef57e9a288973d1ed25..62a5425cc6aa1c83a386f2123281d4ccc07c9cdc 100644 (file)
@@ -748,12 +748,51 @@ static void xfrm_hash_grow_check(struct net *net, int have_hash_collision)
                schedule_work(&net->xfrm.state_hash_work);
 }
 
+static void xfrm_state_look_at(struct xfrm_policy *pol, struct xfrm_state *x,
+                              struct flowi *fl, unsigned short family,
+                              xfrm_address_t *daddr, xfrm_address_t *saddr,
+                              struct xfrm_state **best, int *acq_in_progress,
+                              int *error)
+{
+       /* Resolution logic:
+        * 1. There is a valid state with matching selector. Done.
+        * 2. Valid state with inappropriate selector. Skip.
+        *
+        * Entering area of "sysdeps".
+        *
+        * 3. If state is not valid, selector is temporary, it selects
+        *    only session which triggered previous resolution. Key
+        *    manager will do something to install a state with proper
+        *    selector.
+        */
+       if (x->km.state == XFRM_STATE_VALID) {
+               if ((x->sel.family &&
+                    !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
+                   !security_xfrm_state_pol_flow_match(x, pol, fl))
+                       return;
+
+               if (!*best ||
+                   (*best)->km.dying > x->km.dying ||
+                   ((*best)->km.dying == x->km.dying &&
+                    (*best)->curlft.add_time < x->curlft.add_time))
+                       *best = x;
+       } else if (x->km.state == XFRM_STATE_ACQ) {
+               *acq_in_progress = 1;
+       } else if (x->km.state == XFRM_STATE_ERROR ||
+                  x->km.state == XFRM_STATE_EXPIRED) {
+               if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
+                   security_xfrm_state_pol_flow_match(x, pol, fl))
+                       *error = -ESRCH;
+       }
+}
+
 struct xfrm_state *
 xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
                struct flowi *fl, struct xfrm_tmpl *tmpl,
                struct xfrm_policy *pol, int *err,
                unsigned short family)
 {
+       static xfrm_address_t saddr_wildcard = { };
        struct net *net = xp_net(pol);
        unsigned int h;
        struct hlist_node *entry;
@@ -773,40 +812,27 @@ xfrm_state_find(xfrm_address_t *daddr, xfrm_address_t *saddr,
                    xfrm_state_addr_check(x, daddr, saddr, family) &&
                    tmpl->mode == x->props.mode &&
                    tmpl->id.proto == x->id.proto &&
-                   (tmpl->id.spi == x->id.spi || !tmpl->id.spi)) {
-                       /* Resolution logic:
-                          1. There is a valid state with matching selector.
-                             Done.
-                          2. Valid state with inappropriate selector. Skip.
-
-                          Entering area of "sysdeps".
-
-                          3. If state is not valid, selector is temporary,
-                             it selects only session which triggered
-                             previous resolution. Key manager will do
-                             something to install a state with proper
-                             selector.
-                        */
-                       if (x->km.state == XFRM_STATE_VALID) {
-                               if ((x->sel.family && !xfrm_selector_match(&x->sel, fl, x->sel.family)) ||
-                                   !security_xfrm_state_pol_flow_match(x, pol, fl))
-                                       continue;
-                               if (!best ||
-                                   best->km.dying > x->km.dying ||
-                                   (best->km.dying == x->km.dying &&
-                                    best->curlft.add_time < x->curlft.add_time))
-                                       best = x;
-                       } else if (x->km.state == XFRM_STATE_ACQ) {
-                               acquire_in_progress = 1;
-                       } else if (x->km.state == XFRM_STATE_ERROR ||
-                                  x->km.state == XFRM_STATE_EXPIRED) {
-                               if (xfrm_selector_match(&x->sel, fl, x->sel.family) &&
-                                   security_xfrm_state_pol_flow_match(x, pol, fl))
-                                       error = -ESRCH;
-                       }
-               }
+                   (tmpl->id.spi == x->id.spi || !tmpl->id.spi))
+                       xfrm_state_look_at(pol, x, fl, family, daddr, saddr,
+                                          &best, &acquire_in_progress, &error);
+       }
+       if (best)
+               goto found;
+
+       h = xfrm_dst_hash(net, daddr, &saddr_wildcard, tmpl->reqid, family);
+       hlist_for_each_entry(x, entry, net->xfrm.state_bydst+h, bydst) {
+               if (x->props.family == family &&
+                   x->props.reqid == tmpl->reqid &&
+                   !(x->props.flags & XFRM_STATE_WILDRECV) &&
+                   xfrm_state_addr_check(x, daddr, saddr, family) &&
+                   tmpl->mode == x->props.mode &&
+                   tmpl->id.proto == x->id.proto &&
+                   (tmpl->id.spi == x->id.spi || !tmpl->id.spi))
+                       xfrm_state_look_at(pol, x, fl, family, daddr, saddr,
+                                          &best, &acquire_in_progress, &error);
        }
 
+found:
        x = best;
        if (!x && !error && !acquire_in_progress) {
                if (tmpl->id.spi &&
index b0246307aac497ae36b8266180b48a244c9c374d..12caa822a232eeddc0fc97606fc5002a86a4daf7 100644 (file)
@@ -51,7 +51,7 @@ my %pidctr;
 
 while (<>) {
        my $line = $_;
-       if ($line =~ /([0-9\.]+)\] calling  ([a-zA-Z0-9\_]+)\+/) {
+       if ($line =~ /([0-9\.]+)\] calling  ([a-zA-Z0-9\_\.]+)\+/) {
                my $func = $2;
                if ($done == 0) {
                        $start{$func} = $1;
@@ -87,7 +87,7 @@ while (<>) {
                $count = $count + 1;
        }
 
-       if ($line =~ /([0-9\.]+)\] initcall ([a-zA-Z0-9\_]+)\+.*returned/) {
+       if ($line =~ /([0-9\.]+)\] initcall ([a-zA-Z0-9\_\.]+)\+.*returned/) {
                if ($done == 0) {
                        $end{$2} = $1;
                        $maxtime = $1;
index 45eb0ae98ebab2c6a771e1d10bfbb10df9231823..2d5ece798c4c6e786b3e6ee305e9830e490d75e9 100755 (executable)
@@ -10,7 +10,7 @@ use strict;
 my $P = $0;
 $P =~ s@.*/@@g;
 
-my $V = '0.27';
+my $V = '0.28';
 
 use Getopt::Long qw(:config no_auto_abbrev);
 
@@ -110,7 +110,8 @@ our $Sparse = qr{
                        __iomem|
                        __must_check|
                        __init_refok|
-                       __kprobes
+                       __kprobes|
+                       __ref
                }x;
 our $Attribute = qr{
                        const|
@@ -1240,7 +1241,8 @@ sub process {
                        $realfile =~ s@^([^/]*)/@@;
 
                        $p1_prefix = $1;
-                       if ($tree && $p1_prefix ne '' && -e "$root/$p1_prefix") {
+                       if (!$file && $tree && $p1_prefix ne '' &&
+                           -e "$root/$p1_prefix") {
                                WARN("patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n");
                        }
 
@@ -1583,9 +1585,9 @@ sub process {
                }
 # TEST: allow direct testing of the attribute matcher.
                if ($dbg_attr) {
-                       if ($line =~ /^.\s*$Attribute\s*$/) {
+                       if ($line =~ /^.\s*$Modifier\s*$/) {
                                ERROR("TEST: is attr\n" . $herecurr);
-                       } elsif ($dbg_attr > 1 && $line =~ /^.+($Attribute)/) {
+                       } elsif ($dbg_attr > 1 && $line =~ /^.+($Modifier)/) {
                                ERROR("TEST: is not attr ($1 is)\n". $herecurr);
                        }
                        next;
@@ -1657,7 +1659,7 @@ sub process {
 
 # * goes on variable not on type
                # (char*[ const])
-               if ($line =~ m{\($NonptrType(\s*\*[\s\*]*(?:$Modifier\s*)*)\)}) {
+               if ($line =~ m{\($NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)\)}) {
                        my ($from, $to) = ($1, $1);
 
                        # Should start with a space.
@@ -1672,7 +1674,7 @@ sub process {
                        if ($from ne $to) {
                                ERROR("\"(foo$from)\" should be \"(foo$to)\"\n" .  $herecurr);
                        }
-               } elsif ($line =~ m{\b$NonptrType(\s*\*[\s\*]*(?:$Modifier\s*)?)($Ident)}) {
+               } elsif ($line =~ m{\b$NonptrType(\s*(?:$Modifier\b\s*|\*\s*)+)($Ident)}) {
                        my ($from, $to, $ident) = ($1, $1, $2);
 
                        # Should start with a space.
@@ -1685,8 +1687,8 @@ sub process {
                        # Modifiers should have spaces.
                        $to =~ s/(\b$Modifier$)/$1 /;
 
-                       #print "from<$from> to<$to>\n";
-                       if ($from ne $to) {
+                       #print "from<$from> to<$to> ident<$ident>\n";
+                       if ($from ne $to && $ident !~ /^$Modifier$/) {
                                ERROR("\"foo${from}bar\" should be \"foo${to}bar\"\n" .  $herecurr);
                        }
                }
@@ -1885,11 +1887,11 @@ sub process {
                                        if ($ctx !~ /[WEBC]x./ && $ca !~ /(?:\)|!|~|\*|-|\&|\||\+\+|\-\-|\{)$/) {
                                                ERROR("space required before that '$op' $at\n" . $hereptr);
                                        }
-                                       if ($op eq '*' && $cc =~/\s*const\b/) {
+                                       if ($op eq '*' && $cc =~/\s*$Modifier\b/) {
                                                # A unary '*' may be const
 
                                        } elsif ($ctx =~ /.xW/) {
-                                               ERROR("space prohibited after that '$op' $at\n" . $hereptr);
+                                               ERROR("Aspace prohibited after that '$op' $at\n" . $hereptr);
                                        }
 
                                # unary ++ and unary -- are allowed no space on one side.
@@ -2560,7 +2562,7 @@ sub process {
                if ($line =~ /\bin_atomic\s*\(/) {
                        if ($realfile =~ m@^drivers/@) {
                                ERROR("do not use in_atomic in drivers\n" . $herecurr);
-                       } else {
+                       } elsif ($realfile !~ m@^kernel/@) {
                                WARN("use of in_atomic() is incorrect outside core kernel code\n" . $herecurr);
                        }
                }
index d40449cafa84a44dac9f21c54364913c777ffc6d..528492bcba5bf73e8f809490c9d6d8c8ea821ec8 100644 (file)
@@ -1,4 +1,4 @@
-#!/usr/bin/perl -w
+#!/usr/bin/perl
 
 use File::Basename;
 
@@ -29,27 +29,151 @@ my $filename = $vmlinux_name;
 my $target = "0";
 my $function;
 my $module = "";
-my $func_offset;
+my $func_offset = 0;
 my $vmaoffset = 0;
 
+my %regs;
+
+
+sub parse_x86_regs
+{
+       my ($line) = @_;
+       if ($line =~ /EAX: ([0-9a-f]+) EBX: ([0-9a-f]+) ECX: ([0-9a-f]+) EDX: ([0-9a-f]+)/) {
+               $regs{"%eax"} = $1;
+               $regs{"%ebx"} = $2;
+               $regs{"%ecx"} = $3;
+               $regs{"%edx"} = $4;
+       }
+       if ($line =~ /ESI: ([0-9a-f]+) EDI: ([0-9a-f]+) EBP: ([0-9a-f]+) ESP: ([0-9a-f]+)/) {
+               $regs{"%esi"} = $1;
+               $regs{"%edi"} = $2;
+               $regs{"%esp"} = $4;
+       }
+       if ($line =~ /RAX: ([0-9a-f]+) RBX: ([0-9a-f]+) RCX: ([0-9a-f]+)/) {
+               $regs{"%eax"} = $1;
+               $regs{"%ebx"} = $2;
+               $regs{"%ecx"} = $3;
+       }
+       if ($line =~ /RDX: ([0-9a-f]+) RSI: ([0-9a-f]+) RDI: ([0-9a-f]+)/) {
+               $regs{"%edx"} = $1;
+               $regs{"%esi"} = $2;
+               $regs{"%edi"} = $3;
+       }
+       if ($line =~ /RBP: ([0-9a-f]+) R08: ([0-9a-f]+) R09: ([0-9a-f]+)/) {
+               $regs{"%r08"} = $2;
+               $regs{"%r09"} = $3;
+       }
+       if ($line =~ /R10: ([0-9a-f]+) R11: ([0-9a-f]+) R12: ([0-9a-f]+)/) {
+               $regs{"%r10"} = $1;
+               $regs{"%r11"} = $2;
+               $regs{"%r12"} = $3;
+       }
+       if ($line =~ /R13: ([0-9a-f]+) R14: ([0-9a-f]+) R15: ([0-9a-f]+)/) {
+               $regs{"%r13"} = $1;
+               $regs{"%r14"} = $2;
+               $regs{"%r15"} = $3;
+       }
+}
+
+sub reg_name
+{
+       my ($reg) = @_;
+       $reg =~ s/r(.)x/e\1x/;
+       $reg =~ s/r(.)i/e\1i/;
+       $reg =~ s/r(.)p/e\1p/;
+       return $reg;
+}
+
+sub process_x86_regs
+{
+       my ($line, $cntr) = @_;
+       my $str = "";
+       if (length($line) < 40) {
+               return ""; # not an asm istruction
+       }
+
+       # find the arguments to the instruction
+       if ($line =~ /([0-9a-zA-Z\,\%\(\)\-\+]+)$/) {
+               $lastword = $1;
+       } else {
+               return "";
+       }
+
+       # we need to find the registers that get clobbered,
+       # since their value is no longer relevant for previous
+       # instructions in the stream.
+
+       $clobber = $lastword;
+       # first, remove all memory operands, they're read only
+       $clobber =~ s/\([a-z0-9\%\,]+\)//g;
+       # then, remove everything before the comma, thats the read part
+       $clobber =~ s/.*\,//g;
+
+       # if this is the instruction that faulted, we haven't actually done
+       # the write yet... nothing is clobbered.
+       if ($cntr == 0) {
+               $clobber = "";
+       }
+
+       foreach $reg (keys(%regs)) {
+               my $clobberprime = reg_name($clobber);
+               my $lastwordprime = reg_name($lastword);
+               my $val = $regs{$reg};
+               if ($val =~ /^[0]+$/) {
+                       $val = "0";
+               } else {
+                       $val =~ s/^0*//;
+               }
+
+               # first check if we're clobbering this register; if we do
+               # we print it with a =>, and then delete its value
+               if ($clobber =~ /$reg/ || $clobberprime =~ /$reg/) {
+                       if (length($val) > 0) {
+                               $str = $str . " $reg => $val ";
+                       }
+                       $regs{$reg} = "";
+                       $val = "";
+               }
+               # now check if we're reading this register
+               if ($lastword =~ /$reg/ || $lastwordprime =~ /$reg/) {
+                       if (length($val) > 0) {
+                               $str = $str . " $reg = $val ";
+                       }
+               }
+       }
+       return $str;
+}
+
+# parse the oops
 while (<STDIN>) {
        my $line = $_;
        if ($line =~ /EIP: 0060:\[\<([a-z0-9]+)\>\]/) {
                $target = $1;
        }
+       if ($line =~ /RIP: 0010:\[\<([a-z0-9]+)\>\]/) {
+               $target = $1;
+       }
        if ($line =~ /EIP is at ([a-zA-Z0-9\_]+)\+(0x[0-9a-f]+)\/0x[a-f0-9]/) {
                $function = $1;
                $func_offset = $2;
        }
+       if ($line =~ /RIP: 0010:\[\<[0-9a-f]+\>\]  \[\<[0-9a-f]+\>\] ([a-zA-Z0-9\_]+)\+(0x[0-9a-f]+)\/0x[a-f0-9]/) {
+               $function = $1;
+               $func_offset = $2;
+       }
 
        # check if it's a module
        if ($line =~ /EIP is at ([a-zA-Z0-9\_]+)\+(0x[0-9a-f]+)\/0x[a-f0-9]+\W\[([a-zA-Z0-9\_\-]+)\]/) {
                $module = $3;
        }
+       if ($line =~ /RIP: 0010:\[\<[0-9a-f]+\>\]  \[\<[0-9a-f]+\>\] ([a-zA-Z0-9\_]+)\+(0x[0-9a-f]+)\/0x[a-f0-9]+\W\[([a-zA-Z0-9\_\-]+)\]/) {
+               $module = $3;
+       }
+       parse_x86_regs($line);
 }
 
 my $decodestart = hex($target) - hex($func_offset);
-my $decodestop = $decodestart + 8192;
+my $decodestop = hex($target) + 8192;
 if ($target eq "0") {
        print "No oops found!\n";
        print "Usage: \n";
@@ -84,6 +208,7 @@ my $counter = 0;
 my $state   = 0;
 my $center  = 0;
 my @lines;
+my @reglines;
 
 sub InRange {
        my ($address, $target) = @_;
@@ -188,16 +313,36 @@ while ($finish < $counter) {
 
 my $i;
 
-my $fulltext = "";
+
+# start annotating the registers in the asm.
+# this goes from the oopsing point back, so that the annotator
+# can track (opportunistically) which registers got written and
+# whos value no longer is relevant.
+
+$i = $center;
+while ($i >= $start) {
+       $reglines[$i] = process_x86_regs($lines[$i], $center - $i);
+       $i = $i - 1;
+}
+
 $i = $start;
 while ($i < $finish) {
+       my $line;
        if ($i == $center) {
-               $fulltext = $fulltext . "*$lines[$i]     <----- faulting instruction\n";
+               $line =  "*$lines[$i] ";
        } else {
-               $fulltext = $fulltext .  " $lines[$i]\n";
+               $line =  " $lines[$i] ";
+       }
+       print $line;
+       if (defined($reglines[$i]) && length($reglines[$i]) > 0) {
+               my $c = 60 - length($line);
+               while ($c > 0) { print " "; $c = $c - 1; };
+               print "| $reglines[$i]";
        }
+       if ($i == $center) {
+               print "<--- faulting instruction";
+       }
+       print "\n";
        $i = $i +1;
 }
 
-print $fulltext;
-
index 491b8b1b6abf326cd1e018c813d14fbbd0402e0b..4eea60b1693e1173960f34e7c73927f5fe61fccb 100644 (file)
@@ -210,6 +210,7 @@ static void do_usb_table(void *symval, unsigned long size,
 static int do_hid_entry(const char *filename,
                             struct hid_device_id *id, char *alias)
 {
+       id->bus = TO_NATIVE(id->bus);
        id->vendor = TO_NATIVE(id->vendor);
        id->product = TO_NATIVE(id->product);
 
index 2500886fb90aa0273743cc67ba40da48c6b4fa5c..ee448cdc6a2b3cd47ca22fd94fd0995d5985f9ae 100755 (executable)
@@ -86,6 +86,14 @@ echo "%endif"
 echo 'cp System.map $RPM_BUILD_ROOT'"/boot/System.map-$KERNELRELEASE"
 
 echo 'cp .config $RPM_BUILD_ROOT'"/boot/config-$KERNELRELEASE"
+
+echo "%ifnarch ppc64"
+echo 'cp vmlinux vmlinux.orig'
+echo 'bzip2 -9 vmlinux'
+echo 'mv vmlinux.bz2 $RPM_BUILD_ROOT'"/boot/vmlinux-$KERNELRELEASE.bz2"
+echo 'mv vmlinux.orig vmlinux'
+echo "%endif"
+
 echo ""
 echo "%clean"
 echo '#echo -rf $RPM_BUILD_ROOT'
index f6946cf99ce1bd0a06f9835157f39d4b2b80e971..f1c4b35bc32428b030f053d46010f21b6812c76f 100755 (executable)
@@ -58,14 +58,7 @@ fi
 # Check for svn and a svn repo.
 if rev=`svn info 2>/dev/null | grep '^Last Changed Rev'`; then
        rev=`echo $rev | awk '{print $NF}'`
-       changes=`svn status 2>/dev/null | grep '^[AMD]' | wc -l`
-
-       # Are there uncommitted changes?
-       if [ $changes != 0 ]; then
-               printf -- '-svn%s%s' "$rev" -dirty
-       else
-               printf -- '-svn%s' "$rev"
-       fi
+       printf -- '-svn%s' "$rev"
 
        # All done with svn
        exit
index fdbe78bb5e2b6ad8359aeabb26b0fcf98af44957..5bd8b1003d446b1f4e80dd7e9a788685263a3a6e 100755 (executable)
@@ -76,7 +76,10 @@ all_sources()
 
 all_kconfigs()
 {
-       find_sources $ALLSOURCE_ARCHS 'Kconfig*'
+       for arch in $ALLSOURCE_ARCHS; do
+               find_sources $arch 'Kconfig*'
+       done
+       find_other_sources 'Kconfig*'
 }
 
 all_defconfigs()
@@ -99,7 +102,8 @@ exuberant()
        -I ____cacheline_internodealigned_in_smp                \
        -I EXPORT_SYMBOL,EXPORT_SYMBOL_GPL                      \
        --extra=+f --c-kinds=+px                                \
-       --regex-asm='/^ENTRY\(([^)]*)\).*/\1/'
+       --regex-asm='/^ENTRY\(([^)]*)\).*/\1/'                  \
+       --regex-c='/^SYSCALL_DEFINE[[:digit:]]?\(([^,)]*).*/sys_\1/'
 
        all_kconfigs | xargs $1 -a                              \
        --langdef=kconfig --language-force=kconfig              \
@@ -117,7 +121,9 @@ exuberant()
 
 emacs()
 {
-       all_sources | xargs $1 -a
+       all_sources | xargs $1 -a                               \
+       --regex='/^ENTRY(\([^)]*\)).*/\1/'                      \
+       --regex='/^SYSCALL_DEFINE[0-9]?(\([^,)]*\).*/sys_\1/'
 
        all_kconfigs | xargs $1 -a                              \
        --regex='/^[ \t]*\(\(menu\)*config\)[ \t]+\([a-zA-Z0-9_]+\)/\3/'
index f58701a7b728619a5a50e3bc74981baa23ab60cf..350794ab9b4212d7e50b07f3c778bb42bb81aa3a 100644 (file)
@@ -386,11 +386,12 @@ int selinux_netlbl_inode_permission(struct inode *inode, int mask)
        if (!S_ISSOCK(inode->i_mode) ||
            ((mask & (MAY_WRITE | MAY_APPEND)) == 0))
                return 0;
-
        sock = SOCKET_I(inode);
        sk = sock->sk;
+       if (sk == NULL)
+               return 0;
        sksec = sk->sk_security;
-       if (sksec->nlbl_state != NLBL_REQUIRE)
+       if (sksec == NULL || sksec->nlbl_state != NLBL_REQUIRE)
                return 0;
 
        local_bh_disable();
@@ -490,8 +491,10 @@ int selinux_netlbl_socket_setsockopt(struct socket *sock,
                lock_sock(sk);
                rc = netlbl_sock_getattr(sk, &secattr);
                release_sock(sk);
-               if (rc == 0 && secattr.flags != NETLBL_SECATTR_NONE)
+               if (rc == 0)
                        rc = -EACCES;
+               else if (rc == -ENOMSG)
+                       rc = 0;
                netlbl_secattr_destroy(&secattr);
        }
 
index dd4a12dc09aa44f4c50c5b60f2cf5584c5635589..077a85262c1c2592c8323b6f249fc645aaf5ecc7 100644 (file)
@@ -47,7 +47,7 @@ static int snd_jack_dev_register(struct snd_device *device)
        int err;
 
        snprintf(jack->name, sizeof(jack->name), "%s %s",
-                card->longname, jack->id);
+                card->shortname, jack->id);
        jack->input_dev->name = jack->name;
 
        /* Default to the sound card device. */
index a466443c4a2649b819147e70d9f041bc1f25b38b..2fa9299a440dbb99e767c079e664d0a1133e8762 100644 (file)
@@ -157,7 +157,7 @@ static void resample_shrink(struct snd_pcm_plugin *plugin,
                while (dst_frames1 > 0) {
                        S1 = S2;
                        if (src_frames1-- > 0) {
-                               S1 = *src;
+                               S2 = *src;
                                src += src_step;
                        }
                        if (pos & ~R_MASK) {
index 57d9f154c88b96ad5df87893f70e5690449c1d31..38931f2f6967e0f1f11c0e0296bd398e1770d538 100644 (file)
@@ -847,23 +847,23 @@ static int __init AtaIrqInit(void)
           of events. So all we need to keep the music playing is
           to provide the sound hardware with new data upon
           an interrupt from timer A. */
-       mfp.tim_ct_a = 0;       /* ++roman: Stop timer before programming! */
-       mfp.tim_dt_a = 1;       /* Cause interrupt after first event. */
-       mfp.tim_ct_a = 8;       /* Turn on event counting. */
+       st_mfp.tim_ct_a = 0;    /* ++roman: Stop timer before programming! */
+       st_mfp.tim_dt_a = 1;    /* Cause interrupt after first event. */
+       st_mfp.tim_ct_a = 8;    /* Turn on event counting. */
        /* Register interrupt handler. */
        if (request_irq(IRQ_MFP_TIMA, AtaInterrupt, IRQ_TYPE_SLOW, "DMA sound",
                        AtaInterrupt))
                return 0;
-       mfp.int_en_a |= 0x20;   /* Turn interrupt on. */
-       mfp.int_mk_a |= 0x20;
+       st_mfp.int_en_a |= 0x20;        /* Turn interrupt on. */
+       st_mfp.int_mk_a |= 0x20;
        return 1;
 }
 
 #ifdef MODULE
 static void AtaIrqCleanUp(void)
 {
-       mfp.tim_ct_a = 0;       /* stop timer */
-       mfp.int_en_a &= ~0x20;  /* turn interrupt off */
+       st_mfp.tim_ct_a = 0;            /* stop timer */
+       st_mfp.int_en_a &= ~0x20;       /* turn interrupt off */
        free_irq(IRQ_MFP_TIMA, AtaInterrupt);
 }
 #endif /* MODULE */
@@ -1599,7 +1599,7 @@ static int __init dmasound_atari_init(void)
                is_falcon = 0;
            } else
                return -ENODEV;
-           if ((mfp.int_en_a & mfp.int_mk_a & 0x20) == 0)
+           if ((st_mfp.int_en_a & st_mfp.int_mk_a & 0x20) == 0)
                return dmasound_init();
            else {
                printk("DMA sound driver: Timer A interrupt already in use\n");
index 3f00ddf450f81c287b198cdbdf4c8a17b180c4f8..c7c54e7748e9ac6fdbf09f1d4bb11f7106d1bfc3 100644 (file)
@@ -165,7 +165,7 @@ module_param_array(enable, bool, NULL, 0444);
 MODULE_PARM_DESC(enable, "Enable Audiowerk2 soundcard.");
 
 static struct pci_device_id snd_aw2_ids[] = {
-       {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, PCI_ANY_ID, PCI_ANY_ID,
+       {PCI_VENDOR_ID_SAA7146, PCI_DEVICE_ID_SAA7146, 0, 0,
         0, 0, 0},
        {0}
 };
index 7958006a1d66cf9559a62bbda6fbfd48b0994047..101a1c13a20dd0b4cdd106d89dd5867187b2b2f9 100644 (file)
@@ -1528,6 +1528,7 @@ static struct snd_emu_chip_details emu_chip_details[] = {
         .ca0151_chip = 1,
         .spk71 = 1,
         .spdif_bug = 1,
+        .invert_shared_spdif = 1,      /* digital/analog switch swapped */
         .ac97_chip = 1} ,
        {.vendor = 0x1102, .device = 0x0004, .subsystem = 0x10021102,
         .driver = "Audigy2", .name = "SB Audigy 2 Platinum [SB0240P]",
index 482fb0304ca91fc4a7735408393ec68b888bcefc..4ae51dcb81af861450e37d2219c76b6027746764 100644 (file)
@@ -277,18 +277,19 @@ static ssize_t init_verbs_store(struct device *dev,
 {
        struct snd_hwdep *hwdep = dev_get_drvdata(dev);
        struct hda_codec *codec = hwdep->private_data;
-       char *p;
-       struct hda_verb verb, *v;
+       struct hda_verb *v;
+       int nid, verb, param;
 
-       verb.nid = simple_strtoul(buf, &p, 0);
-       verb.verb = simple_strtoul(p, &p, 0);
-       verb.param = simple_strtoul(p, &p, 0);
-       if (!verb.nid || !verb.verb || !verb.param)
+       if (sscanf(buf, "%i %i %i", &nid, &verb, &param) != 3)
+               return -EINVAL;
+       if (!nid || !verb)
                return -EINVAL;
        v = snd_array_new(&codec->init_verbs);
        if (!v)
                return -ENOMEM;
-       *v = verb;
+       v->nid = nid;
+       v->verb = verb;
+       v->param = param;
        return count;
 }
 
index 11e791b965f6a772588ac7dff64437b3ec836e70..5e909e0da04b4b64d18ee9979f38cbaaa853e354 100644 (file)
@@ -1947,16 +1947,13 @@ static int azx_suspend(struct pci_dev *pci, pm_message_t state)
        return 0;
 }
 
-static int azx_resume_early(struct pci_dev *pci)
-{
-       return pci_restore_state(pci);
-}
-
 static int azx_resume(struct pci_dev *pci)
 {
        struct snd_card *card = pci_get_drvdata(pci);
        struct azx *chip = card->private_data;
 
+       pci_set_power_state(pci, PCI_D0);
+       pci_restore_state(pci);
        if (pci_enable_device(pci) < 0) {
                printk(KERN_ERR "hda-intel: pci_enable_device failed, "
                       "disabling device\n");
@@ -2098,6 +2095,8 @@ static struct snd_pci_quirk probe_mask_list[] __devinitdata = {
        SND_PCI_QUIRK(0x1028, 0x20ac, "Dell Studio Desktop", 0x01),
        /* including bogus ALC268 in slot#2 that conflicts with ALC888 */
        SND_PCI_QUIRK(0x17c0, 0x4085, "Medion MD96630", 0x01),
+       /* conflict of ALC268 in slot#3 (digital I/O); a temporary fix */
+       SND_PCI_QUIRK(0x1179, 0xff00, "Toshiba laptop", 0x03),
        {}
 };
 
@@ -2468,7 +2467,6 @@ static struct pci_driver driver = {
        .remove = __devexit_p(azx_remove),
 #ifdef CONFIG_PM
        .suspend = azx_suspend,
-       .resume_early = azx_resume_early,
        .resume = azx_resume,
 #endif
 };
index ed8fcbd60003cf1ad88af2ded2a5fbda0af2113e..6c26afcb82622d7b0e994f69c334cec8ef90bf33 100644 (file)
@@ -7017,6 +7017,7 @@ static int patch_alc882(struct hda_codec *codec)
                case 0x106b3e00: /* iMac 24 Aluminium */
                        board_config = ALC885_IMAC24;
                        break;
+               case 0x106b00a0: /* MacBookPro3,1 - Another revision */
                case 0x106b00a1: /* Macbook (might be wrong - PCI SSID?) */
                case 0x106b00a4: /* MacbookPro4,1 */
                case 0x106b2c00: /* Macbook Pro rev3 */
@@ -8469,6 +8470,8 @@ static struct snd_pci_quirk alc883_cfg_tbl[] = {
                ALC888_ACER_ASPIRE_4930G),
        SND_PCI_QUIRK(0x1025, 0x015e, "Acer Aspire 6930G",
                ALC888_ACER_ASPIRE_4930G),
+       SND_PCI_QUIRK(0x1025, 0x0166, "Acer Aspire 6530G",
+               ALC888_ACER_ASPIRE_4930G),
        SND_PCI_QUIRK(0x1025, 0, "Acer laptop", ALC883_ACER), /* default Acer */
        SND_PCI_QUIRK(0x1028, 0x020d, "Dell Inspiron 530", ALC888_6ST_DELL),
        SND_PCI_QUIRK(0x103c, 0x2a3d, "HP Pavillion", ALC883_6ST_DIG),
@@ -10554,6 +10557,7 @@ static struct snd_pci_quirk alc262_cfg_tbl[] = {
        SND_PCI_QUIRK(0x103c, 0x1309, "HP xw4*00", ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x130a, "HP xw6*00", ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x130b, "HP xw8*00", ALC262_HP_BPC),
+       SND_PCI_QUIRK(0x103c, 0x170b, "HP xw*", ALC262_HP_BPC),
        SND_PCI_QUIRK(0x103c, 0x2800, "HP D7000", ALC262_HP_BPC_D7000_WL),
        SND_PCI_QUIRK(0x103c, 0x2801, "HP D7000", ALC262_HP_BPC_D7000_WF),
        SND_PCI_QUIRK(0x103c, 0x2802, "HP D7000", ALC262_HP_BPC_D7000_WL),
index 8027edf3c8f2ab2d13848b45ab3a66495ceb2e81..3bc427645da8ef1411400990b67c9fc181e4cece 100644 (file)
@@ -4989,7 +4989,7 @@ again:
        case STAC_DELL_M4_3:
                spec->num_dmics = 1;
                spec->num_smuxes = 0;
-               spec->num_dmuxes = 0;
+               spec->num_dmuxes = 1;
                break;
        default:
                spec->num_dmics = STAC92HD71BXX_NUM_DMICS;
index 18c7c91786bc3d5ff40d615b4a7adc49b13bbedc..6c870c12a1777f887076166b4009d7d18b6cd315 100644 (file)
@@ -26,7 +26,7 @@
  * SPI 0 -> 1st PCM1796 (front)
  * SPI 1 -> 2nd PCM1796 (surround)
  * SPI 2 -> 3rd PCM1796 (center/LFE)
- * SPI 4 -> 4th PCM1796 (back) and EEPROM self-destruct (do not use!)
+ * SPI 4 -> 4th PCM1796 (back)
  *
  * GPIO 2 -> M0 of CS5381
  * GPIO 3 -> M1 of CS5381
@@ -207,12 +207,6 @@ static void xonar_gpio_changed(struct oxygen *chip);
 static inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec,
                                     u8 reg, u8 value)
 {
-       /*
-        * We don't want to do writes on SPI 4 because the EEPROM, which shares
-        * the same pin, might get confused and broken.  We'd better take care
-        * that the driver works with the default register values ...
-        */
-#if 0
        /* maps ALSA channel pair number to SPI output */
        static const u8 codec_map[4] = {
                0, 1, 2, 4
@@ -223,7 +217,6 @@ static inline void pcm1796_write_spi(struct oxygen *chip, unsigned int codec,
                         (codec_map[codec] << OXYGEN_SPI_CODEC_SHIFT) |
                         OXYGEN_SPI_CEN_LATCH_CLOCK_HI,
                         (reg << 8) | value);
-#endif
 }
 
 static inline void pcm1796_write_i2c(struct oxygen *chip, unsigned int codec,
@@ -757,9 +750,6 @@ static const DECLARE_TLV_DB_SCALE(cs4362a_db_scale, -12700, 100, 0);
 
 static int xonar_d2_control_filter(struct snd_kcontrol_new *template)
 {
-       if (!strncmp(template->name, "Master Playback ", 16))
-               /* disable volume/mute because they would require SPI writes */
-               return 1;
        if (!strncmp(template->name, "CD Capture ", 11))
                /* CD in is actually connected to the video in pin */
                template->private_value ^= AC97_CD ^ AC97_VIDEO;
@@ -850,8 +840,9 @@ static const struct oxygen_model model_xonar_d2 = {
        .dac_volume_min = 0x0f,
        .dac_volume_max = 0xff,
        .misc_flags = OXYGEN_MISC_MIDI,
-       .function_flags = OXYGEN_FUNCTION_SPI,
-       .dac_i2s_format = OXYGEN_I2S_FORMAT_I2S,
+       .function_flags = OXYGEN_FUNCTION_SPI |
+                         OXYGEN_FUNCTION_ENABLE_SPI_4_5,
+       .dac_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
        .adc_i2s_format = OXYGEN_I2S_FORMAT_LJUST,
 };
 
index 84131a916c92bc379ec1f07cdb515fc37ae13749..69d87dee6995f72e174940a44bd0a4f302b7e7f4 100644 (file)
@@ -97,12 +97,12 @@ struct pcxhr_mgr {
        int capture_chips;
        int fw_file_set;
        int firmware_num;
-       int is_hr_stereo:1;
-       int board_has_aes1:1;   /* if 1 board has AES1 plug and SRC */
-       int board_has_analog:1; /* if 0 the board is digital only */
-       int board_has_mic:1;    /* if 1 the board has microphone input */
-       int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */
-       int mono_capture:1;     /* if 1 the board does mono capture */
+       unsigned int is_hr_stereo:1;
+       unsigned int board_has_aes1:1;  /* if 1 board has AES1 plug and SRC */
+       unsigned int board_has_analog:1; /* if 0 the board is digital only */
+       unsigned int board_has_mic:1; /* if 1 the board has microphone input */
+       unsigned int board_aes_in_192k:1;/* if 1 the aes input plugs do support 192kHz */
+       unsigned int mono_capture:1; /* if 1 the board does mono capture */
 
        struct snd_dma_buffer hostport;
 
index 2ab83129d9b04b846c7fd15a076a53cdef1d1c21..19e37451c216182ebdc9d800f304a66f5e6bc9e7 100644 (file)
@@ -2524,7 +2524,6 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
                 * build the rate table and bitmap flags
                 */
                int r, idx;
-               unsigned int nonzero_rates = 0;
 
                fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL);
                if (fp->rate_table == NULL) {
@@ -2532,24 +2531,27 @@ static int parse_audio_format_rates(struct snd_usb_audio *chip, struct audioform
                        return -1;
                }
 
-               fp->nr_rates = nr_rates;
-               fp->rate_min = fp->rate_max = combine_triple(&fmt[8]);
+               fp->nr_rates = 0;
+               fp->rate_min = fp->rate_max = 0;
                for (r = 0, idx = offset + 1; r < nr_rates; r++, idx += 3) {
                        unsigned int rate = combine_triple(&fmt[idx]);
+                       if (!rate)
+                               continue;
                        /* C-Media CM6501 mislabels its 96 kHz altsetting */
                        if (rate == 48000 && nr_rates == 1 &&
-                           chip->usb_id == USB_ID(0x0d8c, 0x0201) &&
+                           (chip->usb_id == USB_ID(0x0d8c, 0x0201) ||
+                            chip->usb_id == USB_ID(0x0d8c, 0x0102)) &&
                            fp->altsetting == 5 && fp->maxpacksize == 392)
                                rate = 96000;
-                       fp->rate_table[r] = rate;
-                       nonzero_rates |= rate;
-                       if (rate < fp->rate_min)
+                       fp->rate_table[fp->nr_rates] = rate;
+                       if (!fp->rate_min || rate < fp->rate_min)
                                fp->rate_min = rate;
-                       else if (rate > fp->rate_max)
+                       if (!fp->rate_max || rate > fp->rate_max)
                                fp->rate_max = rate;
                        fp->rates |= snd_pcm_rate_to_rate_bit(rate);
+                       fp->nr_rates++;
                }
-               if (!nonzero_rates) {
+               if (!fp->nr_rates) {
                        hwc_debug("All rates were zero. Skipping format!\n");
                        return -1;
                }
index 320641ab5be7bf972a78603d1c988ef8fae8f08a..26bad373fe65c012de152ac4f753076951390330 100644 (file)
@@ -1625,6 +1625,7 @@ static int snd_usbmidi_create_endpoints_midiman(struct snd_usb_midi* umidi,
        }
 
        ep_info.out_ep = get_endpoint(hostif, 2)->bEndpointAddress & USB_ENDPOINT_NUMBER_MASK;
+       ep_info.out_interval = 0;
        ep_info.out_cables = endpoint->out_cables & 0x5555;
        err = snd_usbmidi_out_endpoint_create(umidi, &ep_info, &umidi->endpoints[0]);
        if (err < 0)
index e9693a29d00e2fe5b159632e301ca4cd0d08bb4d..4c403750360082f0e53d3e5459c17d78797ab9e0 100644 (file)
@@ -73,14 +73,13 @@ static int kvm_iommu_map_memslots(struct kvm *kvm)
 {
        int i, r = 0;
 
-       down_read(&kvm->slots_lock);
        for (i = 0; i < kvm->nmemslots; i++) {
                r = kvm_iommu_map_pages(kvm, kvm->memslots[i].base_gfn,
                                        kvm->memslots[i].npages);
                if (r)
                        break;
        }
-       up_read(&kvm->slots_lock);
+
        return r;
 }
 
@@ -190,12 +189,11 @@ static void kvm_iommu_put_pages(struct kvm *kvm,
 static int kvm_iommu_unmap_memslots(struct kvm *kvm)
 {
        int i;
-       down_read(&kvm->slots_lock);
+
        for (i = 0; i < kvm->nmemslots; i++) {
                kvm_iommu_put_pages(kvm, kvm->memslots[i].base_gfn,
                                    kvm->memslots[i].npages);
        }
-       up_read(&kvm->slots_lock);
 
        return 0;
 }
index 3a5a08298aabd1a06c770c2cf4c2b657fae0af14..29a667ce35b0ebc1840f1fcbb6ae3cf3313fa3b8 100644 (file)
@@ -173,7 +173,6 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
                assigned_dev->host_irq_disabled = false;
        }
        mutex_unlock(&assigned_dev->kvm->lock);
-       kvm_put_kvm(assigned_dev->kvm);
 }
 
 static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id)
@@ -181,8 +180,6 @@ static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id)
        struct kvm_assigned_dev_kernel *assigned_dev =
                (struct kvm_assigned_dev_kernel *) dev_id;
 
-       kvm_get_kvm(assigned_dev->kvm);
-
        schedule_work(&assigned_dev->interrupt_work);
 
        disable_irq_nosync(irq);
@@ -213,6 +210,7 @@ static void kvm_assigned_dev_ack_irq(struct kvm_irq_ack_notifier *kian)
        }
 }
 
+/* The function implicit hold kvm->lock mutex due to cancel_work_sync() */
 static void kvm_free_assigned_irq(struct kvm *kvm,
                                  struct kvm_assigned_dev_kernel *assigned_dev)
 {
@@ -228,11 +226,24 @@ static void kvm_free_assigned_irq(struct kvm *kvm,
        if (!assigned_dev->irq_requested_type)
                return;
 
-       if (cancel_work_sync(&assigned_dev->interrupt_work))
-               /* We had pending work. That means we will have to take
-                * care of kvm_put_kvm.
-                */
-               kvm_put_kvm(kvm);
+       /*
+        * In kvm_free_device_irq, cancel_work_sync return true if:
+        * 1. work is scheduled, and then cancelled.
+        * 2. work callback is executed.
+        *
+        * The first one ensured that the irq is disabled and no more events
+        * would happen. But for the second one, the irq may be enabled (e.g.
+        * for MSI). So we disable irq here to prevent further events.
+        *
+        * Notice this maybe result in nested disable if the interrupt type is
+        * INTx, but it's OK for we are going to free it.
+        *
+        * If this function is a part of VM destroy, please ensure that till
+        * now, the kvm state is still legal for probably we also have to wait
+        * interrupt_work done.
+        */
+       disable_irq_nosync(assigned_dev->host_irq);
+       cancel_work_sync(&assigned_dev->interrupt_work);
 
        free_irq(assigned_dev->host_irq, (void *)assigned_dev);
 
@@ -285,8 +296,8 @@ static int assigned_device_update_intx(struct kvm *kvm,
 
        if (irqchip_in_kernel(kvm)) {
                if (!msi2intx &&
-                   adev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI) {
-                       free_irq(adev->host_irq, (void *)kvm);
+                   (adev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI)) {
+                       free_irq(adev->host_irq, (void *)adev);
                        pci_disable_msi(adev->dev);
                }
 
@@ -455,6 +466,7 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
        struct kvm_assigned_dev_kernel *match;
        struct pci_dev *dev;
 
+       down_read(&kvm->slots_lock);
        mutex_lock(&kvm->lock);
 
        match = kvm_find_assigned_dev(&kvm->arch.assigned_dev_head,
@@ -516,6 +528,7 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm,
 
 out:
        mutex_unlock(&kvm->lock);
+       up_read(&kvm->slots_lock);
        return r;
 out_list_del:
        list_del(&match->list);
@@ -527,6 +540,7 @@ out_put:
 out_free:
        kfree(match);
        mutex_unlock(&kvm->lock);
+       up_read(&kvm->slots_lock);
        return r;
 }
 #endif
@@ -789,11 +803,19 @@ static int kvm_mmu_notifier_clear_flush_young(struct mmu_notifier *mn,
        return young;
 }
 
+static void kvm_mmu_notifier_release(struct mmu_notifier *mn,
+                                    struct mm_struct *mm)
+{
+       struct kvm *kvm = mmu_notifier_to_kvm(mn);
+       kvm_arch_flush_shadow(kvm);
+}
+
 static const struct mmu_notifier_ops kvm_mmu_notifier_ops = {
        .invalidate_page        = kvm_mmu_notifier_invalidate_page,
        .invalidate_range_start = kvm_mmu_notifier_invalidate_range_start,
        .invalidate_range_end   = kvm_mmu_notifier_invalidate_range_end,
        .clear_flush_young      = kvm_mmu_notifier_clear_flush_young,
+       .release                = kvm_mmu_notifier_release,
 };
 #endif /* CONFIG_MMU_NOTIFIER && KVM_ARCH_WANT_MMU_NOTIFIER */
 
@@ -883,6 +905,7 @@ static void kvm_destroy_vm(struct kvm *kvm)
 {
        struct mm_struct *mm = kvm->mm;
 
+       kvm_arch_sync_events(kvm);
        spin_lock(&kvm_lock);
        list_del(&kvm->vm_list);
        spin_unlock(&kvm_lock);